Files
Genarrative/server-rs/crates/spacetime-client
2026-05-08 11:44:42 +08:00
..
1
2026-05-08 11:44:42 +08:00
1
2026-05-08 11:44:42 +08:00
1
2026-05-05 14:40:41 +08:00

spacetime-client 共享 package 说明

日期:2026-05-01

1. package 职责

spacetime-client 是 SpacetimeDB 客户端适配 package后续负责

  1. 生成 bindings 后的客户端访问封装
  2. Axum 与各模块对 reducer、view、订阅的调用适配
  3. 身份透传、连接配置与基础错误处理适配

在 DDD 重构中,本 package 只承接 WP-SC Spacetime Client

  1. 把 SpacetimeDB 生成绑定转换成 api-server 可消费的 typed facade。
  2. 把 row snapshot / procedure result 转换成 BFF record。
  3. 统一 SDK 调用错误、业务 procedure 错误、缺失快照错误和超时错误。
  4. 不承载领域规则,不直接定义 table / reducer / procedure不替代 spacetime-module

本轮方案见 SERVER_RS_DDD_WP_SC_SPACETIME_CLIENT_REFACTOR_2026-04-29.md

2. 当前完成口径

当前目录已不再只是占位。WP-SC Spacetime Client 在当前稳定 SpacetimeDB facade 范围内已经完成收尾:

  1. 通过 npm run spacetime:generate -- --rust-only 生成并纳管公开 Rust bindings。
  2. DbConnection 连接池、握手等待、超时和断线清理已封装在 SpacetimeClient 内部。
  3. 已稳定的 assets、auth、AI task、Big Fish、Custom World、Puzzle、Runtime/Profile/Save、Story session、combat、inventory、NPC facade 均通过 typed 方法对外暴露。
  4. 生成绑定到 BFF record / module record 的 row snapshot mapper 已集中在 mapper.rs
  5. SDK 调用错误、reducer 业务错误、procedure 业务错误、缺快照错误和本地输入校验错误已统一收口到 SpacetimeClientError helper。
  6. Story runtime projection source 已复用 runtime inventory typed facade读取投影不再只依赖 runtime snapshot 中的历史背包 JSON 副本。
  7. Story runtime 投影读取会对历史 currentStory.options 做兼容推断:若旧快照缺少 scope,仍会按 functionId 通过 module-runtime-story 的 option helper 还原为 story / combat / npc 作用域,避免旧存档把读取链路卡死。

confirm_asset_object_and_returnbind_asset_object_to_entity_and_return 的调用必须等到 SDK on_connect 回调后再发起。DbConnection::build() 只代表 WebSocket 已经初始化,不代表 SpacetimeDB 身份握手完成;如果过早调用 procedure本地联调会表现为连接建立但请求长期没有回调最终等到 idle timeout。

后续新增工作只随 WP-ST 新 table / reducer / procedure 或 row shape 稳定后按领域增量接入,不再把整个 WP-SC 包保持为进行中状态。新增 facade 时必须继续满足:

  1. 不手写 module_bindings 生成物。
  2. 不在 spacetime-client 内新增领域规则。
  3. procedure / reducer shape 稳定后再接 typed facade。
  4. 错误映射继续使用 SpacetimeClientError helper。
  5. mapper 测试或 facade 定向测试随新增场景补齐。

2.1 module_bindings 生成物约束

src/module_bindings 目录下的 Rust 文件统一视为 SpacetimeDB CLI 生成产物,后续维护必须遵守:

  1. 只允许通过仓库根目录 npm run spacetime:generate -- --rust-only 刷新,不允许手工修改。
  2. 不生成私有表绑定,不追加 --include-private;如后端需要读取私有表,应先在 api-server 或模块层补明确 contract而不是让客户端 crate 直接依赖私有表结构。
  3. 不允许手工对该目录执行散装 rustfmt;若 SpacetimeDB CLI 已生成文件但自身 formatter 在 Windows 下失败,只能由 scripts/generate-spacetime-bindings.mjs 在短临时目录中分批 rustfmt 后同步。
  4. src/lib.rs 已通过 #[rustfmt::skip] pub mod module_bindings; 显式阻止 workspace 级 cargo fmt 继续递归格式化该目录。
  5. Windows 下 SpacetimeDB CLI 2.1.0 的生成后 formatter 可能因为一次性传入过多 Rust 文件路径而失败;仓库脚本会先输出到短临时目录,必要时接管分批格式化,再同步回本目录。

2.1.1 绑定缺文件恢复流程

mod.rs 已声明 *_table 模块,但目录内缺少对应 *_table.rs 文件,说明 Rust bindings 刷新不完整。不要手工补 generated code统一在仓库根目录执行

npm.cmd run spacetime:generate -- --rust-only

脚本内部会使用 --no-config:仓库根目录的 spacetime.json 同时配置了 TypeScript 与 Rust 两个生成目标,直接追加 --lang / --out-dir 会触发 SpacetimeDB CLI 的多目标参数冲突。

生成后用以下命令确认 mod.rs 声明的模块都有落盘文件:

$modFile = 'server-rs\crates\spacetime-client\src\module_bindings\mod.rs'
$dir = 'server-rs\crates\spacetime-client\src\module_bindings'
$mods = Select-String -Path $modFile -Pattern '^pub mod ([a-zA-Z0-9_]+);' |
  ForEach-Object { $_.Matches[0].Groups[1].Value }
$missing = @()
foreach ($m in $mods) {
  if (-not (Test-Path (Join-Path $dir ($m + '.rs')))) {
    $missing += $m
  }
}
if ($missing.Count -eq 0) { 'missing module files: 0' } else { $missing }

最后至少执行:

cargo check -p spacetime-client --manifest-path server-rs\Cargo.toml

3. 边界约束

  1. spacetime-client 只承接 SpacetimeDB 客户端访问适配,不承接具体业务模块的规则实现。
  2. 业务状态真相仍由 apps/spacetime-module 管理,业务编排由各模块 package 与 apps/api-server 承担。
  3. 不允许把 reducer、view、订阅调用细节重新散落到多个业务模块里各自实现。
  4. 新增 facade 必须等待对应 spacetime-module facade 稳定后再接,不提前假设 row shape。
  5. src/module_bindings/** 是生成产物,只能通过 SpacetimeDB CLI 生成流程刷新。