mirror of
https://github.com/MHSanaei/3x-ui.git
synced 2026-09-04 17:37:19 +00:00
fix(outbounds): preserve stable subscription tags (#6345)
An inserted link could claim a previous positional tag before the existing identity that owned it was processed. The owner was then suffixed and the swapped mapping persisted across refreshes. Reserve tags for identities still present in the batch so positional fallback, fresh allocation, and collision suffixes cannot take them.
This commit is contained in:
@@ -462,6 +462,13 @@ func (s *OutboundSubscriptionService) recordError(sub *model.OutboundSubscriptio
|
||||
// written back into parsed[i]["tag"]. The returned slice holds the assigned tags
|
||||
// in order. When tagPrefix is empty a "sub<subID>-" prefix is used for fresh tags.
|
||||
func assignStableTags(parsed []link.Outbound, identities []string, prev map[string]string, prevTagByIndex map[int]string, subID int, tagPrefix string) []string {
|
||||
reservedStableTags := map[string]bool{}
|
||||
for i := range parsed {
|
||||
if i < len(identities) && prev[identities[i]] != "" {
|
||||
reservedStableTags[prev[identities[i]]] = true
|
||||
}
|
||||
}
|
||||
|
||||
used := map[string]bool{} // uniqueness within this refresh batch
|
||||
assigned := make([]string, len(parsed))
|
||||
for i := range parsed {
|
||||
@@ -470,12 +477,14 @@ func assignStableTags(parsed []link.Outbound, identities []string, prev map[stri
|
||||
id = identities[i]
|
||||
}
|
||||
candidate := ""
|
||||
identityTag := ""
|
||||
if old, ok := prev[id]; ok && old != "" {
|
||||
candidate = old
|
||||
identityTag = old
|
||||
}
|
||||
if candidate == "" {
|
||||
// try to reuse by rough positional match from previous fetch (best effort)
|
||||
if old, ok := prevTagByIndex[i]; ok && old != "" {
|
||||
if old, ok := prevTagByIndex[i]; ok && old != "" && !reservedStableTags[old] {
|
||||
candidate = old
|
||||
}
|
||||
}
|
||||
@@ -493,7 +502,7 @@ func assignStableTags(parsed []link.Outbound, identities []string, prev map[stri
|
||||
}
|
||||
// ensure local uniqueness inside this batch
|
||||
final := candidate
|
||||
for k := 1; used[final]; k++ {
|
||||
for k := 1; used[final] || (reservedStableTags[final] && final != identityTag); k++ {
|
||||
final = fmt.Sprintf("%s-%d", candidate, k)
|
||||
}
|
||||
used[final] = true
|
||||
|
||||
Reference in New Issue
Block a user