推进 SpacetimeDB adapter 与 client 收口
This commit is contained in:
@@ -166,7 +166,7 @@ LLM、OSS、SMS、微信等外部副作用可以独立准备,不等待 `WP-SC`
|
|||||||
| WP-RT Runtime/Profile/Save | G1 后 | `module-runtime`、`spacetime-module/src/runtime/*`、runtime/save/profile API | RPG story 规则 | runtime setting、snapshot、wallet、played world、save archive 领域化 | `cargo test -p module-runtime`,runtime API 测试 |
|
| WP-RT Runtime/Profile/Save | G1 后 | `module-runtime`、`spacetime-module/src/runtime/*`、runtime/save/profile API | RPG story 规则 | runtime setting、snapshot、wallet、played world、save archive 领域化 | `cargo test -p module-runtime`,runtime API 测试 |
|
||||||
| WP-RPG Gameplay 域 | G1 后 | `module-combat`、`module-inventory`、`module-npc`、`module-progression`、`module-quest`、`module-runtime-item`、`module-story` | 创作域 | 战斗、背包、NPC、成长、任务、宝箱、story session 纯规则与跨域事件 | 各 module 测试;跨域应用结果测试 |
|
| WP-RPG Gameplay 域 | G1 后 | `module-combat`、`module-inventory`、`module-npc`、`module-progression`、`module-quest`、`module-runtime-item`、`module-story` | 创作域 | 战斗、背包、NPC、成长、任务、宝箱、story session 纯规则与跨域事件 | 各 module 测试;跨域应用结果测试 |
|
||||||
| WP-RS Runtime Story 去兼容层 | G1 后 | `module-runtime-story`、`api-server/src/runtime_story/*`、`src/hooks/rpg-runtime-story/*` | 非 RPG 创作域 | 先将历史 `module-runtime-story-compat` 迁为新主链 crate,再删除 HTTP compat 层、接 session scoped 新接口、前端匹配新接口 | `cargo test -p module-runtime-story`,runtime story/API/前端定向测试 |
|
| WP-RS Runtime Story 去兼容层 | G1 后 | `module-runtime-story`、`api-server/src/runtime_story/*`、`src/hooks/rpg-runtime-story/*` | 非 RPG 创作域 | 先将历史 `module-runtime-story-compat` 迁为新主链 crate,再删除 HTTP compat 层、接 session scoped 新接口、前端匹配新接口 | `cargo test -p module-runtime-story`,runtime story/API/前端定向测试 |
|
||||||
| WP-ST SpacetimeDB Adapter | 领域任务输出稳定后 | `spacetime-module/src/**`、`migration.rs`、表目录 | `api-server` 业务逻辑 | table/reducer/procedure/mapper/queries 按上下文接入领域函数;必要 event/projection table;`lib.rs/migration.rs/表目录` 单 owner 合流 | `cargo check -p spacetime-module`,需要时 `spacetime build/generate` |
|
| WP-ST SpacetimeDB Adapter | 领域任务输出稳定后 | `spacetime-module/src/**`、`migration.rs`、表目录 | `api-server` 业务逻辑 | table/reducer/procedure/mapper/queries 按上下文接入领域函数;必要 event/projection table;`lib.rs/migration.rs/表目录` 单 owner 合流;已完成 AI task event、Big Fish readiness event、Asset row mapper、Puzzle publish event | `cargo check -p spacetime-module`,需要时 `spacetime build/generate` |
|
||||||
| WP-SC Spacetime Client | 对应 WP-ST facade 稳定后 | `spacetime-client/src/**`、绑定 mapper | 领域规则、未稳定 facade 的预判接线 | typed facade、错误映射、row snapshot mapper | `cargo check -p spacetime-client` |
|
| WP-SC Spacetime Client | 对应 WP-ST facade 稳定后 | `spacetime-client/src/**`、绑定 mapper | 领域规则、未稳定 facade 的预判接线 | typed facade、错误映射、row snapshot mapper | `cargo check -p spacetime-client` |
|
||||||
| WP-PF platform side effects | G1 后可独立准备;接入 API 前与 WP-API 对齐错误模型 | `platform-*`、`api-server` platform 接线 | 领域状态机 | LLM、OSS、SMS、微信等副作用统一 adapter | platform crate 测试或 API smoke |
|
| WP-PF platform side effects | G1 后可独立准备;接入 API 前与 WP-API 对齐错误模型 | `platform-*`、`api-server` platform 接线 | 领域状态机 | LLM、OSS、SMS、微信等副作用统一 adapter | platform crate 测试或 API smoke |
|
||||||
| WP-API api-server BFF | WP-SC facade 和 WP-PF 接口稳定后 | `api-server/src/**`,其中 `app.rs` 单 owner | SpacetimeDB table 定义、领域主规则、绕过 spacetime-client 的直连实现 | 路由、鉴权、SSE、请求响应映射、平台编排收口 | `cargo test -p api-server`,`cargo check -p api-server` |
|
| WP-API api-server BFF | WP-SC facade 和 WP-PF 接口稳定后 | `api-server/src/**`,其中 `app.rs` 单 owner | SpacetimeDB table 定义、领域主规则、绕过 spacetime-client 的直连实现 | 路由、鉴权、SSE、请求响应映射、平台编排收口 | `cargo test -p api-server`,`cargo check -p api-server` |
|
||||||
@@ -755,6 +755,44 @@ npm.cmd run check:encoding -- docs/technical/SERVER_RS_DDD_PARALLEL_TASKLIST_202
|
|||||||
1. `runtime`、`puzzle`、`custom_world` facade 仍有较多重复 SDK 错误映射,可继续按同一方式机械收口。
|
1. `runtime`、`puzzle`、`custom_world` facade 仍有较多重复 SDK 错误映射,可继续按同一方式机械收口。
|
||||||
2. mapper 中仍有部分历史 `Procedure(...)` 构造和旧兼容 JSON 容错逻辑,后续应结合对应工作包逐步替换,避免一次大改影响面过宽。
|
2. mapper 中仍有部分历史 `Procedure(...)` 构造和旧兼容 JSON 容错逻辑,后续应结合对应工作包逐步替换,避免一次大改影响面过宽。
|
||||||
|
|
||||||
|
### 2026-04-29 WP-SC 错误映射第三批收口
|
||||||
|
|
||||||
|
已完成:
|
||||||
|
|
||||||
|
1. 继续把剩余大块 facade 中的 SDK 调用错误统一收口为 `SpacetimeClientError::from_sdk_error`。
|
||||||
|
2. 本批覆盖:
|
||||||
|
- `runtime`
|
||||||
|
- `puzzle`
|
||||||
|
- `custom_world`
|
||||||
|
3. 本批只替换重复 SDK 错误映射,不改变 procedure 名称、输入构造、返回 mapper 或调用顺序。
|
||||||
|
4. 发现 PowerShell 写回 Rust 文件会给首行插入 UTF-8 BOM 后,已用局部补丁清理,避免破坏编码约束。
|
||||||
|
|
||||||
|
当前 `spacetime-client/src/*.rs` facade 中已不再保留重复的 `.map_err(|error| SpacetimeClientError::Procedure(error.to_string()))` 模式。
|
||||||
|
|
||||||
|
待继续:
|
||||||
|
|
||||||
|
1. mapper 中仍有部分历史 `Procedure(...)` 构造,可按领域继续渐进收口。
|
||||||
|
2. 后续新增 `WP-ST` facade 后,需要继续补 typed facade 与 row snapshot mapper。
|
||||||
|
|
||||||
|
### 2026-04-29 WP-SC mapper 错误映射收尾
|
||||||
|
|
||||||
|
已完成:
|
||||||
|
|
||||||
|
1. 继续收口 `spacetime-client/src/mapper.rs` 中稳定 procedure result 的重复错误构造。
|
||||||
|
2. 将 runtime settings、profile dashboard、wallet ledger、recharge、referral、reward、redeem code、play stats、runtime snapshot、save archive 的 `ok=false` 与缺快照分支统一到:
|
||||||
|
- `SpacetimeClientError::procedure_failed`
|
||||||
|
- `SpacetimeClientError::missing_snapshot`
|
||||||
|
3. 将 custom world、puzzle 既有稳定 result mapper 的 procedure 失败与缺返回数据分支统一到同一 helper。
|
||||||
|
4. 修复 auth store snapshot import mapper 中两处历史乱码错误文案,恢复为明确中文语义:`认证快照导入结果`。
|
||||||
|
5. 保留 `custom_world_profile 不存在` 这类领域语义错误,不强行改成缺快照错误。
|
||||||
|
|
||||||
|
当前结论:
|
||||||
|
|
||||||
|
1. `spacetime-client/src/*.rs` facade 中已不再保留重复的 `.map_err(|error| SpacetimeClientError::Procedure(error.to_string()))` 模式。
|
||||||
|
2. `spacetime-client/src/mapper.rs` 中仅保留需要领域语义表达的 `Procedure(...)` 构造。
|
||||||
|
3. 本次未修改 `spacetime-module`、`migration.rs`、生成绑定、`api-server` 路由或前端。
|
||||||
|
4. `WP-SC` 当前基础设施收口已完成;后续只在 `WP-ST` 新 facade 或 row shape 稳定后,按领域补 typed facade 与 row snapshot mapper。
|
||||||
|
|
||||||
### 2026-04-29 WP-ST AI Task 事件 Adapter 切片
|
### 2026-04-29 WP-ST AI Task 事件 Adapter 切片
|
||||||
|
|
||||||
已完成:
|
已完成:
|
||||||
@@ -851,6 +889,22 @@ npm.cmd run check:encoding -- docs/technical/SERVER_RS_DDD_PARALLEL_TASKLIST_202
|
|||||||
|
|
||||||
结果:通过。`cargo check -p api-server` 仍有既有 `api-server/src/prompt/rpg/runtime_chat.rs` 未使用 prompt helper warning,非本次新增。
|
结果:通过。`cargo check -p api-server` 仍有既有 `api-server/src/prompt/rpg/runtime_chat.rs` 未使用 prompt helper warning,非本次新增。
|
||||||
|
|
||||||
|
后端启动:
|
||||||
|
|
||||||
|
```powershell
|
||||||
|
npm.cmd run api-server:maincloud
|
||||||
|
```
|
||||||
|
|
||||||
|
结果:已执行。命令在 90 秒观察窗口内超时,因为 `cargo run` 前台常驻且本轮编译较慢;继续等待后确认 `127.0.0.1:3100` 已由本仓库 `server-rs/target/debug/api-server.exe` 监听。`GET /healthz` 返回 `200`,`GET /api/story/battles/battle_001` 未登录返回 `401`,`GET /api/story/sessions/storysess_001/runtime-projection` 未登录返回 `401`。
|
||||||
|
|
||||||
|
后端启动:
|
||||||
|
|
||||||
|
```powershell
|
||||||
|
npm.cmd run api-server:maincloud
|
||||||
|
```
|
||||||
|
|
||||||
|
结果:命令在 60 秒观察窗口内超时。随后探测 `http://127.0.0.1:3100/healthz` 未连通;进程检查发现存在两组遗留的 `npm run api-server:maincloud -> scripts/api-server-maincloud.mjs -> cargo run -p api-server` 链路,同时还有并行 `module-assets` 测试和 `spacetime-module` 检查在运行。该结果不是本次 WP-API route 编译错误,需清理本次遗留 api-server 启动链后再做一次干净启动。
|
||||||
|
|
||||||
### 2026-04-29 WP-API runtime projection 接线
|
### 2026-04-29 WP-API runtime projection 接线
|
||||||
|
|
||||||
已完成:
|
已完成:
|
||||||
@@ -888,6 +942,30 @@ npm.cmd run api-server:maincloud
|
|||||||
|
|
||||||
结果:命令在 90 秒观察窗口内超时,因为 `cargo run` 前台常驻;随后确认 `127.0.0.1:3100` 已由本仓库 `server-rs/target/debug/api-server.exe` 监听。`GET /healthz` 返回 `200`,`GET /api/story/sessions/storysess_001/runtime-projection` 未登录返回 `401`,无效 bearer token 返回 `401`。
|
结果:命令在 90 秒观察窗口内超时,因为 `cargo run` 前台常驻;随后确认 `127.0.0.1:3100` 已由本仓库 `server-rs/target/debug/api-server.exe` 监听。`GET /healthz` 返回 `200`,`GET /api/story/sessions/storysess_001/runtime-projection` 未登录返回 `401`,无效 bearer token 返回 `401`。
|
||||||
|
|
||||||
|
### 2026-04-29 WP-API story battle typed DTO 收口
|
||||||
|
|
||||||
|
已完成:
|
||||||
|
|
||||||
|
1. 将 story battle / NPC battle 的请求与响应 DTO 收口到 `shared-contracts/src/story.rs`。
|
||||||
|
2. `api-server/src/story_battles.rs` 不再定义本地临时 request struct,也不再用 `json!` 手拼成功响应。
|
||||||
|
3. API 层仍只负责鉴权、request context、请求解析、`spacetime-client` facade 调用、typed DTO 映射和错误 envelope。
|
||||||
|
4. 保持 battle mode、NPC battle function id、reward item 基础格式校验在 BFF 入参边界;战斗结算规则仍由 `module-combat` 与 SpacetimeDB facade 承担。
|
||||||
|
5. 新增 `story_battle_responses_use_story_contract_shape` 共享契约序列化回归测试。
|
||||||
|
6. 本次未修改 SpacetimeDB 表结构,未触碰 `migration.rs`。
|
||||||
|
|
||||||
|
验证:
|
||||||
|
|
||||||
|
```powershell
|
||||||
|
cargo test -p api-server story_battle --manifest-path server-rs/Cargo.toml
|
||||||
|
cargo test -p shared-contracts story_battle_responses_use_story_contract_shape --manifest-path server-rs/Cargo.toml
|
||||||
|
cargo fmt -p api-server -p shared-contracts --manifest-path server-rs/Cargo.toml --check
|
||||||
|
cargo check -p api-server --manifest-path server-rs/Cargo.toml
|
||||||
|
npm.cmd run check:server-rs-ddd
|
||||||
|
npm.cmd run check:encoding -- server-rs/crates/shared-contracts/src/story.rs server-rs/crates/api-server/src/story_battles.rs docs/technical/SERVER_RS_DDD_PARALLEL_TASKLIST_2026-04-29.md
|
||||||
|
```
|
||||||
|
|
||||||
|
结果:通过。`cargo check -p api-server` 仍有既有 `api-server/src/prompt/rpg/runtime_chat.rs` 未使用 prompt helper warning,非本次新增。
|
||||||
|
|
||||||
后端启动:
|
后端启动:
|
||||||
|
|
||||||
```powershell
|
```powershell
|
||||||
@@ -896,6 +974,40 @@ npm.cmd run api-server:maincloud
|
|||||||
|
|
||||||
结果:编译通过,仅有既有 prompt helper warning;运行阶段因 `127.0.0.1:3100` 端口已被既有 `api-server` 进程占用而退出,错误为 `AddrInUse / 10048`。随后探测 `http://127.0.0.1:3100/healthz` 返回 `200`,确认本地已有服务在线。
|
结果:编译通过,仅有既有 prompt helper warning;运行阶段因 `127.0.0.1:3100` 端口已被既有 `api-server` 进程占用而退出,错误为 `AddrInUse / 10048`。随后探测 `http://127.0.0.1:3100/healthz` 返回 `200`,确认本地已有服务在线。
|
||||||
|
|
||||||
|
### 2026-04-29 WP-API story runtime projection route 接线
|
||||||
|
|
||||||
|
已完成:
|
||||||
|
|
||||||
|
1. 确认 `api-server` 已挂载新主链 route:
|
||||||
|
- `GET /api/story/sessions/{story_session_id}/runtime-projection`
|
||||||
|
2. `story_sessions::get_story_runtime_projection` 只执行 BFF 编排:
|
||||||
|
- 从鉴权 token 取得 `actor_user_id`。
|
||||||
|
- 调用 `spacetime_client.get_story_runtime_projection_source(story_session_id, actor_user_id)`。
|
||||||
|
- 调用 `module_runtime_story::build_story_runtime_projection(source)` 输出 `StoryRuntimeProjectionResponse`。
|
||||||
|
3. route 不恢复 `/api/runtime/story/*`,不绕过 `spacetime-client` 访问 SpacetimeDB,不在 API 层复制领域投影规则。
|
||||||
|
4. 新增/确认 API 测试:
|
||||||
|
- `get_story_runtime_projection_requires_authentication`
|
||||||
|
- `get_story_runtime_projection_returns_bad_gateway_when_spacetime_not_published`
|
||||||
|
- `runtime_story_legacy_routes_are_not_mounted`
|
||||||
|
5. 本次未修改 SpacetimeDB 表结构,未触碰 `migration.rs`。
|
||||||
|
|
||||||
|
后续接线边界:
|
||||||
|
|
||||||
|
1. `WP-FE-S` 可在后端 route 稳定后迁移 `src/services/rpg-runtime/rpgRuntimeStoryClient.ts` 到 `/api/story/sessions/{storySessionId}/runtime-projection`。
|
||||||
|
2. `WP-FE-H` 与 `WP-FE-C` 继续等待 service client 完成后再动 hooks/components。
|
||||||
|
3. `WP-DEL` 仍需等前端迁移完成后,统一删除旧 `runtime_story` contract、旧前端 client/helper 和旧 prompt helper。
|
||||||
|
|
||||||
|
验证:
|
||||||
|
|
||||||
|
```powershell
|
||||||
|
cargo test -p api-server get_story_runtime_projection --manifest-path server-rs/Cargo.toml
|
||||||
|
cargo test -p api-server runtime_story_legacy_routes_are_not_mounted --manifest-path server-rs/Cargo.toml
|
||||||
|
cargo check -p api-server --manifest-path server-rs/Cargo.toml
|
||||||
|
npm.cmd run check:server-rs-ddd
|
||||||
|
```
|
||||||
|
|
||||||
|
结果:通过。`cargo check -p api-server` 仍有既有 `api-server/src/prompt/rpg/runtime_chat.rs` 未使用 prompt helper warning,非本次新增。
|
||||||
|
|
||||||
后端启动:
|
后端启动:
|
||||||
|
|
||||||
```powershell
|
```powershell
|
||||||
@@ -989,6 +1101,82 @@ spacetime build --project-path server-rs/crates/spacetime-module
|
|||||||
|
|
||||||
原因:当前环境未找到 `spacetime` CLI,可执行文件不在 PATH 中。
|
原因:当前环境未找到 `spacetime` CLI,可执行文件不在 PATH 中。
|
||||||
|
|
||||||
|
### 2026-04-29 WP-ST SpacetimeDB 根入口 warning 收口
|
||||||
|
|
||||||
|
已完成:
|
||||||
|
|
||||||
|
1. 新增 `SERVER_RS_DDD_WP_ST_ROOT_REEXPORT_WARNING_CLEANUP_2026-04-29.md`,记录本次根入口治理。
|
||||||
|
2. 在 `spacetime-module/src/lib.rs` 顶部补充中文注释,说明根模块继续 re-export 各领域类型是为了 SpacetimeDB 绑定生成。
|
||||||
|
3. 局部允许 `ambiguous_glob_reexports`,收口多个领域包同名 normalize helper 带来的持续 warning。
|
||||||
|
4. 本次不改变任何 table、reducer、procedure、migration 或前端绑定 shape。
|
||||||
|
|
||||||
|
验证:
|
||||||
|
|
||||||
|
```powershell
|
||||||
|
cargo check -p spacetime-module --manifest-path server-rs/Cargo.toml
|
||||||
|
npm.cmd run check:server-rs-ddd
|
||||||
|
npm.cmd run check:encoding -- server-rs/crates/spacetime-module/src/lib.rs
|
||||||
|
```
|
||||||
|
|
||||||
|
结果:通过,`spacetime-module` 编译不再输出 `ambiguous glob re-exports` warning。
|
||||||
|
|
||||||
|
### 2026-04-29 WP-ST Puzzle 发布事件 Adapter 切片
|
||||||
|
|
||||||
|
已完成:
|
||||||
|
|
||||||
|
1. 新增 `SERVER_RS_DDD_WP_ST_PUZZLE_EVENT_ADAPTER_2026-04-29.md`,记录本次 Puzzle event table 接入边界。
|
||||||
|
2. 在 `spacetime-module/src/puzzle.rs` 新增 `puzzle_event` public event table。
|
||||||
|
3. `puzzle_event` 当前承接 `WorkPublished`,用于订阅端、BFF 或审计流程感知拼图作品发布成功事实。
|
||||||
|
4. `publish_puzzle_work_tx` 在成功写入 `puzzle_work_profile` 并更新 `puzzle_agent_session` 后写入事件。
|
||||||
|
5. 已同步 `migration.rs` 迁移白名单,加入 `puzzle_event`,并补齐既有 `puzzle_leaderboard_entry`。
|
||||||
|
6. 已同步 `SPACETIMEDB_TABLE_CATALOG.md` 的 Puzzle 表目录和查询说明。
|
||||||
|
|
||||||
|
边界说明:
|
||||||
|
|
||||||
|
1. `puzzle_event` 不是作品真相表,正式作品状态仍以 `puzzle_work_profile` 和 `puzzle_agent_session` 为准。
|
||||||
|
2. `puzzle_leaderboard_entry` 本次只补迁移白名单和文档账本,不改变成绩规则。
|
||||||
|
3. 本次未修改 `api-server`、`spacetime-client`、前端 services/hooks/components。
|
||||||
|
|
||||||
|
验证:
|
||||||
|
|
||||||
|
```powershell
|
||||||
|
cargo check -p spacetime-module --manifest-path server-rs/Cargo.toml
|
||||||
|
cargo test -p module-puzzle --manifest-path server-rs/Cargo.toml
|
||||||
|
npm.cmd run check:server-rs-ddd
|
||||||
|
npm.cmd run check:encoding -- server-rs/crates/spacetime-module/src/puzzle.rs server-rs/crates/spacetime-module/src/migration.rs docs/technical/SPACETIMEDB_TABLE_CATALOG.md docs/technical/SERVER_RS_DDD_PARALLEL_TASKLIST_2026-04-29.md docs/technical/SERVER_RS_DDD_WP_ST_PUZZLE_EVENT_ADAPTER_2026-04-29.md
|
||||||
|
```
|
||||||
|
|
||||||
|
结果:通过。`cargo test -p module-puzzle` 共 13 个测试通过。
|
||||||
|
|
||||||
|
### 2026-04-29 WP-ST Asset Row Mapper Adapter 切片
|
||||||
|
|
||||||
|
已完成:
|
||||||
|
|
||||||
|
1. 新增 `SERVER_RS_DDD_WP_ST_ASSET_ROW_MAPPER_ADAPTER_2026-04-29.md`,记录本次资产 Adapter 收口范围。
|
||||||
|
2. `upsert_asset_object` 改为先构造 `AssetObjectUpsertSnapshot`,再通过 `build_asset_object_row` 落 SpacetimeDB row。
|
||||||
|
3. `upsert_asset_entity_binding` 改为先构造 `AssetEntityBindingSnapshot`,再通过 `build_asset_entity_binding_row` 落 SpacetimeDB row。
|
||||||
|
4. 本次不改变资产表结构、不改 reducer / procedure 签名、不改 `migration.rs`。
|
||||||
|
5. 本次未修改 `api-server`、`spacetime-client`、前端 services/hooks/components。
|
||||||
|
|
||||||
|
验证:
|
||||||
|
|
||||||
|
```powershell
|
||||||
|
cargo check -p spacetime-module --manifest-path server-rs/Cargo.toml
|
||||||
|
cargo test -p module-assets --manifest-path server-rs/Cargo.toml
|
||||||
|
npm.cmd run check:server-rs-ddd
|
||||||
|
npm.cmd run check:encoding -- docs/technical/SERVER_RS_DDD_WP_ST_ASSET_ROW_MAPPER_ADAPTER_2026-04-29.md server-rs/crates/spacetime-module/src/asset_metadata/objects.rs server-rs/crates/spacetime-module/src/asset_metadata/bindings.rs
|
||||||
|
```
|
||||||
|
|
||||||
|
结果:通过。`cargo test -p module-assets` 共 8 个测试通过。
|
||||||
|
|
||||||
|
后端启动:
|
||||||
|
|
||||||
|
```powershell
|
||||||
|
npm.cmd run api-server:maincloud
|
||||||
|
```
|
||||||
|
|
||||||
|
结果:命令在 60 秒观察窗口内超时,但随后探测 `http://127.0.0.1:3100/healthz` 返回 `200`,本地存在 `api-server` 运行进程。本切片未触发新的 Rust 编译错误。
|
||||||
|
|
||||||
### 2026-04-29 WP-RS 领域投影 builder 切片
|
### 2026-04-29 WP-RS 领域投影 builder 切片
|
||||||
|
|
||||||
已完成:
|
已完成:
|
||||||
|
|||||||
@@ -52,7 +52,18 @@
|
|||||||
3. 前端迁移必须等待 `WP-API` route 和 DTO 稳定后,再按 `services -> hooks -> components` 接入。
|
3. 前端迁移必须等待 `WP-API` route 和 DTO 稳定后,再按 `services -> hooks -> components` 接入。
|
||||||
4. 若后续改变 table / reducer / procedure,必须由 `WP-ST` 同步表目录和必要的绑定生成记录。
|
4. 若后续改变 table / reducer / procedure,必须由 `WP-ST` 同步表目录和必要的绑定生成记录。
|
||||||
|
|
||||||
## 6. 验收
|
## 6. 本次完成范围
|
||||||
|
|
||||||
|
1. `SpacetimeClientError` 已新增并接入统一 helper:
|
||||||
|
- `from_sdk_error`
|
||||||
|
- `procedure_failed`
|
||||||
|
- `missing_snapshot`
|
||||||
|
2. 已覆盖现有稳定 facade 的 SDK 错误映射,包含 AI、Big Fish、assets、auth、story、combat、inventory、npc、runtime、puzzle、custom world。
|
||||||
|
3. `mapper.rs` 中稳定 procedure result 的重复 `ok=false` 默认错误和缺快照错误已收口到统一 helper。
|
||||||
|
4. auth store snapshot import mapper 中历史乱码错误文案已恢复为中文语义。
|
||||||
|
5. 领域语义错误继续保留原样,例如 `custom_world_profile 不存在`,避免把业务不存在误归类为缺快照。
|
||||||
|
|
||||||
|
## 7. 验收
|
||||||
|
|
||||||
必须执行:
|
必须执行:
|
||||||
|
|
||||||
|
|||||||
@@ -0,0 +1,51 @@
|
|||||||
|
# server-rs DDD WP-ST Asset Row Mapper Adapter 落地记录(2026-04-29)
|
||||||
|
|
||||||
|
## 1. 背景
|
||||||
|
|
||||||
|
`module-assets` 已提供资产对象和实体绑定的领域 snapshot / record 构建能力。`spacetime-module` 的资产 Adapter 之前在 upsert 过程中直接重复拼装 SpacetimeDB row 与返回 snapshot,字段规则分散在 Adapter 内。
|
||||||
|
|
||||||
|
本次不改变资产表结构,不改变 reducer / procedure 签名,只把 row 构造收口到更明确的 snapshot -> row mapper。
|
||||||
|
|
||||||
|
## 2. 本次范围
|
||||||
|
|
||||||
|
允许修改:
|
||||||
|
|
||||||
|
1. `server-rs/crates/spacetime-module/src/asset_metadata/objects.rs`
|
||||||
|
2. `server-rs/crates/spacetime-module/src/asset_metadata/bindings.rs`
|
||||||
|
3. 本文档
|
||||||
|
4. 全局任务清单进度记录
|
||||||
|
|
||||||
|
禁止修改:
|
||||||
|
|
||||||
|
1. `server-rs/crates/spacetime-module/src/migration.rs`
|
||||||
|
2. `docs/technical/SPACETIMEDB_TABLE_CATALOG.md`
|
||||||
|
3. `server-rs/crates/api-server/src/**`
|
||||||
|
4. `server-rs/crates/spacetime-client/src/**`
|
||||||
|
5. 前端 services/hooks/components
|
||||||
|
|
||||||
|
## 3. 设计
|
||||||
|
|
||||||
|
本次新增两个 Adapter 内部 mapper:
|
||||||
|
|
||||||
|
1. `build_asset_object_row(&AssetObjectUpsertSnapshot) -> AssetObject`
|
||||||
|
2. `build_asset_entity_binding_row(&AssetEntityBindingSnapshot) -> AssetEntityBinding`
|
||||||
|
|
||||||
|
`upsert_asset_object` 和 `upsert_asset_entity_binding` 先构造领域 snapshot,再由 mapper 落 SpacetimeDB row。这样后续继续迁移到 `module-assets` 应用服务时,Adapter 的职责会更清楚:只做 row 查询、幂等定位、snapshot 持久化和 procedure result 返回。
|
||||||
|
|
||||||
|
## 4. 边界说明
|
||||||
|
|
||||||
|
1. 本次不新增、删除或修改 SpacetimeDB table 字段。
|
||||||
|
2. 本次不改 `migration.rs`。
|
||||||
|
3. 本次不改 `spacetime-client` 绑定和 facade。
|
||||||
|
4. 本次不改 HTTP/BFF 和前端。
|
||||||
|
|
||||||
|
## 5. 验收命令
|
||||||
|
|
||||||
|
```powershell
|
||||||
|
cargo check -p spacetime-module --manifest-path server-rs/Cargo.toml
|
||||||
|
cargo test -p module-assets --manifest-path server-rs/Cargo.toml
|
||||||
|
npm.cmd run check:server-rs-ddd
|
||||||
|
npm.cmd run check:encoding -- docs/technical/SERVER_RS_DDD_WP_ST_ASSET_ROW_MAPPER_ADAPTER_2026-04-29.md server-rs/crates/spacetime-module/src/asset_metadata/objects.rs server-rs/crates/spacetime-module/src/asset_metadata/bindings.rs
|
||||||
|
```
|
||||||
|
|
||||||
|
结果:通过。
|
||||||
@@ -0,0 +1,30 @@
|
|||||||
|
# WP-ST 拼图发布事件 Adapter 落地说明
|
||||||
|
|
||||||
|
## 背景
|
||||||
|
|
||||||
|
`module-puzzle` 已经承载拼图作品创建、发布、运行和成绩规则,`spacetime-module/src/puzzle.rs` 负责把领域对象映射为 SpacetimeDB table/procedure。当前发布成功事实只体现在 `puzzle_work_profile` 和 `puzzle_agent_session` 的最终行状态中,订阅端若要捕获一次性发布动作,需要轮询或自行对比快照。
|
||||||
|
|
||||||
|
本次切片属于 `WP-ST SpacetimeDB Adapter`,只新增 SpacetimeDB 事件投影,不新增业务规则,也不兼容旧 Node/PostgreSQL 路径。
|
||||||
|
|
||||||
|
## 落地范围
|
||||||
|
|
||||||
|
1. 新增 `puzzle_event` public event table。
|
||||||
|
2. 新增 `PuzzleEventKind::WorkPublished`,用于表示作品发布成功。
|
||||||
|
3. 在 `publish_puzzle_work_tx` 完成 `puzzle_work_profile` upsert 和 `puzzle_agent_session` 更新后写入事件。
|
||||||
|
4. 将 `puzzle_event` 纳入 `migration.rs` 迁移白名单。
|
||||||
|
5. 顺手补齐已有 `puzzle_leaderboard_entry` 的迁移白名单和表目录记录,避免 schema 账本遗漏。
|
||||||
|
|
||||||
|
## 边界
|
||||||
|
|
||||||
|
1. `puzzle_event` 只承接跨层订阅和审计所需的轻量事实。
|
||||||
|
2. 正式作品真相仍以 `puzzle_work_profile` 和 `puzzle_agent_session` 为准。
|
||||||
|
3. 排行榜真相仍以 `puzzle_leaderboard_entry` 为准,本次不改成绩规则。
|
||||||
|
4. 前端和 `spacetime-client` 后续如需消费发布事件,应订阅 `puzzle_event`,不要把事件表当作作品列表来源。
|
||||||
|
|
||||||
|
## 验收
|
||||||
|
|
||||||
|
1. `cargo check -p spacetime-module --manifest-path server-rs/Cargo.toml`
|
||||||
|
2. `cargo test -p module-puzzle --manifest-path server-rs/Cargo.toml`
|
||||||
|
3. `npm.cmd run check:server-rs-ddd`
|
||||||
|
4. `npm.cmd run check:encoding -- <本次修改文件>`
|
||||||
|
5. 若本机安装 `spacetime` CLI,再执行 `spacetime build --project-path server-rs/crates/spacetime-module` 和绑定生成。
|
||||||
@@ -0,0 +1,40 @@
|
|||||||
|
# server-rs DDD WP-ST SpacetimeDB 根入口 warning 收口记录(2026-04-29)
|
||||||
|
|
||||||
|
## 1. 背景
|
||||||
|
|
||||||
|
`spacetime-module/src/lib.rs` 需要继续从各 `module-*` re-export 领域类型,供 SpacetimeDB table、reducer、procedure 和绑定生成使用。当前多个领域包仍暴露同名 normalize helper,导致 `cargo check -p spacetime-module` 持续出现 `ambiguous glob re-exports` warning。
|
||||||
|
|
||||||
|
这些同名 helper 只影响 value namespace 的公开导出,不影响 SpacetimeDB 表、输入、输出和枚举类型。
|
||||||
|
|
||||||
|
## 2. 本次范围
|
||||||
|
|
||||||
|
允许修改:
|
||||||
|
|
||||||
|
1. `server-rs/crates/spacetime-module/src/lib.rs`
|
||||||
|
2. 本文档
|
||||||
|
3. 全局任务清单进度记录
|
||||||
|
|
||||||
|
禁止修改:
|
||||||
|
|
||||||
|
1. `module-*` 领域公开 API
|
||||||
|
2. `spacetime-client/src/module_bindings/**`
|
||||||
|
3. `api-server/src/**`
|
||||||
|
4. 前端 services/hooks/components
|
||||||
|
|
||||||
|
## 3. 处理方式
|
||||||
|
|
||||||
|
在 `spacetime-module/src/lib.rs` 顶部增加中文注释,并局部允许 `ambiguous_glob_reexports`:
|
||||||
|
|
||||||
|
1. 保留根模块 re-export,避免影响 SpacetimeDB 绑定生成和既有 adapter 引用。
|
||||||
|
2. 明确 warning 来源是领域 helper 同名,不是 schema 或 reducer 冲突。
|
||||||
|
3. 后续等各领域包进一步缩小公开 API 时,再移除该 lint 允许。
|
||||||
|
|
||||||
|
## 4. 验收
|
||||||
|
|
||||||
|
```powershell
|
||||||
|
cargo check -p spacetime-module --manifest-path server-rs/Cargo.toml
|
||||||
|
npm.cmd run check:server-rs-ddd
|
||||||
|
npm.cmd run check:encoding -- server-rs/crates/spacetime-module/src/lib.rs
|
||||||
|
```
|
||||||
|
|
||||||
|
结果:通过,`spacetime-module` 编译不再输出 `ambiguous glob re-exports` warning。
|
||||||
@@ -26,7 +26,7 @@ spacetime sql <db> "SELECT * FROM custom_world_gallery_entry"
|
|||||||
| 运行时档案 | `runtime_setting`, `runtime_snapshot`, `user_browse_history`, `profile_dashboard_state`, `profile_wallet_ledger`, `profile_redeem_code`, `profile_redeem_code_usage`, `profile_played_world`, `profile_save_archive` |
|
| 运行时档案 | `runtime_setting`, `runtime_snapshot`, `user_browse_history`, `profile_dashboard_state`, `profile_wallet_ledger`, `profile_redeem_code`, `profile_redeem_code_usage`, `profile_played_world`, `profile_save_archive` |
|
||||||
| RPG 运行时 | `story_session`, `story_event`, `npc_state`, `inventory_slot`, `battle_state`, `treasure_record`, `quest_record`, `quest_log`, `player_progression`, `chapter_progression` |
|
| RPG 运行时 | `story_session`, `story_event`, `npc_state`, `inventory_slot`, `battle_state`, `treasure_record`, `quest_record`, `quest_log`, `player_progression`, `chapter_progression` |
|
||||||
| 世界创作 | `custom_world_profile`, `custom_world_session`, `custom_world_agent_session`, `custom_world_agent_message`, `custom_world_agent_operation`, `custom_world_draft_card`, `custom_world_gallery_entry` |
|
| 世界创作 | `custom_world_profile`, `custom_world_session`, `custom_world_agent_session`, `custom_world_agent_message`, `custom_world_agent_operation`, `custom_world_draft_card`, `custom_world_gallery_entry` |
|
||||||
| 拼图 | `puzzle_agent_session`, `puzzle_agent_message`, `puzzle_work_profile`, `puzzle_runtime_run` |
|
| 拼图 | `puzzle_agent_session`, `puzzle_agent_message`, `puzzle_work_profile`, `puzzle_event`, `puzzle_runtime_run`, `puzzle_leaderboard_entry` |
|
||||||
| 大鱼吃小鱼 | `big_fish_creation_session`, `big_fish_agent_message`, `big_fish_asset_slot`, `big_fish_event`, `big_fish_runtime_run` |
|
| 大鱼吃小鱼 | `big_fish_creation_session`, `big_fish_agent_message`, `big_fish_asset_slot`, `big_fish_event`, `big_fish_runtime_run` |
|
||||||
| 资产 | `asset_object`, `asset_entity_binding` |
|
| 资产 | `asset_object`, `asset_entity_binding` |
|
||||||
| AI 任务 | `ai_task`, `ai_task_stage`, `ai_text_chunk`, `ai_result_reference`, `ai_task_event` |
|
| AI 任务 | `ai_task`, `ai_task_stage`, `ai_text_chunk`, `ai_result_reference`, `ai_task_event` |
|
||||||
@@ -419,6 +419,18 @@ SELECT * FROM puzzle_work_profile WHERE owner_user_id = '<user_id>' ORDER BY upd
|
|||||||
SELECT * FROM puzzle_work_profile WHERE publication_status = 'Published';
|
SELECT * FROM puzzle_work_profile WHERE publication_status = 'Published';
|
||||||
```
|
```
|
||||||
|
|
||||||
|
### `puzzle_event`
|
||||||
|
|
||||||
|
- 作用:拼图创作事件表,目前记录作品发布成功事实,供订阅端、BFF 或审计流程感知创作流已产出公开作品;正式作品状态仍以 `puzzle_work_profile` 和 `puzzle_agent_session` 为准。
|
||||||
|
- 可见性:`public event`。
|
||||||
|
- 结构:`event_id PK: String`, `profile_id: String`, `work_id: String`, `session_id: Option<String>`, `owner_user_id: String`, `event_kind: PuzzleEventKind`, `occurred_at: Timestamp`。
|
||||||
|
- 索引:`profile_id`, `owner_user_id`。
|
||||||
|
|
||||||
|
```sql
|
||||||
|
SELECT * FROM puzzle_event WHERE profile_id = '<profile_id>' ORDER BY occurred_at ASC;
|
||||||
|
SELECT * FROM puzzle_event WHERE owner_user_id = '<user_id>' ORDER BY occurred_at DESC;
|
||||||
|
```
|
||||||
|
|
||||||
### `puzzle_runtime_run`
|
### `puzzle_runtime_run`
|
||||||
|
|
||||||
- 作用:拼图游玩运行态,保存当前关卡、网格、已玩 profile 列表、标签和运行快照。
|
- 作用:拼图游玩运行态,保存当前关卡、网格、已玩 profile 列表、标签和运行快照。
|
||||||
@@ -430,6 +442,17 @@ SELECT * FROM puzzle_runtime_run WHERE run_id = '<run_id>';
|
|||||||
SELECT * FROM puzzle_runtime_run WHERE owner_user_id = '<user_id>' ORDER BY updated_at DESC;
|
SELECT * FROM puzzle_runtime_run WHERE owner_user_id = '<user_id>' ORDER BY updated_at DESC;
|
||||||
```
|
```
|
||||||
|
|
||||||
|
### `puzzle_leaderboard_entry`
|
||||||
|
|
||||||
|
- 作用:拼图关卡真实成绩表,按用户、作品和网格规格保留最佳成绩,用于结算弹窗排行榜。
|
||||||
|
- 结构:`entry_id PK: String`, `profile_id: String`, `grid_size: u32`, `user_id: String`, `nickname: String`, `best_elapsed_ms: u64`, `last_run_id: String`, `updated_at: Timestamp`。
|
||||||
|
- 索引:`profile_id + grid_size`, `user_id + profile_id + grid_size`。
|
||||||
|
|
||||||
|
```sql
|
||||||
|
SELECT * FROM puzzle_leaderboard_entry WHERE profile_id = '<profile_id>' AND grid_size = 4 ORDER BY best_elapsed_ms ASC;
|
||||||
|
SELECT * FROM puzzle_leaderboard_entry WHERE user_id = '<user_id>' AND profile_id = '<profile_id>' AND grid_size = 4;
|
||||||
|
```
|
||||||
|
|
||||||
## 大鱼吃小鱼表
|
## 大鱼吃小鱼表
|
||||||
|
|
||||||
### `big_fish_creation_session`
|
### `big_fish_creation_session`
|
||||||
|
|||||||
@@ -8,8 +8,14 @@ use module_combat::{
|
|||||||
BattleMode, BattleStateInput, ResolveCombatActionInput, generate_battle_state_id,
|
BattleMode, BattleStateInput, ResolveCombatActionInput, generate_battle_state_id,
|
||||||
};
|
};
|
||||||
use module_npc::{NPC_FIGHT_FUNCTION_ID, NPC_SPAR_FUNCTION_ID, ResolveNpcInteractionInput};
|
use module_npc::{NPC_FIGHT_FUNCTION_ID, NPC_SPAR_FUNCTION_ID, ResolveNpcInteractionInput};
|
||||||
use serde::Deserialize;
|
|
||||||
use serde_json::{Value, json};
|
use serde_json::{Value, json};
|
||||||
|
use shared_contracts::story::{
|
||||||
|
CreateStoryBattleRequest, CreateStoryNpcBattleRequest, CreateStoryNpcBattleResponse,
|
||||||
|
ResolveStoryBattleRequest, ResolveStoryBattleResponse, StoryBattleRewardItemPayload,
|
||||||
|
StoryBattleRewardItemRequest, StoryBattleStatePayload, StoryBattleStateResponse,
|
||||||
|
StoryCombatActionPayload, StoryNpcInteractionPayload, StoryNpcStanceProfilePayload,
|
||||||
|
StoryNpcStatePayload,
|
||||||
|
};
|
||||||
use shared_kernel::{normalize_optional_string, normalize_required_string, normalize_string_list};
|
use shared_kernel::{normalize_optional_string, normalize_required_string, normalize_string_list};
|
||||||
use spacetime_client::{ResolveNpcBattleInteractionInput, SpacetimeClientError};
|
use spacetime_client::{ResolveNpcBattleInteractionInput, SpacetimeClientError};
|
||||||
|
|
||||||
@@ -18,84 +24,6 @@ use crate::{
|
|||||||
request_context::RequestContext, state::AppState,
|
request_context::RequestContext, state::AppState,
|
||||||
};
|
};
|
||||||
|
|
||||||
#[derive(Debug, Deserialize)]
|
|
||||||
#[serde(rename_all = "camelCase")]
|
|
||||||
pub struct CreateStoryBattleRequest {
|
|
||||||
pub story_session_id: String,
|
|
||||||
pub runtime_session_id: String,
|
|
||||||
#[serde(default)]
|
|
||||||
pub chapter_id: Option<String>,
|
|
||||||
pub target_npc_id: String,
|
|
||||||
pub target_name: String,
|
|
||||||
pub battle_mode: String,
|
|
||||||
pub player_hp: i32,
|
|
||||||
pub player_max_hp: i32,
|
|
||||||
pub player_mana: i32,
|
|
||||||
pub player_max_mana: i32,
|
|
||||||
pub target_hp: i32,
|
|
||||||
pub target_max_hp: i32,
|
|
||||||
#[serde(default)]
|
|
||||||
pub experience_reward: u32,
|
|
||||||
#[serde(default)]
|
|
||||||
pub reward_items: Vec<StoryBattleRewardItemRequest>,
|
|
||||||
}
|
|
||||||
|
|
||||||
#[derive(Debug, Deserialize)]
|
|
||||||
#[serde(rename_all = "camelCase")]
|
|
||||||
pub struct ResolveStoryBattleRequest {
|
|
||||||
pub battle_state_id: String,
|
|
||||||
pub function_id: String,
|
|
||||||
pub action_text: String,
|
|
||||||
pub base_damage: i32,
|
|
||||||
pub mana_cost: i32,
|
|
||||||
pub heal: i32,
|
|
||||||
pub mana_restore: i32,
|
|
||||||
pub counter_multiplier_basis_points: u32,
|
|
||||||
}
|
|
||||||
|
|
||||||
#[derive(Debug, Deserialize)]
|
|
||||||
#[serde(rename_all = "camelCase")]
|
|
||||||
pub struct CreateStoryNpcBattleRequest {
|
|
||||||
pub story_session_id: String,
|
|
||||||
pub runtime_session_id: String,
|
|
||||||
pub npc_id: String,
|
|
||||||
pub npc_name: String,
|
|
||||||
pub interaction_function_id: String,
|
|
||||||
#[serde(default)]
|
|
||||||
pub release_npc_id: Option<String>,
|
|
||||||
#[serde(default)]
|
|
||||||
pub battle_state_id: Option<String>,
|
|
||||||
pub player_hp: i32,
|
|
||||||
pub player_max_hp: i32,
|
|
||||||
pub player_mana: i32,
|
|
||||||
pub player_max_mana: i32,
|
|
||||||
pub target_hp: i32,
|
|
||||||
pub target_max_hp: i32,
|
|
||||||
#[serde(default)]
|
|
||||||
pub experience_reward: u32,
|
|
||||||
#[serde(default)]
|
|
||||||
pub reward_items: Vec<StoryBattleRewardItemRequest>,
|
|
||||||
}
|
|
||||||
|
|
||||||
#[derive(Debug, Deserialize)]
|
|
||||||
#[serde(rename_all = "camelCase")]
|
|
||||||
pub struct StoryBattleRewardItemRequest {
|
|
||||||
pub item_id: String,
|
|
||||||
pub category: String,
|
|
||||||
pub item_name: String,
|
|
||||||
#[serde(default)]
|
|
||||||
pub description: Option<String>,
|
|
||||||
pub quantity: u32,
|
|
||||||
pub rarity: String,
|
|
||||||
#[serde(default)]
|
|
||||||
pub tags: Vec<String>,
|
|
||||||
pub stackable: bool,
|
|
||||||
#[serde(default)]
|
|
||||||
pub stack_key: String,
|
|
||||||
#[serde(default)]
|
|
||||||
pub equipment_slot_id: Option<String>,
|
|
||||||
}
|
|
||||||
|
|
||||||
pub async fn create_story_battle(
|
pub async fn create_story_battle(
|
||||||
State(state): State<AppState>,
|
State(state): State<AppState>,
|
||||||
Extension(request_context): Extension<RequestContext>,
|
Extension(request_context): Extension<RequestContext>,
|
||||||
@@ -152,9 +80,9 @@ pub async fn create_story_battle(
|
|||||||
|
|
||||||
Ok(json_success_body(
|
Ok(json_success_body(
|
||||||
Some(&request_context),
|
Some(&request_context),
|
||||||
json!({
|
StoryBattleStateResponse {
|
||||||
"battleState": build_battle_state_payload(&result),
|
battle_state: build_battle_state_payload(&result),
|
||||||
}),
|
},
|
||||||
))
|
))
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -185,14 +113,14 @@ pub async fn resolve_story_battle(
|
|||||||
|
|
||||||
Ok(json_success_body(
|
Ok(json_success_body(
|
||||||
Some(&request_context),
|
Some(&request_context),
|
||||||
json!({
|
ResolveStoryBattleResponse {
|
||||||
"battleState": build_battle_state_payload(&result.battle_state),
|
battle_state: build_battle_state_payload(&result.battle_state),
|
||||||
"combat": {
|
combat: StoryCombatActionPayload {
|
||||||
"damageDealt": result.damage_dealt,
|
damage_dealt: result.damage_dealt,
|
||||||
"damageTaken": result.damage_taken,
|
damage_taken: result.damage_taken,
|
||||||
"outcome": result.outcome,
|
outcome: result.outcome,
|
||||||
}
|
},
|
||||||
}),
|
},
|
||||||
))
|
))
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -212,9 +140,9 @@ pub async fn get_story_battle_state(
|
|||||||
|
|
||||||
Ok(json_success_body(
|
Ok(json_success_body(
|
||||||
Some(&request_context),
|
Some(&request_context),
|
||||||
json!({
|
StoryBattleStateResponse {
|
||||||
"battleState": build_battle_state_payload(&result),
|
battle_state: build_battle_state_payload(&result),
|
||||||
}),
|
},
|
||||||
))
|
))
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -278,58 +206,69 @@ pub async fn create_story_npc_battle(
|
|||||||
|
|
||||||
Ok(json_success_body(
|
Ok(json_success_body(
|
||||||
Some(&request_context),
|
Some(&request_context),
|
||||||
json!({
|
CreateStoryNpcBattleResponse {
|
||||||
"npcInteraction": build_npc_interaction_payload(&result.npc_interaction),
|
npc_interaction: build_npc_interaction_payload(&result.npc_interaction),
|
||||||
"battleState": build_battle_state_payload(&result.battle_state),
|
battle_state: build_battle_state_payload(&result.battle_state),
|
||||||
}),
|
},
|
||||||
))
|
))
|
||||||
}
|
}
|
||||||
|
|
||||||
fn build_battle_state_payload(record: &spacetime_client::BattleStateRecord) -> Value {
|
fn build_battle_state_payload(
|
||||||
json!({
|
record: &spacetime_client::BattleStateRecord,
|
||||||
"battleStateId": record.battle_state_id,
|
) -> StoryBattleStatePayload {
|
||||||
"storySessionId": record.story_session_id,
|
StoryBattleStatePayload {
|
||||||
"runtimeSessionId": record.runtime_session_id,
|
battle_state_id: record.battle_state_id.clone(),
|
||||||
"actorUserId": record.actor_user_id,
|
story_session_id: record.story_session_id.clone(),
|
||||||
"chapterId": record.chapter_id,
|
runtime_session_id: record.runtime_session_id.clone(),
|
||||||
"targetNpcId": record.target_npc_id,
|
actor_user_id: record.actor_user_id.clone(),
|
||||||
"targetName": record.target_name,
|
chapter_id: record.chapter_id.clone(),
|
||||||
"battleMode": record.battle_mode,
|
target_npc_id: record.target_npc_id.clone(),
|
||||||
"status": record.status,
|
target_name: record.target_name.clone(),
|
||||||
"playerHp": record.player_hp,
|
battle_mode: record.battle_mode.clone(),
|
||||||
"playerMaxHp": record.player_max_hp,
|
status: record.status.clone(),
|
||||||
"playerMana": record.player_mana,
|
player_hp: record.player_hp,
|
||||||
"playerMaxMana": record.player_max_mana,
|
player_max_hp: record.player_max_hp,
|
||||||
"targetHp": record.target_hp,
|
player_mana: record.player_mana,
|
||||||
"targetMaxHp": record.target_max_hp,
|
player_max_mana: record.player_max_mana,
|
||||||
"experienceReward": record.experience_reward,
|
target_hp: record.target_hp,
|
||||||
"rewardItems": record.reward_items.iter().map(|item| {
|
target_max_hp: record.target_max_hp,
|
||||||
json!({
|
experience_reward: record.experience_reward,
|
||||||
"itemId": item.item_id,
|
reward_items: record
|
||||||
"category": item.category,
|
.reward_items
|
||||||
"itemName": item.item_name,
|
.iter()
|
||||||
"description": item.description,
|
.map(build_battle_reward_item_payload)
|
||||||
"quantity": item.quantity,
|
.collect(),
|
||||||
"rarity": format_runtime_item_reward_item_rarity(item.rarity),
|
turn_index: record.turn_index,
|
||||||
"tags": item.tags,
|
last_action_function_id: record.last_action_function_id.clone(),
|
||||||
"stackable": item.stackable,
|
last_action_text: record.last_action_text.clone(),
|
||||||
"stackKey": item.stack_key,
|
last_result_text: record.last_result_text.clone(),
|
||||||
"equipmentSlotId": item
|
last_damage_dealt: record.last_damage_dealt,
|
||||||
.equipment_slot_id
|
last_damage_taken: record.last_damage_taken,
|
||||||
.map(format_runtime_item_equipment_slot),
|
last_outcome: record.last_outcome.clone(),
|
||||||
})
|
version: record.version,
|
||||||
}).collect::<Vec<_>>(),
|
created_at: record.created_at.clone(),
|
||||||
"turnIndex": record.turn_index,
|
updated_at: record.updated_at.clone(),
|
||||||
"lastActionFunctionId": record.last_action_function_id,
|
}
|
||||||
"lastActionText": record.last_action_text,
|
}
|
||||||
"lastResultText": record.last_result_text,
|
|
||||||
"lastDamageDealt": record.last_damage_dealt,
|
fn build_battle_reward_item_payload(
|
||||||
"lastDamageTaken": record.last_damage_taken,
|
item: &module_runtime_item::RuntimeItemRewardItemSnapshot,
|
||||||
"lastOutcome": record.last_outcome,
|
) -> StoryBattleRewardItemPayload {
|
||||||
"version": record.version,
|
StoryBattleRewardItemPayload {
|
||||||
"createdAt": record.created_at,
|
item_id: item.item_id.clone(),
|
||||||
"updatedAt": record.updated_at,
|
category: item.category.clone(),
|
||||||
})
|
item_name: item.item_name.clone(),
|
||||||
|
description: item.description.clone(),
|
||||||
|
quantity: item.quantity,
|
||||||
|
rarity: format_runtime_item_reward_item_rarity(item.rarity).to_string(),
|
||||||
|
tags: item.tags.clone(),
|
||||||
|
stackable: item.stackable,
|
||||||
|
stack_key: item.stack_key.clone(),
|
||||||
|
equipment_slot_id: item
|
||||||
|
.equipment_slot_id
|
||||||
|
.map(format_runtime_item_equipment_slot)
|
||||||
|
.map(ToOwned::to_owned),
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
fn format_runtime_item_reward_item_rarity(
|
fn format_runtime_item_reward_item_rarity(
|
||||||
@@ -354,51 +293,53 @@ fn format_runtime_item_equipment_slot(
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
fn build_npc_state_payload(record: &spacetime_client::NpcStateRecord) -> Value {
|
fn build_npc_state_payload(record: &spacetime_client::NpcStateRecord) -> StoryNpcStatePayload {
|
||||||
json!({
|
StoryNpcStatePayload {
|
||||||
"npcStateId": record.npc_state_id,
|
npc_state_id: record.npc_state_id.clone(),
|
||||||
"runtimeSessionId": record.runtime_session_id,
|
runtime_session_id: record.runtime_session_id.clone(),
|
||||||
"npcId": record.npc_id,
|
npc_id: record.npc_id.clone(),
|
||||||
"npcName": record.npc_name,
|
npc_name: record.npc_name.clone(),
|
||||||
"affinity": record.affinity,
|
affinity: record.affinity,
|
||||||
"relationStance": record.relation_stance,
|
relation_stance: record.relation_stance.clone(),
|
||||||
"helpUsed": record.help_used,
|
help_used: record.help_used,
|
||||||
"chattedCount": record.chatted_count,
|
chatted_count: record.chatted_count,
|
||||||
"giftsGiven": record.gifts_given,
|
gifts_given: record.gifts_given,
|
||||||
"recruited": record.recruited,
|
recruited: record.recruited,
|
||||||
"tradeStockSignature": record.trade_stock_signature,
|
trade_stock_signature: record.trade_stock_signature.clone(),
|
||||||
"revealedFacts": record.revealed_facts,
|
revealed_facts: record.revealed_facts.clone(),
|
||||||
"knownAttributeRumors": record.known_attribute_rumors,
|
known_attribute_rumors: record.known_attribute_rumors.clone(),
|
||||||
"firstMeaningfulContactResolved": record.first_meaningful_contact_resolved,
|
first_meaningful_contact_resolved: record.first_meaningful_contact_resolved,
|
||||||
"seenBackstoryChapterIds": record.seen_backstory_chapter_ids,
|
seen_backstory_chapter_ids: record.seen_backstory_chapter_ids.clone(),
|
||||||
"stanceProfile": {
|
stance_profile: StoryNpcStanceProfilePayload {
|
||||||
"trust": record.trust,
|
trust: record.trust,
|
||||||
"warmth": record.warmth,
|
warmth: record.warmth,
|
||||||
"ideologicalFit": record.ideological_fit,
|
ideological_fit: record.ideological_fit,
|
||||||
"fearOrGuard": record.fear_or_guard,
|
fear_or_guard: record.fear_or_guard,
|
||||||
"loyalty": record.loyalty,
|
loyalty: record.loyalty,
|
||||||
"currentConflictTag": record.current_conflict_tag,
|
current_conflict_tag: record.current_conflict_tag.clone(),
|
||||||
"recentApprovals": record.recent_approvals,
|
recent_approvals: record.recent_approvals.clone(),
|
||||||
"recentDisapprovals": record.recent_disapprovals,
|
recent_disapprovals: record.recent_disapprovals.clone(),
|
||||||
},
|
},
|
||||||
"createdAt": record.created_at,
|
created_at: record.created_at.clone(),
|
||||||
"updatedAt": record.updated_at,
|
updated_at: record.updated_at.clone(),
|
||||||
})
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
fn build_npc_interaction_payload(record: &spacetime_client::NpcInteractionRecord) -> Value {
|
fn build_npc_interaction_payload(
|
||||||
json!({
|
record: &spacetime_client::NpcInteractionRecord,
|
||||||
"npcState": build_npc_state_payload(&record.npc_state),
|
) -> StoryNpcInteractionPayload {
|
||||||
"interactionStatus": record.interaction_status,
|
StoryNpcInteractionPayload {
|
||||||
"actionText": record.action_text,
|
npc_state: build_npc_state_payload(&record.npc_state),
|
||||||
"resultText": record.result_text,
|
interaction_status: record.interaction_status.clone(),
|
||||||
"storyText": record.story_text,
|
action_text: record.action_text.clone(),
|
||||||
"battleMode": record.battle_mode,
|
result_text: record.result_text.clone(),
|
||||||
"encounterClosed": record.encounter_closed,
|
story_text: record.story_text.clone(),
|
||||||
"affinityChanged": record.affinity_changed,
|
battle_mode: record.battle_mode.clone(),
|
||||||
"previousAffinity": record.previous_affinity,
|
encounter_closed: record.encounter_closed,
|
||||||
"nextAffinity": record.next_affinity,
|
affinity_changed: record.affinity_changed,
|
||||||
})
|
previous_affinity: record.previous_affinity,
|
||||||
|
next_affinity: record.next_affinity,
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
fn parse_battle_mode_strict(raw: &str) -> Option<BattleMode> {
|
fn parse_battle_mode_strict(raw: &str) -> Option<BattleMode> {
|
||||||
|
|||||||
@@ -138,6 +138,220 @@ pub struct StoryRuntimeProjectionResponse {
|
|||||||
pub toast: Option<String>,
|
pub toast: Option<String>,
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[derive(Clone, Debug, Serialize, Deserialize, PartialEq, Eq)]
|
||||||
|
#[serde(rename_all = "camelCase")]
|
||||||
|
pub struct StoryBattleRewardItemRequest {
|
||||||
|
pub item_id: String,
|
||||||
|
pub category: String,
|
||||||
|
pub item_name: String,
|
||||||
|
#[serde(default)]
|
||||||
|
pub description: Option<String>,
|
||||||
|
pub quantity: u32,
|
||||||
|
pub rarity: String,
|
||||||
|
#[serde(default)]
|
||||||
|
pub tags: Vec<String>,
|
||||||
|
pub stackable: bool,
|
||||||
|
#[serde(default)]
|
||||||
|
pub stack_key: String,
|
||||||
|
#[serde(default)]
|
||||||
|
pub equipment_slot_id: Option<String>,
|
||||||
|
}
|
||||||
|
|
||||||
|
#[derive(Clone, Debug, Serialize, Deserialize, PartialEq, Eq)]
|
||||||
|
#[serde(rename_all = "camelCase")]
|
||||||
|
pub struct CreateStoryBattleRequest {
|
||||||
|
pub story_session_id: String,
|
||||||
|
pub runtime_session_id: String,
|
||||||
|
#[serde(default)]
|
||||||
|
pub chapter_id: Option<String>,
|
||||||
|
pub target_npc_id: String,
|
||||||
|
pub target_name: String,
|
||||||
|
pub battle_mode: String,
|
||||||
|
pub player_hp: i32,
|
||||||
|
pub player_max_hp: i32,
|
||||||
|
pub player_mana: i32,
|
||||||
|
pub player_max_mana: i32,
|
||||||
|
pub target_hp: i32,
|
||||||
|
pub target_max_hp: i32,
|
||||||
|
#[serde(default)]
|
||||||
|
pub experience_reward: u32,
|
||||||
|
#[serde(default)]
|
||||||
|
pub reward_items: Vec<StoryBattleRewardItemRequest>,
|
||||||
|
}
|
||||||
|
|
||||||
|
#[derive(Clone, Debug, Serialize, Deserialize, PartialEq, Eq)]
|
||||||
|
#[serde(rename_all = "camelCase")]
|
||||||
|
pub struct CreateStoryNpcBattleRequest {
|
||||||
|
pub story_session_id: String,
|
||||||
|
pub runtime_session_id: String,
|
||||||
|
pub npc_id: String,
|
||||||
|
pub npc_name: String,
|
||||||
|
pub interaction_function_id: String,
|
||||||
|
#[serde(default)]
|
||||||
|
pub release_npc_id: Option<String>,
|
||||||
|
#[serde(default)]
|
||||||
|
pub battle_state_id: Option<String>,
|
||||||
|
pub player_hp: i32,
|
||||||
|
pub player_max_hp: i32,
|
||||||
|
pub player_mana: i32,
|
||||||
|
pub player_max_mana: i32,
|
||||||
|
pub target_hp: i32,
|
||||||
|
pub target_max_hp: i32,
|
||||||
|
#[serde(default)]
|
||||||
|
pub experience_reward: u32,
|
||||||
|
#[serde(default)]
|
||||||
|
pub reward_items: Vec<StoryBattleRewardItemRequest>,
|
||||||
|
}
|
||||||
|
|
||||||
|
#[derive(Clone, Debug, Serialize, Deserialize, PartialEq, Eq)]
|
||||||
|
#[serde(rename_all = "camelCase")]
|
||||||
|
pub struct ResolveStoryBattleRequest {
|
||||||
|
pub battle_state_id: String,
|
||||||
|
pub function_id: String,
|
||||||
|
pub action_text: String,
|
||||||
|
pub base_damage: i32,
|
||||||
|
pub mana_cost: i32,
|
||||||
|
pub heal: i32,
|
||||||
|
pub mana_restore: i32,
|
||||||
|
pub counter_multiplier_basis_points: u32,
|
||||||
|
}
|
||||||
|
|
||||||
|
#[derive(Clone, Debug, Serialize, Deserialize, PartialEq)]
|
||||||
|
#[serde(rename_all = "camelCase")]
|
||||||
|
pub struct StoryBattleRewardItemPayload {
|
||||||
|
pub item_id: String,
|
||||||
|
pub category: String,
|
||||||
|
pub item_name: String,
|
||||||
|
#[serde(default, skip_serializing_if = "Option::is_none")]
|
||||||
|
pub description: Option<String>,
|
||||||
|
pub quantity: u32,
|
||||||
|
pub rarity: String,
|
||||||
|
pub tags: Vec<String>,
|
||||||
|
pub stackable: bool,
|
||||||
|
pub stack_key: String,
|
||||||
|
#[serde(default, skip_serializing_if = "Option::is_none")]
|
||||||
|
pub equipment_slot_id: Option<String>,
|
||||||
|
}
|
||||||
|
|
||||||
|
#[derive(Clone, Debug, Serialize, Deserialize, PartialEq)]
|
||||||
|
#[serde(rename_all = "camelCase")]
|
||||||
|
pub struct StoryBattleStatePayload {
|
||||||
|
pub battle_state_id: String,
|
||||||
|
pub story_session_id: String,
|
||||||
|
pub runtime_session_id: String,
|
||||||
|
pub actor_user_id: String,
|
||||||
|
#[serde(default, skip_serializing_if = "Option::is_none")]
|
||||||
|
pub chapter_id: Option<String>,
|
||||||
|
pub target_npc_id: String,
|
||||||
|
pub target_name: String,
|
||||||
|
pub battle_mode: String,
|
||||||
|
pub status: String,
|
||||||
|
pub player_hp: i32,
|
||||||
|
pub player_max_hp: i32,
|
||||||
|
pub player_mana: i32,
|
||||||
|
pub player_max_mana: i32,
|
||||||
|
pub target_hp: i32,
|
||||||
|
pub target_max_hp: i32,
|
||||||
|
pub experience_reward: u32,
|
||||||
|
pub reward_items: Vec<StoryBattleRewardItemPayload>,
|
||||||
|
pub turn_index: u32,
|
||||||
|
#[serde(default, skip_serializing_if = "Option::is_none")]
|
||||||
|
pub last_action_function_id: Option<String>,
|
||||||
|
#[serde(default, skip_serializing_if = "Option::is_none")]
|
||||||
|
pub last_action_text: Option<String>,
|
||||||
|
#[serde(default, skip_serializing_if = "Option::is_none")]
|
||||||
|
pub last_result_text: Option<String>,
|
||||||
|
pub last_damage_dealt: i32,
|
||||||
|
pub last_damage_taken: i32,
|
||||||
|
pub last_outcome: String,
|
||||||
|
pub version: u32,
|
||||||
|
pub created_at: String,
|
||||||
|
pub updated_at: String,
|
||||||
|
}
|
||||||
|
|
||||||
|
#[derive(Clone, Debug, Serialize, Deserialize, PartialEq)]
|
||||||
|
#[serde(rename_all = "camelCase")]
|
||||||
|
pub struct StoryBattleStateResponse {
|
||||||
|
pub battle_state: StoryBattleStatePayload,
|
||||||
|
}
|
||||||
|
|
||||||
|
#[derive(Clone, Debug, Serialize, Deserialize, PartialEq)]
|
||||||
|
#[serde(rename_all = "camelCase")]
|
||||||
|
pub struct StoryCombatActionPayload {
|
||||||
|
pub damage_dealt: i32,
|
||||||
|
pub damage_taken: i32,
|
||||||
|
pub outcome: String,
|
||||||
|
}
|
||||||
|
|
||||||
|
#[derive(Clone, Debug, Serialize, Deserialize, PartialEq)]
|
||||||
|
#[serde(rename_all = "camelCase")]
|
||||||
|
pub struct ResolveStoryBattleResponse {
|
||||||
|
pub battle_state: StoryBattleStatePayload,
|
||||||
|
pub combat: StoryCombatActionPayload,
|
||||||
|
}
|
||||||
|
|
||||||
|
#[derive(Clone, Debug, Serialize, Deserialize, PartialEq)]
|
||||||
|
#[serde(rename_all = "camelCase")]
|
||||||
|
pub struct StoryNpcStanceProfilePayload {
|
||||||
|
pub trust: u8,
|
||||||
|
pub warmth: u8,
|
||||||
|
pub ideological_fit: u8,
|
||||||
|
pub fear_or_guard: u8,
|
||||||
|
pub loyalty: u8,
|
||||||
|
#[serde(default, skip_serializing_if = "Option::is_none")]
|
||||||
|
pub current_conflict_tag: Option<String>,
|
||||||
|
pub recent_approvals: Vec<String>,
|
||||||
|
pub recent_disapprovals: Vec<String>,
|
||||||
|
}
|
||||||
|
|
||||||
|
#[derive(Clone, Debug, Serialize, Deserialize, PartialEq)]
|
||||||
|
#[serde(rename_all = "camelCase")]
|
||||||
|
pub struct StoryNpcStatePayload {
|
||||||
|
pub npc_state_id: String,
|
||||||
|
pub runtime_session_id: String,
|
||||||
|
pub npc_id: String,
|
||||||
|
pub npc_name: String,
|
||||||
|
pub affinity: i32,
|
||||||
|
pub relation_stance: String,
|
||||||
|
pub help_used: bool,
|
||||||
|
pub chatted_count: u32,
|
||||||
|
pub gifts_given: u32,
|
||||||
|
pub recruited: bool,
|
||||||
|
#[serde(default, skip_serializing_if = "Option::is_none")]
|
||||||
|
pub trade_stock_signature: Option<String>,
|
||||||
|
pub revealed_facts: Vec<String>,
|
||||||
|
pub known_attribute_rumors: Vec<String>,
|
||||||
|
pub first_meaningful_contact_resolved: bool,
|
||||||
|
pub seen_backstory_chapter_ids: Vec<String>,
|
||||||
|
pub stance_profile: StoryNpcStanceProfilePayload,
|
||||||
|
pub created_at: String,
|
||||||
|
pub updated_at: String,
|
||||||
|
}
|
||||||
|
|
||||||
|
#[derive(Clone, Debug, Serialize, Deserialize, PartialEq)]
|
||||||
|
#[serde(rename_all = "camelCase")]
|
||||||
|
pub struct StoryNpcInteractionPayload {
|
||||||
|
pub npc_state: StoryNpcStatePayload,
|
||||||
|
pub interaction_status: String,
|
||||||
|
pub action_text: String,
|
||||||
|
pub result_text: String,
|
||||||
|
#[serde(default, skip_serializing_if = "Option::is_none")]
|
||||||
|
pub story_text: Option<String>,
|
||||||
|
#[serde(default, skip_serializing_if = "Option::is_none")]
|
||||||
|
pub battle_mode: Option<String>,
|
||||||
|
pub encounter_closed: bool,
|
||||||
|
pub affinity_changed: bool,
|
||||||
|
pub previous_affinity: i32,
|
||||||
|
pub next_affinity: i32,
|
||||||
|
}
|
||||||
|
|
||||||
|
#[derive(Clone, Debug, Serialize, Deserialize, PartialEq)]
|
||||||
|
#[serde(rename_all = "camelCase")]
|
||||||
|
pub struct CreateStoryNpcBattleResponse {
|
||||||
|
pub npc_interaction: StoryNpcInteractionPayload,
|
||||||
|
pub battle_state: StoryBattleStatePayload,
|
||||||
|
}
|
||||||
|
|
||||||
#[cfg(test)]
|
#[cfg(test)]
|
||||||
mod tests {
|
mod tests {
|
||||||
use super::*;
|
use super::*;
|
||||||
@@ -312,4 +526,66 @@ mod tests {
|
|||||||
assert!(payload.get("viewModel").is_none());
|
assert!(payload.get("viewModel").is_none());
|
||||||
assert!(payload.get("presentation").is_none());
|
assert!(payload.get("presentation").is_none());
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn story_battle_responses_use_story_contract_shape() {
|
||||||
|
let battle_state = StoryBattleStatePayload {
|
||||||
|
battle_state_id: "battle_1".to_string(),
|
||||||
|
story_session_id: "storysess_1".to_string(),
|
||||||
|
runtime_session_id: "runtime_1".to_string(),
|
||||||
|
actor_user_id: "user_1".to_string(),
|
||||||
|
chapter_id: None,
|
||||||
|
target_npc_id: "npc_wolf".to_string(),
|
||||||
|
target_name: "黑爪狼".to_string(),
|
||||||
|
battle_mode: "fight".to_string(),
|
||||||
|
status: "active".to_string(),
|
||||||
|
player_hp: 28,
|
||||||
|
player_max_hp: 40,
|
||||||
|
player_mana: 12,
|
||||||
|
player_max_mana: 20,
|
||||||
|
target_hp: 18,
|
||||||
|
target_max_hp: 30,
|
||||||
|
experience_reward: 12,
|
||||||
|
reward_items: vec![StoryBattleRewardItemPayload {
|
||||||
|
item_id: "wolf-fang".to_string(),
|
||||||
|
category: "material".to_string(),
|
||||||
|
item_name: "狼牙".to_string(),
|
||||||
|
description: None,
|
||||||
|
quantity: 1,
|
||||||
|
rarity: "common".to_string(),
|
||||||
|
tags: vec!["beast".to_string()],
|
||||||
|
stackable: true,
|
||||||
|
stack_key: "wolf-fang".to_string(),
|
||||||
|
equipment_slot_id: None,
|
||||||
|
}],
|
||||||
|
turn_index: 1,
|
||||||
|
last_action_function_id: Some("battle_attack_basic".to_string()),
|
||||||
|
last_action_text: Some("普通攻击".to_string()),
|
||||||
|
last_result_text: Some("你击中了黑爪狼。".to_string()),
|
||||||
|
last_damage_dealt: 10,
|
||||||
|
last_damage_taken: 3,
|
||||||
|
last_outcome: "ongoing".to_string(),
|
||||||
|
version: 2,
|
||||||
|
created_at: "1.000000Z".to_string(),
|
||||||
|
updated_at: "2.000000Z".to_string(),
|
||||||
|
};
|
||||||
|
|
||||||
|
let payload = serde_json::to_value(ResolveStoryBattleResponse {
|
||||||
|
battle_state,
|
||||||
|
combat: StoryCombatActionPayload {
|
||||||
|
damage_dealt: 10,
|
||||||
|
damage_taken: 3,
|
||||||
|
outcome: "ongoing".to_string(),
|
||||||
|
},
|
||||||
|
})
|
||||||
|
.expect("payload should serialize");
|
||||||
|
|
||||||
|
assert_eq!(payload["battleState"]["battleStateId"], json!("battle_1"));
|
||||||
|
assert_eq!(
|
||||||
|
payload["battleState"]["rewardItems"][0]["itemName"],
|
||||||
|
json!("狼牙")
|
||||||
|
);
|
||||||
|
assert_eq!(payload["combat"]["damageDealt"], json!(10));
|
||||||
|
assert!(payload["battleState"].get("chapterId").is_none());
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -14,7 +14,7 @@ impl SpacetimeClient {
|
|||||||
procedure_input,
|
procedure_input,
|
||||||
move |_, result| {
|
move |_, result| {
|
||||||
let mapped = result
|
let mapped = result
|
||||||
.map_err(|error| SpacetimeClientError::Procedure(error.to_string()))
|
.map_err(SpacetimeClientError::from_sdk_error)
|
||||||
.and_then(map_custom_world_profile_list_result);
|
.and_then(map_custom_world_profile_list_result);
|
||||||
send_once(&sender, mapped);
|
send_once(&sender, mapped);
|
||||||
},
|
},
|
||||||
@@ -38,7 +38,7 @@ impl SpacetimeClient {
|
|||||||
.procedures()
|
.procedures()
|
||||||
.get_custom_world_library_detail_then(procedure_input, move |_, result| {
|
.get_custom_world_library_detail_then(procedure_input, move |_, result| {
|
||||||
let mapped = result
|
let mapped = result
|
||||||
.map_err(|error| SpacetimeClientError::Procedure(error.to_string()))
|
.map_err(SpacetimeClientError::from_sdk_error)
|
||||||
.and_then(map_custom_world_library_detail_result);
|
.and_then(map_custom_world_library_detail_result);
|
||||||
send_once(&sender, mapped);
|
send_once(&sender, mapped);
|
||||||
});
|
});
|
||||||
@@ -57,7 +57,7 @@ impl SpacetimeClient {
|
|||||||
.procedures()
|
.procedures()
|
||||||
.upsert_custom_world_profile_and_return_then(procedure_input, move |_, result| {
|
.upsert_custom_world_profile_and_return_then(procedure_input, move |_, result| {
|
||||||
let mapped = result
|
let mapped = result
|
||||||
.map_err(|error| SpacetimeClientError::Procedure(error.to_string()))
|
.map_err(SpacetimeClientError::from_sdk_error)
|
||||||
.and_then(map_custom_world_library_mutation_result);
|
.and_then(map_custom_world_library_mutation_result);
|
||||||
send_once(&sender, mapped);
|
send_once(&sender, mapped);
|
||||||
});
|
});
|
||||||
@@ -88,7 +88,7 @@ impl SpacetimeClient {
|
|||||||
.procedures()
|
.procedures()
|
||||||
.publish_custom_world_profile_and_return_then(procedure_input, move |_, result| {
|
.publish_custom_world_profile_and_return_then(procedure_input, move |_, result| {
|
||||||
let mapped = result
|
let mapped = result
|
||||||
.map_err(|error| SpacetimeClientError::Procedure(error.to_string()))
|
.map_err(SpacetimeClientError::from_sdk_error)
|
||||||
.and_then(map_custom_world_library_mutation_result);
|
.and_then(map_custom_world_library_mutation_result);
|
||||||
send_once(&sender, mapped);
|
send_once(&sender, mapped);
|
||||||
});
|
});
|
||||||
@@ -117,7 +117,7 @@ impl SpacetimeClient {
|
|||||||
procedure_input,
|
procedure_input,
|
||||||
move |_, result| {
|
move |_, result| {
|
||||||
let mapped = result
|
let mapped = result
|
||||||
.map_err(|error| SpacetimeClientError::Procedure(error.to_string()))
|
.map_err(SpacetimeClientError::from_sdk_error)
|
||||||
.and_then(map_custom_world_library_mutation_result);
|
.and_then(map_custom_world_library_mutation_result);
|
||||||
send_once(&sender, mapped);
|
send_once(&sender, mapped);
|
||||||
},
|
},
|
||||||
@@ -143,7 +143,7 @@ impl SpacetimeClient {
|
|||||||
.procedures()
|
.procedures()
|
||||||
.delete_custom_world_profile_and_return_then(procedure_input, move |_, result| {
|
.delete_custom_world_profile_and_return_then(procedure_input, move |_, result| {
|
||||||
let mapped = result
|
let mapped = result
|
||||||
.map_err(|error| SpacetimeClientError::Procedure(error.to_string()))
|
.map_err(SpacetimeClientError::from_sdk_error)
|
||||||
.and_then(map_custom_world_profile_list_result);
|
.and_then(map_custom_world_profile_list_result);
|
||||||
send_once(&sender, mapped);
|
send_once(&sender, mapped);
|
||||||
});
|
});
|
||||||
@@ -159,7 +159,7 @@ impl SpacetimeClient {
|
|||||||
.procedures()
|
.procedures()
|
||||||
.list_custom_world_gallery_entries_then(move |_, result| {
|
.list_custom_world_gallery_entries_then(move |_, result| {
|
||||||
let mapped = result
|
let mapped = result
|
||||||
.map_err(|error| SpacetimeClientError::Procedure(error.to_string()))
|
.map_err(SpacetimeClientError::from_sdk_error)
|
||||||
.and_then(map_custom_world_gallery_list_result);
|
.and_then(map_custom_world_gallery_list_result);
|
||||||
send_once(&sender, mapped);
|
send_once(&sender, mapped);
|
||||||
});
|
});
|
||||||
@@ -182,7 +182,7 @@ impl SpacetimeClient {
|
|||||||
.procedures()
|
.procedures()
|
||||||
.get_custom_world_gallery_detail_then(procedure_input, move |_, result| {
|
.get_custom_world_gallery_detail_then(procedure_input, move |_, result| {
|
||||||
let mapped = result
|
let mapped = result
|
||||||
.map_err(|error| SpacetimeClientError::Procedure(error.to_string()))
|
.map_err(SpacetimeClientError::from_sdk_error)
|
||||||
.and_then(map_custom_world_library_mutation_result);
|
.and_then(map_custom_world_library_mutation_result);
|
||||||
send_once(&sender, mapped);
|
send_once(&sender, mapped);
|
||||||
});
|
});
|
||||||
@@ -201,7 +201,7 @@ impl SpacetimeClient {
|
|||||||
.procedures()
|
.procedures()
|
||||||
.get_custom_world_gallery_detail_by_code_then(procedure_input, move |_, result| {
|
.get_custom_world_gallery_detail_by_code_then(procedure_input, move |_, result| {
|
||||||
let mapped = result
|
let mapped = result
|
||||||
.map_err(|error| SpacetimeClientError::Procedure(error.to_string()))
|
.map_err(SpacetimeClientError::from_sdk_error)
|
||||||
.and_then(map_custom_world_library_mutation_result);
|
.and_then(map_custom_world_library_mutation_result);
|
||||||
send_once(&sender, mapped);
|
send_once(&sender, mapped);
|
||||||
});
|
});
|
||||||
@@ -220,7 +220,7 @@ impl SpacetimeClient {
|
|||||||
procedure_input,
|
procedure_input,
|
||||||
move |_, result| {
|
move |_, result| {
|
||||||
let mapped = result
|
let mapped = result
|
||||||
.map_err(|error| SpacetimeClientError::Procedure(error.to_string()))
|
.map_err(SpacetimeClientError::from_sdk_error)
|
||||||
.and_then(map_custom_world_publish_world_result);
|
.and_then(map_custom_world_publish_world_result);
|
||||||
send_once(&sender, mapped);
|
send_once(&sender, mapped);
|
||||||
},
|
},
|
||||||
@@ -259,7 +259,7 @@ impl SpacetimeClient {
|
|||||||
.procedures()
|
.procedures()
|
||||||
.create_custom_world_agent_session_then(procedure_input, move |_, result| {
|
.create_custom_world_agent_session_then(procedure_input, move |_, result| {
|
||||||
let mapped = result
|
let mapped = result
|
||||||
.map_err(|error| SpacetimeClientError::Procedure(error.to_string()))
|
.map_err(SpacetimeClientError::from_sdk_error)
|
||||||
.and_then(map_custom_world_agent_session_procedure_result);
|
.and_then(map_custom_world_agent_session_procedure_result);
|
||||||
send_once(&sender, mapped);
|
send_once(&sender, mapped);
|
||||||
});
|
});
|
||||||
@@ -282,7 +282,7 @@ impl SpacetimeClient {
|
|||||||
procedure_input,
|
procedure_input,
|
||||||
move |_, result| {
|
move |_, result| {
|
||||||
let mapped = result
|
let mapped = result
|
||||||
.map_err(|error| SpacetimeClientError::Procedure(error.to_string()))
|
.map_err(SpacetimeClientError::from_sdk_error)
|
||||||
.and_then(map_custom_world_agent_session_procedure_result);
|
.and_then(map_custom_world_agent_session_procedure_result);
|
||||||
send_once(&sender, mapped);
|
send_once(&sender, mapped);
|
||||||
},
|
},
|
||||||
@@ -302,7 +302,7 @@ impl SpacetimeClient {
|
|||||||
procedure_input,
|
procedure_input,
|
||||||
move |_, result| {
|
move |_, result| {
|
||||||
let mapped = result
|
let mapped = result
|
||||||
.map_err(|error| SpacetimeClientError::Procedure(error.to_string()))
|
.map_err(SpacetimeClientError::from_sdk_error)
|
||||||
.and_then(map_custom_world_works_list_result);
|
.and_then(map_custom_world_works_list_result);
|
||||||
send_once(&sender, mapped);
|
send_once(&sender, mapped);
|
||||||
},
|
},
|
||||||
@@ -326,7 +326,7 @@ impl SpacetimeClient {
|
|||||||
.procedures()
|
.procedures()
|
||||||
.delete_custom_world_agent_session_then(procedure_input, move |_, result| {
|
.delete_custom_world_agent_session_then(procedure_input, move |_, result| {
|
||||||
let mapped = result
|
let mapped = result
|
||||||
.map_err(|error| SpacetimeClientError::Procedure(error.to_string()))
|
.map_err(SpacetimeClientError::from_sdk_error)
|
||||||
.and_then(map_custom_world_works_list_result);
|
.and_then(map_custom_world_works_list_result);
|
||||||
send_once(&sender, mapped);
|
send_once(&sender, mapped);
|
||||||
});
|
});
|
||||||
@@ -351,7 +351,7 @@ impl SpacetimeClient {
|
|||||||
.procedures()
|
.procedures()
|
||||||
.get_custom_world_agent_card_detail_then(procedure_input, move |_, result| {
|
.get_custom_world_agent_card_detail_then(procedure_input, move |_, result| {
|
||||||
let mapped = result
|
let mapped = result
|
||||||
.map_err(|error| SpacetimeClientError::Procedure(error.to_string()))
|
.map_err(SpacetimeClientError::from_sdk_error)
|
||||||
.and_then(map_custom_world_draft_card_detail_result);
|
.and_then(map_custom_world_draft_card_detail_result);
|
||||||
send_once(&sender, mapped);
|
send_once(&sender, mapped);
|
||||||
});
|
});
|
||||||
@@ -377,7 +377,7 @@ impl SpacetimeClient {
|
|||||||
.procedures()
|
.procedures()
|
||||||
.execute_custom_world_agent_action_then(procedure_input, move |_, result| {
|
.execute_custom_world_agent_action_then(procedure_input, move |_, result| {
|
||||||
let mapped = result
|
let mapped = result
|
||||||
.map_err(|error| SpacetimeClientError::Procedure(error.to_string()))
|
.map_err(SpacetimeClientError::from_sdk_error)
|
||||||
.and_then(map_custom_world_agent_action_execute_result);
|
.and_then(map_custom_world_agent_action_execute_result);
|
||||||
send_once(&sender, mapped);
|
send_once(&sender, mapped);
|
||||||
});
|
});
|
||||||
@@ -403,7 +403,7 @@ impl SpacetimeClient {
|
|||||||
.procedures()
|
.procedures()
|
||||||
.submit_custom_world_agent_message_then(procedure_input, move |_, result| {
|
.submit_custom_world_agent_message_then(procedure_input, move |_, result| {
|
||||||
let mapped = result
|
let mapped = result
|
||||||
.map_err(|error| SpacetimeClientError::Procedure(error.to_string()))
|
.map_err(SpacetimeClientError::from_sdk_error)
|
||||||
.and_then(map_custom_world_agent_operation_procedure_result);
|
.and_then(map_custom_world_agent_operation_procedure_result);
|
||||||
send_once(&sender, mapped);
|
send_once(&sender, mapped);
|
||||||
});
|
});
|
||||||
@@ -451,7 +451,7 @@ impl SpacetimeClient {
|
|||||||
procedure_input,
|
procedure_input,
|
||||||
move |_, result| {
|
move |_, result| {
|
||||||
let mapped = result
|
let mapped = result
|
||||||
.map_err(|error| SpacetimeClientError::Procedure(error.to_string()))
|
.map_err(SpacetimeClientError::from_sdk_error)
|
||||||
.and_then(map_custom_world_agent_operation_procedure_result);
|
.and_then(map_custom_world_agent_operation_procedure_result);
|
||||||
send_once(&sender, mapped);
|
send_once(&sender, mapped);
|
||||||
},
|
},
|
||||||
@@ -486,7 +486,7 @@ impl SpacetimeClient {
|
|||||||
procedure_input,
|
procedure_input,
|
||||||
move |_, result| {
|
move |_, result| {
|
||||||
let mapped = result
|
let mapped = result
|
||||||
.map_err(|error| SpacetimeClientError::Procedure(error.to_string()))
|
.map_err(SpacetimeClientError::from_sdk_error)
|
||||||
.and_then(map_custom_world_agent_operation_procedure_result);
|
.and_then(map_custom_world_agent_operation_procedure_result);
|
||||||
send_once(&sender, mapped);
|
send_once(&sender, mapped);
|
||||||
},
|
},
|
||||||
@@ -512,7 +512,7 @@ impl SpacetimeClient {
|
|||||||
.procedures()
|
.procedures()
|
||||||
.get_custom_world_agent_operation_then(procedure_input, move |_, result| {
|
.get_custom_world_agent_operation_then(procedure_input, move |_, result| {
|
||||||
let mapped = result
|
let mapped = result
|
||||||
.map_err(|error| SpacetimeClientError::Procedure(error.to_string()))
|
.map_err(SpacetimeClientError::from_sdk_error)
|
||||||
.and_then(map_custom_world_agent_operation_procedure_result);
|
.and_then(map_custom_world_agent_operation_procedure_result);
|
||||||
send_once(&sender, mapped);
|
send_once(&sender, mapped);
|
||||||
});
|
});
|
||||||
|
|||||||
@@ -575,18 +575,12 @@ pub(crate) fn map_runtime_setting_procedure_result(
|
|||||||
result: RuntimeSettingProcedureResult,
|
result: RuntimeSettingProcedureResult,
|
||||||
) -> Result<RuntimeSettingsRecord, SpacetimeClientError> {
|
) -> Result<RuntimeSettingsRecord, SpacetimeClientError> {
|
||||||
if !result.ok {
|
if !result.ok {
|
||||||
return Err(SpacetimeClientError::Procedure(
|
return Err(SpacetimeClientError::procedure_failed(result.error_message));
|
||||||
result
|
|
||||||
.error_message
|
|
||||||
.unwrap_or_else(|| "SpacetimeDB procedure 返回未知错误".to_string()),
|
|
||||||
));
|
|
||||||
}
|
}
|
||||||
|
|
||||||
let snapshot = result.record.ok_or_else(|| {
|
let snapshot = result
|
||||||
SpacetimeClientError::Procedure(
|
.record
|
||||||
"SpacetimeDB procedure 未返回 runtime settings 快照".to_string(),
|
.ok_or_else(|| SpacetimeClientError::missing_snapshot("runtime settings 快照"))?;
|
||||||
)
|
|
||||||
})?;
|
|
||||||
|
|
||||||
Ok(build_runtime_setting_record(map_runtime_setting_snapshot(
|
Ok(build_runtime_setting_record(map_runtime_setting_snapshot(
|
||||||
snapshot,
|
snapshot,
|
||||||
@@ -620,16 +614,12 @@ pub(crate) fn map_auth_store_snapshot_import_procedure_result(
|
|||||||
result: AuthStoreSnapshotImportProcedureResult,
|
result: AuthStoreSnapshotImportProcedureResult,
|
||||||
) -> Result<AuthStoreSnapshotImportRecord, SpacetimeClientError> {
|
) -> Result<AuthStoreSnapshotImportRecord, SpacetimeClientError> {
|
||||||
if !result.ok {
|
if !result.ok {
|
||||||
return Err(SpacetimeClientError::Procedure(
|
return Err(SpacetimeClientError::procedure_failed(result.error_message));
|
||||||
result
|
|
||||||
.error_message
|
|
||||||
.unwrap_or_else(|| "SpacetimeDB procedure ??????".to_string()),
|
|
||||||
));
|
|
||||||
}
|
}
|
||||||
|
|
||||||
let record = result.record.ok_or_else(|| {
|
let record = result
|
||||||
SpacetimeClientError::Procedure("SpacetimeDB procedure ???????".to_string())
|
.record
|
||||||
})?;
|
.ok_or_else(|| SpacetimeClientError::missing_snapshot("认证快照导入结果"))?;
|
||||||
|
|
||||||
Ok(AuthStoreSnapshotImportRecord {
|
Ok(AuthStoreSnapshotImportRecord {
|
||||||
imported_user_count: record.imported_user_count,
|
imported_user_count: record.imported_user_count,
|
||||||
@@ -642,11 +632,7 @@ pub(crate) fn map_runtime_browse_history_procedure_result(
|
|||||||
result: RuntimeBrowseHistoryProcedureResult,
|
result: RuntimeBrowseHistoryProcedureResult,
|
||||||
) -> Result<Vec<RuntimeBrowseHistoryRecord>, SpacetimeClientError> {
|
) -> Result<Vec<RuntimeBrowseHistoryRecord>, SpacetimeClientError> {
|
||||||
if !result.ok {
|
if !result.ok {
|
||||||
return Err(SpacetimeClientError::Procedure(
|
return Err(SpacetimeClientError::procedure_failed(result.error_message));
|
||||||
result
|
|
||||||
.error_message
|
|
||||||
.unwrap_or_else(|| "SpacetimeDB procedure 返回未知错误".to_string()),
|
|
||||||
));
|
|
||||||
}
|
}
|
||||||
|
|
||||||
Ok(result
|
Ok(result
|
||||||
@@ -662,18 +648,12 @@ pub(crate) fn map_runtime_profile_dashboard_procedure_result(
|
|||||||
result: RuntimeProfileDashboardProcedureResult,
|
result: RuntimeProfileDashboardProcedureResult,
|
||||||
) -> Result<RuntimeProfileDashboardRecord, SpacetimeClientError> {
|
) -> Result<RuntimeProfileDashboardRecord, SpacetimeClientError> {
|
||||||
if !result.ok {
|
if !result.ok {
|
||||||
return Err(SpacetimeClientError::Procedure(
|
return Err(SpacetimeClientError::procedure_failed(result.error_message));
|
||||||
result
|
|
||||||
.error_message
|
|
||||||
.unwrap_or_else(|| "SpacetimeDB procedure 返回未知错误".to_string()),
|
|
||||||
));
|
|
||||||
}
|
}
|
||||||
|
|
||||||
let snapshot = result.record.ok_or_else(|| {
|
let snapshot = result
|
||||||
SpacetimeClientError::Procedure(
|
.record
|
||||||
"SpacetimeDB procedure 未返回 profile dashboard 快照".to_string(),
|
.ok_or_else(|| SpacetimeClientError::missing_snapshot("profile dashboard 快照"))?;
|
||||||
)
|
|
||||||
})?;
|
|
||||||
|
|
||||||
Ok(build_runtime_profile_dashboard_record(
|
Ok(build_runtime_profile_dashboard_record(
|
||||||
map_runtime_profile_dashboard_snapshot(snapshot),
|
map_runtime_profile_dashboard_snapshot(snapshot),
|
||||||
@@ -684,11 +664,7 @@ pub(crate) fn map_runtime_profile_wallet_ledger_procedure_result(
|
|||||||
result: RuntimeProfileWalletLedgerProcedureResult,
|
result: RuntimeProfileWalletLedgerProcedureResult,
|
||||||
) -> Result<Vec<RuntimeProfileWalletLedgerEntryRecord>, SpacetimeClientError> {
|
) -> Result<Vec<RuntimeProfileWalletLedgerEntryRecord>, SpacetimeClientError> {
|
||||||
if !result.ok {
|
if !result.ok {
|
||||||
return Err(SpacetimeClientError::Procedure(
|
return Err(SpacetimeClientError::procedure_failed(result.error_message));
|
||||||
result
|
|
||||||
.error_message
|
|
||||||
.unwrap_or_else(|| "SpacetimeDB procedure 返回未知错误".to_string()),
|
|
||||||
));
|
|
||||||
}
|
}
|
||||||
|
|
||||||
Ok(result
|
Ok(result
|
||||||
@@ -706,18 +682,12 @@ pub(crate) fn map_runtime_profile_wallet_adjustment_procedure_result(
|
|||||||
result: RuntimeProfileWalletAdjustmentProcedureResult,
|
result: RuntimeProfileWalletAdjustmentProcedureResult,
|
||||||
) -> Result<RuntimeProfileDashboardRecord, SpacetimeClientError> {
|
) -> Result<RuntimeProfileDashboardRecord, SpacetimeClientError> {
|
||||||
if !result.ok {
|
if !result.ok {
|
||||||
return Err(SpacetimeClientError::Procedure(
|
return Err(SpacetimeClientError::procedure_failed(result.error_message));
|
||||||
result
|
|
||||||
.error_message
|
|
||||||
.unwrap_or_else(|| "SpacetimeDB procedure 返回未知错误".to_string()),
|
|
||||||
));
|
|
||||||
}
|
}
|
||||||
|
|
||||||
let snapshot = result.record.ok_or_else(|| {
|
let snapshot = result
|
||||||
SpacetimeClientError::Procedure(
|
.record
|
||||||
"SpacetimeDB procedure 未返回 profile dashboard 快照".to_string(),
|
.ok_or_else(|| SpacetimeClientError::missing_snapshot("profile dashboard 快照"))?;
|
||||||
)
|
|
||||||
})?;
|
|
||||||
|
|
||||||
Ok(build_runtime_profile_dashboard_record(
|
Ok(build_runtime_profile_dashboard_record(
|
||||||
map_runtime_profile_dashboard_snapshot(snapshot),
|
map_runtime_profile_dashboard_snapshot(snapshot),
|
||||||
@@ -728,18 +698,12 @@ pub(crate) fn map_runtime_profile_recharge_center_procedure_result(
|
|||||||
result: RuntimeProfileRechargeCenterProcedureResult,
|
result: RuntimeProfileRechargeCenterProcedureResult,
|
||||||
) -> Result<RuntimeProfileRechargeCenterRecord, SpacetimeClientError> {
|
) -> Result<RuntimeProfileRechargeCenterRecord, SpacetimeClientError> {
|
||||||
if !result.ok {
|
if !result.ok {
|
||||||
return Err(SpacetimeClientError::Procedure(
|
return Err(SpacetimeClientError::procedure_failed(result.error_message));
|
||||||
result
|
|
||||||
.error_message
|
|
||||||
.unwrap_or_else(|| "SpacetimeDB procedure 返回未知错误".to_string()),
|
|
||||||
));
|
|
||||||
}
|
}
|
||||||
|
|
||||||
let snapshot = result.record.ok_or_else(|| {
|
let snapshot = result
|
||||||
SpacetimeClientError::Procedure(
|
.record
|
||||||
"SpacetimeDB procedure 未返回 profile recharge center 快照".to_string(),
|
.ok_or_else(|| SpacetimeClientError::missing_snapshot("profile recharge center 快照"))?;
|
||||||
)
|
|
||||||
})?;
|
|
||||||
|
|
||||||
Ok(build_runtime_profile_recharge_center_record(
|
Ok(build_runtime_profile_recharge_center_record(
|
||||||
map_runtime_profile_recharge_center_snapshot(snapshot),
|
map_runtime_profile_recharge_center_snapshot(snapshot),
|
||||||
@@ -756,23 +720,15 @@ pub(crate) fn map_runtime_profile_recharge_order_procedure_result(
|
|||||||
SpacetimeClientError,
|
SpacetimeClientError,
|
||||||
> {
|
> {
|
||||||
if !result.ok {
|
if !result.ok {
|
||||||
return Err(SpacetimeClientError::Procedure(
|
return Err(SpacetimeClientError::procedure_failed(result.error_message));
|
||||||
result
|
|
||||||
.error_message
|
|
||||||
.unwrap_or_else(|| "SpacetimeDB procedure 返回未知错误".to_string()),
|
|
||||||
));
|
|
||||||
}
|
}
|
||||||
|
|
||||||
let center = result.record.ok_or_else(|| {
|
let center = result
|
||||||
SpacetimeClientError::Procedure(
|
.record
|
||||||
"SpacetimeDB procedure 未返回 profile recharge center 快照".to_string(),
|
.ok_or_else(|| SpacetimeClientError::missing_snapshot("profile recharge center 快照"))?;
|
||||||
)
|
let order = result
|
||||||
})?;
|
.order
|
||||||
let order = result.order.ok_or_else(|| {
|
.ok_or_else(|| SpacetimeClientError::missing_snapshot("profile recharge order 快照"))?;
|
||||||
SpacetimeClientError::Procedure(
|
|
||||||
"SpacetimeDB procedure 未返回 profile recharge order 快照".to_string(),
|
|
||||||
)
|
|
||||||
})?;
|
|
||||||
|
|
||||||
Ok((
|
Ok((
|
||||||
build_runtime_profile_recharge_center_record(map_runtime_profile_recharge_center_snapshot(
|
build_runtime_profile_recharge_center_record(map_runtime_profile_recharge_center_snapshot(
|
||||||
@@ -788,18 +744,12 @@ pub(crate) fn map_runtime_referral_invite_center_procedure_result(
|
|||||||
result: RuntimeReferralInviteCenterProcedureResult,
|
result: RuntimeReferralInviteCenterProcedureResult,
|
||||||
) -> Result<RuntimeReferralInviteCenterRecord, SpacetimeClientError> {
|
) -> Result<RuntimeReferralInviteCenterRecord, SpacetimeClientError> {
|
||||||
if !result.ok {
|
if !result.ok {
|
||||||
return Err(SpacetimeClientError::Procedure(
|
return Err(SpacetimeClientError::procedure_failed(result.error_message));
|
||||||
result
|
|
||||||
.error_message
|
|
||||||
.unwrap_or_else(|| "SpacetimeDB procedure 返回未知错误".to_string()),
|
|
||||||
));
|
|
||||||
}
|
}
|
||||||
|
|
||||||
let snapshot = result.record.ok_or_else(|| {
|
let snapshot = result
|
||||||
SpacetimeClientError::Procedure(
|
.record
|
||||||
"SpacetimeDB procedure 未返回 referral invite center 快照".to_string(),
|
.ok_or_else(|| SpacetimeClientError::missing_snapshot("referral invite center 快照"))?;
|
||||||
)
|
|
||||||
})?;
|
|
||||||
|
|
||||||
Ok(build_runtime_referral_invite_center_record(
|
Ok(build_runtime_referral_invite_center_record(
|
||||||
map_runtime_referral_invite_center_snapshot(snapshot),
|
map_runtime_referral_invite_center_snapshot(snapshot),
|
||||||
@@ -810,18 +760,12 @@ pub(crate) fn map_runtime_referral_redeem_procedure_result(
|
|||||||
result: RuntimeReferralRedeemProcedureResult,
|
result: RuntimeReferralRedeemProcedureResult,
|
||||||
) -> Result<RuntimeReferralRedeemRecord, SpacetimeClientError> {
|
) -> Result<RuntimeReferralRedeemRecord, SpacetimeClientError> {
|
||||||
if !result.ok {
|
if !result.ok {
|
||||||
return Err(SpacetimeClientError::Procedure(
|
return Err(SpacetimeClientError::procedure_failed(result.error_message));
|
||||||
result
|
|
||||||
.error_message
|
|
||||||
.unwrap_or_else(|| "SpacetimeDB procedure 返回未知错误".to_string()),
|
|
||||||
));
|
|
||||||
}
|
}
|
||||||
|
|
||||||
let snapshot = result.record.ok_or_else(|| {
|
let snapshot = result
|
||||||
SpacetimeClientError::Procedure(
|
.record
|
||||||
"SpacetimeDB procedure 未返回 referral redeem 快照".to_string(),
|
.ok_or_else(|| SpacetimeClientError::missing_snapshot("referral redeem 快照"))?;
|
||||||
)
|
|
||||||
})?;
|
|
||||||
|
|
||||||
Ok(build_runtime_referral_redeem_record(
|
Ok(build_runtime_referral_redeem_record(
|
||||||
map_runtime_referral_redeem_snapshot(snapshot),
|
map_runtime_referral_redeem_snapshot(snapshot),
|
||||||
@@ -832,18 +776,12 @@ pub(crate) fn map_runtime_profile_reward_code_redeem_procedure_result(
|
|||||||
result: RuntimeProfileRewardCodeRedeemProcedureResult,
|
result: RuntimeProfileRewardCodeRedeemProcedureResult,
|
||||||
) -> Result<RuntimeProfileRewardCodeRedeemRecord, SpacetimeClientError> {
|
) -> Result<RuntimeProfileRewardCodeRedeemRecord, SpacetimeClientError> {
|
||||||
if !result.ok {
|
if !result.ok {
|
||||||
return Err(SpacetimeClientError::Procedure(
|
return Err(SpacetimeClientError::procedure_failed(result.error_message));
|
||||||
result
|
|
||||||
.error_message
|
|
||||||
.unwrap_or_else(|| "SpacetimeDB procedure 返回未知错误".to_string()),
|
|
||||||
));
|
|
||||||
}
|
}
|
||||||
|
|
||||||
let snapshot = result.record.ok_or_else(|| {
|
let snapshot = result
|
||||||
SpacetimeClientError::Procedure(
|
.record
|
||||||
"SpacetimeDB procedure 未返回 reward redeem 快照".to_string(),
|
.ok_or_else(|| SpacetimeClientError::missing_snapshot("reward redeem 快照"))?;
|
||||||
)
|
|
||||||
})?;
|
|
||||||
|
|
||||||
Ok(build_runtime_profile_reward_code_redeem_record(
|
Ok(build_runtime_profile_reward_code_redeem_record(
|
||||||
map_runtime_profile_reward_code_redeem_snapshot(snapshot),
|
map_runtime_profile_reward_code_redeem_snapshot(snapshot),
|
||||||
@@ -854,16 +792,12 @@ pub(crate) fn map_runtime_profile_redeem_code_admin_procedure_result(
|
|||||||
result: RuntimeProfileRedeemCodeAdminProcedureResult,
|
result: RuntimeProfileRedeemCodeAdminProcedureResult,
|
||||||
) -> Result<RuntimeProfileRedeemCodeRecord, SpacetimeClientError> {
|
) -> Result<RuntimeProfileRedeemCodeRecord, SpacetimeClientError> {
|
||||||
if !result.ok {
|
if !result.ok {
|
||||||
return Err(SpacetimeClientError::Procedure(
|
return Err(SpacetimeClientError::procedure_failed(result.error_message));
|
||||||
result
|
|
||||||
.error_message
|
|
||||||
.unwrap_or_else(|| "SpacetimeDB procedure 返回未知错误".to_string()),
|
|
||||||
));
|
|
||||||
}
|
}
|
||||||
|
|
||||||
let snapshot = result.record.ok_or_else(|| {
|
let snapshot = result
|
||||||
SpacetimeClientError::Procedure("SpacetimeDB procedure 未返回 redeem code 快照".to_string())
|
.record
|
||||||
})?;
|
.ok_or_else(|| SpacetimeClientError::missing_snapshot("redeem code 快照"))?;
|
||||||
|
|
||||||
Ok(build_runtime_profile_redeem_code_record(
|
Ok(build_runtime_profile_redeem_code_record(
|
||||||
map_runtime_profile_redeem_code_snapshot(snapshot),
|
map_runtime_profile_redeem_code_snapshot(snapshot),
|
||||||
@@ -874,18 +808,12 @@ pub(crate) fn map_runtime_profile_play_stats_procedure_result(
|
|||||||
result: RuntimeProfilePlayStatsProcedureResult,
|
result: RuntimeProfilePlayStatsProcedureResult,
|
||||||
) -> Result<RuntimeProfilePlayStatsRecord, SpacetimeClientError> {
|
) -> Result<RuntimeProfilePlayStatsRecord, SpacetimeClientError> {
|
||||||
if !result.ok {
|
if !result.ok {
|
||||||
return Err(SpacetimeClientError::Procedure(
|
return Err(SpacetimeClientError::procedure_failed(result.error_message));
|
||||||
result
|
|
||||||
.error_message
|
|
||||||
.unwrap_or_else(|| "SpacetimeDB procedure 返回未知错误".to_string()),
|
|
||||||
));
|
|
||||||
}
|
}
|
||||||
|
|
||||||
let snapshot = result.record.ok_or_else(|| {
|
let snapshot = result
|
||||||
SpacetimeClientError::Procedure(
|
.record
|
||||||
"SpacetimeDB procedure 未返回 profile play stats 快照".to_string(),
|
.ok_or_else(|| SpacetimeClientError::missing_snapshot("profile play stats 快照"))?;
|
||||||
)
|
|
||||||
})?;
|
|
||||||
|
|
||||||
Ok(build_runtime_profile_play_stats_record(
|
Ok(build_runtime_profile_play_stats_record(
|
||||||
map_runtime_profile_play_stats_snapshot(snapshot),
|
map_runtime_profile_play_stats_snapshot(snapshot),
|
||||||
@@ -896,11 +824,7 @@ pub(crate) fn map_runtime_snapshot_procedure_result(
|
|||||||
result: RuntimeSnapshotProcedureResult,
|
result: RuntimeSnapshotProcedureResult,
|
||||||
) -> Result<Option<RuntimeSnapshotRecord>, SpacetimeClientError> {
|
) -> Result<Option<RuntimeSnapshotRecord>, SpacetimeClientError> {
|
||||||
if !result.ok {
|
if !result.ok {
|
||||||
return Err(SpacetimeClientError::Procedure(
|
return Err(SpacetimeClientError::procedure_failed(result.error_message));
|
||||||
result
|
|
||||||
.error_message
|
|
||||||
.unwrap_or_else(|| "SpacetimeDB procedure 返回未知错误".to_string()),
|
|
||||||
));
|
|
||||||
}
|
}
|
||||||
|
|
||||||
result
|
result
|
||||||
@@ -915,11 +839,8 @@ pub(crate) fn map_runtime_snapshot_procedure_result(
|
|||||||
pub(crate) fn map_runtime_snapshot_required_procedure_result(
|
pub(crate) fn map_runtime_snapshot_required_procedure_result(
|
||||||
result: RuntimeSnapshotProcedureResult,
|
result: RuntimeSnapshotProcedureResult,
|
||||||
) -> Result<RuntimeSnapshotRecord, SpacetimeClientError> {
|
) -> Result<RuntimeSnapshotRecord, SpacetimeClientError> {
|
||||||
map_runtime_snapshot_procedure_result(result)?.ok_or_else(|| {
|
map_runtime_snapshot_procedure_result(result)?
|
||||||
SpacetimeClientError::Procedure(
|
.ok_or_else(|| SpacetimeClientError::missing_snapshot("runtime snapshot 快照"))
|
||||||
"SpacetimeDB procedure 未返回 runtime snapshot 快照".to_string(),
|
|
||||||
)
|
|
||||||
})
|
|
||||||
}
|
}
|
||||||
|
|
||||||
pub(crate) fn map_runtime_snapshot_delete_procedure_result(
|
pub(crate) fn map_runtime_snapshot_delete_procedure_result(
|
||||||
@@ -932,11 +853,7 @@ pub(crate) fn map_runtime_profile_save_archive_list_procedure_result(
|
|||||||
result: RuntimeProfileSaveArchiveProcedureResult,
|
result: RuntimeProfileSaveArchiveProcedureResult,
|
||||||
) -> Result<Vec<RuntimeProfileSaveArchiveRecord>, SpacetimeClientError> {
|
) -> Result<Vec<RuntimeProfileSaveArchiveRecord>, SpacetimeClientError> {
|
||||||
if !result.ok {
|
if !result.ok {
|
||||||
return Err(SpacetimeClientError::Procedure(
|
return Err(SpacetimeClientError::procedure_failed(result.error_message));
|
||||||
result
|
|
||||||
.error_message
|
|
||||||
.unwrap_or_else(|| "SpacetimeDB procedure 返回未知错误".to_string()),
|
|
||||||
));
|
|
||||||
}
|
}
|
||||||
|
|
||||||
result
|
result
|
||||||
@@ -955,23 +872,15 @@ pub(crate) fn map_runtime_profile_save_archive_resume_procedure_result(
|
|||||||
result: RuntimeProfileSaveArchiveProcedureResult,
|
result: RuntimeProfileSaveArchiveProcedureResult,
|
||||||
) -> Result<(RuntimeProfileSaveArchiveRecord, RuntimeSnapshotRecord), SpacetimeClientError> {
|
) -> Result<(RuntimeProfileSaveArchiveRecord, RuntimeSnapshotRecord), SpacetimeClientError> {
|
||||||
if !result.ok {
|
if !result.ok {
|
||||||
return Err(SpacetimeClientError::Procedure(
|
return Err(SpacetimeClientError::procedure_failed(result.error_message));
|
||||||
result
|
|
||||||
.error_message
|
|
||||||
.unwrap_or_else(|| "SpacetimeDB procedure 返回未知错误".to_string()),
|
|
||||||
));
|
|
||||||
}
|
}
|
||||||
|
|
||||||
let archive = result.record.ok_or_else(|| {
|
let archive = result
|
||||||
SpacetimeClientError::Procedure(
|
.record
|
||||||
"SpacetimeDB procedure 未返回 save archive 快照".to_string(),
|
.ok_or_else(|| SpacetimeClientError::missing_snapshot("save archive 快照"))?;
|
||||||
)
|
let snapshot = result
|
||||||
})?;
|
.current_snapshot
|
||||||
let snapshot = result.current_snapshot.ok_or_else(|| {
|
.ok_or_else(|| SpacetimeClientError::missing_snapshot("恢复后的 runtime snapshot"))?;
|
||||||
SpacetimeClientError::Procedure(
|
|
||||||
"SpacetimeDB procedure 未返回恢复后的 runtime snapshot".to_string(),
|
|
||||||
)
|
|
||||||
})?;
|
|
||||||
|
|
||||||
Ok((
|
Ok((
|
||||||
build_runtime_profile_save_archive_record(map_runtime_profile_save_archive_snapshot(
|
build_runtime_profile_save_archive_record(map_runtime_profile_save_archive_snapshot(
|
||||||
@@ -1004,11 +913,7 @@ pub(crate) fn map_custom_world_profile_list_result(
|
|||||||
result: CustomWorldProfileListResult,
|
result: CustomWorldProfileListResult,
|
||||||
) -> Result<Vec<CustomWorldLibraryEntryRecord>, SpacetimeClientError> {
|
) -> Result<Vec<CustomWorldLibraryEntryRecord>, SpacetimeClientError> {
|
||||||
if !result.ok {
|
if !result.ok {
|
||||||
return Err(SpacetimeClientError::Procedure(
|
return Err(SpacetimeClientError::procedure_failed(result.error_message));
|
||||||
result
|
|
||||||
.error_message
|
|
||||||
.unwrap_or_else(|| "SpacetimeDB procedure 返回未知错误".to_string()),
|
|
||||||
));
|
|
||||||
}
|
}
|
||||||
|
|
||||||
result
|
result
|
||||||
@@ -1022,11 +927,7 @@ pub(crate) fn map_custom_world_library_detail_result(
|
|||||||
result: CustomWorldLibraryMutationResult,
|
result: CustomWorldLibraryMutationResult,
|
||||||
) -> Result<CustomWorldLibraryMutationRecord, SpacetimeClientError> {
|
) -> Result<CustomWorldLibraryMutationRecord, SpacetimeClientError> {
|
||||||
if !result.ok {
|
if !result.ok {
|
||||||
return Err(SpacetimeClientError::Procedure(
|
return Err(SpacetimeClientError::procedure_failed(result.error_message));
|
||||||
result
|
|
||||||
.error_message
|
|
||||||
.unwrap_or_else(|| "SpacetimeDB procedure 返回未知错误".to_string()),
|
|
||||||
));
|
|
||||||
}
|
}
|
||||||
|
|
||||||
let entry = result
|
let entry = result
|
||||||
@@ -1048,11 +949,7 @@ pub(crate) fn map_custom_world_gallery_list_result(
|
|||||||
result: CustomWorldGalleryListResult,
|
result: CustomWorldGalleryListResult,
|
||||||
) -> Result<Vec<CustomWorldGalleryEntryRecord>, SpacetimeClientError> {
|
) -> Result<Vec<CustomWorldGalleryEntryRecord>, SpacetimeClientError> {
|
||||||
if !result.ok {
|
if !result.ok {
|
||||||
return Err(SpacetimeClientError::Procedure(
|
return Err(SpacetimeClientError::procedure_failed(result.error_message));
|
||||||
result
|
|
||||||
.error_message
|
|
||||||
.unwrap_or_else(|| "SpacetimeDB procedure 返回未知错误".to_string()),
|
|
||||||
));
|
|
||||||
}
|
}
|
||||||
|
|
||||||
Ok(result
|
Ok(result
|
||||||
@@ -1066,18 +963,12 @@ pub(crate) fn map_custom_world_library_mutation_result(
|
|||||||
result: CustomWorldLibraryMutationResult,
|
result: CustomWorldLibraryMutationResult,
|
||||||
) -> Result<CustomWorldLibraryMutationRecord, SpacetimeClientError> {
|
) -> Result<CustomWorldLibraryMutationRecord, SpacetimeClientError> {
|
||||||
if !result.ok {
|
if !result.ok {
|
||||||
return Err(SpacetimeClientError::Procedure(
|
return Err(SpacetimeClientError::procedure_failed(result.error_message));
|
||||||
result
|
|
||||||
.error_message
|
|
||||||
.unwrap_or_else(|| "SpacetimeDB procedure 返回未知错误".to_string()),
|
|
||||||
));
|
|
||||||
}
|
}
|
||||||
|
|
||||||
let entry = result
|
let entry = result
|
||||||
.entry
|
.entry
|
||||||
.ok_or_else(|| {
|
.ok_or_else(|| SpacetimeClientError::missing_snapshot("custom world entry"))
|
||||||
SpacetimeClientError::Procedure("SpacetimeDB 未返回 custom world entry".to_string())
|
|
||||||
})
|
|
||||||
.and_then(map_custom_world_library_entry_from_profile_snapshot)?;
|
.and_then(map_custom_world_library_entry_from_profile_snapshot)?;
|
||||||
let gallery_entry = result
|
let gallery_entry = result
|
||||||
.gallery_entry
|
.gallery_entry
|
||||||
@@ -1094,26 +985,16 @@ pub(crate) fn map_custom_world_publish_world_result(
|
|||||||
result: CustomWorldPublishWorldResult,
|
result: CustomWorldPublishWorldResult,
|
||||||
) -> Result<CustomWorldPublishWorldRecord, SpacetimeClientError> {
|
) -> Result<CustomWorldPublishWorldRecord, SpacetimeClientError> {
|
||||||
if !result.ok {
|
if !result.ok {
|
||||||
return Err(SpacetimeClientError::Procedure(
|
return Err(SpacetimeClientError::procedure_failed(result.error_message));
|
||||||
result
|
|
||||||
.error_message
|
|
||||||
.unwrap_or_else(|| "SpacetimeDB procedure 返回未知错误".to_string()),
|
|
||||||
));
|
|
||||||
}
|
}
|
||||||
|
|
||||||
let compiled_record = result
|
let compiled_record = result
|
||||||
.compiled_record
|
.compiled_record
|
||||||
.ok_or_else(|| {
|
.ok_or_else(|| SpacetimeClientError::missing_snapshot("published profile compile 快照"))
|
||||||
SpacetimeClientError::Procedure(
|
|
||||||
"SpacetimeDB procedure 未返回 published profile compile 快照".to_string(),
|
|
||||||
)
|
|
||||||
})
|
|
||||||
.and_then(map_custom_world_published_profile_compile_snapshot)?;
|
.and_then(map_custom_world_published_profile_compile_snapshot)?;
|
||||||
let entry = result
|
let entry = result
|
||||||
.entry
|
.entry
|
||||||
.ok_or_else(|| {
|
.ok_or_else(|| SpacetimeClientError::missing_snapshot("custom world entry"))
|
||||||
SpacetimeClientError::Procedure("SpacetimeDB 未返回 custom world entry".to_string())
|
|
||||||
})
|
|
||||||
.and_then(map_custom_world_library_entry_from_profile_snapshot)?;
|
.and_then(map_custom_world_library_entry_from_profile_snapshot)?;
|
||||||
let gallery_entry = result
|
let gallery_entry = result
|
||||||
.gallery_entry
|
.gallery_entry
|
||||||
@@ -1121,9 +1002,7 @@ pub(crate) fn map_custom_world_publish_world_result(
|
|||||||
.transpose()?;
|
.transpose()?;
|
||||||
let session_stage = result
|
let session_stage = result
|
||||||
.session_stage
|
.session_stage
|
||||||
.ok_or_else(|| {
|
.ok_or_else(|| SpacetimeClientError::missing_snapshot("session stage"))
|
||||||
SpacetimeClientError::Procedure("SpacetimeDB 未返回 session stage".to_string())
|
|
||||||
})
|
|
||||||
.map(map_rpg_agent_stage)?;
|
.map(map_rpg_agent_stage)?;
|
||||||
|
|
||||||
Ok(CustomWorldPublishWorldRecord {
|
Ok(CustomWorldPublishWorldRecord {
|
||||||
@@ -1138,18 +1017,12 @@ pub(crate) fn map_custom_world_agent_session_procedure_result(
|
|||||||
result: CustomWorldAgentSessionProcedureResult,
|
result: CustomWorldAgentSessionProcedureResult,
|
||||||
) -> Result<CustomWorldAgentSessionRecord, SpacetimeClientError> {
|
) -> Result<CustomWorldAgentSessionRecord, SpacetimeClientError> {
|
||||||
if !result.ok {
|
if !result.ok {
|
||||||
return Err(SpacetimeClientError::Procedure(
|
return Err(SpacetimeClientError::procedure_failed(result.error_message));
|
||||||
result
|
|
||||||
.error_message
|
|
||||||
.unwrap_or_else(|| "SpacetimeDB procedure 返回未知错误".to_string()),
|
|
||||||
));
|
|
||||||
}
|
}
|
||||||
|
|
||||||
let session = result.session.ok_or_else(|| {
|
let session = result
|
||||||
SpacetimeClientError::Procedure(
|
.session
|
||||||
"SpacetimeDB procedure 未返回 custom world agent session 快照".to_string(),
|
.ok_or_else(|| SpacetimeClientError::missing_snapshot("custom world agent session 快照"))?;
|
||||||
)
|
|
||||||
})?;
|
|
||||||
|
|
||||||
map_custom_world_agent_session_snapshot(session)
|
map_custom_world_agent_session_snapshot(session)
|
||||||
}
|
}
|
||||||
@@ -1158,17 +1031,11 @@ pub(crate) fn map_custom_world_agent_operation_procedure_result(
|
|||||||
result: CustomWorldAgentOperationProcedureResult,
|
result: CustomWorldAgentOperationProcedureResult,
|
||||||
) -> Result<CustomWorldAgentOperationRecord, SpacetimeClientError> {
|
) -> Result<CustomWorldAgentOperationRecord, SpacetimeClientError> {
|
||||||
if !result.ok {
|
if !result.ok {
|
||||||
return Err(SpacetimeClientError::Procedure(
|
return Err(SpacetimeClientError::procedure_failed(result.error_message));
|
||||||
result
|
|
||||||
.error_message
|
|
||||||
.unwrap_or_else(|| "SpacetimeDB procedure 返回未知错误".to_string()),
|
|
||||||
));
|
|
||||||
}
|
}
|
||||||
|
|
||||||
let operation = result.operation.ok_or_else(|| {
|
let operation = result.operation.ok_or_else(|| {
|
||||||
SpacetimeClientError::Procedure(
|
SpacetimeClientError::missing_snapshot("custom world agent operation 快照")
|
||||||
"SpacetimeDB procedure 未返回 custom world agent operation 快照".to_string(),
|
|
||||||
)
|
|
||||||
})?;
|
})?;
|
||||||
|
|
||||||
Ok(map_custom_world_agent_operation_snapshot(operation))
|
Ok(map_custom_world_agent_operation_snapshot(operation))
|
||||||
@@ -1178,11 +1045,7 @@ pub(crate) fn map_custom_world_works_list_result(
|
|||||||
result: CustomWorldWorksListResult,
|
result: CustomWorldWorksListResult,
|
||||||
) -> Result<Vec<CustomWorldWorkSummaryRecord>, SpacetimeClientError> {
|
) -> Result<Vec<CustomWorldWorkSummaryRecord>, SpacetimeClientError> {
|
||||||
if !result.ok {
|
if !result.ok {
|
||||||
return Err(SpacetimeClientError::Procedure(
|
return Err(SpacetimeClientError::procedure_failed(result.error_message));
|
||||||
result
|
|
||||||
.error_message
|
|
||||||
.unwrap_or_else(|| "SpacetimeDB procedure 返回未知错误".to_string()),
|
|
||||||
));
|
|
||||||
}
|
}
|
||||||
|
|
||||||
result
|
result
|
||||||
@@ -1196,18 +1059,12 @@ pub(crate) fn map_custom_world_draft_card_detail_result(
|
|||||||
result: CustomWorldDraftCardDetailResult,
|
result: CustomWorldDraftCardDetailResult,
|
||||||
) -> Result<CustomWorldDraftCardDetailRecord, SpacetimeClientError> {
|
) -> Result<CustomWorldDraftCardDetailRecord, SpacetimeClientError> {
|
||||||
if !result.ok {
|
if !result.ok {
|
||||||
return Err(SpacetimeClientError::Procedure(
|
return Err(SpacetimeClientError::procedure_failed(result.error_message));
|
||||||
result
|
|
||||||
.error_message
|
|
||||||
.unwrap_or_else(|| "SpacetimeDB procedure 返回未知错误".to_string()),
|
|
||||||
));
|
|
||||||
}
|
}
|
||||||
|
|
||||||
let card = result.card.ok_or_else(|| {
|
let card = result
|
||||||
SpacetimeClientError::Procedure(
|
.card
|
||||||
"SpacetimeDB procedure 未返回 custom world card detail 快照".to_string(),
|
.ok_or_else(|| SpacetimeClientError::missing_snapshot("custom world card detail 快照"))?;
|
||||||
)
|
|
||||||
})?;
|
|
||||||
|
|
||||||
map_custom_world_draft_card_detail_snapshot(card)
|
map_custom_world_draft_card_detail_snapshot(card)
|
||||||
}
|
}
|
||||||
@@ -1216,17 +1073,11 @@ pub(crate) fn map_custom_world_agent_action_execute_result(
|
|||||||
result: CustomWorldAgentActionExecuteResult,
|
result: CustomWorldAgentActionExecuteResult,
|
||||||
) -> Result<CustomWorldAgentActionExecuteRecord, SpacetimeClientError> {
|
) -> Result<CustomWorldAgentActionExecuteRecord, SpacetimeClientError> {
|
||||||
if !result.ok {
|
if !result.ok {
|
||||||
return Err(SpacetimeClientError::Procedure(
|
return Err(SpacetimeClientError::procedure_failed(result.error_message));
|
||||||
result
|
|
||||||
.error_message
|
|
||||||
.unwrap_or_else(|| "SpacetimeDB procedure 返回未知错误".to_string()),
|
|
||||||
));
|
|
||||||
}
|
}
|
||||||
|
|
||||||
let operation = result.operation.ok_or_else(|| {
|
let operation = result.operation.ok_or_else(|| {
|
||||||
SpacetimeClientError::Procedure(
|
SpacetimeClientError::missing_snapshot("custom world action operation 快照")
|
||||||
"SpacetimeDB procedure 未返回 custom world action operation 快照".to_string(),
|
|
||||||
)
|
|
||||||
})?;
|
})?;
|
||||||
|
|
||||||
Ok(CustomWorldAgentActionExecuteRecord {
|
Ok(CustomWorldAgentActionExecuteRecord {
|
||||||
@@ -1238,18 +1089,12 @@ pub(crate) fn map_puzzle_agent_session_procedure_result(
|
|||||||
result: PuzzleAgentSessionProcedureResult,
|
result: PuzzleAgentSessionProcedureResult,
|
||||||
) -> Result<PuzzleAgentSessionRecord, SpacetimeClientError> {
|
) -> Result<PuzzleAgentSessionRecord, SpacetimeClientError> {
|
||||||
if !result.ok {
|
if !result.ok {
|
||||||
return Err(SpacetimeClientError::Procedure(
|
return Err(SpacetimeClientError::procedure_failed(result.error_message));
|
||||||
result
|
|
||||||
.error_message
|
|
||||||
.unwrap_or_else(|| "SpacetimeDB procedure 返回未知错误".to_string()),
|
|
||||||
));
|
|
||||||
}
|
}
|
||||||
|
|
||||||
let session_json = result.session_json.ok_or_else(|| {
|
let session_json = result
|
||||||
SpacetimeClientError::Procedure(
|
.session_json
|
||||||
"SpacetimeDB procedure 未返回 puzzle agent session 快照".to_string(),
|
.ok_or_else(|| SpacetimeClientError::missing_snapshot("puzzle agent session 快照"))?;
|
||||||
)
|
|
||||||
})?;
|
|
||||||
let session: DomainPuzzleAgentSessionSnapshot =
|
let session: DomainPuzzleAgentSessionSnapshot =
|
||||||
serde_json::from_str(&session_json).map_err(|error| {
|
serde_json::from_str(&session_json).map_err(|error| {
|
||||||
SpacetimeClientError::Runtime(format!("puzzle agent session_json 非法: {error}"))
|
SpacetimeClientError::Runtime(format!("puzzle agent session_json 非法: {error}"))
|
||||||
@@ -1261,16 +1106,12 @@ pub(crate) fn map_puzzle_work_procedure_result(
|
|||||||
result: PuzzleWorkProcedureResult,
|
result: PuzzleWorkProcedureResult,
|
||||||
) -> Result<PuzzleWorkProfileRecord, SpacetimeClientError> {
|
) -> Result<PuzzleWorkProfileRecord, SpacetimeClientError> {
|
||||||
if !result.ok {
|
if !result.ok {
|
||||||
return Err(SpacetimeClientError::Procedure(
|
return Err(SpacetimeClientError::procedure_failed(result.error_message));
|
||||||
result
|
|
||||||
.error_message
|
|
||||||
.unwrap_or_else(|| "SpacetimeDB procedure 返回未知错误".to_string()),
|
|
||||||
));
|
|
||||||
}
|
}
|
||||||
|
|
||||||
let item_json = result.item_json.ok_or_else(|| {
|
let item_json = result
|
||||||
SpacetimeClientError::Procedure("SpacetimeDB procedure 未返回 puzzle work 快照".to_string())
|
.item_json
|
||||||
})?;
|
.ok_or_else(|| SpacetimeClientError::missing_snapshot("puzzle work 快照"))?;
|
||||||
let item: DomainPuzzleWorkProfile = serde_json::from_str(&item_json).map_err(|error| {
|
let item: DomainPuzzleWorkProfile = serde_json::from_str(&item_json).map_err(|error| {
|
||||||
SpacetimeClientError::Runtime(format!("puzzle work item_json 非法: {error}"))
|
SpacetimeClientError::Runtime(format!("puzzle work item_json 非法: {error}"))
|
||||||
})?;
|
})?;
|
||||||
@@ -1281,18 +1122,12 @@ pub(crate) fn map_puzzle_works_procedure_result(
|
|||||||
result: PuzzleWorksProcedureResult,
|
result: PuzzleWorksProcedureResult,
|
||||||
) -> Result<Vec<PuzzleWorkProfileRecord>, SpacetimeClientError> {
|
) -> Result<Vec<PuzzleWorkProfileRecord>, SpacetimeClientError> {
|
||||||
if !result.ok {
|
if !result.ok {
|
||||||
return Err(SpacetimeClientError::Procedure(
|
return Err(SpacetimeClientError::procedure_failed(result.error_message));
|
||||||
result
|
|
||||||
.error_message
|
|
||||||
.unwrap_or_else(|| "SpacetimeDB procedure 返回未知错误".to_string()),
|
|
||||||
));
|
|
||||||
}
|
}
|
||||||
|
|
||||||
let items_json = result.items_json.ok_or_else(|| {
|
let items_json = result
|
||||||
SpacetimeClientError::Procedure(
|
.items_json
|
||||||
"SpacetimeDB procedure 未返回 puzzle works 快照".to_string(),
|
.ok_or_else(|| SpacetimeClientError::missing_snapshot("puzzle works 快照"))?;
|
||||||
)
|
|
||||||
})?;
|
|
||||||
let items: Vec<DomainPuzzleWorkProfile> =
|
let items: Vec<DomainPuzzleWorkProfile> =
|
||||||
serde_json::from_str(&items_json).map_err(|error| {
|
serde_json::from_str(&items_json).map_err(|error| {
|
||||||
SpacetimeClientError::Runtime(format!("puzzle works items_json 非法: {error}"))
|
SpacetimeClientError::Runtime(format!("puzzle works items_json 非法: {error}"))
|
||||||
@@ -1304,16 +1139,12 @@ pub(crate) fn map_puzzle_run_procedure_result(
|
|||||||
result: PuzzleRunProcedureResult,
|
result: PuzzleRunProcedureResult,
|
||||||
) -> Result<PuzzleRunRecord, SpacetimeClientError> {
|
) -> Result<PuzzleRunRecord, SpacetimeClientError> {
|
||||||
if !result.ok {
|
if !result.ok {
|
||||||
return Err(SpacetimeClientError::Procedure(
|
return Err(SpacetimeClientError::procedure_failed(result.error_message));
|
||||||
result
|
|
||||||
.error_message
|
|
||||||
.unwrap_or_else(|| "SpacetimeDB procedure 返回未知错误".to_string()),
|
|
||||||
));
|
|
||||||
}
|
}
|
||||||
|
|
||||||
let run_json = result.run_json.ok_or_else(|| {
|
let run_json = result
|
||||||
SpacetimeClientError::Procedure("SpacetimeDB procedure 未返回 puzzle run 快照".to_string())
|
.run_json
|
||||||
})?;
|
.ok_or_else(|| SpacetimeClientError::missing_snapshot("puzzle run 快照"))?;
|
||||||
let run: DomainPuzzleRunSnapshot = serde_json::from_str(&run_json).map_err(|error| {
|
let run: DomainPuzzleRunSnapshot = serde_json::from_str(&run_json).map_err(|error| {
|
||||||
SpacetimeClientError::Runtime(format!("puzzle run run_json 非法: {error}"))
|
SpacetimeClientError::Runtime(format!("puzzle run run_json 非法: {error}"))
|
||||||
})?;
|
})?;
|
||||||
@@ -3214,7 +3045,7 @@ pub(crate) fn parse_big_fish_creation_stage(
|
|||||||
"ready_to_publish" => Ok(BigFishCreationStage::ReadyToPublish),
|
"ready_to_publish" => Ok(BigFishCreationStage::ReadyToPublish),
|
||||||
"published" => Ok(BigFishCreationStage::Published),
|
"published" => Ok(BigFishCreationStage::Published),
|
||||||
other => Err(SpacetimeClientError::Runtime(format!(
|
other => Err(SpacetimeClientError::Runtime(format!(
|
||||||
"big fish creation stage `{other}` ??????"
|
"big fish creation stage `{other}` 当前尚未支持"
|
||||||
))),
|
))),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -21,7 +21,7 @@ impl SpacetimeClient {
|
|||||||
procedure_input,
|
procedure_input,
|
||||||
move |_, result| {
|
move |_, result| {
|
||||||
let mapped = result
|
let mapped = result
|
||||||
.map_err(|error| SpacetimeClientError::Procedure(error.to_string()))
|
.map_err(SpacetimeClientError::from_sdk_error)
|
||||||
.and_then(map_puzzle_agent_session_procedure_result);
|
.and_then(map_puzzle_agent_session_procedure_result);
|
||||||
send_once(&sender, mapped);
|
send_once(&sender, mapped);
|
||||||
},
|
},
|
||||||
@@ -45,7 +45,7 @@ impl SpacetimeClient {
|
|||||||
procedure_input,
|
procedure_input,
|
||||||
move |_, result| {
|
move |_, result| {
|
||||||
let mapped = result
|
let mapped = result
|
||||||
.map_err(|error| SpacetimeClientError::Procedure(error.to_string()))
|
.map_err(SpacetimeClientError::from_sdk_error)
|
||||||
.and_then(map_puzzle_agent_session_procedure_result);
|
.and_then(map_puzzle_agent_session_procedure_result);
|
||||||
send_once(&sender, mapped);
|
send_once(&sender, mapped);
|
||||||
},
|
},
|
||||||
@@ -71,7 +71,7 @@ impl SpacetimeClient {
|
|||||||
procedure_input,
|
procedure_input,
|
||||||
move |_, result| {
|
move |_, result| {
|
||||||
let mapped = result
|
let mapped = result
|
||||||
.map_err(|error| SpacetimeClientError::Procedure(error.to_string()))
|
.map_err(SpacetimeClientError::from_sdk_error)
|
||||||
.and_then(map_puzzle_agent_session_procedure_result);
|
.and_then(map_puzzle_agent_session_procedure_result);
|
||||||
send_once(&sender, mapped);
|
send_once(&sender, mapped);
|
||||||
},
|
},
|
||||||
@@ -101,7 +101,7 @@ impl SpacetimeClient {
|
|||||||
.procedures()
|
.procedures()
|
||||||
.finalize_puzzle_agent_message_turn_then(procedure_input, move |_, result| {
|
.finalize_puzzle_agent_message_turn_then(procedure_input, move |_, result| {
|
||||||
let mapped = result
|
let mapped = result
|
||||||
.map_err(|error| SpacetimeClientError::Procedure(error.to_string()))
|
.map_err(SpacetimeClientError::from_sdk_error)
|
||||||
.and_then(map_puzzle_agent_session_procedure_result);
|
.and_then(map_puzzle_agent_session_procedure_result);
|
||||||
send_once(&sender, mapped);
|
send_once(&sender, mapped);
|
||||||
});
|
});
|
||||||
@@ -126,7 +126,7 @@ impl SpacetimeClient {
|
|||||||
procedure_input,
|
procedure_input,
|
||||||
move |_, result| {
|
move |_, result| {
|
||||||
let mapped = result
|
let mapped = result
|
||||||
.map_err(|error| SpacetimeClientError::Procedure(error.to_string()))
|
.map_err(SpacetimeClientError::from_sdk_error)
|
||||||
.and_then(map_puzzle_agent_session_procedure_result);
|
.and_then(map_puzzle_agent_session_procedure_result);
|
||||||
send_once(&sender, mapped);
|
send_once(&sender, mapped);
|
||||||
},
|
},
|
||||||
@@ -151,7 +151,7 @@ impl SpacetimeClient {
|
|||||||
procedure_input,
|
procedure_input,
|
||||||
move |_, result| {
|
move |_, result| {
|
||||||
let mapped = result
|
let mapped = result
|
||||||
.map_err(|error| SpacetimeClientError::Procedure(error.to_string()))
|
.map_err(SpacetimeClientError::from_sdk_error)
|
||||||
.and_then(map_puzzle_agent_session_procedure_result);
|
.and_then(map_puzzle_agent_session_procedure_result);
|
||||||
send_once(&sender, mapped);
|
send_once(&sender, mapped);
|
||||||
},
|
},
|
||||||
@@ -176,7 +176,7 @@ impl SpacetimeClient {
|
|||||||
procedure_input,
|
procedure_input,
|
||||||
move |_, result| {
|
move |_, result| {
|
||||||
let mapped = result
|
let mapped = result
|
||||||
.map_err(|error| SpacetimeClientError::Procedure(error.to_string()))
|
.map_err(SpacetimeClientError::from_sdk_error)
|
||||||
.and_then(map_puzzle_agent_session_procedure_result);
|
.and_then(map_puzzle_agent_session_procedure_result);
|
||||||
send_once(&sender, mapped);
|
send_once(&sender, mapped);
|
||||||
},
|
},
|
||||||
@@ -206,7 +206,7 @@ impl SpacetimeClient {
|
|||||||
.procedures()
|
.procedures()
|
||||||
.publish_puzzle_work_then(procedure_input, move |_, result| {
|
.publish_puzzle_work_then(procedure_input, move |_, result| {
|
||||||
let mapped = result
|
let mapped = result
|
||||||
.map_err(|error| SpacetimeClientError::Procedure(error.to_string()))
|
.map_err(SpacetimeClientError::from_sdk_error)
|
||||||
.and_then(map_puzzle_work_procedure_result);
|
.and_then(map_puzzle_work_procedure_result);
|
||||||
send_once(&sender, mapped);
|
send_once(&sender, mapped);
|
||||||
});
|
});
|
||||||
@@ -225,7 +225,7 @@ impl SpacetimeClient {
|
|||||||
.procedures()
|
.procedures()
|
||||||
.list_puzzle_works_then(procedure_input, move |_, result| {
|
.list_puzzle_works_then(procedure_input, move |_, result| {
|
||||||
let mapped = result
|
let mapped = result
|
||||||
.map_err(|error| SpacetimeClientError::Procedure(error.to_string()))
|
.map_err(SpacetimeClientError::from_sdk_error)
|
||||||
.and_then(map_puzzle_works_procedure_result);
|
.and_then(map_puzzle_works_procedure_result);
|
||||||
send_once(&sender, mapped);
|
send_once(&sender, mapped);
|
||||||
});
|
});
|
||||||
@@ -244,7 +244,7 @@ impl SpacetimeClient {
|
|||||||
procedure_input,
|
procedure_input,
|
||||||
move |_, result| {
|
move |_, result| {
|
||||||
let mapped = result
|
let mapped = result
|
||||||
.map_err(|error| SpacetimeClientError::Procedure(error.to_string()))
|
.map_err(SpacetimeClientError::from_sdk_error)
|
||||||
.and_then(map_puzzle_work_procedure_result);
|
.and_then(map_puzzle_work_procedure_result);
|
||||||
send_once(&sender, mapped);
|
send_once(&sender, mapped);
|
||||||
},
|
},
|
||||||
@@ -273,7 +273,7 @@ impl SpacetimeClient {
|
|||||||
.procedures()
|
.procedures()
|
||||||
.update_puzzle_work_then(procedure_input, move |_, result| {
|
.update_puzzle_work_then(procedure_input, move |_, result| {
|
||||||
let mapped = result
|
let mapped = result
|
||||||
.map_err(|error| SpacetimeClientError::Procedure(error.to_string()))
|
.map_err(SpacetimeClientError::from_sdk_error)
|
||||||
.and_then(map_puzzle_work_procedure_result);
|
.and_then(map_puzzle_work_procedure_result);
|
||||||
send_once(&sender, mapped);
|
send_once(&sender, mapped);
|
||||||
});
|
});
|
||||||
@@ -296,7 +296,7 @@ impl SpacetimeClient {
|
|||||||
.procedures()
|
.procedures()
|
||||||
.delete_puzzle_work_then(procedure_input, move |_, result| {
|
.delete_puzzle_work_then(procedure_input, move |_, result| {
|
||||||
let mapped = result
|
let mapped = result
|
||||||
.map_err(|error| SpacetimeClientError::Procedure(error.to_string()))
|
.map_err(SpacetimeClientError::from_sdk_error)
|
||||||
.and_then(map_puzzle_works_procedure_result);
|
.and_then(map_puzzle_works_procedure_result);
|
||||||
send_once(&sender, mapped);
|
send_once(&sender, mapped);
|
||||||
});
|
});
|
||||||
@@ -312,7 +312,7 @@ impl SpacetimeClient {
|
|||||||
.procedures()
|
.procedures()
|
||||||
.list_puzzle_gallery_then(move |_, result| {
|
.list_puzzle_gallery_then(move |_, result| {
|
||||||
let mapped = result
|
let mapped = result
|
||||||
.map_err(|error| SpacetimeClientError::Procedure(error.to_string()))
|
.map_err(SpacetimeClientError::from_sdk_error)
|
||||||
.and_then(map_puzzle_works_procedure_result);
|
.and_then(map_puzzle_works_procedure_result);
|
||||||
send_once(&sender, mapped);
|
send_once(&sender, mapped);
|
||||||
});
|
});
|
||||||
@@ -331,7 +331,7 @@ impl SpacetimeClient {
|
|||||||
procedure_input,
|
procedure_input,
|
||||||
move |_, result| {
|
move |_, result| {
|
||||||
let mapped = result
|
let mapped = result
|
||||||
.map_err(|error| SpacetimeClientError::Procedure(error.to_string()))
|
.map_err(SpacetimeClientError::from_sdk_error)
|
||||||
.and_then(map_puzzle_work_procedure_result);
|
.and_then(map_puzzle_work_procedure_result);
|
||||||
send_once(&sender, mapped);
|
send_once(&sender, mapped);
|
||||||
},
|
},
|
||||||
@@ -356,7 +356,7 @@ impl SpacetimeClient {
|
|||||||
.procedures()
|
.procedures()
|
||||||
.start_puzzle_run_then(procedure_input, move |_, result| {
|
.start_puzzle_run_then(procedure_input, move |_, result| {
|
||||||
let mapped = result
|
let mapped = result
|
||||||
.map_err(|error| SpacetimeClientError::Procedure(error.to_string()))
|
.map_err(SpacetimeClientError::from_sdk_error)
|
||||||
.and_then(map_puzzle_run_procedure_result);
|
.and_then(map_puzzle_run_procedure_result);
|
||||||
send_once(&sender, mapped);
|
send_once(&sender, mapped);
|
||||||
});
|
});
|
||||||
@@ -379,7 +379,7 @@ impl SpacetimeClient {
|
|||||||
.procedures()
|
.procedures()
|
||||||
.get_puzzle_run_then(procedure_input, move |_, result| {
|
.get_puzzle_run_then(procedure_input, move |_, result| {
|
||||||
let mapped = result
|
let mapped = result
|
||||||
.map_err(|error| SpacetimeClientError::Procedure(error.to_string()))
|
.map_err(SpacetimeClientError::from_sdk_error)
|
||||||
.and_then(map_puzzle_run_procedure_result);
|
.and_then(map_puzzle_run_procedure_result);
|
||||||
send_once(&sender, mapped);
|
send_once(&sender, mapped);
|
||||||
});
|
});
|
||||||
@@ -404,7 +404,7 @@ impl SpacetimeClient {
|
|||||||
.procedures()
|
.procedures()
|
||||||
.swap_puzzle_pieces_then(procedure_input, move |_, result| {
|
.swap_puzzle_pieces_then(procedure_input, move |_, result| {
|
||||||
let mapped = result
|
let mapped = result
|
||||||
.map_err(|error| SpacetimeClientError::Procedure(error.to_string()))
|
.map_err(SpacetimeClientError::from_sdk_error)
|
||||||
.and_then(map_puzzle_run_procedure_result);
|
.and_then(map_puzzle_run_procedure_result);
|
||||||
send_once(&sender, mapped);
|
send_once(&sender, mapped);
|
||||||
});
|
});
|
||||||
@@ -430,7 +430,7 @@ impl SpacetimeClient {
|
|||||||
procedure_input,
|
procedure_input,
|
||||||
move |_, result| {
|
move |_, result| {
|
||||||
let mapped = result
|
let mapped = result
|
||||||
.map_err(|error| SpacetimeClientError::Procedure(error.to_string()))
|
.map_err(SpacetimeClientError::from_sdk_error)
|
||||||
.and_then(map_puzzle_run_procedure_result);
|
.and_then(map_puzzle_run_procedure_result);
|
||||||
send_once(&sender, mapped);
|
send_once(&sender, mapped);
|
||||||
},
|
},
|
||||||
@@ -454,7 +454,7 @@ impl SpacetimeClient {
|
|||||||
procedure_input,
|
procedure_input,
|
||||||
move |_, result| {
|
move |_, result| {
|
||||||
let mapped = result
|
let mapped = result
|
||||||
.map_err(|error| SpacetimeClientError::Procedure(error.to_string()))
|
.map_err(SpacetimeClientError::from_sdk_error)
|
||||||
.and_then(map_puzzle_run_procedure_result);
|
.and_then(map_puzzle_run_procedure_result);
|
||||||
send_once(&sender, mapped);
|
send_once(&sender, mapped);
|
||||||
},
|
},
|
||||||
@@ -482,7 +482,7 @@ impl SpacetimeClient {
|
|||||||
.procedures()
|
.procedures()
|
||||||
.submit_puzzle_leaderboard_entry_then(procedure_input, move |_, result| {
|
.submit_puzzle_leaderboard_entry_then(procedure_input, move |_, result| {
|
||||||
let mapped = result
|
let mapped = result
|
||||||
.map_err(|error| SpacetimeClientError::Procedure(error.to_string()))
|
.map_err(SpacetimeClientError::from_sdk_error)
|
||||||
.and_then(map_puzzle_run_procedure_result);
|
.and_then(map_puzzle_run_procedure_result);
|
||||||
send_once(&sender, mapped);
|
send_once(&sender, mapped);
|
||||||
});
|
});
|
||||||
|
|||||||
@@ -14,7 +14,7 @@ impl SpacetimeClient {
|
|||||||
procedure_input,
|
procedure_input,
|
||||||
move |_, result| {
|
move |_, result| {
|
||||||
let mapped = result
|
let mapped = result
|
||||||
.map_err(|error| SpacetimeClientError::Procedure(error.to_string()))
|
.map_err(SpacetimeClientError::from_sdk_error)
|
||||||
.and_then(map_runtime_setting_procedure_result);
|
.and_then(map_runtime_setting_procedure_result);
|
||||||
send_once(&sender, mapped);
|
send_once(&sender, mapped);
|
||||||
},
|
},
|
||||||
@@ -36,7 +36,7 @@ impl SpacetimeClient {
|
|||||||
procedure_input,
|
procedure_input,
|
||||||
move |_, result| {
|
move |_, result| {
|
||||||
let mapped = result
|
let mapped = result
|
||||||
.map_err(|error| SpacetimeClientError::Procedure(error.to_string()))
|
.map_err(SpacetimeClientError::from_sdk_error)
|
||||||
.and_then(map_runtime_browse_history_procedure_result);
|
.and_then(map_runtime_browse_history_procedure_result);
|
||||||
send_once(&sender, mapped);
|
send_once(&sender, mapped);
|
||||||
},
|
},
|
||||||
@@ -58,7 +58,7 @@ impl SpacetimeClient {
|
|||||||
procedure_input,
|
procedure_input,
|
||||||
move |_, result| {
|
move |_, result| {
|
||||||
let mapped = result
|
let mapped = result
|
||||||
.map_err(|error| SpacetimeClientError::Procedure(error.to_string()))
|
.map_err(SpacetimeClientError::from_sdk_error)
|
||||||
.and_then(map_runtime_profile_dashboard_procedure_result);
|
.and_then(map_runtime_profile_dashboard_procedure_result);
|
||||||
send_once(&sender, mapped);
|
send_once(&sender, mapped);
|
||||||
},
|
},
|
||||||
@@ -80,7 +80,7 @@ impl SpacetimeClient {
|
|||||||
procedure_input,
|
procedure_input,
|
||||||
move |_, result| {
|
move |_, result| {
|
||||||
let mapped = result
|
let mapped = result
|
||||||
.map_err(|error| SpacetimeClientError::Procedure(error.to_string()))
|
.map_err(SpacetimeClientError::from_sdk_error)
|
||||||
.and_then(map_runtime_profile_wallet_ledger_procedure_result);
|
.and_then(map_runtime_profile_wallet_ledger_procedure_result);
|
||||||
send_once(&sender, mapped);
|
send_once(&sender, mapped);
|
||||||
},
|
},
|
||||||
@@ -112,7 +112,7 @@ impl SpacetimeClient {
|
|||||||
procedure_input,
|
procedure_input,
|
||||||
move |_, result| {
|
move |_, result| {
|
||||||
let mapped = result
|
let mapped = result
|
||||||
.map_err(|error| SpacetimeClientError::Procedure(error.to_string()))
|
.map_err(SpacetimeClientError::from_sdk_error)
|
||||||
.and_then(map_runtime_profile_wallet_adjustment_procedure_result);
|
.and_then(map_runtime_profile_wallet_adjustment_procedure_result);
|
||||||
send_once(&sender, mapped);
|
send_once(&sender, mapped);
|
||||||
},
|
},
|
||||||
@@ -142,7 +142,7 @@ impl SpacetimeClient {
|
|||||||
.procedures()
|
.procedures()
|
||||||
.refund_profile_wallet_points_and_return_then(procedure_input, move |_, result| {
|
.refund_profile_wallet_points_and_return_then(procedure_input, move |_, result| {
|
||||||
let mapped = result
|
let mapped = result
|
||||||
.map_err(|error| SpacetimeClientError::Procedure(error.to_string()))
|
.map_err(SpacetimeClientError::from_sdk_error)
|
||||||
.and_then(map_runtime_profile_wallet_adjustment_procedure_result);
|
.and_then(map_runtime_profile_wallet_adjustment_procedure_result);
|
||||||
send_once(&sender, mapped);
|
send_once(&sender, mapped);
|
||||||
});
|
});
|
||||||
@@ -163,7 +163,7 @@ impl SpacetimeClient {
|
|||||||
procedure_input,
|
procedure_input,
|
||||||
move |_, result| {
|
move |_, result| {
|
||||||
let mapped = result
|
let mapped = result
|
||||||
.map_err(|error| SpacetimeClientError::Procedure(error.to_string()))
|
.map_err(SpacetimeClientError::from_sdk_error)
|
||||||
.and_then(map_runtime_profile_recharge_center_procedure_result);
|
.and_then(map_runtime_profile_recharge_center_procedure_result);
|
||||||
send_once(&sender, mapped);
|
send_once(&sender, mapped);
|
||||||
},
|
},
|
||||||
@@ -201,7 +201,7 @@ impl SpacetimeClient {
|
|||||||
procedure_input,
|
procedure_input,
|
||||||
move |_, result| {
|
move |_, result| {
|
||||||
let mapped = result
|
let mapped = result
|
||||||
.map_err(|error| SpacetimeClientError::Procedure(error.to_string()))
|
.map_err(SpacetimeClientError::from_sdk_error)
|
||||||
.and_then(map_runtime_profile_recharge_order_procedure_result);
|
.and_then(map_runtime_profile_recharge_order_procedure_result);
|
||||||
send_once(&sender, mapped);
|
send_once(&sender, mapped);
|
||||||
},
|
},
|
||||||
@@ -223,7 +223,7 @@ impl SpacetimeClient {
|
|||||||
.procedures()
|
.procedures()
|
||||||
.get_profile_referral_invite_center_then(procedure_input, move |_, result| {
|
.get_profile_referral_invite_center_then(procedure_input, move |_, result| {
|
||||||
let mapped = result
|
let mapped = result
|
||||||
.map_err(|error| SpacetimeClientError::Procedure(error.to_string()))
|
.map_err(SpacetimeClientError::from_sdk_error)
|
||||||
.and_then(map_runtime_referral_invite_center_procedure_result);
|
.and_then(map_runtime_referral_invite_center_procedure_result);
|
||||||
send_once(&sender, mapped);
|
send_once(&sender, mapped);
|
||||||
});
|
});
|
||||||
@@ -247,7 +247,7 @@ impl SpacetimeClient {
|
|||||||
.procedures()
|
.procedures()
|
||||||
.redeem_profile_referral_invite_code_then(procedure_input, move |_, result| {
|
.redeem_profile_referral_invite_code_then(procedure_input, move |_, result| {
|
||||||
let mapped = result
|
let mapped = result
|
||||||
.map_err(|error| SpacetimeClientError::Procedure(error.to_string()))
|
.map_err(SpacetimeClientError::from_sdk_error)
|
||||||
.and_then(map_runtime_referral_redeem_procedure_result);
|
.and_then(map_runtime_referral_redeem_procedure_result);
|
||||||
send_once(&sender, mapped);
|
send_once(&sender, mapped);
|
||||||
});
|
});
|
||||||
@@ -271,7 +271,7 @@ impl SpacetimeClient {
|
|||||||
procedure_input,
|
procedure_input,
|
||||||
move |_, result| {
|
move |_, result| {
|
||||||
let mapped = result
|
let mapped = result
|
||||||
.map_err(|error| SpacetimeClientError::Procedure(error.to_string()))
|
.map_err(SpacetimeClientError::from_sdk_error)
|
||||||
.and_then(map_runtime_profile_reward_code_redeem_procedure_result);
|
.and_then(map_runtime_profile_reward_code_redeem_procedure_result);
|
||||||
send_once(&sender, mapped);
|
send_once(&sender, mapped);
|
||||||
},
|
},
|
||||||
@@ -311,7 +311,7 @@ impl SpacetimeClient {
|
|||||||
.procedures()
|
.procedures()
|
||||||
.admin_upsert_profile_redeem_code_then(procedure_input, move |_, result| {
|
.admin_upsert_profile_redeem_code_then(procedure_input, move |_, result| {
|
||||||
let mapped = result
|
let mapped = result
|
||||||
.map_err(|error| SpacetimeClientError::Procedure(error.to_string()))
|
.map_err(SpacetimeClientError::from_sdk_error)
|
||||||
.and_then(map_runtime_profile_redeem_code_admin_procedure_result);
|
.and_then(map_runtime_profile_redeem_code_admin_procedure_result);
|
||||||
send_once(&sender, mapped);
|
send_once(&sender, mapped);
|
||||||
});
|
});
|
||||||
@@ -338,7 +338,7 @@ impl SpacetimeClient {
|
|||||||
.procedures()
|
.procedures()
|
||||||
.admin_disable_profile_redeem_code_then(procedure_input, move |_, result| {
|
.admin_disable_profile_redeem_code_then(procedure_input, move |_, result| {
|
||||||
let mapped = result
|
let mapped = result
|
||||||
.map_err(|error| SpacetimeClientError::Procedure(error.to_string()))
|
.map_err(SpacetimeClientError::from_sdk_error)
|
||||||
.and_then(map_runtime_profile_redeem_code_admin_procedure_result);
|
.and_then(map_runtime_profile_redeem_code_admin_procedure_result);
|
||||||
send_once(&sender, mapped);
|
send_once(&sender, mapped);
|
||||||
});
|
});
|
||||||
@@ -359,7 +359,7 @@ impl SpacetimeClient {
|
|||||||
procedure_input,
|
procedure_input,
|
||||||
move |_, result| {
|
move |_, result| {
|
||||||
let mapped = result
|
let mapped = result
|
||||||
.map_err(|error| SpacetimeClientError::Procedure(error.to_string()))
|
.map_err(SpacetimeClientError::from_sdk_error)
|
||||||
.and_then(map_runtime_profile_play_stats_procedure_result);
|
.and_then(map_runtime_profile_play_stats_procedure_result);
|
||||||
send_once(&sender, mapped);
|
send_once(&sender, mapped);
|
||||||
},
|
},
|
||||||
@@ -381,7 +381,7 @@ impl SpacetimeClient {
|
|||||||
.procedures()
|
.procedures()
|
||||||
.get_runtime_snapshot_then(procedure_input, move |_, result| {
|
.get_runtime_snapshot_then(procedure_input, move |_, result| {
|
||||||
let mapped = result
|
let mapped = result
|
||||||
.map_err(|error| SpacetimeClientError::Procedure(error.to_string()))
|
.map_err(SpacetimeClientError::from_sdk_error)
|
||||||
.and_then(map_runtime_snapshot_procedure_result);
|
.and_then(map_runtime_snapshot_procedure_result);
|
||||||
send_once(&sender, mapped);
|
send_once(&sender, mapped);
|
||||||
});
|
});
|
||||||
@@ -414,7 +414,7 @@ impl SpacetimeClient {
|
|||||||
.procedures()
|
.procedures()
|
||||||
.upsert_runtime_snapshot_and_return_then(procedure_input, move |_, result| {
|
.upsert_runtime_snapshot_and_return_then(procedure_input, move |_, result| {
|
||||||
let mapped = result
|
let mapped = result
|
||||||
.map_err(|error| SpacetimeClientError::Procedure(error.to_string()))
|
.map_err(SpacetimeClientError::from_sdk_error)
|
||||||
.and_then(map_runtime_snapshot_required_procedure_result);
|
.and_then(map_runtime_snapshot_required_procedure_result);
|
||||||
send_once(&sender, mapped);
|
send_once(&sender, mapped);
|
||||||
});
|
});
|
||||||
@@ -435,7 +435,7 @@ impl SpacetimeClient {
|
|||||||
.procedures()
|
.procedures()
|
||||||
.delete_runtime_snapshot_and_return_then(procedure_input, move |_, result| {
|
.delete_runtime_snapshot_and_return_then(procedure_input, move |_, result| {
|
||||||
let mapped = result
|
let mapped = result
|
||||||
.map_err(|error| SpacetimeClientError::Procedure(error.to_string()))
|
.map_err(SpacetimeClientError::from_sdk_error)
|
||||||
.and_then(map_runtime_snapshot_delete_procedure_result);
|
.and_then(map_runtime_snapshot_delete_procedure_result);
|
||||||
send_once(&sender, mapped);
|
send_once(&sender, mapped);
|
||||||
});
|
});
|
||||||
@@ -456,7 +456,7 @@ impl SpacetimeClient {
|
|||||||
procedure_input,
|
procedure_input,
|
||||||
move |_, result| {
|
move |_, result| {
|
||||||
let mapped = result
|
let mapped = result
|
||||||
.map_err(|error| SpacetimeClientError::Procedure(error.to_string()))
|
.map_err(SpacetimeClientError::from_sdk_error)
|
||||||
.and_then(map_runtime_profile_save_archive_list_procedure_result);
|
.and_then(map_runtime_profile_save_archive_list_procedure_result);
|
||||||
send_once(&sender, mapped);
|
send_once(&sender, mapped);
|
||||||
},
|
},
|
||||||
@@ -480,7 +480,7 @@ impl SpacetimeClient {
|
|||||||
.procedures()
|
.procedures()
|
||||||
.resume_profile_save_archive_and_return_then(procedure_input, move |_, result| {
|
.resume_profile_save_archive_and_return_then(procedure_input, move |_, result| {
|
||||||
let mapped = result
|
let mapped = result
|
||||||
.map_err(|error| SpacetimeClientError::Procedure(error.to_string()))
|
.map_err(SpacetimeClientError::from_sdk_error)
|
||||||
.and_then(map_runtime_profile_save_archive_resume_procedure_result);
|
.and_then(map_runtime_profile_save_archive_resume_procedure_result);
|
||||||
send_once(&sender, mapped);
|
send_once(&sender, mapped);
|
||||||
});
|
});
|
||||||
@@ -509,7 +509,7 @@ impl SpacetimeClient {
|
|||||||
.procedures()
|
.procedures()
|
||||||
.upsert_runtime_setting_and_return_then(procedure_input, move |_, result| {
|
.upsert_runtime_setting_and_return_then(procedure_input, move |_, result| {
|
||||||
let mapped = result
|
let mapped = result
|
||||||
.map_err(|error| SpacetimeClientError::Procedure(error.to_string()))
|
.map_err(SpacetimeClientError::from_sdk_error)
|
||||||
.and_then(map_runtime_setting_procedure_result);
|
.and_then(map_runtime_setting_procedure_result);
|
||||||
send_once(&sender, mapped);
|
send_once(&sender, mapped);
|
||||||
});
|
});
|
||||||
@@ -535,7 +535,7 @@ impl SpacetimeClient {
|
|||||||
procedure_input,
|
procedure_input,
|
||||||
move |_, result| {
|
move |_, result| {
|
||||||
let mapped = result
|
let mapped = result
|
||||||
.map_err(|error| SpacetimeClientError::Procedure(error.to_string()))
|
.map_err(SpacetimeClientError::from_sdk_error)
|
||||||
.and_then(map_runtime_browse_history_procedure_result);
|
.and_then(map_runtime_browse_history_procedure_result);
|
||||||
send_once(&sender, mapped);
|
send_once(&sender, mapped);
|
||||||
},
|
},
|
||||||
@@ -559,7 +559,7 @@ impl SpacetimeClient {
|
|||||||
procedure_input,
|
procedure_input,
|
||||||
move |_, result| {
|
move |_, result| {
|
||||||
let mapped = result
|
let mapped = result
|
||||||
.map_err(|error| SpacetimeClientError::Procedure(error.to_string()))
|
.map_err(SpacetimeClientError::from_sdk_error)
|
||||||
.and_then(map_runtime_browse_history_procedure_result);
|
.and_then(map_runtime_browse_history_procedure_result);
|
||||||
send_once(&sender, mapped);
|
send_once(&sender, mapped);
|
||||||
},
|
},
|
||||||
|
|||||||
@@ -66,7 +66,6 @@ fn upsert_asset_entity_binding(
|
|||||||
return Err("asset_entity_binding.asset_object_id 对应的 asset_object 不存在".to_string());
|
return Err("asset_entity_binding.asset_object_id 对应的 asset_object 不存在".to_string());
|
||||||
}
|
}
|
||||||
|
|
||||||
let updated_at = Timestamp::from_micros_since_unix_epoch(input.updated_at_micros);
|
|
||||||
// 首版绑定按 entity_kind + entity_id + slot 幂等定位,后续访问量明确后再改为组合索引扫描。
|
// 首版绑定按 entity_kind + entity_id + slot 幂等定位,后续访问量明确后再改为组合索引扫描。
|
||||||
let current = ctx.db.asset_entity_binding().iter().find(|row| {
|
let current = ctx.db.asset_entity_binding().iter().find(|row| {
|
||||||
row.entity_kind == input.entity_kind
|
row.entity_kind == input.entity_kind
|
||||||
@@ -80,7 +79,7 @@ fn upsert_asset_entity_binding(
|
|||||||
.asset_entity_binding()
|
.asset_entity_binding()
|
||||||
.binding_id()
|
.binding_id()
|
||||||
.delete(&existing.binding_id);
|
.delete(&existing.binding_id);
|
||||||
let row = AssetEntityBinding {
|
let snapshot = AssetEntityBindingSnapshot {
|
||||||
binding_id: existing.binding_id.clone(),
|
binding_id: existing.binding_id.clone(),
|
||||||
asset_object_id: input.asset_object_id.clone(),
|
asset_object_id: input.asset_object_id.clone(),
|
||||||
entity_kind: input.entity_kind.clone(),
|
entity_kind: input.entity_kind.clone(),
|
||||||
@@ -89,27 +88,16 @@ fn upsert_asset_entity_binding(
|
|||||||
asset_kind: input.asset_kind.clone(),
|
asset_kind: input.asset_kind.clone(),
|
||||||
owner_user_id: input.owner_user_id.clone(),
|
owner_user_id: input.owner_user_id.clone(),
|
||||||
profile_id: input.profile_id.clone(),
|
profile_id: input.profile_id.clone(),
|
||||||
created_at: existing.created_at,
|
|
||||||
updated_at,
|
|
||||||
};
|
|
||||||
ctx.db.asset_entity_binding().insert(row);
|
|
||||||
|
|
||||||
AssetEntityBindingSnapshot {
|
|
||||||
binding_id: existing.binding_id,
|
|
||||||
asset_object_id: input.asset_object_id,
|
|
||||||
entity_kind: input.entity_kind,
|
|
||||||
entity_id: input.entity_id,
|
|
||||||
slot: input.slot,
|
|
||||||
asset_kind: input.asset_kind,
|
|
||||||
owner_user_id: input.owner_user_id,
|
|
||||||
profile_id: input.profile_id,
|
|
||||||
created_at_micros: existing.created_at.to_micros_since_unix_epoch(),
|
created_at_micros: existing.created_at.to_micros_since_unix_epoch(),
|
||||||
updated_at_micros: input.updated_at_micros,
|
updated_at_micros: input.updated_at_micros,
|
||||||
}
|
};
|
||||||
|
ctx.db
|
||||||
|
.asset_entity_binding()
|
||||||
|
.insert(build_asset_entity_binding_row(&snapshot));
|
||||||
|
snapshot
|
||||||
}
|
}
|
||||||
None => {
|
None => {
|
||||||
let created_at = updated_at;
|
let snapshot = AssetEntityBindingSnapshot {
|
||||||
let row = AssetEntityBinding {
|
|
||||||
binding_id: input.binding_id.clone(),
|
binding_id: input.binding_id.clone(),
|
||||||
asset_object_id: input.asset_object_id.clone(),
|
asset_object_id: input.asset_object_id.clone(),
|
||||||
entity_kind: input.entity_kind.clone(),
|
entity_kind: input.entity_kind.clone(),
|
||||||
@@ -118,25 +106,30 @@ fn upsert_asset_entity_binding(
|
|||||||
asset_kind: input.asset_kind.clone(),
|
asset_kind: input.asset_kind.clone(),
|
||||||
owner_user_id: input.owner_user_id.clone(),
|
owner_user_id: input.owner_user_id.clone(),
|
||||||
profile_id: input.profile_id.clone(),
|
profile_id: input.profile_id.clone(),
|
||||||
created_at,
|
|
||||||
updated_at,
|
|
||||||
};
|
|
||||||
ctx.db.asset_entity_binding().insert(row);
|
|
||||||
|
|
||||||
AssetEntityBindingSnapshot {
|
|
||||||
binding_id: input.binding_id,
|
|
||||||
asset_object_id: input.asset_object_id,
|
|
||||||
entity_kind: input.entity_kind,
|
|
||||||
entity_id: input.entity_id,
|
|
||||||
slot: input.slot,
|
|
||||||
asset_kind: input.asset_kind,
|
|
||||||
owner_user_id: input.owner_user_id,
|
|
||||||
profile_id: input.profile_id,
|
|
||||||
created_at_micros: input.updated_at_micros,
|
created_at_micros: input.updated_at_micros,
|
||||||
updated_at_micros: input.updated_at_micros,
|
updated_at_micros: input.updated_at_micros,
|
||||||
}
|
};
|
||||||
|
ctx.db
|
||||||
|
.asset_entity_binding()
|
||||||
|
.insert(build_asset_entity_binding_row(&snapshot));
|
||||||
|
snapshot
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
Ok(snapshot)
|
Ok(snapshot)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
fn build_asset_entity_binding_row(snapshot: &AssetEntityBindingSnapshot) -> AssetEntityBinding {
|
||||||
|
AssetEntityBinding {
|
||||||
|
binding_id: snapshot.binding_id.clone(),
|
||||||
|
asset_object_id: snapshot.asset_object_id.clone(),
|
||||||
|
entity_kind: snapshot.entity_kind.clone(),
|
||||||
|
entity_id: snapshot.entity_id.clone(),
|
||||||
|
slot: snapshot.slot.clone(),
|
||||||
|
asset_kind: snapshot.asset_kind.clone(),
|
||||||
|
owner_user_id: snapshot.owner_user_id.clone(),
|
||||||
|
profile_id: snapshot.profile_id.clone(),
|
||||||
|
created_at: Timestamp::from_micros_since_unix_epoch(snapshot.created_at_micros),
|
||||||
|
updated_at: Timestamp::from_micros_since_unix_epoch(snapshot.updated_at_micros),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|||||||
@@ -91,7 +91,6 @@ pub(crate) fn upsert_asset_object(
|
|||||||
)
|
)
|
||||||
.map_err(|error| error.to_string())?;
|
.map_err(|error| error.to_string())?;
|
||||||
|
|
||||||
let updated_at = Timestamp::from_micros_since_unix_epoch(input.updated_at_micros);
|
|
||||||
// 这里先保持最小可发布实现:查重语义已经冻结,后续再把实现优化回组合索引扫描。
|
// 这里先保持最小可发布实现:查重语义已经冻结,后续再把实现优化回组合索引扫描。
|
||||||
let current = ctx
|
let current = ctx
|
||||||
.db
|
.db
|
||||||
@@ -105,7 +104,7 @@ pub(crate) fn upsert_asset_object(
|
|||||||
.asset_object()
|
.asset_object()
|
||||||
.asset_object_id()
|
.asset_object_id()
|
||||||
.delete(&existing.asset_object_id);
|
.delete(&existing.asset_object_id);
|
||||||
let row = AssetObject {
|
let snapshot = AssetObjectUpsertSnapshot {
|
||||||
asset_object_id: existing.asset_object_id.clone(),
|
asset_object_id: existing.asset_object_id.clone(),
|
||||||
bucket: input.bucket.clone(),
|
bucket: input.bucket.clone(),
|
||||||
object_key: input.object_key.clone(),
|
object_key: input.object_key.clone(),
|
||||||
@@ -119,32 +118,16 @@ pub(crate) fn upsert_asset_object(
|
|||||||
profile_id: input.profile_id.clone(),
|
profile_id: input.profile_id.clone(),
|
||||||
entity_id: input.entity_id.clone(),
|
entity_id: input.entity_id.clone(),
|
||||||
asset_kind: input.asset_kind.clone(),
|
asset_kind: input.asset_kind.clone(),
|
||||||
created_at: existing.created_at,
|
|
||||||
updated_at,
|
|
||||||
};
|
|
||||||
ctx.db.asset_object().insert(row);
|
|
||||||
|
|
||||||
AssetObjectUpsertSnapshot {
|
|
||||||
asset_object_id: existing.asset_object_id,
|
|
||||||
bucket: input.bucket,
|
|
||||||
object_key: input.object_key,
|
|
||||||
access_policy: input.access_policy,
|
|
||||||
content_type: input.content_type,
|
|
||||||
content_length: input.content_length,
|
|
||||||
content_hash: input.content_hash,
|
|
||||||
version: input.version,
|
|
||||||
source_job_id: input.source_job_id,
|
|
||||||
owner_user_id: input.owner_user_id,
|
|
||||||
profile_id: input.profile_id,
|
|
||||||
entity_id: input.entity_id,
|
|
||||||
asset_kind: input.asset_kind,
|
|
||||||
created_at_micros: existing.created_at.to_micros_since_unix_epoch(),
|
created_at_micros: existing.created_at.to_micros_since_unix_epoch(),
|
||||||
updated_at_micros: input.updated_at_micros,
|
updated_at_micros: input.updated_at_micros,
|
||||||
}
|
};
|
||||||
|
ctx.db
|
||||||
|
.asset_object()
|
||||||
|
.insert(build_asset_object_row(&snapshot));
|
||||||
|
snapshot
|
||||||
}
|
}
|
||||||
None => {
|
None => {
|
||||||
let created_at = updated_at;
|
let snapshot = AssetObjectUpsertSnapshot {
|
||||||
let row = AssetObject {
|
|
||||||
asset_object_id: input.asset_object_id.clone(),
|
asset_object_id: input.asset_object_id.clone(),
|
||||||
bucket: input.bucket.clone(),
|
bucket: input.bucket.clone(),
|
||||||
object_key: input.object_key.clone(),
|
object_key: input.object_key.clone(),
|
||||||
@@ -158,28 +141,13 @@ pub(crate) fn upsert_asset_object(
|
|||||||
profile_id: input.profile_id.clone(),
|
profile_id: input.profile_id.clone(),
|
||||||
entity_id: input.entity_id.clone(),
|
entity_id: input.entity_id.clone(),
|
||||||
asset_kind: input.asset_kind.clone(),
|
asset_kind: input.asset_kind.clone(),
|
||||||
created_at,
|
|
||||||
updated_at,
|
|
||||||
};
|
|
||||||
ctx.db.asset_object().insert(row);
|
|
||||||
|
|
||||||
AssetObjectUpsertSnapshot {
|
|
||||||
asset_object_id: input.asset_object_id,
|
|
||||||
bucket: input.bucket,
|
|
||||||
object_key: input.object_key,
|
|
||||||
access_policy: input.access_policy,
|
|
||||||
content_type: input.content_type,
|
|
||||||
content_length: input.content_length,
|
|
||||||
content_hash: input.content_hash,
|
|
||||||
version: input.version,
|
|
||||||
source_job_id: input.source_job_id,
|
|
||||||
owner_user_id: input.owner_user_id,
|
|
||||||
profile_id: input.profile_id,
|
|
||||||
entity_id: input.entity_id,
|
|
||||||
asset_kind: input.asset_kind,
|
|
||||||
created_at_micros: input.updated_at_micros,
|
created_at_micros: input.updated_at_micros,
|
||||||
updated_at_micros: input.updated_at_micros,
|
updated_at_micros: input.updated_at_micros,
|
||||||
}
|
};
|
||||||
|
ctx.db
|
||||||
|
.asset_object()
|
||||||
|
.insert(build_asset_object_row(&snapshot));
|
||||||
|
snapshot
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
@@ -244,3 +212,23 @@ fn object_key_to_legacy_image_src(object_key: &str) -> String {
|
|||||||
}
|
}
|
||||||
format!("/{normalized}")
|
format!("/{normalized}")
|
||||||
}
|
}
|
||||||
|
|
||||||
|
fn build_asset_object_row(snapshot: &AssetObjectUpsertSnapshot) -> AssetObject {
|
||||||
|
AssetObject {
|
||||||
|
asset_object_id: snapshot.asset_object_id.clone(),
|
||||||
|
bucket: snapshot.bucket.clone(),
|
||||||
|
object_key: snapshot.object_key.clone(),
|
||||||
|
access_policy: snapshot.access_policy,
|
||||||
|
content_type: snapshot.content_type.clone(),
|
||||||
|
content_length: snapshot.content_length,
|
||||||
|
content_hash: snapshot.content_hash.clone(),
|
||||||
|
version: snapshot.version,
|
||||||
|
source_job_id: snapshot.source_job_id.clone(),
|
||||||
|
owner_user_id: snapshot.owner_user_id.clone(),
|
||||||
|
profile_id: snapshot.profile_id.clone(),
|
||||||
|
entity_id: snapshot.entity_id.clone(),
|
||||||
|
asset_kind: snapshot.asset_kind.clone(),
|
||||||
|
created_at: Timestamp::from_micros_since_unix_epoch(snapshot.created_at_micros),
|
||||||
|
updated_at: Timestamp::from_micros_since_unix_epoch(snapshot.updated_at_micros),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|||||||
@@ -1,3 +1,7 @@
|
|||||||
|
// 中文注释:SpacetimeDB 绑定生成依赖根模块继续公开 re-export 各领域类型;
|
||||||
|
// 少数领域 helper 同名只影响 value namespace 导出,不影响 table / reducer 类型。
|
||||||
|
#![allow(ambiguous_glob_reexports)]
|
||||||
|
|
||||||
pub use module_ai::*;
|
pub use module_ai::*;
|
||||||
pub use module_assets::*;
|
pub use module_assets::*;
|
||||||
pub use module_big_fish::*;
|
pub use module_big_fish::*;
|
||||||
|
|||||||
@@ -5,7 +5,8 @@ use spacetimedb_lib::sats::ser::serde::SerializeWrapper;
|
|||||||
use std::collections::HashSet;
|
use std::collections::HashSet;
|
||||||
|
|
||||||
use crate::puzzle::{
|
use crate::puzzle::{
|
||||||
puzzle_agent_message, puzzle_agent_session, puzzle_runtime_run, puzzle_work_profile,
|
puzzle_agent_message, puzzle_agent_session, puzzle_event, puzzle_leaderboard_entry,
|
||||||
|
puzzle_runtime_run, puzzle_work_profile,
|
||||||
};
|
};
|
||||||
|
|
||||||
const MIGRATION_SCHEMA_VERSION: u32 = 1;
|
const MIGRATION_SCHEMA_VERSION: u32 = 1;
|
||||||
@@ -140,7 +141,9 @@ macro_rules! migration_tables {
|
|||||||
puzzle_agent_session,
|
puzzle_agent_session,
|
||||||
puzzle_agent_message,
|
puzzle_agent_message,
|
||||||
puzzle_work_profile,
|
puzzle_work_profile,
|
||||||
|
puzzle_event,
|
||||||
puzzle_runtime_run,
|
puzzle_runtime_run,
|
||||||
|
puzzle_leaderboard_entry,
|
||||||
big_fish_creation_session,
|
big_fish_creation_session,
|
||||||
big_fish_agent_message,
|
big_fish_agent_message,
|
||||||
big_fish_asset_slot,
|
big_fish_asset_slot,
|
||||||
|
|||||||
@@ -18,7 +18,7 @@ use module_puzzle::{
|
|||||||
};
|
};
|
||||||
use serde_json::from_str as json_from_str;
|
use serde_json::from_str as json_from_str;
|
||||||
use serde_json::to_string as json_to_string;
|
use serde_json::to_string as json_to_string;
|
||||||
use spacetimedb::{ProcedureContext, Table, Timestamp, TxContext};
|
use spacetimedb::{ProcedureContext, SpacetimeType, Table, Timestamp, TxContext};
|
||||||
|
|
||||||
/// 拼图 Agent session 真相表。
|
/// 拼图 Agent session 真相表。
|
||||||
/// 当前只保存结构化字段与 JSON 草稿,不提前拆出更多编辑态子表。
|
/// 当前只保存结构化字段与 JSON 草稿,不提前拆出更多编辑态子表。
|
||||||
@@ -84,6 +84,33 @@ pub struct PuzzleWorkProfileRow {
|
|||||||
published_at: Option<Timestamp>,
|
published_at: Option<Timestamp>,
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// 拼图创作事件类型。
|
||||||
|
///
|
||||||
|
/// 事件表只广播跨层订阅需要的轻量事实,作品真相仍以
|
||||||
|
/// `puzzle_work_profile` 和 `puzzle_agent_session` 为准。
|
||||||
|
#[derive(Clone, Copy, Debug, PartialEq, Eq, SpacetimeType)]
|
||||||
|
pub enum PuzzleEventKind {
|
||||||
|
WorkPublished,
|
||||||
|
}
|
||||||
|
|
||||||
|
#[spacetimedb::table(
|
||||||
|
accessor = puzzle_event,
|
||||||
|
public,
|
||||||
|
event,
|
||||||
|
index(accessor = by_puzzle_event_profile_id, btree(columns = [profile_id])),
|
||||||
|
index(accessor = by_puzzle_event_owner_user_id, btree(columns = [owner_user_id]))
|
||||||
|
)]
|
||||||
|
pub struct PuzzleEvent {
|
||||||
|
#[primary_key]
|
||||||
|
event_id: String,
|
||||||
|
profile_id: String,
|
||||||
|
work_id: String,
|
||||||
|
session_id: Option<String>,
|
||||||
|
owner_user_id: String,
|
||||||
|
event_kind: PuzzleEventKind,
|
||||||
|
occurred_at: Timestamp,
|
||||||
|
}
|
||||||
|
|
||||||
/// 运行态 run 快照表。
|
/// 运行态 run 快照表。
|
||||||
#[spacetimedb::table(
|
#[spacetimedb::table(
|
||||||
accessor = puzzle_runtime_run,
|
accessor = puzzle_runtime_run,
|
||||||
@@ -869,6 +896,7 @@ fn publish_puzzle_work_tx(
|
|||||||
updated_at: Timestamp::from_micros_since_unix_epoch(input.published_at_micros),
|
updated_at: Timestamp::from_micros_since_unix_epoch(input.published_at_micros),
|
||||||
},
|
},
|
||||||
);
|
);
|
||||||
|
emit_puzzle_work_published_event(ctx, &profile, input.published_at_micros);
|
||||||
|
|
||||||
Ok(profile)
|
Ok(profile)
|
||||||
}
|
}
|
||||||
@@ -1543,6 +1571,25 @@ fn upsert_puzzle_work_profile(ctx: &TxContext, profile: PuzzleWorkProfile) -> Re
|
|||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
|
|
||||||
|
fn emit_puzzle_work_published_event(
|
||||||
|
ctx: &TxContext,
|
||||||
|
profile: &PuzzleWorkProfile,
|
||||||
|
occurred_at_micros: i64,
|
||||||
|
) {
|
||||||
|
ctx.db.puzzle_event().insert(PuzzleEvent {
|
||||||
|
event_id: format!(
|
||||||
|
"pzevt_{}_{}_published",
|
||||||
|
profile.profile_id, occurred_at_micros
|
||||||
|
),
|
||||||
|
profile_id: profile.profile_id.clone(),
|
||||||
|
work_id: profile.work_id.clone(),
|
||||||
|
session_id: profile.source_session_id.clone(),
|
||||||
|
owner_user_id: profile.owner_user_id.clone(),
|
||||||
|
event_kind: PuzzleEventKind::WorkPublished,
|
||||||
|
occurred_at: Timestamp::from_micros_since_unix_epoch(occurred_at_micros),
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
fn insert_puzzle_runtime_run(
|
fn insert_puzzle_runtime_run(
|
||||||
ctx: &TxContext,
|
ctx: &TxContext,
|
||||||
run: &PuzzleRunSnapshot,
|
run: &PuzzleRunSnapshot,
|
||||||
|
|||||||
Reference in New Issue
Block a user