mirror of
https://github.com/Mrs4s/go-cqhttp.git
synced 2025-05-05 19:43:49 +08:00
反向WS事件过滤器
This commit is contained in:
parent
d7abe6f7e3
commit
2949f68532
248
global/filter.go
Normal file
248
global/filter.go
Normal file
@ -0,0 +1,248 @@
|
||||
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
|
||||
}
|
1
go.mod
1
go.mod
@ -4,6 +4,7 @@ go 1.14
|
||||
|
||||
require (
|
||||
github.com/Mrs4s/MiraiGo v0.0.0-20200821182324-7654a7a2a106
|
||||
github.com/buger/jsonparser v1.0.0
|
||||
github.com/fastly/go-utils v0.0.0-20180712184237-d95a45783239 // indirect
|
||||
github.com/gin-gonic/gin v1.6.3
|
||||
github.com/gorilla/websocket v1.4.2
|
||||
|
2
go.sum
2
go.sum
@ -6,6 +6,8 @@ github.com/Mrs4s/MiraiGo v0.0.0-20200821164244-fe8e98b9d8c5 h1:LVzj3ahW0LYJQMDcD
|
||||
github.com/Mrs4s/MiraiGo v0.0.0-20200821164244-fe8e98b9d8c5/go.mod h1:0je03wji/tSw4bUH4QCF2Z4/EjyNWjSJTyy5tliX6EM=
|
||||
github.com/Mrs4s/MiraiGo v0.0.0-20200821182324-7654a7a2a106 h1:z2oaXbvOmu7/O666OkUeH5SGUjyQ3wUSNjtTOagY8Sk=
|
||||
github.com/Mrs4s/MiraiGo v0.0.0-20200821182324-7654a7a2a106/go.mod h1:0je03wji/tSw4bUH4QCF2Z4/EjyNWjSJTyy5tliX6EM=
|
||||
github.com/buger/jsonparser v1.0.0 h1:etJTGF5ESxjI0Ic2UaLQs2LQQpa8G9ykQScukbh4L8A=
|
||||
github.com/buger/jsonparser v1.0.0/go.mod h1:tgcrVJ81GPSF0mz+0nu1Xaz0fazGPrmmJfJtxjbHhUQ=
|
||||
github.com/bwmarrin/snowflake v0.3.0 h1:xm67bEhkKh6ij1790JB83OujPR5CzNe8QuQqAgISZN0=
|
||||
github.com/bwmarrin/snowflake v0.3.0/go.mod h1:NdZxfVWX+oR6y2K0o6qAYv6gIOP9rjG0/E9WsDpxqwE=
|
||||
github.com/census-instrumentation/opencensus-proto v0.2.1/go.mod h1:f6KPmirojxKA12rnyqOA5BBL4O983OfeGPqjHWSTneU=
|
||||
|
@ -172,6 +172,12 @@ func (c *websocketClient) listenApi(conn *websocketConn, u bool) {
|
||||
}
|
||||
|
||||
func (c *websocketClient) onBotPushEvent(m coolq.MSG) {
|
||||
payload := []byte(m.ToJson())
|
||||
filter := global.GetFilter()
|
||||
if filter != nil && (*filter).Eval(payload) == false {
|
||||
log.Debug("Event filtered!")
|
||||
return
|
||||
}
|
||||
if c.eventConn != nil {
|
||||
log.Debugf("向WS服务器 %v 推送Event: %v", c.eventConn.RemoteAddr().String(), m.ToJson())
|
||||
c.eventConn.Lock()
|
||||
|
Loading…
x
Reference in New Issue
Block a user