1
0
mirror of https://github.com/Mrs4s/go-cqhttp.git synced 2025-05-08 04:55:55 +08:00

Merge pull request #461 from wdvxdr1123/patch/eventfilter

This commit is contained in:
Mrs4s 2020-12-08 22:51:18 +08:00 committed by GitHub
commit 818cecc279
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
3 changed files with 87 additions and 54 deletions

View File

@ -18,7 +18,6 @@ import (
jsoniter "github.com/json-iterator/go" jsoniter "github.com/json-iterator/go"
log "github.com/sirupsen/logrus" log "github.com/sirupsen/logrus"
"github.com/tidwall/gjson"
) )
var json = jsoniter.ConfigCompatibleWithStandardLibrary var json = jsoniter.ConfigCompatibleWithStandardLibrary
@ -392,22 +391,19 @@ func (bot *CQBot) Release() {
} }
func (bot *CQBot) dispatchEventMessage(m MSG) { func (bot *CQBot) dispatchEventMessage(m MSG) {
payload := gjson.Parse(m.ToJson()) if global.EventFilter != nil && global.EventFilter.Eval(global.MSG(m)) == false {
filter := global.EventFilter
if filter != nil && (*filter).Eval(payload) == false {
log.Debug("Event filtered!") log.Debug("Event filtered!")
return return
} }
for _, f := range bot.events { for _, f := range bot.events {
fn := f go func(fn func(MSG)) {
go func() {
start := time.Now() start := time.Now()
fn(m) fn(m)
end := time.Now() end := time.Now()
if end.Sub(start) > time.Second*5 { if end.Sub(start) > time.Second*5 {
log.Debugf("警告: 事件处理耗时超过 5 秒 (%v), 请检查应用是否有堵塞.", end.Sub(start)) log.Debugf("警告: 事件处理耗时超过 5 秒 (%v), 请检查应用是否有堵塞.", end.Sub(start))
} }
}() }(f)
} }
} }

View File

