mirror of
https://github.com/Mrs4s/MiraiGo.git
synced 2025-07-08 15:18:32 +00:00
Compare commits
8 Commits
367f1d52e9
...
network
Author | SHA1 | Date | |
---|---|---|---|
102bda2cfa | |||
aa4e0e0bbe | |||
c1cbb69110 | |||
6a71884235 | |||
f5b16b19c2 | |||
9bd6b38f90 | |||
435d2fd85f | |||
723563415f |
@ -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
|
||||||
|
@ -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,
|
||||||
}
|
}
|
||||||
|
@ -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)
|
||||||
}
|
}
|
||||||
|
@ -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
|
||||||
}
|
}
|
||||||
|
@ -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
|
||||||
|
347
client/client.go
347
client/client.go
@ -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
|
version *auth.AppVersion
|
||||||
servers []*net.TCPAddr
|
deviceInfo *auth.Device
|
||||||
currServerIndex int
|
|
||||||
retryTimes int
|
|
||||||
version *auth.AppVersion
|
|
||||||
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)
|
"StatSvc.ReqMSFOffline": decodeMSFOfflinePacket,
|
||||||
dynamic bool
|
"MessageSvc.PushNotify": decodeSvcNotify,
|
||||||
params network.RequestParams
|
"OnlinePush.ReqPush": decodeOnlinePushReqPacket,
|
||||||
}
|
"OnlinePush.PbPushTransMsg": decodeOnlinePushTransPacket,
|
||||||
|
"OnlinePush.SidTicketExpired": decodeSidExpiredPacket,
|
||||||
func (h *handlerInfo) getParams() network.RequestParams {
|
"ConfigPushSvc.PushReq": decodePushReqPacket,
|
||||||
if h == nil {
|
"MessageSvc.PushForceOffline": decodeForceOfflinePacket,
|
||||||
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,
|
|
||||||
"MessageSvc.PushNotify": decodeSvcNotify,
|
|
||||||
"OnlinePush.ReqPush": decodeOnlinePushReqPacket,
|
|
||||||
"OnlinePush.PbPushTransMsg": decodeOnlinePushTransPacket,
|
|
||||||
"OnlinePush.SidTicketExpired": decodeSidExpiredPacket,
|
|
||||||
"ConfigPushSvc.PushReq": decodePushReqPacket,
|
|
||||||
"MessageSvc.PbGetMsg": decodeMessageSvcPacket,
|
|
||||||
"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()
|
go c.doHeartbeat()
|
||||||
if !c.heartbeatEnabled {
|
|
||||||
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 // 下线停止goroutine,for 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
|
|
||||||
}
|
}
|
||||||
|
@ -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,19 +267,20 @@ 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:
|
||||||
|
qrResp.State = QRCodeWaitingForScan
|
||||||
|
case 0x35:
|
||||||
|
qrResp.State = QRCodeWaitingForConfirm
|
||||||
|
case 0x36:
|
||||||
|
qrResp.State = QRCodeCanceled
|
||||||
|
case 0x11:
|
||||||
|
qrResp.State = QRCodeTimeout
|
||||||
|
default:
|
||||||
|
return nil, errors.Errorf("wtlogin.trans_emp sub cmd 0x12 error: %v", code)
|
||||||
}
|
}
|
||||||
if code == 0x35 {
|
return qrResp, nil
|
||||||
return &QRCodeLoginResponse{State: QRCodeWaitingForConfirm}, nil
|
|
||||||
}
|
|
||||||
if code == 0x36 {
|
|
||||||
return &QRCodeLoginResponse{State: QRCodeCanceled}, nil
|
|
||||||
}
|
|
||||||
if code == 0x11 {
|
|
||||||
return &QRCodeLoginResponse{State: QRCodeTimeout}, nil
|
|
||||||
}
|
|
||||||
return nil, errors.Errorf("wtlogin.trans_emp sub cmd 0x12 error: %v", code)
|
|
||||||
}
|
}
|
||||||
c.Uin = body.ReadInt64()
|
c.Uin = body.ReadInt64()
|
||||||
c.highwaySession.Uin = strconv.FormatInt(c.Uin, 10)
|
c.highwaySession.Uin = strconv.FormatInt(c.Uin, 10)
|
||||||
@ -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
|
|
||||||
}
|
|
||||||
|
@ -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 {
|
||||||
|
@ -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 {
|
||||||
|
@ -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 {
|
||||||
|
@ -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 {
|
||||||
|
105
client/guild.go
105
client/guild.go
@ -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 {
|
||||||
|
@ -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 {
|
||||||
|
@ -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")
|
||||||
}
|
}
|
||||||
|
@ -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
|
|
||||||
}
|
|
@ -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 {
|
||||||
|
@ -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)
|
// PlannedDisconnect 预料中的断开连接
|
||||||
|
// 如调用 Close() Connect()
|
||||||
|
PlannedDisconnect func(*TCPListener)
|
||||||
|
|
||||||
|
// UnexpectedDisconnect 未预料的断开连接
|
||||||
|
UnexpectedDisconnect func(*TCPListener, error)
|
||||||
}
|
}
|
||||||
|
|
||||||
var ErrConnectionClosed = errors.New("connection closed")
|
func (t *TCPListener) getConn() *net.TCPConn {
|
||||||
|
return (*net.TCPConn)(atomic.LoadPointer((*unsafe.Pointer)(unsafe.Pointer(&t.conn))))
|
||||||
// PlannedDisconnect 预料中的断开连接
|
|
||||||
// 如调用 Close() Connect()
|
|
||||||
func (t *TCPListener) PlannedDisconnect(f func(*TCPListener)) {
|
|
||||||
t.lock.Lock()
|
|
||||||
defer t.lock.Unlock()
|
|
||||||
t.plannedDisconnect = f
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// UnexpectedDisconnect 未预料的断开连接
|
func (t *TCPListener) setConn(conn *net.TCPConn) (swapped bool) {
|
||||||
func (t *TCPListener) UnexpectedDisconnect(f func(*TCPListener, error)) {
|
return atomic.CompareAndSwapPointer((*unsafe.Pointer)(unsafe.Pointer(&t.conn)), unsafe.Pointer(nil), unsafe.Pointer(conn))
|
||||||
t.lock.Lock()
|
}
|
||||||
defer t.lock.Unlock()
|
|
||||||
t.unexpectedDisconnect = f
|
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
|
||||||
}
|
//}
|
||||||
|
@ -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)
|
|
||||||
}
|
|
@ -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
|
||||||
}
|
}
|
||||||
|
@ -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
|
||||||
}
|
}
|
||||||
|
34
client/internal/network/rpc.go
Normal file
34
client/internal/network/rpc.go
Normal 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)
|
||||||
|
}
|
@ -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)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
@ -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
|
||||||
}
|
}
|
||||||
|
@ -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)
|
||||||
}
|
if err != nil {
|
||||||
|
c.pendingMu.Lock()
|
||||||
c.handlers.Store(seq, &handlerInfo{fun: func(i interface{}, err error) {
|
call = c.pending[seq]
|
||||||
ch <- T{
|
delete(c.pending, seq)
|
||||||
Response: i,
|
c.pendingMu.Unlock()
|
||||||
Error: err,
|
call.Err = err
|
||||||
}
|
call.Done <- call
|
||||||
}, params: p, dynamic: false})
|
}
|
||||||
|
}
|
||||||
err := c.sendPacket(pkt)
|
|
||||||
|
func (c *QQClient) sendReq(req *network.Request) {
|
||||||
|
c.send(&network.Call{Request: req})
|
||||||
|
}
|
||||||
|
|
||||||
|
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")
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func (c *QQClient) callAndDecode(req *network.Request) (interface{}, error) {
|
||||||
|
resp, err := c.call(req)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
c.handlers.Delete(seq)
|
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
|
return req.Decode(resp)
|
||||||
retry := 0
|
|
||||||
for {
|
|
||||||
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)
|
|
||||||
return nil, errors.New("Packet timed out")
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// 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
|
c.Disconnect()
|
||||||
|
go c.dispatchDisconnectEvent(&ClientDisconnectedEvent{Message: "session expired"})
|
||||||
}
|
}
|
||||||
if l < 4 || l > 1024*1024*10 { // max 10MB
|
c.Error("parse incoming packet error: %v", netErr)
|
||||||
c.Error("parse incoming packet error: invalid packet length %v", l)
|
return
|
||||||
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()
|
|
||||||
go c.dispatchDisconnectEvent(&ClientDisconnectedEvent{Message: "session expired"})
|
|
||||||
continue
|
|
||||||
}
|
|
||||||
errCount++
|
|
||||||
if errCount > 2 {
|
|
||||||
go c.quickReconnect()
|
|
||||||
}
|
|
||||||
continue
|
|
||||||
}
|
|
||||||
if resp.EncryptType == network.EncryptTypeEmptyKey {
|
|
||||||
m, err := c.oicq.Unmarshal(resp.Body)
|
|
||||||
if err != nil {
|
|
||||||
c.Error("decrypt payload error: %v", err)
|
|
||||||
if errors.Is(err, oicq.ErrUnknownFlag) {
|
|
||||||
go c.quickReconnect()
|
|
||||||
}
|
|
||||||
continue
|
|
||||||
}
|
|
||||||
resp.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() {
|
|
||||||
if pan := recover(); pan != nil {
|
|
||||||
c.Error("panic on decoder %v : %v\n%s", pkt.CommandName, pan, debug.Stack())
|
|
||||||
c.Dump("packet decode error: %v - %v", pkt.Payload, pkt.CommandName, pan)
|
|
||||||
}
|
|
||||||
}()
|
|
||||||
|
|
||||||
if decoder, ok := decoders[pkt.CommandName]; ok {
|
if req.EncryptType == network.EncryptTypeEmptyKey {
|
||||||
// found predefined decoder
|
m, err := c.oicq.Unmarshal(req.Body)
|
||||||
info, ok := c.handlers.LoadAndDelete(pkt.SequenceId)
|
if err != nil {
|
||||||
var decoded interface{}
|
c.Error("decrypt payload error: %v", err)
|
||||||
decoded = pkt.Payload
|
if errors.Is(err, oicq.ErrUnknownFlag) {
|
||||||
if info == nil || !info.dynamic {
|
go c.quickReconnect() // TODO "服务器发送未知响应"
|
||||||
decoded, err = decoder(c, &network.IncomingPacketInfo{
|
|
||||||
SequenceId: pkt.SequenceId,
|
|
||||||
CommandName: pkt.CommandName,
|
|
||||||
Params: info.getParams(),
|
|
||||||
}, pkt.Payload)
|
|
||||||
if err != nil {
|
|
||||||
c.Debug("decode pkt %v error: %+v", pkt.CommandName, err)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
if ok {
|
|
||||||
info.fun(decoded, err)
|
|
||||||
} else if f, ok := c.waiters.Load(pkt.CommandName); ok { // 在不存在handler的情况下触发wait
|
|
||||||
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 {
|
|
||||||
c.Debug("Unhandled Command: %s\nSeq: %d\nThis message can be ignored.", pkt.CommandName, pkt.SequenceId)
|
|
||||||
}
|
}
|
||||||
}(pkt)
|
}
|
||||||
|
req.Body = m.Body
|
||||||
|
}
|
||||||
|
|
||||||
|
defer func() {
|
||||||
|
if pan := recover(); pan != nil {
|
||||||
|
c.Error("panic on decoder %v : %v\n%s", req.CommandName, pan, debug.Stack())
|
||||||
|
c.Dump("packet decode error: %v - %v", req.Body, req.CommandName, pan)
|
||||||
|
}
|
||||||
|
}()
|
||||||
|
|
||||||
|
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
|
||||||
|
resp := network.Response{
|
||||||
|
SequenceID: req.SequenceID,
|
||||||
|
CommandName: req.CommandName,
|
||||||
|
Body: req.Body,
|
||||||
|
// Request: nil,
|
||||||
|
}
|
||||||
|
decoded, err := decoder(c, &resp)
|
||||||
|
if err != nil {
|
||||||
|
c.Debug("decode req %v error: %+v", req.CommandName, err)
|
||||||
|
}
|
||||||
|
if f, ok := c.waiters.Load(req.CommandName); ok { // 在不存在handler的情况下触发wait
|
||||||
|
f.(func(interface{}, error))(decoded, err)
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
c.Debug("Unhandled Command: %s\nSeq: %d\nThis message can be ignored.", req.CommandName, req.SequenceID)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -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")
|
||||||
}
|
}
|
||||||
|
@ -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 {
|
||||||
|
@ -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
|
||||||
}
|
}
|
||||||
|
@ -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)
|
||||||
}
|
}
|
||||||
|
@ -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 {
|
||||||
|
@ -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 {
|
||||||
|
@ -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 {
|
||||||
|
@ -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)
|
||||||
}
|
}
|
||||||
|
@ -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 {
|
||||||
|
@ -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:])
|
||||||
|
@ -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{}
|
||||||
|
@ -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 {
|
||||||
|
@ -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
|
||||||
|
@ -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}}
|
||||||
|
@ -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()))
|
|
||||||
})
|
|
||||||
}
|
|
@ -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 (
|
||||||
|
@ -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
26
utils/func.go
Normal 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
29
utils/func_test.go
Normal 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)
|
||||||
|
}
|
||||||
|
}
|
@ -10,10 +10,7 @@ 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,
|
|
||||||
},
|
},
|
||||||
}
|
}
|
||||||
|
|
||||||
|
Reference in New Issue
Block a user