refactor(edge): 抽取边缘运行时共享包并完成 Phase 3 重构

- 新增 internal/apps/edge/,三组件改为薄包装,删除 3000+ 行重复代码
- Agent 心跳周期下沉至 heartbeat/cycle.go
- 协议类型迁入 pkg/protocol/agent.go
- 补充设计文档与 changelog
This commit is contained in:
ryan
2026-06-19 14:56:00 +08:00
parent cc5e53c51e
commit db9a9f98fd
53 changed files with 2091 additions and 2947 deletions
+3
View File
@@ -18,6 +18,9 @@ sidebar: false
### 变更
- 边缘组件运行时去重:新增 `internal/apps/edge/` 共享包(`updater`、`httpclient`、`nodeip`、`logging`、`heartbeat/autoupdate`、`runner`),Agent/Relay/Flared 三组件改为薄包装委托,删除约 1100 行重复自更新与 HTTP 传输层代码。
- 边缘运行时 Phase 3 Batch 1:抽取 `edge/config/duration`、`edge/observability/linux`、`edge/heartbeat/loop`,统一 MillisecondDuration、Linux 指标采集与 relay/flared 心跳循环。
- 边缘运行时 Phase 3 Batch 2:Agent 心跳周期下沉至 `heartbeat/cycle.go`;`pkg/protocol/agent.go` 统一 Agent 客户端协议类型。
- 合并并简化仓库结构:将 `openflare-server` 单体目录下的所有文件/目录提升至仓库根目录(去除了 `openflare-server` 嵌套层级),保留 `.github` 目录不变;统一配置 `docker-compose.yaml` 及所有 Dockerfile 的构建上下文为根目录。
- 调整子项目结构与包路径:将 `agent`、`relay` 和 `flared` 子项目从 `internal/` 移动至 `internal/apps/`(分别为 `internal/apps/agent`、`internal/apps/relay` 和 `internal/apps/flared`),并递归更新了所有涉及的 Go 导入路径(如 `github.com/Rain-kl/Wavelet/internal/apps/agent` 等)。
- 调整编译产物输出名称与 Makefile:
+121
View File
@@ -0,0 +1,121 @@
# 边缘运行时重构设计
你会学到: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 客户端(鉴权头可配置)
├── 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/` 变为类型别名 + `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
```
### 节点 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
## 可选后续
| 项 | 说明 |
| --- | --- |
| Server 侧协议统一 | 评估 `internal/apps/openflare/agent` 与 `pkg/protocol` 类型去重 |
| `wsclient` 薄包装收敛 | relay/flared/agent wsclient 配置表化 |
---
## 迁移原则
1. **领域逻辑不下沉**:nginx/frps/frpc/sync 核心业务保留在各自组件。
2. **鉴权头显式传入**:禁止 httpclient 默认 Token Header,避免 Agent/Tunnel 混用。
3. **小步 PR**:每阶段独立可测,自更新路径需集成验证。
4. **测试随包迁移**:updater 测试已迁至 `edge/updater/`。
+1
View File
@@ -189,3 +189,4 @@ OpenFlare 已收敛为**单 monorepo**(Go 模块 `github.com/Rain-kl/Wavelet`
* 发布、同步、回滚与 Agent 模型变化:更新 [Agent 与发布模型](./agent-design.md)。
* 部署方式变化:更新 [部署说明](../deployment/deployment.md) 与 README。
* 配置项变化:更新 [配置项参考](../reference/configuration.md)。
* 边缘组件共享运行时重构:更新 [边缘运行时重构](./edge-runtime-refactor.md)。
+53
View File
@@ -0,0 +1,53 @@
# 边缘运行时 Phase 3 — 任务拆解
> **状态**:Batch 1 + Batch 2 已完成(2026-06-19)
> **前置**:[边缘运行时重构设计](../design/edge-runtime-refactor.md) Phase 0–2 已完成
---
## 任务依赖图
```text
Batch 1(并行,互不影响)
├── T1 edge/config/duration.go
├── T2 edge/observability/linux.go
└── T3 edge/heartbeat/loop.go(仅 relay/flared)
Batch 2(串行,依赖 Batch 1 或需独立评审)
├── T4 Agent heartbeat 架构对齐(runner ↔ heartbeat service)
└── T5 agent/protocol → pkg/protocol(影响 Server 侧)
```
---
## Batch 1 — 并行任务
| ID | 任务 | 修改范围 | 风险 | 委派 |
| --- | --- | --- | --- | --- |
| **T1** | 抽取 `MillisecondDuration` | `edge/config/` + `agent/relay/flared/config` | 低 | ✅ 子代理 A |
| **T2** | 抽取 Linux 指标采集 | `edge/observability/` + `agent/relay/observability/collector.go` | 中 | ✅ 子代理 B |
| **T3** | 统一心跳 ticker 循环 | `edge/heartbeat/loop.go` + `relay/flared/heartbeat` | 低 | ✅ 子代理 C |
### 隔离规则
- **T1** 禁止修改 `heartbeat/`、`observability/`、`agent/runner.go`
- **T2** 禁止修改 `config/`、`heartbeat/`
- **T3** 禁止修改 `agent/` 任何文件(Agent 心跳留在 runner,Batch 2 处理)
---
## Batch 2 — 并行任务(已完成)
| ID | 任务 | 修改范围 | 状态 |
| --- | --- | --- | --- |
| **T4** | Agent heartbeat 架构对齐 | `heartbeat/cycle.go` + 精简 `agent/runner.go` | ✅ 子代理 D |
| **T5** | `agent/protocol` → `pkg/protocol` | `pkg/protocol/agent.go` + `protocol/alias.go` | ✅ 子代理 E |
---
## 验收标准(Batch 1)
```bash
go build ./cmd/agent ./cmd/relay ./cmd/flared
go test ./internal/apps/edge/... ./internal/apps/agent/... ./internal/apps/relay/... ./internal/apps/flared/... -count=1
```
+1
View File
@@ -19,6 +19,7 @@
| [OpenFlare 前端迁移 — AI 委派](./handover-openflare-frontend-migration.md) | 前端迁移任务队列与验收状态 |
| [前端路由验证](./verify-frontend-routes.md) · [Service 验证](./verify-frontend-services.md) · [UI 验证](./verify-frontend-ui.md) · [构建验证](./verify-frontend-build.md) | 多角度迁移验收报告 |
| [文档结构更新 — AI 接手](./handover-docs-restructure-update.md) | 重构后多智能体分析结论与文档批量更新记录 |
| [边缘运行时 Phase 3 任务拆解](./20260619-edge-phase3-tasks.md) | Batch 1 并行任务(duration / observability / heartbeat loop) |
## 使用建议