Refactor: remove pkg mem cache
This commit is contained in:
		| @@ -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 | ||||
| } | ||||
|   | ||||
| @@ -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)) | ||||
| 	}) | ||||
| } | ||||
|   | ||||
| @@ -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 { | ||||
|   | ||||
| @@ -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, | ||||
| 	} | ||||
| } | ||||
|   | ||||
							
								
								
									
										2
									
								
								main.go
									
									
									
									
									
								
							
							
						
						
									
										2
									
								
								main.go
									
									
									
									
									
								
							| @@ -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
									
									
								
							
							
						
						
									
										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.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, | ||||
|   | ||||
		Reference in New Issue
	
	Block a user
	 Grail Finder
					Grail Finder