diff --git a/coolq/api.go b/coolq/api.go index f929289..486c069 100644 --- a/coolq/api.go +++ b/coolq/api.go @@ -627,6 +627,11 @@ func (bot *CQBot) CQCanSendRecord() MSG { return OK(MSG{"yes": true}) } +func (bot *CQBot) CQReloadEventFilter() MSG { + global.BootFilter() + return OK(nil) +} + func (bot *CQBot) CQGetStatus() MSG { return OK(MSG{ "app_initialized": true, diff --git a/coolq/bot.go b/coolq/bot.go index 12a96e8..063b94d 100644 --- a/coolq/bot.go +++ b/coolq/bot.go @@ -226,7 +226,7 @@ func (bot *CQBot) Release() { func (bot *CQBot) dispatchEventMessage(m MSG) { payload := gjson.Parse(m.ToJson()) - filter := global.GetFilter() + filter := global.EventFilter if filter != nil && (*filter).Eval(payload) == false { log.Debug("Event filtered!") return diff --git a/global/filter.go b/global/filter.go index e7fdad6..b2ac4cb 100644 --- a/global/filter.go +++ b/global/filter.go @@ -6,7 +6,6 @@ import ( "io/ioutil" "regexp" "strings" - "sync" ) type Filter interface { @@ -14,7 +13,7 @@ type Filter interface { } type OperationNode struct { - key string + key string filter Filter } @@ -24,15 +23,14 @@ type NotOperator struct { func notOperatorConstruct(argument gjson.Result) *NotOperator { if !argument.IsObject() { - log.Error("the argument of 'not' operator must be an object") + panic("the argument of 'not' operator must be an object") } op := new(NotOperator) - op.operand_ = GetOperatorFactory().Generate("and", argument) + op.operand_ = Generate("and", argument) return op } func (notOperator NotOperator) Eval(payload gjson.Result) bool { - log.Debug("not " + payload.Str) return !(notOperator.operand_).Eval(payload) } @@ -42,7 +40,7 @@ type AndOperator struct { func andOperatorConstruct(argument gjson.Result) *AndOperator { if !argument.IsObject() { - log.Error("the argument of 'and' operator must be an object") + panic("the argument of 'and' operator must be an object") } op := new(AndOperator) argument.ForEach(func(key, value gjson.Result) bool { @@ -52,19 +50,19 @@ func andOperatorConstruct(argument gjson.Result) *AndOperator { // "bar": "baz" // } opKey := key.Str[1:] - op.operands = append(op.operands, OperationNode{"", GetOperatorFactory().Generate(opKey, value)}) + 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.Str - op.operands = append(op.operands, OperationNode{opKey, GetOperatorFactory().Generate("and", value)}) + 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.Str - op.operands = append(op.operands, OperationNode{opKey, GetOperatorFactory().Generate("eq", value)}) + opKey := key.String() + op.operands = append(op.operands, OperationNode{opKey, Generate("eq", value)}) } return true }) @@ -72,7 +70,6 @@ func andOperatorConstruct(argument gjson.Result) *AndOperator { } func (andOperator *AndOperator) Eval(payload gjson.Result) bool { - log.Debug("and " + payload.Str) res := true for _, operand := range andOperator.operands { @@ -98,19 +95,18 @@ type OrOperator struct { func orOperatorConstruct(argument gjson.Result) *OrOperator { if !argument.IsArray() { - log.Error("the argument of 'or' operator must be an array") + 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, GetOperatorFactory().Generate("and", value)) + op.operands = append(op.operands, Generate("and", value)) return true }) return op } func (orOperator OrOperator) Eval(payload gjson.Result) bool { - log.Debug("or "+ payload.Str) - res:= false + res := false for _, operand := range orOperator.operands { res = res || operand.Eval(payload) @@ -132,8 +128,7 @@ func equalOperatorConstruct(argument gjson.Result) *EqualOperator { } func (equalOperator EqualOperator) Eval(payload gjson.Result) bool { - log.Debug("eq "+ payload.Str + "==" + equalOperator.value.Str) - return payload.Str == equalOperator.value.Str + return payload.String() == equalOperator.value.String() } type NotEqualOperator struct { @@ -147,18 +142,16 @@ func notEqualOperatorConstruct(argument gjson.Result) *NotEqualOperator { } func (notEqualOperator NotEqualOperator) Eval(payload gjson.Result) bool { - log.Debug("neq " + payload.Str) - return !(payload.Str == notEqualOperator.value.Str) + return !(payload.String() == notEqualOperator.value.String()) } - type InOperator struct { operand gjson.Result } func inOperatorConstruct(argument gjson.Result) *InOperator { if argument.IsObject() { - log.Error("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.operand = argument @@ -166,16 +159,15 @@ func inOperatorConstruct(argument gjson.Result) *InOperator { } func (inOperator InOperator) Eval(payload gjson.Result) bool { - log.Debug("in " + payload.Str) if inOperator.operand.IsArray() { res := false inOperator.operand.ForEach(func(key, value gjson.Result) bool { - res = res || value.Str == payload.Str + res = res || value.String() == payload.String() return true }) return res } - return strings.Contains(inOperator.operand.Str, payload.Str) + return strings.Contains(inOperator.operand.String(), payload.String()) } type ContainsOperator struct { @@ -184,15 +176,14 @@ type ContainsOperator struct { func containsOperatorConstruct(argument gjson.Result) *ContainsOperator { if argument.IsArray() || argument.IsObject() { - log.Error("the argument of 'contains' operator must be a string") + panic("the argument of 'contains' operator must be a string") } op := new(ContainsOperator) - op.operand = argument.Str + op.operand = argument.String() return op } func (containsOperator ContainsOperator) Eval(payload gjson.Result) bool { - log.Debug("contains "+ payload.Str) if payload.IsObject() || payload.IsArray() { return false } @@ -205,29 +196,19 @@ type RegexOperator struct { func regexOperatorConstruct(argument gjson.Result) *RegexOperator { if argument.IsArray() || argument.IsObject() { - log.Error("the argument of 'regex' operator must be a string") + panic("the argument of 'regex' operator must be a string") } op := new(RegexOperator) - op.regex = argument.Str + op.regex = argument.String() return op } func (containsOperator RegexOperator) Eval(payload gjson.Result) bool { - log.Debug("regex " + payload.Str) - matched, _ := regexp.MatchString(containsOperator.regex, payload.Str) + matched, _ := regexp.MatchString(containsOperator.regex, payload.String()) return matched } -// 单例工厂 -type operatorFactory struct{ -} -var instance *operatorFactory = &operatorFactory{} - -func GetOperatorFactory() *operatorFactory { - return instance -} - -func (o operatorFactory) Generate(opName string, argument gjson.Result) Filter { +func Generate(opName string, argument gjson.Result) Filter { switch opName { case "not": return notOperatorConstruct(argument) @@ -246,22 +227,25 @@ func (o operatorFactory) Generate(opName string, argument gjson.Result) Filter { case "regex": return regexOperatorConstruct(argument) default: - log.Warnf("the operator '%s' is not supported", opName) - return nil + panic("the operator " + opName + " is not supported") } } -var filter = new(Filter) -var once sync.Once // 过滤器单例模式 +var EventFilter = new(Filter) -func GetFilter() *Filter { - once.Do(func() { - f, err := ioutil.ReadFile("filter.json") - if err != nil { - filter = nil +func BootFilter() { + defer func() { + if e := recover(); e != nil { + log.Warnf("事件过滤器启动失败: %v", e) + EventFilter = nil } else { - *filter = GetOperatorFactory().Generate("and", gjson.ParseBytes(f)) + log.Info("事件过滤器启动成功.") } - }) - return filter -} \ No newline at end of file + }() + f, err := ioutil.ReadFile("filter.json") + if err != nil { + panic(err) + } else { + *EventFilter = Generate("and", gjson.ParseBytes(f)) + } +} diff --git a/go.mod b/go.mod index b71b7a8..5a5723f 100644 --- a/go.mod +++ b/go.mod @@ -12,7 +12,7 @@ require ( github.com/jehiah/go-strftime v0.0.0-20171201141054-1d33003b3869 // indirect github.com/jonboulle/clockwork v0.2.0 // indirect github.com/json-iterator/go v1.1.10 // indirect - github.com/lestrrat-go/file-rotatelogs v2.3.0+incompatible + github.com/lestrrat-go/file-rotatelogs v2.4.0+incompatible github.com/lestrrat-go/strftime v1.0.3 // indirect github.com/modern-go/concurrent v0.0.0-20180306012644-bacd9c7ef1dd // indirect github.com/modern-go/reflect2 v1.0.1 // indirect @@ -25,7 +25,7 @@ require ( github.com/xujiajun/nutsdb v0.5.0 github.com/yinghau76/go-ascii-art v0.0.0-20190517192627-e7f465a30189 golang.org/x/net v0.0.0-20200904194848-62affa334b73 // indirect - golang.org/x/sys v0.0.0-20200905004654-be1d3432aa8f // indirect + golang.org/x/sys v0.0.0-20200909081042-eff7692f9009 // indirect golang.org/x/time v0.0.0-20200630173020-3af7569d3a1e gopkg.in/yaml.v2 v2.3.0 // indirect ) diff --git a/go.sum b/go.sum index 912714c..7d5ff26 100644 --- a/go.sum +++ b/go.sum @@ -70,6 +70,8 @@ github.com/leodido/go-urn v1.2.0/go.mod h1:+8+nEpDfqqsY+g338gtMEUOtuK+4dEMhiQEgx github.com/lestrrat-go/envload v0.0.0-20180220234015-a3eb8ddeffcc/go.mod h1:kopuH9ugFRkIXf3YoqHKyrJ9YfUFsckUU9S7B+XP+is= github.com/lestrrat-go/file-rotatelogs v2.3.0+incompatible h1:4mNlp+/SvALIPFpbXV3kxNJJno9iKFWGxSDE13Kl66Q= github.com/lestrrat-go/file-rotatelogs v2.3.0+incompatible/go.mod h1:ZQnN8lSECaebrkQytbHj4xNgtg8CR7RYXnPok8e0EHA= +github.com/lestrrat-go/file-rotatelogs v2.4.0+incompatible h1:Y6sqxHMyB1D2YSzWkLibYKgg+SwmyFU9dF2hn6MdTj4= +github.com/lestrrat-go/file-rotatelogs v2.4.0+incompatible/go.mod h1:ZQnN8lSECaebrkQytbHj4xNgtg8CR7RYXnPok8e0EHA= github.com/lestrrat-go/strftime v1.0.3 h1:qqOPU7y+TM8Y803I8fG9c/DyKG3xH/xkng6keC1015Q= github.com/lestrrat-go/strftime v1.0.3/go.mod h1:E1nN3pCbtMSu1yjSVeyuRFVm/U0xoR76fd03sz+Qz4g= github.com/mattn/go-isatty v0.0.9/go.mod h1:YNRxwqDuOph6SZLI9vUUz6OYw3QyUt7WiY2yME+cCiQ= @@ -146,6 +148,8 @@ golang.org/x/sys v0.0.0-20200116001909-b77594299b42/go.mod h1:h1NjWce9XRLGQEsW7w golang.org/x/sys v0.0.0-20200323222414-85ca7c5b95cd/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20200905004654-be1d3432aa8f h1:Fqb3ao1hUmOR3GkUOg/Y+BadLwykBIzs5q8Ez2SbHyc= golang.org/x/sys v0.0.0-20200905004654-be1d3432aa8f/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20200909081042-eff7692f9009 h1:W0lCpv29Hv0UaM1LXb9QlBHLNP8UFfcKjblhVCWftOM= +golang.org/x/sys v0.0.0-20200909081042-eff7692f9009/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ= golang.org/x/text v0.3.2/go.mod h1:bEr9sfX3Q8Zfm5fL9x+3itogRgK3+ptLWKqgva+5dAk= golang.org/x/time v0.0.0-20200630173020-3af7569d3a1e h1:EHBhcS0mlXEAVwNyO2dLfjToGsyY4j24pTs2ScHnX7s= diff --git a/main.go b/main.go index 3aeaba6..307e630 100644 --- a/main.go +++ b/main.go @@ -280,6 +280,8 @@ func main() { for _, rc := range conf.ReverseServers { server.NewWebsocketClient(rc, conf.AccessToken, b).Run() } + log.Info("正在加载事件过滤器.") + global.BootFilter() log.Info("资源初始化完成, 开始处理信息.") log.Info("アトリは、高性能ですから!") cli.OnDisconnected(func(bot *client.QQClient, e *client.ClientDisconnectedEvent) { diff --git a/server/http.go b/server/http.go index 8ca0c29..9b10904 100644 --- a/server/http.go +++ b/server/http.go @@ -324,6 +324,10 @@ func (s *httpServer) GetVersionInfo(c *gin.Context) { c.JSON(200, s.bot.CQGetVersionInfo()) } +func (s *httpServer) ReloadEventFilter(c *gin.Context) { + c.JSON(200, s.bot.CQReloadEventFilter()) +} + func (s *httpServer) GetVipInfo(c *gin.Context) { uid, _ := strconv.ParseInt(getParam(c, "user_id"), 10, 64) c.JSON(200, s.bot.CQGetVipInfo(uid)) @@ -482,6 +486,9 @@ var httpApi = map[string]func(s *httpServer, c *gin.Context){ "_get_vip_info": func(s *httpServer, c *gin.Context) { s.GetVipInfo(c) }, + "reload_event_filter": func(s *httpServer, c *gin.Context) { + s.ReloadEventFilter(c) + }, ".handle_quick_operation": func(s *httpServer, c *gin.Context) { s.HandleQuickOperation(c) }, diff --git a/server/websocket.go b/server/websocket.go index eafe0a7..ecad98a 100644 --- a/server/websocket.go +++ b/server/websocket.go @@ -495,6 +495,9 @@ var wsApi = map[string]func(*coolq.CQBot, gjson.Result) coolq.MSG{ "_get_vip_info": func(bot *coolq.CQBot, p gjson.Result) coolq.MSG { return bot.CQGetVipInfo(p.Get("user_id").Int()) }, + "reload_event_filter": func(bot *coolq.CQBot, p gjson.Result) coolq.MSG { + return bot.CQReloadEventFilter() + }, ".handle_quick_operation": func(bot *coolq.CQBot, p gjson.Result) coolq.MSG { return bot.CQHandleQuickOperation(p.Get("context"), p.Get("operation")) },