1
0
mirror of https://github.com/Mrs4s/MiraiGo.git synced 2025-05-04 19:17:38 +08:00

Merge pull request #260 from Mrs4s/typeparam

all: update to go1.18 with generic
This commit is contained in:
Mrs4s 2022-03-17 16:57:21 +08:00 committed by GitHub
commit 6d84141b8d
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
40 changed files with 448 additions and 918 deletions

View File

@ -2,9 +2,9 @@ name: Go
on: on:
push: push:
branches: [ master ] branches: [ master, typeparam ]
pull_request: pull_request:
branches: [ master ] branches: [ master, typeparam ]
jobs: jobs:
@ -16,7 +16,7 @@ jobs:
- name: Set up Go 1.x - name: Set up Go 1.x
uses: actions/setup-go@v2 uses: actions/setup-go@v2
with: with:
go-version: ^1.13 go-version: 1.18
- name: Check out code into the Go module directory - name: Check out code into the Go module directory
uses: actions/checkout@v2 uses: actions/checkout@v2

View File

@ -99,7 +99,7 @@ func TestJceReader_ReadBytes(t *testing.T) {
assert.Equal(t, b, rb) assert.Equal(t, b, rb)
} }
func (w *JceWriter) WriteObject(i interface{}, tag byte) { func (w *JceWriter) WriteObject(i any, tag byte) {
t := reflect.TypeOf(i) t := reflect.TypeOf(i)
if t.Kind() == reflect.Map { if t.Kind() == reflect.Map {
w.WriteMap(i, tag) w.WriteMap(i, tag)
@ -192,7 +192,7 @@ type decoder struct {
var decoderCache = sync.Map{} var decoderCache = sync.Map{}
// WriteJceStructRaw 写入 Jce 结构体 // WriteJceStructRaw 写入 Jce 结构体
func (w *JceWriter) WriteJceStructRaw(s interface{}) { func (w *JceWriter) WriteJceStructRaw(s any) {
t := reflect.TypeOf(s) t := reflect.TypeOf(s)
if t.Kind() != reflect.Ptr { if t.Kind() != reflect.Ptr {
return return
@ -234,7 +234,7 @@ func (w *JceWriter) WriteJceStruct(s IJceStruct, tag byte) {
w.writeHead(11, 0) w.writeHead(11, 0)
} }
func (w *JceWriter) WriteSlice(i interface{}, tag byte) { func (w *JceWriter) WriteSlice(i any, tag byte) {
va := reflect.ValueOf(i) va := reflect.ValueOf(i)
if va.Kind() != reflect.Slice { if va.Kind() != reflect.Slice {
panic("JceWriter.WriteSlice: not a slice") panic("JceWriter.WriteSlice: not a slice")
@ -270,7 +270,7 @@ func (w *JceWriter) WriteJceStructSlice(l []IJceStruct, tag byte) {
} }
} }
func (w *JceWriter) WriteMap(m interface{}, tag byte) { func (w *JceWriter) WriteMap(m any, tag byte) {
va := reflect.ValueOf(m) va := reflect.ValueOf(m)
if va.Kind() != reflect.Map { if va.Kind() != reflect.Map {
panic("JceWriter.WriteMap: not a map") panic("JceWriter.WriteMap: not a map")

View File

@ -8,7 +8,7 @@ import (
) )
var bufferPool = sync.Pool{ var bufferPool = sync.Pool{
New: func() interface{} { New: func() any {
return new(Writer) return new(Writer)
}, },
} }
@ -24,7 +24,7 @@ func SelectWriter() *Writer {
// PutWriter 将 Writer 放回池中 // PutWriter 将 Writer 放回池中
func PutWriter(w *Writer) { func PutWriter(w *Writer) {
// See https://golang.org/issue/23199 // See https://golang.org/issue/23199
const maxSize = 1 << 16 const maxSize = 32 * 1024
if (*bytes.Buffer)(w).Cap() < maxSize { // 对于大Buffer直接丢弃 if (*bytes.Buffer)(w).Cap() < maxSize { // 对于大Buffer直接丢弃
w.Reset() w.Reset()
bufferPool.Put(w) bufferPool.Put(w)
@ -32,7 +32,7 @@ func PutWriter(w *Writer) {
} }
var gzipPool = sync.Pool{ var gzipPool = sync.Pool{
New: func() interface{} { New: func() any {
buf := new(bytes.Buffer) buf := new(bytes.Buffer)
w := gzip.NewWriter(buf) w := gzip.NewWriter(buf)
return &GzipWriter{ return &GzipWriter{
@ -64,7 +64,7 @@ type zlibWriter struct {
} }
var zlibPool = sync.Pool{ var zlibPool = sync.Pool{
New: func() interface{} { New: func() any {
buf := new(bytes.Buffer) buf := new(bytes.Buffer)
w := zlib.NewWriter(buf) w := zlib.NewWriter(buf)
return &zlibWriter{ return &zlibWriter{

View File

@ -118,7 +118,7 @@ func ToChunkedBytesF(b []byte, size int, f func([]byte)) {
} }
} }
func ToBytes(i interface{}) []byte { func ToBytes(i any) []byte {
return NewWriterF(func(w *Writer) { return NewWriterF(func(w *Writer) {
// TODO: more types // TODO: more types
switch t := i.(type) { switch t := i.(type) {

View File

@ -71,7 +71,7 @@ func (c *QQClient) c2cMessageSyncProcessor(rsp *msg.GetMessageResponse, info *ne
_, _ = c.sendAndWait(c.buildDeleteMessageRequestPacket(delItems)) _, _ = c.sendAndWait(c.buildDeleteMessageRequestPacket(delItems))
} }
if rsp.GetSyncFlag() != msg.SyncFlag_STOP { if rsp.GetSyncFlag() != msg.SyncFlag_STOP {
c.Debug("continue sync with flag: %v", rsp.SyncFlag) c.debug("continue sync with flag: %v", rsp.SyncFlag)
seq, pkt := c.buildGetMessageRequestPacket(rsp.GetSyncFlag(), time.Now().Unix()) seq, pkt := c.buildGetMessageRequestPacket(rsp.GetSyncFlag(), time.Now().Unix())
_, _ = c.sendAndWait(seq, pkt, info.Params) _, _ = c.sendAndWait(seq, pkt, info.Params)
} }
@ -80,12 +80,12 @@ func (c *QQClient) c2cMessageSyncProcessor(rsp *msg.GetMessageResponse, info *ne
func (c *QQClient) commMsgProcessor(pMsg *msg.Message, info *network.IncomingPacketInfo) { func (c *QQClient) commMsgProcessor(pMsg *msg.Message, info *network.IncomingPacketInfo) {
strKey := fmt.Sprintf("%d%d%d%d", pMsg.Head.GetFromUin(), pMsg.Head.GetToUin(), pMsg.Head.GetMsgSeq(), pMsg.Head.GetMsgUid()) strKey := fmt.Sprintf("%d%d%d%d", pMsg.Head.GetFromUin(), pMsg.Head.GetToUin(), pMsg.Head.GetMsgSeq(), pMsg.Head.GetMsgUid())
if _, ok := c.msgSvcCache.GetAndUpdate(strKey, time.Hour); ok { if _, ok := c.msgSvcCache.GetAndUpdate(strKey, time.Hour); ok {
c.Debug("c2c msg %v already exists in cache. skip.", pMsg.Head.GetMsgUid()) c.debug("c2c msg %v already exists in cache. skip.", pMsg.Head.GetMsgUid())
return return
} }
c.msgSvcCache.Add(strKey, "", time.Hour) c.msgSvcCache.Add(strKey, unit{}, time.Hour)
if c.lastC2CMsgTime > int64(pMsg.Head.GetMsgTime()) && (c.lastC2CMsgTime-int64(pMsg.Head.GetMsgTime())) > 60*10 { if c.lastC2CMsgTime > int64(pMsg.Head.GetMsgTime()) && (c.lastC2CMsgTime-int64(pMsg.Head.GetMsgTime())) > 60*10 {
c.Debug("c2c msg filtered by time. lastMsgTime: %v msgTime: %v", c.lastC2CMsgTime, pMsg.Head.GetMsgTime()) c.debug("c2c msg filtered by time. lastMsgTime: %v msgTime: %v", c.lastC2CMsgTime, pMsg.Head.GetMsgTime())
return return
} }
c.lastC2CMsgTime = int64(pMsg.Head.GetMsgTime()) c.lastC2CMsgTime = int64(pMsg.Head.GetMsgTime())
@ -95,7 +95,7 @@ func (c *QQClient) commMsgProcessor(pMsg *msg.Message, info *network.IncomingPac
if decoder, _ := peekC2CDecoder(pMsg.Head.GetMsgType()); decoder != nil { if decoder, _ := peekC2CDecoder(pMsg.Head.GetMsgType()); decoder != nil {
decoder(c, pMsg, info) decoder(c, pMsg, info)
} else { } else {
c.Debug("unknown msg type on c2c processor: %v - %v", pMsg.Head.GetMsgType(), pMsg.Head.GetC2CCmd()) c.debug("unknown msg type on c2c processor: %v - %v", pMsg.Head.GetMsgType(), pMsg.Head.GetC2CCmd())
} }
} }
@ -132,12 +132,12 @@ func privateMessageDecoder(c *QQClient, pMsg *msg.Message, _ *network.IncomingPa
} }
if pMsg.Head.GetFromUin() == c.Uin { if pMsg.Head.GetFromUin() == c.Uin {
c.dispatchPrivateMessageSelf(c.parsePrivateMessage(pMsg)) c.SelfPrivateMessageEvent.dispatch(c, c.parsePrivateMessage(pMsg))
return return
} }
c.dispatchPrivateMessage(c.parsePrivateMessage(pMsg)) c.PrivateMessageEvent.dispatch(c, c.parsePrivateMessage(pMsg))
default: default:
c.Debug("unknown c2c cmd on private msg decoder: %v", pMsg.Head.GetC2CCmd()) c.debug("unknown c2c cmd on private msg decoder: %v", pMsg.Head.GetC2CCmd())
} }
} }
@ -149,7 +149,7 @@ func privatePttDecoder(c *QQClient, pMsg *msg.Message, _ *network.IncomingPacket
// m := binary.NewReader(pMsg.Body.RichText.Ptt.Reserve[1:]).ReadTlvMap(1) // m := binary.NewReader(pMsg.Body.RichText.Ptt.Reserve[1:]).ReadTlvMap(1)
// T3 -> timestamp T8 -> voiceType T9 -> voiceLength T10 -> PbReserveStruct // T3 -> timestamp T8 -> voiceType T9 -> voiceLength T10 -> PbReserveStruct
} }
c.dispatchPrivateMessage(c.parsePrivateMessage(pMsg)) c.PrivateMessageEvent.dispatch(c, c.parsePrivateMessage(pMsg))
} }
func tempSessionDecoder(c *QQClient, pMsg *msg.Message, _ *network.IncomingPacketInfo) { func tempSessionDecoder(c *QQClient, pMsg *msg.Message, _ *network.IncomingPacketInfo) {
@ -206,7 +206,7 @@ func tempSessionDecoder(c *QQClient, pMsg *msg.Message, _ *network.IncomingPacke
if pMsg.Head.GetFromUin() == c.Uin { if pMsg.Head.GetFromUin() == c.Uin {
return return
} }
c.dispatchTempMessage(&TempMessageEvent{ c.TempMessageEvent.dispatch(c, &TempMessageEvent{
Message: c.parseTempMessage(pMsg), Message: c.parseTempMessage(pMsg),
Session: session, Session: session,
}) })
@ -219,20 +219,20 @@ func troopAddMemberBroadcastDecoder(c *QQClient, pMsg *msg.Message, _ *network.I
group := c.FindGroupByUin(pMsg.Head.GetFromUin()) group := c.FindGroupByUin(pMsg.Head.GetFromUin())
if pMsg.Head.GetAuthUin() == c.Uin { if pMsg.Head.GetAuthUin() == c.Uin {
if group == nil && c.ReloadGroupList() == nil { if group == nil && c.ReloadGroupList() == nil {
c.dispatchJoinGroupEvent(c.FindGroupByUin(pMsg.Head.GetFromUin())) c.GroupJoinEvent.dispatch(c, c.FindGroupByUin(pMsg.Head.GetFromUin()))
} }
} else { } else {
if group != nil && group.FindMember(pMsg.Head.GetAuthUin()) == nil { if group != nil && group.FindMember(pMsg.Head.GetAuthUin()) == nil {
mem, err := c.GetMemberInfo(group.Code, pMsg.Head.GetAuthUin()) mem, err := c.GetMemberInfo(group.Code, pMsg.Head.GetAuthUin())
if err != nil { if err != nil {
c.Debug("error to fetch new member info: %v", err) c.debug("error to fetch new member info: %v", err)
return return
} }
group.Update(func(info *GroupInfo) { group.Update(func(info *GroupInfo) {
info.Members = append(info.Members, mem) info.Members = append(info.Members, mem)
info.sort() info.sort()
}) })
c.dispatchNewMemberEvent(&MemberJoinGroupEvent{ c.GroupMemberJoinEvent.dispatch(c, &MemberJoinGroupEvent{
Group: group, Group: group,
Member: mem, Member: mem,
}) })
@ -255,7 +255,7 @@ func troopSystemMessageDecoder(c *QQClient, pMsg *msg.Message, info *network.Inc
reader := binary.NewReader(pMsg.Body.MsgContent) reader := binary.NewReader(pMsg.Body.MsgContent)
groupCode := uint32(reader.ReadInt32()) groupCode := uint32(reader.ReadInt32())
if info := c.FindGroup(int64(groupCode)); info != nil && pMsg.Head.GetGroupName() != "" && info.Name != pMsg.Head.GetGroupName() { if info := c.FindGroup(int64(groupCode)); info != nil && pMsg.Head.GetGroupName() != "" && info.Name != pMsg.Head.GetGroupName() {
c.Debug("group %v name updated. %v -> %v", groupCode, info.Name, pMsg.Head.GetGroupName()) c.debug("group %v name updated. %v -> %v", groupCode, info.Name, pMsg.Head.GetGroupName())
info.Name = pMsg.Head.GetGroupName() info.Name = pMsg.Head.GetGroupName()
} }
} }
@ -267,7 +267,7 @@ func msgType0x211Decoder(c *QQClient, pMsg *msg.Message, info *network.IncomingP
sub4 := msg.SubMsgType0X4Body{} sub4 := msg.SubMsgType0X4Body{}
if err := proto.Unmarshal(pMsg.Body.MsgContent, &sub4); err != nil { if err := proto.Unmarshal(pMsg.Body.MsgContent, &sub4); err != nil {
err = errors.Wrap(err, "unmarshal sub msg 0x4 error") err = errors.Wrap(err, "unmarshal sub msg 0x4 error")
c.Error("unmarshal sub msg 0x4 error: %v", err) c.error("unmarshal sub msg 0x4 error: %v", err)
return return
} }
if sub4.NotOnlineFile != nil && sub4.NotOnlineFile.GetSubcmd() == 1 { // subcmd: 1 -> sendPacket, 2-> recv if sub4.NotOnlineFile != nil && sub4.NotOnlineFile.GetSubcmd() == 1 { // subcmd: 1 -> sendPacket, 2-> recv
@ -275,7 +275,7 @@ func msgType0x211Decoder(c *QQClient, pMsg *msg.Message, info *network.IncomingP
if err != nil { if err != nil {
return return
} }
c.dispatchOfflineFileEvent(&OfflineFileEvent{ c.OfflineFileEvent.dispatch(c, &OfflineFileEvent{
FileName: string(sub4.NotOnlineFile.FileName), FileName: string(sub4.NotOnlineFile.FileName),
FileSize: sub4.NotOnlineFile.GetFileSize(), FileSize: sub4.NotOnlineFile.GetFileSize(),
Sender: pMsg.Head.GetFromUin(), Sender: pMsg.Head.GetFromUin(),

View File

@ -19,6 +19,7 @@ import (
"github.com/Mrs4s/MiraiGo/client/internal/network" "github.com/Mrs4s/MiraiGo/client/internal/network"
"github.com/Mrs4s/MiraiGo/client/internal/oicq" "github.com/Mrs4s/MiraiGo/client/internal/oicq"
"github.com/Mrs4s/MiraiGo/client/pb/msg" "github.com/Mrs4s/MiraiGo/client/pb/msg"
"github.com/Mrs4s/MiraiGo/message"
"github.com/Mrs4s/MiraiGo/utils" "github.com/Mrs4s/MiraiGo/utils"
) )
@ -48,12 +49,12 @@ type QQClient struct {
// protocol public field // protocol public field
SequenceId atomic.Int32 SequenceId atomic.Int32
SessionId []byte SessionId []byte
RandomKey []byte
TCP *network.TCPListener // todo: combine other protocol state into one struct TCP *network.TCPListener // todo: combine other protocol state into one struct
ConnectTime time.Time ConnectTime time.Time
transport *network.Transport transport *network.Transport
oicq *oicq.Codec oicq *oicq.Codec
logger Logger
// internal state // internal state
handlers HandlerMap handlers HandlerMap
@ -76,19 +77,47 @@ type QQClient struct {
// otherSrvAddrs []string // otherSrvAddrs []string
// fileStorageInfo *jce.FileStoragePushFSSvcList // fileStorageInfo *jce.FileStoragePushFSSvcList
// event handles
eventHandlers eventHandlers
PrivateMessageEvent EventHandle[*message.PrivateMessage]
TempMessageEvent EventHandle[*TempMessageEvent]
GroupMessageEvent EventHandle[*message.GroupMessage]
SelfPrivateMessageEvent EventHandle[*message.PrivateMessage]
SelfGroupMessageEvent EventHandle[*message.GroupMessage]
GroupMuteEvent EventHandle[*GroupMuteEvent]
GroupMessageRecalledEvent EventHandle[*GroupMessageRecalledEvent]
FriendMessageRecalledEvent EventHandle[*FriendMessageRecalledEvent]
GroupJoinEvent EventHandle[*GroupInfo]
GroupLeaveEvent EventHandle[*GroupLeaveEvent]
GroupMemberJoinEvent EventHandle[*MemberJoinGroupEvent]
GroupMemberLeaveEvent EventHandle[*MemberLeaveGroupEvent]
MemberCardUpdatedEvent EventHandle[*MemberCardUpdatedEvent]
GroupNameUpdatedEvent EventHandle[*GroupNameUpdatedEvent]
GroupMemberPermissionChangedEvent EventHandle[*MemberPermissionChangedEvent]
GroupInvitedEvent EventHandle[*GroupInvitedRequest]
UserWantJoinGroupEvent EventHandle[*UserJoinGroupRequest]
NewFriendEvent EventHandle[*NewFriendEvent]
NewFriendRequestEvent EventHandle[*NewFriendRequest]
DisconnectedEvent EventHandle[*ClientDisconnectedEvent]
GroupNotifyEvent EventHandle[INotifyEvent]
FriendNotifyEvent EventHandle[INotifyEvent]
MemberSpecialTitleUpdatedEvent EventHandle[*MemberSpecialTitleUpdatedEvent]
GroupDigestEvent EventHandle[*GroupDigestEvent]
OtherClientStatusChangedEvent EventHandle[*OtherClientStatusChangedEvent]
OfflineFileEvent EventHandle[*OfflineFileEvent]
// message state // message state
msgSvcCache *utils.Cache msgSvcCache *utils.Cache[unit]
lastC2CMsgTime int64 lastC2CMsgTime int64
transCache *utils.Cache transCache *utils.Cache[unit]
groupSysMsgCache *GroupSystemMessages groupSysMsgCache *GroupSystemMessages
msgBuilders sync.Map msgBuilders sync.Map
onlinePushCache *utils.Cache onlinePushCache *utils.Cache[unit]
heartbeatEnabled bool heartbeatEnabled bool
requestPacketRequestID atomic.Int32 requestPacketRequestID atomic.Int32
groupSeq atomic.Int32 groupSeq atomic.Int32
friendSeq atomic.Int32 friendSeq atomic.Int32
highwayApplyUpSeq atomic.Int32 highwayApplyUpSeq atomic.Int32
eventHandlers eventHandlers
groupListLock sync.Mutex groupListLock sync.Mutex
} }
@ -103,7 +132,7 @@ type QiDianAccountInfo struct {
} }
type handlerInfo struct { type handlerInfo struct {
fun func(i interface{}, err error) fun func(i any, err error)
dynamic bool dynamic bool
params network.RequestParams params network.RequestParams
} }
@ -115,7 +144,7 @@ func (h *handlerInfo) getParams() network.RequestParams {
return h.params return h.params
} }
var decoders = map[string]func(*QQClient, *network.IncomingPacketInfo, []byte) (interface{}, error){ var decoders = map[string]func(*QQClient, *network.IncomingPacketInfo, []byte) (any, error){
"wtlogin.login": decodeLoginResponse, "wtlogin.login": decodeLoginResponse,
"wtlogin.exchange_emp": decodeExchangeEmpResponse, "wtlogin.exchange_emp": decodeExchangeEmpResponse,
"wtlogin.trans_emp": decodeTransEmpResponse, "wtlogin.trans_emp": decodeTransEmpResponse,
@ -164,9 +193,9 @@ func NewClientMd5(uin int64, passwordMd5 [16]byte) *QQClient {
sig: &auth.SigInfo{ sig: &auth.SigInfo{
OutPacketSessionID: []byte{0x02, 0xB0, 0x5B, 0x8B}, OutPacketSessionID: []byte{0x02, 0xB0, 0x5B, 0x8B},
}, },
msgSvcCache: utils.NewCache(time.Second * 15), msgSvcCache: utils.NewCache[unit](time.Second * 15),
transCache: utils.NewCache(time.Second * 15), transCache: utils.NewCache[unit](time.Second * 15),
onlinePushCache: utils.NewCache(time.Second * 15), onlinePushCache: utils.NewCache[unit](time.Second * 15),
servers: []*net.TCPAddr{}, servers: []*net.TCPAddr{},
alive: true, alive: true,
highwaySession: new(highway.Session), highwaySession: new(highway.Session),
@ -239,7 +268,6 @@ func NewClientMd5(uin int64, passwordMd5 [16]byte) *QQClient {
} }
cli.TCP.PlannedDisconnect(cli.plannedDisconnect) cli.TCP.PlannedDisconnect(cli.plannedDisconnect)
cli.TCP.UnexpectedDisconnect(cli.unexpectedDisconnect) cli.TCP.UnexpectedDisconnect(cli.unexpectedDisconnect)
rand.Read(cli.RandomKey)
return cli return cli
} }
@ -391,7 +419,7 @@ func (c *QQClient) SubmitSMS(code string) (*LoginResponse, error) {
func (c *QQClient) RequestSMS() bool { func (c *QQClient) RequestSMS() bool {
rsp, err := c.sendAndWait(c.buildSMSRequestPacket()) rsp, err := c.sendAndWait(c.buildSMSRequestPacket())
if err != nil { if err != nil {
c.Error("request sms error: %v", err) c.error("request sms error: %v", err)
return false return false
} }
return rsp.(LoginResponse).Error == SMSNeededError return rsp.(LoginResponse).Error == SMSNeededError
@ -399,7 +427,7 @@ func (c *QQClient) RequestSMS() bool {
func (c *QQClient) init(tokenLogin bool) error { func (c *QQClient) init(tokenLogin bool) error {
if len(c.sig.G) == 0 { if len(c.sig.G) == 0 {
c.Warning("device lock is disable. http api may fail.") c.warning("device lock is disable. http api may fail.")
} }
c.highwaySession.Uin = strconv.FormatInt(c.Uin, 10) c.highwaySession.Uin = strconv.FormatInt(c.Uin, 10)
if err := c.registerClient(); err != nil { if err := c.registerClient(); err != nil {
@ -407,10 +435,10 @@ func (c *QQClient) init(tokenLogin bool) error {
} }
if tokenLogin { if tokenLogin {
notify := make(chan struct{}) notify := make(chan struct{})
d := c.waitPacket("StatSvc.ReqMSFOffline", func(i interface{}, err error) { d := c.waitPacket("StatSvc.ReqMSFOffline", func(i any, err error) {
notify <- struct{}{} notify <- struct{}{}
}) })
d2 := c.waitPacket("MessageSvc.PushForceOffline", func(i interface{}, err error) { d2 := c.waitPacket("MessageSvc.PushForceOffline", func(i any, err error) {
notify <- struct{}{} notify <- struct{}{}
}) })
select { select {
@ -645,7 +673,7 @@ func (c *QQClient) FindGroup(code int64) *GroupInfo {
return nil return nil
} }
func (c *QQClient) SolveGroupJoinRequest(i interface{}, accept, block bool, reason string) { func (c *QQClient) SolveGroupJoinRequest(i any, accept, block bool, reason string) {
if accept { if accept {
block = false block = false
reason = "" reason = ""
@ -674,7 +702,7 @@ func (c *QQClient) SolveFriendRequest(req *NewFriendRequest, accept bool) {
func (c *QQClient) getSKey() string { func (c *QQClient) getSKey() string {
if c.sig.SKeyExpiredTime < time.Now().Unix() && len(c.sig.G) > 0 { if c.sig.SKeyExpiredTime < time.Now().Unix() && len(c.sig.G) > 0 {
c.Debug("skey expired. refresh...") c.debug("skey expired. refresh...")
_, _ = c.sendAndWait(c.buildRequestTgtgtNopicsigPacket()) _, _ = c.sendAndWait(c.buildRequestTgtgtNopicsigPacket())
} }
return string(c.sig.SKey) return string(c.sig.SKey)

View File

@ -31,7 +31,7 @@ var (
) )
// wtlogin.login // wtlogin.login
func decodeLoginResponse(c *QQClient, _ *network.IncomingPacketInfo, payload []byte) (interface{}, error) { func decodeLoginResponse(c *QQClient, _ *network.IncomingPacketInfo, payload []byte) (any, error) {
reader := binary.NewReader(payload) reader := binary.NewReader(payload)
reader.ReadUInt16() // sub command reader.ReadUInt16() // sub command
t := reader.ReadByte() t := reader.ReadByte()
@ -47,9 +47,9 @@ func decodeLoginResponse(c *QQClient, _ *network.IncomingPacketInfo, payload []b
// if t150, ok := m[0x150]; ok { // if t150, ok := m[0x150]; ok {
// c.t150 = t150 // c.t150 = t150
// } // }
if t161, ok := m[0x161]; ok { // if t161, ok := m[0x161]; ok {
c.decodeT161(t161) // c.decodeT161(t161)
} // }
if m.Exists(0x403) { if m.Exists(0x403) {
c.sig.RandSeed = m[0x403] c.sig.RandSeed = m[0x403]
} }
@ -171,15 +171,15 @@ func decodeLoginResponse(c *QQClient, _ *network.IncomingPacketInfo, payload []b
ErrorMessage: t146r.ReadStringShort(), ErrorMessage: t146r.ReadStringShort(),
}, nil }, nil
} }
c.Debug("unknown login response: %v", t) c.debug("unknown login response: %v", t)
for k, v := range m { for k, v := range m {
c.Debug("Type: %v Value: %v", strconv.FormatInt(int64(k), 16), hex.EncodeToString(v)) c.debug("Type: %v Value: %v", strconv.FormatInt(int64(k), 16), hex.EncodeToString(v))
} }
return nil, errors.Errorf("unknown login response: %v", t) // ? return nil, errors.Errorf("unknown login response: %v", t) // ?
} }
// StatSvc.register // StatSvc.register
func decodeClientRegisterResponse(c *QQClient, _ *network.IncomingPacketInfo, payload []byte) (interface{}, error) { func decodeClientRegisterResponse(c *QQClient, _ *network.IncomingPacketInfo, payload []byte) (any, error) {
request := &jce.RequestPacket{} request := &jce.RequestPacket{}
request.ReadFrom(jce.NewJceReader(payload)) request.ReadFrom(jce.NewJceReader(payload))
data := &jce.RequestDataVersion2{} data := &jce.RequestDataVersion2{}
@ -188,7 +188,7 @@ func decodeClientRegisterResponse(c *QQClient, _ *network.IncomingPacketInfo, pa
svcRsp.ReadFrom(jce.NewJceReader(data.Map["SvcRespRegister"]["QQService.SvcRespRegister"][1:])) svcRsp.ReadFrom(jce.NewJceReader(data.Map["SvcRespRegister"]["QQService.SvcRespRegister"][1:]))
if svcRsp.Result != "" || svcRsp.ReplyCode != 0 { if svcRsp.Result != "" || svcRsp.ReplyCode != 0 {
if svcRsp.Result != "" { if svcRsp.Result != "" {
c.Error("reg error: %v", svcRsp.Result) c.error("reg error: %v", svcRsp.Result)
} }
return nil, errors.New("reg failed") return nil, errors.New("reg failed")
} }
@ -196,7 +196,7 @@ func decodeClientRegisterResponse(c *QQClient, _ *network.IncomingPacketInfo, pa
} }
// wtlogin.exchange_emp // wtlogin.exchange_emp
func decodeExchangeEmpResponse(c *QQClient, _ *network.IncomingPacketInfo, payload []byte) (interface{}, error) { func decodeExchangeEmpResponse(c *QQClient, _ *network.IncomingPacketInfo, payload []byte) (any, error) {
reader := binary.NewReader(payload) reader := binary.NewReader(payload)
cmd := reader.ReadUInt16() cmd := reader.ReadUInt16()
t := reader.ReadByte() t := reader.ReadByte()
@ -216,7 +216,7 @@ func decodeExchangeEmpResponse(c *QQClient, _ *network.IncomingPacketInfo, paylo
} }
// wtlogin.trans_emp // wtlogin.trans_emp
func decodeTransEmpResponse(c *QQClient, _ *network.IncomingPacketInfo, payload []byte) (interface{}, error) { func decodeTransEmpResponse(c *QQClient, _ *network.IncomingPacketInfo, payload []byte) (any, error) {
if len(payload) < 48 { if len(payload) < 48 {
return nil, errors.New("missing payload length") return nil, errors.New("missing payload length")
} }
@ -299,7 +299,7 @@ func decodeTransEmpResponse(c *QQClient, _ *network.IncomingPacketInfo, payload
} }
// ConfigPushSvc.PushReq // ConfigPushSvc.PushReq
func decodePushReqPacket(c *QQClient, _ *network.IncomingPacketInfo, payload []byte) (interface{}, error) { func decodePushReqPacket(c *QQClient, _ *network.IncomingPacketInfo, payload []byte) (any, error) {
request := &jce.RequestPacket{} request := &jce.RequestPacket{}
request.ReadFrom(jce.NewJceReader(payload)) request.ReadFrom(jce.NewJceReader(payload))
data := &jce.RequestDataVersion2{} data := &jce.RequestDataVersion2{}
@ -318,7 +318,7 @@ func decodePushReqPacket(c *QQClient, _ *network.IncomingPacketInfo, payload []b
if strings.Contains(s.Server, "com") { if strings.Contains(s.Server, "com") {
continue continue
} }
c.Debug("got new server addr: %v location: %v", s.Server, s.Location) c.debug("got new server addr: %v location: %v", s.Server, s.Location)
adds = append(adds, &net.TCPAddr{ adds = append(adds, &net.TCPAddr{
IP: net.ParseIP(s.Server), IP: net.ParseIP(s.Server),
Port: int(s.Port), Port: int(s.Port),
@ -341,7 +341,7 @@ func decodePushReqPacket(c *QQClient, _ *network.IncomingPacketInfo, payload []b
fmtPkt := jce.NewJceReader(jceBuf) fmtPkt := jce.NewJceReader(jceBuf)
list := &jce.FileStoragePushFSSvcList{} list := &jce.FileStoragePushFSSvcList{}
list.ReadFrom(fmtPkt) list.ReadFrom(fmtPkt)
c.Debug("got file storage svc push.") c.debug("got file storage svc push.")
// c.fileStorageInfo = list // c.fileStorageInfo = list
rsp := cmd0x6ff.C501RspBody{} rsp := cmd0x6ff.C501RspBody{}
if err := proto.Unmarshal(list.BigDataChannel.PbBuf, &rsp); err == nil && rsp.RspBody != nil { if err := proto.Unmarshal(list.BigDataChannel.PbBuf, &rsp); err == nil && rsp.RspBody != nil {
@ -372,7 +372,7 @@ func decodePushReqPacket(c *QQClient, _ *network.IncomingPacketInfo, payload []b
} }
// MessageSvc.PbGetMsg // MessageSvc.PbGetMsg
func decodeMessageSvcPacket(c *QQClient, info *network.IncomingPacketInfo, payload []byte) (interface{}, error) { func decodeMessageSvcPacket(c *QQClient, info *network.IncomingPacketInfo, payload []byte) (any, error) {
rsp := msg.GetMessageResponse{} rsp := msg.GetMessageResponse{}
err := proto.Unmarshal(payload, &rsp) err := proto.Unmarshal(payload, &rsp)
if err != nil { if err != nil {
@ -383,7 +383,7 @@ func decodeMessageSvcPacket(c *QQClient, info *network.IncomingPacketInfo, paylo
} }
// MessageSvc.PushNotify // MessageSvc.PushNotify
func decodeSvcNotify(c *QQClient, _ *network.IncomingPacketInfo, payload []byte) (interface{}, error) { func decodeSvcNotify(c *QQClient, _ *network.IncomingPacketInfo, payload []byte) (any, error) {
request := &jce.RequestPacket{} request := &jce.RequestPacket{}
request.ReadFrom(jce.NewJceReader(payload[4:])) request.ReadFrom(jce.NewJceReader(payload[4:]))
data := &jce.RequestDataVersion2{} data := &jce.RequestDataVersion2{}
@ -410,7 +410,7 @@ func decodeSvcNotify(c *QQClient, _ *network.IncomingPacketInfo, payload []byte)
} }
// SummaryCard.ReqSummaryCard // SummaryCard.ReqSummaryCard
func decodeSummaryCardResponse(_ *QQClient, _ *network.IncomingPacketInfo, payload []byte) (interface{}, error) { func decodeSummaryCardResponse(_ *QQClient, _ *network.IncomingPacketInfo, payload []byte) (any, error) {
request := &jce.RequestPacket{} request := &jce.RequestPacket{}
request.ReadFrom(jce.NewJceReader(payload)) request.ReadFrom(jce.NewJceReader(payload))
data := &jce.RequestDataVersion2{} data := &jce.RequestDataVersion2{}
@ -458,7 +458,7 @@ func decodeSummaryCardResponse(_ *QQClient, _ *network.IncomingPacketInfo, paylo
} }
// friendlist.getFriendGroupList // friendlist.getFriendGroupList
func decodeFriendGroupListResponse(_ *QQClient, _ *network.IncomingPacketInfo, payload []byte) (interface{}, error) { func decodeFriendGroupListResponse(_ *QQClient, _ *network.IncomingPacketInfo, payload []byte) (any, error) {
request := &jce.RequestPacket{} request := &jce.RequestPacket{}
request.ReadFrom(jce.NewJceReader(payload)) request.ReadFrom(jce.NewJceReader(payload))
data := &jce.RequestDataVersion3{} data := &jce.RequestDataVersion3{}
@ -483,7 +483,7 @@ func decodeFriendGroupListResponse(_ *QQClient, _ *network.IncomingPacketInfo, p
} }
// friendlist.delFriend // friendlist.delFriend
func decodeFriendDeleteResponse(_ *QQClient, _ *network.IncomingPacketInfo, payload []byte) (interface{}, error) { func decodeFriendDeleteResponse(_ *QQClient, _ *network.IncomingPacketInfo, payload []byte) (any, error) {
request := &jce.RequestPacket{} request := &jce.RequestPacket{}
request.ReadFrom(jce.NewJceReader(payload)) request.ReadFrom(jce.NewJceReader(payload))
data := &jce.RequestDataVersion3{} data := &jce.RequestDataVersion3{}
@ -496,7 +496,7 @@ func decodeFriendDeleteResponse(_ *QQClient, _ *network.IncomingPacketInfo, payl
} }
// friendlist.GetTroopListReqV2 // friendlist.GetTroopListReqV2
func decodeGroupListResponse(c *QQClient, _ *network.IncomingPacketInfo, payload []byte) (interface{}, error) { func decodeGroupListResponse(c *QQClient, _ *network.IncomingPacketInfo, payload []byte) (any, error) {
request := &jce.RequestPacket{} request := &jce.RequestPacket{}
request.ReadFrom(jce.NewJceReader(payload)) request.ReadFrom(jce.NewJceReader(payload))
data := &jce.RequestDataVersion3{} data := &jce.RequestDataVersion3{}
@ -528,7 +528,7 @@ func decodeGroupListResponse(c *QQClient, _ *network.IncomingPacketInfo, payload
} }
// friendlist.GetTroopMemberListReq // friendlist.GetTroopMemberListReq
func decodeGroupMemberListResponse(_ *QQClient, _ *network.IncomingPacketInfo, payload []byte) (interface{}, error) { func decodeGroupMemberListResponse(_ *QQClient, _ *network.IncomingPacketInfo, payload []byte) (any, error) {
request := &jce.RequestPacket{} request := &jce.RequestPacket{}
request.ReadFrom(jce.NewJceReader(payload)) request.ReadFrom(jce.NewJceReader(payload))
data := &jce.RequestDataVersion3{} data := &jce.RequestDataVersion3{}
@ -564,7 +564,7 @@ func decodeGroupMemberListResponse(_ *QQClient, _ *network.IncomingPacketInfo, p
} }
// group_member_card.get_group_member_card_info // group_member_card.get_group_member_card_info
func decodeGroupMemberInfoResponse(c *QQClient, _ *network.IncomingPacketInfo, payload []byte) (interface{}, error) { func decodeGroupMemberInfoResponse(c *QQClient, _ *network.IncomingPacketInfo, payload []byte) (any, error) {
rsp := pb.GroupMemberRspBody{} rsp := pb.GroupMemberRspBody{}
if err := proto.Unmarshal(payload, &rsp); err != nil { if err := proto.Unmarshal(payload, &rsp); err != nil {
return nil, errors.Wrap(err, "failed to unmarshal protobuf message") return nil, errors.Wrap(err, "failed to unmarshal protobuf message")
@ -597,7 +597,7 @@ func decodeGroupMemberInfoResponse(c *QQClient, _ *network.IncomingPacketInfo, p
} }
// LongConn.OffPicUp // LongConn.OffPicUp
func decodeOffPicUpResponse(_ *QQClient, _ *network.IncomingPacketInfo, payload []byte) (interface{}, error) { func decodeOffPicUpResponse(_ *QQClient, _ *network.IncomingPacketInfo, payload []byte) (any, error) {
rsp := cmd0x352.RspBody{} rsp := cmd0x352.RspBody{}
if err := proto.Unmarshal(payload, &rsp); err != nil { if err := proto.Unmarshal(payload, &rsp); err != nil {
return nil, errors.Wrap(err, "failed to unmarshal protobuf message") return nil, errors.Wrap(err, "failed to unmarshal protobuf message")
@ -635,7 +635,7 @@ func decodeOffPicUpResponse(_ *QQClient, _ *network.IncomingPacketInfo, payload
} }
// OnlinePush.PbPushTransMsg // OnlinePush.PbPushTransMsg
func decodeOnlinePushTransPacket(c *QQClient, _ *network.IncomingPacketInfo, payload []byte) (interface{}, error) { func decodeOnlinePushTransPacket(c *QQClient, _ *network.IncomingPacketInfo, payload []byte) (any, error) {
info := msg.TransMsgInfo{} info := msg.TransMsgInfo{}
err := proto.Unmarshal(payload, &info) err := proto.Unmarshal(payload, &info)
if err != nil { if err != nil {
@ -646,7 +646,7 @@ func decodeOnlinePushTransPacket(c *QQClient, _ *network.IncomingPacketInfo, pay
if _, ok := c.transCache.Get(idStr); ok { if _, ok := c.transCache.Get(idStr); ok {
return nil, nil return nil, nil
} }
c.transCache.Add(idStr, "", time.Second*15) c.transCache.Add(idStr, unit{}, time.Second*15)
if info.GetMsgType() == 34 { if info.GetMsgType() == 34 {
data.ReadInt32() data.ReadInt32()
data.ReadByte() data.ReadByte()
@ -659,10 +659,10 @@ func decodeOnlinePushTransPacket(c *QQClient, _ *network.IncomingPacketInfo, pay
switch typ { switch typ {
case 0x02: case 0x02:
if target == c.Uin { if target == c.Uin {
c.dispatchLeaveGroupEvent(&GroupLeaveEvent{Group: g}) c.GroupLeaveEvent.dispatch(c, &GroupLeaveEvent{Group: g})
} else if m := g.FindMember(target); m != nil { } else if m := g.FindMember(target); m != nil {
g.removeMember(target) g.removeMember(target)
c.dispatchMemberLeaveEvent(&MemberLeaveGroupEvent{ c.GroupMemberLeaveEvent.dispatch(c, &MemberLeaveGroupEvent{
Group: g, Group: g,
Member: m, Member: m,
}) })
@ -672,13 +672,13 @@ func decodeOnlinePushTransPacket(c *QQClient, _ *network.IncomingPacketInfo, pay
return nil, err return nil, err
} }
if target == c.Uin { if target == c.Uin {
c.dispatchLeaveGroupEvent(&GroupLeaveEvent{ c.GroupLeaveEvent.dispatch(c, &GroupLeaveEvent{
Group: g, Group: g,
Operator: g.FindMember(operator), Operator: g.FindMember(operator),
}) })
} else if m := g.FindMember(target); m != nil { } else if m := g.FindMember(target); m != nil {
g.removeMember(target) g.removeMember(target)
c.dispatchMemberLeaveEvent(&MemberLeaveGroupEvent{ c.GroupMemberLeaveEvent.dispatch(c, &MemberLeaveGroupEvent{
Group: g, Group: g,
Member: m, Member: m,
Operator: g.FindMember(operator), Operator: g.FindMember(operator),
@ -687,7 +687,7 @@ func decodeOnlinePushTransPacket(c *QQClient, _ *network.IncomingPacketInfo, pay
case 0x82: case 0x82:
if m := g.FindMember(target); m != nil { if m := g.FindMember(target); m != nil {
g.removeMember(target) g.removeMember(target)
c.dispatchMemberLeaveEvent(&MemberLeaveGroupEvent{ c.GroupMemberLeaveEvent.dispatch(c, &MemberLeaveGroupEvent{
Group: g, Group: g,
Member: m, Member: m,
}) })
@ -695,7 +695,7 @@ func decodeOnlinePushTransPacket(c *QQClient, _ *network.IncomingPacketInfo, pay
case 0x83: case 0x83:
if m := g.FindMember(target); m != nil { if m := g.FindMember(target); m != nil {
g.removeMember(target) g.removeMember(target)
c.dispatchMemberLeaveEvent(&MemberLeaveGroupEvent{ c.GroupMemberLeaveEvent.dispatch(c, &MemberLeaveGroupEvent{
Group: g, Group: g,
Member: m, Member: m,
Operator: g.FindMember(operator), Operator: g.FindMember(operator),
@ -724,7 +724,7 @@ func decodeOnlinePushTransPacket(c *QQClient, _ *network.IncomingPacketInfo, pay
if mem.Permission != newPermission { if mem.Permission != newPermission {
old := mem.Permission old := mem.Permission
mem.Permission = newPermission mem.Permission = newPermission
c.dispatchPermissionChanged(&MemberPermissionChangedEvent{ c.GroupMemberPermissionChangedEvent.dispatch(c, &MemberPermissionChangedEvent{
Group: g, Group: g,
Member: mem, Member: mem,
OldPermission: old, OldPermission: old,
@ -738,7 +738,7 @@ func decodeOnlinePushTransPacket(c *QQClient, _ *network.IncomingPacketInfo, pay
} }
// ProfileService.Pb.ReqSystemMsgNew.Friend // ProfileService.Pb.ReqSystemMsgNew.Friend
func decodeSystemMsgFriendPacket(c *QQClient, _ *network.IncomingPacketInfo, payload []byte) (interface{}, error) { func decodeSystemMsgFriendPacket(c *QQClient, _ *network.IncomingPacketInfo, payload []byte) (any, error) {
rsp := structmsg.RspSystemMsgNew{} rsp := structmsg.RspSystemMsgNew{}
if err := proto.Unmarshal(payload, &rsp); err != nil { if err := proto.Unmarshal(payload, &rsp); err != nil {
return nil, errors.Wrap(err, "failed to unmarshal protobuf message") return nil, errors.Wrap(err, "failed to unmarshal protobuf message")
@ -748,7 +748,7 @@ func decodeSystemMsgFriendPacket(c *QQClient, _ *network.IncomingPacketInfo, pay
} }
st := rsp.Friendmsgs[0] st := rsp.Friendmsgs[0]
if st.Msg != nil { if st.Msg != nil {
c.dispatchNewFriendRequest(&NewFriendRequest{ c.NewFriendRequestEvent.dispatch(c, &NewFriendRequest{
RequestId: st.MsgSeq, RequestId: st.MsgSeq,
Message: st.Msg.MsgAdditional, Message: st.Msg.MsgAdditional,
RequesterUin: st.ReqUin, RequesterUin: st.ReqUin,
@ -760,7 +760,7 @@ func decodeSystemMsgFriendPacket(c *QQClient, _ *network.IncomingPacketInfo, pay
} }
// MessageSvc.PushForceOffline // MessageSvc.PushForceOffline
func decodeForceOfflinePacket(c *QQClient, _ *network.IncomingPacketInfo, payload []byte) (interface{}, error) { func decodeForceOfflinePacket(c *QQClient, _ *network.IncomingPacketInfo, payload []byte) (any, error) {
request := &jce.RequestPacket{} request := &jce.RequestPacket{}
request.ReadFrom(jce.NewJceReader(payload)) request.ReadFrom(jce.NewJceReader(payload))
data := &jce.RequestDataVersion2{} data := &jce.RequestDataVersion2{}
@ -768,28 +768,25 @@ func decodeForceOfflinePacket(c *QQClient, _ *network.IncomingPacketInfo, payloa
r := jce.NewJceReader(data.Map["req_PushForceOffline"]["PushNotifyPack.RequestPushForceOffline"][1:]) r := jce.NewJceReader(data.Map["req_PushForceOffline"]["PushNotifyPack.RequestPushForceOffline"][1:])
tips := r.ReadString(2) tips := r.ReadString(2)
c.Disconnect() c.Disconnect()
go c.dispatchDisconnectEvent(&ClientDisconnectedEvent{Message: tips}) go c.DisconnectedEvent.dispatch(c, &ClientDisconnectedEvent{Message: tips})
return nil, nil return nil, nil
} }
// StatSvc.ReqMSFOffline // StatSvc.ReqMSFOffline
func decodeMSFOfflinePacket(c *QQClient, _ *network.IncomingPacketInfo, _ []byte) (interface{}, error) { func decodeMSFOfflinePacket(c *QQClient, _ *network.IncomingPacketInfo, _ []byte) (any, error) {
// c.lastLostMsg = "服务器端强制下线." // c.lastLostMsg = "服务器端强制下线."
c.Disconnect() c.Disconnect()
// 这个decoder不能消耗太多时间, event另起线程处理 // 这个decoder不能消耗太多时间, event另起线程处理
go c.dispatchDisconnectEvent(&ClientDisconnectedEvent{Message: "服务端强制下线."}) go c.DisconnectedEvent.dispatch(c, &ClientDisconnectedEvent{Message: "服务端强制下线."})
return nil, nil return nil, nil
} }
// OidbSvc.0xd79 // OidbSvc.0xd79
func decodeWordSegmentation(_ *QQClient, _ *network.IncomingPacketInfo, payload []byte) (interface{}, error) { func decodeWordSegmentation(_ *QQClient, _ *network.IncomingPacketInfo, payload []byte) (any, error) {
pkg := oidb.OIDBSSOPkg{}
rsp := &oidb.D79RspBody{} rsp := &oidb.D79RspBody{}
if err := proto.Unmarshal(payload, &pkg); err != nil { err := unpackOIDBPackage(payload, &rsp)
return nil, errors.Wrap(err, "failed to unmarshal protobuf message") if err != nil {
} return nil, err
if err := proto.Unmarshal(pkg.Bodybuffer, rsp); err != nil {
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
@ -797,7 +794,7 @@ func decodeWordSegmentation(_ *QQClient, _ *network.IncomingPacketInfo, payload
return nil, errors.New("no word received") return nil, errors.New("no word received")
} }
func decodeSidExpiredPacket(c *QQClient, i *network.IncomingPacketInfo, _ []byte) (interface{}, error) { func decodeSidExpiredPacket(c *QQClient, i *network.IncomingPacketInfo, _ []byte) (any, error) {
_, err := c.sendAndWait(c.buildRequestChangeSigPacket(3554528)) _, err := c.sendAndWait(c.buildRequestChangeSigPacket(3554528))
if err != nil { if err != nil {
return nil, errors.Wrap(err, "resign client error") return nil, errors.Wrap(err, "resign client error")
@ -827,6 +824,6 @@ func decodeAppInfoResponse(_ *QQClient, _ *incomingPacketInfo, payload []byte) (
} }
*/ */
func ignoreDecoder(_ *QQClient, _ *network.IncomingPacketInfo, _ []byte) (interface{}, error) { func ignoreDecoder(_ *QQClient, _ *network.IncomingPacketInfo, _ []byte) (any, error) {
return nil, nil return nil, nil
} }

View File

@ -175,12 +175,6 @@ type (
client *QQClient client *QQClient
} }
LogEvent struct {
Type string
Message string
Dump []byte
}
ServerUpdatedEvent struct { ServerUpdatedEvent struct {
Servers []jce.SsoServerInfo Servers []jce.SsoServerInfo
} }
@ -296,6 +290,9 @@ type (
SigSession []byte SigSession []byte
SessionKey []byte SessionKey []byte
} }
// unit is an alias for struct{}, like `()` in rust
unit = struct{}
) )
const ( const (

View File

@ -8,12 +8,40 @@ import (
"github.com/Mrs4s/MiraiGo/message" "github.com/Mrs4s/MiraiGo/message"
) )
// protected all EventHandle, since write is very rare, use
// only one lock to save memory
var eventMu sync.RWMutex
type EventHandle[T any] struct {
// QQClient?
handlers []func(client *QQClient, event T)
}
func (handle *EventHandle[T]) Subscribe(handler func(client *QQClient, event T)) {
eventMu.Lock()
defer eventMu.Unlock()
// shrink the slice
newHandlers := make([]func(client *QQClient, event T), len(handle.handlers)+1)
copy(newHandlers, handle.handlers)
newHandlers[len(handle.handlers)] = handler
handle.handlers = newHandlers
}
func (handle *EventHandle[T]) dispatch(client *QQClient, event T) {
eventMu.RLock()
defer func() {
eventMu.RUnlock()
if pan := recover(); pan != nil {
fmt.Printf("event error: %v\n%s", pan, debug.Stack())
}
}()
for _, handler := range handle.handlers {
handler(client, event)
}
}
type eventHandlers struct { type eventHandlers struct {
privateMessageHandlers []func(*QQClient, *message.PrivateMessage) // todo: move to event handle
tempMessageHandlers []func(*QQClient, *TempMessageEvent)
groupMessageHandlers []func(*QQClient, *message.GroupMessage)
selfPrivateMessageHandlers []func(*QQClient, *message.PrivateMessage)
selfGroupMessageHandlers []func(*QQClient, *message.GroupMessage)
guildChannelMessageHandlers []func(*QQClient, *message.GuildChannelMessage) guildChannelMessageHandlers []func(*QQClient, *message.GuildChannelMessage)
guildMessageReactionsUpdatedHandlers []func(*QQClient, *GuildMessageReactionsUpdatedEvent) guildMessageReactionsUpdatedHandlers []func(*QQClient, *GuildMessageReactionsUpdatedEvent)
guildMessageRecalledHandlers []func(*QQClient, *GuildMessageRecalledEvent) guildMessageRecalledHandlers []func(*QQClient, *GuildMessageRecalledEvent)
@ -21,60 +49,11 @@ type eventHandlers struct {
guildChannelCreatedHandlers []func(*QQClient, *GuildChannelOperationEvent) guildChannelCreatedHandlers []func(*QQClient, *GuildChannelOperationEvent)
guildChannelDestroyedHandlers []func(*QQClient, *GuildChannelOperationEvent) guildChannelDestroyedHandlers []func(*QQClient, *GuildChannelOperationEvent)
memberJoinedGuildHandlers []func(*QQClient, *MemberJoinGuildEvent) memberJoinedGuildHandlers []func(*QQClient, *MemberJoinGuildEvent)
groupMuteEventHandlers []func(*QQClient, *GroupMuteEvent)
groupRecalledHandlers []func(*QQClient, *GroupMessageRecalledEvent)
friendRecalledHandlers []func(*QQClient, *FriendMessageRecalledEvent)
joinGroupHandlers []func(*QQClient, *GroupInfo)
leaveGroupHandlers []func(*QQClient, *GroupLeaveEvent)
memberJoinedHandlers []func(*QQClient, *MemberJoinGroupEvent)
memberLeavedHandlers []func(*QQClient, *MemberLeaveGroupEvent)
memberCardUpdatedHandlers []func(*QQClient, *MemberCardUpdatedEvent)
groupNameUpdatedHandlers []func(*QQClient, *GroupNameUpdatedEvent)
permissionChangedHandlers []func(*QQClient, *MemberPermissionChangedEvent)
groupInvitedHandlers []func(*QQClient, *GroupInvitedRequest)
joinRequestHandlers []func(*QQClient, *UserJoinGroupRequest)
friendRequestHandlers []func(*QQClient, *NewFriendRequest)
newFriendHandlers []func(*QQClient, *NewFriendEvent)
disconnectHandlers []func(*QQClient, *ClientDisconnectedEvent)
logHandlers []func(*QQClient, *LogEvent)
serverUpdatedHandlers []func(*QQClient, *ServerUpdatedEvent) bool serverUpdatedHandlers []func(*QQClient, *ServerUpdatedEvent) bool
groupNotifyHandlers []func(*QQClient, INotifyEvent)
friendNotifyHandlers []func(*QQClient, INotifyEvent)
memberTitleUpdatedHandlers []func(*QQClient, *MemberSpecialTitleUpdatedEvent)
offlineFileHandlers []func(*QQClient, *OfflineFileEvent)
otherClientStatusChangedHandlers []func(*QQClient, *OtherClientStatusChangedEvent)
groupDigestHandlers []func(*QQClient, *GroupDigestEvent)
groupMessageReceiptHandlers sync.Map groupMessageReceiptHandlers sync.Map
} }
func (c *QQClient) OnPrivateMessage(f func(*QQClient, *message.PrivateMessage)) {
c.eventHandlers.privateMessageHandlers = append(c.eventHandlers.privateMessageHandlers, f)
}
func (c *QQClient) OnPrivateMessageF(filter func(*message.PrivateMessage) bool, f func(*QQClient, *message.PrivateMessage)) {
c.OnPrivateMessage(func(client *QQClient, msg *message.PrivateMessage) {
if filter(msg) {
f(client, msg)
}
})
}
func (c *QQClient) OnTempMessage(f func(*QQClient, *TempMessageEvent)) {
c.eventHandlers.tempMessageHandlers = append(c.eventHandlers.tempMessageHandlers, f)
}
func (c *QQClient) OnGroupMessage(f func(*QQClient, *message.GroupMessage)) {
c.eventHandlers.groupMessageHandlers = append(c.eventHandlers.groupMessageHandlers, f)
}
func (c *QQClient) OnSelfPrivateMessage(f func(*QQClient, *message.PrivateMessage)) {
c.eventHandlers.selfPrivateMessageHandlers = append(c.eventHandlers.selfPrivateMessageHandlers, f)
}
func (c *QQClient) OnSelfGroupMessage(f func(*QQClient, *message.GroupMessage)) {
c.eventHandlers.selfGroupMessageHandlers = append(c.eventHandlers.selfGroupMessageHandlers, f)
}
func (s *GuildService) OnGuildChannelMessage(f func(*QQClient, *message.GuildChannelMessage)) { func (s *GuildService) OnGuildChannelMessage(f func(*QQClient, *message.GuildChannelMessage)) {
s.c.eventHandlers.guildChannelMessageHandlers = append(s.c.eventHandlers.guildChannelMessageHandlers, f) s.c.eventHandlers.guildChannelMessageHandlers = append(s.c.eventHandlers.guildChannelMessageHandlers, f)
} }
@ -103,99 +82,10 @@ func (s *GuildService) OnMemberJoinedGuild(f func(*QQClient, *MemberJoinGuildEve
s.c.eventHandlers.memberJoinedGuildHandlers = append(s.c.eventHandlers.memberJoinedGuildHandlers, f) s.c.eventHandlers.memberJoinedGuildHandlers = append(s.c.eventHandlers.memberJoinedGuildHandlers, f)
} }
func (c *QQClient) OnGroupMuted(f func(*QQClient, *GroupMuteEvent)) {
c.eventHandlers.groupMuteEventHandlers = append(c.eventHandlers.groupMuteEventHandlers, f)
}
func (c *QQClient) OnJoinGroup(f func(*QQClient, *GroupInfo)) {
c.eventHandlers.joinGroupHandlers = append(c.eventHandlers.joinGroupHandlers, f)
}
func (c *QQClient) OnLeaveGroup(f func(*QQClient, *GroupLeaveEvent)) {
c.eventHandlers.leaveGroupHandlers = append(c.eventHandlers.leaveGroupHandlers, f)
}
func (c *QQClient) OnGroupMemberJoined(f func(*QQClient, *MemberJoinGroupEvent)) {
c.eventHandlers.memberJoinedHandlers = append(c.eventHandlers.memberJoinedHandlers, f)
}
func (c *QQClient) OnGroupMemberLeaved(f func(*QQClient, *MemberLeaveGroupEvent)) {
c.eventHandlers.memberLeavedHandlers = append(c.eventHandlers.memberLeavedHandlers, f)
}
func (c *QQClient) OnGroupMemberCardUpdated(f func(*QQClient, *MemberCardUpdatedEvent)) {
c.eventHandlers.memberCardUpdatedHandlers = append(c.eventHandlers.memberCardUpdatedHandlers, f)
}
func (c *QQClient) OnGroupNameUpdated(f func(*QQClient, *GroupNameUpdatedEvent)) {
c.eventHandlers.groupNameUpdatedHandlers = append(c.eventHandlers.groupNameUpdatedHandlers, f)
}
func (c *QQClient) OnGroupMemberPermissionChanged(f func(*QQClient, *MemberPermissionChangedEvent)) {
c.eventHandlers.permissionChangedHandlers = append(c.eventHandlers.permissionChangedHandlers, f)
}
func (c *QQClient) OnGroupMessageRecalled(f func(*QQClient, *GroupMessageRecalledEvent)) {
c.eventHandlers.groupRecalledHandlers = append(c.eventHandlers.groupRecalledHandlers, f)
}
func (c *QQClient) OnFriendMessageRecalled(f func(*QQClient, *FriendMessageRecalledEvent)) {
c.eventHandlers.friendRecalledHandlers = append(c.eventHandlers.friendRecalledHandlers, f)
}
func (c *QQClient) OnGroupInvited(f func(*QQClient, *GroupInvitedRequest)) {
c.eventHandlers.groupInvitedHandlers = append(c.eventHandlers.groupInvitedHandlers, f)
}
func (c *QQClient) OnUserWantJoinGroup(f func(*QQClient, *UserJoinGroupRequest)) {
c.eventHandlers.joinRequestHandlers = append(c.eventHandlers.joinRequestHandlers, f)
}
func (c *QQClient) OnNewFriendRequest(f func(*QQClient, *NewFriendRequest)) {
c.eventHandlers.friendRequestHandlers = append(c.eventHandlers.friendRequestHandlers, f)
}
func (c *QQClient) OnNewFriendAdded(f func(*QQClient, *NewFriendEvent)) {
c.eventHandlers.newFriendHandlers = append(c.eventHandlers.newFriendHandlers, f)
}
func (c *QQClient) OnDisconnected(f func(*QQClient, *ClientDisconnectedEvent)) {
c.eventHandlers.disconnectHandlers = append(c.eventHandlers.disconnectHandlers, f)
}
func (c *QQClient) OnServerUpdated(f func(*QQClient, *ServerUpdatedEvent) bool) { func (c *QQClient) OnServerUpdated(f func(*QQClient, *ServerUpdatedEvent) bool) {
c.eventHandlers.serverUpdatedHandlers = append(c.eventHandlers.serverUpdatedHandlers, f) c.eventHandlers.serverUpdatedHandlers = append(c.eventHandlers.serverUpdatedHandlers, f)
} }
func (c *QQClient) OnReceivedOfflineFile(f func(*QQClient, *OfflineFileEvent)) {
c.eventHandlers.offlineFileHandlers = append(c.eventHandlers.offlineFileHandlers, f)
}
func (c *QQClient) OnOtherClientStatusChanged(f func(*QQClient, *OtherClientStatusChangedEvent)) {
c.eventHandlers.otherClientStatusChangedHandlers = append(c.eventHandlers.otherClientStatusChangedHandlers, f)
}
func (c *QQClient) OnLog(f func(*QQClient, *LogEvent)) {
c.eventHandlers.logHandlers = append(c.eventHandlers.logHandlers, f)
}
func (c *QQClient) OnGroupNotify(f func(*QQClient, INotifyEvent)) {
c.eventHandlers.groupNotifyHandlers = append(c.eventHandlers.groupNotifyHandlers, f)
}
func (c *QQClient) OnFriendNotify(f func(*QQClient, INotifyEvent)) {
c.eventHandlers.friendNotifyHandlers = append(c.eventHandlers.friendNotifyHandlers, f)
}
func (c *QQClient) OnMemberSpecialTitleUpdated(f func(*QQClient, *MemberSpecialTitleUpdatedEvent)) {
c.eventHandlers.memberTitleUpdatedHandlers = append(c.eventHandlers.memberTitleUpdatedHandlers, f)
}
// OnGroupDigest 群精华消息事件注册
func (c *QQClient) OnGroupDigest(f func(*QQClient, *GroupDigestEvent)) {
c.eventHandlers.groupDigestHandlers = append(c.eventHandlers.groupDigestHandlers, f)
}
func NewUinFilterPrivate(uin int64) func(*message.PrivateMessage) bool { func NewUinFilterPrivate(uin int64) func(*message.PrivateMessage) bool {
return func(msg *message.PrivateMessage) bool { return func(msg *message.PrivateMessage) bool {
return msg.Sender.Uin == uin return msg.Sender.Uin == uin
@ -210,61 +100,6 @@ func (c *QQClient) onGroupMessageReceipt(id string, f ...func(*QQClient, *groupM
c.eventHandlers.groupMessageReceiptHandlers.LoadOrStore(id, f[0]) c.eventHandlers.groupMessageReceiptHandlers.LoadOrStore(id, f[0])
} }
func (c *QQClient) dispatchPrivateMessage(msg *message.PrivateMessage) {
if msg == nil {
return
}
for _, f := range c.eventHandlers.privateMessageHandlers {
cover(func() {
f(c, msg)
})
}
}
func (c *QQClient) dispatchTempMessage(e *TempMessageEvent) {
if e == nil {
return
}
for _, f := range c.eventHandlers.tempMessageHandlers {
cover(func() {
f(c, e)
})
}
}
func (c *QQClient) dispatchGroupMessage(msg *message.GroupMessage) {
if msg == nil {
return
}
for _, f := range c.eventHandlers.groupMessageHandlers {
cover(func() {
f(c, msg)
})
}
}
func (c *QQClient) dispatchPrivateMessageSelf(msg *message.PrivateMessage) {
if msg == nil {
return
}
for _, f := range c.eventHandlers.selfPrivateMessageHandlers {
cover(func() {
f(c, msg)
})
}
}
func (c *QQClient) dispatchGroupMessageSelf(msg *message.GroupMessage) {
if msg == nil {
return
}
for _, f := range c.eventHandlers.selfGroupMessageHandlers {
cover(func() {
f(c, msg)
})
}
}
func (c *QQClient) dispatchGuildChannelMessage(msg *message.GuildChannelMessage) { func (c *QQClient) dispatchGuildChannelMessage(msg *message.GuildChannelMessage) {
if msg == nil { if msg == nil {
return return
@ -342,255 +177,13 @@ func (c *QQClient) dispatchMemberJoinedGuildEvent(e *MemberJoinGuildEvent) {
} }
} }
func (c *QQClient) dispatchGroupMuteEvent(e *GroupMuteEvent) {
if e == nil {
return
}
for _, f := range c.eventHandlers.groupMuteEventHandlers {
cover(func() {
f(c, e)
})
}
}
func (c *QQClient) dispatchGroupMessageRecalledEvent(e *GroupMessageRecalledEvent) {
if e == nil {
return
}
for _, f := range c.eventHandlers.groupRecalledHandlers {
cover(func() {
f(c, e)
})
}
}
func (c *QQClient) dispatchFriendMessageRecalledEvent(e *FriendMessageRecalledEvent) {
if e == nil {
return
}
for _, f := range c.eventHandlers.friendRecalledHandlers {
cover(func() {
f(c, e)
})
}
}
func (c *QQClient) dispatchJoinGroupEvent(group *GroupInfo) {
if group == nil {
return
}
for _, f := range c.eventHandlers.joinGroupHandlers {
cover(func() {
f(c, group)
})
}
}
func (c *QQClient) dispatchLeaveGroupEvent(e *GroupLeaveEvent) {
if e == nil {
return
}
for _, f := range c.eventHandlers.leaveGroupHandlers {
cover(func() {
f(c, e)
})
}
}
func (c *QQClient) dispatchNewMemberEvent(e *MemberJoinGroupEvent) {
if e == nil {
return
}
for _, f := range c.eventHandlers.memberJoinedHandlers {
cover(func() {
f(c, e)
})
}
}
func (c *QQClient) dispatchMemberLeaveEvent(e *MemberLeaveGroupEvent) {
if e == nil {
return
}
for _, f := range c.eventHandlers.memberLeavedHandlers {
cover(func() {
f(c, e)
})
}
}
func (c *QQClient) dispatchMemberCardUpdatedEvent(e *MemberCardUpdatedEvent) {
if e == nil {
return
}
for _, f := range c.eventHandlers.memberCardUpdatedHandlers {
cover(func() {
f(c, e)
})
}
}
func (c *QQClient) dispatchGroupNameUpdatedEvent(e *GroupNameUpdatedEvent) {
if e == nil {
return
}
for _, f := range c.eventHandlers.groupNameUpdatedHandlers {
cover(func() {
f(c, e)
})
}
}
func (c *QQClient) dispatchPermissionChanged(e *MemberPermissionChangedEvent) {
if e == nil {
return
}
for _, f := range c.eventHandlers.permissionChangedHandlers {
cover(func() {
f(c, e)
})
}
}
func (c *QQClient) dispatchGroupMessageReceiptEvent(e *groupMessageReceiptEvent) { func (c *QQClient) dispatchGroupMessageReceiptEvent(e *groupMessageReceiptEvent) {
c.eventHandlers.groupMessageReceiptHandlers.Range(func(_, f interface{}) bool { c.eventHandlers.groupMessageReceiptHandlers.Range(func(_, f any) bool {
go f.(func(*QQClient, *groupMessageReceiptEvent))(c, e) go f.(func(*QQClient, *groupMessageReceiptEvent))(c, e)
return true return true
}) })
} }
func (c *QQClient) dispatchGroupInvitedEvent(e *GroupInvitedRequest) {
if e == nil {
return
}
for _, f := range c.eventHandlers.groupInvitedHandlers {
cover(func() {
f(c, e)
})
}
}
func (c *QQClient) dispatchJoinGroupRequest(r *UserJoinGroupRequest) {
if r == nil {
return
}
for _, f := range c.eventHandlers.joinRequestHandlers {
cover(func() {
f(c, r)
})
}
}
func (c *QQClient) dispatchNewFriendRequest(r *NewFriendRequest) {
if r == nil {
return
}
for _, f := range c.eventHandlers.friendRequestHandlers {
cover(func() {
f(c, r)
})
}
}
func (c *QQClient) dispatchNewFriendEvent(e *NewFriendEvent) {
if e == nil {
return
}
for _, f := range c.eventHandlers.newFriendHandlers {
cover(func() {
f(c, e)
})
}
}
func (c *QQClient) dispatchGroupNotifyEvent(e INotifyEvent) {
if e == nil {
return
}
for _, f := range c.eventHandlers.groupNotifyHandlers {
cover(func() {
f(c, e)
})
}
}
func (c *QQClient) dispatchFriendNotifyEvent(e INotifyEvent) {
if e == nil {
return
}
for _, f := range c.eventHandlers.friendNotifyHandlers {
cover(func() {
f(c, e)
})
}
}
func (c *QQClient) dispatchMemberSpecialTitleUpdateEvent(e *MemberSpecialTitleUpdatedEvent) {
if e == nil {
return
}
for _, f := range c.eventHandlers.memberTitleUpdatedHandlers {
cover(func() {
f(c, e)
})
}
}
func (c *QQClient) dispatchDisconnectEvent(e *ClientDisconnectedEvent) {
if e == nil {
return
}
for _, f := range c.eventHandlers.disconnectHandlers {
cover(func() {
f(c, e)
})
}
}
func (c *QQClient) dispatchOfflineFileEvent(e *OfflineFileEvent) {
if e == nil {
return
}
for _, f := range c.eventHandlers.offlineFileHandlers {
cover(func() {
f(c, e)
})
}
}
func (c *QQClient) dispatchOtherClientStatusChangedEvent(e *OtherClientStatusChangedEvent) {
if e == nil {
return
}
for _, f := range c.eventHandlers.otherClientStatusChangedHandlers {
cover(func() {
f(c, e)
})
}
}
func (c *QQClient) dispatchGroupDigestEvent(e *GroupDigestEvent) {
if e == nil {
return
}
for _, f := range c.eventHandlers.groupDigestHandlers {
cover(func() {
f(c, e)
})
}
}
func (c *QQClient) dispatchLogEvent(e *LogEvent) {
if e == nil {
return
}
for _, f := range c.eventHandlers.logHandlers {
cover(func() {
f(c, e)
})
}
}
func cover(f func()) { func cover(f func()) {
defer func() { defer func() {
if pan := recover(); pan != nil { if pan := recover(); pan != nil {

View File

@ -41,7 +41,7 @@ func (c *QQClient) buildFaceroamRequestPacket() (uint16, []byte) {
return c.uniPacket("Faceroam.OpReq", payload) return c.uniPacket("Faceroam.OpReq", payload)
} }
func decodeFaceroamResponse(c *QQClient, _ *network.IncomingPacketInfo, payload []byte) (interface{}, error) { func decodeFaceroamResponse(c *QQClient, _ *network.IncomingPacketInfo, payload []byte) (any, error) {
rsp := faceroam.FaceroamRspBody{} rsp := faceroam.FaceroamRspBody{}
if err := proto.Unmarshal(payload, &rsp); err != nil { if err := proto.Unmarshal(payload, &rsp); err != nil {
return nil, errors.Wrap(err, "failed to unmarshal protobuf message") return nil, errors.Wrap(err, "failed to unmarshal protobuf message")

View File

@ -356,59 +356,16 @@ func (c *QQClient) packOIDBPackageProto(cmd, serviceType int32, msg proto.Messag
return c.packOIDBPackage(cmd, serviceType, b) return c.packOIDBPackage(cmd, serviceType, b)
} }
func unpackOIDBPackage(buff []byte, payload proto.Message) error { func unpackOIDBPackage(payload []byte, rsp proto.Message) error {
pkg := new(oidb.OIDBSSOPkg) pkg := new(oidb.OIDBSSOPkg)
if err := proto.Unmarshal(buff, pkg); err != nil { if err := proto.Unmarshal(payload, pkg); err != nil {
return errors.Wrap(err, "failed to unmarshal protobuf message") return errors.Wrap(err, "failed to unmarshal protobuf message")
} }
if pkg.Result != 0 { if pkg.Result != 0 {
return errors.Errorf("oidb result unsuccessful: %v msg: %v", pkg.Result, pkg.ErrorMsg) return errors.Errorf("oidb result unsuccessful: %v msg: %v", pkg.Result, pkg.ErrorMsg)
} }
if err := proto.Unmarshal(pkg.Bodybuffer, payload); err != nil { if err := proto.Unmarshal(pkg.Bodybuffer, rsp); err != nil {
return errors.Wrap(err, "failed to unmarshal protobuf message") return errors.Wrap(err, "failed to unmarshal protobuf message")
} }
return nil return nil
} }
func (c *QQClient) Error(msg string, args ...interface{}) {
c.dispatchLogEvent(&LogEvent{
Type: "ERROR",
Message: fmt.Sprintf(msg, args...),
})
}
func (c *QQClient) Warning(msg string, args ...interface{}) {
c.dispatchLogEvent(&LogEvent{
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...),
})
}
func (c *QQClient) Debug(msg string, args ...interface{}) {
c.dispatchLogEvent(&LogEvent{
Type: "DEBUG",
Message: fmt.Sprintf(msg, args...),
})
}
func (c *QQClient) Trace(msg string, args ...interface{}) {
c.dispatchLogEvent(&LogEvent{
Type: "TRACE",
Message: fmt.Sprintf(msg, args...),
})
}
func (c *QQClient) Dump(msg string, data []byte, args ...interface{}) {
c.dispatchLogEvent(&LogEvent{
Type: "DUMP",
Message: fmt.Sprintf(msg, args...),
Dump: data,
})
}

View File

@ -71,7 +71,7 @@ func init() {
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\n%s", pan, debug.Stack()) c.error("get group fs error: %v\n%s", pan, debug.Stack())
err = errors.New("fs error") err = errors.New("fs error")
} }
}() }()
@ -276,7 +276,7 @@ func (fs *GroupFileSystem) DeleteFile(parentFolderID, fileId string, busId int32
} }
func (c *QQClient) buildGroupFileUploadReqPacket(parentFolderID, fileName string, groupCode, fileSize int64, md5, sha1 []byte) (uint16, []byte) { func (c *QQClient) buildGroupFileUploadReqPacket(parentFolderID, fileName string, groupCode, fileSize int64, md5, sha1 []byte) (uint16, []byte) {
b, _ := proto.Marshal(&oidb.D6D6ReqBody{UploadFileReq: &oidb.UploadFileReqBody{ body := &oidb.D6D6ReqBody{UploadFileReq: &oidb.UploadFileReqBody{
GroupCode: &groupCode, GroupCode: &groupCode,
AppId: proto.Int32(3), AppId: proto.Int32(3),
BusId: proto.Int32(102), BusId: proto.Int32(102),
@ -288,14 +288,8 @@ func (c *QQClient) buildGroupFileUploadReqPacket(parentFolderID, fileName string
Sha: sha1, Sha: sha1,
Md5: md5, Md5: md5,
SupportMultiUpload: proto.Bool(true), SupportMultiUpload: proto.Bool(true),
}}) }}
req := &oidb.OIDBSSOPkg{ payload := c.packOIDBPackageProto(1750, 0, body)
Command: 1750,
ServiceType: 0,
Bodybuffer: b,
ClientVersion: "android 8.4.8",
}
payload, _ := proto.Marshal(req)
return c.uniPacket("OidbSvc.0x6d6_0", payload) return c.uniPacket("OidbSvc.0x6d6_0", payload)
} }
@ -328,31 +322,19 @@ func (c *QQClient) buildGroupFileListRequestPacket(groupCode int64, folderID str
StartIndex: &startIndex, StartIndex: &startIndex,
Context: EmptyBytes, Context: EmptyBytes,
}} }}
b, _ := proto.Marshal(body) payload := c.packOIDBPackageProto(1752, 1, body)
req := &oidb.OIDBSSOPkg{
Command: 1752,
ServiceType: 1,
Bodybuffer: b,
ClientVersion: "android 8.4.8",
}
payload, _ := proto.Marshal(req)
return c.uniPacket("OidbSvc.0x6d8_1", payload) return c.uniPacket("OidbSvc.0x6d8_1", payload)
} }
func (c *QQClient) buildGroupFileCountRequestPacket(groupCode int64) (uint16, []byte) { func (c *QQClient) buildGroupFileCountRequestPacket(groupCode int64) (uint16, []byte) {
body := &oidb.D6D8ReqBody{GroupFileCountReq: &oidb.GetFileCountReqBody{ body := &oidb.D6D8ReqBody{
GroupFileCountReq: &oidb.GetFileCountReqBody{
GroupCode: proto.Uint64(uint64(groupCode)), GroupCode: proto.Uint64(uint64(groupCode)),
AppId: proto.Uint32(3), AppId: proto.Uint32(3),
BusId: proto.Uint32(0), BusId: proto.Uint32(0),
}} },
b, _ := proto.Marshal(body)
req := &oidb.OIDBSSOPkg{
Command: 1752,
ServiceType: 2,
Bodybuffer: b,
ClientVersion: "android 8.4.8",
} }
payload, _ := proto.Marshal(req) payload := c.packOIDBPackageProto(1752, 2, body)
return c.uniPacket("OidbSvc.0x6d8_1", payload) return c.uniPacket("OidbSvc.0x6d8_1", payload)
} }
@ -361,14 +343,7 @@ func (c *QQClient) buildGroupFileSpaceRequestPacket(groupCode int64) (uint16, []
GroupCode: proto.Uint64(uint64(groupCode)), GroupCode: proto.Uint64(uint64(groupCode)),
AppId: proto.Uint32(3), AppId: proto.Uint32(3),
}} }}
b, _ := proto.Marshal(body) payload := c.packOIDBPackageProto(1752, 3, body)
req := &oidb.OIDBSSOPkg{
Command: 1752,
ServiceType: 3,
Bodybuffer: b,
ClientVersion: "android 8.4.8",
}
payload, _ := proto.Marshal(req)
return c.uniPacket("OidbSvc.0x6d8_1", payload) return c.uniPacket("OidbSvc.0x6d8_1", payload)
} }
@ -411,13 +386,7 @@ func (c *QQClient) buildGroupFileDownloadReqPacket(groupCode int64, fileId strin
FileId: &fileId, FileId: &fileId,
}, },
} }
b, _ := proto.Marshal(body) payload := c.packOIDBPackageProto(1750, 2, body)
req := &oidb.OIDBSSOPkg{
Command: 1750,
ServiceType: 2,
Bodybuffer: b,
}
payload, _ := proto.Marshal(req)
return c.uniPacket("OidbSvc.0x6d6_2", payload) return c.uniPacket("OidbSvc.0x6d6_2", payload)
} }
@ -429,38 +398,25 @@ func (c *QQClient) buildGroupFileDeleteReqPacket(groupCode int64, parentFolderId
ParentFolderId: &parentFolderId, ParentFolderId: &parentFolderId,
FileId: &fileId, FileId: &fileId,
}} }}
b, _ := proto.Marshal(body) payload := c.packOIDBPackageProto(1750, 3, body)
req := &oidb.OIDBSSOPkg{
Command: 1750,
ServiceType: 3,
Bodybuffer: b,
ClientVersion: "android 8.4.8",
}
payload, _ := proto.Marshal(req)
return c.uniPacket("OidbSvc.0x6d6_3", payload) return c.uniPacket("OidbSvc.0x6d6_3", payload)
} }
func decodeOIDB6d81Response(_ *QQClient, _ *network.IncomingPacketInfo, payload []byte) (interface{}, error) { func decodeOIDB6d81Response(_ *QQClient, _ *network.IncomingPacketInfo, payload []byte) (any, error) {
pkg := oidb.OIDBSSOPkg{}
rsp := oidb.D6D8RspBody{} rsp := oidb.D6D8RspBody{}
if err := proto.Unmarshal(payload, &pkg); err != nil { err := unpackOIDBPackage(payload, &rsp)
return nil, errors.Wrap(err, "failed to unmarshal protobuf message") if err != nil {
} return nil, err
if err := proto.Unmarshal(pkg.Bodybuffer, &rsp); err != nil {
return nil, errors.Wrap(err, "failed to unmarshal protobuf message")
} }
return &rsp, nil return &rsp, nil
} }
// OidbSvc.0x6d6_2 // OidbSvc.0x6d6_2
func decodeOIDB6d62Response(_ *QQClient, _ *network.IncomingPacketInfo, payload []byte) (interface{}, error) { func decodeOIDB6d62Response(_ *QQClient, _ *network.IncomingPacketInfo, payload []byte) (any, error) {
pkg := oidb.OIDBSSOPkg{}
rsp := oidb.D6D6RspBody{} rsp := oidb.D6D6RspBody{}
if err := proto.Unmarshal(payload, &pkg); err != nil { err := unpackOIDBPackage(payload, &rsp)
return nil, errors.Wrap(err, "failed to unmarshal protobuf message") if err != nil {
} return nil, err
if err := proto.Unmarshal(pkg.Bodybuffer, &rsp); err != nil {
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.GetClientWording()) return nil, errors.New(rsp.DownloadFileRsp.GetClientWording())
@ -470,50 +426,38 @@ func decodeOIDB6d62Response(_ *QQClient, _ *network.IncomingPacketInfo, payload
return fmt.Sprintf("http://%s/ftn_handler/%s/", ip, url), nil return fmt.Sprintf("http://%s/ftn_handler/%s/", ip, url), nil
} }
func decodeOIDB6d63Response(_ *QQClient, _ *network.IncomingPacketInfo, payload []byte) (interface{}, error) { func decodeOIDB6d63Response(_ *QQClient, _ *network.IncomingPacketInfo, payload []byte) (any, error) {
pkg := oidb.OIDBSSOPkg{}
rsp := oidb.D6D6RspBody{} rsp := oidb.D6D6RspBody{}
if err := proto.Unmarshal(payload, &pkg); err != nil { err := unpackOIDBPackage(payload, &rsp)
return nil, errors.Wrap(err, "failed to unmarshal protobuf message") if err != nil {
} return nil, err
if err := proto.Unmarshal(pkg.Bodybuffer, &rsp); err != nil {
return nil, errors.Wrap(err, "failed to unmarshal protobuf message")
}
if rsp.DeleteFileRsp == nil {
return "", nil
} }
return rsp.DeleteFileRsp.GetClientWording(), nil return rsp.DeleteFileRsp.GetClientWording(), nil
} }
func decodeOIDB6d60Response(_ *QQClient, _ *network.IncomingPacketInfo, payload []byte) (interface{}, error) { func decodeOIDB6d60Response(_ *QQClient, _ *network.IncomingPacketInfo, payload []byte) (any, error) {
pkg := oidb.OIDBSSOPkg{}
rsp := oidb.D6D6RspBody{} rsp := oidb.D6D6RspBody{}
if err := proto.Unmarshal(payload, &pkg); err != nil { err := unpackOIDBPackage(payload, &rsp)
return nil, errors.Wrap(err, "failed to unmarshal protobuf message") if err != nil {
} return nil, err
if err := proto.Unmarshal(pkg.Bodybuffer, &rsp); err != nil {
return nil, errors.Wrap(err, "failed to unmarshal protobuf message")
} }
return rsp.UploadFileRsp, nil return rsp.UploadFileRsp, nil
} }
func decodeOIDB6d7Response(_ *QQClient, _ *network.IncomingPacketInfo, payload []byte) (interface{}, error) { func decodeOIDB6d7Response(_ *QQClient, _ *network.IncomingPacketInfo, payload []byte) (any, error) {
pkg := oidb.OIDBSSOPkg{}
rsp := oidb.D6D7RspBody{} rsp := oidb.D6D7RspBody{}
if err := proto.Unmarshal(payload, &pkg); err != nil { err := unpackOIDBPackage(payload, &rsp)
return nil, errors.Wrap(err, "failed to unmarshal protobuf message") if err != nil {
return nil, err
} }
if err := proto.Unmarshal(pkg.Bodybuffer, &rsp); err != nil { if retCode := rsp.CreateFolderRsp.GetRetCode(); retCode != 0 {
return nil, errors.Wrap(err, "failed to unmarshal protobuf message") return nil, errors.Errorf("create folder error: %v", retCode)
} }
if rsp.CreateFolderRsp != nil && rsp.CreateFolderRsp.GetRetCode() != 0 { if retCode := rsp.RenameFolderRsp.GetRetCode(); retCode != 0 {
return nil, errors.Errorf("create folder error: %v", rsp.CreateFolderRsp.GetRetCode()) return nil, errors.Errorf("rename folder error: %v", retCode)
} }
if rsp.RenameFolderRsp != nil && rsp.RenameFolderRsp.GetRetCode() != 0 { if retCode := rsp.DeleteFolderRsp.GetRetCode(); retCode != 0 {
return nil, errors.Errorf("rename folder error: %v", rsp.CreateFolderRsp.GetRetCode()) return nil, errors.Errorf("delete folder error: %v", retCode)
}
if rsp.DeleteFolderRsp != nil && rsp.DeleteFolderRsp.GetRetCode() != 0 {
return nil, errors.Errorf("delete folder error: %v", rsp.CreateFolderRsp.GetRetCode())
} }
return nil, nil return nil, nil
} }

View File

@ -116,12 +116,7 @@ func (c *QQClient) buildGroupInfoRequestPacket(groupCode int64) (uint16, []byte)
}, },
PcClientVersion: proto.Uint32(0), PcClientVersion: proto.Uint32(0),
} }
b, _ := proto.Marshal(body) payload := c.packOIDBPackageProto(2189, 0, body)
req := &oidb.OIDBSSOPkg{
Command: 2189,
Bodybuffer: b,
}
payload, _ := proto.Marshal(req)
return c.uniPacket("OidbSvc.0x88d_0", payload) return c.uniPacket("OidbSvc.0x88d_0", payload)
} }
@ -188,7 +183,7 @@ func (c *QQClient) buildGroupSearchPacket(keyword string) (uint16, []byte) {
} }
// SummaryCard.ReqSearch // SummaryCard.ReqSearch
func decodeGroupSearchResponse(_ *QQClient, _ *network.IncomingPacketInfo, payload []byte) (interface{}, error) { func decodeGroupSearchResponse(_ *QQClient, _ *network.IncomingPacketInfo, payload []byte) (any, error) {
request := &jce.RequestPacket{} request := &jce.RequestPacket{}
request.ReadFrom(jce.NewJceReader(payload)) request.ReadFrom(jce.NewJceReader(payload))
data := &jce.RequestDataVersion2{} data := &jce.RequestDataVersion2{}
@ -226,14 +221,11 @@ func decodeGroupSearchResponse(_ *QQClient, _ *network.IncomingPacketInfo, paylo
} }
// OidbSvc.0x88d_0 // OidbSvc.0x88d_0
func decodeGroupInfoResponse(c *QQClient, _ *network.IncomingPacketInfo, payload []byte) (interface{}, error) { func decodeGroupInfoResponse(c *QQClient, _ *network.IncomingPacketInfo, payload []byte) (any, error) {
pkg := oidb.OIDBSSOPkg{}
rsp := oidb.D88DRspBody{} rsp := oidb.D88DRspBody{}
if err := proto.Unmarshal(payload, &pkg); err != nil { err := unpackOIDBPackage(payload, &rsp)
return nil, errors.Wrap(err, "failed to unmarshal protobuf message") if err != nil {
} return nil, err
if err := proto.Unmarshal(pkg.Bodybuffer, &rsp); err != nil {
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))
@ -336,7 +328,7 @@ func (g *GroupInfo) AdministratorOrOwner() bool {
} }
func (g *GroupInfo) FindMember(uin int64) *GroupMemberInfo { func (g *GroupInfo) FindMember(uin int64) *GroupMemberInfo {
r := g.Read(func(info *GroupInfo) interface{} { r := g.Read(func(info *GroupInfo) any {
return info.FindMemberWithoutLock(uin) return info.FindMemberWithoutLock(uin)
}) })
if r == nil { if r == nil {
@ -368,7 +360,7 @@ func (g *GroupInfo) Update(f func(*GroupInfo)) {
f(g) f(g)
} }
func (g *GroupInfo) Read(f func(*GroupInfo) interface{}) interface{} { func (g *GroupInfo) Read(f func(*GroupInfo) any) any {
g.lock.RLock() g.lock.RLock()
defer g.lock.RUnlock() defer g.lock.RUnlock()
return f(g) return f(g)

View File

@ -61,7 +61,7 @@ func (c *QQClient) SendGroupMessage(groupCode int64, m *message.SendingMessage,
Message: m.Elements, Message: m.Elements,
})) }))
if err != nil { if err != nil {
c.Error("%v", err) c.error("%v", err)
return nil return nil
} }
ret := c.sendGroupMessage(groupCode, false, &message.SendingMessage{Elements: []message.IMessageElement{lmsg}}) ret := c.sendGroupMessage(groupCode, false, &message.SendingMessage{Elements: []message.IMessageElement{lmsg}})
@ -178,7 +178,7 @@ func (c *QQClient) uploadGroupLongMessage(groupCode int64, m *message.ForwardMes
} }
err := c.highwaySession.Upload(addr, input) err := c.highwaySession.Upload(addr, input)
if err != nil { if err != nil {
c.Error("highway upload long message error: %v", err) c.error("highway upload long message error: %v", err)
continue continue
} }
return genLongTemplate(rsp.MsgResid, m.Brief(), ts), nil return genLongTemplate(rsp.MsgResid, m.Brief(), ts), nil
@ -297,7 +297,7 @@ func (c *QQClient) buildAtAllRemainRequestPacket(groupCode int64) (uint16, []byt
} }
// OnlinePush.PbPushGroupMsg // OnlinePush.PbPushGroupMsg
func decodeGroupMessagePacket(c *QQClient, _ *network.IncomingPacketInfo, payload []byte) (interface{}, error) { func decodeGroupMessagePacket(c *QQClient, _ *network.IncomingPacketInfo, payload []byte) (any, error) {
pkt := msg.PushMessagePacket{} pkt := msg.PushMessagePacket{}
err := proto.Unmarshal(payload, &pkt) err := proto.Unmarshal(payload, &pkt)
if err != nil { if err != nil {
@ -317,22 +317,22 @@ func decodeGroupMessagePacket(c *QQClient, _ *network.IncomingPacketInfo, payloa
if builder.len() >= pkt.Message.Content.GetPkgNum() { if builder.len() >= pkt.Message.Content.GetPkgNum() {
c.msgBuilders.Delete(seq) c.msgBuilders.Delete(seq)
if pkt.Message.Head.GetFromUin() == c.Uin { if pkt.Message.Head.GetFromUin() == c.Uin {
c.dispatchGroupMessageSelf(c.parseGroupMessage(builder.build())) c.SelfGroupMessageEvent.dispatch(c, c.parseGroupMessage(builder.build()))
} else { } else {
c.dispatchGroupMessage(c.parseGroupMessage(builder.build())) c.GroupMessageEvent.dispatch(c, c.parseGroupMessage(builder.build()))
} }
} }
return nil, nil return nil, nil
} }
if pkt.Message.Head.GetFromUin() == c.Uin { if pkt.Message.Head.GetFromUin() == c.Uin {
c.dispatchGroupMessageSelf(c.parseGroupMessage(pkt.Message)) c.SelfGroupMessageEvent.dispatch(c, c.parseGroupMessage(pkt.Message))
} else { } else {
c.dispatchGroupMessage(c.parseGroupMessage(pkt.Message)) c.GroupMessageEvent.dispatch(c, c.parseGroupMessage(pkt.Message))
} }
return nil, nil return nil, nil
} }
func decodeMsgSendResponse(c *QQClient, _ *network.IncomingPacketInfo, payload []byte) (interface{}, error) { func decodeMsgSendResponse(c *QQClient, _ *network.IncomingPacketInfo, payload []byte) (any, error) {
rsp := msg.SendMessageResponse{} rsp := msg.SendMessageResponse{}
if err := proto.Unmarshal(payload, &rsp); err != nil { if err := proto.Unmarshal(payload, &rsp); err != nil {
return nil, errors.Wrap(err, "failed to unmarshal protobuf message") return nil, errors.Wrap(err, "failed to unmarshal protobuf message")
@ -340,20 +340,20 @@ func decodeMsgSendResponse(c *QQClient, _ *network.IncomingPacketInfo, payload [
switch rsp.GetResult() { switch rsp.GetResult() {
case 0: // OK. case 0: // OK.
case 55: case 55:
c.Error("sendPacket msg error: %v Bot has blocked target's content", rsp.GetResult()) c.error("sendPacket msg error: %v Bot has blocked target's content", rsp.GetResult())
default: default:
c.Error("sendPacket msg error: %v %v", rsp.GetResult(), rsp.GetErrMsg()) c.error("sendPacket msg error: %v %v", rsp.GetResult(), rsp.GetErrMsg())
} }
return nil, nil return nil, nil
} }
func decodeGetGroupMsgResponse(c *QQClient, info *network.IncomingPacketInfo, payload []byte) (interface{}, error) { func decodeGetGroupMsgResponse(c *QQClient, info *network.IncomingPacketInfo, payload []byte) (any, error) {
rsp := msg.GetGroupMsgResp{} rsp := msg.GetGroupMsgResp{}
if err := proto.Unmarshal(payload, &rsp); err != nil { if err := proto.Unmarshal(payload, &rsp); err != nil {
return nil, errors.Wrap(err, "failed to unmarshal protobuf message") return nil, errors.Wrap(err, "failed to unmarshal protobuf message")
} }
if rsp.GetResult() != 0 { if rsp.GetResult() != 0 {
c.Error("get msg error: %v %v", rsp.GetResult(), rsp.GetErrmsg()) c.error("get msg error: %v %v", rsp.GetResult(), rsp.GetErrmsg())
return nil, errors.Errorf("get msg error: %v msg: %v", rsp.GetResult(), rsp.GetErrmsg()) return nil, errors.Errorf("get msg error: %v msg: %v", rsp.GetResult(), rsp.GetErrmsg())
} }
var ret []*message.GroupMessage var ret []*message.GroupMessage
@ -363,7 +363,7 @@ func decodeGetGroupMsgResponse(c *QQClient, info *network.IncomingPacketInfo, pa
} }
if m.Content != nil && m.Content.GetPkgNum() > 1 && !info.Params.Bool("raw") { if m.Content != nil && m.Content.GetPkgNum() > 1 && !info.Params.Bool("raw") {
if m.Content.GetPkgIndex() == 0 { if m.Content.GetPkgIndex() == 0 {
c.Debug("build fragmented message from history") c.debug("build fragmented message from history")
i := m.Head.GetMsgSeq() - m.Content.GetPkgNum() i := m.Head.GetMsgSeq() - m.Content.GetPkgNum()
builder := &messageBuilder{} builder := &messageBuilder{}
for { for {
@ -396,14 +396,11 @@ func decodeGetGroupMsgResponse(c *QQClient, info *network.IncomingPacketInfo, pa
return ret, nil return ret, nil
} }
func decodeAtAllRemainResponse(_ *QQClient, _ *network.IncomingPacketInfo, payload []byte) (interface{}, error) { func decodeAtAllRemainResponse(_ *QQClient, _ *network.IncomingPacketInfo, payload []byte) (any, error) {
pkg := oidb.OIDBSSOPkg{}
rsp := oidb.D8A7RspBody{} rsp := oidb.D8A7RspBody{}
if err := proto.Unmarshal(payload, &pkg); err != nil { err := unpackOIDBPackage(payload, &rsp)
return nil, errors.Wrap(err, "failed to unmarshal protobuf message") if err != nil {
} return nil, err
if err := proto.Unmarshal(pkg.Bodybuffer, &rsp); err != nil {
return nil, errors.Wrap(err, "failed to unmarshal protobuf message")
} }
return &AtAllRemainInfo{ return &AtAllRemainInfo{
CanAtAll: rsp.GetCanAtAll(), CanAtAll: rsp.GetCanAtAll(),
@ -415,10 +412,10 @@ func decodeAtAllRemainResponse(_ *QQClient, _ *network.IncomingPacketInfo, paylo
func (c *QQClient) parseGroupMessage(m *msg.Message) *message.GroupMessage { func (c *QQClient) parseGroupMessage(m *msg.Message) *message.GroupMessage {
group := c.FindGroup(m.Head.GroupInfo.GetGroupCode()) group := c.FindGroup(m.Head.GroupInfo.GetGroupCode())
if group == nil { if group == nil {
c.Debug("sync group %v.", m.Head.GroupInfo.GetGroupCode()) c.debug("sync group %v.", m.Head.GroupInfo.GetGroupCode())
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.GetGroupCode(), err) c.error("error to sync group %v : %+v", m.Head.GroupInfo.GetGroupCode(), err)
return nil return nil
} }
group = info group = info
@ -427,7 +424,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
@ -463,7 +460,7 @@ func (c *QQClient) parseGroupMessage(m *msg.Message) *message.GroupMessage {
mem = info mem = info
group.Members = append(group.Members, mem) group.Members = append(group.Members, mem)
group.sort() group.sort()
go c.dispatchNewMemberEvent(&MemberJoinGroupEvent{ go c.GroupMemberJoinEvent.dispatch(c, &MemberJoinGroupEvent{
Group: group, Group: group,
Member: info, Member: info,
}) })
@ -531,7 +528,7 @@ func (c *QQClient) parseGroupMessage(m *msg.Message) *message.GroupMessage {
mem.CardName = groupCard mem.CardName = groupCard
} }
if old != mem.CardName { if old != mem.CardName {
go c.dispatchMemberCardUpdatedEvent(&MemberCardUpdatedEvent{ c.MemberCardUpdatedEvent.dispatch(c, &MemberCardUpdatedEvent{
Group: group, Group: group,
OldCard: old, OldCard: old,
Member: mem, Member: mem,
@ -592,14 +589,11 @@ func (c *QQClient) buildEssenceMsgOperatePacket(groupCode int64, msgSeq, msgRand
} }
// OidbSvc.0xeac_1/2 // OidbSvc.0xeac_1/2
func decodeEssenceMsgResponse(_ *QQClient, _ *network.IncomingPacketInfo, payload []byte) (interface{}, error) { func decodeEssenceMsgResponse(_ *QQClient, _ *network.IncomingPacketInfo, payload []byte) (any, error) {
pkg := oidb.OIDBSSOPkg{}
rsp := &oidb.EACRspBody{} rsp := &oidb.EACRspBody{}
if err := proto.Unmarshal(payload, &pkg); err != nil { err := unpackOIDBPackage(payload, &rsp)
return nil, errors.Wrap(err, "failed to unmarshal protobuf message") if err != nil {
} return nil, err
if err := proto.Unmarshal(pkg.Bodybuffer, rsp); err != nil {
return nil, errors.Wrap(err, "failed to unmarshal protobuf message")
} }
return rsp, nil return rsp, nil
} }

View File

@ -710,7 +710,7 @@ func convertChannelInfo(info *channel.GuildChannelInfo) *ChannelInfo {
func (c *QQClient) syncChannelFirstView() { func (c *QQClient) syncChannelFirstView() {
rsp, err := c.sendAndWaitDynamic(c.buildSyncChannelFirstViewPacket()) rsp, err := c.sendAndWaitDynamic(c.buildSyncChannelFirstViewPacket())
if err != nil { if err != nil {
c.Error("sync channel error: %v", err) c.error("sync channel error: %v", err)
return return
} }
firstViewRsp := new(channel.FirstViewRsp) firstViewRsp := new(channel.FirstViewRsp)
@ -723,7 +723,7 @@ func (c *QQClient) syncChannelFirstView() {
c.GuildService.Nickname = self.Nickname c.GuildService.Nickname = self.Nickname
c.GuildService.AvatarUrl = self.AvatarUrl c.GuildService.AvatarUrl = self.AvatarUrl
} else { } else {
c.Error("get self guild profile error: %v", err) c.error("get self guild profile error: %v", err)
} }
} }
@ -737,7 +737,7 @@ func (c *QQClient) buildSyncChannelFirstViewPacket() (uint16, []byte) {
return c.uniPacket("trpc.group_pro.synclogic.SyncLogic.SyncFirstView", payload) return c.uniPacket("trpc.group_pro.synclogic.SyncLogic.SyncFirstView", payload)
} }
func decodeGuildPushFirstView(c *QQClient, _ *network.IncomingPacketInfo, payload []byte) (interface{}, error) { func decodeGuildPushFirstView(c *QQClient, _ *network.IncomingPacketInfo, payload []byte) (any, error) {
firstViewMsg := new(channel.FirstViewMsg) firstViewMsg := new(channel.FirstViewMsg)
if err := proto.Unmarshal(payload, firstViewMsg); err != nil { if err := proto.Unmarshal(payload, firstViewMsg); err != nil {
return nil, errors.Wrap(err, "failed to unmarshal protobuf message") return nil, errors.Wrap(err, "failed to unmarshal protobuf message")
@ -754,7 +754,7 @@ func decodeGuildPushFirstView(c *QQClient, _ *network.IncomingPacketInfo, payloa
} }
channels, err := c.GuildService.FetchChannelList(info.GuildId) channels, err := c.GuildService.FetchChannelList(info.GuildId)
if err != nil { if err != nil {
c.Warning("waring: fetch guild %v channel error %v. will use sync node to fill channel list field", guild.GuildId, err) c.warning("waring: fetch guild %v channel error %v. will use sync node to fill channel list field", guild.GuildId, err)
for _, node := range guild.ChannelNodes { for _, node := range guild.ChannelNodes {
meta := new(channel.ChannelMsgMeta) meta := new(channel.ChannelMsgMeta)
_ = proto.Unmarshal(node.Meta, meta) _ = proto.Unmarshal(node.Meta, meta)

View File

@ -27,7 +27,7 @@ type tipsPushInfo struct {
ChannelId uint64 ChannelId uint64
} }
func decodeGuildEventFlowPacket(c *QQClient, _ *network.IncomingPacketInfo, payload []byte) (interface{}, error) { func decodeGuildEventFlowPacket(c *QQClient, _ *network.IncomingPacketInfo, payload []byte) (any, error) {
push := new(channel.MsgOnlinePush) push := new(channel.MsgOnlinePush)
if err := proto.Unmarshal(payload, push); err != nil { if err := proto.Unmarshal(payload, push); err != nil {
return nil, errors.Wrap(err, "failed to unmarshal protobuf message") return nil, errors.Wrap(err, "failed to unmarshal protobuf message")
@ -80,7 +80,7 @@ func decodeGuildEventFlowPacket(c *QQClient, _ *network.IncomingPacketInfo, payl
} }
eventBody := new(channel.EventBody) eventBody := new(channel.EventBody)
if err := proto.Unmarshal(common.PbElem, eventBody); err != nil { if err := proto.Unmarshal(common.PbElem, eventBody); err != nil {
c.Error("failed to unmarshal guild channel event body: %v", err) c.error("failed to unmarshal guild channel event body: %v", err)
continue continue
} }
c.processGuildEventBody(m, eventBody) c.processGuildEventBody(m, eventBody)
@ -106,7 +106,7 @@ func (c *QQClient) processGuildEventBody(m *channel.ChannelMsgContent, eventBody
var guild *GuildInfo var guild *GuildInfo
if m.Head.RoutingHead.GetGuildId() != 0 { if m.Head.RoutingHead.GetGuildId() != 0 {
if guild = c.GuildService.FindGuild(m.Head.RoutingHead.GetGuildId()); guild == nil { if guild = c.GuildService.FindGuild(m.Head.RoutingHead.GetGuildId()); guild == nil {
c.Warning("process channel event error: guild not found.") c.warning("process channel event error: guild not found.")
return return
} }
} }
@ -118,7 +118,7 @@ func (c *QQClient) processGuildEventBody(m *channel.ChannelMsgContent, eventBody
} }
channelInfo, err := c.GuildService.FetchChannelInfo(guild.GuildId, chanId.GetChanId()) channelInfo, err := c.GuildService.FetchChannelInfo(guild.GuildId, chanId.GetChanId())
if err != nil { if err != nil {
c.Warning("process create channel event error: fetch channel info error: %v", err) c.warning("process create channel event error: fetch channel info error: %v", err)
continue continue
} }
guild.Channels = append(guild.Channels, channelInfo) guild.Channels = append(guild.Channels, channelInfo)
@ -148,7 +148,7 @@ func (c *QQClient) processGuildEventBody(m *channel.ChannelMsgContent, eventBody
if oldInfo == nil { if oldInfo == nil {
info, err := c.GuildService.FetchChannelInfo(m.Head.RoutingHead.GetGuildId(), eventBody.ChangeChanInfo.GetChanId()) info, err := c.GuildService.FetchChannelInfo(m.Head.RoutingHead.GetGuildId(), eventBody.ChangeChanInfo.GetChanId())
if err != nil { if err != nil {
c.Error("error to decode channel info updated event: fetch channel info failed: %v", err) c.error("error to decode channel info updated event: fetch channel info failed: %v", err)
return return
} }
guild.Channels = append(guild.Channels, info) guild.Channels = append(guild.Channels, info)
@ -159,7 +159,7 @@ func (c *QQClient) processGuildEventBody(m *channel.ChannelMsgContent, eventBody
} }
newInfo, err := c.GuildService.FetchChannelInfo(m.Head.RoutingHead.GetGuildId(), eventBody.ChangeChanInfo.GetChanId()) newInfo, err := c.GuildService.FetchChannelInfo(m.Head.RoutingHead.GetGuildId(), eventBody.ChangeChanInfo.GetChanId())
if err != nil { if err != nil {
c.Error("error to decode channel info updated event: fetch channel info failed: %v", err) c.error("error to decode channel info updated event: fetch channel info failed: %v", err)
return return
} }
for i := range guild.Channels { for i := range guild.Channels {
@ -178,13 +178,13 @@ func (c *QQClient) processGuildEventBody(m *channel.ChannelMsgContent, eventBody
case eventBody.JoinGuild != nil: case eventBody.JoinGuild != nil:
/* 应该不会重复推送把, 不会吧不会吧 /* 应该不会重复推送把, 不会吧不会吧
if mem := guild.FindMember(eventBody.JoinGuild.GetMemberTinyid()); mem != nil { if mem := guild.FindMember(eventBody.JoinGuild.GetMemberTinyid()); mem != nil {
c.Info("ignore join guild event: member %v already exists", mem.TinyId) c.info("ignore join guild event: member %v already exists", mem.TinyId)
return return
} }
*/ */
profile, err := c.GuildService.FetchGuildMemberProfileInfo(guild.GuildId, eventBody.JoinGuild.GetMemberTinyid()) profile, err := c.GuildService.FetchGuildMemberProfileInfo(guild.GuildId, eventBody.JoinGuild.GetMemberTinyid())
if err != nil { if err != nil {
c.Error("error to decode member join guild event: get member profile error: %v", err) c.error("error to decode member join guild event: get member profile error: %v", err)
return return
} }
info := &GuildMemberInfo{ info := &GuildMemberInfo{
@ -210,7 +210,7 @@ func (c *QQClient) processGuildEventBody(m *channel.ChannelMsgContent, eventBody
if eventBody.UpdateMsg.GetEventType() == 4 { // 消息贴表情更新 (包含添加或删除) if eventBody.UpdateMsg.GetEventType() == 4 { // 消息贴表情更新 (包含添加或删除)
t, err := c.GuildService.pullChannelMessages(m.Head.RoutingHead.GetGuildId(), m.Head.RoutingHead.GetChannelId(), eventBody.UpdateMsg.GetMsgSeq(), eventBody.UpdateMsg.GetMsgSeq(), eventBody.UpdateMsg.GetEventVersion()-1, false) t, err := c.GuildService.pullChannelMessages(m.Head.RoutingHead.GetGuildId(), m.Head.RoutingHead.GetChannelId(), eventBody.UpdateMsg.GetMsgSeq(), eventBody.UpdateMsg.GetMsgSeq(), eventBody.UpdateMsg.GetEventVersion()-1, false)
if err != nil || len(t) == 0 { if err != nil || len(t) == 0 {
c.Error("process guild event flow error: pull eventMsg message error: %v", err) c.error("process guild event flow error: pull eventMsg message error: %v", err)
return return
} }
// 自己的消息被贴表情会单独推送一个tips, 这里不需要解析 // 自己的消息被贴表情会单独推送一个tips, 这里不需要解析
@ -223,7 +223,7 @@ func (c *QQClient) processGuildEventBody(m *channel.ChannelMsgContent, eventBody
MessageId: t[0].Head.ContentHead.GetSeq(), MessageId: t[0].Head.ContentHead.GetSeq(),
CurrentReactions: decodeGuildMessageEmojiReactions(t[0]), CurrentReactions: decodeGuildMessageEmojiReactions(t[0]),
} }
tipsInfo, err := c.waitPacketTimeoutSyncF("MsgPush.PushGroupProMsg", time.Second, func(i interface{}) bool { tipsInfo, err := c.waitPacketTimeoutSyncF("MsgPush.PushGroupProMsg", time.Second, func(i any) bool {
if i == nil { if i == nil {
return false return false
} }

View File

@ -230,7 +230,7 @@ func decodeGuildMessageEmojiReactions(content *channel.ChannelMsgContent) (r []*
return return
} }
func decodeGuildImageStoreResponse(_ *QQClient, _ *network.IncomingPacketInfo, payload []byte) (interface{}, error) { func decodeGuildImageStoreResponse(_ *QQClient, _ *network.IncomingPacketInfo, payload []byte) (any, error) {
body := new(cmd0x388.D388RspBody) body := new(cmd0x388.D388RspBody)
if err := proto.Unmarshal(payload, body); err != nil { if err := proto.Unmarshal(payload, body); err != nil {
return nil, errors.Wrap(err, "failed to unmarshal protobuf message") return nil, errors.Wrap(err, "failed to unmarshal protobuf message")

View File

@ -90,7 +90,7 @@ func (c *QQClient) uploadGroupOrGuildImage(target message.Source, img io.ReadSee
}.Encode() }.Encode()
} }
var r interface{} var r any
var err error var err error
var input highway.BdhInput var input highway.BdhInput
switch target.SourceType { switch target.SourceType {
@ -141,7 +141,7 @@ ok:
width := int32(i.Width) width := int32(i.Width)
height := int32(i.Height) height := int32(i.Height)
if err != nil && target.SourceType != message.SourceGroup { if err != nil && target.SourceType != message.SourceGroup {
c.Warning("waring: decode image error: %v. this image will be displayed by wrong size in pc guild client", err) c.warning("waring: decode image error: %v. this image will be displayed by wrong size in pc guild client", err)
width = 200 width = 200
height = 200 height = 200
} }
@ -203,7 +203,7 @@ func (c *QQClient) uploadPrivateImage(target int64, img io.ReadSeeker, count int
return e, nil return e, nil
} }
func (c *QQClient) ImageOcr(img interface{}) (*OcrResponse, error) { func (c *QQClient) ImageOcr(img any) (*OcrResponse, error) {
url := "" url := ""
switch e := img.(type) { switch e := img.(type) {
case *message.GroupImageElement: case *message.GroupImageElement:
@ -362,7 +362,7 @@ func (c *QQClient) buildImageOcrRequestPacket(url, md5 string, size, weight, hei
} }
// ImgStore.GroupPicUp // ImgStore.GroupPicUp
func decodeGroupImageStoreResponse(_ *QQClient, _ *network.IncomingPacketInfo, payload []byte) (interface{}, error) { func decodeGroupImageStoreResponse(_ *QQClient, _ *network.IncomingPacketInfo, payload []byte) (any, error) {
pkt := cmd0x388.D388RspBody{} pkt := cmd0x388.D388RspBody{}
err := proto.Unmarshal(payload, &pkt) err := proto.Unmarshal(payload, &pkt)
if err != nil { if err != nil {
@ -389,7 +389,7 @@ func decodeGroupImageStoreResponse(_ *QQClient, _ *network.IncomingPacketInfo, p
}, nil }, nil
} }
func decodeGroupImageDownloadResponse(_ *QQClient, _ *network.IncomingPacketInfo, payload []byte) (interface{}, error) { func decodeGroupImageDownloadResponse(_ *QQClient, _ *network.IncomingPacketInfo, payload []byte) (any, error) {
pkt := cmd0x388.D388RspBody{} pkt := cmd0x388.D388RspBody{}
if err := proto.Unmarshal(payload, &pkt); err != nil { if err := proto.Unmarshal(payload, &pkt); err != nil {
return nil, errors.Wrap(err, "unmarshal protobuf message error") return nil, errors.Wrap(err, "unmarshal protobuf message error")
@ -404,14 +404,11 @@ func decodeGroupImageDownloadResponse(_ *QQClient, _ *network.IncomingPacketInfo
} }
// OidbSvc.0xe07_0 // OidbSvc.0xe07_0
func decodeImageOcrResponse(_ *QQClient, _ *network.IncomingPacketInfo, payload []byte) (interface{}, error) { func decodeImageOcrResponse(_ *QQClient, _ *network.IncomingPacketInfo, payload []byte) (any, error) {
pkg := oidb.OIDBSSOPkg{}
rsp := oidb.DE07RspBody{} rsp := oidb.DE07RspBody{}
if err := proto.Unmarshal(payload, &pkg); err != nil { err := unpackOIDBPackage(payload, &rsp)
return nil, errors.Wrap(err, "failed to unmarshal protobuf message") if err != nil {
} return nil, err
if err := proto.Unmarshal(pkg.Bodybuffer, &rsp); err != nil {
return nil, errors.Wrap(err, "failed to unmarshal protobuf message")
} }
if rsp.Wording != "" { if rsp.Wording != "" {
if strings.Contains(rsp.Wording, "服务忙") { if strings.Contains(rsp.Wording, "服务忙") {

View File

@ -6,7 +6,7 @@ type IncomingPacketInfo struct {
Params RequestParams Params RequestParams
} }
type RequestParams map[string]interface{} type RequestParams map[string]any
func (p RequestParams) Bool(k string) bool { func (p RequestParams) Bool(k string) bool {
if p == nil { if p == nil {

43
client/log.go Normal file
View File

@ -0,0 +1,43 @@
package client
type Logger interface {
Info(format string, args ...any)
Warning(format string, args ...any)
Error(format string, args ...any)
Debug(format string, args ...any)
Dump(dumped []byte, format string, args ...any)
}
func (c *QQClient) SetLogger(logger Logger) {
c.logger = logger
}
func (c *QQClient) info(msg string, args ...any) {
if c.logger != nil {
c.logger.Info(msg, args...)
}
}
func (c *QQClient) warning(msg string, args ...any) {
if c.logger != nil {
c.logger.Warning(msg, args...)
}
}
func (c *QQClient) error(msg string, args ...any) {
if c.logger != nil {
c.logger.Error(msg, args...)
}
}
func (c *QQClient) debug(msg string, args ...any) {
if c.logger != nil {
c.logger.Debug(msg, args...)
}
}
func (c *QQClient) dump(msg string, data []byte, args ...any) {
if c.logger != nil {
c.logger.Dump(data, msg, args...)
}
}

View File

@ -47,7 +47,7 @@ func (c *QQClient) buildMultiApplyUpPacket(data, hash []byte, buType int32, grou
} }
// MultiMsg.ApplyUp // MultiMsg.ApplyUp
func decodeMultiApplyUpResponse(_ *QQClient, _ *network.IncomingPacketInfo, payload []byte) (interface{}, error) { func decodeMultiApplyUpResponse(_ *QQClient, _ *network.IncomingPacketInfo, payload []byte) (any, error) {
body := multimsg.MultiRspBody{} body := multimsg.MultiRspBody{}
if err := proto.Unmarshal(payload, &body); err != nil { if err := proto.Unmarshal(payload, &body); err != nil {
return nil, errors.Wrap(err, "failed to unmarshal protobuf message") return nil, errors.Wrap(err, "failed to unmarshal protobuf message")
@ -87,7 +87,7 @@ func (c *QQClient) buildMultiApplyDownPacket(resID string) (uint16, []byte) {
} }
// MultiMsg.ApplyDown // MultiMsg.ApplyDown
func decodeMultiApplyDownResponse(_ *QQClient, _ *network.IncomingPacketInfo, payload []byte) (interface{}, error) { func decodeMultiApplyDownResponse(_ *QQClient, _ *network.IncomingPacketInfo, payload []byte) (any, error) {
body := multimsg.MultiRspBody{} body := multimsg.MultiRspBody{}
if err := proto.Unmarshal(payload, &body); err != nil { if err := proto.Unmarshal(payload, &body); err != nil {
return nil, errors.Wrap(err, "failed to unmarshal protobuf message") return nil, errors.Wrap(err, "failed to unmarshal protobuf message")

View File

@ -45,22 +45,22 @@ func (c *QQClient) ConnectionQualityTest() *ConnectionQualityInfo {
var err error var err error
if r.ChatServerLatency, err = qualityTest(c.servers[c.currServerIndex].String()); err != nil { if r.ChatServerLatency, err = qualityTest(c.servers[c.currServerIndex].String()); err != nil {
c.Error("test chat server latency error: %v", err) c.error("test chat server latency error: %v", err)
r.ChatServerLatency = 9999 r.ChatServerLatency = 9999
} }
if addr, err := net.ResolveIPAddr("ip", "ssl.htdata.qq.com"); err == nil { if addr, err := net.ResolveIPAddr("ip", "ssl.htdata.qq.com"); err == nil {
if r.LongMessageServerLatency, err = qualityTest((&net.TCPAddr{IP: addr.IP, Port: 443}).String()); err != nil { if r.LongMessageServerLatency, err = qualityTest((&net.TCPAddr{IP: addr.IP, Port: 443}).String()); err != nil {
c.Error("test long message server latency error: %v", err) c.error("test long message server latency error: %v", err)
r.LongMessageServerLatency = 9999 r.LongMessageServerLatency = 9999
} }
} else { } else {
c.Error("resolve long message server error: %v", err) c.error("resolve long message server error: %v", err)
r.LongMessageServerLatency = 9999 r.LongMessageServerLatency = 9999
} }
if c.highwaySession.AddrLength() > 0 { if c.highwaySession.AddrLength() > 0 {
if r.SrvServerLatency, err = qualityTest(c.highwaySession.SsoAddr[0].String()); err != nil { if r.SrvServerLatency, err = qualityTest(c.highwaySession.SsoAddr[0].String()); err != nil {
c.Error("test srv server latency error: %v", err) c.error("test srv server latency error: %v", err)
r.SrvServerLatency = 9999 r.SrvServerLatency = 9999
} }
} }
@ -78,7 +78,7 @@ func (c *QQClient) ConnectionQualityTest() *ConnectionQualityInfo {
if _, err := utils.HttpGetBytes("https://ssl.htdata.qq.com", ""); err == nil { if _, err := utils.HttpGetBytes("https://ssl.htdata.qq.com", ""); err == nil {
r.LongMessageServerResponseLatency = time.Since(start).Milliseconds() r.LongMessageServerResponseLatency = time.Since(start).Milliseconds()
} else { } else {
c.Error("test long message server response latency error: %v", err) c.error("test long message server response latency error: %v", err)
r.LongMessageServerResponseLatency = 9999 r.LongMessageServerResponseLatency = 9999
} }
wg.Wait() wg.Wait()
@ -87,7 +87,7 @@ func (c *QQClient) ConnectionQualityTest() *ConnectionQualityInfo {
// connect 连接到 QQClient.servers 中的服务器 // connect 连接到 QQClient.servers 中的服务器
func (c *QQClient) connect() error { func (c *QQClient) connect() error {
c.Info("connect to server: %v", c.servers[c.currServerIndex].String()) c.info("connect to server: %v", c.servers[c.currServerIndex].String())
err := c.TCP.Connect(c.servers[c.currServerIndex]) err := c.TCP.Connect(c.servers[c.currServerIndex])
c.currServerIndex++ c.currServerIndex++
if c.currServerIndex == len(c.servers) { if c.currServerIndex == len(c.servers) {
@ -98,19 +98,19 @@ func (c *QQClient) connect() error {
if c.retryTimes > len(c.servers) { if c.retryTimes > len(c.servers) {
return errors.New("All servers are unreachable") return errors.New("All servers are unreachable")
} }
c.Error("connect server error: %v", err) c.error("connect server error: %v", err)
return err return err
} }
c.once.Do(func() { c.once.Do(func() {
c.OnGroupMessage(func(_ *QQClient, _ *message.GroupMessage) { c.GroupMessageEvent.Subscribe(func(_ *QQClient, _ *message.GroupMessage) {
c.stat.MessageReceived.Add(1) c.stat.MessageReceived.Add(1)
c.stat.LastMessageTime.Store(time.Now().Unix()) c.stat.LastMessageTime.Store(time.Now().Unix())
}) })
c.OnPrivateMessage(func(_ *QQClient, _ *message.PrivateMessage) { c.PrivateMessageEvent.Subscribe(func(_ *QQClient, _ *message.PrivateMessage) {
c.stat.MessageReceived.Add(1) c.stat.MessageReceived.Add(1)
c.stat.LastMessageTime.Store(time.Now().Unix()) c.stat.LastMessageTime.Store(time.Now().Unix())
}) })
c.OnTempMessage(func(_ *QQClient, _ *TempMessageEvent) { c.TempMessageEvent.Subscribe(func(_ *QQClient, _ *TempMessageEvent) {
c.stat.MessageReceived.Add(1) c.stat.MessageReceived.Add(1)
c.stat.LastMessageTime.Store(time.Now().Unix()) c.stat.LastMessageTime.Store(time.Now().Unix())
}) })
@ -129,14 +129,14 @@ func (c *QQClient) quickReconnect() {
c.Disconnect() c.Disconnect()
time.Sleep(time.Millisecond * 200) time.Sleep(time.Millisecond * 200)
if err := c.connect(); err != nil { if err := c.connect(); err != nil {
c.Error("connect server error: %v", err) c.error("connect server error: %v", err)
c.dispatchDisconnectEvent(&ClientDisconnectedEvent{Message: "quick reconnect failed"}) c.DisconnectedEvent.dispatch(c, &ClientDisconnectedEvent{Message: "quick reconnect failed"})
return return
} }
if err := c.registerClient(); err != nil { if err := c.registerClient(); err != nil {
c.Error("register client failed: %v", err) c.error("register client failed: %v", err)
c.Disconnect() c.Disconnect()
c.dispatchDisconnectEvent(&ClientDisconnectedEvent{Message: "register error"}) c.DisconnectedEvent.dispatch(c, &ClientDisconnectedEvent{Message: "register error"})
return return
} }
} }
@ -148,9 +148,9 @@ func (c *QQClient) Disconnect() {
} }
// sendAndWait 向服务器发送一个数据包, 并等待返回 // sendAndWait 向服务器发送一个数据包, 并等待返回
func (c *QQClient) sendAndWait(seq uint16, pkt []byte, params ...network.RequestParams) (interface{}, error) { func (c *QQClient) sendAndWait(seq uint16, pkt []byte, params ...network.RequestParams) (any, error) {
type T struct { type T struct {
Response interface{} Response any
Error error Error error
} }
ch := make(chan T, 1) ch := make(chan T, 1)
@ -160,7 +160,7 @@ func (c *QQClient) sendAndWait(seq uint16, pkt []byte, params ...network.Request
p = params[0] p = params[0]
} }
c.handlers.Store(seq, &handlerInfo{fun: func(i interface{}, err error) { c.handlers.Store(seq, &handlerInfo{fun: func(i any, err error) {
ch <- T{ ch <- T{
Response: i, Response: i,
Error: err, Error: err,
@ -204,7 +204,7 @@ func (c *QQClient) sendPacket(pkt []byte) error {
// waitPacket // waitPacket
// 等待一个或多个数据包解析, 优先级低于 sendAndWait // 等待一个或多个数据包解析, 优先级低于 sendAndWait
// 返回终止解析函数 // 返回终止解析函数
func (c *QQClient) waitPacket(cmd string, f func(interface{}, error)) func() { func (c *QQClient) waitPacket(cmd string, f func(any, error)) func() {
c.waiters.Store(cmd, f) c.waiters.Store(cmd, f)
return func() { return func() {
c.waiters.Delete(cmd) c.waiters.Delete(cmd)
@ -213,9 +213,9 @@ func (c *QQClient) waitPacket(cmd string, f func(interface{}, error)) func() {
// waitPacketTimeoutSyncF // waitPacketTimeoutSyncF
// 等待一个数据包解析, 优先级低于 sendAndWait // 等待一个数据包解析, 优先级低于 sendAndWait
func (c *QQClient) waitPacketTimeoutSyncF(cmd string, timeout time.Duration, filter func(interface{}) bool) (r interface{}, e error) { func (c *QQClient) waitPacketTimeoutSyncF(cmd string, timeout time.Duration, filter func(any) bool) (r any, e error) {
notifyChan := make(chan bool) notifyChan := make(chan bool)
defer c.waitPacket(cmd, func(i interface{}, err error) { defer c.waitPacket(cmd, func(i any, err error) {
if filter(i) { if filter(i) {
r = i r = i
e = err e = err
@ -234,7 +234,7 @@ func (c *QQClient) waitPacketTimeoutSyncF(cmd string, timeout time.Duration, fil
// 发送数据包并返回需要解析的 response // 发送数据包并返回需要解析的 response
func (c *QQClient) sendAndWaitDynamic(seq uint16, pkt []byte) ([]byte, error) { func (c *QQClient) sendAndWaitDynamic(seq uint16, pkt []byte) ([]byte, error) {
ch := make(chan []byte, 1) ch := make(chan []byte, 1)
c.handlers.Store(seq, &handlerInfo{fun: func(i interface{}, err error) { ch <- i.([]byte) }, dynamic: true}) c.handlers.Store(seq, &handlerInfo{fun: func(i any, err error) { ch <- i.([]byte) }, dynamic: true})
err := c.sendPacket(pkt) err := c.sendPacket(pkt)
if err != nil { if err != nil {
c.handlers.Delete(seq) c.handlers.Delete(seq)
@ -251,25 +251,25 @@ func (c *QQClient) sendAndWaitDynamic(seq uint16, pkt []byte) ([]byte, error) {
// plannedDisconnect 计划中断线事件 // plannedDisconnect 计划中断线事件
func (c *QQClient) plannedDisconnect(_ *network.TCPListener) { func (c *QQClient) plannedDisconnect(_ *network.TCPListener) {
c.Debug("planned disconnect.") c.debug("planned disconnect.")
c.stat.DisconnectTimes.Add(1) c.stat.DisconnectTimes.Add(1)
c.Online.Store(false) c.Online.Store(false)
} }
// unexpectedDisconnect 非预期断线事件 // unexpectedDisconnect 非预期断线事件
func (c *QQClient) unexpectedDisconnect(_ *network.TCPListener, e error) { func (c *QQClient) unexpectedDisconnect(_ *network.TCPListener, e error) {
c.Error("unexpected disconnect: %v", e) c.error("unexpected disconnect: %v", e)
c.stat.DisconnectTimes.Add(1) c.stat.DisconnectTimes.Add(1)
c.Online.Store(false) c.Online.Store(false)
if err := c.connect(); err != nil { if err := c.connect(); err != nil {
c.Error("connect server error: %v", err) c.error("connect server error: %v", err)
c.dispatchDisconnectEvent(&ClientDisconnectedEvent{Message: "connection dropped by server."}) c.DisconnectedEvent.dispatch(c, &ClientDisconnectedEvent{Message: "connection dropped by server."})
return return
} }
if err := c.registerClient(); err != nil { if err := c.registerClient(); err != nil {
c.Error("register client failed: %v", err) c.error("register client failed: %v", err)
c.Disconnect() c.Disconnect()
c.dispatchDisconnectEvent(&ClientDisconnectedEvent{Message: "register error"}) c.DisconnectedEvent.dispatch(c, &ClientDisconnectedEvent{Message: "register error"})
return return
} }
} }
@ -284,7 +284,7 @@ func (c *QQClient) netLoop() {
continue continue
} }
if l < 4 || l > 1024*1024*10 { // max 10MB if l < 4 || l > 1024*1024*10 { // max 10MB
c.Error("parse incoming packet error: invalid packet length %v", l) c.error("parse incoming packet error: invalid packet length %v", l)
errCount++ errCount++
if errCount > 2 { if errCount > 2 {
go c.quickReconnect() go c.quickReconnect()
@ -295,10 +295,10 @@ func (c *QQClient) netLoop() {
resp, err := c.transport.ReadResponse(data) resp, err := c.transport.ReadResponse(data)
// pkt, err := packets.ParseIncomingPacket(data, c.sig.D2Key) // pkt, err := packets.ParseIncomingPacket(data, c.sig.D2Key)
if err != nil { if err != nil {
c.Error("parse incoming packet error: %v", err) c.error("parse incoming packet error: %v", err)
if errors.Is(err, network.ErrSessionExpired) || errors.Is(err, network.ErrPacketDropped) { if errors.Is(err, network.ErrSessionExpired) || errors.Is(err, network.ErrPacketDropped) {
c.Disconnect() c.Disconnect()
go c.dispatchDisconnectEvent(&ClientDisconnectedEvent{Message: "session expired"}) go c.DisconnectedEvent.dispatch(c, &ClientDisconnectedEvent{Message: "session expired"})
continue continue
} }
errCount++ errCount++
@ -310,7 +310,7 @@ func (c *QQClient) netLoop() {
if resp.EncryptType == network.EncryptTypeEmptyKey { if resp.EncryptType == network.EncryptTypeEmptyKey {
m, err := c.oicq.Unmarshal(resp.Body) m, err := c.oicq.Unmarshal(resp.Body)
if err != nil { if err != nil {
c.Error("decrypt payload error: %v", err) c.error("decrypt payload error: %v", err)
if errors.Is(err, oicq.ErrUnknownFlag) { if errors.Is(err, oicq.ErrUnknownFlag) {
go c.quickReconnect() go c.quickReconnect()
} }
@ -319,7 +319,7 @@ func (c *QQClient) netLoop() {
resp.Body = m.Body resp.Body = m.Body
} }
errCount = 0 errCount = 0
c.Debug("rev pkt: %v seq: %v", resp.CommandName, resp.SequenceID) c.debug("rev pkt: %v seq: %v", resp.CommandName, resp.SequenceID)
c.stat.PacketReceived.Add(1) c.stat.PacketReceived.Add(1)
pkt := &packets.IncomingPacket{ pkt := &packets.IncomingPacket{
SequenceId: uint16(resp.SequenceID), SequenceId: uint16(resp.SequenceID),
@ -329,15 +329,15 @@ func (c *QQClient) netLoop() {
go func(pkt *packets.IncomingPacket) { go func(pkt *packets.IncomingPacket) {
defer func() { defer func() {
if pan := recover(); pan != nil { if pan := recover(); pan != nil {
c.Error("panic on decoder %v : %v\n%s", pkt.CommandName, pan, debug.Stack()) c.error("panic on decoder %v : %v\n%s", pkt.CommandName, pan, debug.Stack())
c.Dump("packet decode error: %v - %v", pkt.Payload, pkt.CommandName, pan) c.dump("packet decode error: %v - %v", pkt.Payload, pkt.CommandName, pan)
} }
}() }()
if decoder, ok := decoders[pkt.CommandName]; ok { if decoder, ok := decoders[pkt.CommandName]; ok {
// found predefined decoder // found predefined decoder
info, ok := c.handlers.LoadAndDelete(pkt.SequenceId) info, ok := c.handlers.LoadAndDelete(pkt.SequenceId)
var decoded interface{} var decoded any
decoded = pkt.Payload decoded = pkt.Payload
if info == nil || !info.dynamic { if info == nil || !info.dynamic {
decoded, err = decoder(c, &network.IncomingPacketInfo{ decoded, err = decoder(c, &network.IncomingPacketInfo{
@ -346,19 +346,19 @@ func (c *QQClient) netLoop() {
Params: info.getParams(), Params: info.getParams(),
}, pkt.Payload) }, pkt.Payload)
if err != nil { if err != nil {
c.Debug("decode pkt %v error: %+v", pkt.CommandName, err) c.debug("decode pkt %v error: %+v", pkt.CommandName, err)
} }
} }
if ok { if ok {
info.fun(decoded, err) info.fun(decoded, err)
} else if f, ok := c.waiters.Load(pkt.CommandName); ok { // 在不存在handler的情况下触发wait } else if f, ok := c.waiters.Load(pkt.CommandName); ok { // 在不存在handler的情况下触发wait
f.(func(interface{}, error))(decoded, err) f.(func(any, error))(decoded, err)
} }
} else if f, ok := c.handlers.LoadAndDelete(pkt.SequenceId); ok { } else if f, ok := c.handlers.LoadAndDelete(pkt.SequenceId); ok {
// does not need decoder // does not need decoder
f.fun(pkt.Payload, nil) f.fun(pkt.Payload, nil)
} else { } else {
c.Debug("Unhandled Command: %s\nSeq: %d\nThis message can be ignored.", pkt.CommandName, pkt.SequenceId) c.debug("Unhandled Command: %s\nSeq: %d\nThis message can be ignored.", pkt.CommandName, pkt.SequenceId)
} }
}(pkt) }(pkt)
} }

View File

@ -62,7 +62,7 @@ func (c *QQClient) grayTipProcessor(groupCode int64, tipInfo *notify.GeneralGray
} }
} }
if sender != 0 { if sender != 0 {
c.dispatchGroupNotifyEvent(&GroupPokeNotifyEvent{ c.GroupNotifyEvent.dispatch(c, &GroupPokeNotifyEvent{
GroupCode: groupCode, GroupCode: groupCode,
Sender: sender, Sender: sender,
Receiver: receiver, Receiver: receiver,
@ -81,7 +81,7 @@ func (c *QQClient) grayTipProcessor(groupCode int64, tipInfo *notify.GeneralGray
uin, _ = strconv.ParseInt(templ.Value, 10, 64) uin, _ = strconv.ParseInt(templ.Value, 10, 64)
} }
} }
c.dispatchGroupNotifyEvent(&MemberHonorChangedNotifyEvent{ c.GroupNotifyEvent.dispatch(c, &MemberHonorChangedNotifyEvent{
GroupCode: groupCode, GroupCode: groupCode,
Honor: func() HonorType { Honor: func() HonorType {
switch tipInfo.TemplId { switch tipInfo.TemplId {
@ -139,13 +139,13 @@ func (c *QQClient) msgGrayTipProcessor(groupCode int64, tipInfo *notify.AIOGrayT
} }
} }
if event.Uin == 0 { if event.Uin == 0 {
c.Error("process special title updated tips error: missing cmd") c.error("process special title updated tips error: missing cmd")
return return
} }
if mem := c.FindGroup(groupCode).FindMember(event.Uin); mem != nil { if mem := c.FindGroup(groupCode).FindMember(event.Uin); mem != nil {
mem.SpecialTitle = event.NewTitle mem.SpecialTitle = event.NewTitle
} }
c.dispatchMemberSpecialTitleUpdateEvent(event) c.MemberSpecialTitleUpdatedEvent.dispatch(c, event)
} }
} }

View File

@ -33,18 +33,18 @@ func (c *QQClient) buildOfflineFileDownloadRequestPacket(uuid []byte) (uint16, [
return seq, packet return seq, packet
} }
func decodeOfflineFileDownloadResponse(c *QQClient, _ *network.IncomingPacketInfo, payload []byte) (interface{}, error) { func decodeOfflineFileDownloadResponse(c *QQClient, _ *network.IncomingPacketInfo, payload []byte) (any, error) {
rsp := cmd0x346.C346RspBody{} rsp := cmd0x346.C346RspBody{}
if err := proto.Unmarshal(payload, &rsp); err != nil { if err := proto.Unmarshal(payload, &rsp); err != nil {
c.Error("unmarshal cmd0x346 rsp body error: %v", err) c.error("unmarshal cmd0x346 rsp body error: %v", err)
return nil, errors.Wrap(err, "unmarshal cmd0x346 rsp body error") 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.")
return nil, errors.New("apply rsp is nil") return nil, errors.New("apply rsp is nil")
} }
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.Errorf("apply download rsp error: %d", 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

@ -23,7 +23,7 @@ var msg0x210Decoders = map[int64]func(*QQClient, []byte) error{
} }
// OnlinePush.ReqPush // OnlinePush.ReqPush
func decodeOnlinePushReqPacket(c *QQClient, info *network.IncomingPacketInfo, payload []byte) (interface{}, error) { func decodeOnlinePushReqPacket(c *QQClient, info *network.IncomingPacketInfo, payload []byte) (any, error) {
request := &jce.RequestPacket{} request := &jce.RequestPacket{}
request.ReadFrom(jce.NewJceReader(payload)) request.ReadFrom(jce.NewJceReader(payload))
data := &jce.RequestDataVersion2{} data := &jce.RequestDataVersion2{}
@ -37,7 +37,7 @@ func decodeOnlinePushReqPacket(c *QQClient, info *network.IncomingPacketInfo, pa
if _, ok := c.onlinePushCache.Get(k); ok { if _, ok := c.onlinePushCache.Get(k); ok {
continue continue
} }
c.onlinePushCache.Add(k, "", time.Second*30) c.onlinePushCache.Add(k, unit{}, time.Second*30)
// 0x2dc // 0x2dc
if m.MsgType == 732 { if m.MsgType == 732 {
r := binary.NewReader(m.VMsg) r := binary.NewReader(m.VMsg)
@ -53,7 +53,7 @@ func decodeOnlinePushReqPacket(c *QQClient, info *network.IncomingPacketInfo, pa
r.ReadBytes(6) r.ReadBytes(6)
target := int64(uint32(r.ReadInt32())) target := int64(uint32(r.ReadInt32()))
t := r.ReadInt32() t := r.ReadInt32()
c.dispatchGroupMuteEvent(&GroupMuteEvent{ c.GroupMuteEvent.dispatch(c, &GroupMuteEvent{
GroupCode: groupCode, GroupCode: groupCode,
OperatorUin: operator, OperatorUin: operator,
TargetUin: target, TargetUin: target,
@ -68,7 +68,7 @@ func decodeOnlinePushReqPacket(c *QQClient, info *network.IncomingPacketInfo, pa
if rm.MsgType == 2 { if rm.MsgType == 2 {
continue continue
} }
c.dispatchGroupMessageRecalledEvent(&GroupMessageRecalledEvent{ c.GroupMessageRecalledEvent.dispatch(c, &GroupMessageRecalledEvent{
GroupCode: groupCode, GroupCode: groupCode,
OperatorUin: b.OptMsgRecall.Uin, OperatorUin: b.OptMsgRecall.Uin,
AuthorUin: rm.AuthorUin, AuthorUin: rm.AuthorUin,
@ -82,7 +82,7 @@ func decodeOnlinePushReqPacket(c *QQClient, info *network.IncomingPacketInfo, pa
} }
if b.OptMsgRedTips != nil { if b.OptMsgRedTips != nil {
if b.OptMsgRedTips.LuckyFlag == 1 { // 运气王提示 if b.OptMsgRedTips.LuckyFlag == 1 { // 运气王提示
c.dispatchGroupNotifyEvent(&GroupRedBagLuckyKingNotifyEvent{ c.GroupNotifyEvent.dispatch(c, &GroupRedBagLuckyKingNotifyEvent{
GroupCode: groupCode, GroupCode: groupCode,
Sender: int64(b.OptMsgRedTips.SenderUin), Sender: int64(b.OptMsgRedTips.SenderUin),
LuckyKing: int64(b.OptMsgRedTips.LuckyUin), LuckyKing: int64(b.OptMsgRedTips.LuckyUin),
@ -91,7 +91,7 @@ func decodeOnlinePushReqPacket(c *QQClient, info *network.IncomingPacketInfo, pa
} }
if b.QqGroupDigestMsg != nil { if b.QqGroupDigestMsg != nil {
digest := b.QqGroupDigestMsg digest := b.QqGroupDigestMsg
c.dispatchGroupDigestEvent(&GroupDigestEvent{ c.GroupDigestEvent.dispatch(c, &GroupDigestEvent{
GroupCode: int64(digest.GroupCode), GroupCode: int64(digest.GroupCode),
MessageID: int32(digest.Seq), MessageID: int32(digest.Seq),
InternalMessageID: int32(digest.Random), InternalMessageID: int32(digest.Random),
@ -118,7 +118,7 @@ func decodeOnlinePushReqPacket(c *QQClient, info *network.IncomingPacketInfo, pa
return nil, errors.Wrap(err, "decode online push 0x210 error") return nil, errors.Wrap(err, "decode online push 0x210 error")
} }
} else { } else {
c.Debug("unknown online push 0x210 sub type 0x%v", strconv.FormatInt(subType, 16)) c.debug("unknown online push 0x210 sub type 0x%v", strconv.FormatInt(subType, 16))
} }
} }
} }
@ -132,7 +132,7 @@ func msgType0x210Sub8ADecoder(c *QQClient, protobuf []byte) error {
} }
for _, m := range s8a.MsgInfo { for _, m := range s8a.MsgInfo {
if m.ToUin == c.Uin { if m.ToUin == c.Uin {
c.dispatchFriendMessageRecalledEvent(&FriendMessageRecalledEvent{ c.FriendMessageRecalledEvent.dispatch(c, &FriendMessageRecalledEvent{
FriendUin: m.FromUin, FriendUin: m.FromUin,
MessageId: m.MsgSeq, MessageId: m.MsgSeq,
Time: m.MsgTime, Time: m.MsgTime,
@ -152,7 +152,7 @@ func msgType0x210SubB3Decoder(c *QQClient, protobuf []byte) error {
Nickname: b3.MsgAddFrdNotify.Nick, Nickname: b3.MsgAddFrdNotify.Nick,
} }
c.FriendList = append(c.FriendList, frd) c.FriendList = append(c.FriendList, frd)
c.dispatchNewFriendEvent(&NewFriendEvent{Friend: frd}) c.NewFriendEvent.dispatch(c, &NewFriendEvent{Friend: frd})
return nil return nil
} }
@ -167,7 +167,7 @@ func msgType0x210SubD4Decoder(c *QQClient, protobuf []byte) error {
groupLeaveLock.Unlock() groupLeaveLock.Unlock()
return err return err
} }
c.dispatchLeaveGroupEvent(&GroupLeaveEvent{Group: g}) c.GroupLeaveEvent.dispatch(c, &GroupLeaveEvent{Group: g})
} }
groupLeaveLock.Unlock() groupLeaveLock.Unlock()
return nil return nil
@ -185,7 +185,7 @@ func msgType0x210Sub27Decoder(c *QQClient, protobuf []byte) error {
if g := c.FindGroup(int64(m.ModGroupProfile.GetGroupCode())); g != nil { if g := c.FindGroup(int64(m.ModGroupProfile.GetGroupCode())); g != nil {
old := g.Name old := g.Name
g.Name = string(info.Value) g.Name = string(info.Value)
c.dispatchGroupNameUpdatedEvent(&GroupNameUpdatedEvent{ c.GroupNameUpdatedEvent.dispatch(c, &GroupNameUpdatedEvent{
Group: g, Group: g,
OldName: old, OldName: old,
NewName: g.Name, NewName: g.Name,
@ -221,7 +221,7 @@ func msgType0x210Sub122Decoder(c *QQClient, protobuf []byte) error {
if sender == 0 { if sender == 0 {
return nil return nil
} }
c.dispatchFriendNotifyEvent(&FriendPokeNotifyEvent{ c.FriendNotifyEvent.dispatch(c, &FriendPokeNotifyEvent{
Sender: sender, Sender: sender,
Receiver: receiver, Receiver: receiver,
}) })
@ -241,7 +241,7 @@ func msgType0x210Sub44Decoder(c *QQClient, protobuf []byte) error {
if s44.GroupSyncMsg.GrpCode == 0 { // member sync if s44.GroupSyncMsg.GrpCode == 0 { // member sync
return errors.New("invalid group code") return errors.New("invalid group code")
} }
c.Debug("syncing members.") c.debug("syncing members.")
if group := c.FindGroup(s44.GroupSyncMsg.GrpCode); group != nil { if group := c.FindGroup(s44.GroupSyncMsg.GrpCode); group != nil {
group.lock.Lock() group.lock.Lock()
defer group.lock.Unlock() defer group.lock.Unlock()
@ -257,7 +257,7 @@ func msgType0x210Sub44Decoder(c *QQClient, protobuf []byte) error {
group.Members = newMem group.Members = newMem
for _, m := range newMem { for _, m := range newMem {
if lastJoinTime < m.JoinTime { if lastJoinTime < m.JoinTime {
go c.dispatchNewMemberEvent(&MemberJoinGroupEvent{ c.GroupMemberJoinEvent.dispatch(c, &MemberJoinGroupEvent{
Group: group, Group: group,
Member: m, Member: m,
}) })

View File

@ -59,7 +59,7 @@ func (c *QQClient) SendPrivateMessage(target int64, m *message.SendingMessage) *
}, },
Elements: m.Elements, Elements: m.Elements,
} }
go c.dispatchPrivateMessageSelf(ret) go c.PrivateMessageEvent.dispatch(c, ret)
return ret return ret
} }

View File

@ -324,7 +324,7 @@ func (c *QQClient) buildC2CPttStoreBDHExt(target int64, md5 []byte, size, voiceL
} }
// PttCenterSvr.ShortVideoDownReq // PttCenterSvr.ShortVideoDownReq
func decodePttShortVideoDownResponse(_ *QQClient, _ *network.IncomingPacketInfo, payload []byte) (interface{}, error) { func decodePttShortVideoDownResponse(_ *QQClient, _ *network.IncomingPacketInfo, payload []byte) (any, error) {
rsp := pttcenter.ShortVideoRspBody{} rsp := pttcenter.ShortVideoRspBody{}
if err := proto.Unmarshal(payload, &rsp); err != nil { if err := proto.Unmarshal(payload, &rsp); err != nil {
return nil, errors.Wrap(err, "failed to unmarshal protobuf message") return nil, errors.Wrap(err, "failed to unmarshal protobuf message")
@ -336,7 +336,7 @@ func decodePttShortVideoDownResponse(_ *QQClient, _ *network.IncomingPacketInfo,
} }
// PttCenterSvr.GroupShortVideoUpReq // PttCenterSvr.GroupShortVideoUpReq
func decodeGroupShortVideoUploadResponse(_ *QQClient, _ *network.IncomingPacketInfo, payload []byte) (interface{}, error) { func decodeGroupShortVideoUploadResponse(_ *QQClient, _ *network.IncomingPacketInfo, payload []byte) (any, error) {
rsp := pttcenter.ShortVideoRspBody{} rsp := pttcenter.ShortVideoRspBody{}
if err := proto.Unmarshal(payload, &rsp); err != nil { if err := proto.Unmarshal(payload, &rsp); err != nil {
return nil, errors.Wrap(err, "failed to unmarshal protobuf message") return nil, errors.Wrap(err, "failed to unmarshal protobuf message")

View File

@ -52,7 +52,7 @@ func (c *QQClient) getQiDianAddressDetailList() ([]*FriendInfo, error) {
ret := []*FriendInfo{} ret := []*FriendInfo{}
for _, detail := range rsp.GetAddressDetailListRspBody.AddressDetail { for _, detail := range rsp.GetAddressDetailListRspBody.AddressDetail {
if len(detail.Qq) == 0 { if len(detail.Qq) == 0 {
c.Warning("address detail %v QQ is 0", string(detail.Name)) c.warning("address detail %v QQ is 0", string(detail.Name))
continue continue
} }
ret = append(ret, &FriendInfo{ ret = append(ret, &FriendInfo{
@ -152,7 +152,7 @@ func (c *QQClient) bigDataRequest(subCmd uint32, req proto.Message) ([]byte, err
return tea.Decrypt(payload), nil return tea.Decrypt(payload), nil
} }
func decodeLoginExtraResponse(c *QQClient, _ *network.IncomingPacketInfo, payload []byte) (interface{}, error) { func decodeLoginExtraResponse(c *QQClient, _ *network.IncomingPacketInfo, payload []byte) (any, error) {
rsp := cmd0x3f6.C3F6RspBody{} rsp := cmd0x3f6.C3F6RspBody{}
if err := proto.Unmarshal(payload, &rsp); err != nil { if err := proto.Unmarshal(payload, &rsp); err != nil {
return nil, errors.Wrap(err, "failed to unmarshal protobuf message") return nil, errors.Wrap(err, "failed to unmarshal protobuf message")
@ -168,7 +168,7 @@ func decodeLoginExtraResponse(c *QQClient, _ *network.IncomingPacketInfo, payloa
return nil, nil return nil, nil
} }
func decodeConnKeyResponse(c *QQClient, _ *network.IncomingPacketInfo, payload []byte) (interface{}, error) { func decodeConnKeyResponse(c *QQClient, _ *network.IncomingPacketInfo, payload []byte) (any, error) {
rsp := cmd0x6ff.C501RspBody{} rsp := cmd0x6ff.C501RspBody{}
if err := proto.Unmarshal(payload, &rsp); err != nil { if err := proto.Unmarshal(payload, &rsp); err != nil {
return nil, errors.Wrap(err, "failed to unmarshal protobuf message") return nil, errors.Wrap(err, "failed to unmarshal protobuf message")

View File

@ -92,7 +92,7 @@ func (c *QQClient) buildPrivateRecallPacket(uin, ts int64, msgSeq, random int32)
return c.uniPacket("PbMessageSvc.PbMsgWithDraw", payload) return c.uniPacket("PbMessageSvc.PbMsgWithDraw", payload)
} }
func decodeMsgWithDrawResponse(_ *QQClient, _ *network.IncomingPacketInfo, payload []byte) (interface{}, error) { func decodeMsgWithDrawResponse(_ *QQClient, _ *network.IncomingPacketInfo, payload []byte) (any, error) {
rsp := msg.MsgWithDrawResp{} rsp := msg.MsgWithDrawResp{}
if err := proto.Unmarshal(payload, &rsp); err != nil { if err := proto.Unmarshal(payload, &rsp); err != nil {
return nil, errors.Wrap(err, "failed to unmarshal protobuf message") return nil, errors.Wrap(err, "failed to unmarshal protobuf message")

View File

@ -48,14 +48,11 @@ func (c *QQClient) buildUrlCheckRequest(url string) (uint16, []byte) {
return c.uniPacket("OidbSvc.0xbcb_0", payload) return c.uniPacket("OidbSvc.0xbcb_0", payload)
} }
func decodeUrlCheckResponse(_ *QQClient, _ *network.IncomingPacketInfo, payload []byte) (interface{}, error) { func decodeUrlCheckResponse(_ *QQClient, _ *network.IncomingPacketInfo, payload []byte) (any, error) {
pkg := &oidb.OIDBSSOPkg{}
rsp := &oidb.DBCBRspBody{} rsp := &oidb.DBCBRspBody{}
if err := proto.Unmarshal(payload, pkg); err != nil { err := unpackOIDBPackage(payload, &rsp)
return nil, errors.Wrap(err, "failed to unmarshal protobuf message") if err != nil {
} return nil, err
if err := proto.Unmarshal(pkg.Bodybuffer, rsp); err != nil {
return nil, errors.Wrap(err, "failed to unmarshal protobuf message")
} }
if rsp.CheckUrlRsp == nil || len(rsp.CheckUrlRsp.Results) == 0 { if rsp.CheckUrlRsp == nil || len(rsp.CheckUrlRsp.Results) == 0 {
return nil, errors.New("response is empty") return nil, errors.New("response is empty")

View File

@ -79,7 +79,7 @@ func (c *QQClient) SyncSessions() (*SessionSyncResponse, error) {
ret := &SessionSyncResponse{} ret := &SessionSyncResponse{}
notifyChan := make(chan bool) notifyChan := make(chan bool)
var groupNum int32 = -1 var groupNum int32 = -1
stop := c.waitPacket("RegPrxySvc.PbSyncMsg", func(i interface{}, err error) { stop := c.waitPacket("RegPrxySvc.PbSyncMsg", func(i any, err error) {
if err != nil { if err != nil {
return return
} }
@ -90,7 +90,7 @@ func (c *QQClient) SyncSessions() (*SessionSyncResponse, error) {
if e.GroupNum != -1 { if e.GroupNum != -1 {
groupNum = e.GroupNum groupNum = e.GroupNum
} }
c.Debug("sync session %v/%v", len(ret.GroupSessions), groupNum) c.debug("sync session %v/%v", len(ret.GroupSessions), groupNum)
if groupNum != -1 && len(ret.GroupSessions) >= int(groupNum) { if groupNum != -1 && len(ret.GroupSessions) >= int(groupNum) {
notifyChan <- true notifyChan <- true
} }
@ -285,7 +285,7 @@ func (c *QQClient) buildPrivateMsgReadedPacket(uin, time int64) (uint16, []byte)
} }
// StatSvc.GetDevLoginInfo // StatSvc.GetDevLoginInfo
func decodeDevListResponse(_ *QQClient, _ *network.IncomingPacketInfo, payload []byte) (interface{}, error) { func decodeDevListResponse(_ *QQClient, _ *network.IncomingPacketInfo, payload []byte) (any, error) {
request := &jce.RequestPacket{} request := &jce.RequestPacket{}
request.ReadFrom(jce.NewJceReader(payload)) request.ReadFrom(jce.NewJceReader(payload))
data := &jce.RequestDataVersion2{} data := &jce.RequestDataVersion2{}
@ -307,7 +307,7 @@ func decodeDevListResponse(_ *QQClient, _ *network.IncomingPacketInfo, payload [
} }
// RegPrxySvc.PushParam // RegPrxySvc.PushParam
func decodePushParamPacket(c *QQClient, _ *network.IncomingPacketInfo, payload []byte) (interface{}, error) { func decodePushParamPacket(c *QQClient, _ *network.IncomingPacketInfo, payload []byte) (any, error) {
request := &jce.RequestPacket{} request := &jce.RequestPacket{}
request.ReadFrom(jce.NewJceReader(payload)) request.ReadFrom(jce.NewJceReader(payload))
data := &jce.RequestDataVersion2{} data := &jce.RequestDataVersion2{}
@ -352,7 +352,7 @@ func decodePushParamPacket(c *QQClient, _ *network.IncomingPacketInfo, payload [
} }
// RegPrxySvc.PbSyncMsg // RegPrxySvc.PbSyncMsg
func decodeMsgSyncResponse(c *QQClient, info *network.IncomingPacketInfo, payload []byte) (interface{}, error) { func decodeMsgSyncResponse(c *QQClient, info *network.IncomingPacketInfo, payload []byte) (any, error) {
rsp := &msf.SvcRegisterProxyMsgResp{} rsp := &msf.SvcRegisterProxyMsgResp{}
if err := proto.Unmarshal(payload, rsp); err != nil { if err := proto.Unmarshal(payload, rsp); err != nil {
return nil, err return nil, err
@ -396,7 +396,7 @@ func decodeMsgSyncResponse(c *QQClient, info *network.IncomingPacketInfo, payloa
} }
// OnlinePush.PbC2CMsgSync // OnlinePush.PbC2CMsgSync
func decodeC2CSyncPacket(c *QQClient, info *network.IncomingPacketInfo, payload []byte) (interface{}, error) { func decodeC2CSyncPacket(c *QQClient, info *network.IncomingPacketInfo, payload []byte) (any, error) {
m := msg.PbPushMsg{} m := msg.PbPushMsg{}
if err := proto.Unmarshal(payload, &m); err != nil { if err := proto.Unmarshal(payload, &m); err != nil {
return nil, err return nil, err
@ -406,7 +406,7 @@ func decodeC2CSyncPacket(c *QQClient, info *network.IncomingPacketInfo, payload
return nil, nil return nil, nil
} }
func decodeMsgReadedResponse(_ *QQClient, _ *network.IncomingPacketInfo, payload []byte) (interface{}, error) { func decodeMsgReadedResponse(_ *QQClient, _ *network.IncomingPacketInfo, payload []byte) (any, error) {
rsp := msg.PbMsgReadedReportResp{} rsp := msg.PbMsgReadedReportResp{}
if err := proto.Unmarshal(payload, &rsp); err != nil { if err := proto.Unmarshal(payload, &rsp); err != nil {
return nil, errors.Wrap(err, "failed to unmarshal protobuf message") return nil, errors.Wrap(err, "failed to unmarshal protobuf message")
@ -420,7 +420,7 @@ func decodeMsgReadedResponse(_ *QQClient, _ *network.IncomingPacketInfo, payload
var loginNotifyLock sync.Mutex var loginNotifyLock sync.Mutex
// StatSvc.SvcReqMSFLoginNotify // StatSvc.SvcReqMSFLoginNotify
func decodeLoginNotifyPacket(c *QQClient, _ *network.IncomingPacketInfo, payload []byte) (interface{}, error) { func decodeLoginNotifyPacket(c *QQClient, _ *network.IncomingPacketInfo, payload []byte) (any, error) {
request := &jce.RequestPacket{} request := &jce.RequestPacket{}
request.ReadFrom(jce.NewJceReader(payload)) request.ReadFrom(jce.NewJceReader(payload))
data := &jce.RequestDataVersion2{} data := &jce.RequestDataVersion2{}
@ -443,7 +443,7 @@ func decodeLoginNotifyPacket(c *QQClient, _ *network.IncomingPacketInfo, payload
t := ac t := ac
if ac.AppId == notify.AppId { if ac.AppId == notify.AppId {
c.OnlineClients = append(c.OnlineClients, t) c.OnlineClients = append(c.OnlineClients, t)
c.dispatchOtherClientStatusChangedEvent(&OtherClientStatusChangedEvent{ c.OtherClientStatusChangedEvent.dispatch(c, &OtherClientStatusChangedEvent{
Client: t, Client: t,
Online: true, Online: true,
}) })
@ -462,7 +462,7 @@ func decodeLoginNotifyPacket(c *QQClient, _ *network.IncomingPacketInfo, payload
if rmi != -1 { if rmi != -1 {
rmc := c.OnlineClients[rmi] rmc := c.OnlineClients[rmi]
c.OnlineClients = append(c.OnlineClients[:rmi], c.OnlineClients[rmi+1:]...) c.OnlineClients = append(c.OnlineClients[:rmi], c.OnlineClients[rmi+1:]...)
c.dispatchOtherClientStatusChangedEvent(&OtherClientStatusChangedEvent{ c.OtherClientStatusChangedEvent.dispatch(c, &OtherClientStatusChangedEvent{
Client: rmc, Client: rmc,
Online: false, Online: false,
}) })

View File

@ -60,7 +60,7 @@ func (c *QQClient) GetGroupSystemMessages() (*GroupSystemMessages, error) {
func (c *QQClient) exceptAndDispatchGroupSysMsg() { func (c *QQClient) exceptAndDispatchGroupSysMsg() {
if c.groupSysMsgCache == nil { if c.groupSysMsgCache == nil {
c.Error("warning: groupSysMsgCache is nil") c.error("warning: groupSysMsgCache is nil")
c.groupSysMsgCache, _ = c.GetGroupSystemMessages() c.groupSysMsgCache, _ = c.GetGroupSystemMessages()
return return
} }
@ -86,12 +86,12 @@ func (c *QQClient) exceptAndDispatchGroupSysMsg() {
} }
for _, msg := range msgs.JoinRequests { for _, msg := range msgs.JoinRequests {
if !joinExists(msg.RequestId) { if !joinExists(msg.RequestId) {
c.dispatchJoinGroupRequest(msg) c.UserWantJoinGroupEvent.dispatch(c, msg)
} }
} }
for _, msg := range msgs.InvitedRequests { for _, msg := range msgs.InvitedRequests {
if !invExists(msg.RequestId) { if !invExists(msg.RequestId) {
c.dispatchGroupInvitedEvent(msg) c.GroupInvitedEvent.dispatch(c, msg)
} }
} }
c.groupSysMsgCache = msgs c.groupSysMsgCache = msgs
@ -190,7 +190,7 @@ func (c *QQClient) buildSystemMsgFriendActionPacket(reqID, requester int64, acce
} }
// ProfileService.Pb.ReqSystemMsgNew.Group // ProfileService.Pb.ReqSystemMsgNew.Group
func decodeSystemMsgGroupPacket(c *QQClient, _ *network.IncomingPacketInfo, payload []byte) (interface{}, error) { func decodeSystemMsgGroupPacket(c *QQClient, _ *network.IncomingPacketInfo, payload []byte) (any, error) {
rsp := structmsg.RspSystemMsgNew{} rsp := structmsg.RspSystemMsgNew{}
if err := proto.Unmarshal(payload, &rsp); err != nil { if err := proto.Unmarshal(payload, &rsp); err != nil {
return nil, err return nil, err
@ -243,12 +243,12 @@ func decodeSystemMsgGroupPacket(c *QQClient, _ *network.IncomingPacketInfo, payl
ActionUinNick: st.Msg.ActionUinQqNick, ActionUinNick: st.Msg.ActionUinQqNick,
}) })
default: default:
c.Debug("unknown group system message type: %v", st.Msg.GroupMsgType) c.debug("unknown group system message type: %v", st.Msg.GroupMsgType)
} }
case 3: // ? case 3: // ?
case 5: // 自身状态变更(管理员/加群退群) case 5: // 自身状态变更(管理员/加群退群)
default: default:
c.Debug("unknown group system msg: %v", st.Msg.SubType) c.debug("unknown group system msg: %v", st.Msg.SubType)
} }
} }
return ret, nil return ret, nil

View File

@ -12,16 +12,16 @@ import (
// --- tlv decoders for qq client --- // --- tlv decoders for qq client ---
func (c *QQClient) decodeT161(data []byte) {
/* /*
func (c *QQClient) decodeT161(data []byte) {
reader := binary.NewReader(data) reader := binary.NewReader(data)
reader.ReadBytes(2) reader.ReadBytes(2)
t := reader.ReadTlvMap(2) t := reader.ReadTlvMap(2)
if t172, ok := t[0x172]; ok { if t172, ok := t[0x172]; ok {
c.rollbackSig = t172 c.rollbackSig = t172
} }
*/
} }
*/
func (c *QQClient) decodeT119(data, ek []byte) { func (c *QQClient) decodeT119(data, ek []byte) {
tea := binary.NewTeaCipher(ek) tea := binary.NewTeaCipher(ek)
@ -63,32 +63,32 @@ func (c *QQClient) decodeT119(data, ek []byte) {
pt4TokenMap map[string][]byte pt4TokenMap map[string][]byte
) )
if t11a, ok := m[0x11a]; ok {
nick, age, gender = readT11A(t11a)
}
/*
if _, ok := m[0x125]; ok { if _, ok := m[0x125]; ok {
// openId, openKey = readT125(t125) openId, openKey = readT125(t125)
} }
if t186, ok := m[0x186]; ok { if t186, ok := m[0x186]; ok {
c.decodeT186(t186) c.decodeT186(t186)
} }
if t11a, ok := m[0x11a]; ok {
nick, age, gender = readT11A(t11a)
}
if _, ok := m[0x199]; ok { if _, ok := m[0x199]; ok {
// openId, payToken = readT199(t199) openId, payToken = readT199(t199)
} }
if _, ok := m[0x200]; ok { if _, ok := m[0x200]; ok {
// pf, pfkey = readT200(t200) pf, pfkey = readT200(t200)
} }
if _, ok := m[0x531]; ok {
a1, noPicSig = readT531(t531)
}
if _, ok := m[0x138]; ok {
readT138(t138) // chg time
}
*/
if t512, ok := m[0x512]; ok { if t512, ok := m[0x512]; ok {
psKeyMap, pt4TokenMap = readT512(t512) psKeyMap, pt4TokenMap = readT512(t512)
} }
if _, ok := m[0x531]; ok {
// a1, noPicSig = readT531(t531)
}
if _, ok := m[0x138]; ok {
// readT138(t138) // chg time
}
c.oicq.WtSessionTicketKey = utils.Select(m[0x134], c.oicq.WtSessionTicketKey) c.oicq.WtSessionTicketKey = utils.Select(m[0x134], c.oicq.WtSessionTicketKey)
// we don't use `c.sigInfo = &auth.SigInfo{...}` here, // we don't use `c.sigInfo = &auth.SigInfo{...}` here,
@ -139,11 +139,11 @@ func (c *QQClient) decodeT119R(data []byte) {
if t120, ok := m[0x120]; ok { if t120, ok := m[0x120]; ok {
c.sig.SKey = t120 c.sig.SKey = t120
c.sig.SKeyExpiredTime = time.Now().Unix() + 21600 c.sig.SKeyExpiredTime = time.Now().Unix() + 21600
c.Debug("skey updated: %v", c.sig.SKey) c.debug("skey updated: %v", c.sig.SKey)
} }
if t11a, ok := m[0x11a]; ok { if t11a, ok := m[0x11a]; ok {
c.Nickname, c.Age, c.Gender = readT11A(t11a) c.Nickname, c.Age, c.Gender = readT11A(t11a)
c.Debug("account info updated: " + c.Nickname) c.debug("account info updated: " + c.Nickname)
} }
} }
@ -160,9 +160,11 @@ func (c *QQClient) decodeT113(data []byte) {
fmt.Println("got t113 uin:", uin) fmt.Println("got t113 uin:", uin)
} }
/*
func (c *QQClient) decodeT186(data []byte) { func (c *QQClient) decodeT186(data []byte) {
// c.pwdFlag = data[1] == 1 // c.pwdFlag = data[1] == 1
} }
*/
// --- tlv readers --- // --- tlv readers ---

View File

@ -5,7 +5,6 @@ import (
"github.com/Mrs4s/MiraiGo/client/internal/network" "github.com/Mrs4s/MiraiGo/client/internal/network"
"github.com/Mrs4s/MiraiGo/client/pb/oidb" "github.com/Mrs4s/MiraiGo/client/pb/oidb"
"github.com/Mrs4s/MiraiGo/internal/proto"
) )
func (c *QQClient) buildTranslatePacket(src, dst, text string) (uint16, []byte) { func (c *QQClient) buildTranslatePacket(src, dst, text string) (uint16, []byte) {
@ -16,13 +15,7 @@ func (c *QQClient) buildTranslatePacket(src, dst, text string) (uint16, []byte)
SrcTextList: []string{text}, SrcTextList: []string{text},
}, },
} }
b, _ := proto.Marshal(body) payload := c.packOIDBPackageProto(2448, 2, body)
req := &oidb.OIDBSSOPkg{
Command: 2448,
ServiceType: 2,
Bodybuffer: b,
}
payload, _ := proto.Marshal(req)
return c.uniPacket("OidbSvc.0x990", payload) return c.uniPacket("OidbSvc.0x990", payload)
} }
@ -41,14 +34,11 @@ func (c *QQClient) Translate(src, dst, text string) (string, error) {
} }
// OidbSvc.0x990 // OidbSvc.0x990
func decodeTranslateResponse(_ *QQClient, _ *network.IncomingPacketInfo, payload []byte) (interface{}, error) { func decodeTranslateResponse(_ *QQClient, _ *network.IncomingPacketInfo, payload []byte) (any, error) {
pkg := oidb.OIDBSSOPkg{}
rsp := oidb.TranslateRspBody{} rsp := oidb.TranslateRspBody{}
if err := proto.Unmarshal(payload, &pkg); err != nil { err := unpackOIDBPackage(payload, &rsp)
return nil, errors.Wrap(err, "failed to unmarshal protobuf message") if err != nil {
} return nil, err
if err := proto.Unmarshal(pkg.Bodybuffer, &rsp); err != nil {
return nil, errors.Wrap(err, "failed to unmarshal protobuf message")
} }
return rsp.BatchTranslateRsp, nil return rsp.BatchTranslateRsp, nil
} }

2
go.mod
View File

@ -1,6 +1,6 @@
module github.com/Mrs4s/MiraiGo module github.com/Mrs4s/MiraiGo
go 1.17 go 1.18
require ( require (
github.com/RomiChan/protobuf v0.0.0-20220227114948-643565fff248 github.com/RomiChan/protobuf v0.0.0-20220227114948-643565fff248

View File

@ -173,7 +173,7 @@ func (g Generator) Generate(w io.Writer) {
} }
} }
func assert(cond bool, val interface{}) { func assert(cond bool, val any) {
if !cond { if !cond {
panic("assertion failed: " + fmt.Sprint(val)) panic("assertion failed: " + fmt.Sprint(val))
} }

View File

@ -6,7 +6,7 @@ import (
"math" "math"
) )
type DynamicMessage map[uint64]interface{} type DynamicMessage map[uint64]any
type encoder struct { type encoder struct {
bytes.Buffer bytes.Buffer

View File

@ -2,7 +2,7 @@ package proto
import "github.com/RomiChan/protobuf/proto" import "github.com/RomiChan/protobuf/proto"
type Message = interface{} type Message = any
func Marshal(m Message) ([]byte, error) { func Marshal(m Message) ([]byte, error) {
return proto.Marshal(m) return proto.Marshal(m)

View File

@ -55,7 +55,7 @@ type (
pack(patternId string, isPatternData bool) content pack(patternId string, isPatternData bool) content
} }
content map[string]interface{} content map[string]any
) )
var globalBlockId int64 = 0 var globalBlockId int64 = 0

View File

@ -7,26 +7,26 @@ import (
// https://github.com/Konstantin8105/SimpleTTL // https://github.com/Konstantin8105/SimpleTTL
// entry - typical element of cache // entry - typical element of cache
type entry struct { type entry[T any] struct {
expiry time.Time expiry time.Time
value interface{} value T
} }
// Cache - simple implementation of cache // Cache - simple implementation of cache
// More information: https://en.wikipedia.org/wiki/Time_to_live // More information: https://en.wikipedia.org/wiki/Time_to_live
type Cache struct { type Cache[T any] struct {
lock sync.RWMutex lock sync.RWMutex
cache map[string]*entry cache map[string]*entry[T]
} }
// NewCache - initialization of new cache. // NewCache - initialization of new cache.
// For avoid mistake - minimal time to live is 1 minute. // For avoid mistake - minimal time to live is 1 minute.
// For simplification, - key is string and cache haven`t stop method // For simplification, - key is string and cache haven`t stop method
func NewCache(interval time.Duration) *Cache { func NewCache[T any](interval time.Duration) *Cache[T] {
if interval < time.Second { if interval < time.Second {
interval = time.Second interval = time.Second
} }
cache := &Cache{cache: make(map[string]*entry)} cache := &Cache[T]{cache: make(map[string]*entry[T])}
go func() { go func() {
ticker := time.NewTicker(interval) ticker := time.NewTicker(interval)
for { for {
@ -47,7 +47,7 @@ func NewCache(interval time.Duration) *Cache {
} }
// Count - return amount element of TTL map. // Count - return amount element of TTL map.
func (cache *Cache) Count() int { func (cache *Cache[_]) Count() int {
cache.lock.RLock() cache.lock.RLock()
defer cache.lock.RUnlock() defer cache.lock.RUnlock()
@ -55,19 +55,18 @@ func (cache *Cache) Count() int {
} }
// Get - return value from cache // Get - return value from cache
func (cache *Cache) Get(key string) (interface{}, bool) { func (cache *Cache[T]) Get(key string) (value T, _ bool) {
cache.lock.RLock() cache.lock.RLock()
defer cache.lock.RUnlock() defer cache.lock.RUnlock()
e, ok := cache.cache[key] e, ok := cache.cache[key]
if ok && e.expiry.After(time.Now()) { if ok && e.expiry.After(time.Now()) {
return e.value, true return e.value, true
} }
return nil, false return
} }
func (cache *Cache) GetAndUpdate(key string, ttl time.Duration) (interface{}, bool) { func (cache *Cache[T]) GetAndUpdate(key string, ttl time.Duration) (_ T, _ bool) {
cache.lock.RLock() cache.lock.RLock()
defer cache.lock.RUnlock() defer cache.lock.RUnlock()
@ -75,22 +74,22 @@ func (cache *Cache) GetAndUpdate(key string, ttl time.Duration) (interface{}, bo
e.expiry = time.Now().Add(ttl) e.expiry = time.Now().Add(ttl)
return e.value, true return e.value, true
} }
return nil, false return
} }
// Add - add key/value in cache // Add - add key/value in cache
func (cache *Cache) Add(key string, value interface{}, ttl time.Duration) { func (cache *Cache[T]) Add(key string, value T, ttl time.Duration) {
cache.lock.Lock() cache.lock.Lock()
defer cache.lock.Unlock() defer cache.lock.Unlock()
cache.cache[key] = &entry{ cache.cache[key] = &entry[T]{
value: value, value: value,
expiry: time.Now().Add(ttl), expiry: time.Now().Add(ttl),
} }
} }
// GetKeys - return all keys of cache map // GetKeys - return all keys of cache map
func (cache *Cache) GetKeys() []string { func (cache *Cache[_]) GetKeys() []string {
cache.lock.RLock() cache.lock.RLock()
defer cache.lock.RUnlock() defer cache.lock.RUnlock()