fix: drop nodes that fail geo detection in collection rename

Nodes whose country cannot be detected are now filtered out instead of
kept with their original name. This prevents unlabelled/unrenamed nodes
from appearing in collection output.
This commit is contained in:
2026-07-29 11:19:19 +08:00
parent 71f814d1ce
commit 585164dca6
2 changed files with 18 additions and 34 deletions
+16 -28
View File
@@ -30,17 +30,18 @@ func resolveRenameOptions(opts *model.RenameOptions) model.RenameOptions {
// RenameCollectionNodes renames proxy nodes in the collection-level format:
//
// [emoji country flag] [alias] [country name] [city] [-1...-N]
// [emoji country flag] [alias] [country name] [city] [01...NN]
//
// The alias is read from each node's "_sourceAlias" field (tagged by the
// subscription service from the source's Alias). Geographic info (flag,
// country, city) is auto-detected from the node's original name and server.
//
// Nodes are grouped by their **display baseName** (the name without the index
// suffix) and numbered sequentially within each group, starting at 1. This
// ensures that nodes producing the same display name get unique suffixes
// (-1, -2, -3, …) in a single pass, so EnsureUniqueProxyNames never needs to
// append a secondary suffix.
// suffix) and numbered sequentially within each group, starting at 1.
//
// Nodes whose geographic info cannot be detected (no country found) are
// dropped from the output — they cannot be meaningfully renamed and would
// appear as unlabelled entries in the collection.
//
// opts controls which fields are included in the output. A nil opts means all
// fields are included (full default format).
@@ -54,13 +55,12 @@ func RenameCollectionNodes(proxies []model.ProxyNode, opts *model.RenameOptions)
// First pass: compute display baseName (without index) for each node.
type nodeInfo struct {
proxy model.ProxyNode
baseName string // display name without index suffix; "" means skip rename
baseName string // display name without index suffix; "" means geo failed
}
infos := make([]nodeInfo, len(proxies))
for i, proxy := range proxies {
infos := make([]nodeInfo, 0, len(proxies))
for _, proxy := range proxies {
if proxy == nil {
infos[i] = nodeInfo{proxy: proxy}
continue
}
@@ -70,7 +70,7 @@ func RenameCollectionNodes(proxies []model.ProxyNode, opts *model.RenameOptions)
geo := util.DetectGeoWithServer(name, server)
if geo.CountryName == "" {
infos[i] = nodeInfo{proxy: proxy}
// Geo detection failed — skip this node
continue
}
@@ -96,34 +96,22 @@ func RenameCollectionNodes(proxies []model.ProxyNode, opts *model.RenameOptions)
parts = append(parts, geo.CityCN)
}
infos[i] = nodeInfo{
infos = append(infos, nodeInfo{
proxy: proxy,
baseName: strings.Join(parts, " "),
}
})
}
// Count group sizes by baseName.
baseCounts := make(map[string]int)
for _, info := range infos {
if info.baseName != "" {
baseCounts[info.baseName]++
}
baseCounts[info.baseName]++
}
// Second pass: assign names with sequential numbering.
counters := make(map[string]int)
results := make([]model.ProxyNode, len(proxies))
for i, info := range infos {
if info.proxy == nil {
results[i] = info.proxy
continue
}
if info.baseName == "" {
// Geo detection failed — keep original name.
results[i] = info.proxy
continue
}
results := make([]model.ProxyNode, 0, len(infos))
for _, info := range infos {
counters[info.baseName]++
total := baseCounts[info.baseName]
@@ -135,7 +123,7 @@ func RenameCollectionNodes(proxies []model.ProxyNode, opts *model.RenameOptions)
next := cloneProxy(info.proxy)
delete(next, "_sourceAlias")
next["name"] = name
results[i] = next
results = append(results, next)
}
return results
+2 -6
View File
@@ -110,12 +110,8 @@ func TestRenameCollectionNodes_UnknownCountry(t *testing.T) {
{"name": "Unknown Node", "type": "ss", "_sourceAlias": "A"},
}
result := RenameCollectionNodes(proxies, nil)
if len(result) != 1 {
t.Fatalf("expected 1 node, got %d", len(result))
}
// Should keep original name
if result[0]["name"] != "Unknown Node" {
t.Errorf("expected original name, got %q", result[0]["name"])
if len(result) != 0 {
t.Fatalf("expected 0 nodes (geo detection failed, should be filtered), got %d", len(result))
}
}