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

View File

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

View File

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

View File

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

View File

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