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

fix issue of repeatedly trigger for OnlinePush events.

This commit is contained in:
Mrs4s 2020-07-08 00:04:24 +08:00
parent d795ee54ce
commit 0e4b1c602b
8 changed files with 134 additions and 67 deletions

View File

@ -348,7 +348,7 @@ func (r *JceReader) readObject(t reflect.Type, tag int) reflect.Value {
r.ReadObject(&s, tag) r.ReadObject(&s, tag)
return reflect.ValueOf(s) return reflect.ValueOf(s)
case reflect.Slice: case reflect.Slice:
s := reflect.New(t.Elem()).Interface().(IJecStruct) s := reflect.New(t.Elem()).Interface().(IJceStruct)
r.readHead() r.readHead()
s.ReadFrom(r) s.ReadFrom(r)
r.skipToStructEnd() r.skipToStructEnd()
@ -410,7 +410,7 @@ func (r *JceReader) ReadObject(i interface{}, tag int) {
*o = r.ReadFloat64(tag) *o = r.ReadFloat64(tag)
case *string: case *string:
*o = r.ReadString(tag) *o = r.ReadString(tag)
case IJecStruct: case IJceStruct:
o.ReadFrom(r) o.ReadFrom(r)
} }
} }

View File

@ -1,7 +1,7 @@
package jce package jce
type IJecStruct interface { type IJceStruct interface {
ToBytes() []byte //ToBytes() []byte
ReadFrom(*JceReader) ReadFrom(*JceReader)
} }
@ -86,6 +86,25 @@ type (
} }
SvcRespPushMsg struct { SvcRespPushMsg struct {
Uin int64 `jceId:"0"`
DelInfos []IJceStruct `jceId:"1"`
Svrip int32 `jceId:"2"`
PushToken []byte `jceId:"3"`
ServiceType int32 `jceId:"4"`
}
DelMsgInfo struct {
FromUin int64 `jceId:"0"`
MsgTime int64 `jceId:"1"`
MsgSeq int16 `jceId:"2"`
MsgCookies []byte `jceId:"3"`
Cmd int16 `jceId:"4"`
MsgType int64 `jceId:"5"`
AppId int64 `jceId:"6"`
SendTime int64 `jceId:"7"`
SsoSeq int32 `jceId:"8"`
SsoIp int32 `jceId:"9"`
ClientIp int32 `jceId:"10"`
} }
FriendListRequest struct { FriendListRequest struct {
@ -304,12 +323,6 @@ func (pkt *RequestDataVersion3) ReadFrom(r *JceReader) {
}) })
} }
func (pkt *RequestDataVersion2) ToBytes() []byte {
w := NewJceWriter()
w.WriteJceStructRaw(pkt)
return w.Bytes()
}
func (pkt *RequestDataVersion2) ReadFrom(r *JceReader) { func (pkt *RequestDataVersion2) ReadFrom(r *JceReader) {
pkt.Map = make(map[string]map[string][]byte) pkt.Map = make(map[string]map[string][]byte)
r.ReadMapF(0, func(k interface{}, v interface{}) { r.ReadMapF(0, func(k interface{}, v interface{}) {
@ -340,12 +353,6 @@ func (pkt *FriendListRequest) ReadFrom(r *JceReader) {
} }
func (pkt *FriendInfo) ToBytes() []byte {
w := NewJceWriter()
w.WriteJceStructRaw(pkt)
return w.Bytes()
}
func (pkt *FriendInfo) ReadFrom(r *JceReader) { func (pkt *FriendInfo) ReadFrom(r *JceReader) {
pkt.FriendUin = r.ReadInt64(0) pkt.FriendUin = r.ReadInt64(0)
pkt.GroupId = r.ReadByte(1) pkt.GroupId = r.ReadByte(1)
@ -370,12 +377,6 @@ func (pkt *TroopListRequest) ReadFrom(r *JceReader) {
} }
func (pkt *TroopNumber) ToBytes() []byte {
w := NewJceWriter()
w.WriteJceStructRaw(pkt)
return w.Bytes()
}
func (pkt *TroopNumber) ReadFrom(r *JceReader) { func (pkt *TroopNumber) ReadFrom(r *JceReader) {
pkt.GroupUin = r.ReadInt64(0) pkt.GroupUin = r.ReadInt64(0)
pkt.GroupCode = r.ReadInt64(1) pkt.GroupCode = r.ReadInt64(1)
@ -396,12 +397,6 @@ func (pkt *TroopMemberListRequest) ReadFrom(r *JceReader) {
} }
func (pkt *TroopMemberInfo) ToBytes() []byte {
w := NewJceWriter()
w.WriteJceStructRaw(pkt)
return w.Bytes()
}
func (pkt *TroopMemberInfo) ReadFrom(r *JceReader) { func (pkt *TroopMemberInfo) ReadFrom(r *JceReader) {
pkt.MemberUin = r.ReadInt64(0) pkt.MemberUin = r.ReadInt64(0)
pkt.FaceId = r.ReadInt16(1) pkt.FaceId = r.ReadInt16(1)
@ -417,12 +412,6 @@ func (pkt *TroopMemberInfo) ReadFrom(r *JceReader) {
pkt.Job = r.ReadString(25) pkt.Job = r.ReadString(25)
} }
func (pkt *PushMessageInfo) ToBytes() []byte {
w := NewJceWriter()
w.WriteJceStructRaw(pkt)
return w.Bytes()
}
func (pkt *PushMessageInfo) ReadFrom(r *JceReader) { func (pkt *PushMessageInfo) ReadFrom(r *JceReader) {
pkt.FromUin = r.ReadInt64(0) pkt.FromUin = r.ReadInt64(0)
pkt.MsgTime = r.ReadInt64(1) pkt.MsgTime = r.ReadInt64(1)
@ -430,6 +419,20 @@ func (pkt *PushMessageInfo) ReadFrom(r *JceReader) {
pkt.MsgSeq = r.ReadInt16(3) pkt.MsgSeq = r.ReadInt16(3)
pkt.Msg = r.ReadString(4) pkt.Msg = r.ReadString(4)
pkt.VMsg = r.ReadAny(6).([]byte) pkt.VMsg = r.ReadAny(6).([]byte)
pkt.MsgCookies = r.ReadAny(8).([]byte)
pkt.MsgUid = r.ReadInt64(10)
pkt.FromMobile = r.ReadString(16) pkt.FromMobile = r.ReadString(16)
pkt.FromName = r.ReadString(17) pkt.FromName = r.ReadString(17)
} }
func (pkt *SvcRespPushMsg) ToBytes() []byte {
w := NewJceWriter()
w.WriteJceStructRaw(pkt)
return w.Bytes()
}
func (pkt *SvcRespPushMsg) ReadFrom(r *JceReader) {
}
func (pkt *DelMsgInfo) ReadFrom(r *JceReader) {
}

View File

@ -112,6 +112,18 @@ func (w *JceWriter) WriteInt64Slice(l []int64, tag int) {
} }
} }
func (w *JceWriter) WriteJceStructSlice(l []IJceStruct, tag int) {
w.writeHead(9, tag)
if len(l) == 0 {
w.WriteInt32(0, 0)
return
}
w.WriteInt32(int32(len(l)), 0)
for _, v := range l {
w.WriteJceStruct(v, 0)
}
}
func (w *JceWriter) WriteMap(m interface{}, tag int) { func (w *JceWriter) WriteMap(m interface{}, tag int) {
if m == nil { if m == nil {
w.writeHead(8, tag) w.writeHead(8, tag)
@ -158,12 +170,14 @@ func (w *JceWriter) WriteObject(i interface{}, tag int) {
w.WriteBytes(o, tag) w.WriteBytes(o, tag)
case []int64: case []int64:
w.WriteInt64Slice(o, tag) w.WriteInt64Slice(o, tag)
case IJecStruct: case IJceStruct:
w.WriteJceStruct(o, tag) w.WriteJceStruct(o, tag)
case []IJceStruct:
w.WriteJceStructSlice(o, tag)
} }
} }
func (w *JceWriter) WriteJceStructRaw(s IJecStruct) { func (w *JceWriter) WriteJceStructRaw(s IJceStruct) {
var ( var (
t = reflect.TypeOf(s).Elem() t = reflect.TypeOf(s).Elem()
v = reflect.ValueOf(s).Elem() v = reflect.ValueOf(s).Elem()
@ -181,7 +195,7 @@ func (w *JceWriter) WriteJceStructRaw(s IJecStruct) {
} }
} }
func (w *JceWriter) WriteJceStruct(s IJecStruct, tag int) { func (w *JceWriter) WriteJceStruct(s IJceStruct, tag int) {
w.writeHead(10, tag) w.writeHead(10, tag)
w.WriteJceStructRaw(s) w.WriteJceStructRaw(s)
w.writeHead(11, 0) w.writeHead(11, 0)

View File

@ -3,12 +3,10 @@ package binary
import ( import (
"bytes" "bytes"
"compress/zlib" "compress/zlib"
"crypto/rand"
binary2 "encoding/binary" binary2 "encoding/binary"
"encoding/hex" "encoding/hex"
"fmt" "fmt"
"io" "io"
"math/big"
"strings" "strings"
) )
@ -20,19 +18,6 @@ func ZlibUncompress(src []byte) []byte {
return out.Bytes() return out.Bytes()
} }
func RandomString(len int) string {
var res string
var str = "abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ1234567890"
b := bytes.NewBufferString(str)
length := b.Len()
bigInt := big.NewInt(int64(length))
for i := 0; i < len; i++ {
randomInt, _ := rand.Int(rand.Reader, bigInt)
res += string(str[randomInt.Int64()])
}
return res
}
func CalculateImageResourceId(md5 []byte) string { func CalculateImageResourceId(md5 []byte) string {
return strings.ToUpper(fmt.Sprintf( return strings.ToUpper(fmt.Sprintf(
"{%s-%s-%s-%s-%s}.png", "{%s-%s-%s-%s-%s}.png",

View File

@ -10,6 +10,7 @@ import (
"github.com/Mrs4s/MiraiGo/protocol/crypto" "github.com/Mrs4s/MiraiGo/protocol/crypto"
"github.com/Mrs4s/MiraiGo/protocol/packets" "github.com/Mrs4s/MiraiGo/protocol/packets"
"github.com/Mrs4s/MiraiGo/protocol/tlv" "github.com/Mrs4s/MiraiGo/protocol/tlv"
"github.com/Mrs4s/MiraiGo/utils"
"github.com/golang/protobuf/proto" "github.com/golang/protobuf/proto"
"math/rand" "math/rand"
"strconv" "strconv"
@ -327,6 +328,33 @@ func (c *QQClient) buildDeleteMessageRequestPacket(msg []*pb.MessageItem) (uint1
return seq, packet return seq, packet
} }
func (c *QQClient) buildDeleteOnlinePushPacket(uin int64, seq uint16, delMsg []jce.PushMessageInfo) []byte {
req := &jce.SvcRespPushMsg{Uin: uin}
for _, m := range delMsg {
req.DelInfos = append(req.DelInfos, &jce.DelMsgInfo{
FromUin: m.FromUin,
MsgSeq: m.MsgSeq,
MsgCookies: m.MsgCookies,
MsgTime: m.MsgTime,
})
}
b := append([]byte{0x0A}, req.ToBytes()...)
b = append(b, 0x0B)
buf := &jce.RequestDataVersion3{
Map: map[string][]byte{"resp": b},
}
pkt := &jce.RequestPacket{
IVersion: 3,
IRequestId: int32(seq),
SServantName: "OnlinePush",
SFuncName: "SvcRespPushMsg",
SBuffer: buf.ToBytes(),
Context: make(map[string]string),
Status: make(map[string]string),
}
return packets.BuildUniPacket(c.Uin, seq, "OnlinePush.RespPush", 1, c.OutGoingPacketSessionId, []byte{}, c.sigInfo.d2Key, pkt.ToBytes())
}
func (c *QQClient) buildGroupSendingPacket(groupCode int64, m *message.SendingMessage) (uint16, []byte) { func (c *QQClient) buildGroupSendingPacket(groupCode int64, m *message.SendingMessage) (uint16, []byte) {
seq := c.nextSeq() seq := c.nextSeq()
req := &msg.SendMessageRequest{ req := &msg.SendMessageRequest{
@ -350,7 +378,7 @@ func (c *QQClient) buildGroupSendingPacket(groupCode int64, m *message.SendingMe
func (c *QQClient) buildGroupImageStorePacket(groupCode int64, md5 [16]byte, size int32) (uint16, []byte) { func (c *QQClient) buildGroupImageStorePacket(groupCode int64, md5 [16]byte, size int32) (uint16, []byte) {
seq := c.nextSeq() seq := c.nextSeq()
name := binary.RandomString(16) + ".gif" name := utils.RandomString(16) + ".gif"
req := &pb.D388ReqBody{ req := &pb.D388ReqBody{
NetType: 3, NetType: 3,
Subcmd: 1, Subcmd: 1,

View File

@ -33,7 +33,7 @@ type QQClient struct {
RandomKey []byte RandomKey []byte
Conn net.Conn Conn net.Conn
decoders map[string]func(*QQClient, []byte) (interface{}, error) decoders map[string]func(*QQClient, uint16, []byte) (interface{}, error)
handlers map[uint16]func(interface{}, error) handlers map[uint16]func(interface{}, error)
syncCookie []byte syncCookie []byte
@ -52,6 +52,7 @@ type QQClient struct {
running bool running bool
lastMessageSeq int32 lastMessageSeq int32
onlinePushCache []int16 // reset on reconnect
requestPacketRequestId int32 requestPacketRequestId int32
messageSeq int32 messageSeq int32
groupDataTransSeq int32 groupDataTransSeq int32
@ -84,7 +85,7 @@ func NewClient(uin int64, password string) *QQClient {
SequenceId: 0x3635, SequenceId: 0x3635,
RandomKey: make([]byte, 16), RandomKey: make([]byte, 16),
OutGoingPacketSessionId: []byte{0x02, 0xB0, 0x5B, 0x8B}, OutGoingPacketSessionId: []byte{0x02, 0xB0, 0x5B, 0x8B},
decoders: map[string]func(*QQClient, []byte) (interface{}, error){ decoders: map[string]func(*QQClient, uint16, []byte) (interface{}, error){
"wtlogin.login": decodeLoginResponse, "wtlogin.login": decodeLoginResponse,
"StatSvc.register": decodeClientRegisterResponse, "StatSvc.register": decodeClientRegisterResponse,
"MessageSvc.PushNotify": decodeSvcNotify, "MessageSvc.PushNotify": decodeSvcNotify,
@ -312,6 +313,7 @@ func (c *QQClient) connect() error {
return err return err
} }
c.Conn = conn c.Conn = conn
c.onlinePushCache = []int16{}
return nil return nil
} }
@ -411,7 +413,7 @@ func (c *QQClient) loop() {
} }
return return
} }
rsp, err := decoder(c, payload) rsp, err := decoder(c, pkt.SequenceId, payload)
if err != nil { if err != nil {
log.Println("decode", pkt.CommandName, "error:", err) log.Println("decode", pkt.CommandName, "error:", err)
} }

View File

@ -10,7 +10,7 @@ import (
"time" "time"
) )
func decodeLoginResponse(c *QQClient, payload []byte) (interface{}, error) { func decodeLoginResponse(c *QQClient, seq uint16, payload []byte) (interface{}, error) {
reader := binary.NewReader(payload) reader := binary.NewReader(payload)
reader.ReadUInt16() // sub command reader.ReadUInt16() // sub command
t := reader.ReadByte() t := reader.ReadByte()
@ -91,7 +91,7 @@ func decodeLoginResponse(c *QQClient, payload []byte) (interface{}, error) {
return nil, nil // ? return nil, nil // ?
} }
func decodeClientRegisterResponse(c *QQClient, payload []byte) (interface{}, error) { func decodeClientRegisterResponse(c *QQClient, seq uint16, payload []byte) (interface{}, error) {
request := &jce.RequestPacket{} request := &jce.RequestPacket{}
request.ReadFrom(jce.NewJceReader(payload)) request.ReadFrom(jce.NewJceReader(payload))
data := &jce.RequestDataVersion2{} data := &jce.RequestDataVersion2{}
@ -99,7 +99,7 @@ func decodeClientRegisterResponse(c *QQClient, payload []byte) (interface{}, err
return nil, nil return nil, nil
} }
func decodePushReqPacket(c *QQClient, payload []byte) (interface{}, error) { func decodePushReqPacket(c *QQClient, s uint16, payload []byte) (interface{}, error) {
request := &jce.RequestPacket{} request := &jce.RequestPacket{}
request.ReadFrom(jce.NewJceReader(payload)) request.ReadFrom(jce.NewJceReader(payload))
data := &jce.RequestDataVersion2{} data := &jce.RequestDataVersion2{}
@ -113,7 +113,7 @@ func decodePushReqPacket(c *QQClient, payload []byte) (interface{}, error) {
return nil, c.send(pkt) return nil, c.send(pkt)
} }
func decodeMessageSvcPacket(c *QQClient, payload []byte) (interface{}, error) { func decodeMessageSvcPacket(c *QQClient, seq uint16, payload []byte) (interface{}, error) {
rsp := msg.GetMessageResponse{} rsp := msg.GetMessageResponse{}
err := proto.Unmarshal(payload, &rsp) err := proto.Unmarshal(payload, &rsp)
if err != nil { if err != nil {
@ -163,7 +163,7 @@ func decodeMessageSvcPacket(c *QQClient, payload []byte) (interface{}, error) {
return nil, err return nil, err
} }
func decodeGroupMessagePacket(c *QQClient, payload []byte) (interface{}, error) { func decodeGroupMessagePacket(c *QQClient, seq uint16, payload []byte) (interface{}, error) {
pkt := msg.PushMessagePacket{} pkt := msg.PushMessagePacket{}
err := proto.Unmarshal(payload, &pkt) err := proto.Unmarshal(payload, &pkt)
if err != nil { if err != nil {
@ -176,12 +176,12 @@ func decodeGroupMessagePacket(c *QQClient, payload []byte) (interface{}, error)
return nil, nil return nil, nil
} }
func decodeSvcNotify(c *QQClient, payload []byte) (interface{}, error) { func decodeSvcNotify(c *QQClient, seq uint16, payload []byte) (interface{}, error) {
_, pkt := c.buildGetMessageRequestPacket(msg.SyncFlag_START, time.Now().Unix()) _, pkt := c.buildGetMessageRequestPacket(msg.SyncFlag_START, time.Now().Unix())
return nil, c.send(pkt) return nil, c.send(pkt)
} }
func decodeFriendGroupListResponse(c *QQClient, payload []byte) (interface{}, error) { func decodeFriendGroupListResponse(c *QQClient, seq uint16, payload []byte) (interface{}, error) {
request := &jce.RequestPacket{} request := &jce.RequestPacket{}
request.ReadFrom(jce.NewJceReader(payload)) request.ReadFrom(jce.NewJceReader(payload))
data := &jce.RequestDataVersion3{} data := &jce.RequestDataVersion3{}
@ -206,7 +206,7 @@ func decodeFriendGroupListResponse(c *QQClient, payload []byte) (interface{}, er
return rsp, nil return rsp, nil
} }
func decodeGroupListResponse(c *QQClient, payload []byte) (interface{}, error) { func decodeGroupListResponse(c *QQClient, seq uint16, payload []byte) (interface{}, error) {
request := &jce.RequestPacket{} request := &jce.RequestPacket{}
request.ReadFrom(jce.NewJceReader(payload)) request.ReadFrom(jce.NewJceReader(payload))
data := &jce.RequestDataVersion3{} data := &jce.RequestDataVersion3{}
@ -229,7 +229,7 @@ func decodeGroupListResponse(c *QQClient, payload []byte) (interface{}, error) {
return l, nil return l, nil
} }
func decodeGroupMemberListResponse(c *QQClient, payload []byte) (interface{}, error) { func decodeGroupMemberListResponse(c *QQClient, seq uint16, payload []byte) (interface{}, error) {
request := &jce.RequestPacket{} request := &jce.RequestPacket{}
request.ReadFrom(jce.NewJceReader(payload)) request.ReadFrom(jce.NewJceReader(payload))
data := &jce.RequestDataVersion3{} data := &jce.RequestDataVersion3{}
@ -258,7 +258,7 @@ func decodeGroupMemberListResponse(c *QQClient, payload []byte) (interface{}, er
}, nil }, nil
} }
func decodeGroupImageStoreResponse(c *QQClient, payload []byte) (interface{}, error) { func decodeGroupImageStoreResponse(c *QQClient, seq uint16, payload []byte) (interface{}, error) {
pkt := pb.D388RespBody{} pkt := pb.D388RespBody{}
err := proto.Unmarshal(payload, &pkt) err := proto.Unmarshal(payload, &pkt)
if err != nil { if err != nil {
@ -281,15 +281,29 @@ func decodeGroupImageStoreResponse(c *QQClient, payload []byte) (interface{}, er
}, nil }, nil
} }
func decodeOnlinePushReqPacket(c *QQClient, payload []byte) (interface{}, error) { func decodeOnlinePushReqPacket(c *QQClient, seq uint16, payload []byte) (interface{}, error) {
request := &jce.RequestPacket{} request := &jce.RequestPacket{}
request.ReadFrom(jce.NewJceReader(payload)) request.ReadFrom(jce.NewJceReader(payload))
data := &jce.RequestDataVersion2{} data := &jce.RequestDataVersion2{}
data.ReadFrom(jce.NewJceReader(request.SBuffer)) data.ReadFrom(jce.NewJceReader(request.SBuffer))
jr := jce.NewJceReader(data.Map["req"]["OnlinePushPack.SvcReqPushMsg"][1:]) jr := jce.NewJceReader(data.Map["req"]["OnlinePushPack.SvcReqPushMsg"][1:])
msgInfos := []jce.PushMessageInfo{} msgInfos := []jce.PushMessageInfo{}
uin := jr.ReadInt64(0)
jr.ReadSlice(&msgInfos, 2) jr.ReadSlice(&msgInfos, 2)
_ = c.send(c.buildDeleteOnlinePushPacket(uin, seq, msgInfos))
seqExists := func(ms int16) bool {
for _, s := range c.onlinePushCache {
if ms == s {
return true
}
}
return false
}
for _, m := range msgInfos { for _, m := range msgInfos {
if seqExists(m.MsgSeq) {
continue
}
c.onlinePushCache = append(c.onlinePushCache, m.MsgSeq)
if m.MsgType == 732 { if m.MsgType == 732 {
r := binary.NewReader(m.VMsg) r := binary.NewReader(m.VMsg)
groupId := int64(uint32(r.ReadInt32())) groupId := int64(uint32(r.ReadInt32()))
@ -329,5 +343,6 @@ func decodeOnlinePushReqPacket(c *QQClient, payload []byte) (interface{}, error)
} }
} }
} }
return nil, nil return nil, nil
} }

20
utils/string.go Normal file
View File

@ -0,0 +1,20 @@
package utils
import (
"bytes"
"crypto/rand"
"math/big"
)
func RandomString(len int) string {
var res string
var str = "abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ1234567890"
b := bytes.NewBufferString(str)
length := b.Len()
bigInt := big.NewInt(int64(length))
for i := 0; i < len; i++ {
randomInt, _ := rand.Int(rand.Reader, bigInt)
res += string(str[randomInt.Int64()])
}
return res
}