fix(xray): force full restart for inbounds with a VLESS reverse client

Hot-applying an inbound change swaps it via DelInbound+AddInbound on
the running core. That unregisters any client's reverse.tag handler
on the xray-core side without closing the bridge's already-established
connection, so the reverse tunnel is silently orphaned until someone
manually restarts xray. diffInbounds now bails out of the hot-apply
path whenever the old or new inbound carries a reverse-tagged client,
falling back to a full restart, which actually drops the socket and
lets the bridge redial on its own.

Also scope the .claude ignore rule to its contents (.claude/*) instead
of the whole directory, so individual files under .claude/ can be
tracked selectively.
This commit is contained in:
MHSanaei
2026-07-01 14:02:13 +02:00
parent 427613b308
commit 49773c18de
2 changed files with 30 additions and 1 deletions
+1 -1
View File
@@ -2,7 +2,7 @@
.idea/
.vscode/
.cursor/
.claude/
.claude/*
.cache/
.sync*
+29
View File
@@ -108,6 +108,10 @@ func diffInbounds(oldCfg, newCfg *Config, diff *HotDiff) bool {
if oldIb.Tag == apiTag || oldIb.Tag == "api" {
return false
}
if exists && (inboundHasReverseClient(oldIb) || inboundHasReverseClient(newIb)) {
logger.Debug("hot diff: inbound [", oldIb.Tag, "] carries a reverse-tagged client, forcing a full restart instead of a hot swap")
return false
}
diff.RemovedInboundTags = append(diff.RemovedInboundTags, oldIb.Tag)
if exists {
raw, err := json.Marshal(newIb)
@@ -134,6 +138,31 @@ func diffInbounds(oldCfg, newCfg *Config, diff *HotDiff) bool {
return true
}
func inboundHasReverseClient(ib *InboundConfig) bool {
if ib == nil {
return false
}
var settings struct {
Clients []struct {
Reverse json.RawMessage `json:"reverse"`
} `json:"clients"`
}
if err := json.Unmarshal(ib.Settings, &settings); err != nil {
return false
}
for _, c := range settings.Clients {
if len(c.Reverse) == 0 {
continue
}
var tag any
if err := json.Unmarshal(c.Reverse, &tag); err != nil || tag == nil {
continue
}
return true
}
return false
}
// diffOutbounds fills diff with outbound removals/additions keyed by tag.
// The first outbound is xray's default handler and the API can only append,
// so any change to its identity or content forces a restart. Reordering of