Files
BlueArchiveToolkit/USERGUIDE.md
T
nyaKazuhaandClaude Fable 5 d7257db447 docs(userguide): 增加 Daemon RPC 接口章节
记录 bat.sock JSON-RPC 2.0 控制面:统一 envelope(ok/status/data/error/request_id)、
方法命名空间与实现状态(daemon.*/resource.*/task.* 已实现,catalog/patch/unityfs
及 task.cancel/logs 返回 700003)、异步任务模型(resource.sync/verify 返回 task_id、
task.status/list 轮询)和调用示例。

对应 issue #1(协议文档)。

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
2026-07-17 05:31:57 -07:00

294 lines
14 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,不安装、不启动官方启动器。
- 生成官方全量 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`)。子命令如下:
| 命令 | 说明 |
|---|---|
| `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/状态文件兼容路径。
---
## 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>`)。
- 后台状态目录:`/tmp/bat-pid``bat.sock``bat.pid``bat-status.json``bat-daemon.log``bat-events.jsonl`、短生命周期 `bat-control.lock`;代理凭据在 `bat-proxy.secret``0600`)。
- 强制刷新:每天北京时间(UTC+8`03:00``16:00``18:00` 各一次。
- 状态类文件默认 `0600` 权限,读写不跟随 symlink。
---
## 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`)已建立并作为公共契约;将各链路的报错逐步接入到该码表的工作在 issue #1 下推进。下表随码表更新。
### 域一览
| 域 | 区间 | 含义 |
|---|---|---|
| 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-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-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-900001` | internal | 否 | 未归类的内部错误 |
新增错误码在 `core/src/error_code.rs` 的码表登记后,同步更新本表。
---
## 6. Daemon RPC 接口
`bat --daemon` 在后台状态目录下创建 `bat.sock`Unix socket),提供**换行分隔的 JSON-RPC 2.0** 控制面。CLI 的 `status`/`stop`/`logs`/`reload`/`refresh` 优先走它;Go 服务层也应通过这个进程边界调用,而非 FFI。
### 传输与 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` |
| `resource.state` | ✅ | 资源发布根 + 版本状态 + 上次同步结果 |
| `resource.sync` | ✅ | 触发同步任务(`params.force`),返回 `task_id` |
| `resource.verify` | ✅ | 触发校验任务(dry-run + audit),返回 `task_id` |
| `task.status` | ✅ | 查询任务(`params.task_id` |
| `task.list` | ✅ | 列出全部任务(最新在前) |
| `catalog.*` / `patch.*` / `unityfs.*` / `task.cancel` / `task.logs` | ⏳ | 已规划,返回 `BAT-ERR-700003`not implemented |
| 未知方法 | — | `BAT-ERR-700001`unknown method |
### 任务模型
`resource.sync` / `resource.verify` 是**异步任务**:入队即返回 `{ "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",
"stage": "download", "message": "…",
"created_at": …, "updated_at": …, "started_at": …, "finished_at": …,
"error": { … }, "result": { … } }
```
- 与后台 watch 循环的定时同步通过进程内锁互斥(任务等待而非失败)。
- 任务目前**仅存内存**,随 daemon 生死;持久化(重启后仍可查)为后续工作。
### 示例
```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
```