feat(cache): 添加复合键缓存操作支持

添加了基于 uint32+string 组合键的缓存操作方法,包括
GetByCompoundKey、SetByCompoundKey、DelByCompoundKey 和
ContainsByCompoundKey 方法,用于处理用户ID和会话ID的组合缓存场景

fix(vscode): 添加 cSpell 配置支持 struc 词汇

refactor(session): 移除过时的会话管理方法

移除了基于单一字符串键的会话管理方法,因为已迁移到使用
复合键的缓存操作方式
```
This commit is contained in:
昔念
2026-01-19 18:51:56 +08:00
parent 08ebf849eb
commit 026689f3ed
120 changed files with 1428 additions and 629 deletions

View File

@@ -0,0 +1,212 @@
package service
import (
"blazing/common/data/share"
"blazing/cool"
"blazing/modules/config/service"
"blazing/modules/player/model"
"context"
"encoding/binary"
"encoding/hex"
"fmt"
"strings"
"time"
"github.com/gogf/gf/v2/os/glog"
"github.com/gogf/gf/v2/os/gtime"
"github.com/google/uuid"
csmap "github.com/mhmtszr/concurrent-swiss-map"
)
// 是否注册,如果注册过,那么就会产生用户player信息
func (s *InfoService) IsReg() bool {
m := s.PModel(s.Model)
record, err := m.One()
if err != nil {
return false
}
if record != nil {
return true
}
return false
}
// 实现注册,id+昵称+颜色
func (s *InfoService) Reg(nick string, color uint32) {
if s.IsReg() {
return
}
t := model.NewPlayer()
t.PlayerID = uint64(s.userid)
//设置用户信息
t.Data = model.NewPlayerInfo()
t.Data.Nick = nick
t.Data.UserID = s.userid
t.Data.Color = color
t.Data.RegisterTime = uint32(time.Now().Unix()) //写入注册时间
_, err := cool.DBM(s.Model).Data(t).FieldsEx("id").Insert()
if err != nil {
glog.Error(context.Background(), err)
return
}
//go s.InitTask()
}
func (s *InfoService) Person(userid uint32) *model.PlayerInfo {
m := cool.DBM(s.Model).Where("player_id", userid)
var tt model.PlayerEX
err := m.Scan(&tt)
if err != nil {
return nil
}
ret := tt.Data
return &ret
}
func (s *InfoService) GetCache() *model.PlayerInfo {
ret, _ := cool.CacheManager.Get(context.TODO(), fmt.Sprintf("player: %d", s.userid))
if ret == nil {
return nil
}
var rets *model.PlayerInfo
ret.Struct(&rets)
return rets
}
func (s *InfoService) SetLogin() *model.PlayerInfo {
m := cool.DBM(s.Model).Where("player_id", s.userid)
var tt *model.PlayerEX
m.Scan(&tt)
if tt == nil {
return nil
}
tt.Data.AllPetNumber = uint32(NewPetService(s.userid).PetCount(0))
if !IsToday(tt.LastResetTime) { //判断是否是今天
//每天login时候检查重置时间然后把电池任务挖矿重置
//挖矿需要单独存,因为防止多开挖矿
tt.LastResetTime = gtime.Now()
//每天login时候检查重置时间然后把电池任务挖矿重置
//挖矿需要单独存,因为防止多开挖矿
tt.Data.TimeToday = 0 //重置电池
for _, v := range service.NewTaskService().GetDaily() {
tt.Data.SetTask(int(v.TaskId), model.Unaccepted)
}
for i := 0; i < 50; i++ { //每日任务区段
tt.Data.DailyResArr[i] = 0 //重置每日任务
}
//defer t.Service.Talk_Reset()
_, err := m.Save(tt)
if err != nil {
panic(err)
}
}
ret := tt.Data
return &ret
}
var User = csmap.New[string, uint32](
// set the number of map shards. the default value is 32.
csmap.WithShardCount[string, uint32](32),
// set the total capacity, every shard map has total capacity/shard count capacity. the default value is 0.
// csmap.WithSize[string, int](1000),
)
// 生成session
// GetSessionId 生成并返回会话ID、UUID字符串及可能的错误
// 会话ID由accountID(4字节) + UUID(16字节) + 随机数(4字节)组成,最终编码为十六进制字符串
func (s *InfoService) Gensession() string {
uuidV7, _ := uuid.NewV7()
// 移除UUID中的连字符便于后续处理
uuidStr := strings.ReplaceAll(uuidV7.String(), "-", "")
// 解码UUID字符串为字节数组32位十六进制字符串对应16字节
uuidBytes, _ := hex.DecodeString(uuidStr)
// 将accountID转换为4字节大端序字节数组
accountBytes := make([]byte, 4)
binary.BigEndian.PutUint32(accountBytes, uint32(s.userid))
// 预分配缓冲区总长度4+16+4=24字节减少内存分配
sessionBytes := make([]byte, 0, 24)
sessionBytes = append(sessionBytes, accountBytes...)
sessionBytes = append(sessionBytes, uuidBytes...)
//sessionBytes = append(sessionBytes, grand.B(4)...)
// 编码为十六进制字符串作为最终会话ID
sessionID := hex.EncodeToString(sessionBytes)
User.Store(string(uuidStr), uint32(s.userid))
//share.ShareManager.SaveSession(string(uuidStr), uint32(s.userid))
return sessionID
}
func (s *InfoService) Kick(id uint32) error {
cool.Logger.Info(context.TODO(), "服务器收到踢人")
useid1, err := share.ShareManager.GetUserOnline(id)
if err != nil {
return err
}
cl, ok := cool.GetClient(useid1)
if ok {
err := cl.KickPerson(id) //实现指定服务器踢人
if err != nil {
return err
}
}
return nil
}
func (s *InfoService) Save(data model.PlayerInfo) {
m := s.PModel(s.Model)
var tt model.PlayerEX
m.Scan(&tt)
tt.Data = data
_, err := m.Save(tt)
if err != nil {
panic(err)
}
}
type InfoService struct {
BaseService
}
func NewInfoService(id uint32) *InfoService {
return &InfoService{
BaseService: BaseService{userid: id,
Service: &cool.Service{Model: model.NewPlayer(), UniqueKey: map[string]string{
"player_id": "角色名称不能重复",
}, PageQueryOp: &cool.QueryOp{
FieldEQ: []string{"player_id"},
}},
},
}
}