外观
对等门户接口
对等门户消费的端点。基址 VITE_PEERING_API ?? https://api.natlan.io, 前缀 /control/v1/autopeering(下表路径均省略该前缀)。
客户端实现 apps/peering/src/lib/api.ts,类型 apps/peering/src/lib/types.ts。
1. 通用约定
| 项 | 约定 |
|---|---|
| 鉴权 | Authorization: Bearer <门户会话令牌>;/auth/login-url 与 /auth/exchange 不带 |
| 401 | 清掉 sessionStorage 里的令牌并触发登出转场 |
| 错误体 | {"detail": …};detail 为数组时是 FastAPI 422 校验错误,前端拼成 loc: msg |
| 时间戳 | 时序点的 t 是桶起点的 epoch 秒,不是 ISO 串 |
⚠️
TrafficPoint.t曾被错标成string。旧图只把它喂给new Date()——不炸, 但 x 轴一直显示 1970 年;新图喂给parseTs时.trim()当场抛异常、整张图画不出来。 类型必须是number。
2. 身份
| 端点 | 说明 |
|---|---|
GET /auth/login-url?next=<path> | → {authorize_url},跳 auth.natlan.io/authorize |
POST /auth/exchange {handoff} | 一次性 handoff 码换 {session_token, profile, expires_at} |
GET /me | 用已存令牌恢复会话 → {profile, expires_at} |
POST /auth/refresh-claims | 用户改过 registry 对象后重查上游 userinfo → {profile} |
POST /auth/logout | 注销 |
会话令牌存 sessionStorage,是门户唯一持有的凭据。链路说明见 apps/peering.md。
3. 对等生命周期
| 端点 | 说明 |
|---|---|
GET /nodes | 可接入节点清单(NodeOffer[]) |
GET /requests | 当前身份名下的对等请求列表 |
GET /requests/{id} | 单条详情 |
POST /requests | 新建 |
DELETE /requests/{id} | 自助拆除 |
NodeOffer.capacity 的口径:容量来自节点的外部端口池,进度条是 used_ports / capacity——不是 provisioned / max_sessions。后者会漏掉手工建立的 peering,且 max_sessions 现在通常是 null。
POST /requests 的载荷:
jsonc
{ "node_id": "hkg1", "public_key": "…",
"endpoint": "host:port", // 可选,对端无 dial-in 时省略
"link_local": "fe80::…", // 可选
"mtu": 1420, "mp_bgp": true,
"session_addressing": "link-local" | "ipv6-ula",
"peer_ipv4": "…", "peer_ipv6": "…", // ULA / 双会话形态才需要
"notes": "…" }NodeOffer.endpoint_host 为 null 表示该节点没有 dial-in 端点(只主动外拨), 此时对端必须提供 endpoint。
PeeringRequest.mtu_probe 为 null 表示尚未探测——落成后会自动跑一次。
4. 观测(仅已落成的对等)
| 端点 | 说明 |
|---|---|
GET /requests/{id}/traffic?range= | 流量,range ∈ 6h | 24h | 7d | 30d |
GET /requests/{id}/metrics?range= | 指标,同上四档 |
GET /requests/{id}/routes?family=4|6&limit=&offset= | 该会话学到的路由 |
POST /requests/{id}/probe-mtu | 同步 MTU 探测 |
POST /requests/{id}/probe-latency | 同步时延采样 |
两个 probe 是同步慢调用:MTU 最长约 60 秒,时延约 10 秒。调用方自己持有 loading 态,并且必须防抖——服务端每会话有 10 分钟冷却,触发即 429。
5. 只读网络态势
控制台同名板块的门户镜像。后端复用 UI 面的同一批 builder 函数、另挂 require_portal_session,因此响应形状与控制台逐字段一致——可以直接喂给 $ui 里 的同一批看板组件。
| 端点 | 说明 |
|---|---|
GET /fleet/dashboard | 概述 / 流量 / 路由三板块一次取全 |
GET /fleet/traffic-breakdown?top= | 当前每节点 / 每对端速率榜 |
GET /fleet/flap-stats?range= | 抖动时序与速率仪表 |
GET /fleet/prefix-flaps?min_score=&limit=&group=prefix | 前缀抖动榜,与管理面同一处理函数 |
GET /my/flaps | 「我这家 AS 抖不抖」 |
/fleet/dashboard 的参数:range、compare=1、origins_top、as_traffic=1, 语义与控制台的 /ui/dashboard 相同,见 control.md。 前缀抖动的字段口径见 flaps.md。
两处口径必须记住:
- fleet 级流量只提供
6h/24h(FleetTrafficRange),而用户自己那条对等的 观测是四档全收(TrafficRange)。两个类型不可混用。 GET /my/flaps在无抖动痕迹时返回 200 +has_flaps: false,不是 404。 对用户来说「没抖」是正向结果,不该长得像出错。
脱敏口径
全网态势的 AS 号、前缀、流量占比、抖动明细不脱敏——这些本就在 DN42 registry 与 explorer 上公开。后端做白名单投影收窄两处:
- WireGuard 对端的
public_key与endpoint(密钥材料与攻击面); - overview 节点行的 agent 遥测(内部运维信息)。
6. 公共机群数据
GET https://api.natlan.io/control/v1/public/fleet不属于 autopeering 契约、不带鉴权,门户用它给节点地图放坐标、画节点间骨干链路。 调用方必须能在它失败时优雅降级——门户的实现是返回空 Map + 空数组,地图退化成无坐标态。
jsonc
{ "nodes": [ { "node_id": "hkg1",
"geo": { "lat": …, "lon": …, "city": …, "country": "HK", "region": 52 } } ],
"links": [ { "a": "hkg1", "b": "sha2" } ] }region 是 DN42 origin-region community(41..57)。country 前端会统一转大写。 同一个端点也是首页 fleet 岛的数据源。