feat: validate official zip structure

This commit is contained in:
2026-07-12 23:37:47 +08:00
parent 559206962c
commit e5fcf26e19
10 changed files with 1004 additions and 23 deletions
@@ -122,13 +122,13 @@
1. 检查 URL 是否属于官方 host。
2. 把 URL 映射到本地输出路径。
3. 读取输出目录下的 `official-download-manifest.json`
4. 已存在目标文件只有在本地清单中的相对路径、size、BLAKE3 都匹配时才跳过。
5. 缺少清单、清单不匹配或文件损坏时重新下载。
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 到最终路径。
10. 新下载写入 `.part`,成功并通过必要校验后原子 rename 到最终路径;断点续传后的 `.zip` 如果结构无效,会删除 `.part` 并重新全量下载
11. 成功下载后更新本地下载清单。
12. 记录最终文件大小、本次传输字节数、官方 hash 校验数和执行状态。
13. 非官方 URL 直接拒绝。
@@ -189,7 +189,7 @@
5. 使用 `OfficialSyncPlan` 和扩展 snapshot diff 判断是否需要下载;URL 未变但 `.hash` / marker 内容变化也会触发更新。
6. 每轮都会基于最新 seed catalog 构建当前 pull plan,并检查输出目录是否已有当前 plan 的 manifest 条目或目标文件。
7. 如果远端 snapshot 未变化但输出目录没有任何当前 plan 的本地资源,仍按首次运行处理并执行全量拉取。
8. 远端无变化且本地已有资源时执行 download manifest audit,检查路径、sizeBLAKE3。
8. 远端无变化且本地已有资源时执行 download manifest audit,检查路径、sizeBLAKE3 和 ZIP 结构
9. 远端变化、本地 audit 发现 repair_needed,或首次空目录运行时,下载并校验官方 URL。
10. 下载成功后写回新的 snapshot。
@@ -233,7 +233,7 @@ Linux 生产路径:
- `OfficialUpdateService` 能持久化 v2 snapshot,并在远端 marker 内容变化时触发下载决策
- `bat` 默认向 stderr 输出 `BlueArchiveToolkit` ASCII banner 和 progress logstdout 默认输出人类可读摘要;支持 `--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` 防止并发写资源目录
- `OfficialUpdateService` 能读写 `official-bootstrap-cache.json`,并支持默认开启的 `audit_local` / `repair` CLI 行为
- 下载层能在本地文件 size/BLAKE3/path 或 manifest 不匹配时重新下载
- 下载层能在本地文件 size/BLAKE3/path、ZIP 结构或 manifest 不匹配时重新下载
- 官方 seed `.hash` mismatch 会导致下载失败,而不是降级为本地 BLAKE3 猜测
- 非官方 URL 会在 fetch/download 入口被拒绝
- 尚未在仓库中记录真实官方网络全量下载 smoke test
+5 -5
View File
@@ -136,11 +136,11 @@ cargo run -p bat-infrastructure --example official_pull_plan -- \
- 只接受官方 URL
- 下载完整官方资源集合
- 下载成功后在输出目录维护 `official-download-manifest.json`
- 已存在目标文件只有在本地下载清单中的 size 和 BLAKE3 校验通过时才会跳过
- 已存在目标文件只有在本地下载清单中的 size 和 BLAKE3 校验通过时才会跳过`.zip` 文件还必须通过 ZIP central directory / local header 结构校验
- `TableCatalog.bytes``BundlePackingInfo.bytes``MediaCatalog.bytes` 会用官方 `.hash` 做强校验;该 `.hash``xxHash32(seed=0)` 的十进制文本
- `catalog_*.hash` 是 Unity Addressables/SBP 写出的 catalog 变更标记,来源是 `HashingMethods.Calculate(json/bin catalog)` 生成的 `Hash128` 文本;它不是 seed catalog 的 `xxHash32` 规则,目前不作为 zip/JSON 内容强校验
- 存在 `.part` 临时文件时会尝试断点续传
- 新下载先写 `.part`,成功后再替换为最终文件
- 新下载先写 `.part`,成功并通过必要校验后再替换为最终文件;如果断点续传后的 `.zip` 结构校验失败,会删除 `.part` 并重新全量下载
- 把结果写入 `--output`
## 5. 自动更新检查
@@ -151,7 +151,7 @@ cargo run -p bat-infrastructure --example official_pull_plan -- \
- URL 没变但 `.hash` / marker 内容变更时,也会判定为需要更新。
- 即使远端 snapshot 未变化,只要输出目录没有任何当前 pull plan 的本地 manifest 条目或目标文件,也会按首次运行处理并执行全量拉取。
- 远端无变化时,默认执行本地 `official-download-manifest.json` audit。
- 本地文件缺失、路径不一致、size 不一致BLAKE3 不一致时,默认进入 repair 并重下必要文件。
- 本地文件缺失、路径不一致、size 不一致BLAKE3 不一致或 ZIP 结构无效时,默认进入 repair 并重下必要文件。
- 官方 seed `.hash` 校验失败会让本轮失败,并清理对应本地 manifest 条目;下一轮会继续把这类文件视为需要 repair,而不是把失败产物当作健康缓存复用。
- 远端和本地都一致:单次模式输出 `update_status=up_to_date`,watch 模式默认静默并等待下次检查。
- 有远端变化或本地 repair:生成 pull plan,下载完整官方资源,成功后更新 snapshot。
@@ -159,7 +159,7 @@ cargo run -p bat-infrastructure --example official_pull_plan -- \
- `--dry-run --plan`:除更新判断外,还会解析 seed catalog 并打印完整下载 URL。
- 真实更新会输出 `downloaded_count``resumed_count``skipped_count``transferred_bytes``official_seed_hash_verified_count`
- 校验报告分层输出 `official_seed_hash_verified_count``local_manifest_verified_count``addressables_marker_checked_count``unverified_marker_count`
- 下载阶段复用同一套本地清单和 `.part` 续传逻辑;没有清单或校验不匹配的文件会重新下载。
- 下载阶段复用同一套本地清单、ZIP 结构校验`.part` 续传逻辑;没有清单或校验不匹配的文件会重新下载。
资源同步状态文件默认位于 `--output` 下:
@@ -241,7 +241,7 @@ cargo run -p bat-infrastructure --bin bat -- clean-stable
- `refresh` 执行一次同步检查;`refresh --force` 强制刷新并重新匹配当前官方资源。
- 如果后台 daemon 正在运行,并且 `refresh` 没有显式指定另一套资源目录、server-info、connection-group、app-version、platforms、snapshot、curl 或 unzip 参数,`refresh` / `refresh --force` 会通过 RPC 唤醒或排队后台进程执行;否则作为一次性前台同步运行。
- `verify` 只读验证当前官方计划、本地 manifest size+BLAKE3,以及本地已有官方 seed `.bytes/.hash` 对的 xxHash32;资源缺失、远端变化或本地损坏时返回非 0。
- `verify` 只读验证当前官方计划、本地 manifest size+BLAKE3、ZIP 结构,以及本地已有官方 seed `.bytes/.hash` 对的 xxHash32;资源缺失、远端变化或本地损坏时返回非 0。
- `repair` 在有异常资源时尝试重新下载并修复,成功后重新写 manifest 和 snapshot。
- `doctor` 检查输出目录、后台状态目录、curl/unzip、后台 PID、RPC socket 和资源锁。
- `clean-stable` 只能在后台未运行且 RPC socket 不可连接时清理 `.part``.tmp`、失效 PID、失效 socket 和失效锁,不删除正式资源文件。