github.com/fumiama/NanoBot@v0.0.0-20231122134259-c22d8183efca/event.go (about) 1 package nano 2 3 import ( 4 "encoding/json" 5 "reflect" 6 "strings" 7 8 log "github.com/sirupsen/logrus" 9 ) 10 11 // Event ... 12 type Event struct { 13 // Type is payload.T 14 Type string 15 // Seq 序列号 16 Seq uint32 17 // Value 是 D 18 Value any 19 // value is the reflect value of Value 20 value reflect.Value 21 } 22 23 // processEvent 处理需要关注的业务事件 24 func (bot *Bot) processEvent(payload *WebsocketPayload) { 25 tp := UnderlineToCamel(payload.T) 26 if bot.Handler != nil { 27 ev, ok := bot.handlers[tp] 28 if !ok { 29 return 30 } 31 log.Debugln(getLogHeader(), "使用 handlers 处理", tp, "事件") 32 x := reflect.New(ev.t) 33 err := json.Unmarshal(payload.D, x.Interface()) 34 if err != nil { 35 log.Warnln(getLogHeader(), "解析", tp, "事件时出现错误:", err) 36 return 37 } 38 go ev.h(payload.S, bot, x.UnsafePointer()) 39 return 40 } 41 ctx := &Ctx{ 42 Event: Event{ 43 Type: tp, 44 Seq: payload.S, 45 }, 46 State: State{}, 47 caller: bot, 48 } 49 switch tp { 50 case "C2cMessageCreate", "GroupAtMessageCreate": 51 ctx.IsQQ = true 52 } 53 switch tp { 54 case "DirectMessageCreate", "C2cMessageCreate", "GroupAtMessageCreate": 55 ctx.IsToMe = true 56 fallthrough 57 case "MessageCreate", "AtMessageCreate": 58 tp = "Message" 59 case "DirectMessageDelete": 60 ctx.IsToMe = true 61 fallthrough 62 case "MessageDelete", "PublicMessageDelete": 63 tp = "MessageDelete" 64 } 65 matcherLock.RLock() 66 n := len(matcherMap[tp]) 67 if n == 0 { 68 matcherLock.RUnlock() 69 return 70 } 71 log.Debugln(getLogHeader(), "pass", tp, "event to plugins") 72 matchers := make([]*Matcher, n) 73 copy(matchers, matcherMap[tp]) 74 matcherLock.RUnlock() 75 x := reflect.New(types[ctx.Type]) 76 err := json.Unmarshal(payload.D, x.Interface()) 77 if err != nil { 78 log.Warnln(getLogHeader(), "解析", ctx.Type, "事件时出现错误:", err) 79 return 80 } 81 ctx.Value = x.Interface() 82 ctx.value = x 83 switch tp { 84 case "Message": 85 ctx.Message = (*Message)(x.UnsafePointer()) 86 if ctx.Message.MentionEveryone { 87 ctx.IsToMe = true 88 } 89 if ctx.IsQQ { 90 if ctx.Message.Author.UserOpenID != "" { 91 ctx.Message.Author.ID = ctx.Message.Author.UserOpenID 92 } else if ctx.Message.Author.MemberOpenID != "" { 93 ctx.Message.Author.ID = ctx.Message.Author.MemberOpenID 94 } 95 ctx.Message.ChannelID = ctx.Message.GroupOpenID 96 } 97 log.Infoln(getLogHeader(), "=>", ctx.Message) 98 case "MessageDelete": 99 mdl := (*MessageDelete)(x.UnsafePointer()) 100 opmember, err := ctx.GetGuildMemberOf(mdl.Message.GuildID, mdl.OpUser.ID) 101 if err != nil { 102 log.Warnln(getLogHeader(), "获取撤回消息者详情错误:", err) 103 return 104 } 105 ctx.Message = (*MessageDelete)(x.UnsafePointer()).Message 106 ctx.Message.Member = &Member{ 107 GuildID: mdl.Message.GuildID, 108 User: ctx.Message.Author, 109 } 110 ctx.Message.Author = opmember.User 111 log.Infoln(getLogHeader(), "x>", mdl) 112 } 113 go match(ctx, matchers) 114 } 115 116 func match(ctx *Ctx, matchers []*Matcher) { 117 if ctx.Message != nil && ctx.Message.Content != "" { // 确保无空 118 ctx.Message.Content = strings.TrimSpace(ctx.Message.Content) 119 if !ctx.IsToMe { 120 ctx.IsToMe = func(ctx *Ctx) bool { 121 name := ctx.GetReady().User.Username 122 if strings.HasPrefix(ctx.Message.Content, name) { 123 log.Debugln(getLogHeader(), "message before process:", ctx.Message.Content) 124 ctx.Message.Content = strings.TrimLeft(ctx.Message.Content[len(name):], " ") 125 log.Debugln(getLogHeader(), "message after process:", ctx.Message.Content) 126 return true 127 } 128 atme := ctx.AtMe() 129 if strings.HasPrefix(ctx.Message.Content, atme) { 130 log.Debugln(getLogHeader(), "message before process:", ctx.Message.Content) 131 ctx.Message.Content = strings.TrimLeft(ctx.Message.Content[len(atme):], " ") 132 log.Debugln(getLogHeader(), "message after process:", ctx.Message.Content) 133 return true 134 } 135 return OnlyPrivate(ctx) 136 }(ctx) 137 } 138 } 139 log.Debugln(getLogHeader(), "message is to me:", ctx.IsToMe) 140 loop: 141 for _, matcher := range matchers { 142 for k := range ctx.State { // Clear State 143 delete(ctx.State, k) 144 } 145 matcherLock.RLock() 146 m := matcher.copy() 147 matcherLock.RUnlock() 148 ctx.ma = m 149 150 // pre handler 151 if m.Engine != nil { 152 for _, handler := range m.Engine.preHandler { 153 if !handler(ctx) { // 有 pre handler 未满足 154 if m.Break { // 阻断后续 155 break loop 156 } 157 continue loop 158 } 159 } 160 } 161 162 for _, rule := range m.Rules { 163 if rule != nil && !rule(ctx) { // 有 Rule 的条件未满足 164 if m.Break { // 阻断后续 165 break loop 166 } 167 continue loop 168 } 169 } 170 171 // mid handler 172 if m.Engine != nil { 173 for _, handler := range m.Engine.midHandler { 174 if !handler(ctx) { // 有 mid handler 未满足 175 if m.Break { // 阻断后续 176 break loop 177 } 178 continue loop 179 } 180 } 181 } 182 183 if m.Process != nil { 184 m.Process(ctx) // 处理事件 185 } 186 if matcher.Temp { // 临时 Matcher 删除 187 matcher.Delete() 188 } 189 190 if m.Engine != nil { 191 // post handler 192 for _, handler := range m.Engine.postHandler { 193 handler(ctx) 194 } 195 } 196 197 if m.Block { // 阻断后续 198 break loop 199 } 200 } 201 }