1
0
mirror of https://github.com/Mrs4s/MiraiGo.git synced 2025-05-04 11:07:40 +08:00

restructure online push decoder.

This commit is contained in:
Mrs4s 2021-03-09 19:14:04 +08:00
parent 8c89d62657
commit ab3ed8f883
4 changed files with 259 additions and 283 deletions

View File

@ -68,89 +68,6 @@ func (c *QQClient) c2cMessageSyncProcessor(rsp *msg.GetMessageResponse, info *in
} else {
c.Debug("unknown msg type on c2c processor: %v", pMsg.Head.GetMsgType())
}
/*
switch pMsg.Head.GetMsgType() {
case 33: // 加群同步
func() {
groupJoinLock.Lock()
defer groupJoinLock.Unlock()
group := c.FindGroupByUin(pMsg.Head.GetFromUin())
if pMsg.Head.GetAuthUin() == c.Uin {
if group == nil && c.ReloadGroupList() == nil {
c.dispatchJoinGroupEvent(c.FindGroupByUin(pMsg.Head.GetFromUin()))
}
} else {
if group != nil && group.FindMember(pMsg.Head.GetAuthUin()) == nil {
mem, err := c.getMemberInfo(group.Code, pMsg.Head.GetAuthUin())
if err != nil {
c.Debug("error to fetch new member info: %v", err)
return
}
group.Update(func(info *GroupInfo) {
info.Members = append(info.Members, mem)
})
c.dispatchNewMemberEvent(&MemberJoinGroupEvent{
Group: group,
Member: mem,
})
}
}
}()
case 84, 87:
c.exceptAndDispatchGroupSysMsg()
case 141: // 临时会话
if pMsg.Head.C2CTmpMsgHead == nil {
continue
}
group := c.FindGroupByUin(pMsg.Head.C2CTmpMsgHead.GetGroupUin())
if group == nil {
continue
}
if pMsg.Head.GetFromUin() == c.Uin {
continue
}
c.dispatchTempMessage(c.parseTempMessage(pMsg))
case 166, 208: // 好友消息
if pMsg.Head.GetFromUin() == c.Uin {
for {
frdSeq := atomic.LoadInt32(&c.friendSeq)
if frdSeq < pMsg.Head.GetMsgSeq() {
if atomic.CompareAndSwapInt32(&c.friendSeq, frdSeq, pMsg.Head.GetMsgSeq()) {
break
}
} else {
break
}
}
}
if pMsg.Body.RichText == nil || pMsg.Body.RichText.Elems == nil {
continue
}
c.dispatchFriendMessage(c.parsePrivateMessage(pMsg))
case 187:
_, pkt := c.buildSystemMsgNewFriendPacket()
_ = c.send(pkt)
case 529:
sub4 := msg.SubMsgType0X4Body{}
if err := proto.Unmarshal(pMsg.Body.MsgContent, &sub4); err != nil {
err = errors.Wrap(err, "unmarshal sub msg 0x4 error")
c.Error("unmarshal sub msg 0x4 error: %v", err)
continue
}
if sub4.NotOnlineFile != nil {
rsp, err := c.sendAndWait(c.buildOfflineFileDownloadRequestPacket(sub4.NotOnlineFile.FileUuid)) // offline_file.go
if err != nil {
continue
}
c.dispatchOfflineFileEvent(&OfflineFileEvent{
FileName: string(sub4.NotOnlineFile.FileName),
FileSize: sub4.NotOnlineFile.GetFileSize(),
Sender: pMsg.Head.GetFromUin(),
DownloadUrl: rsp.(string),
})
}
}
*/
}
}
if delItems != nil {

View File

@ -16,7 +16,6 @@ import (
"github.com/Mrs4s/MiraiGo/client/pb/cmd0x352"
"github.com/Mrs4s/MiraiGo/client/pb/cmd0x6ff"
"github.com/Mrs4s/MiraiGo/client/pb/msg"
"github.com/Mrs4s/MiraiGo/client/pb/notify"
"github.com/Mrs4s/MiraiGo/client/pb/oidb"
"github.com/Mrs4s/MiraiGo/client/pb/profilecard"
"github.com/Mrs4s/MiraiGo/client/pb/qweb"
@ -520,205 +519,6 @@ func decodeOffPicUpResponse(_ *QQClient, _ *incomingPacketInfo, payload []byte)
}, nil
}
// OnlinePush.ReqPush
func decodeOnlinePushReqPacket(c *QQClient, info *incomingPacketInfo, payload []byte) (interface{}, error) {
request := &jce.RequestPacket{}
request.ReadFrom(jce.NewJceReader(payload))
data := &jce.RequestDataVersion2{}
data.ReadFrom(jce.NewJceReader(request.SBuffer))
jr := jce.NewJceReader(data.Map["req"]["OnlinePushPack.SvcReqPushMsg"][1:])
msgInfos := []jce.PushMessageInfo{}
uin := jr.ReadInt64(0)
jr.ReadSlice(&msgInfos, 2)
_ = c.send(c.buildDeleteOnlinePushPacket(uin, info.SequenceId, msgInfos))
for _, m := range msgInfos {
k := fmt.Sprintf("%v%v%v", m.MsgSeq, m.MsgTime, m.MsgUid)
if _, ok := c.onlinePushCache.Get(k); ok {
continue
}
c.onlinePushCache.Add(k, "", time.Second*30)
if m.MsgType == 732 {
r := binary.NewReader(m.VMsg)
groupId := int64(uint32(r.ReadInt32()))
iType := r.ReadByte()
r.ReadByte()
switch iType {
case 0x0c: // 群内禁言
operator := int64(uint32(r.ReadInt32()))
if operator == c.Uin {
continue
}
r.ReadBytes(6)
target := int64(uint32(r.ReadInt32()))
t := r.ReadInt32()
c.dispatchGroupMuteEvent(&GroupMuteEvent{
GroupCode: groupId,
OperatorUin: operator,
TargetUin: target,
Time: t,
})
case 0x10, 0x11, 0x14, 0x15: // group notify msg
r.ReadByte()
b := notify.NotifyMsgBody{}
_ = proto.Unmarshal(r.ReadAvailable(), &b)
if b.OptMsgRecall != nil {
for _, rm := range b.OptMsgRecall.RecalledMsgList {
if rm.MsgType == 2 {
continue
}
c.dispatchGroupMessageRecalledEvent(&GroupMessageRecalledEvent{
GroupCode: groupId,
OperatorUin: b.OptMsgRecall.Uin,
AuthorUin: rm.AuthorUin,
MessageId: rm.Seq,
Time: rm.Time,
})
}
}
if b.OptGeneralGrayTip != nil {
c.grayTipProcessor(groupId, b.OptGeneralGrayTip)
}
if b.OptMsgRedTips != nil {
if b.OptMsgRedTips.LuckyFlag == 1 { // 运气王提示
c.dispatchGroupNotifyEvent(&GroupRedBagLuckyKingNotifyEvent{
GroupCode: groupId,
Sender: int64(b.OptMsgRedTips.SenderUin),
LuckyKing: int64(b.OptMsgRedTips.LuckyUin),
})
}
}
if b.QqGroupDigestMsg != nil {
var digest = b.QqGroupDigestMsg
c.dispatchGroupDigestEvent(&GroupDigestEvent{
GroupCode: int64(digest.GroupCode),
MessageID: int32(digest.Seq),
InternalMessageID: int32(digest.Random),
OperationType: digest.OpType,
OperateTime: digest.OpTime,
SenderUin: int64(digest.Sender),
OperatorUin: int64(digest.DigestOper),
SenderNick: string(digest.SenderNick),
OperatorNick: string(digest.OperNick),
})
}
}
}
if m.MsgType == 528 {
vr := jce.NewJceReader(m.VMsg)
subType := vr.ReadInt64(0)
probuf := vr.ReadAny(10).([]byte)
switch subType {
case 0x8A, 0x8B:
s8a := pb.Sub8A{}
if err := proto.Unmarshal(probuf, &s8a); err != nil {
return nil, errors.Wrap(err, "failed to unmarshal protobuf message")
}
for _, m := range s8a.MsgInfo {
if m.ToUin == c.Uin {
c.dispatchFriendMessageRecalledEvent(&FriendMessageRecalledEvent{
FriendUin: m.FromUin,
MessageId: m.MsgSeq,
Time: m.MsgTime,
})
}
}
case 0xB3:
b3 := pb.SubB3{}
if err := proto.Unmarshal(probuf, &b3); err != nil {
return nil, errors.Wrap(err, "failed to unmarshal protobuf message")
}
frd := &FriendInfo{
Uin: b3.MsgAddFrdNotify.Uin,
Nickname: b3.MsgAddFrdNotify.Nick,
}
c.FriendList = append(c.FriendList, frd)
c.dispatchNewFriendEvent(&NewFriendEvent{Friend: frd})
case 0xD4:
d4 := pb.SubD4{}
if err := proto.Unmarshal(probuf, &d4); err != nil {
return nil, errors.Wrap(err, "failed to unmarshal protobuf message")
}
groupLeaveLock.Lock()
if g := c.FindGroup(d4.Uin); g != nil {
if err := c.ReloadGroupList(); err != nil {
groupLeaveLock.Unlock()
return nil, err
}
c.dispatchLeaveGroupEvent(&GroupLeaveEvent{Group: g})
}
groupLeaveLock.Unlock()
case 0x27:
s27 := pb.Sub27{}
if err := proto.Unmarshal(probuf, &s27); err != nil {
return nil, errors.Wrap(err, "failed to unmarshal protobuf message")
}
for _, m := range s27.ModInfos {
if m.DelFriend != nil {
frdUin := m.DelFriend.Uins[0]
if frd := c.FindFriend(int64(frdUin)); frd != nil {
if err := c.ReloadFriendList(); err != nil {
return nil, errors.Wrap(err, "failed to reload friend list")
}
}
}
}
case 290:
t := &notify.GeneralGrayTipInfo{}
_ = proto.Unmarshal(probuf, t)
var sender int64
for _, templ := range t.MsgTemplParam {
if templ.Name == "uin_str1" {
sender, _ = strconv.ParseInt(templ.Value, 10, 64)
}
}
if sender == 0 {
return nil, nil
}
c.dispatchFriendNotifyEvent(&FriendPokeNotifyEvent{
Sender: sender,
Receiver: c.Uin,
})
case 0x44:
s44 := pb.Sub44{}
if err := proto.Unmarshal(probuf, &s44); err != nil {
return nil, errors.Wrap(err, "failed to unmarshal protobuf message")
}
if s44.GroupSyncMsg != nil {
func() {
groupJoinLock.Lock()
defer groupJoinLock.Unlock()
if s44.GroupSyncMsg.GetGrpCode() != 0 { // member sync
c.Debug("syncing members.")
if group := c.FindGroup(s44.GroupSyncMsg.GetGrpCode()); group != nil {
group.Update(func(_ *GroupInfo) {
var lastJoinTime int64 = 0
for _, m := range group.Members {
if lastJoinTime < m.JoinTime {
lastJoinTime = m.JoinTime
}
}
if newMem, err := c.GetGroupMembers(group); err == nil {
group.Members = newMem
for _, m := range newMem {
if lastJoinTime < m.JoinTime {
go c.dispatchNewMemberEvent(&MemberJoinGroupEvent{
Group: group,
Member: m,
})
}
}
}
})
}
}
}()
}
}
}
}
return nil, nil
}
// OnlinePush.PbPushTransMsg
func decodeOnlinePushTransPacket(c *QQClient, _ *incomingPacketInfo, payload []byte) (interface{}, error) {
info := msg.TransMsgInfo{}

243
client/online_push.go Normal file
View File

@ -0,0 +1,243 @@
package client
import (
"fmt"
"github.com/Mrs4s/MiraiGo/binary"
"github.com/Mrs4s/MiraiGo/binary/jce"
"github.com/Mrs4s/MiraiGo/client/pb"
"github.com/Mrs4s/MiraiGo/client/pb/notify"
"github.com/pkg/errors"
"google.golang.org/protobuf/proto"
"strconv"
"time"
)
var msg0x210Decoders = map[int64]func(*QQClient, []byte) error{
0x8A: msgType0x210Sub8ADecoder, 0x8B: msgType0x210Sub8ADecoder, 0xB3: msgType0x210SubB3Decoder,
0xD4: msgType0x210SubD4Decoder, 0x27: msgType0x210Sub27Decoder, 0x122: msgType0x210Sub122Decoder,
0x123: msgType0x210Sub122Decoder, 0x44: msgType0x210Sub44Decoder,
}
// OnlinePush.ReqPush
func decodeOnlinePushReqPacket(c *QQClient, info *incomingPacketInfo, payload []byte) (interface{}, error) {
request := &jce.RequestPacket{}
request.ReadFrom(jce.NewJceReader(payload))
data := &jce.RequestDataVersion2{}
data.ReadFrom(jce.NewJceReader(request.SBuffer))
jr := jce.NewJceReader(data.Map["req"]["OnlinePushPack.SvcReqPushMsg"][1:])
msgInfos := []jce.PushMessageInfo{}
uin := jr.ReadInt64(0)
jr.ReadSlice(&msgInfos, 2)
_ = c.send(c.buildDeleteOnlinePushPacket(uin, info.SequenceId, msgInfos))
for _, m := range msgInfos {
k := fmt.Sprintf("%v%v%v", m.MsgSeq, m.MsgTime, m.MsgUid)
if _, ok := c.onlinePushCache.Get(k); ok {
continue
}
c.onlinePushCache.Add(k, "", time.Second*30)
// 0x2dc
if m.MsgType == 732 {
r := binary.NewReader(m.VMsg)
groupId := int64(uint32(r.ReadInt32()))
iType := r.ReadByte()
r.ReadByte()
switch iType {
case 0x0c: // 群内禁言
operator := int64(uint32(r.ReadInt32()))
if operator == c.Uin {
continue
}
r.ReadBytes(6)
target := int64(uint32(r.ReadInt32()))
t := r.ReadInt32()
c.dispatchGroupMuteEvent(&GroupMuteEvent{
GroupCode: groupId,
OperatorUin: operator,
TargetUin: target,
Time: t,
})
case 0x10, 0x11, 0x14, 0x15: // group notify msg
r.ReadByte()
b := notify.NotifyMsgBody{}
_ = proto.Unmarshal(r.ReadAvailable(), &b)
if b.OptMsgRecall != nil {
for _, rm := range b.OptMsgRecall.RecalledMsgList {
if rm.MsgType == 2 {
continue
}
c.dispatchGroupMessageRecalledEvent(&GroupMessageRecalledEvent{
GroupCode: groupId,
OperatorUin: b.OptMsgRecall.Uin,
AuthorUin: rm.AuthorUin,
MessageId: rm.Seq,
Time: rm.Time,
})
}
}
if b.OptGeneralGrayTip != nil {
c.grayTipProcessor(groupId, b.OptGeneralGrayTip)
}
if b.OptMsgRedTips != nil {
if b.OptMsgRedTips.LuckyFlag == 1 { // 运气王提示
c.dispatchGroupNotifyEvent(&GroupRedBagLuckyKingNotifyEvent{
GroupCode: groupId,
Sender: int64(b.OptMsgRedTips.SenderUin),
LuckyKing: int64(b.OptMsgRedTips.LuckyUin),
})
}
}
if b.QqGroupDigestMsg != nil {
var digest = b.QqGroupDigestMsg
c.dispatchGroupDigestEvent(&GroupDigestEvent{
GroupCode: int64(digest.GroupCode),
MessageID: int32(digest.Seq),
InternalMessageID: int32(digest.Random),
OperationType: digest.OpType,
OperateTime: digest.OpTime,
SenderUin: int64(digest.Sender),
OperatorUin: int64(digest.DigestOper),
SenderNick: string(digest.SenderNick),
OperatorNick: string(digest.OperNick),
})
}
}
}
// 0x210
if m.MsgType == 528 {
vr := jce.NewJceReader(m.VMsg)
subType := vr.ReadInt64(0)
protobuf := vr.ReadAny(10).([]byte)
if decoder, ok := msg0x210Decoders[subType]; ok {
if err := decoder(c, protobuf); err != nil {
return nil, errors.Wrap(err, "decode online push 0x210 error")
}
} else {
c.Debug("unknown online push 0x210 sub type 0x%v", strconv.FormatInt(subType, 16))
}
}
}
return nil, nil
}
func msgType0x210Sub8ADecoder(c *QQClient, protobuf []byte) error {
s8a := pb.Sub8A{}
if err := proto.Unmarshal(protobuf, &s8a); err != nil {
return errors.Wrap(err, "failed to unmarshal protobuf message")
}
for _, m := range s8a.MsgInfo {
if m.ToUin == c.Uin {
c.dispatchFriendMessageRecalledEvent(&FriendMessageRecalledEvent{
FriendUin: m.FromUin,
MessageId: m.MsgSeq,
Time: m.MsgTime,
})
}
}
return nil
}
func msgType0x210SubB3Decoder(c *QQClient, protobuf []byte) error {
b3 := pb.SubB3{}
if err := proto.Unmarshal(protobuf, &b3); err != nil {
return errors.Wrap(err, "failed to unmarshal protobuf message")
}
frd := &FriendInfo{
Uin: b3.MsgAddFrdNotify.Uin,
Nickname: b3.MsgAddFrdNotify.Nick,
}
c.FriendList = append(c.FriendList, frd)
c.dispatchNewFriendEvent(&NewFriendEvent{Friend: frd})
return nil
}
func msgType0x210SubD4Decoder(c *QQClient, protobuf []byte) error {
d4 := pb.SubD4{}
if err := proto.Unmarshal(protobuf, &d4); err != nil {
return errors.Wrap(err, "failed to unmarshal protobuf message")
}
groupLeaveLock.Lock()
if g := c.FindGroup(d4.Uin); g != nil {
if err := c.ReloadGroupList(); err != nil {
groupLeaveLock.Unlock()
return err
}
c.dispatchLeaveGroupEvent(&GroupLeaveEvent{Group: g})
}
groupLeaveLock.Unlock()
return nil
}
func msgType0x210Sub27Decoder(c *QQClient, protobuf []byte) error {
s27 := pb.Sub27{}
if err := proto.Unmarshal(protobuf, &s27); err != nil {
return errors.Wrap(err, "failed to unmarshal protobuf message")
}
for _, m := range s27.ModInfos {
if m.DelFriend != nil {
frdUin := m.DelFriend.Uins[0]
if frd := c.FindFriend(int64(frdUin)); frd != nil {
if err := c.ReloadFriendList(); err != nil {
return errors.Wrap(err, "failed to reload friend list")
}
}
}
}
return nil
}
func msgType0x210Sub122Decoder(c *QQClient, protobuf []byte) error {
t := &notify.GeneralGrayTipInfo{}
_ = proto.Unmarshal(protobuf, t)
var sender int64
for _, templ := range t.MsgTemplParam {
if templ.Name == "uin_str1" {
sender, _ = strconv.ParseInt(templ.Value, 10, 64)
}
}
if sender == 0 {
return nil
}
c.dispatchFriendNotifyEvent(&FriendPokeNotifyEvent{
Sender: sender,
Receiver: c.Uin,
})
return nil
}
func msgType0x210Sub44Decoder(c *QQClient, protobuf []byte) error {
s44 := pb.Sub44{}
if err := proto.Unmarshal(protobuf, &s44); err != nil {
return errors.Wrap(err, "failed to unmarshal protobuf message")
}
if s44.GroupSyncMsg != nil {
func() {
groupJoinLock.Lock()
defer groupJoinLock.Unlock()
if s44.GroupSyncMsg.GetGrpCode() != 0 { // member sync
c.Debug("syncing members.")
if group := c.FindGroup(s44.GroupSyncMsg.GetGrpCode()); group != nil {
group.Update(func(_ *GroupInfo) {
var lastJoinTime int64 = 0
for _, m := range group.Members {
if lastJoinTime < m.JoinTime {
lastJoinTime = m.JoinTime
}
}
if newMem, err := c.GetGroupMembers(group); err == nil {
group.Members = newMem
for _, m := range newMem {
if lastJoinTime < m.JoinTime {
go c.dispatchNewMemberEvent(&MemberJoinGroupEvent{
Group: group,
Member: m,
})
}
}
}
})
}
}
}()
}
return nil
}

View File

@ -111,6 +111,10 @@ func (c *QQClient) MarkGroupMessageReaded(groupCode, seq int64) {
_, _ = c.sendAndWait(c.buildGroupMsgReadedPacket(groupCode, seq))
}
func (c *QQClient) MarkPrivateMessageReaded(uin, time int64) {
_, _ = c.sendAndWait(c.buildPrivateMsgReadedPacket(uin, time))
}
// StatSvc.GetDevLoginInfo
func (c *QQClient) buildDeviceListRequestPacket() (uint16, []byte) {
seq := c.nextSeq()
@ -272,6 +276,18 @@ func (c *QQClient) buildGroupMsgReadedPacket(groupCode, msgSeq int64) (uint16, [
return seq, packet
}
func (c *QQClient) buildPrivateMsgReadedPacket(uin, time int64) (uint16, []byte) {
seq := c.nextSeq()
req, _ := proto.Marshal(&msg.PbMsgReadedReportReq{C2CReadReport: &msg.PbC2CReadedReportReq{PairInfo: []*msg.UinPairReadInfo{
{
PeerUin: proto.Uint64(uint64(uin)),
LastReadTime: proto.Uint32(uint32(time)),
},
}, SyncCookie: c.syncCookie}})
packet := packets.BuildUniPacket(c.Uin, seq, "PbMessageSvc.PbMsgReadedReport", 1, c.OutGoingPacketSessionId, []byte{}, c.sigInfo.d2Key, req)
return seq, packet
}
// StatSvc.GetDevLoginInfo
func decodeDevListResponse(_ *QQClient, _ *incomingPacketInfo, payload []byte) (interface{}, error) {
request := &jce.RequestPacket{}