style(游戏共创): 按 rustfmt 修正本分支新增代码的格式(无语义变化)
Project CI / AI game creator shell Rust lane 1/2 (pull_request) Has been cancelled
Project CI / AI game creator shell Rust lane 2/2 (pull_request) Has been cancelled
Project CI / AI game creator shell Rust crates (pull_request) Has been cancelled
Project CI / Backend tests (pull_request) Has been cancelled
Project CI / Native shell tests (pull_request) Has been cancelled
Project CI / Frontend tests (pull_request) Has been cancelled
Project CI / Repository checks (pull_request) Has been cancelled
Project CI / AI game creator shell web tests (pull_request) Has been cancelled

判定依据(先判定再动手):仓库根 `rustfmt.toml`(edition 2024 / max_width 100 / use_small_heuristics=Default)与本地 rustfmt 1.9.0-stable 一致;`cargo fmt --all --manifest-path server-rs/Cargo.toml -- --check` 的红项(24 处 hunk / 7 个文件)**全部落在本分支新增的代码上**,且 master 版本的同名文件在同样配置下是干净的(`git show 6c9566058:...errors.rs` 单文件 --check 通过),另三个 workspace(tauri / unity / godot)也 CLEAN。因此是本分支引入的格式漂移,不是环境差异——仓库 `npm run check:rustfmt`(在 `npm run lint` 里)会因此失败,故修正。

- api-server/src/modules/game_distribution.rs:两处 import 列表按宽度重排;`derived_games_payload` / `lineage_tree_payload` / `set_game_distribution_fork_authorization` 调用与 `fork_source_target` 的 `Err(...)`、取件相关测试的换行与尾逗号
- spacetime-module/src/game_distribution.rs:3 处 `return Err(...)` 与 `let Some(game) = ctx.db...` 的换行
- spacetime-client:`active.rs` 的 import 列表、`mapper/game_distribution.rs` 的 `collect()` 链、`game_distribution.rs` 的 procedure 回调换行
- module-game-distribution:`domain.rs` 的错误码字面量元组、`errors.rs` `Display` 分支的换行

