mirror of
https://github.com/Mrs4s/MiraiGo.git
synced 2025-05-04 19:17:38 +08:00
add: friend message sending.
add: friend image uploading.
This commit is contained in:
parent
9d81397b5d
commit
7fd853ef0b
@ -2,9 +2,11 @@ package client
|
|||||||
|
|
||||||
import (
|
import (
|
||||||
"crypto/md5"
|
"crypto/md5"
|
||||||
|
"encoding/hex"
|
||||||
"github.com/Mrs4s/MiraiGo/binary"
|
"github.com/Mrs4s/MiraiGo/binary"
|
||||||
"github.com/Mrs4s/MiraiGo/binary/jce"
|
"github.com/Mrs4s/MiraiGo/binary/jce"
|
||||||
"github.com/Mrs4s/MiraiGo/client/pb"
|
"github.com/Mrs4s/MiraiGo/client/pb"
|
||||||
|
"github.com/Mrs4s/MiraiGo/client/pb/cmd0x352"
|
||||||
"github.com/Mrs4s/MiraiGo/client/pb/msg"
|
"github.com/Mrs4s/MiraiGo/client/pb/msg"
|
||||||
"github.com/Mrs4s/MiraiGo/client/pb/structmsg"
|
"github.com/Mrs4s/MiraiGo/client/pb/structmsg"
|
||||||
"github.com/Mrs4s/MiraiGo/message"
|
"github.com/Mrs4s/MiraiGo/message"
|
||||||
@ -13,7 +15,14 @@ import (
|
|||||||
"github.com/Mrs4s/MiraiGo/protocol/tlv"
|
"github.com/Mrs4s/MiraiGo/protocol/tlv"
|
||||||
"github.com/Mrs4s/MiraiGo/utils"
|
"github.com/Mrs4s/MiraiGo/utils"
|
||||||
"github.com/golang/protobuf/proto"
|
"github.com/golang/protobuf/proto"
|
||||||
|
"math/rand"
|
||||||
"strconv"
|
"strconv"
|
||||||
|
"time"
|
||||||
|
)
|
||||||
|
|
||||||
|
var (
|
||||||
|
syncConst1 = rand.Int63()
|
||||||
|
syncConst2 = rand.Int63()
|
||||||
)
|
)
|
||||||
|
|
||||||
func (c *QQClient) buildLoginPacket() (uint16, []byte) {
|
func (c *QQClient) buildLoginPacket() (uint16, []byte) {
|
||||||
@ -383,7 +392,7 @@ func (c *QQClient) buildGroupSendingPacket(groupCode int64, r int32, m *message.
|
|||||||
Elems: message.ToProtoElems(m.Elements),
|
Elems: message.ToProtoElems(m.Elements),
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
MsgSeq: c.nextMessageSeq(),
|
MsgSeq: c.nextGroupSeq(),
|
||||||
MsgRand: r,
|
MsgRand: r,
|
||||||
SyncCookie: EmptyBytes,
|
SyncCookie: EmptyBytes,
|
||||||
MsgVia: 1,
|
MsgVia: 1,
|
||||||
@ -394,6 +403,66 @@ func (c *QQClient) buildGroupSendingPacket(groupCode int64, r int32, m *message.
|
|||||||
return seq, packet
|
return seq, packet
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// MessageSvc.PbSendMsg
|
||||||
|
func (c *QQClient) buildFriendSendingPacket(target int64, r int32, m *message.SendingMessage) (uint16, []byte) {
|
||||||
|
seq := c.nextSeq()
|
||||||
|
req := &msg.SendMessageRequest{
|
||||||
|
RoutingHead: &msg.RoutingHead{C2C: &msg.C2C{ToUin: target}},
|
||||||
|
ContentHead: &msg.ContentHead{PkgNum: 1},
|
||||||
|
MsgBody: &msg.MessageBody{
|
||||||
|
RichText: &msg.RichText{
|
||||||
|
Elems: message.ToProtoElems(m.Elements),
|
||||||
|
},
|
||||||
|
},
|
||||||
|
MsgSeq: c.nextFriendSeq(),
|
||||||
|
MsgRand: r,
|
||||||
|
SyncCookie: func() []byte {
|
||||||
|
cookie := &msg.SyncCookie{
|
||||||
|
Time: time.Now().Unix(),
|
||||||
|
Ran1: rand.Int63(),
|
||||||
|
Ran2: rand.Int63(),
|
||||||
|
Const1: syncConst1,
|
||||||
|
Const2: syncConst2,
|
||||||
|
Const3: 0x1d,
|
||||||
|
}
|
||||||
|
b, _ := proto.Marshal(cookie)
|
||||||
|
return b
|
||||||
|
}(),
|
||||||
|
}
|
||||||
|
payload, _ := proto.Marshal(req)
|
||||||
|
packet := packets.BuildUniPacket(c.Uin, seq, "MessageSvc.PbSendMsg", 1, c.OutGoingPacketSessionId, EmptyBytes, c.sigInfo.d2Key, payload)
|
||||||
|
return seq, packet
|
||||||
|
}
|
||||||
|
|
||||||
|
// LongConn.OffPicUp
|
||||||
|
func (c *QQClient) buildOffPicUpPacket(target int64, md5 []byte, size int32) (uint16, []byte) {
|
||||||
|
seq := c.nextSeq()
|
||||||
|
req := &cmd0x352.ReqBody{
|
||||||
|
Subcmd: 1,
|
||||||
|
MsgTryupImgReq: []*cmd0x352.D352TryUpImgReq{
|
||||||
|
{
|
||||||
|
SrcUin: int32(c.Uin),
|
||||||
|
DstUin: int32(target),
|
||||||
|
FileMd5: md5,
|
||||||
|
FileSize: size,
|
||||||
|
Filename: hex.EncodeToString(md5) + ".jpg",
|
||||||
|
SrcTerm: 5,
|
||||||
|
PlatformType: 9,
|
||||||
|
BuType: 1,
|
||||||
|
ImgOriginal: 1,
|
||||||
|
ImgType: 1000,
|
||||||
|
BuildVer: "8.2.7.4410",
|
||||||
|
FileIndex: EmptyBytes,
|
||||||
|
SrvUpload: 1,
|
||||||
|
TransferUrl: EmptyBytes,
|
||||||
|
},
|
||||||
|
},
|
||||||
|
}
|
||||||
|
payload, _ := proto.Marshal(req)
|
||||||
|
packet := packets.BuildUniPacket(c.Uin, seq, "LongConn.OffPicUp", 1, c.OutGoingPacketSessionId, EmptyBytes, c.sigInfo.d2Key, payload)
|
||||||
|
return seq, packet
|
||||||
|
}
|
||||||
|
|
||||||
// ImgStore.GroupPicUp
|
// ImgStore.GroupPicUp
|
||||||
func (c *QQClient) buildGroupImageStorePacket(groupCode int64, md5 []byte, size int32) (uint16, []byte) {
|
func (c *QQClient) buildGroupImageStorePacket(groupCode int64, md5 []byte, size int32) (uint16, []byte) {
|
||||||
seq := c.nextSeq()
|
seq := c.nextSeq()
|
||||||
|
107
client/client.go
107
client/client.go
@ -4,11 +4,9 @@ import (
|
|||||||
"crypto/md5"
|
"crypto/md5"
|
||||||
"errors"
|
"errors"
|
||||||
"github.com/Mrs4s/MiraiGo/binary"
|
"github.com/Mrs4s/MiraiGo/binary"
|
||||||
"github.com/Mrs4s/MiraiGo/client/pb"
|
|
||||||
"github.com/Mrs4s/MiraiGo/message"
|
"github.com/Mrs4s/MiraiGo/message"
|
||||||
"github.com/Mrs4s/MiraiGo/protocol/packets"
|
"github.com/Mrs4s/MiraiGo/protocol/packets"
|
||||||
"github.com/Mrs4s/MiraiGo/utils"
|
"github.com/Mrs4s/MiraiGo/utils"
|
||||||
"github.com/golang/protobuf/proto"
|
|
||||||
"io"
|
"io"
|
||||||
"log"
|
"log"
|
||||||
"math/rand"
|
"math/rand"
|
||||||
@ -28,6 +26,7 @@ type QQClient struct {
|
|||||||
Gender uint16
|
Gender uint16
|
||||||
FriendList []*FriendInfo
|
FriendList []*FriendInfo
|
||||||
GroupList []*GroupInfo
|
GroupList []*GroupInfo
|
||||||
|
Online bool
|
||||||
|
|
||||||
SequenceId uint16
|
SequenceId uint16
|
||||||
OutGoingPacketSessionId []byte
|
OutGoingPacketSessionId []byte
|
||||||
@ -50,14 +49,14 @@ type QQClient struct {
|
|||||||
timeDiff int64
|
timeDiff int64
|
||||||
sigInfo *loginSigInfo
|
sigInfo *loginSigInfo
|
||||||
pwdFlag bool
|
pwdFlag bool
|
||||||
running bool
|
|
||||||
|
|
||||||
lastMessageSeq int32
|
lastMessageSeq int32
|
||||||
lastMessageSeqTmp sync.Map
|
lastMessageSeqTmp sync.Map
|
||||||
groupMsgBuilders sync.Map
|
groupMsgBuilders sync.Map
|
||||||
onlinePushCache []int16 // reset on reconnect
|
onlinePushCache []int16 // reset on reconnect
|
||||||
requestPacketRequestId int32
|
requestPacketRequestId int32
|
||||||
messageSeq int32
|
groupSeq int32
|
||||||
|
friendSeq int32
|
||||||
groupDataTransSeq int32
|
groupDataTransSeq int32
|
||||||
eventHandlers *eventHandlers
|
eventHandlers *eventHandlers
|
||||||
|
|
||||||
@ -107,6 +106,7 @@ func NewClientMd5(uin int64, passwordMd5 [16]byte) *QQClient {
|
|||||||
"friendlist.GetTroopListReqV2": decodeGroupListResponse,
|
"friendlist.GetTroopListReqV2": decodeGroupListResponse,
|
||||||
"friendlist.GetTroopMemberListReq": decodeGroupMemberListResponse,
|
"friendlist.GetTroopMemberListReq": decodeGroupMemberListResponse,
|
||||||
"ImgStore.GroupPicUp": decodeGroupImageStoreResponse,
|
"ImgStore.GroupPicUp": decodeGroupImageStoreResponse,
|
||||||
|
"LongConn.OffPicUp": decodeOffPicUpResponse,
|
||||||
"ProfileService.Pb.ReqSystemMsgNew.Group": decodeSystemMsgGroupPacket,
|
"ProfileService.Pb.ReqSystemMsgNew.Group": decodeSystemMsgGroupPacket,
|
||||||
"ProfileService.Pb.ReqSystemMsgNew.Friend": decodeSystemMsgFriendPacket,
|
"ProfileService.Pb.ReqSystemMsgNew.Friend": decodeSystemMsgFriendPacket,
|
||||||
//"MultiMsg.ApplyDown": decodeMultiMsgDownPacket,
|
//"MultiMsg.ApplyDown": decodeMultiMsgDownPacket,
|
||||||
@ -114,7 +114,8 @@ func NewClientMd5(uin int64, passwordMd5 [16]byte) *QQClient {
|
|||||||
handlers: map[uint16]func(interface{}, error){},
|
handlers: map[uint16]func(interface{}, error){},
|
||||||
sigInfo: &loginSigInfo{},
|
sigInfo: &loginSigInfo{},
|
||||||
requestPacketRequestId: 1921334513,
|
requestPacketRequestId: 1921334513,
|
||||||
messageSeq: 22911,
|
groupSeq: 22911,
|
||||||
|
friendSeq: 22911,
|
||||||
ksid: []byte("|454001228437590|A8.2.7.27f6ea96"),
|
ksid: []byte("|454001228437590|A8.2.7.27f6ea96"),
|
||||||
eventHandlers: &eventHandlers{},
|
eventHandlers: &eventHandlers{},
|
||||||
groupListLock: new(sync.Mutex),
|
groupListLock: new(sync.Mutex),
|
||||||
@ -125,14 +126,14 @@ func NewClientMd5(uin int64, passwordMd5 [16]byte) *QQClient {
|
|||||||
|
|
||||||
// Login send login request
|
// Login send login request
|
||||||
func (c *QQClient) Login() (*LoginResponse, error) {
|
func (c *QQClient) Login() (*LoginResponse, error) {
|
||||||
if c.running {
|
if c.Online {
|
||||||
return nil, ErrAlreadyRunning
|
return nil, ErrAlreadyOnline
|
||||||
}
|
}
|
||||||
err := c.connect()
|
err := c.connect()
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
c.running = true
|
c.Online = true
|
||||||
go c.loop()
|
go c.loop()
|
||||||
seq, packet := c.buildLoginPacket()
|
seq, packet := c.buildLoginPacket()
|
||||||
rsp, err := c.sendAndWait(seq, packet)
|
rsp, err := c.sendAndWait(seq, packet)
|
||||||
@ -226,6 +227,12 @@ func (c *QQClient) SendGroupMessage(groupCode int64, m *message.SendingMessage)
|
|||||||
return ret
|
return ret
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func (c *QQClient) SendPrivateMessage(target int64, m *message.SendingMessage) {
|
||||||
|
mr := int32(rand.Uint32())
|
||||||
|
_, pkt := c.buildFriendSendingPacket(target, mr, m)
|
||||||
|
_ = c.send(pkt)
|
||||||
|
}
|
||||||
|
|
||||||
func (c *QQClient) RecallGroupMessage(groupCode int64, msgId, msgInternalId int32) {
|
func (c *QQClient) RecallGroupMessage(groupCode int64, msgId, msgInternalId int32) {
|
||||||
_, pkt := c.buildGroupRecallPacket(groupCode, msgId, msgInternalId)
|
_, pkt := c.buildGroupRecallPacket(groupCode, msgId, msgInternalId)
|
||||||
_ = c.send(pkt)
|
_ = c.send(pkt)
|
||||||
@ -238,7 +245,7 @@ func (c *QQClient) UploadGroupImage(groupCode int64, img []byte) (*message.Group
|
|||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
rsp := r.(groupImageUploadResponse)
|
rsp := r.(imageUploadResponse)
|
||||||
if rsp.ResultCode != 0 {
|
if rsp.ResultCode != 0 {
|
||||||
return nil, errors.New(rsp.Message)
|
return nil, errors.New(rsp.Message)
|
||||||
}
|
}
|
||||||
@ -247,48 +254,52 @@ func (c *QQClient) UploadGroupImage(groupCode int64, img []byte) (*message.Group
|
|||||||
}
|
}
|
||||||
for i, ip := range rsp.UploadIp {
|
for i, ip := range rsp.UploadIp {
|
||||||
updServer := binary.UInt32ToIPV4Address(uint32(ip))
|
updServer := binary.UInt32ToIPV4Address(uint32(ip))
|
||||||
conn, err := net.DialTimeout("tcp", updServer+":"+strconv.FormatInt(int64(rsp.UploadPort[i]), 10), time.Second*5)
|
err := c.highwayUploadImage(updServer+":"+strconv.FormatInt(int64(rsp.UploadPort[i]), 10), rsp.UploadKey, img)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
continue
|
return nil, err
|
||||||
}
|
|
||||||
if conn.SetDeadline(time.Now().Add(time.Second*10)) != nil {
|
|
||||||
_ = conn.Close()
|
|
||||||
continue
|
|
||||||
}
|
|
||||||
pkt := c.buildImageUploadPacket(img, rsp.UploadKey, 2, h)
|
|
||||||
for _, p := range pkt {
|
|
||||||
_, err = conn.Write(p)
|
|
||||||
}
|
|
||||||
if err != nil {
|
|
||||||
continue
|
|
||||||
}
|
|
||||||
r := binary.NewNetworkReader(conn)
|
|
||||||
_, err = r.ReadByte()
|
|
||||||
if err != nil {
|
|
||||||
continue
|
|
||||||
}
|
|
||||||
hl, _ := r.ReadInt32()
|
|
||||||
_, _ = r.ReadBytes(4)
|
|
||||||
payload, _ := r.ReadBytes(int(hl))
|
|
||||||
_ = conn.Close()
|
|
||||||
rsp := pb.RspDataHighwayHead{}
|
|
||||||
if proto.Unmarshal(payload, &rsp) != nil {
|
|
||||||
continue
|
|
||||||
}
|
|
||||||
if rsp.ErrorCode != 0 {
|
|
||||||
return nil, errors.New("upload failed")
|
|
||||||
}
|
}
|
||||||
return message.NewGroupImage(binary.CalculateImageResourceId(h[:]), h[:]), nil
|
return message.NewGroupImage(binary.CalculateImageResourceId(h[:]), h[:]), nil
|
||||||
}
|
}
|
||||||
return nil, errors.New("upload failed")
|
return nil, errors.New("upload failed")
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func (c *QQClient) UploadPrivateImage(target int64, img []byte) (*message.FriendImageElement, error) {
|
||||||
|
return c.uploadPrivateImage(target, img, 0)
|
||||||
|
}
|
||||||
|
|
||||||
|
func (c *QQClient) uploadPrivateImage(target int64, img []byte, count int) (*message.FriendImageElement, error) {
|
||||||
|
count++
|
||||||
|
h := md5.Sum(img)
|
||||||
|
i, err := c.sendAndWait(c.buildOffPicUpPacket(target, h[:], int32(len(img))))
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
rsp := i.(imageUploadResponse)
|
||||||
|
if rsp.ResultCode != 0 {
|
||||||
|
return nil, errors.New(rsp.Message)
|
||||||
|
}
|
||||||
|
if !rsp.IsExists {
|
||||||
|
if _, err = c.UploadGroupImage(0, img); err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
// safe
|
||||||
|
if count >= 5 {
|
||||||
|
return nil, errors.New("upload failed")
|
||||||
|
}
|
||||||
|
return c.uploadPrivateImage(target, img, count)
|
||||||
|
}
|
||||||
|
return &message.FriendImageElement{
|
||||||
|
ImageId: rsp.ResourceId,
|
||||||
|
Md5: h[:],
|
||||||
|
}, nil
|
||||||
|
}
|
||||||
|
|
||||||
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.sendAndWait(c.buildGroupImageStorePacket(groupCode, hash, size))
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
rsp := r.(groupImageUploadResponse)
|
rsp := r.(imageUploadResponse)
|
||||||
if rsp.ResultCode != 0 {
|
if rsp.ResultCode != 0 {
|
||||||
return nil, errors.New(rsp.Message)
|
return nil, errors.New(rsp.Message)
|
||||||
}
|
}
|
||||||
@ -448,9 +459,15 @@ func (c *QQClient) nextPacketSeq() int32 {
|
|||||||
return s
|
return s
|
||||||
}
|
}
|
||||||
|
|
||||||
func (c *QQClient) nextMessageSeq() int32 {
|
func (c *QQClient) nextGroupSeq() int32 {
|
||||||
s := atomic.LoadInt32(&c.messageSeq)
|
s := atomic.LoadInt32(&c.groupSeq)
|
||||||
atomic.AddInt32(&c.messageSeq, 2)
|
atomic.AddInt32(&c.groupSeq, 2)
|
||||||
|
return s
|
||||||
|
}
|
||||||
|
|
||||||
|
func (c *QQClient) nextFriendSeq() int32 {
|
||||||
|
s := atomic.LoadInt32(&c.friendSeq)
|
||||||
|
atomic.AddInt32(&c.friendSeq, 2)
|
||||||
return s
|
return s
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -487,12 +504,12 @@ func (c *QQClient) sendAndWait(seq uint16, pkt []byte) (interface{}, error) {
|
|||||||
|
|
||||||
func (c *QQClient) loop() {
|
func (c *QQClient) loop() {
|
||||||
reader := binary.NewNetworkReader(c.Conn)
|
reader := binary.NewNetworkReader(c.Conn)
|
||||||
for c.running {
|
for c.Online {
|
||||||
l, err := reader.ReadInt32()
|
l, err := reader.ReadInt32()
|
||||||
if err == io.EOF || err == io.ErrClosedPipe {
|
if err == io.EOF || err == io.ErrClosedPipe {
|
||||||
err = c.connect()
|
err = c.connect()
|
||||||
if err != nil {
|
if err != nil {
|
||||||
c.running = false
|
c.Online = false
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
reader = binary.NewNetworkReader(c.Conn)
|
reader = binary.NewNetworkReader(c.Conn)
|
||||||
@ -537,7 +554,7 @@ func (c *QQClient) loop() {
|
|||||||
}
|
}
|
||||||
|
|
||||||
func (c *QQClient) heartbeat() {
|
func (c *QQClient) heartbeat() {
|
||||||
for c.running {
|
for c.Online {
|
||||||
time.Sleep(time.Second * 30)
|
time.Sleep(time.Second * 30)
|
||||||
seq := c.nextSeq()
|
seq := c.nextSeq()
|
||||||
sso := packets.BuildSsoPacket(seq, "Heartbeat.Alive", SystemDeviceInfo.IMEI, []byte{}, c.OutGoingPacketSessionId, []byte{}, c.ksid)
|
sso := packets.BuildSsoPacket(seq, "Heartbeat.Alive", SystemDeviceInfo.IMEI, []byte{}, c.OutGoingPacketSessionId, []byte{}, c.ksid)
|
||||||
|
@ -5,6 +5,7 @@ import (
|
|||||||
"github.com/Mrs4s/MiraiGo/binary"
|
"github.com/Mrs4s/MiraiGo/binary"
|
||||||
"github.com/Mrs4s/MiraiGo/binary/jce"
|
"github.com/Mrs4s/MiraiGo/binary/jce"
|
||||||
"github.com/Mrs4s/MiraiGo/client/pb"
|
"github.com/Mrs4s/MiraiGo/client/pb"
|
||||||
|
"github.com/Mrs4s/MiraiGo/client/pb/cmd0x352"
|
||||||
"github.com/Mrs4s/MiraiGo/client/pb/msg"
|
"github.com/Mrs4s/MiraiGo/client/pb/msg"
|
||||||
"github.com/Mrs4s/MiraiGo/client/pb/structmsg"
|
"github.com/Mrs4s/MiraiGo/client/pb/structmsg"
|
||||||
"github.com/golang/protobuf/proto"
|
"github.com/golang/protobuf/proto"
|
||||||
@ -211,8 +212,10 @@ func decodeMessageSvcPacket(c *QQClient, _ uint16, payload []byte) (interface{},
|
|||||||
continue
|
continue
|
||||||
}
|
}
|
||||||
if c.lastMessageSeq >= message.Head.MsgSeq {
|
if c.lastMessageSeq >= message.Head.MsgSeq {
|
||||||
|
if c.lastMessageSeq-message.Head.MsgSeq < 1000 {
|
||||||
continue
|
continue
|
||||||
}
|
}
|
||||||
|
}
|
||||||
c.lastMessageSeq = message.Head.MsgSeq
|
c.lastMessageSeq = message.Head.MsgSeq
|
||||||
c.dispatchFriendMessage(c.parsePrivateMessage(message))
|
c.dispatchFriendMessage(c.parsePrivateMessage(message))
|
||||||
case 187:
|
case 187:
|
||||||
@ -360,21 +363,58 @@ func decodeGroupImageStoreResponse(_ *QQClient, _ uint16, payload []byte) (inter
|
|||||||
}
|
}
|
||||||
rsp := pkt.MsgTryupImgRsp[0]
|
rsp := pkt.MsgTryupImgRsp[0]
|
||||||
if rsp.Result != 0 {
|
if rsp.Result != 0 {
|
||||||
return groupImageUploadResponse{
|
return imageUploadResponse{
|
||||||
ResultCode: rsp.Result,
|
ResultCode: rsp.Result,
|
||||||
Message: rsp.FailMsg,
|
Message: rsp.FailMsg,
|
||||||
}, nil
|
}, nil
|
||||||
}
|
}
|
||||||
if rsp.BoolFileExit {
|
if rsp.BoolFileExit {
|
||||||
return groupImageUploadResponse{IsExists: true}, nil
|
return imageUploadResponse{IsExists: true}, nil
|
||||||
}
|
}
|
||||||
return groupImageUploadResponse{
|
return imageUploadResponse{
|
||||||
UploadKey: rsp.UpUkey,
|
UploadKey: rsp.UpUkey,
|
||||||
UploadIp: rsp.Uint32UpIp,
|
UploadIp: rsp.Uint32UpIp,
|
||||||
UploadPort: rsp.Uint32UpPort,
|
UploadPort: rsp.Uint32UpPort,
|
||||||
}, nil
|
}, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func decodeOffPicUpResponse(c *QQClient, _ uint16, payload []byte) (interface{}, error) {
|
||||||
|
rsp := cmd0x352.RspBody{}
|
||||||
|
if err := proto.Unmarshal(payload, &rsp); err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
if rsp.FailMsg != "" {
|
||||||
|
return imageUploadResponse{
|
||||||
|
ResultCode: -1,
|
||||||
|
Message: rsp.FailMsg,
|
||||||
|
}, nil
|
||||||
|
}
|
||||||
|
if rsp.Subcmd != 1 || len(rsp.MsgTryupImgRsp) == 0 {
|
||||||
|
return imageUploadResponse{
|
||||||
|
ResultCode: -2,
|
||||||
|
}, nil
|
||||||
|
}
|
||||||
|
imgRsp := rsp.MsgTryupImgRsp[0]
|
||||||
|
if imgRsp.Result != 0 {
|
||||||
|
return imageUploadResponse{
|
||||||
|
ResultCode: imgRsp.Result,
|
||||||
|
Message: imgRsp.FailMsg,
|
||||||
|
}, nil
|
||||||
|
}
|
||||||
|
if imgRsp.BoolFileExit {
|
||||||
|
return imageUploadResponse{
|
||||||
|
IsExists: true,
|
||||||
|
ResourceId: imgRsp.UpResid,
|
||||||
|
}, nil
|
||||||
|
}
|
||||||
|
return imageUploadResponse{
|
||||||
|
ResourceId: imgRsp.UpResid,
|
||||||
|
UploadKey: imgRsp.UpUkey,
|
||||||
|
UploadIp: imgRsp.Uint32UpIp,
|
||||||
|
UploadPort: imgRsp.Uint32UpPort,
|
||||||
|
}, nil
|
||||||
|
}
|
||||||
|
|
||||||
func decodeOnlinePushReqPacket(c *QQClient, seq uint16, payload []byte) (interface{}, error) {
|
func decodeOnlinePushReqPacket(c *QQClient, seq uint16, payload []byte) (interface{}, error) {
|
||||||
request := &jce.RequestPacket{}
|
request := &jce.RequestPacket{}
|
||||||
request.ReadFrom(jce.NewJceReader(payload))
|
request.ReadFrom(jce.NewJceReader(payload))
|
||||||
|
@ -6,7 +6,7 @@ import (
|
|||||||
)
|
)
|
||||||
|
|
||||||
var (
|
var (
|
||||||
ErrAlreadyRunning = errors.New("already running")
|
ErrAlreadyOnline = errors.New("already online")
|
||||||
)
|
)
|
||||||
|
|
||||||
type (
|
type (
|
||||||
@ -139,12 +139,13 @@ type (
|
|||||||
list []*GroupMemberInfo
|
list []*GroupMemberInfo
|
||||||
}
|
}
|
||||||
|
|
||||||
groupImageUploadResponse struct {
|
imageUploadResponse struct {
|
||||||
ResultCode int32
|
ResultCode int32
|
||||||
Message string
|
Message string
|
||||||
|
|
||||||
IsExists bool
|
IsExists bool
|
||||||
|
|
||||||
|
ResourceId string
|
||||||
UploadKey []byte
|
UploadKey []byte
|
||||||
UploadIp []int32
|
UploadIp []int32
|
||||||
UploadPort []int32
|
UploadPort []int32
|
||||||
|
47
client/highway.go
Normal file
47
client/highway.go
Normal file
@ -0,0 +1,47 @@
|
|||||||
|
package client
|
||||||
|
|
||||||
|
import (
|
||||||
|
"crypto/md5"
|
||||||
|
"errors"
|
||||||
|
"github.com/Mrs4s/MiraiGo/binary"
|
||||||
|
"github.com/Mrs4s/MiraiGo/client/pb"
|
||||||
|
"github.com/golang/protobuf/proto"
|
||||||
|
"net"
|
||||||
|
"time"
|
||||||
|
)
|
||||||
|
|
||||||
|
func (c *QQClient) highwayUploadImage(ser string, updKey, img []byte) error {
|
||||||
|
conn, err := net.DialTimeout("tcp", ser, time.Second*5)
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
defer conn.Close()
|
||||||
|
if err = conn.SetDeadline(time.Now().Add(time.Second * 10)); err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
h := md5.Sum(img)
|
||||||
|
pkt := c.buildImageUploadPacket(img, updKey, 2, h)
|
||||||
|
for _, p := range pkt {
|
||||||
|
_, err = conn.Write(p)
|
||||||
|
}
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
r := binary.NewNetworkReader(conn)
|
||||||
|
_, err = r.ReadByte()
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
hl, _ := r.ReadInt32()
|
||||||
|
_, _ = r.ReadBytes(4)
|
||||||
|
payload, _ := r.ReadBytes(int(hl))
|
||||||
|
_ = conn.Close()
|
||||||
|
rsp := pb.RspDataHighwayHead{}
|
||||||
|
if err = proto.Unmarshal(payload, &rsp); err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
if rsp.ErrorCode != 0 {
|
||||||
|
return errors.New("upload failed")
|
||||||
|
}
|
||||||
|
return nil
|
||||||
|
}
|
1842
client/pb/cmd0x352/cmd0x352.pb.go
Normal file
1842
client/pb/cmd0x352/cmd0x352.pb.go
Normal file
File diff suppressed because it is too large
Load Diff
143
client/pb/cmd0x352/cmd0x352.proto
Normal file
143
client/pb/cmd0x352/cmd0x352.proto
Normal file
@ -0,0 +1,143 @@
|
|||||||
|
syntax = "proto3";
|
||||||
|
|
||||||
|
option go_package = ".;cmd0x352";
|
||||||
|
|
||||||
|
message DelImgReq {
|
||||||
|
int64 srcUin = 1;
|
||||||
|
int64 dstUin = 2;
|
||||||
|
int32 reqTerm = 3;
|
||||||
|
int32 reqPlatformType = 4;
|
||||||
|
int32 buType = 5;
|
||||||
|
bytes buildVer = 6;
|
||||||
|
bytes fileResid = 7;
|
||||||
|
int32 picWidth = 8;
|
||||||
|
int32 picHeight = 9;
|
||||||
|
}
|
||||||
|
message DelImgRsp {
|
||||||
|
int32 result = 1;
|
||||||
|
bytes failMsg = 2;
|
||||||
|
bytes fileResid = 3;
|
||||||
|
}
|
||||||
|
message GetImgUrlReq {
|
||||||
|
int64 srcUin = 1;
|
||||||
|
int64 dstUin = 2;
|
||||||
|
bytes fileResid = 3;
|
||||||
|
int32 urlFlag = 4;
|
||||||
|
int32 urlType = 6;
|
||||||
|
int32 reqTerm = 7;
|
||||||
|
int32 reqPlatformType = 8;
|
||||||
|
int32 srcFileType = 9;
|
||||||
|
int32 innerIp = 10;
|
||||||
|
bool boolAddressBook = 11;
|
||||||
|
int32 buType = 12;
|
||||||
|
bytes buildVer = 13;
|
||||||
|
int32 picUpTimestamp = 14;
|
||||||
|
int32 reqTransferType = 15;
|
||||||
|
}
|
||||||
|
message GetImgUrlRsp {
|
||||||
|
bytes fileResid = 1;
|
||||||
|
int32 clientIp = 2;
|
||||||
|
int32 result = 3;
|
||||||
|
bytes failMsg = 4;
|
||||||
|
bytes bytesThumbDownUrl = 5;
|
||||||
|
bytes bytesOriginalDownUrl = 6;
|
||||||
|
D352ImgInfo msgImgInfo = 7;
|
||||||
|
repeated int32 uint32DownIp = 8;
|
||||||
|
repeated int32 uint32DownPort = 9;
|
||||||
|
bytes thumbDownPara = 10;
|
||||||
|
bytes originalDownPara = 11;
|
||||||
|
bytes downDomain = 12;
|
||||||
|
bytes bytesBigDownUrl = 13;
|
||||||
|
bytes bigDownPara = 14;
|
||||||
|
bytes bigThumbDownPara = 15;
|
||||||
|
int32 httpsUrlFlag = 16;
|
||||||
|
repeated IPv6Info msgDownIp6 = 26;
|
||||||
|
bytes clientIp6 = 27;
|
||||||
|
}
|
||||||
|
message D352ImgInfo {
|
||||||
|
bytes fileMd5 = 1;
|
||||||
|
int32 fileType = 2;
|
||||||
|
int64 fileSize = 3;
|
||||||
|
int32 fileWidth = 4;
|
||||||
|
int32 fileHeight = 5;
|
||||||
|
int64 fileFlag = 6;
|
||||||
|
int32 fileCutPos = 7;
|
||||||
|
}
|
||||||
|
message IPv6Info {
|
||||||
|
bytes ip6 = 1;
|
||||||
|
int32 port = 2;
|
||||||
|
}
|
||||||
|
message ReqBody {
|
||||||
|
int32 subcmd = 1;
|
||||||
|
repeated D352TryUpImgReq msgTryupImgReq = 2;
|
||||||
|
repeated GetImgUrlReq msgGetimgUrlReq = 3;
|
||||||
|
repeated DelImgReq msgDelImgReq = 4;
|
||||||
|
int32 netType = 10;
|
||||||
|
}
|
||||||
|
message RspBody {
|
||||||
|
int32 subcmd = 1;
|
||||||
|
repeated TryUpImgRsp msgTryupImgRsp = 2;
|
||||||
|
repeated GetImgUrlRsp msgGetimgUrlRsp = 3;
|
||||||
|
bool boolNewBigchan = 4;
|
||||||
|
repeated DelImgRsp msgDelImgRsp = 5;
|
||||||
|
string failMsg = 10;
|
||||||
|
}
|
||||||
|
message D352TryUpImgReq {
|
||||||
|
int32 srcUin = 1;
|
||||||
|
int32 dstUin = 2;
|
||||||
|
int32 fileId = 3;
|
||||||
|
bytes fileMd5 = 4;
|
||||||
|
int32 fileSize = 5;
|
||||||
|
string filename = 6;
|
||||||
|
int32 srcTerm = 7;
|
||||||
|
int32 platformType = 8;
|
||||||
|
int32 innerIP = 9;
|
||||||
|
int32 addressBook = 10;
|
||||||
|
int32 retry = 11;
|
||||||
|
int32 buType = 12;
|
||||||
|
int32 imgOriginal = 13;
|
||||||
|
int32 imgWidth = 14;
|
||||||
|
int32 imgHeight = 15;
|
||||||
|
int32 imgType = 16;
|
||||||
|
string buildVer = 17;
|
||||||
|
bytes fileIndex = 18;
|
||||||
|
int32 fileStoreDays = 19;
|
||||||
|
int32 stepFlag = 20;
|
||||||
|
int32 rejectTryFast = 21;
|
||||||
|
int32 srvUpload = 22;
|
||||||
|
bytes transferUrl = 23;
|
||||||
|
}
|
||||||
|
message TryUpImgRsp {
|
||||||
|
int64 fileId = 1;
|
||||||
|
int32 clientIp = 2;
|
||||||
|
int32 result = 3;
|
||||||
|
string failMsg = 4;
|
||||||
|
bool boolFileExit = 5;
|
||||||
|
D352ImgInfo msgImgInfo = 6;
|
||||||
|
repeated int32 uint32UpIp = 7;
|
||||||
|
repeated int32 uint32UpPort = 8;
|
||||||
|
bytes upUkey = 9;
|
||||||
|
string upResid = 10;
|
||||||
|
string upUuid = 11;
|
||||||
|
int64 upOffset = 12;
|
||||||
|
int64 blockSize = 13;
|
||||||
|
bytes encryptDstip = 14;
|
||||||
|
int32 roamdays = 15;
|
||||||
|
repeated IPv6Info msgUpIp6 = 26;
|
||||||
|
bytes clientIp6 = 27;
|
||||||
|
bytes thumbDownPara = 60;
|
||||||
|
bytes originalDownPara = 61;
|
||||||
|
bytes downDomain = 62;
|
||||||
|
bytes bigDownPara = 64;
|
||||||
|
bytes bigThumbDownPara = 65;
|
||||||
|
int32 httpsUrlFlag = 66;
|
||||||
|
TryUpInfo4Busi msgInfo4busi = 1001;
|
||||||
|
}
|
||||||
|
message TryUpInfo4Busi {
|
||||||
|
bytes fileResid = 1;
|
||||||
|
bytes downDomain = 2;
|
||||||
|
bytes thumbDownUrl = 3;
|
||||||
|
bytes originalDownUrl = 4;
|
||||||
|
bytes bigDownUrl = 5;
|
||||||
|
}
|
||||||
|
|
@ -2,6 +2,7 @@ syntax = "proto3";
|
|||||||
|
|
||||||
option go_package = ".;pb";
|
option go_package = ".;pb";
|
||||||
|
|
||||||
|
|
||||||
message DeviceInfo {
|
message DeviceInfo {
|
||||||
string bootloader = 1;
|
string bootloader = 1;
|
||||||
string procVersion = 2;
|
string procVersion = 2;
|
||||||
|
@ -23,6 +23,12 @@ type GroupImageElement struct {
|
|||||||
Url string
|
Url string
|
||||||
}
|
}
|
||||||
|
|
||||||
|
type FriendImageElement struct {
|
||||||
|
ImageId string
|
||||||
|
Md5 []byte
|
||||||
|
Url string
|
||||||
|
}
|
||||||
|
|
||||||
type FaceElement struct {
|
type FaceElement struct {
|
||||||
Index int32
|
Index int32
|
||||||
Name string
|
Name string
|
||||||
@ -115,6 +121,10 @@ func (e *GroupImageElement) Type() ElementType {
|
|||||||
return Image
|
return Image
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func (e *FriendImageElement) Type() ElementType {
|
||||||
|
return Image
|
||||||
|
}
|
||||||
|
|
||||||
func (e *AtElement) Type() ElementType {
|
func (e *AtElement) Type() ElementType {
|
||||||
return At
|
return At
|
||||||
}
|
}
|
||||||
|
@ -194,6 +194,18 @@ func ToProtoElems(elems []IMessageElement) (r []*msg.Elem) {
|
|||||||
0x2D, 0x45, 0x41, 0x45, 0x33, 0x2D, 0x42, 0x33, 0x37, 0x43, 0x2D, 0x31, 0x30, 0x31, 0x46, 0x31, 0x45, 0x45, 0x42, 0x46, 0x35, 0x42, 0x35, 0x7D, 0x2E, 0x70, 0x6E, 0x67, 0x41},
|
0x2D, 0x45, 0x41, 0x45, 0x33, 0x2D, 0x42, 0x33, 0x37, 0x43, 0x2D, 0x31, 0x30, 0x31, 0x46, 0x31, 0x45, 0x45, 0x42, 0x46, 0x35, 0x42, 0x35, 0x7D, 0x2E, 0x70, 0x6E, 0x67, 0x41},
|
||||||
},
|
},
|
||||||
})
|
})
|
||||||
|
case *FriendImageElement:
|
||||||
|
r = append(r, &msg.Elem{
|
||||||
|
NotOnlineImage: &msg.NotOnlineImage{
|
||||||
|
FilePath: e.ImageId,
|
||||||
|
ResId: e.ImageId,
|
||||||
|
OldPicMd5: false,
|
||||||
|
PicMd5: e.Md5,
|
||||||
|
DownloadPath: e.ImageId,
|
||||||
|
Original: 1,
|
||||||
|
PbReserve: []byte{0x78, 0x02},
|
||||||
|
},
|
||||||
|
})
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
return
|
return
|
||||||
|
@ -1 +0,0 @@
|
|||||||
package protocol
|
|
Loading…
x
Reference in New Issue
Block a user