diff --git a/adapter/provider/override.go b/adapter/provider/override.go new file mode 100644 index 00000000..e310458c --- /dev/null +++ b/adapter/provider/override.go @@ -0,0 +1,88 @@ +package provider + +import ( + "encoding" + "fmt" + + "github.com/dlclark/regexp2" +) + +type overrideSchema struct { + TFO *bool `provider:"tfo,omitempty"` + MPTcp *bool `provider:"mptcp,omitempty"` + UDP *bool `provider:"udp,omitempty"` + UDPOverTCP *bool `provider:"udp-over-tcp,omitempty"` + Up *string `provider:"up,omitempty"` + Down *string `provider:"down,omitempty"` + DialerProxy *string `provider:"dialer-proxy,omitempty"` + SkipCertVerify *bool `provider:"skip-cert-verify,omitempty"` + Interface *string `provider:"interface-name,omitempty"` + RoutingMark *int `provider:"routing-mark,omitempty"` + IPVersion *string `provider:"ip-version,omitempty"` + + AdditionalPrefix *string `provider:"additional-prefix,omitempty"` + AdditionalSuffix *string `provider:"additional-suffix,omitempty"` + ProxyName []overrideProxyNameSchema `provider:"proxy-name,omitempty"` +} + +type overrideProxyNameSchema struct { + // matching expression for regex replacement + Pattern *regexp2.Regexp `provider:"pattern"` + // the new content after regex matching + Target string `provider:"target"` +} + +var _ encoding.TextUnmarshaler = (*regexp2.Regexp)(nil) // ensure *regexp2.Regexp can decode direct by structure package + +func (o *overrideSchema) Apply(mapping map[string]any) error { + if o.TFO != nil { + mapping["tfo"] = *o.TFO + } + if o.MPTcp != nil { + mapping["mptcp"] = *o.MPTcp + } + if o.UDP != nil { + mapping["udp"] = *o.UDP + } + if o.UDPOverTCP != nil { + mapping["udp-over-tcp"] = *o.UDPOverTCP + } + if o.Up != nil { + mapping["up"] = *o.Up + } + if o.Down != nil { + mapping["down"] = *o.Down + } + if o.DialerProxy != nil { + mapping["dialer-proxy"] = *o.DialerProxy + } + if o.SkipCertVerify != nil { + mapping["skip-cert-verify"] = *o.SkipCertVerify + } + if o.Interface != nil { + mapping["interface"] = *o.Interface + } + if o.RoutingMark != nil { + mapping["routing-mark"] = *o.RoutingMark + } + if o.IPVersion != nil { + mapping["ip-version"] = *o.IPVersion + } + + for _, expr := range o.ProxyName { + name := mapping["name"].(string) + newName, err := expr.Pattern.Replace(name, expr.Target, 0, -1) + if err != nil { + return fmt.Errorf("proxy name replace error: %w", err) + } + mapping["name"] = newName + } + if o.AdditionalPrefix != nil { + mapping["name"] = fmt.Sprintf("%s%s", *o.AdditionalPrefix, mapping["name"]) + } + if o.AdditionalSuffix != nil { + mapping["name"] = fmt.Sprintf("%s%s", mapping["name"], *o.AdditionalSuffix) + } + + return nil +} diff --git a/adapter/provider/parser.go b/adapter/provider/parser.go index 6e0da678..f6200fdd 100644 --- a/adapter/provider/parser.go +++ b/adapter/provider/parser.go @@ -1,7 +1,6 @@ package provider import ( - "encoding" "errors" "fmt" "time" @@ -11,8 +10,6 @@ import ( "github.com/metacubex/mihomo/component/resource" C "github.com/metacubex/mihomo/constant" P "github.com/metacubex/mihomo/constant/provider" - - "github.com/dlclark/regexp2" ) var ( @@ -28,33 +25,6 @@ type healthCheckSchema struct { ExpectedStatus string `provider:"expected-status,omitempty"` } -type OverrideProxyNameSchema struct { - // matching expression for regex replacement - Pattern *regexp2.Regexp `provider:"pattern"` - // the new content after regex matching - Target string `provider:"target"` -} - -var _ encoding.TextUnmarshaler = (*regexp2.Regexp)(nil) // ensure *regexp2.Regexp can decode direct by structure package - -type OverrideSchema struct { - TFO *bool `provider:"tfo,omitempty"` - MPTcp *bool `provider:"mptcp,omitempty"` - UDP *bool `provider:"udp,omitempty"` - UDPOverTCP *bool `provider:"udp-over-tcp,omitempty"` - Up *string `provider:"up,omitempty"` - Down *string `provider:"down,omitempty"` - DialerProxy *string `provider:"dialer-proxy,omitempty"` - SkipCertVerify *bool `provider:"skip-cert-verify,omitempty"` - Interface *string `provider:"interface-name,omitempty"` - RoutingMark *int `provider:"routing-mark,omitempty"` - IPVersion *string `provider:"ip-version,omitempty"` - AdditionalPrefix *string `provider:"additional-prefix,omitempty"` - AdditionalSuffix *string `provider:"additional-suffix,omitempty"` - - ProxyName []OverrideProxyNameSchema `provider:"proxy-name,omitempty"` -} - type proxyProviderSchema struct { Type string `provider:"type"` Path string `provider:"path,omitempty"` @@ -69,7 +39,7 @@ type proxyProviderSchema struct { Payload []map[string]any `provider:"payload,omitempty"` HealthCheck healthCheckSchema `provider:"health-check,omitempty"` - Override OverrideSchema `provider:"override,omitempty"` + Override overrideSchema `provider:"override,omitempty"` Header map[string][]string `provider:"header,omitempty"` } diff --git a/adapter/provider/provider.go b/adapter/provider/provider.go index c9007892..1faa2147 100644 --- a/adapter/provider/provider.go +++ b/adapter/provider/provider.go @@ -4,7 +4,6 @@ import ( "encoding/json" "errors" "fmt" - "reflect" "runtime" "strings" "sync" @@ -340,7 +339,7 @@ func (cp *CompatibleProvider) Close() error { return cp.compatibleProvider.Close() } -func NewProxiesParser(pdName string, filter string, excludeFilter string, excludeType string, dialerProxy string, override OverrideSchema) (resource.Parser[[]C.Proxy], error) { +func NewProxiesParser(pdName string, filter string, excludeFilter string, excludeType string, dialerProxy string, override overrideSchema) (resource.Parser[[]C.Proxy], error) { var excludeTypeArray []string if excludeType != "" { excludeTypeArray = strings.Split(excludeType, "|") @@ -429,33 +428,9 @@ func NewProxiesParser(pdName string, filter string, excludeFilter string, exclud mapping["dialer-proxy"] = dialerProxy } - val := reflect.ValueOf(override) - for i := 0; i < val.NumField(); i++ { - field := val.Field(i) - if field.IsNil() { - continue - } - fieldName := strings.Split(val.Type().Field(i).Tag.Get("provider"), ",")[0] - switch fieldName { - case "additional-prefix": - name := mapping["name"].(string) - mapping["name"] = *field.Interface().(*string) + name - case "additional-suffix": - name := mapping["name"].(string) - mapping["name"] = name + *field.Interface().(*string) - case "proxy-name": - // Iterate through all naming replacement rules and perform the replacements. - for _, expr := range override.ProxyName { - name := mapping["name"].(string) - newName, err := expr.Pattern.Replace(name, expr.Target, 0, -1) - if err != nil { - return nil, fmt.Errorf("proxy name replace error: %w", err) - } - mapping["name"] = newName - } - default: - mapping[fieldName] = field.Elem().Interface() - } + err := override.Apply(mapping) + if err != nil { + return nil, fmt.Errorf("proxy %d override error: %w", idx, err) } proxy, err := adapter.ParseProxy(mapping, adapter.WithProviderName(pdName))