mirror of
https://github.com/Mrs4s/go-cqhttp.git
synced 2025-05-05 03:23:49 +08:00
253 lines
5.6 KiB
Go
253 lines
5.6 KiB
Go
package global
|
|
|
|
import (
|
|
"io/ioutil"
|
|
"regexp"
|
|
"strings"
|
|
|
|
log "github.com/sirupsen/logrus"
|
|
"github.com/tidwall/gjson"
|
|
)
|
|
|
|
type Filter interface {
|
|
Eval(payload gjson.Result) bool
|
|
}
|
|
|
|
type OperationNode struct {
|
|
key string
|
|
filter Filter
|
|
}
|
|
|
|
type NotOperator struct {
|
|
operand_ Filter
|
|
}
|
|
|
|
func notOperatorConstruct(argument gjson.Result) *NotOperator {
|
|
if !argument.IsObject() {
|
|
panic("the argument of 'not' operator must be an object")
|
|
}
|
|
op := new(NotOperator)
|
|
op.operand_ = Generate("and", argument)
|
|
return op
|
|
}
|
|
|
|
func (notOperator NotOperator) Eval(payload gjson.Result) bool {
|
|
return !(notOperator.operand_).Eval(payload)
|
|
}
|
|
|
|
type AndOperator struct {
|
|
operands []OperationNode
|
|
}
|
|
|
|
func andOperatorConstruct(argument gjson.Result) *AndOperator {
|
|
if !argument.IsObject() {
|
|
panic("the argument of 'and' operator must be an object")
|
|
}
|
|
op := new(AndOperator)
|
|
argument.ForEach(func(key, value gjson.Result) bool {
|
|
if key.Str[0] == '.' {
|
|
// is an operator
|
|
// ".foo": {
|
|
// "bar": "baz"
|
|
// }
|
|
opKey := key.Str[1:]
|
|
op.operands = append(op.operands, OperationNode{"", Generate(opKey, value)})
|
|
} else if value.IsObject() {
|
|
// is an normal key with an object as the value
|
|
// "foo": {
|
|
// ".bar": "baz"
|
|
// }
|
|
opKey := key.String()
|
|
op.operands = append(op.operands, OperationNode{opKey, Generate("and", value)})
|
|
} else {
|
|
// is an normal key with a non-object as the value
|
|
// "foo": "bar"
|
|
opKey := key.String()
|
|
op.operands = append(op.operands, OperationNode{opKey, Generate("eq", value)})
|
|
}
|
|
return true
|
|
})
|
|
return op
|
|
}
|
|
|
|
func (andOperator *AndOperator) Eval(payload gjson.Result) bool {
|
|
res := true
|
|
for _, operand := range andOperator.operands {
|
|
|
|
if len(operand.key) == 0 {
|
|
// is an operator
|
|
res = res && operand.filter.Eval(payload)
|
|
} else {
|
|
// is an normal key
|
|
val := payload.Get(operand.key)
|
|
res = res && operand.filter.Eval(val)
|
|
}
|
|
|
|
if res == false {
|
|
break
|
|
}
|
|
}
|
|
return res
|
|
}
|
|
|
|
type OrOperator struct {
|
|
operands []Filter
|
|
}
|
|
|
|
func orOperatorConstruct(argument gjson.Result) *OrOperator {
|
|
if !argument.IsArray() {
|
|
panic("the argument of 'or' operator must be an array")
|
|
}
|
|
op := new(OrOperator)
|
|
argument.ForEach(func(_, value gjson.Result) bool {
|
|
op.operands = append(op.operands, Generate("and", value))
|
|
return true
|
|
})
|
|
return op
|
|
}
|
|
|
|
func (orOperator OrOperator) Eval(payload gjson.Result) bool {
|
|
res := false
|
|
for _, operand := range orOperator.operands {
|
|
res = res || operand.Eval(payload)
|
|
|
|
if res == true {
|
|
break
|
|
}
|
|
}
|
|
return res
|
|
}
|
|
|
|
type EqualOperator struct {
|
|
value gjson.Result
|
|
}
|
|
|
|
func equalOperatorConstruct(argument gjson.Result) *EqualOperator {
|
|
op := new(EqualOperator)
|
|
op.value = argument
|
|
return op
|
|
}
|
|
|
|
func (equalOperator EqualOperator) Eval(payload gjson.Result) bool {
|
|
return payload.String() == equalOperator.value.String()
|
|
}
|
|
|
|
type NotEqualOperator struct {
|
|
value gjson.Result
|
|
}
|
|
|
|
func notEqualOperatorConstruct(argument gjson.Result) *NotEqualOperator {
|
|
op := new(NotEqualOperator)
|
|
op.value = argument
|
|
return op
|
|
}
|
|
|
|
func (notEqualOperator NotEqualOperator) Eval(payload gjson.Result) bool {
|
|
return !(payload.String() == notEqualOperator.value.String())
|
|
}
|
|
|
|
type InOperator struct {
|
|
operand gjson.Result
|
|
}
|
|
|
|
func inOperatorConstruct(argument gjson.Result) *InOperator {
|
|
if argument.IsObject() {
|
|
panic("the argument of 'in' operator must be an array or a string")
|
|
}
|
|
op := new(InOperator)
|
|
op.operand = argument
|
|
return op
|
|
}
|
|
|
|
func (inOperator InOperator) Eval(payload gjson.Result) bool {
|
|
if inOperator.operand.IsArray() {
|
|
res := false
|
|
inOperator.operand.ForEach(func(key, value gjson.Result) bool {
|
|
res = res || value.String() == payload.String()
|
|
return true
|
|
})
|
|
return res
|
|
}
|
|
return strings.Contains(inOperator.operand.String(), payload.String())
|
|
}
|
|
|
|
type ContainsOperator struct {
|
|
operand string
|
|
}
|
|
|
|
func containsOperatorConstruct(argument gjson.Result) *ContainsOperator {
|
|
if argument.IsArray() || argument.IsObject() {
|
|
panic("the argument of 'contains' operator must be a string")
|
|
}
|
|
op := new(ContainsOperator)
|
|
op.operand = argument.String()
|
|
return op
|
|
}
|
|
|
|
func (containsOperator ContainsOperator) Eval(payload gjson.Result) bool {
|
|
if payload.IsObject() || payload.IsArray() {
|
|
return false
|
|
}
|
|
return strings.Contains(payload.String(), containsOperator.operand)
|
|
}
|
|
|
|
type RegexOperator struct {
|
|
regex string
|
|
}
|
|
|
|
func regexOperatorConstruct(argument gjson.Result) *RegexOperator {
|
|
if argument.IsArray() || argument.IsObject() {
|
|
panic("the argument of 'regex' operator must be a string")
|
|
}
|
|
op := new(RegexOperator)
|
|
op.regex = argument.String()
|
|
return op
|
|
}
|
|
|
|
func (containsOperator RegexOperator) Eval(payload gjson.Result) bool {
|
|
matched, _ := regexp.MatchString(containsOperator.regex, payload.String())
|
|
return matched
|
|
}
|
|
|
|
func Generate(opName string, argument gjson.Result) Filter {
|
|
switch opName {
|
|
case "not":
|
|
return notOperatorConstruct(argument)
|
|
case "and":
|
|
return andOperatorConstruct(argument)
|
|
case "or":
|
|
return orOperatorConstruct(argument)
|
|
case "neq":
|
|
return notEqualOperatorConstruct(argument)
|
|
case "eq":
|
|
return equalOperatorConstruct(argument)
|
|
case "in":
|
|
return inOperatorConstruct(argument)
|
|
case "contains":
|
|
return containsOperatorConstruct(argument)
|
|
case "regex":
|
|
return regexOperatorConstruct(argument)
|
|
default:
|
|
panic("the operator " + opName + " is not supported")
|
|
}
|
|
}
|
|
|
|
var EventFilter = new(Filter)
|
|
|
|
func BootFilter() {
|
|
defer func() {
|
|
if e := recover(); e != nil {
|
|
log.Warnf("事件过滤器启动失败: %v", e)
|
|
EventFilter = nil
|
|
} else {
|
|
log.Info("事件过滤器启动成功.")
|
|
}
|
|
}()
|
|
f, err := ioutil.ReadFile("filter.json")
|
|
if err != nil {
|
|
panic(err)
|
|
} else {
|
|
*EventFilter = Generate("and", gjson.ParseBytes(f))
|
|
}
|
|
}
|