refactor: optimize the performance of filter in proxy-group
This commit is contained in:
parent
8217db82ce
commit
f1dab9e9ce
8 changed files with 182 additions and 117 deletions
|
@ -8,18 +8,14 @@ import (
|
||||||
"time"
|
"time"
|
||||||
|
|
||||||
"github.com/Dreamacro/clash/adapter/outbound"
|
"github.com/Dreamacro/clash/adapter/outbound"
|
||||||
"github.com/Dreamacro/clash/common/singledo"
|
|
||||||
"github.com/Dreamacro/clash/component/dialer"
|
"github.com/Dreamacro/clash/component/dialer"
|
||||||
C "github.com/Dreamacro/clash/constant"
|
C "github.com/Dreamacro/clash/constant"
|
||||||
"github.com/Dreamacro/clash/constant/provider"
|
"github.com/Dreamacro/clash/constant/provider"
|
||||||
)
|
)
|
||||||
|
|
||||||
type Fallback struct {
|
type Fallback struct {
|
||||||
*outbound.Base
|
*GroupBase
|
||||||
disableUDP bool
|
disableUDP bool
|
||||||
filter string
|
|
||||||
single *singledo.Single[[]C.Proxy]
|
|
||||||
providers []provider.ProxyProvider
|
|
||||||
failedTimes *atomic.Int32
|
failedTimes *atomic.Int32
|
||||||
failedTime *atomic.Int64
|
failedTime *atomic.Int64
|
||||||
}
|
}
|
||||||
|
@ -98,7 +94,7 @@ func (f *Fallback) SupportUDP() bool {
|
||||||
// MarshalJSON implements C.ProxyAdapter
|
// MarshalJSON implements C.ProxyAdapter
|
||||||
func (f *Fallback) MarshalJSON() ([]byte, error) {
|
func (f *Fallback) MarshalJSON() ([]byte, error) {
|
||||||
all := []string{}
|
all := []string{}
|
||||||
for _, proxy := range f.proxies(false) {
|
for _, proxy := range f.GetProxies(false) {
|
||||||
all = append(all, proxy.Name())
|
all = append(all, proxy.Name())
|
||||||
}
|
}
|
||||||
return json.Marshal(map[string]any{
|
return json.Marshal(map[string]any{
|
||||||
|
@ -114,16 +110,8 @@ func (f *Fallback) Unwrap(metadata *C.Metadata) C.Proxy {
|
||||||
return proxy
|
return proxy
|
||||||
}
|
}
|
||||||
|
|
||||||
func (f *Fallback) proxies(touch bool) []C.Proxy {
|
|
||||||
elm, _, _ := f.single.Do(func() ([]C.Proxy, error) {
|
|
||||||
return getProvidersProxies(f.providers, touch, f.filter), nil
|
|
||||||
})
|
|
||||||
|
|
||||||
return elm
|
|
||||||
}
|
|
||||||
|
|
||||||
func (f *Fallback) findAliveProxy(touch bool) C.Proxy {
|
func (f *Fallback) findAliveProxy(touch bool) C.Proxy {
|
||||||
proxies := f.proxies(touch)
|
proxies := f.GetProxies(touch)
|
||||||
for _, proxy := range proxies {
|
for _, proxy := range proxies {
|
||||||
if proxy.Alive() {
|
if proxy.Alive() {
|
||||||
return proxy
|
return proxy
|
||||||
|
@ -135,16 +123,17 @@ func (f *Fallback) findAliveProxy(touch bool) C.Proxy {
|
||||||
|
|
||||||
func NewFallback(option *GroupCommonOption, providers []provider.ProxyProvider) *Fallback {
|
func NewFallback(option *GroupCommonOption, providers []provider.ProxyProvider) *Fallback {
|
||||||
return &Fallback{
|
return &Fallback{
|
||||||
Base: outbound.NewBase(outbound.BaseOption{
|
GroupBase: NewGroupBase(GroupBaseOption{
|
||||||
Name: option.Name,
|
outbound.BaseOption{
|
||||||
Type: C.Fallback,
|
Name: option.Name,
|
||||||
Interface: option.Interface,
|
Type: C.Fallback,
|
||||||
RoutingMark: option.RoutingMark,
|
Interface: option.Interface,
|
||||||
|
RoutingMark: option.RoutingMark,
|
||||||
|
},
|
||||||
|
option.Filter,
|
||||||
|
providers,
|
||||||
}),
|
}),
|
||||||
single: singledo.NewSingle[[]C.Proxy](defaultGetProxiesDuration),
|
|
||||||
providers: providers,
|
|
||||||
disableUDP: option.DisableUDP,
|
disableUDP: option.DisableUDP,
|
||||||
filter: option.Filter,
|
|
||||||
failedTimes: atomic.NewInt32(-1),
|
failedTimes: atomic.NewInt32(-1),
|
||||||
failedTime: atomic.NewInt64(-1),
|
failedTime: atomic.NewInt64(-1),
|
||||||
}
|
}
|
||||||
|
|
99
adapter/outboundgroup/groupbase.go
Normal file
99
adapter/outboundgroup/groupbase.go
Normal file
|
@ -0,0 +1,99 @@
|
||||||
|
package outboundgroup
|
||||||
|
|
||||||
|
import (
|
||||||
|
"github.com/Dreamacro/clash/adapter/outbound"
|
||||||
|
C "github.com/Dreamacro/clash/constant"
|
||||||
|
"github.com/Dreamacro/clash/constant/provider"
|
||||||
|
types "github.com/Dreamacro/clash/constant/provider"
|
||||||
|
"github.com/Dreamacro/clash/tunnel"
|
||||||
|
"github.com/dlclark/regexp2"
|
||||||
|
)
|
||||||
|
|
||||||
|
type GroupBase struct {
|
||||||
|
*outbound.Base
|
||||||
|
filter *regexp2.Regexp
|
||||||
|
providers []provider.ProxyProvider
|
||||||
|
flags map[string]uint
|
||||||
|
proxies map[string][]C.Proxy
|
||||||
|
}
|
||||||
|
|
||||||
|
type GroupBaseOption struct {
|
||||||
|
outbound.BaseOption
|
||||||
|
filter string
|
||||||
|
providers []provider.ProxyProvider
|
||||||
|
}
|
||||||
|
|
||||||
|
func NewGroupBase(opt GroupBaseOption) *GroupBase {
|
||||||
|
var filter *regexp2.Regexp = nil
|
||||||
|
if opt.filter != "" {
|
||||||
|
filter = regexp2.MustCompile(opt.filter, 0)
|
||||||
|
}
|
||||||
|
return &GroupBase{
|
||||||
|
Base: outbound.NewBase(opt.BaseOption),
|
||||||
|
filter: filter,
|
||||||
|
providers: opt.providers,
|
||||||
|
flags: map[string]uint{},
|
||||||
|
proxies: map[string][]C.Proxy{},
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func (gb *GroupBase) GetProxies(touch bool) []C.Proxy {
|
||||||
|
if gb.filter == nil {
|
||||||
|
var proxies []C.Proxy
|
||||||
|
for _, pd := range gb.providers {
|
||||||
|
if touch {
|
||||||
|
proxies = append(proxies, pd.ProxiesWithTouch()...)
|
||||||
|
} else {
|
||||||
|
proxies = append(proxies, pd.Proxies()...)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if len(proxies) == 0 {
|
||||||
|
return append(proxies, tunnel.Proxies()["COMPATIBLE"])
|
||||||
|
}
|
||||||
|
return proxies
|
||||||
|
}
|
||||||
|
//TODO("Touch Flag 没变的")
|
||||||
|
for _, pd := range gb.providers {
|
||||||
|
vt := pd.VehicleType()
|
||||||
|
if vt == types.Compatible {
|
||||||
|
if touch {
|
||||||
|
gb.proxies[pd.Name()] = pd.ProxiesWithTouch()
|
||||||
|
} else {
|
||||||
|
gb.proxies[pd.Name()] = pd.Proxies()
|
||||||
|
}
|
||||||
|
|
||||||
|
gb.flags[pd.Name()] = pd.Flag()
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
|
||||||
|
if flag, ok := gb.flags[pd.Name()]; !ok || flag != pd.Flag() {
|
||||||
|
var (
|
||||||
|
proxies []C.Proxy
|
||||||
|
newProxies []C.Proxy
|
||||||
|
)
|
||||||
|
|
||||||
|
if touch {
|
||||||
|
proxies = pd.ProxiesWithTouch()
|
||||||
|
} else {
|
||||||
|
proxies = pd.Proxies()
|
||||||
|
}
|
||||||
|
|
||||||
|
for _, p := range proxies {
|
||||||
|
if mat, _ := gb.filter.FindStringMatch(p.Name()); mat != nil {
|
||||||
|
newProxies = append(newProxies, p)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
gb.proxies[pd.Name()] = newProxies
|
||||||
|
gb.flags[pd.Name()] = pd.Flag()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
var proxies []C.Proxy
|
||||||
|
for _, v := range gb.proxies {
|
||||||
|
proxies = append(proxies, v...)
|
||||||
|
}
|
||||||
|
if len(proxies) == 0 {
|
||||||
|
return append(proxies, tunnel.Proxies()["COMPATIBLE"])
|
||||||
|
}
|
||||||
|
return proxies
|
||||||
|
}
|
|
@ -9,7 +9,6 @@ import (
|
||||||
|
|
||||||
"github.com/Dreamacro/clash/adapter/outbound"
|
"github.com/Dreamacro/clash/adapter/outbound"
|
||||||
"github.com/Dreamacro/clash/common/murmur3"
|
"github.com/Dreamacro/clash/common/murmur3"
|
||||||
"github.com/Dreamacro/clash/common/singledo"
|
|
||||||
"github.com/Dreamacro/clash/component/dialer"
|
"github.com/Dreamacro/clash/component/dialer"
|
||||||
C "github.com/Dreamacro/clash/constant"
|
C "github.com/Dreamacro/clash/constant"
|
||||||
"github.com/Dreamacro/clash/constant/provider"
|
"github.com/Dreamacro/clash/constant/provider"
|
||||||
|
@ -20,11 +19,8 @@ import (
|
||||||
type strategyFn = func(proxies []C.Proxy, metadata *C.Metadata) C.Proxy
|
type strategyFn = func(proxies []C.Proxy, metadata *C.Metadata) C.Proxy
|
||||||
|
|
||||||
type LoadBalance struct {
|
type LoadBalance struct {
|
||||||
*outbound.Base
|
*GroupBase
|
||||||
disableUDP bool
|
disableUDP bool
|
||||||
filter string
|
|
||||||
single *singledo.Single[[]C.Proxy]
|
|
||||||
providers []provider.ProxyProvider
|
|
||||||
strategyFn strategyFn
|
strategyFn strategyFn
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -136,22 +132,14 @@ func strategyConsistentHashing() strategyFn {
|
||||||
|
|
||||||
// Unwrap implements C.ProxyAdapter
|
// Unwrap implements C.ProxyAdapter
|
||||||
func (lb *LoadBalance) Unwrap(metadata *C.Metadata) C.Proxy {
|
func (lb *LoadBalance) Unwrap(metadata *C.Metadata) C.Proxy {
|
||||||
proxies := lb.proxies(true)
|
proxies := lb.GetProxies(true)
|
||||||
return lb.strategyFn(proxies, metadata)
|
return lb.strategyFn(proxies, metadata)
|
||||||
}
|
}
|
||||||
|
|
||||||
func (lb *LoadBalance) proxies(touch bool) []C.Proxy {
|
|
||||||
elm, _, _ := lb.single.Do(func() ([]C.Proxy, error) {
|
|
||||||
return getProvidersProxies(lb.providers, touch, lb.filter), nil
|
|
||||||
})
|
|
||||||
|
|
||||||
return elm
|
|
||||||
}
|
|
||||||
|
|
||||||
// MarshalJSON implements C.ProxyAdapter
|
// MarshalJSON implements C.ProxyAdapter
|
||||||
func (lb *LoadBalance) MarshalJSON() ([]byte, error) {
|
func (lb *LoadBalance) MarshalJSON() ([]byte, error) {
|
||||||
all := []string{}
|
all := []string{}
|
||||||
for _, proxy := range lb.proxies(false) {
|
for _, proxy := range lb.GetProxies(false) {
|
||||||
all = append(all, proxy.Name())
|
all = append(all, proxy.Name())
|
||||||
}
|
}
|
||||||
return json.Marshal(map[string]any{
|
return json.Marshal(map[string]any{
|
||||||
|
@ -171,16 +159,17 @@ func NewLoadBalance(option *GroupCommonOption, providers []provider.ProxyProvide
|
||||||
return nil, fmt.Errorf("%w: %s", errStrategy, strategy)
|
return nil, fmt.Errorf("%w: %s", errStrategy, strategy)
|
||||||
}
|
}
|
||||||
return &LoadBalance{
|
return &LoadBalance{
|
||||||
Base: outbound.NewBase(outbound.BaseOption{
|
GroupBase: NewGroupBase(GroupBaseOption{
|
||||||
Name: option.Name,
|
outbound.BaseOption{
|
||||||
Type: C.LoadBalance,
|
Name: option.Name,
|
||||||
Interface: option.Interface,
|
Type: C.LoadBalance,
|
||||||
RoutingMark: option.RoutingMark,
|
Interface: option.Interface,
|
||||||
|
RoutingMark: option.RoutingMark,
|
||||||
|
},
|
||||||
|
option.Filter,
|
||||||
|
providers,
|
||||||
}),
|
}),
|
||||||
single: singledo.NewSingle[[]C.Proxy](defaultGetProxiesDuration),
|
|
||||||
providers: providers,
|
|
||||||
strategyFn: strategyFn,
|
strategyFn: strategyFn,
|
||||||
disableUDP: option.DisableUDP,
|
disableUDP: option.DisableUDP,
|
||||||
filter: option.Filter,
|
|
||||||
}, nil
|
}, nil
|
||||||
}
|
}
|
||||||
|
|
|
@ -6,17 +6,13 @@ import (
|
||||||
"fmt"
|
"fmt"
|
||||||
|
|
||||||
"github.com/Dreamacro/clash/adapter/outbound"
|
"github.com/Dreamacro/clash/adapter/outbound"
|
||||||
"github.com/Dreamacro/clash/common/singledo"
|
|
||||||
"github.com/Dreamacro/clash/component/dialer"
|
"github.com/Dreamacro/clash/component/dialer"
|
||||||
C "github.com/Dreamacro/clash/constant"
|
C "github.com/Dreamacro/clash/constant"
|
||||||
"github.com/Dreamacro/clash/constant/provider"
|
"github.com/Dreamacro/clash/constant/provider"
|
||||||
)
|
)
|
||||||
|
|
||||||
type Relay struct {
|
type Relay struct {
|
||||||
*outbound.Base
|
*GroupBase
|
||||||
single *singledo.Single[[]C.Proxy]
|
|
||||||
providers []provider.ProxyProvider
|
|
||||||
filter string
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// DialContext implements C.ProxyAdapter
|
// DialContext implements C.ProxyAdapter
|
||||||
|
@ -70,7 +66,7 @@ func (r *Relay) DialContext(ctx context.Context, metadata *C.Metadata, opts ...d
|
||||||
// MarshalJSON implements C.ProxyAdapter
|
// MarshalJSON implements C.ProxyAdapter
|
||||||
func (r *Relay) MarshalJSON() ([]byte, error) {
|
func (r *Relay) MarshalJSON() ([]byte, error) {
|
||||||
all := []string{}
|
all := []string{}
|
||||||
for _, proxy := range r.rawProxies(false) {
|
for _, proxy := range r.GetProxies(false) {
|
||||||
all = append(all, proxy.Name())
|
all = append(all, proxy.Name())
|
||||||
}
|
}
|
||||||
return json.Marshal(map[string]any{
|
return json.Marshal(map[string]any{
|
||||||
|
@ -79,16 +75,8 @@ func (r *Relay) MarshalJSON() ([]byte, error) {
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
func (r *Relay) rawProxies(touch bool) []C.Proxy {
|
|
||||||
elm, _, _ := r.single.Do(func() ([]C.Proxy, error) {
|
|
||||||
return getProvidersProxies(r.providers, touch, r.filter), nil
|
|
||||||
})
|
|
||||||
|
|
||||||
return elm
|
|
||||||
}
|
|
||||||
|
|
||||||
func (r *Relay) proxies(metadata *C.Metadata, touch bool) []C.Proxy {
|
func (r *Relay) proxies(metadata *C.Metadata, touch bool) []C.Proxy {
|
||||||
proxies := r.rawProxies(touch)
|
proxies := r.GetProxies(touch)
|
||||||
|
|
||||||
for n, proxy := range proxies {
|
for n, proxy := range proxies {
|
||||||
subproxy := proxy.Unwrap(metadata)
|
subproxy := proxy.Unwrap(metadata)
|
||||||
|
@ -103,14 +91,15 @@ func (r *Relay) proxies(metadata *C.Metadata, touch bool) []C.Proxy {
|
||||||
|
|
||||||
func NewRelay(option *GroupCommonOption, providers []provider.ProxyProvider) *Relay {
|
func NewRelay(option *GroupCommonOption, providers []provider.ProxyProvider) *Relay {
|
||||||
return &Relay{
|
return &Relay{
|
||||||
Base: outbound.NewBase(outbound.BaseOption{
|
GroupBase: NewGroupBase(GroupBaseOption{
|
||||||
Name: option.Name,
|
outbound.BaseOption{
|
||||||
Type: C.Relay,
|
Name: option.Name,
|
||||||
Interface: option.Interface,
|
Type: C.Relay,
|
||||||
RoutingMark: option.RoutingMark,
|
Interface: option.Interface,
|
||||||
|
RoutingMark: option.RoutingMark,
|
||||||
|
},
|
||||||
|
"",
|
||||||
|
providers,
|
||||||
}),
|
}),
|
||||||
single: singledo.NewSingle[[]C.Proxy](defaultGetProxiesDuration),
|
|
||||||
providers: providers,
|
|
||||||
filter: option.Filter,
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -6,19 +6,15 @@ import (
|
||||||
"errors"
|
"errors"
|
||||||
|
|
||||||
"github.com/Dreamacro/clash/adapter/outbound"
|
"github.com/Dreamacro/clash/adapter/outbound"
|
||||||
"github.com/Dreamacro/clash/common/singledo"
|
|
||||||
"github.com/Dreamacro/clash/component/dialer"
|
"github.com/Dreamacro/clash/component/dialer"
|
||||||
C "github.com/Dreamacro/clash/constant"
|
C "github.com/Dreamacro/clash/constant"
|
||||||
"github.com/Dreamacro/clash/constant/provider"
|
"github.com/Dreamacro/clash/constant/provider"
|
||||||
)
|
)
|
||||||
|
|
||||||
type Selector struct {
|
type Selector struct {
|
||||||
*outbound.Base
|
*GroupBase
|
||||||
disableUDP bool
|
disableUDP bool
|
||||||
single *singledo.Single[C.Proxy]
|
|
||||||
selected string
|
selected string
|
||||||
filter string
|
|
||||||
providers []provider.ProxyProvider
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// DialContext implements C.ProxyAdapter
|
// DialContext implements C.ProxyAdapter
|
||||||
|
@ -51,7 +47,7 @@ func (s *Selector) SupportUDP() bool {
|
||||||
// MarshalJSON implements C.ProxyAdapter
|
// MarshalJSON implements C.ProxyAdapter
|
||||||
func (s *Selector) MarshalJSON() ([]byte, error) {
|
func (s *Selector) MarshalJSON() ([]byte, error) {
|
||||||
all := []string{}
|
all := []string{}
|
||||||
for _, proxy := range getProvidersProxies(s.providers, false, s.filter) {
|
for _, proxy := range s.GetProxies(false) {
|
||||||
all = append(all, proxy.Name())
|
all = append(all, proxy.Name())
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -67,10 +63,9 @@ func (s *Selector) Now() string {
|
||||||
}
|
}
|
||||||
|
|
||||||
func (s *Selector) Set(name string) error {
|
func (s *Selector) Set(name string) error {
|
||||||
for _, proxy := range getProvidersProxies(s.providers, false, s.filter) {
|
for _, proxy := range s.GetProxies(false) {
|
||||||
if proxy.Name() == name {
|
if proxy.Name() == name {
|
||||||
s.selected = name
|
s.selected = name
|
||||||
s.single.Reset()
|
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -84,32 +79,29 @@ func (s *Selector) Unwrap(*C.Metadata) C.Proxy {
|
||||||
}
|
}
|
||||||
|
|
||||||
func (s *Selector) selectedProxy(touch bool) C.Proxy {
|
func (s *Selector) selectedProxy(touch bool) C.Proxy {
|
||||||
elm, _, _ := s.single.Do(func() (C.Proxy, error) {
|
proxies := s.GetProxies(touch)
|
||||||
proxies := getProvidersProxies(s.providers, touch, s.filter)
|
for _, proxy := range proxies {
|
||||||
for _, proxy := range proxies {
|
if proxy.Name() == s.selected {
|
||||||
if proxy.Name() == s.selected {
|
return proxy
|
||||||
return proxy, nil
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
return proxies[0], nil
|
return proxies[0]
|
||||||
})
|
|
||||||
|
|
||||||
return elm
|
|
||||||
}
|
}
|
||||||
|
|
||||||
func NewSelector(option *GroupCommonOption, providers []provider.ProxyProvider) *Selector {
|
func NewSelector(option *GroupCommonOption, providers []provider.ProxyProvider) *Selector {
|
||||||
return &Selector{
|
return &Selector{
|
||||||
Base: outbound.NewBase(outbound.BaseOption{
|
GroupBase: NewGroupBase(GroupBaseOption{
|
||||||
Name: option.Name,
|
outbound.BaseOption{
|
||||||
Type: C.Selector,
|
Name: option.Name,
|
||||||
Interface: option.Interface,
|
Type: C.Selector,
|
||||||
RoutingMark: option.RoutingMark,
|
Interface: option.Interface,
|
||||||
|
RoutingMark: option.RoutingMark,
|
||||||
|
},
|
||||||
|
option.Filter,
|
||||||
|
providers,
|
||||||
}),
|
}),
|
||||||
single: singledo.NewSingle[C.Proxy](defaultGetProxiesDuration),
|
|
||||||
providers: providers,
|
|
||||||
selected: "COMPATIBLE",
|
selected: "COMPATIBLE",
|
||||||
disableUDP: option.DisableUDP,
|
disableUDP: option.DisableUDP,
|
||||||
filter: option.Filter,
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -23,14 +23,11 @@ func urlTestWithTolerance(tolerance uint16) urlTestOption {
|
||||||
}
|
}
|
||||||
|
|
||||||
type URLTest struct {
|
type URLTest struct {
|
||||||
*outbound.Base
|
*GroupBase
|
||||||
tolerance uint16
|
tolerance uint16
|
||||||
disableUDP bool
|
disableUDP bool
|
||||||
fastNode C.Proxy
|
fastNode C.Proxy
|
||||||
filter string
|
|
||||||
single *singledo.Single[[]C.Proxy]
|
|
||||||
fastSingle *singledo.Single[C.Proxy]
|
fastSingle *singledo.Single[C.Proxy]
|
||||||
providers []provider.ProxyProvider
|
|
||||||
failedTimes *atomic.Int32
|
failedTimes *atomic.Int32
|
||||||
failedTime *atomic.Int64
|
failedTime *atomic.Int64
|
||||||
}
|
}
|
||||||
|
@ -70,17 +67,9 @@ func (u *URLTest) Unwrap(*C.Metadata) C.Proxy {
|
||||||
return u.fast(true)
|
return u.fast(true)
|
||||||
}
|
}
|
||||||
|
|
||||||
func (u *URLTest) proxies(touch bool) []C.Proxy {
|
|
||||||
elm, _, _ := u.single.Do(func() ([]C.Proxy, error) {
|
|
||||||
return getProvidersProxies(u.providers, touch, u.filter), nil
|
|
||||||
})
|
|
||||||
|
|
||||||
return elm
|
|
||||||
}
|
|
||||||
|
|
||||||
func (u *URLTest) fast(touch bool) C.Proxy {
|
func (u *URLTest) fast(touch bool) C.Proxy {
|
||||||
elm, _, _ := u.fastSingle.Do(func() (C.Proxy, error) {
|
elm, _, _ := u.fastSingle.Do(func() (C.Proxy, error) {
|
||||||
proxies := u.proxies(touch)
|
proxies := u.GetProxies(touch)
|
||||||
fast := proxies[0]
|
fast := proxies[0]
|
||||||
min := fast.LastDelay()
|
min := fast.LastDelay()
|
||||||
fastNotExist := true
|
fastNotExist := true
|
||||||
|
@ -124,7 +113,7 @@ func (u *URLTest) SupportUDP() bool {
|
||||||
// MarshalJSON implements C.ProxyAdapter
|
// MarshalJSON implements C.ProxyAdapter
|
||||||
func (u *URLTest) MarshalJSON() ([]byte, error) {
|
func (u *URLTest) MarshalJSON() ([]byte, error) {
|
||||||
all := []string{}
|
all := []string{}
|
||||||
for _, proxy := range u.proxies(false) {
|
for _, proxy := range u.GetProxies(false) {
|
||||||
all = append(all, proxy.Name())
|
all = append(all, proxy.Name())
|
||||||
}
|
}
|
||||||
return json.Marshal(map[string]any{
|
return json.Marshal(map[string]any{
|
||||||
|
@ -175,17 +164,18 @@ func parseURLTestOption(config map[string]any) []urlTestOption {
|
||||||
|
|
||||||
func NewURLTest(option *GroupCommonOption, providers []provider.ProxyProvider, options ...urlTestOption) *URLTest {
|
func NewURLTest(option *GroupCommonOption, providers []provider.ProxyProvider, options ...urlTestOption) *URLTest {
|
||||||
urlTest := &URLTest{
|
urlTest := &URLTest{
|
||||||
Base: outbound.NewBase(outbound.BaseOption{
|
GroupBase: NewGroupBase(GroupBaseOption{
|
||||||
Name: option.Name,
|
outbound.BaseOption{
|
||||||
Type: C.URLTest,
|
Name: option.Name,
|
||||||
Interface: option.Interface,
|
Type: C.URLTest,
|
||||||
RoutingMark: option.RoutingMark,
|
Interface: option.Interface,
|
||||||
|
RoutingMark: option.RoutingMark,
|
||||||
|
},
|
||||||
|
option.Filter,
|
||||||
|
providers,
|
||||||
}),
|
}),
|
||||||
single: singledo.NewSingle[[]C.Proxy](defaultGetProxiesDuration),
|
|
||||||
fastSingle: singledo.NewSingle[C.Proxy](time.Second * 10),
|
fastSingle: singledo.NewSingle[C.Proxy](time.Second * 10),
|
||||||
providers: providers,
|
|
||||||
disableUDP: option.DisableUDP,
|
disableUDP: option.DisableUDP,
|
||||||
filter: option.Filter,
|
|
||||||
failedTimes: atomic.NewInt32(-1),
|
failedTimes: atomic.NewInt32(-1),
|
||||||
failedTime: atomic.NewInt64(-1),
|
failedTime: atomic.NewInt64(-1),
|
||||||
}
|
}
|
||||||
|
|
|
@ -5,6 +5,7 @@ import (
|
||||||
"errors"
|
"errors"
|
||||||
"fmt"
|
"fmt"
|
||||||
"github.com/dlclark/regexp2"
|
"github.com/dlclark/regexp2"
|
||||||
|
"math"
|
||||||
"runtime"
|
"runtime"
|
||||||
"time"
|
"time"
|
||||||
|
|
||||||
|
@ -32,6 +33,11 @@ type proxySetProvider struct {
|
||||||
*fetcher
|
*fetcher
|
||||||
proxies []C.Proxy
|
proxies []C.Proxy
|
||||||
healthCheck *HealthCheck
|
healthCheck *HealthCheck
|
||||||
|
flag uint
|
||||||
|
}
|
||||||
|
|
||||||
|
func (pp *proxySetProvider) Flag() uint {
|
||||||
|
return pp.flag
|
||||||
}
|
}
|
||||||
|
|
||||||
func (pp *proxySetProvider) MarshalJSON() ([]byte, error) {
|
func (pp *proxySetProvider) MarshalJSON() ([]byte, error) {
|
||||||
|
@ -117,6 +123,11 @@ func NewProxySetProvider(name string, interval time.Duration, filter string, veh
|
||||||
onUpdate := func(elm any) {
|
onUpdate := func(elm any) {
|
||||||
ret := elm.([]C.Proxy)
|
ret := elm.([]C.Proxy)
|
||||||
pd.setProxies(ret)
|
pd.setProxies(ret)
|
||||||
|
if pd.flag == math.MaxUint {
|
||||||
|
pd.flag = 0
|
||||||
|
} else {
|
||||||
|
pd.flag++
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
proxiesParseAndFilter := func(buf []byte) (any, error) {
|
proxiesParseAndFilter := func(buf []byte) (any, error) {
|
||||||
|
@ -171,6 +182,11 @@ type compatibleProvider struct {
|
||||||
name string
|
name string
|
||||||
healthCheck *HealthCheck
|
healthCheck *HealthCheck
|
||||||
proxies []C.Proxy
|
proxies []C.Proxy
|
||||||
|
flag uint
|
||||||
|
}
|
||||||
|
|
||||||
|
func (cp *compatibleProvider) Flag() uint {
|
||||||
|
return cp.flag
|
||||||
}
|
}
|
||||||
|
|
||||||
func (cp *compatibleProvider) MarshalJSON() ([]byte, error) {
|
func (cp *compatibleProvider) MarshalJSON() ([]byte, error) {
|
||||||
|
|
|
@ -70,6 +70,7 @@ type ProxyProvider interface {
|
||||||
// Commonly used in DialContext and DialPacketConn
|
// Commonly used in DialContext and DialPacketConn
|
||||||
ProxiesWithTouch() []constant.Proxy
|
ProxiesWithTouch() []constant.Proxy
|
||||||
HealthCheck()
|
HealthCheck()
|
||||||
|
Flag() uint
|
||||||
}
|
}
|
||||||
|
|
||||||
// Rule Type
|
// Rule Type
|
||||||
|
|
Loading…
Reference in a new issue