github.com/yaling888/clash@v1.53.0/component/script/expr_matcher.go (about)

     1  package script
     2  
     3  import (
     4  	"fmt"
     5  
     6  	"github.com/expr-lang/expr"
     7  	"github.com/expr-lang/expr/vm"
     8  	"github.com/expr-lang/expr/vm/runtime"
     9  
    10  	C "github.com/yaling888/clash/constant"
    11  )
    12  
    13  var inStringPatch = &stringInString{}
    14  
    15  var _ C.Matcher = (*ExprMatcher)(nil)
    16  
    17  type ExprMatcher struct {
    18  	name    string
    19  	hasNow  bool
    20  	program *vm.Program
    21  }
    22  
    23  func (e *ExprMatcher) Name() string {
    24  	return e.name
    25  }
    26  
    27  func (*ExprMatcher) Eval(*C.Metadata) (string, error) {
    28  	panic("unimplemented")
    29  }
    30  
    31  func (e *ExprMatcher) Match(mtd *C.Metadata) (bool, error) {
    32  	env := parseEnv(mtd, e.hasNow)
    33  
    34  	result, err := expr.Run(e.program, env)
    35  	if err != nil {
    36  		return false, err
    37  	}
    38  
    39  	if v, ok := result.(bool); ok {
    40  		return v, nil
    41  	}
    42  
    43  	return false, fmt.Errorf("invalid return type, got %T, want bool", result)
    44  }
    45  
    46  func NewExprMatcher(name, code string) (*ExprMatcher, error) {
    47  	options := []expr.Option{
    48  		expr.Env(shortcutEnvironment{}),
    49  		expr.Patch(inStringPatch),
    50  		expr.DisableBuiltin("now"),
    51  		expr.AsBool(),
    52  	}
    53  
    54  	program, err := expr.Compile(code, options...)
    55  	if err != nil {
    56  		return nil, fmt.Errorf("compile expr code error: %w", err)
    57  	}
    58  
    59  	var hasNow bool
    60  	for _, m := range program.Constants {
    61  		if f, ok := m.(*runtime.Field); ok {
    62  			if l := len(f.Path); l != 0 && f.Path[0] == "now" {
    63  				hasNow = true
    64  				break
    65  			}
    66  		}
    67  	}
    68  
    69  	return &ExprMatcher{
    70  		name:    name,
    71  		hasNow:  hasNow,
    72  		program: program,
    73  	}, nil
    74  }