Files
OpenFlare/docs/design/edge-runtime-refactor.md
T
ryan 0b34792709 refactor(edge): Server 协议统一与 wsclient 收敛(Phase 3 Batch 3)
- openflare/agent/relay/flared 协议类型改为 pkg/protocol 别名,删除重复 struct
- 新增 edge/wsclient Preset 表,三组件 wsclient 改为薄包装
- 更新设计文档、计划与 changelog
2026-06-19 15:00:46 +08:00

133 lines
4.3 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.
# 边缘运行时重构设计
你会学到:Agent、Relay、OpenFlared 三组件的重复代码如何收敛到 `internal/apps/edge/`,以及后续演进路线。
---
## 背景
三类边缘守护进程共享同一运行时骨架:
```text
配置加载 → HTTP/WS 客户端 → 定时心跳 →(可选)配置同步 → 自更新 → 信号优雅退出
```
重构前,以下模块在三个组件间近乎复制粘贴:
| 模块 | 重复度 |
| --- | --- |
| `updater/` + `restart_{unix,windows}.go` | ~98% |
| `httpclient` 传输层 (`do/postJSON/getJSON`) | ~90% |
| `tryAutoUpdate` | ~98% |
| `detectNodeIP` | ~95% |
| `relay/flared runner` WS 重连环 | ~85% |
| `parseLevel`(main 内联) | 100% |
Agent 额外包含 nginx 栈、geoip、观测缓冲等**领域特有**逻辑,不宜强行合并。
---
## 共享包结构
```
internal/apps/edge/
├── logging/ # Setup、ParseLevel
├── nodeip/ # Detect、DetectLocal(可注入 LookupOutboundIP)
├── httpclient/ # 基础 HTTP 客户端(鉴权头可配置)
├── wsclient/ # 基础 WebSocket 客户端(组件 Preset 驱动 HeaderKey + WSPath)
├── updater/ # GitHub Release 自更新 + 二进制替换重启
├── heartbeat/ # TryAutoUpdate 统一入口
└── runner/ # WS 重连循环、SleepContext
```
### 组件层保留
各组件仅保留**薄包装**与**领域逻辑**:
| 组件 | 保留模块 |
| --- | --- |
| Agent | `nginx/`、`sync/`(OpenResty)、`geoipupdate/`、`agent/runner`(discovery/WS 混合) |
| Relay | `frps/`、`observability/` |
| Flared | `frpc/`、`sync/`(tunnel) |
各组件 `updater/`、`httpclient/`、`wsclient/` 变为类型别名 + `New()` 工厂函数。
---
## API 约定
### 自更新
```go
edgeupdater.New(edgeupdater.Config{
LocalVersion: config.Version,
AssetPrefix: "openflare-agent", // relay: openflare-relay, flared: openflared
LogLabel: "agent",
})
```
### HTTP 客户端
```go
edgehttp.New(baseURL, token, timeout, "X-Agent-Token") // Agent/Relay
edgehttp.New(baseURL, token, timeout, "X-Tunnel-Token") // Flared
```
### WebSocket 客户端
```go
edgews.New(edgews.PresetAgent, baseURL, token, timeout) // HeaderKey=X-Agent-Token, /api/v1/agent/ws
edgews.New(edgews.PresetRelay, baseURL, token, timeout) // HeaderKey=X-Agent-Token, /api/v1/relay/ws
edgews.New(edgews.PresetFlared, baseURL, token, timeout) // HeaderKey=X-Tunnel-Token, /api/v1/tunnel/ws
```
### 节点 IP 探测
```go
nodeip.Detect() // outbound → local 回退
```
测试可通过替换 `nodeip.LookupOutboundIP` / `nodeip.LookupLocalIP` 注入桩。
---
## 已完成(Phase 0–2)
- [x] `edge/updater` — 三组件 updater 收敛(删除 ~1100 行重复)
- [x] `edge/logging` — relay/flared main 统一日志初始化
- [x] `edge/nodeip` — 删除三处 detectNodeIP 重复
- [x] `edge/httpclient` — 三组件 HTTP 传输层收敛
- [x] `edge/heartbeat/autoupdate` — tryAutoUpdate 统一
- [x] `edge/runner` — relay/flared WS 重连环收敛
---
## 已完成(Phase 3 Batch 1)
- [x] `edge/config/duration.go` — MillisecondDuration 三处合并(含 MarshalJSON)
- [x] `edge/observability/linux.go` — agent/relay collector 底层 Linux 指标采集收敛
- [x] `edge/heartbeat/loop.go` — relay/flared 心跳 ticker 循环统一
## 已完成(Phase 3 Batch 2)
- [x] `heartbeat/cycle.go` — Agent HTTP 心跳周期从 runner 下沉(payload 构建、同步、自动更新)
- [x] `pkg/protocol/agent.go` — Agent 客户端协议类型迁入公共包,`internal/apps/agent/protocol` 保留别名 re-export
## 已完成(Phase 3 Batch 3)
- [x] `edge/wsclient` — Agent/Relay/Flared WebSocket 传输层收敛(Preset 配置表 + `AgentConnection` 适配 `protocol.WebSocketConnection`)
- [x] Server 侧协议统一 — `internal/apps/openflare/{agent,relay,flared}` 心跳/观测类型改为 `pkg/protocol` 别名
## 可选后续
| 项 | 说明 |
| --- | --- |
---
## 迁移原则
1. **领域逻辑不下沉**:nginx/frps/frpc/sync 核心业务保留在各自组件。
2. **鉴权头显式传入**:禁止 httpclient 默认 Token Header,避免 Agent/Tunnel 混用。
3. **小步 PR**:每阶段独立可测,自更新路径需集成验证。
4. **测试随包迁移**:updater 测试已迁至 `edge/updater/`。