mirror of
https://github.com/MHSanaei/3x-ui.git
synced 2026-08-15 07:40:59 +00:00
fix(node): adopt a matching deployed inbound instead of recreating it (#6197)
* fix(node): adopt compatible origin inbounds without mutation * fix(nodes): preserve ambiguous and adopted aliases --------- Co-authored-by: n0ctal <293235942+n0ctal@users.noreply.github.com>
This commit is contained in:
@@ -78,8 +78,9 @@ func (e *remoteAPIError) Error() string { return "remote: " + e.msg }
|
||||
type Remote struct {
|
||||
node *model.Node
|
||||
|
||||
mu sync.RWMutex
|
||||
remoteIDByTag map[string]int
|
||||
mu sync.RWMutex
|
||||
remoteIDByTag map[string]int
|
||||
adoptedAliases map[string]string
|
||||
// pushedFP holds the fingerprint of the last inbound wire payload successfully
|
||||
// pushed, keyed by panel-side tag, so reconcile can skip re-sending an
|
||||
// unchanged inbound. Guarded by mu; dropped with the Remote on node config change.
|
||||
@@ -99,8 +100,10 @@ type Remote struct {
|
||||
}
|
||||
|
||||
type RemoteInboundOption struct {
|
||||
Id int `json:"id"`
|
||||
Tag string `json:"tag"`
|
||||
Remark string `json:"remark"`
|
||||
Listen string `json:"listen"`
|
||||
Protocol model.Protocol `json:"protocol"`
|
||||
Port int `json:"port"`
|
||||
}
|
||||
@@ -109,6 +112,7 @@ func NewRemote(n *model.Node, r NodeEgressResolver) *Remote {
|
||||
return &Remote{
|
||||
node: n,
|
||||
remoteIDByTag: make(map[string]int),
|
||||
adoptedAliases: make(map[string]string),
|
||||
pushedFP: make(map[string]string),
|
||||
egressResolver: r,
|
||||
}
|
||||
@@ -479,13 +483,33 @@ func (r *Remote) recordPushedInbound(ib *model.Inbound) {
|
||||
r.mu.Unlock()
|
||||
}
|
||||
|
||||
// RecordAdoptedInbound stamps the fingerprint when the master adopts the
|
||||
// node's own settings serialization into its DB — direct knowledge of the
|
||||
// exact payload the node holds.
|
||||
// RecordAdoptedInbound stamps the exact payload fingerprint after the master
|
||||
// adopts a node's settings serialization.
|
||||
func (r *Remote) RecordAdoptedInbound(ib *model.Inbound) {
|
||||
r.recordPushedInbound(ib)
|
||||
}
|
||||
|
||||
// AdoptInboundAlias records a deployed alias without mutating either panel.
|
||||
// The runtime association is rediscovered after a master restart.
|
||||
func (r *Remote) AdoptInboundAlias(ib *model.Inbound, remote RemoteInboundOption) {
|
||||
r.mu.Lock()
|
||||
r.remoteIDByTag[remote.Tag] = remote.Id
|
||||
r.remoteIDByTag[ib.Tag] = remote.Id
|
||||
r.adoptedAliases[ib.Tag] = remote.Tag
|
||||
r.pushedFP[ib.Tag] = wireFingerprint(wireInbound(ib, r.node.Id))
|
||||
r.mu.Unlock()
|
||||
}
|
||||
|
||||
func (r *Remote) AdoptedInboundAliases() []string {
|
||||
r.mu.RLock()
|
||||
defer r.mu.RUnlock()
|
||||
aliases := make([]string, 0, len(r.adoptedAliases))
|
||||
for _, alias := range r.adoptedAliases {
|
||||
aliases = append(aliases, alias)
|
||||
}
|
||||
return aliases
|
||||
}
|
||||
|
||||
// AdvancePushedInbound moves the reconcile-skip fingerprint from an inbound's
|
||||
// pre-edit payload to its post-edit payload once every per-client push for the
|
||||
// edit succeeded. It advances only when the recorded fingerprint proves the
|
||||
@@ -661,8 +685,9 @@ func (r *Remote) ResetInboundTraffic(ctx context.Context, ib *model.Inbound) err
|
||||
}
|
||||
|
||||
type TrafficSnapshot struct {
|
||||
Inbounds []*model.Inbound
|
||||
OnlineEmails []string
|
||||
Inbounds []*model.Inbound
|
||||
OnlineEmails []string
|
||||
ManagedAliases []string
|
||||
// OnlineTree is the node's GUID-keyed online subtree (its own clients under
|
||||
// its panelGuid plus every descendant under theirs). Preferred over the flat
|
||||
// OnlineEmails so the master can attribute deeply nested clients to the real
|
||||
|
||||
Reference in New Issue
Block a user