Feature: add filter
option to proxy group (#2518)
This commit is contained in:
parent
20a521f02d
commit
9b2b7c662d
@ -3,6 +3,7 @@ package outboundgroup
|
|||||||
import (
|
import (
|
||||||
"errors"
|
"errors"
|
||||||
"fmt"
|
"fmt"
|
||||||
|
"regexp"
|
||||||
|
|
||||||
"github.com/Dreamacro/clash/adapter/outbound"
|
"github.com/Dreamacro/clash/adapter/outbound"
|
||||||
"github.com/Dreamacro/clash/adapter/provider"
|
"github.com/Dreamacro/clash/adapter/provider"
|
||||||
@ -29,6 +30,7 @@ type GroupCommonOption struct {
|
|||||||
Interval int `group:"interval,omitempty"`
|
Interval int `group:"interval,omitempty"`
|
||||||
Lazy bool `group:"lazy,omitempty"`
|
Lazy bool `group:"lazy,omitempty"`
|
||||||
DisableUDP bool `group:"disable-udp,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) {
|
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
|
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 {
|
if len(groupOption.Proxies) == 0 && len(groupOption.Use) == 0 {
|
||||||
return nil, fmt.Errorf("%s: %w", groupName, errMissProxy)
|
return nil, fmt.Errorf("%s: %w", groupName, errMissProxy)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
providers := []types.ProxyProvider{}
|
||||||
|
|
||||||
if len(groupOption.Proxies) != 0 {
|
if len(groupOption.Proxies) != 0 {
|
||||||
ps, err := getProxies(proxyMap, groupOption.Proxies)
|
ps, err := getProxies(proxyMap, groupOption.Proxies)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
@ -94,7 +107,12 @@ func ParseProxyGroup(config map[string]any, proxyMap map[string]C.Proxy, provide
|
|||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, fmt.Errorf("%s: %w", groupName, err)
|
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
|
var group C.ProxyAdapter
|
||||||
|
@ -9,12 +9,17 @@ import (
|
|||||||
"time"
|
"time"
|
||||||
|
|
||||||
"github.com/Dreamacro/clash/adapter"
|
"github.com/Dreamacro/clash/adapter"
|
||||||
|
"github.com/Dreamacro/clash/adapter/outbound"
|
||||||
|
"github.com/Dreamacro/clash/common/singledo"
|
||||||
C "github.com/Dreamacro/clash/constant"
|
C "github.com/Dreamacro/clash/constant"
|
||||||
types "github.com/Dreamacro/clash/constant/provider"
|
types "github.com/Dreamacro/clash/constant/provider"
|
||||||
|
|
||||||
|
"github.com/samber/lo"
|
||||||
"gopkg.in/yaml.v3"
|
"gopkg.in/yaml.v3"
|
||||||
)
|
)
|
||||||
|
|
||||||
|
var reject = adapter.NewProxy(outbound.NewReject())
|
||||||
|
|
||||||
const (
|
const (
|
||||||
ReservedName = "default"
|
ReservedName = "default"
|
||||||
)
|
)
|
||||||
@ -231,3 +236,77 @@ func NewCompatibleProvider(name string, proxies []C.Proxy, hc *HealthCheck) (*Co
|
|||||||
runtime.SetFinalizer(wrapper, stopCompatibleProvider)
|
runtime.SetFinalizer(wrapper, stopCompatibleProvider)
|
||||||
return wrapper, nil
|
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…
x
Reference in New Issue
Block a user