Files
MoShiro/docs/api.md
T

15 KiB
Raw Blame History

Backend API 规范(v1)

本文列出 Backend 的全部对外接口。通用规则见 api-guidelines.md;OpenAPI 3.1 文档在运行时由 /openapi/v1.json 提供,构建时同时生成快照 backend/openapi/v1.json。两者冲突时,以 OpenAPI 为准。

1. 分层

/api/public/*     只读。站点设为公开时匿名可访问,设为私有时需要登录或只读令牌;
                  public_visible = false 的 Agent 对匿名访客隐藏
/api/admin/*      管理。需要 Cookie 会话(含 CSRF 校验)或 admin 作用域的 API 令牌(`POST /api/admin/releases` 也接受只能登记发布清单的 release 令牌)
/api/agent/v1/*   节点专用:注册(使用加入令牌)和 RPC(使用签名认证)
/healthz  /metrics  /openapi/v1.json  /install.sh  /install.ps1

资源总览:

/api/public
├─ overview                          首屏快照:所有线路的在线状态、最新指标、评分
├─ live                              SSE 实时推送
├─ lines/{line_id}                   线路详情(线路 = Agent 与 Probe 的一对,id 形如 agt_…~prb_…)
├─ lines/{line_id}/series            历史曲线(指标与评分)
├─ nodes   about                      节点的展示信息(系统、国家、运营商,开启后带版本和 tag);后端的版本信息
├─ compare                           多条线路对比
├─ tests/{test_id}                   测试结果
└─ catalog/{kinds|plans|metrics|models}   目录(由代码注册表生成)

/api/admin
├─ auth/{login|logout|me}
├─ agents  agents/{id}  agents/{id}/{approve|disable|enable|takeover}
├─ join-tokens
├─ probes  probes/{id}  probes/{id}/{rotate|revoke}   Probe 身份(后端生成、吊销、删除)
├─ links  links/{probe_id}/{agent_id}   线路开关:哪些(Probe,Agent)连成线路(自动连接 + 手动选择)
├─ tasks  tasks/{id}                 线路模板、针对单个 Agent 的覆盖、目标任务
├─ lines/{line_id}/tests             在某条线路(某个 Probe)上发起按需测试;tests/{id}/cancel
├─ raw/chunks  raw/chunks/{id}       原始数据检索与下载
├─ build-info                        后端和每个节点的版本、tag、提交、构建时间、更新状态
├─ releases  nodes/{id}/update       CI 签名的发布清单(登记、列表);请求节点更新
├─ events   analysis/recompute   api-tokens   settings   users

2. Public API

展示数据的查询规则(时间段、步长、分层、指标分组、列式响应、实时跟随、缓存)以 query.md 为准。本节只列出端点。

2.1 首屏排行

GET /api/public/overview?range=5m&preset=udp,tcp,scores&sort=score.mc&order=desc

  • 返回每条线路在该时间段内的精确汇总,以及在线状态、会话信息(源地址变化次数)、最近一次测试的摘要;
  • range 默认 5m,也可以写 from/to;
  • 汇总字段的格式见 query.md 第 6 节。

2.2 实时推送(SSE)

GET /api/public/live?topics=nodes,overview:15m:udp,series:agt_…:2s:udp,tcp,test:tst_…(text/event-stream)

事件 订阅主题 频率 内容
node nodes 上下线时 {kind, id, online, at}
overview overview:{range}:{preset} 约每 10 s 每条线路的最新汇总
series series:{line_id}:{step}:{preset}(step ≤ 1m) 约每 10 s 新增的桶(列式)和最新的汇总
host hosts Agent 每次上报(约 2 s) {agent_id, online, host}:Agent 主机资源占用的最新快照(连接时先推一份当前的)
test test:{test_id} 状态变化时 {test_id, status, phase, phases}
  • 每 15 秒发送一行注释作为心跳;断线后浏览器会自动重连,服务端先推送当前快照,再推送增量,不补发历史。
  • 单个连接最多订阅 32 个主题;每个客户端最多 4 个 SSE 连接。

2.3 时序、对比、分布

端点 说明
GET /api/public/lines/{line_id}/series?range=15m&preset=udp,tcp 单条线路的时序(列式),附带整个时间段的精确汇总、缺口和事件
GET /api/public/compare?lines=a~p1,b~p1,c~p2&metric=loss.down&range=1h 多条线路的时间轴对齐对比
GET /api/public/lines/{line_id}/distribution?metric=rtt&range=15m 该时间段内的直方图和 CDF
GET /api/public/lines/{line_id}/heatmap?metric=rtt&range=6h 时间 × 延迟桶的热力图

参数、响应示例和限额见 query.md。

线路详情 GET /api/public/lines/{line_id} 带 data_since:这条线路最早的数据是什么时候(没有数据是 null),前端据此只提供「有数据」的时间范围。展示端的响应里没有 Probe 的版本和来源地址(那些只在管理端)。

2.3.1 Agent 的主机资源占用

端点 内容
GET /api/public/hosts 每个对外可见的 Agent 的最新快照:{agent_id, name, online, stale, last_seen_at, host};超过 15 s 没有更新 stale 为真(离线,或者 Agent 关了上报)
GET /api/public/agents/{agent_id}/host?range=1h 历史曲线(列式,按步长取平均;range 从 1 小时到 30 天):cpu、mem、disk(百分比)、rx_bps、tx_bps

host 只有汇总的数字:CPU 占用、内存与根分区的已用和总量、网卡累计收发字节与瞬时网速、系统运行时长。没有 CPU 型号、主机名、网卡名,也没有任何 IP——Agent 不采集这些,公开接口当然也不会返回;有测试断言响应里不出现这类字段。实时更新走 SSE 的 hosts 主题,历史每个 Agent 每分钟存一个样本(retention.host_days,默认 7 天)。

2.3.2 节点的展示信息

GET /api/public/nodes:看得见的 Agent 和没被吊销的 Probe 的展示信息,{id, kind, os, os_name, arch, country, isp_key, isp_name}——系统(linux / windows / macos)、「Debian 12」这样的系统名、架构(x64 / arm64…)、国家代码(CN)、运营商类别(mobile / telecom / unicom / broadnet / other)和名字。没有 IP 地址、城市、ASN、经纬度,有测试保证:公开接口的整个响应里不出现 IP 形状的字符串,也没有 ip、city、asn 这些字段。管理员在设置里打开 site.show_build 之后,每项还有 version 和 tag(节点自己上报的程序版本和 tag);关着时这两个字段是 null。

GET /api/public/about:{show_build, backend}。show_build 关着时 backend 是 null;打开后 backend 是 {version, tag, built_at}(后端自己的版本、tag、构建时间,不含提交号)。

  • 系统和架构是节点自报的:Agent 和 Probe 都在各自连面板时的 fleet.hello 里自报。只有粗粒度的名字,没有主机名、内核版本、CPU 型号。
  • 国家和运营商由 Backend 用节点的来源地址向 IP 归属服务查一次(Monitor__GeoLookupUrl,缺省 https://ip.007995.xyz,留空就不查):Probe 用 Agent 看到的来源 IP,Agent 用它的公开地址。Probe 和 Agent 不访问任何外部服务。 只查公网地址(回环、内网、CGNAT、链路本地一律不发出去);同一个地址一周内只查一次,失败 10 分钟后再试;查到的只留国家代码和运营商,地址只存在 Backend 内部的 node_meta.geo_host,不对外。

2.4 测试结果与目录

  • GET /api/public/tests/{test_id}:包括计划、参数、状态、阶段,metrics 与 scores,series(例如码率–丢包曲线),以及置信说明 caveats。
  • GET /api/public/catalog/kinds:每个 Kind 的积木组合与 ParamSpec(默认值和上下限)。
  • GET /api/public/catalog/plans、/metrics(id、单位、标签、说明、better、阈值、来源 Kind、版本)、/presets(指标分组)、/models(评分维度与所需指标)。

2.5 跨域访问

默认前端和 Backend 同源(Cookie 会话)。前端在别的来源时(比如本机跑前端、连线上的 Backend),Backend 设 Monitor__CorsOrigins(逗号分隔的来源,或 *;默认空 = 不允许)。只对 /api/* 生效,响应带 Access-Control-Allow-Origin,预检请求(OPTIONS)返回 204,允许的头是 Authorization, Content-Type, X-CSRF-Token。不带凭据,Cookie 不会跨域,所以跨域的调用只能用 Authorization: Bearer <API 令牌>:展示端用只读令牌(站点私有时需要),管理端用 admin 范围的令牌(/api/admin/auth/me 对令牌同样可用)。SSE 在跨域时前端用 fetch 读流,因为 EventSource 带不了请求头。

3. Admin API

方法 路径 说明
POST /api/admin/auth/login {username, password} → 设置 HttpOnly; Secure; SameSite=Strict 的会话 Cookie,并返回 csrf_token
POST /api/admin/auth/logout
GET /api/admin/auth/me
GET /api/admin/agents 全部 Agent(包括 pending/disabled)、版本、本地硬上限、心跳计数、任务同步状态
PATCH /api/admin/agents/{id} name、labels、public_host、public_visible
POST /api/admin/agents/{id}/approve /disable /enable /takeover 见 enrollment.md
DELETE /api/admin/agents/{id} 删除;历史数据按保留策略自然过期
GET/POST /api/admin/join-tokens 创建时返回令牌明文和安装命令(仅此一次)
DELETE /api/admin/join-tokens/{id} 吊销
GET/POST /api/admin/probes 列出所有 Probe(含它现在连着哪些 Agent:版本、远端 IP、起始时间);创建 Probe 身份,返回 probe.json(含私钥,仅此一次)
GET/PATCH/DELETE /api/admin/probes/{id} 详情、改名、删除(历史数据按保留策略自然过期)
POST /api/admin/probes/{id}/rotate 换新密钥(id 不变):旧密钥立即失效,所有 Agent 断开它的会话;返回新的 probe.json(仅此一次)
POST /api/admin/probes/{id}/revoke 吊销:公钥从所有 Agent 的名单里移除,Agent 立即断开它;记录和历史保留
POST /api/admin/agents/{id}/probes/{probe_id}/disconnect 让这个 Agent 断开这个 Probe 的会话(Probe 会重连,除非已吊销);没有会话时返回 409 probe_offline
GET/POST /api/admin/tasks 列表和创建:line 模板(不带 agent_id)、单个 Agent 的覆盖(带 agent_id + base_task_id)、target 任务
GET/PATCH/DELETE /api/admin/tasks/{id} 参数按 Kind 的 ParamSpec 校验,并检查带宽预算
POST /api/admin/lines/{line_id}/tests {plan, params?} → 202 + Location: /api/public/tests/{id};Probe 离线时返回 409 probe_offline,节点繁忙时返回 409 test_busy
POST /api/admin/tests/{id}/cancel
GET /api/admin/raw/chunks?agent_id=&kind=&from=&to=&test_id= 原始块元数据
GET /api/admin/raw/chunks/{chunk_id} 下载原始块(application/vnd.monitor.rawchunk);过期返回 410 raw_expired
GET /api/admin/events?agent_id=&kind=&from=&to= 事件
GET /api/admin/analysis/recompute 指标重算进度
GET/POST/DELETE /api/admin/api-tokens 作用域为 read、admin 或 release(只能登记发布清单,给 CI 用,什么都读不了);明文只显示一次
GET /api/admin/releases 各应用、各通道的当前版本,以及节点的版本分布(由 Fleet.Server.Releases 提供)
POST /api/admin/releases/{app}/{channel}/rollout {version, batches:[{labels?, count?}], soak_minutes}:分批灰度;只能选择已经签名的清单
POST /api/admin/releases/{app}/approve 对 policy = notify 的节点批准更新 {version, agents?}
GET/PATCH /api/admin/settings 站点公开或私有、是否对访客显示构建信息(site.show_build)、保留期等
GET /api/admin/build-info 后端和每个 Agent、Probe 的版本、tag、提交、构建时间、系统,以及节点宿主机更新器报告的更新状态(管理端「系统 → 版本」)
GET/POST /api/admin/releases CI 签名的发布清单:POST 登记({manifest, signature},面板不验签、原样转给在线的节点和之后连上的节点),GET 看每个组件最新的一份
GET /api/admin/links 每一对(Probe,Agent)的线路开关:linked(最终结果)、override(手动设置,null 跟随自动连接)、connected,以及 auto_link
PUT /api/admin/links/{probe_id}/{agent_id} {enabled: true|false|null}:手动强制连或不连,null 取消手动设置;改完立即重新下发
POST /api/admin/nodes/{id}/update 请求一个在线的 Agent 或 Probe 更新到它收到的清单(节点不在线返回 409)
GET/POST/PATCH /api/admin/users 首次启动时通过命令行或环境变量创建初始管理员

任务的请求体示例:

{ "scope": "line", "kind": "tcp_echo", "schedule": "continuous",
  "params": { "rate_hz": 50, "tcp_info_ms": 20, "port": 7444 } }

4. Agent API

方法 路径 说明
POST /api/agent/v1/enroll 由 MapFleetEnrollment 提供(使用加入令牌认证),见 fleet/link.md 第 3 节
GET /api/agent/v1/rpc 由 MapFleetLink 提供,升级为 WebSocket;Monitor 的方法见 protocol.md
GET /fleet/releases/{app}/{channel}/latest.json、/fleet/releases/{app}/{version}/… 由 MapFleetReleases 提供的公开发布源(清单和制品),供 fleet-updater 轮询;也可以改用 GitHub Releases

5. 运维端点

路径 认证 说明
GET /healthz 无 SQLite 与原始数据目录都可写
GET /metrics admin 令牌 Prometheus 格式:在线数、块入库速率、分析队列长度、重算进度、磁盘占用、SSE 连接数
GET /openapi/v1.json 无
GET /install.sh /install.ps1 无 安装脚本(只下载二进制并写入配置)

6. 错误码(节选,完整列表见共享的 ErrorCode)

HTTP code
400 validation_failed、budget_exceeded
401 unauthorized、csrf_failed
403 forbidden(令牌作用域不足)、site_private
404 agent_not_found、task_not_found、test_not_found、chunk_not_found、unknown_kind、unknown_plan
409 name_conflict、probe_offline、test_busy、agent_not_active
410 raw_expired、join_token_expired
422 range_too_large、invalid_step、unknown_metric、unknown_preset、too_many_metrics
429 too_many_requests、too_many_streams
503 storage_unavailable