1
0
mirror of https://github.com/Mrs4s/MiraiGo.git synced 2025-05-04 19:17:38 +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"
"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,27 +1158,27 @@ 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 f, ok := c.handlers.Load(pkt.SequenceId); ok {
c.handlers.Delete(pkt.SequenceId)
f.(func(i interface{}, err error))(nil, nil)
}
return
}
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)
//log.Println("decode", pkt.CommandName, "error:", err)
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))(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

View File

@ -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
}

View File

@ -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 (

View File

@ -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()

View File

@ -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...),
})
}

View File

@ -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

View File

@ -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))

View File

@ -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

View File

@ -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
}

View File

@ -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
}

View File

@ -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

View File

@ -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 {

View File

@ -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
}

View File

@ -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")

3
go.mod
View File

@ -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
)

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.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=

View File

@ -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)
}