@ -1,12 +1,22 @@
# 事件过滤器 # 事件过滤器
在go-cqhttp同级目录下新建`filter.json`文件即可开启事件过滤器,启动时会读取该文件中定义的过滤规则(使用 JSON 编写),若文件不存在,或过滤规则语法错误,则会暂停所有上报 在go-cqhttp同级目录下新建`filter.json`文件即可开启事件过滤器,启动时会读取该文件中定义的过滤规则(使用 JSON 编写),若文件不存在,或过滤规则语法错误,则不会启用事件过滤器
事件过滤器会处理所有事件(包括心跳事件在内的元事件),请谨慎使用!! 事件过滤器会处理所有事件(包括心跳事件在内的元事件),请谨慎使用!!
注意: 与客户端建立连接的握手事件**不会**经过事件过滤器
## 示例 ## 示例
这节首先给出一些示例,演示过滤器的基本用法,下一节将给出具体语法说明。 这节首先给出一些示例,演示过滤器的基本用法,下一节将给出具体语法说明。
### 过滤所有事件
```json
{
".not": {}
}
```
### 只上报以「!!」开头的消息 ### 只上报以「!!」开头的消息
```json ```json
@ -128,5 +138,5 @@
这里有几点需要注意: 这里有几点需要注意:
- `message` 字段在运行过滤器时是消息段数组的形式(见 [消息格式]( https://github.com/howmanybots/onebot/blob/master/v11/specs/message/array.md ) - `message` 字段在运行过滤器时和上报信息类型相同(见 [消息格式]( https://github.com/howmanybots/onebot/blob/master/v11/specs/message/array.md )
- `raw_message` 字段为未经**CQ码**处理的原始消息字符串,这意味着其中可能会出现形如 `[CQ:face,id=123]` 的 CQ 码 - `raw_message` 字段为未经**CQ码**处理的原始消息字符串,这意味着其中可能会出现形如 `[CQ:face,id=123]` 的 CQ 码

View File

@ -1,6 +1,7 @@
package global package global
import ( import (
"fmt"
"io/ioutil" "io/ioutil"
"regexp" "regexp"
"strings" "strings"
@ -9,17 +10,37 @@ import (
"github.com/tidwall/gjson" "github.com/tidwall/gjson"
) )
type Filter interface { type MSG map[string]interface{}
Eval(payload gjson.Result) bool
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{}
} }
type OperationNode struct { 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 key string
filter Filter filter Filter
} }
type NotOperator struct { type NotOperator struct {
operand_ Filter operand Filter
} }
func notOperatorConstruct(argument gjson.Result) *NotOperator { func notOperatorConstruct(argument gjson.Result) *NotOperator {
@ -27,16 +48,16 @@ func notOperatorConstruct(argument gjson.Result) *NotOperator {
panic("the argument of 'not' operator must be an object") panic("the argument of 'not' operator must be an object")
} }
op := new(NotOperator) op := new(NotOperator)
op.operand_ = Generate("and", argument) op.operand = Generate("and", argument)
return op return op
} }
func (notOperator NotOperator) Eval(payload gjson.Result) bool { func (op *NotOperator) Eval(payload MSG) bool {
return !(notOperator.operand_).Eval(payload) return !op.operand.Eval(payload)
} }
type AndOperator struct { type AndOperator struct {
operands []OperationNode operands []operationNode
} }
func andOperatorConstruct(argument gjson.Result) *AndOperator { func andOperatorConstruct(argument gjson.Result) *AndOperator {
@ -51,26 +72,26 @@ func andOperatorConstruct(argument gjson.Result) *AndOperator {
// "bar": "baz" // "bar": "baz"
// } // }
opKey := key.Str[1:] opKey := key.Str[1:]
op.operands = append(op.operands, OperationNode{"", Generate(opKey, value)}) op.operands = append(op.operands, operationNode{"", Generate(opKey, value)})
} else if value.IsObject() { } else if value.IsObject() {
// is an normal key with an object as the value // is an normal key with an object as the value
// "foo": { // "foo": {
// ".bar": "baz" // ".bar": "baz"
// } // }
opKey := key.String() opKey := key.String()
op.operands = append(op.operands, OperationNode{opKey, Generate("and", value)}) op.operands = append(op.operands, operationNode{opKey, Generate("and", value)})
} else { } else {
// is an normal key with a non-object as the value // is an normal key with a non-object as the value
// "foo": "bar" // "foo": "bar"
opKey := key.String() opKey := key.String()
op.operands = append(op.operands, OperationNode{opKey, Generate("eq", value)}) op.operands = append(op.operands, operationNode{opKey, Generate("eq", value)})
} }
return true return true
}) })
return op return op
} }
func (andOperator *AndOperator) Eval(payload gjson.Result) bool { func (andOperator *AndOperator) Eval(payload MSG) bool {
res := true res := true
for _, operand := range andOperator.operands { for _, operand := range andOperator.operands {
@ -106,11 +127,10 @@ func orOperatorConstruct(argument gjson.Result) *OrOperator {
return op return op
} }
func (orOperator OrOperator) Eval(payload gjson.Result) bool { func (op *OrOperator) Eval(payload MSG) bool {
res := false res := false
for _, operand := range orOperator.operands { for _, operand := range op.operands {
res = res || operand.Eval(payload) res = res || operand.Eval(payload)
if res == true { if res == true {
break break
} }
@ -119,35 +139,36 @@ func (orOperator OrOperator) Eval(payload gjson.Result) bool {
} }
type EqualOperator struct { type EqualOperator struct {
value gjson.Result operand string
} }
func equalOperatorConstruct(argument gjson.Result) *EqualOperator { func equalOperatorConstruct(argument gjson.Result) *EqualOperator {
op := new(EqualOperator) op := new(EqualOperator)
op.value = argument op.operand = argument.String()
return op return op
} }
func (equalOperator EqualOperator) Eval(payload gjson.Result) bool { func (op *EqualOperator) Eval(payload MSG) bool {
return payload.String() == equalOperator.value.String() return payload.String() == op.operand
} }
type NotEqualOperator struct { type NotEqualOperator struct {
value gjson.Result operand string
} }
func notEqualOperatorConstruct(argument gjson.Result) *NotEqualOperator { func notEqualOperatorConstruct(argument gjson.Result) *NotEqualOperator {
op := new(NotEqualOperator) op := new(NotEqualOperator)
op.value = argument op.operand = argument.String()
return op return op
} }
func (notEqualOperator NotEqualOperator) Eval(payload gjson.Result) bool { func (op *NotEqualOperator) Eval(payload MSG) bool {
return !(payload.String() == notEqualOperator.value.String()) return !(payload.String() == op.operand)
} }
type InOperator struct { type InOperator struct {
operand gjson.Result operandString string
operandArray []string
} }
func inOperatorConstruct(argument gjson.Result) *InOperator { func inOperatorConstruct(argument gjson.Result) *InOperator {
@ -155,20 +176,29 @@ func inOperatorConstruct(argument gjson.Result) *InOperator {
panic("the argument of 'in' operator must be an array or a string") panic("the argument of 'in' operator must be an array or a string")
} }
op := new(InOperator) op := new(InOperator)
op.operand = argument 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 return op
} }
func (inOperator InOperator) Eval(payload gjson.Result) bool { func (op *InOperator) Eval(payload MSG) bool {
if inOperator.operand.IsArray() { payloadStr := payload.String()
res := false if op.operandArray != nil {
inOperator.operand.ForEach(func(key, value gjson.Result) bool { for _, value := range op.operandArray {
res = res || value.String() == payload.String() if value == payloadStr {
return true return true
}) }
return res }
return false
} }
return strings.Contains(inOperator.operand.String(), payload.String()) return strings.Contains(op.operandString, payloadStr)
} }
type ContainsOperator struct { type ContainsOperator struct {
@ -184,15 +214,12 @@ func containsOperatorConstruct(argument gjson.Result) *ContainsOperator {
return op return op
} }
func (containsOperator ContainsOperator) Eval(payload gjson.Result) bool { func (op *ContainsOperator) Eval(payload MSG) bool {
if payload.IsObject() || payload.IsArray() { return strings.Contains(payload.String(), op.operand)
return false
}
return strings.Contains(payload.String(), containsOperator.operand)
} }
type RegexOperator struct { type RegexOperator struct {
regex string regex *regexp.Regexp
} }
func regexOperatorConstruct(argument gjson.Result) *RegexOperator { func regexOperatorConstruct(argument gjson.Result) *RegexOperator {
@ -200,12 +227,12 @@ func regexOperatorConstruct(argument gjson.Result) *RegexOperator {
panic("the argument of 'regex' operator must be a string") panic("the argument of 'regex' operator must be a string")
} }
op := new(RegexOperator) op := new(RegexOperator)
op.regex = argument.String() op.regex = regexp.MustCompile(argument.String())
return op return op
} }
func (containsOperator RegexOperator) Eval(payload gjson.Result) bool { func (op *RegexOperator) Eval(payload MSG) bool {
matched, _ := regexp.MatchString(containsOperator.regex, payload.String()) matched := op.regex.MatchString(payload.String())
return matched return matched
} }
@ -232,7 +259,7 @@ func Generate(opName string, argument gjson.Result) Filter {
} }
} }
var EventFilter = new(Filter) var EventFilter Filter = nil
func BootFilter() { func BootFilter() {
defer func() { defer func() {
@ -247,6 +274,6 @@ func BootFilter() {
if err != nil { if err != nil {
panic(err) panic(err)
} else { } else {
*EventFilter = Generate("and", gjson.ParseBytes(f)) EventFilter = Generate("and", gjson.ParseBytes(f))
} }
} }