mirror of
https://gitcode.com/JianFeeeee/webui4frpc.git
synced 2026-10-03 23:53:59 +00:00
feat(M6): localOnly forward option (loopback→LAN rewrite for cluster, local direct), canvas diff-based create/revoke commands, revoke task semantics, topology derived canvas on sync nodes, LAN addr helper
This commit is contained in:
@ -20,6 +20,7 @@ const (
|
||||
// (create the frpc worker / forward). Injected to avoid import cycle.
|
||||
type Handler interface {
|
||||
Claim(ctx context.Context, tk *Task) error
|
||||
Revoke(ctx context.Context, tk *Task) error
|
||||
RuntimeLoad() Load
|
||||
}
|
||||
|
||||
@ -145,6 +146,23 @@ func (e *Engine) phase2(ctx context.Context, tk *Token) error {
|
||||
if claimed == nil {
|
||||
break
|
||||
}
|
||||
// Revocation task: the owning node cancels the forward (stop worker,
|
||||
// drop from topology, log forward.remove). Idempotent if missing.
|
||||
if claimed.Revoke {
|
||||
if e.state.RemoveTopology(claimed.Local.Name, claimed.Remote.Name, claimed.Link.RemotePort) {
|
||||
if e.Handler != nil {
|
||||
if err := e.Handler.Revoke(ctx, claimed); err != nil {
|
||||
log.Printf("ring[%s] revoke %s: %v", e.ID, claimed.ID, err)
|
||||
}
|
||||
}
|
||||
if e.Log != nil {
|
||||
_, _ = e.Log.Append(e.ID, LogForwardRemove, map[string]any{
|
||||
"taskId": claimed.ID, "local": claimed.Local.Name, "remote": claimed.Remote.Name,
|
||||
})
|
||||
}
|
||||
}
|
||||
continue
|
||||
}
|
||||
if e.Handler != nil {
|
||||
if err := e.Handler.Claim(ctx, claimed); err != nil {
|
||||
e.state.PendingTasks[claimed.ID] = claimed
|
||||
@ -366,10 +384,35 @@ func (e *Engine) AdoptState(s State) {
|
||||
|
||||
// SubmitTask adds a new forward request to pending; it rides the next token
|
||||
// round and is claimed by the lowest-load member.
|
||||
// RevokeTask publishes a revocation for an established forward through the
|
||||
// same token channel; the owning node stops the worker and drops topology.
|
||||
func (e *Engine) RevokeTask(local store.Local, remote store.Remote, link store.Link) *Task {
|
||||
return e.state.AddRevoke(local, remote, link)
|
||||
}
|
||||
|
||||
func (e *Engine) SubmitTask(local store.Local, remote store.Remote, link store.Link) *Task {
|
||||
if e.HasTask(local.Name, remote.Name, link.RemotePort) {
|
||||
return nil
|
||||
}
|
||||
return e.state.AddPending(local, remote, link)
|
||||
}
|
||||
|
||||
// HasTask reports whether a forward with the same local/remote/remotePort is
|
||||
// already pending or active in the topology (idempotency guard for resaves).
|
||||
func (e *Engine) HasTask(local, remote string, port int) bool {
|
||||
for _, t := range e.state.PendingList() {
|
||||
if t.Local.Name == local && t.Remote.Name == remote && t.Link.RemotePort == port {
|
||||
return true
|
||||
}
|
||||
}
|
||||
for _, t := range e.state.TopologyList() {
|
||||
if t.Local.Name == local && t.Remote.Name == remote && t.Link.RemotePort == port {
|
||||
return true
|
||||
}
|
||||
}
|
||||
return false
|
||||
}
|
||||
|
||||
// IsLeader reports whether this node is the current ring leader.
|
||||
func (e *Engine) IsLeader() bool { return e.state.LeaderID == e.ID }
|
||||
|
||||
|
||||
Reference in New Issue
Block a user