验证:`cargo fmt --all --manifest-path server-rs/Cargo.toml -- --check` 退出 0;逐文件比对「删除全部空白后」的字符流,差异仅为 rustfmt 展开/折叠时增删的**尾逗号**(每文件长度差 ≤4 字符),无语义变化;格式化后 `cargo check --all-targets` 与 `cargo test -p api-server game_distribution`(52 passed)仍通过。
This commit is contained in:
2026-10-05 01:35:46 +08:00
parent 3d60caa14a
commit e71ab190f7
7 changed files with 86 additions and 99 deletions
@@ -40,10 +40,9 @@ use shared_contracts::game_distribution::{
GAME_DISTRIBUTION_CATEGORIES, GAME_DISTRIBUTION_VERSION_NUMBER_CONFLICT,
GameDistributionAuthor, GameDistributionCreateGameRequest,
GameDistributionCreateVersionRequest, GameDistributionDerivedResponse,
GameDistributionForkAuthorization, GameDistributionForkSource,
GameDistributionForkSourceKind, GameDistributionForkSourceResponse,
GameDistributionInputMode, GameDistributionLineageNode, GameDistributionLineageResponse,
GameDistributionMyReviewResponse, GameDistributionOrientation,
GameDistributionForkAuthorization, GameDistributionForkSource, GameDistributionForkSourceKind,
GameDistributionForkSourceResponse, GameDistributionInputMode, GameDistributionLineageNode,
GameDistributionLineageResponse, GameDistributionMyReviewResponse, GameDistributionOrientation,
GameDistributionPublishMetadataSuggestion, GameDistributionPublishMetadataSuggestionRequest,
GameDistributionRatingSummary, GameDistributionReview, GameDistributionReviewsResponse,
GameDistributionSaveReviewRequest, GameDistributionSaveReviewResponse,
@@ -57,16 +56,15 @@ use spacetime_client::{
GameDistributionCancelVersionRecordInput, GameDistributionDeleteGameRecordInput,
GameDistributionDerivedGamesRecord, GameDistributionForkSourceRecord,
GameDistributionGameRecord, GameDistributionGetGameRecordInput,
GameDistributionLineageNodeRecord,
GameDistributionLineageTreeRecord, GameDistributionOwnerGameRecord,
GameDistributionPublicGameListRecordInput, GameDistributionPublicGameRecord,
GameDistributionRatingSummaryRecord, GameDistributionRejectRecordInput,
GameDistributionRestoreRecordInput, GameDistributionReviewGameListRecordInput,
GameDistributionReviewModerationOperationRecord, GameDistributionReviewModerationRecordInput,
GameDistributionSetForkAuthorizationRecordInput, GameDistributionSubmitReviewRecordInput,
GameDistributionSuspendRecordInput, GameDistributionUnpublishRecordInput,
GameDistributionUpdateMetadataRecordInput, GameDistributionUserReviewRecord,
GameDistributionVersionRecord, SpacetimeClientError,
GameDistributionLineageNodeRecord, GameDistributionLineageTreeRecord,
GameDistributionOwnerGameRecord, GameDistributionPublicGameListRecordInput,
GameDistributionPublicGameRecord, GameDistributionRatingSummaryRecord,
GameDistributionRejectRecordInput, GameDistributionRestoreRecordInput,
GameDistributionReviewGameListRecordInput, GameDistributionReviewModerationOperationRecord,
GameDistributionReviewModerationRecordInput, GameDistributionSetForkAuthorizationRecordInput,
GameDistributionSubmitReviewRecordInput, GameDistributionSuspendRecordInput,
GameDistributionUnpublishRecordInput, GameDistributionUpdateMetadataRecordInput,
GameDistributionUserReviewRecord, GameDistributionVersionRecord, SpacetimeClientError,
};
use tracing::{debug, info, warn};
use uuid::Uuid;
@@ -1123,7 +1121,10 @@ async fn get_game_derived_games(
.await
.map_err(map_spacetime_error)?,
)?;
Ok(json_success_body(Some(&ctx), derived_games_payload(derived)))
Ok(json_success_body(
Some(&ctx),
derived_games_payload(derived),
))
}
/// 线上可见性字符串 → DTO 枚举;未知取值按「未公开」保守解释,不会因此多暴露任何信息。
@@ -1149,7 +1150,9 @@ fn lineage_node_payload(node: GameDistributionLineageNodeRecord) -> GameDistribu
/// 族谱 / 衍生列表走结构化 DTO 而不是手拼 JSON:节点字段本来就少且固定,
/// 用 DTO 才能让「不发对象键、不发素材键」由类型保证,而不是靠人肉回忆。
fn lineage_tree_payload(tree: GameDistributionLineageTreeRecord) -> GameDistributionLineageResponse {
fn lineage_tree_payload(
tree: GameDistributionLineageTreeRecord,
) -> GameDistributionLineageResponse {
GameDistributionLineageResponse {
root_game_id: tree.root_game_id,
root: tree.root.map(lineage_node_payload),
@@ -2481,19 +2484,17 @@ async fn set_fork_authorization(
);
let game = state
.spacetime_client()
.set_game_distribution_fork_authorization(
GameDistributionSetForkAuthorizationRecordInput {
game_id,
owner_user_id,
fork_authorization: fork_authorization_value(payload.fork_authorization),
expected_fork_authorization: fork_authorization_value(
payload.expected_fork_authorization,
),
idempotency_key,
request_digest,
now_micros: now_micros(),
},
)
.set_game_distribution_fork_authorization(GameDistributionSetForkAuthorizationRecordInput {
game_id,
owner_user_id,
fork_authorization: fork_authorization_value(payload.fork_authorization),
expected_fork_authorization: fork_authorization_value(
payload.expected_fork_authorization,
),
idempotency_key,
request_digest,
now_micros: now_micros(),
})
.await
.map_err(map_spacetime_error)?;
Ok(json_success_body(
@@ -2520,9 +2521,7 @@ fn fork_source_target(
record: GameDistributionForkSourceRecord,
) -> Result<ForkSourceTarget, AppError> {
if !record.found {
return Err(
AppError::from_status(StatusCode::NOT_FOUND).with_code("FORK_SOURCE_NOT_FOUND")
);
return Err(AppError::from_status(StatusCode::NOT_FOUND).with_code("FORK_SOURCE_NOT_FOUND"));
}
if !record.available {
return Err(
@@ -2533,9 +2532,7 @@ fn fork_source_target(
module_game_distribution::ForkAuthorization::parse(record.fork_authorization.as_str())
.unwrap_or(module_game_distribution::ForkAuthorization::Forbidden);
if !authorization.allows_fork() {
return Err(
AppError::from_status(StatusCode::FORBIDDEN).with_code("FORK_NOT_AUTHORIZED")
);
return Err(AppError::from_status(StatusCode::FORBIDDEN).with_code("FORK_NOT_AUTHORIZED"));
}
// 失败关闭:`available` 为真却没有版本元数据时不发半截信息,按不可用处理。
let (Some(version_id), Some(package_sha256), Some(package_bytes)) = (
@@ -2668,10 +2665,7 @@ fn fork_source_package_response(game_id: &str, version_id: &str, package: Bytes)
))
.unwrap_or_else(|_| HeaderValue::from_static("attachment")),
);
headers.insert(
header::CACHE_CONTROL,
HeaderValue::from_static("no-store"),
);
headers.insert(header::CACHE_CONTROL, HeaderValue::from_static("no-store"));
response
}
@@ -3723,9 +3717,7 @@ fn map_spacetime_error(error: SpacetimeClientError) -> AppError {
let (status, code) = match code {
"FORK_NOT_AUTHORIZED" => (StatusCode::FORBIDDEN, "FORK_NOT_AUTHORIZED"),
"FORK_SOURCE_NOT_FOUND" => (StatusCode::NOT_FOUND, "FORK_SOURCE_NOT_FOUND"),
"FORK_SOURCE_NOT_AVAILABLE" => {
(StatusCode::CONFLICT, "FORK_SOURCE_NOT_AVAILABLE")
}
"FORK_SOURCE_NOT_AVAILABLE" => (StatusCode::CONFLICT, "FORK_SOURCE_NOT_AVAILABLE"),
"FORK_SOURCE_VERSION_MISMATCH" => {
(StatusCode::CONFLICT, "FORK_SOURCE_VERSION_MISMATCH")
}
@@ -5021,7 +5013,9 @@ mod tests {
.layer(Extension(AuthenticatedAccessToken::new(claims)))
// 用生产同一套 request context 中间件:错误 envelope 的 `ok` / `meta` 由它挂上的
// task-local 决定(直接手塞 Extension 只能拿到 legacy 形状,断言不到 envelope)。
.layer(middleware::from_fn(crate::request_context::attach_request_context))
.layer(middleware::from_fn(
crate::request_context::attach_request_context,
))
.with_state(state);
for (payload, label) in [
@@ -5160,14 +5154,12 @@ mod tests {
play_count: 3,
status: "mystery".to_string(),
};
let tree = serde_json::to_value(lineage_tree_payload(
GameDistributionLineageTreeRecord {
root_game_id: "game-root".to_string(),
root: Some(root.clone()),
nodes: vec![root, child],
truncated: true,
},
))
let tree = serde_json::to_value(lineage_tree_payload(GameDistributionLineageTreeRecord {
root_game_id: "game-root".to_string(),
root: Some(root.clone()),
nodes: vec![root, child],
truncated: true,
}))
.expect("族谱负载应可序列化");
assert_eq!(tree["rootGameId"], Value::String("game-root".to_string()));
@@ -5203,14 +5195,13 @@ mod tests {
expected_keys.sort();
assert_eq!(node_keys, expected_keys);
let derived = serde_json::to_value(derived_games_payload(
GameDistributionDerivedGamesRecord {
let derived =
serde_json::to_value(derived_games_payload(GameDistributionDerivedGamesRecord {
game_id: "game-root".to_string(),
nodes: Vec::new(),
truncated: false,
},
))
.expect("衍生列表负载应可序列化");
}))
.expect("衍生列表负载应可序列化");
assert_eq!(derived["gameId"], Value::String("game-root".to_string()));
assert_eq!(derived["nodes"], Value::Array(Vec::new()));
assert_eq!(derived["truncated"], Value::Bool(false));
@@ -5274,26 +5265,17 @@ mod tests {
#[test]
fn fork_source_target_maps_contract_status_codes() {
// 行不存在 → 404;此时其余字段无意义,不得被误判成 409/403。
let missing = fork_source_target(fork_source_record(
false,
false,
"forbidden",
None,
))
.expect_err("行不存在必须失败");
let missing = fork_source_target(fork_source_record(false, false, "forbidden", None))
.expect_err("行不存在必须失败");
assert_eq!(missing.status_code(), StatusCode::NOT_FOUND);
assert_eq!(missing.code(), "FORK_SOURCE_NOT_FOUND");
// 行存在但不可用(已软删除 / 未公开 / 没有当前公开版本)→ 409,且**先于**授权判定:
// 未公开 + 允许共创仍然是 409,不能因为授权开放就暴露「这个 gameId 存在」。
for label in ["已软删除", "未公开", "没有当前公开版本"] {
let unavailable = fork_source_target(fork_source_record(
true,
false,
"nonCommercial",
None,
))
.expect_err("不可用作来源必须失败");
let unavailable =
fork_source_target(fork_source_record(true, false, "nonCommercial", None))
.expect_err("不可用作来源必须失败");
assert_eq!(unavailable.status_code(), StatusCode::CONFLICT, "{label}");
assert_eq!(unavailable.code(), "FORK_SOURCE_NOT_AVAILABLE", "{label}");
}
@@ -408,7 +408,10 @@ mod fork_authorization_tests {
},
"FORK_AUTHORIZATION_DOWNGRADE_NOT_ALLOWED",
),
(GameDistributionError::ForkNotAuthorized, "FORK_NOT_AUTHORIZED"),
(
GameDistributionError::ForkNotAuthorized,
"FORK_NOT_AUTHORIZED",
),
(
GameDistributionError::ForkSourceNotFound,
"FORK_SOURCE_NOT_FOUND",
@@ -125,12 +125,10 @@ impl fmt::Display for GameDistributionError {
Self::ForkSourceNotAvailable => {
formatter.write_str("FORK_SOURCE_NOT_AVAILABLE: 改编来源作品当前不可改编")
}
Self::ForkSourceVersionMismatch => formatter.write_str(
"FORK_SOURCE_VERSION_MISMATCH: 改编来源版本不是该作品的当前公开版本",
),
Self::ForkDeclarationOnExistingGame => formatter.write_str(
"FORK_DECLARATION_ON_EXISTING_GAME: 已存在的作品不能再声明改编来源",
),
Self::ForkSourceVersionMismatch => formatter
.write_str("FORK_SOURCE_VERSION_MISMATCH: 改编来源版本不是该作品的当前公开版本"),
Self::ForkDeclarationOnExistingGame => formatter
.write_str("FORK_DECLARATION_ON_EXISTING_GAME: 已存在的作品不能再声明改编来源"),
}
}
}
@@ -31,9 +31,8 @@ pub use game_distribution::{
GameDistributionPublicGameListRecordInput, GameDistributionRejectRecordInput,
GameDistributionRestoreRecordInput, GameDistributionReviewGameListRecordInput,
GameDistributionReviewModerationRecordInput, GameDistributionSetForkAuthorizationRecordInput,
GameDistributionSubmitReviewRecordInput,
GameDistributionSuspendRecordInput, GameDistributionUnpublishRecordInput,
GameDistributionUpdateMetadataRecordInput,
GameDistributionSubmitReviewRecordInput, GameDistributionSuspendRecordInput,
GameDistributionUnpublishRecordInput, GameDistributionUpdateMetadataRecordInput,
};
#[path = "active/external_generation.rs"]
pub mod external_generation;
@@ -582,11 +582,7 @@ pub(crate) fn map_game_distribution_public_game_list_result(
if !result.ok {
return Err(SpacetimeClientError::procedure_failed(result.error_message));
}
Ok(result
.games
.into_iter()
.map(map_public_game)
.collect())
Ok(result.games.into_iter().map(map_public_game).collect())
}
pub(crate) fn map_game_distribution_version_result(
@@ -662,12 +662,15 @@ impl SpacetimeClient {
move |connection, sender| {
connection
.procedures()
.list_game_distribution_derived_games_and_return_then(input, move |_, result| {
let mapped = result
.map_err(SpacetimeClientError::from_sdk_error)
.and_then(map_game_distribution_derived_games_result);
send_once(&sender, mapped);
});
.list_game_distribution_derived_games_and_return_then(
input,
move |_, result| {
let mapped = result
.map_err(SpacetimeClientError::from_sdk_error)
.and_then(map_game_distribution_derived_games_result);
send_once(&sender, mapped);
},
);
},
)
.await
@@ -2194,8 +2194,9 @@ fn resolve_game_distribution_fork_declaration_tx(
module_game_distribution::GameDistributionError::ForkSourceNotAvailable.to_string()
})?;
if current_version_id.as_str() != forked_from_version_id {
return Err(module_game_distribution::GameDistributionError::ForkSourceVersionMismatch
.to_string());
return Err(
module_game_distribution::GameDistributionError::ForkSourceVersionMismatch.to_string(),
);
}
let (root_game_id, parent_generation) = match ctx
.db
@@ -2285,8 +2286,10 @@ fn create_game_distribution_game_tx(
if let Some(game) = existing {
// 复用既有作品身份时不允许再声明改编来源:否则会把别人的原创作改判成衍生作品。
if fork_resolution.is_some() {
return Err(module_game_distribution::GameDistributionError::ForkDeclarationOnExistingGame
.to_string());
return Err(
module_game_distribution::GameDistributionError::ForkDeclarationOnExistingGame
.to_string(),
);
}
insert_game_distribution_receipt(
ctx,
@@ -4221,9 +4224,7 @@ fn get_game_distribution_fork_source_tx(
found: true,
available,
fork_authorization: game.fork_authorization.clone(),
version_id: version
.as_ref()
.map(|version| version.version_id.clone()),
version_id: version.as_ref().map(|version| version.version_id.clone()),
package_sha256: version
.as_ref()
.map(|version| version.package_sha256.clone()),
@@ -4254,7 +4255,12 @@ fn game_distribution_lineage_entries(
.by_game_distribution_lineage_root_game_id()
.filter(&root_game_id.to_string())
{
let Some(game) = ctx.db.game_distribution_game().game_id().find(&lineage.game_id) else {
let Some(game) = ctx
.db
.game_distribution_game()
.game_id()
.find(&lineage.game_id)
else {
continue;
};
entries.push(game_distribution_lineage_entry(