mirror of
https://gitcode.com/JianFeeeee/webui4frpc.git
synced 2026-09-20 00:47:57 +00:00
- 主题: sakura×frost 玻璃拟态 (theme.css) + SCSS 变量重映射 - 侧栏: 玻璃侧栏 246px + 渐变品牌区 + 面包屑导航 - 状态页: 玻璃 KPI 卡 + 远程节点/本地服务卡片网格 - 集群页: 英雄玻璃卡 + 横向环拓扑链 + 待办命令/活跃拓扑/日志区 - 令牌环: 新增 lastSync 上次同步时间替代周期计数 - 模拟 frps: frps2/frps3 容器 + test-forward.sh 全链路验证脚本 - 修复: BinaryPath 空导致 worker 不启动, 撤销仅撤第一个 link, 任务复活风暴 (published 追踪)
58 lines
1.7 KiB
Go
58 lines
1.7 KiB
Go
// Join helper: a newcomer POSTs its JoinInfo to a target node's join endpoint
|
|
// and adopts the returned ring state (leader preserved, newcomer inserted as
|
|
// the target's successor).
|
|
package cluster
|
|
|
|
import (
|
|
"bytes"
|
|
"context"
|
|
"encoding/json"
|
|
"fmt"
|
|
"net/http"
|
|
"time"
|
|
)
|
|
|
|
// JoinRing asks target to add us to its ring and returns the adopted state.
|
|
func (e *Engine) JoinRing(ctx context.Context, targetAddr string, ji JoinInfo) error {
|
|
url := fmt.Sprintf("http://%s/api/manager/cluster/join", targetAddr)
|
|
body, err := json.Marshal(ji)
|
|
if err != nil {
|
|
return err
|
|
}
|
|
req, err := http.NewRequestWithContext(ctx, http.MethodPost, url, bytes.NewReader(body))
|
|
if err != nil {
|
|
return err
|
|
}
|
|
req.Header.Set("Content-Type", "application/json")
|
|
if e.User != "" || e.Pass != "" {
|
|
req.SetBasicAuth(e.User, e.Pass)
|
|
}
|
|
cli := &http.Client{Timeout: 8 * time.Second}
|
|
resp, err := cli.Do(req)
|
|
if err != nil {
|
|
return err
|
|
}
|
|
defer resp.Body.Close()
|
|
if resp.StatusCode != http.StatusOK {
|
|
return fmt.Errorf("join %s -> HTTP %d", targetAddr, resp.StatusCode)
|
|
}
|
|
var out struct {
|
|
State State `json:"state"`
|
|
}
|
|
if err := json.NewDecoder(resp.Body).Decode(&out); err != nil {
|
|
return err
|
|
}
|
|
e.AdoptState(out.State)
|
|
return nil
|
|
}
|
|
|
|
// JoinRingAddr wraps JoinRing for HTTP handlers: it builds the newcomer's
|
|
// JoinInfo from this node's own id/addr/version/cache (so the caller doesn't
|
|
// touch the engine's unexported fields) and asks targetAddr to sponsor us
|
|
// into its ring. This is the runtime "加入集群" path (vs. the startup
|
|
// bootstrap call in cmd/webui4frpc/main.go).
|
|
func (e *Engine) JoinRingAddr(ctx context.Context, targetAddr string) error {
|
|
ji := JoinInfo{ID: e.ID, Addr: e.myAddr, Version: e.Version, Cache: e.Cache}
|
|
return e.JoinRing(ctx, targetAddr, ji)
|
|
}
|