github.com/yaling888/clash@v1.53.0/adapter/provider/parser.go (about)

     1  package provider
     2  
     3  import (
     4  	"errors"
     5  	"fmt"
     6  	"time"
     7  
     8  	"github.com/yaling888/clash/adapter"
     9  	"github.com/yaling888/clash/common/structure"
    10  	C "github.com/yaling888/clash/constant"
    11  	types "github.com/yaling888/clash/constant/provider"
    12  )
    13  
    14  var errVehicleType = errors.New("unsupport vehicle type")
    15  
    16  type healthCheckSchema struct {
    17  	Enable   bool          `provider:"enable"`
    18  	URL      string        `provider:"url"`
    19  	Interval time.Duration `provider:"interval"`
    20  	Lazy     bool          `provider:"lazy,omitempty"`
    21  }
    22  
    23  type proxyProviderSchema struct {
    24  	Type            string              `provider:"type"`
    25  	Path            string              `provider:"path"`
    26  	URL             string              `provider:"url,omitempty"`
    27  	URLProxy        bool                `provider:"url-proxy,omitempty"`
    28  	Interval        time.Duration       `provider:"interval,omitempty"`
    29  	Filter          string              `provider:"filter,omitempty"`
    30  	HealthCheck     healthCheckSchema   `provider:"health-check,omitempty"`
    31  	ForceCertVerify bool                `provider:"force-cert-verify,omitempty"`
    32  	UDP             bool                `provider:"udp,omitempty"`
    33  	DisableUDP      bool                `provider:"disable-udp,omitempty"`
    34  	DisableDNS      bool                `provider:"disable-dns,omitempty"`
    35  	RandomHost      bool                `provider:"rand-host,omitempty"`
    36  	PrefixName      string              `provider:"prefix-name,omitempty"`
    37  	Header          map[string][]string `provider:"header,omitempty"`
    38  }
    39  
    40  func ParseProxyProvider(name string, mapping map[string]any, _ bool) (types.ProxyProvider, error) {
    41  	decoder := structure.NewDecoder(structure.Option{TagName: "provider", WeaklyTypedInput: true})
    42  
    43  	globalForceCertVerify := true
    44  	schema := &proxyProviderSchema{
    45  		ForceCertVerify: globalForceCertVerify,
    46  		HealthCheck: healthCheckSchema{
    47  			Lazy: true,
    48  		},
    49  	}
    50  
    51  	if err := decoder.Decode(mapping, schema); err != nil {
    52  		return nil, err
    53  	}
    54  
    55  	var hcInterval time.Duration
    56  	if schema.HealthCheck.Enable {
    57  		hcInterval = schema.HealthCheck.Interval
    58  	}
    59  	hc := NewHealthCheck([]C.Proxy{}, schema.HealthCheck.URL, hcInterval, schema.HealthCheck.Lazy)
    60  
    61  	vehicle, err := newVehicle(schema)
    62  	if err != nil {
    63  		return nil, err
    64  	}
    65  
    66  	interval := schema.Interval
    67  	filter := schema.Filter
    68  	option := adapter.ProxyOption{
    69  		ForceCertVerify: schema.ForceCertVerify,
    70  		ForceUDP:        schema.UDP,
    71  		DisableUDP:      schema.DisableUDP,
    72  		DisableDNS:      schema.DisableDNS,
    73  		RandomHost:      schema.RandomHost,
    74  		PrefixName:      schema.PrefixName,
    75  		AutoCipher:      true,
    76  	}
    77  	return NewProxySetProvider(name, interval, filter, vehicle, hc, globalForceCertVerify, option)
    78  }
    79  
    80  func newVehicle(schema *proxyProviderSchema) (types.Vehicle, error) {
    81  	path := C.Path.Resolve(schema.Path)
    82  
    83  	switch schema.Type {
    84  	case "file":
    85  		return NewFileVehicle(path), nil
    86  	case "http":
    87  		if !C.Path.IsSubHomeDir(path) {
    88  			return nil, errors.New("the path is not a sub path of home directory")
    89  		}
    90  
    91  		if schema.Header == nil {
    92  			schema.Header = map[string][]string{
    93  				"User-Agent": {"ClashPlusPro/" + C.Version},
    94  			}
    95  		} else if _, ok := schema.Header["User-Agent"]; !ok {
    96  			schema.Header["User-Agent"] = []string{"ClashPlusPro/" + C.Version}
    97  		}
    98  
    99  		return NewHTTPVehicle(path, schema.URL, schema.URLProxy, schema.Header), nil
   100  	default:
   101  		return nil, fmt.Errorf("%w: %s", errVehicleType, schema.Type)
   102  	}
   103  }