Files
BlueArchiveToolkit/docs/architecture/resource-release-layout.md
T

312 lines
12 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-24
- **用途**:冻结日服官方资源在本地发布根上的布局、URL 映射、seed 规则,以及 `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 后端 |
| 资源只读分发 | Go `bat-api` | 按官方 CDN path 提供已发布字节;经 `bat.sock` 发现版本 |
| 试验 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-sync-snapshot.json # 常在 active root / current 下
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 缓存
<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 | `current` 解析后的 versioned 目录,或 RPC 给出的 `version.resource_root` |
---
## 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 主体。)
### 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 匹配** 的文件。
---
## 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 行为 |
|---|---|---|
| client-patch 内容 | GET 官方 path;无业务鉴权头(资源 CDN) | `GET/HEAD /prod-clientpatch.../...` 原样字节 |
| server-info | GET JSON;字段 PascalCase`ConnectionGroups` 等) | 可选加载并**只改** `AddressablesCatalogUrlRoot` 指向 `{public-base}/prod-clientpatch.../{token}` |
| seed `.hash` | 纯文本十进制(可含空白) | 原样分发 |
| Range / 断点 | 官方客户端下载器用 Range;bat 用 curl `.part` | **本轮 bat-api 可不实现 Range**;记入后续 |
| 业务 ApiUrl/Gateway | 游戏协议 | **不改写、不仿造** |
Addressables 改写后客户端拼接:
```text
{rewritten_root}/TableBundles/TableCatalog.bytes
≡ {public-base}/prod-clientpatch.../{token}/TableBundles/TableCatalog.bytes
```
与磁盘映射一致。
---
## 8. RPC 与分发发现顺序
`bat-api`(及任何 Go 服务层)发现当前 release
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`;应急 `--resource-root`。见 `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. 真机实勘若发现与本文冲突 → **以真机为准** 修代码与本文,禁止静默分叉。