mirror of
https://github.com/Mrs4s/MiraiGo.git
synced 2025-05-08 04:55:56 +08:00
commit
cef9c9ddee
@ -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")
|
||||||
|
@ -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)
|
||||||
}
|
}
|
||||||
|
@ -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
|
||||||
}
|
}
|
||||||
|
187
client/global.go
187
client/global.go
@ -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,
|
||||||
|
@ -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 {
|
||||||
|
@ -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 {
|
||||||
|
@ -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 {
|
||||||
|
@ -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
|
||||||
|
@ -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 {
|
||||||
|
@ -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")
|
||||||
|
@ -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)
|
||||||
|
@ -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 (
|
||||||
|
@ -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)
|
||||||
|
})
|
||||||
|
}
|
||||||
|
@ -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")
|
||||||
|
@ -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 {
|
||||||
|
@ -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{}
|
||||||
|
@ -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
|
||||||
|
@ -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
1
go.mod
@ -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
4
go.sum
@ -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=
|
||||||
|
@ -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",
|
||||||
|
@ -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},
|
||||||
})
|
})
|
||||||
|
Loading…
x
Reference in New Issue
Block a user