Refactor: remove pkg mem cache

This commit is contained in:
Grail Finder
2025-07-03 14:26:52 +03:00
parent 873c35ab08
commit 9e058b04e0
8 changed files with 60 additions and 228 deletions

View File

@ -5,10 +5,8 @@ import (
"crypto/hmac"
"crypto/sha256"
"encoding/base64"
"encoding/json"
"fmt"
"gralias/models"
"gralias/pkg/cache"
"gralias/utils"
"html/template"
"net/http"
@ -187,32 +185,5 @@ func makeCookie(username string, remote string) (*http.Cookie, error) {
if err := repo.SessionCreate(context.Background(), session); err != nil {
return nil, err
}
// set user in session
if err := cacheSetSession(sessionToken, session); err != nil {
return nil, err
}
return cookie, nil
}
//nolint: unused
func cacheGetSession(key string) (*models.Session, error) {
userSessionB, err := cache.MemCache.Get(key)
if err != nil {
return nil, err
}
var us *models.Session
if err := json.Unmarshal(userSessionB, &us); err != nil {
return nil, err
}
return us, nil
}
func cacheSetSession(key string, session *models.Session) error {
sesb, err := json.Marshal(session)
if err != nil {
return err
}
cache.MemCache.Set(key, sesb)
cache.MemCache.Expire(key, cfg.SessionLifetime)
return nil
}

View File

@ -6,7 +6,6 @@ import (
"crypto/sha256"
"encoding/base64"
"gralias/models"
"gralias/pkg/cache"
"net/http"
)
@ -71,7 +70,8 @@ func GetSession(next http.Handler) http.Handler {
return
}
if userSession.IsExpired() {
cache.MemCache.RemoveKey(sessionToken)
repo.SessionDelete(r.Context(), sessionToken)
// cache.MemCache.RemoveKey(sessionToken)
msg := "session is expired"
log.Debug(msg, "error", err, "token", sessionToken)
next.ServeHTTP(w, r)
@ -81,13 +81,13 @@ func GetSession(next http.Handler) http.Handler {
models.CtxUsernameKey, userSession.Username)
ctx = context.WithValue(ctx,
models.CtxSessionKey, userSession)
if err := cacheSetSession(sessionToken,
userSession); err != nil {
msg := "failed to marshal user session"
log.Warn(msg, "error", err)
next.ServeHTTP(w, r)
return
}
// if err := cacheSetSession(sessionToken,
// userSession); err != nil {
// msg := "failed to marshal user session"
// log.Warn(msg, "error", err)
// next.ServeHTTP(w, r)
// return
// }
next.ServeHTTP(w, r.WithContext(ctx))
})
}

View File

