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

Merge pull request #1 from Mrs4s/master

Repo update
This commit is contained in:
sam01101 2021-03-06 14:36:37 +08:00 committed by GitHub
commit cef9c9ddee
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
22 changed files with 373 additions and 314 deletions

View File

@ -5,25 +5,31 @@ import (
"sync/atomic" "sync/atomic"
"time" "time"
"github.com/Mrs4s/MiraiGo/binary"
"github.com/Mrs4s/MiraiGo/client/pb" "github.com/Mrs4s/MiraiGo/client/pb"
"github.com/Mrs4s/MiraiGo/client/pb/msg" "github.com/Mrs4s/MiraiGo/client/pb/msg"
"github.com/pkg/errors" "github.com/pkg/errors"
"google.golang.org/protobuf/proto" "google.golang.org/protobuf/proto"
) )
var c2cDecoders = map[int32]func(*QQClient, *msg.Message){ var c2cDecoders = map[int32]func(*QQClient, *msg.Message, *incomingPacketInfo){
33: troopAddMemberBroadcastDecoder, 33: troopAddMemberBroadcastDecoder,
35: troopSystemMessageDecoder, 36: troopSystemMessageDecoder, 37: troopSystemMessageDecoder, 35: troopSystemMessageDecoder, 36: troopSystemMessageDecoder, 37: troopSystemMessageDecoder,
45: troopSystemMessageDecoder, 46: troopSystemMessageDecoder, 84: troopSystemMessageDecoder, 45: troopSystemMessageDecoder, 46: troopSystemMessageDecoder, 84: troopSystemMessageDecoder,
85: troopSystemMessageDecoder, 86: troopSystemMessageDecoder, 87: troopSystemMessageDecoder, 85: troopSystemMessageDecoder, 86: troopSystemMessageDecoder, 87: troopSystemMessageDecoder,
140: tempSessionDecoder, 141: tempSessionDecoder, 140: tempSessionDecoder, 141: tempSessionDecoder,
166: privateMessageDecoder, 208: privateMessageDecoder, 9: privateMessageDecoder, 10: privateMessageDecoder, 31: privateMessageDecoder,
79: privateMessageDecoder, 97: privateMessageDecoder, 120: privateMessageDecoder,
132: privateMessageDecoder, 133: privateMessageDecoder, 166: privateMessageDecoder,
167: privateMessageDecoder,
208: privatePttDecoder,
187: systemMessageDecoder, 188: systemMessageDecoder, 189: systemMessageDecoder, 187: systemMessageDecoder, 188: systemMessageDecoder, 189: systemMessageDecoder,
190: systemMessageDecoder, 191: systemMessageDecoder, 190: systemMessageDecoder, 191: systemMessageDecoder,
529: msgType0x211Decoder, 529: msgType0x211Decoder,
} }
func (c *QQClient) c2cMessageSyncProcessor(rsp *msg.GetMessageResponse) { func (c *QQClient) c2cMessageSyncProcessor(rsp *msg.GetMessageResponse, info *incomingPacketInfo) {
c.syncCookie = rsp.SyncCookie c.syncCookie = rsp.SyncCookie
c.pubAccountCookie = rsp.PubAccountCookie c.pubAccountCookie = rsp.PubAccountCookie
c.msgCtrlBuf = rsp.MsgCtrlBuf c.msgCtrlBuf = rsp.MsgCtrlBuf
@ -50,11 +56,17 @@ func (c *QQClient) c2cMessageSyncProcessor(rsp *msg.GetMessageResponse) {
} }
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.Minute*5); ok { if _, ok := c.msgSvcCache.GetAndUpdate(strKey, time.Minute*5); ok {
c.Debug("c2c msg %v already exists in cache. skip.", pMsg.Head.GetMsgUid())
continue continue
} }
c.msgSvcCache.Add(strKey, "", time.Minute*5) c.msgSvcCache.Add(strKey, "", time.Minute*5)
if info.Params.bool("init") {
continue
}
if decoder, ok := c2cDecoders[pMsg.Head.GetMsgType()]; ok { if decoder, ok := c2cDecoders[pMsg.Head.GetMsgType()]; ok {
decoder(c, pMsg) decoder(c, pMsg, info)
} else {
c.Debug("unknown msg type on c2c processor: %v", pMsg.Head.GetMsgType())
} }
/* /*
switch pMsg.Head.GetMsgType() { switch pMsg.Head.GetMsgType() {
@ -144,44 +156,63 @@ func (c *QQClient) c2cMessageSyncProcessor(rsp *msg.GetMessageResponse) {
_, _ = c.sendAndWait(c.buildDeleteMessageRequestPacket(delItems)) _, _ = c.sendAndWait(c.buildDeleteMessageRequestPacket(delItems))
if rsp.GetSyncFlag() != msg.SyncFlag_STOP { if rsp.GetSyncFlag() != msg.SyncFlag_STOP {
c.Debug("continue sync with flag: %v", rsp.SyncFlag.String()) c.Debug("continue sync with flag: %v", rsp.SyncFlag.String())
_, _ = c.sendAndWait(c.buildGetMessageRequestPacket(rsp.GetSyncFlag(), time.Now().Unix())) seq, pkt := c.buildGetMessageRequestPacket(rsp.GetSyncFlag(), time.Now().Unix())
_, _ = c.sendAndWait(seq, pkt, info.Params)
} }
} }
func privateMessageDecoder(c *QQClient, pMsg *msg.Message) { func privateMessageDecoder(c *QQClient, pMsg *msg.Message, _ *incomingPacketInfo) {
if pMsg.Head.GetFromUin() == c.Uin { switch pMsg.Head.GetC2CCmd() {
for { case 11, 175: // friend msg
frdSeq := atomic.LoadInt32(&c.friendSeq) if pMsg.Head.GetFromUin() == c.Uin {
if frdSeq < pMsg.Head.GetMsgSeq() { for {
if atomic.CompareAndSwapInt32(&c.friendSeq, frdSeq, pMsg.Head.GetMsgSeq()) { frdSeq := atomic.LoadInt32(&c.friendSeq)
if frdSeq < pMsg.Head.GetMsgSeq() {
if atomic.CompareAndSwapInt32(&c.friendSeq, frdSeq, pMsg.Head.GetMsgSeq()) {
break
}
} else {
break break
} }
} else {
break
} }
} }
if pMsg.Body.RichText == nil || pMsg.Body.RichText.Elems == nil {
return
}
c.dispatchFriendMessage(c.parsePrivateMessage(pMsg))
default:
c.Debug("unknown c2c cmd on private msg decoder: %v", pMsg.Head.GetC2CCmd())
} }
if pMsg.Body.RichText == nil || pMsg.Body.RichText.Elems == nil { }
func privatePttDecoder(c *QQClient, pMsg *msg.Message, _ *incomingPacketInfo) {
if pMsg.Body == nil || pMsg.Body.RichText == nil || pMsg.Body.RichText.Ptt == nil {
return return
} }
if len(pMsg.Body.RichText.Ptt.Reserve) != 0 {
// m := binary.NewReader(pMsg.Body.RichText.Ptt.Reserve[1:]).ReadTlvMap(1)
// T3 -> timestamp T8 -> voiceType T9 -> voiceLength T10 -> PbReserveStruct
}
c.dispatchFriendMessage(c.parsePrivateMessage(pMsg)) c.dispatchFriendMessage(c.parsePrivateMessage(pMsg))
} }
func tempSessionDecoder(c *QQClient, pMsg *msg.Message) { func tempSessionDecoder(c *QQClient, pMsg *msg.Message, _ *incomingPacketInfo) {
if pMsg.Head.C2CTmpMsgHead == nil { if pMsg.Head.C2CTmpMsgHead == nil || pMsg.Body == nil {
return return
} }
group := c.FindGroupByUin(pMsg.Head.C2CTmpMsgHead.GetGroupUin()) if pMsg.Head.GetMsgType() == 529 && pMsg.Head.GetC2CCmd() == 6 {
if group == nil { group := c.FindGroup(pMsg.Head.C2CTmpMsgHead.GetGroupCode())
return if group == nil {
return
}
if pMsg.Head.GetFromUin() == c.Uin {
return
}
c.dispatchTempMessage(c.parseTempMessage(pMsg))
} }
if pMsg.Head.GetFromUin() == c.Uin {
return
}
c.dispatchTempMessage(c.parseTempMessage(pMsg))
} }
func troopAddMemberBroadcastDecoder(c *QQClient, pMsg *msg.Message) { func troopAddMemberBroadcastDecoder(c *QQClient, pMsg *msg.Message, _ *incomingPacketInfo) {
groupJoinLock.Lock() groupJoinLock.Lock()
defer groupJoinLock.Unlock() defer groupJoinLock.Unlock()
group := c.FindGroupByUin(pMsg.Head.GetFromUin()) group := c.FindGroupByUin(pMsg.Head.GetFromUin())
@ -207,16 +238,27 @@ func troopAddMemberBroadcastDecoder(c *QQClient, pMsg *msg.Message) {
} }
} }
func systemMessageDecoder(c *QQClient, pMsg *msg.Message) { func systemMessageDecoder(c *QQClient, pMsg *msg.Message, _ *incomingPacketInfo) {
_, pkt := c.buildSystemMsgNewFriendPacket() _, pkt := c.buildSystemMsgNewFriendPacket()
_ = c.send(pkt) _ = c.send(pkt)
} }
func troopSystemMessageDecoder(c *QQClient, pMsg *msg.Message) { func troopSystemMessageDecoder(c *QQClient, pMsg *msg.Message, info *incomingPacketInfo) {
c.exceptAndDispatchGroupSysMsg() if !info.Params.bool("used_reg_proxy") && pMsg.Head.GetMsgType() != 85 && pMsg.Head.GetMsgType() != 36 {
c.exceptAndDispatchGroupSysMsg()
}
if len(pMsg.Body.GetMsgContent()) == 0 {
return
}
reader := binary.NewReader(pMsg.GetBody().GetMsgContent())
groupCode := uint32(reader.ReadInt32())
if info := c.FindGroup(int64(groupCode)); info != nil && pMsg.Head.GetGroupName() != "" && info.Name != pMsg.Head.GetGroupName() {
c.Debug("group %v name updated. %v -> %v", groupCode, info.Name, pMsg.Head.GetGroupName())
info.Name = pMsg.Head.GetGroupName()
}
} }
func msgType0x211Decoder(c *QQClient, pMsg *msg.Message) { func msgType0x211Decoder(c *QQClient, pMsg *msg.Message, _ *incomingPacketInfo) {
sub4 := msg.SubMsgType0X4Body{} sub4 := msg.SubMsgType0X4Body{}
if err := proto.Unmarshal(pMsg.Body.MsgContent, &sub4); err != nil { if err := proto.Unmarshal(pMsg.Body.MsgContent, &sub4); err != nil {
err = errors.Wrap(err, "unmarshal sub msg 0x4 error") err = errors.Wrap(err, "unmarshal sub msg 0x4 error")

View File

@ -28,7 +28,7 @@ import (
var json = jsoniter.ConfigFastest var json = jsoniter.ConfigFastest
//go:generate go run github.com/a8m/syncmap -o "handler_map_gen.go" -pkg client -name HandlerMap "map[uint16]func(i interface{}, err error)" //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
@ -121,32 +121,36 @@ type loginSigInfo struct {
pt4TokenMap map[string][]byte pt4TokenMap map[string][]byte
} }
var decoders = map[string]func(*QQClient, uint16, []byte) (interface{}, error){ type handlerInfo struct {
"wtlogin.login": decodeLoginResponse, fun func(i interface{}, err error)
"wtlogin.exchange_emp": decodeExchangeEmpResponse, params requestParams
"StatSvc.register": decodeClientRegisterResponse, }
"StatSvc.ReqMSFOffline": decodeMSFOfflinePacket,
"MessageSvc.PushNotify": decodeSvcNotify, var decoders = map[string]func(*QQClient, *incomingPacketInfo, []byte) (interface{}, error){
"OnlinePush.ReqPush": decodeOnlinePushReqPacket, "wtlogin.login": decodeLoginResponse,
"OnlinePush.PbPushTransMsg": decodeOnlinePushTransPacket, "wtlogin.exchange_emp": decodeExchangeEmpResponse,
"ConfigPushSvc.PushReq": decodePushReqPacket, "StatSvc.register": decodeClientRegisterResponse,
"MessageSvc.PbGetMsg": decodeMessageSvcPacket, "StatSvc.ReqMSFOffline": decodeMSFOfflinePacket,
"MessageSvc.PushForceOffline": decodeForceOfflinePacket, "MessageSvc.PushNotify": decodeSvcNotify,
"PbMessageSvc.PbMsgWithDraw": decodeMsgWithDrawResponse, "OnlinePush.ReqPush": decodeOnlinePushReqPacket,
"friendlist.getFriendGroupList": decodeFriendGroupListResponse, "OnlinePush.PbPushTransMsg": decodeOnlinePushTransPacket,
"friendlist.GetTroopListReqV2": decodeGroupListResponse, "ConfigPushSvc.PushReq": decodePushReqPacket,
"friendlist.GetTroopMemberListReq": decodeGroupMemberListResponse, "MessageSvc.PbGetMsg": decodeMessageSvcPacket,
"group_member_card.get_group_member_card_info": decodeGroupMemberInfoResponse, "MessageSvc.PushForceOffline": decodeForceOfflinePacket,
"PttStore.GroupPttUp": decodeGroupPttStoreResponse, "PbMessageSvc.PbMsgWithDraw": decodeMsgWithDrawResponse,
"LongConn.OffPicUp": decodeOffPicUpResponse, "friendlist.getFriendGroupList": decodeFriendGroupListResponse,
"ProfileService.Pb.ReqSystemMsgNew.Group": decodeSystemMsgGroupPacket, "friendlist.GetTroopListReqV2": decodeGroupListResponse,
"ProfileService.Pb.ReqSystemMsgNew.Friend": decodeSystemMsgFriendPacket, "friendlist.GetTroopMemberListReq": decodeGroupMemberListResponse,
"OidbSvc.0xe07_0": decodeImageOcrResponse, "group_member_card.get_group_member_card_info": decodeGroupMemberInfoResponse,
"OidbSvc.0xd79": decodeWordSegmentation, "PttStore.GroupPttUp": decodeGroupPttStoreResponse,
"OidbSvc.0x990": decodeTranslateResponse, "LongConn.OffPicUp": decodeOffPicUpResponse,
"SummaryCard.ReqSummaryCard": decodeSummaryCardResponse, "ProfileService.Pb.ReqSystemMsgNew.Group": decodeSystemMsgGroupPacket,
"LightAppSvc.mini_app_info.GetAppInfoById": decodeAppInfoResponse, "ProfileService.Pb.ReqSystemMsgNew.Friend": decodeSystemMsgFriendPacket,
"PttCenterSvr.pb_pttCenter_CMD_REQ_APPLY_UPLOAD-500": decodePrivatePttStoreResponse, "OidbSvc.0xe07_0": decodeImageOcrResponse,
"OidbSvc.0xd79": decodeWordSegmentation,
"OidbSvc.0x990": decodeTranslateResponse,
"SummaryCard.ReqSummaryCard": decodeSummaryCardResponse,
"LightAppSvc.mini_app_info.GetAppInfoById": decodeAppInfoResponse,
} }
func init() { func init() {
@ -304,6 +308,9 @@ func (c *QQClient) RequestSMS() bool {
} }
func (c *QQClient) init() { func (c *QQClient) init() {
if len(c.g) == 0 {
c.Warning("device lock is disable. http api may fail.")
}
c.Online = true c.Online = true
_ = c.registerClient() _ = c.registerClient()
c.groupSysMsgCache, _ = c.GetGroupSystemMessages() c.groupSysMsgCache, _ = c.GetGroupSystemMessages()
@ -311,7 +318,8 @@ func (c *QQClient) init() {
go c.doHeartbeat() go c.doHeartbeat()
} }
_ = c.RefreshStatus() _ = c.RefreshStatus()
_, _ = c.SyncSessions() seq, pkt := c.buildGetMessageRequestPacket(msg.SyncFlag_START, time.Now().Unix())
_, _ = c.sendAndWait(seq, pkt, requestParams{"used_reg_proxy": true, "init": true})
c.stat.once.Do(func() { c.stat.once.Do(func() {
c.OnGroupMessage(func(_ *QQClient, _ *message.GroupMessage) { c.OnGroupMessage(func(_ *QQClient, _ *message.GroupMessage) {
c.stat.MessageReceived++ c.stat.MessageReceived++
@ -629,7 +637,7 @@ func (c *QQClient) SolveFriendRequest(req *NewFriendRequest, accept bool) {
} }
func (c *QQClient) getSKey() string { func (c *QQClient) getSKey() string {
if c.sigInfo.sKeyExpiredTime < time.Now().Unix() { if c.sigInfo.sKeyExpiredTime < time.Now().Unix() && len(c.g) > 0 {
c.Debug("skey expired. refresh...") c.Debug("skey expired. refresh...")
_, _ = c.sendAndWait(c.buildRequestTgtgtNopicsigPacket()) _, _ = c.sendAndWait(c.buildRequestTgtgtNopicsigPacket())
} }
@ -793,7 +801,7 @@ func (c *QQClient) send(pkt []byte) error {
return errors.Wrap(err, "Packet failed to send") return errors.Wrap(err, "Packet failed to send")
} }
func (c *QQClient) sendAndWait(seq uint16, pkt []byte) (interface{}, error) { func (c *QQClient) sendAndWait(seq uint16, pkt []byte, params ...requestParams) (interface{}, error) {
type T struct { type T struct {
Response interface{} Response interface{}
Error error Error error
@ -806,12 +814,20 @@ func (c *QQClient) sendAndWait(seq uint16, pkt []byte) (interface{}, error) {
ch := make(chan T) ch := make(chan T)
defer close(ch) defer close(ch)
c.handlers.Store(seq, func(i interface{}, err error) {
p := func() requestParams {
if len(params) == 0 {
return nil
}
return params[0]
}()
c.handlers.Store(seq, &handlerInfo{fun: func(i interface{}, err error) {
ch <- T{ ch <- T{
Response: i, Response: i,
Error: err, Error: err,
} }
}) }, params: p})
retry := 0 retry := 0
for true { for true {
@ -913,18 +929,28 @@ func (c *QQClient) netLoop() {
if decoder, ok := decoders[pkt.CommandName]; ok { if decoder, ok := decoders[pkt.CommandName]; ok {
// found predefined decoder // found predefined decoder
rsp, err := decoder(c, pkt.SequenceId, payload) info, ok := c.handlers.LoadAndDelete(pkt.SequenceId)
rsp, err := decoder(c, &incomingPacketInfo{
SequenceId: pkt.SequenceId,
CommandName: pkt.CommandName,
Params: func() requestParams {
if !ok {
return nil
}
return info.params
}(),
}, payload)
if err != nil { if err != nil {
c.Debug("decode pkt %v error: %+v", pkt.CommandName, err) c.Debug("decode pkt %v error: %+v", pkt.CommandName, err)
} }
if f, ok := c.handlers.LoadAndDelete(pkt.SequenceId); ok { if ok {
f(rsp, err) info.fun(rsp, err)
} else if f, ok := c.waiters.Load(pkt.CommandName); ok { // 在不存在handler的情况下触发wait } else if f, ok := c.waiters.Load(pkt.CommandName); ok { // 在不存在handler的情况下触发wait
f.(func(interface{}, error))(rsp, err) f.(func(interface{}, error))(rsp, err)
} }
} else if f, ok := c.handlers.LoadAndDelete(pkt.SequenceId); ok { } else if f, ok := c.handlers.LoadAndDelete(pkt.SequenceId); ok {
// does not need decoder // does not need decoder
f(nil, nil) f.fun(nil, nil)
} else { } else {
c.Debug("Unhandled Command: %s\nSeq: %d\nThis message can be ignored.", pkt.CommandName, pkt.SequenceId) c.Debug("Unhandled Command: %s\nSeq: %d\nThis message can be ignored.", pkt.CommandName, pkt.SequenceId)
} }

View File

@ -4,7 +4,6 @@ import (
"crypto/md5" "crypto/md5"
"encoding/hex" "encoding/hex"
"fmt" "fmt"
log "github.com/sirupsen/logrus"
"net" "net"
"strconv" "strconv"
"strings" "strings"
@ -33,7 +32,7 @@ var (
) )
// wtlogin.login // wtlogin.login
func decodeLoginResponse(c *QQClient, _ uint16, payload []byte) (interface{}, error) { func decodeLoginResponse(c *QQClient, _ *incomingPacketInfo, payload []byte) (interface{}, error) {
reader := binary.NewReader(payload) reader := binary.NewReader(payload)
reader.ReadUInt16() // sub command reader.ReadUInt16() // sub command
t := reader.ReadByte() t := reader.ReadByte()
@ -182,7 +181,7 @@ func decodeLoginResponse(c *QQClient, _ uint16, payload []byte) (interface{}, er
} }
// StatSvc.register // StatSvc.register
func decodeClientRegisterResponse(c *QQClient, _ uint16, payload []byte) (interface{}, error) { func decodeClientRegisterResponse(c *QQClient, _ *incomingPacketInfo, payload []byte) (interface{}, error) {
request := &jce.RequestPacket{} request := &jce.RequestPacket{}
request.ReadFrom(jce.NewJceReader(payload)) request.ReadFrom(jce.NewJceReader(payload))
data := &jce.RequestDataVersion2{} data := &jce.RequestDataVersion2{}
@ -199,7 +198,7 @@ func decodeClientRegisterResponse(c *QQClient, _ uint16, payload []byte) (interf
} }
// wtlogin.exchange_emp // wtlogin.exchange_emp
func decodeExchangeEmpResponse(c *QQClient, _ uint16, payload []byte) (interface{}, error) { func decodeExchangeEmpResponse(c *QQClient, _ *incomingPacketInfo, payload []byte) (interface{}, error) {
reader := binary.NewReader(payload) reader := binary.NewReader(payload)
cmd := reader.ReadUInt16() cmd := reader.ReadUInt16()
t := reader.ReadByte() t := reader.ReadByte()
@ -216,7 +215,7 @@ func decodeExchangeEmpResponse(c *QQClient, _ uint16, payload []byte) (interface
} }
// ConfigPushSvc.PushReq // ConfigPushSvc.PushReq
func decodePushReqPacket(c *QQClient, _ uint16, payload []byte) (interface{}, error) { func decodePushReqPacket(c *QQClient, _ *incomingPacketInfo, payload []byte) (interface{}, error) {
request := &jce.RequestPacket{} request := &jce.RequestPacket{}
request.ReadFrom(jce.NewJceReader(payload)) request.ReadFrom(jce.NewJceReader(payload))
data := &jce.RequestDataVersion2{} data := &jce.RequestDataVersion2{}
@ -289,24 +288,24 @@ func decodePushReqPacket(c *QQClient, _ uint16, payload []byte) (interface{}, er
} }
// MessageSvc.PbGetMsg // MessageSvc.PbGetMsg
func decodeMessageSvcPacket(c *QQClient, _ uint16, payload []byte) (interface{}, error) { func decodeMessageSvcPacket(c *QQClient, info *incomingPacketInfo, payload []byte) (interface{}, error) {
rsp := msg.GetMessageResponse{} rsp := msg.GetMessageResponse{}
err := proto.Unmarshal(payload, &rsp) err := proto.Unmarshal(payload, &rsp)
if err != nil { if err != nil {
return nil, errors.Wrap(err, "failed to unmarshal protobuf message") return nil, errors.Wrap(err, "failed to unmarshal protobuf message")
} }
c.c2cMessageSyncProcessor(&rsp) c.c2cMessageSyncProcessor(&rsp, info)
return nil, nil return nil, nil
} }
// MessageSvc.PushNotify // MessageSvc.PushNotify
func decodeSvcNotify(c *QQClient, _ uint16, _ []byte) (interface{}, error) { func decodeSvcNotify(c *QQClient, _ *incomingPacketInfo, _ []byte) (interface{}, error) {
_, err := c.sendAndWait(c.buildGetMessageRequestPacket(msg.SyncFlag_START, time.Now().Unix())) _, err := c.sendAndWait(c.buildGetMessageRequestPacket(msg.SyncFlag_START, time.Now().Unix()))
return nil, err return nil, err
} }
// SummaryCard.ReqSummaryCard // SummaryCard.ReqSummaryCard
func decodeSummaryCardResponse(_ *QQClient, _ uint16, payload []byte) (interface{}, error) { func decodeSummaryCardResponse(_ *QQClient, _ *incomingPacketInfo, payload []byte) (interface{}, error) {
request := &jce.RequestPacket{} request := &jce.RequestPacket{}
request.ReadFrom(jce.NewJceReader(payload)) request.ReadFrom(jce.NewJceReader(payload))
data := &jce.RequestDataVersion2{} data := &jce.RequestDataVersion2{}
@ -355,7 +354,7 @@ func decodeSummaryCardResponse(_ *QQClient, _ uint16, payload []byte) (interface
} }
// friendlist.getFriendGroupList // friendlist.getFriendGroupList
func decodeFriendGroupListResponse(_ *QQClient, _ uint16, payload []byte) (interface{}, error) { func decodeFriendGroupListResponse(_ *QQClient, _ *incomingPacketInfo, payload []byte) (interface{}, error) {
request := &jce.RequestPacket{} request := &jce.RequestPacket{}
request.ReadFrom(jce.NewJceReader(payload)) request.ReadFrom(jce.NewJceReader(payload))
data := &jce.RequestDataVersion3{} data := &jce.RequestDataVersion3{}
@ -381,7 +380,7 @@ func decodeFriendGroupListResponse(_ *QQClient, _ uint16, payload []byte) (inter
} }
// friendlist.GetTroopListReqV2 // friendlist.GetTroopListReqV2
func decodeGroupListResponse(c *QQClient, _ uint16, payload []byte) (interface{}, error) { func decodeGroupListResponse(c *QQClient, _ *incomingPacketInfo, payload []byte) (interface{}, error) {
request := &jce.RequestPacket{} request := &jce.RequestPacket{}
request.ReadFrom(jce.NewJceReader(payload)) request.ReadFrom(jce.NewJceReader(payload))
data := &jce.RequestDataVersion3{} data := &jce.RequestDataVersion3{}
@ -415,7 +414,7 @@ func decodeGroupListResponse(c *QQClient, _ uint16, payload []byte) (interface{}
} }
// friendlist.GetTroopMemberListReq // friendlist.GetTroopMemberListReq
func decodeGroupMemberListResponse(_ *QQClient, _ uint16, payload []byte) (interface{}, error) { func decodeGroupMemberListResponse(_ *QQClient, _ *incomingPacketInfo, payload []byte) (interface{}, error) {
request := &jce.RequestPacket{} request := &jce.RequestPacket{}
request.ReadFrom(jce.NewJceReader(payload)) request.ReadFrom(jce.NewJceReader(payload))
data := &jce.RequestDataVersion3{} data := &jce.RequestDataVersion3{}
@ -451,7 +450,7 @@ func decodeGroupMemberListResponse(_ *QQClient, _ uint16, payload []byte) (inter
} }
// group_member_card.get_group_member_card_info // group_member_card.get_group_member_card_info
func decodeGroupMemberInfoResponse(c *QQClient, _ uint16, payload []byte) (interface{}, error) { func decodeGroupMemberInfoResponse(c *QQClient, _ *incomingPacketInfo, payload []byte) (interface{}, error) {
rsp := pb.GroupMemberRspBody{} rsp := pb.GroupMemberRspBody{}
if err := proto.Unmarshal(payload, &rsp); err != nil { if err := proto.Unmarshal(payload, &rsp); err != nil {
return nil, errors.Wrap(err, "failed to unmarshal protobuf message") return nil, errors.Wrap(err, "failed to unmarshal protobuf message")
@ -484,7 +483,7 @@ func decodeGroupMemberInfoResponse(c *QQClient, _ uint16, payload []byte) (inter
} }
// LongConn.OffPicUp // LongConn.OffPicUp
func decodeOffPicUpResponse(_ *QQClient, _ uint16, payload []byte) (interface{}, error) { func decodeOffPicUpResponse(_ *QQClient, _ *incomingPacketInfo, payload []byte) (interface{}, error) {
rsp := cmd0x352.RspBody{} rsp := cmd0x352.RspBody{}
if err := proto.Unmarshal(payload, &rsp); err != nil { if err := proto.Unmarshal(payload, &rsp); err != nil {
return nil, errors.Wrap(err, "failed to unmarshal protobuf message") return nil, errors.Wrap(err, "failed to unmarshal protobuf message")
@ -522,7 +521,7 @@ func decodeOffPicUpResponse(_ *QQClient, _ uint16, payload []byte) (interface{},
} }
// OnlinePush.ReqPush // OnlinePush.ReqPush
func decodeOnlinePushReqPacket(c *QQClient, seq uint16, payload []byte) (interface{}, error) { func decodeOnlinePushReqPacket(c *QQClient, info *incomingPacketInfo, payload []byte) (interface{}, error) {
request := &jce.RequestPacket{} request := &jce.RequestPacket{}
request.ReadFrom(jce.NewJceReader(payload)) request.ReadFrom(jce.NewJceReader(payload))
data := &jce.RequestDataVersion2{} data := &jce.RequestDataVersion2{}
@ -531,7 +530,7 @@ func decodeOnlinePushReqPacket(c *QQClient, seq uint16, payload []byte) (interfa
msgInfos := []jce.PushMessageInfo{} msgInfos := []jce.PushMessageInfo{}
uin := jr.ReadInt64(0) uin := jr.ReadInt64(0)
jr.ReadSlice(&msgInfos, 2) jr.ReadSlice(&msgInfos, 2)
_ = c.send(c.buildDeleteOnlinePushPacket(uin, seq, msgInfos)) _ = c.send(c.buildDeleteOnlinePushPacket(uin, info.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 {
@ -657,7 +656,6 @@ func decodeOnlinePushReqPacket(c *QQClient, seq uint16, payload []byte) (interfa
if m.DelFriend != nil { if m.DelFriend != nil {
frdUin := m.DelFriend.Uins[0] frdUin := m.DelFriend.Uins[0]
if frd := c.FindFriend(int64(frdUin)); frd != nil { if frd := c.FindFriend(int64(frdUin)); frd != nil {
log.Infof("好友被删除: %v(%v)", frd.Nickname, frd.Uin)
if err := c.ReloadFriendList(); err != nil { if err := c.ReloadFriendList(); err != nil {
return nil, errors.Wrap(err, "failed to reload friend list") return nil, errors.Wrap(err, "failed to reload friend list")
} }
@ -722,7 +720,7 @@ func decodeOnlinePushReqPacket(c *QQClient, seq uint16, payload []byte) (interfa
} }
// OnlinePush.PbPushTransMsg // OnlinePush.PbPushTransMsg
func decodeOnlinePushTransPacket(c *QQClient, _ uint16, payload []byte) (interface{}, error) { func decodeOnlinePushTransPacket(c *QQClient, _ *incomingPacketInfo, payload []byte) (interface{}, error) {
info := msg.TransMsgInfo{} info := msg.TransMsgInfo{}
err := proto.Unmarshal(payload, &info) err := proto.Unmarshal(payload, &info)
if err != nil { if err != nil {
@ -829,7 +827,7 @@ func decodeOnlinePushTransPacket(c *QQClient, _ uint16, payload []byte) (interfa
} }
// ProfileService.Pb.ReqSystemMsgNew.Friend // ProfileService.Pb.ReqSystemMsgNew.Friend
func decodeSystemMsgFriendPacket(c *QQClient, _ uint16, payload []byte) (interface{}, error) { func decodeSystemMsgFriendPacket(c *QQClient, _ *incomingPacketInfo, payload []byte) (interface{}, error) {
rsp := structmsg.RspSystemMsgNew{} rsp := structmsg.RspSystemMsgNew{}
if err := proto.Unmarshal(payload, &rsp); err != nil { if err := proto.Unmarshal(payload, &rsp); err != nil {
return nil, errors.Wrap(err, "failed to unmarshal protobuf message") return nil, errors.Wrap(err, "failed to unmarshal protobuf message")
@ -851,7 +849,7 @@ func decodeSystemMsgFriendPacket(c *QQClient, _ uint16, payload []byte) (interfa
} }
// MessageSvc.PushForceOffline // MessageSvc.PushForceOffline
func decodeForceOfflinePacket(c *QQClient, _ uint16, payload []byte) (interface{}, error) { func decodeForceOfflinePacket(c *QQClient, _ *incomingPacketInfo, payload []byte) (interface{}, error) {
request := &jce.RequestPacket{} request := &jce.RequestPacket{}
request.ReadFrom(jce.NewJceReader(payload)) request.ReadFrom(jce.NewJceReader(payload))
data := &jce.RequestDataVersion2{} data := &jce.RequestDataVersion2{}
@ -865,7 +863,7 @@ func decodeForceOfflinePacket(c *QQClient, _ uint16, payload []byte) (interface{
} }
// StatSvc.ReqMSFOffline // StatSvc.ReqMSFOffline
func decodeMSFOfflinePacket(c *QQClient, _ uint16, _ []byte) (interface{}, error) { func decodeMSFOfflinePacket(c *QQClient, _ *incomingPacketInfo, _ []byte) (interface{}, error) {
c.lastLostMsg = "服务器端强制下线." c.lastLostMsg = "服务器端强制下线."
c.NetLooping = false c.NetLooping = false
c.Online = false c.Online = false
@ -873,7 +871,7 @@ func decodeMSFOfflinePacket(c *QQClient, _ uint16, _ []byte) (interface{}, error
} }
// OidbSvc.0xd79 // OidbSvc.0xd79
func decodeWordSegmentation(_ *QQClient, _ uint16, payload []byte) (interface{}, error) { func decodeWordSegmentation(_ *QQClient, _ *incomingPacketInfo, payload []byte) (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(payload, &pkg); err != nil {
@ -889,7 +887,7 @@ func decodeWordSegmentation(_ *QQClient, _ uint16, payload []byte) (interface{},
} }
// OidbSvc.0xe07_0 // OidbSvc.0xe07_0
func decodeImageOcrResponse(_ *QQClient, _ uint16, payload []byte) (interface{}, error) { func decodeImageOcrResponse(_ *QQClient, _ *incomingPacketInfo, payload []byte) (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(payload, &pkg); err != nil {
@ -926,7 +924,7 @@ func decodeImageOcrResponse(_ *QQClient, _ uint16, payload []byte) (interface{},
} }
// LightAppSvc.mini_app_info.GetAppInfoById // LightAppSvc.mini_app_info.GetAppInfoById
func decodeAppInfoResponse(_ *QQClient, _ uint16, payload []byte) (interface{}, error) { func decodeAppInfoResponse(_ *QQClient, _ *incomingPacketInfo, payload []byte) (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 {
@ -941,6 +939,6 @@ func decodeAppInfoResponse(_ *QQClient, _ uint16, payload []byte) (interface{},
return rsp.AppInfo, nil return rsp.AppInfo, nil
} }
func ignoreDecoder(_ *QQClient, _ uint16, _ []byte) (interface{}, error) { func ignoreDecoder(_ *QQClient, _ *incomingPacketInfo, _ []byte) (interface{}, error) {
return nil, nil return nil, nil
} }

View File

@ -24,94 +24,104 @@ import (
"google.golang.org/protobuf/proto" "google.golang.org/protobuf/proto"
) )
type DeviceInfo struct { type (
Display []byte DeviceInfo struct {
Product []byte Display []byte
Device []byte Product []byte
Board []byte Device []byte
Brand []byte Board []byte
Model []byte Brand []byte
Bootloader []byte Model []byte
FingerPrint []byte Bootloader []byte
BootId []byte FingerPrint []byte
ProcVersion []byte BootId []byte
BaseBand []byte ProcVersion []byte
SimInfo []byte BaseBand []byte
OSType []byte SimInfo []byte
MacAddress []byte OSType []byte
IpAddress []byte MacAddress []byte
WifiBSSID []byte IpAddress []byte
WifiSSID []byte WifiBSSID []byte
IMSIMd5 []byte WifiSSID []byte
IMEI string IMSIMd5 []byte
AndroidId []byte IMEI string
APN []byte AndroidId []byte
VendorName []byte APN []byte
VendorOSName []byte VendorName []byte
Guid []byte VendorOSName []byte
TgtgtKey []byte Guid []byte
Protocol ClientProtocol TgtgtKey []byte
Version *Version Protocol ClientProtocol
} Version *Version
}
type Version struct { Version struct {
Incremental []byte Incremental []byte
Release []byte Release []byte
CodeName []byte CodeName []byte
Sdk uint32 Sdk uint32
} }
type DeviceInfoFile struct { DeviceInfoFile struct {
Display string `json:"display"` Display string `json:"display"`
Product string `json:"product"` Product string `json:"product"`
Device string `json:"device"` Device string `json:"device"`
Board string `json:"board"` Board string `json:"board"`
Model string `json:"model"` Model string `json:"model"`
FingerPrint string `json:"finger_print"` FingerPrint string `json:"finger_print"`
BootId string `json:"boot_id"` BootId string `json:"boot_id"`
ProcVersion string `json:"proc_version"` ProcVersion string `json:"proc_version"`
Protocol int `json:"protocol"` // 0: Pad 1: Phone 2: Watch Protocol int `json:"protocol"` // 0: Pad 1: Phone 2: Watch
IMEI string `json:"imei"` IMEI string `json:"imei"`
Brand string `json:"brand"` Brand string `json:"brand"`
Bootloader string `json:"bootloader"` Bootloader string `json:"bootloader"`
BaseBand string `json:"base_band"` BaseBand string `json:"base_band"`
Version *VersionFile `json:"version"` Version *VersionFile `json:"version"`
SimInfo string `json:"sim_info"` SimInfo string `json:"sim_info"`
OsType string `json:"os_type"` OsType string `json:"os_type"`
MacAddress string `json:"mac_address"` MacAddress string `json:"mac_address"`
IpAddress []int32 `json:"ip_address"` IpAddress []int32 `json:"ip_address"`
WifiBSSID string `json:"wifi_bssid"` WifiBSSID string `json:"wifi_bssid"`
WifiSSID string `json:"wifi_ssid"` WifiSSID string `json:"wifi_ssid"`
ImsiMd5 string `json:"imsi_md5"` ImsiMd5 string `json:"imsi_md5"`
AndroidId string `json:"android_id"` AndroidId string `json:"android_id"`
Apn string `json:"apn"` Apn string `json:"apn"`
VendorName string `json:"vendor_name"` VendorName string `json:"vendor_name"`
VendorOSName string `json:"vendor_os_name"` VendorOSName string `json:"vendor_os_name"`
} }
type VersionFile struct { VersionFile struct {
Incremental string `json:"incremental"` Incremental string `json:"incremental"`
Release string `json:"release"` Release string `json:"release"`
Codename string `json:"codename"` Codename string `json:"codename"`
Sdk uint32 `json:"sdk"` Sdk uint32 `json:"sdk"`
} }
type groupMessageBuilder struct { groupMessageBuilder struct {
MessageSlices []*msg.Message MessageSlices []*msg.Message
} }
type versionInfo struct { versionInfo struct {
ApkSign []byte ApkSign []byte
ApkId string ApkId string
SortVersionName string SortVersionName string
SdkVersion string SdkVersion string
AppId uint32 AppId uint32
BuildTime uint32 BuildTime uint32
SSOVersion uint32 SSOVersion uint32
MiscBitmap uint32 MiscBitmap uint32
SubSigmap uint32 SubSigmap uint32
MainSigMap uint32 MainSigMap uint32
} }
incomingPacketInfo struct {
CommandName string
SequenceId uint16
Params requestParams
}
requestParams map[string]interface{}
)
// default // default
var SystemDeviceInfo = &DeviceInfo{ var SystemDeviceInfo = &DeviceInfo{
@ -577,6 +587,17 @@ func genLongTemplate(resId, brief string, ts int64) *message.ServiceElement {
} }
} }
func (p requestParams) bool(k string) bool {
if p == nil {
return false
}
i, ok := p[k]
if !ok {
return false
}
return i.(bool)
}
func (c *QQClient) packOIDBPackage(cmd, serviceType int32, body []byte) []byte { func (c *QQClient) packOIDBPackage(cmd, serviceType int32, body []byte) []byte {
pkg := &oidb.OIDBSSOPkg{ pkg := &oidb.OIDBSSOPkg{
Command: cmd, Command: cmd,

View File

@ -8,6 +8,7 @@ import (
"math/rand" "math/rand"
"os" "os"
"runtime/debug" "runtime/debug"
"sync"
"google.golang.org/protobuf/proto" "google.golang.org/protobuf/proto"
@ -54,6 +55,8 @@ type (
} }
) )
var fileSingleFlight = sync.Map{}
func init() { func init() {
decoders["OidbSvc.0x6d8_1"] = decodeOIDB6d81Response decoders["OidbSvc.0x6d8_1"] = decodeOIDB6d81Response
decoders["OidbSvc.0x6d6_0"] = decodeOIDB6d60Response decoders["OidbSvc.0x6d6_0"] = decodeOIDB6d60Response
@ -156,11 +159,22 @@ func (fs *GroupFileSystem) GetFilesByFolder(folderId string) ([]*GroupFile, []*G
} }
func (fs *GroupFileSystem) UploadFile(p, name, folderId string) error { func (fs *GroupFileSystem) UploadFile(p, name, folderId string) error {
// 同文件等待其他线程上传
if wg, ok := fileSingleFlight.Load(p); ok {
wg.(*sync.WaitGroup).Wait()
} else {
wg := &sync.WaitGroup{}
wg.Add(1)
fileSingleFlight.Store(p, wg)
defer wg.Done()
defer fileSingleFlight.Delete(p)
}
file, err := os.OpenFile(p, os.O_RDONLY, 0666) file, err := os.OpenFile(p, os.O_RDONLY, 0666)
if err != nil { if err != nil {
return errors.Wrap(err, "open file error") return errors.Wrap(err, "open file error")
} }
defer file.Close() defer func() { _ = file.Close() }()
md5Hash, size := utils.ComputeMd5AndLength(file) md5Hash, size := utils.ComputeMd5AndLength(file)
_, _ = file.Seek(0, io.SeekStart) _, _ = file.Seek(0, io.SeekStart)
sha1H := sha1.New() sha1H := sha1.New()
@ -387,7 +401,7 @@ func (c *QQClient) buildGroupFileDeleteReqPacket(groupCode int64, parentFolderId
return seq, packet return seq, packet
} }
func decodeOIDB6d81Response(c *QQClient, _ uint16, payload []byte) (interface{}, error) { func decodeOIDB6d81Response(_ *QQClient, _ *incomingPacketInfo, payload []byte) (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(payload, &pkg); err != nil {
@ -400,7 +414,7 @@ func decodeOIDB6d81Response(c *QQClient, _ uint16, payload []byte) (interface{},
} }
// OidbSvc.0x6d6_2 // OidbSvc.0x6d6_2
func decodeOIDB6d62Response(_ *QQClient, _ uint16, payload []byte) (interface{}, error) { func decodeOIDB6d62Response(_ *QQClient, _ *incomingPacketInfo, payload []byte) (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(payload, &pkg); err != nil {
@ -417,7 +431,7 @@ func decodeOIDB6d62Response(_ *QQClient, _ uint16, payload []byte) (interface{},
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, _ uint16, payload []byte) (interface{}, error) { func decodeOIDB6d63Response(_ *QQClient, _ *incomingPacketInfo, payload []byte) (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(payload, &pkg); err != nil {
@ -432,7 +446,7 @@ func decodeOIDB6d63Response(_ *QQClient, _ uint16, payload []byte) (interface{},
return rsp.DeleteFileRsp.ClientWording, nil return rsp.DeleteFileRsp.ClientWording, nil
} }
func decodeOIDB6d60Response(_ *QQClient, _ uint16, payload []byte) (interface{}, error) { func decodeOIDB6d60Response(_ *QQClient, _ *incomingPacketInfo, payload []byte) (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(payload, &pkg); err != nil {

View File

@ -183,7 +183,7 @@ func (c *QQClient) buildGroupSearchPacket(keyword string) (uint16, []byte) {
} }
// SummaryCard.ReqSearch // SummaryCard.ReqSearch
func decodeGroupSearchResponse(_ *QQClient, _ uint16, payload []byte) (interface{}, error) { func decodeGroupSearchResponse(_ *QQClient, _ *incomingPacketInfo, payload []byte) (interface{}, error) {
request := &jce.RequestPacket{} request := &jce.RequestPacket{}
request.ReadFrom(jce.NewJceReader(payload)) request.ReadFrom(jce.NewJceReader(payload))
data := &jce.RequestDataVersion2{} data := &jce.RequestDataVersion2{}
@ -219,7 +219,7 @@ func decodeGroupSearchResponse(_ *QQClient, _ uint16, payload []byte) (interface
} }
// OidbSvc.0x88d_0 // OidbSvc.0x88d_0
func decodeGroupInfoResponse(c *QQClient, _ uint16, payload []byte) (interface{}, error) { func decodeGroupInfoResponse(c *QQClient, _ *incomingPacketInfo, payload []byte) (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(payload, &pkg); err != nil {

View File

@ -304,7 +304,7 @@ func (c *QQClient) buildAtAllRemainRequestPacket(groupCode int64) (uint16, []byt
} }
// OnlinePush.PbPushGroupMsg // OnlinePush.PbPushGroupMsg
func decodeGroupMessagePacket(c *QQClient, _ uint16, payload []byte) (interface{}, error) { func decodeGroupMessagePacket(c *QQClient, _ *incomingPacketInfo, payload []byte) (interface{}, error) {
pkt := msg.PushMessagePacket{} pkt := msg.PushMessagePacket{}
err := proto.Unmarshal(payload, &pkt) err := proto.Unmarshal(payload, &pkt)
if err != nil { if err != nil {
@ -345,7 +345,7 @@ func decodeGroupMessagePacket(c *QQClient, _ uint16, payload []byte) (interface{
return nil, nil return nil, nil
} }
func decodeMsgSendResponse(c *QQClient, _ uint16, payload []byte) (interface{}, error) { func decodeMsgSendResponse(c *QQClient, _ *incomingPacketInfo, payload []byte) (interface{}, error) {
rsp := msg.SendMessageResponse{} rsp := msg.SendMessageResponse{}
if err := proto.Unmarshal(payload, &rsp); err != nil { if err := proto.Unmarshal(payload, &rsp); err != nil {
return nil, errors.Wrap(err, "failed to unmarshal protobuf message") return nil, errors.Wrap(err, "failed to unmarshal protobuf message")
@ -356,7 +356,7 @@ func decodeMsgSendResponse(c *QQClient, _ uint16, payload []byte) (interface{},
return nil, nil return nil, nil
} }
func decodeGetGroupMsgResponse(c *QQClient, _ uint16, payload []byte) (interface{}, error) { func decodeGetGroupMsgResponse(c *QQClient, _ *incomingPacketInfo, payload []byte) (interface{}, error) {
rsp := msg.GetGroupMsgResp{} rsp := msg.GetGroupMsgResp{}
if err := proto.Unmarshal(payload, &rsp); err != nil { if err := proto.Unmarshal(payload, &rsp); err != nil {
return nil, errors.Wrap(err, "failed to unmarshal protobuf message") return nil, errors.Wrap(err, "failed to unmarshal protobuf message")
@ -377,7 +377,7 @@ func decodeGetGroupMsgResponse(c *QQClient, _ uint16, payload []byte) (interface
return ret, nil return ret, nil
} }
func decodeAtAllRemainResponse(_ *QQClient, _ uint16, payload []byte) (interface{}, error) { func decodeAtAllRemainResponse(_ *QQClient, _ *incomingPacketInfo, payload []byte) (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(payload, &pkg); err != nil {
@ -573,7 +573,7 @@ func (c *QQClient) buildEssenceMsgOperatePacket(groupCode int64, msgSeq, msgRand
} }
// OidbSvc.0xeac_1/2 // OidbSvc.0xeac_1/2
func decodeEssenceMsgResponse(_ *QQClient, _ uint16, payload []byte) (interface{}, error) { func decodeEssenceMsgResponse(_ *QQClient, _ *incomingPacketInfo, payload []byte) (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(payload, &pkg); err != nil {

View File

@ -70,9 +70,7 @@ type readOnlyHandlerMap struct {
// expunged is an arbitrary pointer that marks entries which have been deleted // expunged is an arbitrary pointer that marks entries which have been deleted
// from the dirty map. // from the dirty map.
var expungedHandlerMap = unsafe.Pointer(new(func(i interface{}, err error, var expungedHandlerMap = unsafe.Pointer(new(*handlerInfo))
)))
// An entry is a slot in the map corresponding to a particular key. // An entry is a slot in the map corresponding to a particular key.
type entryHandlerMap struct { type entryHandlerMap struct {
@ -97,18 +95,14 @@ type entryHandlerMap struct {
p unsafe.Pointer // *interface{} p unsafe.Pointer // *interface{}
} }
func newEntryHandlerMap(i func(i interface{}, err error, func newEntryHandlerMap(i *handlerInfo) *entryHandlerMap {
)) *entryHandlerMap {
return &entryHandlerMap{p: unsafe.Pointer(&i)} return &entryHandlerMap{p: unsafe.Pointer(&i)}
} }
// Load returns the value stored in the map for a key, or nil if no // Load returns the value stored in the map for a key, or nil if no
// value is present. // value is present.
// The ok result indicates whether value was found in the map. // The ok result indicates whether value was found in the map.
func (m *HandlerMap) Load(key uint16) (value func(i interface{}, err error, func (m *HandlerMap) Load(key uint16) (value *handlerInfo, ok bool) {
), ok bool) {
read, _ := m.read.Load().(readOnlyHandlerMap) read, _ := m.read.Load().(readOnlyHandlerMap)
e, ok := read.m[key] e, ok := read.m[key]
if !ok && read.amended { if !ok && read.amended {
@ -133,22 +127,16 @@ func (m *HandlerMap) Load(key uint16) (value func(i interface{}, err error,
return e.load() return e.load()
} }
func (e *entryHandlerMap) load() (value func(i interface{}, err error, func (e *entryHandlerMap) load() (value *handlerInfo, ok bool) {
), ok bool) {
p := atomic.LoadPointer(&e.p) p := atomic.LoadPointer(&e.p)
if p == nil || p == expungedHandlerMap { if p == nil || p == expungedHandlerMap {
return value, false return value, false
} }
return *(*func(i interface{}, err error, return *(**handlerInfo)(p), true
))(p), true
} }
// Store sets the value for a key. // Store sets the value for a key.
func (m *HandlerMap) Store(key uint16, value func(i interface{}, err error, func (m *HandlerMap) Store(key uint16, value *handlerInfo) {
)) {
read, _ := m.read.Load().(readOnlyHandlerMap) read, _ := m.read.Load().(readOnlyHandlerMap)
if e, ok := read.m[key]; ok && e.tryStore(&value) { if e, ok := read.m[key]; ok && e.tryStore(&value) {
return return
@ -181,9 +169,7 @@ func (m *HandlerMap) Store(key uint16, value func(i interface{}, err error,
// //
// If the entry is expunged, tryStore returns false and leaves the entry // If the entry is expunged, tryStore returns false and leaves the entry
// unchanged. // unchanged.
func (e *entryHandlerMap) tryStore(i *func(i interface{}, err error, func (e *entryHandlerMap) tryStore(i **handlerInfo) bool {
)) bool {
for { for {
p := atomic.LoadPointer(&e.p) p := atomic.LoadPointer(&e.p)
if p == expungedHandlerMap { if p == expungedHandlerMap {
@ -206,20 +192,14 @@ func (e *entryHandlerMap) unexpungeLocked() (wasExpunged bool) {
// storeLocked unconditionally stores a value to the entry. // storeLocked unconditionally stores a value to the entry.
// //
// The entry must be known not to be expunged. // The entry must be known not to be expunged.
func (e *entryHandlerMap) storeLocked(i *func(i interface{}, err error, func (e *entryHandlerMap) storeLocked(i **handlerInfo) {
)) {
atomic.StorePointer(&e.p, unsafe.Pointer(i)) atomic.StorePointer(&e.p, unsafe.Pointer(i))
} }
// LoadOrStore returns the existing value for the key if present. // LoadOrStore returns the existing value for the key if present.
// Otherwise, it stores and returns the given value. // Otherwise, it stores and returns the given value.
// The loaded result is true if the value was loaded, false if stored. // The loaded result is true if the value was loaded, false if stored.
func (m *HandlerMap) LoadOrStore(key uint16, value func(i interface{}, err error, func (m *HandlerMap) LoadOrStore(key uint16, value *handlerInfo) (actual *handlerInfo, loaded bool) {
)) (actual func(i interface{}, err error,
), loaded bool) {
// Avoid locking if it's a clean hit. // Avoid locking if it's a clean hit.
read, _ := m.read.Load().(readOnlyHandlerMap) read, _ := m.read.Load().(readOnlyHandlerMap)
if e, ok := read.m[key]; ok { if e, ok := read.m[key]; ok {
@ -259,19 +239,13 @@ func (m *HandlerMap) LoadOrStore(key uint16, value func(i interface{}, err error
// //
// If the entry is expunged, tryLoadOrStore leaves the entry unchanged and // If the entry is expunged, tryLoadOrStore leaves the entry unchanged and
// returns with ok==false. // returns with ok==false.
func (e *entryHandlerMap) tryLoadOrStore(i func(i interface{}, err error, func (e *entryHandlerMap) tryLoadOrStore(i *handlerInfo) (actual *handlerInfo, loaded, ok bool) {
)) (actual func(i interface{}, err error,
), loaded, ok bool) {
p := atomic.LoadPointer(&e.p) p := atomic.LoadPointer(&e.p)
if p == expungedHandlerMap { if p == expungedHandlerMap {
return actual, false, false return actual, false, false
} }
if p != nil { if p != nil {
return *(*func(i interface{}, err error, return *(**handlerInfo)(p), true, true
))(p), true, true
} }
// Copy the interface after the first load to make this method more amenable // Copy the interface after the first load to make this method more amenable
@ -287,18 +261,14 @@ func (e *entryHandlerMap) tryLoadOrStore(i func(i interface{}, err error,
return actual, false, false return actual, false, false
} }
if p != nil { if p != nil {
return *(*func(i interface{}, err error, return *(**handlerInfo)(p), true, true
))(p), true, true
} }
} }
} }
// LoadAndDelete deletes the value for a key, returning the previous value if any. // LoadAndDelete deletes the value for a key, returning the previous value if any.
// The loaded result reports whether the key was present. // The loaded result reports whether the key was present.
func (m *HandlerMap) LoadAndDelete(key uint16) (value func(i interface{}, err error, func (m *HandlerMap) LoadAndDelete(key uint16) (value *handlerInfo, loaded bool) {
), loaded bool) {
read, _ := m.read.Load().(readOnlyHandlerMap) read, _ := m.read.Load().(readOnlyHandlerMap)
e, ok := read.m[key] e, ok := read.m[key]
if !ok && read.amended { if !ok && read.amended {
@ -326,18 +296,14 @@ func (m *HandlerMap) Delete(key uint16) {
m.LoadAndDelete(key) m.LoadAndDelete(key)
} }
func (e *entryHandlerMap) delete() (value func(i interface{}, err error, func (e *entryHandlerMap) delete() (value *handlerInfo, ok bool) {
), ok bool) {
for { for {
p := atomic.LoadPointer(&e.p) p := atomic.LoadPointer(&e.p)
if p == nil || p == expungedHandlerMap { if p == nil || p == expungedHandlerMap {
return value, false return value, false
} }
if atomic.CompareAndSwapPointer(&e.p, p, nil) { if atomic.CompareAndSwapPointer(&e.p, p, nil) {
return *(*func(i interface{}, err error, return *(**handlerInfo)(p), true
))(p), true
} }
} }
} }
@ -352,9 +318,7 @@ func (e *entryHandlerMap) delete() (value func(i interface{}, err error,
// //
// Range may be O(N) with the number of elements in the map even if f returns // Range may be O(N) with the number of elements in the map even if f returns
// false after a constant number of calls. // false after a constant number of calls.
func (m *HandlerMap) Range(f func(key uint16, value func(i interface{}, err error, func (m *HandlerMap) Range(f func(key uint16, value *handlerInfo) bool) {
)) bool) {
// We need to be able to iterate over all of the keys that were already // We need to be able to iterate over all of the keys that were already
// present at the start of the call to Range. // present at the start of the call to Range.
// If read.amended is false, then read.m satisfies that property without // If read.amended is false, then read.m satisfies that property without

View File

@ -65,7 +65,7 @@ func (c *QQClient) UploadGroupImageByFile(groupCode int64, path string) (*messag
if err != nil { if err != nil {
return nil, err return nil, err
} }
defer img.Close() defer func() { _ = img.Close() }()
fh, length := utils.ComputeMd5AndLength(img) fh, length := utils.ComputeMd5AndLength(img)
seq, pkt := c.buildGroupImageStorePacket(groupCode, fh[:], int32(length)) seq, pkt := c.buildGroupImageStorePacket(groupCode, fh[:], int32(length))
r, err := c.sendAndWait(seq, pkt) r, err := c.sendAndWait(seq, pkt)
@ -213,7 +213,7 @@ func (c *QQClient) buildGroupImageStorePacket(groupCode int64, md5 []byte, size
} }
// ImgStore.GroupPicUp // ImgStore.GroupPicUp
func decodeGroupImageStoreResponse(_ *QQClient, _ uint16, payload []byte) (interface{}, error) { func decodeGroupImageStoreResponse(_ *QQClient, _ *incomingPacketInfo, payload []byte) (interface{}, error) {
pkt := pb.D388RespBody{} pkt := pb.D388RespBody{}
err := proto.Unmarshal(payload, &pkt) err := proto.Unmarshal(payload, &pkt)
if err != nil { if err != nil {

View File

@ -43,7 +43,7 @@ func (c *QQClient) buildMultiApplyUpPacket(data, hash []byte, buType int32, grou
} }
// MultiMsg.ApplyUp // MultiMsg.ApplyUp
func decodeMultiApplyUpResponse(_ *QQClient, _ uint16, payload []byte) (interface{}, error) { func decodeMultiApplyUpResponse(_ *QQClient, _ *incomingPacketInfo, payload []byte) (interface{}, error) {
body := multimsg.MultiRspBody{} body := multimsg.MultiRspBody{}
if err := proto.Unmarshal(payload, &body); err != nil { if err := proto.Unmarshal(payload, &body); err != nil {
return nil, errors.Wrap(err, "failed to unmarshal protobuf message") return nil, errors.Wrap(err, "failed to unmarshal protobuf message")
@ -85,7 +85,7 @@ func (c *QQClient) buildMultiApplyDownPacket(resId string) (uint16, []byte) {
} }
// MultiMsg.ApplyDown // MultiMsg.ApplyDown
func decodeMultiApplyDownResponse(_ *QQClient, _ uint16, payload []byte) (interface{}, error) { func decodeMultiApplyDownResponse(_ *QQClient, _ *incomingPacketInfo, payload []byte) (interface{}, error) {
body := multimsg.MultiRspBody{} body := multimsg.MultiRspBody{}
if err := proto.Unmarshal(payload, &body); err != nil { if err := proto.Unmarshal(payload, &body); err != nil {
return nil, errors.Wrap(err, "failed to unmarshal protobuf message") return nil, errors.Wrap(err, "failed to unmarshal protobuf message")

View File

@ -32,7 +32,7 @@ func (c *QQClient) buildOfflineFileDownloadRequestPacket(uuid []byte) (uint16, [
return seq, packet return seq, packet
} }
func decodeOfflineFileDownloadResponse(c *QQClient, _ uint16, payload []byte) (interface{}, error) { func decodeOfflineFileDownloadResponse(c *QQClient, _ *incomingPacketInfo, payload []byte) (interface{}, error) {
rsp := cmd0x346.C346RspBody{} rsp := cmd0x346.C346RspBody{}
if err := proto.Unmarshal(payload, &rsp); err != nil { if err := proto.Unmarshal(payload, &rsp); err != nil {
c.Error("unmarshal cmd0x346 rsp body error: %v", err) c.Error("unmarshal cmd0x346 rsp body error: %v", err)

View File

@ -7,11 +7,12 @@
package pb package pb
import ( import (
reflect "reflect"
sync "sync"
proto "github.com/golang/protobuf/proto" proto "github.com/golang/protobuf/proto"
protoreflect "google.golang.org/protobuf/reflect/protoreflect" protoreflect "google.golang.org/protobuf/reflect/protoreflect"
protoimpl "google.golang.org/protobuf/runtime/protoimpl" protoimpl "google.golang.org/protobuf/runtime/protoimpl"
reflect "reflect"
sync "sync"
) )
const ( const (

View File

@ -1,6 +1,7 @@
package client package client
import ( import (
"bytes"
"crypto/md5" "crypto/md5"
"encoding/hex" "encoding/hex"
"io" "io"
@ -60,33 +61,31 @@ func (c *QQClient) UploadGroupPtt(groupCode int64, voice io.ReadSeeker) (*messag
// UploadPrivatePtt 将语音数据使用好友语音通道上传到服务器, 返回 message.PrivateVoiceElement 可直接发送 // UploadPrivatePtt 将语音数据使用好友语音通道上传到服务器, 返回 message.PrivateVoiceElement 可直接发送
func (c *QQClient) UploadPrivatePtt(target int64, voice []byte) (*message.PrivateVoiceElement, error) { func (c *QQClient) UploadPrivatePtt(target int64, voice []byte) (*message.PrivateVoiceElement, error) {
h := md5.Sum(voice) h := md5.Sum(voice)
i, err := c.sendAndWait(c.buildPrivatePttStorePacket(target, h[:], int32(len(voice)), int32(len(voice)))) ext := c.buildC2CPttStoreBDHExt(target, h[:], int32(len(voice)), int32(len(voice)))
rsp, err := c.highwayUploadByBDH(bytes.NewReader(voice), 26, c.highwaySession.SigSession, ext, false)
if err != nil { if err != nil {
return nil, err return nil, err
} }
rsp := i.(pttUploadResponse) if len(rsp) == 0 {
if rsp.IsExists { return nil, errors.New("miss rsp")
goto ok
} }
for i, ip := range rsp.UploadIp { pkt := cmd0x346.C346RspBody{}
err := c.uploadPtt(ip, rsp.UploadPort[i], rsp.UploadKey, rsp.FileKey, voice, h[:]) if err = proto.Unmarshal(rsp, &pkt); err != nil {
if err != nil { return nil, errors.Wrap(err, "failed to unmarshal protobuf message")
continue }
} if pkt.ApplyUploadRsp == nil {
goto ok return nil, errors.New("miss apply upload rsp")
} }
return nil, errors.New("upload failed")
ok:
return &message.PrivateVoiceElement{ return &message.PrivateVoiceElement{
Ptt: &msg.Ptt{ Ptt: &msg.Ptt{
FileType: proto.Int32(4), FileType: proto.Int32(4),
SrcUin: &c.Uin, SrcUin: &c.Uin,
FileMd5: h[:], FileUuid: pkt.ApplyUploadRsp.Uuid,
FileName: proto.String(hex.EncodeToString(h[:]) + ".amr"), FileMd5: h[:],
FileSize: proto.Int32(int32(len(voice))), FileName: proto.String(hex.EncodeToString(h[:]) + ".amr"),
FileKey: rsp.FileKey, FileSize: proto.Int32(int32(len(voice))),
// Reserve: constructPTTExtraInfo(1, int32(len(voice))), // todo length
BoolValid: proto.Bool(true), BoolValid: proto.Bool(true),
PbReserve: []byte{8, 0, 40, 0, 56, 0},
}}, nil }}, nil
} }
@ -261,7 +260,7 @@ func (c *QQClient) buildPttGroupShortVideoUploadReqPacket(videoHash, thumbHash [
} }
// PttStore.GroupPttUp // PttStore.GroupPttUp
func decodeGroupPttStoreResponse(_ *QQClient, _ uint16, payload []byte) (interface{}, error) { func decodeGroupPttStoreResponse(_ *QQClient, _ *incomingPacketInfo, payload []byte) (interface{}, error) {
pkt := pb.D388RespBody{} pkt := pb.D388RespBody{}
err := proto.Unmarshal(payload, &pkt) err := proto.Unmarshal(payload, &pkt)
if err != nil { if err != nil {
@ -291,7 +290,7 @@ func decodeGroupPttStoreResponse(_ *QQClient, _ uint16, payload []byte) (interfa
} }
// PttCenterSvr.pb_pttCenter_CMD_REQ_APPLY_UPLOAD-500 // PttCenterSvr.pb_pttCenter_CMD_REQ_APPLY_UPLOAD-500
func (c *QQClient) buildPrivatePttStorePacket(target int64, md5 []byte, size, voiceLength int32) (uint16, []byte) { func (c *QQClient) buildC2CPttStoreBDHExt(target int64, md5 []byte, size, voiceLength int32) []byte {
seq := c.nextSeq() seq := c.nextSeq()
req := &cmd0x346.C346ReqBody{ req := &cmd0x346.C346ReqBody{
Cmd: 500, Cmd: 500,
@ -315,42 +314,11 @@ func (c *QQClient) buildPrivatePttStorePacket(target int64, md5 []byte, size, vo
}, },
} }
payload, _ := proto.Marshal(req) payload, _ := proto.Marshal(req)
packet := packets.BuildUniPacket(c.Uin, seq, "PttCenterSvr.pb_pttCenter_CMD_REQ_APPLY_UPLOAD-500", 1, c.OutGoingPacketSessionId, EmptyBytes, c.sigInfo.d2Key, payload) return payload
return seq, packet
}
// PttCenterSvr.pb_pttCenter_CMD_REQ_APPLY_UPLOAD-500
func decodePrivatePttStoreResponse(c *QQClient, _ uint16, payload []byte) (interface{}, error) {
rsp := cmd0x346.C346RspBody{}
if err := proto.Unmarshal(payload, &rsp); err != nil {
c.Error("unmarshal cmd0x346 rsp body error: %v", err)
return nil, errors.Wrap(err, "unmarshal cmd0x346 rsp body error")
}
if rsp.ApplyUploadRsp == nil {
c.Error("decode apply upload 500 error: apply rsp is nil.")
return nil, errors.New("apply rsp is nil")
}
if rsp.ApplyUploadRsp.RetCode != 0 {
c.Error("decode apply upload 500 error: %v", rsp.ApplyUploadRsp.RetCode)
return nil, errors.Errorf("apply upload rsp error: %d", rsp.ApplyUploadRsp.RetCode)
}
if rsp.ApplyUploadRsp.BoolFileExist {
return pttUploadResponse{IsExists: true}, nil
}
var port []int32
for range rsp.ApplyUploadRsp.UploadipList {
port = append(port, rsp.ApplyUploadRsp.UploadPort)
}
return pttUploadResponse{
UploadKey: rsp.ApplyUploadRsp.UploadKey,
UploadIp: rsp.ApplyUploadRsp.UploadipList,
UploadPort: port,
FileKey: rsp.ApplyUploadRsp.Uuid,
}, nil
} }
// PttCenterSvr.ShortVideoDownReq // PttCenterSvr.ShortVideoDownReq
func decodePttShortVideoDownResponse(_ *QQClient, _ uint16, payload []byte) (interface{}, error) { func decodePttShortVideoDownResponse(_ *QQClient, _ *incomingPacketInfo, payload []byte) (interface{}, error) {
rsp := pttcenter.ShortVideoRspBody{} rsp := pttcenter.ShortVideoRspBody{}
if err := proto.Unmarshal(payload, &rsp); err != nil { if err := proto.Unmarshal(payload, &rsp); err != nil {
return nil, errors.Wrap(err, "failed to unmarshal protobuf message") return nil, errors.Wrap(err, "failed to unmarshal protobuf message")
@ -362,7 +330,7 @@ func decodePttShortVideoDownResponse(_ *QQClient, _ uint16, payload []byte) (int
} }
// PttCenterSvr.GroupShortVideoUpReq // PttCenterSvr.GroupShortVideoUpReq
func decodeGroupShortVideoUploadResponse(_ *QQClient, _ uint16, payload []byte) (interface{}, error) { func decodeGroupShortVideoUploadResponse(_ *QQClient, _ *incomingPacketInfo, payload []byte) (interface{}, error) {
rsp := pttcenter.ShortVideoRspBody{} rsp := pttcenter.ShortVideoRspBody{}
if err := proto.Unmarshal(payload, &rsp); err != nil { if err := proto.Unmarshal(payload, &rsp); err != nil {
return nil, errors.Wrap(err, "failed to unmarshal protobuf message") return nil, errors.Wrap(err, "failed to unmarshal protobuf message")
@ -375,3 +343,19 @@ func decodeGroupShortVideoUploadResponse(_ *QQClient, _ uint16, payload []byte)
} }
return rsp.PttShortVideoUploadRsp, nil return rsp.PttShortVideoUploadRsp, nil
} }
func constructPTTExtraInfo(codec, length int32) []byte {
return binary.NewWriterF(func(w *binary.Writer) {
w.WriteByte(3)
w.WriteByte(8)
w.WriteUInt16(4)
w.WriteUInt32(uint32(codec))
w.WriteByte(9)
w.WriteUInt16(4)
w.WriteUInt32(uint32(14)) // length 时间
w.WriteByte(10)
info := []byte{0x08, 0x00, 0x28, 0x00, 0x38, 0x00} // todo
w.WriteUInt16(uint16(len(info)))
w.Write(info)
})
}

View File

@ -89,7 +89,7 @@ func (c *QQClient) buildPrivateRecallPacket(uin, ts int64, msgSeq, random int32)
return seq, packet return seq, packet
} }
func decodeMsgWithDrawResponse(_ *QQClient, _ uint16, payload []byte) (interface{}, error) { func decodeMsgWithDrawResponse(_ *QQClient, _ *incomingPacketInfo, payload []byte) (interface{}, error) {
rsp := msg.MsgWithDrawResp{} rsp := msg.MsgWithDrawResp{}
if err := proto.Unmarshal(payload, &rsp); err != nil { if err := proto.Unmarshal(payload, &rsp); err != nil {
return nil, errors.Wrap(err, "failed to unmarshal protobuf message") return nil, errors.Wrap(err, "failed to unmarshal protobuf message")

View File

@ -49,7 +49,7 @@ func (c *QQClient) buildUrlCheckRequest(url string) (uint16, []byte) {
return seq, packet return seq, packet
} }
func decodeUrlCheckResponse(c *QQClient, _ uint16, payload []byte) (interface{}, error) { func decodeUrlCheckResponse(_ *QQClient, _ *incomingPacketInfo, payload []byte) (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(payload, pkg); err != nil {

View File

@ -29,7 +29,6 @@ func init() {
} }
type ( type (
// SessionSyncResponse 会话同步结果 // SessionSyncResponse 会话同步结果
SessionSyncResponse struct { SessionSyncResponse struct {
GroupSessions []*GroupSessionInfo GroupSessions []*GroupSessionInfo
@ -101,7 +100,7 @@ func (c *QQClient) SyncSessions() (*SessionSyncResponse, error) {
select { select {
case <-notifyChan: case <-notifyChan:
stop() stop()
case <-time.After(time.Second * 5): case <-time.After(time.Second * 20):
stop() stop()
} }
return ret, nil return ret, nil
@ -274,7 +273,7 @@ func (c *QQClient) buildGroupMsgReadedPacket(groupCode, msgSeq int64) (uint16, [
} }
// StatSvc.GetDevLoginInfo // StatSvc.GetDevLoginInfo
func decodeDevListResponse(_ *QQClient, _ uint16, payload []byte) (interface{}, error) { func decodeDevListResponse(_ *QQClient, _ *incomingPacketInfo, payload []byte) (interface{}, error) {
request := &jce.RequestPacket{} request := &jce.RequestPacket{}
request.ReadFrom(jce.NewJceReader(payload)) request.ReadFrom(jce.NewJceReader(payload))
data := &jce.RequestDataVersion2{} data := &jce.RequestDataVersion2{}
@ -297,7 +296,7 @@ func decodeDevListResponse(_ *QQClient, _ uint16, payload []byte) (interface{},
} }
// RegPrxySvc.PushParam // RegPrxySvc.PushParam
func decodePushParamPacket(c *QQClient, _ uint16, payload []byte) (interface{}, error) { func decodePushParamPacket(c *QQClient, _ *incomingPacketInfo, payload []byte) (interface{}, error) {
request := &jce.RequestPacket{} request := &jce.RequestPacket{}
request.ReadFrom(jce.NewJceReader(payload)) request.ReadFrom(jce.NewJceReader(payload))
data := &jce.RequestDataVersion2{} data := &jce.RequestDataVersion2{}
@ -342,7 +341,7 @@ func decodePushParamPacket(c *QQClient, _ uint16, payload []byte) (interface{},
} }
// RegPrxySvc.PbSyncMsg // RegPrxySvc.PbSyncMsg
func decodeMsgSyncResponse(c *QQClient, _ uint16, payload []byte) (interface{}, error) { func decodeMsgSyncResponse(c *QQClient, info *incomingPacketInfo, payload []byte) (interface{}, error) {
rsp := &msf.SvcRegisterProxyMsgResp{} rsp := &msf.SvcRegisterProxyMsgResp{}
if err := proto.Unmarshal(payload, rsp); err != nil { if err := proto.Unmarshal(payload, rsp); err != nil {
return nil, err return nil, err
@ -376,13 +375,13 @@ func decodeMsgSyncResponse(c *QQClient, _ uint16, payload []byte) (interface{},
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) // todo rewrite c2c processor c.c2cMessageSyncProcessor(c2cRsp, info)
} }
} }
return ret, nil return ret, nil
} }
func decodeMsgReadedResponse(c *QQClient, _ uint16, payload []byte) (interface{}, error) { func decodeMsgReadedResponse(_ *QQClient, _ *incomingPacketInfo, payload []byte) (interface{}, error) {
rsp := msg.PbMsgReadedReportResp{} rsp := msg.PbMsgReadedReportResp{}
if err := proto.Unmarshal(payload, &rsp); err != nil { if err := proto.Unmarshal(payload, &rsp); err != nil {
return nil, errors.Wrap(err, "failed to unmarshal protobuf message") return nil, errors.Wrap(err, "failed to unmarshal protobuf message")
@ -396,7 +395,7 @@ func decodeMsgReadedResponse(c *QQClient, _ uint16, payload []byte) (interface{}
var loginNotifyLock sync.Mutex var loginNotifyLock sync.Mutex
// StatSvc.SvcReqMSFLoginNotify // StatSvc.SvcReqMSFLoginNotify
func decodeLoginNotifyPacket(c *QQClient, _ uint16, payload []byte) (interface{}, error) { func decodeLoginNotifyPacket(c *QQClient, _ *incomingPacketInfo, payload []byte) (interface{}, error) {
request := &jce.RequestPacket{} request := &jce.RequestPacket{}
request.ReadFrom(jce.NewJceReader(payload)) request.ReadFrom(jce.NewJceReader(payload))
data := &jce.RequestDataVersion2{} data := &jce.RequestDataVersion2{}

View File

@ -200,7 +200,7 @@ func (c *QQClient) buildSystemMsgFriendActionPacket(reqId, requester int64, acce
} }
// ProfileService.Pb.ReqSystemMsgNew.Group // ProfileService.Pb.ReqSystemMsgNew.Group
func decodeSystemMsgGroupPacket(c *QQClient, _ uint16, payload []byte) (interface{}, error) { func decodeSystemMsgGroupPacket(c *QQClient, _ *incomingPacketInfo, payload []byte) (interface{}, error) {
rsp := structmsg.RspSystemMsgNew{} rsp := structmsg.RspSystemMsgNew{}
if err := proto.Unmarshal(payload, &rsp); err != nil { if err := proto.Unmarshal(payload, &rsp); err != nil {
return nil, err return nil, err

View File

@ -42,7 +42,7 @@ func (c *QQClient) Translate(src, dst, text string) (string, error) {
} }
// OidbSvc.0x990 // OidbSvc.0x990
func decodeTranslateResponse(c *QQClient, _ uint16, payload []byte) (interface{}, error) { func decodeTranslateResponse(_ *QQClient, _ *incomingPacketInfo, payload []byte) (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(payload, &pkg); err != nil {

1
go.mod
View File

@ -3,6 +3,7 @@ module github.com/Mrs4s/MiraiGo
go 1.15 go 1.15
require ( require (
github.com/a8m/syncmap v0.0.0-20200818084611-4bbbd178de97 // indirect
github.com/golang/protobuf v1.4.3 github.com/golang/protobuf v1.4.3
github.com/json-iterator/go v1.1.10 github.com/json-iterator/go v1.1.10
github.com/modern-go/reflect2 v0.0.0-20180701023420-4b7aa43c6742 github.com/modern-go/reflect2 v0.0.0-20180701023420-4b7aa43c6742

4
go.sum
View File

@ -1,5 +1,7 @@
cloud.google.com/go v0.26.0/go.mod h1:aQUYkXzVsufM+DwF1aE+0xfcU+56JwCaLick0ClmMTw= cloud.google.com/go v0.26.0/go.mod h1:aQUYkXzVsufM+DwF1aE+0xfcU+56JwCaLick0ClmMTw=
github.com/BurntSushi/toml v0.3.1/go.mod h1:xHWCNGjB5oqiDr8zfno3MHue2Ht5sIBksp03qcyfWMU= github.com/BurntSushi/toml v0.3.1/go.mod h1:xHWCNGjB5oqiDr8zfno3MHue2Ht5sIBksp03qcyfWMU=
github.com/a8m/syncmap v0.0.0-20200818084611-4bbbd178de97 h1:QJIAdw5m5tNUy7fjBxgg73+YUs/AkeESeqdJ1L3lN10=
github.com/a8m/syncmap v0.0.0-20200818084611-4bbbd178de97/go.mod h1:f3iF7/3t9i9hsYF8DPgT0XeIVyNzevhMCKf2445Q6pE=
github.com/census-instrumentation/opencensus-proto v0.2.1/go.mod h1:f6KPmirojxKA12rnyqOA5BBL4O983OfeGPqjHWSTneU= github.com/census-instrumentation/opencensus-proto v0.2.1/go.mod h1:f6KPmirojxKA12rnyqOA5BBL4O983OfeGPqjHWSTneU=
github.com/client9/misspell v0.3.4/go.mod h1:qj6jICC3Q7zFZvVWo7KLAzC3yx5G7kyvSDkc90ppPyw= github.com/client9/misspell v0.3.4/go.mod h1:qj6jICC3Q7zFZvVWo7KLAzC3yx5G7kyvSDkc90ppPyw=
github.com/davecgh/go-spew v1.1.0/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= github.com/davecgh/go-spew v1.1.0/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
@ -59,6 +61,8 @@ golang.org/x/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ=
golang.org/x/tools v0.0.0-20190114222345-bf090417da8b/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ= golang.org/x/tools v0.0.0-20190114222345-bf090417da8b/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ=
golang.org/x/tools v0.0.0-20190226205152-f727befe758c/go.mod h1:9Yl7xja0Znq3iFh3HoIrodX9oNMXvdceNzlUR8zjMvY= golang.org/x/tools v0.0.0-20190226205152-f727befe758c/go.mod h1:9Yl7xja0Znq3iFh3HoIrodX9oNMXvdceNzlUR8zjMvY=
golang.org/x/tools v0.0.0-20190311212946-11955173bddd/go.mod h1:LCzVGOaR6xXOjkQ3onu1FJEFr0SW1gC7cKk1uF8kGRs= golang.org/x/tools v0.0.0-20190311212946-11955173bddd/go.mod h1:LCzVGOaR6xXOjkQ3onu1FJEFr0SW1gC7cKk1uF8kGRs=
golang.org/x/tools v0.0.0-20190501045030-23463209683d/go.mod h1:RgjU9mgBXZiqYHBnxXauZ1Gv1EHHAz9KjViQ78xBX0Q=
golang.org/x/tools v0.0.0-20190524140312-2c0ae7006135 h1:5Beo0mZN8dRzgrMMkDp0jc8YXQKx9DiJ2k1dkvGsn5A=
golang.org/x/tools v0.0.0-20190524140312-2c0ae7006135/go.mod h1:RgjU9mgBXZiqYHBnxXauZ1Gv1EHHAz9KjViQ78xBX0Q= golang.org/x/tools v0.0.0-20190524140312-2c0ae7006135/go.mod h1:RgjU9mgBXZiqYHBnxXauZ1Gv1EHHAz9KjViQ78xBX0Q=
golang.org/x/xerrors v0.0.0-20191204190536-9bdfabe68543 h1:E7g+9GITq07hpfrRu66IVDexMakfv52eLZ2CXBWiKr4= golang.org/x/xerrors v0.0.0-20191204190536-9bdfabe68543 h1:E7g+9GITq07hpfrRu66IVDexMakfv52eLZ2CXBWiKr4=
golang.org/x/xerrors v0.0.0-20191204190536-9bdfabe68543/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= golang.org/x/xerrors v0.0.0-20191204190536-9bdfabe68543/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=

View File

@ -253,11 +253,16 @@ func NewReply(m *GroupMessage) *ReplyElement {
} }
func NewUrlShare(url, title, content, image string) *ServiceElement { func NewUrlShare(url, title, content, image string) *ServiceElement {
template := fmt.Sprintf(`<?xml version='1.0' encoding='UTF-8' standalone='yes'?><msg templateID="123" url="%s" serviceID="33" action="web" actionData="" brief="【链接】%s" flag="8"><item layout="2"><picture cover="%s"/><title>%s</title><summary>%s</summary></item></msg>`, template := fmt.Sprintf(`<?xml version="1.0" encoding="utf-8"?><msg templateID="12345" action="web" brief="[分享] %s" serviceID="1" url="%s"><item layout="2"><picture cover="%v"/><title>%v</title><summary>%v</summary></item><source/></msg>`,
url, url, image, title, content, title, url, image, title, content,
) )
/*
template := fmt.Sprintf(`<?xml version='1.0' encoding='UTF-8' standalone='yes'?><msg templateID="123" url="%s" serviceID="33" action="web" actionData="" brief="【链接】%s" flag="8"><item layout="2"><picture cover="%s"/><title>%s</title><summary>%s</summary></item></msg>`,
url, url, image, title, content,
)
*/
return &ServiceElement{ return &ServiceElement{
Id: 33, Id: 1,
Content: template, Content: template,
ResId: url, ResId: url,
SubType: "UrlShare", SubType: "UrlShare",

View File

@ -128,7 +128,7 @@ func (e *FriendImageElement) Pack() (r []*msg.Elem) {
func (e *ServiceElement) Pack() (r []*msg.Elem) { func (e *ServiceElement) Pack() (r []*msg.Elem) {
r = []*msg.Elem{} r = []*msg.Elem{}
// id =35 已移至 ForwardElement // id =35 已移至 ForwardElement
if e.Id == 33 { if e.Id == 1 {
r = append(r, &msg.Elem{ r = append(r, &msg.Elem{
Text: &msg.Text{Str: &e.ResId}, Text: &msg.Text{Str: &e.ResId},
}) })