github.com/kelleygo/clashcore@v1.0.2/rules/provider/parse.go (about)

     1  package provider
     2  
     3  import (
     4  	"errors"
     5  	"fmt"
     6  	"time"
     7  
     8  	"github.com/kelleygo/clashcore/common/structure"
     9  	"github.com/kelleygo/clashcore/component/resource"
    10  	C "github.com/kelleygo/clashcore/constant"
    11  	"github.com/kelleygo/clashcore/constant/features"
    12  	P "github.com/kelleygo/clashcore/constant/provider"
    13  )
    14  
    15  var (
    16  	errSubPath = errors.New("path is not subpath of home directory")
    17  )
    18  
    19  type ruleProviderSchema struct {
    20  	Type     string `provider:"type"`
    21  	Behavior string `provider:"behavior"`
    22  	Path     string `provider:"path,omitempty"`
    23  	URL      string `provider:"url,omitempty"`
    24  	Proxy    string `provider:"proxy,omitempty"`
    25  	Format   string `provider:"format,omitempty"`
    26  	Interval int    `provider:"interval,omitempty"`
    27  }
    28  
    29  func ParseRuleProvider(name string, mapping map[string]interface{}, parse func(tp, payload, target string, params []string, subRules map[string][]C.Rule) (parsed C.Rule, parseErr error)) (P.RuleProvider, error) {
    30  	schema := &ruleProviderSchema{}
    31  	decoder := structure.NewDecoder(structure.Option{TagName: "provider", WeaklyTypedInput: true})
    32  	if err := decoder.Decode(mapping, schema); err != nil {
    33  		return nil, err
    34  	}
    35  	var behavior P.RuleBehavior
    36  
    37  	switch schema.Behavior {
    38  	case "domain":
    39  		behavior = P.Domain
    40  	case "ipcidr":
    41  		behavior = P.IPCIDR
    42  	case "classical":
    43  		behavior = P.Classical
    44  	default:
    45  		return nil, fmt.Errorf("unsupported behavior type: %s", schema.Behavior)
    46  	}
    47  
    48  	var format P.RuleFormat
    49  
    50  	switch schema.Format {
    51  	case "", "yaml":
    52  		format = P.YamlRule
    53  	case "text":
    54  		format = P.TextRule
    55  	default:
    56  		return nil, fmt.Errorf("unsupported format type: %s", schema.Format)
    57  	}
    58  
    59  	var vehicle P.Vehicle
    60  	switch schema.Type {
    61  	case "file":
    62  		path := C.Path.Resolve(schema.Path)
    63  		vehicle = resource.NewFileVehicle(path)
    64  	case "http":
    65  		path := C.Path.GetPathByHash("rules", schema.URL)
    66  		if schema.Path != "" {
    67  			path = C.Path.Resolve(schema.Path)
    68  			if !features.CMFA && !C.Path.IsSafePath(path) {
    69  				return nil, fmt.Errorf("%w: %s", errSubPath, path)
    70  			}
    71  		}
    72  		vehicle = resource.NewHTTPVehicle(schema.URL, path, schema.Proxy, nil)
    73  	default:
    74  		return nil, fmt.Errorf("unsupported vehicle type: %s", schema.Type)
    75  	}
    76  
    77  	return NewRuleSetProvider(name, behavior, format, time.Duration(uint(schema.Interval))*time.Second, vehicle, parse), nil
    78  }