Files
webui4frpc/plan.md
jianf b518a13446 feat: Phase C 完成 — ModelRouter 风格 UI 重设计 + 模拟 frps 测试 + lastSync 修复 + 集群作坊搭建
- 主题: sakura×frost 玻璃拟态 (theme.css) + SCSS 变量重映射
- 侧栏: 玻璃侧栏 246px + 渐变品牌区 + 面包屑导航
- 状态页: 玻璃 KPI 卡 + 远程节点/本地服务卡片网格
- 集群页: 英雄玻璃卡 + 横向环拓扑链 + 待办命令/活跃拓扑/日志区
- 令牌环: 新增 lastSync 上次同步时间替代周期计数
- 模拟 frps: frps2/frps3 容器 + test-forward.sh 全链路验证脚本
- 修复: BinaryPath 空导致 worker 不启动, 撤销仅撤第一个 link, 任务复活风暴 (published 追踪)
2026-08-18 23:38:20 +08:00

194 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.

# webui4frpc 开发计划
> webui4frpc —— 独立于 frp 源码的可视化 frpc 控制器(单二进制,零 frp 代码依赖frpc 运行时一键从官方 Releases 下载或手动指定)。
## 目标
用画布方式把「本地转发项」连到「远程服务器」,自动为每台远程服务器生成 frpc 配置并拉起独立 worker 进程,避免运维反复手写 frpc 配置。
## 已完成M0骨架与核心
- [x] 独立仓库module `webui4frpc`,仅依赖 `modernc.org/sqlite`,零 frp 源码引用
- [x] 目录结构cmd / internal/{store,render,process,httpapi,install} + webVue3 + VueFlow + Element Plus
- [x] 画布模型local / remote / link 多对多连线,节点可编辑、可添加
- [x] 渲染器tcp/udp/http/https → frpc JSON 配置http 用 customDomains=`<name>.local`
- [x] worker 进程管理spawn/stop/restart、日志轮转、崩溃自愈指数退避
- [x] 一键安装 frpcGitHub Releases 手动指定路径
- [x] REST APIstatus/canvas/settings/remotes/profiles/binary
- [x] 三页 UI状态默认/ 连接配置 / 设置
- [x] 状态页:远程节点状态框 + 本地服务转发表(每 5s 轮询),节点可增删改启停
- [x] 画布可用性检查:端口冲突 / http 域名唯一性,标红 + 弹窗提示,保存前拦截
- [x] 演示环境3 本地 × 3 远程多对多全连通tcp + http 转发实测返回数据)
- [x] 后端单元测试store / render / process / httpapi / install
## 项目现状核对(代码审查记录 2024-08 单 commit c193688
- 后端入口 `cmd/webui4frpc/main.go`flag 解析(-addr/-user/-password/-workdir/-bin→ 建数据目录 → `store.New``process.NewManager`BinaryPath/AutoRestart/RestartInterval 动态闭包AutoStartProfiles 启动已启用 worker`httpapi.NewServeMux`healthz 免认证,其余 Basic Auth→ SIGINT/SIGTERM 优雅退出15s 超时 + StopAll
- 核心数据流PUT `/api/manager/canvas` → store 全量 upsert/删除 + 事务替换 links → `SyncWorkers` 重启受影响 worker → 每台远程独立 `frpc -c configs/<name>.json` 进程
- 渲染器当前能力tcp/udp 用 remotePorthttp/https 用 customDomains默认 `<name>.local`重名服务自动加端口后缀transport 段仅有 protocol 字段且从未填充
- 前端App.vue 三页手动切换(状态/连接配置/设置CanvasView/VueFlow 画布 + StatusView 5s 轮询 + SettingsView
## 已知问题(审查发现,待修复)
1. ~~设置保存失效P0~~ **已修复**`server.go``NewServeMux` 现在对 `PUT /api/manager/settings` 分发到 `handleSettingsPut`,新增 `TestSettingsPutRoundTrip` 回归测试,前端 SettingsView 保存生效。
2. ~~dev proxy 端口不一致~~ **已修复**`web/vite.config.ts` proxy 指向 `127.0.0.1:7500`(可用 `VITE_PROXY_TARGET` 覆盖),与后端默认一致。
3. **冗余依赖**`vue-router` 在 package.json 依赖中但未被使用App.vue 以视图 ref 手动切页,无路由)。
4. **README 笔误**:架构图写 `cmds/webui4frpc`,实际目录为 `cmd/webui4frpc`
## 里程碑
### M1 高级传输参数P0建议优先
目标:让常用 frpc 能力可配置,保持画布简洁(折叠高级区)。
- [x] Local 增加高级字段useEncryption / useCompression / bandwidthLimit / poolCount / metadatas / annotations渲染器 + 编辑表单 + 折叠 UI
- [x] Remote 增加 transportprotocoltcp/quic/kcp/websocket、tls.enable、poolCount
- [x] 渲染器补齐 transport 段输出;增加 render 单测覆盖新字段
- [x] 高级字段随 canvas API 持久化store 表扩展 + 迁移)
### M2 HTTP/HTTPS 完善
- [x] local http/https 增加可编辑域名字段customDomains / subdomain
- [x] locations路径路由多配置
- [x] httpHeaderRewrite / hostHeaderRewrite / basicAuth站点访问认证
- [x] frps vhostHTTPPort 的显示与状态映射(状态页展示)
### M3 负载均衡与健康检查
- [x] 模型扩展Local 增加 lbGroup / lbGroupKey / healthCheck* 字段Remote 增加 adminAddr / adminPort / adminUser / adminPasswordlocal frpc admin API
- [x] 渲染器proxy 输出 loadBalancer + healthCheck 段worker 配置输出 webServer 段frpc >= 0.52 支持)
- [x] 状态页:按 admin API GET /api/status 拉取真实 per-proxy 状态running / check failed / wait start / start error / new / closed未启用 admin 时回退日志推断
- [x] 前端LocalNode/RemoteNode 表单 + StatusView per-proxy 状态与 LB 组徽标vue-tsc 通过)
- [x] CLUSTER 页展示负载均衡组group+ 健康检查状态e2e 验证backend 停止→check failed 剔除,恢复→自动收回)
### M4 更多代理类型
- [ ] tcpmuxHTTP/2 多路复用)
- [ ] stcp / sudp点对点加密穿透
- [ ] xtcpP2P需 kcp
- [ ] 按类型动态显示字段的表单
### M5 运维与发布
- [x] git init + 首次 commit + .gitignore排除 node_modules / web/dist.pi/ 本地代理状态已忽略)
- [ ] 一键构建脚本web→dist→embed→单二进制
- [ ] GitHub Actionsrelease 构建linux/windows/mac
- [ ] 配置导出/导入(备份)
- [ ] 日志查看页worker 日志 tail UI
> 注:发布类条目已并入 **M7 运维与发布(原 M5**,本节 M5 保留初始清单。
>
### M6 集群(令牌环网拓扑)
> **权威设计(用户约定,必须固化)**:集群节点间通过**令牌环网token ring**通信,单轮为一个周期。
#### 拓扑与角色
- 集群 = 若干 webui4frpc 节点组成的内网协作网络;逻辑上各节点**平等**,均持有**完整集群信息**(节点表、转发链、各自配置)与完整 webui。
- **leader**:唯一特殊角色,负责启动时发送第一个令牌;默认**创建集群的节点**为初始 leader。
- **转发链ring**:令牌按固定顺序传递;每个节点记录前驱/后继。
#### 令牌环协议(单轮:边传播边同步,收敛快半轮)
- **令牌环行时,各节点收到令牌后同时做两件事**
1. **透传/同步**:采纳令牌已携带的完整集群信息(其它节点此前追加的节点表、负载、拓扑、日志增量),更新自己的完整集群视图。
2. **追加/顺带更新**把自己的信息地址、负载指标、frpc 缓存、转发能力、本机产生的命令)追加进令牌。
- 因每经过一个节点就立即传播当前已知的最新状态,第一个节点的信息在**第二个节点**就被同步到,全网收敛只需**约半圈**——无需分两轮——第一轮即同步,全网收敛只需约半圈。
- 令牌同一时刻只有一个;由"收到令牌的节点处理后交给下家"驱动,无定时重启、无竞态。
- **节奏控制(并行计时器 + 同步操作,非硬性 sleep**:令牌到达时节点做自己的操作(摘取/追加/日志同步/差异预计算),**同时起一个独立的节奏计时器**。操作完成后若计时器未走完则等计时器(保持环的稳定节奏);计时器先到而操作未完则等操作完成(操作皆轻量,且大部分耗时操作如差异计算在令牌到来前已完成)。故转发时机 = max(操作完成, 节奏计时器),两者并行不互斥。
- **令牌带时间戳,只取最新**:每个令牌携带发起时间戳(`SentAt`);节点收到令牌时比较时间戳——若令牌比本机最近记录的旧,说明是**重发残留的旧令牌**,直接丢弃。此机制彻底消除"重发时旧令牌可能还活着"的担忧,即使重发,旧令牌也会被下游识别过期而消失,环上始终只有一个有效令牌。
- 新转发任务:需要建立转发时,**把任务附加在令牌中**(而非直接指派);因每节点都持完整集群信息,由**负载最低的节点****内存使用率 + 网络使用率共同判断**)自行摘取并创建转发。
- **负载摘取**:令牌传递到某节点时,若该节点在上一轮被判定为负载最低,则**先主动摘取任务**,随后在令牌中更新自身信息。
#### 容错与邻居离线
- 令牌传递超时(未收到回执)→ 判定邻居离线。因每节点持完整集群信息,当前节点可**自动修改集群状态**,并把邻居负责的转发**作为新任务追加到令牌**,再传给下一节点。
- leader 检测令牌丢失:发出令牌后超过 **(轮次延迟 / 2 + 20ms)** 未回传 → 判定令牌丢失(可能某节点接令后崩溃),**重发令牌**。
- leader 每轮探测后更新一次轮次延迟。
#### leader 补充/监控
- leader 受其上家邻居监控:二者**交换心跳包**(因节点都持完整信息,容易做到)。
- 上家邻居探测到 leader 崩溃 → **自身成为新 leader**
#### 新节点加入
- 每个节点都有 webui用户登录到哪个节点的 webui就由**该节点**执行新节点加入:令牌发到自己时,**先转发给新节点**,并把新节点加入令牌中的集群信息,**更新转发链**:新节点放在自己后面,自己原本的后继放在新节点之后。
#### 增量日志同步(本机事件 → 令牌 → 全网一致)
- 每个节点维护一份**集群事件日志operation log**:本机发生的变更(创建/删除转发、节点加入/离开、负载变化、leader 变更)以**递增序号**追加为本机日志条目。
- 令牌携带**本机日志增量**(同步与追加在同一轮):号码 > 上一周期已同步水位(`lastSyncedSeq`)的条目,随令牌环行时让其它节点**按序追加重放到本地日志**,从而实现全网**增量日志同步**。
- 日志条目不可变(追加式);节点收到增量后校验序号连续性(缺失则请求补齐),因每个节点持有完整集群信息,可从其它节点补拉。
- 集群状态(拓扑/任务/leader可**由日志重放得到**:新节点加入时,通过令牌/邻居拉取完整日志并重放,即可获得与其它节点一致的完整视图(满足"每个节点都掌握完整集群信息")。
- 该机制与"令牌承载中间配置文件/转发拓扑"正交共存:令牌同时携带〔拓扑快照〕与〔日志增量〕,快照用于即时校验,日志用于一致性追补。
#### 任务撤销(复用任务发布通道,撤销语义)
- 撤销一个转发 = **发布一个"撤销任务"到令牌**与任务发布走同一基础通道round-1 注入、round-2 执行),只是 Type 为撤销、载荷为〔任务 ID + 该转发中间配置〕。
- 令牌环行时,**持有该转发的节点**(其 owner 记录在拓扑中)收到撤销任务后:取消本地 frpc worker → 从活跃拓扑移除该转发 → 记 `forward.remove` 增量日志,全网随之下一次轮次收敛一致。
- 撤销任务幂等:若转发已不在拓扑(已被撤销/离线重挂),收到撤销仅记日志、不报错。
- localOnly 的本地转发撤销不发布到令牌,直接本机取消(因本机即 owner仅本节点可见
#### 画布差异判断diff与命令追加
- **在哪个节点修改 webui 画布,就由该节点进行差异判断**:将该节点画布的「期望状态」与当前集群拓扑(该节点持有的完整视图)比对。
- 差异结果转为**一批转发/撤销命令,追加到令牌任务**
- 画布有、拓扑无 → 追加**新增转发命令**(任务+中间配置)→ 后续由负载最低者摘取创建。
- 画布无、拓扑有 → 追加**撤销转发命令**(撤任务+转发的中间配置)→ 持有者收到后取消 worker 并移出拓扑。
- 画布即唯一编辑入口:编辑节点只发命令,不直接改其它节点;拓扑随令牌轮次收敛全网一致。
- **其它节点根据集群拓扑生成本地画布存储**非编辑节点收到令牌同步的完整拓扑后把拓扑中的转发locals/remotes/links重建为本地画布视图叠加本节点的 localOnly 项。故所有节点的画布展示一致(都源自拓扑),编辑只在入口节点生效。
#### 增删节点
- **加入节点addnode**:维持原设计——在**哪个节点的 webui 做添加节点,哪个节点负责把新节点并入集群**(临近节点处理):
1. 临近节点(如 B收到新节点C的加入请求后**修改转发链与拓扑**:把 C 插入自己后面B 的后继=C自己的原后继A移到 C 后面C 的后继=A形成 `A→B→C→A`
2. **B 将令牌交给 C**(而非原后继 A——C 作为 B 的后继参与环C 处理令牌后继续传给自己的后继 A**形成完整的 join 语义**。
3. 随令牌轮转,全节点收敛到含 C 的一致拓扑。
- **移除节点removenode****借用现有任务发布基础设施**——在某节点 webui 发起删除节点,发布 `node.remove` 命令进令牌;令牌传递到**被移除节点自身**时,该节点执行自移除:
1. 将自己负责的转发任务**重新追加到待分配任务**(自然的 `owner 离线重挂` 语义),
2. **修改拓扑与转发链、移除自身**(拓扑去掉自己的项、环去掉自己、后继衔接),
3. 令牌传递给自身**原本的下一家**。
- **脱离集群后的本地视图**:被移除节点脱离后,自身内部维持的拓扑**只保留本地 locallocalOnly 不进集群的转发)****完全取消一切集群远程转发**(删掉由集群分发的转发、停其 worker
#### 故障自愈(传递令牌间隙判定邻居离线)
- 邻居离线判定**仅在传递令牌的间隙**发生:上家传递令牌给下家后,若在预期窗口内未收到回执,则判定下家离线 → **修改集群状态、移除该节点、将其负责的任务重新追加为待办**,令牌传给再下家。
#### 节点消亡(防脑裂最强兜底)
- 任何节点若**超时收不到令牌**(超过既定周期的 N 倍),**直接自杀退出**不探测上家、不生成新令牌、不做任何协商。这是防止集群脑裂split-brain的最后防线——宁可单一节点自毁不让两个各自为政的残环长期并存。
#### 实现里程碑(待按上述设计重建)
- [x] 数据面Ring State节点表/转发链/leader/轮次延迟/负载/待办任务)+ 日志(追加式 + 水位)
- [x] 令牌环传输HTTP POST /cluster/token + 回执;单轮一周期(信息追加与同步同步完成)
- [x] leader创建集群者为首 leaderStartRing 首令牌 + 轮次延迟测量 + 令牌丢失重发LossTimeout
- [x] 新转发任务POST /cluster/task 挂 pending → 令牌携带 → 负载最低者摘取 → 持久化 + 拉 workere2e 验证)
- [x] 增量日志同步LogForwardAdd/LogNodeJoin 等事件随令牌 delta 传播单轮内完成同步各节点重放收敛e2e 验证)
- [x] 拓扑回写:摘取后 state 写入令牌全网一致e2e topology=[t1,owner]
- [x] 新节点加入POST /cluster/join → 插入环(后继) → AdoptStatee2e A+B 环)
- [ ] 离线处理:令牌超时 → 改集群状态 → 邻居转发转任务重挂forwardToNext 已实现,待 e2e
- [ ] leader 监控:上家邻居心跳探测 → 崩溃提升WatchLeader 已实现,待 e2e
- [ ] 前端:集群页展示环拓扑/令牌轮次/负载/任务摘取;设置页二进制缓存状态
### M7 运维与发布(原 M5
- [x] git init + 首次 commit + .gitignore
- [ ] 一键构建脚本 / GitHub Actions release / 配置导入导出 / 日志查看页
## 建议推进顺序
1. [x] 修复「设置保存失效」——给 `PUT /api/manager/settings` 补注册server.go 方法分发 + httpapi 单测)
2. [x] 对齐 dev proxy 端口——vite.config.ts → 7500支持 VITE_PROXY_TARGET 覆盖)
3. M1 高级传输参数store 加列 → render 输出 → 前端折叠表单 → 单测回归)
4. M3 负载均衡与健康检查(模型 → 渲染 → admin API 状态 → 集群页)— 进行中
5. M6 集群内 frpc 二进制分发(节点间优先 → 外部 URL 兜底 → 新节点自动传输)
## 审查结论摘要(详见 FRPC_FEATURES_AUDIT.md
- 已支持tcp / httpcustomDomains、token 认证、多对多、worker 管理
- 未支持stcp/sudp/xtcp/tcpmux、OIDC/TLS 证书、加密/压缩/限速/连接池、LB/健康检查、http 路由高级、插件/虚拟 IP
- 优先级P0 高级传输参数 → P1 域名字段+transport → P2 LB/健康检查 → P3 低频项
- UI 原则:高级字段折叠式 / 按类型动态显示,保画布简洁