Files
BlueArchiveToolkit/USERGUIDE.md
T
nyaKazuha 4ed81f0030
bat-rust / Build and test Rust (push) Canceled after 0s
bat-rust / Build and test Go API (push) Canceled after 0s
feat(bat-api): 实现内嵌 dashboard
Closes #46
2026-08-31 23:17:23 +08:00

503 lines
32 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.
# BlueArchiveToolkit 用户指南
本指南面向 `bat` 官方资源同步二进制的使用者,覆盖:命令、选项、退出码、运行时行为,以及统一错误码参考。
- 权威运行/部署说明另见 `docs/guides/official-resource-test-pull.md``docs/guides/deployment.md`
- 本文档中的命令、选项以 `bat --help` 为准;错误码以 `core/src/error_code.rs` 的码表为准。
---
## 1. 概览
`bat` 是 Linux 上官方日服(Yostar JP)资源同步的正式入口。它可以:
- `--auto-discover` 从官方 HTTP metadata 解析 `GameMainConfig`,自动获得 app-version、连接组和 server-info,不安装、不启动官方启动器;已发布 release 会保存 `official-launcher-bootstrap.json`
- 生成官方全量 pull plan、执行真实下载,维护 release 内的下载 manifest,并做 size + BLAKE3 复用校验、官方 seed `.hash`(标准 xxHash32(seed=0))强校验、ZIP 结构校验。
- 断点续传、失败分类重试、下载 quarantine、本地 manifest audit/repair。
- 原子发布:先写 `.staging/<id>`,校验通过后发布 `versions/<id>` 并原子切换 `current` symlink。
- 常驻运行(`--watch`)或后台化(`--daemon`),通过 `bat.sock` Unix socket JSON-RPC 控制。
### 运行形态
```bash
# 一次性 dry-run(不写状态)
bat --auto-discover --dry-run
# 前台常驻
bat --auto-discover --watch --output /var/lib/bluearchive-toolkit/official
# 后台守护
bat --auto-discover --daemon --output /var/lib/bluearchive-toolkit/official
```
带凭据的代理**推荐用环境变量**(凭据不进命令行/argv/状态文件):
```bash
HTTPS_PROXY=http://user:pass@127.0.0.1:7890 bat --auto-discover --daemon
```
---
## 2. 命令
无子命令时执行一次性同步(或配合 `--watch`/`--daemon`)。子命令如下:
| 命令 | 说明 |
|---|---|
| `res pull` | 拉取官方资源;支持单次、限定次数和 `--watch` 周期执行 |
| `res schedule` | 管理资源拉取计划;CLI、RPC 和 `bat-api` dashboard 共用计划状态 |
| `parse run` | 执行当前官方 release 的解析和 TextUnit 队列刷新 |
| `parse clear-cache` | 使用 `--force` 清理当前 release 的可再生解析缓存和翻译队列 |
| `parse repack` | 根据 JSON spec 批量重打包 UnityFS bundle |
| `parse schedule` | 管理解析计划;与 `res schedule` / `i18n schedule` 共用同一计划状态 |
| `i18n run` / `i18n export` | 刷新离线翻译队列或导出可编辑翻译工作台 |
| `i18n set` / `i18n get` / `i18n unset` | 手动查看、修改或清空一个翻译工作台条目;也可通过 `i18n workbench ...``--workbench` 访问 |
| `i18n validate` | 发布前校验工作台 release、source text 和 patch 目标 |
| `i18n proofread` | 将当前汉化 workflow 标记为人工校对中 |
| `i18n tasks` / `i18n task list` / `i18n task status` | 查询当前离线 TextUnit 翻译任务状态 |
| `i18n handoff` | 查询当前翻译交接视图 |
| `i18n status` | 显示当前汉化 release 状态 |
| `i18n task update` | 回写 provider worker 任务状态 |
| `i18n worker run` | 运行真实 provider worker;支持单次、限定次数和周期执行 |
| `i18n publish` | 校验工作台并发布独立汉化 release;`--force` 使用新的手动 release ID |
| `i18n schedule` | 管理翻译和汉化发布计划 |
| `refresh` | 执行一次更新检查;若有 live daemon,则通过 RPC 请求其刷新 |
| `verify` | 校验远端计划、本地 manifest 和官方 seed hashdry-run + 审计当前 release |
| `repair` | 重新下载本地校验失败的资源 |
| `status` | 显示 daemon 状态 |
| `stop` | 停止 daemon |
| `restart` | 重启 daemon;未显式传参时复用保存的参数 |
| `reload` | 请求 daemon 重新自动发现并强制刷新 |
| `logs` | 显示 daemon 日志尾部(配合 `--tail` |
| `doctor` | 运行时诊断(输出目录、状态目录、curl/unzip、代理、PID、socket、锁) |
| `clean-stable` | 清理 `.part`/`.tmp`/失效锁、PID、socketdaemon 运行中会拒绝执行) |
`status`/`stop`/`logs`/`reload` 和默认形态的 `refresh` 优先走 `bat.sock` JSON-RPCsocket 不可用时 `status`/`stop` 回退到 PID/状态文件兼容路径。
Rust `bat` 工作流的完整命令、工作台字段、重打包 spec、调度计划和
`bat-api` 调度接口见 [`docs/guides/bat-workflows.md`](docs/guides/bat-workflows.md)。
一级命令推荐使用短名称 `res``parse``i18n``resource``resources`
`translation``translate` 仍是兼容别名。
其中 `translation` / `translate` 也支持 `tasks``handoff``status`
`task update``--translation-file` 也可写成 `--workbench``--schedule-id` /
`--schedule-action` 也可简写为 `--id` / `--action`
`resource status``resource schedule``translation tasks``translation handoff`
`translation status` 也都与对应短命令一致。
### bat-api 资源 bootstrap / 分发服务
`bat-api` 是 Go 侧正式服务入口,用于给客户端、补丁器或上层工具提供启动前资源入口和 CDN 形态只读分发。它不负责自动发现、下载、校验或发布资源;这些长期状态由 Rust `bat` / daemon 持有。
生产拓扑上,`bat-api` 基本应与 Rust `bat` 运行在同一台服务器、同一容器或同一共享文件系统环境。当前可读资源目录不在 `bat-api` 配置里写死,而是由 `bat.sock` RPC 的 `catalog.status` / `resource.manifest` 返回 `resource_root`
推荐运行关系:
```bash
# 先让 Rust bat 生产并维护 release
bat --auto-discover --daemon \
--output /var/lib/bluearchive-toolkit/official \
--state-dir /var/lib/bluearchive-toolkit/daemon-state
# 再启动 bat-api 读取同一个 daemon socket
bat-api \
--listen :18080 \
--public-base-url http://127.0.0.1:18080 \
--socket /var/lib/bluearchive-toolkit/daemon-state/bat.sock \
--refresh-interval 1m
```
测试、fixture 或应急只读诊断场景可用 `--resource-root <DIR>` 直接指向已发布 release 根;生产默认应通过 `--socket` / `BAT_API_SOCKET``bat.sock` 发现当前版本。`bat.sock` 不应暴露到公网;对外发布时只暴露 `bat-api` HTTP,并把 `--public-base-url` 设为客户端实际访问的 HTTPS 根。
开发环境不能本地全量运行 `bat` 时,用 fixture 验证 Go 服务面即可:
```bash
BAT_API_SKIP_ENV_FILE=1 go run ./cmd/bat-api \
--listen 127.0.0.1:18080 \
--public-base-url http://127.0.0.1:18080 \
--resource-root internal/api/testdata/release \
--refresh-interval 0
```
常用接口:
| 接口 | 说明 |
|---|---|
| `GET /healthz` | 服务存活、RPC 可用性、release ready 状态和最近一次 RPC refresh 诊断 |
| `GET/HEAD /readyz` | release 就绪检查;当前无可分发 release 时返回 `503` |
| `GET /v1/bootstrap` | 启动前资源入口:`bat` RPC 健康、release 摘要、server-info URL、client-patch base、改写后的 Addressables root |
| `GET /v1/launcher/bootstrap` | 启动器资源引导聚合视图:release、launcher metadata、GameMainConfig 摘要和资源 URL |
| `GET /api/launcher/game/config` | launcher 资源 metadata 兼容 envelope;字段来自 Rust `bat` 已发布 snapshot/RPC |
| `GET /api/launcher/game/config/json` | launcher 形状的资源引导 JSON URL;不会返回完整 PC package update manifest |
| `GET /api/launcher/advanced/game/download/cdn` | launcher 形状的 CDN 配置;返回当前 `--public-base-url`,用于资源引导 |
| `GET /api-launcher-jp.yo-star.com/api/launcher/...` | 与上面 `/api/launcher/...` 等价,便于反代或 hosts 映射保持官方 host 形状 |
| `GET /v1/release` | 当前 release 摘要 |
| `GET /v1/resources?offset=0&limit=100` | 当前 manifest 索引分页 |
| `GET /v1/server-info` | 调试用 server-info JSON,只改 `AddressablesCatalogUrlRoot` |
| `GET /yostar-serverinfo.bluearchiveyostar.com/server-info.json` | 官方 host/path 形态的 server-info |
| `GET/HEAD /prod-clientpatch.bluearchiveyostar.com/...` | 官方 CDN path 形态资源字节 |
| `GET /openapi.yaml` | bat-api OpenAPI 文档 |
| `GET /admin/` | 管理控制入口与允许操作列表 |
| `GET /admin/dashboard/` | 内嵌管理 dashboard 静态页面;页面调用的管理 API 仍需要 token |
| `GET /admin/diagnostics` | 读取 Rust daemon 诊断;需要管理 token |
| `GET /admin/logs?tail=200` | 读取 Rust daemon 日志尾部;需要管理 token |
| `GET /admin/tasks` | 读取 Rust daemon 任务列表;需要管理 token |
| `GET /admin/tasks/status?task_id=...` | 读取单项任务状态;需要管理 token |
| `GET /admin/tasks/logs?task_id=...` | 读取单项任务日志;需要管理 token |
| `GET /admin/schedules?id=...&group=...&enabled=...` | 读取/过滤 Rust `bat` 调度计划;需要管理 token |
| `GET /admin/parse/status` | 读取当前 release 解析状态;需要管理 token |
| `GET /admin/parse/text-units?...` | 分页查询当前 release TextUnit 明细;需要管理 token |
| `GET /admin/parse/errors?...` | 分页查询当前 release 解析错误;需要管理 token |
| `GET /admin/translation/tasks?limit=100&worker_status=failed` | 读取/过滤 Rust 翻译任务和 provider worker 状态;需要管理 token |
| `GET /admin/translation/handoff` | 读取当前 release 的完整翻译交接视图;需要管理 token |
| `GET /admin/translation/status` | 读取当前汉化 release、current 指针和 workflow 状态;需要管理 token |
| `POST /admin/control/{action}` | 经白名单转发 Rust `bat` 控制请求;见下文 |
launcher 兼容端点只服务启动前资源发现。它们复用 Rust `bat` snapshot 中的 `launcher_metadata``game_main_config_bootstrap`,显式标记 `scope=resource_bootstrap_only` / `package_update_manifest=false``bat-api` 不下载 launcher 包,不生成官方 PC package update manifest,也不仿造登录、账号、网关、鉴权或游戏业务协议。
生产面对玩家分发时,应启用 HTTP token 鉴权、限流和访问日志:
- `BAT_API_AUTH_TOKEN`:启用 `Authorization: Bearer <token>``X-BAT-Token` 或 query fallback 鉴权;token 推荐由 secret manager 或进程环境提供,不建议写入提交文件。`/admin/control/*``/admin/schedules``/admin/tasks*``/admin/logs``/admin/diagnostics``/admin/parse/*``/admin/translation/*` 需要此 token`/admin/dashboard/` 静态资产默认免鉴权,便于浏览器打开后再在页面内配置 token。
- `BAT_API_AUTH_QUERY_PARAM`query fallback 参数名,默认 `bat_token`;兼容不能写 header 的客户端,访问日志不会记录 query。
- `BAT_API_AUTH_EXEMPT_PATHS`:逗号分隔的免鉴权 path 或 slash-prefix,例如 `/healthz,/readyz`
- `BAT_API_RATE_LIMIT_RPS` / `BAT_API_RATE_LIMIT_BURST`:按客户端 IP 的进程内 token bucket 限流;边缘反代/CDN 仍应配置独立限流。
- `BAT_API_TRUST_PROXY_HEADERS`:只有反代已经清洗并覆盖 `X-Forwarded-For` / `X-Real-IP` 时才设为 `true`
- `BAT_API_ACCESS_LOG`:结构化访问日志,记录 method/path/status/bytes/duration/client_ip/request_id/user_agent,不记录 query string。
- `BAT_API_MAX_RESOURCE_LIMIT``/v1/resources` 最大分页上限,默认 `1000`
`POST /admin/control/{action}` 只转发固定白名单内的 Rust RPC,不是任意 RPC proxy
| action | Rust RPC | 参数 | 返回 |
|---|---|---|---|
| `reload` | `daemon.reload` | 无 | `202` accepted |
| `refresh` | `daemon.refresh` | 可选 `{ "force": true }` | `202` accepted |
| `restart` | `daemon.restart` | 无 | `202` accepted |
| `sync` | `resource.sync` | 可选 `{ "force": true }` | `202` + task |
| `verify` | `resource.verify` | 无 | `202` + task |
| `repair` | `resource.repair` | 无 | `202` + task |
| `catalog-refresh` | `catalog.refresh` | 可选 `{ "force": true }` | `202` + task |
| `schedule-add` | `schedule.add` | 调度 mutation JSON | `202` + Rust schedule report |
| `schedule-update` | `schedule.update` | 调度 mutation JSON | `202` + Rust schedule report |
| `schedule-remove` | `schedule.remove` | `{ "id": "..." }` | `202` + Rust schedule report |
| `schedule-run` | `schedule.run` | 可选 `{ "id": "...", "force": true }` | `202` + 执行报告 |
| `task-cancel` | `task.cancel` | `{ "task_id": "..." }` | `202` + 取消请求结果 |
| `translation-task-update` | `translation.task.update` | `{ "task_id": "...", "status": "completed", "provider": "manual", "provider_run_id": "...", "translation_results": [{ "unit_id": "...", "source_text": "...", "translated_text": "..." }] }` | `202` + 当前任务记录 |
| `translation-worker-run` | `translation.worker.run` | `{ "provider": "mock", "concurrency": 8, "max_tasks": 2 }` | `202` + worker task |
| `translation-proofread` | `translation.proofread` | 无 | `202` + 汉化状态 |
| `localized-publish` | `localized.publish` | `{ "translation_file": "...", "localized_release_id": "..." }``{ "from_worker": true, "localized_release_id": "..." }` | `202` + localized release manifest |
| `localized-rollback` | `localized.rollback` | 可选 `{ "localized_release_id": "..." }` | `202` + rollback report |
`stop``clean-stable`、patch 和 UnityFS 写入命令不会经 HTTP 暴露。
所有动态 JSONbootstrap、health、ready、release、resources、launcher 兼容、server-info、OpenAPI、admin 和错误响应)显式返回 `Cache-Control: no-store`。资源字节 CDN path 仍返回长期 immutable cache header。
CDN path 只服务 manifest 索引内且磁盘存在、size 匹配的文件。响应支持 `GET``HEAD``Range`、条件请求、ETag、Last-Modified、Accept-Ranges 和长期缓存头;ETag 优先使用 manifest 中的 BLAKE3。`.hash``text/plain` 返回,其它未知扩展默认为 `application/octet-stream`
`bat-api` 只改写资源相关入口:server-info 中的 `AddressablesCatalogUrlRoot` 会指向 `--public-base-url` 下的 `prod-clientpatch...` path`ApiUrl``GatewayUrl`、登录、账号、网关和游戏业务协议不会被仿造或改写。
示例:
```bash
curl -fsS http://127.0.0.1:18080/v1/bootstrap
curl -fsS http://127.0.0.1:18080/v1/launcher/bootstrap
curl -fsS http://127.0.0.1:18080/api-launcher-jp.yo-star.com/api/launcher/game/config
curl -fsS http://127.0.0.1:18080/openapi.yaml
curl -fsS \
http://127.0.0.1:18080/prod-clientpatch.bluearchiveyostar.com/<root_token>/TableBundles/TableCatalog.hash
curl -i -H 'Range: bytes=0-1023' \
http://127.0.0.1:18080/prod-clientpatch.bluearchiveyostar.com/<root_token>/TableBundles/TableCatalog.bytes
```
---
## 3. 选项
### 发现(Discovery
| 选项 | 说明 |
|---|---|
| `--auto-discover` | 自动发现 app-version、server-info、连接组 |
| `--server-info-url <URL>` | 使用官方 server-info URL |
| `--server-info-file <NAME>` | 使用官方 server-info 文件名 |
| `--server-info-path <PATH>` | 使用本地 server-info JSON 文件 |
| `--app-version <VERSION>` | 覆盖 app 版本 |
| `--connection-group <NAME>` | 覆盖连接组 |
| `--launcher-version <VERSION>` | 启动器 metadata API 版本(默认 `1.7.2` |
### 同步(Sync
| 选项 | 说明 |
|---|---|
| `--platforms <LIST>` | 平台,如 `Windows,Android`(默认 `Windows,Android` |
| `--output <DIR>` | 资源发布根目录(默认 `./bat-resources` |
| `--snapshot <PATH>` | 覆盖 snapshot 路径(默认 `<output>/current/official-sync-snapshot.json` |
| `--curl <PATH>` | curl 可执行文件(默认 `curl` |
| `--proxy <URL\|auto\|none>` | curl 代理覆盖(默认 `auto`,从环境变量检测)。scheme 支持 http/https/socks4/socks4a/socks5/socks5h |
| `--no-proxy` | 强制直连 |
| `--unzip <PATH>` | unzip 可执行文件(默认 `unzip` |
| `--dry-run` | 不写同步状态 |
| `--plan` | dry-run 时输出计划中的 URL |
| `--force` | 强制下载/刷新 |
| `--audit-local` / `--no-audit-local` | 启用/关闭本地 manifest 审计 |
| `--repair` / `--no-repair` | 启用/关闭自动修复 |
### 守护(Daemon
| 选项 | 说明 |
|---|---|
| `--watch` | 前台常驻循环 |
| `--daemon` | 启动脱离终端的后台 watch 进程 |
| `--state-dir <DIR>` | 后台状态目录(默认 `/tmp/bat-pid` |
| `--interval <DURATION>` | 正常检查周期(默认 `1h` |
| `--error-retry <DURATION>` | 失败后重试周期(默认 `60s` |
| `--quiet-up-to-date` / `--no-quiet-up-to-date` | 静默/总是打印 up-to-date 报告 |
| `--tail <N>` | `logs` 命令返回的日志行数(默认 `200` |
### 输出(Output
| 选项 | 说明 |
|---|---|
| `--human` | 人类可读输出(默认) |
| `--json` | 面向脚本的稳定 JSON 输出 |
| `--progress` / `--no-progress` | 启用/关闭 stderr 进度日志 |
| `--banner` / `--no-banner` | 启用/关闭启动横幅 |
| `-h`, `--help` | 显示帮助 |
### 默认值与运行时行为
- 平台:`Windows,Android`
- 资源输出:`./bat-resources``current``versions/<id>``.staging/<id>`;自动发现 release 下包含 `official-launcher-bootstrap.json`,维护期 pending 证据位于发布根 `official-launcher-bootstrap.pending.json`)。
- 后台状态目录:`/tmp/bat-pid``bat.sock``bat.pid``bat-status.json``bat-daemon.log``bat-events.jsonl`、任务历史 `bat-tasks.json`、短生命周期 `bat-control.lock`;代理凭据在 `bat-proxy.secret``0600`)。
- 强制刷新:每天北京时间(UTC+8`03:00``16:00``18:00` 各一次。
- 状态类文件默认 `0600` 权限,读写不跟随 symlink。
### 配置文件(`.env`,无参启动)
`bat` 首次启动时会在**二进制所在目录**释放一个 `.env` 配置模板(`0600` 权限,已存在则不动)。之后每次启动自动加载该文件,把其中的键作为进程环境变量(不覆盖已存在的环境变量),因此编辑 `.env` 后直接运行 `bat`(无参数)即可按配置启动。
- 优先级:**命令行参数 > 进程环境变量 > `.env` > 内置默认值**。
- 语法:每行 `KEY=VALUE``#` 开头为注释;值两侧成对引号会剥除;空值视为未设置。
- 支持的键:`BAT_OUTPUT``BAT_STATE_DIR``BAT_AUTO_DISCOVER``BAT_WATCH``BAT_DAEMON``BAT_PROXY``BAT_NO_PROXY``BAT_INTERVAL_SECONDS``BAT_ERROR_RETRY_SECONDS``BAT_APP_VERSION``BAT_CONNECTION_GROUP``BAT_LAUNCHER_VERSION``BAT_PLATFORMS``BAT_CURL``BAT_UNZIP``BAT_JSON``BAT_QUIET_UP_TO_DATE`;也可以直接写 `HTTPS_PROXY` 等通用环境变量(走现有代理自动检测)。布尔值支持 `1/0/true/false/yes/no/on/off`
- `BAT_WATCH` / `BAT_DAEMON` 只对无子命令的 `bat` 生效(两者同时为 `1` 时 daemon 优先);命令行显式传入 `--watch` / `--daemon` / `--dry-run``.env` 的模式开关让位。`status` / `verify` 等子命令不受它们影响。
- `BAT_REDIS_URL` / `BAT_REDIS_PASSWORD` 为**预留键**:Redis 任务后端尚未接入,当前任务历史持久化在 `<state-dir>/bat-tasks.json`
-`BAT_SKIP_ENV_FILE=1` 可让 `bat` 完全跳过 `.env` 的生成与加载。
---
## 4. 退出码
| 退出码 | 含义 |
|---|---|
| `0` | 成功;`verify`/`doctor` 检查通过 |
| `1` | 普通错误 |
| `75` | 资源目录锁冲突(有 live daemon 正在管理同一目录,或 `.official-sync.lock` 被占用) |
`verify``doctor` 发现问题也返回非 0。`--json` 模式下错误以 JSON 写到 stderr。
---
## 5. 错误码参考
`bat` 使用一套稳定的数字错误码,作为 CLI、daemon RPC 和结构化日志的公共错误契约。
- **格式**`BAT-ERR-<域 3 位><序号 3 位>`,共 6 位,例如 `BAT-ERR-300012`
- **域**:错误码首位按百位分大类。
- **承载结构**RPC envelope 的 `error` 字段、`--json` 输出、`bat-events.jsonl` 一致):
```json
"error": {
"code": "BAT-ERR-310001",
"kind": "proxy_failure",
"domain": "network",
"location": "official-sync.download.pull_one",
"message": "代理返回 407 认证失败",
"retryable": false
}
```
`location` 是稳定的「组件·操作」标签(跟随语义、不随行号漂移)。`retryable` 是该类错误的默认可重试性。
> 说明:错误码模型(`core/src/error_code.rs`)已建立并作为公共契约;下载、launcher/metadata、server-info/marker、配置校验、任务/RPC 等主要链路已接入该码表。剩余未实现命名空间和后续引擎能力继续按本表扩展。
### 域一览
| 域 | 区间 | 含义 |
|---|---|---|
| input | `1xxxxx` | 输入/配置:CLI 参数、配置校验、代理配置 |
| path_security | `2xxxxx` | 路径/安全边界:危险目录、路径逃逸、symlink、权限 |
| network | `3xxxxx` | 网络/下载:HTTP/网络错误、代理故障、重试耗尽、quarantine |
| integrity | `4xxxxx` | 校验/完整性:BLAKE3、官方 seed hash、size、ZIP 结构 |
| publish_storage | `5xxxxx` | 发布/版本状态/存储:staging、原子发布、version-state、锁、CAS |
| parse | `6xxxxx` | 解析/适配:manifest、UnityFS、GameMainConfig |
| task_rpc | `7xxxxx` | 任务/RPC:未知方法、参数非法、未实现、任务不存在 |
| internal | `9xxxxx` | 内部/未知:兜底 |
### 码表
| 码 | kind | 可重试 | 含义 |
|---|---|:---:|---|
| `BAT-ERR-100001` | missing_app_version | 否 | 缺少应用版本(未传 `--app-version` 且未启用 `--auto-discover` |
| `BAT-ERR-100002` | missing_connection_group | 否 | 缺少连接组 |
| `BAT-ERR-100003` | missing_server_info_source | 否 | 缺少服务器信息来源 |
| `BAT-ERR-100004` | invalid_proxy_scheme | 否 | 代理 URL scheme 不受支持 |
| `BAT-ERR-100010` | invalid_argument | 否 | 命令行参数无效 |
| `BAT-ERR-200001` | dangerous_output_root | 否 | 输出目录被判定为危险路径 |
| `BAT-ERR-200002` | path_escape | 否 | 路径逃逸出允许根目录 |
| `BAT-ERR-200003` | symlink_rejected | 否 | 目标不允许是 symlink 或路径组件含 symlink |
| `BAT-ERR-200004` | file_permission | 否 | 文件权限或模式错误 |
| `BAT-ERR-300001` | http_forbidden | 否 | HTTP 403 |
| `BAT-ERR-300002` | http_not_found | 否 | HTTP 404 |
| `BAT-ERR-300003` | http_client_error | 否 | HTTP 其它 4xx |
| `BAT-ERR-300004` | http_too_many_requests | 是 | HTTP 429 / 请求过多 |
| `BAT-ERR-300005` | http_server_error | 是 | HTTP 5xx |
| `BAT-ERR-300010` | network_dns | 是 | DNS 解析失败 |
| `BAT-ERR-300011` | network_connect | 是 | 连接失败 |
| `BAT-ERR-300012` | network_timeout | 是 | 超时 |
| `BAT-ERR-300013` | network_tls | 是 | TLS 失败 |
| `BAT-ERR-300014` | network_interrupted | 是 | 传输中断 |
| `BAT-ERR-300015` | network_other | 是 | 其它网络错误 |
| `BAT-ERR-300020` | retry_exhausted | 否 | 下载重试次数耗尽 |
| `BAT-ERR-300021` | quarantined | 否 | URL 因反复失败进入 quarantine |
| `BAT-ERR-300030` | non_official_url | 否 | URL 不是官方 host(被拒绝) |
| `BAT-ERR-300031` | launcher_api_rejected | 否 | 官方启动器 API 返回非 200 业务码(版本/鉴权被拒等) |
| `BAT-ERR-310001` | proxy_failure | 否 | 代理自身故障(认证/解析/连接代理失败) |
| `BAT-ERR-400001` | blake3_mismatch | 否 | 本地 BLAKE3 与 manifest 不符 |
| `BAT-ERR-400002` | official_hash_mismatch | 否 | 官方 seed `.hash`xxHash32)校验不符 |
| `BAT-ERR-400003` | size_mismatch | 否 | 文件大小与 manifest 不符 |
| `BAT-ERR-400004` | zip_structure_invalid | 否 | ZIP 结构无效 |
| `BAT-ERR-500001` | resource_locked | 否 | 资源目录锁冲突(对应退出码 75) |
| `BAT-ERR-500002` | staging_prepare_failed | 否 | staging 准备失败 |
| `BAT-ERR-500003` | publish_failed | 否 | 原子发布失败 |
| `BAT-ERR-500004` | version_state_write_failed | 是 | 版本状态写入失败 |
| `BAT-ERR-500010` | cas_hash_mismatch | 否 | CAS 对象 Hash 不匹配 |
| `BAT-ERR-500011` | cas_object_not_found | 否 | CAS 对象不存在 |
| `BAT-ERR-500012` | cas_reference_underflow | 否 | CAS 引用计数下溢 |
| `BAT-ERR-500013` | cas_database | 否 | CAS 元数据库错误 |
| `BAT-ERR-600001` | manifest_parse_failed | 否 | Manifest / Addressables catalog 解析失败 |
| `BAT-ERR-600002` | unityfs_parse_failed | 否 | UnityFS 解析失败 |
| `BAT-ERR-600003` | game_main_config_failed | 否 | GameMainConfig 解密/解析失败 |
| `BAT-ERR-600004` | launcher_response_invalid | 否 | 官方启动器链内容无效(API 响应、远端 manifest 或包内容无法解析/缺少必需内容) |
| `BAT-ERR-700001` | rpc_unknown_method | 否 | 未知 RPC 方法 |
| `BAT-ERR-700002` | rpc_invalid_params | 否 | RPC 参数无效 |
| `BAT-ERR-700003` | rpc_not_implemented | 否 | 方法/命名空间尚未实现 |
| `BAT-ERR-700004` | task_not_found | 否 | 任务不存在 |
| `BAT-ERR-700005` | task_interrupted | 否 | 任务因 daemon 停止/重启而中断 |
| `BAT-ERR-900001` | internal | 否 | 未归类的内部错误 |
新增错误码在 `core/src/error_code.rs` 的码表登记后,同步更新本表。
---
## 6. Daemon RPC 接口
稳定 contract 以 `docs/reference/rpc-backend-api.md` 为准,本节保留常用说明和命令行示例。
`bat --daemon` 在后台状态目录下创建 `bat.sock`Unix socket),提供**换行分隔的 JSON-RPC 2.0** 控制面。CLI 的 `status`/`stop`/`logs`/`reload`/`refresh`/`repair` 优先走它;Go 服务层也应通过这个进程边界调用,而非 FFI 或执行 `bat` binary 后再解析 stdout。
### 传输与 envelope
- 请求:一行 JSON-RPC 2.0`{"jsonrpc":"2.0","id":<n>,"method":"<ns>.<action>","params":{…}}`。
- 响应:JSON-RPC 2.0,应用层负载统一装入 `result` 的 envelope
```json
{"jsonrpc":"2.0","id":1,"result":{
"ok": true,
"status": "ok",
"data": { … },
"request_id": "req-<pid>-<seq>"
}}
```
- `ok`:应用层成功与否。失败时 `ok=false`、`status="error"`、`error` 为 §5 的 `ApiError` 结构(含 `BAT-ERR` 码)。
- `status``ok` | `accepted`(长任务已入队) | `error`。
- `request_id`:进程内唯一请求 ID。
- 请求解析失败(畸形 JSON)走 JSON-RPC 顶层 `error`(如 `-32700`),不进 envelope。
### 方法命名空间
方法采用 `<namespace>.<action>`。`bat.*` 为兼容别名(解析为 `daemon.*`)。
| 方法 | 状态 | 说明 |
|---|---|---|
| `daemon.status` | ✅ | 后台状态快照 |
| `daemon.logs` | ✅ | 日志尾部(`params.tail`,默认 200 |
| `daemon.stop` | ✅ | 请求停止(`accepted` |
| `daemon.reload` | ✅ | 请求重新发现并强制刷新(`accepted` |
| `daemon.refresh` | ✅ | 请求刷新检查(`params.force``accepted` |
| `daemon.restart` | ✅ | 启动 Rust lifecycle controller,并在响应后停止当前 daemon(`accepted` |
| `daemon.doctor` | ✅ | 返回运行时诊断报告(只读,不清理、不重启) |
| `resource.state` | ✅ | 资源发布根 + 版本状态 + 上次同步结果 |
| `resource.sync` | ✅ | 触发同步任务(`params.force`),返回 `task_id` |
| `resource.verify` | ✅ | 触发校验任务(dry-run + audit),返回 `task_id` |
| `resource.repair` | ✅ | 触发本地 manifest 审计 + 修复任务,返回 `task_id`;不继承 `force` |
| `resource.manifest` / `resource.list` | ✅ | 当前版本下载 manifest 分页查询(`params.offset` 默认 0、`params.limit` 默认 100/上限 1000 |
| `resource.index` | ✅ | 查询现有 SQLite ResourceRepository 索引,支持资源类型、hash、路径模式、release、平台、destination、bundle path、archive entry、parse status 和 TextUnit format 过滤 |
| `parse.status` | ✅ | 查询当前 release 的解析缓存、TextUnit 索引和队列摘要 |
| `parse.text_units` / `parse.errors` | ✅ | 查询当前 release 的 TextUnit 明细和解析错误 |
| `translation.tasks` | ✅ | 查询离线 TextUnit 翻译任务及 worker 状态 |
| `translation.handoff` | ✅ | 查询完整 job/unit/provider run 交接视图 |
| `translation.task.update` | ✅ | 回写当前 release 的 provider worker 状态 |
| `translation.worker.run` | ✅ | 触发 Rust provider worker,落库 TextUnit 译文结果、lease、失败分类和重试状态 |
| `translation.proofread` | ✅ | 将当前汉化 workflow 标记为人工校对中 |
| `localized.status` | ✅ | 查询汉化 release 与当前官方 release 的匹配状态 |
| `catalog.status` | ✅ | 当前已发布版本的 catalog 概览(app/bundle 版本、addressables 根、端点与 marker 计数、launcher 元数据) |
| `catalog.versions` | ✅ | 版本历史:current / in_progress / previous / failed |
| `catalog.diff` | ✅ | 当前 snapshot 相对上一个可用版本的差异(base_delta + extended_delta + 变更端点 URL |
| `catalog.refresh` | ✅ | 触发 catalog 更新检查任务(dry-run 计划,不下载;`params.force`),返回 `task_id` |
| `task.status` | ✅ | 查询任务(`params.task_id` |
| `task.list` | ✅ | 列出全部任务(最新在前) |
| `task.cancel` | ✅ | 请求取消任务(`params.task_id`);协作式,在同步检查点生效 |
| `task.logs` | ✅ | 返回任务的进度日志(`params.task_id`,有界) |
| `patch.apply` | ✅ | 对显式 source/patch/target 文件同步执行 Binary/JSON/Text patch |
| `unityfs.patch_text_asset` / `unityfs.patch_string_field` / `unityfs.patch_field` | ✅ | 对显式 UnityFS bundle 文件执行文件级写入并原子输出 |
| `daemon.clean-stable` / 发布级 patch 方法 / 其他未开放 `unityfs.*` / `task.create` | ⏳ | 返回 `BAT-ERR-700003`not implemented);clean-stable 仍由 CLI 侧按进程生命周期显式执行,task.create 暂不开放通用任务入口 |
| 未知方法 | — | `BAT-ERR-700001`unknown method |
只读查询(`daemon.doctor` / `resource.state` / `resource.manifest` / `resource.list` /
`resource.index` / `parse.*` / `translation.tasks` / `translation.handoff` /
`localized.status` / `catalog.status` / `catalog.versions` / `catalog.diff`)在尚无已发布版本
或对应文件不存在时返回 `ok: true` 且 `data.available: false`(正常状态而非错误,便于调用方直接分支)。
### 任务模型
`resource.sync` / `resource.verify` / `resource.repair` / `catalog.refresh` 是**异步任务**:入队即返回 `{ "task_id": "task-<pid>-<seq>", "kind": "resource.sync" }``status: "accepted"`),实际执行由后台任务 worker 串行完成,通过 `task.status` / `task.list` 轮询。任务记录:
```json
{ "id": "task-1234-1", "kind": "resource.sync",
"status": "queued|running|succeeded|failed|cancelled",
"stage": "download", "message": "…",
"created_at": …, "updated_at": …, "started_at": …, "finished_at": …,
"error": { … }, "result": { … } }
```
- `task.cancel` 请求取消:置任务的取消标志,worker 在下一个同步检查点中止,任务转为 `cancelled`(协作式,不硬杀正在执行的 curl)。
- 与后台 watch 循环的定时同步通过进程内锁互斥(任务等待而非失败)。
- 任务历史**持久化**在 `<state-dir>/bat-tasks.json`(版本化、`0600` 原子写):生命周期转换(入队/开始/结束)时落盘,进行中任务的 `stage`/`message`/日志以内存实时值为准、随下一次转换写入。daemon 重启后历史任务经 `task.status` / `task.list` / `task.logs` 仍可查;重启时仍处于 `queued`/`running` 的任务标记为 `failed`(错误码 `BAT-ERR-700005` task_interrupted)。文件损坏时改名 `bat-tasks.json.corrupt` 留证并从空历史开始。历史保留最近 64 条(运行中任务不裁剪)。
### 示例
```bash
# 触发同步任务并取回 task_idsocat 演示)
printf '{"jsonrpc":"2.0","id":1,"method":"resource.sync","params":{"force":true}}\n' \
| socat - UNIX-CONNECT:/tmp/bat-pid/bat.sock
# 轮询任务
printf '{"jsonrpc":"2.0","id":2,"method":"task.status","params":{"task_id":"task-1234-1"}}\n' \
| socat - UNIX-CONNECT:/tmp/bat-pid/bat.sock
# 查询当前 catalog 概览与版本历史
printf '{"jsonrpc":"2.0","id":3,"method":"catalog.status"}\n' \
| socat - UNIX-CONNECT:/tmp/bat-pid/bat.sock
printf '{"jsonrpc":"2.0","id":4,"method":"catalog.versions"}\n' \
| socat - UNIX-CONNECT:/tmp/bat-pid/bat.sock
# 分页读取当前版本的下载 manifest
printf '{"jsonrpc":"2.0","id":5,"method":"resource.manifest","params":{"offset":0,"limit":50}}\n' \
| socat - UNIX-CONNECT:/tmp/bat-pid/bat.sock
# 触发本地资源审计+修复任务
printf '{"jsonrpc":"2.0","id":6,"method":"resource.repair"}\n' \
| socat - UNIX-CONNECT:/tmp/bat-pid/bat.sock
```