From 02eb1c63575d543eaaa13fae475f8afd6673b869 Mon Sep 17 00:00:00 2001 From: wfjsw Date: Wed, 25 Nov 2020 13:14:55 +0800 Subject: [PATCH] better error support --- client/client.go | 57 ++++++++++++++++++++------------------ client/decoders.go | 54 +++++++++++++++++++----------------- client/entities.go | 7 +++-- client/events.go | 6 ++-- client/global.go | 46 ++++++++++++++++++++---------- client/group_file.go | 18 ++++++------ client/group_info.go | 6 ++-- client/highway.go | 23 +++++++-------- client/multimsg.go | 15 +++++----- client/offline_file.go | 7 ++--- client/ptt.go | 10 +++---- client/richmsg.go | 7 +++-- client/translate.go | 6 ++-- client/tts.go | 7 +++-- go.mod | 3 +- go.sum | 8 +++--- protocol/packets/global.go | 19 +++++++------ 17 files changed, 165 insertions(+), 134 deletions(-) diff --git a/client/client.go b/client/client.go index a73c4334..407a349e 100644 --- a/client/client.go +++ b/client/client.go @@ -5,13 +5,13 @@ import ( "crypto/md5" "encoding/hex" "encoding/json" - "errors" "fmt" "image" "io" "math" "math/rand" "net" + "runtime/debug" "sort" "strconv" "strings" @@ -19,6 +19,8 @@ import ( "sync/atomic" "time" + "github.com/pkg/errors" + "github.com/golang/protobuf/proto" "github.com/Mrs4s/MiraiGo/binary" @@ -701,7 +703,7 @@ func (c *QQClient) uploadPrivateImage(target int64, img []byte, count int) (*mes count++ h := md5.Sum(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. if _, err = c.UploadGroupImage(target, img); err != nil { return nil, err @@ -747,7 +749,7 @@ func (c *QQClient) QueryGroupImage(groupCode int64, hash []byte, size int32) (*m if rsp.IsExists { 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) { @@ -763,7 +765,7 @@ func (c *QQClient) QueryFriendImage(target int64, hash []byte, size int32) (*mes return &message.FriendImageElement{ ImageId: rsp.ResourceId, Md5: hash, - }, ErrNotExists + }, errors.WithStack(ErrNotExists) } return &message.FriendImageElement{ ImageId: rsp.ResourceId, @@ -820,7 +822,7 @@ func (c *QQClient) GetGroupMembers(group *GroupInfo) ([]*GroupMemberInfo, error) return nil, err } if data == nil { - return nil, errors.New("rsp is nil") + return nil, errors.New("group member list unavailable: rsp is nil") } rsp := data.(groupMemberListResponse) nextUin = rsp.NextUin @@ -983,7 +985,7 @@ func (c *QQClient) connect() error { if err != nil || conn == nil { c.retryTimes++ 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) if err = c.connect(); err != nil { @@ -1050,7 +1052,7 @@ func (c *QQClient) send(pkt []byte) error { } else { c.stat.PacketSent++ } - return err + return errors.Wrap(err, "Packet failed to send") } 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{} Error error } - _, err := c.Conn.Write(pkt) + + err := c.send(pkt) if err != nil { - c.stat.PacketLost++ return nil, err } - c.stat.PacketSent++ + ch := make(chan T) defer close(ch) 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, } }) + retry := 0 for true { select { @@ -1086,7 +1089,7 @@ func (c *QQClient) sendAndWait(seq uint16, pkt []byte) (interface{}, error) { c.handlers.Delete(seq) //c.Error("packet timed out, seq: %v", seq) //println("Packet Timed out") - return nil, errors.New("timeout") + return nil, errors.New("Packet timed out") } } return nil, nil @@ -1102,7 +1105,7 @@ func (c *QQClient) netLoop() { errCount := 0 for c.NetLooping { 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.stat.DisconnectTimes++ err = c.connect() @@ -1130,7 +1133,7 @@ func (c *QQClient) netLoop() { pkt, err := packets.ParseIncomingPacket(data, c.sigInfo.d2Key) if err != nil { 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 } errCount++ @@ -1155,26 +1158,26 @@ func (c *QQClient) netLoop() { go func() { defer func() { if pan := recover(); pan != nil { - c.Error("panic on decoder %v : %v", pkt.CommandName, pan) - //fmt.Println("panic on decoder:", pan) + c.Error("panic on decoder %v : %v\n%s", pkt.CommandName, pan, debug.Stack()) } }() - decoder, ok := c.decoders[pkt.CommandName] - if !ok { + + if decoder, ok := c.decoders[pkt.CommandName]; ok { + // found predefined decoder + rsp, err := decoder(c, pkt.SequenceId, payload) + if err != nil { + c.Debug("decode pkt %v error: %+v", pkt.CommandName, err) + } if f, ok := c.handlers.Load(pkt.SequenceId); ok { c.handlers.Delete(pkt.SequenceId) - f.(func(i interface{}, err error))(nil, nil) + f.(func(i interface{}, err error))(rsp, err) } - return - } - rsp, err := decoder(c, pkt.SequenceId, payload) - if err != nil { - 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 { + } 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))(rsp, err) + f.(func(i interface{}, err error))(nil, nil) + } else { + c.Debug("\nUnhandled Command: %s\nSeq: %d\nData: %x\n", pkt.CommandName, pkt.SequenceId, payload) } }() } diff --git a/client/decoders.go b/client/decoders.go index 3ca7cb3f..4b7980c0 100644 --- a/client/decoders.go +++ b/client/decoders.go @@ -1,11 +1,7 @@ package client import ( - "errors" "fmt" - "github.com/Mrs4s/MiraiGo/client/pb/notify" - "github.com/Mrs4s/MiraiGo/client/pb/pttcenter" - "github.com/Mrs4s/MiraiGo/client/pb/qweb" "net" "strconv" "strings" @@ -13,6 +9,11 @@ import ( "sync/atomic" "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/jce" "github.com/Mrs4s/MiraiGo/client/pb" @@ -161,7 +162,7 @@ func decodeLoginResponse(c *QQClient, _ uint16, payload []byte) (interface{}, er }, nil } - return nil, errors.New(fmt.Sprintf("unknown login response: %v", t)) // ? + return nil, errors.Errorf("unknown login response: %v", t) // ? } // StatSvc.register @@ -248,7 +249,7 @@ func decodeMessageSvcPacket(c *QQClient, _ uint16, payload []byte) (interface{}, rsp := msg.GetMessageResponse{} err := proto.Unmarshal(payload, &rsp) if err != nil { - return nil, err + return nil, errors.Wrap(err, "failed to unmarshal protobuf message") } if rsp.GetResult() != 0 { return nil, errors.New("message svc result unsuccessful") @@ -351,6 +352,7 @@ func decodeMessageSvcPacket(c *QQClient, _ uint16, payload []byte) (interface{}, case 529: sub4 := msg.SubMsgType0X4Body{} 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) continue } @@ -382,7 +384,7 @@ func decodeGroupMessagePacket(c *QQClient, _ uint16, payload []byte) (interface{ pkt := msg.PushMessagePacket{} err := proto.Unmarshal(payload, &pkt) if err != nil { - return nil, err + return nil, errors.Wrap(err, "failed to unmarshal protobuf message") } if pkt.Message.Head.GetFromUin() == c.Uin { c.dispatchGroupMessageReceiptEvent(&groupMessageReceiptEvent{ @@ -416,7 +418,7 @@ func decodeGroupMessagePacket(c *QQClient, _ uint16, payload []byte) (interface{ func decodeMsgSendResponse(c *QQClient, _ uint16, payload []byte) (interface{}, error) { rsp := msg.SendMessageResponse{} 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 { 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) { rsp := pb.GroupMemberRspBody{} 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 { - return nil, ErrMemberNotFound + return nil, errors.WithStack(ErrMemberNotFound) } group := c.FindGroup(rsp.GroupCode) return &GroupMemberInfo{ @@ -602,7 +604,7 @@ func decodeGroupImageStoreResponse(_ *QQClient, _ uint16, payload []byte) (inter pkt := pb.D388RespBody{} err := proto.Unmarshal(payload, &pkt) if err != nil { - return nil, err + return nil, errors.Wrap(err, "failed to unmarshal protobuf message") } rsp := pkt.MsgTryUpImgRsp[0] if rsp.Result != 0 { @@ -629,7 +631,7 @@ func decodeGroupImageStoreResponse(_ *QQClient, _ uint16, payload []byte) (inter func decodeOffPicUpResponse(_ *QQClient, _ uint16, payload []byte) (interface{}, error) { rsp := cmd0x352.RspBody{} if err := proto.Unmarshal(payload, &rsp); err != nil { - return nil, err + return nil, errors.Wrap(err, "failed to unmarshal protobuf message") } if rsp.FailMsg != "" { return imageUploadResponse{ @@ -740,7 +742,7 @@ func decodeOnlinePushReqPacket(c *QQClient, seq uint16, payload []byte) (interfa case 0x8A, 0x8B: s8a := pb.Sub8A{} 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 { if m.ToUin == c.Uin { @@ -754,7 +756,7 @@ func decodeOnlinePushReqPacket(c *QQClient, seq uint16, payload []byte) (interfa case 0xB3: b3 := pb.SubB3{} if err := proto.Unmarshal(probuf, &b3); err != nil { - return nil, err + return nil, errors.Wrap(err, "failed to unmarshal protobuf message") } frd := &FriendInfo{ Uin: b3.MsgAddFrdNotify.Uin, @@ -765,7 +767,7 @@ func decodeOnlinePushReqPacket(c *QQClient, seq uint16, payload []byte) (interfa case 0xD4: d4 := pb.SubD4{} if err := proto.Unmarshal(probuf, &d4); err != nil { - return nil, err + return nil, errors.Wrap(err, "failed to unmarshal protobuf message") } groupLeaveLock.Lock() if g := c.FindGroup(d4.Uin); g != nil { @@ -795,7 +797,7 @@ func decodeOnlinePushReqPacket(c *QQClient, seq uint16, payload []byte) (interfa case 0x44: s44 := pb.Sub44{} 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 { func() { @@ -832,7 +834,7 @@ func decodeOnlinePushTransPacket(c *QQClient, _ uint16, payload []byte) (interfa info := msg.TransMsgInfo{} err := proto.Unmarshal(payload, &info) if err != nil { - return nil, err + return nil, errors.Wrap(err, "failed to unmarshal protobuf message") } data := binary.NewReader(info.MsgData) 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) { rsp := structmsg.RspSystemMsgNew{} 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 { return nil, nil @@ -983,15 +985,15 @@ func decodeWordSegmentation(_ *QQClient, _ uint16, payload []byte) (interface{}, pkg := oidb.OIDBSSOPkg{} rsp := &oidb.D79RspBody{} 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 { - return nil, err + return nil, errors.Wrap(err, "failed to unmarshal protobuf message") } if rsp.Content != nil { return rsp.Content.SliceContent, nil } - return nil, errors.New("no word receive") + return nil, errors.New("no word received") } // OidbSvc.0xe07_0 @@ -999,10 +1001,10 @@ func decodeImageOcrResponse(_ *QQClient, _ uint16, payload []byte) (interface{}, pkg := oidb.OIDBSSOPkg{} rsp := oidb.DE07RspBody{} 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 { - return nil, err + return nil, errors.Wrap(err, "failed to unmarshal protobuf message") } if 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) { rsp := pttcenter.ShortVideoRspBody{} 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 { return nil, errors.New("resp error") @@ -1045,13 +1047,13 @@ func decodeAppInfoResponse(_ *QQClient, _ uint16, payload []byte) (interface{}, pkg := qweb.QWebRsp{} rsp := qweb.GetAppInfoByIdRsp{} 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 { return nil, errors.New(pkg.ErrMsg) } 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 } diff --git a/client/entities.go b/client/entities.go index d15dc793..18c9f6b5 100644 --- a/client/entities.go +++ b/client/entities.go @@ -1,11 +1,12 @@ package client import ( - "errors" - "github.com/Mrs4s/MiraiGo/binary/jce" - "github.com/Mrs4s/MiraiGo/message" "strings" "sync" + + "github.com/Mrs4s/MiraiGo/binary/jce" + "github.com/Mrs4s/MiraiGo/message" + "github.com/pkg/errors" ) var ( diff --git a/client/events.go b/client/events.go index 441b6bc5..03174b4b 100644 --- a/client/events.go +++ b/client/events.go @@ -2,8 +2,10 @@ package client import ( "fmt" - "github.com/Mrs4s/MiraiGo/message" + "runtime/debug" "sync" + + "github.com/Mrs4s/MiraiGo/message" ) type eventHandlers struct { @@ -383,7 +385,7 @@ func (c *QQClient) dispatchLogEvent(e *LogEvent) { func cover(f func()) { defer func() { if pan := recover(); pan != nil { - fmt.Println("event error:", pan) + fmt.Printf("event error: %v\n%s", pan, debug.Stack()) } }() f() diff --git a/client/global.go b/client/global.go index 85104ffc..5dbc5ef8 100644 --- a/client/global.go +++ b/client/global.go @@ -5,6 +5,12 @@ import ( "encoding/hex" "encoding/json" "fmt" + "math/rand" + "net" + "sort" + "strings" + "time" + "github.com/Mrs4s/MiraiGo/binary" "github.com/Mrs4s/MiraiGo/binary/jce" devinfo "github.com/Mrs4s/MiraiGo/client/pb" @@ -12,12 +18,8 @@ import ( "github.com/Mrs4s/MiraiGo/client/pb/oidb" "github.com/Mrs4s/MiraiGo/message" "github.com/Mrs4s/MiraiGo/utils" + "github.com/pkg/errors" "google.golang.org/protobuf/proto" - "math/rand" - "net" - "sort" - "strings" - "time" ) type DeviceInfo struct { @@ -232,7 +234,7 @@ func (info *DeviceInfo) ToJson() []byte { func (info *DeviceInfo) ReadJson(d []byte) error { var f DeviceInfoFile if err := json.Unmarshal(d, &f); err != nil { - return err + return errors.Wrap(err, "failed to unmarshal protobuf message") } info.Display = []byte(f.Display) if f.Product != "" { @@ -287,7 +289,7 @@ func (info *DeviceInfo) GenDeviceInfoData() []byte { } data, err := proto.Marshal(m) if err != nil { - panic(err) + panic(errors.Wrap(err, "failed to unmarshal protobuf message")) } return data } @@ -317,7 +319,7 @@ func getSSOAddress() ([]*net.TCPAddr, error) { }) }))) if err != nil { - return nil, err + return nil, errors.Wrap(err, "unable to fetch server list") } rspPkt := &jce.RequestPacket{} data := &jce.RequestDataVersion2{} @@ -344,7 +346,7 @@ func qualityTest(addr *net.TCPAddr) (int64, error) { start := time.Now() conn, err := net.DialTimeout("tcp", addr.String(), time.Second*5) if err != nil { - return 0, err + return 0, errors.Wrap(err, "failed to connect to server during quality test") } _ = conn.Close() 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) info, err := c.GetGroupInfo(m.Head.GroupInfo.GetGroupCode()) 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 } group = info @@ -427,7 +429,7 @@ func (c *QQClient) parseGroupMessage(m *msg.Message) *message.GroupMessage { if len(group.Members) == 0 { mem, err := c.GetGroupMembers(group) 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 } 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{ - Type: "INFO", + Type: "ERROR", Message: fmt.Sprintf(msg, args...), }) } -func (c *QQClient) Error(msg string, args ...interface{}) { +func (c *QQClient) Warning(msg string, args ...interface{}) { 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...), }) } @@ -610,3 +619,10 @@ func (c *QQClient) Debug(msg string, args ...interface{}) { Message: fmt.Sprintf(msg, args...), }) } + +func (c *QQClient) Trace(msg string, args ...interface{}) { + c.dispatchLogEvent(&LogEvent{ + Type: "TRACE", + Message: fmt.Sprintf(msg, args...), + }) +} diff --git a/client/group_file.go b/client/group_file.go index fe873408..3c323d3b 100644 --- a/client/group_file.go +++ b/client/group_file.go @@ -2,11 +2,13 @@ package client import ( "encoding/hex" - "errors" "fmt" + "runtime/debug" + "github.com/Mrs4s/MiraiGo/client/pb/oidb" "github.com/Mrs4s/MiraiGo/protocol/packets" "github.com/golang/protobuf/proto" + "github.com/pkg/errors" ) type ( @@ -48,7 +50,7 @@ type ( func (c *QQClient) GetGroupFileSystem(groupCode int64) (fs *GroupFileSystem, err error) { defer func() { 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") } }() @@ -264,10 +266,10 @@ func decodeOIDB6d81Response(c *QQClient, _ uint16, payload []byte) (interface{}, pkg := oidb.OIDBSSOPkg{} rsp := oidb.D6D8RspBody{} 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 { - return nil, err + return nil, errors.Wrap(err, "failed to unmarshal protobuf message") } return &rsp, nil } @@ -277,10 +279,10 @@ func decodeOIDB6d62Response(_ *QQClient, _ uint16, payload []byte) (interface{}, pkg := oidb.OIDBSSOPkg{} rsp := oidb.D6D6RspBody{} 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 { - return nil, err + return nil, errors.Wrap(err, "failed to unmarshal protobuf message") } if rsp.DownloadFileRsp.DownloadUrl == nil { return nil, errors.New(rsp.DownloadFileRsp.ClientWording) @@ -294,10 +296,10 @@ func decodeOIDB6d63Response(_ *QQClient, _ uint16, payload []byte) (interface{}, pkg := oidb.OIDBSSOPkg{} rsp := oidb.D6D6RspBody{} 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 { - return nil, err + return nil, errors.Wrap(err, "failed to unmarshal protobuf message") } if rsp.DeleteFileRsp == nil { return "", nil diff --git a/client/group_info.go b/client/group_info.go index baa57f8b..f10d8957 100644 --- a/client/group_info.go +++ b/client/group_info.go @@ -1,11 +1,11 @@ package client import ( - "errors" "github.com/Mrs4s/MiraiGo/binary" "github.com/Mrs4s/MiraiGo/binary/jce" "github.com/Mrs4s/MiraiGo/client/pb/oidb" "github.com/Mrs4s/MiraiGo/protocol/packets" + "github.com/pkg/errors" "google.golang.org/protobuf/proto" ) @@ -120,10 +120,10 @@ func decodeGroupInfoResponse(c *QQClient, _ uint16, payload []byte) (interface{} pkg := oidb.OIDBSSOPkg{} rsp := oidb.D88DRspBody{} 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 { - return nil, err + return nil, errors.Wrap(err, "failed to unmarshal protobuf message") } if len(rsp.RspGroupInfo) == 0 { return nil, errors.New(string(rsp.StrErrorInfo)) diff --git a/client/highway.go b/client/highway.go index 89ee0db1..156f7177 100644 --- a/client/highway.go +++ b/client/highway.go @@ -5,15 +5,16 @@ import ( "crypto/md5" binary2 "encoding/binary" "encoding/hex" - "errors" "fmt" - "github.com/Mrs4s/MiraiGo/binary" - "github.com/Mrs4s/MiraiGo/client/pb" - "github.com/Mrs4s/MiraiGo/utils" - "google.golang.org/protobuf/proto" "net" "net/http" "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 { @@ -24,7 +25,7 @@ func (c *QQClient) highwayUpload(ip uint32, port int, updKey, data []byte, cmdId binary2.LittleEndian.PutUint32(addr.IP, ip) conn, err := net.DialTCP("tcp", nil, &addr) if err != nil { - return err + return errors.Wrap(err, "failed to connect to highway server") } defer conn.Close() h := md5.Sum(data) @@ -33,11 +34,11 @@ func (c *QQClient) highwayUpload(ip uint32, port int, updKey, data []byte, cmdId for _, p := range pkt { _, err = conn.Write(p) if err != nil { - return err + return errors.Wrap(err, "failed to write") } _, err = r.ReadByte() if err != nil { - return err + return errors.Wrap(err, "failed to read byte") } hl, _ := r.ReadInt32() a2, _ := r.ReadInt32() @@ -46,7 +47,7 @@ func (c *QQClient) highwayUpload(ip uint32, port int, updKey, data []byte, cmdId r.ReadByte() rsp := new(pb.RspDataHighwayHead) if err = proto.Unmarshal(payload, rsp); err != nil { - return err + return errors.Wrap(err, "failed to unmarshal protobuf message") } if rsp.ErrorCode != 0 { 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) url = append(url, "&mType=pttDu&voice_encodec=1"...) _, 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 { @@ -95,7 +96,7 @@ func (c *QQClient) uploadGroupHeadPortrait(groupCode int64, img []byte) error { req.Header["Content-Type"] = []string{"multipart/form-data;boundary=****"} rsp, err := http.DefaultClient.Do(req) if err != nil { - return err + return errors.Wrap(err, "failed to upload group head portrait") } rsp.Body.Close() return nil diff --git a/client/multimsg.go b/client/multimsg.go index b9ac7508..829834f7 100644 --- a/client/multimsg.go +++ b/client/multimsg.go @@ -1,14 +1,15 @@ package client import ( - "errors" "fmt" + "github.com/Mrs4s/MiraiGo/binary" "github.com/Mrs4s/MiraiGo/client/pb/longmsg" "github.com/Mrs4s/MiraiGo/client/pb/msg" "github.com/Mrs4s/MiraiGo/client/pb/multimsg" "github.com/Mrs4s/MiraiGo/protocol/packets" "github.com/Mrs4s/MiraiGo/utils" + "github.com/pkg/errors" "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) { body := multimsg.MultiRspBody{} 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 { return nil, errors.New("rsp is empty") @@ -52,7 +53,7 @@ func decodeMultiApplyUpResponse(_ *QQClient, _ uint16, payload []byte) (interfac case 193: 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 @@ -82,7 +83,7 @@ func (c *QQClient) buildMultiApplyDownPacket(resId string) (uint16, []byte) { func decodeMultiApplyDownResponse(_ *QQClient, _ uint16, payload []byte) (interface{}, error) { body := multimsg.MultiRspBody{} 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 { 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)), "") if err != nil { - return nil, err + return nil, errors.Wrap(err, "failed to download by multi apply down") } if b[0] != 40 { 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))) lb := longmsg.LongRspBody{} 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) mt := msg.PbMultiMsgTransmit{} if err = proto.Unmarshal(uc, &mt); err != nil { - return nil, err + return nil, errors.Wrap(err, "failed to unmarshal protobuf message") } return &mt, nil } diff --git a/client/offline_file.go b/client/offline_file.go index 4d38d0c4..1f172978 100644 --- a/client/offline_file.go +++ b/client/offline_file.go @@ -1,10 +1,9 @@ package client import ( - "errors" - "fmt" "github.com/Mrs4s/MiraiGo/client/pb/cmd0x346" "github.com/Mrs4s/MiraiGo/protocol/packets" + "github.com/pkg/errors" "google.golang.org/protobuf/proto" ) @@ -33,7 +32,7 @@ func decodeOfflineFileDownloadResponse(c *QQClient, _ uint16, payload []byte) (i rsp := cmd0x346.C346RspBody{} if err := proto.Unmarshal(payload, &rsp); err != nil { 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 { 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 { 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 } diff --git a/client/ptt.go b/client/ptt.go index 12c082ad..1ced44d5 100644 --- a/client/ptt.go +++ b/client/ptt.go @@ -3,14 +3,14 @@ package client import ( "crypto/md5" "encoding/hex" - "errors" - "fmt" + "github.com/Mrs4s/MiraiGo/binary" "github.com/Mrs4s/MiraiGo/client/pb" "github.com/Mrs4s/MiraiGo/client/pb/cmd0x346" "github.com/Mrs4s/MiraiGo/client/pb/msg" "github.com/Mrs4s/MiraiGo/message" "github.com/Mrs4s/MiraiGo/protocol/packets" + "github.com/pkg/errors" "google.golang.org/protobuf/proto" ) @@ -122,7 +122,7 @@ func decodeGroupPttStoreResponse(_ *QQClient, _ uint16, payload []byte) (interfa pkt := pb.D388RespBody{} err := proto.Unmarshal(payload, &pkt) if err != nil { - return nil, err + return nil, errors.Wrap(err, "failed to unmarshal protobuf message") } rsp := pkt.MsgTryUpPttRsp[0] if rsp.Result != 0 { @@ -180,7 +180,7 @@ func decodePrivatePttStoreResponse(c *QQClient, _ uint16, payload []byte) (inter rsp := cmd0x346.C346RspBody{} if err := proto.Unmarshal(payload, &rsp); err != nil { 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 { 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 { 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 { return pttUploadResponse{IsExists: true}, nil diff --git a/client/richmsg.go b/client/richmsg.go index eea21212..2a56a92e 100644 --- a/client/richmsg.go +++ b/client/richmsg.go @@ -1,14 +1,15 @@ package client import ( - "errors" + "math/rand" + "time" + "github.com/Mrs4s/MiraiGo/client/pb/oidb" "github.com/Mrs4s/MiraiGo/message" "github.com/Mrs4s/MiraiGo/protocol/packets" "github.com/Mrs4s/MiraiGo/utils" + "github.com/pkg/errors" "google.golang.org/protobuf/proto" - "math/rand" - "time" ) type RichClientInfo struct { diff --git a/client/translate.go b/client/translate.go index 341801ec..b4afd1a1 100644 --- a/client/translate.go +++ b/client/translate.go @@ -1,10 +1,10 @@ package client import ( - "errors" "github.com/Mrs4s/MiraiGo/client/pb/oidb" "github.com/Mrs4s/MiraiGo/protocol/packets" "github.com/golang/protobuf/proto" + "github.com/pkg/errors" ) 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{} rsp := oidb.TranslateRspBody{} 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 { - return nil, err + return nil, errors.Wrap(err, "failed to unmarshal protobuf message") } return rsp.BatchTranslateRsp, nil } diff --git a/client/tts.go b/client/tts.go index 4e68815e..ec77a279 100644 --- a/client/tts.go +++ b/client/tts.go @@ -1,12 +1,13 @@ package client import ( - "errors" "fmt" + "github.com/Mrs4s/MiraiGo/binary" "github.com/Mrs4s/MiraiGo/client/pb/richmedia" "github.com/Mrs4s/MiraiGo/utils" "github.com/golang/protobuf/proto" + "github.com/pkg/errors" ) 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) rsp, err := utils.HttpPostBytesWithCookie(url, []byte(data), c.getCookies()) if err != nil { - return nil, err + return nil, errors.Wrap(err, "failed to post to tts server") } ttsReader := binary.NewReader(rsp) ttsWriter := binary.NewWriter() @@ -34,7 +35,7 @@ func (c *QQClient) GetTts(text string) ([]byte, error) { ttsRsp := &richmedia.TtsRspBody{} err := proto.Unmarshal(ttsReader.ReadBytes(length), ttsRsp) if err != nil { - return nil, err + return nil, errors.Wrap(err, "failed to unmarshal protobuf message") } if ttsRsp.RetCode != 0 { return nil, errors.New("can't convert text to voice") diff --git a/go.mod b/go.mod index 202f4723..0f0a1d10 100644 --- a/go.mod +++ b/go.mod @@ -4,6 +4,7 @@ go 1.14 require ( 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 ) diff --git a/go.sum b/go.sum index 4768d625..b47bdce7 100644 --- a/go.sum +++ b/go.sum @@ -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.1 h1:ZFgWrT+bLgsYPirOnRfKLYJLvssAegOj/hgyMFdJZe0= 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/go.mod h1:oDoupMAO8OvCJWAcko0GGGIgR6R6ocIYbsSw735rRwI= 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.5.0 h1:/QaMHBdZ26BB3SSst0Iwl10Epc+xhTquomWX0oZEB6w= 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/tidwall/gjson v1.6.1 h1:LRbvNuNuvAiISWg6gxLEFuCe72UKy5hDqhxW/8183ws= -github.com/tidwall/gjson v1.6.1/go.mod h1:BaHyNc5bjzYkPqgLq7mdVzeiRtULKULXLgZFKsxEHI0= +github.com/tidwall/gjson v1.6.3 h1:aHoiiem0dr7GHkW001T1SMTJ7X5PvyekH5WX0whWGnI= +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/go.mod h1:LujAq0jyVjBy028G1WhWfIzbpQfMO8bBZ6Tyb0+pL9E= github.com/tidwall/pretty v1.0.2 h1:Z7S3cePv9Jwm1KwS0513MRaoUe3S01WPbLNV40pwWZU= diff --git a/protocol/packets/global.go b/protocol/packets/global.go index 167314fa..46d11784 100644 --- a/protocol/packets/global.go +++ b/protocol/packets/global.go @@ -1,10 +1,11 @@ package packets import ( - "errors" + "strconv" + "github.com/Mrs4s/MiraiGo/binary" "github.com/Mrs4s/MiraiGo/protocol/crypto" - "strconv" + "github.com/pkg/errors" ) 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) { if len(payload) < 6 { - return nil, ErrInvalidPayload + return nil, errors.WithStack(ErrInvalidPayload) } reader := binary.NewReader(payload) flag1 := reader.ReadInt32() flag2 := reader.ReadByte() if reader.ReadByte() != 0 { // flag3 - return nil, ErrUnknownFlag + return nil, errors.WithStack(ErrUnknownFlag) } reader.ReadString() // uin string decrypted := func() (data []byte) { @@ -111,10 +112,10 @@ func ParseIncomingPacket(payload, d2key []byte) (*IncomingPacket, error) { return nil }() if len(decrypted) == 0 { - return nil, ErrDecryptFailed + return nil, errors.WithStack(ErrDecryptFailed) } if flag1 != 0x0A && flag1 != 0x0B { - return nil, ErrDecryptFailed + return nil, errors.WithStack(ErrDecryptFailed) } return parseSsoFrame(decrypted, flag2) } @@ -122,13 +123,13 @@ func ParseIncomingPacket(payload, d2key []byte) (*IncomingPacket, error) { func parseSsoFrame(payload []byte, flag2 byte) (*IncomingPacket, error) { reader := binary.NewReader(payload) if reader.ReadInt32()-4 > int32(reader.Len()) { - return nil, ErrPacketDropped + return nil, errors.WithStack(ErrPacketDropped) } seqId := reader.ReadInt32() retCode := reader.ReadInt32() if retCode != 0 { if retCode == -10008 { - return nil, ErrSessionExpired + return nil, errors.WithStack(ErrSessionExpired) } 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 { panic("todo") } - return nil, ErrUnknownFlag + return nil, errors.WithStack(ErrUnknownFlag) }