Refactor: allow to add an empty proxy provider to proxy group

This commit is contained in:
yaling888 2022-06-22 04:36:27 +08:00
parent e31be4edc2
commit 1f12ef069b
7 changed files with 76 additions and 48 deletions

View File

@ -3,6 +3,8 @@ package outboundgroup
import ( import (
"time" "time"
"github.com/Dreamacro/clash/adapter"
"github.com/Dreamacro/clash/adapter/outbound"
C "github.com/Dreamacro/clash/constant" C "github.com/Dreamacro/clash/constant"
"github.com/Dreamacro/clash/constant/provider" "github.com/Dreamacro/clash/constant/provider"
) )
@ -11,14 +13,19 @@ const (
defaultGetProxiesDuration = time.Second * 5 defaultGetProxiesDuration = time.Second * 5
) )
var defaultRejectProxy = adapter.NewProxy(outbound.NewReject())
func getProvidersProxies(providers []provider.ProxyProvider, touch bool) []C.Proxy { func getProvidersProxies(providers []provider.ProxyProvider, touch bool) []C.Proxy {
proxies := []C.Proxy{} proxies := []C.Proxy{}
for _, provider := range providers { for _, pd := range providers {
if touch { if touch {
proxies = append(proxies, provider.ProxiesWithTouch()...) proxies = append(proxies, pd.ProxiesWithTouch()...)
} else { } else {
proxies = append(proxies, provider.Proxies()...) proxies = append(proxies, pd.Proxies()...)
} }
} }
if len(proxies) == 0 {
proxies = append(proxies, defaultRejectProxy)
}
return proxies return proxies
} }

View File

@ -78,30 +78,18 @@ func ParseProxyGroup(config map[string]any, proxyMap map[string]C.Proxy, provide
return nil, errDuplicateProvider return nil, errDuplicateProvider
} }
// select don't need health check hc, err := newHealthCheck(ps, groupOption)
if groupOption.Type == "select" || groupOption.Type == "relay" { if err != nil {
hc := provider.NewHealthCheck(ps, "", 0, true) return nil, err
pd, err := provider.NewCompatibleProvider(groupName, ps, hc)
if err != nil {
return nil, err
}
providers = append(providers, pd)
providersMap[groupName] = pd
} else {
if groupOption.URL == "" || groupOption.Interval == 0 {
return nil, errMissHealthCheck
}
hc := provider.NewHealthCheck(ps, groupOption.URL, uint(groupOption.Interval), groupOption.Lazy)
pd, err := provider.NewCompatibleProvider(groupName, ps, hc)
if err != nil {
return nil, err
}
providers = append(providers, pd)
providersMap[groupName] = pd
} }
pd, err := provider.NewCompatibleProvider(groupName, ps, hc)
if err != nil {
return nil, err
}
providers = append(providers, pd)
providersMap[groupName] = pd
} }
if len(groupOption.Use) != 0 { if len(groupOption.Use) != 0 {
@ -109,7 +97,12 @@ func ParseProxyGroup(config map[string]any, proxyMap map[string]C.Proxy, provide
if err != nil { if err != nil {
return nil, err return nil, err
} }
providers = append(providers, list...)
if groupOption.Type == "fallback" {
providers = append(list, providers...)
} else {
providers = append(providers, list...)
}
} }
var group C.ProxyAdapter var group C.ProxyAdapter
@ -163,22 +156,18 @@ func getProviders(mapping map[string]types.ProxyProvider, groupOption *GroupComm
} }
if filterRegx != nil { if filterRegx != nil {
var hc *provider.HealthCheck hc, err := newHealthCheck([]C.Proxy{}, groupOption)
if groupOption.Type == "select" || groupOption.Type == "relay" { if err != nil {
hc = provider.NewHealthCheck([]C.Proxy{}, "", 0, true) return nil, err
} else {
if groupOption.URL == "" || groupOption.Interval == 0 {
return nil, errMissHealthCheck
}
hc = provider.NewHealthCheck([]C.Proxy{}, groupOption.URL, uint(groupOption.Interval), groupOption.Lazy)
} }
if _, ok = mapping[groupName]; ok { gName := groupName
groupName += "->" + p.Name() if _, ok = mapping[gName]; ok {
gName = groupName + " -> " + p.Name()
} }
pd := p.(*provider.ProxySetProvider) pd := p.(*provider.ProxySetProvider)
p = provider.NewProxyFilterProvider(groupName, pd, hc, filterRegx) p = provider.NewProxyFilterProvider(gName, pd, hc, filterRegx)
pd.RegisterProvidersInUse(p) pd.RegisterProvidersInUse(p)
} }
@ -186,3 +175,18 @@ func getProviders(mapping map[string]types.ProxyProvider, groupOption *GroupComm
} }
return ps, nil return ps, nil
} }
func newHealthCheck(ps []C.Proxy, groupOption *GroupCommonOption) (*provider.HealthCheck, error) {
var hc *provider.HealthCheck
// select don't need health check
if groupOption.Type == "select" || groupOption.Type == "relay" {
hc = provider.NewHealthCheck(ps, "", 0, true)
} else {
if groupOption.URL == "" || groupOption.Interval == 0 {
return nil, errMissHealthCheck
}
hc = provider.NewHealthCheck(ps, groupOption.URL, uint(groupOption.Interval), groupOption.Lazy)
}
return hc, nil
}

View File

