From f4582fe5b3eb2e6d361d198e49b668fbe75c5076 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E7=8E=8B=E5=BE=B7=E5=AE=87?= Date: Wed, 7 Oct 2026 14:07:52 +0800 Subject: [PATCH] =?UTF-8?q?=E6=B8=B8=E6=88=8F=E5=88=86=E5=8F=91=E5=BB=BA?= =?UTF-8?q?=E6=B8=B8/=E5=BB=BA=E7=89=88=E5=85=88=E6=A0=A1=E9=AA=8C=20local?= =?UTF-8?q?=5Fproject=5Fid=20=E5=86=8D=E4=B8=8A=E4=BC=A0=E5=AA=92=E4=BD=93?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit - create_game 与 create_version 把 normalize_local_project_id 提前到 resolve_publish_media 之前,避免用户输入非法时提前返回、已上传的封面/截图成为孤儿对象 --- .../api-server/src/modules/game_distribution.rs | 14 ++++++++------ 1 file changed, 8 insertions(+), 6 deletions(-) diff --git a/server-rs/crates/api-server/src/modules/game_distribution.rs b/server-rs/crates/api-server/src/modules/game_distribution.rs index f3d3024a3..99320232d 100644 --- a/server-rs/crates/api-server/src/modules/game_distribution.rs +++ b/server-rs/crates/api-server/src/modules/game_distribution.rs @@ -2016,6 +2016,9 @@ async fn create_game( // 幂等摘要只覆盖请求内容(元数据 + 图片字节),不含服务端生成的 objectKey, // 这样重放同一个 Idempotency-Key 时摘要稳定、命中既有结果。 let request_digest = publish_request_digest(&payload, cover.as_ref(), screenshots.as_slice())?; + // 先在接触对象存储前完成所有会让用户输入失败的转换:normalize_local_project_id 的 `?` + // 如果留到 create_game_distribution_game 实参里求值,上传完的封面/截图会因提前返回而成为孤儿。 + let local_project_id = normalize_local_project_id(payload.local_project_id.as_deref())?; let (cover_object_key, resolved_screenshots, uploaded_media) = resolve_publish_media( &state, game_id.as_str(), @@ -2057,9 +2060,7 @@ async fn create_game( idempotency_key, request_digest, now_micros: now, - local_project_id: normalize_local_project_id( - payload.local_project_id.as_deref(), - )?, + local_project_id, }, ) .await, @@ -2104,6 +2105,9 @@ async fn create_version( cover.as_ref(), screenshots.as_slice(), )?; + // 与 create_game 同理:用户输入相关的失败必须在 resolve_publish_media 上传之前发生, + // 否则 `?` 会在 cleanup_uncommitted_publish_media 之前返回,留下孤儿媒体对象。 + let local_project_id = normalize_local_project_id(payload.local_project_id.as_deref())?; let (cover_object_key, resolved_screenshots, uploaded_media) = resolve_publish_media( &state, game_id.as_str(), @@ -2137,9 +2141,7 @@ async fn create_version( package_bytes: payload.package_bytes, package_file_count: payload.package_file_count, package_entry_path: payload.package_entry_path, - local_project_id: normalize_local_project_id( - payload.local_project_id.as_deref(), - )?, + local_project_id, idempotency_key, request_digest, now_micros: now,