diff --git a/adapter/outboundgroup/urltest.go b/adapter/outboundgroup/urltest.go index 64ce17f6..f3426a3e 100644 --- a/adapter/outboundgroup/urltest.go +++ b/adapter/outboundgroup/urltest.go @@ -3,6 +3,7 @@ package outboundgroup import ( "context" "encoding/json" + "errors" "time" "github.com/Dreamacro/clash/adapter/outbound" @@ -24,6 +25,8 @@ func urlTestWithTolerance(tolerance uint16) urlTestOption { type URLTest struct { *GroupBase + selected string + testUrl string tolerance uint16 disableUDP bool fastNode C.Proxy @@ -34,6 +37,22 @@ func (u *URLTest) Now() string { return u.fast(false).Name() } +func (u *URLTest) Set(name string) error { + var p C.Proxy + for _, proxy := range u.GetProxies(false) { + if proxy.Name() == name { + p = proxy + break + } + } + if p == nil { + return errors.New("proxy not exist") + } + u.selected = name + u.fast(false) + return nil +} + // DialContext implements C.ProxyAdapter func (u *URLTest) DialContext(ctx context.Context, metadata *C.Metadata, opts ...dialer.Option) (c C.Conn, err error) { proxy := u.fast(true) @@ -74,16 +93,24 @@ func (u *URLTest) Unwrap(metadata *C.Metadata, touch bool) C.Proxy { func (u *URLTest) fast(touch bool) C.Proxy { elm, _, shared := u.fastSingle.Do(func() (C.Proxy, error) { + var s C.Proxy proxies := u.GetProxies(touch) fast := proxies[0] + if fast.Name() == u.selected { + s = fast + } min := fast.LastDelay() fastNotExist := true for _, proxy := range proxies[1:] { + if u.fastNode != nil && proxy.Name() == u.fastNode.Name() { fastNotExist = false } + if proxy.Name() == u.selected { + s = proxy + } if !proxy.Alive() { continue } @@ -94,12 +121,15 @@ func (u *URLTest) fast(touch bool) C.Proxy { min = delay } } - // tolerance if u.fastNode == nil || fastNotExist || !u.fastNode.Alive() || u.fastNode.LastDelay() > fast.LastDelay()+u.tolerance { u.fastNode = fast } - + if s != nil { + if s.Alive() && s.LastDelay() < fast.LastDelay()+u.tolerance { + u.fastNode = s + } + } return u.fastNode, nil }) if shared && touch { // a shared fastSingle.Do() may cause providers untouched, so we touch them again @@ -114,7 +144,6 @@ func (u *URLTest) SupportUDP() bool { if u.disableUDP { return false } - return u.fast(false).SupportUDP() } @@ -161,6 +190,7 @@ func NewURLTest(option *GroupCommonOption, providers []provider.ProxyProvider, o }), fastSingle: singledo.NewSingle[C.Proxy](time.Second * 10), disableUDP: option.DisableUDP, + testUrl: option.URL, } for _, option := range options {