mirror of
https://github.com/MHSanaei/3x-ui.git
synced 2026-09-02 00:17:13 +00:00
fix(xray): reconcile client auto-disable through the API instead of a forced restart
When a client expired or hit its traffic limit, XrayTrafficJob called RestartXray(true), stopping the whole process and dropping every live connection on every inbound (#5712 reported this as XHTTP on 443 dying) — even though disableInvalidClients had already removed the user from the running core over gRPC. The force restart existed only to re-sync the process's config snapshot. Switch the job to a non-forced restart and teach ComputeHotDiff to express a client-only inbound change as per-user AlterInbound operations for vless/vmess/trojan, so the reconcile is a no-op RemoveUser plus a snapshot update rather than a handler swap that would still blip that inbound's listener. Anything beyond the clients list still falls back to handler replacement or a full restart as before. Closes #5712
This commit is contained in:
@@ -50,8 +50,8 @@ func (j *XrayTrafficJob) Run() {
|
||||
logger.Warning("get RestartXrayOnClientDisable failed:", settingErr)
|
||||
}
|
||||
if restartOnDisable {
|
||||
if err := j.xrayService.RestartXray(true); err != nil {
|
||||
logger.Warning("restart xray after disabling clients failed:", err)
|
||||
if err := j.xrayService.RestartXray(false); err != nil {
|
||||
logger.Warning("reconcile xray after disabling clients failed:", err)
|
||||
j.xrayService.SetToNeedRestart()
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1004,6 +1004,12 @@ func (s *XrayService) tryHotApply(newCfg *xray.Config) bool {
|
||||
|
||||
// Removals first so changed handlers and port swaps never collide with
|
||||
// the additions that follow.
|
||||
for _, u := range diff.RemovedUsers {
|
||||
if err := hotAPI.RemoveUser(u.Tag, u.Email); err != nil && !xray.IsMissingHandlerErr(err) {
|
||||
logger.Info("hot apply: remove user [", u.Email, "] from [", u.Tag, "] failed:", err)
|
||||
return false
|
||||
}
|
||||
}
|
||||
for _, tag := range diff.RemovedInboundTags {
|
||||
if err := hotAPI.DelInbound(tag); err != nil && !xray.IsMissingHandlerErr(err) {
|
||||
logger.Info("hot apply: remove inbound [", tag, "] failed:", err)
|
||||
@@ -1028,6 +1034,12 @@ func (s *XrayService) tryHotApply(newCfg *xray.Config) bool {
|
||||
return false
|
||||
}
|
||||
}
|
||||
for _, u := range diff.AddedUsers {
|
||||
if err := addUserReconciling(&hotAPI, u); err != nil {
|
||||
logger.Info("hot apply: add user [", u.Email, "] to [", u.Tag, "] failed:", err)
|
||||
return false
|
||||
}
|
||||
}
|
||||
if diff.RoutingConfig != nil {
|
||||
if err := hotAPI.ApplyRoutingConfig(diff.RoutingConfig); err != nil {
|
||||
logger.Info("hot apply: apply routing config failed:", err)
|
||||
@@ -1039,6 +1051,19 @@ func (s *XrayService) tryHotApply(newCfg *xray.Config) bool {
|
||||
return true
|
||||
}
|
||||
|
||||
// addUserReconciling adds a user, and on an email conflict (the user was
|
||||
// already applied through the runtime API) replaces the existing user instead.
|
||||
func addUserReconciling(api *xray.XrayAPI, u xray.UserOp) error {
|
||||
err := api.AddUser(u.Protocol, u.Tag, u.User)
|
||||
if err == nil || !xray.IsUserExistsErr(err) {
|
||||
return err
|
||||
}
|
||||
if delErr := api.RemoveUser(u.Tag, u.Email); delErr != nil && !xray.IsMissingHandlerErr(delErr) {
|
||||
return delErr
|
||||
}
|
||||
return api.AddUser(u.Protocol, u.Tag, u.User)
|
||||
}
|
||||
|
||||
// addInboundReconciling adds an inbound, and on a tag conflict (the handler
|
||||
// was already created through the runtime API while the stored snapshot was
|
||||
// stale) replaces the existing handler instead.
|
||||
|
||||
Reference in New Issue
Block a user