Files
BlueArchiveToolkit/docs/reference/rpc-backend-api.md
T
nyaKazuha 03021ad649
bat-rust / Build and test Rust (push) Canceled after 0s
docs(project): 同步维护冻结与运行文档
补齐解析模块维护冻结规则,并同步 CURRENT_STATUS、CURRENT_GAPS、PROJECT_PLAN、RPC 参考、部署指南、用户指南和官方资源运行说明。

文档同时反映 bat-api 资源 bootstrap/分发边界、官方同步解析缓存、TextUnit 队列、双目录发布和 patch 入口的当前状态。

验证:未运行新命令;本轮已按要求停止重复构建/测试。
2026-07-31 00:45:46 +08:00

315 lines
15 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.
# Rust Resource Backend RPC API
本文档冻结本机 Rust Resource Backend API 的稳定调用边界。Go 项目
`bat-api`、Go 服务层、运维脚本和 `bat` CLI 都应以这里的 JSON-RPC
contract 为准,不应绕过 daemon 状态文件或扩展 `bat-ffi` 作为主路径。
## 传输
- 传输:Unix domain socket。
- 默认 socket`/tmp/bat-pid/bat.sock`
- 协议:JSON-RPC 2.0,每行一个 request,每行一个 response。
- 编码:UTF-8 JSON。
- 访问控制:依赖本机文件权限和状态目录权限;不要把 socket 暴露到公网。
请求:
```json
{"jsonrpc":"2.0","id":1,"method":"resource.repair","params":null}
```
成功响应的 JSON-RPC 顶层 `result` 一律是应用层 envelope
```json
{
"jsonrpc": "2.0",
"id": 1,
"result": {
"ok": true,
"status": "accepted",
"data": {"task_id": "task-1234-1", "kind": "resource.repair"},
"request_id": "req-1234-1"
}
}
```
应用层失败也放在 `result` 的 envelope 中:
```json
{
"ok": false,
"status": "error",
"error": {
"code": "BAT-ERR-700003",
"kind": "not_implemented",
"domain": "rpc",
"location": "rpc.dispatch",
"message": "方法尚未实现:daemon.clean-stable",
"retryable": false
},
"request_id": "req-1234-2"
}
```
只有 JSON 解析失败等传输层错误使用 JSON-RPC 顶层 `error`
## Envelope
| 字段 | 类型 | 说明 |
|---|---|---|
| `ok` | bool | 应用层是否成功。 |
| `status` | string | `ok``accepted``error`。 |
| `data` | object/null | 成功结果。失败时省略。 |
| `error` | object/null | `ApiError`。成功时省略。 |
| `request_id` | string | daemon 进程内请求 ID,用于日志关联。 |
`ApiError` 结构以 `core/src/error_code.rs` 码表为准:
| 字段 | 类型 | 说明 |
|---|---|---|
| `code` | string | `BAT-ERR-<6位>`。 |
| `kind` | string | 错误类别。 |
| `domain` | string | 错误域。 |
| `location` | string | Rust 侧出错位置。 |
| `message` | string | 可诊断错误信息。 |
| `retryable` | bool | 调用方是否可以按策略重试。 |
## 方法
### daemon
| 方法 | 状态 | params | data |
|---|---|---|---|
| `daemon.status` | 已实现 | `null` | 后台状态报告。 |
| `daemon.logs` | 已实现 | `{ "tail": 200 }` | 日志尾部报告。 |
| `daemon.stop` | 已实现 | `null` | accepted ack。 |
| `daemon.reload` | 已实现 | `null` | accepted ack。 |
| `daemon.refresh` | 已实现 | `{ "force": false }` | accepted ack。 |
| `daemon.doctor` | 已实现 | `null` | 只读诊断报告。 |
| `daemon.restart` | 保留 | `null` | live RPC 不执行;由 CLI 生命周期入口处理。 |
| `daemon.clean-stable` | 保留 | `null` | live RPC 不执行;由 CLI 离线清理入口处理。 |
`bat.status``bat.stop``bat.reload``bat.refresh``bat.logs`
`bat.doctor``bat.clean-stable` 是兼容别名;新代码应使用 `daemon.*`
### resource
| 方法 | 状态 | params | data |
|---|---|---|---|
| `resource.state` | 已实现 | `null` | 资源发布根、版本状态、上次同步结果。 |
| `resource.sync` | 已实现 | `{ "force": false }` | `{ "task_id": "...", "kind": "resource.sync" }`。 |
| `resource.verify` | 已实现 | `null` | `{ "task_id": "...", "kind": "resource.verify" }`。 |
| `resource.repair` | 已实现 | `null` | `{ "task_id": "...", "kind": "resource.repair" }`。 |
| `resource.manifest` | 已实现 | `{ "offset": 0, "limit": 100 }` | 当前 download manifest 分页。 |
| `resource.list` | 已实现 | `{ "offset": 0, "limit": 100 }` | `resource.manifest` 的兼容别名。 |
| `resource.index` | 已实现 | `{ "offset": 0, "limit": 100, "type": "asset_bundle", "hash": "...", "path_pattern": "*" }` | 当前 `ResourceRepository` 分页/过滤查询。 |
`resource.repair` 会开启本地 manifest audit + repair,不继承 `force`
`resource.manifest` / `resource.list` 查询当前已发布 release 的
`official-download-manifest.json``resource.index` 查询可选导入产生的
SQLite `ResourceRepository`,索引不存在时返回 `ok=true`
`data.available=false`,不会隐式创建数据库。`limit` 范围是 `1..=1000`
非法参数返回 `BAT-ERR-700002`
`resource.index``entries[]``Resource` JSON,除 `id``local_path`
`entry` 外会包含 `metadata``official_release_id``platform`
`bundle_path``archive_entries``parse_statuses``unity_versions`
`text_assets``text_unit_count``text_unit_formats`
`text_unit_error_count` 等字段。旧索引库会通过 `metadata_json` 迁移列得到
默认空 metadata。
官方资源完整新版本发布后,Rust 侧会先比较上一完整 release 与当前 release
的 download manifest,并在当前 release 根目录写出:
- `official-resource-changes.json`:记录 added / modified / removed 资源。
同一 destination 只有 size 或 BLAKE3 变化才算 modifiedURL 或 CDN root
变化但内容一致时不进入解析/翻译候选。
- `crowdin-translation-handoff.json`:只包含 added + modified 资源,作为后续
Crowdin worker 的稳定本地队列输入;当前 RPC 不直接调用 Crowdin API。
- `official-parse-cache.json`:解析缓存。up-to-date 轮询发现本地文件未变且缓存
有效时只读取摘要,不重复解析。
- `official-textunit-index.json`:TextUnit 明细和解析错误索引。up-to-date 轮询发现
本地文件未变且索引有效时复用,不重复解析。
- `official-textunit-tasks.json`:只由 added + modified 资源、parse cache 和
TextUnit 明细索引派生,记录 TextUnit 任务、跳过原因和解析诊断。
- `crowdin-textunit-queue.json`:只包含已产生 TextUnit 的离线任务,预留给后续
Crowdin worker;当前不会发出网络请求。
删除资源只进入 `official-resource-changes.json`,不进入 Crowdin handoff。
### parse
| 方法 | 状态 | params | data |
|---|---|---|---|
| `parse.status` | 已实现 | `null` | 当前官方 release 的解析缓存状态。 |
| `parse.text_units` | 已实现 | `{ "offset": 0, "limit": 100, "destination": "*Table*", "archive_entry": "*.bytes", "path_id": 1, "class_id": 114, "field_path": "*Text*", "format": "json" }` | 当前官方 release 的 TextUnit 明细分页。 |
| `parse.errors` | 已实现 | `{ "offset": 0, "limit": 100, "destination": "*Table*", "archive_entry": "*.bytes", "path_id": 1, "class_id": 114, "field_path": "*Text*", "format": "json" }` | 当前官方 release 的解析错误分页。 |
`parse.status` 是只读查询;没有当前 release 或没有解析缓存时返回
`ok=true``data.available=false`。解析缓存来自官方原版资源目录,不读取
汉化输出目录。存在 `official-textunit-index.json` 时,响应会包含
`textunit_index_available=true``textunit_index_path`
`textunit_index_summary`;存在 `official-textunit-tasks.json` 时,响应会包含
`textunit_queue_available=true``textunit_task_queue_path`
`textunit_task_summary`
`parse.text_units` / `parse.errors` 是只读查询;没有当前 release 或没有
`official-textunit-index.json` 时返回 `ok=true``data.available=false`
分页参数 `offset` 默认 0`limit` 默认 100,范围是 `1..=1000`。过滤参数:
| 字段 | 类型 | 说明 |
|---|---|---|
| `destination` | string | official download manifest destination,支持 `*` 通配。 |
| `archive_entry` | string | zip 内条目,支持 `*` 通配;直接 bundle 通常为 `null`。 |
| `path_id` | integer | Unity object path id。 |
| `class_id` | integer | Unity class id。 |
| `field_path` | string | TypeTree/TextAsset 字段路径,支持 `*` 通配。 |
| `format` | string | TextUnit 格式,例如 `json``csv``tsv``plain``typetree_string`。 |
`parse.text_units``entries[]` 会包含 source text、source URL、
destination、archive entry、source kind、Unity version、serialized file、
path id、class id、field path、字段 offset/byte size、format、asset name 和
context。`parse.errors``entries[]` 会包含 source URL、destination、
archive entry、status、serialized file、path id、class id、field path、
offset 和 error。TypeTree-covered managed reference 字段会进入结构化字段遍历;
完整 managed reference registry 等暂不支持结构会进入解析错误,而不是静默降级为
低保真文本。
### localized
| 方法 | 状态 | params | data |
|---|---|---|---|
| `localized.status` | 已实现 | `null` | 汉化发布状态、当前官方 release 匹配关系和汉化输出目录。 |
`localized.status` 严格按 daemon / `.env` 中的 `BAT_LOCALIZED_OUTPUT`
`--localized-output` 查询汉化产物目录,不把 `./bat-resources`
`./bat-localized` 混用。当前支持未汉化发布状态和已汉化发布状态的只读报告。
返回 `localized` 的条件是:`localized-version-state.json` 的官方 release ID
匹配当前官方 release`current` symlink 指向汉化发布根下对应的
`versions/<id>`,并且该版本目录中的
`localized-patch-manifest.json` 存在且 release ID 匹配。响应会返回
`patch_manifest_path``patch_manifest_available`
`patch_manifest_matches_release``patch_file_count`
`patch_text_asset_operation_count``rollback_previous_current_target`
### catalog
| 方法 | 状态 | params | data |
|---|---|---|---|
| `catalog.status` | 已实现 | `null` | 当前已发布 catalog 概览。 |
| `catalog.versions` | 已实现 | `null` | current / in_progress / previous / failed。 |
| `catalog.diff` | 已实现 | `null` | 当前 snapshot 相对上一可用版本的差异。 |
| `catalog.refresh` | 已实现 | `{ "force": false }` | `{ "task_id": "...", "kind": "catalog.refresh" }`。 |
只读查询在没有可用版本时返回 `ok=true``data.available=false`
### task
| 方法 | 状态 | params | data |
|---|---|---|---|
| `task.status` | 已实现 | `{ "task_id": "..." }` | 单个任务记录。 |
| `task.list` | 已实现 | `null` | `{ "tasks": [...] }`。 |
| `task.cancel` | 已实现 | `{ "task_id": "..." }` | cancel ack。 |
| `task.logs` | 已实现 | `{ "task_id": "..." }` | `{ "task_id": "...", "lines": [...] }`。 |
| `task.create` | 保留 | object | 不开放通用任务入口;由语义方法创建任务。 |
任务记录:
```json
{
"id": "task-1234-1",
"kind": "resource.repair",
"status": "queued",
"stage": null,
"message": null,
"created_at": 1780000000,
"updated_at": 1780000000,
"started_at": null,
"finished_at": null,
"error": null,
"result": null
}
```
`status` 取值:`queued``running``succeeded``failed``cancelled`
daemon 重启后仍处于 `queued``running` 的历史任务会被标记为
`failed`,错误码为 `BAT-ERR-700005`
### patch / unityfs
已开放的文件级写入方法:
- `patch.apply`:对显式 `source_path``patch_path``target_path` 执行
Binary/JSON/Text patch apply`kind` 取值为 `binary``json``text`
- `unityfs.patch_text_asset`:对显式 UnityFS `bundle_path` 中的
`serialized_file_path` / `path_id` TextAsset 应用 `replacement_path`,写入
`target_path`,可选 `expected_name`
- `unityfs.patch_string_field`:对显式 UnityFS `bundle_path` 中的
`serialized_file_path` / `path_id` / `field_path` TypeTree string 字段应用
`replacement_text` 或 UTF-8 `replacement_path`,写入 `target_path`,可选
`expected_value`
- `unityfs.patch_field`:对显式 UnityFS `bundle_path` 中的
`serialized_file_path` / `path_id` / `field_path` TypeTree 字段应用语义
`replacement` JSON,写入 `target_path`,可选 `expected_value``replacement`
使用 `{"kind":"signed","value":42}` 这类 tagged JSON;支持
`bool``signed``unsigned``float32``float64``string``bytes`
`enum``bit_field``p_ptr`、固定 Unity 叶子结构、object 字段组合和 TypeTree schema 支撑的 array/map 整体替换。enum 形如
`{"kind":"enum","value":{"type_name":"ScenarioDifficulty","storage_type":"int","value":3}}`
`type_name` 是 TypeTree enum 类型名,`storage_type` 是 backing integer 类型。`LayerMask` / `BitField` 形如
`{"kind":"bit_field","value":{"type_name":"LayerMask","storage_type":"UInt32","bits":9}}`
array 形如
`{"kind":"array","value":[{"kind":"string","value":"你好"}]}`map entry 用
object 表达,例如
`{"kind":"object","value":[{"name":"first","value":{"kind":"string","value":"jp"}}]}`
扩容时复用当前首个元素或 TypeTree data node 的编码 schemamap entry schema
变化、unknown 字段和未覆盖的 managed reference registry 变体仍会返回明确错误。
固定 Unity 叶子结构使用 raw bits/bytes 表达,例如
`{"kind":"float32_struct","value":{"type_name":"Vector3f","values":[1065353216,1073741824,1077936128]}}`
`{"kind":"fixed_bytes","value":{"type_name":"GUID","bytes":[0,1,2,3,4,5,6,7,8,9,10,11,12,13,14,15]}}`
这些方法同步执行,不进入 `task.*` 队列;输出文件使用临时文件原子写入,响应
`data` 会返回 source / patch 或 replacement / target 的 size 与 BLAKE3。`target_path`
不能与输入文件相同。
仍关闭的范围:发布级 `patch build` / `patch rollback`、复杂 UnityFS 语义编辑、
`unityfs.inspect`、通用 manifest 驱动 release 切换。调用这些规划方法仍返回
`BAT-ERR-700003`
CLI 对应关系:
| CLI | RPC |
|---|---|
| `bat patch-apply` | `patch.apply` |
| `bat unityfs-patch-text-asset` | `unityfs.patch_text_asset` |
| `bat unityfs-patch-string-field` | `unityfs.patch_string_field` |
| `bat unityfs-patch-field` | `unityfs.patch_field` |
## Go 调用边界
`bat-api` 应直接调用本 RPC contract,不通过 `exec` 调用 `bat` binary。
`bat` binary 是人类 CLI 和进程生命周期工具;默认 `refresh` / `repair`
在 daemon 可用时也会作为 RPC client 调用同一个 socket。
人类 CLI 的只读查询命令与 RPC 对应关系如下:
| CLI | RPC |
|---|---|
| `bat parse-status` | `parse.status` |
| `bat parse-text-units` | `parse.text_units` |
| `bat parse-errors` | `parse.errors` |
| `bat localized-status` | `localized.status` |
| `bat resource-index` | `resource.index` |
`bat resource-index` 支持 `--offset``--limit``--resource-type``--hash`
`--path-pattern``bat parse-text-units` / `bat parse-errors` 支持
`--offset``--limit``--destination``--archive-entry``--path-id`
`--class-id``--field-path``--format`;这些过滤参数不适用于
`parse-status``localized-status`
禁止事项:
- Go 服务层不直接读写 `bat-status.json``bat-tasks.json` 等 daemon 内部状态文件。
- Go 服务层不扩展 `bat-ffi` 为主控制面。
- Go 服务层不通过 stdout 解析 `bat status --json` 作为常规调用路径。