Files
BlueArchiveToolkit/docs/architecture/resource-release-layout.md
T
nyaKazuha 03021ad649
bat-rust / Build and test Rust (push) Canceled after 0s
docs(project): 同步维护冻结与运行文档
补齐解析模块维护冻结规则,并同步 CURRENT_STATUS、CURRENT_GAPS、PROJECT_PLAN、RPC 参考、部署指南、用户指南和官方资源运行说明。

文档同时反映 bat-api 资源 bootstrap/分发边界、官方同步解析缓存、TextUnit 队列、双目录发布和 patch 入口的当前状态。

验证:未运行新命令;本轮已按要求停止重复构建/测试。
2026-07-31 00:45:46 +08:00

360 lines
16 KiB
Markdown
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
# 官方资源 Release 布局与资源侧契约
- **更新时间**2026-07-27
- **用途**:冻结日服官方资源在本地发布根上的布局、URL 映射、seed 规则、`bat`/`bat-api` 关系,以及 `bat-api` 分发 path 的 1:1 对应关系。
- **范围**:资源发现 / 清单 / 落盘 / 只读分发(**不是**完整游戏业务 API)。
- **权威代码**
- URL / 平台 / seed`adapters/src/official/yostar_jp.rs`
- inventory 抽取:`adapters/src/official/inventory.rs`
- 落盘与 manifest`infrastructure/src/official_download.rs``destination_for_url`
- 发布布局:`infrastructure/src/official_update.rs`
- 分发:`cmd/bat-api` + `internal/api`(见 `docs/reports/GO_STATUS.md`
---
## 1. 产品边界(资源侧)
| 角色 | 组件 | 职责 |
|---|---|---|
| 同步 / 运维(近乎全自动) | Rust `bat` | auto-discover、拉取、校验、发布、watch/daemon、RPC 后端 |
| 资源 bootstrap / 只读分发 | Go `bat-api` | 同环境经 `bat.sock` 发现已发布版本和 `resource_root`,提供 `/v1/bootstrap`、server-info 改写和官方 CDN path 字节 |
| 试验 CLI | Go `cmd/bat``bin/bat-go` | 非产品;禁止与 Rust `bat` 重名 |
**禁止**:把已安装客户端目录或 `/home/wanye/D/BlueArchive` 当作生产输入;真实全量样本优先服务器 release 或 `/tmp` 隔离目录。
---
## 2. 发布根布局(L1
```text
<output>/ # 官方原版资源发布根(--output / BAT_OUTPUT
current -> versions/<id> # 原子 symlink,生产读侧
versions/<id>/ # 已发布 versioned release= resource_root
official-download-manifest.json
official-parse-cache.json # 校验后派生解析缓存,不是汉化产物
official-textunit-index.json # TextUnit 明细与解析错误索引,不是汉化产物
official-textunit-tasks.json # 翻译任务候选派生队列,不发 Crowdin 网络请求
crowdin-textunit-queue.json # Crowdin worker 离线输入队列
official-sync-snapshot.json # 常在 active root / current 下
official-launcher-bootstrap.json # 官方 launcher 引导链版本化产物
prod-clientpatch.bluearchiveyostar.com/
<root_token>/
TableBundles/
TableCatalog.bytes
TableCatalog.hash
<table files...> # e.g. ExcelDB.db, Excel.zip
Windows_PatchPack/
BundlePackingInfo.bytes
BundlePackingInfo.hash
catalog_StandaloneWindows64.zip
catalog_StandaloneWindows64.hash
FullPatch_NNN.zip
Android_PatchPack/
BundlePackingInfo.bytes
BundlePackingInfo.hash
catalog_Android.zip
catalog_Android.hash
FullPatch_NNN.zip
MediaResources-Windows/
Catalog/MediaCatalog.bytes
Catalog/MediaCatalog.hash
GameData/...
Prologue/...
MediaResources/ # Android
Catalog/MediaCatalog.bytes
Catalog/MediaCatalog.hash
...
yostar-serverinfo.bluearchiveyostar.com/ # 若曾下载 server-info
<name>.json
.staging/<id>/ # 未发布写侧(失败可复用)
official-version-state.json # 发布根级版本状态
official-bootstrap-cache.json # auto-discover 缓存
official-launcher-bootstrap.pending.json # 维护期 launcher 已前进但资源未开放时的待处理证据
<localized-output>/ # 汉化产物发布根(--localized-output / BAT_LOCALIZED_OUTPUT
current -> versions/<id> # 已汉化后才切换;未汉化状态不发布
versions/<id>/ # 与官方相对路径一致的汉化资源
localized-version-state.json # 预留:后续 Patch 发布阶段维护,官方同步阶段不写入
```
官方资源发布和汉化发布是两个独立状态:
- `not_localized`:官方原版资源已经完成下载、校验和发布,汉化资源尚未发布;这是官方同步完成后的默认状态。
- `localized`:同一官方版本的原版资源和汉化资源都已发布,生产侧可以同时提供两套资源。
### 2.1 读侧 vs 写侧
| 阶段 | 根目录 |
|---|---|
| 下载写入 | `<output>/.staging/<id>` |
| 发布完成 | rename 到 `versions/<id>`,再切换 `current` |
| 生产读取 / bat-api | RPC 给出的 `version.resource_root`;通常等价于 `current` 解析后的 versioned 目录 |
---
## 3. URL → 磁盘映射(核心不变量)
实现:`OfficialResourcePullService::destination_for_url`
```text
https://{host}/{path...} → <resource_root>/{host}/{path...}
```
规则:
1.`https://`
2. host 必须是官方 JP 资源 host(见下节)
3. path 分段不得为 `.` / `..`
4. **禁止** query / fragment(否则直接拒绝,避免同路径覆盖)
5. 分段经 sanitize 后 join;结果必须在 `resource_root`
### 3.1 官方 host
| Host | 用途 |
|---|---|
| `prod-clientpatch.bluearchiveyostar.com` | Addressables / Table / Media / PatchPack 内容 |
| `yostar-serverinfo.bluearchiveyostar.com` | server-info JSON |
launcher 包 CDN 属于启动器链,**不是**默认资源 release 主体。Rust `bat` 会把启动器链中与资源发现相关的 launcher metadata、CDN config、remote manifest 文件列表、选中的 `resources.assets` 来源和 `GameMainConfig` 摘要写入 `official-launcher-bootstrap.json`,供后续 `bat-api` / 自研客户端在 Rust 侧完成前继续以 versioned release 为权威来源。)
### 3.2 bat-api 对外 path1:1
```text
GET {public-base-url}/prod-clientpatch.bluearchiveyostar.com/<root_token>/...
≡ 磁盘 <resource_root>/prod-clientpatch.bluearchiveyostar.com/<root_token>/...
```
默认仅服务 **download manifest 索引内且 Present + size 匹配** 的文件。
### 3.3 launcher 资源引导兼容
只读分析本机样本时可见两类启动器形态:
| 目录形态 | 说明 |
|---|---|
| `AllResources/YostarGames/BlueArchive_JP_Gamelauncher` | 官方 Electron 启动器目录 |
| `Localized` / `Localized_Official` | 汉化或改造启动器目录 |
| `AllResources/YostarGames/BlueArchive_JP` | 官方安装后的游戏客户端目录,含 `game-launcher-config.json``manifest.json``BlueArchive_Data/StreamingAssets/catalog_Remote.*` |
这些目录只作为开发期样本;生产链路不得依赖 `/home/wanye/D/BlueArchive` 或任何已安装客户端目录。
官方启动器样本中与资源发现相关的 HTTP path:
| Host / path | 资源侧意义 |
|---|---|
| `https://api-launcher-jp.yo-star.com/api/launcher/game/config` | 返回 launcher 观察到的最新客户端版本和包路径 |
| `https://api-launcher-jp.yo-star.com/api/launcher/game/config/json?version=...&file_path=...` | 返回远端 package manifest URL |
| `https://api-launcher-jp.yo-star.com/api/launcher/advanced/game/download/cdn` | 返回 launcher package CDN primary / backup |
`bat-api` 的兼容范围是**资源引导**,不是完整启动器更新服务:
| bat-api path | 行为 |
|---|---|
| `/v1/launcher/bootstrap` | 返回资源引导聚合视图:已发布 release、launcher metadata、GameMainConfig 摘要、server-info URL、client-patch base、改写后的 Addressables root |
| `/api/launcher/game/config` | 返回 `{code,message,data}` envelope,字段来自 Rust `bat` snapshot/RPC 中的 `launcher_metadata`,并附带 `resource_bootstrap_url` |
| `/api/launcher/game/config/json` | 返回指向 `/api-launcher-jp.yo-star.com/api/launcher/resource/bootstrap.json` 的资源引导 JSON URL,显式标记 `package_update_manifest=false` |
| `/api/launcher/advanced/game/download/cdn` | 返回 `public-base-url` 作为资源引导 CDN 根,显式标记 `package_update_manifest=false` |
| `/api-launcher-jp.yo-star.com/...` | 与上面裸 path 等价,便于反向代理或 hosts 映射保持官方 host 形状 |
数据来源只能是 Rust `bat` 已发布状态;当前 Go `bat-api` 仍主要消费 snapshot/RPC 摘要,后续字段统一与联调时应把 versioned launcher artifact 纳入 contract fixture
1. `catalog.status` / `official-sync-snapshot.json` 中的 `launcher_metadata`
2. `catalog.status` / `official-sync-snapshot.json` 中的 `game_main_config_bootstrap`
3. `official-launcher-bootstrap.json` 中的官方 launcher bootstrap versioned artifact。
4. `resource.manifest` 和磁盘 Present/size 检查得到的当前 release 索引。
`bat-api` 不下载 launcher 包、不生成官方 PC package update manifest、不执行启动器签名/鉴权链、不仿造登录、账号、网关或游戏业务 API。需要真实资源拉取时,仍由 Rust `bat --auto-discover` 在隔离 staging 中通过官方 HTTP metadata 完成,并把已发布结果通过 RPC 暴露给 `bat-api`
---
## 4. `official-download-manifest.json`
| 字段 | 类型 | 说明 |
|---|---|---|
| `version` | u32 | 当前为 `1` |
| `entries` | map URL → entry | 按完整官方 URL 为键(有序 BTreeMap |
每条 entry
| 字段 | 说明 |
|---|---|
| `url` | 官方 https URL |
| `destination` | 相对 resource_root 的路径(`host/path...` |
| `bytes` | 文件大小 |
| `blake3` | 本地 BLAKE3 hex |
**权威清单**:拉取闭环写入的 manifest`bat-api` / RPC `resource.manifest` 以此为应有集合,再以磁盘校验 Present。
---
## 5. 发现与 seed URL 规则(L2
常量根:
- server-info`https://yostar-serverinfo.bluearchiveyostar.com`
- client-patch`https://prod-clientpatch.bluearchiveyostar.com`
`AddressablesCatalogUrlRoot` 形如:
```text
https://prod-clientpatch.bluearchiveyostar.com/<root_token>
```
默认平台:`Windows` + `Android`
### 5.1 平台目录名
| 平台 | Patch 目录 | Media 目录 | Addressables catalog zip |
|---|---|---|---|
| Windows | `Windows_PatchPack` | `MediaResources-Windows` | `catalog_StandaloneWindows64.zip` |
| Android | `Android_PatchPack` | `MediaResources` | `catalog_Android.zip` |
### 5.2 Seed 端点模板
共享(非平台):
```text
{CLIENT_PATCH}/{token}/TableBundles/TableCatalog.bytes
{CLIENT_PATCH}/{token}/TableBundles/TableCatalog.hash
```
每平台:
```text
{CLIENT_PATCH}/{token}/{PatchDir}/BundlePackingInfo.bytes
{CLIENT_PATCH}/{token}/{PatchDir}/BundlePackingInfo.hash
{CLIENT_PATCH}/{token}/{PatchDir}/{catalog_zip}
{CLIENT_PATCH}/{token}/{PatchDir}/{catalog_base}.hash
{CLIENT_PATCH}/{token}/{MediaDir}/Catalog/MediaCatalog.bytes
{CLIENT_PATCH}/{token}/{MediaDir}/Catalog/MediaCatalog.hash
```
### 5.3 Content URL 模板
| 类型 | 模板 |
|---|---|
| Table 文件 | `{CLIENT_PATCH}/{token}/TableBundles/{Name}` |
| Patch pack | `{CLIENT_PATCH}/{token}/{PatchDir}/{FullPatch_NNN.zip}` |
| Media 文件 | `{CLIENT_PATCH}/{token}/{MediaDir}/{relative_path}` |
`relative_path` 示例:`GameData/Audio/VOC_JP/JP_Airi.zip``Prologue/Scenario/Event/10000_Title_Sound.ogg`
### 5.4 校验分层
| 对象 | 算法 / 规则 |
|---|---|
| seed `.bytes` + `.hash` | 官方 `.hash`**xxHash32(seed=0)** 的十进制文本;强校验 |
| 一般已下载文件 | 本地 manifest **size + BLAKE3** |
| `.zip` | 另加 ZIP central/local 结构校验 |
| `catalog_*.hash` | Addressables/SBP **Hash128 文本标记****不是** seed 的 xxHash32 规则 |
---
## 6. Inventory 抽取规则(L3,当前实现)
实现:`adapters/src/official/inventory.rs`(**可打印串启发式**,非完整 schema 反序列化)。
| Catalog | 抽取逻辑 | 风险 |
|---|---|---|
| `BundlePackingInfo.bytes` | 可打印串中扩展名为 `zip` 且匹配 `FullPatch_NNN.zip`(总长 17,中间 3 位数字) | 漏抽非 FullPatch 包名(当前有意只 FullPatch |
| `TableCatalog.bytes` | 可打印串中 `.db`/`.zip` 文件名;**出现次数 ≥ 2** 才收录 | 依赖「双份列表」启发式;形态变化会漏/多 |
| `MediaCatalog.bytes` | 可打印串中相对路径,扩展名 zip/mp4/png/jpg/jpeg/ogg/wav | 路径须 `is_plausible_relative_path` |
**R2 待真机核对**:用服务器全量 seed 字节跑抽取,与 manifest 中 content URL 集合 diff;有未解释差异再改 inventory + fixture。
仓库内已有:`adapters/tests/fixtures``infrastructure/tests/fixtures/official_regression`**不能替代**全量 release 实勘。
---
## 7. 客户端资源请求假设(R3,服务 bat-api)
| 面 | 假设(当前工程) | bat-api 行为 |
|---|---|---|
| 启动前资源发现 | 客户端/补丁器需要知道当前资源版本、server-info 和 client-patch 根 | `GET /v1/bootstrap` 返回 `bat` RPC 健康、release 摘要、server-info URL、client-patch base 和改写后的 Addressables root |
| 服务就绪 | 运维需要区分进程存活和 release 是否可分发 | `GET /healthz` 返回 liveness + RPC refresh 诊断;`GET/HEAD /readyz` 无可分发 release 时返回 `503` |
| client-patch 内容 | GET 官方 path;无业务鉴权头(资源 CDN) | `GET/HEAD /prod-clientpatch.../...` 原样字节,支持 Range |
| server-info | GET JSON;字段 PascalCase`ConnectionGroups` 等) | 可选加载并**只改** `AddressablesCatalogUrlRoot` 指向 `{public-base}/prod-clientpatch.../{token}` |
| launcher bootstrap | 启动器链会先查 launcher metadata,再找到 server-info / Addressables root | `/v1/launcher/bootstrap``/api/launcher/...` 只输出资源引导兼容信息,来源是 Rust snapshot/RPC |
| seed `.hash` | 纯文本十进制(可含空白) | 原样分发 |
| Range / 断点 | 官方客户端下载器用 Range;bat 用 curl `.part` | `ServeContent` 支持 Range / `206` / `416` / `If-Range` |
| 缓存 / 条件请求 | 资源位于 versioned rootmanifest 有 BLAKE3 | ETag 优先使用 manifest BLAKE3;返回 Last-Modified、Accept-Ranges、长期 Cache-Control |
| 业务 ApiUrl/Gateway | 游戏协议 | **不改写、不仿造** |
Addressables 改写后客户端拼接:
```text
{rewritten_root}/TableBundles/TableCatalog.bytes
≡ {public-base}/prod-clientpatch.../{token}/TableBundles/TableCatalog.bytes
```
与磁盘映射一致。
---
## 8. RPC 与分发发现顺序
`bat-api`(及任何 Go 服务层)发现当前 release,并由 `/v1/bootstrap` 组织为启动前资源入口:
1. `daemon.status`
2. `daemon.doctor`
3. `catalog.status``version.resource_root``addressables_root`、app/bundle
4. `resource.manifest` 分页(url / destination / bytes / blake3
5.`resource_root` 上 Lstat 校验 Present / size
**不读** `bat-status.json` / `bat-tasks.json` 作为常规路径。
生产配置:`--socket` / `BAT_API_SOCKET``bat-api``bat` 在同服务器、同容器或同共享文件系统环境内运行。`--resource-root` 只用于本地 fixture 或应急只读诊断,不作为生产资源根配置。`BAT_API_REFRESH_INTERVAL` 控制 bat-api 周期重读 RPC,以跟随 Rust `bat` 发布新 release。见 `cmd/bat-api/.env.example`
---
## 9. issue #2 / #3 样本索引(R4/R5 预置)
在服务器 release 上优先采集到 `/tmp` 隔离目录(**不入库大文件**):
| 用途 | 建议路径模式 |
|---|---|
| Addressables#2 | `{PatchDir}/catalog_*.zip` 解压后的 JSON/bin + 旁路 `.hash` |
| UnityFS#3 | `FullPatch_*.zip` 内抽样 `.bundle`,或已解包 bundle |
| seed 加固(R2 | 各平台 `TableCatalog` / `BundlePackingInfo` / `MediaCatalog``.bytes`+`.hash` |
字段目标(#2,已有 `m_Crc` 部分):继续扩大 hash/size/CRC/依赖等可校验字段覆盖。
结构目标(#3):header / block / directory / metadata / object table 引擎级解析。
---
## 10. 服务器实勘清单(R1,等 SSH)
连接信息到位后只读执行:
1. `readlink current` → version id
2. 顶层是否仅有官方 host 目录 + manifest/snapshot
3. manifest 条目数 vs 磁盘抽样 size
4. RPC 四步(status → doctor → catalog.status → manifest 首页)
5. 将结论写入 `docs/reports/resource-server-survey-YYYYMMDD.md`(无凭据)
所需:
```text
SSH: user@host -p PORT
资源目录: .../official
bat.sock 或 state-dir: ...
```
---
## 11. 相关文档
- `docs/reports/GO_STATUS.md` — Go 边界与进度
- `docs/architecture/official-resource-backend.md` — 拉取后端总览
- `docs/reference/rpc-backend-api.md` — RPC 契约
- `docs/guides/official-resource-test-pull.md` — 用户向运行说明
- `docs/reports/CURRENT_GAPS.md` — G-009 / #2 / #3
---
## 12. 变更纪律
1. 改 URL 模板或落盘规则 → **必须**同步本文 + 相关单测。
2. 改 inventory 启发式 → 说明覆盖的真实风险并补 fixture。
3. 真机实勘若发现与本文冲突 → **以真机为准** 修代码与本文,禁止静默分叉。