mirror of
https://github.com/MHSanaei/3x-ui.git
synced 2026-08-29 14:37:13 +00:00
fix(nodes): propagate single-client deletion to remote nodes (#5352)
Deleting a client attached to a remote-node inbound could silently fail to reach the node, so the node's next traffic snapshot resurrected the client once the 90s delete tombstone expired. Two paths in the single-client delete (Delete -> DelInboundClientByEmail): - A disabled client was skipped entirely: the node-propagation and mark-dirty block sat behind the client's enable flag (needApiDel), so a disabled client on a node never detached and never marked the node dirty. The bulk and multi-client delete paths already handle the node case independently of enable state; mirror that structure here. - Remote.DeleteUser returned nil when resolveRemoteID failed, hiding the failure from the caller so the node was never marked dirty. Surface the error like AddClient/UpdateUser do, so the caller marks the node dirty and the next reconcile converges. Add a regression test asserting a disabled node client's deletion marks the node dirty.
This commit is contained in:
@@ -742,15 +742,17 @@ func (s *ClientService) DelInboundClientByEmail(inboundSvc *InboundService, inbo
|
||||
}
|
||||
}
|
||||
|
||||
if needApiDel {
|
||||
rt, push, dirty, perr := inboundSvc.nodePushPlan(oldInbound)
|
||||
if perr != nil {
|
||||
return false, perr
|
||||
}
|
||||
if dirty {
|
||||
markDirty = true
|
||||
}
|
||||
if oldInbound.NodeID == nil {
|
||||
if oldInbound.NodeID == nil {
|
||||
// Local inbound: a disabled client isn't in the running Xray, so only
|
||||
// a live one (needApiDel) needs an API removal.
|
||||
if needApiDel {
|
||||
rt, push, dirty, perr := inboundSvc.nodePushPlan(oldInbound)
|
||||
if perr != nil {
|
||||
return false, perr
|
||||
}
|
||||
if dirty {
|
||||
markDirty = true
|
||||
}
|
||||
if !push {
|
||||
needRestart = true
|
||||
} else if err1 := rt.RemoveUser(context.Background(), oldInbound, email); err1 == nil {
|
||||
@@ -762,7 +764,19 @@ func (s *ClientService) DelInboundClientByEmail(inboundSvc *InboundService, inbo
|
||||
logger.Debug("Error in deleting client on", rt.Name(), ":", email)
|
||||
needRestart = true
|
||||
}
|
||||
} else if push {
|
||||
}
|
||||
} else {
|
||||
// Node inbound: propagate the delete regardless of the enable flag —
|
||||
// the node's own DB still carries a disabled client and would
|
||||
// resurrect it on the next snapshot otherwise.
|
||||
rt, push, dirty, perr := inboundSvc.nodePushPlan(oldInbound)
|
||||
if perr != nil {
|
||||
return false, perr
|
||||
}
|
||||
if dirty {
|
||||
markDirty = true
|
||||
}
|
||||
if push {
|
||||
if err1 := rt.DeleteUser(context.Background(), oldInbound, email); err1 != nil {
|
||||
logger.Warning("Error in deleting client on", rt.Name(), ":", err1)
|
||||
markDirty = true
|
||||
|
||||
Reference in New Issue
Block a user