github.com/Mrs4s/MiraiGo@v0.0.0-20240226124653-54bdd873e3fe/client/c2c_processor.go (about) 1 package client 2 3 //go:generate go run github.com/Mrs4s/MiraiGo/internal/generator/c2c_switcher 4 5 import ( 6 "fmt" 7 "time" 8 9 "github.com/pkg/errors" 10 11 "github.com/Mrs4s/MiraiGo/binary" 12 "github.com/Mrs4s/MiraiGo/client/internal/network" 13 "github.com/Mrs4s/MiraiGo/client/pb" 14 "github.com/Mrs4s/MiraiGo/client/pb/msg" 15 "github.com/Mrs4s/MiraiGo/internal/proto" 16 ) 17 18 type ( 19 TempSessionInfo struct { 20 Source TempSessionSource 21 GroupCode int64 22 Sender int64 23 24 sig []byte 25 client *QQClient 26 } 27 TempSessionSource int 28 ) 29 30 const ( 31 GroupSource TempSessionSource = iota // 来自群聊 32 ConsultingSource // 来自QQ咨询 33 SearchSource // 来自查找 34 MovieSource // 来自QQ电影 35 HotChatSource // 来自热聊 36 SystemMessageSource // 来自验证消息 37 MultiChatSource // 来自多人聊天 38 DateSource // 来自约会 39 AddressBookSource // 来自通讯录 40 ) 41 42 func (c *QQClient) c2cMessageSyncProcessor(rsp *msg.GetMessageResponse, info network.RequestParams) { 43 c.sig.SyncCookie = rsp.SyncCookie 44 c.sig.PubAccountCookie = rsp.PubAccountCookie 45 // c.msgCtrlBuf = rsp.MsgCtrlBuf 46 if rsp.UinPairMsgs == nil { 47 return 48 } 49 var delItems []*pb.MessageItem 50 for _, pairMsg := range rsp.UinPairMsgs { 51 for _, pMsg := range pairMsg.Messages { 52 // delete message 53 delItem := &pb.MessageItem{ 54 FromUin: pMsg.Head.FromUin.Unwrap(), 55 ToUin: pMsg.Head.ToUin.Unwrap(), 56 MsgType: pMsg.Head.MsgType.Unwrap(), 57 MsgSeq: pMsg.Head.MsgSeq.Unwrap(), 58 MsgUid: pMsg.Head.MsgUid.Unwrap(), 59 } 60 delItems = append(delItems, delItem) 61 if pMsg.Head.ToUin.Unwrap() != c.Uin { 62 continue 63 } 64 if (int64(pairMsg.LastReadTime.Unwrap()) & 4294967295) > int64(pMsg.Head.MsgTime.Unwrap()) { 65 continue 66 } 67 c.commMsgProcessor(pMsg, info) 68 } 69 } 70 if delItems != nil { 71 _, _ = c.sendAndWait(c.buildDeleteMessageRequestPacket(delItems)) 72 } 73 if rsp.SyncFlag.Unwrap() != msg.SyncFlag_STOP { 74 c.debug("continue sync with flag: %v", rsp.SyncFlag) 75 seq, pkt := c.buildGetMessageRequestPacket(rsp.SyncFlag.Unwrap(), time.Now().Unix()) 76 _, _ = c.sendAndWait(seq, pkt, info) 77 } 78 } 79 80 func (c *QQClient) commMsgProcessor(pMsg *msg.Message, info network.RequestParams) { 81 strKey := fmt.Sprintf("%d%d%d%d", pMsg.Head.FromUin.Unwrap(), pMsg.Head.ToUin.Unwrap(), pMsg.Head.MsgSeq.Unwrap(), pMsg.Head.MsgUid.Unwrap()) 82 if _, ok := c.msgSvcCache.GetAndUpdate(strKey, time.Hour); ok { 83 c.debug("c2c msg %v already exists in cache. skip.", pMsg.Head.MsgUid.Unwrap()) 84 return 85 } 86 c.msgSvcCache.Add(strKey, unit{}, time.Hour) 87 if c.lastC2CMsgTime > int64(pMsg.Head.MsgTime.Unwrap()) && (c.lastC2CMsgTime-int64(pMsg.Head.MsgTime.Unwrap())) > 60*10 { 88 c.debug("c2c msg filtered by time. lastMsgTime: %v msgTime: %v", c.lastC2CMsgTime, pMsg.Head.MsgTime.Unwrap()) 89 return 90 } 91 c.lastC2CMsgTime = int64(pMsg.Head.MsgTime.Unwrap()) 92 if info.Bool("init") { 93 return 94 } 95 if decoder, _ := peekC2CDecoder(pMsg.Head.MsgType.Unwrap()); decoder != nil { 96 decoder(c, pMsg, info) 97 } else { 98 c.debug("unknown msg type on c2c processor: %v - %v", pMsg.Head.MsgType.Unwrap(), pMsg.Head.C2CCmd.Unwrap()) 99 } 100 } 101 102 func privateMessageDecoder(c *QQClient, pMsg *msg.Message, _ network.RequestParams) { 103 switch pMsg.Head.C2CCmd.Unwrap() { 104 case 11, 175: // friend msg 105 if pMsg.Head.FromUin.Unwrap() == c.Uin { 106 for { 107 frdSeq := c.friendSeq.Load() 108 if frdSeq < pMsg.Head.MsgSeq.Unwrap() { 109 if c.friendSeq.CompareAndSwap(frdSeq, pMsg.Head.MsgSeq.Unwrap()) { 110 break 111 } 112 } else { 113 break 114 } 115 } 116 } 117 if pMsg.Body.RichText == nil || pMsg.Body.RichText.Elems == nil { 118 return 119 } 120 121 // handle fragmented message 122 if pMsg.Content != nil && pMsg.Content.PkgNum.Unwrap() > 1 { 123 seq := pMsg.Content.DivSeq.Unwrap() 124 builder := c.messageBuilder(seq) 125 builder.append(pMsg) 126 if builder.len() < pMsg.Content.PkgNum.Unwrap() { 127 // continue to receive other fragments 128 return 129 } 130 c.msgBuilders.Delete(seq) 131 pMsg = builder.build() 132 } 133 134 if pMsg.Head.FromUin.Unwrap() == c.Uin { 135 c.SelfPrivateMessageEvent.dispatch(c, c.parsePrivateMessage(pMsg)) 136 return 137 } 138 c.PrivateMessageEvent.dispatch(c, c.parsePrivateMessage(pMsg)) 139 default: 140 c.debug("unknown c2c cmd on private msg decoder: %v", pMsg.Head.C2CCmd.Unwrap()) 141 } 142 } 143 144 func privatePttDecoder(c *QQClient, pMsg *msg.Message, _ network.RequestParams) { 145 if pMsg.Body == nil || pMsg.Body.RichText == nil || pMsg.Body.RichText.Ptt == nil { 146 return 147 } 148 // if len(pMsg.Body.RichText.Ptt.Reserve) != 0 { 149 // m := binary.NewReader(pMsg.Body.RichText.Ptt.Reserve[1:]).ReadTlvMap(1) 150 // T3 -> timestamp T8 -> voiceType T9 -> voiceLength T10 -> PbReserveStruct 151 //} 152 c.PrivateMessageEvent.dispatch(c, c.parsePrivateMessage(pMsg)) 153 } 154 155 func tempSessionDecoder(c *QQClient, pMsg *msg.Message, _ network.RequestParams) { 156 if pMsg.Head.C2CTmpMsgHead == nil || pMsg.Body == nil { 157 return 158 } 159 if (pMsg.Head.MsgType.Unwrap() == 529 && pMsg.Head.C2CCmd.Unwrap() == 6) || pMsg.Body.RichText != nil { 160 genTempSessionInfo := func() *TempSessionInfo { 161 if pMsg.Head.C2CTmpMsgHead.ServiceType.Unwrap() == 0 { 162 group := c.FindGroup(pMsg.Head.C2CTmpMsgHead.GroupCode.Unwrap()) 163 if group == nil { 164 return nil 165 } 166 return &TempSessionInfo{ 167 Source: GroupSource, 168 GroupCode: group.Code, 169 Sender: pMsg.Head.FromUin.Unwrap(), 170 client: c, 171 } 172 } 173 info := &TempSessionInfo{ 174 Source: 0, 175 Sender: pMsg.Head.FromUin.Unwrap(), 176 sig: pMsg.Head.C2CTmpMsgHead.Sig, 177 client: c, 178 } 179 180 switch pMsg.Head.C2CTmpMsgHead.ServiceType.Unwrap() { 181 case 1: 182 info.Source = MultiChatSource 183 case 130: 184 info.Source = AddressBookSource 185 case 132: 186 info.Source = HotChatSource 187 case 134: 188 info.Source = SystemMessageSource 189 case 201: 190 info.Source = ConsultingSource 191 default: 192 return nil 193 } 194 return info 195 } 196 session := genTempSessionInfo() 197 if session == nil { 198 return 199 } 200 /* 201 group := c.FindGroup(pMsg.Head.C2CTmpMsgHead.GroupCode.Unwrap()) 202 if group == nil { 203 return 204 } 205 */ 206 if pMsg.Head.FromUin.Unwrap() == c.Uin { 207 return 208 } 209 c.TempMessageEvent.dispatch(c, &TempMessageEvent{ 210 Message: c.parseTempMessage(pMsg), 211 Session: session, 212 }) 213 } 214 } 215 216 func troopAddMemberBroadcastDecoder(c *QQClient, pMsg *msg.Message, _ network.RequestParams) { 217 groupJoinLock.Lock() 218 defer groupJoinLock.Unlock() 219 group := c.FindGroupByUin(pMsg.Head.FromUin.Unwrap()) 220 if pMsg.Head.AuthUin.Unwrap() == c.Uin { 221 if group == nil && c.ReloadGroupList() == nil { 222 c.GroupJoinEvent.dispatch(c, c.FindGroupByUin(pMsg.Head.FromUin.Unwrap())) 223 } 224 } else { 225 if group != nil && group.FindMember(pMsg.Head.AuthUin.Unwrap()) == nil { 226 mem, err := c.GetMemberInfo(group.Code, pMsg.Head.AuthUin.Unwrap()) 227 if err != nil { 228 c.debug("failed to fetch new member info: %v", err) 229 return 230 } 231 group.Update(func(info *GroupInfo) { 232 info.Members = append(info.Members, mem) 233 info.sort() 234 }) 235 c.GroupMemberJoinEvent.dispatch(c, &MemberJoinGroupEvent{ 236 Group: group, 237 Member: mem, 238 }) 239 } 240 } 241 } 242 243 func systemMessageDecoder(c *QQClient, _ *msg.Message, _ network.RequestParams) { 244 _, pkt := c.buildSystemMsgNewFriendPacket() 245 _ = c.sendPacket(pkt) 246 } 247 248 func troopSystemMessageDecoder(c *QQClient, pMsg *msg.Message, info network.RequestParams) { 249 if !info.Bool("used_reg_proxy") && pMsg.Head.MsgType.Unwrap() != 85 && pMsg.Head.MsgType.Unwrap() != 36 { 250 c.exceptAndDispatchGroupSysMsg() 251 } 252 if len(pMsg.Body.MsgContent) == 0 { 253 return 254 } 255 reader := binary.NewReader(pMsg.Body.MsgContent) 256 groupCode := uint32(reader.ReadInt32()) 257 if info := c.FindGroup(int64(groupCode)); info != nil && pMsg.Head.GroupName.Unwrap() != "" && info.Name != pMsg.Head.GroupName.Unwrap() { 258 c.debug("group %v name updated. %v -> %v", groupCode, info.Name, pMsg.Head.GroupName.Unwrap()) 259 info.Name = pMsg.Head.GroupName.Unwrap() 260 } 261 } 262 263 func msgType0x211Decoder(c *QQClient, pMsg *msg.Message, info network.RequestParams) { 264 if pMsg.Head.C2CCmd.Unwrap() == 6 || pMsg.Head.C2CTmpMsgHead != nil { 265 tempSessionDecoder(c, pMsg, info) 266 } 267 sub4 := msg.SubMsgType0X4Body{} 268 if err := proto.Unmarshal(pMsg.Body.MsgContent, &sub4); err != nil { 269 err = errors.Wrap(err, "unmarshal sub msg 0x4 error") 270 c.error("unmarshal sub msg 0x4 error: %v", err) 271 return 272 } 273 if sub4.NotOnlineFile != nil && sub4.NotOnlineFile.Subcmd.Unwrap() == 1 { // subcmd: 1 -> sendPacket, 2-> recv 274 rsp, err := c.sendAndWait(c.buildOfflineFileDownloadRequestPacket(sub4.NotOnlineFile.FileUuid)) // offline_file.go 275 if err != nil { 276 return 277 } 278 c.OfflineFileEvent.dispatch(c, &OfflineFileEvent{ 279 FileName: string(sub4.NotOnlineFile.FileName), 280 FileSize: sub4.NotOnlineFile.FileSize.Unwrap(), 281 Sender: pMsg.Head.FromUin.Unwrap(), 282 DownloadUrl: rsp.(string), 283 }) 284 } 285 }