Files
frontend-miniapp/static/sgs-map-sdk/sdk-protocol.md

137 lines
7.6 KiB
Markdown
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
# SGS Map SDK 通信协议规格 (Protocol Specification)
> 版本: V2.3.0
> 适用对象: SGS Map SDK 核心开发者、渲染基座 (h5-sdk) 开发者
本文档定义了外壳 SDK (`sgs-map-sdk.js`) 与 独立渲染基座 iframe (`h5-sdk/page.tsx`) 之间的 `postMessage` 通信契约。所有消息传递必须严格遵循此结构,以保障多域环境下的确权、安全过滤与异步生命周期追踪。
---
## 1. 消息模型抽象
双方通信产生的 JSON 对象统一分为三大类:
### 1.1 命令 (Command): SDK -> 基座
外壳 SDK 向基座发起的主动操作。
```json
{
"type": "SGS_MAP_COMMAND",
"action": "PLAN_ROUTE", // [必填] 行为动词
"requestId": "req_sdk_123_45", // [可选] 异步确权追踪信标
"payload": { ... } // [可选] 负载参数
}
```
### 1.2 响应 (Response): 基座 -> SDK
基座处理完 `Command` 后(同步或异步计算),向 SDK 携带结果的被动回执。
```json
{
"type": "SGS_MAP_RESPONSE",
"action": "PLAN_ROUTE", // [必填] 原样回显 Command 的 action
"requestId": "req_sdk_123_45", // [必填] 原样回显 Command 的 requestId
"payload": { "success": true }, // [可选] 成功时的返回值
"error": { "code": "ERR_NO_PATH", "message": "无路径" } // [可选] 失败时的异常信息
}
```
### 1.3 事件 (Event): 基座 -> SDK
基座中发生的不可预知行为(如鼠标点击)或系统状态变更,主动向外广播。
```json
{
"type": "SGS_MAP_EVENT",
"action": "ON_POI_CLICK", // [必填] 事件动词 (ON_开头)
"payload": { "poiId": 1234 } // [可选] 事件负载
}
```
---
## 2. 握手时序 (Handshake Sequence)
为了解决 iframe 初始化过程中的“假死”与状态竞态,必须采用基于事件的确权握手。
```mermaid
sequenceDiagram
participant SDK as 外壳 SDK
participant Iframe as 浏览器 DOM
participant Base as 渲染基座 (h5-sdk)
SDK->>Iframe: 动态创建 iframe(src)
Iframe-->>SDK: 触发 iframe.onload
Note over SDK,Base: 此时 HTML 刚加载WebGL/GLB 模型并未解析完成
SDK->>Base: 发送 HELLO { protocolVersion: 2, sdkVersion: "2.3.0" }
Base->>Base: 挂载 WebGL拉取 GLB 及 POI 接口
Base-->>SDK: 内部加载完毕,推送 ENGINE_READY 事件
SDK->>SDK: 解锁 isReady = true清空缓存命令队列
```
---
## 3. 指令字典 (Command Action Dictionary)
基座通过严格的**白名单机制**过滤 `action`,任何未在下表中声明的指令都将被立刻退回 `ERR_UNSUPPORTED` 响应。
| Action | Payload 负载签名 | 成功 Response 负载 | 说明 |
|--------|------------------|--------------------|------|
| `HELLO` | `{ protocolVersion, sdkVersion }` | (无,以 `ENGINE_READY` 代替回执) | 初始心跳探测 |
| `CHANGE_FLOOR` | `{ floorId: number }` | `{ success: true, floorId }` | 触发析构当前层并加载新层 |
| `FOCUS_TO` | `SgsMapNode` | `{ success: true }` | 镜头平滑转移,改变相机视角 |
| `PLAN_ROUTE` | `{ startNode?: SgsMapNode, endNode?: SgsMapNode, from?: SgsMapNode, to?: SgsMapNode, options? }` | `RouteResult` | 寻路计算。基座将转换为微服务调用 |
| `CLEAR_ROUTE` | (空) | `{ success: true }` | 销毁当前的 NavMeshPathLayer |
| `GET_STATE` | (空) | `{ floorId, isReady, ... }` | 查询内部状态机当前切片 |
| `ADD_MARKER` | `MarkerConfig` | `{ success: true }` | 生成三维图钉并依附到骨骼节点 |
| `REMOVE_MARKER`| `{ markerId: string }` | `{ success: true }` | 释放指定图钉的材质 |
| `CLEAR_MARKERS`| (空) | `{ success: true }` | 卸载所有动态业务图钉 |
| `HIGHLIGHT_POLYGON`| `{ nodeName: string }` | `{ success: true }` | 激活发光材质特效 |
| `RESET_VIEW` | (空) | `{ success: true }` | 重置相机视角至初始状态 |
| `SET_VIEW_MODE` | `{ mode: '2d' | '3d' }` | `{ success: true }` | 切换 2D/3D 视角模式 |
| `TOGGLE_LAYER` | `{ types: string[], visible: boolean }` | `{ success: true, visibleTypes: string[] }` | 批量控制某类底座设施的显示隐藏 |
| `GET_MANIFEST` | `{}` | `ManifestData` | 获取地图 Manifest楼层列表、元数据 |
| `LOAD_FLOOR_BUNDLE` | `{ floorId: string \| number }` | `FloorBundleData` | 一次性加载楼层完整 Bundle模型+POI+空间面+讲解点) |
| `GET_FLOOR_POIS` | `{ floorId: string \| number }` | `{ pois: PoiItem[] }` | 获取指定楼层 POI 列表 |
| `GET_SPACES` | `{ floorId: string \| number }` | `{ spaces: SpaceItem[] }` | 获取指定楼层空间面列表 |
| `GET_GUIDE_STOPS` | `{ floorId: string \| number }` | `{ guideStops: GuideStopItem[] }` | 获取指定楼层讲解点列表 |
| `GET_NAVIGABLE_PLACES` | `{ floorId: string \| number }` | `{ navigablePlaces: SgsNavigablePlace[] }` | 获取指定楼层可导航目的地列表 |
| `PRELOAD_FLOOR` | `{ floorId: string \| number }` | `{ success: true }` | 后台静默预加载指定楼层模型资源 |
| `CLEAR_MODEL_CACHE` | (空) | `{ success: true, freedBytes: number }` | 清空客户端模型缓存 |
| `GET_PERFORMANCE_STATS` | (空) | `PerformanceStats` | 获取渲染性能统计FPS/DrawCall/纹理内存) |
| `GET_DIAGNOSTICS` | `{}` | `SgsMapDiagnostics` | 获取地图级 SDK 数据健康诊断 |
| `GET_FLOOR_DIAGNOSTICS` | `{ floorId: string \| number }` | `SgsFloorDiagnostics` | 获取指定楼层 SDK 数据健康诊断 |
> **类型定义备注:**
> `SgsMapNode` 及 `RouteResult` 的精确结构请参考 TypeScript 源码定义:`sdk-src/types.ts`。
>
> **v2.3.0 类型放宽**:所有 ID 字段(`floorId`、`mapId`、`poiId` 等)支持 `string | number`,向下兼容纯数字调用。
>
> **v2.3.0 主要类型**`ManifestData`、`FloorBundleData`、`PoiItem`、`SpaceItem`、`GuideStopItem`、`SgsNavigablePlace`、`SgsMapDiagnostics`、`SgsFloorDiagnostics`、`PerformanceStats` 的精确结构请参考 `sdk-src/types.ts`。
---
## 4. 事件广播列表 (Event Action List)
| 事件 Action | Payload 结构 | SDK 派发事件名 | 触发时机 |
|-------------|--------------|----------------|----------|
| `ENGINE_READY` | `{ engineVersion, protocolVersion, sdkVersion }` | `ready` | 基座完全挂载WebGL 画布可渲染 |
| `ON_POI_CLICK` | `{ id, name, type }` | `poiClick` | 用户在触摸屏或鼠标点击了高亮要素 |
| `ON_FLOOR_CHANGED`| `{ floorId }` | `floorChanged` | 楼层完全切换完毕后自动抛出 |
| `ON_MODEL_LOADING` | `{ floorId, modelUrl }` | `modelLoading` | 模型文件开始网络加载 |
| `ON_MODEL_READY` | `{ floorId, parseTimeMs }` | `modelReady` | 模型解析完成Scene 已挂载 |
| `ON_MODEL_ERROR` | `{ floorId, error, fallbackUsed }` | `modelError` | 模型加载失败(含 fallback 信息) |
| `ON_FLOOR_BUNDLE_READY` | `{ floorId, dataVersion }` | `floorBundleReady` | 楼层 Bundle 数据全部就绪 |
| `ON_ROUTE_READY` | `{ routeId, distance, duration }` | `routeReady` | 路径规划完成 |
---
## 5. 安全沙箱规则 (Security & Sandboxing)
1. **Origin 发射校验 (SDK 侧)**
- `sgs-map-sdk.js` 使用 `iframe.contentWindow.postMessage(msg, targetOrigin)` 发射指令。若 `targetOrigin` 错误,浏览器底层会进行跨域阻断。
2. **Origin 监听校验 (SDK 侧)**
- 收到事件时比对 `event.origin !== targetOrigin`,丢弃第三方注入的伪造消息。
- 收到事件时比对 `event.source !== this.iframe.contentWindow`,丢弃宿主页面其他无关 iframe 的干扰。
3. **安全内存释放 (GC)**
- 断网或后服务宕机时SDK 侧的 `Promise` 将在设定的 `timeout` (默认 5000ms) 到达后自动 `reject`
- SDK 实例调用 `destroy()` 后,会清除自身 DOM 及事件树,杜绝闭包引用与孤儿 WebGL Context。