mirror of
https://github.com/Yuyi-Oak/BlueArchiveToolkit.git
synced 2026-09-18 06:34:54 +08:00
feat(api): 补齐资源分发服务入口
新增 bat-api 资源 bootstrap/分发 HTTP 服务、RPC release 发现、CDN path 分发、launcher 资源引导兼容、控制面中间件、OpenAPI 和 systemd 模板。 同步 Go 边界文档,明确 Rust bat 是资源生产者和同步运维入口,Go bat-api 是只读 bootstrap/分发服务,试验 Go CLI 产物为 bin/bat-go。 验证:未运行新命令;本轮已按要求停止重复构建/测试。
This commit is contained in:
@@ -0,0 +1,196 @@
|
||||
# bat-api / Rust bat Contract Fixture Handoff
|
||||
|
||||
更新时间:2026-07-28
|
||||
|
||||
本文用于两个 Codex 窗口之间间接联调 `bat-api` 与 Rust `bat` 的跨语言 contract fixture。它只定义协作协议和验收标准,不包含已审核 fixture。
|
||||
|
||||
## 最小上下文包
|
||||
|
||||
另一个窗口不需要知道本窗口的完整对话,只需要遵守以下上下文:
|
||||
|
||||
- 本次联调对象是 Rust `bat` RPC / snapshot JSON 与 Go `bat-api` mirror struct 的 contract fixture。
|
||||
- 联调不要求本地运行全量长期服务端 `bat`;允许 Rust 侧使用 fixture root 或临时目录走真实代码路径导出 JSON。
|
||||
- fixture 审核前只能放在 `/tmp/bat-contract-fixture/`,不能直接提交到仓库。
|
||||
- Go 侧已经实现 player-facing HTTP 鉴权、限流、访问日志、反代适配、OpenAPI 和 `/admin/` 预留;contract fixture 是剩余跨语言强契约工作。
|
||||
- Go 侧当前相关代码入口:
|
||||
- `internal/api/rpc_release.go`
|
||||
- `internal/api/release_index.go`
|
||||
- `internal/api/responses.go`
|
||||
- `internal/backendrpc/`
|
||||
|
||||
## 背景
|
||||
|
||||
- Rust `bat` 是资源同步、状态发布和 `bat.sock` RPC 的权威实现。
|
||||
- Go `bat-api` 是只读 HTTP bootstrap / 分发服务,消费 Rust RPC 输出和已发布资源目录。
|
||||
- contract fixture 不能由任一侧手写猜测;必须由 Rust 侧真实输出,经归一化和用户审核后,再由 Go 侧固化测试。
|
||||
|
||||
## 非目标
|
||||
|
||||
- 不引入真实玩家账号、登录、网关、鉴权绕过或游戏业务 API fixture。
|
||||
- 不写入开发机绝对资源路径,例如 `/home/wanye/D/BlueArchive`。
|
||||
- 不把当前某个真实版本号、日期、远程目录或本地目录写成长期契约。
|
||||
- 不让 Go fixture 反向约束 Rust 内部实现;只约束对外 JSON contract。
|
||||
|
||||
## 建议共享目录
|
||||
|
||||
联调前使用临时目录交换未审核产物:
|
||||
|
||||
```text
|
||||
/tmp/bat-contract-fixture/
|
||||
rust/
|
||||
catalog-status.available.raw.json
|
||||
catalog-status.unavailable.raw.json
|
||||
resource-manifest.page0.raw.json
|
||||
official-sync-snapshot.raw.json
|
||||
normalized/
|
||||
catalog-status.available.json
|
||||
catalog-status.unavailable.json
|
||||
resource-manifest.page0.json
|
||||
official-sync-snapshot.json
|
||||
notes.md
|
||||
```
|
||||
|
||||
只有用户审核通过后,才允许把归一化 fixture 落入仓库,例如:
|
||||
|
||||
```text
|
||||
internal/api/testdata/contract/
|
||||
```
|
||||
|
||||
## Rust 侧需要产出
|
||||
|
||||
Rust 窗口请基于当前真实代码生成或导出以下 JSON:
|
||||
|
||||
1. `catalog.status` available=true 响应。
|
||||
2. `catalog.status` available=false 响应。
|
||||
3. `resource.manifest` 第一页响应,至少包含 1 到 2 个 entries。
|
||||
4. 对应 release 的 `official-sync-snapshot.json`。
|
||||
|
||||
输出应来自 Rust 代码路径,而不是手写 JSON。允许使用 fixture resource root 或临时目录,但不能依赖开发机真实资源目录。
|
||||
|
||||
## 归一化规则
|
||||
|
||||
归一化只允许处理环境相关值,不改变 schema:
|
||||
|
||||
- 绝对路径归一化为 `${RESOURCE_ROOT}` 或 `${STATE_DIR}`。
|
||||
- 版本 id 归一化为 `${VERSION_ID}`。
|
||||
- 时间戳可归一化为固定小整数或 `${COMPLETED_UNIX_SECONDS}`。
|
||||
- 真实 URL host 保留;路径中若含具体 release token,可归一化为 `{addressables-root}` / `{manifest-path}`。
|
||||
- 字段名、字段类型、字段层级、null / missing / array / number 语义不得修改。
|
||||
|
||||
## Go 侧验证范围
|
||||
|
||||
Go 窗口读取归一化后的 JSON,验证:
|
||||
|
||||
1. `parseCatalogStatus` 能解析 `available=true`,并正确映射:
|
||||
- `app_version`
|
||||
- `bundle_version`
|
||||
- `connection_group_name`
|
||||
- `addressables_root`
|
||||
- `version.id`
|
||||
- `version.completed_unix_seconds`
|
||||
- `version.resource_root`
|
||||
- `launcher_metadata`
|
||||
- `game_main_config`
|
||||
2. `parseCatalogStatus` 对 `available=false` 返回不可用而不是错误。
|
||||
3. `resource.manifest` entry 字段能映射为 Go `ResourceManifestEntry`:
|
||||
- `url`
|
||||
- `destination`
|
||||
- `bytes`
|
||||
- `blake3`
|
||||
4. 本地 snapshot fixture 使用 `game_main_config_bootstrap`,RPC `catalog.status` 使用 `game_main_config`。
|
||||
5. `bat-api` bootstrap 和 launcher bootstrap 不泄露归一化前的开发机路径。
|
||||
|
||||
Go 侧审核通过后的落地建议:
|
||||
|
||||
- `internal/api/testdata/contract/catalog-status.available.json`
|
||||
- `internal/api/testdata/contract/catalog-status.unavailable.json`
|
||||
- `internal/api/testdata/contract/resource-manifest.page0.json`
|
||||
- `internal/api/testdata/contract/official-sync-snapshot.json`
|
||||
- `internal/api/contract_fixture_test.go`
|
||||
|
||||
测试不应依赖 `/tmp/bat-contract-fixture/`;该目录只用于两窗口交接未审核产物。
|
||||
|
||||
## 必须覆盖的 optional 语义
|
||||
|
||||
至少需要两组 Rust 输出或派生 fixture 覆盖:
|
||||
|
||||
1. optional 字段非空:
|
||||
- `launcher_metadata.game_lowest_version`
|
||||
- `launcher_metadata.game_start_exe_name`
|
||||
- `launcher_metadata.manifest_source`
|
||||
- `game_main_config.server_info_data_url`
|
||||
- `game_main_config.default_connection_group`
|
||||
2. optional 字段为 null 或缺省:
|
||||
- Go mirror 不应崩溃。
|
||||
- HTTP response 中按当前 Go struct `omitempty` 策略输出。
|
||||
|
||||
## 用户审核点
|
||||
|
||||
落仓库前请用户审核:
|
||||
|
||||
- 归一化是否过度改变 Rust 真实输出。
|
||||
- fixture 是否意外绑定真实版本、日期、本机路径或私有部署路径。
|
||||
- `game_main_config` 与 `game_main_config_bootstrap` 的 RPC / snapshot 差异是否符合预期。
|
||||
- optional 字段覆盖是否足够。
|
||||
|
||||
## notes.md 模板
|
||||
|
||||
Rust 侧生成 `/tmp/bat-contract-fixture/notes.md` 时建议使用以下结构:
|
||||
|
||||
```markdown
|
||||
# bat contract fixture notes
|
||||
|
||||
## 生成命令
|
||||
|
||||
- catalog.status available=true: ...
|
||||
- catalog.status available=false: ...
|
||||
- resource.manifest page0: ...
|
||||
- official-sync-snapshot: ...
|
||||
|
||||
## 原始输出来源
|
||||
|
||||
- Rust commit / working tree: ...
|
||||
- 使用的 fixture root 或临时目录: ...
|
||||
- 是否依赖真实开发机资源目录: 否
|
||||
|
||||
## 归一化
|
||||
|
||||
- `${RESOURCE_ROOT}`: ...
|
||||
- `${STATE_DIR}`: ...
|
||||
- `${VERSION_ID}`: ...
|
||||
- `${COMPLETED_UNIX_SECONDS}`: ...
|
||||
- URL 路径占位符: ...
|
||||
|
||||
## 需要用户审核
|
||||
|
||||
- ...
|
||||
```
|
||||
|
||||
## 完成判定
|
||||
|
||||
contract fixture 工作只有在以下条件同时满足时才算完成:
|
||||
|
||||
1. Rust 侧原始 JSON 来自真实 Rust 代码路径。
|
||||
2. 归一化 JSON 经过用户审核。
|
||||
3. Go 侧测试读取归一化 fixture 并验证 mirror struct / launcher bootstrap 行为。
|
||||
4. Go 测试不依赖开发机资源目录、远程长期运行 `bat` 或 `/tmp` 中的交接目录。
|
||||
5. 文档记录 fixture 覆盖的风险和仍未覆盖的字段。
|
||||
|
||||
## 建议给另一个窗口的短指令
|
||||
|
||||
```text
|
||||
请读取 docs/reports/BAT_API_CONTRACT_FIXTURE_HANDOFF.md。
|
||||
你负责 Rust bat 侧 contract fixture 原始输出:
|
||||
1. catalog.status available=true
|
||||
2. catalog.status available=false
|
||||
3. resource.manifest page0
|
||||
4. 对应 official-sync-snapshot.json
|
||||
请输出到 /tmp/bat-contract-fixture/rust/,不要手写 JSON,不要引用开发机真实资源目录。
|
||||
输出后在 /tmp/bat-contract-fixture/notes.md 说明生成命令、是否做过归一化、哪些字段需要用户审核。
|
||||
```
|
||||
|
||||
## 当前状态
|
||||
|
||||
- Go `bat-api` 已具备消费 `launcher_metadata` / `game_main_config` 的 mirror struct。
|
||||
- Go `bat-api` 已具备 player-facing HTTP 控制面、OpenAPI 和管理面板预留。
|
||||
- contract fixture 尚未落仓库,等待 Rust 侧真实输出与用户审核。
|
||||
@@ -0,0 +1,151 @@
|
||||
# Go 侧进度与边界(权威)
|
||||
|
||||
- **更新时间**:2026-07-27
|
||||
- **用途**:统一 Go module `bat-api` 的产品边界、既有约定和组件进度;其他文档与此冲突时以本文为准。
|
||||
- **关联**:issue #19 / G-009(资源 bootstrap/分发)、G-008(已决策关闭)、`docs/architecture/official-resource-backend.md` §7
|
||||
|
||||
---
|
||||
|
||||
## 1. 三个入口分别是什么
|
||||
|
||||
| 名称 | 路径 / 产物 | 角色 | 是否产品入口 |
|
||||
|---|---|---|---|
|
||||
| **Rust `bat`** | `infrastructure` bin → 正式同步二进制 | 官方资源**自动**发现 / 拉取 / 校验 / 发布 / watch·daemon / 运维子命令 | **是(同步与运维命令行)** |
|
||||
| **Go `bat-api`** | `cmd/bat-api` → `bin/bat-api` | **资源 bootstrap + 分发 HTTP 服务**(官方 CDN path 形态)+ release 观察 API | **是(bootstrap/分发服务)** |
|
||||
| **Go 试验 CLI** | `cmd/bat` → `bin/bat-go`(不得再叫 `bin/bat`) | FFI 演示骨架 | **否** |
|
||||
|
||||
### 1.1 「同步命令行 = Rust `bat`」的含义
|
||||
|
||||
人类做资源同步与运维时,正式命令行是 **Rust 编译的 `bat`**(近乎全自动:`--auto-discover`、`--watch` / `--daemon` 后只需偶发 `status` / `refresh` / `repair`,不需要持久手操维护)。
|
||||
|
||||
这**不是**说整个项目只有 Rust,也**不是**取消 Go 入口:
|
||||
|
||||
- Go 的正式产品入口是 **`bat-api` 服务进程**(给客户端/工具提供启动前资源 bootstrap、server-info 改写和已发布资源字节),不是再做一套同步 CLI。
|
||||
- Go `cmd/bat` 仅试验,禁止与 Rust `bat` 二进制重名。
|
||||
|
||||
### 1.2 `bat` 与 `bat-api` 的关系
|
||||
|
||||
`bat` 是资源生产者和状态拥有者;`bat-api` 是资源读侧和 HTTP 入口。
|
||||
|
||||
| 关系面 | Rust `bat` / daemon | Go `bat-api` |
|
||||
|---|---|---|
|
||||
| 资源发现 | 读取官方 launcher/resource metadata,解析 `GameMainConfig`、server-info 和 Addressables root | 通过 `bat.sock` 读取已发布版本摘要,不重新探测官方 metadata |
|
||||
| 下载与发布 | 下载、校验、staging、原子发布 `current -> versions/<id>`,维护 manifest/snapshot/version-state | 不下载、不写 staging、不改 version-state;生产资源根来自 RPC 返回的 `resource_root` |
|
||||
| 启动前资源入口 | 暴露 `catalog.status` / `resource.manifest` 等 RPC 数据 | 提供 `/v1/bootstrap`、`/v1/launcher/bootstrap`、launcher 资源 metadata 兼容端点、`/v1/server-info` 和 CDN path,组织给客户端/补丁器使用 |
|
||||
| 长期状态 | watch/daemon、任务队列、日志、错误码、repair/sync/verify | 周期性经 RPC 刷新内存索引,只展示 ready、RPC 健康和 release;需要拉取/修复时由外部运维调用 `bat` 或 RPC 任务 |
|
||||
|
||||
这条边界允许 `bat-api` 做资源 bootstrap 兼容,但不允许它复制 Rust 下载器或伪装完整游戏业务服务。
|
||||
|
||||
### 1.3 决策(已核验)
|
||||
|
||||
1. **G-008 决策关闭(wontfix)**:不另做产品级 Go 同步/运维 CLI。
|
||||
2. **G-009**:资源 bootstrap/分发 MVP 部分完成;非完整游戏业务 API。
|
||||
3. **USERGUIDE 的 bat-api 基础章节已补**;全量 release 联调后继续补充生产参数和排障样例。
|
||||
|
||||
---
|
||||
|
||||
## 2. 既有约定核对表(不可丢)
|
||||
|
||||
### 职责
|
||||
|
||||
| ID | 约定 |
|
||||
|---|---|
|
||||
| A | **自动发现 / 下载 / 校验 / 发布 / watch·daemon** 只在 **Rust `bat`** |
|
||||
| B | **`bat-api` 只读分发**已发布 release,不实现下载器,不写 staging/version-state |
|
||||
| C | 仿真范围 = **资源拉取相关**(resource bootstrap + CDN path + 可选 server-info);**不是**完整游戏业务 API |
|
||||
| D | launcher 资源 metadata 可作为 bootstrap 输入/输出兼容;账号、登录、网关和鉴权全链 **非 G-009 关闭条件** |
|
||||
| E | USERGUIDE bat-api 基础章节已补;联调后补充实战样例 |
|
||||
|
||||
### 发现与数据
|
||||
|
||||
| ID | 约定 |
|
||||
|---|---|
|
||||
| F | 版本/清单经 **`bat.sock` JSON-RPC**(`--socket`);不读 daemon 内部状态文件 |
|
||||
| G | RPC 顺序:先 **`daemon.status`**,再 **`daemon.doctor`**,再 catalog/manifest |
|
||||
| H | 生产文件字节从 RPC 返回的 `resource_root` 读盘;`bat-api` 与 daemon 同服务器/同容器/共享文件系统部署;`--resource-root` 仅 fixture 或应急只读诊断 |
|
||||
| I | 真数据在**已全量拉取且长期运行 Rust `bat` 的远程服务器**;开发机不跑全量 `bat`,用 fixture、mock RPC 和 Go 门禁验证;远程联调等连接信息 |
|
||||
| J | 索引以 **manifest + 磁盘 Present/size** 为准 |
|
||||
|
||||
### 进程配置
|
||||
|
||||
| ID | 约定 |
|
||||
|---|---|
|
||||
| K | `.env` / 环境变量 / CLI:端口、public base、RPC socket、RPC 刷新周期;**预留** database/redis |
|
||||
| L | 管理面 / bootstrap:`/healthz`、`/readyz`、`/v1/bootstrap`、`/v1/release`、`/v1/resources`、`/openapi.yaml`、`/admin/` 预留 |
|
||||
| M | CDN:`GET/HEAD /prod-clientpatch.bluearchiveyostar.com/...`,支持 Range、ETag、Last-Modified、长期缓存头 |
|
||||
| N | server-info 可选;**只改 AddressablesCatalogUrlRoot** |
|
||||
| N2 | launcher 兼容仅限资源引导:`/v1/launcher/bootstrap` 与 `/api/launcher/...` 形状端点输出已发布 release、launcher metadata 和 GameMainConfig 摘要;不下载 launcher 包、不生成完整 PC package update manifest、不仿造登录/网关 |
|
||||
| N3 | 玩家-facing HTTP 控制面:可配置 token 鉴权、进程内限流、访问日志、反代 IP 适配、动态 JSON `no-store`、`/v1/resources` 分页上限 |
|
||||
|
||||
### 工程
|
||||
|
||||
| ID | 约定 |
|
||||
|---|---|
|
||||
| O | 权威文档与 `go list` 一致,禁止「API 完全没有」等过时句 |
|
||||
| P | 试验 CLI 产物 **`bin/bat-go`**,禁止 `bin/bat` |
|
||||
| Q | 空目录标明 reserved empty |
|
||||
| R | 默认门禁:`make test-go-api` + `make build-go-api`(无 FFI) |
|
||||
|
||||
---
|
||||
|
||||
## 3. 组件进度
|
||||
|
||||
| 组件 | 路径 | 状态 | 说明 |
|
||||
|---|---|---|---|
|
||||
| Module | `go.mod` → `bat-api` | 已用 | 服务层模块名 |
|
||||
| RPC client | `internal/backendrpc` | **完成** | typed JSON-RPC;fake transport 单测 |
|
||||
| 资源 bootstrap/分发 | `cmd/bat-api` + `internal/api` | **MVP+生产控制面** | RPC 发现 + 周期刷新/诊断 + `/v1/bootstrap` + `/v1/launcher/bootstrap` + launcher 资源 metadata 兼容 + `/readyz` + CDN Range/缓存头 + 鉴权/限流/访问日志/反代适配 + OpenAPI + 管理面预留 + `.env` |
|
||||
| 试验 CLI | `cmd/bat` | **试验** | doctor 固定 ok;manifest/sync 走 FFI |
|
||||
| FFI | `internal/ffi` | **可选** | 需 `build-ffi` |
|
||||
| 空骨架 | `api/`、`pkg/*`、部分 `internal/*` | **空** | 见各目录 README |
|
||||
| Web | `web/` | **空** | G-010 |
|
||||
|
||||
`go list ./...` 当前包:
|
||||
|
||||
- `bat-api/cmd/bat-api`
|
||||
- `bat-api/cmd/bat`
|
||||
- `bat-api/internal/api`
|
||||
- `bat-api/internal/backendrpc`
|
||||
- `bat-api/internal/ffi`
|
||||
|
||||
---
|
||||
|
||||
## 4. 验证门禁
|
||||
|
||||
```bash
|
||||
# 默认(提交前 / CI 建议)
|
||||
make test-go-api
|
||||
make build-go-api
|
||||
go vet ./internal/api/... ./internal/backendrpc/... ./cmd/bat-api/...
|
||||
|
||||
# 可选:改 FFI 或试验 CLI 时
|
||||
make build-ffi
|
||||
make test-go-ffi
|
||||
make build-go-cli # 产出 bin/bat-go
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## 5. 与缺口 / issue 对应
|
||||
|
||||
| 项 | 状态 |
|
||||
|---|---|
|
||||
| G-008 Go 同步 CLI | **已决策关闭**(正式同步 CLI = Rust `bat`) |
|
||||
| G-009 bat-api 资源 bootstrap/分发 | **部分完成**(MVP+生产控制面);已含资源 bootstrap 关系面、launcher 资源 metadata 兼容、HTTP 鉴权/限流/日志/反代适配、RPC 周期刷新/诊断、readiness、OpenAPI、管理面预留和部署模板,后续远程服务器联调/可选持久化 |
|
||||
| issue #19 | 资源面 MVP 与 USERGUIDE 基础章节已编码;真机联调后继续补充实战样例;**未自动关 issue** |
|
||||
| G-010 Web | 未开始 |
|
||||
|
||||
---
|
||||
|
||||
## 6. 资源布局与逆向
|
||||
|
||||
- **Release / URL / 分发契约(权威)**:`docs/architecture/resource-release-layout.md`
|
||||
- 真机全量实勘、seed inventory diff、issue #2/#3 样本采集按该文档 §9–§10 执行
|
||||
|
||||
## 7. 后续(不在进度统一范围内)
|
||||
|
||||
1. 服务器 SSH 只读实勘(连接信息到位后)
|
||||
2. bat-api 与远程长期运行的 `bat` / 全量 release 联调(含 `/v1/bootstrap`、server-info 和 CDN path)
|
||||
3. 预留 database/redis 的接入时机另议
|
||||
4. USERGUIDE bat-api 联调排障样例(全量 release 验证后)
|
||||
5. launcher 完整安装包更新链 / 登录网关链(若需要,新 issue)
|
||||
Reference in New Issue
Block a user