1
0
mirror of https://github.com/Mrs4s/MiraiGo.git synced 2025-07-08 15:18:32 +00:00

8 Commits

Author SHA1 Message Date
102bda2cfa network: move server addr list to transport 2022-02-03 22:10:08 +08:00
aa4e0e0bbe network: replace Params with Request 2022-01-28 22:54:32 +08:00
c1cbb69110 Merge remote-tracking branch 'origin/master' into network 2022-01-28 22:17:44 +08:00
6a71884235 refactor: handle decode func in Request 2021-12-27 15:41:59 +08:00
LXY
f5b16b19c2 Network refactor (#229)
* 重构:netLoop下移到Listener

* 格式:修正NewClient中注释段缩进

* 格式:更名&将代码移动到对应位置

* 格式:TCPListener去锁化

* 修正:netLoop中的错误调用

* 修正:使其可用

* 修正:使功能一致

* 修正:现在可正常运行

* 优化:更早的释放锁(?

* 修正:未写完的部分

* 修正:潜在的断线时仍然认为在线这件事&删除空重复文件

* 文档:添加部分注释

* 修正:CoverError可能引起死锁

* 修正:永远不会被触发的DisconnectEvent

* 文档:将注释移动至对应位置
2021-12-27 15:36:52 +08:00
9bd6b38f90 refactor: handle params in request 2021-12-27 15:36:47 +08:00
435d2fd85f refactor: 手动指定decode函数
(cherry picked from commit 13d6711f27)
2021-12-27 15:36:44 +08:00
723563415f client: refactor decoder
(cherry picked from commit 3e201bd449)
2021-12-27 15:36:38 +08:00
44 changed files with 1229 additions and 1382 deletions

View File

@ -120,10 +120,6 @@ func (r *Reader) Len() int {
return r.buf.Len() return r.buf.Len()
} }
func (r *Reader) Index() int64 {
return r.buf.Size()
}
func (tlv TlvMap) Exists(key uint16) bool { func (tlv TlvMap) Exists(key uint16) bool {
_, ok := tlv[key] _, ok := tlv[key]
return ok return ok

View File

@ -5,7 +5,7 @@ import (
"github.com/Mrs4s/MiraiGo/client/pb/msg" "github.com/Mrs4s/MiraiGo/client/pb/msg"
) )
var privateMsgDecoders = map[int32]func(*QQClient, *msg.Message, *network.IncomingPacketInfo){ var privateMsgDecoders = map[int32]func(*QQClient, *msg.Message, *network.Response){
9: privateMessageDecoder, 10: privateMessageDecoder, 31: privateMessageDecoder, 9: privateMessageDecoder, 10: privateMessageDecoder, 31: privateMessageDecoder,
79: privateMessageDecoder, 97: privateMessageDecoder, 120: privateMessageDecoder, 79: privateMessageDecoder, 97: privateMessageDecoder, 120: privateMessageDecoder,
132: privateMessageDecoder, 133: privateMessageDecoder, 166: privateMessageDecoder, 132: privateMessageDecoder, 133: privateMessageDecoder, 166: privateMessageDecoder,
@ -13,21 +13,21 @@ var privateMsgDecoders = map[int32]func(*QQClient, *msg.Message, *network.Incomi
208: privatePttDecoder, 208: privatePttDecoder,
} }
var nonSvcNotifyTroopSystemMsgDecoders = map[int32]func(*QQClient, *msg.Message, *network.IncomingPacketInfo){ var nonSvcNotifyTroopSystemMsgDecoders = map[int32]func(*QQClient, *msg.Message, *network.Response){
36: troopSystemMessageDecoder, 85: troopSystemMessageDecoder, 36: troopSystemMessageDecoder, 85: troopSystemMessageDecoder,
} }
var troopSystemMsgDecoders = map[int32]func(*QQClient, *msg.Message, *network.IncomingPacketInfo){ var troopSystemMsgDecoders = map[int32]func(*QQClient, *msg.Message, *network.Response){
35: troopSystemMessageDecoder, 37: troopSystemMessageDecoder, 35: troopSystemMessageDecoder, 37: troopSystemMessageDecoder,
45: troopSystemMessageDecoder, 46: troopSystemMessageDecoder, 84: troopSystemMessageDecoder, 45: troopSystemMessageDecoder, 46: troopSystemMessageDecoder, 84: troopSystemMessageDecoder,
86: troopSystemMessageDecoder, 87: troopSystemMessageDecoder, 86: troopSystemMessageDecoder, 87: troopSystemMessageDecoder,
} // IsSvcNotify } // IsSvcNotify
var sysMsgDecoders = map[int32]func(*QQClient, *msg.Message, *network.IncomingPacketInfo){ var sysMsgDecoders = map[int32]func(*QQClient, *msg.Message, *network.Response){
187: systemMessageDecoder, 188: systemMessageDecoder, 189: systemMessageDecoder, 187: systemMessageDecoder, 188: systemMessageDecoder, 189: systemMessageDecoder,
190: systemMessageDecoder, 191: systemMessageDecoder, 190: systemMessageDecoder, 191: systemMessageDecoder,
} // IsSvcNotify } // IsSvcNotify
var otherDecoders = map[int32]func(*QQClient, *msg.Message, *network.IncomingPacketInfo){ var otherDecoders = map[int32]func(*QQClient, *msg.Message, *network.Response){
33: troopAddMemberBroadcastDecoder, 529: msgType0x211Decoder, 33: troopAddMemberBroadcastDecoder, 529: msgType0x211Decoder,
} }

View File

@ -17,7 +17,6 @@ import (
"github.com/Mrs4s/MiraiGo/client/pb/oidb" "github.com/Mrs4s/MiraiGo/client/pb/oidb"
"github.com/Mrs4s/MiraiGo/client/pb/profilecard" "github.com/Mrs4s/MiraiGo/client/pb/profilecard"
"github.com/Mrs4s/MiraiGo/client/pb/structmsg" "github.com/Mrs4s/MiraiGo/client/pb/structmsg"
"github.com/Mrs4s/MiraiGo/internal/packets"
"github.com/Mrs4s/MiraiGo/internal/proto" "github.com/Mrs4s/MiraiGo/internal/proto"
"github.com/Mrs4s/MiraiGo/internal/tlv" "github.com/Mrs4s/MiraiGo/internal/tlv"
) )
@ -27,7 +26,24 @@ var (
syncConst2 = rand.Int63() syncConst2 = rand.Int63()
) )
func (c *QQClient) buildLoginPacket() (uint16, []byte) { func buildCode2DRequestPacket(seq uint32, j uint64, cmd uint16, bodyFunc func(writer *binary.Writer)) []byte {
return binary.NewWriterF(func(w *binary.Writer) {
w.WriteByte(2)
pos := w.FillUInt16()
w.WriteUInt16(cmd)
w.Write(make([]byte, 21))
w.WriteByte(3)
w.WriteUInt16(0)
w.WriteUInt16(50) // version
w.WriteUInt32(seq)
w.WriteUInt64(j)
bodyFunc(w)
w.WriteByte(3)
w.WriteUInt16At(pos, uint16(w.Len()))
})
}
func (c *QQClient) buildLoginRequest() *network.Request {
seq := c.nextSeq() seq := c.nextSeq()
req := c.buildOicqRequestPacket(c.Uin, 0x0810, binary.NewWriterF(func(w *binary.Writer) { req := c.buildOicqRequestPacket(c.Uin, 0x0810, binary.NewWriterF(func(w *binary.Writer) {
w.WriteUInt16(9) w.WriteUInt16(9)
@ -91,18 +107,18 @@ func (c *QQClient) buildLoginPacket() (uint16, []byte) {
w.Write(tlv.T525(tlv.T536([]byte{0x01, 0x00}))) w.Write(tlv.T525(tlv.T536([]byte{0x01, 0x00})))
})) }))
req2 := network.Request{ return &network.Request{
Type: network.RequestTypeLogin, Type: network.RequestTypeLogin,
EncryptType: network.EncryptTypeEmptyKey, EncryptType: network.EncryptTypeEmptyKey,
SequenceID: int32(seq), SequenceID: int32(seq),
Uin: c.Uin, Uin: c.Uin,
CommandName: "wtlogin.login", CommandName: "wtlogin.login",
Body: req, Body: req,
Decode: bindDecoder(c, decodeLoginResponse),
} }
return seq, c.transport.PackPacket(&req2)
} }
func (c *QQClient) buildDeviceLockLoginPacket() (uint16, []byte) { func (c *QQClient) buildDeviceLockLoginRequest() *network.Request {
seq := c.nextSeq() seq := c.nextSeq()
req := c.buildOicqRequestPacket(c.Uin, 0x0810, binary.NewWriterF(func(w *binary.Writer) { req := c.buildOicqRequestPacket(c.Uin, 0x0810, binary.NewWriterF(func(w *binary.Writer) {
w.WriteUInt16(20) w.WriteUInt16(20)
@ -113,24 +129,24 @@ func (c *QQClient) buildDeviceLockLoginPacket() (uint16, []byte) {
w.Write(tlv.T116(c.version.MiscBitmap, c.version.SubSigmap)) w.Write(tlv.T116(c.version.MiscBitmap, c.version.SubSigmap))
w.Write(tlv.T401(c.sig.G)) w.Write(tlv.T401(c.sig.G))
})) }))
req2 := network.Request{ return &network.Request{
Type: network.RequestTypeLogin, Type: network.RequestTypeLogin,
EncryptType: network.EncryptTypeEmptyKey, EncryptType: network.EncryptTypeEmptyKey,
SequenceID: int32(seq), SequenceID: int32(seq),
Uin: c.Uin, Uin: c.Uin,
CommandName: "wtlogin.login", CommandName: "wtlogin.login",
Body: req, Body: req,
Decode: bindDecoder(c, decodeLoginResponse),
} }
return seq, c.transport.PackPacket(&req2)
} }
func (c *QQClient) buildQRCodeFetchRequestPacket(size, margin, ecLevel uint32) (uint16, []byte) { func (c *QQClient) buildQRCodeFetchRequest(size, margin, ecLevel uint32) *network.Request {
watch := auth.AndroidWatch.Version() watch := auth.AndroidWatch.Version()
seq := c.nextSeq() seq := c.nextSeq()
req := c.buildOicqRequestPacket(0, 0x0812, binary.NewWriterF(func(w *binary.Writer) { req := c.buildOicqRequestPacket(0, 0x0812, binary.NewWriterF(func(w *binary.Writer) {
w.WriteHex(`0001110000001000000072000000`) // trans header w.WriteHex(`0001110000001000000072000000`) // trans header
w.WriteUInt32(uint32(time.Now().Unix())) w.WriteUInt32(uint32(time.Now().Unix()))
w.Write(packets.BuildCode2DRequestPacket(0, 0, 0x31, func(w *binary.Writer) { w.Write(buildCode2DRequestPacket(0, 0, 0x31, func(w *binary.Writer) {
w.WriteUInt16(0) // const w.WriteUInt16(0) // const
w.WriteUInt32(16) // app id w.WriteUInt32(16) // app id
w.WriteUInt64(0) // const w.WriteUInt64(0) // const
@ -147,25 +163,23 @@ func (c *QQClient) buildQRCodeFetchRequestPacket(size, margin, ecLevel uint32) (
})) }))
})) }))
req2 := network.Request{ return &network.Request{
Type: network.RequestTypeLogin, Type: network.RequestTypeLogin,
EncryptType: network.EncryptTypeEmptyKey, EncryptType: network.EncryptTypeEmptyKey,
SequenceID: int32(seq), SequenceID: int32(seq),
Uin: 0, Uin: 0,
CommandName: "wtlogin.trans_emp", CommandName: "wtlogin.trans_emp",
Body: req, Body: req,
Decode: bindDecoder(c, decodeTransEmpResponse),
} }
return seq, c.transport.PackPacket(&req2)
} }
func (c *QQClient) buildQRCodeResultQueryRequestPacket(sig []byte) (uint16, []byte) { func (c *QQClient) buildQRCodeResultQueryRequest(sig []byte) *network.Request {
version := c.transport.Version
c.transport.Version = auth.AndroidWatch.Version()
seq := c.nextSeq() seq := c.nextSeq()
req := c.buildOicqRequestPacket(0, 0x0812, binary.NewWriterF(func(w *binary.Writer) { req := c.buildOicqRequestPacket(0, 0x0812, binary.NewWriterF(func(w *binary.Writer) {
w.WriteHex(`0000620000001000000072000000`) // trans header w.WriteHex(`0000620000001000000072000000`) // trans header
w.WriteUInt32(uint32(time.Now().Unix())) w.WriteUInt32(uint32(time.Now().Unix()))
w.Write(packets.BuildCode2DRequestPacket(1, 0, 0x12, func(w *binary.Writer) { w.Write(buildCode2DRequestPacket(1, 0, 0x12, func(w *binary.Writer) {
w.WriteUInt16(5) // const w.WriteUInt16(5) // const
w.WriteByte(1) // const w.WriteByte(1) // const
w.WriteUInt32(8) // product type w.WriteUInt32(8) // product type
@ -178,20 +192,18 @@ func (c *QQClient) buildQRCodeResultQueryRequestPacket(sig []byte) (uint16, []by
})) }))
})) }))
req2 := network.Request{ return &network.Request{
Type: network.RequestTypeLogin, Type: network.RequestTypeLogin,
EncryptType: network.EncryptTypeEmptyKey, EncryptType: network.EncryptTypeEmptyKey,
SequenceID: int32(seq), SequenceID: int32(seq),
Uin: 0, Uin: 0,
CommandName: "wtlogin.trans_emp", CommandName: "wtlogin.trans_emp",
Body: req, Body: req,
Decode: bindDecoder(c, decodeTransEmpResponse),
} }
payload := c.transport.PackPacket(&req2)
c.transport.Version = version
return seq, payload
} }
func (c *QQClient) buildQRCodeLoginPacket(t106, t16a, t318 []byte) (uint16, []byte) { func (c *QQClient) buildQRCodeLoginRequest(t106, t16a, t318 []byte) *network.Request {
seq := c.nextSeq() seq := c.nextSeq()
req := c.buildOicqRequestPacket(c.Uin, 0x0810, binary.NewWriterF(func(w *binary.Writer) { req := c.buildOicqRequestPacket(c.Uin, 0x0810, binary.NewWriterF(func(w *binary.Writer) {
w.WriteUInt16(9) w.WriteUInt16(9)
@ -254,18 +266,18 @@ func (c *QQClient) buildQRCodeLoginPacket(t106, t16a, t318 []byte) (uint16, []by
w.WriteBytesShort(t318) w.WriteBytesShort(t318)
})) }))
req2 := network.Request{ return &network.Request{
Type: network.RequestTypeLogin, Type: network.RequestTypeLogin,
EncryptType: network.EncryptTypeEmptyKey, EncryptType: network.EncryptTypeEmptyKey,
SequenceID: int32(seq), SequenceID: int32(seq),
Uin: c.Uin, Uin: c.Uin,
CommandName: "wtlogin.login", CommandName: "wtlogin.login",
Body: req, Body: req,
Decode: bindDecoder(c, decodeLoginResponse),
} }
return seq, c.transport.PackPacket(&req2)
} }
func (c *QQClient) buildCaptchaPacket(result string, sign []byte) (uint16, []byte) { func (c *QQClient) buildCaptchaRequest(result string, sign []byte) *network.Request {
seq := c.nextSeq() seq := c.nextSeq()
req := c.buildOicqRequestPacket(c.Uin, 0x0810, binary.NewWriterF(func(w *binary.Writer) { req := c.buildOicqRequestPacket(c.Uin, 0x0810, binary.NewWriterF(func(w *binary.Writer) {
w.WriteUInt16(2) // sub command w.WriteUInt16(2) // sub command
@ -277,18 +289,18 @@ func (c *QQClient) buildCaptchaPacket(result string, sign []byte) (uint16, []byt
w.Write(tlv.T116(c.version.MiscBitmap, c.version.SubSigmap)) w.Write(tlv.T116(c.version.MiscBitmap, c.version.SubSigmap))
})) }))
req2 := network.Request{ return &network.Request{
Type: network.RequestTypeLogin, Type: network.RequestTypeLogin,
EncryptType: network.EncryptTypeEmptyKey, EncryptType: network.EncryptTypeEmptyKey,
SequenceID: int32(seq), SequenceID: int32(seq),
Uin: c.Uin, Uin: c.Uin,
CommandName: "wtlogin.login", CommandName: "wtlogin.login",
Body: req, Body: req,
Decode: bindDecoder(c, decodeLoginResponse),
} }
return seq, c.transport.PackPacket(&req2)
} }
func (c *QQClient) buildSMSRequestPacket() (uint16, []byte) { func (c *QQClient) buildSMSRequest() *network.Request {
seq := c.nextSeq() seq := c.nextSeq()
req := c.buildOicqRequestPacket(c.Uin, 0x0810, binary.NewWriterF(func(w *binary.Writer) { req := c.buildOicqRequestPacket(c.Uin, 0x0810, binary.NewWriterF(func(w *binary.Writer) {
w.WriteUInt16(8) w.WriteUInt16(8)
@ -302,18 +314,18 @@ func (c *QQClient) buildSMSRequestPacket() (uint16, []byte) {
w.Write(tlv.T197()) w.Write(tlv.T197())
})) }))
req2 := network.Request{ return &network.Request{
Type: network.RequestTypeLogin, Type: network.RequestTypeLogin,
EncryptType: network.EncryptTypeEmptyKey, EncryptType: network.EncryptTypeEmptyKey,
SequenceID: int32(seq), SequenceID: int32(seq),
Uin: c.Uin, Uin: c.Uin,
CommandName: "wtlogin.login", CommandName: "wtlogin.login",
Body: req, Body: req,
Decode: bindDecoder(c, decodeLoginResponse),
} }
return seq, c.transport.PackPacket(&req2)
} }
func (c *QQClient) buildSMSCodeSubmitPacket(code string) (uint16, []byte) { func (c *QQClient) buildSMSCodeSubmitRequest(code string) *network.Request {
seq := c.nextSeq() seq := c.nextSeq()
req := c.buildOicqRequestPacket(c.Uin, 0x0810, binary.NewWriterF(func(w *binary.Writer) { req := c.buildOicqRequestPacket(c.Uin, 0x0810, binary.NewWriterF(func(w *binary.Writer) {
w.WriteUInt16(7) w.WriteUInt16(7)
@ -328,18 +340,18 @@ func (c *QQClient) buildSMSCodeSubmitPacket(code string) (uint16, []byte) {
w.Write(tlv.T198()) w.Write(tlv.T198())
})) }))
req2 := network.Request{ return &network.Request{
Type: network.RequestTypeLogin, Type: network.RequestTypeLogin,
EncryptType: network.EncryptTypeEmptyKey, EncryptType: network.EncryptTypeEmptyKey,
SequenceID: int32(seq), SequenceID: int32(seq),
Uin: c.Uin, Uin: c.Uin,
CommandName: "wtlogin.login", CommandName: "wtlogin.login",
Body: req, Body: req,
Decode: bindDecoder(c, decodeLoginResponse),
} }
return seq, c.transport.PackPacket(&req2)
} }
func (c *QQClient) buildTicketSubmitPacket(ticket string) (uint16, []byte) { func (c *QQClient) buildTicketSubmitRequest(ticket string) *network.Request {
seq := c.nextSeq() seq := c.nextSeq()
req := c.buildOicqRequestPacket(c.Uin, 0x0810, binary.NewWriterF(func(w *binary.Writer) { req := c.buildOicqRequestPacket(c.Uin, 0x0810, binary.NewWriterF(func(w *binary.Writer) {
w.WriteUInt16(2) w.WriteUInt16(2)
@ -351,18 +363,18 @@ func (c *QQClient) buildTicketSubmitPacket(ticket string) (uint16, []byte) {
w.Write(tlv.T116(c.version.MiscBitmap, c.version.SubSigmap)) w.Write(tlv.T116(c.version.MiscBitmap, c.version.SubSigmap))
})) }))
req2 := network.Request{ return &network.Request{
Type: network.RequestTypeLogin, Type: network.RequestTypeLogin,
EncryptType: network.EncryptTypeEmptyKey, EncryptType: network.EncryptTypeEmptyKey,
SequenceID: int32(seq), SequenceID: int32(seq),
Uin: c.Uin, Uin: c.Uin,
CommandName: "wtlogin.login", CommandName: "wtlogin.login",
Body: req, Body: req,
Decode: bindDecoder(c, decodeLoginResponse),
} }
return seq, c.transport.PackPacket(&req2)
} }
func (c *QQClient) buildRequestTgtgtNopicsigPacket() (uint16, []byte) { func (c *QQClient) buildRequestTgtgtNopicsigRequest() *network.Request {
seq := c.nextSeq() seq := c.nextSeq()
req := binary.NewWriterF(func(w *binary.Writer) { req := binary.NewWriterF(func(w *binary.Writer) {
w.WriteUInt16(15) w.WriteUInt16(15)
@ -423,18 +435,18 @@ func (c *QQClient) buildRequestTgtgtNopicsigPacket() (uint16, []byte) {
Body: req, Body: req,
} }
nreq := network.Request{ return &network.Request{
Type: network.RequestTypeSimple, Type: network.RequestTypeSimple,
EncryptType: network.EncryptTypeEmptyKey, EncryptType: network.EncryptTypeEmptyKey,
Uin: c.Uin, Uin: c.Uin,
SequenceID: int32(seq), SequenceID: int32(seq),
CommandName: "wtlogin.exchange_emp", CommandName: "wtlogin.exchange_emp",
Decode: bindDecoder(c, decodeExchangeEmpResponse),
Body: c.oicq.Marshal(&m), Body: c.oicq.Marshal(&m),
} }
return seq, c.transport.PackPacket(&nreq)
} }
func (c *QQClient) buildRequestChangeSigPacket(mainSigMap uint32) (uint16, []byte) { func (c *QQClient) buildRequestChangeSigRequest(mainSigMap uint32) *network.Request {
seq := c.nextSeq() seq := c.nextSeq()
req := c.buildOicqRequestPacket(c.Uin, 0x0810, binary.NewWriterF(func(w *binary.Writer) { req := c.buildOicqRequestPacket(c.Uin, 0x0810, binary.NewWriterF(func(w *binary.Writer) {
w.WriteUInt16(11) w.WriteUInt16(11)
@ -477,19 +489,19 @@ func (c *QQClient) buildRequestChangeSigPacket(mainSigMap uint32) (uint16, []byt
// w.Write(tlv.T202(c.deviceInfo.WifiBSSID, c.deviceInfo.WifiSSID)) // w.Write(tlv.T202(c.deviceInfo.WifiBSSID, c.deviceInfo.WifiSSID))
})) }))
req2 := network.Request{ return &network.Request{
Type: network.RequestTypeLogin, Type: network.RequestTypeLogin,
EncryptType: network.EncryptTypeEmptyKey, EncryptType: network.EncryptTypeEmptyKey,
SequenceID: int32(seq), SequenceID: int32(seq),
Uin: c.Uin, Uin: c.Uin,
CommandName: "wtlogin.exchange_emp", CommandName: "wtlogin.exchange_emp",
Body: req, Body: req,
Decode: bindDecoder(c, decodeExchangeEmpResponse),
} }
return seq, c.transport.PackPacket(&req2)
} }
// StatSvc.register // StatSvc.register
func (c *QQClient) buildClientRegisterPacket() (uint16, []byte) { func (c *QQClient) buildClientRegisterPacket() *network.Request {
seq := c.nextSeq() seq := c.nextSeq()
svc := &jce.SvcReqRegister{ svc := &jce.SvcReqRegister{
ConnType: 0, ConnType: 0,
@ -532,18 +544,18 @@ func (c *QQClient) buildClientRegisterPacket() (uint16, []byte) {
Status: make(map[string]string), Status: make(map[string]string),
} }
req2 := network.Request{ return &network.Request{
Type: network.RequestTypeLogin, Type: network.RequestTypeLogin,
EncryptType: network.EncryptTypeD2Key, EncryptType: network.EncryptTypeD2Key,
SequenceID: int32(seq), SequenceID: int32(seq),
Uin: c.Uin, Uin: c.Uin,
CommandName: "StatSvc.register", CommandName: "StatSvc.register",
Body: pkt.ToBytes(), Body: pkt.ToBytes(),
Decode: bindDecoder(c, decodeClientRegisterResponse),
} }
return seq, c.transport.PackPacket(&req2)
} }
func (c *QQClient) buildStatusSetPacket(status, extStatus int32) (uint16, []byte) { func (c *QQClient) buildStatusSetPacket(status, extStatus int32) *network.Request {
svc := &jce.SvcReqRegister{ svc := &jce.SvcReqRegister{
ConnType: 0, ConnType: 0,
Uin: c.Uin, Uin: c.Uin,
@ -576,11 +588,11 @@ func (c *QQClient) buildStatusSetPacket(status, extStatus int32) (uint16, []byte
Context: make(map[string]string), Context: make(map[string]string),
Status: make(map[string]string), Status: make(map[string]string),
} }
return c.uniPacket("StatSvc.SetStatusFromClient", pkt.ToBytes()) return c.uniRequest("StatSvc.SetStatusFromClient", pkt.ToBytes(), nil)
} }
// ConfigPushSvc.PushResp // ConfigPushSvc.PushResp
func (c *QQClient) buildConfPushRespPacket(t int32, pktSeq int64, jceBuf []byte) (uint16, []byte) { func (c *QQClient) buildConfPushRespPacket(t int32, pktSeq int64, jceBuf []byte) *network.Request {
req := jce.NewJceWriter() req := jce.NewJceWriter()
req.WriteInt32(t, 1) req.WriteInt32(t, 1)
req.WriteInt64(pktSeq, 2) req.WriteInt64(pktSeq, 2)
@ -596,11 +608,11 @@ func (c *QQClient) buildConfPushRespPacket(t int32, pktSeq int64, jceBuf []byte)
Context: make(map[string]string), Context: make(map[string]string),
Status: make(map[string]string), Status: make(map[string]string),
} }
return c.uniPacket("ConfigPushSvc.PushResp", pkt.ToBytes()) return c.uniRequest("ConfigPushSvc.PushResp", pkt.ToBytes(), nil)
} }
// friendlist.getFriendGroupList // friendlist.getFriendGroupList
func (c *QQClient) buildFriendGroupListRequestPacket(friendStartIndex, friendListCount, groupStartIndex, groupListCount int16) (uint16, []byte) { func (c *QQClient) buildFriendGroupListRequest(friendStartIndex, friendListCount, groupStartIndex, groupListCount int16) *network.Request {
d50, _ := proto.Marshal(&pb.D50ReqBody{ d50, _ := proto.Marshal(&pb.D50ReqBody{
Appid: 1002, Appid: 1002,
ReqMusicSwitch: 1, ReqMusicSwitch: 1,
@ -652,11 +664,11 @@ func (c *QQClient) buildFriendGroupListRequestPacket(friendStartIndex, friendLis
Context: make(map[string]string), Context: make(map[string]string),
Status: make(map[string]string), Status: make(map[string]string),
} }
return c.uniPacket("friendlist.getFriendGroupList", pkt.ToBytes()) return c.uniRequest("friendlist.getFriendGroupList", pkt.ToBytes(), decodeFriendGroupListResponse)
} }
// SummaryCard.ReqSummaryCard // SummaryCard.ReqSummaryCard
func (c *QQClient) buildSummaryCardRequestPacket(target int64) (uint16, []byte) { func (c *QQClient) buildSummaryCardRequest(target int64) *network.Request {
seq := c.nextSeq() seq := c.nextSeq()
packBusinessBuf := func(t int32, buf []byte) []byte { packBusinessBuf := func(t int32, buf []byte) []byte {
return binary.NewWriterF(func(w *binary.Writer) { return binary.NewWriterF(func(w *binary.Writer) {
@ -736,11 +748,11 @@ func (c *QQClient) buildSummaryCardRequestPacket(target int64) (uint16, []byte)
Context: make(map[string]string), Context: make(map[string]string),
Status: make(map[string]string), Status: make(map[string]string),
} }
return seq, c.uniPacketWithSeq(seq, "SummaryCard.ReqSummaryCard", pkt.ToBytes()) return c.uniPacketWithSeq(seq, "SummaryCard.ReqSummaryCard", pkt.ToBytes(), decodeSummaryCardResponse)
} }
// friendlist.delFriend // friendlist.delFriend
func (c *QQClient) buildFriendDeletePacket(target int64) (uint16, []byte) { func (c *QQClient) buildFriendDeletePacket(target int64) *network.Request {
req := &jce.DelFriendReq{ req := &jce.DelFriendReq{
Uin: c.Uin, Uin: c.Uin,
DelUin: target, DelUin: target,
@ -759,11 +771,11 @@ func (c *QQClient) buildFriendDeletePacket(target int64) (uint16, []byte) {
Context: make(map[string]string), Context: make(map[string]string),
Status: make(map[string]string), Status: make(map[string]string),
} }
return c.uniPacket("friendlist.delFriend", pkt.ToBytes()) return c.uniRequest("friendlist.delFriend", pkt.ToBytes(), decodeFriendDeleteResponse)
} }
// friendlist.GetTroopListReqV2 // friendlist.GetTroopListReqV2
func (c *QQClient) buildGroupListRequestPacket(vecCookie []byte) (uint16, []byte) { func (c *QQClient) buildGroupListRequest(vecCookie []byte) *network.Request {
req := &jce.TroopListRequest{ req := &jce.TroopListRequest{
Uin: c.Uin, Uin: c.Uin,
GetMSFMsgFlag: 1, GetMSFMsgFlag: 1,
@ -788,11 +800,11 @@ func (c *QQClient) buildGroupListRequestPacket(vecCookie []byte) (uint16, []byte
Context: make(map[string]string), Context: make(map[string]string),
Status: make(map[string]string), Status: make(map[string]string),
} }
return c.uniPacket("friendlist.GetTroopListReqV2", pkt.ToBytes()) return c.uniRequest("friendlist.GetTroopListReqV2", pkt.ToBytes(), decodeGroupListResponse)
} }
// friendlist.GetTroopMemberListReq // friendlist.GetTroopMemberListReq
func (c *QQClient) buildGroupMemberListRequestPacket(groupUin, groupCode, nextUin int64) (uint16, []byte) { func (c *QQClient) buildGroupMemberListRequest(groupUin, groupCode, nextUin int64) *network.Request {
req := &jce.TroopMemberListRequest{ req := &jce.TroopMemberListRequest{
Uin: c.Uin, Uin: c.Uin,
GroupCode: groupCode, GroupCode: groupCode,
@ -814,11 +826,11 @@ func (c *QQClient) buildGroupMemberListRequestPacket(groupUin, groupCode, nextUi
Context: make(map[string]string), Context: make(map[string]string),
Status: make(map[string]string), Status: make(map[string]string),
} }
return c.uniPacket("friendlist.GetTroopMemberListReq", pkt.ToBytes()) return c.uniRequest("friendlist.GetTroopMemberListReq", pkt.ToBytes(), decodeGroupMemberListResponse)
} }
// group_member_card.get_group_member_card_info // group_member_card.get_group_member_card_info
func (c *QQClient) buildGroupMemberInfoRequestPacket(groupCode, uin int64) (uint16, []byte) { func (c *QQClient) buildGroupMemberInfoRequest(groupCode, uin int64) *network.Request {
req := &pb.GroupMemberReqBody{ req := &pb.GroupMemberReqBody{
GroupCode: groupCode, GroupCode: groupCode,
Uin: uin, Uin: uin,
@ -827,11 +839,11 @@ func (c *QQClient) buildGroupMemberInfoRequestPacket(groupCode, uin int64) (uint
RichCardNameVer: 1, RichCardNameVer: 1,
} }
payload, _ := proto.Marshal(req) payload, _ := proto.Marshal(req)
return c.uniPacket("group_member_card.get_group_member_card_info", payload) return c.uniRequest("group_member_card.get_group_member_card_info", payload, decodeGroupMemberInfoResponse)
} }
// MessageSvc.PbGetMsg // MessageSvc.PbGetMsg
func (c *QQClient) buildGetMessageRequestPacket(flag msg.SyncFlag, msgTime int64) (uint16, []byte) { func (c *QQClient) buildGetMessageRequest(flag msg.SyncFlag, msgTime int64) *network.Request {
cook := c.sig.SyncCookie cook := c.sig.SyncCookie
if cook == nil { if cook == nil {
cook, _ = proto.Marshal(&msg.SyncCookie{ cook, _ = proto.Marshal(&msg.SyncCookie{
@ -856,14 +868,14 @@ func (c *QQClient) buildGetMessageRequestPacket(flag msg.SyncFlag, msgTime int64
ServerBuf: EmptyBytes, ServerBuf: EmptyBytes,
} }
payload, _ := proto.Marshal(req) payload, _ := proto.Marshal(req)
return c.uniPacket("MessageSvc.PbGetMsg", payload) return c.uniRequest("MessageSvc.PbGetMsg", payload, decodeMessageSvcPacket)
} }
// MessageSvc.PbDeleteMsg // MessageSvc.PbDeleteMsg
func (c *QQClient) buildDeleteMessageRequestPacket(msg []*pb.MessageItem) (uint16, []byte) { func (c *QQClient) buildDeleteMessageRequestPacket(msg []*pb.MessageItem) *network.Request {
req := &pb.DeleteMessageRequest{Items: msg} req := &pb.DeleteMessageRequest{Items: msg}
payload, _ := proto.Marshal(req) payload, _ := proto.Marshal(req)
return c.uniPacket("MessageSvc.PbDeleteMsg", payload) return c.uniRequest("MessageSvc.PbDeleteMsg", payload, nil)
} }
// OnlinePush.RespPush // OnlinePush.RespPush
@ -890,11 +902,11 @@ func (c *QQClient) buildDeleteOnlinePushPacket(uin int64, svrip int32, pushToken
Context: make(map[string]string), Context: make(map[string]string),
Status: make(map[string]string), Status: make(map[string]string),
} }
return c.uniPacketWithSeq(seq, "OnlinePush.RespPush", pkt.ToBytes()) return c.transport.PackPacket(c.uniPacketWithSeq(seq, "OnlinePush.RespPush", pkt.ToBytes(), nil))
} }
// LongConn.OffPicUp // LongConn.OffPicUp
func (c *QQClient) buildOffPicUpPacket(target int64, md5 []byte, size int32) (uint16, []byte) { func (c *QQClient) buildOffPicUpRequest(target int64, md5 []byte, size int32) *network.Request {
req := &cmd0x352.ReqBody{ req := &cmd0x352.ReqBody{
Subcmd: proto.Uint32(1), Subcmd: proto.Uint32(1),
TryupImgReq: []*cmd0x352.D352TryUpImgReq{ TryupImgReq: []*cmd0x352.D352TryUpImgReq{
@ -917,11 +929,11 @@ func (c *QQClient) buildOffPicUpPacket(target int64, md5 []byte, size int32) (ui
}, },
} }
payload, _ := proto.Marshal(req) payload, _ := proto.Marshal(req)
return c.uniPacket("LongConn.OffPicUp", payload) return c.uniRequest("LongConn.OffPicUp", payload, decodeOffPicUpResponse)
} }
// ProfileService.Pb.ReqSystemMsgNew.Friend // ProfileService.Pb.ReqSystemMsgNew.Friend
func (c *QQClient) buildSystemMsgNewFriendPacket() (uint16, []byte) { func (c *QQClient) buildSystemMsgNewFriendRequest() *network.Request {
req := &structmsg.ReqSystemMsgNew{ req := &structmsg.ReqSystemMsgNew{
MsgNum: 20, MsgNum: 20,
Version: 1000, Version: 1000,
@ -936,11 +948,11 @@ func (c *QQClient) buildSystemMsgNewFriendPacket() (uint16, []byte) {
FriendMsgTypeFlag: 1, FriendMsgTypeFlag: 1,
} }
payload, _ := proto.Marshal(req) payload, _ := proto.Marshal(req)
return c.uniPacket("ProfileService.Pb.ReqSystemMsgNew.Friend", payload) return c.uniRequest("ProfileService.Pb.ReqSystemMsgNew.Friend", payload, decodeSystemMsgFriendPacket)
} }
// friendlist.ModifyGroupCardReq // friendlist.ModifyGroupCardReq
func (c *QQClient) buildEditGroupTagPacket(groupCode, memberUin int64, newTag string) (uint16, []byte) { func (c *QQClient) buildEditGroupTagPacket(groupCode, memberUin int64, newTag string) *network.Request {
req := &jce.ModifyGroupCardRequest{ req := &jce.ModifyGroupCardRequest{
GroupCode: groupCode, GroupCode: groupCode,
UinInfo: []jce.IJceStruct{ UinInfo: []jce.IJceStruct{
@ -961,11 +973,11 @@ func (c *QQClient) buildEditGroupTagPacket(groupCode, memberUin int64, newTag st
Context: map[string]string{}, Context: map[string]string{},
Status: map[string]string{}, Status: map[string]string{},
} }
return c.uniPacket("friendlist.ModifyGroupCardReq", pkt.ToBytes()) return c.uniRequest("friendlist.ModifyGroupCardReq", pkt.ToBytes(), nil)
} }
// OidbSvc.0x8fc_2 // OidbSvc.0x8fc_2
func (c *QQClient) buildEditSpecialTitlePacket(groupCode, memberUin int64, newTitle string) (uint16, []byte) { func (c *QQClient) buildEditSpecialTitlePacket(groupCode, memberUin int64, newTitle string) *network.Request {
body := &oidb.D8FCReqBody{ body := &oidb.D8FCReqBody{
GroupCode: &groupCode, GroupCode: &groupCode,
MemLevelInfo: []*oidb.D8FCMemberInfo{ MemLevelInfo: []*oidb.D8FCMemberInfo{
@ -979,18 +991,18 @@ func (c *QQClient) buildEditSpecialTitlePacket(groupCode, memberUin int64, newTi
} }
b, _ := proto.Marshal(body) b, _ := proto.Marshal(body)
payload := c.packOIDBPackage(2300, 2, b) payload := c.packOIDBPackage(2300, 2, b)
return c.uniPacket("OidbSvc.0x8fc_2", payload) return c.uniRequest("OidbSvc.0x8fc_2", payload, nil)
} }
// OidbSvc.0x89a_0 // OidbSvc.0x89a_0
func (c *QQClient) buildGroupOperationPacket(body *oidb.D89AReqBody) (uint16, []byte) { func (c *QQClient) buildGroupOperationPacket(body *oidb.D89AReqBody) *network.Request {
b, _ := proto.Marshal(body) b, _ := proto.Marshal(body)
payload := c.packOIDBPackage(2202, 0, b) payload := c.packOIDBPackage(2202, 0, b)
return c.uniPacket("OidbSvc.0x89a_0", payload) return c.uniRequest("OidbSvc.0x89a_0", payload, nil)
} }
// OidbSvc.0x89a_0 // OidbSvc.0x89a_0
func (c *QQClient) buildGroupNameUpdatePacket(groupCode int64, newName string) (uint16, []byte) { func (c *QQClient) buildGroupNameUpdateRequest(groupCode int64, newName string) *network.Request {
body := &oidb.D89AReqBody{ body := &oidb.D89AReqBody{
GroupCode: groupCode, GroupCode: groupCode,
StGroupInfo: &oidb.D89AGroupinfo{ StGroupInfo: &oidb.D89AGroupinfo{
@ -1000,7 +1012,7 @@ func (c *QQClient) buildGroupNameUpdatePacket(groupCode int64, newName string) (
return c.buildGroupOperationPacket(body) return c.buildGroupOperationPacket(body)
} }
func (c *QQClient) buildGroupMemoUpdatePacket(groupCode int64, newMemo string) (uint16, []byte) { func (c *QQClient) buildGroupMemoUpdatePacket(groupCode int64, newMemo string) *network.Request {
body := &oidb.D89AReqBody{ body := &oidb.D89AReqBody{
GroupCode: groupCode, GroupCode: groupCode,
StGroupInfo: &oidb.D89AGroupinfo{ StGroupInfo: &oidb.D89AGroupinfo{
@ -1011,7 +1023,7 @@ func (c *QQClient) buildGroupMemoUpdatePacket(groupCode int64, newMemo string) (
} }
// OidbSvc.0x89a_0 // OidbSvc.0x89a_0
func (c *QQClient) buildGroupMuteAllPacket(groupCode int64, mute bool) (uint16, []byte) { func (c *QQClient) buildGroupMuteAllPacket(groupCode int64, mute bool) *network.Request {
shutUpTime := int32(0) shutUpTime := int32(0)
if mute { if mute {
shutUpTime = 268435455 shutUpTime = 268435455
@ -1026,7 +1038,7 @@ func (c *QQClient) buildGroupMuteAllPacket(groupCode int64, mute bool) (uint16,
} }
// OidbSvc.0x8a0_0 // OidbSvc.0x8a0_0
func (c *QQClient) buildGroupKickPacket(groupCode, memberUin int64, kickMsg string, block bool) (uint16, []byte) { func (c *QQClient) buildGroupKickPacket(groupCode, memberUin int64, kickMsg string, block bool) *network.Request {
flagBlock := 0 flagBlock := 0
if block { if block {
flagBlock = 1 flagBlock = 1
@ -1044,11 +1056,11 @@ func (c *QQClient) buildGroupKickPacket(groupCode, memberUin int64, kickMsg stri
} }
b, _ := proto.Marshal(body) b, _ := proto.Marshal(body)
payload := c.packOIDBPackage(2208, 0, b) payload := c.packOIDBPackage(2208, 0, b)
return c.uniPacket("OidbSvc.0x8a0_0", payload) return c.uniRequest("OidbSvc.0x8a0_0", payload, nil)
} }
// OidbSvc.0x570_8 // OidbSvc.0x570_8
func (c *QQClient) buildGroupMutePacket(groupCode, memberUin int64, time uint32) (uint16, []byte) { func (c *QQClient) buildGroupMutePacket(groupCode, memberUin int64, time uint32) *network.Request {
b, cl := binary.OpenWriterF(func(w *binary.Writer) { b, cl := binary.OpenWriterF(func(w *binary.Writer) {
w.WriteUInt32(uint32(groupCode)) w.WriteUInt32(uint32(groupCode))
w.WriteByte(32) w.WriteByte(32)
@ -1058,33 +1070,33 @@ func (c *QQClient) buildGroupMutePacket(groupCode, memberUin int64, time uint32)
}) })
payload := c.packOIDBPackage(1392, 8, b) payload := c.packOIDBPackage(1392, 8, b)
cl() cl()
return c.uniPacket("OidbSvc.0x570_8", payload) return c.uniRequest("OidbSvc.0x570_8", payload, nil)
} }
// OidbSvc.0xed3 // OidbSvc.0xed3
func (c *QQClient) buildGroupPokePacket(groupCode, target int64) (uint16, []byte) { func (c *QQClient) buildGroupPokeRequest(groupCode, target int64) *network.Request {
body := &oidb.DED3ReqBody{ body := &oidb.DED3ReqBody{
ToUin: target, ToUin: target,
GroupCode: groupCode, GroupCode: groupCode,
} }
b, _ := proto.Marshal(body) b, _ := proto.Marshal(body)
payload := c.packOIDBPackage(3795, 1, b) payload := c.packOIDBPackage(3795, 1, b)
return c.uniPacket("OidbSvc.0xed3", payload) return c.uniRequest("OidbSvc.0xed3", payload, nil)
} }
// OidbSvc.0xed3 // OidbSvc.0xed3
func (c *QQClient) buildFriendPokePacket(target int64) (uint16, []byte) { func (c *QQClient) buildFriendPokeRequest(target int64) *network.Request {
body := &oidb.DED3ReqBody{ body := &oidb.DED3ReqBody{
ToUin: target, ToUin: target,
AioUin: target, AioUin: target,
} }
b, _ := proto.Marshal(body) b, _ := proto.Marshal(body)
payload := c.packOIDBPackage(3795, 1, b) payload := c.packOIDBPackage(3795, 1, b)
return c.uniPacket("OidbSvc.0xed3", payload) return c.uniRequest("OidbSvc.0xed3", payload, nil)
} }
// OidbSvc.0x55c_1 // OidbSvc.0x55c_1
func (c *QQClient) buildGroupAdminSetPacket(groupCode, member int64, flag bool) (uint16, []byte) { func (c *QQClient) buildGroupAdminSetPacket(groupCode, member int64, flag bool) *network.Request {
b, cl := binary.OpenWriterF(func(w *binary.Writer) { b, cl := binary.OpenWriterF(func(w *binary.Writer) {
w.WriteUInt32(uint32(groupCode)) w.WriteUInt32(uint32(groupCode))
w.WriteUInt32(uint32(member)) w.WriteUInt32(uint32(member))
@ -1092,11 +1104,11 @@ func (c *QQClient) buildGroupAdminSetPacket(groupCode, member int64, flag bool)
}) })
payload := c.packOIDBPackage(1372, 1, b) payload := c.packOIDBPackage(1372, 1, b)
cl() cl()
return c.uniPacket("OidbSvc.0x55c_1", payload) return c.uniRequest("OidbSvc.0x55c_1", payload, nil)
} }
// ProfileService.GroupMngReq // ProfileService.GroupMngReq
func (c *QQClient) buildQuitGroupPacket(groupCode int64) (uint16, []byte) { func (c *QQClient) buildQuitGroupPacket(groupCode int64) *network.Request {
jw := jce.NewJceWriter() jw := jce.NewJceWriter()
jw.WriteInt32(2, 0) jw.WriteInt32(2, 0)
jw.WriteInt64(c.Uin, 1) jw.WriteInt64(c.Uin, 1)
@ -1116,12 +1128,12 @@ func (c *QQClient) buildQuitGroupPacket(groupCode int64) (uint16, []byte) {
Context: map[string]string{}, Context: map[string]string{},
Status: map[string]string{}, Status: map[string]string{},
} }
return c.uniPacket("ProfileService.GroupMngReq", pkt.ToBytes()) return c.uniRequest("ProfileService.GroupMngReq", pkt.ToBytes(), nil)
} }
/* this function is unused /* this function is unused
// LightAppSvc.mini_app_info.GetAppInfoById // LightAppSvc.mini_app_info.GetAppInfoById
func (c *QQClient) buildAppInfoRequestPacket(id string) (uint16, []byte) { func (c *QQClient) buildAppInfoRequestPacket(id string) *network.Request {
seq := c.nextSeq() seq := c.nextSeq()
req := &qweb.GetAppInfoByIdReq{ req := &qweb.GetAppInfoByIdReq{
AppId: id, AppId: id,
@ -1141,11 +1153,11 @@ func (c *QQClient) buildAppInfoRequestPacket(id string) (uint16, []byte) {
} }
*/ */
func (c *QQClient) buildWordSegmentationPacket(data []byte) (uint16, []byte) { func (c *QQClient) buildWordSegmentationPacket(data []byte) *network.Request {
payload := c.packOIDBPackageProto(3449, 1, &oidb.D79ReqBody{ payload := c.packOIDBPackageProto(3449, 1, &oidb.D79ReqBody{
Uin: uint64(c.Uin), Uin: uint64(c.Uin),
Content: data, Content: data,
Qua: []byte("and_537065262_8.4.5"), Qua: []byte("and_537065262_8.4.5"),
}) })
return c.uniPacket("OidbSvc.0xd79", payload) return c.uniRequest("OidbSvc.0xd79", payload, decodeWordSegmentation)
} }

View File

@ -39,7 +39,7 @@ const (
AddressBookSource // 来自通讯录 AddressBookSource // 来自通讯录
) )
func (c *QQClient) c2cMessageSyncProcessor(rsp *msg.GetMessageResponse, info *network.IncomingPacketInfo) { func (c *QQClient) c2cMessageSyncProcessor(rsp *msg.GetMessageResponse, resp *network.Response) {
c.sig.SyncCookie = rsp.SyncCookie c.sig.SyncCookie = rsp.SyncCookie
c.sig.PubAccountCookie = rsp.PubAccountCookie c.sig.PubAccountCookie = rsp.PubAccountCookie
// c.msgCtrlBuf = rsp.MsgCtrlBuf // c.msgCtrlBuf = rsp.MsgCtrlBuf
@ -64,20 +64,21 @@ func (c *QQClient) c2cMessageSyncProcessor(rsp *msg.GetMessageResponse, info *ne
if (int64(pairMsg.GetLastReadTime()) & 4294967295) > int64(pMsg.Head.GetMsgTime()) { if (int64(pairMsg.GetLastReadTime()) & 4294967295) > int64(pMsg.Head.GetMsgTime()) {
continue continue
} }
c.commMsgProcessor(pMsg, info) c.commMsgProcessor(pMsg, resp)
} }
} }
if delItems != nil { if delItems != nil {
_, _ = c.sendAndWait(c.buildDeleteMessageRequestPacket(delItems)) _, _ = c.call(c.buildDeleteMessageRequestPacket(delItems))
} }
if rsp.GetSyncFlag() != msg.SyncFlag_STOP { if rsp.GetSyncFlag() != msg.SyncFlag_STOP {
c.Debug("continue sync with flag: %v", rsp.SyncFlag) c.Debug("continue sync with flag: %v", rsp.SyncFlag)
seq, pkt := c.buildGetMessageRequestPacket(rsp.GetSyncFlag(), time.Now().Unix()) req := c.buildGetMessageRequest(rsp.GetSyncFlag(), time.Now().Unix())
_, _ = c.sendAndWait(seq, pkt, info.Params) req.Params = resp.Params()
_, _ = c.callAndDecode(req)
} }
} }
func (c *QQClient) commMsgProcessor(pMsg *msg.Message, info *network.IncomingPacketInfo) { func (c *QQClient) commMsgProcessor(pMsg *msg.Message, resp *network.Response) {
strKey := fmt.Sprintf("%d%d%d%d", pMsg.Head.GetFromUin(), pMsg.Head.GetToUin(), pMsg.Head.GetMsgSeq(), pMsg.Head.GetMsgUid()) strKey := fmt.Sprintf("%d%d%d%d", pMsg.Head.GetFromUin(), pMsg.Head.GetToUin(), pMsg.Head.GetMsgSeq(), pMsg.Head.GetMsgUid())
if _, ok := c.msgSvcCache.GetAndUpdate(strKey, time.Hour); ok { if _, ok := c.msgSvcCache.GetAndUpdate(strKey, time.Hour); ok {
c.Debug("c2c msg %v already exists in cache. skip.", pMsg.Head.GetMsgUid()) c.Debug("c2c msg %v already exists in cache. skip.", pMsg.Head.GetMsgUid())
@ -89,17 +90,17 @@ func (c *QQClient) commMsgProcessor(pMsg *msg.Message, info *network.IncomingPac
return return
} }
c.lastC2CMsgTime = int64(pMsg.Head.GetMsgTime()) c.lastC2CMsgTime = int64(pMsg.Head.GetMsgTime())
if info.Params.Bool("init") { if resp.Params().Bool("init") {
return return
} }
if decoder, _ := peekC2CDecoder(pMsg.Head.GetMsgType()); decoder != nil { if decoder, _ := peekC2CDecoder(pMsg.Head.GetMsgType()); decoder != nil {
decoder(c, pMsg, info) decoder(c, pMsg, resp)
} else { } else {
c.Debug("unknown msg type on c2c processor: %v - %v", pMsg.Head.GetMsgType(), pMsg.Head.GetC2CCmd()) c.Debug("unknown msg type on c2c processor: %v - %v", pMsg.Head.GetMsgType(), pMsg.Head.GetC2CCmd())
} }
} }
func privateMessageDecoder(c *QQClient, pMsg *msg.Message, _ *network.IncomingPacketInfo) { func privateMessageDecoder(c *QQClient, pMsg *msg.Message, _ *network.Response) {
switch pMsg.Head.GetC2CCmd() { switch pMsg.Head.GetC2CCmd() {
case 11, 175: // friend msg case 11, 175: // friend msg
if pMsg.Head.GetFromUin() == c.Uin { if pMsg.Head.GetFromUin() == c.Uin {
@ -127,7 +128,7 @@ func privateMessageDecoder(c *QQClient, pMsg *msg.Message, _ *network.IncomingPa
} }
} }
func privatePttDecoder(c *QQClient, pMsg *msg.Message, _ *network.IncomingPacketInfo) { func privatePttDecoder(c *QQClient, pMsg *msg.Message, _ *network.Response) {
if pMsg.Body == nil || pMsg.Body.RichText == nil || pMsg.Body.RichText.Ptt == nil { if pMsg.Body == nil || pMsg.Body.RichText == nil || pMsg.Body.RichText.Ptt == nil {
return return
} }
@ -138,7 +139,7 @@ func privatePttDecoder(c *QQClient, pMsg *msg.Message, _ *network.IncomingPacket
c.dispatchPrivateMessage(c.parsePrivateMessage(pMsg)) c.dispatchPrivateMessage(c.parsePrivateMessage(pMsg))
} }
func tempSessionDecoder(c *QQClient, pMsg *msg.Message, _ *network.IncomingPacketInfo) { func tempSessionDecoder(c *QQClient, pMsg *msg.Message, _ *network.Response) {
if pMsg.Head.C2CTmpMsgHead == nil || pMsg.Body == nil { if pMsg.Head.C2CTmpMsgHead == nil || pMsg.Body == nil {
return return
} }
@ -199,7 +200,7 @@ func tempSessionDecoder(c *QQClient, pMsg *msg.Message, _ *network.IncomingPacke
} }
} }
func troopAddMemberBroadcastDecoder(c *QQClient, pMsg *msg.Message, _ *network.IncomingPacketInfo) { func troopAddMemberBroadcastDecoder(c *QQClient, pMsg *msg.Message, resp *network.Response) {
groupJoinLock.Lock() groupJoinLock.Lock()
defer groupJoinLock.Unlock() defer groupJoinLock.Unlock()
group := c.FindGroupByUin(pMsg.Head.GetFromUin()) group := c.FindGroupByUin(pMsg.Head.GetFromUin())
@ -226,13 +227,12 @@ func troopAddMemberBroadcastDecoder(c *QQClient, pMsg *msg.Message, _ *network.I
} }
} }
func systemMessageDecoder(c *QQClient, _ *msg.Message, _ *network.IncomingPacketInfo) { func systemMessageDecoder(c *QQClient, _ *msg.Message, _ *network.Response) {
_, pkt := c.buildSystemMsgNewFriendPacket() _, _ = c.call(c.buildSystemMsgNewFriendRequest())
_ = c.sendPacket(pkt)
} }
func troopSystemMessageDecoder(c *QQClient, pMsg *msg.Message, info *network.IncomingPacketInfo) { func troopSystemMessageDecoder(c *QQClient, pMsg *msg.Message, info *network.Response) {
if !info.Params.Bool("used_reg_proxy") && pMsg.Head.GetMsgType() != 85 && pMsg.Head.GetMsgType() != 36 { if !info.Params().Bool("used_reg_proxy") && pMsg.Head.GetMsgType() != 85 && pMsg.Head.GetMsgType() != 36 {
c.exceptAndDispatchGroupSysMsg() c.exceptAndDispatchGroupSysMsg()
} }
if len(pMsg.Body.GetMsgContent()) == 0 { if len(pMsg.Body.GetMsgContent()) == 0 {
@ -246,7 +246,7 @@ func troopSystemMessageDecoder(c *QQClient, pMsg *msg.Message, info *network.Inc
} }
} }
func msgType0x211Decoder(c *QQClient, pMsg *msg.Message, info *network.IncomingPacketInfo) { func msgType0x211Decoder(c *QQClient, pMsg *msg.Message, info *network.Response) {
if pMsg.Head.GetC2CCmd() == 6 || pMsg.Head.C2CTmpMsgHead != nil { if pMsg.Head.GetC2CCmd() == 6 || pMsg.Head.C2CTmpMsgHead != nil {
tempSessionDecoder(c, pMsg, info) tempSessionDecoder(c, pMsg, info)
} }
@ -257,7 +257,7 @@ func msgType0x211Decoder(c *QQClient, pMsg *msg.Message, info *network.IncomingP
return return
} }
if sub4.NotOnlineFile != nil && sub4.NotOnlineFile.GetSubcmd() == 1 { // subcmd: 1 -> sendPacket, 2-> recv if sub4.NotOnlineFile != nil && sub4.NotOnlineFile.GetSubcmd() == 1 { // subcmd: 1 -> sendPacket, 2-> recv
rsp, err := c.sendAndWait(c.buildOfflineFileDownloadRequestPacket(sub4.NotOnlineFile.FileUuid)) // offline_file.go rsp, err := c.callAndDecode(c.buildOfflineFileDownloadRequestPacket(sub4.NotOnlineFile.FileUuid)) // offline_file.go
if err != nil { if err != nil {
return return
} }

View File

@ -16,7 +16,7 @@ const (
troopSystemMsgDecoders troopSystemMsgDecoders
) )
func peekC2CDecoder(msgType int32) (decoder func(*QQClient, *msg.Message, *network.IncomingPacketInfo), decoderType uint8) { func peekC2CDecoder(msgType int32) (decoder func(*QQClient, *msg.Message, *network.Response), decoderType uint8) {
switch msgType { switch msgType {
case 9: case 9:
return privateMessageDecoder, privateMsgDecoders return privateMessageDecoder, privateMsgDecoders

View File

@ -23,8 +23,6 @@ import (
"github.com/Mrs4s/MiraiGo/utils" "github.com/Mrs4s/MiraiGo/utils"
) )
//go:generate go run github.com/a8m/syncmap -o "handler_map_gen.go" -pkg client -name HandlerMap "map[uint16]*handlerInfo"
type QQClient struct { type QQClient struct {
Uin int64 Uin int64
PasswordMd5 [16]byte PasswordMd5 [16]byte
@ -50,21 +48,19 @@ type QQClient struct {
SequenceId atomic.Int32 SequenceId atomic.Int32
SessionId []byte SessionId []byte
RandomKey []byte RandomKey []byte
TCP *network.TCPListener // todo: combine other protocol state into one struct
ConnectTime time.Time ConnectTime time.Time
// todo: combine net conn, transport, pending into one struct
pendingMu sync.Mutex
pending map[int32]*network.Call
// TCP *network.TCPListener
transport *network.Transport transport *network.Transport
oicq *oicq.Codec oicq *oicq.Codec
// internal state // internal state
handlers HandlerMap
waiters sync.Map waiters sync.Map
servers []*net.TCPAddr
currServerIndex int
retryTimes int
version *auth.AppVersion version *auth.AppVersion
deviceInfo *auth.Device deviceInfo *auth.Device
alive bool
// session info // session info
qwebSeq atomic.Int64 qwebSeq atomic.Int64
@ -103,44 +99,14 @@ type QiDianAccountInfo struct {
bigDataReqSession *bigDataSessionInfo bigDataReqSession *bigDataSessionInfo
} }
type handlerInfo struct { var decoders = map[string]func(*QQClient, *network.Response) (interface{}, error){
fun func(i interface{}, err error)
dynamic bool
params network.RequestParams
}
func (h *handlerInfo) getParams() network.RequestParams {
if h == nil {
return nil
}
return h.params
}
var decoders = map[string]func(*QQClient, *network.IncomingPacketInfo, []byte) (interface{}, error){
"wtlogin.login": decodeLoginResponse,
"wtlogin.exchange_emp": decodeExchangeEmpResponse,
"wtlogin.trans_emp": decodeTransEmpResponse,
"StatSvc.register": decodeClientRegisterResponse,
"StatSvc.ReqMSFOffline": decodeMSFOfflinePacket, "StatSvc.ReqMSFOffline": decodeMSFOfflinePacket,
"MessageSvc.PushNotify": decodeSvcNotify, "MessageSvc.PushNotify": decodeSvcNotify,
"OnlinePush.ReqPush": decodeOnlinePushReqPacket, "OnlinePush.ReqPush": decodeOnlinePushReqPacket,
"OnlinePush.PbPushTransMsg": decodeOnlinePushTransPacket, "OnlinePush.PbPushTransMsg": decodeOnlinePushTransPacket,
"OnlinePush.SidTicketExpired": decodeSidExpiredPacket, "OnlinePush.SidTicketExpired": decodeSidExpiredPacket,
"ConfigPushSvc.PushReq": decodePushReqPacket, "ConfigPushSvc.PushReq": decodePushReqPacket,
"MessageSvc.PbGetMsg": decodeMessageSvcPacket,
"MessageSvc.PushForceOffline": decodeForceOfflinePacket, "MessageSvc.PushForceOffline": decodeForceOfflinePacket,
"PbMessageSvc.PbMsgWithDraw": decodeMsgWithDrawResponse,
"friendlist.getFriendGroupList": decodeFriendGroupListResponse,
"friendlist.delFriend": decodeFriendDeleteResponse,
"friendlist.GetTroopListReqV2": decodeGroupListResponse,
"friendlist.GetTroopMemberListReq": decodeGroupMemberListResponse,
"group_member_card.get_group_member_card_info": decodeGroupMemberInfoResponse,
"LongConn.OffPicUp": decodeOffPicUpResponse,
"ProfileService.Pb.ReqSystemMsgNew.Group": decodeSystemMsgGroupPacket,
"ProfileService.Pb.ReqSystemMsgNew.Friend": decodeSystemMsgFriendPacket,
"OidbSvc.0xd79": decodeWordSegmentation,
"OidbSvc.0x990": decodeTranslateResponse,
"SummaryCard.ReqSummaryCard": decodeSummaryCardResponse,
} }
func init() { func init() {
@ -161,7 +127,7 @@ func NewClientMd5(uin int64, passwordMd5 [16]byte) *QQClient {
Uin: uin, Uin: uin,
PasswordMd5: passwordMd5, PasswordMd5: passwordMd5,
AllowSlider: true, AllowSlider: true,
TCP: &network.TCPListener{}, // TCP: &network.TCPListener{},
sig: &auth.SigInfo{ sig: &auth.SigInfo{
OutPacketSessionID: []byte{0x02, 0xB0, 0x5B, 0x8B}, OutPacketSessionID: []byte{0x02, 0xB0, 0x5B, 0x8B},
}, },
@ -169,10 +135,9 @@ func NewClientMd5(uin int64, passwordMd5 [16]byte) *QQClient {
msgSvcCache: utils.NewCache(time.Second * 15), msgSvcCache: utils.NewCache(time.Second * 15),
transCache: utils.NewCache(time.Second * 15), transCache: utils.NewCache(time.Second * 15),
onlinePushCache: utils.NewCache(time.Second * 15), onlinePushCache: utils.NewCache(time.Second * 15),
servers: []*net.TCPAddr{},
alive: true,
highwaySession: new(highway.Session), highwaySession: new(highway.Session),
pending: make(map[int32]*network.Call),
version: new(auth.AppVersion), version: new(auth.AppVersion),
deviceInfo: new(auth.Device), deviceInfo: new(auth.Device),
} }
@ -195,30 +160,32 @@ func NewClientMd5(uin int64, passwordMd5 [16]byte) *QQClient {
cli.UseDevice(SystemDeviceInfo) cli.UseDevice(SystemDeviceInfo)
sso, err := getSSOAddress() sso, err := getSSOAddress()
if err == nil && len(sso) > 0 { if err == nil && len(sso) > 0 {
cli.servers = append(sso, cli.servers...) for _, addr := range sso {
cli.transport.AddServerAddr(addr)
}
} }
adds, err := net.LookupIP("msfwifi.3g.qq.com") // host servers adds, err := net.LookupIP("msfwifi.3g.qq.com") // host servers
if err == nil && len(adds) > 0 { if err == nil && len(adds) > 0 {
var hostAddrs []*net.TCPAddr
for _, addr := range adds { for _, addr := range adds {
hostAddrs = append(hostAddrs, &net.TCPAddr{ cli.transport.AddServerAddr(&net.TCPAddr{
IP: addr, IP: addr,
Port: 8080, Port: 8080,
}) })
} }
cli.servers = append(hostAddrs, cli.servers...)
} }
if len(cli.servers) == 0 { if cli.transport.ServerCount() == 0 {
cli.servers = []*net.TCPAddr{ // default servers for _, addr := range []*net.TCPAddr{ // default servers
{IP: net.IP{42, 81, 172, 81}, Port: 80},
{IP: net.IP{114, 221, 148, 59}, Port: 14000},
{IP: net.IP{42, 81, 172, 147}, Port: 443},
{IP: net.IP{125, 94, 60, 146}, Port: 80},
{IP: net.IP{114, 221, 144, 215}, Port: 80},
{IP: net.IP{42, 81, 172, 22}, Port: 80}, {IP: net.IP{42, 81, 172, 22}, Port: 80},
{IP: net.IP{42, 81, 172, 81}, Port: 80},
{IP: net.IP{42, 81, 172, 147}, Port: 443},
{IP: net.IP{114, 221, 144, 215}, Port: 80},
{IP: net.IP{114, 221, 148, 59}, Port: 14000},
{IP: net.IP{125, 94, 60, 146}, Port: 80},
} {
cli.transport.AddServerAddr(addr)
} }
} }
pings := make([]int64, len(cli.servers)) /*pings := make([]int64, len(cli.servers))
wg := sync.WaitGroup{} wg := sync.WaitGroup{}
wg.Add(len(cli.servers)) wg.Add(len(cli.servers))
for i := range cli.servers { for i := range cli.servers {
@ -238,9 +205,9 @@ func NewClientMd5(uin int64, passwordMd5 [16]byte) *QQClient {
}) })
if len(cli.servers) > 3 { if len(cli.servers) > 3 {
cli.servers = cli.servers[0 : len(cli.servers)/2] // 保留ping值中位数以上的server cli.servers = cli.servers[0 : len(cli.servers)/2] // 保留ping值中位数以上的server
} }*/
cli.TCP.PlannedDisconnect(cli.plannedDisconnect) cli.transport.PlannedDisconnect(cli.plannedDisconnect)
cli.TCP.UnexpectedDisconnect(cli.unexpectedDisconnect) cli.transport.UnexpectedDisconnect(cli.unexpectedDisconnect)
rand.Read(cli.RandomKey) rand.Read(cli.RandomKey)
return cli return cli
} }
@ -256,7 +223,6 @@ func (c *QQClient) Release() {
if c.Online.Load() { if c.Online.Load() {
c.Disconnect() c.Disconnect()
} }
c.alive = false
} }
// Login send login request // Login send login request
@ -268,7 +234,7 @@ func (c *QQClient) Login() (*LoginResponse, error) {
if err != nil { if err != nil {
return nil, err return nil, err
} }
rsp, err := c.sendAndWait(c.buildLoginPacket()) rsp, err := c.callAndDecode(c.buildLoginRequest())
if err != nil { if err != nil {
c.Disconnect() c.Disconnect()
return nil, err return nil, err
@ -284,11 +250,50 @@ func (c *QQClient) TokenLogin(token []byte) error {
if c.Online.Load() { if c.Online.Load() {
return ErrAlreadyOnline return ErrAlreadyOnline
} }
err := c.connect() err := c.LoadToken(token)
if err != nil { if err != nil {
return err return err
} }
{ return c.ReLogin()
}
func (c *QQClient) ReLogin() error {
if c.Online.Load() {
return ErrAlreadyOnline
}
err := c.connectFastest()
if err != nil {
return err
}
_, err = c.callAndDecode(c.buildRequestChangeSigRequest(c.version.MainSigMap))
if err != nil {
return err
}
err = c.init(true)
// 登录失败
if err != nil {
c.Disconnect()
}
return err
}
func (c *QQClient) DumpToken() []byte {
return binary.NewWriterF(func(w *binary.Writer) {
w.WriteUInt64(uint64(c.Uin))
w.WriteBytesShort(c.sig.D2)
w.WriteBytesShort(c.sig.D2Key)
w.WriteBytesShort(c.sig.TGT)
w.WriteBytesShort(c.sig.SrmToken)
w.WriteBytesShort(c.sig.T133)
w.WriteBytesShort(c.sig.EncryptedA1)
w.WriteBytesShort(c.oicq.WtSessionTicketKey)
w.WriteBytesShort(c.sig.OutPacketSessionID)
w.WriteBytesShort(c.deviceInfo.TgtgtKey)
})
}
func (c *QQClient) LoadToken(token []byte) error {
return utils.CoverError(func() {
r := binary.NewReader(token) r := binary.NewReader(token)
c.Uin = r.ReadInt64() c.Uin = r.ReadInt64()
c.sig.D2 = r.ReadBytesShort() c.sig.D2 = r.ReadBytesShort()
@ -301,18 +306,83 @@ func (c *QQClient) TokenLogin(token []byte) error {
c.sig.OutPacketSessionID = r.ReadBytesShort() c.sig.OutPacketSessionID = r.ReadBytesShort()
// SystemDeviceInfo.TgtgtKey = r.ReadBytesShort() // SystemDeviceInfo.TgtgtKey = r.ReadBytesShort()
c.deviceInfo.TgtgtKey = r.ReadBytesShort() c.deviceInfo.TgtgtKey = r.ReadBytesShort()
} copy(SystemDeviceInfo.TgtgtKey, c.deviceInfo.TgtgtKey)
_, err = c.sendAndWait(c.buildRequestChangeSigPacket(c.version.MainSigMap)) })
if err != nil {
return err
}
return c.init(true)
} }
func (c *QQClient) DumpDevice() []byte {
return binary.NewWriterF(func(w *binary.Writer) {
w.WriteBytesShort(c.deviceInfo.Display)
w.WriteBytesShort(c.deviceInfo.Product)
w.WriteBytesShort(c.deviceInfo.Device)
w.WriteBytesShort(c.deviceInfo.Board)
w.WriteBytesShort(c.deviceInfo.Brand)
w.WriteBytesShort(c.deviceInfo.Model)
w.WriteBytesShort(c.deviceInfo.Bootloader)
w.WriteBytesShort(c.deviceInfo.FingerPrint)
w.WriteBytesShort(c.deviceInfo.BootId)
w.WriteBytesShort(c.deviceInfo.ProcVersion)
w.WriteBytesShort(c.deviceInfo.BaseBand)
w.WriteBytesShort(c.deviceInfo.SimInfo)
w.WriteBytesShort(c.deviceInfo.OSType)
w.WriteBytesShort(c.deviceInfo.MacAddress)
w.WriteBytesShort(c.deviceInfo.IpAddress)
w.WriteBytesShort(c.deviceInfo.WifiBSSID)
w.WriteBytesShort(c.deviceInfo.WifiSSID)
w.WriteBytesShort(c.deviceInfo.IMSIMd5)
w.WriteStringShort(c.deviceInfo.IMEI)
w.WriteBytesShort(c.deviceInfo.APN)
w.WriteBytesShort(c.deviceInfo.VendorName)
w.WriteBytesShort(c.deviceInfo.VendorOSName)
w.WriteBytesShort(c.deviceInfo.AndroidId)
w.Write(c.PasswordMd5[:])
})
}
func (c *QQClient) LoadDevice(device []byte) error {
return utils.CoverError(func() {
r := binary.NewReader(device)
c.deviceInfo.Display = r.ReadBytesShort()
c.deviceInfo.Product = r.ReadBytesShort()
c.deviceInfo.Device = r.ReadBytesShort()
c.deviceInfo.Board = r.ReadBytesShort()
c.deviceInfo.Brand = r.ReadBytesShort()
c.deviceInfo.Model = r.ReadBytesShort()
c.deviceInfo.Bootloader = r.ReadBytesShort()
c.deviceInfo.FingerPrint = r.ReadBytesShort()
c.deviceInfo.BootId = r.ReadBytesShort()
c.deviceInfo.ProcVersion = r.ReadBytesShort()
c.deviceInfo.BaseBand = r.ReadBytesShort()
c.deviceInfo.SimInfo = r.ReadBytesShort()
c.deviceInfo.OSType = r.ReadBytesShort()
c.deviceInfo.MacAddress = r.ReadBytesShort()
c.deviceInfo.IpAddress = r.ReadBytesShort()
c.deviceInfo.WifiBSSID = r.ReadBytesShort()
c.deviceInfo.WifiSSID = r.ReadBytesShort()
c.deviceInfo.IMSIMd5 = r.ReadBytesShort()
c.deviceInfo.IMEI = r.ReadStringShort()
c.deviceInfo.APN = r.ReadBytesShort()
c.deviceInfo.VendorName = r.ReadBytesShort()
c.deviceInfo.VendorOSName = r.ReadBytesShort()
c.deviceInfo.AndroidId = r.ReadBytesShort()
copy(c.PasswordMd5[:], r.ReadBytes(md5.Size))
})
}
// FetchQRCode 以默认值获取登录二维码
// 函数已被弃用 请使用FetchQRCodeCustomSize获得更可控结果
// 但该兼容函数不会被删除
// Deprecated use FetchQRCodeCustomSize(3, 4, 2) instead
func (c *QQClient) FetchQRCode() (*QRCodeLoginResponse, error) { func (c *QQClient) FetchQRCode() (*QRCodeLoginResponse, error) {
return c.FetchQRCodeCustomSize(3, 4, 2) return c.FetchQRCodeCustomSize(3, 4, 2)
} }
// FetchQRCodeCustomSize 以特定参数获取登录二维码
// size: 块尺寸 默认值3 即单个黑/白块大小为3x3像素
// margin: 与图片边界的距离 默认值4 即二维码主体至图片边界有4像素白色填充
// ecLevel: 纠错等级 可用值1,2,3 默认值2
func (c *QQClient) FetchQRCodeCustomSize(size, margin, ecLevel uint32) (*QRCodeLoginResponse, error) { func (c *QQClient) FetchQRCodeCustomSize(size, margin, ecLevel uint32) (*QRCodeLoginResponse, error) {
if c.Online.Load() { if c.Online.Load() {
return nil, ErrAlreadyOnline return nil, ErrAlreadyOnline
@ -321,7 +391,9 @@ func (c *QQClient) FetchQRCodeCustomSize(size, margin, ecLevel uint32) (*QRCodeL
if err != nil { if err != nil {
return nil, err return nil, err
} }
i, err := c.sendAndWait(c.buildQRCodeFetchRequestPacket(size, margin, ecLevel)) c.transport.Version = auth.AndroidWatch.Version()
i, err := c.callAndDecode(c.buildQRCodeFetchRequest(size, margin, ecLevel))
c.transport.Version = c.version
if err != nil { if err != nil {
return nil, errors.Wrap(err, "fetch qrcode error") return nil, errors.Wrap(err, "fetch qrcode error")
} }
@ -329,7 +401,9 @@ func (c *QQClient) FetchQRCodeCustomSize(size, margin, ecLevel uint32) (*QRCodeL
} }
func (c *QQClient) QueryQRCodeStatus(sig []byte) (*QRCodeLoginResponse, error) { func (c *QQClient) QueryQRCodeStatus(sig []byte) (*QRCodeLoginResponse, error) {
i, err := c.sendAndWait(c.buildQRCodeResultQueryRequestPacket(sig)) c.transport.Version = auth.AndroidWatch.Version()
i, err := c.callAndDecode(c.buildQRCodeResultQueryRequest(sig))
c.transport.Version = c.version
if err != nil { if err != nil {
return nil, errors.Wrap(err, "query result error") return nil, errors.Wrap(err, "query result error")
} }
@ -337,7 +411,7 @@ func (c *QQClient) QueryQRCodeStatus(sig []byte) (*QRCodeLoginResponse, error) {
} }
func (c *QQClient) QRCodeLogin(info *QRCodeLoginInfo) (*LoginResponse, error) { func (c *QQClient) QRCodeLogin(info *QRCodeLoginInfo) (*LoginResponse, error) {
i, err := c.sendAndWait(c.buildQRCodeLoginPacket(info.tmpPwd, info.tmpNoPicSig, info.tgtQR)) i, err := c.callAndDecode(c.buildQRCodeLoginRequest(info.tmpPwd, info.tmpNoPicSig, info.tgtQR))
if err != nil { if err != nil {
return nil, errors.Wrap(err, "qrcode login error") return nil, errors.Wrap(err, "qrcode login error")
} }
@ -350,8 +424,8 @@ func (c *QQClient) QRCodeLogin(info *QRCodeLoginInfo) (*LoginResponse, error) {
// SubmitCaptcha send captcha to server // SubmitCaptcha send captcha to server
func (c *QQClient) SubmitCaptcha(result string, sign []byte) (*LoginResponse, error) { func (c *QQClient) SubmitCaptcha(result string, sign []byte) (*LoginResponse, error) {
seq, packet := c.buildCaptchaPacket(result, sign) req := c.buildCaptchaRequest(result, sign)
rsp, err := c.sendAndWait(seq, packet) rsp, err := c.callAndDecode(req)
if err != nil { if err != nil {
c.Disconnect() c.Disconnect()
return nil, err return nil, err
@ -364,8 +438,8 @@ func (c *QQClient) SubmitCaptcha(result string, sign []byte) (*LoginResponse, er
} }
func (c *QQClient) SubmitTicket(ticket string) (*LoginResponse, error) { func (c *QQClient) SubmitTicket(ticket string) (*LoginResponse, error) {
seq, packet := c.buildTicketSubmitPacket(ticket) req := c.buildTicketSubmitRequest(ticket)
rsp, err := c.sendAndWait(seq, packet) rsp, err := c.callAndDecode(req)
if err != nil { if err != nil {
c.Disconnect() c.Disconnect()
return nil, err return nil, err
@ -378,7 +452,7 @@ func (c *QQClient) SubmitTicket(ticket string) (*LoginResponse, error) {
} }
func (c *QQClient) SubmitSMS(code string) (*LoginResponse, error) { func (c *QQClient) SubmitSMS(code string) (*LoginResponse, error) {
rsp, err := c.sendAndWait(c.buildSMSCodeSubmitPacket(code)) rsp, err := c.callAndDecode(c.buildSMSCodeSubmitRequest(code))
if err != nil { if err != nil {
c.Disconnect() c.Disconnect()
return nil, err return nil, err
@ -391,7 +465,7 @@ func (c *QQClient) SubmitSMS(code string) (*LoginResponse, error) {
} }
func (c *QQClient) RequestSMS() bool { func (c *QQClient) RequestSMS() bool {
rsp, err := c.sendAndWait(c.buildSMSRequestPacket()) rsp, err := c.callAndDecode(c.buildSMSRequest())
if err != nil { if err != nil {
c.Error("request sms error: %v", err) c.Error("request sms error: %v", err)
return false return false
@ -425,17 +499,16 @@ func (c *QQClient) init(tokenLogin bool) error {
d2() d2()
} }
} }
c.groupSysMsgCache, _ = c.GetGroupSystemMessages()
if !c.heartbeatEnabled {
go c.doHeartbeat() go c.doHeartbeat()
}
_ = c.RefreshStatus() _ = c.RefreshStatus()
if c.version.Protocol == auth.QiDian { if c.version.Protocol == auth.QiDian {
_, _ = c.sendAndWait(c.buildLoginExtraPacket()) // 小登录 _, _ = c.callAndDecode(c.buildLoginExtraPacket()) // 小登录
_, _ = c.sendAndWait(c.buildConnKeyRequestPacket()) // big data key 如果等待 config push 的话时间来不及 _, _ = c.callAndDecode(c.buildConnKeyRequestPacket()) // big data key 如果等待 config push 的话时间来不及
} }
seq, pkt := c.buildGetMessageRequestPacket(msg.SyncFlag_START, time.Now().Unix()) c.groupSysMsgCache, _ = c.GetGroupSystemMessages()
_, _ = c.sendAndWait(seq, pkt, network.RequestParams{"used_reg_proxy": true, "init": true}) req := c.buildGetMessageRequest(msg.SyncFlag_START, time.Now().Unix())
req.Params = network.Params{"used_reg_proxy": true, "init": true}
_, _ = c.callAndDecode(req)
c.syncChannelFirstView() c.syncChannelFirstView()
return nil return nil
} }
@ -457,14 +530,14 @@ func (c *QQClient) GenToken() []byte {
func (c *QQClient) SetOnlineStatus(s UserOnlineStatus) { func (c *QQClient) SetOnlineStatus(s UserOnlineStatus) {
if s < 1000 { if s < 1000 {
_, _ = c.sendAndWait(c.buildStatusSetPacket(int32(s), 0)) _, _ = c.call(c.buildStatusSetPacket(int32(s), 0))
return return
} }
_, _ = c.sendAndWait(c.buildStatusSetPacket(11, int32(s))) _, _ = c.call(c.buildStatusSetPacket(11, int32(s)))
} }
func (c *QQClient) GetWordSegmentation(text string) ([]string, error) { func (c *QQClient) GetWordSegmentation(text string) ([]string, error) {
rsp, err := c.sendAndWait(c.buildWordSegmentationPacket([]byte(text))) rsp, err := c.callAndDecode(c.buildWordSegmentationPacket([]byte(text)))
if err != nil { if err != nil {
return nil, err return nil, err
} }
@ -479,7 +552,7 @@ func (c *QQClient) GetWordSegmentation(text string) ([]string, error) {
} }
func (c *QQClient) GetSummaryInfo(target int64) (*SummaryCardInfo, error) { func (c *QQClient) GetSummaryInfo(target int64) (*SummaryCardInfo, error) {
rsp, err := c.sendAndWait(c.buildSummaryCardRequestPacket(target)) rsp, err := c.callAndDecode(c.buildSummaryCardRequest(target))
if err != nil { if err != nil {
return nil, err return nil, err
} }
@ -510,7 +583,8 @@ func (c *QQClient) GetFriendList() (*FriendListResponse, error) {
curFriendCount := 0 curFriendCount := 0
r := &FriendListResponse{} r := &FriendListResponse{}
for { for {
rsp, err := c.sendAndWait(c.buildFriendGroupListRequestPacket(int16(curFriendCount), 150, 0, 0)) call := c.buildFriendGroupListRequest(int16(curFriendCount), 150, 0, 0)
rsp, err := c.callAndDecode(call)
if err != nil { if err != nil {
return nil, err return nil, err
} }
@ -526,11 +600,11 @@ func (c *QQClient) GetFriendList() (*FriendListResponse, error) {
} }
func (c *QQClient) SendGroupPoke(groupCode, target int64) { func (c *QQClient) SendGroupPoke(groupCode, target int64) {
_, _ = c.sendAndWait(c.buildGroupPokePacket(groupCode, target)) _, _ = c.call(c.buildGroupPokeRequest(groupCode, target))
} }
func (c *QQClient) SendFriendPoke(target int64) { func (c *QQClient) SendFriendPoke(target int64) {
_, _ = c.sendAndWait(c.buildFriendPokePacket(target)) _, _ = c.call(c.buildFriendPokeRequest(target))
} }
func (c *QQClient) ReloadGroupList() error { func (c *QQClient) ReloadGroupList() error {
@ -545,7 +619,7 @@ func (c *QQClient) ReloadGroupList() error {
} }
func (c *QQClient) GetGroupList() ([]*GroupInfo, error) { func (c *QQClient) GetGroupList() ([]*GroupInfo, error) {
rsp, err := c.sendAndWait(c.buildGroupListRequestPacket(EmptyBytes)) rsp, err := c.callAndDecode(c.buildGroupListRequest(EmptyBytes))
if err != nil { if err != nil {
return nil, err return nil, err
} }
@ -577,7 +651,7 @@ func (c *QQClient) GetGroupMembers(group *GroupInfo) ([]*GroupMemberInfo, error)
var nextUin int64 var nextUin int64
var list []*GroupMemberInfo var list []*GroupMemberInfo
for { for {
data, err := c.sendAndWait(c.buildGroupMemberListRequestPacket(group.Uin, group.Code, nextUin)) data, err := c.callAndDecode(c.buildGroupMemberListRequest(group.Uin, group.Code, nextUin))
if err != nil { if err != nil {
return nil, err return nil, err
} }
@ -603,7 +677,7 @@ func (c *QQClient) GetGroupMembers(group *GroupInfo) ([]*GroupMemberInfo, error)
} }
func (c *QQClient) GetMemberInfo(groupCode, memberUin int64) (*GroupMemberInfo, error) { func (c *QQClient) GetMemberInfo(groupCode, memberUin int64) (*GroupMemberInfo, error) {
info, err := c.sendAndWait(c.buildGroupMemberInfoRequestPacket(groupCode, memberUin)) info, err := c.callAndDecode(c.buildGroupMemberInfoRequest(groupCode, memberUin))
if err != nil { if err != nil {
return nil, err return nil, err
} }
@ -624,7 +698,7 @@ func (c *QQClient) DeleteFriend(uin int64) error {
if c.FindFriend(uin) == nil { if c.FindFriend(uin) == nil {
return errors.New("friend not found") return errors.New("friend not found")
} }
_, err := c.sendAndWait(c.buildFriendDeletePacket(uin)) _, err := c.callAndDecode(c.buildFriendDeletePacket(uin))
return errors.Wrap(err, "delete friend error") return errors.Wrap(err, "delete friend error")
} }
@ -655,29 +729,28 @@ func (c *QQClient) SolveGroupJoinRequest(i interface{}, accept, block bool, reas
switch req := i.(type) { switch req := i.(type) {
case *UserJoinGroupRequest: case *UserJoinGroupRequest:
_, pkt := c.buildSystemMsgGroupActionPacket(req.RequestId, req.RequesterUin, req.GroupCode, func() int32 { call := c.buildSystemMsgGroupActionPacket(req.RequestId, req.RequesterUin, req.GroupCode, func() int32 {
if req.Suspicious { if req.Suspicious {
return 2 return 2
} else { } else {
return 1 return 1
} }
}(), false, accept, block, reason) }(), false, accept, block, reason)
_ = c.sendPacket(pkt) _, _ = c.call(call)
case *GroupInvitedRequest: case *GroupInvitedRequest:
_, pkt := c.buildSystemMsgGroupActionPacket(req.RequestId, req.InvitorUin, req.GroupCode, 1, true, accept, block, reason) call := c.buildSystemMsgGroupActionPacket(req.RequestId, req.InvitorUin, req.GroupCode, 1, true, accept, block, reason)
_ = c.sendPacket(pkt) _, _ = c.call(call)
} }
} }
func (c *QQClient) SolveFriendRequest(req *NewFriendRequest, accept bool) { func (c *QQClient) SolveFriendRequest(req *NewFriendRequest, accept bool) {
_, pkt := c.buildSystemMsgFriendActionPacket(req.RequestId, req.RequesterUin, accept) _, _ = c.call(c.buildSystemMsgFriendActionPacket(req.RequestId, req.RequesterUin, accept))
_ = c.sendPacket(pkt)
} }
func (c *QQClient) getSKey() string { func (c *QQClient) getSKey() string {
if c.sig.SKeyExpiredTime < time.Now().Unix() && len(c.sig.G) > 0 { if c.sig.SKeyExpiredTime < time.Now().Unix() && len(c.sig.G) > 0 {
c.Debug("skey expired. refresh...") c.Debug("skey expired. refresh...")
_, _ = c.sendAndWait(c.buildRequestTgtgtNopicsigPacket()) _, _ = c.callAndDecode(c.buildRequestTgtgtNopicsigRequest())
} }
return string(c.sig.SKey) return string(c.sig.SKey)
} }
@ -705,39 +778,39 @@ func (c *QQClient) getCSRFToken() int {
} }
func (c *QQClient) editMemberCard(groupCode, memberUin int64, card string) { func (c *QQClient) editMemberCard(groupCode, memberUin int64, card string) {
_, _ = c.sendAndWait(c.buildEditGroupTagPacket(groupCode, memberUin, card)) _, _ = c.call(c.buildEditGroupTagPacket(groupCode, memberUin, card))
} }
func (c *QQClient) editMemberSpecialTitle(groupCode, memberUin int64, title string) { func (c *QQClient) editMemberSpecialTitle(groupCode, memberUin int64, title string) {
_, _ = c.sendAndWait(c.buildEditSpecialTitlePacket(groupCode, memberUin, title)) _, _ = c.call(c.buildEditSpecialTitlePacket(groupCode, memberUin, title))
} }
func (c *QQClient) setGroupAdmin(groupCode, memberUin int64, flag bool) { func (c *QQClient) setGroupAdmin(groupCode, memberUin int64, flag bool) {
_, _ = c.sendAndWait(c.buildGroupAdminSetPacket(groupCode, memberUin, flag)) _, _ = c.call(c.buildGroupAdminSetPacket(groupCode, memberUin, flag))
} }
func (c *QQClient) updateGroupName(groupCode int64, newName string) { func (c *QQClient) updateGroupName(groupCode int64, newName string) {
_, _ = c.sendAndWait(c.buildGroupNameUpdatePacket(groupCode, newName)) _, _ = c.call(c.buildGroupNameUpdateRequest(groupCode, newName))
} }
func (c *QQClient) updateGroupMemo(groupCode int64, newMemo string) { func (c *QQClient) updateGroupMemo(groupCode int64, newMemo string) {
_, _ = c.sendAndWait(c.buildGroupMemoUpdatePacket(groupCode, newMemo)) _, _ = c.call(c.buildGroupMemoUpdatePacket(groupCode, newMemo))
} }
func (c *QQClient) groupMuteAll(groupCode int64, mute bool) { func (c *QQClient) groupMuteAll(groupCode int64, mute bool) {
_, _ = c.sendAndWait(c.buildGroupMuteAllPacket(groupCode, mute)) _, _ = c.call(c.buildGroupMuteAllPacket(groupCode, mute))
} }
func (c *QQClient) groupMute(groupCode, memberUin int64, time uint32) { func (c *QQClient) groupMute(groupCode, memberUin int64, time uint32) {
_, _ = c.sendAndWait(c.buildGroupMutePacket(groupCode, memberUin, time)) _, _ = c.call(c.buildGroupMutePacket(groupCode, memberUin, time))
} }
func (c *QQClient) quitGroup(groupCode int64) { func (c *QQClient) quitGroup(groupCode int64) {
_, _ = c.sendAndWait(c.buildQuitGroupPacket(groupCode)) _, _ = c.call(c.buildQuitGroupPacket(groupCode))
} }
func (c *QQClient) kickGroupMember(groupCode, memberUin int64, msg string, block bool) { func (c *QQClient) kickGroupMember(groupCode, memberUin int64, msg string, block bool) {
_, _ = c.sendAndWait(c.buildGroupKickPacket(groupCode, memberUin, msg, block)) _, _ = c.call(c.buildGroupKickPacket(groupCode, memberUin, msg, block))
} }
func (g *GroupInfo) removeMember(uin int64) { func (g *GroupInfo) removeMember(uin int64) {
@ -753,11 +826,13 @@ func (g *GroupInfo) removeMember(uin int64) {
} }
func (c *QQClient) SetCustomServer(servers []*net.TCPAddr) { func (c *QQClient) SetCustomServer(servers []*net.TCPAddr) {
c.servers = append(servers, c.servers...) for _, server := range servers {
c.transport.AddServerAddr(server)
}
} }
func (c *QQClient) registerClient() error { func (c *QQClient) registerClient() error {
_, err := c.sendAndWait(c.buildClientRegisterPacket()) _, err := c.callAndDecode(c.buildClientRegisterPacket())
if err == nil { if err == nil {
c.Online.Store(true) c.Online.Store(true)
} }
@ -789,10 +864,21 @@ func (c *QQClient) nextHighwayApplySeq() int32 {
} }
func (c *QQClient) doHeartbeat() { func (c *QQClient) doHeartbeat() {
// 不需要atomic/锁
if c.heartbeatEnabled {
return
}
c.heartbeatEnabled = true c.heartbeatEnabled = true
defer func() {
c.heartbeatEnabled = false
}()
times := 0 times := 0
for c.Online.Load() { ticker := time.NewTicker(time.Second * 30)
time.Sleep(time.Second * 30) for range ticker.C {
if !c.Online.Load() {
ticker.Stop()
return // 下线停止goroutinefor gc
}
seq := c.nextSeq() seq := c.nextSeq()
req := network.Request{ req := network.Request{
Type: network.RequestTypeLogin, Type: network.RequestTypeLogin,
@ -802,10 +888,12 @@ func (c *QQClient) doHeartbeat() {
CommandName: "Heartbeat.Alive", CommandName: "Heartbeat.Alive",
Body: EmptyBytes, Body: EmptyBytes,
} }
packet := c.transport.PackPacket(&req) _, err := c.call(&req)
_, err := c.sendAndWait(seq, packet) if err != nil {
if errors.Is(err, network.ErrConnectionClosed) { if errors.Is(err, network.ErrConnectionBroken) {
continue break
}
continue // skip time++
} }
times++ times++
if times >= 7 { if times >= 7 {
@ -813,5 +901,4 @@ func (c *QQClient) doHeartbeat() {
times = 0 times = 0
} }
} }
c.heartbeatEnabled = false
} }

View File

@ -32,8 +32,8 @@ var (
) )
// wtlogin.login // wtlogin.login
func decodeLoginResponse(c *QQClient, _ *network.IncomingPacketInfo, payload []byte) (interface{}, error) { func decodeLoginResponse(c *QQClient, resp *network.Response) (interface{}, error) {
reader := binary.NewReader(payload) reader := binary.NewReader(resp.Body)
reader.ReadUInt16() // sub command reader.ReadUInt16() // sub command
t := reader.ReadByte() t := reader.ReadByte()
reader.ReadUInt16() reader.ReadUInt16()
@ -148,7 +148,7 @@ func decodeLoginResponse(c *QQClient, _ *network.IncomingPacketInfo, payload []b
if t == 204 { if t == 204 {
c.sig.T104 = m[0x104] c.sig.T104 = m[0x104]
c.sig.RandSeed = m[0x403] c.sig.RandSeed = m[0x403]
return c.sendAndWait(c.buildDeviceLockLoginPacket()) return c.callAndDecode(c.buildDeviceLockLoginRequest())
} // drive lock } // drive lock
if t149, ok := m[0x149]; ok { if t149, ok := m[0x149]; ok {
@ -180,9 +180,9 @@ func decodeLoginResponse(c *QQClient, _ *network.IncomingPacketInfo, payload []b
} }
// StatSvc.register // StatSvc.register
func decodeClientRegisterResponse(c *QQClient, _ *network.IncomingPacketInfo, payload []byte) (interface{}, error) { func decodeClientRegisterResponse(c *QQClient, resp *network.Response) (interface{}, error) {
request := &jce.RequestPacket{} request := &jce.RequestPacket{}
request.ReadFrom(jce.NewJceReader(payload)) request.ReadFrom(jce.NewJceReader(resp.Body))
data := &jce.RequestDataVersion2{} data := &jce.RequestDataVersion2{}
data.ReadFrom(jce.NewJceReader(request.SBuffer)) data.ReadFrom(jce.NewJceReader(request.SBuffer))
svcRsp := &jce.SvcRespRegister{} svcRsp := &jce.SvcRespRegister{}
@ -197,8 +197,8 @@ func decodeClientRegisterResponse(c *QQClient, _ *network.IncomingPacketInfo, pa
} }
// wtlogin.exchange_emp // wtlogin.exchange_emp
func decodeExchangeEmpResponse(c *QQClient, _ *network.IncomingPacketInfo, payload []byte) (interface{}, error) { func decodeExchangeEmpResponse(c *QQClient, resp *network.Response) (interface{}, error) {
reader := binary.NewReader(payload) reader := binary.NewReader(resp.Body)
cmd := reader.ReadUInt16() cmd := reader.ReadUInt16()
t := reader.ReadByte() t := reader.ReadByte()
reader.ReadUInt16() reader.ReadUInt16()
@ -217,11 +217,11 @@ func decodeExchangeEmpResponse(c *QQClient, _ *network.IncomingPacketInfo, paylo
} }
// wtlogin.trans_emp // wtlogin.trans_emp
func decodeTransEmpResponse(c *QQClient, _ *network.IncomingPacketInfo, payload []byte) (interface{}, error) { func decodeTransEmpResponse(c *QQClient, resp *network.Response) (interface{}, error) {
if len(payload) < 48 { if len(resp.Body) < 48 {
return nil, errors.New("missing payload length") return nil, errors.New("missing payload length")
} }
reader := binary.NewReader(payload) reader := binary.NewReader(resp.Body)
reader.ReadBytes(5) // trans req head reader.ReadBytes(5) // trans req head
reader.ReadByte() reader.ReadByte()
reader.ReadUInt16() reader.ReadUInt16()
@ -267,20 +267,21 @@ func decodeTransEmpResponse(c *QQClient, _ *network.IncomingPacketInfo, payload
body.ReadInt32() // app id? body.ReadInt32() // app id?
code := body.ReadByte() code := body.ReadByte()
if code != 0 { if code != 0 {
if code == 0x30 { var qrResp QRCodeLoginResponse
return &QRCodeLoginResponse{State: QRCodeWaitingForScan}, nil switch code {
} case 0x30:
if code == 0x35 { qrResp.State = QRCodeWaitingForScan
return &QRCodeLoginResponse{State: QRCodeWaitingForConfirm}, nil case 0x35:
} qrResp.State = QRCodeWaitingForConfirm
if code == 0x36 { case 0x36:
return &QRCodeLoginResponse{State: QRCodeCanceled}, nil qrResp.State = QRCodeCanceled
} case 0x11:
if code == 0x11 { qrResp.State = QRCodeTimeout
return &QRCodeLoginResponse{State: QRCodeTimeout}, nil default:
}
return nil, errors.Errorf("wtlogin.trans_emp sub cmd 0x12 error: %v", code) return nil, errors.Errorf("wtlogin.trans_emp sub cmd 0x12 error: %v", code)
} }
return qrResp, nil
}
c.Uin = body.ReadInt64() c.Uin = body.ReadInt64()
c.highwaySession.Uin = strconv.FormatInt(c.Uin, 10) c.highwaySession.Uin = strconv.FormatInt(c.Uin, 10)
body.ReadInt32() // sig create time body.ReadInt32() // sig create time
@ -300,9 +301,9 @@ func decodeTransEmpResponse(c *QQClient, _ *network.IncomingPacketInfo, payload
} }
// ConfigPushSvc.PushReq // ConfigPushSvc.PushReq
func decodePushReqPacket(c *QQClient, _ *network.IncomingPacketInfo, payload []byte) (interface{}, error) { func decodePushReqPacket(c *QQClient, resp *network.Response) (interface{}, error) {
request := &jce.RequestPacket{} request := &jce.RequestPacket{}
request.ReadFrom(jce.NewJceReader(payload)) request.ReadFrom(jce.NewJceReader(resp.Body))
data := &jce.RequestDataVersion2{} data := &jce.RequestDataVersion2{}
data.ReadFrom(jce.NewJceReader(request.SBuffer)) data.ReadFrom(jce.NewJceReader(request.SBuffer))
r := jce.NewJceReader(data.Map["PushReq"]["ConfigPush.PushReq"][1:]) r := jce.NewJceReader(data.Map["PushReq"]["ConfigPush.PushReq"][1:])
@ -365,29 +366,29 @@ func decodePushReqPacket(c *QQClient, _ *network.IncomingPacketInfo, payload []b
} }
seq := r.ReadInt64(3) seq := r.ReadInt64(3)
_, pkt := c.buildConfPushRespPacket(t, seq, jceBuf) err := c.sendPacket(c.transport.PackPacket(c.buildConfPushRespPacket(t, seq, jceBuf)))
return nil, c.sendPacket(pkt) return nil, err
} }
// MessageSvc.PbGetMsg // MessageSvc.PbGetMsg
func decodeMessageSvcPacket(c *QQClient, info *network.IncomingPacketInfo, payload []byte) (interface{}, error) { func decodeMessageSvcPacket(c *QQClient, resp *network.Response) (interface{}, error) {
rsp := msg.GetMessageResponse{} rsp := msg.GetMessageResponse{}
err := proto.Unmarshal(payload, &rsp) err := proto.Unmarshal(resp.Body, &rsp)
if err != nil { if err != nil {
return nil, errors.Wrap(err, "failed to unmarshal protobuf message") return nil, errors.Wrap(err, "failed to unmarshal protobuf message")
} }
c.c2cMessageSyncProcessor(&rsp, info) c.c2cMessageSyncProcessor(&rsp, resp)
return nil, nil return nil, nil
} }
// MessageSvc.PushNotify // MessageSvc.PushNotify
func decodeSvcNotify(c *QQClient, _ *network.IncomingPacketInfo, payload []byte) (interface{}, error) { func decodeSvcNotify(c *QQClient, resp *network.Response) (interface{}, error) {
request := &jce.RequestPacket{} request := &jce.RequestPacket{}
request.ReadFrom(jce.NewJceReader(payload[4:])) request.ReadFrom(jce.NewJceReader(resp.Body[4:]))
data := &jce.RequestDataVersion2{} data := &jce.RequestDataVersion2{}
data.ReadFrom(jce.NewJceReader(request.SBuffer)) data.ReadFrom(jce.NewJceReader(request.SBuffer))
if len(data.Map) == 0 { if len(data.Map) == 0 {
_, err := c.sendAndWait(c.buildGetMessageRequestPacket(msg.SyncFlag_START, time.Now().Unix())) _, err := c.callAndDecode(c.buildGetMessageRequest(msg.SyncFlag_START, time.Now().Unix()))
return nil, err return nil, err
} }
notify := &jce.RequestPushNotify{} notify := &jce.RequestPushNotify{}
@ -399,18 +400,18 @@ func decodeSvcNotify(c *QQClient, _ *network.IncomingPacketInfo, payload []byte)
return nil, nil return nil, nil
} }
if typ == sysMsgDecoders { if typ == sysMsgDecoders {
_, pkt := c.buildSystemMsgNewFriendPacket() _, err := c.callAndDecode(c.buildSystemMsgNewFriendRequest())
return nil, c.sendPacket(pkt) return nil, err
} }
} }
_, err := c.sendAndWait(c.buildGetMessageRequestPacket(msg.SyncFlag_START, time.Now().Unix())) _, err := c.callAndDecode(c.buildGetMessageRequest(msg.SyncFlag_START, time.Now().Unix()))
return nil, err return nil, err
} }
// SummaryCard.ReqSummaryCard // SummaryCard.ReqSummaryCard
func decodeSummaryCardResponse(_ *QQClient, _ *network.IncomingPacketInfo, payload []byte) (interface{}, error) { func decodeSummaryCardResponse(_ *QQClient, resp *network.Response) (interface{}, error) {
request := &jce.RequestPacket{} request := &jce.RequestPacket{}
request.ReadFrom(jce.NewJceReader(payload)) request.ReadFrom(jce.NewJceReader(resp.Body))
data := &jce.RequestDataVersion2{} data := &jce.RequestDataVersion2{}
data.ReadFrom(jce.NewJceReader(request.SBuffer)) data.ReadFrom(jce.NewJceReader(request.SBuffer))
rsp := func() *jce.JceReader { rsp := func() *jce.JceReader {
@ -456,9 +457,9 @@ func decodeSummaryCardResponse(_ *QQClient, _ *network.IncomingPacketInfo, paylo
} }
// friendlist.getFriendGroupList // friendlist.getFriendGroupList
func decodeFriendGroupListResponse(_ *QQClient, _ *network.IncomingPacketInfo, payload []byte) (interface{}, error) { func decodeFriendGroupListResponse(_ *QQClient, resp *network.Response) (interface{}, error) {
request := &jce.RequestPacket{} request := &jce.RequestPacket{}
request.ReadFrom(jce.NewJceReader(payload)) request.ReadFrom(jce.NewJceReader(resp.Body))
data := &jce.RequestDataVersion3{} data := &jce.RequestDataVersion3{}
data.ReadFrom(jce.NewJceReader(request.SBuffer)) data.ReadFrom(jce.NewJceReader(request.SBuffer))
r := jce.NewJceReader(data.Map["FLRESP"][1:]) r := jce.NewJceReader(data.Map["FLRESP"][1:])
@ -481,9 +482,9 @@ func decodeFriendGroupListResponse(_ *QQClient, _ *network.IncomingPacketInfo, p
} }
// friendlist.delFriend // friendlist.delFriend
func decodeFriendDeleteResponse(_ *QQClient, _ *network.IncomingPacketInfo, payload []byte) (interface{}, error) { func decodeFriendDeleteResponse(_ *QQClient, resp *network.Response) (interface{}, error) {
request := &jce.RequestPacket{} request := &jce.RequestPacket{}
request.ReadFrom(jce.NewJceReader(payload)) request.ReadFrom(jce.NewJceReader(resp.Body))
data := &jce.RequestDataVersion3{} data := &jce.RequestDataVersion3{}
data.ReadFrom(jce.NewJceReader(request.SBuffer)) data.ReadFrom(jce.NewJceReader(request.SBuffer))
r := jce.NewJceReader(data.Map["DFRESP"][1:]) r := jce.NewJceReader(data.Map["DFRESP"][1:])
@ -494,9 +495,9 @@ func decodeFriendDeleteResponse(_ *QQClient, _ *network.IncomingPacketInfo, payl
} }
// friendlist.GetTroopListReqV2 // friendlist.GetTroopListReqV2
func decodeGroupListResponse(c *QQClient, _ *network.IncomingPacketInfo, payload []byte) (interface{}, error) { func decodeGroupListResponse(c *QQClient, resp *network.Response) (interface{}, error) {
request := &jce.RequestPacket{} request := &jce.RequestPacket{}
request.ReadFrom(jce.NewJceReader(payload)) request.ReadFrom(jce.NewJceReader(resp.Body))
data := &jce.RequestDataVersion3{} data := &jce.RequestDataVersion3{}
data.ReadFrom(jce.NewJceReader(request.SBuffer)) data.ReadFrom(jce.NewJceReader(request.SBuffer))
r := jce.NewJceReader(data.Map["GetTroopListRespV2"][1:]) r := jce.NewJceReader(data.Map["GetTroopListRespV2"][1:])
@ -516,7 +517,7 @@ func decodeGroupListResponse(c *QQClient, _ *network.IncomingPacketInfo, payload
}) })
} }
if len(vecCookie) > 0 { if len(vecCookie) > 0 {
rsp, err := c.sendAndWait(c.buildGroupListRequestPacket(vecCookie)) rsp, err := c.callAndDecode(c.buildGroupListRequest(vecCookie))
if err != nil { if err != nil {
return nil, err return nil, err
} }
@ -526,9 +527,9 @@ func decodeGroupListResponse(c *QQClient, _ *network.IncomingPacketInfo, payload
} }
// friendlist.GetTroopMemberListReq // friendlist.GetTroopMemberListReq
func decodeGroupMemberListResponse(_ *QQClient, _ *network.IncomingPacketInfo, payload []byte) (interface{}, error) { func decodeGroupMemberListResponse(_ *QQClient, resp *network.Response) (interface{}, error) {
request := &jce.RequestPacket{} request := &jce.RequestPacket{}
request.ReadFrom(jce.NewJceReader(payload)) request.ReadFrom(jce.NewJceReader(resp.Body))
data := &jce.RequestDataVersion3{} data := &jce.RequestDataVersion3{}
data.ReadFrom(jce.NewJceReader(request.SBuffer)) data.ReadFrom(jce.NewJceReader(request.SBuffer))
r := jce.NewJceReader(data.Map["GTMLRESP"][1:]) r := jce.NewJceReader(data.Map["GTMLRESP"][1:])
@ -562,9 +563,9 @@ func decodeGroupMemberListResponse(_ *QQClient, _ *network.IncomingPacketInfo, p
} }
// group_member_card.get_group_member_card_info // group_member_card.get_group_member_card_info
func decodeGroupMemberInfoResponse(c *QQClient, _ *network.IncomingPacketInfo, payload []byte) (interface{}, error) { func decodeGroupMemberInfoResponse(c *QQClient, resp *network.Response) (interface{}, error) {
rsp := pb.GroupMemberRspBody{} rsp := pb.GroupMemberRspBody{}
if err := proto.Unmarshal(payload, &rsp); err != nil { if err := proto.Unmarshal(resp.Body, &rsp); err != nil {
return nil, errors.Wrap(err, "failed to unmarshal protobuf message") return nil, errors.Wrap(err, "failed to unmarshal protobuf message")
} }
if rsp.MemInfo == nil || (rsp.MemInfo.Nick == nil && rsp.MemInfo.Age == 0) { if rsp.MemInfo == nil || (rsp.MemInfo.Nick == nil && rsp.MemInfo.Age == 0) {
@ -595,9 +596,9 @@ func decodeGroupMemberInfoResponse(c *QQClient, _ *network.IncomingPacketInfo, p
} }
// LongConn.OffPicUp // LongConn.OffPicUp
func decodeOffPicUpResponse(_ *QQClient, _ *network.IncomingPacketInfo, payload []byte) (interface{}, error) { func decodeOffPicUpResponse(_ *QQClient, resp *network.Response) (interface{}, error) {
rsp := cmd0x352.RspBody{} rsp := cmd0x352.RspBody{}
if err := proto.Unmarshal(payload, &rsp); err != nil { if err := proto.Unmarshal(resp.Body, &rsp); err != nil {
return nil, errors.Wrap(err, "failed to unmarshal protobuf message") return nil, errors.Wrap(err, "failed to unmarshal protobuf message")
} }
if rsp.GetFailMsg() != nil { if rsp.GetFailMsg() != nil {
@ -633,9 +634,9 @@ func decodeOffPicUpResponse(_ *QQClient, _ *network.IncomingPacketInfo, payload
} }
// OnlinePush.PbPushTransMsg // OnlinePush.PbPushTransMsg
func decodeOnlinePushTransPacket(c *QQClient, _ *network.IncomingPacketInfo, payload []byte) (interface{}, error) { func decodeOnlinePushTransPacket(c *QQClient, resp *network.Response) (interface{}, error) {
info := msg.TransMsgInfo{} info := msg.TransMsgInfo{}
err := proto.Unmarshal(payload, &info) err := proto.Unmarshal(resp.Body, &info)
if err != nil { if err != nil {
return nil, errors.Wrap(err, "failed to unmarshal protobuf message") return nil, errors.Wrap(err, "failed to unmarshal protobuf message")
} }
@ -736,9 +737,9 @@ func decodeOnlinePushTransPacket(c *QQClient, _ *network.IncomingPacketInfo, pay
} }
// ProfileService.Pb.ReqSystemMsgNew.Friend // ProfileService.Pb.ReqSystemMsgNew.Friend
func decodeSystemMsgFriendPacket(c *QQClient, _ *network.IncomingPacketInfo, payload []byte) (interface{}, error) { func decodeSystemMsgFriendPacket(c *QQClient, resp *network.Response) (interface{}, error) {
rsp := structmsg.RspSystemMsgNew{} rsp := structmsg.RspSystemMsgNew{}
if err := proto.Unmarshal(payload, &rsp); err != nil { if err := proto.Unmarshal(resp.Body, &rsp); err != nil {
return nil, errors.Wrap(err, "failed to unmarshal protobuf message") return nil, errors.Wrap(err, "failed to unmarshal protobuf message")
} }
if len(rsp.Friendmsgs) == 0 { if len(rsp.Friendmsgs) == 0 {
@ -758,9 +759,9 @@ func decodeSystemMsgFriendPacket(c *QQClient, _ *network.IncomingPacketInfo, pay
} }
// MessageSvc.PushForceOffline // MessageSvc.PushForceOffline
func decodeForceOfflinePacket(c *QQClient, _ *network.IncomingPacketInfo, payload []byte) (interface{}, error) { func decodeForceOfflinePacket(c *QQClient, resp *network.Response) (interface{}, error) {
request := &jce.RequestPacket{} request := &jce.RequestPacket{}
request.ReadFrom(jce.NewJceReader(payload)) request.ReadFrom(jce.NewJceReader(resp.Body))
data := &jce.RequestDataVersion2{} data := &jce.RequestDataVersion2{}
data.ReadFrom(jce.NewJceReader(request.SBuffer)) data.ReadFrom(jce.NewJceReader(request.SBuffer))
r := jce.NewJceReader(data.Map["req_PushForceOffline"]["PushNotifyPack.RequestPushForceOffline"][1:]) r := jce.NewJceReader(data.Map["req_PushForceOffline"]["PushNotifyPack.RequestPushForceOffline"][1:])
@ -771,7 +772,7 @@ func decodeForceOfflinePacket(c *QQClient, _ *network.IncomingPacketInfo, payloa
} }
// StatSvc.ReqMSFOffline // StatSvc.ReqMSFOffline
func decodeMSFOfflinePacket(c *QQClient, _ *network.IncomingPacketInfo, _ []byte) (interface{}, error) { func decodeMSFOfflinePacket(c *QQClient, _ *network.Response) (interface{}, error) {
// c.lastLostMsg = "服务器端强制下线." // c.lastLostMsg = "服务器端强制下线."
c.Disconnect() c.Disconnect()
// 这个decoder不能消耗太多时间, event另起线程处理 // 这个decoder不能消耗太多时间, event另起线程处理
@ -780,10 +781,10 @@ func decodeMSFOfflinePacket(c *QQClient, _ *network.IncomingPacketInfo, _ []byte
} }
// OidbSvc.0xd79 // OidbSvc.0xd79
func decodeWordSegmentation(_ *QQClient, _ *network.IncomingPacketInfo, payload []byte) (interface{}, error) { func decodeWordSegmentation(_ *QQClient, resp *network.Response) (interface{}, error) {
pkg := oidb.OIDBSSOPkg{} pkg := oidb.OIDBSSOPkg{}
rsp := &oidb.D79RspBody{} rsp := &oidb.D79RspBody{}
if err := proto.Unmarshal(payload, &pkg); err != nil { if err := proto.Unmarshal(resp.Body, &pkg); err != nil {
return nil, errors.Wrap(err, "failed to unmarshal protobuf message") return nil, errors.Wrap(err, "failed to unmarshal protobuf message")
} }
if err := proto.Unmarshal(pkg.Bodybuffer, rsp); err != nil { if err := proto.Unmarshal(pkg.Bodybuffer, rsp); err != nil {
@ -795,21 +796,21 @@ func decodeWordSegmentation(_ *QQClient, _ *network.IncomingPacketInfo, payload
return nil, errors.New("no word received") return nil, errors.New("no word received")
} }
func decodeSidExpiredPacket(c *QQClient, i *network.IncomingPacketInfo, _ []byte) (interface{}, error) { func decodeSidExpiredPacket(c *QQClient, resp *network.Response) (interface{}, error) {
_, err := c.sendAndWait(c.buildRequestChangeSigPacket(3554528)) _, err := c.callAndDecode(c.buildRequestChangeSigRequest(3554528))
if err != nil { if err != nil {
return nil, errors.Wrap(err, "resign client error") return nil, errors.Wrap(err, "resign client error")
} }
if err = c.registerClient(); err != nil { if err = c.registerClient(); err != nil {
return nil, errors.Wrap(err, "register error") return nil, errors.Wrap(err, "register error")
} }
_ = c.sendPacket(c.uniPacketWithSeq(i.SequenceId, "OnlinePush.SidTicketExpired", EmptyBytes)) _, _ = c.call(c.uniPacketWithSeq(uint16(resp.SequenceID), "OnlinePush.SidTicketExpired", EmptyBytes, nil))
return nil, nil return nil, nil
} }
/* unused /* unused
// LightAppSvc.mini_app_info.GetAppInfoById // LightAppSvc.mini_app_info.GetAppInfoById
func decodeAppInfoResponse(_ *QQClient, _ *incomingPacketInfo, payload []byte) (interface{}, error) { func decodeAppInfoResponse(_ *QQClient, _ *incomingPacketInfo) (interface{}, error) {
pkg := qweb.QWebRsp{} pkg := qweb.QWebRsp{}
rsp := qweb.GetAppInfoByIdRsp{} rsp := qweb.GetAppInfoByIdRsp{}
if err := proto.Unmarshal(payload, &pkg); err != nil { if err := proto.Unmarshal(payload, &pkg); err != nil {
@ -824,7 +825,3 @@ func decodeAppInfoResponse(_ *QQClient, _ *incomingPacketInfo, payload []byte) (
return rsp.AppInfo, nil return rsp.AppInfo, nil
} }
*/ */
func ignoreDecoder(_ *QQClient, _ *network.IncomingPacketInfo, _ []byte) (interface{}, error) {
return nil, nil
}

View File

@ -15,19 +15,15 @@ type CustomFace struct {
Url string Url string
} }
func init() {
decoders["Faceroam.OpReq"] = decodeFaceroamResponse
}
func (c *QQClient) GetCustomFaces() ([]*CustomFace, error) { func (c *QQClient) GetCustomFaces() ([]*CustomFace, error) {
i, err := c.sendAndWait(c.buildFaceroamRequestPacket()) i, err := c.callAndDecode(c.buildFaceroamRequestPacket())
if err != nil { if err != nil {
return nil, errors.Wrap(err, "get faces error") return nil, errors.Wrap(err, "get faces error")
} }
return i.([]*CustomFace), nil return i.([]*CustomFace), nil
} }
func (c *QQClient) buildFaceroamRequestPacket() (uint16, []byte) { func (c *QQClient) buildFaceroamRequestPacket() *network.Request {
payload, _ := proto.Marshal(&faceroam.FaceroamReqBody{ payload, _ := proto.Marshal(&faceroam.FaceroamReqBody{
Comm: &faceroam.PlatInfo{ Comm: &faceroam.PlatInfo{
Implat: proto.Int64(109), Implat: proto.Int64(109),
@ -38,12 +34,12 @@ func (c *QQClient) buildFaceroamRequestPacket() (uint16, []byte) {
SubCmd: proto.Uint32(1), SubCmd: proto.Uint32(1),
ReqUserInfo: &faceroam.ReqUserInfo{}, ReqUserInfo: &faceroam.ReqUserInfo{},
}) })
return c.uniPacket("Faceroam.OpReq", payload) return c.uniRequest("Faceroam.OpReq", payload, decodeFaceroamResponse)
} }
func decodeFaceroamResponse(c *QQClient, _ *network.IncomingPacketInfo, payload []byte) (interface{}, error) { func decodeFaceroamResponse(c *QQClient, resp *network.Response) (interface{}, error) {
rsp := faceroam.FaceroamRspBody{} rsp := faceroam.FaceroamRspBody{}
if err := proto.Unmarshal(payload, &rsp); err != nil { if err := proto.Unmarshal(resp.Body, &rsp); err != nil {
return nil, errors.Wrap(err, "failed to unmarshal protobuf message") return nil, errors.Wrap(err, "failed to unmarshal protobuf message")
} }
if rsp.RspUserInfo == nil { if rsp.RspUserInfo == nil {

View File

@ -57,17 +57,6 @@ type (
var fsWaiter = utils.NewUploadWaiter() var fsWaiter = utils.NewUploadWaiter()
func init() {
decoders["OidbSvc.0x6d8_1"] = decodeOIDB6d81Response
decoders["OidbSvc.0x6d6_0"] = decodeOIDB6d60Response
decoders["OidbSvc.0x6d6_2"] = decodeOIDB6d62Response
decoders["OidbSvc.0x6d6_3"] = decodeOIDB6d63Response
decoders["OidbSvc.0x6d7_0"] = decodeOIDB6d7Response
decoders["OidbSvc.0x6d7_1"] = decodeOIDB6d7Response
decoders["OidbSvc.0x6d7_2"] = decodeOIDB6d7Response
decoders["OidbSvc.0x6d9_4"] = ignoreDecoder
}
func (c *QQClient) GetGroupFileSystem(groupCode int64) (fs *GroupFileSystem, err error) { func (c *QQClient) GetGroupFileSystem(groupCode int64) (fs *GroupFileSystem, err error) {
defer func() { defer func() {
if pan := recover(); pan != nil { if pan := recover(); pan != nil {
@ -79,7 +68,7 @@ func (c *QQClient) GetGroupFileSystem(groupCode int64) (fs *GroupFileSystem, err
if g == nil { if g == nil {
return nil, errors.New("group not found") return nil, errors.New("group not found")
} }
rsp, e := c.sendAndWait(c.buildGroupFileCountRequestPacket(groupCode)) rsp, e := c.callAndDecode(c.buildGroupFileCountRequest(groupCode))
if e != nil { if e != nil {
return nil, e return nil, e
} }
@ -89,7 +78,7 @@ func (c *QQClient) GetGroupFileSystem(groupCode int64) (fs *GroupFileSystem, err
GroupCode: groupCode, GroupCode: groupCode,
client: c, client: c,
} }
rsp, err = c.sendAndWait(c.buildGroupFileSpaceRequestPacket(groupCode)) rsp, err = c.callAndDecode(c.buildGroupFileSpaceRequest(groupCode))
if err != nil { if err != nil {
return nil, err return nil, err
} }
@ -99,7 +88,7 @@ func (c *QQClient) GetGroupFileSystem(groupCode int64) (fs *GroupFileSystem, err
} }
func (c *QQClient) GetGroupFileUrl(groupCode int64, fileId string, busId int32) string { func (c *QQClient) GetGroupFileUrl(groupCode int64, fileId string, busId int32) string {
i, err := c.sendAndWait(c.buildGroupFileDownloadReqPacket(groupCode, fileId, busId)) i, err := c.callAndDecode(c.buildGroupFileDownloadReq(groupCode, fileId, busId))
if err != nil { if err != nil {
return "" return ""
} }
@ -117,7 +106,8 @@ func (fs *GroupFileSystem) GetFilesByFolder(folderID string) ([]*GroupFile, []*G
var files []*GroupFile var files []*GroupFile
var folders []*GroupFolder var folders []*GroupFolder
for { for {
i, err := fs.client.sendAndWait(fs.client.buildGroupFileListRequestPacket(fs.GroupCode, folderID, startIndex)) req := fs.client.buildGroupFileListRequest(fs.GroupCode, folderID, startIndex)
i, err := fs.client.callAndDecode(req)
if err != nil { if err != nil {
return nil, nil, err return nil, nil, err
} }
@ -177,14 +167,16 @@ func (fs *GroupFileSystem) UploadFile(p, name, folderId string) error {
_, _ = io.Copy(sha1H, file) _, _ = io.Copy(sha1H, file)
sha1Hash := sha1H.Sum(nil) sha1Hash := sha1H.Sum(nil)
_, _ = file.Seek(0, io.SeekStart) _, _ = file.Seek(0, io.SeekStart)
i, err := fs.client.sendAndWait(fs.client.buildGroupFileUploadReqPacket(folderId, name, fs.GroupCode, size, md5Hash, sha1Hash)) req := fs.client.buildGroupFileUploadReq(folderId, name, fs.GroupCode, size, md5Hash, sha1Hash)
i, err := fs.client.callAndDecode(req)
if err != nil { if err != nil {
return errors.Wrap(err, "query upload failed") return errors.Wrap(err, "query upload failed")
} }
rsp := i.(*oidb.UploadFileRspBody) rsp := i.(*oidb.UploadFileRspBody)
if rsp.GetBoolFileExist() { if rsp.GetBoolFileExist() {
_, pkt := fs.client.buildGroupFileFeedsRequest(fs.GroupCode, rsp.GetFileId(), rsp.GetBusId(), rand.Int31()) req := fs.client.buildGroupFileFeedsRequest(fs.GroupCode, rsp.GetFileId(), rsp.GetBusId(), rand.Int31())
return fs.client.sendPacket(pkt) _, err := fs.client.call(req)
return err
} }
if len(rsp.UploadIpLanV4) == 0 { if len(rsp.UploadIpLanV4) == 0 {
return errors.New("server requires unsupported ftn upload") return errors.New("server requires unsupported ftn upload")
@ -236,8 +228,9 @@ func (fs *GroupFileSystem) UploadFile(p, name, folderId string) error {
if _, err = fs.client.highwaySession.UploadExciting(input); err != nil { if _, err = fs.client.highwaySession.UploadExciting(input); err != nil {
return errors.Wrap(err, "upload failed") return errors.Wrap(err, "upload failed")
} }
_, pkt := client.buildGroupFileFeedsRequest(fs.GroupCode, rsp.GetFileId(), rsp.GetBusId(), rand.Int31()) req = client.buildGroupFileFeedsRequest(fs.GroupCode, rsp.GetFileId(), rsp.GetBusId(), rand.Int31())
return client.sendPacket(pkt) _, err = client.call(req)
return err
} }
func (fs *GroupFileSystem) GetDownloadUrl(file *GroupFile) string { func (fs *GroupFileSystem) GetDownloadUrl(file *GroupFile) string {
@ -245,21 +238,21 @@ func (fs *GroupFileSystem) GetDownloadUrl(file *GroupFile) string {
} }
func (fs *GroupFileSystem) CreateFolder(parentFolder, name string) error { func (fs *GroupFileSystem) CreateFolder(parentFolder, name string) error {
if _, err := fs.client.sendAndWait(fs.client.buildGroupFileCreateFolderPacket(fs.GroupCode, parentFolder, name)); err != nil { if _, err := fs.client.callAndDecode(fs.client.buildGroupFileCreateFolderRequest(fs.GroupCode, parentFolder, name)); err != nil {
return errors.Wrap(err, "create folder error") return errors.Wrap(err, "create folder error")
} }
return nil return nil
} }
func (fs *GroupFileSystem) RenameFolder(folderId, newName string) error { func (fs *GroupFileSystem) RenameFolder(folderId, newName string) error {
if _, err := fs.client.sendAndWait(fs.client.buildGroupFileRenameFolderPacket(fs.GroupCode, folderId, newName)); err != nil { if _, err := fs.client.callAndDecode(fs.client.buildGroupFileRenameFolderRequest(fs.GroupCode, folderId, newName)); err != nil {
return errors.Wrap(err, "rename folder error") return errors.Wrap(err, "rename folder error")
} }
return nil return nil
} }
func (fs *GroupFileSystem) DeleteFolder(folderId string) error { func (fs *GroupFileSystem) DeleteFolder(folderId string) error {
if _, err := fs.client.sendAndWait(fs.client.buildGroupFileDeleteFolderPacket(fs.GroupCode, folderId)); err != nil { if _, err := fs.client.callAndDecode(fs.client.buildGroupFileDeleteFolderRequest(fs.GroupCode, folderId)); err != nil {
return errors.Wrap(err, "rename folder error") return errors.Wrap(err, "rename folder error")
} }
return nil return nil
@ -268,14 +261,14 @@ func (fs *GroupFileSystem) DeleteFolder(folderId string) error {
// DeleteFile 删除群文件,需要管理权限. // DeleteFile 删除群文件,需要管理权限.
// 返回错误, 空为删除成功 // 返回错误, 空为删除成功
func (fs *GroupFileSystem) DeleteFile(parentFolderID, fileId string, busId int32) string { func (fs *GroupFileSystem) DeleteFile(parentFolderID, fileId string, busId int32) string {
i, err := fs.client.sendAndWait(fs.client.buildGroupFileDeleteReqPacket(fs.GroupCode, parentFolderID, fileId, busId)) i, err := fs.client.callAndDecode(fs.client.buildGroupFileDeleteReq(fs.GroupCode, parentFolderID, fileId, busId))
if err != nil { if err != nil {
return err.Error() return err.Error()
} }
return i.(string) return i.(string)
} }
func (c *QQClient) buildGroupFileUploadReqPacket(parentFolderID, fileName string, groupCode, fileSize int64, md5, sha1 []byte) (uint16, []byte) { func (c *QQClient) buildGroupFileUploadReq(parentFolderID, fileName string, groupCode, fileSize int64, md5, sha1 []byte) *network.Request {
b, _ := proto.Marshal(&oidb.D6D6ReqBody{UploadFileReq: &oidb.UploadFileReqBody{ b, _ := proto.Marshal(&oidb.D6D6ReqBody{UploadFileReq: &oidb.UploadFileReqBody{
GroupCode: &groupCode, GroupCode: &groupCode,
AppId: proto.Int32(3), AppId: proto.Int32(3),
@ -296,10 +289,10 @@ func (c *QQClient) buildGroupFileUploadReqPacket(parentFolderID, fileName string
ClientVersion: "android 8.4.8", ClientVersion: "android 8.4.8",
} }
payload, _ := proto.Marshal(req) payload, _ := proto.Marshal(req)
return c.uniPacket("OidbSvc.0x6d6_0", payload) return c.uniRequest("OidbSvc.0x6d6_0", payload, decodeOIDB6d60Response)
} }
func (c *QQClient) buildGroupFileFeedsRequest(groupCode int64, fileID string, busId, msgRand int32) (uint16, []byte) { func (c *QQClient) buildGroupFileFeedsRequest(groupCode int64, fileID string, busId, msgRand int32) *network.Request {
req := c.packOIDBPackageProto(1753, 4, &oidb.D6D9ReqBody{FeedsInfoReq: &oidb.FeedsReqBody{ req := c.packOIDBPackageProto(1753, 4, &oidb.D6D9ReqBody{FeedsInfoReq: &oidb.FeedsReqBody{
GroupCode: proto.Uint64(uint64(groupCode)), GroupCode: proto.Uint64(uint64(groupCode)),
AppId: proto.Uint32(3), AppId: proto.Uint32(3),
@ -310,11 +303,11 @@ func (c *QQClient) buildGroupFileFeedsRequest(groupCode int64, fileID string, bu
MsgRandom: proto.Uint32(uint32(msgRand)), MsgRandom: proto.Uint32(uint32(msgRand)),
}}, }},
}}) }})
return c.uniPacket("OidbSvc.0x6d9_4", req) return c.uniRequest("OidbSvc.0x6d9_4", req, nil)
} }
// OidbSvc.0x6d8_1 // OidbSvc.0x6d8_1
func (c *QQClient) buildGroupFileListRequestPacket(groupCode int64, folderID string, startIndex uint32) (uint16, []byte) { func (c *QQClient) buildGroupFileListRequest(groupCode int64, folderID string, startIndex uint32) *network.Request {
body := &oidb.D6D8ReqBody{FileListInfoReq: &oidb.GetFileListReqBody{ body := &oidb.D6D8ReqBody{FileListInfoReq: &oidb.GetFileListReqBody{
GroupCode: proto.Uint64(uint64(groupCode)), GroupCode: proto.Uint64(uint64(groupCode)),
AppId: proto.Uint32(3), AppId: proto.Uint32(3),
@ -336,10 +329,10 @@ func (c *QQClient) buildGroupFileListRequestPacket(groupCode int64, folderID str
ClientVersion: "android 8.4.8", ClientVersion: "android 8.4.8",
} }
payload, _ := proto.Marshal(req) payload, _ := proto.Marshal(req)
return c.uniPacket("OidbSvc.0x6d8_1", payload) return c.uniRequest("OidbSvc.0x6d8_1", payload, decodeOIDB6d81Response)
} }
func (c *QQClient) buildGroupFileCountRequestPacket(groupCode int64) (uint16, []byte) { func (c *QQClient) buildGroupFileCountRequest(groupCode int64) *network.Request {
body := &oidb.D6D8ReqBody{GroupFileCountReq: &oidb.GetFileCountReqBody{ body := &oidb.D6D8ReqBody{GroupFileCountReq: &oidb.GetFileCountReqBody{
GroupCode: proto.Uint64(uint64(groupCode)), GroupCode: proto.Uint64(uint64(groupCode)),
AppId: proto.Uint32(3), AppId: proto.Uint32(3),
@ -353,10 +346,10 @@ func (c *QQClient) buildGroupFileCountRequestPacket(groupCode int64) (uint16, []
ClientVersion: "android 8.4.8", ClientVersion: "android 8.4.8",
} }
payload, _ := proto.Marshal(req) payload, _ := proto.Marshal(req)
return c.uniPacket("OidbSvc.0x6d8_1", payload) return c.uniRequest("OidbSvc.0x6d8_1", payload, decodeOIDB6d81Response)
} }
func (c *QQClient) buildGroupFileSpaceRequestPacket(groupCode int64) (uint16, []byte) { func (c *QQClient) buildGroupFileSpaceRequest(groupCode int64) *network.Request {
body := &oidb.D6D8ReqBody{GroupSpaceReq: &oidb.GetSpaceReqBody{ body := &oidb.D6D8ReqBody{GroupSpaceReq: &oidb.GetSpaceReqBody{
GroupCode: proto.Uint64(uint64(groupCode)), GroupCode: proto.Uint64(uint64(groupCode)),
AppId: proto.Uint32(3), AppId: proto.Uint32(3),
@ -369,40 +362,40 @@ func (c *QQClient) buildGroupFileSpaceRequestPacket(groupCode int64) (uint16, []
ClientVersion: "android 8.4.8", ClientVersion: "android 8.4.8",
} }
payload, _ := proto.Marshal(req) payload, _ := proto.Marshal(req)
return c.uniPacket("OidbSvc.0x6d8_1", payload) return c.uniRequest("OidbSvc.0x6d8_1", payload, decodeOIDB6d81Response)
} }
func (c *QQClient) buildGroupFileCreateFolderPacket(groupCode int64, parentFolder, name string) (uint16, []byte) { func (c *QQClient) buildGroupFileCreateFolderRequest(groupCode int64, parentFolder, name string) *network.Request {
payload := c.packOIDBPackageProto(1751, 0, &oidb.D6D7ReqBody{CreateFolderReq: &oidb.CreateFolderReqBody{ payload := c.packOIDBPackageProto(1751, 0, &oidb.D6D7ReqBody{CreateFolderReq: &oidb.CreateFolderReqBody{
GroupCode: proto.Uint64(uint64(groupCode)), GroupCode: proto.Uint64(uint64(groupCode)),
AppId: proto.Uint32(3), AppId: proto.Uint32(3),
ParentFolderId: &parentFolder, ParentFolderId: &parentFolder,
FolderName: &name, FolderName: &name,
}}) }})
return c.uniPacket("OidbSvc.0x6d7_0", payload) return c.uniRequest("OidbSvc.0x6d7_0", payload, decodeOIDB6d7Response)
} }
func (c *QQClient) buildGroupFileRenameFolderPacket(groupCode int64, folderId, newName string) (uint16, []byte) { func (c *QQClient) buildGroupFileRenameFolderRequest(groupCode int64, folderId, newName string) *network.Request {
payload := c.packOIDBPackageProto(1751, 2, &oidb.D6D7ReqBody{RenameFolderReq: &oidb.RenameFolderReqBody{ payload := c.packOIDBPackageProto(1751, 2, &oidb.D6D7ReqBody{RenameFolderReq: &oidb.RenameFolderReqBody{
GroupCode: proto.Uint64(uint64(groupCode)), GroupCode: proto.Uint64(uint64(groupCode)),
AppId: proto.Uint32(3), AppId: proto.Uint32(3),
FolderId: proto.String(folderId), FolderId: proto.String(folderId),
NewFolderName: proto.String(newName), NewFolderName: proto.String(newName),
}}) }})
return c.uniPacket("OidbSvc.0x6d7_2", payload) return c.uniRequest("OidbSvc.0x6d7_2", payload, decodeOIDB6d7Response)
} }
func (c *QQClient) buildGroupFileDeleteFolderPacket(groupCode int64, folderId string) (uint16, []byte) { func (c *QQClient) buildGroupFileDeleteFolderRequest(groupCode int64, folderId string) *network.Request {
payload := c.packOIDBPackageProto(1751, 1, &oidb.D6D7ReqBody{DeleteFolderReq: &oidb.DeleteFolderReqBody{ payload := c.packOIDBPackageProto(1751, 1, &oidb.D6D7ReqBody{DeleteFolderReq: &oidb.DeleteFolderReqBody{
GroupCode: proto.Uint64(uint64(groupCode)), GroupCode: proto.Uint64(uint64(groupCode)),
AppId: proto.Uint32(3), AppId: proto.Uint32(3),
FolderId: proto.String(folderId), FolderId: proto.String(folderId),
}}) }})
return c.uniPacket("OidbSvc.0x6d7_1", payload) return c.uniRequest("OidbSvc.0x6d7_1", payload, decodeOIDB6d7Response)
} }
// OidbSvc.0x6d6_2 // OidbSvc.0x6d6_2
func (c *QQClient) buildGroupFileDownloadReqPacket(groupCode int64, fileId string, busId int32) (uint16, []byte) { func (c *QQClient) buildGroupFileDownloadReq(groupCode int64, fileId string, busId int32) *network.Request {
body := &oidb.D6D6ReqBody{ body := &oidb.D6D6ReqBody{
DownloadFileReq: &oidb.DownloadFileReqBody{ DownloadFileReq: &oidb.DownloadFileReqBody{
GroupCode: &groupCode, GroupCode: &groupCode,
@ -418,10 +411,10 @@ func (c *QQClient) buildGroupFileDownloadReqPacket(groupCode int64, fileId strin
Bodybuffer: b, Bodybuffer: b,
} }
payload, _ := proto.Marshal(req) payload, _ := proto.Marshal(req)
return c.uniPacket("OidbSvc.0x6d6_2", payload) return c.uniRequest("OidbSvc.0x6d6_2", payload, decodeOIDB6d62Response)
} }
func (c *QQClient) buildGroupFileDeleteReqPacket(groupCode int64, parentFolderId, fileId string, busId int32) (uint16, []byte) { func (c *QQClient) buildGroupFileDeleteReq(groupCode int64, parentFolderId, fileId string, busId int32) *network.Request {
body := &oidb.D6D6ReqBody{DeleteFileReq: &oidb.DeleteFileReqBody{ body := &oidb.D6D6ReqBody{DeleteFileReq: &oidb.DeleteFileReqBody{
GroupCode: &groupCode, GroupCode: &groupCode,
AppId: proto.Int32(3), AppId: proto.Int32(3),
@ -437,13 +430,13 @@ func (c *QQClient) buildGroupFileDeleteReqPacket(groupCode int64, parentFolderId
ClientVersion: "android 8.4.8", ClientVersion: "android 8.4.8",
} }
payload, _ := proto.Marshal(req) payload, _ := proto.Marshal(req)
return c.uniPacket("OidbSvc.0x6d6_3", payload) return c.uniRequest("OidbSvc.0x6d6_3", payload, decodeOIDB6d63Response)
} }
func decodeOIDB6d81Response(_ *QQClient, _ *network.IncomingPacketInfo, payload []byte) (interface{}, error) { func decodeOIDB6d81Response(_ *QQClient, resp *network.Response) (interface{}, error) {
pkg := oidb.OIDBSSOPkg{} pkg := oidb.OIDBSSOPkg{}
rsp := oidb.D6D8RspBody{} rsp := oidb.D6D8RspBody{}
if err := proto.Unmarshal(payload, &pkg); err != nil { if err := proto.Unmarshal(resp.Body, &pkg); err != nil {
return nil, errors.Wrap(err, "failed to unmarshal protobuf message") return nil, errors.Wrap(err, "failed to unmarshal protobuf message")
} }
if err := proto.Unmarshal(pkg.Bodybuffer, &rsp); err != nil { if err := proto.Unmarshal(pkg.Bodybuffer, &rsp); err != nil {
@ -453,10 +446,10 @@ func decodeOIDB6d81Response(_ *QQClient, _ *network.IncomingPacketInfo, payload
} }
// OidbSvc.0x6d6_2 // OidbSvc.0x6d6_2
func decodeOIDB6d62Response(_ *QQClient, _ *network.IncomingPacketInfo, payload []byte) (interface{}, error) { func decodeOIDB6d62Response(_ *QQClient, resp *network.Response) (interface{}, error) {
pkg := oidb.OIDBSSOPkg{} pkg := oidb.OIDBSSOPkg{}
rsp := oidb.D6D6RspBody{} rsp := oidb.D6D6RspBody{}
if err := proto.Unmarshal(payload, &pkg); err != nil { if err := proto.Unmarshal(resp.Body, &pkg); err != nil {
return nil, errors.Wrap(err, "failed to unmarshal protobuf message") return nil, errors.Wrap(err, "failed to unmarshal protobuf message")
} }
if err := proto.Unmarshal(pkg.Bodybuffer, &rsp); err != nil { if err := proto.Unmarshal(pkg.Bodybuffer, &rsp); err != nil {
@ -470,10 +463,10 @@ func decodeOIDB6d62Response(_ *QQClient, _ *network.IncomingPacketInfo, payload
return fmt.Sprintf("http://%s/ftn_handler/%s/", ip, url), nil return fmt.Sprintf("http://%s/ftn_handler/%s/", ip, url), nil
} }
func decodeOIDB6d63Response(_ *QQClient, _ *network.IncomingPacketInfo, payload []byte) (interface{}, error) { func decodeOIDB6d63Response(_ *QQClient, resp *network.Response) (interface{}, error) {
pkg := oidb.OIDBSSOPkg{} pkg := oidb.OIDBSSOPkg{}
rsp := oidb.D6D6RspBody{} rsp := oidb.D6D6RspBody{}
if err := proto.Unmarshal(payload, &pkg); err != nil { if err := proto.Unmarshal(resp.Body, &pkg); err != nil {
return nil, errors.Wrap(err, "failed to unmarshal protobuf message") return nil, errors.Wrap(err, "failed to unmarshal protobuf message")
} }
if err := proto.Unmarshal(pkg.Bodybuffer, &rsp); err != nil { if err := proto.Unmarshal(pkg.Bodybuffer, &rsp); err != nil {
@ -485,10 +478,10 @@ func decodeOIDB6d63Response(_ *QQClient, _ *network.IncomingPacketInfo, payload
return rsp.DeleteFileRsp.GetClientWording(), nil return rsp.DeleteFileRsp.GetClientWording(), nil
} }
func decodeOIDB6d60Response(_ *QQClient, _ *network.IncomingPacketInfo, payload []byte) (interface{}, error) { func decodeOIDB6d60Response(_ *QQClient, resp *network.Response) (interface{}, error) {
pkg := oidb.OIDBSSOPkg{} pkg := oidb.OIDBSSOPkg{}
rsp := oidb.D6D6RspBody{} rsp := oidb.D6D6RspBody{}
if err := proto.Unmarshal(payload, &pkg); err != nil { if err := proto.Unmarshal(resp.Body, &pkg); err != nil {
return nil, errors.Wrap(err, "failed to unmarshal protobuf message") return nil, errors.Wrap(err, "failed to unmarshal protobuf message")
} }
if err := proto.Unmarshal(pkg.Bodybuffer, &rsp); err != nil { if err := proto.Unmarshal(pkg.Bodybuffer, &rsp); err != nil {
@ -497,10 +490,10 @@ func decodeOIDB6d60Response(_ *QQClient, _ *network.IncomingPacketInfo, payload
return rsp.UploadFileRsp, nil return rsp.UploadFileRsp, nil
} }
func decodeOIDB6d7Response(_ *QQClient, _ *network.IncomingPacketInfo, payload []byte) (interface{}, error) { func decodeOIDB6d7Response(_ *QQClient, resp *network.Response) (interface{}, error) {
pkg := oidb.OIDBSSOPkg{} pkg := oidb.OIDBSSOPkg{}
rsp := oidb.D6D7RspBody{} rsp := oidb.D6D7RspBody{}
if err := proto.Unmarshal(payload, &pkg); err != nil { if err := proto.Unmarshal(resp.Body, &pkg); err != nil {
return nil, errors.Wrap(err, "failed to unmarshal protobuf message") return nil, errors.Wrap(err, "failed to unmarshal protobuf message")
} }
if err := proto.Unmarshal(pkg.Bodybuffer, &rsp); err != nil { if err := proto.Unmarshal(pkg.Bodybuffer, &rsp); err != nil {

View File

@ -65,13 +65,8 @@ type (
} }
) )
func init() {
decoders["SummaryCard.ReqSearch"] = decodeGroupSearchResponse
decoders["OidbSvc.0x88d_0"] = decodeGroupInfoResponse
}
func (c *QQClient) GetGroupInfo(groupCode int64) (*GroupInfo, error) { func (c *QQClient) GetGroupInfo(groupCode int64) (*GroupInfo, error) {
i, err := c.sendAndWait(c.buildGroupInfoRequestPacket(groupCode)) i, err := c.callAndDecode(c.buildGroupInfoRequestPacket(groupCode))
if err != nil { if err != nil {
return nil, err return nil, err
} }
@ -79,7 +74,7 @@ func (c *QQClient) GetGroupInfo(groupCode int64) (*GroupInfo, error) {
} }
// OidbSvc.0x88d_0 // OidbSvc.0x88d_0
func (c *QQClient) buildGroupInfoRequestPacket(groupCode int64) (uint16, []byte) { func (c *QQClient) buildGroupInfoRequestPacket(groupCode int64) *network.Request {
body := &oidb.D88DReqBody{ body := &oidb.D88DReqBody{
AppId: proto.Uint32(c.version.AppId), AppId: proto.Uint32(c.version.AppId),
ReqGroupInfo: []*oidb.ReqGroupInfo{ ReqGroupInfo: []*oidb.ReqGroupInfo{
@ -122,12 +117,12 @@ func (c *QQClient) buildGroupInfoRequestPacket(groupCode int64) (uint16, []byte)
Bodybuffer: b, Bodybuffer: b,
} }
payload, _ := proto.Marshal(req) payload, _ := proto.Marshal(req)
return c.uniPacket("OidbSvc.0x88d_0", payload) return c.uniRequest("OidbSvc.0x88d_0", payload, decodeGroupInfoResponse)
} }
// SearchGroupByKeyword 通过关键词搜索陌生群组 // SearchGroupByKeyword 通过关键词搜索陌生群组
func (c *QQClient) SearchGroupByKeyword(keyword string) ([]GroupSearchInfo, error) { func (c *QQClient) SearchGroupByKeyword(keyword string) ([]GroupSearchInfo, error) {
rsp, err := c.sendAndWait(c.buildGroupSearchPacket(keyword)) rsp, err := c.callAndDecode(c.buildGroupSearchPacket(keyword))
if err != nil { if err != nil {
return nil, errors.Wrap(err, "group search failed") return nil, errors.Wrap(err, "group search failed")
} }
@ -135,7 +130,7 @@ func (c *QQClient) SearchGroupByKeyword(keyword string) ([]GroupSearchInfo, erro
} }
// SummaryCard.ReqSearch // SummaryCard.ReqSearch
func (c *QQClient) buildGroupSearchPacket(keyword string) (uint16, []byte) { func (c *QQClient) buildGroupSearchPacket(keyword string) *network.Request {
comm, _ := proto.Marshal(&profilecard.BusiComm{ comm, _ := proto.Marshal(&profilecard.BusiComm{
Ver: proto.Int32(1), Ver: proto.Int32(1),
Seq: proto.Int32(rand.Int31()), Seq: proto.Int32(rand.Int31()),
@ -184,13 +179,13 @@ func (c *QQClient) buildGroupSearchPacket(keyword string) (uint16, []byte) {
Context: make(map[string]string), Context: make(map[string]string),
Status: make(map[string]string), Status: make(map[string]string),
} }
return c.uniPacket("SummaryCard.ReqSearch", pkt.ToBytes()) return c.uniRequest("SummaryCard.ReqSearch", pkt.ToBytes(), decodeGroupSearchResponse)
} }
// SummaryCard.ReqSearch // SummaryCard.ReqSearch
func decodeGroupSearchResponse(_ *QQClient, _ *network.IncomingPacketInfo, payload []byte) (interface{}, error) { func decodeGroupSearchResponse(_ *QQClient, resp *network.Response) (interface{}, error) {
request := &jce.RequestPacket{} request := &jce.RequestPacket{}
request.ReadFrom(jce.NewJceReader(payload)) request.ReadFrom(jce.NewJceReader(resp.Body))
data := &jce.RequestDataVersion2{} data := &jce.RequestDataVersion2{}
data.ReadFrom(jce.NewJceReader(request.SBuffer)) data.ReadFrom(jce.NewJceReader(request.SBuffer))
if len(data.Map["RespHead"]["SummaryCard.RespHead"]) > 20 { if len(data.Map["RespHead"]["SummaryCard.RespHead"]) > 20 {
@ -226,10 +221,10 @@ func decodeGroupSearchResponse(_ *QQClient, _ *network.IncomingPacketInfo, paylo
} }
// OidbSvc.0x88d_0 // OidbSvc.0x88d_0
func decodeGroupInfoResponse(c *QQClient, _ *network.IncomingPacketInfo, payload []byte) (interface{}, error) { func decodeGroupInfoResponse(c *QQClient, resp *network.Response) (interface{}, error) {
pkg := oidb.OIDBSSOPkg{} pkg := oidb.OIDBSSOPkg{}
rsp := oidb.D88DRspBody{} rsp := oidb.D88DRspBody{}
if err := proto.Unmarshal(payload, &pkg); err != nil { if err := proto.Unmarshal(resp.Body, &pkg); err != nil {
return nil, errors.Wrap(err, "failed to unmarshal protobuf message") return nil, errors.Wrap(err, "failed to unmarshal protobuf message")
} }
if err := proto.Unmarshal(pkg.Bodybuffer, &rsp); err != nil { if err := proto.Unmarshal(pkg.Bodybuffer, &rsp); err != nil {

View File

@ -26,11 +26,6 @@ import (
func init() { func init() {
decoders["OnlinePush.PbPushGroupMsg"] = decodeGroupMessagePacket decoders["OnlinePush.PbPushGroupMsg"] = decodeGroupMessagePacket
decoders["MessageSvc.PbSendMsg"] = decodeMsgSendResponse
decoders["MessageSvc.PbGetGroupMsg"] = decodeGetGroupMsgResponse
decoders["OidbSvc.0x8a7_0"] = decodeAtAllRemainResponse
decoders["OidbSvc.0xeac_1"] = decodeEssenceMsgResponse
decoders["OidbSvc.0xeac_2"] = decodeEssenceMsgResponse
} }
// SendGroupMessage 发送群消息 // SendGroupMessage 发送群消息
@ -80,8 +75,9 @@ func (c *QQClient) SendGroupForwardMessage(groupCode int64, m *message.ForwardEl
// GetGroupMessages 从服务器获取历史信息 // GetGroupMessages 从服务器获取历史信息
func (c *QQClient) GetGroupMessages(groupCode, beginSeq, endSeq int64) ([]*message.GroupMessage, error) { func (c *QQClient) GetGroupMessages(groupCode, beginSeq, endSeq int64) ([]*message.GroupMessage, error) {
seq, pkt := c.buildGetGroupMsgRequest(groupCode, beginSeq, endSeq) req := c.buildGetGroupMsgRequest(groupCode, beginSeq, endSeq)
i, err := c.sendAndWait(seq, pkt, network.RequestParams{"raw": false}) req.Params = network.Params{"raw": false}
i, err := c.callAndDecode(req)
if err != nil { if err != nil {
return nil, err return nil, err
} }
@ -89,7 +85,7 @@ func (c *QQClient) GetGroupMessages(groupCode, beginSeq, endSeq int64) ([]*messa
} }
func (c *QQClient) GetAtAllRemain(groupCode int64) (*AtAllRemainInfo, error) { func (c *QQClient) GetAtAllRemain(groupCode int64) (*AtAllRemainInfo, error) {
i, err := c.sendAndWait(c.buildAtAllRemainRequestPacket(groupCode)) i, err := c.callAndDecode(c.buildAtAllRemainRequestPacket(groupCode))
if err != nil { if err != nil {
return nil, err return nil, err
} }
@ -123,12 +119,12 @@ func (c *QQClient) sendGroupMessage(groupCode int64, forward bool, m *message.Se
div := int32(rand.Uint32()) div := int32(rand.Uint32())
fragmented := m.ToFragmented() fragmented := m.ToFragmented()
for i, elems := range fragmented { for i, elems := range fragmented {
_, pkt := c.buildGroupSendingPacket(groupCode, mr, int32(len(fragmented)), int32(i), div, forward, elems) req := c.buildGroupSendingReq(groupCode, mr, int32(len(fragmented)), int32(i), div, forward, elems)
_ = c.sendPacket(pkt) c.sendReq(req)
} }
} else { } else {
_, pkt := c.buildGroupSendingPacket(groupCode, mr, 1, 0, 0, forward, m.Elements) req := c.buildGroupSendingReq(groupCode, mr, 1, 0, 0, forward, m.Elements)
_ = c.sendPacket(pkt) c.sendReq(req)
} }
var mid int32 var mid int32
ret := &message.GroupMessage{ ret := &message.GroupMessage{
@ -214,7 +210,7 @@ func (c *QQClient) UploadGroupForwardMessage(groupCode int64, m *message.Forward
} }
func (c *QQClient) multiMsgApplyUp(groupCode int64, data []byte, hash []byte, buType int32) (*multimsg.MultiMsgApplyUpRsp, []byte, error) { func (c *QQClient) multiMsgApplyUp(groupCode int64, data []byte, hash []byte, buType int32) (*multimsg.MultiMsgApplyUpRsp, []byte, error) {
i, err := c.sendAndWait(c.buildMultiApplyUpPacket(data, hash, buType, utils.ToGroupUin(groupCode))) i, err := c.callAndDecode(c.buildMultiApplyUpPacket(data, hash, buType, utils.ToGroupUin(groupCode)))
if err != nil { if err != nil {
return nil, nil, err return nil, nil, err
} }
@ -237,7 +233,7 @@ func (c *QQClient) multiMsgApplyUp(groupCode int64, data []byte, hash []byte, bu
} }
// MessageSvc.PbSendMsg // MessageSvc.PbSendMsg
func (c *QQClient) buildGroupSendingPacket(groupCode int64, r, pkgNum, pkgIndex, pkgDiv int32, forward bool, m []message.IMessageElement) (uint16, []byte) { func (c *QQClient) buildGroupSendingReq(groupCode int64, r, pkgNum, pkgIndex, pkgDiv int32, forward bool, m []message.IMessageElement) *network.Request {
var ptt *message.GroupVoiceElement var ptt *message.GroupVoiceElement
if len(m) > 0 { if len(m) > 0 {
if p, ok := m[0].(*message.GroupVoiceElement); ok { if p, ok := m[0].(*message.GroupVoiceElement); ok {
@ -271,10 +267,10 @@ func (c *QQClient) buildGroupSendingPacket(groupCode int64, r, pkgNum, pkgIndex,
}(), }(),
} }
payload, _ := proto.Marshal(req) payload, _ := proto.Marshal(req)
return c.uniPacket("MessageSvc.PbSendMsg", payload) return c.uniRequest("MessageSvc.PbSendMsg", payload, nil)
} }
func (c *QQClient) buildGetGroupMsgRequest(groupCode, beginSeq, endSeq int64) (uint16, []byte) { func (c *QQClient) buildGetGroupMsgRequest(groupCode, beginSeq, endSeq int64) *network.Request {
req := &msg.GetGroupMsgReq{ req := &msg.GetGroupMsgReq{
GroupCode: proto.Uint64(uint64(groupCode)), GroupCode: proto.Uint64(uint64(groupCode)),
BeginSeq: proto.Uint64(uint64(beginSeq)), BeginSeq: proto.Uint64(uint64(beginSeq)),
@ -282,10 +278,10 @@ func (c *QQClient) buildGetGroupMsgRequest(groupCode, beginSeq, endSeq int64) (u
PublicGroup: proto.Bool(false), PublicGroup: proto.Bool(false),
} }
payload, _ := proto.Marshal(req) payload, _ := proto.Marshal(req)
return c.uniPacket("MessageSvc.PbGetGroupMsg", payload) return c.uniRequest("MessageSvc.PbGetGroupMsg", payload, decodeGetGroupMsgResponse)
} }
func (c *QQClient) buildAtAllRemainRequestPacket(groupCode int64) (uint16, []byte) { func (c *QQClient) buildAtAllRemainRequestPacket(groupCode int64) *network.Request {
payload := c.packOIDBPackageProto(2215, 0, &oidb.D8A7ReqBody{ payload := c.packOIDBPackageProto(2215, 0, &oidb.D8A7ReqBody{
SubCmd: proto.Uint32(1), SubCmd: proto.Uint32(1),
LimitIntervalTypeForUin: proto.Uint32(2), LimitIntervalTypeForUin: proto.Uint32(2),
@ -293,13 +289,13 @@ func (c *QQClient) buildAtAllRemainRequestPacket(groupCode int64) (uint16, []byt
Uin: proto.Uint64(uint64(c.Uin)), Uin: proto.Uint64(uint64(c.Uin)),
GroupCode: proto.Uint64(uint64(groupCode)), GroupCode: proto.Uint64(uint64(groupCode)),
}) })
return c.uniPacket("OidbSvc.0x8a7_0", payload) return c.uniRequest("OidbSvc.0x8a7_0", payload, decodeAtAllRemainResponse)
} }
// OnlinePush.PbPushGroupMsg // OnlinePush.PbPushGroupMsg
func decodeGroupMessagePacket(c *QQClient, _ *network.IncomingPacketInfo, payload []byte) (interface{}, error) { func decodeGroupMessagePacket(c *QQClient, resp *network.Response) (interface{}, error) {
pkt := msg.PushMessagePacket{} pkt := msg.PushMessagePacket{}
err := proto.Unmarshal(payload, &pkt) err := proto.Unmarshal(resp.Body, &pkt)
if err != nil { if err != nil {
return nil, errors.Wrap(err, "failed to unmarshal protobuf message") return nil, errors.Wrap(err, "failed to unmarshal protobuf message")
} }
@ -338,24 +334,9 @@ func decodeGroupMessagePacket(c *QQClient, _ *network.IncomingPacketInfo, payloa
return nil, nil return nil, nil
} }
func decodeMsgSendResponse(c *QQClient, _ *network.IncomingPacketInfo, payload []byte) (interface{}, error) { func decodeGetGroupMsgResponse(c *QQClient, resp *network.Response) (interface{}, error) {
rsp := msg.SendMessageResponse{}
if err := proto.Unmarshal(payload, &rsp); err != nil {
return nil, errors.Wrap(err, "failed to unmarshal protobuf message")
}
switch rsp.GetResult() {
case 0: // OK.
case 55:
c.Error("sendPacket msg error: %v Bot has blocked target's content", rsp.GetResult())
default:
c.Error("sendPacket msg error: %v %v", rsp.GetResult(), rsp.GetErrMsg())
}
return nil, nil
}
func decodeGetGroupMsgResponse(c *QQClient, info *network.IncomingPacketInfo, payload []byte) (interface{}, error) {
rsp := msg.GetGroupMsgResp{} rsp := msg.GetGroupMsgResp{}
if err := proto.Unmarshal(payload, &rsp); err != nil { if err := proto.Unmarshal(resp.Body, &rsp); err != nil {
return nil, errors.Wrap(err, "failed to unmarshal protobuf message") return nil, errors.Wrap(err, "failed to unmarshal protobuf message")
} }
if rsp.GetResult() != 0 { if rsp.GetResult() != 0 {
@ -367,15 +348,16 @@ func decodeGetGroupMsgResponse(c *QQClient, info *network.IncomingPacketInfo, pa
if m.Head.FromUin == nil { if m.Head.FromUin == nil {
continue continue
} }
if m.Content != nil && m.Content.GetPkgNum() > 1 && !info.Params.Bool("raw") { if m.Content != nil && m.Content.GetPkgNum() > 1 && !resp.Params().Bool("raw") {
if m.Content.GetPkgIndex() == 0 { if m.Content.GetPkgIndex() == 0 {
c.Debug("build fragmented message from history") c.Debug("build fragmented message from history")
i := m.Head.GetMsgSeq() - m.Content.GetPkgNum() i := m.Head.GetMsgSeq() - m.Content.GetPkgNum()
builder := &groupMessageBuilder{} builder := &groupMessageBuilder{}
for { for {
end := int32(math.Min(float64(i+19), float64(m.Head.GetMsgSeq()+m.Content.GetPkgNum()))) end := int32(math.Min(float64(i+19), float64(m.Head.GetMsgSeq()+m.Content.GetPkgNum())))
seq, pkt := c.buildGetGroupMsgRequest(m.Head.GroupInfo.GetGroupCode(), int64(i), int64(end)) req := c.buildGetGroupMsgRequest(m.Head.GroupInfo.GetGroupCode(), int64(i), int64(end))
data, err := c.sendAndWait(seq, pkt, network.RequestParams{"raw": true}) req.Params = network.Params{"raw": true}
data, err := c.callAndDecode(req)
if err != nil { if err != nil {
return nil, errors.Wrap(err, "build fragmented message error") return nil, errors.Wrap(err, "build fragmented message error")
} }
@ -402,10 +384,10 @@ func decodeGetGroupMsgResponse(c *QQClient, info *network.IncomingPacketInfo, pa
return ret, nil return ret, nil
} }
func decodeAtAllRemainResponse(_ *QQClient, _ *network.IncomingPacketInfo, payload []byte) (interface{}, error) { func decodeAtAllRemainResponse(_ *QQClient, resp *network.Response) (interface{}, error) {
pkg := oidb.OIDBSSOPkg{} pkg := oidb.OIDBSSOPkg{}
rsp := oidb.D8A7RspBody{} rsp := oidb.D8A7RspBody{}
if err := proto.Unmarshal(payload, &pkg); err != nil { if err := proto.Unmarshal(resp.Body, &pkg); err != nil {
return nil, errors.Wrap(err, "failed to unmarshal protobuf message") return nil, errors.Wrap(err, "failed to unmarshal protobuf message")
} }
if err := proto.Unmarshal(pkg.Bodybuffer, &rsp); err != nil { if err := proto.Unmarshal(pkg.Bodybuffer, &rsp); err != nil {
@ -563,7 +545,7 @@ func (c *QQClient) parseGroupMessage(m *msg.Message) *message.GroupMessage {
// SetEssenceMessage 设为群精华消息 // SetEssenceMessage 设为群精华消息
func (c *QQClient) SetEssenceMessage(groupCode int64, msgID, msgInternalId int32) error { func (c *QQClient) SetEssenceMessage(groupCode int64, msgID, msgInternalId int32) error {
r, err := c.sendAndWait(c.buildEssenceMsgOperatePacket(groupCode, uint32(msgID), uint32(msgInternalId), 1)) r, err := c.callAndDecode(c.buildEssenceMsgOperatePacket(groupCode, uint32(msgID), uint32(msgInternalId), 1))
if err != nil { if err != nil {
return errors.Wrap(err, "set essence msg network") return errors.Wrap(err, "set essence msg network")
} }
@ -576,7 +558,7 @@ func (c *QQClient) SetEssenceMessage(groupCode int64, msgID, msgInternalId int32
// DeleteEssenceMessage 移出群精华消息 // DeleteEssenceMessage 移出群精华消息
func (c *QQClient) DeleteEssenceMessage(groupCode int64, msgID, msgInternalId int32) error { func (c *QQClient) DeleteEssenceMessage(groupCode int64, msgID, msgInternalId int32) error {
r, err := c.sendAndWait(c.buildEssenceMsgOperatePacket(groupCode, uint32(msgID), uint32(msgInternalId), 2)) r, err := c.callAndDecode(c.buildEssenceMsgOperatePacket(groupCode, uint32(msgID), uint32(msgInternalId), 2))
if err != nil { if err != nil {
return errors.Wrap(err, "set essence msg networ") return errors.Wrap(err, "set essence msg networ")
} }
@ -587,21 +569,21 @@ func (c *QQClient) DeleteEssenceMessage(groupCode int64, msgID, msgInternalId in
return nil return nil
} }
func (c *QQClient) buildEssenceMsgOperatePacket(groupCode int64, msgSeq, msgRand, opType uint32) (uint16, []byte) { func (c *QQClient) buildEssenceMsgOperatePacket(groupCode int64, msgSeq, msgRand, opType uint32) *network.Request {
commandName := "OidbSvc.0xeac_" + strconv.FormatInt(int64(opType), 10) commandName := "OidbSvc.0xeac_" + strconv.FormatInt(int64(opType), 10)
payload := c.packOIDBPackageProto(3756, int32(opType), &oidb.EACReqBody{ // serviceType 2 取消 payload := c.packOIDBPackageProto(3756, int32(opType), &oidb.EACReqBody{ // serviceType 2 取消
GroupCode: proto.Uint64(uint64(groupCode)), GroupCode: proto.Uint64(uint64(groupCode)),
Seq: proto.Uint32(msgSeq), Seq: proto.Uint32(msgSeq),
Random: proto.Uint32(msgRand), Random: proto.Uint32(msgRand),
}) })
return c.uniPacket(commandName, payload) return c.uniRequest(commandName, payload, decodeEssenceMsgResponse)
} }
// OidbSvc.0xeac_1/2 // OidbSvc.0xeac_1/2
func decodeEssenceMsgResponse(_ *QQClient, _ *network.IncomingPacketInfo, payload []byte) (interface{}, error) { func decodeEssenceMsgResponse(_ *QQClient, resp *network.Response) (interface{}, error) {
pkg := oidb.OIDBSSOPkg{} pkg := oidb.OIDBSSOPkg{}
rsp := &oidb.EACRspBody{} rsp := &oidb.EACRspBody{}
if err := proto.Unmarshal(payload, &pkg); err != nil { if err := proto.Unmarshal(resp.Body, &pkg); err != nil {
return nil, errors.Wrap(err, "failed to unmarshal protobuf message") return nil, errors.Wrap(err, "failed to unmarshal protobuf message")
} }
if err := proto.Unmarshal(pkg.Bodybuffer, rsp); err != nil { if err := proto.Unmarshal(pkg.Bodybuffer, rsp); err != nil {

View File

@ -187,12 +187,12 @@ func (s *GuildService) GetUserProfile(tinyId uint64) (*GuildUserProfile, error)
3: tinyId, 3: tinyId,
4: uint32(0), 4: uint32(0),
}) })
rsp, err := s.c.sendAndWaitDynamic(s.c.uniPacket("OidbSvcTrpcTcp.0xfc9_1", payload)) rsp, err := s.c.uniCall("OidbSvcTrpcTcp.0xfc9_1", payload)
if err != nil { if err != nil {
return nil, errors.Wrap(err, "send packet error") return nil, errors.Wrap(err, "send packet error")
} }
body := new(channel.ChannelOidb0Xfc9Rsp) body := new(channel.ChannelOidb0Xfc9Rsp)
if err = unpackOIDBPackage(rsp, body); err != nil { if err = unpackOIDBPackage(rsp.Body, body); err != nil {
return nil, errors.Wrap(err, "decode packet error") return nil, errors.Wrap(err, "decode packet error")
} }
// todo: 解析个性档案 // todo: 解析个性档案
@ -208,7 +208,6 @@ func (s *GuildService) GetUserProfile(tinyId uint64) (*GuildUserProfile, error)
// 第一次请求: startIndex = 0 , roleIdIndex = 2 param = "" // 第一次请求: startIndex = 0 , roleIdIndex = 2 param = ""
// 后续请求请根据上次请求的返回值进行设置 // 后续请求请根据上次请求的返回值进行设置
func (s *GuildService) FetchGuildMemberListWithRole(guildId, channelId uint64, startIndex uint32, roleIdIndex uint64, param string) (*FetchGuildMemberListWithRoleResult, error) { func (s *GuildService) FetchGuildMemberListWithRole(guildId, channelId uint64, startIndex uint32, roleIdIndex uint64, param string) (*FetchGuildMemberListWithRoleResult, error) {
seq := s.c.nextSeq()
u1 := uint32(1) u1 := uint32(1)
m := binary.DynamicProtoMessage{ m := binary.DynamicProtoMessage{
1: guildId, // guild id 1: guildId, // guild id
@ -225,13 +224,12 @@ func (s *GuildService) FetchGuildMemberListWithRole(guildId, channelId uint64, s
m[13] = param m[13] = param
} }
m[14] = roleIdIndex m[14] = roleIdIndex
packet := s.c.uniPacketWithSeq(seq, "OidbSvcTrpcTcp.0xf5b_1", s.c.packOIDBPackageDynamically(3931, 1, m)) rsp, err := s.c.uniCall("OidbSvcTrpcTcp.0xf5b_1", s.c.packOIDBPackageDynamically(3931, 1, m))
rsp, err := s.c.sendAndWaitDynamic(seq, packet)
if err != nil { if err != nil {
return nil, errors.Wrap(err, "send packet error") return nil, errors.Wrap(err, "send packet error")
} }
body := new(channel.ChannelOidb0Xf5BRsp) body := new(channel.ChannelOidb0Xf5BRsp)
if err = unpackOIDBPackage(rsp, body); err != nil { if err = unpackOIDBPackage(rsp.Body, body); err != nil {
return nil, errors.Wrap(err, "decode packet error") return nil, errors.Wrap(err, "decode packet error")
} }
var ret []*GuildMemberInfo var ret []*GuildMemberInfo
@ -268,7 +266,6 @@ func (s *GuildService) FetchGuildMemberListWithRole(guildId, channelId uint64, s
// FetchGuildMemberProfileInfo 获取单个频道成员资料 // FetchGuildMemberProfileInfo 获取单个频道成员资料
func (s *GuildService) FetchGuildMemberProfileInfo(guildId, tinyId uint64) (*GuildUserProfile, error) { func (s *GuildService) FetchGuildMemberProfileInfo(guildId, tinyId uint64) (*GuildUserProfile, error) {
seq := s.c.nextSeq()
flags := binary.DynamicProtoMessage{} flags := binary.DynamicProtoMessage{}
for i := 3; i <= 29; i++ { for i := 3; i <= 29; i++ {
flags[uint64(i)] = uint32(1) flags[uint64(i)] = uint32(1)
@ -280,13 +277,12 @@ func (s *GuildService) FetchGuildMemberProfileInfo(guildId, tinyId uint64) (*Gui
3: tinyId, 3: tinyId,
4: guildId, 4: guildId,
}) })
packet := s.c.uniPacketWithSeq(seq, "OidbSvcTrpcTcp.0xf88_1", payload) rsp, err := s.c.uniCall("OidbSvcTrpcTcp.0xf88_1", payload)
rsp, err := s.c.sendAndWaitDynamic(seq, packet)
if err != nil { if err != nil {
return nil, errors.Wrap(err, "send packet error") return nil, errors.Wrap(err, "send packet error")
} }
body := new(channel.ChannelOidb0Xf88Rsp) body := new(channel.ChannelOidb0Xf88Rsp)
if err = unpackOIDBPackage(rsp, body); err != nil { if err = unpackOIDBPackage(rsp.Body, body); err != nil {
return nil, errors.Wrap(err, "decode packet error") return nil, errors.Wrap(err, "decode packet error")
} }
roles, err := s.fetchMemberRoles(guildId, tinyId) roles, err := s.fetchMemberRoles(guildId, tinyId)
@ -304,14 +300,14 @@ func (s *GuildService) FetchGuildMemberProfileInfo(guildId, tinyId uint64) (*Gui
} }
func (s *GuildService) GetGuildRoles(guildId uint64) ([]*GuildRole, error) { func (s *GuildService) GetGuildRoles(guildId uint64) ([]*GuildRole, error) {
seq, packet := s.c.uniPacket("OidbSvcTrpcTcp.0x1019_1", req := s.c.uniRequest("OidbSvcTrpcTcp.0x1019_1",
s.c.packOIDBPackageDynamically(4121, 1, binary.DynamicProtoMessage{1: guildId})) s.c.packOIDBPackageDynamically(4121, 1, binary.DynamicProtoMessage{1: guildId}), nil)
rsp, err := s.c.sendAndWaitDynamic(seq, packet) rsp, err := s.c.call(req)
if err != nil { if err != nil {
return nil, errors.Wrap(err, "send packet error") return nil, errors.Wrap(err, "send packet error")
} }
body := new(channel.ChannelOidb0X1019Rsp) body := new(channel.ChannelOidb0X1019Rsp)
if err = unpackOIDBPackage(rsp, body); err != nil { if err = unpackOIDBPackage(rsp.Body, body); err != nil {
return nil, errors.Wrap(err, "decode packet error") return nil, errors.Wrap(err, "decode packet error")
} }
roles := make([]*GuildRole, 0, len(body.GetRoles())) roles := make([]*GuildRole, 0, len(body.GetRoles()))
@ -332,7 +328,7 @@ func (s *GuildService) GetGuildRoles(guildId uint64) ([]*GuildRole, error) {
func (s *GuildService) CreateGuildRole(guildId uint64, name string, color uint32, independent bool, initialUsers []uint64) (uint64, error) { func (s *GuildService) CreateGuildRole(guildId uint64, name string, color uint32, independent bool, initialUsers []uint64) (uint64, error) {
u1 := uint32(1) u1 := uint32(1)
seq, packet := s.c.uniPacket("OidbSvcTrpcTcp.0x1016_1", s.c.packOIDBPackageDynamically(4118, 1, binary.DynamicProtoMessage{ req := s.c.uniRequest("OidbSvcTrpcTcp.0x1016_1", s.c.packOIDBPackageDynamically(4118, 1, binary.DynamicProtoMessage{
1: guildId, 1: guildId,
2: binary.DynamicProtoMessage{ // todo: 未知参数 2: binary.DynamicProtoMessage{ // todo: 未知参数
1: u1, 1: u1,
@ -345,24 +341,24 @@ func (s *GuildService) CreateGuildRole(guildId uint64, name string, color uint32
3: independent, 3: independent,
}, },
4: initialUsers, 4: initialUsers,
})) }), nil)
rsp, err := s.c.sendAndWaitDynamic(seq, packet) rsp, err := s.c.call(req)
if err != nil { if err != nil {
return 0, errors.Wrap(err, "send packet error") return 0, errors.Wrap(err, "send packet error")
} }
body := new(channel.ChannelOidb0X1016Rsp) body := new(channel.ChannelOidb0X1016Rsp)
if err = unpackOIDBPackage(rsp, body); err != nil { if err = unpackOIDBPackage(rsp.Body, body); err != nil {
return 0, errors.Wrap(err, "decode packet error") return 0, errors.Wrap(err, "decode packet error")
} }
return body.GetRoleId(), nil return body.GetRoleId(), nil
} }
func (s *GuildService) DeleteGuildRole(guildId uint64, roleId uint64) error { func (s *GuildService) DeleteGuildRole(guildId uint64, roleId uint64) error {
seq, packet := s.c.uniPacket("OidbSvcTrpcTcp.0x100e_1", s.c.packOIDBPackageDynamically(4110, 1, binary.DynamicProtoMessage{ req := s.c.uniRequest("OidbSvcTrpcTcp.0x100e_1", s.c.packOIDBPackageDynamically(4110, 1, binary.DynamicProtoMessage{
1: guildId, 1: guildId,
2: roleId, 2: roleId,
})) }), nil)
_, err := s.c.sendAndWaitDynamic(seq, packet) _, err := s.c.call(req)
if err != nil { if err != nil {
return errors.Wrap(err, "send packet error") return errors.Wrap(err, "send packet error")
} }
@ -378,11 +374,11 @@ func (s *GuildService) SetUserRoleInGuild(guildId uint64, set bool, roleId uint6
} else { } else {
setOrRemove[3] = user setOrRemove[3] = user
} }
seq, packet := s.c.uniPacket("OidbSvcTrpcTcp.0x101a_1", s.c.packOIDBPackageDynamically(4122, 1, binary.DynamicProtoMessage{ req := s.c.uniRequest("OidbSvcTrpcTcp.0x101a_1", s.c.packOIDBPackageDynamically(4122, 1, binary.DynamicProtoMessage{
1: guildId, 1: guildId,
2: setOrRemove, 2: setOrRemove,
})) }), nil)
_, err := s.c.sendAndWaitDynamic(seq, packet) _, err := s.c.call(req)
if err != nil { if err != nil {
return errors.Wrap(err, "send packet error") return errors.Wrap(err, "send packet error")
} }
@ -391,7 +387,7 @@ func (s *GuildService) SetUserRoleInGuild(guildId uint64, set bool, roleId uint6
func (s *GuildService) ModifyRoleInGuild(guildId uint64, roleId uint64, name string, color uint32, indepedent bool) error { func (s *GuildService) ModifyRoleInGuild(guildId uint64, roleId uint64, name string, color uint32, indepedent bool) error {
u1 := uint32(1) u1 := uint32(1)
seq, packet := s.c.uniPacket("OidbSvcTrpcTcp.0x100d_1", s.c.packOIDBPackageDynamically(4109, 1, binary.DynamicProtoMessage{ req := s.c.uniRequest("OidbSvcTrpcTcp.0x100d_1", s.c.packOIDBPackageDynamically(4109, 1, binary.DynamicProtoMessage{
1: guildId, 1: guildId,
2: roleId, 2: roleId,
3: binary.DynamicProtoMessage{ 3: binary.DynamicProtoMessage{
@ -404,8 +400,8 @@ func (s *GuildService) ModifyRoleInGuild(guildId uint64, roleId uint64, name str
2: color, 2: color,
3: indepedent, 3: indepedent,
}, },
})) }), nil)
_, err := s.c.sendAndWaitDynamic(seq, packet) _, err := s.c.call(req)
if err != nil { if err != nil {
return errors.Wrap(err, "send packet error") return errors.Wrap(err, "send packet error")
} }
@ -428,13 +424,13 @@ func (s *GuildService) FetchGuestGuild(guildId uint64) (*GuildMeta, error) {
1: guildId, 1: guildId,
}, },
}) })
seq, packet := s.c.uniPacket("OidbSvcTrpcTcp.0xf57_9", payload) req := s.c.uniRequest("OidbSvcTrpcTcp.0xf57_9", payload, nil)
rsp, err := s.c.sendAndWaitDynamic(seq, packet) rsp, err := s.c.call(req)
if err != nil { if err != nil {
return nil, errors.Wrap(err, "send packet error") return nil, errors.Wrap(err, "send packet error")
} }
body := new(channel.ChannelOidb0Xf57Rsp) body := new(channel.ChannelOidb0Xf57Rsp)
if err = unpackOIDBPackage(rsp, body); err != nil { if err = unpackOIDBPackage(rsp.Body, body); err != nil {
return nil, errors.Wrap(err, "decode packet error") return nil, errors.Wrap(err, "decode packet error")
} }
return &GuildMeta{ return &GuildMeta{
@ -450,20 +446,20 @@ func (s *GuildService) FetchGuestGuild(guildId uint64) (*GuildMeta, error) {
} }
func (s *GuildService) FetchChannelList(guildId uint64) (r []*ChannelInfo, e error) { func (s *GuildService) FetchChannelList(guildId uint64) (r []*ChannelInfo, e error) {
seq, packet := s.c.uniPacket("OidbSvcTrpcTcp.0xf5d_1", req := s.c.uniRequest("OidbSvcTrpcTcp.0xf5d_1",
s.c.packOIDBPackageDynamically(3933, 1, s.c.packOIDBPackageDynamically(3933, 1,
binary.DynamicProtoMessage{ binary.DynamicProtoMessage{
1: guildId, 1: guildId,
3: binary.DynamicProtoMessage{ 3: binary.DynamicProtoMessage{
1: uint32(1), 1: uint32(1),
}, },
})) }), nil)
rsp, err := s.c.sendAndWaitDynamic(seq, packet) rsp, err := s.c.call(req)
if err != nil { if err != nil {
return nil, errors.Wrap(err, "send packet error") return nil, errors.Wrap(err, "send packet error")
} }
body := new(channel.ChannelOidb0Xf5DRsp) body := new(channel.ChannelOidb0Xf5DRsp)
if err = unpackOIDBPackage(rsp, body); err != nil { if err = unpackOIDBPackage(rsp.Body, body); err != nil {
return nil, errors.Wrap(err, "decode packet error") return nil, errors.Wrap(err, "decode packet error")
} }
for _, info := range body.Rsp.Channels { for _, info := range body.Rsp.Channels {
@ -473,13 +469,17 @@ func (s *GuildService) FetchChannelList(guildId uint64) (r []*ChannelInfo, e err
} }
func (s *GuildService) FetchChannelInfo(guildId, channelId uint64) (*ChannelInfo, error) { func (s *GuildService) FetchChannelInfo(guildId, channelId uint64) (*ChannelInfo, error) {
seq, packet := s.c.uniPacket("OidbSvcTrpcTcp.0xf55_1", s.c.packOIDBPackageDynamically(3925, 1, binary.DynamicProtoMessage{1: guildId, 2: channelId})) req := s.c.uniRequest("OidbSvcTrpcTcp.0xf55_1",
rsp, err := s.c.sendAndWaitDynamic(seq, packet) s.c.packOIDBPackageDynamically(3925, 1, binary.DynamicProtoMessage{
1: guildId,
2: channelId,
}), nil)
rsp, err := s.c.call(req)
if err != nil { if err != nil {
return nil, errors.Wrap(err, "send packet error") return nil, errors.Wrap(err, "send packet error")
} }
body := new(channel.ChannelOidb0Xf55Rsp) body := new(channel.ChannelOidb0Xf55Rsp)
if err = unpackOIDBPackage(rsp, body); err != nil { if err = unpackOIDBPackage(rsp.Body, body); err != nil {
return nil, errors.Wrap(err, "decode packet error") return nil, errors.Wrap(err, "decode packet error")
} }
return convertChannelInfo(body.Info), nil return convertChannelInfo(body.Info), nil
@ -527,14 +527,14 @@ func (s *GuildService) GetTopicChannelFeeds(guildId, channelId uint64) ([]*topic
}, },
}, },
}) })
seq, packet := s.c.uniPacket("QChannelSvr.trpc.qchannel.commreader.ComReader.GetChannelTimelineFeeds", payload) call := s.c.uniRequest("QChannelSvr.trpc.qchannel.commreader.ComReader.GetChannelTimelineFeeds", payload, nil)
rsp, err := s.c.sendAndWaitDynamic(seq, packet) rsp, err := s.c.call(call)
if err != nil { if err != nil {
return nil, errors.New("send packet error") return nil, errors.New("send packet error")
} }
pkg := new(qweb.QWebRsp) pkg := new(qweb.QWebRsp)
body := new(channel.StGetChannelFeedsRsp) body := new(channel.StGetChannelFeedsRsp)
if err = proto.Unmarshal(rsp, pkg); err != nil { if err = proto.Unmarshal(rsp.Body, pkg); err != nil {
return nil, errors.Wrap(err, "failed to unmarshal protobuf message") return nil, errors.Wrap(err, "failed to unmarshal protobuf message")
} }
if err = proto.Unmarshal(pkg.BusiBuff, body); err != nil { if err = proto.Unmarshal(pkg.BusiBuff, body); err != nil {
@ -597,14 +597,13 @@ func (s *GuildService) PostTopicChannelFeed(guildId, channelId uint64, feed *top
}, },
}, },
}) })
seq, packet := s.c.uniPacket("QChannelSvr.trpc.qchannel.commwriter.ComWriter.PublishFeed", payload) rsp, err := s.c.call(s.c.uniRequest("QChannelSvr.trpc.qchannel.commwriter.ComWriter.PublishFeed", payload, nil))
rsp, err := s.c.sendAndWaitDynamic(seq, packet)
if err != nil { if err != nil {
return errors.New("send packet error") return errors.New("send packet error")
} }
pkg := new(qweb.QWebRsp) pkg := new(qweb.QWebRsp)
body := new(channel.StPublishFeedRsp) body := new(channel.StPublishFeedRsp)
if err = proto.Unmarshal(rsp, pkg); err != nil { if err = proto.Unmarshal(rsp.Body, pkg); err != nil {
return errors.Wrap(err, "failed to unmarshal protobuf message") return errors.Wrap(err, "failed to unmarshal protobuf message")
} }
if err = proto.Unmarshal(pkg.BusiBuff, body); err != nil { if err = proto.Unmarshal(pkg.BusiBuff, body); err != nil {
@ -618,7 +617,7 @@ func (s *GuildService) PostTopicChannelFeed(guildId, channelId uint64, feed *top
func (s *GuildService) fetchMemberRoles(guildId uint64, tinyId uint64) ([]*GuildRole, error) { func (s *GuildService) fetchMemberRoles(guildId uint64, tinyId uint64) ([]*GuildRole, error) {
u1 := uint32(1) u1 := uint32(1)
seq, packet := s.c.uniPacket("OidbSvcTrpcTcp.0x1017_1", s.c.packOIDBPackageDynamically(4119, 1, binary.DynamicProtoMessage{ req := s.c.uniRequest("OidbSvcTrpcTcp.0x1017_1", s.c.packOIDBPackageDynamically(4119, 1, binary.DynamicProtoMessage{
1: guildId, 1: guildId,
2: tinyId, 2: tinyId,
4: binary.DynamicProtoMessage{ 4: binary.DynamicProtoMessage{
@ -626,13 +625,13 @@ func (s *GuildService) fetchMemberRoles(guildId uint64, tinyId uint64) ([]*Guild
2: u1, 2: u1,
3: u1, 3: u1,
}, },
})) }), nil)
rsp, err := s.c.sendAndWaitDynamic(seq, packet) rsp, err := s.c.call(req)
if err != nil { if err != nil {
return nil, errors.Wrap(err, "send packet error") return nil, errors.Wrap(err, "send packet error")
} }
body := new(channel.ChannelOidb0X1017Rsp) body := new(channel.ChannelOidb0X1017Rsp)
if err = unpackOIDBPackage(rsp, body); err != nil { if err = unpackOIDBPackage(rsp.Body, body); err != nil {
return nil, errors.Wrap(err, "decode packet error") return nil, errors.Wrap(err, "decode packet error")
} }
p1 := body.GetP1() p1 := body.GetP1()
@ -709,13 +708,13 @@ func convertChannelInfo(info *channel.GuildChannelInfo) *ChannelInfo {
} }
func (c *QQClient) syncChannelFirstView() { func (c *QQClient) syncChannelFirstView() {
rsp, err := c.sendAndWaitDynamic(c.buildSyncChannelFirstViewPacket()) rsp, err := c.call(c.buildSyncChannelFirstViewPacket())
if err != nil { if err != nil {
c.Error("sync channel error: %v", err) c.Error("sync channel error: %v", err)
return return
} }
firstViewRsp := new(channel.FirstViewRsp) firstViewRsp := new(channel.FirstViewRsp)
if err = proto.Unmarshal(rsp, firstViewRsp); err != nil { if err = proto.Unmarshal(rsp.Body, firstViewRsp); err != nil {
return return
} }
c.GuildService.TinyId = firstViewRsp.GetSelfTinyid() c.GuildService.TinyId = firstViewRsp.GetSelfTinyid()
@ -728,19 +727,19 @@ func (c *QQClient) syncChannelFirstView() {
} }
} }
func (c *QQClient) buildSyncChannelFirstViewPacket() (uint16, []byte) { func (c *QQClient) buildSyncChannelFirstViewPacket() *network.Request {
req := &channel.FirstViewReq{ req := &channel.FirstViewReq{
LastMsgTime: proto.Uint64(0), LastMsgTime: proto.Uint64(0),
Seq: proto.Uint32(0), Seq: proto.Uint32(0),
DirectMessageFlag: proto.Uint32(1), DirectMessageFlag: proto.Uint32(1),
} }
payload, _ := proto.Marshal(req) payload, _ := proto.Marshal(req)
return c.uniPacket("trpc.group_pro.synclogic.SyncLogic.SyncFirstView", payload) return c.uniRequest("trpc.group_pro.synclogic.SyncLogic.SyncFirstView", payload, nil)
} }
func decodeGuildPushFirstView(c *QQClient, _ *network.IncomingPacketInfo, payload []byte) (interface{}, error) { func decodeGuildPushFirstView(c *QQClient, resp *network.Response) (interface{}, error) {
firstViewMsg := new(channel.FirstViewMsg) firstViewMsg := new(channel.FirstViewMsg)
if err := proto.Unmarshal(payload, firstViewMsg); err != nil { if err := proto.Unmarshal(resp.Body, firstViewMsg); err != nil {
return nil, errors.Wrap(err, "failed to unmarshal protobuf message") return nil, errors.Wrap(err, "failed to unmarshal protobuf message")
} }
if len(firstViewMsg.GuildNodes) > 0 { if len(firstViewMsg.GuildNodes) > 0 {

View File

@ -27,9 +27,9 @@ type tipsPushInfo struct {
ChannelId uint64 ChannelId uint64
} }
func decodeGuildEventFlowPacket(c *QQClient, _ *network.IncomingPacketInfo, payload []byte) (interface{}, error) { func decodeGuildEventFlowPacket(c *QQClient, resp *network.Response) (interface{}, error) {
push := new(channel.MsgOnlinePush) push := new(channel.MsgOnlinePush)
if err := proto.Unmarshal(payload, push); err != nil { if err := proto.Unmarshal(resp.Body, push); err != nil {
return nil, errors.Wrap(err, "failed to unmarshal protobuf message") return nil, errors.Wrap(err, "failed to unmarshal protobuf message")
} }
if push.GetCompressFlag() == 1 && len(push.CompressMsg) > 0 { if push.GetCompressFlag() == 1 && len(push.CompressMsg) > 0 {

View File

@ -35,10 +35,6 @@ type guildImageUploadResponse struct {
IsExists bool IsExists bool
} }
func init() {
decoders["ImgStore.QQMeetPicUp"] = decodeGuildImageStoreResponse
}
func (s *GuildService) SendGuildChannelMessage(guildId, channelId uint64, m *message.SendingMessage) (*message.GuildChannelMessage, error) { func (s *GuildService) SendGuildChannelMessage(guildId, channelId uint64, m *message.SendingMessage) (*message.GuildChannelMessage, error) {
mr := rand.Uint32() // 客户端似乎是生成的 u32 虽然类型是u64 mr := rand.Uint32() // 客户端似乎是生成的 u32 虽然类型是u64
for _, elem := range m.Elements { for _, elem := range m.Elements {
@ -68,13 +64,12 @@ func (s *GuildService) SendGuildChannelMessage(guildId, channelId uint64, m *mes
}, },
}} }}
payload, _ := proto.Marshal(req) payload, _ := proto.Marshal(req)
seq, packet := s.c.uniPacket("MsgProxy.SendMsg", payload) rsp, err := s.c.uniCall("MsgProxy.SendMsg", payload)
rsp, err := s.c.sendAndWaitDynamic(seq, packet)
if err != nil { if err != nil {
return nil, errors.Wrap(err, "send packet error") return nil, errors.Wrap(err, "send packet error")
} }
body := new(channel.DF62RspBody) body := new(channel.DF62RspBody)
if err = proto.Unmarshal(rsp, body); err != nil { if err = proto.Unmarshal(rsp.Body, body); err != nil {
return nil, errors.Wrap(err, "failed to unmarshal protobuf message") return nil, errors.Wrap(err, "failed to unmarshal protobuf message")
} }
if body.GetResult() != 0 { if body.GetResult() != 0 {
@ -99,7 +94,7 @@ func (s *GuildService) SendGuildChannelMessage(guildId, channelId uint64, m *mes
} }
func (s *GuildService) QueryImage(guildId, channelId uint64, hash []byte, size uint64) (*message.GuildImageElement, error) { func (s *GuildService) QueryImage(guildId, channelId uint64, hash []byte, size uint64) (*message.GuildImageElement, error) {
rsp, err := s.c.sendAndWait(s.c.buildGuildImageStorePacket(guildId, channelId, hash, size)) rsp, err := s.c.callAndDecode(s.c.buildGuildImageStorePacket(guildId, channelId, hash, size))
if err != nil { if err != nil {
return nil, errors.Wrap(err, "send packet error") return nil, errors.Wrap(err, "send packet error")
} }
@ -122,7 +117,7 @@ func (s *GuildService) UploadGuildImage(guildId, channelId uint64, img io.ReadSe
_, _ = img.Seek(0, io.SeekStart) // safe _, _ = img.Seek(0, io.SeekStart) // safe
fh, length := utils.ComputeMd5AndLength(img) fh, length := utils.ComputeMd5AndLength(img)
_, _ = img.Seek(0, io.SeekStart) _, _ = img.Seek(0, io.SeekStart)
rsp, err := s.c.sendAndWait(s.c.buildGuildImageStorePacket(guildId, channelId, fh, uint64(length))) rsp, err := s.c.callAndDecode(s.c.buildGuildImageStorePacket(guildId, channelId, fh, uint64(length)))
if err != nil { if err != nil {
return nil, err return nil, err
} }
@ -215,19 +210,18 @@ func (s *GuildService) pullChannelMessages(guildId, channelId, beginSeq, endSeq,
WithVersionFlag: &withVersionFlag, WithVersionFlag: &withVersionFlag,
DirectMessageFlag: &directFlag, DirectMessageFlag: &directFlag,
}) })
seq, packet := s.c.uniPacket("trpc.group_pro.synclogic.SyncLogic.GetChannelMsg", payload) rsp, err := s.c.uniCall("trpc.group_pro.synclogic.SyncLogic.GetChannelMsg", payload)
rsp, err := s.c.sendAndWaitDynamic(seq, packet)
if err != nil { if err != nil {
return nil, errors.Wrap(err, "send packet error") return nil, errors.Wrap(err, "send packet error")
} }
msgRsp := new(channel.ChannelMsgRsp) msgRsp := new(channel.ChannelMsgRsp)
if err = proto.Unmarshal(rsp, msgRsp); err != nil { if err = proto.Unmarshal(rsp.Body, msgRsp); err != nil {
return nil, errors.Wrap(err, "failed to unmarshal protobuf message") return nil, errors.Wrap(err, "failed to unmarshal protobuf message")
} }
return msgRsp.ChannelMsg.Msgs, nil return msgRsp.ChannelMsg.Msgs, nil
} }
func (c *QQClient) buildGuildImageStorePacket(guildId, channelId uint64, hash []byte, size uint64) (uint16, []byte) { func (c *QQClient) buildGuildImageStorePacket(guildId, channelId uint64, hash []byte, size uint64) *network.Request {
payload, _ := proto.Marshal(&cmd0x388.D388ReqBody{ payload, _ := proto.Marshal(&cmd0x388.D388ReqBody{
NetType: proto.Uint32(3), NetType: proto.Uint32(3),
Subcmd: proto.Uint32(1), Subcmd: proto.Uint32(1),
@ -252,7 +246,7 @@ func (c *QQClient) buildGuildImageStorePacket(guildId, channelId uint64, hash []
}, },
CommandId: proto.Uint32(83), CommandId: proto.Uint32(83),
}) })
return c.uniPacket("ImgStore.QQMeetPicUp", payload) return c.uniRequest("ImgStore.QQMeetPicUp", payload, decodeGuildImageStoreResponse)
} }
func decodeGuildMessageEmojiReactions(content *channel.ChannelMsgContent) (r []*message.GuildMessageEmojiReaction) { func decodeGuildMessageEmojiReactions(content *channel.ChannelMsgContent) (r []*message.GuildMessageEmojiReaction) {
@ -291,9 +285,9 @@ func decodeGuildMessageEmojiReactions(content *channel.ChannelMsgContent) (r []*
return return
} }
func decodeGuildImageStoreResponse(_ *QQClient, _ *network.IncomingPacketInfo, payload []byte) (interface{}, error) { func decodeGuildImageStoreResponse(_ *QQClient, resp *network.Response) (interface{}, error) {
body := new(cmd0x388.D388RspBody) body := new(cmd0x388.D388RspBody)
if err := proto.Unmarshal(payload, body); err != nil { if err := proto.Unmarshal(resp.Body, body); err != nil {
return nil, errors.Wrap(err, "failed to unmarshal protobuf message") return nil, errors.Wrap(err, "failed to unmarshal protobuf message")
} }
if len(body.TryupImgRsp) == 0 { if len(body.TryupImgRsp) == 0 {
@ -349,13 +343,13 @@ func (s *GuildService) parseGuildChannelMessage(msg *channel.ChannelMsgContent)
} }
// PttCenterSvr.GroupShortVideoUpReq // PttCenterSvr.GroupShortVideoUpReq
func (c *QQClient) buildPttGuildVideoUpReq(videoHash, thumbHash []byte, guildId, channelId int64, videoSize, thumbSize int64) (uint16, []byte) { func (c *QQClient) buildPttGuildVideoUpReq(videoHash, thumbHash []byte, guildId, channelId int64, videoSize, thumbSize int64) *network.Request {
pb := c.buildPttGroupShortVideoProto(videoHash, thumbHash, guildId, videoSize, thumbSize, 4) pb := c.buildPttGroupShortVideoProto(videoHash, thumbHash, guildId, videoSize, thumbSize, 4)
pb.PttShortVideoUploadReq.BusinessType = 4601 pb.PttShortVideoUploadReq.BusinessType = 4601
pb.PttShortVideoUploadReq.ToUin = channelId pb.PttShortVideoUploadReq.ToUin = channelId
pb.ExtensionReq[0].SubBusiType = 4601 pb.ExtensionReq[0].SubBusiType = 4601
payload, _ := proto.Marshal(pb) payload, _ := proto.Marshal(pb)
return c.uniPacket("PttCenterSvr.GroupShortVideoUpReq", payload) return c.uniRequest("PttCenterSvr.GroupShortVideoUpReq", payload, decodeGroupShortVideoUploadResponse)
} }
func (c *QQClient) UploadGuildShortVideo(guildId, channelId uint64, video, thumb io.ReadSeeker) (*message.ShortVideoElement, error) { func (c *QQClient) UploadGuildShortVideo(guildId, channelId uint64, video, thumb io.ReadSeeker) (*message.ShortVideoElement, error) {
@ -367,7 +361,7 @@ func (c *QQClient) UploadGuildShortVideo(guildId, channelId uint64, video, thumb
pttWaiter.Wait(key) pttWaiter.Wait(key)
defer pttWaiter.Done(key) defer pttWaiter.Done(key)
i, err := c.sendAndWait(c.buildPttGuildVideoUpReq(videoHash, thumbHash, int64(guildId), int64(channelId), videoLen, thumbLen)) i, err := c.callAndDecode(c.buildPttGuildVideoUpReq(videoHash, thumbHash, int64(guildId), int64(channelId), videoLen, thumbLen))
if err != nil { if err != nil {
return nil, errors.Wrap(err, "upload req error") return nil, errors.Wrap(err, "upload req error")
} }

View File

@ -1,387 +0,0 @@
// Code generated by syncmap; DO NOT EDIT.
// Copyright 2016 The Go Authors. All rights reserved.
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.
package client
import (
"sync"
"sync/atomic"
"unsafe"
)
// Map is like a Go map[interface{}]interface{} but is safe for concurrent use
// by multiple goroutines without additional locking or coordination.
// Loads, stores, and deletes run in amortized constant time.
//
// The Map type is specialized. Most code should use a plain Go map instead,
// with separate locking or coordination, for better type safety and to make it
// easier to maintain other invariants along with the map content.
//
// The Map type is optimized for two common use cases: (1) when the entry for a given
// key is only ever written once but read many times, as in caches that only grow,
// or (2) when multiple goroutines read, write, and overwrite entries for disjoint
// sets of keys. In these two cases, use of a Map may significantly reduce lock
// contention compared to a Go map paired with a separate Mutex or RWMutex.
//
// The zero Map is empty and ready for use. A Map must not be copied after first use.
type HandlerMap struct {
mu sync.Mutex
// read contains the portion of the map's contents that are safe for
// concurrent access (with or without mu held).
//
// The read field itself is always safe to load, but must only be stored with
// mu held.
//
// Entries stored in read may be updated concurrently without mu, but updating
// a previously-expunged entry requires that the entry be copied to the dirty
// map and unexpunged with mu held.
read atomic.Value // readOnly
// dirty contains the portion of the map's contents that require mu to be
// held. To ensure that the dirty map can be promoted to the read map quickly,
// it also includes all of the non-expunged entries in the read map.
//
// Expunged entries are not stored in the dirty map. An expunged entry in the
// clean map must be unexpunged and added to the dirty map before a new value
// can be stored to it.
//
// If the dirty map is nil, the next write to the map will initialize it by
// making a shallow copy of the clean map, omitting stale entries.
dirty map[uint16]*entryHandlerMap
// misses counts the number of loads since the read map was last updated that
// needed to lock mu to determine whether the key was present.
//
// Once enough misses have occurred to cover the cost of copying the dirty
// map, the dirty map will be promoted to the read map (in the unamended
// state) and the next store to the map will make a new dirty copy.
misses int
}
// readOnly is an immutable struct stored atomically in the Map.read field.
type readOnlyHandlerMap struct {
m map[uint16]*entryHandlerMap
amended bool // true if the dirty map contains some key not in m.
}
// expunged is an arbitrary pointer that marks entries which have been deleted
// from the dirty map.
var expungedHandlerMap = unsafe.Pointer(new(*handlerInfo))
// An entry is a slot in the map corresponding to a particular key.
type entryHandlerMap struct {
// p points to the interface{} value stored for the entry.
//
// If p == nil, the entry has been deleted and m.dirty == nil.
//
// If p == expunged, the entry has been deleted, m.dirty != nil, and the entry
// is missing from m.dirty.
//
// Otherwise, the entry is valid and recorded in m.read.m[key] and, if m.dirty
// != nil, in m.dirty[key].
//
// An entry can be deleted by atomic replacement with nil: when m.dirty is
// next created, it will atomically replace nil with expunged and leave
// m.dirty[key] unset.
//
// An entry's associated value can be updated by atomic replacement, provided
// p != expunged. If p == expunged, an entry's associated value can be updated
// only after first setting m.dirty[key] = e so that lookups using the dirty
// map find the entry.
p unsafe.Pointer // *interface{}
}
func newEntryHandlerMap(i *handlerInfo) *entryHandlerMap {
return &entryHandlerMap{p: unsafe.Pointer(&i)}
}
// Load returns the value stored in the map for a key, or nil if no
// value is present.
// The ok result indicates whether value was found in the map.
func (m *HandlerMap) Load(key uint16) (value *handlerInfo, ok bool) {
read, _ := m.read.Load().(readOnlyHandlerMap)
e, ok := read.m[key]
if !ok && read.amended {
m.mu.Lock()
// Avoid reporting a spurious miss if m.dirty got promoted while we were
// blocked on m.mu. (If further loads of the same key will not miss, it's
// not worth copying the dirty map for this key.)
read, _ = m.read.Load().(readOnlyHandlerMap)
e, ok = read.m[key]
if !ok && read.amended {
e, ok = m.dirty[key]
// Regardless of whether the entry was present, record a miss: this key
// will take the slow path until the dirty map is promoted to the read
// map.
m.missLocked()
}
m.mu.Unlock()
}
if !ok {
return value, false
}
return e.load()
}
func (e *entryHandlerMap) load() (value *handlerInfo, ok bool) {
p := atomic.LoadPointer(&e.p)
if p == nil || p == expungedHandlerMap {
return value, false
}
return *(**handlerInfo)(p), true
}
// Store sets the value for a key.
func (m *HandlerMap) Store(key uint16, value *handlerInfo) {
read, _ := m.read.Load().(readOnlyHandlerMap)
if e, ok := read.m[key]; ok && e.tryStore(&value) {
return
}
m.mu.Lock()
read, _ = m.read.Load().(readOnlyHandlerMap)
if e, ok := read.m[key]; ok {
if e.unexpungeLocked() {
// The entry was previously expunged, which implies that there is a
// non-nil dirty map and this entry is not in it.
m.dirty[key] = e
}
e.storeLocked(&value)
} else if e, ok := m.dirty[key]; ok {
e.storeLocked(&value)
} else {
if !read.amended {
// We're adding the first new key to the dirty map.
// Make sure it is allocated and mark the read-only map as incomplete.
m.dirtyLocked()
m.read.Store(readOnlyHandlerMap{m: read.m, amended: true})
}
m.dirty[key] = newEntryHandlerMap(value)
}
m.mu.Unlock()
}
// tryStore stores a value if the entry has not been expunged.
//
// If the entry is expunged, tryStore returns false and leaves the entry
// unchanged.
func (e *entryHandlerMap) tryStore(i **handlerInfo) bool {
for {
p := atomic.LoadPointer(&e.p)
if p == expungedHandlerMap {
return false
}
if atomic.CompareAndSwapPointer(&e.p, p, unsafe.Pointer(i)) {
return true
}
}
}
// unexpungeLocked ensures that the entry is not marked as expunged.
//
// If the entry was previously expunged, it must be added to the dirty map
// before m.mu is unlocked.
func (e *entryHandlerMap) unexpungeLocked() (wasExpunged bool) {
return atomic.CompareAndSwapPointer(&e.p, expungedHandlerMap, nil)
}
// storeLocked unconditionally stores a value to the entry.
//
// The entry must be known not to be expunged.
func (e *entryHandlerMap) storeLocked(i **handlerInfo) {
atomic.StorePointer(&e.p, unsafe.Pointer(i))
}
// LoadOrStore returns the existing value for the key if present.
// Otherwise, it stores and returns the given value.
// The loaded result is true if the value was loaded, false if stored.
func (m *HandlerMap) LoadOrStore(key uint16, value *handlerInfo) (actual *handlerInfo, loaded bool) {
// Avoid locking if it's a clean hit.
read, _ := m.read.Load().(readOnlyHandlerMap)
if e, ok := read.m[key]; ok {
actual, loaded, ok := e.tryLoadOrStore(value)
if ok {
return actual, loaded
}
}
m.mu.Lock()
read, _ = m.read.Load().(readOnlyHandlerMap)
if e, ok := read.m[key]; ok {
if e.unexpungeLocked() {
m.dirty[key] = e
}
actual, loaded, _ = e.tryLoadOrStore(value)
} else if e, ok := m.dirty[key]; ok {
actual, loaded, _ = e.tryLoadOrStore(value)
m.missLocked()
} else {
if !read.amended {
// We're adding the first new key to the dirty map.
// Make sure it is allocated and mark the read-only map as incomplete.
m.dirtyLocked()
m.read.Store(readOnlyHandlerMap{m: read.m, amended: true})
}
m.dirty[key] = newEntryHandlerMap(value)
actual, loaded = value, false
}
m.mu.Unlock()
return actual, loaded
}
// tryLoadOrStore atomically loads or stores a value if the entry is not
// expunged.
//
// If the entry is expunged, tryLoadOrStore leaves the entry unchanged and
// returns with ok==false.
func (e *entryHandlerMap) tryLoadOrStore(i *handlerInfo) (actual *handlerInfo, loaded, ok bool) {
p := atomic.LoadPointer(&e.p)
if p == expungedHandlerMap {
return actual, false, false
}
if p != nil {
return *(**handlerInfo)(p), true, true
}
// Copy the interface after the first load to make this method more amenable
// to escape analysis: if we hit the "load" path or the entry is expunged, we
// shouldn't bother heap-allocating.
ic := i
for {
if atomic.CompareAndSwapPointer(&e.p, nil, unsafe.Pointer(&ic)) {
return i, false, true
}
p = atomic.LoadPointer(&e.p)
if p == expungedHandlerMap {
return actual, false, false
}
if p != nil {
return *(**handlerInfo)(p), true, true
}
}
}
// LoadAndDelete deletes the value for a key, returning the previous value if any.
// The loaded result reports whether the key was present.
func (m *HandlerMap) LoadAndDelete(key uint16) (value *handlerInfo, loaded bool) {
read, _ := m.read.Load().(readOnlyHandlerMap)
e, ok := read.m[key]
if !ok && read.amended {
m.mu.Lock()
read, _ = m.read.Load().(readOnlyHandlerMap)
e, ok = read.m[key]
if !ok && read.amended {
e, ok = m.dirty[key]
delete(m.dirty, key)
// Regardless of whether the entry was present, record a miss: this key
// will take the slow path until the dirty map is promoted to the read
// map.
m.missLocked()
}
m.mu.Unlock()
}
if ok {
return e.delete()
}
return value, false
}
// Delete deletes the value for a key.
func (m *HandlerMap) Delete(key uint16) {
m.LoadAndDelete(key)
}
func (e *entryHandlerMap) delete() (value *handlerInfo, ok bool) {
for {
p := atomic.LoadPointer(&e.p)
if p == nil || p == expungedHandlerMap {
return value, false
}
if atomic.CompareAndSwapPointer(&e.p, p, nil) {
return *(**handlerInfo)(p), true
}
}
}
// Range calls f sequentially for each key and value present in the map.
// If f returns false, range stops the iteration.
//
// Range does not necessarily correspond to any consistent snapshot of the Map's
// contents: no key will be visited more than once, but if the value for any key
// is stored or deleted concurrently, Range may reflect any mapping for that key
// from any point during the Range call.
//
// Range may be O(N) with the number of elements in the map even if f returns
// false after a constant number of calls.
func (m *HandlerMap) Range(f func(key uint16, value *handlerInfo) bool) {
// We need to be able to iterate over all of the keys that were already
// present at the start of the call to Range.
// If read.amended is false, then read.m satisfies that property without
// requiring us to hold m.mu for a long time.
read, _ := m.read.Load().(readOnlyHandlerMap)
if read.amended {
// m.dirty contains keys not in read.m. Fortunately, Range is already O(N)
// (assuming the caller does not break out early), so a call to Range
// amortizes an entire copy of the map: we can promote the dirty copy
// immediately!
m.mu.Lock()
read, _ = m.read.Load().(readOnlyHandlerMap)
if read.amended {
read = readOnlyHandlerMap{m: m.dirty}
m.read.Store(read)
m.dirty = nil
m.misses = 0
}
m.mu.Unlock()
}
for k, e := range read.m {
v, ok := e.load()
if !ok {
continue
}
if !f(k, v) {
break
}
}
}
func (m *HandlerMap) missLocked() {
m.misses++
if m.misses < len(m.dirty) {
return
}
m.read.Store(readOnlyHandlerMap{m: m.dirty})
m.dirty = nil
m.misses = 0
}
func (m *HandlerMap) dirtyLocked() {
if m.dirty != nil {
return
}
read, _ := m.read.Load().(readOnlyHandlerMap)
m.dirty = make(map[uint16]*entryHandlerMap, len(read.m))
for k, e := range read.m {
if !e.tryExpungeLocked() {
m.dirty[k] = e
}
}
}
func (e *entryHandlerMap) tryExpungeLocked() (isExpunged bool) {
p := atomic.LoadPointer(&e.p)
for p == nil {
if atomic.CompareAndSwapPointer(&e.p, nil, expungedHandlerMap) {
return true
}
p = atomic.LoadPointer(&e.p)
}
return p == expungedHandlerMap
}

View File

@ -23,12 +23,6 @@ import (
"github.com/Mrs4s/MiraiGo/utils" "github.com/Mrs4s/MiraiGo/utils"
) )
func init() {
decoders["ImgStore.GroupPicUp"] = decodeGroupImageStoreResponse
decoders["ImgStore.GroupPicDown"] = decodeGroupImageDownloadResponse
decoders["OidbSvc.0xe07_0"] = decodeImageOcrResponse
}
var imgWaiter = utils.NewUploadWaiter() var imgWaiter = utils.NewUploadWaiter()
type imageUploadResponse struct { type imageUploadResponse struct {
@ -53,8 +47,8 @@ func (c *QQClient) UploadGroupImage(groupCode int64, img io.ReadSeeker) (*messag
imgWaiter.Wait(key) imgWaiter.Wait(key)
defer imgWaiter.Done(key) defer imgWaiter.Done(key)
seq, pkt := c.buildGroupImageStorePacket(groupCode, fh, int32(length)) req := c.buildGroupImageStoreRequest(groupCode, fh, int32(length))
r, err := c.sendAndWait(seq, pkt) r, err := c.callAndDecode(req)
if err != nil { if err != nil {
return nil, err return nil, err
} }
@ -102,8 +96,8 @@ func (c *QQClient) UploadGroupImageByFile(groupCode int64, path string) (*messag
imgWaiter.Wait(key) imgWaiter.Wait(key)
defer imgWaiter.Done(key) defer imgWaiter.Done(key)
seq, pkt := c.buildGroupImageStorePacket(groupCode, fh, int32(length)) req := c.buildGroupImageStoreRequest(groupCode, fh, int32(length))
r, err := c.sendAndWait(seq, pkt) r, err := c.callAndDecode(req)
if err != nil { if err != nil {
return nil, err return nil, err
} }
@ -145,7 +139,7 @@ func (c *QQClient) UploadPrivateImage(target int64, img io.ReadSeeker) (*message
} }
func (c *QQClient) GetGroupImageDownloadUrl(fileId, groupCode int64, fileMd5 []byte) (string, error) { func (c *QQClient) GetGroupImageDownloadUrl(fileId, groupCode int64, fileMd5 []byte) (string, error) {
i, err := c.sendAndWait(c.buildGroupImageDownloadPacket(fileId, groupCode, fileMd5)) i, err := c.callAndDecode(c.buildGroupImageDownloadRequest(fileId, groupCode, fileMd5))
if err != nil { if err != nil {
return "", err return "", err
} }
@ -185,7 +179,8 @@ func (c *QQClient) ImageOcr(img interface{}) (*OcrResponse, error) {
} }
_ = b.Close() _ = b.Close()
} }
rsp, err := c.sendAndWait(c.buildImageOcrRequestPacket(url, strings.ToUpper(hex.EncodeToString(e.Md5)), e.Size, e.Width, e.Height)) call := c.buildImageOcrRequestPacket(url, strings.ToUpper(hex.EncodeToString(e.Md5)), e.Size, e.Width, e.Height)
rsp, err := c.callAndDecode(call)
if err != nil { if err != nil {
return nil, err return nil, err
} }
@ -195,7 +190,7 @@ func (c *QQClient) ImageOcr(img interface{}) (*OcrResponse, error) {
} }
func (c *QQClient) QueryGroupImage(groupCode int64, hash []byte, size int32) (*message.GroupImageElement, error) { func (c *QQClient) QueryGroupImage(groupCode int64, hash []byte, size int32) (*message.GroupImageElement, error) {
r, err := c.sendAndWait(c.buildGroupImageStorePacket(groupCode, hash, size)) r, err := c.callAndDecode(c.buildGroupImageStoreRequest(groupCode, hash, size))
if err != nil { if err != nil {
return nil, err return nil, err
} }
@ -210,7 +205,7 @@ func (c *QQClient) QueryGroupImage(groupCode int64, hash []byte, size int32) (*m
} }
func (c *QQClient) QueryFriendImage(target int64, hash []byte, size int32) (*message.FriendImageElement, error) { func (c *QQClient) QueryFriendImage(target int64, hash []byte, size int32) (*message.FriendImageElement, error) {
i, err := c.sendAndWait(c.buildOffPicUpPacket(target, hash, size)) i, err := c.callAndDecode(c.buildOffPicUpRequest(target, hash, size))
if err != nil { if err != nil {
return nil, err return nil, err
} }
@ -233,7 +228,7 @@ func (c *QQClient) QueryFriendImage(target int64, hash []byte, size int32) (*mes
} }
// ImgStore.GroupPicUp // ImgStore.GroupPicUp
func (c *QQClient) buildGroupImageStorePacket(groupCode int64, md5 []byte, size int32) (uint16, []byte) { func (c *QQClient) buildGroupImageStoreRequest(groupCode int64, md5 []byte, size int32) *network.Request {
name := utils.RandomString(16) + ".gif" name := utils.RandomString(16) + ".gif"
req := &cmd0x388.D388ReqBody{ req := &cmd0x388.D388ReqBody{
NetType: proto.Uint32(3), NetType: proto.Uint32(3),
@ -258,10 +253,10 @@ func (c *QQClient) buildGroupImageStorePacket(groupCode int64, md5 []byte, size
Extension: EmptyBytes, Extension: EmptyBytes,
} }
payload, _ := proto.Marshal(req) payload, _ := proto.Marshal(req)
return c.uniPacket("ImgStore.GroupPicUp", payload) return c.uniRequest("ImgStore.GroupPicUp", payload, decodeGroupImageStoreResponse)
} }
func (c *QQClient) buildGroupImageDownloadPacket(fileId, groupCode int64, fileMd5 []byte) (uint16, []byte) { func (c *QQClient) buildGroupImageDownloadRequest(fileId, groupCode int64, fileMd5 []byte) *network.Request {
req := &cmd0x388.D388ReqBody{ req := &cmd0x388.D388ReqBody{
NetType: proto.Uint32(3), NetType: proto.Uint32(3),
Subcmd: proto.Uint32(2), Subcmd: proto.Uint32(2),
@ -282,7 +277,7 @@ func (c *QQClient) buildGroupImageDownloadPacket(fileId, groupCode int64, fileMd
}, },
} }
payload, _ := proto.Marshal(req) payload, _ := proto.Marshal(req)
return c.uniPacket("ImgStore.GroupPicDown", payload) return c.uniRequest("ImgStore.GroupPicDown", payload, decodeGroupImageDownloadResponse)
} }
func (c *QQClient) uploadOcrImage(img io.Reader) (string, error) { func (c *QQClient) uploadOcrImage(img io.Reader) (string, error) {
@ -312,7 +307,7 @@ func (c *QQClient) uploadOcrImage(img io.Reader) (string, error) {
} }
// OidbSvc.0xe07_0 // OidbSvc.0xe07_0
func (c *QQClient) buildImageOcrRequestPacket(url, md5 string, size, weight, height int32) (uint16, []byte) { func (c *QQClient) buildImageOcrRequestPacket(url, md5 string, size, weight, height int32) *network.Request {
body := &oidb.DE07ReqBody{ body := &oidb.DE07ReqBody{
Version: 1, Version: 1,
Entrance: 3, Entrance: 3,
@ -328,13 +323,13 @@ func (c *QQClient) buildImageOcrRequestPacket(url, md5 string, size, weight, hei
} }
b, _ := proto.Marshal(body) b, _ := proto.Marshal(body)
payload := c.packOIDBPackage(3591, 0, b) payload := c.packOIDBPackage(3591, 0, b)
return c.uniPacket("OidbSvc.0xe07_0", payload) return c.uniRequest("OidbSvc.0xe07_0", payload, decodeImageOcrResponse)
} }
// ImgStore.GroupPicUp // ImgStore.GroupPicUp
func decodeGroupImageStoreResponse(_ *QQClient, _ *network.IncomingPacketInfo, payload []byte) (interface{}, error) { func decodeGroupImageStoreResponse(_ *QQClient, resp *network.Response) (interface{}, error) {
pkt := cmd0x388.D388RspBody{} pkt := cmd0x388.D388RspBody{}
err := proto.Unmarshal(payload, &pkt) err := proto.Unmarshal(resp.Body, &pkt)
if err != nil { if err != nil {
return nil, errors.Wrap(err, "failed to unmarshal protobuf message") return nil, errors.Wrap(err, "failed to unmarshal protobuf message")
} }
@ -359,9 +354,9 @@ func decodeGroupImageStoreResponse(_ *QQClient, _ *network.IncomingPacketInfo, p
}, nil }, nil
} }
func decodeGroupImageDownloadResponse(_ *QQClient, _ *network.IncomingPacketInfo, payload []byte) (interface{}, error) { func decodeGroupImageDownloadResponse(_ *QQClient, resp *network.Response) (interface{}, error) {
pkt := cmd0x388.D388RspBody{} pkt := cmd0x388.D388RspBody{}
if err := proto.Unmarshal(payload, &pkt); err != nil { if err := proto.Unmarshal(resp.Body, &pkt); err != nil {
return nil, errors.Wrap(err, "unmarshal protobuf message error") return nil, errors.Wrap(err, "unmarshal protobuf message error")
} }
if len(pkt.GetimgUrlRsp) == 0 { if len(pkt.GetimgUrlRsp) == 0 {
@ -374,10 +369,10 @@ func decodeGroupImageDownloadResponse(_ *QQClient, _ *network.IncomingPacketInfo
} }
// OidbSvc.0xe07_0 // OidbSvc.0xe07_0
func decodeImageOcrResponse(_ *QQClient, _ *network.IncomingPacketInfo, payload []byte) (interface{}, error) { func decodeImageOcrResponse(_ *QQClient, resp *network.Response) (interface{}, error) {
pkg := oidb.OIDBSSOPkg{} pkg := oidb.OIDBSSOPkg{}
rsp := oidb.DE07RspBody{} rsp := oidb.DE07RspBody{}
if err := proto.Unmarshal(payload, &pkg); err != nil { if err := proto.Unmarshal(resp.Body, &pkg); err != nil {
return nil, errors.Wrap(err, "failed to unmarshal protobuf message") return nil, errors.Wrap(err, "failed to unmarshal protobuf message")
} }
if err := proto.Unmarshal(pkg.Bodybuffer, &rsp); err != nil { if err := proto.Unmarshal(pkg.Bodybuffer, &rsp); err != nil {

View File

@ -5,33 +5,40 @@ import (
"io" "io"
"net" "net"
"sync" "sync"
"sync/atomic"
"unsafe"
"github.com/pkg/errors" "github.com/pkg/errors"
) )
type TCPListener struct { type TCPListener struct {
lock sync.RWMutex //lock sync.RWMutex
conn net.Conn conn *net.TCPConn
connected bool //connected bool
plannedDisconnect func(*TCPListener)
unexpectedDisconnect func(*TCPListener, error)
}
var ErrConnectionClosed = errors.New("connection closed")
// PlannedDisconnect 预料中的断开连接 // PlannedDisconnect 预料中的断开连接
// 如调用 Close() Connect() // 如调用 Close() Connect()
func (t *TCPListener) PlannedDisconnect(f func(*TCPListener)) { PlannedDisconnect func(*TCPListener)
t.lock.Lock()
defer t.lock.Unlock()
t.plannedDisconnect = f
}
// UnexpectedDisconnect 未预料的断开连接 // UnexpectedDisconnect 未预料的断开连接
func (t *TCPListener) UnexpectedDisconnect(f func(*TCPListener, error)) { UnexpectedDisconnect func(*TCPListener, error)
t.lock.Lock() }
defer t.lock.Unlock()
t.unexpectedDisconnect = f func (t *TCPListener) getConn() *net.TCPConn {
return (*net.TCPConn)(atomic.LoadPointer((*unsafe.Pointer)(unsafe.Pointer(&t.conn))))
}
func (t *TCPListener) setConn(conn *net.TCPConn) (swapped bool) {
return atomic.CompareAndSwapPointer((*unsafe.Pointer)(unsafe.Pointer(&t.conn)), unsafe.Pointer(nil), unsafe.Pointer(conn))
}
func (t *TCPListener) closeConn() *net.TCPConn {
return (*net.TCPConn)(atomic.SwapPointer((*unsafe.Pointer)(unsafe.Pointer(&t.conn)), unsafe.Pointer(nil)))
}
func (t *TCPListener) Connected() bool {
// 等同于 t.getConn() != nil (? copilot写的)
return t.getConn() != nil
} }
func (t *TCPListener) Connect(addr *net.TCPAddr) error { func (t *TCPListener) Connect(addr *net.TCPAddr) error {
@ -40,24 +47,59 @@ func (t *TCPListener) Connect(addr *net.TCPAddr) error {
if err != nil { if err != nil {
return errors.Wrap(err, "dial tcp error") return errors.Wrap(err, "dial tcp error")
} }
t.lock.Lock() t.setConn(conn)
defer t.lock.Unlock() //t.lock.Lock()
t.conn = conn //defer t.lock.Unlock()
t.connected = true //t.conn = conn
return nil return nil
} }
// ConnectFastest 连接到最快的服务器
// TODO 禁用不可用服务器
func (t *TCPListener) ConnectFastest(addr []*net.TCPAddr) (*net.TCPAddr, error) {
ch := make(chan error)
wg := sync.WaitGroup{}
wg.Add(len(addr))
for _, remote := range addr {
go func(remote *net.TCPAddr) {
defer wg.Done()
conn, err := net.DialTCP("tcp", nil, remote)
if err != nil {
return
}
//addrs = append(addrs, remote)
if !t.setConn(conn) {
_ = conn.Close()
return
}
ch <- nil
}(remote)
}
go func() {
wg.Wait()
if t.getConn() == nil {
ch <- errors.New("All addr are unreachable")
}
}()
err := <-ch
if err != nil {
return nil, err
}
conn := t.getConn()
return conn.RemoteAddr().(*net.TCPAddr), nil
}
func (t *TCPListener) Write(buf []byte) error { func (t *TCPListener) Write(buf []byte) error {
if conn := t.getConn(); conn != nil { if conn := t.getConn(); conn != nil {
_, err := conn.Write(buf) _, err := conn.Write(buf)
if err != nil { if err != nil {
t.unexpectedClose(err) t.unexpectedClose(err)
return ErrConnectionClosed return ErrConnectionBroken
} }
return nil return nil
} }
return ErrConnectionClosed return ErrConnectionBroken
} }
func (t *TCPListener) ReadBytes(len int) ([]byte, error) { func (t *TCPListener) ReadBytes(len int) ([]byte, error) {
@ -67,12 +109,12 @@ func (t *TCPListener) ReadBytes(len int) ([]byte, error) {
if err != nil { if err != nil {
// time.Sleep(time.Millisecond * 100) // 服务器会发送offline包后立即断开连接, 此时还没解析, 可能还是得加锁 // time.Sleep(time.Millisecond * 100) // 服务器会发送offline包后立即断开连接, 此时还没解析, 可能还是得加锁
t.unexpectedClose(err) t.unexpectedClose(err)
return nil, ErrConnectionClosed return nil, ErrConnectionBroken
} }
return buf, nil return buf, nil
} }
return nil, ErrConnectionClosed return nil, ErrConnectionBroken
} }
func (t *TCPListener) ReadInt32() (int32, error) { func (t *TCPListener) ReadInt32() (int32, error) {
@ -94,34 +136,37 @@ func (t *TCPListener) unexpectedClose(err error) {
} }
func (t *TCPListener) close() { func (t *TCPListener) close() {
t.lock.Lock() if conn := t.closeConn(); conn != nil {
defer t.lock.Unlock() _ = conn.Close()
if t.conn != nil {
_ = t.conn.Close()
t.conn = nil
} }
} }
func (t *TCPListener) invokePlannedDisconnect() { func (t *TCPListener) invokePlannedDisconnect() {
t.lock.RLock() //if t.Connected() {
defer t.lock.RUnlock() t.PlannedDisconnect(t)
if t.plannedDisconnect != nil && t.connected { //}
go t.plannedDisconnect(t) //t.lock.RLock()
t.connected = false //defer t.lock.RUnlock()
} //if t.plannedDisconnect != nil && t.connected {
// go t.plannedDisconnect(t)
// t.connected = false
//}
} }
func (t *TCPListener) invokeUnexpectedDisconnect(err error) { func (t *TCPListener) invokeUnexpectedDisconnect(err error) {
t.lock.RLock() //if t.Connected() {
defer t.lock.RUnlock() t.UnexpectedDisconnect(t, err)
if t.unexpectedDisconnect != nil && t.connected { //}
go t.unexpectedDisconnect(t, err) //t.lock.RLock()
t.connected = false //defer t.lock.RUnlock()
} //if t.unexpectedDisconnect != nil && t.connected {
// go t.unexpectedDisconnect(t, err)
// t.connected = false
//}
} }
func (t *TCPListener) getConn() net.Conn { //func (t *TCPListener) getConn() net.Conn {
t.lock.RLock() // t.lock.RLock()
defer t.lock.RUnlock() // defer t.lock.RUnlock()
return t.conn // return t.conn
} //}

View File

@ -1,31 +0,0 @@
package network
type IncomingPacketInfo struct {
CommandName string
SequenceId uint16
Params RequestParams
}
type RequestParams map[string]interface{}
func (p RequestParams) Bool(k string) bool {
if p == nil {
return false
}
i, ok := p[k]
if !ok {
return false
}
return i.(bool)
}
func (p RequestParams) Int32(k string) int32 {
if p == nil {
return 0
}
i, ok := p[k]
if !ok {
return 0
}
return i.(int32)
}

View File

@ -24,4 +24,7 @@ type Request struct {
Uin int64 Uin int64
CommandName string CommandName string
Body []byte Body []byte
Params Params
Decode func(*Response) (interface{}, error) // callAndDecode use this function to decode response
} }

View File

@ -9,38 +9,41 @@ import (
) )
type Response struct { type Response struct {
Type RequestType
EncryptType EncryptType
SequenceID int32 SequenceID int32
Uin int64
CommandName string CommandName string
Body []byte Body []byte
Message string
// Request is the original request that obtained this response. // Request is the original request that obtained this response.
// Request *Request Request *Request
}
func (r *Response) Params() Params {
if r.Request == nil {
return nil
}
return r.Request.Params
} }
var ( var (
ErrSessionExpired = errors.New("session expired") ErrSessionExpired = errors.New("session expired")
ErrPacketDropped = errors.New("packet dropped") ErrPacketDropped = errors.New("packet dropped")
ErrInvalidPacketType = errors.New("invalid packet type") ErrInvalidPacketType = errors.New("invalid packet type")
ErrConnectionBroken = errors.New("connection broken")
) )
func (t *Transport) ReadResponse(head []byte) (*Response, error) { func (t *Transport) ReadRequest(head []byte) (*Request, error) {
resp := new(Response) req := new(Request)
r := binary.NewReader(head) r := binary.NewReader(head)
resp.Type = RequestType(r.ReadInt32()) req.Type = RequestType(r.ReadInt32())
if resp.Type != RequestTypeLogin && resp.Type != RequestTypeSimple { if req.Type != RequestTypeLogin && req.Type != RequestTypeSimple {
return resp, ErrInvalidPacketType return req, ErrInvalidPacketType
} }
resp.EncryptType = EncryptType(r.ReadByte()) req.EncryptType = EncryptType(r.ReadByte())
_ = r.ReadByte() // 0x00? _ = r.ReadByte() // 0x00?
resp.Uin, _ = strconv.ParseInt(r.ReadString(), 10, 64) req.Uin, _ = strconv.ParseInt(r.ReadString(), 10, 64)
body := r.ReadAvailable() body := r.ReadAvailable()
switch resp.EncryptType { switch req.EncryptType {
case EncryptTypeNoEncrypt: case EncryptTypeNoEncrypt:
// nothing to do // nothing to do
case EncryptTypeD2Key: case EncryptTypeD2Key:
@ -48,11 +51,11 @@ func (t *Transport) ReadResponse(head []byte) (*Response, error) {
case EncryptTypeEmptyKey: case EncryptTypeEmptyKey:
body = binary.NewTeaCipher(emptyKey).Decrypt(body) body = binary.NewTeaCipher(emptyKey).Decrypt(body)
} }
err := t.readSSOFrame(resp, body) err := t.readSSOFrame(req, body)
return resp, err return req, err
} }
func (t *Transport) readSSOFrame(resp *Response, payload []byte) error { func (t *Transport) readSSOFrame(req *Request, payload []byte) error {
reader := binary.NewReader(payload) reader := binary.NewReader(payload)
headLen := reader.ReadInt32() headLen := reader.ReadInt32()
if headLen-4 > int32(reader.Len()) { if headLen-4 > int32(reader.Len()) {
@ -60,18 +63,19 @@ func (t *Transport) readSSOFrame(resp *Response, payload []byte) error {
} }
head := binary.NewReader(reader.ReadBytes(int(headLen) - 4)) head := binary.NewReader(reader.ReadBytes(int(headLen) - 4))
resp.SequenceID = head.ReadInt32() req.SequenceID = head.ReadInt32()
switch retCode := head.ReadInt32(); retCode { retCode := head.ReadInt32()
message := head.ReadString()
switch retCode {
case 0: case 0:
// ok // ok
case -10008: case -10008:
return errors.WithStack(ErrSessionExpired) return errors.WithMessage(ErrSessionExpired, message)
default: default:
return errors.Errorf("return code unsuccessful: %d", retCode) return errors.Errorf("return code unsuccessful: %d message: %s", retCode, message)
} }
resp.Message = head.ReadString() req.CommandName = head.ReadString()
resp.CommandName = head.ReadString() if req.CommandName == "Heartbeat.Alive" {
if resp.CommandName == "Heartbeat.Alive" {
return nil return nil
} }
_ = head.ReadInt32Bytes() // session id _ = head.ReadInt32Bytes() // session id
@ -87,6 +91,6 @@ func (t *Transport) readSSOFrame(resp *Response, payload []byte) error {
case 1: case 1:
body = binary.ZlibUncompress(body) body = binary.ZlibUncompress(body)
} }
resp.Body = body req.Body = body
return nil return nil
} }

View File

@ -0,0 +1,34 @@
package network
// Call is a client-side RPC call.
// refer to `net/rpc`
type Call struct {
Request *Request
Response *Response
Err error
Done chan *Call
}
type Params map[string]interface{}
func (p Params) Bool(k string) bool {
if p == nil {
return false
}
i, ok := p[k]
if !ok {
return false
}
return i.(bool)
}
func (p Params) Int32(k string) int32 {
if p == nil {
return 0
}
i, ok := p[k]
if !ok {
return 0
}
return i.(int32)
}

View File

@ -1,22 +1,73 @@
package network package network
import ( import (
goBinary "encoding/binary"
"fmt"
"io"
"net"
"strconv" "strconv"
"sync" "sync"
"github.com/pkg/errors"
"github.com/Mrs4s/MiraiGo/binary" "github.com/Mrs4s/MiraiGo/binary"
"github.com/Mrs4s/MiraiGo/client/internal/auth" "github.com/Mrs4s/MiraiGo/client/internal/auth"
) )
// Transport is a network transport. // Transport is a network transport.
type Transport struct { type Transport struct {
sessionMu sync.Mutex // sessionMu sync.Mutex
Sig *auth.SigInfo Sig *auth.SigInfo
Version *auth.AppVersion Version *auth.AppVersion
Device *auth.Device Device *auth.Device
// connection // connection
// conn *TCPListener connMu sync.Mutex
servers []*net.TCPAddr
curServerAddr *net.TCPAddr
conn TCPListener
}
func (t *Transport) AddServerAddr(addr *net.TCPAddr) {
t.connMu.Lock()
defer t.connMu.Unlock()
t.servers = append(t.servers, addr)
}
func (t *Transport) GetServerAddr() *net.TCPAddr {
t.connMu.Lock()
defer t.connMu.Unlock()
return t.curServerAddr
}
func (t *Transport) ServerCount() int {
t.connMu.Lock()
defer t.connMu.Unlock()
return len(t.servers)
}
func (t *Transport) PlannedDisconnect(fun func(*TCPListener)) {
t.conn.PlannedDisconnect = fun
}
func (t *Transport) UnexpectedDisconnect(fun func(*TCPListener, error)) {
t.conn.UnexpectedDisconnect = fun
}
func (t *Transport) ConnectFastest() (chosen *net.TCPAddr, err error) {
t.connMu.Lock()
defer t.connMu.Unlock()
chosen, err = t.conn.ConnectFastest(t.servers)
t.curServerAddr = chosen
return
}
func (t *Transport) Close() {
t.conn.Close()
}
func (t *Transport) Write(data []byte) error {
return t.conn.Write(data)
} }
func (t *Transport) packBody(req *Request, w *binary.Writer) { func (t *Transport) packBody(req *Request, w *binary.Writer) {
@ -97,3 +148,59 @@ func (t *Transport) PackPacket(req *Request) []byte {
w.WriteUInt32At(pos, uint32(w.Len())) w.WriteUInt32At(pos, uint32(w.Len()))
return append([]byte(nil), w.Bytes()...) return append([]byte(nil), w.Bytes()...)
} }
type PktHandler func(pkt *Request, netErr error)
type RequestHandler func(head []byte) (*Request, error)
func (t *Transport) NetLoop(pktHandler PktHandler, respHandler RequestHandler) {
go t.netLoop(pktHandler, respHandler)
}
// readPacket 帮助函数(Helper function)
func readPacket(conn *net.TCPConn, minSize, maxSize uint32) ([]byte, error) {
lBuf := make([]byte, 4)
_, err := io.ReadFull(conn, lBuf)
if err != nil {
return nil, err
}
l := goBinary.BigEndian.Uint32(lBuf)
if l < minSize || l > maxSize {
return nil, fmt.Errorf("parse incoming packet error: invalid packet length %v", l)
}
data := make([]byte, l-4)
_, err = io.ReadFull(conn, data)
return data, err
}
// netLoop 整个函数周期使用同一个连接,确保不会发生串线这种奇怪的事情
func (t *Transport) netLoop(pktHandler PktHandler, respHandler RequestHandler) {
conn := t.conn.getConn()
defer func() {
if r := recover(); r != nil {
pktHandler(nil, fmt.Errorf("panic: %v", r))
}
t.conn.Close()
}()
errCount := 0
for {
data, err := readPacket(conn, 4, 10<<20) // max 10MB
if err != nil {
// 在且仅在没有新连接建立时断线才被认为是意外的
if t.conn.getConn() == conn {
pktHandler(nil, errors.Wrap(ErrConnectionBroken, err.Error()))
}
return
}
req, err := respHandler(data)
if err == nil {
errCount = 0
goto ok
}
errCount++
if errCount > 2 {
err = errors.Wrap(ErrConnectionBroken, err.Error())
}
ok:
go pktHandler(req, err)
}
}

View File

@ -17,13 +17,8 @@ import (
"github.com/Mrs4s/MiraiGo/utils" "github.com/Mrs4s/MiraiGo/utils"
) )
func init() {
decoders["MultiMsg.ApplyUp"] = decodeMultiApplyUpResponse
decoders["MultiMsg.ApplyDown"] = decodeMultiApplyDownResponse
}
// MultiMsg.ApplyUp // MultiMsg.ApplyUp
func (c *QQClient) buildMultiApplyUpPacket(data, hash []byte, buType int32, groupUin int64) (uint16, []byte) { func (c *QQClient) buildMultiApplyUpPacket(data, hash []byte, buType int32, groupUin int64) *network.Request {
req := &multimsg.MultiReqBody{ req := &multimsg.MultiReqBody{
Subcmd: 1, Subcmd: 1,
TermType: 5, TermType: 5,
@ -41,13 +36,13 @@ func (c *QQClient) buildMultiApplyUpPacket(data, hash []byte, buType int32, grou
BuType: buType, BuType: buType,
} }
payload, _ := proto.Marshal(req) payload, _ := proto.Marshal(req)
return c.uniPacket("MultiMsg.ApplyUp", payload) return c.uniRequest("MultiMsg.ApplyUp", payload, decodeMultiApplyUpResponse)
} }
// MultiMsg.ApplyUp // MultiMsg.ApplyUp
func decodeMultiApplyUpResponse(_ *QQClient, _ *network.IncomingPacketInfo, payload []byte) (interface{}, error) { func decodeMultiApplyUpResponse(_ *QQClient, resp *network.Response) (interface{}, error) {
body := multimsg.MultiRspBody{} body := multimsg.MultiRspBody{}
if err := proto.Unmarshal(payload, &body); err != nil { if err := proto.Unmarshal(resp.Body, &body); err != nil {
return nil, errors.Wrap(err, "failed to unmarshal protobuf message") return nil, errors.Wrap(err, "failed to unmarshal protobuf message")
} }
if len(body.MultimsgApplyupRsp) == 0 { if len(body.MultimsgApplyupRsp) == 0 {
@ -64,7 +59,7 @@ func decodeMultiApplyUpResponse(_ *QQClient, _ *network.IncomingPacketInfo, payl
} }
// MultiMsg.ApplyDown // MultiMsg.ApplyDown
func (c *QQClient) buildMultiApplyDownPacket(resID string) (uint16, []byte) { func (c *QQClient) buildMultiApplyDownPacket(resID string) *network.Request {
req := &multimsg.MultiReqBody{ req := &multimsg.MultiReqBody{
Subcmd: 2, Subcmd: 2,
TermType: 5, TermType: 5,
@ -81,13 +76,13 @@ func (c *QQClient) buildMultiApplyDownPacket(resID string) (uint16, []byte) {
ReqChannelType: 2, ReqChannelType: 2,
} }
payload, _ := proto.Marshal(req) payload, _ := proto.Marshal(req)
return c.uniPacket("MultiMsg.ApplyDown", payload) return c.uniRequest("MultiMsg.ApplyDown", payload, decodeMultiApplyDownResponse)
} }
// MultiMsg.ApplyDown // MultiMsg.ApplyDown
func decodeMultiApplyDownResponse(_ *QQClient, _ *network.IncomingPacketInfo, payload []byte) (interface{}, error) { func decodeMultiApplyDownResponse(_ *QQClient, resp *network.Response) (interface{}, error) {
body := multimsg.MultiRspBody{} body := multimsg.MultiRspBody{}
if err := proto.Unmarshal(payload, &body); err != nil { if err := proto.Unmarshal(resp.Body, &body); err != nil {
return nil, errors.Wrap(err, "failed to unmarshal protobuf message") return nil, errors.Wrap(err, "failed to unmarshal protobuf message")
} }
if len(body.MultimsgApplydownRsp) == 0 { if len(body.MultimsgApplydownRsp) == 0 {
@ -182,7 +177,7 @@ func (c *QQClient) GetForwardMessage(resID string) *message.ForwardMessage {
} }
func (c *QQClient) DownloadForwardMessage(resId string) *message.ForwardElement { func (c *QQClient) DownloadForwardMessage(resId string) *message.ForwardElement {
i, err := c.sendAndWait(c.buildMultiApplyDownPacket(resId)) i, err := c.callAndDecode(c.buildMultiApplyDownPacket(resId))
if err != nil { if err != nil {
return nil return nil
} }

View File

@ -6,12 +6,12 @@ import (
"sync" "sync"
"time" "time"
"github.com/Mrs4s/MiraiGo/message"
"github.com/pkg/errors" "github.com/pkg/errors"
"github.com/Mrs4s/MiraiGo/client/internal/network" "github.com/Mrs4s/MiraiGo/client/internal/network"
"github.com/Mrs4s/MiraiGo/client/internal/oicq" "github.com/Mrs4s/MiraiGo/client/internal/oicq"
"github.com/Mrs4s/MiraiGo/internal/packets"
"github.com/Mrs4s/MiraiGo/message"
"github.com/Mrs4s/MiraiGo/utils" "github.com/Mrs4s/MiraiGo/utils"
) )
@ -44,7 +44,7 @@ func (c *QQClient) ConnectionQualityTest() *ConnectionQualityInfo {
defer wg.Done() defer wg.Done()
var err error var err error
if r.ChatServerLatency, err = qualityTest(c.servers[c.currServerIndex].String()); err != nil { if r.ChatServerLatency, err = qualityTest(c.transport.GetServerAddr().String()); err != nil {
c.Error("test chat server latency error: %v", err) c.Error("test chat server latency error: %v", err)
r.ChatServerLatency = 9999 r.ChatServerLatency = 9999
} }
@ -67,7 +67,7 @@ func (c *QQClient) ConnectionQualityTest() *ConnectionQualityInfo {
}() }()
go func() { go func() {
defer wg.Done() defer wg.Done()
res := utils.RunTCPPingLoop(c.servers[c.currServerIndex].String(), 10) res := utils.RunTCPPingLoop(c.transport.GetServerAddr().String(), 10)
r.ChatServerPacketLoss = res.PacketsLoss r.ChatServerPacketLoss = res.PacketsLoss
if c.highwaySession.AddrLength() > 0 { if c.highwaySession.AddrLength() > 0 {
res = utils.RunTCPPingLoop(c.highwaySession.SsoAddr[0].String(), 10) res = utils.RunTCPPingLoop(c.highwaySession.SsoAddr[0].String(), 10)
@ -85,22 +85,21 @@ func (c *QQClient) ConnectionQualityTest() *ConnectionQualityInfo {
return r return r
} }
// connect 连接到 QQClient.servers 中的服务器 func (c *QQClient) connectFastest() error {
func (c *QQClient) connect() error { c.Disconnect()
c.Info("connect to server: %v", c.servers[c.currServerIndex].String()) addr, err := c.transport.ConnectFastest()
err := c.TCP.Connect(c.servers[c.currServerIndex])
c.currServerIndex++
if c.currServerIndex == len(c.servers) {
c.currServerIndex = 0
}
if err != nil { if err != nil {
c.retryTimes++ c.Disconnect()
if c.retryTimes > len(c.servers) {
return errors.New("All servers are unreachable")
}
c.Error("connect server error: %v", err)
return err return err
} }
c.Debug("connected to server: %v [fastest]", addr.String())
c.transport.NetLoop(c.pktProc, c.transport.ReadRequest)
c.ConnectTime = time.Now()
return nil
}
// connect 连接到 QQClient.servers 中的服务器
func (c *QQClient) connect() error {
c.once.Do(func() { c.once.Do(func() {
c.OnGroupMessage(func(_ *QQClient, _ *message.GroupMessage) { c.OnGroupMessage(func(_ *QQClient, _ *message.GroupMessage) {
c.stat.MessageReceived.Add(1) c.stat.MessageReceived.Add(1)
@ -117,11 +116,30 @@ func (c *QQClient) connect() error {
c.onGroupMessageReceipt("internal", func(_ *QQClient, _ *groupMessageReceiptEvent) { c.onGroupMessageReceipt("internal", func(_ *QQClient, _ *groupMessageReceiptEvent) {
c.stat.MessageSent.Add(1) c.stat.MessageSent.Add(1)
}) })
go c.netLoop() // go c.netLoop()
}) })
return c.connectFastest() // 暂时?
/*c.Info("connect to server: %v", c.servers[c.currServerIndex].String())
err := c.TCP.Connect(c.servers[c.currServerIndex])
c.currServerIndex++
if c.currServerIndex == len(c.servers) {
c.currServerIndex = 0
}
if err != nil {
c.retryTimes++
if c.retryTimes > len(c.servers) {
return errors.New("All servers are unreachable")
}
c.Error("connect server error: %v", err)
return err
}
c.retryTimes = 0 c.retryTimes = 0
c.ConnectTime = time.Now() c.ConnectTime = time.Now()
return nil return nil*/
}
func (c *QQClient) QuickReconnect() {
c.quickReconnect() // TODO "用户请求快速重连"
} }
// quickReconnect 快速重连 // quickReconnect 快速重连
@ -130,7 +148,7 @@ func (c *QQClient) quickReconnect() {
time.Sleep(time.Millisecond * 200) time.Sleep(time.Millisecond * 200)
if err := c.connect(); err != nil { if err := c.connect(); err != nil {
c.Error("connect server error: %v", err) c.Error("connect server error: %v", err)
c.dispatchDisconnectEvent(&ClientDisconnectedEvent{Message: "quick reconnect failed"}) c.dispatchDisconnectEvent(&ClientDisconnectedEvent{Message: "快速重连失败"})
return return
} }
if err := c.registerClient(); err != nil { if err := c.registerClient(); err != nil {
@ -144,55 +162,59 @@ func (c *QQClient) quickReconnect() {
// Disconnect 中断连接, 不释放资源 // Disconnect 中断连接, 不释放资源
func (c *QQClient) Disconnect() { func (c *QQClient) Disconnect() {
c.Online.Store(false) c.Online.Store(false)
c.TCP.Close() c.transport.Close()
} }
// sendAndWait 向服务器发送一个数据包, 并等待返回 func (c *QQClient) send(call *network.Call) {
func (c *QQClient) sendAndWait(seq uint16, pkt []byte, params ...network.RequestParams) (interface{}, error) { if call.Done == nil {
type T struct { call.Done = make(chan *network.Call, 3) // use buffered channel
Response interface{}
Error error
} }
ch := make(chan T, 1) seq := call.Request.SequenceID
var p network.RequestParams c.pendingMu.Lock()
c.pending[seq] = call
c.pendingMu.Unlock()
if len(params) != 0 { err := c.sendPacket(c.transport.PackPacket(call.Request))
p = params[0] c.Debug("send pkt: %v seq: %d", call.Request.CommandName, call.Request.SequenceID)
}
c.handlers.Store(seq, &handlerInfo{fun: func(i interface{}, err error) {
ch <- T{
Response: i,
Error: err,
}
}, params: p, dynamic: false})
err := c.sendPacket(pkt)
if err != nil { if err != nil {
c.handlers.Delete(seq) c.pendingMu.Lock()
return nil, err call = c.pending[seq]
delete(c.pending, seq)
c.pendingMu.Unlock()
call.Err = err
call.Done <- call
}
} }
retry := 0 func (c *QQClient) sendReq(req *network.Request) {
for { c.send(&network.Call{Request: req})
select {
case rsp := <-ch:
return rsp.Response, rsp.Error
case <-time.After(time.Second * 15):
retry++
if retry < 2 {
_ = c.sendPacket(pkt)
continue
} }
c.handlers.Delete(seq)
func (c *QQClient) call(req *network.Request) (*network.Response, error) {
call := &network.Call{
Request: req,
Done: make(chan *network.Call, 3),
}
c.send(call)
select {
case <-call.Done:
return call.Response, call.Err
case <-time.After(time.Second * 15):
return nil, errors.New("Packet timed out") return nil, errors.New("Packet timed out")
} }
} }
func (c *QQClient) callAndDecode(req *network.Request) (interface{}, error) {
resp, err := c.call(req)
if err != nil {
return nil, err
}
return req.Decode(resp)
} }
// sendPacket 向服务器发送一个数据包 // sendPacket 向服务器发送一个数据包
func (c *QQClient) sendPacket(pkt []byte) error { func (c *QQClient) sendPacket(pkt []byte) error {
err := c.TCP.Write(pkt) err := c.transport.Write(pkt)
if err != nil { if err != nil {
c.stat.PacketLost.Add(1) c.stat.PacketLost.Add(1)
} else { } else {
@ -230,25 +252,6 @@ func (c *QQClient) waitPacketTimeoutSyncF(cmd string, timeout time.Duration, fil
} }
} }
// sendAndWaitDynamic
// 发送数据包并返回需要解析的 response
func (c *QQClient) sendAndWaitDynamic(seq uint16, pkt []byte) ([]byte, error) {
ch := make(chan []byte, 1)
c.handlers.Store(seq, &handlerInfo{fun: func(i interface{}, err error) { ch <- i.([]byte) }, dynamic: true})
err := c.sendPacket(pkt)
if err != nil {
c.handlers.Delete(seq)
return nil, err
}
select {
case rsp := <-ch:
return rsp, nil
case <-time.After(time.Second * 15):
c.handlers.Delete(seq)
return nil, errors.New("Packet timed out")
}
}
// plannedDisconnect 计划中断线事件 // plannedDisconnect 计划中断线事件
func (c *QQClient) plannedDisconnect(_ *network.TCPListener) { func (c *QQClient) plannedDisconnect(_ *network.TCPListener) {
c.Debug("planned disconnect.") c.Debug("planned disconnect.")
@ -274,92 +277,79 @@ func (c *QQClient) unexpectedDisconnect(_ *network.TCPListener, e error) {
} }
} }
// netLoop 通过循环来不停接收数据包 func (c *QQClient) pktProc(req *network.Request, netErr error) {
func (c *QQClient) netLoop() { if netErr != nil {
errCount := 0 switch true {
for c.alive { case errors.Is(netErr, network.ErrConnectionBroken):
l, err := c.TCP.ReadInt32() go c.dispatchDisconnectEvent(&ClientDisconnectedEvent{Message: netErr.Error()})
if err != nil { c.QuickReconnect()
time.Sleep(time.Millisecond * 500) case errors.Is(netErr, network.ErrSessionExpired) || errors.Is(netErr, network.ErrPacketDropped):
continue
}
if l < 4 || l > 1024*1024*10 { // max 10MB
c.Error("parse incoming packet error: invalid packet length %v", l)
errCount++
if errCount > 2 {
go c.quickReconnect()
}
continue
}
data, _ := c.TCP.ReadBytes(int(l) - 4)
resp, err := c.transport.ReadResponse(data)
// pkt, err := packets.ParseIncomingPacket(data, c.sig.D2Key)
if err != nil {
c.Error("parse incoming packet error: %v", err)
if errors.Is(err, network.ErrSessionExpired) || errors.Is(err, network.ErrPacketDropped) {
c.Disconnect() c.Disconnect()
go c.dispatchDisconnectEvent(&ClientDisconnectedEvent{Message: "session expired"}) go c.dispatchDisconnectEvent(&ClientDisconnectedEvent{Message: "session expired"})
continue
} }
errCount++ c.Error("parse incoming packet error: %v", netErr)
if errCount > 2 { return
go c.quickReconnect()
} }
continue
} if req.EncryptType == network.EncryptTypeEmptyKey {
if resp.EncryptType == network.EncryptTypeEmptyKey { m, err := c.oicq.Unmarshal(req.Body)
m, err := c.oicq.Unmarshal(resp.Body)
if err != nil { if err != nil {
c.Error("decrypt payload error: %v", err) c.Error("decrypt payload error: %v", err)
if errors.Is(err, oicq.ErrUnknownFlag) { if errors.Is(err, oicq.ErrUnknownFlag) {
go c.quickReconnect() go c.quickReconnect() // TODO "服务器发送未知响应"
} }
continue
} }
resp.Body = m.Body req.Body = m.Body
} }
errCount = 0
c.Debug("rev pkt: %v seq: %v", resp.CommandName, resp.SequenceID)
c.stat.PacketReceived.Add(1)
pkt := &packets.IncomingPacket{
SequenceId: uint16(resp.SequenceID),
CommandName: resp.CommandName,
Payload: resp.Body,
}
go func(pkt *packets.IncomingPacket) {
defer func() { defer func() {
if pan := recover(); pan != nil { if pan := recover(); pan != nil {
c.Error("panic on decoder %v : %v\n%s", pkt.CommandName, pan, debug.Stack()) c.Error("panic on decoder %v : %v\n%s", req.CommandName, pan, debug.Stack())
c.Dump("packet decode error: %v - %v", pkt.Payload, pkt.CommandName, pan) c.Dump("packet decode error: %v - %v", req.Body, req.CommandName, pan)
} }
}() }()
if decoder, ok := decoders[pkt.CommandName]; ok { c.Debug("recv pkt: %v seq: %v", req.CommandName, req.SequenceID)
c.stat.PacketReceived.Add(1)
// snapshot of read call
c.pendingMu.Lock()
call := c.pending[req.SequenceID]
if call != nil {
call.Response = &network.Response{
SequenceID: req.SequenceID,
CommandName: req.CommandName,
Body: req.Body,
Request: call.Request,
}
delete(c.pending, req.SequenceID)
}
c.pendingMu.Unlock()
if call != nil && call.Request.CommandName == req.CommandName {
select {
case call.Done <- call:
default:
// we don't want blocking
}
return
}
if decoder, ok := decoders[req.CommandName]; ok {
// found predefined decoder // found predefined decoder
info, ok := c.handlers.LoadAndDelete(pkt.SequenceId) resp := network.Response{
var decoded interface{} SequenceID: req.SequenceID,
decoded = pkt.Payload CommandName: req.CommandName,
if info == nil || !info.dynamic { Body: req.Body,
decoded, err = decoder(c, &network.IncomingPacketInfo{ // Request: nil,
SequenceId: pkt.SequenceId, }
CommandName: pkt.CommandName, decoded, err := decoder(c, &resp)
Params: info.getParams(),
}, pkt.Payload)
if err != nil { if err != nil {
c.Debug("decode pkt %v error: %+v", pkt.CommandName, err) c.Debug("decode req %v error: %+v", req.CommandName, err)
} }
} if f, ok := c.waiters.Load(req.CommandName); ok { // 在不存在handler的情况下触发wait
if ok {
info.fun(decoded, err)
} else if f, ok := c.waiters.Load(pkt.CommandName); ok { // 在不存在handler的情况下触发wait
f.(func(interface{}, error))(decoded, err) f.(func(interface{}, error))(decoded, err)
} }
} else if f, ok := c.handlers.LoadAndDelete(pkt.SequenceId); ok {
// does not need decoder
f.fun(pkt.Payload, nil)
} else { } else {
c.Debug("Unhandled Command: %s\nSeq: %d\nThis message can be ignored.", pkt.CommandName, pkt.SequenceId) c.Debug("Unhandled Command: %s\nSeq: %d\nThis message can be ignored.", req.CommandName, req.SequenceID)
}
}(pkt)
} }
} }

View File

@ -8,11 +8,7 @@ import (
"github.com/Mrs4s/MiraiGo/internal/proto" "github.com/Mrs4s/MiraiGo/internal/proto"
) )
func init() { func (c *QQClient) buildOfflineFileDownloadRequestPacket(uuid []byte) *network.Request {
decoders["OfflineFilleHandleSvr.pb_ftn_CMD_REQ_APPLY_DOWNLOAD-1200"] = decodeOfflineFileDownloadResponse
}
func (c *QQClient) buildOfflineFileDownloadRequestPacket(uuid []byte) (uint16, []byte) {
seq := c.nextSeq() seq := c.nextSeq()
req := &cmd0x346.C346ReqBody{ req := &cmd0x346.C346ReqBody{
Cmd: 1200, Cmd: 1200,
@ -29,13 +25,12 @@ func (c *QQClient) buildOfflineFileDownloadRequestPacket(uuid []byte) (uint16, [
}, },
} }
payload, _ := proto.Marshal(req) payload, _ := proto.Marshal(req)
packet := c.uniPacketWithSeq(seq, "OfflineFilleHandleSvr.pb_ftn_CMD_REQ_APPLY_DOWNLOAD-1200", payload) return c.uniPacketWithSeq(seq, "OfflineFilleHandleSvr.pb_ftn_CMD_REQ_APPLY_DOWNLOAD-1200", payload, decodeOfflineFileDownloadResponse)
return seq, packet
} }
func decodeOfflineFileDownloadResponse(c *QQClient, _ *network.IncomingPacketInfo, payload []byte) (interface{}, error) { func decodeOfflineFileDownloadResponse(c *QQClient, resp *network.Response) (interface{}, error) {
rsp := cmd0x346.C346RspBody{} rsp := cmd0x346.C346RspBody{}
if err := proto.Unmarshal(payload, &rsp); err != nil { if err := proto.Unmarshal(resp.Body, &rsp); err != nil {
c.Error("unmarshal cmd0x346 rsp body error: %v", err) c.Error("unmarshal cmd0x346 rsp body error: %v", err)
return nil, errors.Wrap(err, "unmarshal cmd0x346 rsp body error") return nil, errors.Wrap(err, "unmarshal cmd0x346 rsp body error")
} }

View File

@ -23,15 +23,15 @@ var msg0x210Decoders = map[int64]func(*QQClient, []byte) error{
} }
// OnlinePush.ReqPush // OnlinePush.ReqPush
func decodeOnlinePushReqPacket(c *QQClient, info *network.IncomingPacketInfo, payload []byte) (interface{}, error) { func decodeOnlinePushReqPacket(c *QQClient, resp *network.Response) (interface{}, error) {
request := &jce.RequestPacket{} request := &jce.RequestPacket{}
request.ReadFrom(jce.NewJceReader(payload)) request.ReadFrom(jce.NewJceReader(resp.Body))
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:])
uin := jr.ReadInt64(0) uin := jr.ReadInt64(0)
msgInfos := jr.ReadPushMessageInfos(2) msgInfos := jr.ReadPushMessageInfos(2)
_ = c.sendPacket(c.buildDeleteOnlinePushPacket(uin, 0, nil, info.SequenceId, msgInfos)) _ = c.sendPacket(c.buildDeleteOnlinePushPacket(uin, 0, nil, uint16(resp.SequenceID), msgInfos))
for _, m := range msgInfos { for _, m := range msgInfos {
k := fmt.Sprintf("%v%v%v", m.MsgSeq, m.MsgTime, m.MsgUid) k := fmt.Sprintf("%v%v%v", m.MsgSeq, m.MsgTime, m.MsgUid)
if _, ok := c.onlinePushCache.Get(k); ok { if _, ok := c.onlinePushCache.Get(k); ok {

View File

@ -16,8 +16,34 @@ func (c *QQClient) buildOicqRequestPacket(uin int64, command uint16, body []byte
return c.oicq.Marshal(&req) return c.oicq.Marshal(&req)
} }
type decoderFunc = func(*QQClient, *network.Response) (interface{}, error)
func bindDecoder(c *QQClient, decoder decoderFunc) func(*network.Response) (interface{}, error) {
return func(response *network.Response) (interface{}, error) {
return decoder(c, response)
}
}
//go:noinline //go:noinline
func (c *QQClient) uniPacket(command string, body []byte) (uint16, []byte) { func (c *QQClient) uniRequest(command string, body []byte, decoder decoderFunc) *network.Request {
seq := c.nextSeq()
var decode func(*network.Response) (interface{}, error)
if decoder != nil {
decode = bindDecoder(c, decoder)
}
return &network.Request{
Type: network.RequestTypeSimple,
EncryptType: network.EncryptTypeD2Key,
Uin: c.Uin,
SequenceID: int32(seq),
CommandName: command,
Body: body,
Decode: decode,
}
}
//go:noinline
func (c *QQClient) uniCall(command string, body []byte) (*network.Response, error) {
seq := c.nextSeq() seq := c.nextSeq()
req := network.Request{ req := network.Request{
Type: network.RequestTypeSimple, Type: network.RequestTypeSimple,
@ -27,11 +53,15 @@ func (c *QQClient) uniPacket(command string, body []byte) (uint16, []byte) {
CommandName: command, CommandName: command,
Body: body, Body: body,
} }
return seq, c.transport.PackPacket(&req) return c.call(&req)
} }
//go:noinline //go:noinline
func (c *QQClient) uniPacketWithSeq(seq uint16, command string, body []byte) []byte { func (c *QQClient) uniPacketWithSeq(seq uint16, command string, body []byte, decoder decoderFunc) *network.Request {
var decode func(*network.Response) (interface{}, error)
if decoder != nil {
decode = bindDecoder(c, decoder)
}
req := network.Request{ req := network.Request{
Type: network.RequestTypeSimple, Type: network.RequestTypeSimple,
EncryptType: network.EncryptTypeD2Key, EncryptType: network.EncryptTypeD2Key,
@ -39,6 +69,7 @@ func (c *QQClient) uniPacketWithSeq(seq uint16, command string, body []byte) []b
SequenceID: int32(seq), SequenceID: int32(seq),
CommandName: command, CommandName: command,
Body: body, Body: body,
Decode: decode,
} }
return c.transport.PackPacket(&req) return &req
} }

View File

@ -6,6 +6,7 @@ import (
"github.com/pkg/errors" "github.com/pkg/errors"
"github.com/Mrs4s/MiraiGo/client/internal/network"
"github.com/Mrs4s/MiraiGo/client/pb/msg" "github.com/Mrs4s/MiraiGo/client/pb/msg"
"github.com/Mrs4s/MiraiGo/internal/proto" "github.com/Mrs4s/MiraiGo/internal/proto"
"github.com/Mrs4s/MiraiGo/message" "github.com/Mrs4s/MiraiGo/message"
@ -37,13 +38,13 @@ func (c *QQClient) SendPrivateMessage(target int64, m *message.SendingMessage) *
if i == 0 { if i == 0 {
seq = fseq seq = fseq
} }
_, pkt := c.buildFriendSendingPacket(target, fseq, mr, int32(len(fragmented)), int32(i), div, t, elems) req := c.buildFriendSendingPacket(target, fseq, mr, int32(len(fragmented)), int32(i), div, t, elems)
_ = c.sendPacket(pkt) c.sendReq(req)
} }
} else { } else {
seq = c.nextFriendSeq() seq = c.nextFriendSeq()
_, pkt := c.buildFriendSendingPacket(target, seq, mr, 1, 0, 0, t, m.Elements) pkt := c.buildFriendSendingPacket(target, seq, mr, 1, 0, 0, t, m.Elements)
_ = c.sendPacket(pkt) c.sendReq(pkt)
} }
c.stat.MessageSent.Add(1) c.stat.MessageSent.Add(1)
ret := &message.PrivateMessage{ ret := &message.PrivateMessage{
@ -82,8 +83,8 @@ func (c *QQClient) SendGroupTempMessage(groupCode, target int64, m *message.Send
mr := int32(rand.Uint32()) mr := int32(rand.Uint32())
seq := c.nextFriendSeq() seq := c.nextFriendSeq()
t := time.Now().Unix() t := time.Now().Unix()
_, pkt := c.buildGroupTempSendingPacket(group.Uin, target, seq, mr, t, m) pkt := c.buildGroupTempSendingPacket(group.Uin, target, seq, mr, t, m)
_ = c.sendPacket(pkt) c.sendReq(pkt)
c.stat.MessageSent.Add(1) c.stat.MessageSent.Add(1)
return &message.TempMessage{ return &message.TempMessage{
Id: seq, Id: seq,
@ -103,8 +104,8 @@ func (c *QQClient) sendWPATempMessage(target int64, sig []byte, m *message.Sendi
mr := int32(rand.Uint32()) mr := int32(rand.Uint32())
seq := c.nextFriendSeq() seq := c.nextFriendSeq()
t := time.Now().Unix() t := time.Now().Unix()
_, pkt := c.buildWPATempSendingPacket(target, sig, seq, mr, t, m) pkt := c.buildWPATempSendingPacket(target, sig, seq, mr, t, m)
_ = c.sendPacket(pkt) c.sendReq(pkt)
c.stat.MessageSent.Add(1) c.stat.MessageSent.Add(1)
return &message.TempMessage{ return &message.TempMessage{
Id: seq, Id: seq,
@ -130,7 +131,7 @@ func (s *TempSessionInfo) SendMessage(m *message.SendingMessage) (*message.TempM
} }
/* this function is unused /* this function is unused
func (c *QQClient) buildGetOneDayRoamMsgRequest(target, lastMsgTime, random int64, count uint32) (uint16, []byte) { func (c *QQClient) buildGetOneDayRoamMsgRequest(target, lastMsgTime, random int64, count uint32) *network.Request {
seq := c.nextSeq() seq := c.nextSeq()
req := &msg.PbGetOneDayRoamMsgReq{ req := &msg.PbGetOneDayRoamMsgReq{
PeerUin: proto.Uint64(uint64(target)), PeerUin: proto.Uint64(uint64(target)),
@ -145,7 +146,7 @@ func (c *QQClient) buildGetOneDayRoamMsgRequest(target, lastMsgTime, random int6
*/ */
// MessageSvc.PbSendMsg // MessageSvc.PbSendMsg
func (c *QQClient) buildFriendSendingPacket(target int64, msgSeq, r, pkgNum, pkgIndex, pkgDiv int32, time int64, m []message.IMessageElement) (uint16, []byte) { func (c *QQClient) buildFriendSendingPacket(target int64, msgSeq, r, pkgNum, pkgIndex, pkgDiv int32, time int64, m []message.IMessageElement) *network.Request {
var ptt *msg.Ptt var ptt *msg.Ptt
if len(m) > 0 { if len(m) > 0 {
if p, ok := m[0].(*message.PrivateVoiceElement); ok { if p, ok := m[0].(*message.PrivateVoiceElement); ok {
@ -178,11 +179,11 @@ func (c *QQClient) buildFriendSendingPacket(target int64, msgSeq, r, pkgNum, pkg
}(), }(),
} }
payload, _ := proto.Marshal(req) payload, _ := proto.Marshal(req)
return c.uniPacket("MessageSvc.PbSendMsg", payload) return c.uniRequest("MessageSvc.PbSendMsg", payload, nil)
} }
// MessageSvc.PbSendMsg // MessageSvc.PbSendMsg
func (c *QQClient) buildGroupTempSendingPacket(groupUin, target int64, msgSeq, r int32, time int64, m *message.SendingMessage) (uint16, []byte) { func (c *QQClient) buildGroupTempSendingPacket(groupUin, target int64, msgSeq, r int32, time int64, m *message.SendingMessage) *network.Request {
req := &msg.SendMessageRequest{ req := &msg.SendMessageRequest{
RoutingHead: &msg.RoutingHead{GrpTmp: &msg.GrpTmp{ RoutingHead: &msg.RoutingHead{GrpTmp: &msg.GrpTmp{
GroupUin: &groupUin, GroupUin: &groupUin,
@ -210,10 +211,10 @@ func (c *QQClient) buildGroupTempSendingPacket(groupUin, target int64, msgSeq, r
}(), }(),
} }
payload, _ := proto.Marshal(req) payload, _ := proto.Marshal(req)
return c.uniPacket("MessageSvc.PbSendMsg", payload) return c.uniRequest("MessageSvc.PbSendMsg", payload, nil)
} }
func (c *QQClient) buildWPATempSendingPacket(uin int64, sig []byte, msgSeq, r int32, time int64, m *message.SendingMessage) (uint16, []byte) { func (c *QQClient) buildWPATempSendingPacket(uin int64, sig []byte, msgSeq, r int32, time int64, m *message.SendingMessage) *network.Request {
req := &msg.SendMessageRequest{ req := &msg.SendMessageRequest{
RoutingHead: &msg.RoutingHead{WpaTmp: &msg.WPATmp{ RoutingHead: &msg.RoutingHead{WpaTmp: &msg.WPATmp{
ToUin: proto.Uint64(uint64(uin)), ToUin: proto.Uint64(uint64(uin)),
@ -241,5 +242,5 @@ func (c *QQClient) buildWPATempSendingPacket(uin int64, sig []byte, msgSeq, r in
}(), }(),
} }
payload, _ := proto.Marshal(req) payload, _ := proto.Marshal(req)
return c.uniPacket("MessageSvc.PbSendMsg", payload) return c.uniRequest("MessageSvc.PbSendMsg", payload, nil)
} }

View File

@ -147,7 +147,7 @@ func (c *QQClient) UploadGroupShortVideo(groupCode int64, video, thumb io.ReadSe
pttWaiter.Wait(key) pttWaiter.Wait(key)
defer pttWaiter.Done(key) defer pttWaiter.Done(key)
i, err := c.sendAndWait(c.buildPttGroupShortVideoUploadReqPacket(videoHash, thumbHash, groupCode, videoLen, thumbLen)) i, err := c.callAndDecode(c.buildPttGroupShortVideoUploadReq(videoHash, thumbHash, groupCode, videoLen, thumbLen))
if err != nil { if err != nil {
return nil, errors.Wrap(err, "upload req error") return nil, errors.Wrap(err, "upload req error")
} }
@ -210,7 +210,7 @@ func (c *QQClient) UploadGroupShortVideo(groupCode int64, video, thumb io.ReadSe
} }
func (c *QQClient) GetShortVideoUrl(uuid, md5 []byte) string { func (c *QQClient) GetShortVideoUrl(uuid, md5 []byte) string {
i, err := c.sendAndWait(c.buildPttShortVideoDownReqPacket(uuid, md5)) i, err := c.callAndDecode(c.buildPttShortVideoDownReq(uuid, md5))
if err != nil { if err != nil {
return "" return ""
} }
@ -245,7 +245,7 @@ func (c *QQClient) buildGroupPttStoreBDHExt(groupCode int64, md5 []byte, size, c
} }
// PttCenterSvr.ShortVideoDownReq // PttCenterSvr.ShortVideoDownReq
func (c *QQClient) buildPttShortVideoDownReqPacket(uuid, md5 []byte) (uint16, []byte) { func (c *QQClient) buildPttShortVideoDownReq(uuid, md5 []byte) *network.Request {
seq := c.nextSeq() seq := c.nextSeq()
body := &pttcenter.ShortVideoReqBody{ body := &pttcenter.ShortVideoReqBody{
Cmd: 400, Cmd: 400,
@ -265,8 +265,7 @@ func (c *QQClient) buildPttShortVideoDownReqPacket(uuid, md5 []byte) (uint16, []
}, },
} }
payload, _ := proto.Marshal(body) payload, _ := proto.Marshal(body)
packet := c.uniPacketWithSeq(seq, "PttCenterSvr.ShortVideoDownReq", payload) return c.uniPacketWithSeq(seq, "PttCenterSvr.ShortVideoDownReq", payload, decodePttShortVideoDownResponse)
return seq, packet
} }
func (c *QQClient) buildPttGroupShortVideoProto(videoHash, thumbHash []byte, toUin, videoSize, thumbSize int64, chattype int32) *pttcenter.ShortVideoReqBody { func (c *QQClient) buildPttGroupShortVideoProto(videoHash, thumbHash []byte, toUin, videoSize, thumbSize int64, chattype int32) *pttcenter.ShortVideoReqBody {
@ -303,9 +302,9 @@ func (c *QQClient) buildPttGroupShortVideoProto(videoHash, thumbHash []byte, toU
} }
// PttCenterSvr.GroupShortVideoUpReq // PttCenterSvr.GroupShortVideoUpReq
func (c *QQClient) buildPttGroupShortVideoUploadReqPacket(videoHash, thumbHash []byte, toUin, videoSize, thumbSize int64) (uint16, []byte) { func (c *QQClient) buildPttGroupShortVideoUploadReq(videoHash, thumbHash []byte, toUin, videoSize, thumbSize int64) *network.Request {
payload, _ := proto.Marshal(c.buildPttGroupShortVideoProto(videoHash, thumbHash, toUin, videoSize, thumbSize, 1)) payload, _ := proto.Marshal(c.buildPttGroupShortVideoProto(videoHash, thumbHash, toUin, videoSize, thumbSize, 1))
return c.uniPacket("PttCenterSvr.GroupShortVideoUpReq", payload) return c.uniRequest("PttCenterSvr.GroupShortVideoUpReq", payload, decodeGroupShortVideoUploadResponse)
} }
// PttCenterSvr.pb_pttCenter_CMD_REQ_APPLY_UPLOAD-500 // PttCenterSvr.pb_pttCenter_CMD_REQ_APPLY_UPLOAD-500
@ -337,9 +336,9 @@ func (c *QQClient) buildC2CPttStoreBDHExt(target int64, md5 []byte, size, voiceL
} }
// PttCenterSvr.ShortVideoDownReq // PttCenterSvr.ShortVideoDownReq
func decodePttShortVideoDownResponse(_ *QQClient, _ *network.IncomingPacketInfo, payload []byte) (interface{}, error) { func decodePttShortVideoDownResponse(_ *QQClient, resp *network.Response) (interface{}, error) {
rsp := pttcenter.ShortVideoRspBody{} rsp := pttcenter.ShortVideoRspBody{}
if err := proto.Unmarshal(payload, &rsp); err != nil { if err := proto.Unmarshal(resp.Body, &rsp); err != nil {
return nil, errors.Wrap(err, "failed to unmarshal protobuf message") return nil, errors.Wrap(err, "failed to unmarshal protobuf message")
} }
if rsp.PttShortVideoDownloadRsp == nil || rsp.PttShortVideoDownloadRsp.DownloadAddr == nil { if rsp.PttShortVideoDownloadRsp == nil || rsp.PttShortVideoDownloadRsp.DownloadAddr == nil {
@ -349,9 +348,9 @@ func decodePttShortVideoDownResponse(_ *QQClient, _ *network.IncomingPacketInfo,
} }
// PttCenterSvr.GroupShortVideoUpReq // PttCenterSvr.GroupShortVideoUpReq
func decodeGroupShortVideoUploadResponse(_ *QQClient, _ *network.IncomingPacketInfo, payload []byte) (interface{}, error) { func decodeGroupShortVideoUploadResponse(_ *QQClient, resp *network.Response) (interface{}, error) {
rsp := pttcenter.ShortVideoRspBody{} rsp := pttcenter.ShortVideoRspBody{}
if err := proto.Unmarshal(payload, &rsp); err != nil { if err := proto.Unmarshal(resp.Body, &rsp); err != nil {
return nil, errors.Wrap(err, "failed to unmarshal protobuf message") return nil, errors.Wrap(err, "failed to unmarshal protobuf message")
} }
if rsp.PttShortVideoUploadRsp == nil { if rsp.PttShortVideoUploadRsp == nil {

View File

@ -63,7 +63,7 @@ func (c *QQClient) getQiDianAddressDetailList() ([]*FriendInfo, error) {
return ret, nil return ret, nil
} }
func (c *QQClient) buildLoginExtraPacket() (uint16, []byte) { func (c *QQClient) buildLoginExtraPacket() *network.Request {
req := &cmd0x3f6.C3F6ReqBody{ req := &cmd0x3f6.C3F6ReqBody{
SubCmd: proto.Uint32(69), SubCmd: proto.Uint32(69),
CrmCommonHead: &cmd0x3f6.C3F6CRMMsgHead{ CrmCommonHead: &cmd0x3f6.C3F6CRMMsgHead{
@ -86,10 +86,10 @@ func (c *QQClient) buildLoginExtraPacket() (uint16, []byte) {
}, },
} }
payload, _ := proto.Marshal(req) payload, _ := proto.Marshal(req)
return c.uniPacket("qidianservice.69", payload) return c.uniRequest("qidianservice.69", payload, nil)
} }
func (c *QQClient) buildConnKeyRequestPacket() (uint16, []byte) { func (c *QQClient) buildConnKeyRequestPacket() *network.Request {
req := &cmd0x6ff.C501ReqBody{ req := &cmd0x6ff.C501ReqBody{
ReqBody: &cmd0x6ff.SubCmd0X501ReqBody{ ReqBody: &cmd0x6ff.SubCmd0X501ReqBody{
Uin: proto.Uint64(uint64(c.Uin)), Uin: proto.Uint64(uint64(c.Uin)),
@ -101,7 +101,7 @@ func (c *QQClient) buildConnKeyRequestPacket() (uint16, []byte) {
}, },
} }
payload, _ := proto.Marshal(req) payload, _ := proto.Marshal(req)
return c.uniPacket("HttpConn.0x6ff_501", payload) return c.uniRequest("HttpConn.0x6ff_501", payload, nil)
} }
func (c *QQClient) bigDataRequest(subCmd uint32, req proto.Message) ([]byte, error) { func (c *QQClient) bigDataRequest(subCmd uint32, req proto.Message) ([]byte, error) {
@ -152,9 +152,9 @@ func (c *QQClient) bigDataRequest(subCmd uint32, req proto.Message) ([]byte, err
return tea.Decrypt(payload), nil return tea.Decrypt(payload), nil
} }
func decodeLoginExtraResponse(c *QQClient, _ *network.IncomingPacketInfo, payload []byte) (interface{}, error) { func decodeLoginExtraResponse(c *QQClient, resp *network.Response) (interface{}, error) {
rsp := cmd0x3f6.C3F6RspBody{} rsp := cmd0x3f6.C3F6RspBody{}
if err := proto.Unmarshal(payload, &rsp); err != nil { if err := proto.Unmarshal(resp.Body, &rsp); err != nil {
return nil, errors.Wrap(err, "failed to unmarshal protobuf message") return nil, errors.Wrap(err, "failed to unmarshal protobuf message")
} }
if rsp.SubcmdLoginProcessCompleteRspBody == nil { if rsp.SubcmdLoginProcessCompleteRspBody == nil {
@ -168,9 +168,9 @@ func decodeLoginExtraResponse(c *QQClient, _ *network.IncomingPacketInfo, payloa
return nil, nil return nil, nil
} }
func decodeConnKeyResponse(c *QQClient, _ *network.IncomingPacketInfo, payload []byte) (interface{}, error) { func decodeConnKeyResponse(c *QQClient, resp *network.Response) (interface{}, error) {
rsp := cmd0x6ff.C501RspBody{} rsp := cmd0x6ff.C501RspBody{}
if err := proto.Unmarshal(payload, &rsp); err != nil { if err := proto.Unmarshal(resp.Body, &rsp); err != nil {
return nil, errors.Wrap(err, "failed to unmarshal protobuf message") return nil, errors.Wrap(err, "failed to unmarshal protobuf message")
} }
if c.QiDian == nil { if c.QiDian == nil {

View File

@ -22,7 +22,7 @@ func (c *QQClient) RecallGroupMessage(groupCode int64, msgID, msgInternalId int3
} }
} }
} }
_, err := c.sendAndWait(c.buildGroupRecallPacket(groupCode, msgID, msgInternalId)) _, err := c.callAndDecode(c.buildGroupRecallPacket(groupCode, msgID, msgInternalId))
return err return err
} }
@ -30,7 +30,7 @@ func (c *QQClient) internalGroupRecall(groupCode int64, msgInternalID int32, m [
for _, item := range m { for _, item := range m {
if item.InternalId == msgInternalID { if item.InternalId == msgInternalID {
flag = true flag = true
if _, err := c.sendAndWait(c.buildGroupRecallPacket(groupCode, item.Id, item.InternalId)); err != nil { if _, err := c.callAndDecode(c.buildGroupRecallPacket(groupCode, item.Id, item.InternalId)); err != nil {
return false, err return false, err
} }
} }
@ -39,12 +39,12 @@ func (c *QQClient) internalGroupRecall(groupCode int64, msgInternalID int32, m [
} }
func (c *QQClient) RecallPrivateMessage(uin, ts int64, msgID, msgInternalId int32) error { func (c *QQClient) RecallPrivateMessage(uin, ts int64, msgID, msgInternalId int32) error {
_, err := c.sendAndWait(c.buildPrivateRecallPacket(uin, ts, msgID, msgInternalId)) _, err := c.callAndDecode(c.buildPrivateRecallPacket(uin, ts, msgID, msgInternalId))
return err return err
} }
// PbMessageSvc.PbMsgWithDraw // PbMessageSvc.PbMsgWithDraw
func (c *QQClient) buildGroupRecallPacket(groupCode int64, msgSeq, msgRan int32) (uint16, []byte) { func (c *QQClient) buildGroupRecallPacket(groupCode int64, msgSeq, msgRan int32) *network.Request {
req := &msg.MsgWithDrawReq{ req := &msg.MsgWithDrawReq{
GroupWithDraw: []*msg.GroupMsgWithDrawReq{ GroupWithDraw: []*msg.GroupMsgWithDrawReq{
{ {
@ -62,10 +62,10 @@ func (c *QQClient) buildGroupRecallPacket(groupCode int64, msgSeq, msgRan int32)
}, },
} }
payload, _ := proto.Marshal(req) payload, _ := proto.Marshal(req)
return c.uniPacket("PbMessageSvc.PbMsgWithDraw", payload) return c.uniRequest("PbMessageSvc.PbMsgWithDraw", payload, decodeMsgWithDrawResponse)
} }
func (c *QQClient) buildPrivateRecallPacket(uin, ts int64, msgSeq, random int32) (uint16, []byte) { func (c *QQClient) buildPrivateRecallPacket(uin, ts int64, msgSeq, random int32) *network.Request {
req := &msg.MsgWithDrawReq{C2CWithDraw: []*msg.C2CMsgWithDrawReq{ req := &msg.MsgWithDrawReq{C2CWithDraw: []*msg.C2CMsgWithDrawReq{
{ {
MsgInfo: []*msg.C2CMsgInfo{ MsgInfo: []*msg.C2CMsgInfo{
@ -89,12 +89,12 @@ func (c *QQClient) buildPrivateRecallPacket(uin, ts int64, msgSeq, random int32)
}, },
}} }}
payload, _ := proto.Marshal(req) payload, _ := proto.Marshal(req)
return c.uniPacket("PbMessageSvc.PbMsgWithDraw", payload) return c.uniRequest("PbMessageSvc.PbMsgWithDraw", payload, decodeMsgWithDrawResponse)
} }
func decodeMsgWithDrawResponse(_ *QQClient, _ *network.IncomingPacketInfo, payload []byte) (interface{}, error) { func decodeMsgWithDrawResponse(_ *QQClient, resp *network.Response) (interface{}, error) {
rsp := msg.MsgWithDrawResp{} rsp := msg.MsgWithDrawResp{}
if err := proto.Unmarshal(payload, &rsp); err != nil { if err := proto.Unmarshal(resp.Body, &rsp); err != nil {
return nil, errors.Wrap(err, "failed to unmarshal protobuf message") return nil, errors.Wrap(err, "failed to unmarshal protobuf message")
} }
if len(rsp.C2CWithDraw) > 0 { if len(rsp.C2CWithDraw) > 0 {

View File

@ -6,6 +6,7 @@ import (
"github.com/pkg/errors" "github.com/pkg/errors"
"github.com/Mrs4s/MiraiGo/client/internal/network"
"github.com/Mrs4s/MiraiGo/client/pb/oidb" "github.com/Mrs4s/MiraiGo/client/pb/oidb"
"github.com/Mrs4s/MiraiGo/internal/proto" "github.com/Mrs4s/MiraiGo/internal/proto"
"github.com/Mrs4s/MiraiGo/message" "github.com/Mrs4s/MiraiGo/message"
@ -76,7 +77,7 @@ func (c *QQClient) SendGroupMusicShare(target int64, msg *message.MusicShareElem
} }
}) })
defer c.onGroupMessageReceipt(eid) defer c.onGroupMessageReceipt(eid)
_, _ = c.sendAndWait(c.buildRichMsgSendingPacket(0, target, msg, 1)) // rsp is empty chunk _, _ = c.call(c.buildRichMsgSendingReq(0, target, msg, 1)) // rsp is empty chunk
select { select {
case ret := <-ch: case ret := <-ch:
return ret, nil return ret, nil
@ -87,17 +88,17 @@ func (c *QQClient) SendGroupMusicShare(target int64, msg *message.MusicShareElem
// SendFriendMusicShare 发送好友音乐卡片 // SendFriendMusicShare 发送好友音乐卡片
func (c *QQClient) SendFriendMusicShare(target int64, msg *message.MusicShareElement) { func (c *QQClient) SendFriendMusicShare(target int64, msg *message.MusicShareElement) {
_, _ = c.sendAndWait(c.buildRichMsgSendingPacket(0, target, msg, 0)) _, _ = c.call(c.buildRichMsgSendingReq(0, target, msg, 0))
} }
// SendGuildMusicShare 发送频道音乐卡片 // SendGuildMusicShare 发送频道音乐卡片
func (c *QQClient) SendGuildMusicShare(guildID, channelID uint64, msg *message.MusicShareElement) { func (c *QQClient) SendGuildMusicShare(guildID, channelID uint64, msg *message.MusicShareElement) {
// todo(wdvxdr): message receipt? // todo(wdvxdr): message receipt?
_, _ = c.sendAndWait(c.buildRichMsgSendingPacket(guildID, int64(channelID), msg, 3)) _, _ = c.call(c.buildRichMsgSendingReq(guildID, int64(channelID), msg, 3))
} }
// OidbSvc.0xb77_9 // OidbSvc.0xb77_9
func (c *QQClient) buildRichMsgSendingPacket(guild uint64, target int64, msg *message.MusicShareElement, sendType uint32) (uint16, []byte) { func (c *QQClient) buildRichMsgSendingReq(guild uint64, target int64, msg *message.MusicShareElement, sendType uint32) *network.Request {
tp := musicType[msg.MusicType] // MusicType tp := musicType[msg.MusicType] // MusicType
msgStyle := uint32(0) msgStyle := uint32(0)
if msg.MusicUrl != "" { if msg.MusicUrl != "" {
@ -128,5 +129,5 @@ func (c *QQClient) buildRichMsgSendingPacket(guild uint64, target int64, msg *me
} }
b, _ := proto.Marshal(body) b, _ := proto.Marshal(body)
payload := c.packOIDBPackage(2935, 9, b) payload := c.packOIDBPackage(2935, 9, b)
return c.uniPacket("OidbSvc.0xb77_9", payload) return c.uniRequest("OidbSvc.0xb77_9", payload, nil)
} }

View File

@ -8,10 +8,6 @@ import (
"github.com/Mrs4s/MiraiGo/internal/proto" "github.com/Mrs4s/MiraiGo/internal/proto"
) )
func init() {
decoders["OidbSvc.0xbcb_0"] = decodeUrlCheckResponse
}
type UrlSecurityLevel int type UrlSecurityLevel int
const ( const (
@ -22,14 +18,14 @@ const (
// CheckUrlSafely 通过TX服务器检查URL安全性 // CheckUrlSafely 通过TX服务器检查URL安全性
func (c *QQClient) CheckUrlSafely(url string) UrlSecurityLevel { func (c *QQClient) CheckUrlSafely(url string) UrlSecurityLevel {
i, err := c.sendAndWait(c.buildUrlCheckRequest(url)) i, err := c.callAndDecode(c.buildUrlCheckRequest(url))
if err != nil { if err != nil {
return Unknown return Unknown
} }
return i.(UrlSecurityLevel) return i.(UrlSecurityLevel)
} }
func (c *QQClient) buildUrlCheckRequest(url string) (uint16, []byte) { func (c *QQClient) buildUrlCheckRequest(url string) *network.Request {
payload := c.packOIDBPackageProto(3019, 0, &oidb.DBCBReqBody{ payload := c.packOIDBPackageProto(3019, 0, &oidb.DBCBReqBody{
CheckUrlReq: &oidb.CheckUrlReq{ CheckUrlReq: &oidb.CheckUrlReq{
Url: []string{url}, Url: []string{url},
@ -45,13 +41,13 @@ func (c *QQClient) buildUrlCheckRequest(url string) (uint16, []byte) {
Qua: proto.String("AQQ_2013 4.6/2013 8.4.184945&NA_0/000000&ADR&null18&linux&2017&C2293D02BEE31158&7.1.2&V3"), Qua: proto.String("AQQ_2013 4.6/2013 8.4.184945&NA_0/000000&ADR&null18&linux&2017&C2293D02BEE31158&7.1.2&V3"),
}, },
}) })
return c.uniPacket("OidbSvc.0xbcb_0", payload) return c.uniRequest("OidbSvc.0xbcb_0", payload, decodeUrlCheckResponse)
} }
func decodeUrlCheckResponse(_ *QQClient, _ *network.IncomingPacketInfo, payload []byte) (interface{}, error) { func decodeUrlCheckResponse(_ *QQClient, resp *network.Response) (interface{}, error) {
pkg := &oidb.OIDBSSOPkg{} pkg := &oidb.OIDBSSOPkg{}
rsp := &oidb.DBCBRspBody{} rsp := &oidb.DBCBRspBody{}
if err := proto.Unmarshal(payload, pkg); err != nil { if err := proto.Unmarshal(resp.Body, pkg); err != nil {
return nil, errors.Wrap(err, "failed to unmarshal protobuf message") return nil, errors.Wrap(err, "failed to unmarshal protobuf message")
} }
if err := proto.Unmarshal(pkg.Bodybuffer, rsp); err != nil { if err := proto.Unmarshal(pkg.Bodybuffer, rsp); err != nil {

View File

@ -17,16 +17,9 @@ import (
) )
func init() { func init() {
decoders["StatSvc.GetDevLoginInfo"] = decodeDevListResponse
decoders["StatSvc.SvcReqMSFLoginNotify"] = decodeLoginNotifyPacket decoders["StatSvc.SvcReqMSFLoginNotify"] = decodeLoginNotifyPacket
decoders["RegPrxySvc.getOffMsg"] = ignoreDecoder
decoders["RegPrxySvc.GetMsgV2"] = ignoreDecoder
decoders["RegPrxySvc.PbGetMsg"] = ignoreDecoder
decoders["RegPrxySvc.NoticeEnd"] = ignoreDecoder
decoders["RegPrxySvc.PushParam"] = decodePushParamPacket decoders["RegPrxySvc.PushParam"] = decodePushParamPacket
decoders["RegPrxySvc.PbSyncMsg"] = decodeMsgSyncResponse decoders["RegPrxySvc.PbSyncMsg"] = decodeMsgSyncResponse
decoders["PbMessageSvc.PbMsgReadedReport"] = decodeMsgReadedResponse
decoders["MessageSvc.PushReaded"] = ignoreDecoder
decoders["OnlinePush.PbC2CMsgSync"] = decodeC2CSyncPacket decoders["OnlinePush.PbC2CMsgSync"] = decodeC2CSyncPacket
} }
@ -52,7 +45,7 @@ type (
// GetAllowedClients 获取已允许的其他客户端 // GetAllowedClients 获取已允许的其他客户端
func (c *QQClient) GetAllowedClients() ([]*OtherClientInfo, error) { func (c *QQClient) GetAllowedClients() ([]*OtherClientInfo, error) {
i, err := c.sendAndWait(c.buildDeviceListRequestPacket()) i, err := c.callAndDecode(c.buildDeviceListRequestPacket())
if err != nil { if err != nil {
return nil, err return nil, err
} }
@ -70,7 +63,7 @@ func (c *QQClient) GetAllowedClients() ([]*OtherClientInfo, error) {
// RefreshStatus 刷新客户端状态 // RefreshStatus 刷新客户端状态
func (c *QQClient) RefreshStatus() error { func (c *QQClient) RefreshStatus() error {
_, err := c.sendAndWait(c.buildGetOfflineMsgRequestPacket()) _, err := c.call(c.buildGetOfflineMsgRequestPacket())
return err return err
} }
@ -95,8 +88,8 @@ func (c *QQClient) SyncSessions() (*SessionSyncResponse, error) {
notifyChan <- true notifyChan <- true
} }
}) })
_, pkt := c.buildSyncMsgRequestPacket() pkt := c.buildSyncMsgRequestPacket()
if err := c.sendPacket(pkt); err != nil { if _, err := c.call(pkt); err != nil {
stop() stop()
return nil, err return nil, err
} }
@ -111,15 +104,15 @@ func (c *QQClient) SyncSessions() (*SessionSyncResponse, error) {
// MarkGroupMessageReaded 标记群消息已读, 适当调用应该能减少风控 // MarkGroupMessageReaded 标记群消息已读, 适当调用应该能减少风控
func (c *QQClient) MarkGroupMessageReaded(groupCode, seq int64) { func (c *QQClient) MarkGroupMessageReaded(groupCode, seq int64) {
_, _ = c.sendAndWait(c.buildGroupMsgReadedPacket(groupCode, seq)) _, _ = c.callAndDecode(c.buildGroupMsgReadedPacket(groupCode, seq))
} }
func (c *QQClient) MarkPrivateMessageReaded(uin, time int64) { func (c *QQClient) MarkPrivateMessageReaded(uin, time int64) {
_, _ = c.sendAndWait(c.buildPrivateMsgReadedPacket(uin, time)) _, _ = c.callAndDecode(c.buildPrivateMsgReadedPacket(uin, time))
} }
// StatSvc.GetDevLoginInfo // StatSvc.GetDevLoginInfo
func (c *QQClient) buildDeviceListRequestPacket() (uint16, []byte) { func (c *QQClient) buildDeviceListRequestPacket() *network.Request {
req := &jce.SvcReqGetDevLoginInfo{ req := &jce.SvcReqGetDevLoginInfo{
Guid: c.deviceInfo.Guid, Guid: c.deviceInfo.Guid,
LoginType: 1, LoginType: 1,
@ -136,11 +129,11 @@ func (c *QQClient) buildDeviceListRequestPacket() (uint16, []byte) {
Context: make(map[string]string), Context: make(map[string]string),
Status: make(map[string]string), Status: make(map[string]string),
} }
return c.uniPacket("StatSvc.GetDevLoginInfo", pkt.ToBytes()) return c.uniRequest("StatSvc.GetDevLoginInfo", pkt.ToBytes(), decodeDevListResponse)
} }
// RegPrxySvc.getOffMsg // RegPrxySvc.getOffMsg
func (c *QQClient) buildGetOfflineMsgRequestPacket() (uint16, []byte) { func (c *QQClient) buildGetOfflineMsgRequestPacket() *network.Request {
regReq := &jce.SvcReqRegisterNew{ regReq := &jce.SvcReqRegisterNew{
RequestOptional: 0x101C2 | 32, RequestOptional: 0x101C2 | 32,
C2CMsg: &jce.SvcReqGetMsgV2{ C2CMsg: &jce.SvcReqGetMsgV2{
@ -190,11 +183,11 @@ func (c *QQClient) buildGetOfflineMsgRequestPacket() (uint16, []byte) {
Context: make(map[string]string), Context: make(map[string]string),
Status: make(map[string]string), Status: make(map[string]string),
} }
return c.uniPacket("RegPrxySvc.getOffMsg", pkt.ToBytes()) return c.uniRequest("RegPrxySvc.getOffMsg", pkt.ToBytes(), nil)
} }
// RegPrxySvc.PbSyncMsg // RegPrxySvc.PbSyncMsg
func (c *QQClient) buildSyncMsgRequestPacket() (uint16, []byte) { func (c *QQClient) buildSyncMsgRequestPacket() *network.Request {
oidbReq, _ := proto.Marshal(&oidb.D769RspBody{ oidbReq, _ := proto.Marshal(&oidb.D769RspBody{
ConfigList: []*oidb.D769ConfigSeq{ ConfigList: []*oidb.D769ConfigSeq{
{ {
@ -262,32 +255,32 @@ func (c *QQClient) buildSyncMsgRequestPacket() (uint16, []byte) {
Context: make(map[string]string), Context: make(map[string]string),
Status: make(map[string]string), Status: make(map[string]string),
} }
return c.uniPacket("RegPrxySvc.infoSync", pkt.ToBytes()) return c.uniRequest("RegPrxySvc.infoSync", pkt.ToBytes(), nil)
} }
// PbMessageSvc.PbMsgReadedReport // PbMessageSvc.PbMsgReadedReport
func (c *QQClient) buildGroupMsgReadedPacket(groupCode, msgSeq int64) (uint16, []byte) { func (c *QQClient) buildGroupMsgReadedPacket(groupCode, msgSeq int64) *network.Request {
req, _ := proto.Marshal(&msg.PbMsgReadedReportReq{GrpReadReport: []*msg.PbGroupReadedReportReq{{ req, _ := proto.Marshal(&msg.PbMsgReadedReportReq{GrpReadReport: []*msg.PbGroupReadedReportReq{{
GroupCode: proto.Uint64(uint64(groupCode)), GroupCode: proto.Uint64(uint64(groupCode)),
LastReadSeq: proto.Uint64(uint64(msgSeq)), LastReadSeq: proto.Uint64(uint64(msgSeq)),
}}}) }}})
return c.uniPacket("PbMessageSvc.PbMsgReadedReport", req) return c.uniRequest("PbMessageSvc.PbMsgReadedReport", req, decodeMsgReadedResponse)
} }
func (c *QQClient) buildPrivateMsgReadedPacket(uin, time int64) (uint16, []byte) { func (c *QQClient) buildPrivateMsgReadedPacket(uin, time int64) *network.Request {
req, _ := proto.Marshal(&msg.PbMsgReadedReportReq{C2CReadReport: &msg.PbC2CReadedReportReq{PairInfo: []*msg.UinPairReadInfo{ req, _ := proto.Marshal(&msg.PbMsgReadedReportReq{C2CReadReport: &msg.PbC2CReadedReportReq{PairInfo: []*msg.UinPairReadInfo{
{ {
PeerUin: proto.Uint64(uint64(uin)), PeerUin: proto.Uint64(uint64(uin)),
LastReadTime: proto.Uint32(uint32(time)), LastReadTime: proto.Uint32(uint32(time)),
}, },
}, SyncCookie: c.sig.SyncCookie}}) }, SyncCookie: c.sig.SyncCookie}})
return c.uniPacket("PbMessageSvc.PbMsgReadedReport", req) return c.uniRequest("PbMessageSvc.PbMsgReadedReport", req, decodeMsgReadedResponse)
} }
// StatSvc.GetDevLoginInfo // StatSvc.GetDevLoginInfo
func decodeDevListResponse(_ *QQClient, _ *network.IncomingPacketInfo, payload []byte) (interface{}, error) { func decodeDevListResponse(_ *QQClient, resp *network.Response) (interface{}, error) {
request := &jce.RequestPacket{} request := &jce.RequestPacket{}
request.ReadFrom(jce.NewJceReader(payload)) request.ReadFrom(jce.NewJceReader(resp.Body))
data := &jce.RequestDataVersion2{} data := &jce.RequestDataVersion2{}
data.ReadFrom(jce.NewJceReader(request.SBuffer)) data.ReadFrom(jce.NewJceReader(request.SBuffer))
rsp := jce.NewJceReader(data.Map["SvcRspGetDevLoginInfo"]["QQService.SvcRspGetDevLoginInfo"][1:]) rsp := jce.NewJceReader(data.Map["SvcRspGetDevLoginInfo"]["QQService.SvcRspGetDevLoginInfo"][1:])
@ -307,9 +300,9 @@ func decodeDevListResponse(_ *QQClient, _ *network.IncomingPacketInfo, payload [
} }
// RegPrxySvc.PushParam // RegPrxySvc.PushParam
func decodePushParamPacket(c *QQClient, _ *network.IncomingPacketInfo, payload []byte) (interface{}, error) { func decodePushParamPacket(c *QQClient, resp *network.Response) (interface{}, error) {
request := &jce.RequestPacket{} request := &jce.RequestPacket{}
request.ReadFrom(jce.NewJceReader(payload)) request.ReadFrom(jce.NewJceReader(resp.Body))
data := &jce.RequestDataVersion2{} data := &jce.RequestDataVersion2{}
data.ReadFrom(jce.NewJceReader(request.SBuffer)) data.ReadFrom(jce.NewJceReader(request.SBuffer))
reader := jce.NewJceReader(data.Map["SvcRespParam"]["RegisterProxySvcPack.SvcRespParam"][1:]) reader := jce.NewJceReader(data.Map["SvcRespParam"]["RegisterProxySvcPack.SvcRespParam"][1:])
@ -352,9 +345,9 @@ func decodePushParamPacket(c *QQClient, _ *network.IncomingPacketInfo, payload [
} }
// RegPrxySvc.PbSyncMsg // RegPrxySvc.PbSyncMsg
func decodeMsgSyncResponse(c *QQClient, info *network.IncomingPacketInfo, payload []byte) (interface{}, error) { func decodeMsgSyncResponse(c *QQClient, resp *network.Response) (interface{}, error) {
rsp := &msf.SvcRegisterProxyMsgResp{} rsp := &msf.SvcRegisterProxyMsgResp{}
if err := proto.Unmarshal(payload, rsp); err != nil { if err := proto.Unmarshal(resp.Body, rsp); err != nil {
return nil, err return nil, err
} }
ret := &sessionSyncEvent{ ret := &sessionSyncEvent{
@ -389,26 +382,26 @@ func decodeMsgSyncResponse(c *QQClient, info *network.IncomingPacketInfo, payloa
if len(rsp.C2CMsg) > 4 { if len(rsp.C2CMsg) > 4 {
c2cRsp := &msg.GetMessageResponse{} c2cRsp := &msg.GetMessageResponse{}
if proto.Unmarshal(rsp.C2CMsg[4:], c2cRsp) == nil { if proto.Unmarshal(rsp.C2CMsg[4:], c2cRsp) == nil {
c.c2cMessageSyncProcessor(c2cRsp, info) c.c2cMessageSyncProcessor(c2cRsp, resp)
} }
} }
return ret, nil return ret, nil
} }
// OnlinePush.PbC2CMsgSync // OnlinePush.PbC2CMsgSync
func decodeC2CSyncPacket(c *QQClient, info *network.IncomingPacketInfo, payload []byte) (interface{}, error) { func decodeC2CSyncPacket(c *QQClient, resp *network.Response) (interface{}, error) {
m := msg.PbPushMsg{} m := msg.PbPushMsg{}
if err := proto.Unmarshal(payload, &m); err != nil { if err := proto.Unmarshal(resp.Body, &m); err != nil {
return nil, err return nil, err
} }
_ = c.sendPacket(c.buildDeleteOnlinePushPacket(c.Uin, m.GetSvrip(), m.GetPushToken(), info.SequenceId, nil)) _ = c.sendPacket(c.buildDeleteOnlinePushPacket(c.Uin, m.GetSvrip(), m.GetPushToken(), uint16(resp.SequenceID), nil))
c.commMsgProcessor(m.Msg, info) c.commMsgProcessor(m.Msg, resp)
return nil, nil return nil, nil
} }
func decodeMsgReadedResponse(_ *QQClient, _ *network.IncomingPacketInfo, payload []byte) (interface{}, error) { func decodeMsgReadedResponse(_ *QQClient, resp *network.Response) (interface{}, error) {
rsp := msg.PbMsgReadedReportResp{} rsp := msg.PbMsgReadedReportResp{}
if err := proto.Unmarshal(payload, &rsp); err != nil { if err := proto.Unmarshal(resp.Body, &rsp); err != nil {
return nil, errors.Wrap(err, "failed to unmarshal protobuf message") return nil, errors.Wrap(err, "failed to unmarshal protobuf message")
} }
if len(rsp.GrpReadReport) > 0 { if len(rsp.GrpReadReport) > 0 {
@ -420,9 +413,9 @@ func decodeMsgReadedResponse(_ *QQClient, _ *network.IncomingPacketInfo, payload
var loginNotifyLock sync.Mutex var loginNotifyLock sync.Mutex
// StatSvc.SvcReqMSFLoginNotify // StatSvc.SvcReqMSFLoginNotify
func decodeLoginNotifyPacket(c *QQClient, _ *network.IncomingPacketInfo, payload []byte) (interface{}, error) { func decodeLoginNotifyPacket(c *QQClient, resp *network.Response) (interface{}, error) {
request := &jce.RequestPacket{} request := &jce.RequestPacket{}
request.ReadFrom(jce.NewJceReader(payload)) request.ReadFrom(jce.NewJceReader(resp.Body))
data := &jce.RequestDataVersion2{} data := &jce.RequestDataVersion2{}
data.ReadFrom(jce.NewJceReader(request.SBuffer)) data.ReadFrom(jce.NewJceReader(request.SBuffer))
reader := jce.NewJceReader(data.Map["SvcReqMSFLoginNotify"]["QQService.SvcReqMSFLoginNotify"][1:]) reader := jce.NewJceReader(data.Map["SvcReqMSFLoginNotify"]["QQService.SvcReqMSFLoginNotify"][1:])

View File

@ -44,12 +44,12 @@ type (
) )
func (c *QQClient) GetGroupSystemMessages() (*GroupSystemMessages, error) { func (c *QQClient) GetGroupSystemMessages() (*GroupSystemMessages, error) {
i, err := c.sendAndWait(c.buildSystemMsgNewGroupPacket(false)) i, err := c.callAndDecode(c.buildSystemMsgNewGroupPacket(false))
if err != nil { if err != nil {
return nil, err return nil, err
} }
msg := i.(*GroupSystemMessages) msg := i.(*GroupSystemMessages)
i, err = c.sendAndWait(c.buildSystemMsgNewGroupPacket(true)) i, err = c.callAndDecode(c.buildSystemMsgNewGroupPacket(true))
if err != nil { if err != nil {
return nil, err return nil, err
} }
@ -98,7 +98,7 @@ func (c *QQClient) exceptAndDispatchGroupSysMsg() {
} }
// ProfileService.Pb.ReqSystemMsgNew.Group // ProfileService.Pb.ReqSystemMsgNew.Group
func (c *QQClient) buildSystemMsgNewGroupPacket(suspicious bool) (uint16, []byte) { func (c *QQClient) buildSystemMsgNewGroupPacket(suspicious bool) *network.Request {
req := &structmsg.ReqSystemMsgNew{ req := &structmsg.ReqSystemMsgNew{
MsgNum: 100, MsgNum: 100,
Version: 1000, Version: 1000,
@ -130,11 +130,11 @@ func (c *QQClient) buildSystemMsgNewGroupPacket(suspicious bool) (uint16, []byte
}(), }(),
} }
payload, _ := proto.Marshal(req) payload, _ := proto.Marshal(req)
return c.uniPacket("ProfileService.Pb.ReqSystemMsgNew.Group", payload) return c.uniRequest("ProfileService.Pb.ReqSystemMsgNew.Group", payload, decodeSystemMsgGroupPacket)
} }
// ProfileService.Pb.ReqSystemMsgAction.Group // ProfileService.Pb.ReqSystemMsgAction.Group
func (c *QQClient) buildSystemMsgGroupActionPacket(reqID, requester, group int64, msgType int32, isInvite, accept, block bool, reason string) (uint16, []byte) { func (c *QQClient) buildSystemMsgGroupActionPacket(reqID, requester, group int64, msgType int32, isInvite, accept, block bool, reason string) *network.Request {
subSrcId := int32(31) subSrcId := int32(31)
groupMsgType := int32(1) groupMsgType := int32(1)
if isInvite { if isInvite {
@ -163,11 +163,11 @@ func (c *QQClient) buildSystemMsgGroupActionPacket(reqID, requester, group int64
Language: 1000, Language: 1000,
} }
payload, _ := proto.Marshal(req) payload, _ := proto.Marshal(req)
return c.uniPacket("ProfileService.Pb.ReqSystemMsgAction.Group", payload) return c.uniRequest("ProfileService.Pb.ReqSystemMsgAction.Group", payload, nil)
} }
// ProfileService.Pb.ReqSystemMsgAction.Friend // ProfileService.Pb.ReqSystemMsgAction.Friend
func (c *QQClient) buildSystemMsgFriendActionPacket(reqID, requester int64, accept bool) (uint16, []byte) { func (c *QQClient) buildSystemMsgFriendActionPacket(reqID, requester int64, accept bool) *network.Request {
infoType := int32(3) infoType := int32(3)
if accept { if accept {
infoType = 2 infoType = 2
@ -186,13 +186,13 @@ func (c *QQClient) buildSystemMsgFriendActionPacket(reqID, requester int64, acce
}, },
} }
payload, _ := proto.Marshal(req) payload, _ := proto.Marshal(req)
return c.uniPacket("ProfileService.Pb.ReqSystemMsgAction.Friend", payload) return c.uniRequest("ProfileService.Pb.ReqSystemMsgAction.Friend", payload, nil)
} }
// ProfileService.Pb.ReqSystemMsgNew.Group // ProfileService.Pb.ReqSystemMsgNew.Group
func decodeSystemMsgGroupPacket(c *QQClient, _ *network.IncomingPacketInfo, payload []byte) (interface{}, error) { func decodeSystemMsgGroupPacket(c *QQClient, resp *network.Response) (interface{}, error) {
rsp := structmsg.RspSystemMsgNew{} rsp := structmsg.RspSystemMsgNew{}
if err := proto.Unmarshal(payload, &rsp); err != nil { if err := proto.Unmarshal(resp.Body, &rsp); err != nil {
return nil, err return nil, err
} }
ret := &GroupSystemMessages{} ret := &GroupSystemMessages{}

View File

@ -8,7 +8,7 @@ import (
"github.com/Mrs4s/MiraiGo/internal/proto" "github.com/Mrs4s/MiraiGo/internal/proto"
) )
func (c *QQClient) buildTranslatePacket(src, dst, text string) (uint16, []byte) { func (c *QQClient) buildTranslatePacket(src, dst, text string) *network.Request {
body := &oidb.TranslateReqBody{ body := &oidb.TranslateReqBody{
BatchTranslateReq: &oidb.BatchTranslateReq{ BatchTranslateReq: &oidb.BatchTranslateReq{
SrcLanguage: src, SrcLanguage: src,
@ -23,11 +23,11 @@ func (c *QQClient) buildTranslatePacket(src, dst, text string) (uint16, []byte)
Bodybuffer: b, Bodybuffer: b,
} }
payload, _ := proto.Marshal(req) payload, _ := proto.Marshal(req)
return c.uniPacket("OidbSvc.0x990", payload) return c.uniRequest("OidbSvc.0x990", payload, decodeTranslateResponse)
} }
func (c *QQClient) Translate(src, dst, text string) (string, error) { func (c *QQClient) Translate(src, dst, text string) (string, error) {
rsp, err := c.sendAndWait(c.buildTranslatePacket(src, dst, text)) rsp, err := c.callAndDecode(c.buildTranslatePacket(src, dst, text))
if err != nil { if err != nil {
return "", err return "", err
} }
@ -41,10 +41,10 @@ func (c *QQClient) Translate(src, dst, text string) (string, error) {
} }
// OidbSvc.0x990 // OidbSvc.0x990
func decodeTranslateResponse(_ *QQClient, _ *network.IncomingPacketInfo, payload []byte) (interface{}, error) { func decodeTranslateResponse(_ *QQClient, resp *network.Response) (interface{}, error) {
pkg := oidb.OIDBSSOPkg{} pkg := oidb.OIDBSSOPkg{}
rsp := oidb.TranslateRspBody{} rsp := oidb.TranslateRspBody{}
if err := proto.Unmarshal(payload, &pkg); err != nil { if err := proto.Unmarshal(resp.Body, &pkg); err != nil {
return nil, errors.Wrap(err, "failed to unmarshal protobuf message") return nil, errors.Wrap(err, "failed to unmarshal protobuf message")
} }
if err := proto.Unmarshal(pkg.Bodybuffer, &rsp); err != nil { if err := proto.Unmarshal(pkg.Bodybuffer, &rsp); err != nil {

View File

@ -90,12 +90,12 @@ func (c *QQClient) webSsoRequest(host, webCmd, data string) (string, error) {
Type: proto.Uint32(0), Type: proto.Uint32(0),
Data: &data, Data: &data,
}) })
rspData, err := c.sendAndWaitDynamic(c.uniPacket(cmd, req)) rspData, err := c.call(c.uniRequest(cmd, req, nil))
if err != nil { if err != nil {
return "", errors.Wrap(err, "send web sso request error") return "", errors.Wrap(err, "send web sso request error")
} }
rsp := &web.WebSsoResponseBody{} rsp := &web.WebSsoResponseBody{}
if err = proto.Unmarshal(rspData, rsp); err != nil { if err = proto.Unmarshal(rspData.Body, rsp); err != nil {
return "", errors.Wrap(err, "unmarshal response error") return "", errors.Wrap(err, "unmarshal response error")
} }
return rsp.GetData(), nil return rsp.GetData(), nil

View File

@ -27,7 +27,7 @@ const (
{{end}} {{end}}
) )
func peekC2CDecoder(msgType int32) (decoder func(*QQClient, *msg.Message, *network.IncomingPacketInfo), decoderType uint8) { func peekC2CDecoder(msgType int32) (decoder func(*QQClient, *msg.Message, *network.Response), decoderType uint8) {
switch msgType { switch msgType {
{{range .Decoders}} case {{.Id}}: {{range .Decoders}} case {{.Id}}:
return {{.Func}}, {{.DecoderType}} return {{.Func}}, {{.DecoderType}}

View File

@ -1,30 +0,0 @@
package packets
import (
"github.com/Mrs4s/MiraiGo/binary"
)
type IncomingPacket struct {
SequenceId uint16
Flag2 byte
CommandName string
SessionId []byte
Payload []byte
}
func BuildCode2DRequestPacket(seq uint32, j uint64, cmd uint16, bodyFunc func(writer *binary.Writer)) []byte {
return binary.NewWriterF(func(w *binary.Writer) {
w.WriteByte(2)
pos := w.FillUInt16()
w.WriteUInt16(cmd)
w.Write(make([]byte, 21))
w.WriteByte(3)
w.WriteUInt16(0)
w.WriteUInt16(50) // version
w.WriteUInt32(seq)
w.WriteUInt64(j)
bodyFunc(w)
w.WriteByte(3)
w.WriteUInt16At(pos, uint16(w.Len()))
})
}

View File

@ -106,8 +106,10 @@ type AnimatedSticker struct {
Name string Name string
} }
type RedBagMessageType int type (
type AtType int RedBagMessageType int
AtType int
)
// /com/tencent/mobileqq/data/MessageForQQWalletMsg.java // /com/tencent/mobileqq/data/MessageForQQWalletMsg.java
const ( const (

View File

@ -236,6 +236,7 @@ func ToProtoElems(elems []IMessageElement, generalFlags bool) (r []*msg.Elem) {
if len(elems) == 0 { if len(elems) == 0 {
return nil return nil
} }
r = make([]*msg.Elem, 0, len(elems))
for _, elem := range elems { for _, elem := range elems {
if reply, ok := elem.(*ReplyElement); ok { if reply, ok := elem.(*ReplyElement); ok {
r = append(r, &msg.Elem{ r = append(r, &msg.Elem{
@ -776,7 +777,7 @@ func splitPlainMessage(content string) []IMessageElement {
} }
} }
if last != len(content) { if last != len(content) {
splittedMessage = append(splittedMessage, NewText(content[last:len(content)])) splittedMessage = append(splittedMessage, NewText(content[last:]))
} }
return splittedMessage return splittedMessage

26
utils/func.go Normal file
View File

@ -0,0 +1,26 @@
package utils
import "fmt"
// CoverError == catch{}
func CoverError(fun func()) error {
if fun == nil {
return nil
}
errCh := make(chan error, 1)
func() {
defer func() {
if r := recover(); r != nil {
if err, ok := r.(error); ok {
errCh <- err
} else {
errCh <- fmt.Errorf("%v", r)
}
} else {
errCh <- nil
}
}()
fun()
}()
return <-errCh
}

29
utils/func_test.go Normal file
View File

@ -0,0 +1,29 @@
package utils
import (
"errors"
"testing"
)
var errTest = errors.New("test error")
func TestCoverError(t *testing.T) {
err := CoverError(nil)
if err != nil {
t.Errorf(`CoverError(nil) = %v, want nil`, err)
}
err = CoverError(func() {
panic("test")
})
if err.Error() != "test" {
t.Errorf(`CoverError(func() { panic("test") }) = %v, want "test"`, err)
}
err = CoverError(func() {
panic(errTest)
})
if err != errTest {
t.Errorf(`CoverError(func() { panic(errTest) }) = %v, want errTest`, err)
}
}

View File

@ -11,9 +11,6 @@ import (
var client = &http.Client{ var client = &http.Client{
Transport: &http.Transport{ Transport: &http.Transport{
ForceAttemptHTTP2: true, ForceAttemptHTTP2: true,
MaxConnsPerHost: 0,
MaxIdleConns: 0,
MaxIdleConnsPerHost: 999,
}, },
} }