13 KiB
Custom Source Live Mock 计划
状态:实施中
创建日期:2026-05-01
任务名:Custom Source Live Mock
核心目标:把自定义源升级为同时支持 REST 与 WebSocket 的可映射采集入口,并提供本地 AIS mock WebSocket 服务,用于验证 Earth 船只实时新增与 upsert 链路。
背景
真实 AIS 接口变化频率不可控,无法稳定验证 Earth 页面“不刷新也能看到新船只”的实时链路。当前系统已经有自定义源基础设施:
datasource_configs保存 endpoint、auth、headers、config。datasource_mapping_templates保存目标 schema 的确定性映射模板。run-mapped支持保存后的自定义 REST 源通过 active mapping 写入目标数据。
但现有能力主要面向 REST sample 和批量 mapping,缺少以下能力:
- 自定义源不能明确选择
REST或WebSocket采集模式。 - WebSocket 长连接、订阅消息、重连、消息路径提取还没有通用 runtime。
vessel_ais自定义数据写入后需要进入 AIS raw observation 和vesselsWS channel,才能真实验证 Earth 实时 upsert。- 删除自定义源时没有清晰的数据清理选项。
- 设置中心里“采集调度 / 凭证 / 自定义源”入口混杂,用户很难判断该在哪里配置。
已确认决策
| 项目 | 决策 |
|---|---|
| 计划名称 | Custom Source Live Mock |
| 自定义源传输类型 | 支持 REST 与 WebSocket |
| 采集写入方式 | 先映射到目标 schema,再由 destination handler 写入 |
| AIS mock 目标 | 优先打通 vessel_ais,验证 Earth 船只实时新增和同 MMSI upsert |
| mock 服务 runtime | 使用 bun 启动本地 mock WS 服务 |
| 凭证配置 | 支持 headers、bearer、api key、basic,并保留 query/header API key 位置配置 |
| 删除策略 | 删除自定义源时允许选择是否删除该源写入的数据 |
| 合并语义 | 自定义源必须选择“合并到哪个内置数据”,作为内置源的补充数据进入同一聚合链路 |
| UI 方向 | 自定义源创建和维护放在“配置中心 > 采集器设置”的采集器下拉框内联入口;数据源页保留总览与运行控制 |
范围
本阶段要做
- 自定义源可选择
REST或WebSocket。 - 自定义源支持请求头、凭证、query params、body、WS subscribe message。
- WebSocket 自定义源支持长连接、重连、消息解析、mapping、写入。
vessel_ais自定义源写入 AIS raw observations,并广播vesselschannel。- 提供 mock AIS WS 服务,持续发送新增 MMSI 和位置变更。
- 删除自定义源时提供“是否删除该源数据”的选项。
- 梳理设置中心信息架构,明确后续 UI 重构方向。
暂不做
- 不新增任意动态数据库表。
- 不允许用户提交可执行脚本作为 mapping。
- 不让 LLM 进入正式采集链路。
- 不把 mock 数据直接写 legacy
vessel_position,优先写 AIS raw observations,保持可追踪和可删除。 - 不在本阶段完成完整
Earth Live Sync,但要为后续 summary invalidation 留出 hook。
现状入口
| 能力 | 当前位置 |
|---|---|
| 自定义源配置模型 | backend/app/models/datasource_config.py |
| 自定义源 mapping 模型 | backend/app/models/datasource_mapping.py |
| 自定义源 API | backend/app/api/v1/datasource_config.py |
| 目标 schema registry | backend/app/core/target_schema_registry.py |
| mapping engine | backend/app/services/datasource_mapping.py |
| 数据源总览 UI | frontend/src/pages/DataSources/DataSources.tsx |
| 采集器设置 UI | frontend/src/pages/Settings/Settings.tsx |
目标架构
flowchart LR
A[Custom Source Config] --> B{source_type}
B -->|rest| C[Mapped REST Runner]
B -->|websocket| D[Mapped WS Runner]
C --> E[Mapping Engine]
D --> E
E --> F[Target Schema Validator]
F --> G{Destination Handler}
G -->|vessel_ais| H[AIS Raw Observations]
H --> I[AIS Aggregation]
H --> J[vessels WS Channel]
J --> K[Earth Vessel Upsert]
数据配置设计
短期可以继续复用 DataSourceConfig,避免大迁移。语义约定如下:
| 字段 | 用途 |
|---|---|
name |
自定义源唯一名称,例如 mock_ais_ws |
source_type |
rest 或 websocket |
endpoint |
http(s)://... 或 ws(s)://... |
auth_type |
none、bearer、api_key、basic |
auth_config |
token、api_key、key name、basic username/password 等 |
headers |
静态请求头 |
config |
method、params、body、timeout、retry、WS 订阅消息、重连策略、消息路径等 |
建议 config 结构:
{
"transport": "websocket",
"delivery_mode": "realtime_stream",
"merge_target_source": "barentswatch_vessels",
"target_schema": "vessel_ais",
"method": "GET",
"params": {},
"body": null,
"timeout": 30,
"retry": 3,
"ws_subscribe_message": {"type": "subscribe", "channel": "vessels"},
"ws_message_path": "$.data",
"ws_items_path": "$.vessels[*]",
"ws_reconnect": true,
"reconnect_delay_seconds": 3,
"debug_max_messages": null,
"delete_policy": "config_only"
}
后端实施计划
Phase 1 — 自定义源类型与连接测试
- 允许
source_type为rest或websocket。 - REST 连接测试保留现有 HTTP 请求逻辑。
- WebSocket 连接测试新增:
- 校验 endpoint 必须是
ws://或wss://。 - 注入 headers 和 auth。
- 连接后可选发送
ws_subscribe_message。 - 读取一条消息或超时返回诊断。
- 校验 endpoint 必须是
Phase 2 — Mapped REST Runner 补齐
现有 run-mapped 继续作为 REST 一次性采集入口,补齐:
GET/POSTmethod。- query params。
- JSON body。
- headers 和 auth 注入。
- sample limit 与响应大小限制。
vessel_aisdestination handler。
Phase 3 — Mapped WebSocket Runner
新增通用 WebSocket runner,读取 DataSourceConfig + active mapping:
- 建立长连接。
- 发送可选订阅消息。
- 循环接收消息。
- JSON parse。
- 按
ws_message_path/ws_items_path提取 item 或 list。 - 使用 mapping engine 转换。
- 使用 target schema validator 校验。
- 调用 destination handler 写入。
- 更新采集任务状态:
connectingstreamingreconnectingstopped
- 维护运行指标:
messages_seenrecords_writtenunique_entitieslast_message_atlast_error
- 后台长连接不读取
config.debug_max_messages;该字段只用于显式的一次性调试运行,避免正式 WS 流被测试上限截断。
Phase 4 — Destination Handler
为 target schema 建立明确写入处理器。
vessel_ais handler:
- 写入
AISRawObservation。 source = datasource.name。delivery_mode来自 config,默认 WS 为realtime_stream、REST 为polling。transport来自source_type。- 生成幂等 observation hash。
- 更新 AIS source health。
- 广播
vesselschannel,payload 使用当前 Earth 已支持的 upsert 格式。
generic_records handler:
- 写入通用 collected data 或后续 generic store。
- 不直接进入 Earth。
Phase 5 — 删除与数据清理
删除自定义源时新增清理策略:
| 选项 | 行为 |
|---|---|
| 只删除配置 | 删除 datasource_configs,保留 mapping 和历史数据需要另行处理 |
| 删除配置和 mapping | 删除配置及对应 datasource_mapping_templates |
| 删除配置、mapping 和该源数据 | 同时删除该源写入的数据 |
数据删除范围:
collected_data.source == datasource.nameais_raw_observations.source == datasource.nameais_source_health.source == datasource.name
不建议直接删除 legacy vessel_position,因为当前 legacy 表不带 source,无法安全归因。自定义 AIS 源应优先只写 raw observations。
删除数据后应触发:
vesselschannel 的 reload/invalidation 事件,提示 Earth 重新拉船只聚合。- 后续接入
Earth Live Sync后,触发earth_summaryinvalidation。
Phase 6 — Mock AIS WebSocket 服务
新增脚本:
scripts/mock-ais-ws-server.ts
运行方式建议:
bun run mock:ais-ws
服务行为:
- 监听
ws://localhost:8787/ais。 - 接受任意客户端连接。
- 可记录收到的 subscribe message。
- 每 1-2 秒发送一条 AIS-like JSON。
- 每隔 N 条生成新 MMSI,验证船只数量增长。
- 已存在 MMSI 随时间改变
lat/lon/cog/heading,验证同 MMSI upsert。 - 支持固定 seed,保证测试可复现。
示例 payload:
{
"type": "vessel",
"data": {
"mmsi": "999000001",
"name": "MOCK VESSEL 001",
"lat": 31.23,
"lon": 121.47,
"sog": 12.4,
"cog": 86,
"heading": 90,
"received_at": "2026-05-01T00:00:00Z"
}
}
前端实施计划
信息架构调整
自定义源不作为割裂的新入口,而是作为内置采集器的补充源,直接纳入“配置中心 > 采集器设置”的采集器选择器:
- 采集器下拉框同时展示内置采集器和自定义补充源。
- 下拉框右侧提供加号按钮,用于添加自定义源。
- 新建自定义源时必须选择“合并到内置数据”,例如合并到
barentswatch_vessels。 - 选择自定义源后,右侧基础配置区域沿用正常采集器配置形态,支持连接测试、保存、endpoint、headers、auth、高级 JSON。
- 自定义源比内置源多一个“删除自定义源”按钮。
- 删除时弹出确认框,可勾选“同时删除该自定义源生成的所有数据”。
数据源页保留:
- 内置源总览。
- 内置源最近状态。
- 内置源手动触发。
- 不展示自定义源管理入口;自定义源创建、维护、删除统一在采集器设置中完成。
自定义源表单
新增或重构自定义源表单:
- 源名称。
- 类型:
REST/WebSocket。 - 合并到内置数据:必选,用于声明该源补充哪个内置数据域。
- endpoint。
- method/body/params,仅 REST 显示。
- subscribe message/message path/items path,仅 WS 显示。
- auth type。
- headers。
- target schema。
- sample/test 按钮。
- mapping assistant/preview。
- 保存并运行。
删除确认
删除自定义源时弹出确认:
- 默认只删除配置。
- 可勾选删除 mapping。
- 可勾选删除该源写入的数据。
- 显示将删除的数据范围和不可恢复提示。
验证方案
Mock WS 验证路径
- 启动 mock 服务:
bun run mock:ais-ws
- 新建自定义源:
| 字段 | 值 |
|---|---|
| name | mock_ais_ws |
| source_type | websocket |
| endpoint | ws://localhost:8787/ais |
| merge_target_source | barentswatch_vessels |
| target_schema | vessel_ais |
| ws_message_path | $.data |
- 保存 active mapping:
{
"source": {
"items_path": "$"
},
"fields": {
"mmsi": {"path": "$.mmsi", "type": "integer"},
"name": {"path": "$.name", "type": "string"},
"lat": {"path": "$.lat", "type": "float"},
"lon": {"path": "$.lon", "type": "float"},
"sog": {"path": "$.sog", "type": "float", "default": null},
"cog": {"path": "$.cog", "type": "float", "default": null},
"heading": {"path": "$.heading", "type": "integer", "default": null},
"received_at": {"path": "$.received_at", "type": "datetime", "default": null}
}
}
-
启动自定义源。
-
打开 Earth 船只图层,不刷新页面观察:
vesselsWS channel 收到source = mock_ais_ws。- HUD 船只数在新 MMSI 到达时增加。
- 地球出现
MOCK VESSEL。 - 同 MMSI 后续消息更新位置和航向,不重复叠加。
自动化测试
后端测试:
- WebSocket 自定义源连接测试。
- WS message path 和 items path 提取。
- mapping 到
vessel_ais。 - 写入 AIS raw observation。
- 广播
vesselschannel。 - 删除自定义源时按策略删除 mapping 和源数据。
前端测试:
- REST/WS 表单条件显示。
- 删除确认选项。
- mock 源配置保存 payload。
- mapping preview 展示错误和成功记录。
风险与约束
- WebSocket 自定义源是长连接,不能沿用一次性 REST 进度条。
- 如果 mock 源写 legacy vessel 表,删除会变得不安全,因此先只写 raw observations。
- 自定义 WS 可能消息量很大,必须有 backpressure、日志限流和任务取消能力。
- 任意外部 WS 不能信任 payload,必须经过 mapping 和 schema validation。
- headers/auth 不能进入 LLM mapping prompt。
交付顺序
- Mock AIS WS 服务。
- 后端自定义 WS runner。
vessel_aisdestination handler 和vesselsbroadcast。- 删除自定义源及数据清理。
- 设置中心采集器下拉框内联自定义源 UI。
- 配置中心信息架构重整。
- 与
Earth Live Sync对接 summary invalidation。