Files
planet/docs/technical/zh/datasource-collector-settings-connectivity.md
linkong 93eb41a9f7
Some checks failed
ci / backend (push) Has been cancelled
ci / frontend (push) Has been cancelled
ci / delivery (push) Has been cancelled
release / images (push) Has been cancelled
release: bump version to 0.58.0
Release 0.58.0 includes the Earth high-precision boundary PMTiles/MVT pipeline, standardized Earth boundary source collectors, China POV boundary configuration templates, and removal of the legacy low-precision GeoJSON fallback. It also adds Earth news target-location queueing/archive support, fixes datasource task status visibility, documents the Earth surface depth-spacing rules that prevent far-zoom z-fighting snow/black blocks, and updates bilingual operations/developer docs.
2026-05-15 17:40:07 +08:00

462 lines
16 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.
# 采集器设置与连接验证
## 背景
控制台现在把“数据源目录”和“采集器配置”拆开:
- `/datasources`
- 展示所有数据源,包括内置和自定义。
- 点击名称只打开信息抽屉。
- 负责查看状态、触发采集和查看采集中任务。
- `/settings?tab=collector_credentials`
- 显示为“采集器设置”。
- 负责 endpoint、请求头、基础参数和凭证配置。
- 所有采集器都提供连接按钮,用于健康检查。
这样做是为了减少首次使用时的认知分裂:接口地址、请求头、凭证和自定义源配置都属于“采集器设置”,而不是散落在数据源列表和系统设置多个入口里。
## 用户侧规则
连接状态不是前端样式状态,而是由后端根据配置 checksum 和已验证记录判断。
一个内置采集器被视为“已连接”需要满足任一条件:
- 当前配置已经成功采集过数据。
- 当前配置点击过连接按钮,并且后端验证成功。
如果 endpoint、请求头、基础配置或凭证指纹相对上次验证成功时发生变化状态会回到“需要重新连接”。
## 前端入口
### 数据源目录
文件:
- [DataSources.tsx](/home/ray/dev/linkong/planet/frontend/src/pages/DataSources/DataSources.tsx)
- [index.css](/home/ray/dev/linkong/planet/frontend/src/index.css)
当前行为:
- 内置数据源和自定义数据源合并为 `UnifiedDataSource` 列表。
- 表格只保留查看、采集和状态类操作。
- 名称点击打开只读抽屉。
- 抽屉中展示:
- 是否内置
- 是否启用
- 模块、优先级、频率
- endpoint
- 请求头
- 基础配置
- 是否需要凭证
- 有任务运行时,顶部进度区显示 `采集中 N` 可点击标签。
- 点击 `采集中 N` 打开任务列表弹窗,显示各任务进度。
`data-source-bulk-toolbar__running-pill` 是“采集中”标签的样式入口。它和其他状态标签同排,但通过 hover、箭头和蓝色描边表达可交互性。
### 采集器设置
文件:
- [Settings.tsx](/home/ray/dev/linkong/planet/frontend/src/pages/Settings/Settings.tsx)
当前行为:
- `collector_credentials` tab 展示为“采集器设置”。
- 下拉框列出内置采集器,并支持维护合并到内置数据的自定义补充源。
- 下拉框右侧只有一个插头图标按钮,用于健康检查。
- 下拉框下方用状态标签展示:
- `需要凭证` / `无需凭证`
- 模块
- `启用` / `禁用`
- `未检查` / `可用` / `不可用`
- 是否覆盖 endpoint
- 需要凭证的采集器把凭证卡片放在基础配置上方。
- 不需要凭证的采集器只显示基础配置。
- AISStream 采集器使用 WebSocket 语义,状态会显示为连接中、实时接收、重连或停止,不使用固定百分比表达完成度。
- 自定义源入口放在采集器设置内,不在数据源目录里重复提供编辑入口;数据源目录只保留总览、运行和只读抽屉。
连接按钮使用内联 Tabler 风格插头图标,来源语义对应 `plug-connected`,避免继续使用刷新图标表达连接动作。
## 后端接口
### 数据源配置列表
```http
GET /api/v1/datasources/configs/all
```
返回 YAML 默认数据源和数据库覆盖配置的合并结果。该路由必须定义在 `/configs/{config_id}` 之前,否则 `all` 会被 FastAPI 当成路径参数并触发 422。
返回字段包括:
- `name`
- `default_url`
- `endpoint`
- `is_overridden`
- `is_active`
- `source_type`
- `auth_type`
- `headers`
- `config`
- `config_id`
- `description`
`config` 返回前会移除内部连接验证字段,避免前端把校验元数据当成用户配置展示。
### 内置采集器连接状态
```http
POST /api/v1/datasources/configs/builtin/connection-status
```
用途:
- 给定一份候选配置。
- 计算 checksum。
- 判断当前配置是否已经连接。
当前前端主要通过连接按钮即时检查,不强依赖这个接口,但它是后续保存按钮置灰、页面初始化状态恢复的后端依据。
### 内置采集器连接验证
```http
POST /api/v1/datasources/configs/builtin/connect
```
用途:
- 免费采集器直接请求 endpoint。
- 需要凭证的采集器走对应 credential provider。
- 验证成功后写入系统级连接记录。
成功返回中会带:
- `success`
- `connected`
- `checksum`
- `stage`
- `message`
- `response_time_ms`
- `credential_provider`
- `credential_source`
### BarentsWatch AIS 连接验证
```http
POST /api/v1/settings/integrations/barentswatch/connect
GET /api/v1/settings/integrations/barentswatch/connectivity
```
BarentsWatch 使用独立接口,是因为它需要在保存前验证草稿凭证:
- 使用草稿 `client_id` / `client_secret` 获取 token。
- 使用 token 请求 AIS endpoint。
- 连接成功后用草稿凭证指纹写入内置采集器连接记录。
## 连接校验服务
文件:
- [datasource_connectivity.py](/home/ray/dev/linkong/planet/backend/app/services/datasource_connectivity.py)
核心职责:
- 计算内置采集器配置 checksum。
- 读取环境变量和 `~/.zshrc` 中的凭证。
- 判断当前配置是否已连接。
- 执行 endpoint 健康检查。
- 保存连接成功记录。
### checksum 组成
checksum 包含:
- 采集器名称
- endpoint
- auth type
- headers
- 去掉内部校验字段后的 config
- credential provider
- 凭证指纹
凭证指纹使用凭证内容 hash不把明文凭证写入连接记录。
### 连接记录
连接成功记录写入 `SystemSetting`
```text
category = datasource_connectivity_validations
```
payload 以采集器 source 为 key
```json
{
"barentswatch_vessels": {
"checksum": "...",
"status": "success",
"validated_at": "2026-04-29T00:00:00+00:00",
"status_code": 200,
"credential_source": "datasource_config",
"connected_by": "connection_button"
}
}
```
`connected_by` 当前有两个来源:
- `connection_button`
- 用户手动点击连接按钮。
- `collection`
- 采集任务成功完成,系统自动记录当前有效配置已连通。
### 成功采集即连接
调度器在采集成功后会调用连接记录写入逻辑:
- [scheduler.py](/home/ray/dev/linkong/planet/backend/app/services/scheduler.py)
这样已有数据的采集器不会要求用户重复验证。只有当配置 checksum 变化时,才需要重新点击连接。
## BarentsWatch AIS 凭证链路
文件:
- [barentswatch.py](/home/ray/dev/linkong/planet/backend/app/services/barentswatch.py)
- [vessel_ais.py](/home/ray/dev/linkong/planet/backend/app/services/collectors/vessel_ais.py)
解析优先级:
1. `DataSourceConfig.auth_config`
2. `DataSourceConfig.config`
3. 环境变量
4. `~/.zshrc`
支持的环境变量:
```bash
export BARENTSWATCH_CLIENT_ID="..."
export BARENTSWATCH_CLIENT_SECRET="..."
```
也兼容历史拼写:
```bash
export BARRENTSWATCH_CLIENT_ID="..."
export BARRENTSWATCH_CLIENT_SECRET="..."
```
Token 请求规则:
- Token URL`https://id.barentswatch.no/connect/token`
- `Content-Type`: `application/x-www-form-urlencoded`
- Body:
- `grant_type=client_credentials`
- `client_id`
- `client_secret`
- `scope=ais`
AIS 请求规则:
- Endpoint 默认:`https://live.ais.barentswatch.no/v1/latest/combined`
- Header`Authorization: Bearer <access_token>`
`VesselAISCollector` 不再自己读取环境变量,而是统一走 `resolve_barentswatch_config()``fetch_barentswatch_access_token()`,避免设置页、连接验证和采集器三套凭证逻辑分叉。
## AISStream 采集器链路
文件:
- [aisstream.py](/home/ray/dev/linkong/planet/backend/app/services/collectors/aisstream.py)
- [vessel_ais_aggregation.py](/home/ray/dev/linkong/planet/backend/app/services/vessel_ais_aggregation.py)
AISStream 使用 WebSocket 实时流,采集器只写入 `ais_raw_observations` 原始观测层,不直接覆盖最终船只展示表。聚合接口负责多源去重、字段选择和冲突记录。
配置项:
- `api_key`:保存在 `DataSourceConfig.auth_config`,也可用环境变量 `AISSTREAM_API_KEY`
- `endpoint`:默认 `wss://stream.aisstream.io/v0/stream`
- `message_types`:默认 `PositionReport``ShipStaticData`
- `bounding_boxes`AISStream 格式为 `[[[lat_min, lon_min], [lat_max, lon_max]]]`,设置页提供全球、挪威 / 北海、欧洲近海、东亚、北美东西海岸 preset。
- `max_messages``receive_timeout_seconds`:控制单次批次式 WebSocket 采集窗口。
标准化规则:
- `PositionReport` 主要提供位置、速度、航向和状态。
- 船名可以从 `MetaData.ShipName` 补入,即使消息体本身没有 `name`
- 船型通常来自低频 `ShipStaticData.Type`;后端会把 AIS 数字类型码映射为 Cargo / Tanker / Passenger / Fishing / Military。
- 如果某艘船尚未收到静态消息,聚合结果的船型仍可能是 `Other`,后续由 v5 船舶资料 enrichment 补齐。
连接验证会读取保存配置、环境变量和 `~/.zshrc` 中的 `AISSTREAM_API_KEY`。正式采集时,推荐把 API Key 保存到采集器设置;如果只写在 `~/.zshrc`,需要确认后端进程实际继承了该变量,否则连接验证可能可用但 collector 运行时拿不到 key。
连接验证和正式采集是两个不同动作。设置页出现 `AISStream 凭证已配置WebSocket endpoint 格式有效` 只说明配置可以用于连接;运行状态仍可能是 `disconnected`。只有 `aisstream_vessels` 处于 `streaming` / `connected`,并且实时流计数、`last_seen_at` 持续更新时,全球 AIS 数据才会不断写入本地库。启动、停止、重连、健康状态和计数统一从 `/datasources -> 实时流``/api/v1/realtime-sources` 查看AISStream 不再参与普通一键采集进度。
新版本不再使用 legacy `/api/v1/visualization/geo/vessels` 作为船只列表入口。Earth 初始状态应调用:
```http
GET /api/v1/vessels/snapshot?bbox=lon_min,lat_min,lon_max,lat_max&zoom=12&limit=1000
```
该接口优先查询本地 `ais_raw_observations` 聚合结果;当当前 raw 窗口为空时,会受控回退到 legacy `vessel_position` / `vessel_static` 最新点,并通过 `diagnostics.legacy_fallback_used` 暴露。实时更新走 `/ws``vessels` channel订阅时必须提供 `bbox``zoom``limit`。服务端按连接过滤 bbox并对 collector 广播做 1 秒合并,同一 MMSI 只推送最新位置。
## 自定义 REST / WebSocket 映射运行时
文件:
- [custom_datasource_runtime.py](/home/ray/dev/linkong/planet/backend/app/services/custom_datasource_runtime.py)
- [datasource_mapping.py](/home/ray/dev/linkong/planet/backend/app/services/datasource_mapping.py)
自定义源现在不是独立的新数据孤岛,而是作为内置数据源的补充源写入目标 schema。当前最完整的目标是 `vessel_ais`:自定义 REST 或 WebSocket 源经过确定性 mapping 后写入 AIS raw observations再通过 `vessels` WebSocket channel 推送给 Earth。
Earth 高精度边界使用同一套目标 schema 机制。`earth_boundary_source` 承接 `earth_admin0_boundaries``earth_coastline``earth_claim_lines` 三类源的映射结果;完整 GeoJSON / JSON 原文保存为 artifact数据库只保存 source kind、sha256、feature count、license、artifact path 和 sample properties避免把大型几何塞进单行记录。
### 配置语义
关键字段:
- `source_type``rest` / `http` / `websocket` / `ws`
- `endpoint`REST 使用 `http(s)://`WebSocket 使用 `ws(s)://`
- `auth_type``none``bearer``api_key``basic`
- `headers`:静态请求头。
- `auth_config`token、API key、basic 用户名密码API key 支持 header 或 query。
- `config.target_schema`:例如 `vessel_ais``earth_boundary_source`
- `config.delivery_mode`REST 默认 `polling`WebSocket 默认 `realtime_stream`
- `config.merge_target_source`:记录该自定义源补充哪个内置数据,例如 `barentswatch_vessels`
REST runner 支持:
- `GET` / `POST`
- query params
- JSON body
- headers 和 auth 注入
- active mapping 写入目标 schema
WebSocket runner 支持:
- endpoint 格式校验
- headers 和 auth 注入
- 可选 `ws_subscribe_message`
- `ws_message_path` / `ws_items_path` 提取消息主体或数组
- 断线重连
- `debug_max_messages` 调试上限
- 后台 stream start / stop / status
相关 API
```http
POST /api/v1/datasources/custom/sample
GET /api/v1/datasources/target-schemas
POST /api/v1/datasources/{config_id}/run-mapped
POST /api/v1/datasources/{config_id}/stop-mapped
GET /api/v1/datasources/{config_id}/mapped-status
DELETE /api/v1/datasources/configs/{config_id}?delete_mappings=true&delete_source_data=true
```
`run-mapped?background=true` 只对 WebSocket 源有意义,会启动后台 stream。REST 源仍是一次性采集。
### 删除与数据清理
删除自定义源时有三种层级:
- 只删除配置:保留 mapping 和历史数据。
- 删除配置和 mapping同时删除该配置的 mapping 模板。
- 删除配置、mapping 和该源数据:删除该源写入的 `collected_data``ais_raw_observations``ais_source_health`
如果删除的是 `vessel_ais` 自定义源数据,后端会向 `vessels` channel 广播 `reload_required`,提示 Earth 重新拉取船只聚合结果。legacy `vessel_position` 不按自定义源直接删除,因为它没有可靠的 source 归因。
### 本地 AIS mock WebSocket
文件:
- [mock-ais-ws-server.ts](/home/ray/dev/linkong/planet/scripts/mock-ais-ws-server.ts)
运行方式:
```bash
bun run mock:ais-ws
```
mock 服务持续发送 AIS-like JSON用于验证“WebSocket 自定义源 -> mapping -> AIS raw observation -> `vessels` channel -> Earth 船只 upsert”链路。典型配置
```json
{
"source_type": "websocket",
"endpoint": "ws://localhost:8787",
"config": {
"target_schema": "vessel_ais",
"delivery_mode": "realtime_stream",
"merge_target_source": "barentswatch_vessels",
"ws_message_path": "$.data",
"ws_items_path": "$.vessels[*]",
"ws_reconnect": true
}
}
```
## 凭证教程
文件:
- [credential_guides.py](/home/ray/dev/linkong/planet/backend/app/services/credential_guides.py)
接口:
```http
GET /api/v1/settings/credential-guides/{provider}
POST /api/v1/settings/credential-guides/{provider}/generate
POST /api/v1/settings/credential-guides/{provider}/reset
```
当前支持:
- `barentswatch`
- `aisstream`
默认教程包含 BarentsWatch 官方 tutorial 地址:
```text
https://developer.barentswatch.no/docs/tutorial
```
如果用户点击“教程不好用”,后端会把默认 prompt 发给 AI Provider 生成新的中文教程,并保存到 `SystemSetting`
```text
category = collector_credential_guides
```
“重置”会删除自定义教程,恢复默认教程。
## 保存规则
内置采集器配置保存时会移除内部 `connectivity_validation` 字段,避免校验状态跟用户配置混在一起。
BarentsWatch `client_secret` 保存时有特殊处理:
- 输入框显示脱敏预览。
- 如果提交值仍等于脱敏预览,后端保留原 secret。
- 如果输入新值,才替换 secret。
- 不再提供单独“清除当前 secret”复选框。
## 测试覆盖
相关测试:
- [test_vessels.py](/home/ray/dev/linkong/planet/backend/tests/test_vessels.py)
新增覆盖:
- 能从 `~/.zshrc` 解析 BarentsWatch 凭证。
- 环境变量为空时,`resolve_barentswatch_config()` 能回退到 `~/.zshrc`
- 船只数据转换和 GeoJSON 输出保持兼容。
## 当前 Provider 覆盖
当前已经支持的凭证 provider
- `barentswatch`
- `aisstream`
- `spacetrack`
其他 `requires_credentials=true` 的采集器如果还没有 provider会返回“凭证链路尚未接入”前端显示 `不可用`