Refactor: remove pkg mem cache
This commit is contained in:
@ -5,10 +5,8 @@ import (
|
|||||||
"crypto/hmac"
|
"crypto/hmac"
|
||||||
"crypto/sha256"
|
"crypto/sha256"
|
||||||
"encoding/base64"
|
"encoding/base64"
|
||||||
"encoding/json"
|
|
||||||
"fmt"
|
"fmt"
|
||||||
"gralias/models"
|
"gralias/models"
|
||||||
"gralias/pkg/cache"
|
|
||||||
"gralias/utils"
|
"gralias/utils"
|
||||||
"html/template"
|
"html/template"
|
||||||
"net/http"
|
"net/http"
|
||||||
@ -187,32 +185,5 @@ func makeCookie(username string, remote string) (*http.Cookie, error) {
|
|||||||
if err := repo.SessionCreate(context.Background(), session); err != nil {
|
if err := repo.SessionCreate(context.Background(), session); err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
// set user in session
|
|
||||||
if err := cacheSetSession(sessionToken, session); err != nil {
|
|
||||||
return nil, err
|
|
||||||
}
|
|
||||||
return cookie, nil
|
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
|
|
||||||
}
|
|
||||||
|
@ -6,7 +6,6 @@ import (
|
|||||||
"crypto/sha256"
|
"crypto/sha256"
|
||||||
"encoding/base64"
|
"encoding/base64"
|
||||||
"gralias/models"
|
"gralias/models"
|
||||||
"gralias/pkg/cache"
|
|
||||||
"net/http"
|
"net/http"
|
||||||
)
|
)
|
||||||
|
|
||||||
@ -71,7 +70,8 @@ func GetSession(next http.Handler) http.Handler {
|
|||||||
return
|
return
|
||||||
}
|
}
|
||||||
if userSession.IsExpired() {
|
if userSession.IsExpired() {
|
||||||
cache.MemCache.RemoveKey(sessionToken)
|
repo.SessionDelete(r.Context(), sessionToken)
|
||||||
|
// cache.MemCache.RemoveKey(sessionToken)
|
||||||
msg := "session is expired"
|
msg := "session is expired"
|
||||||
log.Debug(msg, "error", err, "token", sessionToken)
|
log.Debug(msg, "error", err, "token", sessionToken)
|
||||||
next.ServeHTTP(w, r)
|
next.ServeHTTP(w, r)
|
||||||
@ -81,13 +81,13 @@ func GetSession(next http.Handler) http.Handler {
|
|||||||
models.CtxUsernameKey, userSession.Username)
|
models.CtxUsernameKey, userSession.Username)
|
||||||
ctx = context.WithValue(ctx,
|
ctx = context.WithValue(ctx,
|
||||||
models.CtxSessionKey, userSession)
|
models.CtxSessionKey, userSession)
|
||||||
if err := cacheSetSession(sessionToken,
|
// if err := cacheSetSession(sessionToken,
|
||||||
userSession); err != nil {
|
// userSession); err != nil {
|
||||||
msg := "failed to marshal user session"
|
// msg := "failed to marshal user session"
|
||||||
log.Warn(msg, "error", err)
|
// log.Warn(msg, "error", err)
|
||||||
next.ServeHTTP(w, r)
|
// next.ServeHTTP(w, r)
|
||||||
return
|
// return
|
||||||
}
|
// }
|
||||||
next.ServeHTTP(w, r.WithContext(ctx))
|
next.ServeHTTP(w, r.WithContext(ctx))
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
@ -1,13 +1,13 @@
|
|||||||
package llmapi
|
package llmapi
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"encoding/json"
|
"context"
|
||||||
"errors"
|
"errors"
|
||||||
"fmt"
|
"fmt"
|
||||||
"gralias/broker"
|
"gralias/broker"
|
||||||
"gralias/config"
|
"gralias/config"
|
||||||
"gralias/models"
|
"gralias/models"
|
||||||
"gralias/pkg/cache"
|
"gralias/repos"
|
||||||
"io"
|
"io"
|
||||||
"log/slog"
|
"log/slog"
|
||||||
"net/http"
|
"net/http"
|
||||||
@ -19,6 +19,7 @@ import (
|
|||||||
|
|
||||||
var (
|
var (
|
||||||
// botname -> channel
|
// botname -> channel
|
||||||
|
repo = repos.NewRepoProvider("sqlite3://../gralias.db")
|
||||||
SignalChanMap = make(map[string]chan bool)
|
SignalChanMap = make(map[string]chan bool)
|
||||||
DoneChanMap = 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
|
// got prompt: control character (\\u0000-\\u001F) found while parsing a string at line 4 column 0
|
||||||
@ -49,7 +50,7 @@ func convertToSliceOfStrings(value any) ([]string, error) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
//nolint: unused
|
// nolint: unused
|
||||||
func (b *Bot) checkGuesses(tempMap map[string]any, room *models.Room) error {
|
func (b *Bot) checkGuesses(tempMap map[string]any, room *models.Room) error {
|
||||||
guesses, err := convertToSliceOfStrings(tempMap["guesses"])
|
guesses, err := convertToSliceOfStrings(tempMap["guesses"])
|
||||||
if err != nil {
|
if err != nil {
|
||||||
@ -162,7 +163,8 @@ func (b *Bot) BotMove() {
|
|||||||
// botJournalName := models.NotifyJournalPrefix + b.RoomID
|
// botJournalName := models.NotifyJournalPrefix + b.RoomID
|
||||||
b.log.Debug("got signal", "bot-team", b.Team, "bot-role", b.Role)
|
b.log.Debug("got signal", "bot-team", b.Team, "bot-role", b.Role)
|
||||||
// get room cards and actions
|
// 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 {
|
if err != nil {
|
||||||
b.log.Error("bot loop", "error", err)
|
b.log.Error("bot loop", "error", err)
|
||||||
return
|
return
|
||||||
@ -316,7 +318,8 @@ func NewBot(role, team, name, roomID string, cfg *config.Config, recovery bool)
|
|||||||
bot.LLMParser = NewOpenRouterParser(bot.log)
|
bot.LLMParser = NewOpenRouterParser(bot.log)
|
||||||
}
|
}
|
||||||
// add to room
|
// add to room
|
||||||
room, err := getRoomByID(bot.RoomID)
|
// room, err := getRoomByID(bot.RoomID)
|
||||||
|
room, err := repo.RoomGetExtended(context.Background(), bot.RoomID)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
@ -371,35 +374,39 @@ func NewBot(role, team, name, roomID string, cfg *config.Config, recovery bool)
|
|||||||
}
|
}
|
||||||
|
|
||||||
func saveBot(bot *Bot) error {
|
func saveBot(bot *Bot) error {
|
||||||
key := models.CacheBotPredix + bot.RoomID + bot.BotName
|
// key := models.CacheBotPredix + bot.RoomID + bot.BotName
|
||||||
data, err := json.Marshal(bot)
|
// data, err := json.Marshal(bot)
|
||||||
if err != nil {
|
// if err != nil {
|
||||||
return err
|
// return err
|
||||||
}
|
// // }
|
||||||
cache.MemCache.Set(key, data)
|
// cache.MemCache.Set(key, data)
|
||||||
return nil
|
botPlayer := bot.ToPlayer()
|
||||||
|
return repo.PlayerAdd(context.Background(), botPlayer)
|
||||||
}
|
}
|
||||||
|
|
||||||
func getRoomByID(roomID string) (*models.Room, error) {
|
// func getRoomByID(roomID string) (*models.Room, error) {
|
||||||
roomBytes, err := cache.MemCache.Get(models.CacheRoomPrefix + roomID)
|
// roomBytes, err := cache.MemCache.Get(models.CacheRoomPrefix + roomID)
|
||||||
if err != nil {
|
// if err != nil {
|
||||||
return nil, err
|
// return nil, err
|
||||||
}
|
// }
|
||||||
resp := &models.Room{}
|
// resp := &models.Room{}
|
||||||
if err := json.Unmarshal(roomBytes, &resp); err != nil {
|
// if err := json.Unmarshal(roomBytes, &resp); err != nil {
|
||||||
return nil, err
|
// return nil, err
|
||||||
}
|
// }
|
||||||
return resp, nil
|
// return resp, nil
|
||||||
}
|
// }
|
||||||
|
|
||||||
func saveRoom(room *models.Room) error {
|
func saveRoom(room *models.Room) error {
|
||||||
key := models.CacheRoomPrefix + room.ID
|
// key := models.CacheRoomPrefix + room.ID
|
||||||
data, err := json.Marshal(room)
|
// data, err := json.Marshal(room)
|
||||||
if err != nil {
|
// if err != nil {
|
||||||
return err
|
// return err
|
||||||
}
|
// }
|
||||||
cache.MemCache.Set(key, data)
|
// cache.MemCache.Set(key, data)
|
||||||
return nil
|
// ------------
|
||||||
|
// 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 {
|
func (b *Bot) BuildSimpleGuesserPrompt(room *models.Room) string {
|
||||||
|
@ -2,6 +2,7 @@ package llmapi
|
|||||||
|
|
||||||
import (
|
import (
|
||||||
"gralias/config"
|
"gralias/config"
|
||||||
|
"gralias/models"
|
||||||
"log/slog"
|
"log/slog"
|
||||||
)
|
)
|
||||||
|
|
||||||
@ -84,3 +85,13 @@ type Bot struct {
|
|||||||
// SignalsCh chan bool
|
// SignalsCh chan bool
|
||||||
// DoneCh 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,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
2
main.go
2
main.go
@ -4,7 +4,6 @@ import (
|
|||||||
"context"
|
"context"
|
||||||
"gralias/config"
|
"gralias/config"
|
||||||
"gralias/handlers"
|
"gralias/handlers"
|
||||||
"gralias/pkg/cache"
|
|
||||||
"log/slog"
|
"log/slog"
|
||||||
"net/http"
|
"net/http"
|
||||||
"os"
|
"os"
|
||||||
@ -76,5 +75,4 @@ func main() {
|
|||||||
if err := server.Shutdown(ctx); err != nil {
|
if err := server.Shutdown(ctx); err != nil {
|
||||||
slog.Error("server shutdown failed", "error", err)
|
slog.Error("server shutdown failed", "error", err)
|
||||||
}
|
}
|
||||||
cache.MemCache.BackupNow()
|
|
||||||
}
|
}
|
||||||
|
146
pkg/cache/impl.go
vendored
146
pkg/cache/impl.go
vendored
@ -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
9
pkg/cache/main.go
vendored
@ -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)
|
|
||||||
}
|
|
@ -84,6 +84,9 @@ func (p *RepoProvider) RoomGetExtended(ctx context.Context, id string) (*models.
|
|||||||
}
|
}
|
||||||
room.RedTeam.Color = string(models.UserTeamRed)
|
room.RedTeam.Color = string(models.UserTeamRed)
|
||||||
room.BlueTeam.Color = string(models.UserTeamBlue)
|
room.BlueTeam.Color = string(models.UserTeamBlue)
|
||||||
|
if room.BotMap == nil {
|
||||||
|
room.BotMap = make(map[string]models.BotPlayer)
|
||||||
|
}
|
||||||
for _, player := range players {
|
for _, player := range players {
|
||||||
if player.Team == models.UserTeamRed {
|
if player.Team == models.UserTeamRed {
|
||||||
if player.Role == models.UserRoleMime {
|
if player.Role == models.UserRoleMime {
|
||||||
@ -99,9 +102,6 @@ func (p *RepoProvider) RoomGetExtended(ctx context.Context, id string) (*models.
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
if player.IsBot {
|
if player.IsBot {
|
||||||
if room.BotMap == nil {
|
|
||||||
room.BotMap = make(map[string]models.BotPlayer)
|
|
||||||
}
|
|
||||||
room.BotMap[player.Username] = models.BotPlayer{
|
room.BotMap[player.Username] = models.BotPlayer{
|
||||||
Role: player.Role,
|
Role: player.Role,
|
||||||
Team: player.Team,
|
Team: player.Team,
|
||||||
|
Reference in New Issue
Block a user