diff --git a/adapter/outboundgroup/groupbase.go b/adapter/outboundgroup/groupbase.go index 5ec0c999..eb383ab1 100644 --- a/adapter/outboundgroup/groupbase.go +++ b/adapter/outboundgroup/groupbase.go @@ -19,12 +19,12 @@ type GroupBase struct { *outbound.Base filter *regexp2.Regexp providers []provider.ProxyProvider - versions sync.Map // map[string]uint - proxies sync.Map // map[string][]C.Proxy failedTestMux sync.Mutex failedTimes int failedTime time.Time failedTesting *atomic.Bool + proxies [][]C.Proxy + versions []atomic.Uint32 } type GroupBaseOption struct { @@ -38,12 +38,18 @@ func NewGroupBase(opt GroupBaseOption) *GroupBase { if opt.filter != "" { filter = regexp2.MustCompile(opt.filter, 0) } - return &GroupBase{ + + gb := &GroupBase{ Base: outbound.NewBase(opt.BaseOption), filter: filter, providers: opt.providers, failedTesting: atomic.NewBool(false), } + + gb.proxies = make([][]C.Proxy, len(opt.providers)) + gb.versions = make([]atomic.Uint32, len(opt.providers)) + + return gb } func (gb *GroupBase) GetProxies(touch bool) []C.Proxy { @@ -61,43 +67,44 @@ func (gb *GroupBase) GetProxies(touch bool) []C.Proxy { return proxies } - for _, pd := range gb.providers { + for i, pd := range gb.providers { if touch { pd.Touch() } if pd.VehicleType() == types.Compatible { - gb.proxies.Store(pd.Name(), pd.Proxies()) - gb.versions.Store(pd.Name(), pd.Version()) + gb.versions[i].Store(pd.Version()) + gb.proxies[i] = pd.Proxies() continue } - if version, ok := gb.versions.Load(pd.Name()); !ok || version != pd.Version() { + version := gb.versions[i].Load() + if version != pd.Version() && gb.versions[i].CAS(version, pd.Version()) { var ( proxies []C.Proxy newProxies []C.Proxy ) proxies = pd.Proxies() - for _, p := range proxies { if mat, _ := gb.filter.FindStringMatch(p.Name()); mat != nil { newProxies = append(newProxies, p) } } - gb.proxies.Store(pd.Name(), newProxies) - gb.versions.Store(pd.Name(), pd.Version()) + gb.proxies[i] = newProxies } } + var proxies []C.Proxy - gb.proxies.Range(func(key, value any) bool { - proxies = append(proxies, value.([]C.Proxy)...) - return true - }) + for _, p := range gb.proxies { + proxies = append(proxies, p...) + } + if len(proxies) == 0 { return append(proxies, tunnel.Proxies()["COMPATIBLE"]) } + return proxies } diff --git a/adapter/provider/provider.go b/adapter/provider/provider.go index 4cab2517..00bcde1d 100644 --- a/adapter/provider/provider.go +++ b/adapter/provider/provider.go @@ -7,7 +7,6 @@ import ( "github.com/Dreamacro/clash/common/convert" "github.com/Dreamacro/clash/component/resource" "github.com/dlclark/regexp2" - "math" "runtime" "time" @@ -35,7 +34,7 @@ type proxySetProvider struct { *resource.Fetcher[[]C.Proxy] proxies []C.Proxy healthCheck *HealthCheck - version uint + version uint32 } func (pp *proxySetProvider) MarshalJSON() ([]byte, error) { @@ -48,7 +47,7 @@ func (pp *proxySetProvider) MarshalJSON() ([]byte, error) { }) } -func (pp *proxySetProvider) Version() uint { +func (pp *proxySetProvider) Version() uint32 { return pp.version } @@ -134,7 +133,7 @@ type compatibleProvider struct { name string healthCheck *HealthCheck proxies []C.Proxy - version uint + version uint32 } func (cp *compatibleProvider) MarshalJSON() ([]byte, error) { @@ -146,7 +145,7 @@ func (cp *compatibleProvider) MarshalJSON() ([]byte, error) { }) } -func (cp *compatibleProvider) Version() uint { +func (cp *compatibleProvider) Version() uint32 { return cp.version } @@ -209,11 +208,7 @@ func NewCompatibleProvider(name string, proxies []C.Proxy, hc *HealthCheck) (*Co func proxiesOnUpdate(pd *proxySetProvider) func([]C.Proxy) { return func(elm []C.Proxy) { pd.setProxies(elm) - if pd.version == math.MaxUint { - pd.version = 0 - } else { - pd.version++ - } + pd.version += 1 } } diff --git a/constant/provider/interface.go b/constant/provider/interface.go index 4e281925..a56bc0a3 100644 --- a/constant/provider/interface.go +++ b/constant/provider/interface.go @@ -68,7 +68,7 @@ type ProxyProvider interface { Proxies() []C.Proxy Touch() HealthCheck() - Version() uint + Version() uint32 } // Rule Type