diff --git a/cache/base.go b/cache/base.go index d60c5fb0..c4977956 100644 --- a/cache/base.go +++ b/cache/base.go @@ -1,25 +1,112 @@ package cache import ( - "sync" + "reflect" + "unsafe" "github.com/LagrangeDev/LagrangeGo/entity" + "github.com/LagrangeDev/LagrangeGo/utils" + "github.com/RomiChan/syncx" ) +var cacheLogger = utils.GetLogger("cache") + +type cacheType uint32 + +const ( + cacheTypeCache cacheType = 1 << iota + cacheTypeFriend + cacheTypeGroupInfo + cacheTypeGroupMember +) + +func typenameof[T any]() string { + return reflect.ValueOf((*T)(nil)).Type().String() +} + +var cacheTypesMap = map[string]cacheType{ + typenameof[Cache](): cacheTypeCache, + typenameof[entity.Friend](): cacheTypeFriend, + typenameof[entity.Group](): cacheTypeGroupInfo, + typenameof[entity.GroupMember](): cacheTypeGroupMember, +} + type Cache struct { - refreshLock sync.RWMutex - // FriendCache 好友缓存 uin *entity.Friend - FriendCache map[uint32]*entity.Friend - // GroupInfoCache 群信息缓存 groupUin *entity.Group - GroupInfoCache map[uint32]*entity.Group - // GroupMemberCache 群内群员信息缓存 groupUin uin *entity.GroupMember - GroupMemberCache map[uint32]map[uint32]*entity.GroupMember + m syncx.Map[uint64, unsafe.Pointer] + refreshed syncx.Map[cacheType, struct{}] +} + +func hasRefreshed[T any](c *Cache) bool { + typ := cacheTypesMap[reflect.ValueOf((*T)(nil)).Type().String()] + if typ == 0 { + return false + } + _, ok := c.refreshed.Load(typ) + return ok +} + +func refreshAllCacheOf[T any](c *Cache, newcache map[uint32]*T) { + typstr := reflect.ValueOf((*T)(nil)).Type().String() + typ := cacheTypesMap[typstr] + if typ == 0 { + return + } + cacheLogger.Debugln("refresh all cache of", typstr) + c.refreshed.Store(typ, struct{}{}) + key := uint64(typ) << 32 + dellst := make([]uint64, 0, 64) + c.m.Range(func(k uint64, v unsafe.Pointer) bool { + if k&key != 0 { + if _, ok := newcache[uint32(k)]; !ok { + dellst = append(dellst, k) + } + } + return true + }) + for k, v := range newcache { + c.m.Store(key|uint64(k), unsafe.Pointer(v)) + } + for _, k := range dellst { + c.m.Delete(k) + } +} + +func setCacheOf[T any](c *Cache, k uint32, v *T) { + typstr := reflect.ValueOf(v).Type().String() + typ := cacheTypesMap[typstr] + if typ == 0 { + return + } + key := uint64(typ)<<32 | uint64(k) + c.m.Store(key, unsafe.Pointer(v)) + cacheLogger.Debugln("set cache of", typstr, k, "=", v) +} + +func getCacheOf[T any](c *Cache, k uint32) (v *T, ok bool) { + typstr := reflect.ValueOf(v).Type().String() + typ := cacheTypesMap[typstr] + if typ == 0 { + return + } + key := uint64(typ)<<32 | uint64(k) + unsafev, ok := c.m.Load(key) + if ok { + v = (*T)(unsafev) + } + cacheLogger.Debugln("get cache of", typstr, k, "=", v) + return } -func NewCache() *Cache { - return &Cache{ - FriendCache: make(map[uint32]*entity.Friend), - GroupInfoCache: make(map[uint32]*entity.Group), - GroupMemberCache: make(map[uint32]map[uint32]*entity.GroupMember), +func rangeCacheOf[T any](c *Cache, iter func(k uint32, v *T) bool) { + typ := cacheTypesMap[reflect.ValueOf((*T)(nil)).Type().String()] + if typ == 0 { + return } + key := uint64(typ) << 32 + c.m.Range(func(k uint64, v unsafe.Pointer) bool { + if k&key != 0 { + return iter(uint32(k), (*T)(v)) + } + return true + }) } diff --git a/cache/cache.go b/cache/cache.go index 5c0833a5..14a86315 100644 --- a/cache/cache.go +++ b/cache/cache.go @@ -4,114 +4,106 @@ import "github.com/LagrangeDev/LagrangeGo/entity" // GetUid 根据uin获取uid func (c *Cache) GetUid(uin uint32, groupUin ...uint32) string { - c.refreshLock.RLock() - defer c.refreshLock.RUnlock() if len(groupUin) == 0 { - if friend, ok := c.FriendCache[uin]; ok { + if friend, ok := getCacheOf[entity.Friend](c, uin); ok { return friend.Uid } - } else { - if group, ok := c.GroupMemberCache[groupUin[0]]; ok { - if member, ok := group[uin]; ok { - return member.Uid - } + return "" + } + if group, ok := getCacheOf[Cache](c, groupUin[0]); ok { + if member, ok := getCacheOf[entity.GroupMember](group, uin); ok { + return member.Uid } } return "" } // GetUin 根据uid获取uin -func (c *Cache) GetUin(uid string, groupUin ...uint32) uint32 { - c.refreshLock.RLock() - defer c.refreshLock.RUnlock() +func (c *Cache) GetUin(uid string, groupUin ...uint32) (uin uint32) { if len(groupUin) == 0 { - for uin, friend := range c.FriendCache { + rangeCacheOf[entity.Friend](c, func(k uint32, friend *entity.Friend) bool { if friend.Uid == uid { - return uin + uin = k + return false } - } - } else { - if group, ok := c.GroupMemberCache[groupUin[0]]; ok { - for uin, member := range group { - if member.Uid == uid { - return uin - } + return true + }) + return uin + } + if group, ok := getCacheOf[Cache](c, groupUin[0]); ok { + rangeCacheOf[entity.GroupMember](group, func(k uint32, member *entity.GroupMember) bool { + if member.Uid == uid { + uin = k + return false } - } + return true + }) } return 0 } // GetFriend 获取好友信息 func (c *Cache) GetFriend(uin uint32) *entity.Friend { - c.refreshLock.RLock() - defer c.refreshLock.RUnlock() - return c.FriendCache[uin] + v, _ := getCacheOf[entity.Friend](c, uin) + return v } // GetGroupInfo 获取群信息 func (c *Cache) GetGroupInfo(groupUin uint32) *entity.Group { - c.refreshLock.RLock() - defer c.refreshLock.RUnlock() - return c.GroupInfoCache[groupUin] + v, _ := getCacheOf[entity.Group](c, groupUin) + return v } // GetAllGroupsInfo 获取所有群信息 func (c *Cache) GetAllGroupsInfo() map[uint32]*entity.Group { - c.refreshLock.RLock() - defer c.refreshLock.RUnlock() - groups := make(map[uint32]*entity.Group, len(c.GroupInfoCache)) - for group, grpInfo := range c.GroupInfoCache { - groups[group] = grpInfo - } + groups := make(map[uint32]*entity.Group, 64) + rangeCacheOf[entity.Group](c, func(k uint32, v *entity.Group) bool { + groups[k] = v + return true + }) return groups } // GetGroupMember 获取群成员信息 func (c *Cache) GetGroupMember(uin, groupUin uint32) *entity.GroupMember { - c.refreshLock.RLock() - defer c.refreshLock.RUnlock() - if group, ok := c.GroupMemberCache[groupUin]; ok { - return group[uin] + if group, ok := getCacheOf[Cache](c, groupUin); ok { + v, _ := getCacheOf[entity.GroupMember](group, uin) + return v } return nil } // GetGroupMembers 获取指定群所有群成员信息 func (c *Cache) GetGroupMembers(groupUin uint32) map[uint32]*entity.GroupMember { - c.refreshLock.RLock() - defer c.refreshLock.RUnlock() - members := make(map[uint32]*entity.GroupMember, len(c.GroupMemberCache)) - for _, member := range c.GroupMemberCache[groupUin] { - members[member.Uin] = member + members := make(map[uint32]*entity.GroupMember, 64) + if group, ok := getCacheOf[Cache](c, groupUin); ok { + rangeCacheOf[entity.GroupMember](group, func(k uint32, member *entity.GroupMember) bool { + members[member.Uin] = member + return true + }) } return members } // FriendCacheIsEmpty 好友信息缓存是否为空 func (c *Cache) FriendCacheIsEmpty() bool { - c.refreshLock.RLock() - defer c.refreshLock.RUnlock() - return len(c.FriendCache) == 0 + return !hasRefreshed[entity.Friend](c) } // GroupMembersCacheIsEmpty 群成员缓存是否为空 func (c *Cache) GroupMembersCacheIsEmpty() bool { - c.refreshLock.RLock() - defer c.refreshLock.RUnlock() - return len(c.GroupMemberCache) == 0 + return !hasRefreshed[Cache](c) } // GroupMemberCacheIsEmpty 指定群的群成员缓存是否为空 func (c *Cache) GroupMemberCacheIsEmpty(groupUin uint32) bool { - c.refreshLock.RLock() - defer c.refreshLock.RUnlock() - return len(c.GroupMemberCache[groupUin]) == 0 + if group, ok := getCacheOf[Cache](c, groupUin); ok { + return !hasRefreshed[entity.GroupMember](group) + } + return true } // GroupInfoCacheIsEmpty 群信息缓存是否为空 func (c *Cache) GroupInfoCacheIsEmpty() bool { - c.refreshLock.RLock() - defer c.refreshLock.RUnlock() - return len(c.GroupInfoCache) == 0 + return !hasRefreshed[entity.Group](c) } diff --git a/cache/operation.go b/cache/operation.go index 01635e24..1f8a6442 100644 --- a/cache/operation.go +++ b/cache/operation.go @@ -5,58 +5,57 @@ import ( ) func (c *Cache) RefreshAll(friendCache map[uint32]*entity.Friend, groupCache map[uint32]*entity.Group, groupMemberCache map[uint32]map[uint32]*entity.GroupMember) { - c.refreshLock.Lock() - defer c.refreshLock.Unlock() - c.FriendCache = friendCache - c.GroupMemberCache = groupMemberCache - c.GroupInfoCache = groupCache + c.RefreshAllFriend(friendCache) + c.RefreshAllGroup(groupCache) + c.RefreshAllGroupMembers(groupMemberCache) } // RefreshFriend 刷新一个好友的缓存 func (c *Cache) RefreshFriend(friend *entity.Friend) { - c.refreshLock.Lock() - defer c.refreshLock.Unlock() - c.FriendCache[friend.Uin] = friend + setCacheOf(c, friend.Uin, friend) } // RefreshAllFriend 刷新所有好友缓存 func (c *Cache) RefreshAllFriend(friendCache map[uint32]*entity.Friend) { - c.refreshLock.Lock() - defer c.refreshLock.Unlock() - c.FriendCache = friendCache + refreshAllCacheOf(c, friendCache) } // RefreshGroupMember 刷新指定群的一个群成员缓存 func (c *Cache) RefreshGroupMember(groupUin uint32, groupMember *entity.GroupMember) { - c.refreshLock.Lock() - defer c.refreshLock.Unlock() - c.GroupMemberCache[groupUin][groupMember.Uin] = groupMember + group, ok := getCacheOf[Cache](c, groupUin) + if !ok { + group = &Cache{} + setCacheOf(c, groupUin, group) + } + setCacheOf(group, groupMember.Uin, groupMember) } // RefreshGroupMembers 刷新一个群内的所有群成员缓存 func (c *Cache) RefreshGroupMembers(groupUin uint32, groupMembers map[uint32]*entity.GroupMember) { - c.refreshLock.Lock() - defer c.refreshLock.Unlock() - c.GroupMemberCache[groupUin] = groupMembers + newc := &Cache{} + for k, v := range groupMembers { + setCacheOf(newc, k, v) + } + setCacheOf(c, groupUin, newc) } // RefreshAllGroupMembers 刷新所有群的群员缓存 func (c *Cache) RefreshAllGroupMembers(groupMemberCache map[uint32]map[uint32]*entity.GroupMember) { - c.refreshLock.Lock() - defer c.refreshLock.Unlock() - c.GroupMemberCache = groupMemberCache + newc := make(map[uint32]*Cache, len(groupMemberCache)*2) + for groupUin, v := range groupMemberCache { + group := &Cache{} + refreshAllCacheOf(group, v) + newc[groupUin] = group + } + refreshAllCacheOf(c, newc) } // RefreshGroup 刷新一个群的群信息缓存 func (c *Cache) RefreshGroup(group *entity.Group) { - c.refreshLock.Lock() - defer c.refreshLock.Unlock() - c.GroupInfoCache[group.GroupUin] = group + setCacheOf(c, group.GroupUin, group) } // RefreshAllGroup 刷新所有群的群信息缓存 func (c *Cache) RefreshAllGroup(groupCache map[uint32]*entity.Group) { - c.refreshLock.Lock() - defer c.refreshLock.Unlock() - c.GroupInfoCache = groupCache + refreshAllCacheOf(c, groupCache) } diff --git a/client/base.go b/client/base.go index 01a71481..d3ca9596 100644 --- a/client/base.go +++ b/client/base.go @@ -32,7 +32,7 @@ func NewQQclient(uin uint32, signUrl string, appInfo *info.AppInfo, deviceInfo * pushStore: make(chan *wtlogin.SSOPacket, 128), stopChan: make(chan struct{}), tcp: NewTCPClient(Server, 5), - cache: cache.NewCache(), + cache: &cache.Cache{}, } client.Online.Store(false) return client diff --git a/client/client.go b/client/client.go index 689804dd..16d9b0e5 100644 --- a/client/client.go +++ b/client/client.go @@ -184,7 +184,8 @@ func (c *QQClient) KeyExchange() error { networkLogger.Errorln(err) return err } - return wtlogin.ParseKeyExchangeResponse(packet.Data, c.sig) + c.sig.ExchangeKey, c.sig.KeySig, err = wtlogin.ParseKeyExchangeResponse(packet.Data) + return err } func (c *QQClient) PasswordLogin(password string) (loginState.State, error) { @@ -294,12 +295,13 @@ func (c *QQClient) Register() error { return err } - if wtlogin.ParseRegisterResponse(response.Data) { + err = wtlogin.ParseRegisterResponse(response.Data) + if err == nil { c.sig.Uin = c.Uin c.setOnline() - networkLogger.Info("Register successful") + networkLogger.Info("Register succeeded") return nil } - networkLogger.Error("Register failure") - return errors.New("register failure") + networkLogger.Errorln("Register failed:", err) + return err } diff --git a/client/listener.go b/client/listener.go index a185410a..f87bae4e 100644 --- a/client/listener.go +++ b/client/listener.go @@ -106,7 +106,7 @@ func decodeOlPushServicePacket(c *QQClient, pkt *wtlogin.SSOPacket) (any, error) } return eventConverter.ParseFriendRecallEvent(&pb), nil case 39: // friend rename - networkLogger.Info("friend rename") + networkLogger.Debugln("friend rename") pb := message.FriendRenameMsg{} err = proto.Unmarshal(pkg.Body.MsgContent, &pb) if err != nil { @@ -114,7 +114,7 @@ func decodeOlPushServicePacket(c *QQClient, pkt *wtlogin.SSOPacket) (any, error) } return eventConverter.ParseFriendRenameEvent(&pb, c.cache), nil case 29: - networkLogger.Info("self rename") + networkLogger.Debugln("self rename") pb := message.SelfRenameMsg{} err = proto.Unmarshal(pkg.Body.MsgContent, &pb) if err != nil { diff --git a/client/operation.go b/client/operation.go index 4535eada..dbf34bf1 100644 --- a/client/operation.go +++ b/client/operation.go @@ -70,15 +70,7 @@ func (c *QQClient) GroupRemark(groupID uint32, remark string) error { if err != nil { return err } - ok, err := oidb.ParseGroupRemarkResp(resp.Data) - if err != nil { - return err - } - if !ok { - return errors.New("remark failed") - } - - return nil + return oidb.ParseGroupRemarkResp(resp.Data) } func (c *QQClient) GroupRename(groupID uint32, name string) error { @@ -90,15 +82,7 @@ func (c *QQClient) GroupRename(groupID uint32, name string) error { if err != nil { return err } - ok, err := oidb.ParseGroupRenameResp(resp.Data) - if err != nil { - return err - } - if !ok { - return errors.New("rename failed") - } - - return nil + return oidb.ParseGroupRenameResp(resp.Data) } func (c *QQClient) GroupMuteGlobal(groupID uint32, isMute bool) error { @@ -110,15 +94,7 @@ func (c *QQClient) GroupMuteGlobal(groupID uint32, isMute bool) error { if err != nil { return err } - ok, err := oidb.ParseGroupMuteGlobalResp(resp.Data) - if err != nil { - return err - } - if !ok { - return errors.New("mute failed") - } - - return nil + return oidb.ParseGroupMuteGlobalResp(resp.Data) } func (c *QQClient) GroupMuteMember(groupID, duration, uin uint32) error { @@ -134,15 +110,7 @@ func (c *QQClient) GroupMuteMember(groupID, duration, uin uint32) error { if err != nil { return err } - ok, err := oidb.ParseGroupMuteMemberResp(resp.Data) - if err != nil { - return err - } - if !ok { - return errors.New("mute failed") - } - - return nil + return oidb.ParseGroupMuteMemberResp(resp.Data) } func (c *QQClient) GroupLeave(groupID uint32) error { @@ -154,15 +122,7 @@ func (c *QQClient) GroupLeave(groupID uint32) error { if err != nil { return err } - ok, err := oidb.ParseGroupLeaveResp(resp.Data) - if err != nil { - return err - } - if !ok { - return errors.New("leave failed") - } - - return nil + return oidb.ParseGroupLeaveResp(resp.Data) } func (c *QQClient) GroupSetAdmin(groupID, uin uint32, isAdmin bool) error { @@ -178,13 +138,10 @@ func (c *QQClient) GroupSetAdmin(groupID, uin uint32, isAdmin bool) error { if err != nil { return err } - ok, err := oidb.ParseGroupSetAdminResp(resp.Data) + err = oidb.ParseGroupSetAdminResp(resp.Data) if err != nil { return err } - if !ok { - return errors.New("set admin failed") - } if m, _ := c.GetCachedMemberInfo(uin, groupID); m != nil { m.Permission = entity.Admin c.cache.RefreshGroupMember(groupID, m) @@ -206,13 +163,10 @@ func (c *QQClient) GroupRenameMember(groupID, uin uint32, name string) error { if err != nil { return err } - ok, err := oidb.ParseGroupRenameMemberResp(resp.Data) + err = oidb.ParseGroupRenameMemberResp(resp.Data) if err != nil { return err } - if !ok { - return errors.New("rename member failed") - } if m, _ := c.GetCachedMemberInfo(uin, groupID); m != nil { m.MemberCard = name c.cache.RefreshGroupMember(groupID, m) @@ -234,15 +188,7 @@ func (c *QQClient) GroupKickMember(groupID, uin uint32, rejectAddRequest bool) e if err != nil { return err } - ok, err := oidb.ParseGroupKickMemberResp(resp.Data) - if err != nil { - return err - } - if !ok { - return errors.New("kick member failed") - } - - return nil + return oidb.ParseGroupKickMemberResp(resp.Data) } func (c *QQClient) GroupSetSpecialTitle(groupUin, uin uint32, title string) error { @@ -258,15 +204,7 @@ func (c *QQClient) GroupSetSpecialTitle(groupUin, uin uint32, title string) erro if err != nil { return err } - ok, err := oidb.ParseGroupSetSpecialTitleResp(resp.Data) - if err != nil { - return err - } - if !ok { - return errors.New("set special title failed") - } - - return nil + return oidb.ParseGroupSetSpecialTitleResp(resp.Data) } func (c *QQClient) GroupPoke(groupID, uin uint32) error { @@ -278,15 +216,7 @@ func (c *QQClient) GroupPoke(groupID, uin uint32) error { if err != nil { return err } - ok, err := oidb.ParsePokeResp(resp.Data) - if err != nil { - return err - } - if !ok { - return errors.New("poke failed") - } - - return nil + return oidb.ParsePokeResp(resp.Data) } func (c *QQClient) FriendPoke(uin uint32) error { @@ -298,18 +228,10 @@ func (c *QQClient) FriendPoke(uin uint32) error { if err != nil { return err } - ok, err := oidb.ParsePokeResp(resp.Data) - if err != nil { - return err - } - if !ok { - return errors.New("poke failed") - } - - return nil + return oidb.ParsePokeResp(resp.Data) } -func (c *QQClient) RecallGroupMessage(GrpUin, seq uint32) (bool, error) { +func (c *QQClient) RecallGroupMessage(GrpUin, seq uint32) error { packet := message.GroupRecallMsg{ Type: 1, GroupUin: GrpUin, @@ -321,14 +243,14 @@ func (c *QQClient) RecallGroupMessage(GrpUin, seq uint32) (bool, error) { } pktData, err := proto.Marshal(&packet) if err != nil { - return false, err + return err } resp, err := c.SendUniPacketAndAwait("trpc.msg.msg_svc.MsgService.SsoGroupRecallMsg", pktData) if err != nil { - return false, err + return err } if len(resp.Data) == 0 { - return false, nil + return errors.New("empty response data") } - return true, nil + return nil } diff --git a/packets/highway/HighWayUrl.go b/packets/highway/HighWayUrl.go index 18200d4c..7b60e42d 100644 --- a/packets/highway/HighWayUrl.go +++ b/packets/highway/HighWayUrl.go @@ -9,14 +9,13 @@ import ( ) func BuildHighWayUrlReq(tgt []byte) ([]byte, error) { - tgtHex := hex.EncodeToString(tgt) - body := &action.HttpConn0X6Ff_501{ + return proto.Marshal(&action.HttpConn0X6Ff_501{ HttpConn: &action.HttpConn{ Field1: 0, Field2: 0, Field3: 16, Field4: 1, - Tgt: tgtHex, + Tgt: hex.EncodeToString(tgt), Field6: 3, ServiceTypes: []int32{1, 5, 10, 21}, Field9: 2, @@ -24,19 +23,10 @@ func BuildHighWayUrlReq(tgt []byte) ([]byte, error) { Field11: 8, Ver: "1.0.1", }, - } - packet, err := proto.Marshal(body) - if err != nil { - return nil, err - } - return packet, nil + }) } -func ParseHighWayUrlReq(data []byte) (*action.HttpConn0X6Ff_501Response, error) { - var req action.HttpConn0X6Ff_501Response - err := proto.Unmarshal(data, &req) - if err != nil { - return nil, err - } - return &req, nil +func ParseHighWayUrlReq(data []byte) (req action.HttpConn0X6Ff_501Response, err error) { + err = proto.Unmarshal(data, &req) + return } diff --git a/packets/oidb/FetchFriends.go b/packets/oidb/FetchFriends.go index 3c72a61d..fcecd9c6 100644 --- a/packets/oidb/FetchFriends.go +++ b/packets/oidb/FetchFriends.go @@ -37,14 +37,14 @@ func ParseFetchFriendsResp(data []byte) ([]*entity.Friend, error) { } friends := make([]*entity.Friend, len(resp.Friends)) for i, raw := range resp.Friends { - additional := GetFirstType1(raw.Additional) - properties := ParseFriendProperty(additional.Layer1.Properties) + additional := getFirstFriendAdditionalTypeEqualTo1(raw.Additional) + properties := parseFriendProperty(additional.Layer1.Properties) friends[i] = entity.NewFriend(raw.Uin, raw.Uid, properties[20002], properties[103], properties[102]) } return friends, nil } -func GetFirstType1(additionals []*oidb.OidbFriendAdditional) *oidb.OidbFriendAdditional { +func getFirstFriendAdditionalTypeEqualTo1(additionals []*oidb.OidbFriendAdditional) *oidb.OidbFriendAdditional { for _, additional := range additionals { if additional.Type == 1 { return additional @@ -53,9 +53,9 @@ func GetFirstType1(additionals []*oidb.OidbFriendAdditional) *oidb.OidbFriendAdd return nil } -func ParseFriendProperty(propertys []*oidb.OidbFriendProperty) map[uint32]string { - dict := make(map[uint32]string, len(propertys)) - for _, property := range propertys { +func parseFriendProperty(properties []*oidb.OidbFriendProperty) map[uint32]string { + dict := make(map[uint32]string, len(properties)) + for _, property := range properties { dict[property.Code] = property.Value } return dict diff --git a/packets/oidb/FriendLike.go b/packets/oidb/FriendLike.go index cd4cd97e..52119235 100644 --- a/packets/oidb/FriendLike.go +++ b/packets/oidb/FriendLike.go @@ -1,8 +1,6 @@ package oidb import ( - "errors" - "github.com/LagrangeDev/LagrangeGo/packets/pb/service/oidb" "github.com/LagrangeDev/LagrangeGo/utils/proto" ) @@ -16,13 +14,6 @@ func BuildFriendLikeReq(uid string, count uint32) (*OidbPacket, error) { return BuildOidbPacket(0x7E5, 104, body, false, false) } -func ParseFriendLikeResp(data []byte) (bool, error) { - baseResp, err := ParseOidbPacket(data, nil) - if err != nil { - return false, err - } - if baseResp.ErrorCode != 0 { - return false, errors.New(baseResp.ErrorMsg) - } - return true, nil +func ParseFriendLikeResp(data []byte) error { + return CheckError(data) } diff --git a/packets/oidb/GroupKickMember.go b/packets/oidb/GroupKickMember.go index 18d634b9..e2847e0e 100644 --- a/packets/oidb/GroupKickMember.go +++ b/packets/oidb/GroupKickMember.go @@ -1,8 +1,6 @@ package oidb import ( - "errors" - "github.com/LagrangeDev/LagrangeGo/packets/pb/service/oidb" ) @@ -16,14 +14,6 @@ func BuildGroupKickMemberReq(groupUin uint32, uid string, rejectAddRequest bool) return BuildOidbPacket(0x8A0, 1, body, false, false) } -func ParseGroupKickMemberResp(data []byte) (bool, error) { - var resp oidb.OidbSvcTrpcTcp0X8A0_1Response - baseResp, err := ParseOidbPacket(data, &resp) - if err != nil { - return false, err - } - if baseResp.ErrorCode != 0 { - return false, errors.New(baseResp.ErrorMsg) - } - return true, nil +func ParseGroupKickMemberResp(data []byte) error { + return CheckTypedError[oidb.OidbSvcTrpcTcp0X8A0_1Response](data) } diff --git a/packets/oidb/GroupLeave.go b/packets/oidb/GroupLeave.go index 6cbabc04..dc9b40e1 100644 --- a/packets/oidb/GroupLeave.go +++ b/packets/oidb/GroupLeave.go @@ -1,8 +1,6 @@ package oidb import ( - "errors" - "github.com/LagrangeDev/LagrangeGo/packets/pb/service/oidb" ) @@ -11,13 +9,6 @@ func BuildGroupLeaveReq(groupUin uint32) (*OidbPacket, error) { return BuildOidbPacket(0x1097, 1, body, false, false) } -func ParseGroupLeaveResp(data []byte) (bool, error) { - baseResp, err := ParseOidbPacket(data, nil) - if err != nil { - return false, err - } - if baseResp.ErrorCode != 0 { - return false, errors.New(baseResp.ErrorMsg) - } - return true, nil +func ParseGroupLeaveResp(data []byte) error { + return CheckError(data) } diff --git a/packets/oidb/GroupMuteGlobal.go b/packets/oidb/GroupMuteGlobal.go index 961b83b4..3cbb56dd 100644 --- a/packets/oidb/GroupMuteGlobal.go +++ b/packets/oidb/GroupMuteGlobal.go @@ -1,7 +1,6 @@ package oidb import ( - "errors" "math" "github.com/LagrangeDev/LagrangeGo/packets/pb/service/oidb" @@ -19,13 +18,6 @@ func BuildGroupMuteGlobalReq(groupUin uint32, isMute bool) (*OidbPacket, error) return BuildOidbPacket(0x89A, 0, body, false, false) } -func ParseGroupMuteGlobalResp(data []byte) (bool, error) { - baseResp, err := ParseOidbPacket(data, nil) - if err != nil { - return false, err - } - if baseResp.ErrorCode != 0 { - return false, errors.New(baseResp.ErrorMsg) - } - return true, nil +func ParseGroupMuteGlobalResp(data []byte) error { + return CheckError(data) } diff --git a/packets/oidb/GroupMuteMember.go b/packets/oidb/GroupMuteMember.go index e1d2cec7..deefcdf5 100644 --- a/packets/oidb/GroupMuteMember.go +++ b/packets/oidb/GroupMuteMember.go @@ -1,8 +1,6 @@ package oidb import ( - "errors" - "github.com/LagrangeDev/LagrangeGo/packets/pb/service/oidb" ) @@ -19,14 +17,6 @@ func BuildGroupMuteMemberReq(groupUin, duration uint32, uid string) (*OidbPacket } // ParseGroupMuteMemberResp 失败了会返回错误原因 -func ParseGroupMuteMemberResp(data []byte) (bool, error) { - var resp oidb.OidbSvcTrpcTcp0X1253_1Response - baseResp, err := ParseOidbPacket(data, &resp) - if err != nil { - return false, err - } - if baseResp.ErrorCode != 0 { - return false, errors.New(baseResp.ErrorMsg) - } - return true, nil +func ParseGroupMuteMemberResp(data []byte) error { + return CheckTypedError[oidb.OidbSvcTrpcTcp0X1253_1Response](data) } diff --git a/packets/oidb/GroupRemark.go b/packets/oidb/GroupRemark.go index 28aca4dc..5be6cac8 100644 --- a/packets/oidb/GroupRemark.go +++ b/packets/oidb/GroupRemark.go @@ -1,8 +1,6 @@ package oidb import ( - "errors" - "github.com/LagrangeDev/LagrangeGo/packets/pb/service/oidb" ) @@ -16,13 +14,6 @@ func BuildGroupRemarkReq(groupUin uint32, mark string) (*OidbPacket, error) { return BuildOidbPacket(0xF16, 1, body, false, false) } -func ParseGroupRemarkResp(data []byte) (bool, error) { - baseResp, err := ParseOidbPacket(data, nil) - if err != nil { - return false, err - } - if baseResp.ErrorCode != 0 { - return false, errors.New(baseResp.ErrorMsg) - } - return true, nil +func ParseGroupRemarkResp(data []byte) error { + return CheckError(data) } diff --git a/packets/oidb/GroupRename.go b/packets/oidb/GroupRename.go index 6d3bd4b7..34797910 100644 --- a/packets/oidb/GroupRename.go +++ b/packets/oidb/GroupRename.go @@ -1,8 +1,6 @@ package oidb import ( - "errors" - "github.com/LagrangeDev/LagrangeGo/packets/pb/service/oidb" ) @@ -14,13 +12,6 @@ func BuildGroupRenameReq(groupUin uint32, name string) (*OidbPacket, error) { return BuildOidbPacket(0x89A, 15, body, false, false) } -func ParseGroupRenameResp(data []byte) (bool, error) { - baseResp, err := ParseOidbPacket(data, nil) - if err != nil { - return false, err - } - if baseResp.ErrorCode != 0 { - return false, errors.New(baseResp.ErrorMsg) - } - return true, nil +func ParseGroupRenameResp(data []byte) error { + return CheckError(data) } diff --git a/packets/oidb/GroupRenameMember.go b/packets/oidb/GroupRenameMember.go index 1b881e9b..dce364dd 100644 --- a/packets/oidb/GroupRenameMember.go +++ b/packets/oidb/GroupRenameMember.go @@ -1,8 +1,6 @@ package oidb import ( - "errors" - "github.com/LagrangeDev/LagrangeGo/packets/pb/service/oidb" ) @@ -17,13 +15,6 @@ func BuildGroupRenameMemberReq(groupUin uint32, uid, name string) (*OidbPacket, return BuildOidbPacket(0x8FC, 3, body, false, false) } -func ParseGroupRenameMemberResp(data []byte) (bool, error) { - baseResp, err := ParseOidbPacket(data, nil) - if err != nil { - return false, err - } - if baseResp.ErrorCode != 0 { - return false, errors.New(baseResp.ErrorMsg) - } - return true, nil +func ParseGroupRenameMemberResp(data []byte) error { + return CheckError(data) } diff --git a/packets/oidb/GroupSetAdmin.go b/packets/oidb/GroupSetAdmin.go index 7db83150..6a8a2445 100644 --- a/packets/oidb/GroupSetAdmin.go +++ b/packets/oidb/GroupSetAdmin.go @@ -1,8 +1,6 @@ package oidb import ( - "errors" - "github.com/LagrangeDev/LagrangeGo/packets/pb/service/oidb" ) @@ -15,13 +13,6 @@ func BuildGroupSetAdminReq(groupUin uint32, uid string, isAdmin bool) (*OidbPack return BuildOidbPacket(0x1096, 1, body, false, false) } -func ParseGroupSetAdminResp(data []byte) (bool, error) { - baseResp, err := ParseOidbPacket(data, nil) - if err != nil { - return false, err - } - if baseResp.ErrorCode != 0 { - return false, errors.New(baseResp.ErrorMsg) - } - return true, nil +func ParseGroupSetAdminResp(data []byte) error { + return CheckError(data) } diff --git a/packets/oidb/GroupSetReaction.go b/packets/oidb/GroupSetReaction.go index 538a869e..fe3b6308 100644 --- a/packets/oidb/GroupSetReaction.go +++ b/packets/oidb/GroupSetReaction.go @@ -1,8 +1,6 @@ package oidb import ( - "errors" - "github.com/LagrangeDev/LagrangeGo/packets/pb/service/oidb" "github.com/LagrangeDev/LagrangeGo/utils/proto" ) @@ -19,13 +17,6 @@ func BuildGroupSetReactionReq(groupUin, sequence uint32, code string) (*OidbPack return BuildOidbPacket(0x9082, 1, body, false, true) } -func ParseGroupSetReactionResp(data []byte) (bool, error) { - baseResp, err := ParseOidbPacket(data, nil) - if err != nil { - return false, err - } - if baseResp.ErrorCode != 0 { - return false, errors.New(baseResp.ErrorMsg) - } - return true, nil +func ParseGroupSetReactionResp(data []byte) error { + return CheckError(data) } diff --git a/packets/oidb/GroupSetSpecialTitle.go b/packets/oidb/GroupSetSpecialTitle.go index 804755f7..570e614e 100644 --- a/packets/oidb/GroupSetSpecialTitle.go +++ b/packets/oidb/GroupSetSpecialTitle.go @@ -1,8 +1,6 @@ package oidb import ( - "errors" - "github.com/LagrangeDev/LagrangeGo/packets/pb/service/oidb" ) @@ -19,13 +17,6 @@ func BuildGroupSetSpecialTitleReq(groupUin uint32, uid, title string) (*OidbPack return BuildOidbPacket(0x8FC, 2, body, false, false) } -func ParseGroupSetSpecialTitleResp(data []byte) (bool, error) { - baseResp, err := ParseOidbPacket(data, nil) - if err != nil { - return false, err - } - if baseResp.ErrorCode != 0 { - return false, errors.New(baseResp.ErrorMsg) - } - return true, nil +func ParseGroupSetSpecialTitleResp(data []byte) error { + return CheckError(data) } diff --git a/packets/oidb/Poke.go b/packets/oidb/Poke.go index 2f76caea..d18f34b1 100644 --- a/packets/oidb/Poke.go +++ b/packets/oidb/Poke.go @@ -1,7 +1,6 @@ package oidb import ( - "errors" "github.com/LagrangeDev/LagrangeGo/packets/pb/service/oidb" "github.com/RomiChan/protobuf/proto" ) @@ -24,13 +23,6 @@ func BuildFriendPokeReq(uin uint32) (*OidbPacket, error) { return BuildOidbPacket(0xED3, 1, body, false, false) } -func ParsePokeResp(data []byte) (bool, error) { - baseResp, err := ParseOidbPacket(data, nil) - if err != nil { - return false, err - } - if baseResp.ErrorCode != 0 { - return false, errors.New(baseResp.ErrorMsg) - } - return true, nil +func ParsePokeResp(data []byte) error { + return CheckError(data) } diff --git a/packets/oidb/SetGroupRequest.go b/packets/oidb/SetGroupRequest.go index 00631425..06da2a7c 100644 --- a/packets/oidb/SetGroupRequest.go +++ b/packets/oidb/SetGroupRequest.go @@ -24,13 +24,6 @@ func BuildSetGroupRequestReq(accept bool, sequence uint64, typ uint32, groupUin return BuildOidbPacket(0x10C8, 1, body, false, false) } -func ParseSetGroupRequestResp(data []byte) (bool, error) { - baseResp, err := ParseOidbPacket(data, nil) - if err != nil { - return false, err - } - if baseResp.ErrorCode != 0 { - return false, nil - } - return true, nil +func ParseSetGroupRequestResp(data []byte) error { + return CheckError(data) } diff --git a/packets/oidb/builder.go b/packets/oidb/builder.go index d9a26970..b1010dbc 100644 --- a/packets/oidb/builder.go +++ b/packets/oidb/builder.go @@ -1,6 +1,7 @@ package oidb import ( + "errors" "fmt" "github.com/LagrangeDev/LagrangeGo/packets/pb/service/oidb" @@ -8,8 +9,7 @@ import ( "github.com/LagrangeDev/LagrangeGo/utils/proto" ) -//nolint:unused -var oidbLogger = utils.GetLogger("oidb") +// var oidbLogger = utils.GetLogger("oidb") type OidbPacket struct { Cmd string @@ -26,9 +26,6 @@ func BuildOidbPacket(cmd, subCmd uint32, body any, isLafter, isUid bool) (*OidbP Command: cmd, SubCommand: subCmd, Body: bodyData, - ErrorMsg: "", - Lafter: nil, - Properties: make([]*oidb.OidbProperty, 0), Reserved: int32(utils.Bool2Int(isUid)), } if isLafter { @@ -46,14 +43,37 @@ func BuildOidbPacket(cmd, subCmd uint32, body any, isLafter, isUid bool) (*OidbP }, nil } -func ParseOidbPacket(b []byte, pkt any) (*oidb.OidbSvcTrpcTcpBase, error) { - var oidbBaseResp oidb.OidbSvcTrpcTcpBase - err := proto.Unmarshal(b, &oidbBaseResp) +func ParseOidbPacket(b []byte, pkt any) (oidbBaseResp oidb.OidbSvcTrpcTcpBase, err error) { + err = proto.Unmarshal(b, &oidbBaseResp) if err != nil { - return nil, err + return } if pkt == nil { - return &oidbBaseResp, nil + return + } + err = proto.Unmarshal(oidbBaseResp.Body, pkt) + return +} + +func CheckError(data []byte) error { + baseResp, err := ParseOidbPacket(data, nil) + if err != nil { + return err + } + if baseResp.ErrorCode != 0 { + return errors.New(baseResp.ErrorMsg) + } + return nil +} + +func CheckTypedError[T any](data []byte) error { + var resp T + baseResp, err := ParseOidbPacket(data, &resp) + if err != nil { + return err + } + if baseResp.ErrorCode != 0 { + return errors.New(baseResp.ErrorMsg) } - return &oidbBaseResp, proto.Unmarshal(oidbBaseResp.Body, pkt) + return nil } diff --git a/packets/wtlogin/exchange.go b/packets/wtlogin/exchange.go index 86b4a673..0eafbf5b 100644 --- a/packets/wtlogin/exchange.go +++ b/packets/wtlogin/exchange.go @@ -3,7 +3,6 @@ package wtlogin import ( "encoding/hex" - "github.com/LagrangeDev/LagrangeGo/info" "github.com/LagrangeDev/LagrangeGo/packets/pb/login" "github.com/LagrangeDev/LagrangeGo/utils" "github.com/LagrangeDev/LagrangeGo/utils/binary" @@ -16,25 +15,23 @@ var encKey, _ = hex.DecodeString("e2733bf403149913cbf80c7a95168bd4ca6935ee53cd39 var keyExangeLogger = utils.GetLogger("KeyExchange") func BuildKexExchangeRequest(uin uint32, guid string) ([]byte, error) { - p1 := proto.DynamicMessage{ + encl, err := crypto.AesGCMEncrypt(proto.DynamicMessage{ 1: uin, 2: guid, - }.Encode() - - encl, err := crypto.AesGCMEncrypt(p1, ecdh.P256().SharedKey()) + }.Encode(), ecdh.P256().SharedKey()) if err != nil { return nil, err } - p2 := binary.NewBuilder(nil). - WriteBytes(ecdh.P256().PublicKey(), false). - WriteU32(1). - WriteBytes(encl, false). - WriteU32(0). - WriteU32(uint32(utils.TimeStamp())). - ToBytes() - - p2Hash := crypto.SHA256Digest(p2) + p2Hash := crypto.SHA256Digest( + binary.NewBuilder(nil). + WriteBytes(ecdh.P256().PublicKey(), false). + WriteU32(1). + WriteBytes(encl, false). + WriteU32(0). + WriteU32(uint32(utils.TimeStamp())). + ToBytes(), + ) encP2Hash, err := crypto.AesGCMEncrypt(p2Hash, encKey) if err != nil { return nil, err @@ -49,36 +46,33 @@ func BuildKexExchangeRequest(uin uint32, guid string) ([]byte, error) { }.Encode(), nil } -func ParseKeyExchangeResponse(response []byte, sig *info.SigInfo) error { +func ParseKeyExchangeResponse(response []byte) (key, sign []byte, err error) { keyExangeLogger.Debugf("keyexchange proto data: %x", response) var p login.SsoKeyExchangeResponse - err := proto.Unmarshal(response, &p) + err = proto.Unmarshal(response, &p) if err != nil { keyExangeLogger.Errorln(err) - return err + return } shareKey, err := ecdh.P256().Exange(p.PublicKey) if err != nil { keyExangeLogger.Errorln(err) - return err + return } var decPb login.SsoKeyExchangeDecrypted data, err := crypto.AesGCMDecrypt(p.GcmEncrypted, shareKey) if err != nil { keyExangeLogger.Errorln(err) - return err + return } err = proto.Unmarshal(data, &decPb) if err != nil { keyExangeLogger.Errorln(err) - return err + return } - sig.ExchangeKey = decPb.GcmKey - sig.KeySig = decPb.Sign - - return nil + return decPb.GcmKey, decPb.Sign, nil } diff --git a/packets/wtlogin/loginState/enum.go b/packets/wtlogin/loginState/enum.go index 2c7964f9..e0b43c02 100644 --- a/packets/wtlogin/loginState/enum.go +++ b/packets/wtlogin/loginState/enum.go @@ -16,30 +16,24 @@ const ( Success State = 0 ) +var statenames = map[State]string{ + TokenExpired: "TokenExpired", + UnusualVerify: "UnusualVerify", + LoginFailure: "LoginFailure", + UserTokenExpired: "UserTokenExpired", + ServerFailure: "ServerFailure", + WrongCaptcha: "WrongCaptcha", + WrongArgument: "WrongArgument", + NewDeviceVerify: "NewDeviceVerify", + CaptchaVerify: "CaptchaVerify", + UnknownError: "UnknownError", + Success: "Success", +} + func (r State) Name() string { - switch r { - case TokenExpired: - return "TokenExpired" - case UnusualVerify: - return "UnusualVerify" - case LoginFailure: - return "LoginFailure" - case UserTokenExpired: - return "UserTokenExpired" - case ServerFailure: - return "ServerFailure" - case WrongCaptcha: - return "WrongCaptcha" - case WrongArgument: - return "WrongArgument" - case NewDeviceVerify: - return "NewDeviceVerify" - case CaptchaVerify: - return "CaptchaVerify" - case UnknownError: - return "UnknownError" - case Success: - return "Success" + name, ok := statenames[r] + if ok { + return name } return "Unknown" } diff --git a/packets/wtlogin/oicq.go b/packets/wtlogin/oicq.go index 4222e075..e19490ab 100644 --- a/packets/wtlogin/oicq.go +++ b/packets/wtlogin/oicq.go @@ -165,7 +165,7 @@ func DecodeLoginResponse(buf []byte, sig *info.SigInfo) error { sig.D2Key = d2Key } if tlv11a, ok := tlv[0x11A]; ok { - loginLogger.Infof("tlv11a data: %x", tlv11a) + loginLogger.Debugf("tlv11a data: %x", tlv11a) tlvReader := binary.NewReader(tlv11a) tlvReader.ReadU16() sig.Age = tlvReader.ReadU8() diff --git a/packets/wtlogin/qrcodeState/enum.go b/packets/wtlogin/qrcodeState/enum.go index 3a6571e5..80220cf6 100644 --- a/packets/wtlogin/qrcodeState/enum.go +++ b/packets/wtlogin/qrcodeState/enum.go @@ -10,18 +10,18 @@ const ( Canceled State = 54 ) +var statenames = map[State]string{ + Confirmed: "Confirmed", + Expired: "Expired", + WaitingForScan: "WaitingForScan", + WaitingForConfirm: "WaitingForConfirm", + Canceled: "Canceled", +} + func (r State) Name() string { - switch r { - case Confirmed: - return "Confirmed" - case Expired: - return "Expired" - case WaitingForScan: - return "WaitingForScan" - case WaitingForConfirm: - return "WaitingForConfirm" - case Canceled: - return "Canceled" + name, ok := statenames[r] + if ok { + return name } return "Unknown" } diff --git a/packets/wtlogin/sso.go b/packets/wtlogin/sso.go index 175a9e13..87fb5b31 100644 --- a/packets/wtlogin/sso.go +++ b/packets/wtlogin/sso.go @@ -80,7 +80,7 @@ func ParseSSOHeader(raw, d2Key []byte) (*SSOHeader, error) { }, nil } -func ParseSSOFrame(buffer []byte, IsOicqBody bool) (*SSOPacket, error) { +func ParseSSOFrame(buffer []byte, isoicqbody bool) (*SSOPacket, error) { reader := binary2.NewReader(buffer) _ = reader.ReadU32() // head length seq := reader.ReadI32() @@ -111,7 +111,7 @@ func ParseSSOFrame(buffer []byte, IsOicqBody bool) (*SSOPacket, error) { } var err error - if IsOicqBody && strings.Index(cmd, "wtlogin") == 0 { + if isoicqbody && strings.Index(cmd, "wtlogin") == 0 { data, err = ParseOicqBody(data) if err != nil { return nil, err diff --git a/packets/wtlogin/statusService.go b/packets/wtlogin/statusService.go index e3fbcf20..2961e120 100644 --- a/packets/wtlogin/statusService.go +++ b/packets/wtlogin/statusService.go @@ -1,6 +1,7 @@ package wtlogin import ( + "errors" "strings" "unicode" @@ -40,17 +41,17 @@ func BuildSSOHeartbeatRequest() []byte { return []byte{0x08, 0x01} } -func ParseRegisterResponse(response []byte) bool { +func ParseRegisterResponse(response []byte) error { var resp system.ServiceRegisterResponse err := proto.Unmarshal(response, &resp) if err != nil { - loginLogger.Errorf("Unmarshal register response failed: %s", err) - return false + return err } - if resp.Message.Unwrap() == "register success" { - return true + msg := resp.Message.Unwrap() + if msg == "register success" { + return nil } - return false + return errors.New(msg) } func capitalize(s string) string {