1
0
mirror of https://github.com/Mrs4s/go-cqhttp.git synced 2025-05-06 12:03:50 +08:00
go-cqhttp/global/filter.go
2020-08-22 13:24:32 +08:00

248 lines
5.6 KiB
Go

package global
import (
"bytes"
"github.com/buger/jsonparser"
log "github.com/sirupsen/logrus"
"io/ioutil"
"regexp"
"sync"
)
type Filter interface {
Eval(payload []byte) bool
}
type OperationNode struct {
key string
filter Filter
}
type NotOperator struct {
operand_ Filter
}
func notOperatorConstruct(argument []byte) *NotOperator {
op := new(NotOperator)
op.operand_ = GetOperatorFactory().Generate("and", argument)
return op
}
func (notOperator NotOperator) Eval(payload []byte) bool {
log.Debug("not "+string(payload))
return !(notOperator.operand_).Eval(payload)
}
type AndOperator struct {
operands []OperationNode
}
func andOperatorConstruct(argument []byte) *AndOperator {
op := new(AndOperator)
_ = jsonparser.ObjectEach(argument, func(key []byte, value []byte, dataType jsonparser.ValueType, offset int) error {
if key[0] == '.' {
// is an operator
// ".foo": {
// "bar": "baz"
// }
opKey := string(key[1:])
op.operands = append(op.operands, OperationNode{"", GetOperatorFactory().Generate(opKey, value)})
} else if value[0] == '{' {
// is an normal key with an object as the value
// "foo": {
// ".bar": "baz"
// }
opKey := string(key)
op.operands = append(op.operands, OperationNode{opKey, GetOperatorFactory().Generate("and", value)})
} else {
// is an normal key with a non-object as the value
// "foo": "bar"
opKey := string(key)
op.operands = append(op.operands, OperationNode{opKey, GetOperatorFactory().Generate("eq", value)})
}
return nil
})
return op
}
func (andOperator *AndOperator) Eval(payload []byte) bool {
log.Debug("and "+string(payload))
res := true
nodesLength := len(andOperator.operands)
for i := 0; i < nodesLength ; i++ {
if len(andOperator.operands[i].key) == 0 {
// is an operator
res = res && andOperator.operands[i].filter.Eval(payload)
} else {
// is an normal key
val, _, _, _ := jsonparser.Get(payload, andOperator.operands[i].key)
res = res && andOperator.operands[i].filter.Eval(val)
}
if res == false {
break
}
}
return res
}
type OrOperator struct {
operands []Filter
}
func orOperatorConstruct(argument []byte) *OrOperator {
op := new(OrOperator)
_, _ = jsonparser.ArrayEach(argument, func(value []byte, dataType jsonparser.ValueType, offset int, err error) {
op.operands = append(op.operands, GetOperatorFactory().Generate("and", value))
})
return op
}
func (orOperator OrOperator) Eval(payload []byte) bool {
log.Debug("or "+string(payload))
res:= false
nodesLength := len(orOperator.operands)
for i := 0; i < nodesLength ; i++ {
res = res || orOperator.operands[i].Eval(payload)
if res == true {
break
}
}
return res
}
type EqualOperator struct {
value []byte
}
func equalOperatorConstruct(argument []byte) *EqualOperator {
op := new(EqualOperator)
op.value = argument
return op
}
func (equalOperator EqualOperator) Eval(payload []byte) bool {
log.Debug("eq "+string(payload))
return bytes.Equal(payload, equalOperator.value)
}
type NotEqualOperator struct {
value []byte
}
func notEqualOperatorConstruct(argument []byte) *NotEqualOperator {
op := new(NotEqualOperator)
op.value = argument
return op
}
func (notEqualOperator NotEqualOperator) Eval(payload []byte) bool {
log.Debug("neq "+string(payload))
return !bytes.Equal(payload, notEqualOperator.value)
}
type InOperator struct {
operands [][]byte
}
func inOperatorConstruct(argument []byte) *InOperator {
op := new(InOperator)
_, _ = jsonparser.ArrayEach(argument, func(value []byte, dataType jsonparser.ValueType, offset int, err error) {
op.operands = append(op.operands, value)
})
return op
}
func (inOperator InOperator) Eval(payload []byte) bool {
log.Debug("in "+string(payload))
res := false
for _, v := range inOperator.operands {
res = res || bytes.Equal(payload, v)
if res == true {
break
}
}
return res
}
type ContainsOperator struct {
operand []byte
}
func containsOperatorConstruct(argument []byte) *ContainsOperator {
op := new(ContainsOperator)
op.operand = argument
return op
}
func (containsOperator ContainsOperator) Eval(payload []byte) bool {
log.Debug("contains "+string(payload))
return bytes.Contains(payload, containsOperator.operand)
}
type RegexOperator struct {
regex string
}
func regexOperatorConstruct(argument []byte) *RegexOperator {
op := new(RegexOperator)
op.regex = string(argument)
return op
}
func (containsOperator RegexOperator) Eval(payload []byte) bool {
log.Debug("regex "+string(payload))
matched, _ := regexp.Match(containsOperator.regex, payload)
return matched
}
// 单例工厂
type operatorFactory struct{
}
var instance *operatorFactory = &operatorFactory{}
func GetOperatorFactory() *operatorFactory {
return instance
}
func (o operatorFactory) Generate(opName string, argument []byte) 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:
log.Warnf("the operator '%s' is not supported", opName)
return nil
}
}
var filter = new(Filter)
var once sync.Once // 过滤器单例模式
func GetFilter() *Filter {
once.Do(func() {
f, err := ioutil.ReadFile("filter.json")
if err != nil {
filter = nil
} else {
*filter = GetOperatorFactory().Generate("and", f)
}
})
return filter
}