Skip to content

存储与前端对接 ​

本文面向两类集成方:想把存储层接到自己数据库的,以及自研前端要接入的。

存储接口契约 ​

签名与路径以代码为准:server/internal/store/store.go、server/internal/{issue,change,override}/、server/cmd/server/main.go。

两种存储实现 ​

文件存储是默认实现,零依赖:所有状态落在数据目录里,JSON 文件加原子写。

PostgreSQL 可选:设置 VIEWER_PG_DSN 即切换。三张表由各自的 pgstore.go 在构造时自动建立。

两处不对称要知道:

  1. 模型注册表不进 PG。模型元数据和上传文件始终是文件存储,PG 只承接 issue、change、override 三个网关侧数据。
  2. Issue 截图不进 PG。PG 模式下 PNG 仍落盘,库里只存相对路径。

数据目录布局 ​

Go server 和两个 Python 服务必须共享同一个数据目录,配错会 404 或改错文件。

{VIEWER_DATA_DIR}/
├── uploads/
│   └── {id}.ifc|.dxf               # 当前模型态(script/run 或 save 时原子替换)
└── models/{id}/
    ├── model.json                  # 模型状态:name/size/status/error(Go store,原子写)
    ├── model.xkt                   # converter 产物(GET /v1/models/{id}/model.xkt 服务)
    ├── metadata.json               # converter 产物(xeokit 元模型)
    ├── issues.json                 # issue 列表(仅文件存储模式)
    ├── issues/{issueId}.png        # issue 截图(文件/PG 模式均在此)
    ├── changes.json                # 修改记录(仅文件存储模式)
    ├── overrides.json              # 属性 override(仅文件存储模式)
    ├── edit-history.json           # services/ifc 持久化编辑历史
    ├── pending.json                # script-run 回放簿记(内部)
    ├── script_staging.json         # 暂存脚本链
    ├── bootstrap.ifc               # 首次暂存脚本时保留的上传原件
    ├── current.map.json            # 当前 ScriptMap 发布信封
    ├── scripts/                    # 大版本脚本快照:v{n}.py + v{n}.map.json 全留
    ├── versions/                   # 大版本产物:v{n}.ifc|.dxf 只留最新
    └── ifc_cache/                  # diff/下载时按需重建的历史版本 + .map.json sidecar

写入方分两组:uploads、model.json、XKT、metadata 和 issues/changes/overrides 由 Go server 与 converter 写;其余由 Python 服务直接读写,不经过 Go store。Go 和 Python 共享的是目录契约,不是同一个 store 实例。

第三方整合路径 ​

按耦合从高到低三条路:

  1. 实现 Go store 接口,用自己的数据库承接网关侧状态。三个接口分别在 issue.go、change.go、override.go:

    接口方法职责
    issue.StoreList / Create / Update / Delete / DeleteModel / SaveScreenshotissue 增删改查、按模型清理、截图落盘
    change.StoreList / Append / DeleteModel修改记录追加与按模型清理
    override.StoreGetAll / Set / DeleteModel属性 override 读写与按模型清理

    注意模型注册表 store.Store 是具体类型不是接口,替换它要改 server 内部装配。

  2. 复用本仓 PG schema:把三个 pgstore.go 里的建表语句跑到自己的 PG 实例,设 VIEWER_PG_DSN 指向它即可。

  3. 只做文件级对接:直接读写数据目录,耦合最低,适合只读消费 XKT、metadata 或旁路分析。写入方必须遵守同样的并发纪律:先写临时文件再 rename,禁止原地截断写。

data/ 是运行时目录,不要手工修改。

前端对接契约 ​

envelope、错误码和鉴权行为以 server/internal/api/api.go 与 auth.go 为准。

web 是参考实现 ​

平台本体是 API,web/ 只是一个可整体替换的参考实现。对接面是 Go 网关的 /api/v1/* 和 /v1/models/*。机器可读契约见 REST API 的机器可消费一节。

协议基线 ​

除静态文件端点外,所有响应统一 envelope,code=0 表示成功:

json
{"code": 0, "message": "ok", "data": {...}}

错误码一览:

code含义
40001参数或校验错误,编辑服务的 422 经代理也映射为此
40002超限,如上传大小
40100鉴权失败
40400模型或资源不存在
40900冲突
50000服务器内部错误
50200编辑服务不可达等代理错误
50400编辑服务超时

鉴权与 CORS:

  • 默认关闭,设 VIEWER_API_TOKEN 后,除 OPTIONS 预检和三个只读文件端点外全部要求 Authorization: Bearer <token>。
  • 三个豁免端点是 model.xkt、metadata.json 和 issue 截图的 GET,因为 xeokit 和 <img> 带不了请求头。
  • chat 的 SSE 是唯一放行 ?token= 查询参数的路径,因为 EventSource 不支持自定义头。
  • CORS 白名单用 VIEWER_CORS_ORIGINS 配置,逗号分隔。

SSE 事件流:GET /api/v1/chat/sessions/{cid}/events 返回标准 SSE 帧,服务端维护编号缓冲,断线可以用 Last-Event-ID 重放。帧类型见 REST API 的帧表。

编辑流程对接 ​

一切修改落在构建脚本上,原直改端点已退役。典型链路:

bash
BASE=http://127.0.0.1:8090/api/v1
MID=m_0123456789abcdef

# 1. 暂存脚本(整脚本或 params 增量)
curl -X PUT "$BASE/models/$MID/script" \
  -H 'Content-Type: application/json' \
  -d '{"script": "PARAMS = {...}\n\ndef build(params, out_path):\n    ...\n"}'

# 2. 沙箱试运行(预览,无版本;成功后 Go 侧排队重转 XKT)
curl -X POST "$BASE/models/$MID/script/run"

# 3. 保存大版本 v{n}
curl -X POST "$BASE/models/$MID/script/save" \
  -H 'Content-Type: application/json' -d '{"note": "v1"}'

# 4. 按 guid 定位脚本调用点
curl "$BASE/models/$MID/script/locate?guid=2O2Fr\$t4X7ZfFPoeewFlqU"

# 5. 版本与 diff
curl "$BASE/models/$MID/edit/versions"
curl -X POST "$BASE/models/$MID/script/diff" \
  -H 'Content-Type: application/json' -d '{"base": "v1", "target": "v2"}'
curl -X POST "$BASE/models/$MID/edit/diff" \
  -H 'Content-Type: application/json' -d '{"base": "v1", "target": "current"}'

配套端点还有 script/undo|redo|discard、script/rollback、script/staging/diff 和 GET .../scripts。保存或回滚后轮询 GET /api/v1/models,状态从 converting 变成 ready 就说明新 XKT 可取了。

显示对接 ​

端点说明
GET /v1/models/{id}/model.xktXKT 几何数据,支持 Range
GET /v1/models/{id}/metadata.jsonxeokit 元模型,schema 见 REST API
GET /v1/models/{id}/render.jsonDXF 渲染数据,仅 dxf 模型

自研前端可以用任何渲染器。用 xeokit 时 metadata.json 可以直接作为 XKTLoaderPlugin.load 的输入,实体 id 就是 IFC GlobalId,和编辑 API 的 guid 天然对齐。

Apache-2.0 · xeokit AGPL 注意事项见项目介绍