diff --git a/client/client.go b/client/client.go index e7a3fef1..30093de4 100644 --- a/client/client.go +++ b/client/client.go @@ -98,7 +98,7 @@ type QQClient struct { groupDataTransSeq int32 highwayApplyUpSeq int32 eventHandlers *eventHandlers - stat *Statistics + stat Statistics groupListLock sync.Mutex } @@ -201,7 +201,6 @@ func NewClientMd5(uin int64, passwordMd5 [16]byte) *QQClient { onlinePushCache: utils.NewCache(time.Second * 15), version: genVersionInfo(SystemDeviceInfo.Protocol), servers: []*net.TCPAddr{}, - stat: &Statistics{}, } sso, err := getSSOAddress() if err == nil && len(sso) > 0 { @@ -429,19 +428,19 @@ func (c *QQClient) init(tokenLogin bool) error { _, _ = c.sendAndWait(seq, pkt, requestParams{"used_reg_proxy": true, "init": true}) c.stat.once.Do(func() { c.OnGroupMessage(func(_ *QQClient, _ *message.GroupMessage) { - c.stat.MessageReceived++ - c.stat.LastMessageTime = time.Now().Unix() + atomic.AddUint64(&c.stat.MessageReceived, 1) + atomic.StoreInt64(&c.stat.LastMessageTime, time.Now().Unix()) }) c.OnPrivateMessage(func(_ *QQClient, _ *message.PrivateMessage) { - c.stat.MessageReceived++ - c.stat.LastMessageTime = time.Now().Unix() + atomic.AddUint64(&c.stat.MessageReceived, 1) + atomic.StoreInt64(&c.stat.LastMessageTime, time.Now().Unix()) }) c.OnTempMessage(func(_ *QQClient, _ *TempMessageEvent) { - c.stat.MessageReceived++ - c.stat.LastMessageTime = time.Now().Unix() + atomic.AddUint64(&c.stat.MessageReceived, 1) + atomic.StoreInt64(&c.stat.LastMessageTime, time.Now().Unix()) }) c.onGroupMessageReceipt("internal", func(_ *QQClient, _ *groupMessageReceiptEvent) { - c.stat.MessageSent++ + atomic.AddUint64(&c.stat.MessageSent, 1) }) }) return nil @@ -917,9 +916,9 @@ func (c *QQClient) nextHighwayApplySeq() int32 { func (c *QQClient) send(pkt []byte) error { err := c.TCP.Write(pkt) if err != nil { - c.stat.PacketLost++ + atomic.AddUint64(&c.stat.PacketLost, 1) } else { - c.stat.PacketSent++ + atomic.AddUint64(&c.stat.PacketSent, 1) } return errors.Wrap(err, "Packet failed to send") } @@ -1023,13 +1022,13 @@ func (c *QQClient) Disconnect() { func (c *QQClient) plannedDisconnect(_ *utils.TCPListener) { c.Debug("planned disconnect.") - c.stat.DisconnectTimes++ + atomic.AddUint32(&c.stat.DisconnectTimes, 1) c.Online = false } func (c *QQClient) unexpectedDisconnect(_ *utils.TCPListener, e error) { c.Error("unexpected disconnect: %v", e) - c.stat.DisconnectTimes++ + atomic.AddUint32(&c.stat.DisconnectTimes, 1) c.Online = false if err := c.connect(); err != nil { c.Error("connect server error: %v", err) @@ -1079,7 +1078,7 @@ func (c *QQClient) netLoop() { } errCount = 0 c.Debug("rev pkt: %v seq: %v", pkt.CommandName, pkt.SequenceId) - c.stat.PacketReceived++ + atomic.AddUint64(&c.stat.PacketReceived, 1) go func() { defer func() { if pan := recover(); pan != nil { diff --git a/client/private_msg.go b/client/private_msg.go index dac4d501..16519650 100644 --- a/client/private_msg.go +++ b/client/private_msg.go @@ -2,6 +2,7 @@ package client import ( "math/rand" + "sync/atomic" "time" "github.com/pkg/errors" @@ -37,7 +38,7 @@ func (c *QQClient) SendPrivateMessage(target int64, m *message.SendingMessage) * _, pkt := c.buildFriendSendingPacket(target, seq, mr, 1, 0, 0, t, m.Elements) _ = c.send(pkt) } - c.stat.MessageSent++ + atomic.AddUint64(&c.stat.MessageSent, 1) ret := &message.PrivateMessage{ Id: seq, InternalId: mr, @@ -76,7 +77,7 @@ func (c *QQClient) SendGroupTempMessage(groupCode, target int64, m *message.Send t := time.Now().Unix() _, pkt := c.buildGroupTempSendingPacket(group.Uin, target, seq, mr, t, m) _ = c.send(pkt) - c.stat.MessageSent++ + atomic.AddUint64(&c.stat.MessageSent, 1) return &message.TempMessage{ Id: seq, GroupCode: group.Code, @@ -97,7 +98,7 @@ func (c *QQClient) sendWPATempMessage(target int64, sig []byte, m *message.Sendi t := time.Now().Unix() _, pkt := c.buildWPATempSendingPacket(target, sig, seq, mr, t, m) _ = c.send(pkt) - c.stat.MessageSent++ + atomic.AddUint64(&c.stat.MessageSent, 1) return &message.TempMessage{ Id: seq, Self: c.Uin, diff --git a/client/statistics.go b/client/statistics.go index 1abf5ff4..b9af1c1c 100644 --- a/client/statistics.go +++ b/client/statistics.go @@ -1,20 +1,47 @@ package client -import "sync" +import ( + "bytes" + "strconv" + "sync" + "sync/atomic" +) type Statistics struct { - PacketReceived uint64 `json:"packet_received"` - PacketSent uint64 `json:"packet_sent"` - PacketLost uint32 `json:"packet_lost"` - MessageReceived uint64 `json:"message_received"` - MessageSent uint64 `json:"message_sent"` - DisconnectTimes uint32 `json:"disconnect_times"` - LostTimes uint32 `json:"lost_times"` - LastMessageTime int64 `json:"last_message_time"` + PacketReceived uint64 + PacketSent uint64 + PacketLost uint64 + MessageReceived uint64 + MessageSent uint64 + DisconnectTimes uint32 + LostTimes uint32 + LastMessageTime int64 once sync.Once } -func (c *QQClient) GetStatistics() *Statistics { - return c.stat +func (s *Statistics) MarshalJSON() ([]byte, error) { + var w bytes.Buffer + w.Grow(256) + w.WriteString(strconv.FormatUint(atomic.LoadUint64(&s.PacketReceived), 10)) + w.WriteString(`,"packet_sent":`) + w.WriteString(strconv.FormatUint(atomic.LoadUint64(&s.PacketSent), 10)) + w.WriteString(`,"packet_lost":`) + w.WriteString(strconv.FormatUint(atomic.LoadUint64(&s.PacketLost), 10)) + w.WriteString(`,"message_received":`) + w.WriteString(strconv.FormatUint(atomic.LoadUint64(&s.MessageReceived), 10)) + w.WriteString(`,"message_sent":`) + w.WriteString(strconv.FormatUint(atomic.LoadUint64(&s.MessageSent), 10)) + w.WriteString(`,"disconnect_times":`) + w.WriteString(strconv.FormatUint(uint64(atomic.LoadUint32(&s.DisconnectTimes)), 10)) + w.WriteString(`,"lost_times":`) + w.WriteString(strconv.FormatUint(uint64(atomic.LoadUint32(&s.LostTimes)), 10)) + w.WriteString(`,"last_message_time":`) + w.WriteString(strconv.FormatInt(atomic.LoadInt64(&s.LastMessageTime), 10)) + w.WriteByte('}') + return w.Bytes(), nil +} + +func (c *QQClient) GetStatistics() *Statistics { + return &c.stat } diff --git a/client/sync.go b/client/sync.go index 4c469a52..b7197a6c 100644 --- a/client/sync.go +++ b/client/sync.go @@ -3,6 +3,7 @@ package client import ( "math/rand" "sync" + "sync/atomic" "time" "google.golang.org/protobuf/proto" @@ -150,10 +151,11 @@ func (c *QQClient) buildGetOfflineMsgRequestPacket() (uint16, []byte) { C2CMsg: &jce.SvcReqGetMsgV2{ Uin: c.Uin, DateTime: func() int32 { - if c.stat.LastMessageTime == 0 { + t := atomic.LoadInt64(&c.stat.LastMessageTime) + if t == 0 { return 1 } - return int32(c.stat.LastMessageTime) + return int32(t) }(), RecivePic: 1, Ability: 15, @@ -218,10 +220,11 @@ func (c *QQClient) buildSyncMsgRequestPacket() (uint16, []byte) { C2CMsg: &jce.SvcReqGetMsgV2{ Uin: c.Uin, DateTime: func() int32 { - if c.stat.LastMessageTime == 0 { + t := atomic.LoadInt64(&c.stat.LastMessageTime) + if t == 0 { return 1 } - return int32(c.stat.LastMessageTime) + return int32(t) }(), RecivePic: 1, Ability: 15,