@ -98,7 +98,11 @@ func (s *Selector) selectedProxy(touch bool) C.Proxy {
} }
func NewSelector(option *GroupCommonOption, providers []provider.ProxyProvider) *Selector { func NewSelector(option *GroupCommonOption, providers []provider.ProxyProvider) *Selector {
selected := providers[0].Proxies()[0].Name() selected := "REJECT"
if len(providers) != 0 && len(providers[0].Proxies()) != 0 {
selected = providers[0].Proxies()[0].Name()
}
return &Selector{ return &Selector{
Base: outbound.NewBase(outbound.BaseOption{ Base: outbound.NewBase(outbound.BaseOption{
Name: option.Name, Name: option.Name,

View File

@ -10,7 +10,7 @@ import (
func ParseProxy(mapping map[string]any, forceCertVerify bool) (C.Proxy, error) { func ParseProxy(mapping map[string]any, forceCertVerify bool) (C.Proxy, error) {
decoder := structure.NewDecoder(structure.Option{TagName: "proxy", WeaklyTypedInput: true}) decoder := structure.NewDecoder(structure.Option{TagName: "proxy", WeaklyTypedInput: true})
proxyType, existType := mapping["type"].(string) proxyType, existType := mapping["type"]
if !existType { if !existType {
return nil, fmt.Errorf("missing type") return nil, fmt.Errorf("missing type")
} }
@ -19,7 +19,7 @@ func ParseProxy(mapping map[string]any, forceCertVerify bool) (C.Proxy, error) {
proxy C.ProxyAdapter proxy C.ProxyAdapter
err error err error
) )
switch proxyType { switch proxyType.(string) {
case "ss": case "ss":
ssOption := &outbound.ShadowSocksOption{} ssOption := &outbound.ShadowSocksOption{}
err = decoder.Decode(mapping, ssOption) err = decoder.Decode(mapping, ssOption)

View File

@ -25,10 +25,16 @@ type HealthCheck struct {
interval uint interval uint
lazy bool lazy bool
lastTouch *atomic.Int64 lastTouch *atomic.Int64
running *atomic.Bool
done chan struct{} done chan struct{}
} }
func (hc *HealthCheck) process() { func (hc *HealthCheck) process() {
if hc.running.Load() {
return
}
hc.running.Store(true)
ticker := time.NewTicker(time.Duration(hc.interval) * time.Second) ticker := time.NewTicker(time.Duration(hc.interval) * time.Second)
go func() { go func() {
@ -84,6 +90,10 @@ func (hc *HealthCheck) check() {
} }
func (hc *HealthCheck) close() { func (hc *HealthCheck) close() {
if !hc.running.Load() {
return
}
hc.running.Store(false)
hc.done <- struct{}{} hc.done <- struct{}{}
} }
@ -94,6 +104,7 @@ func NewHealthCheck(proxies []C.Proxy, url string, interval uint, lazy bool) *He
interval: interval, interval: interval,
lazy: lazy, lazy: lazy,
lastTouch: atomic.NewInt64(0), lastTouch: atomic.NewInt64(0),
running: atomic.NewBool(false),
done: make(chan struct{}, 1), done: make(chan struct{}, 1),
} }
} }

View File

@ -234,7 +234,9 @@ func (pf *proxyFilterProvider) HealthCheck() {
} }
func (pf *proxyFilterProvider) Update() error { func (pf *proxyFilterProvider) Update() error {
var proxies []C.Proxy pf.healthCheck.close()
proxies := []C.Proxy{}
if pf.filter != nil { if pf.filter != nil {
for _, proxy := range pf.psd.Proxies() { for _, proxy := range pf.psd.Proxies() {
if !pf.filter.MatchString(proxy.Name()) { if !pf.filter.MatchString(proxy.Name()) {
@ -248,6 +250,10 @@ func (pf *proxyFilterProvider) Update() error {
pf.proxies = proxies pf.proxies = proxies
pf.healthCheck.setProxy(proxies) pf.healthCheck.setProxy(proxies)
if len(proxies) != 0 && pf.healthCheck.auto() {
go pf.healthCheck.process()
}
return nil return nil
} }
@ -286,10 +292,6 @@ func NewProxyFilterProvider(name string, psd *ProxySetProvider, hc *HealthCheck,
_ = pd.Update() _ = pd.Update()
if hc.auto() {
go hc.process()
}
wrapper := &ProxyFilterProvider{pd} wrapper := &ProxyFilterProvider{pd}
runtime.SetFinalizer(wrapper, stopProxyFilterProvider) runtime.SetFinalizer(wrapper, stopProxyFilterProvider)
return wrapper return wrapper

View File

@ -415,11 +415,11 @@ func parseProxies(cfg *RawConfig) (proxies map[string]C.Proxy, providersMap map[
// keep the original order of ProxyGroups in config file // keep the original order of ProxyGroups in config file
for idx, mapping := range groupsConfig { for idx, mapping := range groupsConfig {
groupName, existName := mapping["name"].(string) groupName, existName := mapping["name"]
if !existName { if !existName {
return nil, nil, fmt.Errorf("proxy group %d: missing name", idx) return nil, nil, fmt.Errorf("proxy group %d: missing name", idx)
} }
proxyList = append(proxyList, groupName) proxyList = append(proxyList, groupName.(string))
} }
// check if any loop exists and sort the ProxyGroups // check if any loop exists and sort the ProxyGroups