mirror of https://github.com/Dreamacro/clash.git
Feature: add `filter` option to proxy group (#2518)
This commit is contained in:
parent
20a521f02d
commit
9b2b7c662d
|
@ -3,6 +3,7 @@ package outboundgroup
|
|||
import (
|
||||
"errors"
|
||||
"fmt"
|
||||
"regexp"
|
||||
|
||||
"github.com/Dreamacro/clash/adapter/outbound"
|
||||
"github.com/Dreamacro/clash/adapter/provider"
|
||||
|
@ -29,6 +30,7 @@ type GroupCommonOption struct {
|
|||
Interval int `group:"interval,omitempty"`
|
||||
Lazy bool `group:"lazy,omitempty"`
|
||||
DisableUDP bool `group:"disable-udp,omitempty"`
|
||||
Filter string `group:"filter,omitempty"`
|
||||
}
|
||||
|
||||
func ParseProxyGroup(config map[string]any, proxyMap map[string]C.Proxy, providersMap map[string]types.ProxyProvider) (C.ProxyAdapter, error) {
|
||||
|
@ -45,14 +47,25 @@ func ParseProxyGroup(config map[string]any, proxyMap map[string]C.Proxy, provide
|
|||
return nil, errFormat
|
||||
}
|
||||
|
||||
groupName := groupOption.Name
|
||||
var (
|
||||
groupName = groupOption.Name
|
||||
filterReg *regexp.Regexp
|
||||
)
|
||||
|
||||
providers := []types.ProxyProvider{}
|
||||
if groupOption.Filter != "" {
|
||||
f, err := regexp.Compile(groupOption.Filter)
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("%s: invalid filter regex: %w", groupName, err)
|
||||
}
|
||||
filterReg = f
|
||||
}
|
||||
|
||||
if len(groupOption.Proxies) == 0 && len(groupOption.Use) == 0 {
|
||||
return nil, fmt.Errorf("%s: %w", groupName, errMissProxy)
|
||||
}
|
||||
|
||||
providers := []types.ProxyProvider{}
|
||||
|
||||
if len(groupOption.Proxies) != 0 {
|
||||
ps, err := getProxies(proxyMap, groupOption.Proxies)
|
||||
if err != nil {
|
||||
|
@ -94,7 +107,12 @@ func ParseProxyGroup(config map[string]any, proxyMap map[string]C.Proxy, provide
|
|||
if err != nil {
|
||||
return nil, fmt.Errorf("%s: %w", groupName, err)
|
||||
}
|
||||
providers = append(providers, list...)
|
||||
if filterReg != nil {
|
||||
pd := provider.NewFilterableProvider(groupName, list, filterReg)
|
||||
providers = append(providers, pd)
|
||||
} else {
|
||||
providers = append(providers, list...)
|
||||
}
|
||||
}
|
||||
|
||||
var group C.ProxyAdapter
|
||||
|
|
|
@ -9,12 +9,17 @@ import (
|
|||
"time"
|
||||
|
||||
"github.com/Dreamacro/clash/adapter"
|
||||
"github.com/Dreamacro/clash/adapter/outbound"
|
||||
"github.com/Dreamacro/clash/common/singledo"
|
||||
C "github.com/Dreamacro/clash/constant"
|
||||
types "github.com/Dreamacro/clash/constant/provider"
|
||||
|
||||
"github.com/samber/lo"
|
||||
"gopkg.in/yaml.v3"
|
||||
)
|
||||
|
||||
var reject = adapter.NewProxy(outbound.NewReject())
|
||||
|
||||
const (
|
||||
ReservedName = "default"
|
||||
)
|
||||
|
@ -231,3 +236,77 @@ func NewCompatibleProvider(name string, proxies []C.Proxy, hc *HealthCheck) (*Co
|
|||
runtime.SetFinalizer(wrapper, stopCompatibleProvider)
|
||||
return wrapper, nil
|
||||
}
|
||||
|
||||
var _ types.ProxyProvider = (*FilterableProvider)(nil)
|
||||
|
||||
type FilterableProvider struct {
|
||||
name string
|
||||
providers []types.ProxyProvider
|
||||
filterReg *regexp.Regexp
|
||||
single *singledo.Single
|
||||
}
|
||||
|
||||
func (fp *FilterableProvider) MarshalJSON() ([]byte, error) {
|
||||
return json.Marshal(map[string]any{
|
||||
"name": fp.Name(),
|
||||
"type": fp.Type().String(),
|
||||
"vehicleType": fp.VehicleType().String(),
|
||||
"proxies": fp.Proxies(),
|
||||
})
|
||||
}
|
||||
|
||||
func (fp *FilterableProvider) Name() string {
|
||||
return fp.name
|
||||
}
|
||||
|
||||
func (fp *FilterableProvider) HealthCheck() {
|
||||
}
|
||||
|
||||
func (fp *FilterableProvider) Update() error {
|
||||
return nil
|
||||
}
|
||||
|
||||
func (fp *FilterableProvider) Initial() error {
|
||||
return nil
|
||||
}
|
||||
|
||||
func (fp *FilterableProvider) VehicleType() types.VehicleType {
|
||||
return types.Compatible
|
||||
}
|
||||
|
||||
func (fp *FilterableProvider) Type() types.ProviderType {
|
||||
return types.Proxy
|
||||
}
|
||||
|
||||
func (fp *FilterableProvider) Proxies() []C.Proxy {
|
||||
elm, _, _ := fp.single.Do(func() (any, error) {
|
||||
proxies := lo.FlatMap(
|
||||
fp.providers,
|
||||
func(item types.ProxyProvider, _ int) []C.Proxy {
|
||||
return lo.Filter(
|
||||
item.Proxies(),
|
||||
func(item C.Proxy, _ int) bool {
|
||||
return fp.filterReg.MatchString(item.Name())
|
||||
})
|
||||
})
|
||||
|
||||
if len(proxies) == 0 {
|
||||
proxies = append(proxies, reject)
|
||||
}
|
||||
return proxies, nil
|
||||
})
|
||||
|
||||
return elm.([]C.Proxy)
|
||||
}
|
||||
|
||||
func (fp *FilterableProvider) Touch() {
|
||||
}
|
||||
|
||||
func NewFilterableProvider(name string, providers []types.ProxyProvider, filterReg *regexp.Regexp) *FilterableProvider {
|
||||
return &FilterableProvider{
|
||||
name: name,
|
||||
providers: providers,
|
||||
filterReg: filterReg,
|
||||
single: singledo.NewSingle(time.Second * 10),
|
||||
}
|
||||
}
|
||||
|
|
Loading…
Reference in New Issue