github.com/metacubex/mihomo@v1.18.5/adapter/provider/parser.go (about)

     1  package provider
     2  
     3  import (
     4  	"errors"
     5  	"fmt"
     6  	"time"
     7  
     8  	"github.com/metacubex/mihomo/common/structure"
     9  	"github.com/metacubex/mihomo/common/utils"
    10  	"github.com/metacubex/mihomo/component/resource"
    11  	C "github.com/metacubex/mihomo/constant"
    12  	"github.com/metacubex/mihomo/constant/features"
    13  	types "github.com/metacubex/mihomo/constant/provider"
    14  )
    15  
    16  var (
    17  	errVehicleType = errors.New("unsupport vehicle type")
    18  	errSubPath     = errors.New("path is not subpath of home directory")
    19  )
    20  
    21  type healthCheckSchema struct {
    22  	Enable         bool   `provider:"enable"`
    23  	URL            string `provider:"url"`
    24  	Interval       int    `provider:"interval"`
    25  	TestTimeout    int    `provider:"timeout,omitempty"`
    26  	Lazy           bool   `provider:"lazy,omitempty"`
    27  	ExpectedStatus string `provider:"expected-status,omitempty"`
    28  }
    29  
    30  type OverrideSchema struct {
    31  	UDP              *bool   `provider:"udp,omitempty"`
    32  	Up               *string `provider:"up,omitempty"`
    33  	Down             *string `provider:"down,omitempty"`
    34  	DialerProxy      *string `provider:"dialer-proxy,omitempty"`
    35  	SkipCertVerify   *bool   `provider:"skip-cert-verify,omitempty"`
    36  	Interface        *string `provider:"interface-name,omitempty"`
    37  	RoutingMark      *int    `provider:"routing-mark,omitempty"`
    38  	IPVersion        *string `provider:"ip-version,omitempty"`
    39  	AdditionalPrefix *string `provider:"additional-prefix,omitempty"`
    40  	AdditionalSuffix *string `provider:"additional-suffix,omitempty"`
    41  }
    42  
    43  type proxyProviderSchema struct {
    44  	Type          string `provider:"type"`
    45  	Path          string `provider:"path,omitempty"`
    46  	URL           string `provider:"url,omitempty"`
    47  	Proxy         string `provider:"proxy,omitempty"`
    48  	Interval      int    `provider:"interval,omitempty"`
    49  	Filter        string `provider:"filter,omitempty"`
    50  	ExcludeFilter string `provider:"exclude-filter,omitempty"`
    51  	ExcludeType   string `provider:"exclude-type,omitempty"`
    52  	DialerProxy   string `provider:"dialer-proxy,omitempty"`
    53  
    54  	HealthCheck healthCheckSchema   `provider:"health-check,omitempty"`
    55  	Override    OverrideSchema      `provider:"override,omitempty"`
    56  	Header      map[string][]string `provider:"header,omitempty"`
    57  }
    58  
    59  func ParseProxyProvider(name string, mapping map[string]any) (types.ProxyProvider, error) {
    60  	decoder := structure.NewDecoder(structure.Option{TagName: "provider", WeaklyTypedInput: true})
    61  
    62  	schema := &proxyProviderSchema{
    63  		HealthCheck: healthCheckSchema{
    64  			Lazy: true,
    65  		},
    66  	}
    67  	if err := decoder.Decode(mapping, schema); err != nil {
    68  		return nil, err
    69  	}
    70  
    71  	expectedStatus, err := utils.NewUnsignedRanges[uint16](schema.HealthCheck.ExpectedStatus)
    72  	if err != nil {
    73  		return nil, err
    74  	}
    75  
    76  	var hcInterval uint
    77  	if schema.HealthCheck.Enable {
    78  		if schema.HealthCheck.Interval == 0 {
    79  			schema.HealthCheck.Interval = 300
    80  		}
    81  		hcInterval = uint(schema.HealthCheck.Interval)
    82  	}
    83  	hc := NewHealthCheck([]C.Proxy{}, schema.HealthCheck.URL, uint(schema.HealthCheck.TestTimeout), hcInterval, schema.HealthCheck.Lazy, expectedStatus)
    84  
    85  	var vehicle types.Vehicle
    86  	switch schema.Type {
    87  	case "file":
    88  		path := C.Path.Resolve(schema.Path)
    89  		vehicle = resource.NewFileVehicle(path)
    90  	case "http":
    91  		path := C.Path.GetPathByHash("proxies", schema.URL)
    92  		if schema.Path != "" {
    93  			path = C.Path.Resolve(schema.Path)
    94  			if !features.CMFA && !C.Path.IsSafePath(path) {
    95  				return nil, fmt.Errorf("%w: %s", errSubPath, path)
    96  			}
    97  		}
    98  		vehicle = resource.NewHTTPVehicle(schema.URL, path, schema.Proxy, schema.Header)
    99  	default:
   100  		return nil, fmt.Errorf("%w: %s", errVehicleType, schema.Type)
   101  	}
   102  
   103  	interval := time.Duration(uint(schema.Interval)) * time.Second
   104  	filter := schema.Filter
   105  	excludeFilter := schema.ExcludeFilter
   106  	excludeType := schema.ExcludeType
   107  	dialerProxy := schema.DialerProxy
   108  	override := schema.Override
   109  
   110  	return NewProxySetProvider(name, interval, filter, excludeFilter, excludeType, dialerProxy, override, vehicle, hc)
   111  }