--- name: demo description: W-07 实时演示模块 —— demo 会话管理、three.js 预览、状态隔离(演示改动不污染正式数据)、多人预览。开发/修改 demo 相关功能前必读。 --- # demo 模块技能 ## 架构 - 交互层业务模块(有自己的数据表 + dspy + bricks 前端),通过 `load_demo(env)` 挂到宿主。 - 依赖宿主提供:sqlor/ahserver/ServerEnv;跨模块校验 world 存在性时按需用 world 模块(防御式 try/except)。 ## 数据模型(models/*.json) | 表 | 作用 | 关键字段 | |----|------|----------| | demo_session | 演示会话 | status(preview/paused/ended), camera_mode(orbit/topdown/firstperson), viewer_count, extra_json | | demo_session_state | 实体状态覆盖层 | session_id, entity_id, base_json(基线), demo_json(当前) | | demo_hot_script | 热加载脚本 | session_id, script_id, script_type(python/expr), script_content | | demo_presence | 多人预览在线 | session_id, user_id, user_name, last_seen_at | ## 关键端点(wwwroot/api/*.dspy,全部 logined) - `start.dspy` — world_id 必填;重复开始同世界 → 409 - `stop.dspy` — 删除覆盖层/脚本/在线表(状态隔离核心) - `entity_edit.dspy` — session_id+entity_id+fields(对象) 必填;只写覆盖层 - `entity_attrs.dspy` — 返回 base/demo/merged - `hotload.dspy` — 语法校验(compile)通过才落库;SyntaxError → 400 - `camera.dspy` — camera_mode 白名单 orbit/topdown/firstperson - `pause.dspy` — paused=true/false - `presence.dspy` — action=join/leave,viewer_count 实时回写 - `fullscreen.dspy` — enabled true/false,写入 extra_json - `state.dspy` — 前端 500ms 轮询,聚合实体状态+脚本+在线人数 ## 状态机(会话级) preview ⇄ paused(pause.dspy);preview/paused → ended(stop.dspy,唯一出口);ended 后任何操作 → 400。 ## 模块专属坑 1. **状态隔离是硬约束**:任何实体修改只允许写 `demo_session_state`,严禁写 entity/scene/world 正式表。stop_demo 必须级联删除 3 张子表,否则正式数据被"演示污染"。 2. **三处同步注册**:新增函数必须同步 demo/demo.py、demo/__init__.py、demo/init.py 三处(env.xxx = xxx)。 3. **异常→状态码映射**:DemoParamError→400、DemoNotFoundError→404、DemoDuplicateError→409、DemoStateError→400;dspy 里必须 try/except 后返回 `{"status":..., "message":...}`。 4. **sor.C 必须显式带 created_at**:sqlor 不自动补时间戳,缺 created_at 会导致插入静默丢失。 5. **dspy 禁止 import**:所有函数经 load_demo 注册为全局;dspy 里直接 `await start_demo(...)`。 6. **取库名**:`get_module_dbname('demo')`(dspy 全局)或 `ServerEnv().get_module_dbname('demo')`(.py),禁止硬编码 DBNAME。 7. **dspy 显式 return**:ahserver 包裹 async 函数,裸表达式返回 None。 8. 前端 `.js` 里可用 fetch/setInterval(非 script actiontype);bricks script actiontype 内禁止 fetch/setInterval。