mirror of
https://github.com/Mrs4s/go-cqhttp.git
synced 2025-05-05 03:23:49 +08:00
280 lines
5.9 KiB
Go
280 lines
5.9 KiB
Go
package global
|
|
|
|
import (
|
|
"fmt"
|
|
"io/ioutil"
|
|
"regexp"
|
|
"strings"
|
|
|
|
log "github.com/sirupsen/logrus"
|
|
"github.com/tidwall/gjson"
|
|
)
|
|
|
|
type MSG map[string]interface{}
|
|
|
|
func (m MSG) Get(s string) MSG {
|
|
if v, ok := m[s]; ok {
|
|
if msg, ok := v.(MSG); ok {
|
|
return msg
|
|
}
|
|
return MSG{"__str__": v} // 用这个名字应该没问题吧
|
|
}
|
|
return MSG{}
|
|
}
|
|
|
|
func (m MSG) String() string {
|
|
if str, ok := m["__str__"]; ok {
|
|
return fmt.Sprint(str)
|
|
}
|
|
str, _ := json.MarshalToString(m)
|
|
return str
|
|
}
|
|
|
|
type Filter interface {
|
|
Eval(payload MSG) 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 (op *NotOperator) Eval(payload MSG) bool {
|
|
return !op.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 MSG) 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 (op *OrOperator) Eval(payload MSG) bool {
|
|
res := false
|
|
for _, operand := range op.operands {
|
|
res = res || operand.Eval(payload)
|
|
if res == true {
|
|
break
|
|
}
|
|
}
|
|
return res
|
|
}
|
|
|
|
type EqualOperator struct {
|
|
operand string
|
|
}
|
|
|
|
func equalOperatorConstruct(argument gjson.Result) *EqualOperator {
|
|
op := new(EqualOperator)
|
|
op.operand = argument.String()
|
|
return op
|
|
}
|
|
|
|
func (op *EqualOperator) Eval(payload MSG) bool {
|
|
return payload.String() == op.operand
|
|
}
|
|
|
|
type NotEqualOperator struct {
|
|
operand string
|
|
}
|
|
|
|
func notEqualOperatorConstruct(argument gjson.Result) *NotEqualOperator {
|
|
op := new(NotEqualOperator)
|
|
op.operand = argument.String()
|
|
return op
|
|
}
|
|
|
|
func (op *NotEqualOperator) Eval(payload MSG) bool {
|
|
return !(payload.String() == op.operand)
|
|
}
|
|
|
|
type InOperator struct {
|
|
operandString string
|
|
operandArray []string
|
|
}
|
|
|
|
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)
|
|
if argument.IsArray() {
|
|
op.operandArray = []string{}
|
|
argument.ForEach(func(_, value gjson.Result) bool {
|
|
op.operandArray = append(op.operandArray, value.String())
|
|
return true
|
|
})
|
|
} else {
|
|
op.operandString = argument.String()
|
|
}
|
|
return op
|
|
}
|
|
|
|
func (op *InOperator) Eval(payload MSG) bool {
|
|
payloadStr := payload.String()
|
|
if op.operandArray != nil {
|
|
for _, value := range op.operandArray {
|
|
if value == payloadStr {
|
|
return true
|
|
}
|
|
}
|
|
return false
|
|
}
|
|
return strings.Contains(op.operandString, payloadStr)
|
|
}
|
|
|
|
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 (op *ContainsOperator) Eval(payload MSG) bool {
|
|
return strings.Contains(payload.String(), op.operand)
|
|
}
|
|
|
|
type RegexOperator struct {
|
|
regex *regexp.Regexp
|
|
}
|
|
|
|
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 = regexp.MustCompile(argument.String())
|
|
return op
|
|
}
|
|
|
|
func (op *RegexOperator) Eval(payload MSG) bool {
|
|
matched := op.regex.MatchString(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 Filter = nil
|
|
|
|
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))
|
|
}
|
|
}
|