Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

optimize: packet & cache #36

Merged
merged 5 commits into from
May 8, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
113 changes: 100 additions & 13 deletions cache/base.go
Original file line number Diff line number Diff line change
@@ -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
})
}
100 changes: 46 additions & 54 deletions cache/cache.go
Original file line number Diff line number Diff line change
Expand Up @@ -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)
}
51 changes: 25 additions & 26 deletions cache/operation.go
Original file line number Diff line number Diff line change
Expand Up @@ -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)
}
2 changes: 1 addition & 1 deletion client/base.go
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand Down
Loading
Loading