@ -1,13 +1,13 @@
package llmapi
import (
"encoding/json"
"context"
"errors"
"fmt"
"gralias/broker"
"gralias/config"
"gralias/models"
"gralias/pkg/cache"
"gralias/repos"
"io"
"log/slog"
"net/http"
@ -19,6 +19,7 @@ import (
var (
// botname -> channel
repo = repos.NewRepoProvider("sqlite3://../gralias.db")
SignalChanMap = make(map[string]chan bool)
DoneChanMap = make(map[string]chan bool)
// got prompt: control character (\\u0000-\\u001F) found while parsing a string at line 4 column 0
@ -162,7 +163,8 @@ func (b *Bot) BotMove() {
// botJournalName := models.NotifyJournalPrefix + b.RoomID
b.log.Debug("got signal", "bot-team", b.Team, "bot-role", b.Role)
// get room cards and actions
room, err := getRoomByID(b.RoomID)
// room, err := getRoomByID(b.RoomID)
room, err := repo.RoomGetExtended(context.Background(), b.RoomID)
if err != nil {
b.log.Error("bot loop", "error", err)
return
@ -316,7 +318,8 @@ func NewBot(role, team, name, roomID string, cfg *config.Config, recovery bool)
bot.LLMParser = NewOpenRouterParser(bot.log)
}
// add to room
room, err := getRoomByID(bot.RoomID)
// room, err := getRoomByID(bot.RoomID)
room, err := repo.RoomGetExtended(context.Background(), bot.RoomID)
if err != nil {
return nil, err
}
@ -371,35 +374,39 @@ func NewBot(role, team, name, roomID string, cfg *config.Config, recovery bool)
}
func saveBot(bot *Bot) error {
key := models.CacheBotPredix + bot.RoomID + bot.BotName
data, err := json.Marshal(bot)
if err != nil {
return err
}
cache.MemCache.Set(key, data)
return nil
// key := models.CacheBotPredix + bot.RoomID + bot.BotName
// data, err := json.Marshal(bot)
// if err != nil {
// return err
// // }
// cache.MemCache.Set(key, data)
botPlayer := bot.ToPlayer()
return repo.PlayerAdd(context.Background(), botPlayer)
}
func getRoomByID(roomID string) (*models.Room, error) {
roomBytes, err := cache.MemCache.Get(models.CacheRoomPrefix + roomID)
if err != nil {
return nil, err
}
resp := &models.Room{}
if err := json.Unmarshal(roomBytes, &resp); err != nil {
return nil, err
}
return resp, nil
}
// func getRoomByID(roomID string) (*models.Room, error) {
// roomBytes, err := cache.MemCache.Get(models.CacheRoomPrefix + roomID)
// if err != nil {
// return nil, err
// }
// resp := &models.Room{}
// if err := json.Unmarshal(roomBytes, &resp); err != nil {
// return nil, err
// }
// return resp, nil
// }
func saveRoom(room *models.Room) error {
key := models.CacheRoomPrefix + room.ID
data, err := json.Marshal(room)
if err != nil {
return err
}
cache.MemCache.Set(key, data)
return nil
// key := models.CacheRoomPrefix + room.ID
// data, err := json.Marshal(room)
// if err != nil {
// return err
// }
// cache.MemCache.Set(key, data)
// ------------
// probably need to update other tables
// like word_cards or marks;
return repo.RoomUpdate(context.Background(), room)
}
func (b *Bot) BuildSimpleGuesserPrompt(room *models.Room) string {

View File

@ -2,6 +2,7 @@ package llmapi
import (
"gralias/config"
"gralias/models"
"log/slog"
)
@ -84,3 +85,13 @@ type Bot struct {
// SignalsCh chan bool
// DoneCh chan bool
}
func (b *Bot) ToPlayer() *models.Player {
return &models.Player{
Role: models.StrToUserRole(b.Role),
Team: models.StrToUserTeam(b.Team),
RoomID: &b.RoomID,
Username: b.BotName,
IsBot: true,
}
}

View File

@ -4,7 +4,6 @@ import (
"context"
"gralias/config"
"gralias/handlers"
"gralias/pkg/cache"
"log/slog"
"net/http"
"os"
@ -76,5 +75,4 @@ func main() {
if err := server.Shutdown(ctx); err != nil {
slog.Error("server shutdown failed", "error", err)
}
cache.MemCache.BackupNow()
}

146
pkg/cache/impl.go vendored
View File

@ -1,146 +0,0 @@
package cache
import (
"encoding/json"
"fmt"
"log/slog"
"os"
"sync"
"time"
)
const storeFileName = "store.json"
// var MemCache Cache
var (
MemCache *MemoryCache
)
func readJSON(fileName string) (map[string][]byte, error) {
data := make(map[string][]byte)
file, err := os.Open(fileName)
if err != nil {
return data, err
}
defer file.Close()
decoder := json.NewDecoder(file)
if err := decoder.Decode(&data); err != nil {
return data, err
}
return data, nil
}
func init() {
data, err := readJSON(storeFileName)
if err != nil {
slog.Error("failed to load store from file")
}
MemCache = &MemoryCache{
data: data,
timeMap: make(map[string]time.Time),
lock: &sync.RWMutex{},
}
MemCache.StartExpiryRoutine(time.Minute)
MemCache.StartBackupRoutine(time.Minute)
}
type MemoryCache struct {
data map[string][]byte
timeMap map[string]time.Time
lock *sync.RWMutex
}
// Get a value by key from the cache
func (mc *MemoryCache) Get(key string) (value []byte, err error) {
var ok bool
mc.lock.RLock()
if value, ok = mc.data[key]; !ok {
err = fmt.Errorf("not found data in mc for the key: %v", key)
}
mc.lock.RUnlock()
return value, err
}
// Update a single value in the cache
func (mc *MemoryCache) Set(key string, value []byte) {
// no async writing
mc.lock.Lock()
mc.data[key] = value
mc.lock.Unlock()
}
func (mc *MemoryCache) Expire(key string, exp int64) {
mc.lock.RLock()
mc.timeMap[key] = time.Now().Add(time.Duration(exp) * time.Second)
mc.lock.RUnlock()
}
func (mc *MemoryCache) GetAll() (resp map[string][]byte) {
resp = make(map[string][]byte)
mc.lock.RLock()
for k, v := range mc.data {
resp[k] = v
}
mc.lock.RUnlock()
return
}
func (mc *MemoryCache) GetAllTime() (resp map[string]time.Time) {
resp = make(map[string]time.Time)
mc.lock.RLock()
for k, v := range mc.timeMap {
resp[k] = v
}
mc.lock.RUnlock()
return
}
func (mc *MemoryCache) RemoveKey(key string) {
mc.lock.RLock()
delete(mc.data, key)
delete(mc.timeMap, key)
mc.lock.RUnlock()
}
func (mc *MemoryCache) BackupNow() {
data := mc.GetAll()
jsonString, err := json.Marshal(data)
if err != nil {
slog.Warn("immediate backup failed to marshal", "err", err)
return
}
err = os.WriteFile(storeFileName, jsonString, os.ModePerm)
if err != nil {
slog.Warn("immediate backup failed to write", "err", err)
}
}
func (mc *MemoryCache) StartExpiryRoutine(n time.Duration) {
ticker := time.NewTicker(n)
go func() {
for {
<-ticker.C
// get all
timeData := mc.GetAllTime()
// check time
currentTS := time.Now()
for k, ts := range timeData {
if ts.Before(currentTS) {
// delete exp keys
mc.RemoveKey(k)
slog.Debug("remove by expiry", "key", k)
}
}
}
}()
}
func (mc *MemoryCache) StartBackupRoutine(n time.Duration) {
ticker := time.NewTicker(n)
go func() {
for {
<-ticker.C
mc.BackupNow()
}
}()
}

9
pkg/cache/main.go vendored
View File

@ -1,9 +0,0 @@
package cache
type Cache interface {
Get(key string) ([]byte, error)
Set(key string, value []byte)
Expire(key string, exp int64)
GetAll() (resp map[string][]byte)
RemoveKey(key string)
}

View File

@ -84,6 +84,9 @@ func (p *RepoProvider) RoomGetExtended(ctx context.Context, id string) (*models.
}
room.RedTeam.Color = string(models.UserTeamRed)
room.BlueTeam.Color = string(models.UserTeamBlue)
if room.BotMap == nil {
room.BotMap = make(map[string]models.BotPlayer)
}
for _, player := range players {
if player.Team == models.UserTeamRed {
if player.Role == models.UserRoleMime {
@ -99,9 +102,6 @@ func (p *RepoProvider) RoomGetExtended(ctx context.Context, id string) (*models.
}
}
if player.IsBot {
if room.BotMap == nil {
room.BotMap = make(map[string]models.BotPlayer)
}
room.BotMap[player.Username] = models.BotPlayer{
Role: player.Role,
Team: player.Team,