From 3e0d24f5f848a07792d99e64746c43e3cd479396 Mon Sep 17 00:00:00 2001 From: Grail Finder Date: Wed, 2 Jul 2025 15:51:14 +0300 Subject: [PATCH] Fix: buildable --- handlers/actions.go | 149 +++++++++++++++++------------------------ handlers/auth.go | 14 ++-- handlers/handlers.go | 6 +- handlers/middleware.go | 3 +- handlers/timer.go | 6 +- models/main.go | 11 +-- repos/players.go | 26 +++++++ 7 files changed, 110 insertions(+), 105 deletions(-) diff --git a/handlers/actions.go b/handlers/actions.go index a812361..967fea7 100644 --- a/handlers/actions.go +++ b/handlers/actions.go @@ -2,14 +2,12 @@ package handlers import ( "context" - "encoding/json" "errors" "fmt" "gralias/broker" "gralias/llmapi" "gralias/models" "gralias/wordloader" - "strings" ) func createRoom(ctx context.Context, req *models.RoomReq) (*models.Room, error) { @@ -20,7 +18,7 @@ func createRoom(ctx context.Context, req *models.RoomReq) (*models.Room, error) } room := req.CreateRoom(creator) room.RoomLink = cfg.BaseURL + "/room-join?id=" + room.ID - if err := repo.CreateRoom(ctx, room); err != nil { + if err := repo.RoomCreate(ctx, room); err != nil { return nil, err } return room, nil @@ -109,25 +107,24 @@ func notifyBotIfNeeded(room *models.Room) { // return nil // } -func getAllNames() []string { - names := []string{} - // will not scale - wholeMemStore := memcache.GetAll() - session := &models.Session{} - // filter by key size only sessions - for k, v := range wholeMemStore { - // xid is 20 in len - if len(k) != 20 { - continue - } - if err := json.Unmarshal(v, &session); err != nil { - log.Error("failed to unmarshal", "error", err) - continue - } - names = append(names, session.Username) - } - return names -} +// func getAllNames() []string { +// names := []string{} +// // will not scale +// session := &models.Session{} +// // filter by key size only sessions +// for _, name := range wholeMemStore { +// // xid is 20 in len +// if len(k) != 20 { +// continue +// } +// if err := json.Unmarshal(v, &session); err != nil { +// log.Error("failed to unmarshal", "error", err) +// continue +// } +// names = append(names, session.Username) +// } +// return names +// } // can room exists without state? I think no func getFullInfoByCtx(ctx context.Context) (*models.FullInfo, error) { @@ -142,7 +139,7 @@ func getFullInfoByCtx(ctx context.Context) (*models.FullInfo, error) { return resp, nil } // room, err := getRoomByID(state.RoomID) - room, err := repo.GetRoomByID(ctx, state.RoomID) + room, err := repo.RoomGetByID(ctx, state.RoomID) if err != nil { log.Warn("failed to find room despite knowing room_id;", "room_id", state.RoomID) @@ -158,7 +155,7 @@ func getPlayerByCtx(ctx context.Context) (*models.Player, error) { log.Debug("no username in ctx") return &models.Player{}, errors.New("no username in ctx") } - return repo.GetPlayerByName(username) + return repo.PlayerGetByName(username) } // // DEPRECATED @@ -249,41 +246,15 @@ func joinTeam(ctx context.Context, role, team string) (*models.FullInfo, error) // } // get bots -func listBots() map[string]map[string]string { - cacheMap := memcache.GetAll() - resp := make(map[string]map[string]string) - // no way to know if room is public until unmarshal -_-; - for key, value := range cacheMap { - if strings.HasPrefix(key, models.CacheBotPredix) { - botMap := make(map[string]string) - if err := json.Unmarshal(value, &botMap); err != nil { - log.Warn("failed to unmarshal bot", "error", err) - continue - } - resp[botMap["bot_name"]] = botMap - } +func listBots() []models.Player { + bots, err := repo.PlayerList(true) + if err != nil { + log.Error("failed to fetch bots from db", "error", err) } - return resp + return bots } // get players -func listPlayers() map[string]map[string]string { - cacheMap := memcache.GetAll() - resp := make(map[string]map[string]string) - // no way to know if room is public until unmarshal -_-; - for key, value := range cacheMap { - if strings.HasPrefix(key, models.CacheStatePrefix) { - playerMap := make(map[string]string) - if err := json.Unmarshal(value, &playerMap); err != nil { - log.Warn("failed to unmarshal player", "error", err) - continue - } - resp[playerMap["Username"]] = playerMap - } - } - return resp -} - func notify(event, msg string) { Notifier.Notifier <- broker.NotificationEvent{ EventName: event, @@ -312,54 +283,54 @@ func loadCards(room *models.Room) { func recoverBots() { bots := listBots() - for botName, botMap := range bots { - if err := recoverBot(botMap); err != nil { - log.Warn("failed to recover bot", "botName", botName, "error", err) + for _, bot := range bots { + if err := recoverBot(bot); err != nil { + log.Warn("failed to recover bot", "botName", bot.Username, "error", err) } } } -func recoverBot(bm map[string]string) error { +func recoverBot(bm models.Player) error { // check if room still exists - if _, err := getRoomByID(bm["room_id"]); err != nil { - return fmt.Errorf("no such room: %s; err: %w", bm["room_id"], err) + if _, err := repo.RoomGetByID(context.Background(), bm.RoomID); err != nil { + return fmt.Errorf("no such room: %s; err: %w", bm.RoomID, err) } log.Debug("recovering bot", "bot", bm) - _, err := llmapi.NewBot(bm["role"], bm["team"], bm["bot_name"], bm["room_id"], cfg, true) + _, err := llmapi.NewBot(string(bm.Role), string(bm.Team), bm.Username, bm.RoomID, cfg, true) if err != nil { return err } return nil } -func recoverPlayers() { - players := listPlayers() - for playerName, playerMap := range players { - if err := recoverPlayer(playerMap); err != nil { - log.Warn("failed to recover player", "playerName", playerName, "error", err) - } - } -} +// func recoverPlayers() { +// players := listPlayers() +// for playerName, playerMap := range players { +// if err := recoverPlayer(playerMap); err != nil { +// log.Warn("failed to recover player", "playerName", playerName, "error", err) +// } +// } +// } -func recoverPlayer(pm map[string]string) error { - // check if room still exists - room, err := getRoomByID(pm["RoomID"]) - if err != nil { - return fmt.Errorf("no such room: %s; err: %w", pm["RoomID"], err) - } - log.Debug("recovering player", "player", pm) - role, team, ok := room.GetPlayerByName(pm["Username"]) - if !ok { - return fmt.Errorf("failed to find player %s in the room %v", pm["Username"], room) - } - us := &models.UserState{ - Username: pm["Username"], - RoomID: pm["RoomID"], - Team: team, - Role: role, - } - return saveState(pm["Username"], us) -} +// func recoverPlayer(pm map[string]string) error { +// // check if room still exists +// room, err := repo.RoomGetByID(context.Background(), pm["RoomID"]) +// if err != nil { +// return fmt.Errorf("no such room: %s; err: %w", pm["RoomID"], err) +// } +// log.Debug("recovering player", "player", pm) +// role, team, ok := room.GetPlayerByName(pm["Username"]) +// if !ok { +// return fmt.Errorf("failed to find player %s in the room %v", pm["Username"], room) +// } +// us := &models.Player{ +// Username: pm["Username"], +// RoomID: pm["RoomID"], +// Team: team, +// Role: role, +// } +// return saveState(pm["Username"], us) +// } // validateMove checks if it is players turn func validateMove(fi *models.FullInfo, ur models.UserRole) error { diff --git a/handlers/auth.go b/handlers/auth.go index ce63d1c..5264aa4 100644 --- a/handlers/auth.go +++ b/handlers/auth.go @@ -7,6 +7,7 @@ import ( "encoding/json" "fmt" "gralias/models" + "gralias/pkg/cache" "gralias/utils" "html/template" "net/http" @@ -36,7 +37,12 @@ func HandleNameCheck(w http.ResponseWriter, r *http.Request) { return } cleanName := utils.RemoveSpacesFromStr(username) - allNames := getAllNames() + // allNames := getAllNames() + allNames, err := repo.PlayerListNames() + if err != nil { + abortWithError(w, err.Error()) + return + } log.Info("names check", "taken_names", allNames, "trying_name", cleanName) tmpl, err := template.ParseGlob("components/*.html") if err != nil { @@ -175,7 +181,7 @@ func makeCookie(username string, remote string) (*http.Cookie, error) { } func cacheGetSession(key string) (*models.Session, error) { - userSessionB, err := memcache.Get(key) + userSessionB, err := cache.MemCache.Get(key) if err != nil { return nil, err } @@ -191,7 +197,7 @@ func cacheSetSession(key string, session *models.Session) error { if err != nil { return err } - memcache.Set(key, sesb) - memcache.Expire(key, cfg.SessionLifetime) + cache.MemCache.Set(key, sesb) + cache.MemCache.Expire(key, cfg.SessionLifetime) return nil } diff --git a/handlers/handlers.go b/handlers/handlers.go index dffb163..72d2e68 100644 --- a/handlers/handlers.go +++ b/handlers/handlers.go @@ -4,13 +4,11 @@ import ( "gralias/broker" "gralias/config" "gralias/models" - "gralias/pkg/cache" "gralias/repos" "html/template" "log/slog" "net/http" "os" - "time" ) var ( @@ -29,13 +27,13 @@ func init() { // memcache = cache.MemCache cfg = config.LoadConfigOrDefault("") Notifier = broker.Notifier - cache.MemCache.StartBackupRoutine(15 * time.Second) // Reduced backup interval + // cache.MemCache.StartBackupRoutine(15 * time.Second) // Reduced backup interval // bot loader // check the rooms if it has bot_{digits} in them, create bots if have repo = repos.NewRepoProvider("sqlite3://../gralias.db") recoverBots() // if player has a roomID, but no team and role, try to recover - recoverPlayers() + // recoverPlayers() } func HandlePing(w http.ResponseWriter, r *http.Request) { diff --git a/handlers/middleware.go b/handlers/middleware.go index e66010b..d53a760 100644 --- a/handlers/middleware.go +++ b/handlers/middleware.go @@ -6,6 +6,7 @@ import ( "crypto/sha256" "encoding/base64" "gralias/models" + "gralias/pkg/cache" "net/http" ) @@ -70,7 +71,7 @@ func GetSession(next http.Handler) http.Handler { return } if userSession.IsExpired() { - memcache.RemoveKey(sessionToken) + cache.MemCache.RemoveKey(sessionToken) msg := "session is expired" log.Debug(msg, "error", err, "token", sessionToken) next.ServeHTTP(w, r) diff --git a/handlers/timer.go b/handlers/timer.go index 7564d0e..ed95a19 100644 --- a/handlers/timer.go +++ b/handlers/timer.go @@ -1,6 +1,7 @@ package handlers import ( + "context" "fmt" "gralias/models" "sync" @@ -35,7 +36,7 @@ func StartTurnTimer(roomID string, duration time.Duration) { case <-done: return case <-ticker.C: - room, err := getRoomByID(roomID) + room, err := repo.RoomGetByID(context.Background(), roomID) if err != nil { log.Error("failed to get room by id", "error", err) StopTurnTimer(roomID) @@ -45,7 +46,7 @@ func StartTurnTimer(roomID string, duration time.Duration) { log.Info("turn time is over", "room_id", roomID) room.ChangeTurn() room.MimeDone = false - if err := saveRoom(room); err != nil { + if err := repo.RoomUpdate(context.Background(), room); err != nil { log.Error("failed to save room", "error", err) } notify(models.NotifyTurnTimerPrefix+room.ID, fmt.Sprintf("%d", room.Settings.TurnSecondsLeft)) @@ -72,4 +73,3 @@ func StopTurnTimer(roomID string) { delete(timers, roomID) } } - diff --git a/models/main.go b/models/main.go index b1c1ef7..bc481cd 100644 --- a/models/main.go +++ b/models/main.go @@ -378,7 +378,7 @@ type WordCard struct { Word string `json:"word" db:"word"` Color WordColor `json:"color" db:"color"` Revealed bool `json:"revealed" db:"revealed"` - MimeView bool `json:"mime_view" db:"mime_view"` // user who sees that card is mime + Mime bool `json:"mime" db:"mime"` // user who sees that card is mime Mark []CardMark `json:"marks" db:"-"` } @@ -402,13 +402,16 @@ type RoomReq struct { func (rr *RoomReq) CreateRoom(creator string) *Room { roomID := xid.New().String() + settings := GameSettings{ + Language: rr.Language, + RoundTime: rr.RoundTime, + RoomPass: rr.RoomPass, + } return &Room{ ID: roomID, CreatedAt: time.Now(), CreatorName: creator, - Language: rr.Language, - RoundTime: rr.RoundTime, - RoomPass: rr.RoomPass, + Settings: settings, BotMap: make(map[string]BotPlayer), } } diff --git a/repos/players.go b/repos/players.go index 487e42c..09531f5 100644 --- a/repos/players.go +++ b/repos/players.go @@ -12,6 +12,17 @@ type PlayersRepo interface { PlayerDelete(roomID, username string) error PlayerSetRoomID(username, roomID string) error PlayerExitRoom(username string) error + PlayerListNames() ([]string, error) + PlayerList(isBot bool) ([]models.Player, error) +} + +func (p *RepoProvider) PlayerListNames() ([]string, error) { + var names []string + err := p.DB.SelectContext(context.Background(), &names, "SELECT username FROM players;") + if err != nil { + return nil, err + } + return names, nil } func (p *RepoProvider) PlayerGetByName(username string) (*models.Player, error) { @@ -49,3 +60,18 @@ func (p *RepoProvider) PlayerExitRoom(username string) error { _, err := p.DB.ExecContext(context.Background(), "UPDATE players SET room_id = null WHERE username = ?", username) return err } + +func (p *RepoProvider) PlayerList(isBot bool) ([]models.Player, error) { + var players []models.Player + var query string + if isBot { + query = "SELECT id, room_id, username, team, role, is_bot FROM players WHERE is_bot = true;" + } else { + query = "SELECT id, room_id, username, team, role, is_bot FROM players WHERE is_bot = false;" + } + err := p.DB.SelectContext(context.Background(), &players, query) + if err != nil { + return nil, err + } + return players, nil +}