1
0
mirror of https://github.com/Mrs4s/MiraiGo.git synced 2025-05-05 03:23:50 +08:00

Merge pull request #70 from wfjsw/features/stack-trace-on-panic-catch

better error support
This commit is contained in:
Mrs4s 2020-11-25 15:36:06 +08:00 committed by GitHub
commit b3233e604e
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
17 changed files with 165 additions and 134 deletions

View File

@ -5,13 +5,13 @@ import (
"crypto/md5" "crypto/md5"
"encoding/hex" "encoding/hex"
"encoding/json" "encoding/json"
"errors"
"fmt" "fmt"
"image" "image"
"io" "io"
"math" "math"
"math/rand" "math/rand"
"net" "net"
"runtime/debug"
"sort" "sort"
"strconv" "strconv"
"strings" "strings"
@ -19,6 +19,8 @@ import (
"sync/atomic" "sync/atomic"
"time" "time"
"github.com/pkg/errors"
"github.com/golang/protobuf/proto" "github.com/golang/protobuf/proto"
"github.com/Mrs4s/MiraiGo/binary" "github.com/Mrs4s/MiraiGo/binary"
@ -701,7 +703,7 @@ func (c *QQClient) uploadPrivateImage(target int64, img []byte, count int) (*mes
count++ count++
h := md5.Sum(img) h := md5.Sum(img)
e, err := c.QueryFriendImage(target, h[:], int32(len(img))) e, err := c.QueryFriendImage(target, h[:], int32(len(img)))
if err == ErrNotExists { if errors.Is(err, ErrNotExists) {
// use group highway upload and query again for image id. // use group highway upload and query again for image id.
if _, err = c.UploadGroupImage(target, img); err != nil { if _, err = c.UploadGroupImage(target, img); err != nil {
return nil, err return nil, err
@ -747,7 +749,7 @@ func (c *QQClient) QueryGroupImage(groupCode int64, hash []byte, size int32) (*m
if rsp.IsExists { if rsp.IsExists {
return message.NewGroupImage(binary.CalculateImageResourceId(hash), hash, rsp.FileId, size, rsp.Width, rsp.Height, 1000), nil return message.NewGroupImage(binary.CalculateImageResourceId(hash), hash, rsp.FileId, size, rsp.Width, rsp.Height, 1000), nil
} }
return nil, errors.New("image not exists") return nil, errors.New("image does not exist")
} }
func (c *QQClient) QueryFriendImage(target int64, hash []byte, size int32) (*message.FriendImageElement, error) { func (c *QQClient) QueryFriendImage(target int64, hash []byte, size int32) (*message.FriendImageElement, error) {
@ -763,7 +765,7 @@ func (c *QQClient) QueryFriendImage(target int64, hash []byte, size int32) (*mes
return &message.FriendImageElement{ return &message.FriendImageElement{
ImageId: rsp.ResourceId, ImageId: rsp.ResourceId,
Md5: hash, Md5: hash,
}, ErrNotExists }, errors.WithStack(ErrNotExists)
} }
return &message.FriendImageElement{ return &message.FriendImageElement{
ImageId: rsp.ResourceId, ImageId: rsp.ResourceId,
@ -820,7 +822,7 @@ func (c *QQClient) GetGroupMembers(group *GroupInfo) ([]*GroupMemberInfo, error)
return nil, err return nil, err
} }
if data == nil { if data == nil {
return nil, errors.New("rsp is nil") return nil, errors.New("group member list unavailable: rsp is nil")
} }
rsp := data.(groupMemberListResponse) rsp := data.(groupMemberListResponse)
nextUin = rsp.NextUin nextUin = rsp.NextUin
@ -983,7 +985,7 @@ func (c *QQClient) connect() error {
if err != nil || conn == nil { if err != nil || conn == nil {
c.retryTimes++ c.retryTimes++
if c.retryTimes > len(c.servers) { if c.retryTimes > len(c.servers) {
return errors.New("network error") return errors.New("All servers are unreachable")
} }
c.Error("connect server error: %v", err) c.Error("connect server error: %v", err)
if err = c.connect(); err != nil { if err = c.connect(); err != nil {
@ -1050,7 +1052,7 @@ func (c *QQClient) send(pkt []byte) error {
} else { } else {
c.stat.PacketSent++ c.stat.PacketSent++
} }
return err 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) (interface{}, error) {
@ -1058,12 +1060,12 @@ func (c *QQClient) sendAndWait(seq uint16, pkt []byte) (interface{}, error) {
Response interface{} Response interface{}
Error error Error error
} }
_, err := c.Conn.Write(pkt)
err := c.send(pkt)
if err != nil { if err != nil {
c.stat.PacketLost++
return nil, err return nil, err
} }
c.stat.PacketSent++
ch := make(chan T) ch := make(chan T)
defer close(ch) defer close(ch)
c.handlers.Store(seq, func(i interface{}, err error) { c.handlers.Store(seq, func(i interface{}, err error) {
@ -1072,6 +1074,7 @@ func (c *QQClient) sendAndWait(seq uint16, pkt []byte) (interface{}, error) {
Error: err, Error: err,
} }
}) })
retry := 0 retry := 0
for true { for true {
select { select {
@ -1086,7 +1089,7 @@ func (c *QQClient) sendAndWait(seq uint16, pkt []byte) (interface{}, error) {
c.handlers.Delete(seq) c.handlers.Delete(seq)
//c.Error("packet timed out, seq: %v", seq) //c.Error("packet timed out, seq: %v", seq)
//println("Packet Timed out") //println("Packet Timed out")
return nil, errors.New("timeout") return nil, errors.New("Packet timed out")
} }
} }
return nil, nil return nil, nil
@ -1102,7 +1105,7 @@ func (c *QQClient) netLoop() {
errCount := 0 errCount := 0
for c.NetLooping { for c.NetLooping {
l, err := reader.ReadInt32() l, err := reader.ReadInt32()
if err == io.EOF || err == io.ErrClosedPipe { if errors.Is(err, io.EOF) || errors.Is(err, io.ErrClosedPipe) {
c.Error("connection dropped by server: %v", err) c.Error("connection dropped by server: %v", err)
c.stat.DisconnectTimes++ c.stat.DisconnectTimes++
err = c.connect() err = c.connect()
@ -1130,7 +1133,7 @@ func (c *QQClient) netLoop() {
pkt, err := packets.ParseIncomingPacket(data, c.sigInfo.d2Key) pkt, err := packets.ParseIncomingPacket(data, c.sigInfo.d2Key)
if err != nil { if err != nil {
c.Error("parse incoming packet error: %v", err) c.Error("parse incoming packet error: %v", err)
if err == packets.ErrSessionExpired || err == packets.ErrPacketDropped { if errors.Is(err, packets.ErrSessionExpired) || errors.Is(err, packets.ErrPacketDropped) {
break break
} }
errCount++ errCount++
@ -1155,27 +1158,27 @@ func (c *QQClient) netLoop() {
go func() { go func() {
defer func() { defer func() {
if pan := recover(); pan != nil { if pan := recover(); pan != nil {
c.Error("panic on decoder %v : %v", pkt.CommandName, pan) c.Error("panic on decoder %v : %v\n%s", pkt.CommandName, pan, debug.Stack())
//fmt.Println("panic on decoder:", pan)
} }
}() }()
decoder, ok := c.decoders[pkt.CommandName]
if !ok { if decoder, ok := c.decoders[pkt.CommandName]; ok {
if f, ok := c.handlers.Load(pkt.SequenceId); ok { // found predefined decoder
c.handlers.Delete(pkt.SequenceId)
f.(func(i interface{}, err error))(nil, nil)
}
return
}
rsp, err := decoder(c, pkt.SequenceId, payload) rsp, err := decoder(c, pkt.SequenceId, 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)
//log.Println("decode", pkt.CommandName, "error:", err)
} }
if f, ok := c.handlers.Load(pkt.SequenceId); ok { if f, ok := c.handlers.Load(pkt.SequenceId); ok {
c.handlers.Delete(pkt.SequenceId) c.handlers.Delete(pkt.SequenceId)
f.(func(i interface{}, err error))(rsp, err) f.(func(i interface{}, err error))(rsp, err)
} }
} else if f, ok := c.handlers.Load(pkt.SequenceId); ok {
// does not need decoder
c.handlers.Delete(pkt.SequenceId)
f.(func(i interface{}, err error))(nil, nil)
} else {
c.Debug("\nUnhandled Command: %s\nSeq: %d\nData: %x\n", pkt.CommandName, pkt.SequenceId, payload)
}
}() }()
} }
c.NetLooping = false c.NetLooping = false

View File

@ -1,11 +1,7 @@
package client package client
import ( import (
"errors"
"fmt" "fmt"
"github.com/Mrs4s/MiraiGo/client/pb/notify"
"github.com/Mrs4s/MiraiGo/client/pb/pttcenter"
"github.com/Mrs4s/MiraiGo/client/pb/qweb"
"net" "net"
"strconv" "strconv"
"strings" "strings"
@ -13,6 +9,11 @@ import (
"sync/atomic" "sync/atomic"
"time" "time"
"github.com/Mrs4s/MiraiGo/client/pb/notify"
"github.com/Mrs4s/MiraiGo/client/pb/pttcenter"
"github.com/Mrs4s/MiraiGo/client/pb/qweb"
"github.com/pkg/errors"
"github.com/Mrs4s/MiraiGo/binary" "github.com/Mrs4s/MiraiGo/binary"
"github.com/Mrs4s/MiraiGo/binary/jce" "github.com/Mrs4s/MiraiGo/binary/jce"
"github.com/Mrs4s/MiraiGo/client/pb" "github.com/Mrs4s/MiraiGo/client/pb"
@ -161,7 +162,7 @@ func decodeLoginResponse(c *QQClient, _ uint16, payload []byte) (interface{}, er
}, nil }, nil
} }
return nil, errors.New(fmt.Sprintf("unknown login response: %v", t)) // ? return nil, errors.Errorf("unknown login response: %v", t) // ?
} }
// StatSvc.register // StatSvc.register
@ -248,7 +249,7 @@ func decodeMessageSvcPacket(c *QQClient, _ uint16, payload []byte) (interface{},
rsp := msg.GetMessageResponse{} rsp := msg.GetMessageResponse{}
err := proto.Unmarshal(payload, &rsp) err := proto.Unmarshal(payload, &rsp)
if err != nil { if err != nil {
return nil, err return nil, errors.Wrap(err, "failed to unmarshal protobuf message")
} }
if rsp.GetResult() != 0 { if rsp.GetResult() != 0 {
return nil, errors.New("message svc result unsuccessful") return nil, errors.New("message svc result unsuccessful")
@ -351,6 +352,7 @@ func decodeMessageSvcPacket(c *QQClient, _ uint16, payload []byte) (interface{},
case 529: case 529:
sub4 := msg.SubMsgType0X4Body{} sub4 := msg.SubMsgType0X4Body{}
if err := proto.Unmarshal(message.Body.MsgContent, &sub4); err != nil { if err := proto.Unmarshal(message.Body.MsgContent, &sub4); err != nil {
err = errors.Wrap(err, "unmarshal sub msg 0x4 error")
c.Error("unmarshal sub msg 0x4 error: %v", err) c.Error("unmarshal sub msg 0x4 error: %v", err)
continue continue
} }
@ -382,7 +384,7 @@ func decodeGroupMessagePacket(c *QQClient, _ uint16, payload []byte) (interface{
pkt := msg.PushMessagePacket{} pkt := msg.PushMessagePacket{}
err := proto.Unmarshal(payload, &pkt) err := proto.Unmarshal(payload, &pkt)
if err != nil { if err != nil {
return nil, err return nil, errors.Wrap(err, "failed to unmarshal protobuf message")
} }
if pkt.Message.Head.GetFromUin() == c.Uin { if pkt.Message.Head.GetFromUin() == c.Uin {
c.dispatchGroupMessageReceiptEvent(&groupMessageReceiptEvent{ c.dispatchGroupMessageReceiptEvent(&groupMessageReceiptEvent{
@ -416,7 +418,7 @@ func decodeGroupMessagePacket(c *QQClient, _ uint16, payload []byte) (interface{
func decodeMsgSendResponse(c *QQClient, _ uint16, payload []byte) (interface{}, error) { func decodeMsgSendResponse(c *QQClient, _ uint16, 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, err return nil, errors.Wrap(err, "failed to unmarshal protobuf message")
} }
if rsp.GetResult() != 0 { if rsp.GetResult() != 0 {
c.Error("send msg error: %v %v", rsp.Result, rsp.ErrMsg) c.Error("send msg error: %v %v", rsp.Result, rsp.ErrMsg)
@ -568,10 +570,10 @@ func decodeGroupMemberListResponse(_ *QQClient, _ uint16, payload []byte) (inter
func decodeGroupMemberInfoResponse(c *QQClient, _ uint16, payload []byte) (interface{}, error) { func decodeGroupMemberInfoResponse(c *QQClient, _ uint16, 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, err return nil, errors.Wrap(err, "failed to unmarshal protobuf message")
} }
if rsp.MemInfo.Nick == nil && rsp.MemInfo.Age == 0 { if rsp.MemInfo.Nick == nil && rsp.MemInfo.Age == 0 {
return nil, ErrMemberNotFound return nil, errors.WithStack(ErrMemberNotFound)
} }
group := c.FindGroup(rsp.GroupCode) group := c.FindGroup(rsp.GroupCode)
return &GroupMemberInfo{ return &GroupMemberInfo{
@ -602,7 +604,7 @@ func decodeGroupImageStoreResponse(_ *QQClient, _ uint16, payload []byte) (inter
pkt := pb.D388RespBody{} pkt := pb.D388RespBody{}
err := proto.Unmarshal(payload, &pkt) err := proto.Unmarshal(payload, &pkt)
if err != nil { if err != nil {
return nil, err return nil, errors.Wrap(err, "failed to unmarshal protobuf message")
} }
rsp := pkt.MsgTryUpImgRsp[0] rsp := pkt.MsgTryUpImgRsp[0]
if rsp.Result != 0 { if rsp.Result != 0 {
@ -629,7 +631,7 @@ func decodeGroupImageStoreResponse(_ *QQClient, _ uint16, payload []byte) (inter
func decodeOffPicUpResponse(_ *QQClient, _ uint16, payload []byte) (interface{}, error) { func decodeOffPicUpResponse(_ *QQClient, _ uint16, 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, err return nil, errors.Wrap(err, "failed to unmarshal protobuf message")
} }
if rsp.FailMsg != "" { if rsp.FailMsg != "" {
return imageUploadResponse{ return imageUploadResponse{
@ -740,7 +742,7 @@ func decodeOnlinePushReqPacket(c *QQClient, seq uint16, payload []byte) (interfa
case 0x8A, 0x8B: case 0x8A, 0x8B:
s8a := pb.Sub8A{} s8a := pb.Sub8A{}
if err := proto.Unmarshal(probuf, &s8a); err != nil { if err := proto.Unmarshal(probuf, &s8a); err != nil {
return nil, err return nil, errors.Wrap(err, "failed to unmarshal protobuf message")
} }
for _, m := range s8a.MsgInfo { for _, m := range s8a.MsgInfo {
if m.ToUin == c.Uin { if m.ToUin == c.Uin {
@ -754,7 +756,7 @@ func decodeOnlinePushReqPacket(c *QQClient, seq uint16, payload []byte) (interfa
case 0xB3: case 0xB3:
b3 := pb.SubB3{} b3 := pb.SubB3{}
if err := proto.Unmarshal(probuf, &b3); err != nil { if err := proto.Unmarshal(probuf, &b3); err != nil {
return nil, err return nil, errors.Wrap(err, "failed to unmarshal protobuf message")
} }
frd := &FriendInfo{ frd := &FriendInfo{
Uin: b3.MsgAddFrdNotify.Uin, Uin: b3.MsgAddFrdNotify.Uin,
@ -765,7 +767,7 @@ func decodeOnlinePushReqPacket(c *QQClient, seq uint16, payload []byte) (interfa
case 0xD4: case 0xD4:
d4 := pb.SubD4{} d4 := pb.SubD4{}
if err := proto.Unmarshal(probuf, &d4); err != nil { if err := proto.Unmarshal(probuf, &d4); err != nil {
return nil, err return nil, errors.Wrap(err, "failed to unmarshal protobuf message")
} }
groupLeaveLock.Lock() groupLeaveLock.Lock()
if g := c.FindGroup(d4.Uin); g != nil { if g := c.FindGroup(d4.Uin); g != nil {
@ -795,7 +797,7 @@ func decodeOnlinePushReqPacket(c *QQClient, seq uint16, payload []byte) (interfa
case 0x44: case 0x44:
s44 := pb.Sub44{} s44 := pb.Sub44{}
if err := proto.Unmarshal(probuf, &s44); err != nil { if err := proto.Unmarshal(probuf, &s44); err != nil {
return nil, err return nil, errors.Wrap(err, "failed to unmarshal protobuf message")
} }
if s44.GroupSyncMsg != nil { if s44.GroupSyncMsg != nil {
func() { func() {
@ -832,7 +834,7 @@ func decodeOnlinePushTransPacket(c *QQClient, _ uint16, payload []byte) (interfa
info := msg.TransMsgInfo{} info := msg.TransMsgInfo{}
err := proto.Unmarshal(payload, &info) err := proto.Unmarshal(payload, &info)
if err != nil { if err != nil {
return nil, err return nil, errors.Wrap(err, "failed to unmarshal protobuf message")
} }
data := binary.NewReader(info.MsgData) data := binary.NewReader(info.MsgData)
idStr := strconv.FormatInt(info.GetMsgUid(), 10) idStr := strconv.FormatInt(info.GetMsgUid(), 10)
@ -938,7 +940,7 @@ func decodeOnlinePushTransPacket(c *QQClient, _ uint16, payload []byte) (interfa
func decodeSystemMsgFriendPacket(c *QQClient, _ uint16, payload []byte) (interface{}, error) { func decodeSystemMsgFriendPacket(c *QQClient, _ uint16, 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, errors.Wrap(err, "failed to unmarshal protobuf message")
} }
if len(rsp.Friendmsgs) == 0 { if len(rsp.Friendmsgs) == 0 {
return nil, nil return nil, nil
@ -983,15 +985,15 @@ func decodeWordSegmentation(_ *QQClient, _ uint16, payload []byte) (interface{},
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 {
return nil, err return nil, errors.Wrap(err, "failed to unmarshal protobuf message")
} }
if err := proto.Unmarshal(pkg.Bodybuffer, rsp); err != nil { if err := proto.Unmarshal(pkg.Bodybuffer, rsp); err != nil {
return nil, err return nil, errors.Wrap(err, "failed to unmarshal protobuf message")
} }
if rsp.Content != nil { if rsp.Content != nil {
return rsp.Content.SliceContent, nil return rsp.Content.SliceContent, nil
} }
return nil, errors.New("no word receive") return nil, errors.New("no word received")
} }
// OidbSvc.0xe07_0 // OidbSvc.0xe07_0
@ -999,10 +1001,10 @@ func decodeImageOcrResponse(_ *QQClient, _ uint16, payload []byte) (interface{},
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 {
return nil, err return nil, errors.Wrap(err, "failed to unmarshal protobuf message")
} }
if err := proto.Unmarshal(pkg.Bodybuffer, &rsp); err != nil { if err := proto.Unmarshal(pkg.Bodybuffer, &rsp); err != nil {
return nil, err return nil, errors.Wrap(err, "failed to unmarshal protobuf message")
} }
if rsp.Wording != "" { if rsp.Wording != "" {
return nil, errors.New(rsp.Wording) return nil, errors.New(rsp.Wording)
@ -1032,7 +1034,7 @@ func decodeImageOcrResponse(_ *QQClient, _ uint16, payload []byte) (interface{},
func decodePttShortVideoDownResponse(_ *QQClient, _ uint16, payload []byte) (interface{}, error) { func decodePttShortVideoDownResponse(_ *QQClient, _ uint16, 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, err return nil, errors.Wrap(err, "failed to unmarshal protobuf message")
} }
if rsp.PttShortVideoDownloadRsp == nil || rsp.PttShortVideoDownloadRsp.DownloadAddr == nil { if rsp.PttShortVideoDownloadRsp == nil || rsp.PttShortVideoDownloadRsp.DownloadAddr == nil {
return nil, errors.New("resp error") return nil, errors.New("resp error")
@ -1045,13 +1047,13 @@ func decodeAppInfoResponse(_ *QQClient, _ uint16, payload []byte) (interface{},
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 {
return nil, err return nil, errors.Wrap(err, "failed to unmarshal protobuf message")
} }
if pkg.RetCode != 0 { if pkg.RetCode != 0 {
return nil, errors.New(pkg.ErrMsg) return nil, errors.New(pkg.ErrMsg)
} }
if err := proto.Unmarshal(pkg.BusiBuff, &rsp); err != nil { if err := proto.Unmarshal(pkg.BusiBuff, &rsp); err != nil {
return nil, err return nil, errors.Wrap(err, "failed to unmarshal protobuf message")
} }
return rsp.AppInfo, nil return rsp.AppInfo, nil
} }

View File

@ -1,11 +1,12 @@
package client package client
import ( import (
"errors"
"github.com/Mrs4s/MiraiGo/binary/jce"
"github.com/Mrs4s/MiraiGo/message"
"strings" "strings"
"sync" "sync"
"github.com/Mrs4s/MiraiGo/binary/jce"
"github.com/Mrs4s/MiraiGo/message"
"github.com/pkg/errors"
) )
var ( var (

View File

@ -2,8 +2,10 @@ package client
import ( import (
"fmt" "fmt"
"github.com/Mrs4s/MiraiGo/message" "runtime/debug"
"sync" "sync"
"github.com/Mrs4s/MiraiGo/message"
) )
type eventHandlers struct { type eventHandlers struct {
@ -383,7 +385,7 @@ func (c *QQClient) dispatchLogEvent(e *LogEvent) {
func cover(f func()) { func cover(f func()) {
defer func() { defer func() {
if pan := recover(); pan != nil { if pan := recover(); pan != nil {
fmt.Println("event error:", pan) fmt.Printf("event error: %v\n%s", pan, debug.Stack())
} }
}() }()
f() f()

View File

@ -5,6 +5,12 @@ import (
"encoding/hex" "encoding/hex"
"encoding/json" "encoding/json"
"fmt" "fmt"
"math/rand"
"net"
"sort"
"strings"
"time"
"github.com/Mrs4s/MiraiGo/binary" "github.com/Mrs4s/MiraiGo/binary"
"github.com/Mrs4s/MiraiGo/binary/jce" "github.com/Mrs4s/MiraiGo/binary/jce"
devinfo "github.com/Mrs4s/MiraiGo/client/pb" devinfo "github.com/Mrs4s/MiraiGo/client/pb"
@ -12,12 +18,8 @@ import (
"github.com/Mrs4s/MiraiGo/client/pb/oidb" "github.com/Mrs4s/MiraiGo/client/pb/oidb"
"github.com/Mrs4s/MiraiGo/message" "github.com/Mrs4s/MiraiGo/message"
"github.com/Mrs4s/MiraiGo/utils" "github.com/Mrs4s/MiraiGo/utils"
"github.com/pkg/errors"
"google.golang.org/protobuf/proto" "google.golang.org/protobuf/proto"
"math/rand"
"net"
"sort"
"strings"
"time"
) )
type DeviceInfo struct { type DeviceInfo struct {
@ -232,7 +234,7 @@ func (info *DeviceInfo) ToJson() []byte {
func (info *DeviceInfo) ReadJson(d []byte) error { func (info *DeviceInfo) ReadJson(d []byte) error {
var f DeviceInfoFile var f DeviceInfoFile
if err := json.Unmarshal(d, &f); err != nil { if err := json.Unmarshal(d, &f); err != nil {
return err return errors.Wrap(err, "failed to unmarshal protobuf message")
} }
info.Display = []byte(f.Display) info.Display = []byte(f.Display)
if f.Product != "" { if f.Product != "" {
@ -287,7 +289,7 @@ func (info *DeviceInfo) GenDeviceInfoData() []byte {
} }
data, err := proto.Marshal(m) data, err := proto.Marshal(m)
if err != nil { if err != nil {
panic(err) panic(errors.Wrap(err, "failed to unmarshal protobuf message"))
} }
return data return data
} }
@ -317,7 +319,7 @@ func getSSOAddress() ([]*net.TCPAddr, error) {
}) })
}))) })))
if err != nil { if err != nil {
return nil, err return nil, errors.Wrap(err, "unable to fetch server list")
} }
rspPkt := &jce.RequestPacket{} rspPkt := &jce.RequestPacket{}
data := &jce.RequestDataVersion2{} data := &jce.RequestDataVersion2{}
@ -344,7 +346,7 @@ func qualityTest(addr *net.TCPAddr) (int64, error) {
start := time.Now() start := time.Now()
conn, err := net.DialTimeout("tcp", addr.String(), time.Second*5) conn, err := net.DialTimeout("tcp", addr.String(), time.Second*5)
if err != nil { if err != nil {
return 0, err return 0, errors.Wrap(err, "failed to connect to server during quality test")
} }
_ = conn.Close() _ = conn.Close()
end := time.Now() end := time.Now()
@ -418,7 +420,7 @@ func (c *QQClient) parseGroupMessage(m *msg.Message) *message.GroupMessage {
c.Debug("sync group %v.", m.Head.GroupInfo.GroupCode) c.Debug("sync group %v.", m.Head.GroupInfo.GroupCode)
info, err := c.GetGroupInfo(m.Head.GroupInfo.GetGroupCode()) info, err := c.GetGroupInfo(m.Head.GroupInfo.GetGroupCode())
if err != nil { if err != nil {
c.Error("error to sync group %v : %v", m.Head.GroupInfo.GroupCode, err) c.Error("error to sync group %v : %+v", m.Head.GroupInfo.GroupCode, err)
return nil return nil
} }
group = info group = info
@ -427,7 +429,7 @@ func (c *QQClient) parseGroupMessage(m *msg.Message) *message.GroupMessage {
if len(group.Members) == 0 { if len(group.Members) == 0 {
mem, err := c.GetGroupMembers(group) mem, err := c.GetGroupMembers(group)
if err != nil { if err != nil {
c.Error("error to sync group %v member : %v", m.Head.GroupInfo.GroupCode, err) c.Error("error to sync group %v member : %+v", m.Head.GroupInfo.GroupCode, err)
return nil return nil
} }
group.Members = mem group.Members = mem
@ -590,16 +592,23 @@ func genLongTemplate(resId, brief string, ts int64) *message.SendingMessage {
}} }}
} }
func (c *QQClient) Info(msg string, args ...interface{}) { func (c *QQClient) Error(msg string, args ...interface{}) {
c.dispatchLogEvent(&LogEvent{ c.dispatchLogEvent(&LogEvent{
Type: "INFO", Type: "ERROR",
Message: fmt.Sprintf(msg, args...), Message: fmt.Sprintf(msg, args...),
}) })
} }
func (c *QQClient) Error(msg string, args ...interface{}) { func (c *QQClient) Warning(msg string, args ...interface{}) {
c.dispatchLogEvent(&LogEvent{ c.dispatchLogEvent(&LogEvent{
Type: "ERROR", Type: "WARNING",
Message: fmt.Sprintf(msg, args...),
})
}
func (c *QQClient) Info(msg string, args ...interface{}) {
c.dispatchLogEvent(&LogEvent{
Type: "INFO",
Message: fmt.Sprintf(msg, args...), Message: fmt.Sprintf(msg, args...),
}) })
} }
@ -610,3 +619,10 @@ func (c *QQClient) Debug(msg string, args ...interface{}) {
Message: fmt.Sprintf(msg, args...), Message: fmt.Sprintf(msg, args...),
}) })
} }
func (c *QQClient) Trace(msg string, args ...interface{}) {
c.dispatchLogEvent(&LogEvent{
Type: "TRACE",
Message: fmt.Sprintf(msg, args...),
})
}

View File

@ -2,11 +2,13 @@ package client
import ( import (
"encoding/hex" "encoding/hex"
"errors"
"fmt" "fmt"
"runtime/debug"
"github.com/Mrs4s/MiraiGo/client/pb/oidb" "github.com/Mrs4s/MiraiGo/client/pb/oidb"
"github.com/Mrs4s/MiraiGo/protocol/packets" "github.com/Mrs4s/MiraiGo/protocol/packets"
"github.com/golang/protobuf/proto" "github.com/golang/protobuf/proto"
"github.com/pkg/errors"
) )
type ( type (
@ -48,7 +50,7 @@ type (
func (c *QQClient) GetGroupFileSystem(groupCode int64) (fs *GroupFileSystem, err error) { func (c *QQClient) GetGroupFileSystem(groupCode int64) (fs *GroupFileSystem, err error) {
defer func() { defer func() {
if pan := recover(); pan != nil { if pan := recover(); pan != nil {
c.Error("get group fs error: %v", pan) c.Error("get group fs error: %v\n%s", pan, debug.Stack())
err = errors.New("fs error") err = errors.New("fs error")
} }
}() }()
@ -264,10 +266,10 @@ func decodeOIDB6d81Response(c *QQClient, _ uint16, payload []byte) (interface{},
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 {
return nil, err return nil, errors.Wrap(err, "failed to unmarshal protobuf message")
} }
if err := proto.Unmarshal(pkg.Bodybuffer, &rsp); err != nil { if err := proto.Unmarshal(pkg.Bodybuffer, &rsp); err != nil {
return nil, err return nil, errors.Wrap(err, "failed to unmarshal protobuf message")
} }
return &rsp, nil return &rsp, nil
} }
@ -277,10 +279,10 @@ func decodeOIDB6d62Response(_ *QQClient, _ uint16, payload []byte) (interface{},
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 {
return nil, err return nil, errors.Wrap(err, "failed to unmarshal protobuf message")
} }
if err := proto.Unmarshal(pkg.Bodybuffer, &rsp); err != nil { if err := proto.Unmarshal(pkg.Bodybuffer, &rsp); err != nil {
return nil, err return nil, errors.Wrap(err, "failed to unmarshal protobuf message")
} }
if rsp.DownloadFileRsp.DownloadUrl == nil { if rsp.DownloadFileRsp.DownloadUrl == nil {
return nil, errors.New(rsp.DownloadFileRsp.ClientWording) return nil, errors.New(rsp.DownloadFileRsp.ClientWording)
@ -294,10 +296,10 @@ func decodeOIDB6d63Response(_ *QQClient, _ uint16, payload []byte) (interface{},
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 {
return nil, err return nil, errors.Wrap(err, "failed to unmarshal protobuf message")
} }
if err := proto.Unmarshal(pkg.Bodybuffer, &rsp); err != nil { if err := proto.Unmarshal(pkg.Bodybuffer, &rsp); err != nil {
return nil, err return nil, errors.Wrap(err, "failed to unmarshal protobuf message")
} }
if rsp.DeleteFileRsp == nil { if rsp.DeleteFileRsp == nil {
return "", nil return "", nil

View File

@ -1,11 +1,11 @@
package client package client
import ( import (
"errors"
"github.com/Mrs4s/MiraiGo/binary" "github.com/Mrs4s/MiraiGo/binary"
"github.com/Mrs4s/MiraiGo/binary/jce" "github.com/Mrs4s/MiraiGo/binary/jce"
"github.com/Mrs4s/MiraiGo/client/pb/oidb" "github.com/Mrs4s/MiraiGo/client/pb/oidb"
"github.com/Mrs4s/MiraiGo/protocol/packets" "github.com/Mrs4s/MiraiGo/protocol/packets"
"github.com/pkg/errors"
"google.golang.org/protobuf/proto" "google.golang.org/protobuf/proto"
) )
@ -120,10 +120,10 @@ func decodeGroupInfoResponse(c *QQClient, _ uint16, payload []byte) (interface{}
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 {
return nil, err return nil, errors.Wrap(err, "failed to unmarshal protobuf message")
} }
if err := proto.Unmarshal(pkg.Bodybuffer, &rsp); err != nil { if err := proto.Unmarshal(pkg.Bodybuffer, &rsp); err != nil {
return nil, err return nil, errors.Wrap(err, "failed to unmarshal protobuf message")
} }
if len(rsp.RspGroupInfo) == 0 { if len(rsp.RspGroupInfo) == 0 {
return nil, errors.New(string(rsp.StrErrorInfo)) return nil, errors.New(string(rsp.StrErrorInfo))

View File

@ -5,15 +5,16 @@ import (
"crypto/md5" "crypto/md5"
binary2 "encoding/binary" binary2 "encoding/binary"
"encoding/hex" "encoding/hex"
"errors"
"fmt" "fmt"
"github.com/Mrs4s/MiraiGo/binary"
"github.com/Mrs4s/MiraiGo/client/pb"
"github.com/Mrs4s/MiraiGo/utils"
"google.golang.org/protobuf/proto"
"net" "net"
"net/http" "net/http"
"strconv" "strconv"
"github.com/Mrs4s/MiraiGo/binary"
"github.com/Mrs4s/MiraiGo/client/pb"
"github.com/Mrs4s/MiraiGo/utils"
"github.com/pkg/errors"
"google.golang.org/protobuf/proto"
) )
func (c *QQClient) highwayUpload(ip uint32, port int, updKey, data []byte, cmdId int32) error { func (c *QQClient) highwayUpload(ip uint32, port int, updKey, data []byte, cmdId int32) error {
@ -24,7 +25,7 @@ func (c *QQClient) highwayUpload(ip uint32, port int, updKey, data []byte, cmdId
binary2.LittleEndian.PutUint32(addr.IP, ip) binary2.LittleEndian.PutUint32(addr.IP, ip)
conn, err := net.DialTCP("tcp", nil, &addr) conn, err := net.DialTCP("tcp", nil, &addr)
if err != nil { if err != nil {
return err return errors.Wrap(err, "failed to connect to highway server")
} }
defer conn.Close() defer conn.Close()
h := md5.Sum(data) h := md5.Sum(data)
@ -33,11 +34,11 @@ func (c *QQClient) highwayUpload(ip uint32, port int, updKey, data []byte, cmdId
for _, p := range pkt { for _, p := range pkt {
_, err = conn.Write(p) _, err = conn.Write(p)
if err != nil { if err != nil {
return err return errors.Wrap(err, "failed to write")
} }
_, err = r.ReadByte() _, err = r.ReadByte()
if err != nil { if err != nil {
return err return errors.Wrap(err, "failed to read byte")
} }
hl, _ := r.ReadInt32() hl, _ := r.ReadInt32()
a2, _ := r.ReadInt32() a2, _ := r.ReadInt32()
@ -46,7 +47,7 @@ func (c *QQClient) highwayUpload(ip uint32, port int, updKey, data []byte, cmdId
r.ReadByte() r.ReadByte()
rsp := new(pb.RspDataHighwayHead) rsp := new(pb.RspDataHighwayHead)
if err = proto.Unmarshal(payload, rsp); err != nil { if err = proto.Unmarshal(payload, rsp); err != nil {
return err return errors.Wrap(err, "failed to unmarshal protobuf message")
} }
if rsp.ErrorCode != 0 { if rsp.ErrorCode != 0 {
return errors.New("upload failed") return errors.New("upload failed")
@ -79,7 +80,7 @@ func (c *QQClient) uploadPtt(ip string, port int32, updKey, fileKey, data, md5 [
hex.Encode(url[p:], md5) hex.Encode(url[p:], md5)
url = append(url, "&mType=pttDu&voice_encodec=1"...) url = append(url, "&mType=pttDu&voice_encodec=1"...)
_, err := utils.HttpPostBytes(string(url), data) _, err := utils.HttpPostBytes(string(url), data)
return err return errors.Wrap(err, "failed to upload ptt")
} }
func (c *QQClient) uploadGroupHeadPortrait(groupCode int64, img []byte) error { func (c *QQClient) uploadGroupHeadPortrait(groupCode int64, img []byte) error {
@ -95,7 +96,7 @@ func (c *QQClient) uploadGroupHeadPortrait(groupCode int64, img []byte) error {
req.Header["Content-Type"] = []string{"multipart/form-data;boundary=****"} req.Header["Content-Type"] = []string{"multipart/form-data;boundary=****"}
rsp, err := http.DefaultClient.Do(req) rsp, err := http.DefaultClient.Do(req)
if err != nil { if err != nil {
return err return errors.Wrap(err, "failed to upload group head portrait")
} }
rsp.Body.Close() rsp.Body.Close()
return nil return nil

View File

@ -1,14 +1,15 @@
package client package client
import ( import (
"errors"
"fmt" "fmt"
"github.com/Mrs4s/MiraiGo/binary" "github.com/Mrs4s/MiraiGo/binary"
"github.com/Mrs4s/MiraiGo/client/pb/longmsg" "github.com/Mrs4s/MiraiGo/client/pb/longmsg"
"github.com/Mrs4s/MiraiGo/client/pb/msg" "github.com/Mrs4s/MiraiGo/client/pb/msg"
"github.com/Mrs4s/MiraiGo/client/pb/multimsg" "github.com/Mrs4s/MiraiGo/client/pb/multimsg"
"github.com/Mrs4s/MiraiGo/protocol/packets" "github.com/Mrs4s/MiraiGo/protocol/packets"
"github.com/Mrs4s/MiraiGo/utils" "github.com/Mrs4s/MiraiGo/utils"
"github.com/pkg/errors"
"google.golang.org/protobuf/proto" "google.golang.org/protobuf/proto"
) )
@ -40,7 +41,7 @@ func (c *QQClient) buildMultiApplyUpPacket(data, hash []byte, buType int32, grou
func decodeMultiApplyUpResponse(_ *QQClient, _ uint16, payload []byte) (interface{}, error) { func decodeMultiApplyUpResponse(_ *QQClient, _ uint16, 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, err return nil, errors.Wrap(err, "failed to unmarshal protobuf message")
} }
if len(body.MultimsgApplyupRsp) == 0 { if len(body.MultimsgApplyupRsp) == 0 {
return nil, errors.New("rsp is empty") return nil, errors.New("rsp is empty")
@ -52,7 +53,7 @@ func decodeMultiApplyUpResponse(_ *QQClient, _ uint16, payload []byte) (interfac
case 193: case 193:
return nil, errors.New("too large") return nil, errors.New("too large")
} }
return nil, errors.New("failed") return nil, errors.Errorf("unexpected multimsg apply up response: %d", rsp.Result)
} }
// MultiMsg.ApplyDown // MultiMsg.ApplyDown
@ -82,7 +83,7 @@ func (c *QQClient) buildMultiApplyDownPacket(resId string) (uint16, []byte) {
func decodeMultiApplyDownResponse(_ *QQClient, _ uint16, payload []byte) (interface{}, error) { func decodeMultiApplyDownResponse(_ *QQClient, _ uint16, 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, err return nil, errors.Wrap(err, "failed to unmarshal protobuf message")
} }
if len(body.MultimsgApplydownRsp) == 0 { if len(body.MultimsgApplydownRsp) == 0 {
return nil, errors.New("not found") return nil, errors.New("not found")
@ -96,7 +97,7 @@ func decodeMultiApplyDownResponse(_ *QQClient, _ uint16, payload []byte) (interf
}() }()
b, err := utils.HttpGetBytes(fmt.Sprintf("%s%s", prefix, string(rsp.ThumbDownPara)), "") b, err := utils.HttpGetBytes(fmt.Sprintf("%s%s", prefix, string(rsp.ThumbDownPara)), "")
if err != nil { if err != nil {
return nil, err return nil, errors.Wrap(err, "failed to download by multi apply down")
} }
if b[0] != 40 { if b[0] != 40 {
return nil, errors.New("unexpected body data") return nil, errors.New("unexpected body data")
@ -111,12 +112,12 @@ func decodeMultiApplyDownResponse(_ *QQClient, _ uint16, payload []byte) (interf
data := tea.Decrypt(r.ReadBytes(int(i2))) data := tea.Decrypt(r.ReadBytes(int(i2)))
lb := longmsg.LongRspBody{} lb := longmsg.LongRspBody{}
if err = proto.Unmarshal(data, &lb); err != nil { if err = proto.Unmarshal(data, &lb); err != nil {
return nil, err return nil, errors.Wrap(err, "failed to unmarshal protobuf message")
} }
uc := binary.GZipUncompress(lb.MsgDownRsp[0].MsgContent) uc := binary.GZipUncompress(lb.MsgDownRsp[0].MsgContent)
mt := msg.PbMultiMsgTransmit{} mt := msg.PbMultiMsgTransmit{}
if err = proto.Unmarshal(uc, &mt); err != nil { if err = proto.Unmarshal(uc, &mt); err != nil {
return nil, err return nil, errors.Wrap(err, "failed to unmarshal protobuf message")
} }
return &mt, nil return &mt, nil
} }

View File

@ -1,10 +1,9 @@
package client package client
import ( import (
"errors"
"fmt"
"github.com/Mrs4s/MiraiGo/client/pb/cmd0x346" "github.com/Mrs4s/MiraiGo/client/pb/cmd0x346"
"github.com/Mrs4s/MiraiGo/protocol/packets" "github.com/Mrs4s/MiraiGo/protocol/packets"
"github.com/pkg/errors"
"google.golang.org/protobuf/proto" "google.golang.org/protobuf/proto"
) )
@ -33,7 +32,7 @@ func decodeOfflineFileDownloadResponse(c *QQClient, _ uint16, payload []byte) (i
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)
return nil, err return nil, errors.Wrap(err, "unmarshal cmd0x346 rsp body error")
} }
if rsp.ApplyDownloadRsp == nil { if rsp.ApplyDownloadRsp == nil {
c.Error("decode apply download 1200 error: apply rsp is nil.") c.Error("decode apply download 1200 error: apply rsp is nil.")
@ -41,7 +40,7 @@ func decodeOfflineFileDownloadResponse(c *QQClient, _ uint16, payload []byte) (i
} }
if rsp.ApplyDownloadRsp.RetCode != 0 { if rsp.ApplyDownloadRsp.RetCode != 0 {
c.Error("decode apply download 1200 error: %v", rsp.ApplyDownloadRsp.RetCode) c.Error("decode apply download 1200 error: %v", rsp.ApplyDownloadRsp.RetCode)
return nil, errors.New(fmt.Sprint(rsp.ApplyDownloadRsp.RetCode)) return nil, errors.Errorf("apply download rsp error: %d", rsp.ApplyDownloadRsp.RetCode)
} }
return "http://" + rsp.ApplyDownloadRsp.DownloadInfo.DownloadDomain + rsp.ApplyDownloadRsp.DownloadInfo.DownloadUrl, nil return "http://" + rsp.ApplyDownloadRsp.DownloadInfo.DownloadDomain + rsp.ApplyDownloadRsp.DownloadInfo.DownloadUrl, nil
} }

View File

@ -3,14 +3,14 @@ package client
import ( import (
"crypto/md5" "crypto/md5"
"encoding/hex" "encoding/hex"
"errors"
"fmt"
"github.com/Mrs4s/MiraiGo/binary" "github.com/Mrs4s/MiraiGo/binary"
"github.com/Mrs4s/MiraiGo/client/pb" "github.com/Mrs4s/MiraiGo/client/pb"
"github.com/Mrs4s/MiraiGo/client/pb/cmd0x346" "github.com/Mrs4s/MiraiGo/client/pb/cmd0x346"
"github.com/Mrs4s/MiraiGo/client/pb/msg" "github.com/Mrs4s/MiraiGo/client/pb/msg"
"github.com/Mrs4s/MiraiGo/message" "github.com/Mrs4s/MiraiGo/message"
"github.com/Mrs4s/MiraiGo/protocol/packets" "github.com/Mrs4s/MiraiGo/protocol/packets"
"github.com/pkg/errors"
"google.golang.org/protobuf/proto" "google.golang.org/protobuf/proto"
) )
@ -122,7 +122,7 @@ func decodeGroupPttStoreResponse(_ *QQClient, _ uint16, payload []byte) (interfa
pkt := pb.D388RespBody{} pkt := pb.D388RespBody{}
err := proto.Unmarshal(payload, &pkt) err := proto.Unmarshal(payload, &pkt)
if err != nil { if err != nil {
return nil, err return nil, errors.Wrap(err, "failed to unmarshal protobuf message")
} }
rsp := pkt.MsgTryUpPttRsp[0] rsp := pkt.MsgTryUpPttRsp[0]
if rsp.Result != 0 { if rsp.Result != 0 {
@ -180,7 +180,7 @@ func decodePrivatePttStoreResponse(c *QQClient, _ uint16, payload []byte) (inter
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)
return nil, err return nil, errors.Wrap(err, "unmarshal cmd0x346 rsp body error")
} }
if rsp.ApplyUploadRsp == nil { if rsp.ApplyUploadRsp == nil {
c.Error("decode apply upload 500 error: apply rsp is nil.") c.Error("decode apply upload 500 error: apply rsp is nil.")
@ -188,7 +188,7 @@ func decodePrivatePttStoreResponse(c *QQClient, _ uint16, payload []byte) (inter
} }
if rsp.ApplyUploadRsp.RetCode != 0 { if rsp.ApplyUploadRsp.RetCode != 0 {
c.Error("decode apply upload 500 error: %v", rsp.ApplyUploadRsp.RetCode) c.Error("decode apply upload 500 error: %v", rsp.ApplyUploadRsp.RetCode)
return nil, errors.New(fmt.Sprint(rsp.ApplyUploadRsp.RetCode)) return nil, errors.Errorf("apply upload rsp error: %d", rsp.ApplyUploadRsp.RetCode)
} }
if rsp.ApplyUploadRsp.BoolFileExist { if rsp.ApplyUploadRsp.BoolFileExist {
return pttUploadResponse{IsExists: true}, nil return pttUploadResponse{IsExists: true}, nil

View File

@ -1,14 +1,15 @@
package client package client
import ( import (
"errors" "math/rand"
"time"
"github.com/Mrs4s/MiraiGo/client/pb/oidb" "github.com/Mrs4s/MiraiGo/client/pb/oidb"
"github.com/Mrs4s/MiraiGo/message" "github.com/Mrs4s/MiraiGo/message"
"github.com/Mrs4s/MiraiGo/protocol/packets" "github.com/Mrs4s/MiraiGo/protocol/packets"
"github.com/Mrs4s/MiraiGo/utils" "github.com/Mrs4s/MiraiGo/utils"
"github.com/pkg/errors"
"google.golang.org/protobuf/proto" "google.golang.org/protobuf/proto"
"math/rand"
"time"
) )
type RichClientInfo struct { type RichClientInfo struct {

View File

@ -1,10 +1,10 @@
package client package client
import ( import (
"errors"
"github.com/Mrs4s/MiraiGo/client/pb/oidb" "github.com/Mrs4s/MiraiGo/client/pb/oidb"
"github.com/Mrs4s/MiraiGo/protocol/packets" "github.com/Mrs4s/MiraiGo/protocol/packets"
"github.com/golang/protobuf/proto" "github.com/golang/protobuf/proto"
"github.com/pkg/errors"
) )
func (c *QQClient) buildTranslatePacket(src, dst, text string) (uint16, []byte) { func (c *QQClient) buildTranslatePacket(src, dst, text string) (uint16, []byte) {
@ -46,10 +46,10 @@ func decodeTranslateResponse(c *QQClient, _ uint16, payload []byte) (interface{}
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 {
return nil, err return nil, errors.Wrap(err, "failed to unmarshal protobuf message")
} }
if err := proto.Unmarshal(pkg.Bodybuffer, &rsp); err != nil { if err := proto.Unmarshal(pkg.Bodybuffer, &rsp); err != nil {
return nil, err return nil, errors.Wrap(err, "failed to unmarshal protobuf message")
} }
return rsp.BatchTranslateRsp, nil return rsp.BatchTranslateRsp, nil
} }

View File

@ -1,12 +1,13 @@
package client package client
import ( import (
"errors"
"fmt" "fmt"
"github.com/Mrs4s/MiraiGo/binary" "github.com/Mrs4s/MiraiGo/binary"
"github.com/Mrs4s/MiraiGo/client/pb/richmedia" "github.com/Mrs4s/MiraiGo/client/pb/richmedia"
"github.com/Mrs4s/MiraiGo/utils" "github.com/Mrs4s/MiraiGo/utils"
"github.com/golang/protobuf/proto" "github.com/golang/protobuf/proto"
"github.com/pkg/errors"
) )
func (c *QQClient) GetTts(text string) ([]byte, error) { func (c *QQClient) GetTts(text string) ([]byte, error) {
@ -14,7 +15,7 @@ func (c *QQClient) GetTts(text string) ([]byte, error) {
data := fmt.Sprintf("{\"appid\": \"201908021016\",\"sendUin\": %v,\"text\": \"%v\"}", c.Uin, text) data := fmt.Sprintf("{\"appid\": \"201908021016\",\"sendUin\": %v,\"text\": \"%v\"}", c.Uin, text)
rsp, err := utils.HttpPostBytesWithCookie(url, []byte(data), c.getCookies()) rsp, err := utils.HttpPostBytesWithCookie(url, []byte(data), c.getCookies())
if err != nil { if err != nil {
return nil, err return nil, errors.Wrap(err, "failed to post to tts server")
} }
ttsReader := binary.NewReader(rsp) ttsReader := binary.NewReader(rsp)
ttsWriter := binary.NewWriter() ttsWriter := binary.NewWriter()
@ -34,7 +35,7 @@ func (c *QQClient) GetTts(text string) ([]byte, error) {
ttsRsp := &richmedia.TtsRspBody{} ttsRsp := &richmedia.TtsRspBody{}
err := proto.Unmarshal(ttsReader.ReadBytes(length), ttsRsp) err := proto.Unmarshal(ttsReader.ReadBytes(length), ttsRsp)
if err != nil { if err != nil {
return nil, err return nil, errors.Wrap(err, "failed to unmarshal protobuf message")
} }
if ttsRsp.RetCode != 0 { if ttsRsp.RetCode != 0 {
return nil, errors.New("can't convert text to voice") return nil, errors.New("can't convert text to voice")

3
go.mod
View File

@ -4,6 +4,7 @@ go 1.14
require ( require (
github.com/golang/protobuf v1.4.3 github.com/golang/protobuf v1.4.3
github.com/tidwall/gjson v1.6.1 github.com/pkg/errors v0.9.1
github.com/tidwall/gjson v1.6.3
google.golang.org/protobuf v1.25.0 google.golang.org/protobuf v1.25.0
) )

8
go.sum
View File

@ -15,8 +15,6 @@ github.com/golang/protobuf v1.4.0-rc.4.0.20200313231945-b860323f09d0/go.mod h1:W
github.com/golang/protobuf v1.4.0/go.mod h1:jodUvKwWbYaEsadDk5Fwe5c77LiNKVO9IDvqG2KuDX0= github.com/golang/protobuf v1.4.0/go.mod h1:jodUvKwWbYaEsadDk5Fwe5c77LiNKVO9IDvqG2KuDX0=
github.com/golang/protobuf v1.4.1 h1:ZFgWrT+bLgsYPirOnRfKLYJLvssAegOj/hgyMFdJZe0= github.com/golang/protobuf v1.4.1 h1:ZFgWrT+bLgsYPirOnRfKLYJLvssAegOj/hgyMFdJZe0=
github.com/golang/protobuf v1.4.1/go.mod h1:U8fpvMrcmy5pZrNK1lt4xCsGvpyWQ/VVv6QDs8UjoX8= github.com/golang/protobuf v1.4.1/go.mod h1:U8fpvMrcmy5pZrNK1lt4xCsGvpyWQ/VVv6QDs8UjoX8=
github.com/golang/protobuf v1.4.2 h1:+Z5KGCizgyZCbGh1KZqA0fcLLkwbsjIzS4aV2v7wJX0=
github.com/golang/protobuf v1.4.2/go.mod h1:oDoupMAO8OvCJWAcko0GGGIgR6R6ocIYbsSw735rRwI=
github.com/golang/protobuf v1.4.3 h1:JjCZWpVbqXDqFVmTfYWEVTMIYrL/NPdPSCHPJ0T/raM= github.com/golang/protobuf v1.4.3 h1:JjCZWpVbqXDqFVmTfYWEVTMIYrL/NPdPSCHPJ0T/raM=
github.com/golang/protobuf v1.4.3/go.mod h1:oDoupMAO8OvCJWAcko0GGGIgR6R6ocIYbsSw735rRwI= github.com/golang/protobuf v1.4.3/go.mod h1:oDoupMAO8OvCJWAcko0GGGIgR6R6ocIYbsSw735rRwI=
github.com/google/go-cmp v0.2.0/go.mod h1:oXzfMopK8JAjlY9xF4vHSVASa0yLyX7SntLO5aqRK0M= github.com/google/go-cmp v0.2.0/go.mod h1:oXzfMopK8JAjlY9xF4vHSVASa0yLyX7SntLO5aqRK0M=
@ -25,9 +23,11 @@ github.com/google/go-cmp v0.3.1/go.mod h1:8QqcDgzrUqlUb/G2PQTWiueGozuR1884gddMyw
github.com/google/go-cmp v0.4.0/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE= github.com/google/go-cmp v0.4.0/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE=
github.com/google/go-cmp v0.5.0 h1:/QaMHBdZ26BB3SSst0Iwl10Epc+xhTquomWX0oZEB6w= github.com/google/go-cmp v0.5.0 h1:/QaMHBdZ26BB3SSst0Iwl10Epc+xhTquomWX0oZEB6w=
github.com/google/go-cmp v0.5.0/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE= github.com/google/go-cmp v0.5.0/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE=
github.com/pkg/errors v0.9.1 h1:FEBLx1zS214owpjy7qsBeixbURkuhQAwrK5UwLGTwt4=
github.com/pkg/errors v0.9.1/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0=
github.com/prometheus/client_model v0.0.0-20190812154241-14fe0d1b01d4/go.mod h1:xMI15A0UPsDsEKsMN9yxemIoYk6Tm2C1GtYGdfGttqA= github.com/prometheus/client_model v0.0.0-20190812154241-14fe0d1b01d4/go.mod h1:xMI15A0UPsDsEKsMN9yxemIoYk6Tm2C1GtYGdfGttqA=
github.com/tidwall/gjson v1.6.1 h1:LRbvNuNuvAiISWg6gxLEFuCe72UKy5hDqhxW/8183ws= github.com/tidwall/gjson v1.6.3 h1:aHoiiem0dr7GHkW001T1SMTJ7X5PvyekH5WX0whWGnI=
github.com/tidwall/gjson v1.6.1/go.mod h1:BaHyNc5bjzYkPqgLq7mdVzeiRtULKULXLgZFKsxEHI0= github.com/tidwall/gjson v1.6.3/go.mod h1:BaHyNc5bjzYkPqgLq7mdVzeiRtULKULXLgZFKsxEHI0=
github.com/tidwall/match v1.0.1 h1:PnKP62LPNxHKTwvHHZZzdOAOCtsJTjo6dZLCwpKm5xc= github.com/tidwall/match v1.0.1 h1:PnKP62LPNxHKTwvHHZZzdOAOCtsJTjo6dZLCwpKm5xc=
github.com/tidwall/match v1.0.1/go.mod h1:LujAq0jyVjBy028G1WhWfIzbpQfMO8bBZ6Tyb0+pL9E= github.com/tidwall/match v1.0.1/go.mod h1:LujAq0jyVjBy028G1WhWfIzbpQfMO8bBZ6Tyb0+pL9E=
github.com/tidwall/pretty v1.0.2 h1:Z7S3cePv9Jwm1KwS0513MRaoUe3S01WPbLNV40pwWZU= github.com/tidwall/pretty v1.0.2 h1:Z7S3cePv9Jwm1KwS0513MRaoUe3S01WPbLNV40pwWZU=

View File

@ -1,10 +1,11 @@
package packets package packets
import ( import (
"errors" "strconv"
"github.com/Mrs4s/MiraiGo/binary" "github.com/Mrs4s/MiraiGo/binary"
"github.com/Mrs4s/MiraiGo/protocol/crypto" "github.com/Mrs4s/MiraiGo/protocol/crypto"
"strconv" "github.com/pkg/errors"
) )
var ErrUnknownFlag = errors.New("unknown flag") var ErrUnknownFlag = errors.New("unknown flag")
@ -88,13 +89,13 @@ func BuildSsoPacket(seq uint16, appId uint32, commandName, imei string, extData,
func ParseIncomingPacket(payload, d2key []byte) (*IncomingPacket, error) { func ParseIncomingPacket(payload, d2key []byte) (*IncomingPacket, error) {
if len(payload) < 6 { if len(payload) < 6 {
return nil, ErrInvalidPayload return nil, errors.WithStack(ErrInvalidPayload)
} }
reader := binary.NewReader(payload) reader := binary.NewReader(payload)
flag1 := reader.ReadInt32() flag1 := reader.ReadInt32()
flag2 := reader.ReadByte() flag2 := reader.ReadByte()
if reader.ReadByte() != 0 { // flag3 if reader.ReadByte() != 0 { // flag3
return nil, ErrUnknownFlag return nil, errors.WithStack(ErrUnknownFlag)
} }
reader.ReadString() // uin string reader.ReadString() // uin string
decrypted := func() (data []byte) { decrypted := func() (data []byte) {
@ -111,10 +112,10 @@ func ParseIncomingPacket(payload, d2key []byte) (*IncomingPacket, error) {
return nil return nil
}() }()
if len(decrypted) == 0 { if len(decrypted) == 0 {
return nil, ErrDecryptFailed return nil, errors.WithStack(ErrDecryptFailed)
} }
if flag1 != 0x0A && flag1 != 0x0B { if flag1 != 0x0A && flag1 != 0x0B {
return nil, ErrDecryptFailed return nil, errors.WithStack(ErrDecryptFailed)
} }
return parseSsoFrame(decrypted, flag2) return parseSsoFrame(decrypted, flag2)
} }
@ -122,13 +123,13 @@ func ParseIncomingPacket(payload, d2key []byte) (*IncomingPacket, error) {
func parseSsoFrame(payload []byte, flag2 byte) (*IncomingPacket, error) { func parseSsoFrame(payload []byte, flag2 byte) (*IncomingPacket, error) {
reader := binary.NewReader(payload) reader := binary.NewReader(payload)
if reader.ReadInt32()-4 > int32(reader.Len()) { if reader.ReadInt32()-4 > int32(reader.Len()) {
return nil, ErrPacketDropped return nil, errors.WithStack(ErrPacketDropped)
} }
seqId := reader.ReadInt32() seqId := reader.ReadInt32()
retCode := reader.ReadInt32() retCode := reader.ReadInt32()
if retCode != 0 { if retCode != 0 {
if retCode == -10008 { if retCode == -10008 {
return nil, ErrSessionExpired return nil, errors.WithStack(ErrSessionExpired)
} }
return nil, errors.New("return code unsuccessful: " + strconv.FormatInt(int64(retCode), 10)) return nil, errors.New("return code unsuccessful: " + strconv.FormatInt(int64(retCode), 10))
} }
@ -208,5 +209,5 @@ func (pkt *IncomingPacket) DecryptPayload(random, sessionKey []byte) ([]byte, er
if encryptType == 4 { if encryptType == 4 {
panic("todo") panic("todo")
} }
return nil, ErrUnknownFlag return nil, errors.WithStack(ErrUnknownFlag)
} }