github.com/Mrs4s/MiraiGo@v0.0.0-20240226124653-54bdd873e3fe/client/group_msg.go (about) 1 package client 2 3 import ( 4 "bytes" 5 "encoding/base64" 6 "encoding/json" 7 "math" 8 "math/rand" 9 "strconv" 10 "strings" 11 "time" 12 13 "github.com/pkg/errors" 14 15 "github.com/Mrs4s/MiraiGo/client/internal/network" 16 "github.com/Mrs4s/MiraiGo/client/pb/cmd0x388" 17 "github.com/Mrs4s/MiraiGo/client/pb/longmsg" 18 "github.com/Mrs4s/MiraiGo/client/pb/msg" 19 "github.com/Mrs4s/MiraiGo/client/pb/multimsg" 20 "github.com/Mrs4s/MiraiGo/client/pb/oidb" 21 "github.com/Mrs4s/MiraiGo/internal/proto" 22 "github.com/Mrs4s/MiraiGo/message" 23 "github.com/Mrs4s/MiraiGo/utils" 24 ) 25 26 func init() { 27 decoders["OnlinePush.PbPushGroupMsg"] = decodeGroupMessagePacket 28 decoders["MessageSvc.PbSendMsg"] = decodeMsgSendResponse 29 decoders["MessageSvc.PbGetGroupMsg"] = decodeGetGroupMsgResponse 30 decoders["OidbSvc.0x8a7_0"] = decodeAtAllRemainResponse 31 decoders["OidbSvc.0xeac_1"] = decodeEssenceMsgResponse 32 decoders["OidbSvc.0xeac_2"] = decodeEssenceMsgResponse 33 } 34 35 // SendGroupMessage 发送群消息 36 func (c *QQClient) SendGroupMessage(groupCode int64, m *message.SendingMessage) *message.GroupMessage { 37 imgCount := 0 38 for _, e := range m.Elements { 39 switch e.Type() { 40 case message.Image: 41 imgCount++ 42 } 43 } 44 msgLen := message.EstimateLength(m.Elements) 45 if msgLen > message.MaxMessageSize || imgCount > 50 { 46 return nil 47 } 48 return c.sendGroupMessage(groupCode, false, m) 49 } 50 51 // SendGroupForwardMessage 发送群合并转发消息 52 func (c *QQClient) SendGroupForwardMessage(groupCode int64, m *message.ForwardElement) *message.GroupMessage { 53 return c.sendGroupMessage(groupCode, true, 54 &message.SendingMessage{Elements: []message.IMessageElement{m}}, 55 ) 56 } 57 58 // GetGroupMessages 从服务器获取历史信息 59 func (c *QQClient) GetGroupMessages(groupCode, beginSeq, endSeq int64) ([]*message.GroupMessage, error) { 60 seq, pkt := c.buildGetGroupMsgRequest(groupCode, beginSeq, endSeq) 61 i, err := c.sendAndWait(seq, pkt, network.RequestParams{"raw": false}) 62 if err != nil { 63 return nil, err 64 } 65 return i.([]*message.GroupMessage), nil 66 } 67 68 func (c *QQClient) GetAtAllRemain(groupCode int64) (*AtAllRemainInfo, error) { 69 i, err := c.sendAndWait(c.buildAtAllRemainRequestPacket(groupCode)) 70 if err != nil { 71 return nil, err 72 } 73 return i.(*AtAllRemainInfo), nil 74 } 75 76 func (c *QQClient) sendGroupMessage(groupCode int64, forward bool, m *message.SendingMessage) *message.GroupMessage { 77 eid := utils.RandomString(6) 78 mr := int32(rand.Uint32()) 79 ch := make(chan int32, 1) 80 c.onGroupMessageReceipt(eid, func(c *QQClient, e *groupMessageReceiptEvent) { 81 if e.Rand == mr { 82 ch <- e.Seq 83 } 84 }) 85 defer c.onGroupMessageReceipt(eid) 86 imgCount := 0 87 serviceFlag := true 88 for _, e := range m.Elements { 89 switch e.Type() { 90 case message.Image: 91 imgCount++ 92 case message.Forward: 93 forward = true 94 fallthrough 95 case message.Reply, message.Voice, message.Service: 96 serviceFlag = false 97 } 98 } 99 if !forward && serviceFlag && c.UseFragmentMessage && (imgCount > 1 || message.EstimateLength(m.Elements) > 100) { 100 div := int32(rand.Uint32()) 101 fragmented := m.ToFragmented() 102 for i, elems := range fragmented { 103 _, pkt := c.buildGroupSendingPacket(groupCode, mr, int32(len(fragmented)), int32(i), div, forward, elems) 104 _ = c.sendPacket(pkt) 105 } 106 } else { 107 _, pkt := c.buildGroupSendingPacket(groupCode, mr, 1, 0, 0, forward, m.Elements) 108 _ = c.sendPacket(pkt) 109 } 110 var mid int32 111 ret := &message.GroupMessage{ 112 Id: -1, 113 InternalId: mr, 114 GroupCode: groupCode, 115 Sender: &message.Sender{ 116 Uin: c.Uin, 117 Nickname: c.Nickname, 118 IsFriend: true, 119 }, 120 Time: int32(time.Now().Unix()), 121 Elements: m.Elements, 122 } 123 select { 124 case mid = <-ch: 125 ret.Id = mid 126 return ret 127 case <-time.After(time.Second * 5): 128 if g, err := c.GetGroupInfo(groupCode); err == nil { 129 if history, err := c.GetGroupMessages(groupCode, g.LastMsgSeq-10, g.LastMsgSeq+1); err == nil { 130 for _, m := range history { 131 if m.InternalId == mr { 132 return m 133 } 134 } 135 } 136 } 137 return ret 138 } 139 } 140 141 func (c *QQClient) multiMsgApplyUp(groupCode int64, data []byte, hash []byte, buType int32) (*multimsg.MultiMsgApplyUpRsp, []byte, error) { 142 i, err := c.sendAndWait(c.buildMultiApplyUpPacket(data, hash, buType, utils.ToGroupUin(groupCode))) 143 if err != nil { 144 return nil, nil, err 145 } 146 rsp := i.(*multimsg.MultiMsgApplyUpRsp) 147 body, _ := proto.Marshal(&longmsg.LongReqBody{ 148 Subcmd: 1, 149 TermType: 5, 150 PlatformType: 9, 151 MsgUpReq: []*longmsg.LongMsgUpReq{ 152 { 153 MsgType: 3, 154 DstUin: utils.ToGroupUin(groupCode), 155 MsgContent: data, 156 StoreType: 2, 157 MsgUkey: rsp.MsgUkey, 158 }, 159 }, 160 }) 161 return rsp, body, nil 162 } 163 164 // MessageSvc.PbSendMsg 165 func (c *QQClient) buildGroupSendingPacket(groupCode int64, r, pkgNum, pkgIndex, pkgDiv int32, forward bool, m []message.IMessageElement) (uint16, []byte) { 166 var ptt *message.GroupVoiceElement 167 if len(m) > 0 { 168 if p, ok := m[0].(*message.GroupVoiceElement); ok { 169 ptt = p 170 m = []message.IMessageElement{} 171 } 172 } 173 req := &msg.SendMessageRequest{ 174 RoutingHead: &msg.RoutingHead{Grp: &msg.Grp{GroupCode: proto.Some(groupCode)}}, 175 ContentHead: &msg.ContentHead{PkgNum: proto.Some(pkgNum), PkgIndex: proto.Some(pkgIndex), DivSeq: proto.Some(pkgDiv)}, 176 MsgBody: &msg.MessageBody{ 177 RichText: &msg.RichText{ 178 Elems: message.ToProtoElems(m, true), 179 Ptt: func() *msg.Ptt { 180 if ptt != nil { 181 return ptt.Ptt 182 } 183 return nil 184 }(), 185 }, 186 }, 187 MsgSeq: proto.Int32(c.nextGroupSeq()), 188 MsgRand: proto.Some(r), 189 SyncCookie: EmptyBytes, 190 MsgVia: proto.Int32(1), 191 MsgCtrl: func() *msg.MsgCtrl { 192 if forward { 193 return &msg.MsgCtrl{MsgFlag: proto.Int32(4)} 194 } 195 return nil 196 }(), 197 } 198 payload, _ := proto.Marshal(req) 199 return c.uniPacket("MessageSvc.PbSendMsg", payload) 200 } 201 202 func (c *QQClient) buildGetGroupMsgRequest(groupCode, beginSeq, endSeq int64) (uint16, []byte) { 203 req := &msg.GetGroupMsgReq{ 204 GroupCode: proto.Uint64(uint64(groupCode)), 205 BeginSeq: proto.Uint64(uint64(beginSeq)), 206 EndSeq: proto.Uint64(uint64(endSeq)), 207 PublicGroup: proto.Bool(false), 208 } 209 payload, _ := proto.Marshal(req) 210 return c.uniPacket("MessageSvc.PbGetGroupMsg", payload) 211 } 212 213 func (c *QQClient) buildAtAllRemainRequestPacket(groupCode int64) (uint16, []byte) { 214 payload := c.packOIDBPackageProto(2215, 0, &oidb.D8A7ReqBody{ 215 SubCmd: proto.Uint32(1), 216 LimitIntervalTypeForUin: proto.Uint32(2), 217 LimitIntervalTypeForGroup: proto.Uint32(1), 218 Uin: proto.Uint64(uint64(c.Uin)), 219 GroupCode: proto.Uint64(uint64(groupCode)), 220 }) 221 return c.uniPacket("OidbSvc.0x8a7_0", payload) 222 } 223 224 // OnlinePush.PbPushGroupMsg 225 func decodeGroupMessagePacket(c *QQClient, packet *network.Packet) (any, error) { 226 pkt := msg.PushMessagePacket{} 227 err := proto.Unmarshal(packet.Payload, &pkt) 228 if err != nil { 229 return nil, errors.Wrap(err, "failed to unmarshal protobuf message") 230 } 231 if pkt.Message.Head.FromUin.Unwrap() == c.Uin { 232 c.dispatchGroupMessageReceiptEvent(&groupMessageReceiptEvent{ 233 Rand: pkt.Message.Body.RichText.Attr.Random.Unwrap(), 234 Seq: pkt.Message.Head.MsgSeq.Unwrap(), 235 Msg: c.parseGroupMessage(pkt.Message), 236 }) 237 } 238 if pkt.Message.Content != nil && pkt.Message.Content.PkgNum.Unwrap() > 1 { 239 seq := pkt.Message.Content.DivSeq.Unwrap() 240 builder := c.messageBuilder(pkt.Message.Content.DivSeq.Unwrap()) 241 builder.append(pkt.Message) 242 if builder.len() >= pkt.Message.Content.PkgNum.Unwrap() { 243 c.msgBuilders.Delete(seq) 244 if pkt.Message.Head.FromUin.Unwrap() == c.Uin { 245 c.SelfGroupMessageEvent.dispatch(c, c.parseGroupMessage(builder.build())) 246 } else { 247 c.GroupMessageEvent.dispatch(c, c.parseGroupMessage(builder.build())) 248 } 249 } 250 return nil, nil 251 } 252 if pkt.Message.Head.FromUin.Unwrap() == c.Uin { 253 c.SelfGroupMessageEvent.dispatch(c, c.parseGroupMessage(pkt.Message)) 254 } else { 255 c.GroupMessageEvent.dispatch(c, c.parseGroupMessage(pkt.Message)) 256 } 257 return nil, nil 258 } 259 260 func decodeMsgSendResponse(c *QQClient, pkt *network.Packet) (any, error) { 261 rsp := msg.SendMessageResponse{} 262 if err := proto.Unmarshal(pkt.Payload, &rsp); err != nil { 263 return nil, errors.Wrap(err, "failed to unmarshal protobuf message") 264 } 265 switch rsp.Result.Unwrap() { 266 case 0: // OK. 267 case 46: 268 c.error("sendPacket msg error: 需要使用安全设备验证") 269 case 55: 270 c.error("sendPacket msg error: %v Bot has been blocked ta.'s content", rsp.Result.Unwrap()) 271 default: 272 c.error("sendPacket msg error: %v %v", rsp.Result.Unwrap(), rsp.ErrMsg.Unwrap()) 273 } 274 return nil, nil 275 } 276 277 func decodeGetGroupMsgResponse(c *QQClient, pkt *network.Packet) (any, error) { 278 rsp := msg.GetGroupMsgResp{} 279 if err := proto.Unmarshal(pkt.Payload, &rsp); err != nil { 280 return nil, errors.Wrap(err, "failed to unmarshal protobuf message") 281 } 282 if rsp.Result.Unwrap() != 0 { 283 c.error("get msg error: %v %v", rsp.Result.Unwrap(), rsp.Errmsg.Unwrap()) 284 return nil, errors.Errorf("get msg error: %v msg: %v", rsp.Result.Unwrap(), rsp.Errmsg.Unwrap()) 285 } 286 var ret []*message.GroupMessage 287 for _, m := range rsp.Msg { 288 if m.Head.FromUin.IsNone() { 289 continue 290 } 291 if m.Content != nil && m.Content.PkgNum.Unwrap() > 1 && !pkt.Params.Bool("raw") { 292 if m.Content.PkgIndex.Unwrap() == 0 { 293 c.debug("build fragmented message from history") 294 i := m.Head.MsgSeq.Unwrap() - m.Content.PkgNum.Unwrap() 295 builder := &messageBuilder{} 296 for { 297 end := int32(math.Min(float64(i+19), float64(m.Head.MsgSeq.Unwrap()+m.Content.PkgNum.Unwrap()))) 298 seq, pkt := c.buildGetGroupMsgRequest(m.Head.GroupInfo.GroupCode.Unwrap(), int64(i), int64(end)) 299 data, err := c.sendAndWait(seq, pkt, network.RequestParams{"raw": true}) 300 if err != nil { 301 return nil, errors.Wrap(err, "build fragmented message error") 302 } 303 for _, fm := range data.([]*message.GroupMessage) { 304 if fm.OriginalObject.Content != nil && fm.OriginalObject.Content.DivSeq.Unwrap() == m.Content.DivSeq.Unwrap() { 305 builder.append(fm.OriginalObject) 306 } 307 } 308 if end >= m.Head.MsgSeq.Unwrap()+m.Content.PkgNum.Unwrap() { 309 break 310 } 311 i = end 312 } 313 if elem := c.parseGroupMessage(builder.build()); elem != nil { 314 ret = append(ret, elem) 315 } 316 } 317 continue 318 } 319 if elem := c.parseGroupMessage(m); elem != nil { 320 ret = append(ret, elem) 321 } 322 } 323 return ret, nil 324 } 325 326 func decodeAtAllRemainResponse(_ *QQClient, pkt *network.Packet) (any, error) { 327 rsp := oidb.D8A7RspBody{} 328 err := unpackOIDBPackage(pkt.Payload, &rsp) 329 if err != nil { 330 return nil, err 331 } 332 return &AtAllRemainInfo{ 333 CanAtAll: rsp.CanAtAll.Unwrap(), 334 RemainAtAllCountForGroup: rsp.RemainAtAllCountForGroup.Unwrap(), 335 RemainAtAllCountForUin: rsp.RemainAtAllCountForUin.Unwrap(), 336 }, nil 337 } 338 339 func (c *QQClient) parseGroupMessage(m *msg.Message) *message.GroupMessage { 340 group := c.FindGroup(m.Head.GroupInfo.GroupCode.Unwrap()) 341 if group == nil { 342 c.debug("sync group %v.", m.Head.GroupInfo.GroupCode.Unwrap()) 343 info, err := c.GetGroupInfo(m.Head.GroupInfo.GroupCode.Unwrap()) 344 if err != nil { 345 c.error("failed to sync group %v : %+v", m.Head.GroupInfo.GroupCode.Unwrap(), err) 346 return nil 347 } 348 group = info 349 c.GroupList = append(c.GroupList, info) 350 } 351 if len(group.Members) == 0 { 352 mem, err := c.GetGroupMembers(group) 353 if err != nil { 354 c.error("failed to sync group %v members : %+v", m.Head.GroupInfo.GroupCode, err) 355 return nil 356 } 357 group.Members = mem 358 } 359 var anonInfo *msg.AnonymousGroupMessage 360 for _, e := range m.Body.RichText.Elems { 361 if e.AnonGroupMsg != nil { 362 anonInfo = e.AnonGroupMsg 363 } 364 } 365 var sender *message.Sender 366 if anonInfo != nil { 367 sender = &message.Sender{ 368 Uin: 80000000, 369 Nickname: string(anonInfo.AnonNick), 370 AnonymousInfo: &message.AnonymousInfo{ 371 AnonymousId: base64.StdEncoding.EncodeToString(anonInfo.AnonId), 372 AnonymousNick: string(anonInfo.AnonNick), 373 }, 374 IsFriend: false, 375 } 376 } else { 377 mem := group.FindMember(m.Head.FromUin.Unwrap()) 378 if mem == nil { 379 group.Update(func(_ *GroupInfo) { 380 if mem = group.FindMemberWithoutLock(m.Head.FromUin.Unwrap()); mem != nil { 381 return 382 } 383 info, _ := c.GetMemberInfo(group.Code, m.Head.FromUin.Unwrap()) 384 if info == nil { 385 return 386 } 387 mem = info 388 group.Members = append(group.Members, mem) 389 group.sort() 390 go c.GroupMemberJoinEvent.dispatch(c, &MemberJoinGroupEvent{ 391 Group: group, 392 Member: info, 393 }) 394 }) 395 if mem == nil { 396 return nil 397 } 398 } 399 sender = &message.Sender{ 400 Uin: mem.Uin, 401 Nickname: mem.Nickname, 402 CardName: mem.CardName, 403 IsFriend: c.FindFriend(mem.Uin) != nil, 404 } 405 } 406 var g *message.GroupMessage 407 g = &message.GroupMessage{ 408 Id: m.Head.MsgSeq.Unwrap(), 409 GroupCode: group.Code, 410 GroupName: string(m.Head.GroupInfo.GroupName), 411 Sender: sender, 412 Time: m.Head.MsgTime.Unwrap(), 413 Elements: message.ParseMessageElems(m.Body.RichText.Elems), 414 OriginalObject: m, 415 } 416 var extInfo *msg.ExtraInfo 417 // pre parse 418 for _, elem := range m.Body.RichText.Elems { 419 // is rich long msg 420 if elem.GeneralFlags != nil && elem.GeneralFlags.LongTextResid.Unwrap() != "" && len(g.Elements) == 1 { 421 if f := c.GetForwardMessage(elem.GeneralFlags.LongTextResid.Unwrap()); f != nil && len(f.Nodes) == 1 { 422 g = &message.GroupMessage{ 423 Id: m.Head.MsgSeq.Unwrap(), 424 GroupCode: group.Code, 425 GroupName: string(m.Head.GroupInfo.GroupName), 426 Sender: sender, 427 Time: m.Head.MsgTime.Unwrap(), 428 Elements: f.Nodes[0].Message, 429 OriginalObject: m, 430 } 431 } 432 } 433 if elem.ExtraInfo != nil { 434 extInfo = elem.ExtraInfo 435 } 436 } 437 if !sender.IsAnonymous() { 438 mem := group.FindMember(m.Head.FromUin.Unwrap()) 439 groupCard := m.Head.GroupInfo.GroupCard.Unwrap() 440 if extInfo != nil && len(extInfo.GroupCard) > 0 && extInfo.GroupCard[0] == 0x0A { 441 buf := oidb.D8FCCommCardNameBuf{} 442 if err := proto.Unmarshal(extInfo.GroupCard, &buf); err == nil && len(buf.RichCardName) > 0 { 443 var gcard strings.Builder 444 for _, e := range buf.RichCardName { 445 gcard.Write(e.Text) 446 } 447 groupCard = gcard.String() 448 } 449 } 450 if m.Head.GroupInfo != nil && groupCard != "" && mem.CardName != groupCard { 451 old := mem.CardName 452 if mem.Nickname == groupCard { 453 mem.CardName = "" 454 } else { 455 mem.CardName = groupCard 456 } 457 if old != mem.CardName { 458 c.MemberCardUpdatedEvent.dispatch(c, &MemberCardUpdatedEvent{ 459 Group: group, 460 OldCard: old, 461 Member: mem, 462 }) 463 } 464 } 465 } 466 if m.Body.RichText.Ptt != nil { 467 var url string 468 if len(m.Body.RichText.Ptt.DownPara) == 0 { 469 req := &cmd0x388.D388ReqBody{ 470 NetType: proto.Uint32(3), 471 Subcmd: proto.Uint32(4), 472 GetpttUrlReq: []*cmd0x388.GetPttUrlReq{ 473 { 474 GroupCode: proto.Uint64(uint64(m.Head.GroupInfo.GroupCode.Unwrap())), 475 DstUin: proto.Uint64(uint64(m.Head.ToUin.Unwrap())), 476 Fileid: proto.Uint64(uint64(m.Body.RichText.Ptt.FileId.Unwrap())), 477 FileMd5: m.Body.RichText.Ptt.FileMd5, 478 ReqTerm: proto.Uint32(5), 479 ReqPlatformType: proto.Uint32(9), 480 InnerIp: proto.Uint32(0), 481 BuType: proto.Uint32(3), 482 FileId: proto.Uint64(0), 483 FileKey: m.Body.RichText.Ptt.FileKey, 484 ReqTransferType: proto.Uint32(2), 485 IsAuto: proto.Uint32(1), 486 }, 487 }, 488 } 489 payload, _ := proto.Marshal(req) 490 rsp_raw, _ := c.sendAndWaitDynamic(c.uniPacket("PttStore.GroupPttDown", payload)) 491 rsp := new(cmd0x388.D388RspBody) 492 proto.Unmarshal(rsp_raw, rsp) 493 resp := rsp.GetpttUrlRsp[0] 494 url = "http://" + string(resp.DownDomain) + string(resp.DownPara) 495 } else { 496 url = "http://grouptalk.c2c.qq.com" + string(m.Body.RichText.Ptt.DownPara) 497 } 498 499 g.Elements = []message.IMessageElement{ 500 &message.VoiceElement{ 501 Name: m.Body.RichText.Ptt.FileName.Unwrap(), 502 Md5: m.Body.RichText.Ptt.FileMd5, 503 Size: m.Body.RichText.Ptt.FileSize.Unwrap(), 504 Url: url, 505 }, 506 } 507 } 508 if m.Body.RichText.Attr != nil { 509 g.InternalId = m.Body.RichText.Attr.Random.Unwrap() 510 } 511 return g 512 } 513 514 // SetEssenceMessage 设为群精华消息 515 func (c *QQClient) SetEssenceMessage(groupCode int64, msgID, msgInternalId int32) error { 516 r, err := c.sendAndWait(c.buildEssenceMsgOperatePacket(groupCode, uint32(msgID), uint32(msgInternalId), 1)) 517 if err != nil { 518 return errors.Wrap(err, "set essence msg network") 519 } 520 rsp := r.(*oidb.EACRspBody) 521 if rsp.ErrorCode.Unwrap() != 0 { 522 return errors.New(rsp.Wording.Unwrap()) 523 } 524 return nil 525 } 526 527 // DeleteEssenceMessage 移出群精华消息 528 func (c *QQClient) DeleteEssenceMessage(groupCode int64, msgID, msgInternalId int32) error { 529 r, err := c.sendAndWait(c.buildEssenceMsgOperatePacket(groupCode, uint32(msgID), uint32(msgInternalId), 2)) 530 if err != nil { 531 return errors.Wrap(err, "set essence msg networ") 532 } 533 rsp := r.(*oidb.EACRspBody) 534 if rsp.ErrorCode.Unwrap() != 0 { 535 return errors.New(rsp.Wording.Unwrap()) 536 } 537 return nil 538 } 539 540 func (c *QQClient) buildEssenceMsgOperatePacket(groupCode int64, msgSeq, msgRand, opType uint32) (uint16, []byte) { 541 commandName := "OidbSvc.0xeac_" + strconv.FormatInt(int64(opType), 10) 542 payload := c.packOIDBPackageProto(3756, int32(opType), &oidb.EACReqBody{ // serviceType 2 取消 543 GroupCode: proto.Uint64(uint64(groupCode)), 544 Seq: proto.Uint32(msgSeq), 545 Random: proto.Uint32(msgRand), 546 }) 547 return c.uniPacket(commandName, payload) 548 } 549 550 // OidbSvc.0xeac_1/2 551 func decodeEssenceMsgResponse(_ *QQClient, pkt *network.Packet) (any, error) { 552 rsp := &oidb.EACRspBody{} 553 err := unpackOIDBPackage(pkt.Payload, &rsp) 554 if err != nil { 555 return nil, err 556 } 557 return rsp, nil 558 } 559 560 // GetGroupEssenceMsgList 获取群精华消息列表 561 func (c *QQClient) GetGroupEssenceMsgList(groupCode int64) ([]GroupDigest, error) { 562 essenceURL := "https://qun.qq.com/essence/index?gc=" + strconv.FormatInt(groupCode, 10) + "&_wv=3&_wwv=128&_wvx=2&_wvxBclr=f5f6fa" 563 rsp, err := utils.HttpGetBytes(essenceURL, c.getCookiesWithDomain("qun.qq.com")) 564 if err != nil { 565 return nil, errors.Wrap(err, "get essence msg network error") 566 } 567 rsp = rsp[bytes.Index(rsp, []byte("window.__INITIAL_STATE__={"))+25:] 568 rsp = rsp[:bytes.Index(rsp, []byte("</script>"))] 569 data := &struct { 570 List []GroupDigest `json:"msgList"` 571 }{} 572 err = json.Unmarshal(rsp, data) 573 if err != nil { 574 return nil, errors.Wrap(err, "failed to unmarshal json") 575 } 576 return data.List, nil 577 }