mirror of
https://gitcode.com/JianFeeeee/webui4frpc.git
synced 2026-09-20 17:07:57 +00:00
refactor: 审查修复 — netload 消除重复 /sys 读 + 全项目 gofmt
- netload_linux.go: SampleNetLoad 聚合循环不再对每接口重复 readIfaceSpeed (snapshot 已汇总 cur.capMbps), 每次采样省 N 次 /sys 读 - gofmt -w: ring.go/ring_engine.go/auth.go/handlers.go/handlers_logs.go/ handlers_users.go/store.go 结构体字段对齐与注释缩进 - README.md: markdownlint 自动修复 (MD028/MD040) 审查结论: 令牌环本身即互斥协议 — OnToken(收令牌)与 StartRing(发令牌) 在同一节点上由令牌串行化, 不存在需要加锁的竞争; WatchLeader 的读为 良性读, 无需 mutex
This commit is contained in:
@ -196,8 +196,9 @@ func SampleNetLoad() float64 {
|
||||
//
|
||||
// rx+tx counts BOTH directions — a forward proxies in AND out, so a NIC
|
||||
// that's saturated in one direction is saturated for forwarding purposes.
|
||||
// Capacity comes from the CURRENT snapshot's capMbps (already summed in
|
||||
// snapshotNet) — no extra /sys reads per interface here.
|
||||
var deltaBits float64
|
||||
sharedCap := uint64(0)
|
||||
for name, c := range cur.bytes {
|
||||
p, ok := prev.bytes[name]
|
||||
if !ok {
|
||||
@ -209,15 +210,11 @@ func SampleNetLoad() float64 {
|
||||
continue
|
||||
}
|
||||
deltaBits += float64(c-p) * 8
|
||||
// approximate this interface's capacity contribution proportional to
|
||||
// its share of the summed speed — read back from /sys would be noisy
|
||||
// per call, so reuse the prior snapshot's capMbps scaling.
|
||||
sharedCap += readIfaceSpeed(name)
|
||||
}
|
||||
if sharedCap == 0 {
|
||||
if cur.capMbps == 0 {
|
||||
return 0
|
||||
}
|
||||
capBitsPerSec := float64(sharedCap) * 1e6
|
||||
capBitsPerSec := float64(cur.capMbps) * 1e6
|
||||
pct := (deltaBits / dt) / capBitsPerSec * 100
|
||||
if pct < 0 {
|
||||
return 0
|
||||
|
||||
@ -81,9 +81,9 @@ type TopoEntry struct {
|
||||
// State is the full cluster picture, replicated on every node:
|
||||
// ring membership + pending tasks + active forward topology.
|
||||
type State struct {
|
||||
LeaderID string `json:"leaderId"`
|
||||
Nodes []Node `json:"nodes"`
|
||||
Cycle int64 `json:"cycle"`
|
||||
LeaderID string `json:"leaderId"`
|
||||
Nodes []Node `json:"nodes"`
|
||||
Cycle int64 `json:"cycle"`
|
||||
// RoundDelay rides the token so every node converges on the same ring
|
||||
// cadence (serialized as nanoseconds; the leader refreshes it each round
|
||||
// via tkDelaySince). MUST be serialized — otherwise a token round-trip
|
||||
|
||||
@ -162,16 +162,17 @@ func (e *Engine) loadSnapshot() Load {
|
||||
|
||||
// OnToken is the SINGLE-ROUND token handler. Per the authoritative design
|
||||
// (plan §令牌环协议): on receiving the token a node simultaneously
|
||||
// (a) ADOPTS the carried cluster picture — incoming state is authoritative
|
||||
// for membership + per-node fields. This is safe because structural
|
||||
// changes (join/remove) are NOT kept in local state waiting to survive
|
||||
// a merge: joins ride a separate pendingJoin channel injected INTO the
|
||||
// token here, and a self-remove writes the node out of state so the
|
||||
// downstream merge naturally drops it.
|
||||
// (b) APPLIES the incremental log delta, then re-attaches own fresh entries.
|
||||
// (c) APPENDS own node info (load/version) — skipped if we self-removed.
|
||||
// (d) INJECTS pending newcomers right after ourselves + forwards to them.
|
||||
// (e) Paces via a parallel rhythm timer (max(ops, timer)).
|
||||
//
|
||||
// (a) ADOPTS the carried cluster picture — incoming state is authoritative
|
||||
// for membership + per-node fields. This is safe because structural
|
||||
// changes (join/remove) are NOT kept in local state waiting to survive
|
||||
// a merge: joins ride a separate pendingJoin channel injected INTO the
|
||||
// token here, and a self-remove writes the node out of state so the
|
||||
// downstream merge naturally drops it.
|
||||
// (b) APPLIES the incremental log delta, then re-attaches own fresh entries.
|
||||
// (c) APPENDS own node info (load/version) — skipped if we self-removed.
|
||||
// (d) INJECTS pending newcomers right after ourselves + forwards to them.
|
||||
// (e) Paces via a parallel rhythm timer (max(ops, timer)).
|
||||
func (e *Engine) OnToken(ctx context.Context, tk *Token) (*Token, error) {
|
||||
// Multi-token guard: only the newest leader-stamped token is kept.
|
||||
if tk.SentAt > 0 && e.lastTokenAt > 0 && tk.SentAt < e.lastTokenAt {
|
||||
|
||||
@ -15,7 +15,7 @@ import (
|
||||
// Type is one of:
|
||||
// - "user": a row in the users table, authenticated via Basic + bcrypt.
|
||||
// - "service": the -user/-password flag creds (inter-node cluster traffic
|
||||
// and bootstrap), authenticated via a constant-time compare.
|
||||
// and bootstrap), authenticated via a constant-time compare.
|
||||
// - "key": an API key, authenticated via Bearer + sha256 lookup.
|
||||
//
|
||||
// Level is the effective access tier: "read" | "write" | "admin". For users it
|
||||
|
||||
@ -38,7 +38,10 @@ func (h *Handler) handleCanvasGet(w http.ResponseWriter, _ *http.Request) {
|
||||
for _, r := range remotes {
|
||||
remoteNames[r.Name] = true
|
||||
}
|
||||
type linkKey struct{ local, remote string; port int }
|
||||
type linkKey struct {
|
||||
local, remote string
|
||||
port int
|
||||
}
|
||||
linkSeen := make(map[linkKey]bool, len(links))
|
||||
for _, l := range links {
|
||||
linkSeen[linkKey{l.Local, l.Remote, l.RemotePort}] = true
|
||||
@ -201,7 +204,10 @@ func (h *Handler) applyCanvas(w http.ResponseWriter, r *http.Request, canvas *ca
|
||||
// Build a set of (local, remote, remotePort) triples from the incoming
|
||||
// canvas links so we can revoke any stale topology entries no longer
|
||||
// present in the canvas (e.g. links that were deleted from the UI).
|
||||
type triple struct{ local, remote string; port int }
|
||||
type triple struct {
|
||||
local, remote string
|
||||
port int
|
||||
}
|
||||
canvasTriples := make(map[triple]bool, len(canvas.Links))
|
||||
for _, ln := range canvas.Links {
|
||||
canvasTriples[triple{ln.Local, ln.Remote, ln.RemotePort}] = true
|
||||
|
||||
@ -60,10 +60,10 @@ func (h *Handler) handleNodeLogs(w http.ResponseWriter, r *http.Request) {
|
||||
|
||||
// clusterWorkerLogNode is one node's entry in the export bundle.
|
||||
type clusterWorkerLogNode struct {
|
||||
ID string `json:"id"`
|
||||
Addr string `json:"addr"`
|
||||
OK bool `json:"ok"`
|
||||
Error string `json:"error,omitempty"`
|
||||
ID string `json:"id"`
|
||||
Addr string `json:"addr"`
|
||||
OK bool `json:"ok"`
|
||||
Error string `json:"error,omitempty"`
|
||||
Logs *nodeLogsResp `json:"logs,omitempty"`
|
||||
}
|
||||
|
||||
|
||||
@ -162,7 +162,7 @@ func (h *Handler) handleApiKeys(w http.ResponseWriter, r *http.Request) {
|
||||
"userId": k.UserID,
|
||||
"label": k.Label,
|
||||
"scope": k.Scope,
|
||||
"prefix": k.Prefix,
|
||||
"prefix": k.Prefix,
|
||||
"createdAt": k.CreatedAt,
|
||||
"key": plaintext, // shown exactly once
|
||||
})
|
||||
|
||||
@ -148,10 +148,10 @@ type Forward struct {
|
||||
type User struct {
|
||||
ID int64 `json:"id"`
|
||||
Username string `json:"username"`
|
||||
PasswordHash string `json:"-"` // never serialized to clients
|
||||
Role string `json:"role"` // "admin" | "viewer"
|
||||
PasswordHash string `json:"-"` // never serialized to clients
|
||||
Role string `json:"role"` // "admin" | "viewer"
|
||||
Enabled bool `json:"enabled"`
|
||||
System bool `json:"system"` // true = flag-synced, UI read-only
|
||||
System bool `json:"system"` // true = flag-synced, UI read-only
|
||||
CreatedAt int64 `json:"createdAt"`
|
||||
LastLoginAt int64 `json:"lastLoginAt"`
|
||||
}
|
||||
@ -162,12 +162,12 @@ type User struct {
|
||||
type ApiKey struct {
|
||||
ID int64 `json:"id"`
|
||||
UserID int64 `json:"userId"`
|
||||
Prefix string `json:"prefix"` // first 8 chars of plaintext, for display
|
||||
Prefix string `json:"prefix"` // first 8 chars of plaintext, for display
|
||||
Label string `json:"label"`
|
||||
Scope string `json:"scope"` // "read" | "write" | "admin"
|
||||
Scope string `json:"scope"` // "read" | "write" | "admin"
|
||||
CreatedAt int64 `json:"createdAt"`
|
||||
LastUsedAt int64 `json:"lastUsedAt"`
|
||||
ExpiresAt int64 `json:"expiresAt"` // 0 = never expires
|
||||
ExpiresAt int64 `json:"expiresAt"` // 0 = never expires
|
||||
}
|
||||
|
||||
const schema = `
|
||||
|
||||
Reference in New Issue
Block a user