github.com/Mrs4s/go-cqhttp@v1.2.0/modules/filter/filter.go (about)

     1  // Package filter implements an event filter for go-cqhttp
     2  package filter
     3  
     4  import (
     5  	"regexp"
     6  	"strings"
     7  
     8  	"github.com/tidwall/gjson"
     9  )
    10  
    11  // Filter 定义了一个消息上报过滤接口
    12  type Filter interface {
    13  	Eval(payload gjson.Result) bool
    14  }
    15  
    16  type operationNode struct {
    17  	key    string
    18  	filter Filter
    19  }
    20  
    21  // notOperator 定义了过滤器中Not操作符
    22  type notOperator struct {
    23  	operand Filter
    24  }
    25  
    26  func newNotOp(argument gjson.Result) Filter {
    27  	if !argument.IsObject() {
    28  		panic("the argument of 'not' operator must be an object")
    29  	}
    30  	return &notOperator{operand: Generate("and", argument)}
    31  }
    32  
    33  // Eval 对payload执行Not过滤
    34  func (op *notOperator) Eval(payload gjson.Result) bool {
    35  	return !op.operand.Eval(payload)
    36  }
    37  
    38  // andOperator 定义了过滤器中And操作符
    39  type andOperator struct {
    40  	operands []operationNode
    41  }
    42  
    43  func newAndOp(argument gjson.Result) Filter {
    44  	if !argument.IsObject() {
    45  		panic("the argument of 'and' operator must be an object")
    46  	}
    47  	op := new(andOperator)
    48  	argument.ForEach(func(key, value gjson.Result) bool {
    49  		switch {
    50  		case key.Str[0] == '.':
    51  			// is an operator
    52  			//   ".foo": {
    53  			//       "bar": "baz"
    54  			//   }
    55  			opKey := key.Str[1:]
    56  			op.operands = append(op.operands, operationNode{"", Generate(opKey, value)})
    57  		case value.IsObject():
    58  			// is a normal key with an object as the value
    59  			//   "foo": {
    60  			//       ".bar": "baz"
    61  			//   }
    62  			opKey := key.String()
    63  			op.operands = append(op.operands, operationNode{opKey, Generate("and", value)})
    64  		default:
    65  			// is a normal key with a non-object as the value
    66  			//   "foo": "bar"
    67  			opKey := key.String()
    68  			op.operands = append(op.operands, operationNode{opKey, Generate("eq", value)})
    69  		}
    70  		return true
    71  	})
    72  	return op
    73  }
    74  
    75  // Eval 对payload执行And过滤
    76  func (op *andOperator) Eval(payload gjson.Result) bool {
    77  	res := true
    78  	for _, operand := range op.operands {
    79  		if len(operand.key) == 0 {
    80  			// is an operator
    81  			res = res && operand.filter.Eval(payload)
    82  		} else {
    83  			// is a normal key
    84  			val := payload.Get(operand.key)
    85  			res = res && operand.filter.Eval(val)
    86  		}
    87  
    88  		if !res {
    89  			break
    90  		}
    91  	}
    92  	return res
    93  }
    94  
    95  // orOperator 定义了过滤器中Or操作符
    96  type orOperator struct {
    97  	operands []Filter
    98  }
    99  
   100  func newOrOp(argument gjson.Result) Filter {
   101  	if !argument.IsArray() {
   102  		panic("the argument of 'or' operator must be an array")
   103  	}
   104  	op := new(orOperator)
   105  	argument.ForEach(func(_, value gjson.Result) bool {
   106  		op.operands = append(op.operands, Generate("and", value))
   107  		return true
   108  	})
   109  	return op
   110  }
   111  
   112  // Eval 对payload执行Or过滤
   113  func (op *orOperator) Eval(payload gjson.Result) bool {
   114  	res := false
   115  	for _, operand := range op.operands {
   116  		res = res || operand.Eval(payload)
   117  		if res {
   118  			break
   119  		}
   120  	}
   121  	return res
   122  }
   123  
   124  // eqOperator 定义了过滤器中Equal操作符
   125  type eqOperator struct {
   126  	operand string
   127  }
   128  
   129  func newEqOp(argument gjson.Result) Filter {
   130  	return &eqOperator{operand: argument.String()}
   131  }
   132  
   133  // Eval 对payload执行Equal过滤
   134  func (op *eqOperator) Eval(payload gjson.Result) bool {
   135  	return payload.String() == op.operand
   136  }
   137  
   138  // neqOperator 定义了过滤器中NotEqual操作符
   139  type neqOperator struct {
   140  	operand string
   141  }
   142  
   143  func newNeqOp(argument gjson.Result) Filter {
   144  	return &neqOperator{operand: argument.String()}
   145  }
   146  
   147  // Eval 对payload执行NotEqual过滤
   148  func (op *neqOperator) Eval(payload gjson.Result) bool {
   149  	return !(payload.String() == op.operand)
   150  }
   151  
   152  // inOperator 定义了过滤器中In操作符
   153  type inOperator struct {
   154  	operandString string
   155  	operandArray  []string
   156  }
   157  
   158  func newInOp(argument gjson.Result) Filter {
   159  	if argument.IsObject() {
   160  		panic("the argument of 'in' operator must be an array or a string")
   161  	}
   162  	op := new(inOperator)
   163  	if argument.IsArray() {
   164  		op.operandArray = []string{}
   165  		argument.ForEach(func(_, value gjson.Result) bool {
   166  			op.operandArray = append(op.operandArray, value.String())
   167  			return true
   168  		})
   169  	} else {
   170  		op.operandString = argument.String()
   171  	}
   172  	return op
   173  }
   174  
   175  // Eval 对payload执行In过滤
   176  func (op *inOperator) Eval(payload gjson.Result) bool {
   177  	payloadStr := payload.String()
   178  	if op.operandArray != nil {
   179  		for _, value := range op.operandArray {
   180  			if value == payloadStr {
   181  				return true
   182  			}
   183  		}
   184  		return false
   185  	}
   186  	return strings.Contains(op.operandString, payloadStr)
   187  }
   188  
   189  // containsOperator 定义了过滤器中Contains操作符
   190  type containsOperator struct {
   191  	operand string
   192  }
   193  
   194  func newContainOp(argument gjson.Result) Filter {
   195  	if argument.IsArray() || argument.IsObject() {
   196  		panic("the argument of 'contains' operator must be a string")
   197  	}
   198  	return &containsOperator{operand: argument.String()}
   199  }
   200  
   201  // Eval 对payload执行Contains过滤
   202  func (op *containsOperator) Eval(payload gjson.Result) bool {
   203  	return strings.Contains(payload.String(), op.operand)
   204  }
   205  
   206  // regexOperator 定义了过滤器中Regex操作符
   207  type regexOperator struct {
   208  	regex *regexp.Regexp
   209  }
   210  
   211  func newRegexOp(argument gjson.Result) Filter {
   212  	if argument.IsArray() || argument.IsObject() {
   213  		panic("the argument of 'regex' operator must be a string")
   214  	}
   215  	return &regexOperator{regex: regexp.MustCompile(argument.String())}
   216  }
   217  
   218  // Eval 对payload执行RegexO过滤
   219  func (op *regexOperator) Eval(payload gjson.Result) bool {
   220  	return op.regex.MatchString(payload.String())
   221  }
   222  
   223  // Generate 根据给定操作符名opName及操作符参数argument创建一个过滤器实例
   224  func Generate(opName string, argument gjson.Result) Filter {
   225  	switch opName {
   226  	case "not":
   227  		return newNotOp(argument)
   228  	case "and":
   229  		return newAndOp(argument)
   230  	case "or":
   231  		return newOrOp(argument)
   232  	case "eq":
   233  		return newEqOp(argument)
   234  	case "neq":
   235  		return newNeqOp(argument)
   236  	case "in":
   237  		return newInOp(argument)
   238  	case "contains":
   239  		return newContainOp(argument)
   240  	case "regex":
   241  		return newRegexOp(argument)
   242  	default:
   243  		panic("the operator " + opName + " is not supported")
   244  	}
   245  }