fix(api): 统一 catalog GameMainConfig 字段

This commit is contained in:
2026-07-31 16:05:17 +08:00
parent 4cc143f66d
commit 20ddd67947
4 changed files with 42 additions and 21 deletions
@@ -90,14 +90,14 @@ Go 窗口读取归一化后的 JSON,验证:
- `version.completed_unix_seconds` - `version.completed_unix_seconds`
- `version.resource_root` - `version.resource_root`
- `launcher_metadata` - `launcher_metadata`
- `game_main_config` - `game_main_config_bootstrap`
2. `parseCatalogStatus``available=false` 返回不可用而不是错误。 2. `parseCatalogStatus``available=false` 返回不可用而不是错误。
3. `resource.manifest` entry 字段能映射为 Go `ResourceManifestEntry` 3. `resource.manifest` entry 字段能映射为 Go `ResourceManifestEntry`
- `url` - `url`
- `destination` - `destination`
- `bytes` - `bytes`
- `blake3` - `blake3`
4. 本地 snapshot fixture 使用 `game_main_config_bootstrap`RPC `catalog.status` 使用 `game_main_config` 4. 本地 snapshot fixture RPC `catalog.status` 使用 `game_main_config_bootstrap`
5. `bat-api` bootstrap 和 launcher bootstrap 不泄露归一化前的开发机路径。 5. `bat-api` bootstrap 和 launcher bootstrap 不泄露归一化前的开发机路径。
Go 侧审核通过后的落地建议: Go 侧审核通过后的落地建议:
@@ -118,8 +118,8 @@ Go 侧审核通过后的落地建议:
- `launcher_metadata.game_lowest_version` - `launcher_metadata.game_lowest_version`
- `launcher_metadata.game_start_exe_name` - `launcher_metadata.game_start_exe_name`
- `launcher_metadata.manifest_source` - `launcher_metadata.manifest_source`
- `game_main_config.server_info_data_url` - `game_main_config_bootstrap.server_info_data_url`
- `game_main_config.default_connection_group` - `game_main_config_bootstrap.default_connection_group`
2. optional 字段为 null 或缺省: 2. optional 字段为 null 或缺省:
- Go mirror 不应崩溃。 - Go mirror 不应崩溃。
- HTTP response 中按当前 Go struct `omitempty` 策略输出。 - HTTP response 中按当前 Go struct `omitempty` 策略输出。
@@ -130,7 +130,7 @@ Go 侧审核通过后的落地建议:
- 归一化是否过度改变 Rust 真实输出。 - 归一化是否过度改变 Rust 真实输出。
- fixture 是否意外绑定真实版本、日期、本机路径或私有部署路径。 - fixture 是否意外绑定真实版本、日期、本机路径或私有部署路径。
- `game_main_config``game_main_config_bootstrap` RPC / snapshot 差异是否符合预期 - `game_main_config_bootstrap` RPC / snapshot 中是否保持同一语义
- optional 字段覆盖是否足够。 - optional 字段覆盖是否足够。
## notes.md 模板 ## notes.md 模板
@@ -191,6 +191,6 @@ contract fixture 工作只有在以下条件同时满足时才算完成:
## 当前状态 ## 当前状态
- Go `bat-api` 已具备消费 `launcher_metadata` / `game_main_config` 的 mirror struct。 - Go `bat-api` 已具备消费 `launcher_metadata` / `game_main_config_bootstrap` 的 mirror struct。
- Go `bat-api` 已具备 player-facing HTTP 控制面、OpenAPI 和管理面板预留。 - Go `bat-api` 已具备 player-facing HTTP 控制面、OpenAPI 和管理面板预留。
- contract fixture 尚未落仓库,等待 Rust 侧真实输出与用户审核。 - contract fixture 尚未落仓库,等待 Rust 侧真实输出与用户审核。
+16 -2
View File
@@ -2572,7 +2572,7 @@ fn build_catalog_status_report(state_dir: &Path) -> anyhow::Result<serde_json::V
"official_seed_hash_marker_count": official_seed_hash_marker_count, "official_seed_hash_marker_count": official_seed_hash_marker_count,
"addressables_catalog_marker_count": snapshot.addressables_marker_checked_count(), "addressables_catalog_marker_count": snapshot.addressables_marker_checked_count(),
"launcher_metadata": snapshot.launcher_metadata, "launcher_metadata": snapshot.launcher_metadata,
"game_main_config": snapshot.game_main_config_bootstrap, "game_main_config_bootstrap": snapshot.game_main_config_bootstrap,
"snapshot_version": snapshot.snapshot_version, "snapshot_version": snapshot.snapshot_version,
})) }))
} }
@@ -9987,7 +9987,13 @@ mod tests {
endpoints: Vec::new(), endpoints: Vec::new(),
endpoint_markers: Vec::new(), endpoint_markers: Vec::new(),
launcher_metadata: None, launcher_metadata: None,
game_main_config_bootstrap: None, game_main_config_bootstrap: Some(bat_infrastructure::GameMainConfigSnapshot {
server_info_data_url: Some(
"https://prod-serverinfo.bluearchiveyostar.com/server-info.json"
.to_string(),
),
default_connection_group: Some("Prod-Audit".to_string()),
}),
}; };
bat_infrastructure::write_snapshot(&snapshot_path, &snapshot).unwrap(); bat_infrastructure::write_snapshot(&snapshot_path, &snapshot).unwrap();
OfficialVersionRecord { OfficialVersionRecord {
@@ -10091,6 +10097,14 @@ mod tests {
assert_eq!(value["data"]["version"]["id"], "v-current"); assert_eq!(value["data"]["version"]["id"], "v-current");
assert_eq!(value["data"]["endpoint_count"], 0); assert_eq!(value["data"]["endpoint_count"], 0);
assert_eq!(value["data"]["connection_group_name"], "Prod-Audit"); assert_eq!(value["data"]["connection_group_name"], "Prod-Audit");
assert_eq!(
value["data"]["game_main_config_bootstrap"]["default_connection_group"],
"Prod-Audit"
);
assert!(!value["data"]
.as_object()
.unwrap()
.contains_key("game_main_config"));
} }
#[test] #[test]
+7
View File
@@ -567,6 +567,10 @@ func TestDiscoverCallsStatusBeforeDoctor(t *testing.T) {
"bundle_version": "s8tloc7lo3", "bundle_version": "s8tloc7lo3",
"connection_group_name": "Prod", "connection_group_name": "Prod",
"addressables_root": "https://prod-clientpatch.bluearchiveyostar.com/r93_fixture", "addressables_root": "https://prod-clientpatch.bluearchiveyostar.com/r93_fixture",
"game_main_config_bootstrap": map[string]any{
"server_info_data_url": "https://prod-serverinfo.bluearchiveyostar.com/server-info.json",
"default_connection_group": "Prod",
},
"version": map[string]any{ "version": map[string]any{
"id": "v1", "id": "v1",
"resource_root": root, "resource_root": root,
@@ -614,6 +618,9 @@ func TestDiscoverCallsStatusBeforeDoctor(t *testing.T) {
if summary.Snapshot.DistributionStatusCode != "distribution.ready" { if summary.Snapshot.DistributionStatusCode != "distribution.ready" {
t.Fatalf("distribution status code=%q", summary.Snapshot.DistributionStatusCode) t.Fatalf("distribution status code=%q", summary.Snapshot.DistributionStatusCode)
} }
if summary.Snapshot.GameMainConfig == nil || summary.Snapshot.GameMainConfig.DefaultConnectionGroup != "Prod" {
t.Fatalf("game main config=%+v", summary.Snapshot.GameMainConfig)
}
} }
func TestLoadEnvFileDoesNotOverride(t *testing.T) { func TestLoadEnvFileDoesNotOverride(t *testing.T) {
+2 -2
View File
@@ -205,7 +205,7 @@ func parseCatalogStatus(raw json.RawMessage) (*SnapshotSummary, string, bool) {
ConnectionGroupName string `json:"connection_group_name"` ConnectionGroupName string `json:"connection_group_name"`
AddressablesRoot string `json:"addressables_root"` AddressablesRoot string `json:"addressables_root"`
LauncherMetadata *LauncherMetadataSummary `json:"launcher_metadata"` LauncherMetadata *LauncherMetadataSummary `json:"launcher_metadata"`
GameMainConfig *GameMainConfigSummary `json:"game_main_config"` GameMainConfigBootstrap *GameMainConfigSummary `json:"game_main_config_bootstrap"`
Version *struct { Version *struct {
ID string `json:"id"` ID string `json:"id"`
CompletedUnixSeconds *uint64 `json:"completed_unix_seconds"` CompletedUnixSeconds *uint64 `json:"completed_unix_seconds"`
@@ -225,7 +225,7 @@ func parseCatalogStatus(raw json.RawMessage) (*SnapshotSummary, string, bool) {
ConnectionGroupName: payload.ConnectionGroupName, ConnectionGroupName: payload.ConnectionGroupName,
AddressablesRoot: payload.AddressablesRoot, AddressablesRoot: payload.AddressablesRoot,
LauncherMetadata: payload.LauncherMetadata, LauncherMetadata: payload.LauncherMetadata,
GameMainConfig: payload.GameMainConfig, GameMainConfig: payload.GameMainConfigBootstrap,
} }
root := "" root := ""
if payload.Version != nil { if payload.Version != nil {