mirror of
https://gitclone.com/github.com/MetaCubeX/Clash.Meta
synced 2025-02-23 20:52:15 +08:00
feat: support inline proxy provider
This commit is contained in:
parent
20739f5db7
commit
72a126e580
@ -67,6 +67,7 @@ type proxyProviderSchema struct {
|
|||||||
ExcludeType string `provider:"exclude-type,omitempty"`
|
ExcludeType string `provider:"exclude-type,omitempty"`
|
||||||
DialerProxy string `provider:"dialer-proxy,omitempty"`
|
DialerProxy string `provider:"dialer-proxy,omitempty"`
|
||||||
SizeLimit int64 `provider:"size-limit,omitempty"`
|
SizeLimit int64 `provider:"size-limit,omitempty"`
|
||||||
|
Payload []map[string]any `provider:"payload,omitempty"`
|
||||||
|
|
||||||
HealthCheck healthCheckSchema `provider:"health-check,omitempty"`
|
HealthCheck healthCheckSchema `provider:"health-check,omitempty"`
|
||||||
Override OverrideSchema `provider:"override,omitempty"`
|
Override OverrideSchema `provider:"override,omitempty"`
|
||||||
@ -99,6 +100,11 @@ func ParseProxyProvider(name string, mapping map[string]any) (types.ProxyProvide
|
|||||||
}
|
}
|
||||||
hc := NewHealthCheck([]C.Proxy{}, schema.HealthCheck.URL, uint(schema.HealthCheck.TestTimeout), hcInterval, schema.HealthCheck.Lazy, expectedStatus)
|
hc := NewHealthCheck([]C.Proxy{}, schema.HealthCheck.URL, uint(schema.HealthCheck.TestTimeout), hcInterval, schema.HealthCheck.Lazy, expectedStatus)
|
||||||
|
|
||||||
|
parser, err := NewProxiesParser(schema.Filter, schema.ExcludeFilter, schema.ExcludeType, schema.DialerProxy, schema.Override)
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
|
||||||
var vehicle types.Vehicle
|
var vehicle types.Vehicle
|
||||||
switch schema.Type {
|
switch schema.Type {
|
||||||
case "file":
|
case "file":
|
||||||
@ -113,16 +119,13 @@ func ParseProxyProvider(name string, mapping map[string]any) (types.ProxyProvide
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
vehicle = resource.NewHTTPVehicle(schema.URL, path, schema.Proxy, schema.Header, resource.DefaultHttpTimeout, schema.SizeLimit)
|
vehicle = resource.NewHTTPVehicle(schema.URL, path, schema.Proxy, schema.Header, resource.DefaultHttpTimeout, schema.SizeLimit)
|
||||||
|
case "inline":
|
||||||
|
return NewInlineProvider(name, schema.Payload, parser, hc)
|
||||||
default:
|
default:
|
||||||
return nil, fmt.Errorf("%w: %s", errVehicleType, schema.Type)
|
return nil, fmt.Errorf("%w: %s", errVehicleType, schema.Type)
|
||||||
}
|
}
|
||||||
|
|
||||||
interval := time.Duration(uint(schema.Interval)) * time.Second
|
interval := time.Duration(uint(schema.Interval)) * time.Second
|
||||||
filter := schema.Filter
|
|
||||||
excludeFilter := schema.ExcludeFilter
|
|
||||||
excludeType := schema.ExcludeType
|
|
||||||
dialerProxy := schema.DialerProxy
|
|
||||||
override := schema.Override
|
|
||||||
|
|
||||||
return NewProxySetProvider(name, interval, filter, excludeFilter, excludeType, dialerProxy, override, vehicle, hc)
|
return NewProxySetProvider(name, interval, parser, vehicle, hc)
|
||||||
}
|
}
|
||||||
|
@ -4,6 +4,7 @@ import (
|
|||||||
"encoding/json"
|
"encoding/json"
|
||||||
"errors"
|
"errors"
|
||||||
"fmt"
|
"fmt"
|
||||||
|
"net/http"
|
||||||
"reflect"
|
"reflect"
|
||||||
"runtime"
|
"runtime"
|
||||||
"strings"
|
"strings"
|
||||||
@ -30,44 +31,101 @@ type ProxySchema struct {
|
|||||||
Proxies []map[string]any `yaml:"proxies"`
|
Proxies []map[string]any `yaml:"proxies"`
|
||||||
}
|
}
|
||||||
|
|
||||||
|
type providerForApi struct {
|
||||||
|
Name string `json:"name"`
|
||||||
|
Type string `json:"type"`
|
||||||
|
VehicleType string `json:"vehicleType"`
|
||||||
|
Proxies []C.Proxy `json:"proxies"`
|
||||||
|
TestUrl string `json:"testUrl"`
|
||||||
|
ExpectedStatus string `json:"expectedStatus"`
|
||||||
|
UpdatedAt time.Time `json:"updatedAt,omitempty"`
|
||||||
|
SubscriptionInfo *SubscriptionInfo `json:"subscriptionInfo,omitempty"`
|
||||||
|
}
|
||||||
|
|
||||||
|
type baseProvider struct {
|
||||||
|
name string
|
||||||
|
proxies []C.Proxy
|
||||||
|
healthCheck *HealthCheck
|
||||||
|
version uint32
|
||||||
|
}
|
||||||
|
|
||||||
|
func (bp *baseProvider) Name() string {
|
||||||
|
return bp.name
|
||||||
|
}
|
||||||
|
|
||||||
|
func (bp *baseProvider) Version() uint32 {
|
||||||
|
return bp.version
|
||||||
|
}
|
||||||
|
|
||||||
|
func (bp *baseProvider) HealthCheck() {
|
||||||
|
bp.healthCheck.check()
|
||||||
|
}
|
||||||
|
|
||||||
|
func (bp *baseProvider) Type() types.ProviderType {
|
||||||
|
return types.Proxy
|
||||||
|
}
|
||||||
|
|
||||||
|
func (bp *baseProvider) Proxies() []C.Proxy {
|
||||||
|
return bp.proxies
|
||||||
|
}
|
||||||
|
|
||||||
|
func (bp *baseProvider) Count() int {
|
||||||
|
return len(bp.proxies)
|
||||||
|
}
|
||||||
|
|
||||||
|
func (bp *baseProvider) Touch() {
|
||||||
|
bp.healthCheck.touch()
|
||||||
|
}
|
||||||
|
|
||||||
|
func (bp *baseProvider) HealthCheckURL() string {
|
||||||
|
return bp.healthCheck.url
|
||||||
|
}
|
||||||
|
|
||||||
|
func (bp *baseProvider) RegisterHealthCheckTask(url string, expectedStatus utils.IntRanges[uint16], filter string, interval uint) {
|
||||||
|
bp.healthCheck.registerHealthCheckTask(url, expectedStatus, filter, interval)
|
||||||
|
}
|
||||||
|
|
||||||
|
func (bp *baseProvider) setProxies(proxies []C.Proxy) {
|
||||||
|
bp.proxies = proxies
|
||||||
|
bp.healthCheck.setProxy(proxies)
|
||||||
|
if bp.healthCheck.auto() {
|
||||||
|
go bp.healthCheck.check()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func (bp *baseProvider) Close() error {
|
||||||
|
bp.healthCheck.close()
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
// ProxySetProvider for auto gc
|
// ProxySetProvider for auto gc
|
||||||
type ProxySetProvider struct {
|
type ProxySetProvider struct {
|
||||||
*proxySetProvider
|
*proxySetProvider
|
||||||
}
|
}
|
||||||
|
|
||||||
type proxySetProvider struct {
|
type proxySetProvider struct {
|
||||||
|
baseProvider
|
||||||
*resource.Fetcher[[]C.Proxy]
|
*resource.Fetcher[[]C.Proxy]
|
||||||
proxies []C.Proxy
|
|
||||||
healthCheck *HealthCheck
|
|
||||||
version uint32
|
|
||||||
subscriptionInfo *SubscriptionInfo
|
subscriptionInfo *SubscriptionInfo
|
||||||
}
|
}
|
||||||
|
|
||||||
func (pp *proxySetProvider) MarshalJSON() ([]byte, error) {
|
func (pp *proxySetProvider) MarshalJSON() ([]byte, error) {
|
||||||
return json.Marshal(map[string]any{
|
return json.Marshal(providerForApi{
|
||||||
"name": pp.Name(),
|
Name: pp.Name(),
|
||||||
"type": pp.Type().String(),
|
Type: pp.Type().String(),
|
||||||
"vehicleType": pp.VehicleType().String(),
|
VehicleType: pp.VehicleType().String(),
|
||||||
"proxies": pp.Proxies(),
|
Proxies: pp.Proxies(),
|
||||||
"testUrl": pp.healthCheck.url,
|
TestUrl: pp.healthCheck.url,
|
||||||
"expectedStatus": pp.healthCheck.expectedStatus.String(),
|
ExpectedStatus: pp.healthCheck.expectedStatus.String(),
|
||||||
"updatedAt": pp.UpdatedAt(),
|
UpdatedAt: pp.UpdatedAt(),
|
||||||
"subscriptionInfo": pp.subscriptionInfo,
|
SubscriptionInfo: pp.subscriptionInfo,
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
func (pp *proxySetProvider) Version() uint32 {
|
|
||||||
return pp.version
|
|
||||||
}
|
|
||||||
|
|
||||||
func (pp *proxySetProvider) Name() string {
|
func (pp *proxySetProvider) Name() string {
|
||||||
return pp.Fetcher.Name()
|
return pp.Fetcher.Name()
|
||||||
}
|
}
|
||||||
|
|
||||||
func (pp *proxySetProvider) HealthCheck() {
|
|
||||||
pp.healthCheck.check()
|
|
||||||
}
|
|
||||||
|
|
||||||
func (pp *proxySetProvider) Update() error {
|
func (pp *proxySetProvider) Update() error {
|
||||||
_, _, err := pp.Fetcher.Update()
|
_, _, err := pp.Fetcher.Update()
|
||||||
return err
|
return err
|
||||||
@ -79,54 +137,12 @@ func (pp *proxySetProvider) Initial() error {
|
|||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
if subscriptionInfo := cachefile.Cache().GetSubscriptionInfo(pp.Name()); subscriptionInfo != "" {
|
if subscriptionInfo := cachefile.Cache().GetSubscriptionInfo(pp.Name()); subscriptionInfo != "" {
|
||||||
pp.SetSubscriptionInfo(subscriptionInfo)
|
pp.subscriptionInfo.Update(subscriptionInfo)
|
||||||
}
|
}
|
||||||
pp.closeAllConnections()
|
pp.closeAllConnections()
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func (pp *proxySetProvider) Type() types.ProviderType {
|
|
||||||
return types.Proxy
|
|
||||||
}
|
|
||||||
|
|
||||||
func (pp *proxySetProvider) Proxies() []C.Proxy {
|
|
||||||
return pp.proxies
|
|
||||||
}
|
|
||||||
|
|
||||||
func (pp *proxySetProvider) Count() int {
|
|
||||||
return len(pp.proxies)
|
|
||||||
}
|
|
||||||
|
|
||||||
func (pp *proxySetProvider) Touch() {
|
|
||||||
pp.healthCheck.touch()
|
|
||||||
}
|
|
||||||
|
|
||||||
func (pp *proxySetProvider) HealthCheckURL() string {
|
|
||||||
return pp.healthCheck.url
|
|
||||||
}
|
|
||||||
|
|
||||||
func (pp *proxySetProvider) RegisterHealthCheckTask(url string, expectedStatus utils.IntRanges[uint16], filter string, interval uint) {
|
|
||||||
pp.healthCheck.registerHealthCheckTask(url, expectedStatus, filter, interval)
|
|
||||||
}
|
|
||||||
|
|
||||||
func (pp *proxySetProvider) setProxies(proxies []C.Proxy) {
|
|
||||||
pp.proxies = proxies
|
|
||||||
pp.healthCheck.setProxy(proxies)
|
|
||||||
if pp.healthCheck.auto() {
|
|
||||||
go pp.healthCheck.check()
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
func (pp *proxySetProvider) SetSubscriptionInfo(userInfo string) {
|
|
||||||
pp.subscriptionInfo = NewSubscriptionInfo(userInfo)
|
|
||||||
}
|
|
||||||
|
|
||||||
func (pp *proxySetProvider) SetProvider(provider types.ProxyProvider) {
|
|
||||||
if httpVehicle, ok := pp.Vehicle().(*resource.HTTPVehicle); ok {
|
|
||||||
httpVehicle.SetProvider(provider)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
func (pp *proxySetProvider) closeAllConnections() {
|
func (pp *proxySetProvider) closeAllConnections() {
|
||||||
statistic.DefaultManager.Range(func(c statistic.Tracker) bool {
|
statistic.DefaultManager.Range(func(c statistic.Tracker) bool {
|
||||||
for _, chain := range c.Chains() {
|
for _, chain := range c.Chains() {
|
||||||
@ -140,44 +156,37 @@ func (pp *proxySetProvider) closeAllConnections() {
|
|||||||
}
|
}
|
||||||
|
|
||||||
func (pp *proxySetProvider) Close() error {
|
func (pp *proxySetProvider) Close() error {
|
||||||
pp.healthCheck.close()
|
_ = pp.baseProvider.Close()
|
||||||
return pp.Fetcher.Close()
|
return pp.Fetcher.Close()
|
||||||
}
|
}
|
||||||
|
|
||||||
func NewProxySetProvider(name string, interval time.Duration, filter string, excludeFilter string, excludeType string, dialerProxy string, override OverrideSchema, vehicle types.Vehicle, hc *HealthCheck) (*ProxySetProvider, error) {
|
func NewProxySetProvider(name string, interval time.Duration, parser resource.Parser[[]C.Proxy], vehicle types.Vehicle, hc *HealthCheck) (*ProxySetProvider, error) {
|
||||||
excludeFilterReg, err := regexp2.Compile(excludeFilter, regexp2.None)
|
|
||||||
if err != nil {
|
|
||||||
return nil, fmt.Errorf("invalid excludeFilter regex: %w", err)
|
|
||||||
}
|
|
||||||
var excludeTypeArray []string
|
|
||||||
if excludeType != "" {
|
|
||||||
excludeTypeArray = strings.Split(excludeType, "|")
|
|
||||||
}
|
|
||||||
|
|
||||||
var filterRegs []*regexp2.Regexp
|
|
||||||
for _, filter := range strings.Split(filter, "`") {
|
|
||||||
filterReg, err := regexp2.Compile(filter, regexp2.None)
|
|
||||||
if err != nil {
|
|
||||||
return nil, fmt.Errorf("invalid filter regex: %w", err)
|
|
||||||
}
|
|
||||||
filterRegs = append(filterRegs, filterReg)
|
|
||||||
}
|
|
||||||
|
|
||||||
if hc.auto() {
|
if hc.auto() {
|
||||||
go hc.process()
|
go hc.process()
|
||||||
}
|
}
|
||||||
|
|
||||||
|
si := new(SubscriptionInfo)
|
||||||
pd := &proxySetProvider{
|
pd := &proxySetProvider{
|
||||||
|
baseProvider: baseProvider{
|
||||||
|
name: name,
|
||||||
proxies: []C.Proxy{},
|
proxies: []C.Proxy{},
|
||||||
healthCheck: hc,
|
healthCheck: hc,
|
||||||
|
},
|
||||||
|
subscriptionInfo: si,
|
||||||
}
|
}
|
||||||
|
|
||||||
fetcher := resource.NewFetcher[[]C.Proxy](name, interval, vehicle, proxiesParseAndFilter(filter, excludeFilter, excludeTypeArray, filterRegs, excludeFilterReg, dialerProxy, override), proxiesOnUpdate(pd))
|
fetcher := resource.NewFetcher[[]C.Proxy](name, interval, vehicle, parser, proxiesOnUpdate(pd))
|
||||||
pd.Fetcher = fetcher
|
pd.Fetcher = fetcher
|
||||||
wrapper := &ProxySetProvider{pd}
|
|
||||||
if httpVehicle, ok := vehicle.(*resource.HTTPVehicle); ok {
|
if httpVehicle, ok := vehicle.(*resource.HTTPVehicle); ok {
|
||||||
httpVehicle.SetProvider(wrapper)
|
httpVehicle.SetInRead(func(resp *http.Response) {
|
||||||
|
if subscriptionInfo := resp.Header.Get("subscription-userinfo"); subscriptionInfo != "" {
|
||||||
|
cachefile.Cache().SetSubscriptionInfo(name, subscriptionInfo)
|
||||||
|
si.Update(subscriptionInfo)
|
||||||
}
|
}
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
wrapper := &ProxySetProvider{pd}
|
||||||
runtime.SetFinalizer(wrapper, (*ProxySetProvider).Close)
|
runtime.SetFinalizer(wrapper, (*ProxySetProvider).Close)
|
||||||
return wrapper, nil
|
return wrapper, nil
|
||||||
}
|
}
|
||||||
@ -187,8 +196,73 @@ func (pp *ProxySetProvider) Close() error {
|
|||||||
return pp.proxySetProvider.Close()
|
return pp.proxySetProvider.Close()
|
||||||
}
|
}
|
||||||
|
|
||||||
func (pp *ProxySetProvider) SetProvider(provider types.ProxyProvider) {
|
// InlineProvider for auto gc
|
||||||
pp.proxySetProvider.SetProvider(provider)
|
type InlineProvider struct {
|
||||||
|
*inlineProvider
|
||||||
|
}
|
||||||
|
|
||||||
|
type inlineProvider struct {
|
||||||
|
baseProvider
|
||||||
|
updateAt time.Time
|
||||||
|
}
|
||||||
|
|
||||||
|
func (ip *inlineProvider) MarshalJSON() ([]byte, error) {
|
||||||
|
return json.Marshal(providerForApi{
|
||||||
|
Name: ip.Name(),
|
||||||
|
Type: ip.Type().String(),
|
||||||
|
VehicleType: ip.VehicleType().String(),
|
||||||
|
Proxies: ip.Proxies(),
|
||||||
|
TestUrl: ip.healthCheck.url,
|
||||||
|
ExpectedStatus: ip.healthCheck.expectedStatus.String(),
|
||||||
|
UpdatedAt: ip.updateAt,
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
func (ip *inlineProvider) VehicleType() types.VehicleType {
|
||||||
|
return types.Inline
|
||||||
|
}
|
||||||
|
|
||||||
|
func (ip *inlineProvider) Initial() error {
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func (ip *inlineProvider) Update() error {
|
||||||
|
// make api update happy
|
||||||
|
ip.updateAt = time.Now()
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func NewInlineProvider(name string, payload []map[string]any, parser resource.Parser[[]C.Proxy], hc *HealthCheck) (*InlineProvider, error) {
|
||||||
|
if hc.auto() {
|
||||||
|
go hc.process()
|
||||||
|
}
|
||||||
|
|
||||||
|
ps := ProxySchema{Proxies: payload}
|
||||||
|
buf, err := yaml.Marshal(ps)
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
proxies, err := parser(buf)
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
|
||||||
|
ip := &inlineProvider{
|
||||||
|
baseProvider: baseProvider{
|
||||||
|
name: name,
|
||||||
|
proxies: proxies,
|
||||||
|
healthCheck: hc,
|
||||||
|
},
|
||||||
|
updateAt: time.Now(),
|
||||||
|
}
|
||||||
|
wrapper := &InlineProvider{ip}
|
||||||
|
runtime.SetFinalizer(wrapper, (*InlineProvider).Close)
|
||||||
|
return wrapper, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func (ip *InlineProvider) Close() error {
|
||||||
|
runtime.SetFinalizer(ip, nil)
|
||||||
|
return ip.baseProvider.Close()
|
||||||
}
|
}
|
||||||
|
|
||||||
// CompatibleProvider for auto gc
|
// CompatibleProvider for auto gc
|
||||||
@ -197,36 +271,20 @@ type CompatibleProvider struct {
|
|||||||
}
|
}
|
||||||
|
|
||||||
type compatibleProvider struct {
|
type compatibleProvider struct {
|
||||||
name string
|
baseProvider
|
||||||
healthCheck *HealthCheck
|
|
||||||
subscriptionInfo *SubscriptionInfo
|
|
||||||
proxies []C.Proxy
|
|
||||||
version uint32
|
|
||||||
}
|
}
|
||||||
|
|
||||||
func (cp *compatibleProvider) MarshalJSON() ([]byte, error) {
|
func (cp *compatibleProvider) MarshalJSON() ([]byte, error) {
|
||||||
return json.Marshal(map[string]any{
|
return json.Marshal(providerForApi{
|
||||||
"name": cp.Name(),
|
Name: cp.Name(),
|
||||||
"type": cp.Type().String(),
|
Type: cp.Type().String(),
|
||||||
"vehicleType": cp.VehicleType().String(),
|
VehicleType: cp.VehicleType().String(),
|
||||||
"proxies": cp.Proxies(),
|
Proxies: cp.Proxies(),
|
||||||
"testUrl": cp.healthCheck.url,
|
TestUrl: cp.healthCheck.url,
|
||||||
"expectedStatus": cp.healthCheck.expectedStatus.String(),
|
ExpectedStatus: cp.healthCheck.expectedStatus.String(),
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
func (cp *compatibleProvider) Version() uint32 {
|
|
||||||
return cp.version
|
|
||||||
}
|
|
||||||
|
|
||||||
func (cp *compatibleProvider) Name() string {
|
|
||||||
return cp.name
|
|
||||||
}
|
|
||||||
|
|
||||||
func (cp *compatibleProvider) HealthCheck() {
|
|
||||||
cp.healthCheck.check()
|
|
||||||
}
|
|
||||||
|
|
||||||
func (cp *compatibleProvider) Update() error {
|
func (cp *compatibleProvider) Update() error {
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
@ -242,39 +300,6 @@ func (cp *compatibleProvider) VehicleType() types.VehicleType {
|
|||||||
return types.Compatible
|
return types.Compatible
|
||||||
}
|
}
|
||||||
|
|
||||||
func (cp *compatibleProvider) Type() types.ProviderType {
|
|
||||||
return types.Proxy
|
|
||||||
}
|
|
||||||
|
|
||||||
func (cp *compatibleProvider) Proxies() []C.Proxy {
|
|
||||||
return cp.proxies
|
|
||||||
}
|
|
||||||
|
|
||||||
func (cp *compatibleProvider) Count() int {
|
|
||||||
return len(cp.proxies)
|
|
||||||
}
|
|
||||||
|
|
||||||
func (cp *compatibleProvider) Touch() {
|
|
||||||
cp.healthCheck.touch()
|
|
||||||
}
|
|
||||||
|
|
||||||
func (cp *compatibleProvider) HealthCheckURL() string {
|
|
||||||
return cp.healthCheck.url
|
|
||||||
}
|
|
||||||
|
|
||||||
func (cp *compatibleProvider) RegisterHealthCheckTask(url string, expectedStatus utils.IntRanges[uint16], filter string, interval uint) {
|
|
||||||
cp.healthCheck.registerHealthCheckTask(url, expectedStatus, filter, interval)
|
|
||||||
}
|
|
||||||
|
|
||||||
func (cp *compatibleProvider) Close() error {
|
|
||||||
cp.healthCheck.close()
|
|
||||||
return nil
|
|
||||||
}
|
|
||||||
|
|
||||||
func (cp *compatibleProvider) SetSubscriptionInfo(userInfo string) {
|
|
||||||
cp.subscriptionInfo = NewSubscriptionInfo(userInfo)
|
|
||||||
}
|
|
||||||
|
|
||||||
func NewCompatibleProvider(name string, proxies []C.Proxy, hc *HealthCheck) (*CompatibleProvider, error) {
|
func NewCompatibleProvider(name string, proxies []C.Proxy, hc *HealthCheck) (*CompatibleProvider, error) {
|
||||||
if len(proxies) == 0 {
|
if len(proxies) == 0 {
|
||||||
return nil, errors.New("provider need one proxy at least")
|
return nil, errors.New("provider need one proxy at least")
|
||||||
@ -285,9 +310,11 @@ func NewCompatibleProvider(name string, proxies []C.Proxy, hc *HealthCheck) (*Co
|
|||||||
}
|
}
|
||||||
|
|
||||||
pd := &compatibleProvider{
|
pd := &compatibleProvider{
|
||||||
|
baseProvider: baseProvider{
|
||||||
name: name,
|
name: name,
|
||||||
proxies: proxies,
|
proxies: proxies,
|
||||||
healthCheck: hc,
|
healthCheck: hc,
|
||||||
|
},
|
||||||
}
|
}
|
||||||
|
|
||||||
wrapper := &CompatibleProvider{pd}
|
wrapper := &CompatibleProvider{pd}
|
||||||
@ -307,7 +334,25 @@ func proxiesOnUpdate(pd *proxySetProvider) func([]C.Proxy) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
func proxiesParseAndFilter(filter string, excludeFilter string, excludeTypeArray []string, filterRegs []*regexp2.Regexp, excludeFilterReg *regexp2.Regexp, dialerProxy string, override OverrideSchema) resource.Parser[[]C.Proxy] {
|
func NewProxiesParser(filter string, excludeFilter string, excludeType string, dialerProxy string, override OverrideSchema) (resource.Parser[[]C.Proxy], error) {
|
||||||
|
excludeFilterReg, err := regexp2.Compile(excludeFilter, regexp2.None)
|
||||||
|
if err != nil {
|
||||||
|
return nil, fmt.Errorf("invalid excludeFilter regex: %w", err)
|
||||||
|
}
|
||||||
|
var excludeTypeArray []string
|
||||||
|
if excludeType != "" {
|
||||||
|
excludeTypeArray = strings.Split(excludeType, "|")
|
||||||
|
}
|
||||||
|
|
||||||
|
var filterRegs []*regexp2.Regexp
|
||||||
|
for _, filter := range strings.Split(filter, "`") {
|
||||||
|
filterReg, err := regexp2.Compile(filter, regexp2.None)
|
||||||
|
if err != nil {
|
||||||
|
return nil, fmt.Errorf("invalid filter regex: %w", err)
|
||||||
|
}
|
||||||
|
filterRegs = append(filterRegs, filterReg)
|
||||||
|
}
|
||||||
|
|
||||||
return func(buf []byte) ([]C.Proxy, error) {
|
return func(buf []byte) ([]C.Proxy, error) {
|
||||||
schema := &ProxySchema{}
|
schema := &ProxySchema{}
|
||||||
|
|
||||||
@ -422,5 +467,5 @@ func proxiesParseAndFilter(filter string, excludeFilter string, excludeTypeArray
|
|||||||
}
|
}
|
||||||
|
|
||||||
return proxies, nil
|
return proxies, nil
|
||||||
}
|
}, nil
|
||||||
}
|
}
|
||||||
|
@ -15,9 +15,8 @@ type SubscriptionInfo struct {
|
|||||||
Expire int64
|
Expire int64
|
||||||
}
|
}
|
||||||
|
|
||||||
func NewSubscriptionInfo(userinfo string) (si *SubscriptionInfo) {
|
func (info *SubscriptionInfo) Update(userinfo string) {
|
||||||
userinfo = strings.ReplaceAll(strings.ToLower(userinfo), " ", "")
|
userinfo = strings.ReplaceAll(strings.ToLower(userinfo), " ", "")
|
||||||
si = new(SubscriptionInfo)
|
|
||||||
|
|
||||||
for _, field := range strings.Split(userinfo, ";") {
|
for _, field := range strings.Split(userinfo, ";") {
|
||||||
name, value, ok := strings.Cut(field, "=")
|
name, value, ok := strings.Cut(field, "=")
|
||||||
@ -33,17 +32,15 @@ func NewSubscriptionInfo(userinfo string) (si *SubscriptionInfo) {
|
|||||||
|
|
||||||
switch name {
|
switch name {
|
||||||
case "upload":
|
case "upload":
|
||||||
si.Upload = intValue
|
info.Upload = intValue
|
||||||
case "download":
|
case "download":
|
||||||
si.Download = intValue
|
info.Download = intValue
|
||||||
case "total":
|
case "total":
|
||||||
si.Total = intValue
|
info.Total = intValue
|
||||||
case "expire":
|
case "expire":
|
||||||
si.Expire = intValue
|
info.Expire = intValue
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
return si
|
|
||||||
}
|
}
|
||||||
|
|
||||||
func parseValue(value string) (int64, error) {
|
func parseValue(value string) (int64, error) {
|
||||||
|
@ -90,6 +90,7 @@ type HTTPVehicle struct {
|
|||||||
header http.Header
|
header http.Header
|
||||||
timeout time.Duration
|
timeout time.Duration
|
||||||
sizeLimit int64
|
sizeLimit int64
|
||||||
|
inRead func(response *http.Response)
|
||||||
provider types.ProxyProvider
|
provider types.ProxyProvider
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -113,8 +114,8 @@ func (h *HTTPVehicle) Write(buf []byte) error {
|
|||||||
return safeWrite(h.path, buf)
|
return safeWrite(h.path, buf)
|
||||||
}
|
}
|
||||||
|
|
||||||
func (h *HTTPVehicle) SetProvider(provider types.ProxyProvider) {
|
func (h *HTTPVehicle) SetInRead(fn func(response *http.Response)) {
|
||||||
h.provider = provider
|
h.inRead = fn
|
||||||
}
|
}
|
||||||
|
|
||||||
func (h *HTTPVehicle) Read(ctx context.Context, oldHash utils.HashType) (buf []byte, hash utils.HashType, err error) {
|
func (h *HTTPVehicle) Read(ctx context.Context, oldHash utils.HashType) (buf []byte, hash utils.HashType, err error) {
|
||||||
@ -140,9 +141,8 @@ func (h *HTTPVehicle) Read(ctx context.Context, oldHash utils.HashType) (buf []b
|
|||||||
}
|
}
|
||||||
defer resp.Body.Close()
|
defer resp.Body.Close()
|
||||||
|
|
||||||
if subscriptionInfo := resp.Header.Get("subscription-userinfo"); h.provider != nil && subscriptionInfo != "" {
|
if h.inRead != nil {
|
||||||
cachefile.Cache().SetSubscriptionInfo(h.provider.Name(), subscriptionInfo)
|
h.inRead(resp)
|
||||||
h.provider.SetSubscriptionInfo(subscriptionInfo)
|
|
||||||
}
|
}
|
||||||
|
|
||||||
if resp.StatusCode < 200 || resp.StatusCode > 299 {
|
if resp.StatusCode < 200 || resp.StatusCode > 299 {
|
||||||
|
@ -84,7 +84,6 @@ type ProxyProvider interface {
|
|||||||
Version() uint32
|
Version() uint32
|
||||||
RegisterHealthCheckTask(url string, expectedStatus utils.IntRanges[uint16], filter string, interval uint)
|
RegisterHealthCheckTask(url string, expectedStatus utils.IntRanges[uint16], filter string, interval uint)
|
||||||
HealthCheckURL() string
|
HealthCheckURL() string
|
||||||
SetSubscriptionInfo(userInfo string)
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// RuleProvider interface
|
// RuleProvider interface
|
||||||
|
@ -975,6 +975,17 @@ proxy-providers:
|
|||||||
# - pattern: "IPLC-(.*?)倍"
|
# - pattern: "IPLC-(.*?)倍"
|
||||||
# target: "iplc x $1"
|
# target: "iplc x $1"
|
||||||
|
|
||||||
|
provider2:
|
||||||
|
type: inline
|
||||||
|
dialer-proxy: proxy
|
||||||
|
payload:
|
||||||
|
- name: "ss1"
|
||||||
|
type: ss
|
||||||
|
server: server
|
||||||
|
port: 443
|
||||||
|
cipher: chacha20-ietf-poly1305
|
||||||
|
password: "password"
|
||||||
|
|
||||||
test:
|
test:
|
||||||
type: file
|
type: file
|
||||||
path: /test.yaml
|
path: /test.yaml
|
||||||
|
Loading…
Reference in New Issue
Block a user