mirror of
https://github.com/Yuyi-Oak/BlueArchiveToolkit.git
synced 2026-07-22 04:35:16 +08:00
将 bat-ffi 明确收敛为无状态 C ABI 兼容层,默认集成路径改为 bat --json 进程边界或未来稳定 SDK。 同步 README、当前状态、项目计划、架构文档、开发指南和缺口清单,移除 FFI 作为主集成边界的表述。 新增 AGENTS.md 和 CONTRIBUTING.md,压缩 CLAUDE.md 为兼容入口,并归档阶段性报告、同步 .gitignore 规则。
274 lines
16 KiB
Markdown
274 lines
16 KiB
Markdown
# 官方资源后端说明
|
||
|
||
本文档说明 BlueArchiveToolkit 中“官方资源后端”的职责、数据流和工作原理,供审核使用。
|
||
|
||
## 1. 范围
|
||
|
||
这个后端只处理 **日服官方资源**,只接受官方 `.jp/.com` 域名下的资源链路。
|
||
|
||
明确排除:
|
||
|
||
- `bluearchive.cafe`
|
||
- 任何镜像层、转写层、二次代理层
|
||
- 人工拼接出来的样例 URL
|
||
- Linux 生产环境安装或执行官方启动器
|
||
- 把已安装客户端目录或官方启动器安装目录当作生产输入
|
||
|
||
当前默认平台集合是:
|
||
|
||
- `Windows`
|
||
- `Android`
|
||
|
||
`iOS` 和 `macOS` 已从默认支持中移除。
|
||
|
||
## 2. 后端负责什么
|
||
|
||
| 层 | 任务 | 结果 |
|
||
|---|---|---|
|
||
| 发现层 | 读取官方 `server-info`,选择 connection group 和版本覆盖 | 得到官方资源根和种子端点 |
|
||
| 清单层 | 解析 `BundlePackingInfo.bytes`、`TableCatalog.bytes`、`MediaCatalog.bytes` | 得到完整文件清单 |
|
||
| 计划层 | 合并 discovery + inventory,去重并保序 | 得到全量 pull plan |
|
||
| 下载层 | 校验官方 URL,调用下载器,落盘并记录字节数 | 得到本地资源副本 |
|
||
| 导入层 | 将 bundle 写入 CAS 和 ResourceRepository | 得到可查询的资源索引 |
|
||
| 同步层 | 比较当前快照和历史快照 | 决定下载、校验、发布 |
|
||
| 更新层 | 保存上次官方 snapshot,定期执行 discovery + diff + pull | 形成自动更新闭环 |
|
||
|
||
## 3. 工作原理
|
||
|
||
### 3.0 Linux 生产约束
|
||
|
||
生产环境目标是 Linux 后端任务,不是 Windows 桌面客户端环境。
|
||
|
||
因此生产同步入口必须满足:
|
||
|
||
1. 不要求安装官方启动器。
|
||
2. 不要求启动官方启动器进程。
|
||
3. 不要求把生产环境当作客户端安装目录。
|
||
4. 可以显式执行 official metadata discovery 自动发现 `server-info` URL、`connection-group` 和 `app-version`。
|
||
5. 也可以通过配置、调度状态或已审计 metadata snapshot 显式提供这些值。
|
||
6. `--auto-discover` 只允许通过官方 HTTP metadata 和临时目录解析 `GameMainConfig`;launcher metadata 未变时必须复用缓存,metadata 变化时才按 manifest 重新下载必要 `resources.assets` 或旧版官方 game zip。
|
||
|
||
### 3.1 发现官方资源根
|
||
|
||
入口是 `YostarJpServerInfo`。
|
||
|
||
流程是:
|
||
|
||
1. 读取官方 `server-info` JSON。
|
||
2. 按 `connection_group + app_version` 规则选择版本覆盖。
|
||
3. 从 `AddressablesCatalogUrlRoot` 提取 `root token`。
|
||
4. 校验该 root 只能落在官方 `prod-clientpatch.bluearchiveyostar.com` 之下。
|
||
5. 基于 root token 生成 discovery 端点。
|
||
|
||
对应实现主要在:
|
||
|
||
- `adapters/src/official/yostar_jp.rs`
|
||
|
||
### 3.2 枚举完整资源清单
|
||
|
||
资源清单不是“猜几个文件”,而是从官方 catalog 字节里提取完整文件名列表。
|
||
|
||
当前做法:
|
||
|
||
1. 读取 `BundlePackingInfo.bytes`。
|
||
2. 提取所有 `FullPatch_*.zip` 包名。
|
||
3. 读取 `TableCatalog.bytes`。
|
||
4. 提取所有表资源名,例如 `ExcelDB.db`。
|
||
5. 读取 `MediaCatalog.bytes`。
|
||
6. 提取所有媒体资源名,例如 `JP_Airi.zip`。
|
||
|
||
然后对 verified platforms 生成完整 URL 集:
|
||
|
||
- Windows patch pack
|
||
- Android patch pack
|
||
- TableBundles
|
||
- MediaResources-Windows
|
||
- MediaResources
|
||
|
||
对应实现主要在:
|
||
|
||
- `adapters/src/official/inventory.rs`
|
||
- `adapters/src/official/yostar_jp.rs`
|
||
|
||
### 3.3 组装全量 pull plan
|
||
|
||
`OfficialResourcePullPlan` 是这个后端的关键对象。
|
||
|
||
它做三件事:
|
||
|
||
1. 保存 discovery 端点。
|
||
2. 保存完整 inventory。
|
||
3. 用默认平台集或指定平台集生成最终 URL 列表。
|
||
|
||
`all_urls()` 是执行层的权威输入:
|
||
|
||
- 先放 discovery URLs
|
||
- 再放 content URLs
|
||
- 统一去重
|
||
- 保持顺序
|
||
|
||
这意味着后端拉取的是 **完整资源包集合**,不是抽样下载。
|
||
|
||
对应实现主要在:
|
||
|
||
- `infrastructure/src/official_pull.rs`
|
||
|
||
### 3.4 执行下载
|
||
|
||
`OfficialResourcePullService` 负责真正下载。
|
||
|
||
工作方式:
|
||
|
||
1. 检查 URL 是否属于官方 host。
|
||
2. 把 URL 映射到当前工作根目录下的本地输出路径;在自动更新服务中,读侧根目录是 `current` 指向的 versioned 目录,写侧根目录是 staging。
|
||
3. 读取工作根目录下的 `official-download-manifest.json`。
|
||
4. 已存在目标文件只有在本地清单中的相对路径、size、BLAKE3 都匹配时才跳过;`.zip` 文件还必须通过 ZIP central directory / local header 结构校验。
|
||
5. 缺少清单、清单不匹配、ZIP 结构无效或文件损坏时重新下载。
|
||
6. `TableCatalog.bytes`、`BundlePackingInfo.bytes`、`MediaCatalog.bytes` 总是刷新并用官方 `.hash` 强校验;该 `.hash` 是 `xxHash32(seed=0)` 的十进制文本。
|
||
7. `catalog_*.hash` 当前只作为 Addressables catalog 变更标记,不作为 zip/JSON 内容校验算法;Unity Addressables/SBP builder 对 JSON/bin catalog 使用 `HashingMethods.Calculate` 生成 `Hash128` 文本,运行时用它判断 remote catalog cache 是否过期,它不能套用 seed catalog 的 `xxHash32` 规则。
|
||
8. 官方 seed `.hash` 校验失败会让当前下载失败,并移除对应 data/hash URL 的本地 manifest 条目,避免失败产物在下一轮被本地 BLAKE3 audit 误判为健康缓存。
|
||
9. 存在 `.part` 临时文件时通过 `curl --continue-at -` 尝试断点续传。
|
||
10. 新下载写入 `.part`,成功并通过必要校验后原子 rename 到 staging 内最终路径;断点续传后的 `.zip` 如果结构无效,会删除 `.part` 并重新全量下载。
|
||
11. 成功下载后更新本地下载清单。
|
||
12. curl 失败按 HTTP/网络类型分类:403/404/普通 4xx 不重试,5xx、429、DNS、连接、超时、中断和网络类错误按尝试次数重试。
|
||
13. 单个 URL 最终失败时写入 `official-download-quarantine.json`,发出 Failed progress,并阻止发布不完整资源。
|
||
14. 旧 launcher 包或 `resources.assets` 下载使用官方 launcher CDN 配置,primary CDN 失败后切换 official backup CDN;资源 patch host 不猜测非官方镜像。
|
||
15. 记录最终文件大小、本次传输字节数、官方 hash 校验数和执行状态。
|
||
16. 非官方 URL 直接拒绝。
|
||
|
||
路径映射时会做分段清理,并在写入前做输出目录安全校验、相对路径归属校验和现有路径组件 symlink 检查,避免把不安全路径写进输出目录或通过 symlink 跳出输出目录。
|
||
|
||
对应实现主要在:
|
||
|
||
- `infrastructure/src/official_download.rs`
|
||
|
||
### 3.5 导入到 CAS 和资源仓储
|
||
|
||
资源下载后,导入层会:
|
||
|
||
1. 把 bundle 原始字节写入 CAS。
|
||
2. 解析 UnityFS 基础摘要。
|
||
3. 把资源条目写入 `ResourceRepository`。
|
||
4. 记录资源路径、hash、大小和解析摘要。
|
||
|
||
这层的意义是把“下载到磁盘的文件”变成“可查询、可复用、可去重”的资源对象。
|
||
|
||
对应实现主要在:
|
||
|
||
- `infrastructure/src/import.rs`
|
||
- `infrastructure/src/resources.rs`
|
||
|
||
### 3.6 同步决策
|
||
|
||
同步层只做判断,不做重业务。
|
||
|
||
它比较当前快照和历史快照,关注:
|
||
|
||
- root token 是否变化
|
||
- addressables root 是否变化
|
||
- endpoint 是否变化
|
||
- bundle version 是否变化
|
||
|
||
判断结果分三类:
|
||
|
||
- `UpToDate`
|
||
- `DownloadAndVerify`
|
||
- `DownloadVerifyAndPublish`
|
||
|
||
对应实现主要在:
|
||
|
||
- `infrastructure/src/official_sync.rs`
|
||
|
||
### 3.7 自动更新闭环
|
||
|
||
`OfficialUpdateService` 是当前 Rust 侧的自动更新核心,正式命令入口是 `bat`。
|
||
|
||
集成边界:
|
||
|
||
1. 当前生产和 Go CLI 默认集成路径是运行 `bat --json` 并消费结构化 report。
|
||
2. systemd、容器或上层 Go 进程只负责守护 `bat --watch` / `bat --daemon`,不直接接管下载器内部状态。
|
||
3. `bat-ffi` 只允许作为可选无状态 C ABI 兼容层,用于 Manifest inspect 和 sync plan 这类一次性 JSON helper;它不是官方同步 daemon、下载器、资源锁、CAS handle 或主控制面的承载位置。
|
||
|
||
流程是:
|
||
|
||
1. 显式执行 `--auto-discover` 或读取已审计 `server-info` 输入。
|
||
2. `--auto-discover` 先抓官方 launcher metadata;metadata 未变时复用 `official-bootstrap-cache.json` 中的 `GameMainConfig` 摘要,metadata 变化时按 manifest 临时下载 `resources.assets` 或旧版官方 game zip 并重新解析。
|
||
3. 生成当前 v2 snapshot,记录 `app_version`、`connection_group`、`bundle_version`、`addressables_root`、endpoint URL、seed `.hash` 内容、`catalog_*.hash` marker、launcher metadata 摘要和 `GameMainConfig` 摘要。
|
||
4. 读取上一次成功同步写出的 snapshot。
|
||
5. 使用 `OfficialSyncPlan` 和扩展 snapshot diff 判断是否需要下载;URL 未变但 `.hash` / marker 内容变化也会触发更新。
|
||
6. 每轮都会基于最新 seed catalog 构建当前 pull plan,并检查输出目录是否已有当前 plan 的 manifest 条目或目标文件。
|
||
7. 如果远端 snapshot 未变化但输出目录没有任何当前 plan 的本地资源,仍按首次运行处理并执行全量拉取。
|
||
8. 远端无变化且本地已有资源时执行 download manifest audit,检查路径、size、BLAKE3 和 ZIP 结构。
|
||
9. 远端变化、本地 audit 发现 repair_needed,首次空目录运行,或缺少 `current` 原子发布指针时,进入下载/发布流程。
|
||
10. 下载先写入 `<output>/.staging/<id>`;若已有 active release,会先 seed staging 以复用已验证文件。
|
||
11. 下载、manifest、本地 BLAKE3、ZIP 和官方 `.hash` 校验完成后写入新的 snapshot。
|
||
12. 将 staging rename 为 `<output>/versions/<id>`,再原子替换 `<output>/current` symlink 指向该 versioned 目录。
|
||
|
||
该入口不安装、不执行官方启动器,也不读取生产外的本地客户端目录。Rust 正式 binary `bat` 支持单次运行、`--watch` 常驻模式、`--daemon` 后台模式,以及 `status`、`stop`、`restart`、`reload`、`logs`、`refresh`、`verify`、`repair`、`doctor`、`clean-stable` 管理命令。`--daemon` 会在后台状态目录下创建 `bat.sock`,使用 Unix socket JSON-RPC 作为 live control plane;`bat.pid`、`bat-status.json` 和 `bat-daemon.log` 是快照、诊断和兼容 fallback;`bat-events.jsonl` 是带轮转的结构化 JSONL 事件日志;`bat-control.lock` 串行化控制命令,并在 stale/corrupt 时由下一次控制命令或 `clean-stable` 恢复。`bat-status.json` 和 `status` 子命令包含最后成功时间、下次检查时间、最后错误摘要、当前阶段和当前下载 URL 进度。PID、status、log 和控制锁文件创建时使用私有权限,读取和写入时不跟随 symlink。`status`、`stop`、`logs`、`reload` 和默认形态的 `refresh` 优先走 RPC;`reload` 会唤醒或排队 watch 循环重新自动发现并强制刷新,`restart` 才负责重启进程或替换启动参数。后台 daemon 管理某个资源目录时,前台 `run/watch/refresh/repair` 不允许直接写入同一目录;默认形态 `refresh` 会通过 RPC 触发后台刷新。正常情况下默认每 1 小时执行一次检查;每天北京时间(UTC+8)`03:00`、`16:00`、`18:00` 会中断普通 sleep 并强制执行一次自动刷新,该轮注入 `force=true`。远端和本地一致时静默等待下次检查,不一致时自动下载或 repair。下载、发现或校验失败时不等待完整正常周期,默认 60 秒后重试;如果固定时间强制刷新失败,会保留 pending force 并按失败重试周期继续重试,可用 `--error-retry` 或 `--error-retry-seconds` 调整。默认资源输出目录是 `./bat-resources`,默认后台状态目录是 `/tmp/bat-pid`,二者通过 `--output` 和 `--state-dir` 分别配置。单次运行仍保留为核心幂等路径,systemd service、容器或 Go 进程可以只负责守护该常驻进程;cron/systemd timer 调单次模式只是可选集成方式。项目是否热更新、热重载或重启进程,由上层业务集成决定。
|
||
|
||
对应实现主要在:
|
||
|
||
- `infrastructure/src/official_update.rs`
|
||
- `infrastructure/src/bin/bat_official_sync.rs`
|
||
- `infrastructure/examples/official_update_check.rs`(历史/开发入口)
|
||
|
||
## 4. 官方 bootstrap 与用户流程
|
||
|
||
当前已经提供的官方用户流程分两类。
|
||
|
||
Linux 生产路径:
|
||
|
||
1. 显式执行 `--auto-discover`,或提供已审计的官方 metadata snapshot。
|
||
2. `official_pull_plan` 依据官方 `server-info`、catalog 和 verified platforms 生成全量拉取计划。
|
||
3. `bat` 对比上次 snapshot 和远端 `.hash` marker;远端无变化时 audit 本地清单,有变化或本地损坏时下载、校验并落盘官方资源。
|
||
|
||
开发/审计辅助路径:
|
||
|
||
1. `official_launcher_bootstrap` 获取官方 launcher 信息。
|
||
2. `official_game_main_config` 按官方 manifest 获取 `resources.assets`(旧 ZIP manifest 则先解出)并解密 `GameMainConfig`。
|
||
3. 手动确认最新 PC metadata、`server-info` URL 和默认 connection group。
|
||
|
||
自动发现路径和开发/审计辅助路径都只使用官方 HTTP 和临时目录,不安装或启动官方 launcher。
|
||
|
||
这些入口都只接受官方域名,不走 `bluearchive.cafe` 镜像链。
|
||
|
||
## 5. 已验证行为
|
||
|
||
当前代码已经验证:
|
||
|
||
- 默认平台是 `Windows + Android`
|
||
- `iOS` 和 `macOS` 不再进入默认官方流程
|
||
- verified inventory 会产出完整内容 URL 集
|
||
- pull plan 会同时包含 discovery URLs 和 content URLs
|
||
- 全量样本下是 `2` 个 discovery URL + `5` 个内容 URL = `7` 个 URL
|
||
- `OfficialUpdateService` 能持久化 v2 snapshot,并在远端 marker 内容变化时触发下载决策
|
||
- `bat` 默认向 stderr 输出 `BlueArchiveToolkit` ASCII banner 和 progress log,stdout 默认输出人类可读摘要;progress log 覆盖总体下载进度、单文件开始/完成状态、下载中断失败分类和校验结果摘要;支持 `--json` 输出稳定 JSON,支持 `--no-progress` 关闭进度日志,支持 `--no-banner` 只关闭横幅,支持 `--watch --interval 1h --error-retry 60s` 常驻运行,支持 `--daemon` Unix socket JSON-RPC 控制、`status`、`stop`、`restart`、`reload`、`logs`、`refresh --force`、`verify`、`repair`、`doctor`、`clean-stable`,非 dry-run 使用 `.official-sync.lock` 防止并发写资源目录,控制命令使用 `bat-control.lock` 防止并发状态修改,资源发布使用 `.staging`、`versions` 和 `current` 原子切换,daemon 写 `bat-events.jsonl` 结构化日志并在 `status` 中暴露下载进度、失败类型、HTTP 状态和调度状态
|
||
- curl 失败分类和重试策略已覆盖 404 不重试、5xx 重试耗尽后 quarantine、launcher primary CDN 失败后切换 official backup CDN
|
||
- `official-version-state.json` 已覆盖当前完成版本、正在拉取版本、上一个可用版本和失败版本,`bat status` 会暴露版本状态摘要
|
||
- 资源导入链路已覆盖 CAS 写入、`ResourceRepository` 索引、AssetBundle UnityFS 摘要,以及 TextAsset/Table/Media 分类
|
||
- 离线回归样本已覆盖当前 catalog、上一个版本 catalog、catalog 结构变化、403、404 和 seed hash mismatch
|
||
- `OfficialUpdateService` 能读写 `official-bootstrap-cache.json`,并支持默认开启的 `audit_local` / `repair` CLI 行为
|
||
- 下载层能在本地文件 size/BLAKE3/path、ZIP 结构或 manifest 不匹配时重新下载
|
||
- 官方 seed `.hash` mismatch 会导致下载失败,而不是降级为本地 BLAKE3 猜测
|
||
- 非官方 URL 会在 fetch/download 入口被拒绝
|
||
- 真实官方网络全量下载 smoke 已固化为 `scripts/official-full-pull-smoke.sh`、`make official-smoke` 和 `docs/guides/official-full-pull-smoke.md`;大型资源文件和运行报告默认保留在 `/tmp` 隔离目录,不纳入 Git
|
||
|
||
相关验证主要来自:
|
||
|
||
- `cargo test -p bat-adapters -- --nocapture`
|
||
- `cargo test -p bat-ffi -- --nocapture`
|
||
- `cargo test -p bat-infrastructure -- --nocapture`
|
||
- `cargo test -p bat-infrastructure --bin bat -- --nocapture`
|
||
- `cargo run -p bat-infrastructure --bin bat -- --help`
|
||
|
||
## 6. 审核重点
|
||
|
||
请重点检查这几件事:
|
||
|
||
1. 是否只接受官方 host。
|
||
2. 是否默认只走 Windows + Android。
|
||
3. 是否把完整 content URL 集都纳入 `all_urls()`。
|
||
4. 是否拒绝镜像域名和手工拼接样例。
|
||
5. 是否在下载前做了 URL 和路径安全校验。
|
||
6. 是否能在官方客户端变动时只改适配层。
|