Skip to content

Commit

Permalink
Merge pull request #36 from fumiama/pkt
Browse files Browse the repository at this point in the history
  • Loading branch information
Redmomn authored May 8, 2024
2 parents b69c076 + 5ee4957 commit beb6239
Show file tree
Hide file tree
Showing 29 changed files with 322 additions and 436 deletions.
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

0 comments on commit beb6239

Please sign in to comment.