github.com/Mrs4s/MiraiGo@v0.0.0-20240226124653-54bdd873e3fe/client/guild_eventflow.go (about) 1 package client 2 3 import ( 4 "sync" 5 "time" 6 7 "github.com/pierrec/lz4/v4" 8 9 "github.com/pkg/errors" 10 11 "github.com/Mrs4s/MiraiGo/client/internal/network" 12 "github.com/Mrs4s/MiraiGo/client/pb/channel" 13 "github.com/Mrs4s/MiraiGo/client/pb/msg" 14 "github.com/Mrs4s/MiraiGo/internal/proto" 15 ) 16 17 func init() { 18 decoders["MsgPush.PushGroupProMsg"] = decodeGuildEventFlowPacket 19 } 20 21 var updateChanLock sync.Mutex 22 23 type tipsPushInfo struct { 24 TinyId uint64 25 // TargetMessageSenderUin int64 26 GuildId uint64 27 ChannelId uint64 28 } 29 30 func decodeGuildEventFlowPacket(c *QQClient, pkt *network.Packet) (any, error) { 31 push := new(channel.MsgOnlinePush) 32 if err := proto.Unmarshal(pkt.Payload, push); err != nil { 33 return nil, errors.Wrap(err, "failed to unmarshal protobuf message") 34 } 35 if push.CompressFlag.Unwrap() == 1 && len(push.CompressMsg) > 0 { 36 press := new(channel.PressMsg) 37 dst := make([]byte, len(push.CompressMsg)*2) 38 i, err := lz4.UncompressBlock(push.CompressMsg, dst) 39 for times := 0; err != nil && err.Error() == "lz4: invalid source or destination buffer too short" && times < 5; times++ { 40 dst = append(dst, make([]byte, 1024)...) 41 i, err = lz4.UncompressBlock(push.CompressMsg, dst) 42 } 43 if err != nil { 44 return nil, errors.Wrap(err, "failed to decompress guild event packet") 45 } 46 if err = proto.Unmarshal(dst[:i], press); err != nil { 47 return nil, errors.Wrap(err, "failed to unmarshal protobuf message") 48 } 49 push.Msgs = press.Msgs 50 } 51 for _, m := range push.Msgs { 52 if m.Head == nil { 53 continue 54 } 55 if m.Head.ContentHead.Type.Unwrap() == 3841 { 56 // todo: 回头 event flow 的处理移出去重构下逻辑, 先暂时这样方便改 57 var common *msg.CommonElem 58 if m.Body != nil && m.Body.RichText != nil { 59 for _, e := range m.Body.RichText.Elems { 60 if e.CommonElem != nil { 61 common = e.CommonElem 62 break 63 } 64 } 65 } 66 if m.Head.ContentHead.SubType.Unwrap() == 2 { // todo: tips? 67 // if common == nil { // empty tips 68 // } 69 tipsInfo := &tipsPushInfo{ 70 TinyId: m.Head.RoutingHead.FromTinyid.Unwrap(), 71 GuildId: m.Head.RoutingHead.GuildId.Unwrap(), 72 ChannelId: m.Head.RoutingHead.ChannelId.Unwrap(), 73 } 74 /* 75 if len(m.CtrlHead.IncludeUin) > 0 { 76 tipsInfo.TargetMessageSenderUin = int64(m.CtrlHead.IncludeUin[0]) 77 } 78 */ 79 return tipsInfo, nil 80 } 81 if common == nil || common.ServiceType.Unwrap() != 500 { 82 continue 83 } 84 eventBody := new(channel.EventBody) 85 if err := proto.Unmarshal(common.PbElem, eventBody); err != nil { 86 c.error("failed to unmarshal guild channel event body: %v", err) 87 continue 88 } 89 c.processGuildEventBody(m, eventBody) 90 continue 91 } 92 if m.Head.ContentHead.Type.Unwrap() == 3840 { 93 if m.Head.RoutingHead.DirectMessageFlag.Unwrap() == 1 { 94 // todo: direct message decode 95 continue 96 } 97 if m.Head.RoutingHead.FromTinyid.Unwrap() == c.GuildService.TinyId { 98 continue 99 } 100 if cm := c.GuildService.parseGuildChannelMessage(m); cm != nil { 101 c.dispatchGuildChannelMessage(cm) 102 } 103 } 104 } 105 return nil, nil 106 } 107 108 func (c *QQClient) processGuildEventBody(m *channel.ChannelMsgContent, eventBody *channel.EventBody) { 109 var guild *GuildInfo 110 if m.Head.RoutingHead.GuildId.Unwrap() != 0 { 111 if guild = c.GuildService.FindGuild(m.Head.RoutingHead.GuildId.Unwrap()); guild == nil { 112 c.warning("process channel event error: guild not found.") 113 return 114 } 115 } 116 switch { 117 case eventBody.CreateChan != nil: 118 for _, chanId := range eventBody.CreateChan.CreateId { 119 if guild.FindChannel(chanId.ChanId.Unwrap()) != nil { 120 continue 121 } 122 channelInfo, err := c.GuildService.FetchChannelInfo(guild.GuildId, chanId.ChanId.Unwrap()) 123 if err != nil { 124 c.warning("process create channel event error: fetch channel info error: %v", err) 125 continue 126 } 127 guild.Channels = append(guild.Channels, channelInfo) 128 c.dispatchGuildChannelCreatedEvent(&GuildChannelOperationEvent{ 129 OperatorId: m.Head.RoutingHead.FromTinyid.Unwrap(), 130 GuildId: m.Head.RoutingHead.GuildId.Unwrap(), 131 ChannelInfo: channelInfo, 132 }) 133 } 134 case eventBody.DestroyChan != nil: 135 for _, chanId := range eventBody.DestroyChan.DeleteId { 136 channelInfo := guild.FindChannel(chanId.ChanId.Unwrap()) 137 if channelInfo == nil { 138 continue 139 } 140 guild.removeChannel(chanId.ChanId.Unwrap()) 141 c.dispatchGuildChannelDestroyedEvent(&GuildChannelOperationEvent{ 142 OperatorId: m.Head.RoutingHead.FromTinyid.Unwrap(), 143 GuildId: guild.GuildId, 144 ChannelInfo: channelInfo, 145 }) 146 } 147 case eventBody.ChangeChanInfo != nil: 148 updateChanLock.Lock() 149 defer updateChanLock.Unlock() 150 oldInfo := guild.FindChannel(eventBody.ChangeChanInfo.ChanId.Unwrap()) 151 if oldInfo == nil { 152 info, err := c.GuildService.FetchChannelInfo(m.Head.RoutingHead.GuildId.Unwrap(), eventBody.ChangeChanInfo.ChanId.Unwrap()) 153 if err != nil { 154 c.error("failed to decode channel info updated event: fetch channel info failed: %v", err) 155 return 156 } 157 guild.Channels = append(guild.Channels, info) 158 oldInfo = info 159 } 160 if time.Now().Unix()-oldInfo.fetchTime <= 2 { 161 return 162 } 163 newInfo, err := c.GuildService.FetchChannelInfo(m.Head.RoutingHead.GuildId.Unwrap(), eventBody.ChangeChanInfo.ChanId.Unwrap()) 164 if err != nil { 165 c.error("failed to decode channel info updated event: fetch channel info failed: %v", err) 166 return 167 } 168 for i := range guild.Channels { 169 if guild.Channels[i].ChannelId == newInfo.ChannelId { 170 guild.Channels[i] = newInfo 171 break 172 } 173 } 174 c.dispatchGuildChannelUpdatedEvent(&GuildChannelUpdatedEvent{ 175 OperatorId: m.Head.RoutingHead.FromTinyid.Unwrap(), 176 GuildId: m.Head.RoutingHead.GuildId.Unwrap(), 177 ChannelId: eventBody.ChangeChanInfo.ChanId.Unwrap(), 178 OldChannelInfo: oldInfo, 179 NewChannelInfo: newInfo, 180 }) 181 case eventBody.JoinGuild != nil: 182 /* 应该不会重复推送把, 不会吧不会吧 183 if mem := guild.FindMember(eventBody.JoinGuild.MemberTinyid.Unwrap()); mem != nil { 184 c.info("ignore join guild event: member %v already exists", mem.TinyId) 185 return 186 } 187 */ 188 profile, err := c.GuildService.FetchGuildMemberProfileInfo(guild.GuildId, eventBody.JoinGuild.MemberTinyid.Unwrap()) 189 if err != nil { 190 c.error("failed to decode member join guild event: get member profile error: %v", err) 191 return 192 } 193 info := &GuildMemberInfo{ 194 TinyId: profile.TinyId, 195 Nickname: profile.Nickname, 196 } 197 // guild.Members = append(guild.Members, info) 198 c.dispatchMemberJoinedGuildEvent(&MemberJoinGuildEvent{ 199 Guild: guild, 200 Member: info, 201 }) 202 case eventBody.UpdateMsg != nil: 203 if eventBody.UpdateMsg.EventType.Unwrap() == 1 || eventBody.UpdateMsg.EventType.Unwrap() == 2 { 204 c.dispatchGuildMessageRecalledEvent(&GuildMessageRecalledEvent{ 205 OperatorId: eventBody.UpdateMsg.OperatorTinyid.Unwrap(), 206 GuildId: m.Head.RoutingHead.GuildId.Unwrap(), 207 ChannelId: m.Head.RoutingHead.ChannelId.Unwrap(), 208 MessageId: eventBody.UpdateMsg.MsgSeq.Unwrap(), 209 RecallTime: int64(m.Head.ContentHead.Time.Unwrap()), 210 }) 211 return 212 } 213 if eventBody.UpdateMsg.EventType.Unwrap() == 4 { // 消息贴表情更新 (包含添加或删除) 214 t, err := c.GuildService.pullChannelMessages(m.Head.RoutingHead.GuildId.Unwrap(), m.Head.RoutingHead.ChannelId.Unwrap(), eventBody.UpdateMsg.MsgSeq.Unwrap(), eventBody.UpdateMsg.MsgSeq.Unwrap(), eventBody.UpdateMsg.EventVersion.Unwrap()-1, false) 215 if err != nil || len(t) == 0 { 216 c.error("process guild event flow error: pull eventMsg message error: %v", err) 217 return 218 } 219 // 自己的消息被贴表情会单独推送一个tips, 这里不需要解析 220 if t[0].Head.RoutingHead.FromTinyid.Unwrap() == c.GuildService.TinyId { 221 return 222 } 223 updatedEvent := &GuildMessageReactionsUpdatedEvent{ 224 GuildId: m.Head.RoutingHead.GuildId.Unwrap(), 225 ChannelId: m.Head.RoutingHead.ChannelId.Unwrap(), 226 MessageId: t[0].Head.ContentHead.Seq.Unwrap(), 227 CurrentReactions: decodeGuildMessageEmojiReactions(t[0]), 228 } 229 tipsInfo, err := c.waitPacketTimeoutSyncF("MsgPush.PushGroupProMsg", time.Second, func(i any) bool { 230 if i == nil { 231 return false 232 } 233 _, ok := i.(*tipsPushInfo) 234 return ok 235 }) 236 if err == nil { 237 updatedEvent.OperatorId = tipsInfo.(*tipsPushInfo).TinyId 238 // updatedEvent.MessageSenderUin = tipsInfo.(*tipsPushInfo).TargetMessageSenderUin 239 } 240 c.dispatchGuildMessageReactionsUpdatedEvent(updatedEvent) 241 } 242 } 243 }