Enha: model update

This commit is contained in:
Grail Finder
2025-07-02 11:18:28 +03:00
parent 76bae3693a
commit b66f9c4c06
6 changed files with 153 additions and 60 deletions

View File

@ -20,42 +20,43 @@ func createRoom(ctx context.Context, req *models.RoomReq) (*models.Room, error)
} }
room := req.CreateRoom(creator) room := req.CreateRoom(creator)
room.RoomLink = cfg.BaseURL + "/room-join?id=" + room.ID room.RoomLink = cfg.BaseURL + "/room-join?id=" + room.ID
if err := saveRoom(room); err != nil { if err := repo.CreateRoom(ctx, room); err != nil {
return nil, err return nil, err
} }
return room, nil return room, nil
} }
func saveRoom(room *models.Room) error { // // DEPRECATED
key := models.CacheRoomPrefix + room.ID // func saveRoom(room *models.Room) error {
data, err := json.Marshal(room) // key := models.CacheRoomPrefix + room.ID
if err != nil { // data, err := json.Marshal(room)
return err // if err != nil {
} // return err
memcache.Set(key, data) // }
// do I need last action here? since room save is kind of an action on itself // memcache.Set(key, data)
// time.Now().Add(time.Hour).Sub(room.LastActionTS) // // do I need last action here? since room save is kind of an action on itself
anHour := int64(216000) // 60 * 60 * 60 // // time.Now().Add(time.Hour).Sub(room.LastActionTS)
memcache.Expire(key, anHour) // anHour := int64(216000) // 60 * 60 * 60
return nil // memcache.Expire(key, anHour)
} // return nil
// }
func getRoomByID(roomID string) (*models.Room, error) { // func getRoomByID(roomID string) (*models.Room, error) {
roomBytes, err := memcache.Get(models.CacheRoomPrefix + roomID) // roomBytes, err := 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 removeRoom(roomID string) { // func removeRoom(roomID string) {
key := models.CacheRoomPrefix + roomID // key := models.CacheRoomPrefix + roomID
memcache.RemoveKey(key) // memcache.RemoveKey(key)
} // }
// context // context
@ -76,17 +77,17 @@ func getStateByCtx(ctx context.Context) (*models.UserState, error) {
// repo.CreateRoom() // repo.CreateRoom()
// } // }
func saveFullInfo(fi *models.FullInfo) error { // func saveFullInfo(fi *models.FullInfo) error {
// INFO: no transactions; so case is possible where first object is updated but the second is not // // INFO: no transactions; so case is possible where first object is updated but the second is not
if err := saveState(fi.State.Username, fi.State); err != nil { // if err := saveState(fi.State.Username, fi.State); err != nil {
return err // return err
} // }
log.Debug("saved user state", "state", fi.State) // log.Debug("saved user state", "state", fi.State)
if err := saveRoom(fi.Room); err != nil { // if err := saveRoom(fi.Room); err != nil {
return err // return err
} // }
return nil // return nil
} // }
func notifyBotIfNeeded(room *models.Room) { func notifyBotIfNeeded(room *models.Room) {
if botName := room.WhichBotToMove(); botName != "" { if botName := room.WhichBotToMove(); botName != "" {

View File

@ -14,9 +14,9 @@ import (
) )
var ( var (
log *slog.Logger log *slog.Logger
cfg *config.Config cfg *config.Config
memcache cache.Cache // memcache cache.Cache
Notifier *broker.Broker Notifier *broker.Broker
repo repos.AllRepos repo repos.AllRepos
) )
@ -26,7 +26,7 @@ func init() {
Level: slog.LevelDebug, Level: slog.LevelDebug,
AddSource: true, AddSource: true,
})) }))
memcache = cache.MemCache // memcache = cache.MemCache
cfg = config.LoadConfigOrDefault("") cfg = config.LoadConfigOrDefault("")
Notifier = broker.Notifier Notifier = broker.Notifier
cache.MemCache.StartBackupRoutine(15 * time.Second) // Reduced backup interval cache.MemCache.StartBackupRoutine(15 * time.Second) // Reduced backup interval
@ -91,17 +91,25 @@ func HandleExit(w http.ResponseWriter, r *http.Request) {
creatorLeft = true creatorLeft = true
} }
exitedRoom := fi.ExitRoom() exitedRoom := fi.ExitRoom()
if err := saveRoom(exitedRoom); err != nil { // if err := saveRoom(exitedRoom); err != nil {
abortWithError(w, err.Error()) // abortWithError(w, err.Error())
return // return
} // }
if creatorLeft { if creatorLeft {
removeRoom(exitedRoom.ID) if err := repo.DeleteRoomByID(r.Context(), exitedRoom.ID); err != nil {
log.Error("failed to remove room", "error", err)
}
// removeRoom(exitedRoom.ID)
// TODO: notify users if creator left // TODO: notify users if creator left
// and throw them away // and throw them away
notify(models.NotifyRoomListUpdate, "") notify(models.NotifyRoomListUpdate, "")
} }
if err := saveState(fi.State.Username, fi.State); err != nil { // scary to update the whole room
if err := repo.UpdateRoom(r.Context(), exitedRoom); err != nil {
abortWithError(w, err.Error())
return
}
if err := repo.PlayerExitRoom(fi.State.Username); err != nil {
abortWithError(w, err.Error()) abortWithError(w, err.Error())
return return
} }

View File

@ -14,7 +14,7 @@ CREATE TABLE rooms (
is_running BOOLEAN NOT NULL DEFAULT FALSE, is_running BOOLEAN NOT NULL DEFAULT FALSE,
is_over BOOLEAN NOT NULL DEFAULT FALSE, is_over BOOLEAN NOT NULL DEFAULT FALSE,
team_won TEXT NOT NULL DEFAULT '', team_won TEXT NOT NULL DEFAULT '',
room_pass TEXT NOT NULL DEFAULT '' room_link TEXT NOT NULL DEFAULT ''
); );
CREATE TABLE players ( CREATE TABLE players (

View File

@ -373,11 +373,13 @@ func (r *Room) RevealSpecificWord(word string) {
} }
type WordCard struct { type WordCard struct {
Word string `json:"word"` ID uint32 `json:"id" db:"id"`
Color WordColor `json:"color"` RoomID string `json:"room_id" db:"room_id"`
Revealed bool `json:"revealed"` Word string `json:"word" db:"word"`
Mime bool `json:"mime"` // user who sees that card is mime Color WordColor `json:"color" db:"color"`
Mark []CardMark `json:"marks"` Revealed bool `json:"revealed" db:"revealed"`
MimeView bool `json:"mime_view" db:"mime_view"` // user who sees that card is mime
Mark []CardMark `json:"marks" db:"-"`
} }
// table: settings // table: settings

View File

@ -10,6 +10,8 @@ type PlayersRepo interface {
PlayerAdd(player *models.Player) error PlayerAdd(player *models.Player) error
PlayerUpdate(player *models.Player) error PlayerUpdate(player *models.Player) error
PlayerDelete(roomID, username string) error PlayerDelete(roomID, username string) error
PlayerSetRoomID(username, roomID string) error
PlayerExitRoom(username string) error
} }
func (p *RepoProvider) PlayerGetByName(username string) (*models.Player, error) { func (p *RepoProvider) PlayerGetByName(username string) (*models.Player, error) {
@ -22,12 +24,14 @@ func (p *RepoProvider) PlayerGetByName(username string) (*models.Player, error)
} }
func (p *RepoProvider) PlayerAdd(player *models.Player) error { func (p *RepoProvider) PlayerAdd(player *models.Player) error {
_, err := p.DB.ExecContext(context.Background(), "INSERT INTO players (room_id, username, team, role, is_bot) VALUES (?, ?, ?, ?, ?)", player.RoomID, player.Username, player.Team, player.Role, player.IsBot) _, err := p.DB.ExecContext(context.Background(), "INSERT INTO players (room_id, username, team, role, is_bot) VALUES (?, ?, ?, ?, ?)",
player.RoomID, player.Username, player.Team, player.Role, player.IsBot)
return err return err
} }
func (p *RepoProvider) PlayerUpdate(player *models.Player) error { func (p *RepoProvider) PlayerUpdate(player *models.Player) error {
_, err := p.DB.ExecContext(context.Background(), "UPDATE players SET room_id = ?, username = ?, team = ?, role = ?, is_bot = ? WHERE id = ?", player.RoomID, player.Username, player.Team, player.Role, player.IsBot, player.ID) _, err := p.DB.ExecContext(context.Background(), "UPDATE players SET room_id = ?, username = ?, team = ?, role = ?, is_bot = ? WHERE id = ?",
player.RoomID, player.Username, player.Team, player.Role, player.IsBot, player.ID)
return err return err
} }
@ -35,3 +39,13 @@ func (p *RepoProvider) PlayerDelete(roomID, username string) error {
_, err := p.DB.ExecContext(context.Background(), "DELETE FROM players WHERE room_id = ? AND username = ?", roomID, username) _, err := p.DB.ExecContext(context.Background(), "DELETE FROM players WHERE room_id = ? AND username = ?", roomID, username)
return err return err
} }
func (p *RepoProvider) PlayerSetRoomID(username, roomID string) error {
_, err := p.DB.ExecContext(context.Background(), "UPDATE players SET room_id = ? WHERE username = ?", roomID, username)
return err
}
func (p *RepoProvider) PlayerExitRoom(username string) error {
_, err := p.DB.ExecContext(context.Background(), "UPDATE players SET room_id = null WHERE username = ?", username)
return err
}

View File

@ -8,6 +8,7 @@ import (
type RoomsRepo interface { type RoomsRepo interface {
ListRooms(ctx context.Context) ([]*models.Room, error) ListRooms(ctx context.Context) ([]*models.Room, error)
GetRoomByID(ctx context.Context, id string) (*models.Room, error) GetRoomByID(ctx context.Context, id string) (*models.Room, error)
GetRoomExtended(ctx context.Context, id string) (*models.Room, error)
CreateRoom(ctx context.Context, room *models.Room) error CreateRoom(ctx context.Context, room *models.Room) error
DeleteRoomByID(ctx context.Context, id string) error DeleteRoomByID(ctx context.Context, id string) error
UpdateRoom(ctx context.Context, room *models.Room) error UpdateRoom(ctx context.Context, room *models.Room) error
@ -32,7 +33,7 @@ func (p *RepoProvider) GetRoomByID(ctx context.Context, id string) (*models.Room
} }
func (p *RepoProvider) CreateRoom(ctx context.Context, r *models.Room) error { func (p *RepoProvider) CreateRoom(ctx context.Context, r *models.Room) error {
_, err := p.DB.ExecContext(ctx, `INSERT INTO rooms (id, created_at, creator_name, team_turn, this_turn_limit, opened_this_turn, blue_counter, red_counter, red_turn, mime_done, is_running, round_time, is_over, team_won, room_pass) VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?)`, r.ID, r.CreatedAt, r.CreatorName, r.TeamTurn, r.ThisTurnLimit, r.OpenedThisTurn, r.BlueCounter, r.RedCounter, r.RedTurn, r.MimeDone, r.IsRunning, r.RoundTime, r.IsOver, r.TeamWon, r.RoomPass) _, err := p.DB.ExecContext(ctx, `INSERT INTO rooms (id, created_at, creator_name, team_turn, this_turn_limit, opened_this_turn, blue_counter, red_counter, red_turn, mime_done, , is_running, is_over, team_won, room_link) VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?)`, r.ID, r.CreatedAt, r.CreatorName, r.TeamTurn, r.ThisTurnLimit, r.OpenedThisTurn, r.BlueCounter, r.RedCounter, r.RedTurn, r.MimeDone, r.IsRunning, r.IsOver, r.TeamWon, r.RoomLink)
return err return err
} }
@ -42,6 +43,73 @@ func (p *RepoProvider) DeleteRoomByID(ctx context.Context, id string) error {
} }
func (p *RepoProvider) UpdateRoom(ctx context.Context, r *models.Room) error { func (p *RepoProvider) UpdateRoom(ctx context.Context, r *models.Room) error {
_, err := p.DB.ExecContext(ctx, `UPDATE rooms SET team_turn = ?, this_turn_limit = ?, opened_this_turn = ?, blue_counter = ?, red_counter = ?, red_turn = ?, mime_done = ?, is_running = ?, round_time = ?, is_over = ?, team_won = ?, room_pass = ? WHERE id = ?`, r.TeamTurn, r.ThisTurnLimit, r.OpenedThisTurn, r.BlueCounter, r.RedCounter, r.RedTurn, r.MimeDone, r.IsRunning, r.RoundTime, r.IsOver, r.TeamWon, r.RoomPass, r.ID) _, err := p.DB.ExecContext(ctx, `UPDATE rooms SET team_turn = ?, this_turn_limit = ?, opened_this_turn = ?, blue_counter = ?, red_counter = ?, red_turn = ?, mime_done = ?, = ?, is_running = ?, is_over = ?, team_won = ?, room_link = ? WHERE id = ?`, r.TeamTurn, r.ThisTurnLimit, r.OpenedThisTurn, r.BlueCounter, r.RedCounter, r.RedTurn, r.MimeDone, r.IsRunning, r.IsOver, r.TeamWon, r.RoomLink, r.ID)
return err return err
} }
func (p *RepoProvider) GetRoomExtended(ctx context.Context, id string) (*models.Room, error) {
room := &models.Room{}
err := p.DB.GetContext(ctx, room, `SELECT * FROM rooms WHERE id = ?`, id)
if err != nil {
return nil, err
}
// Get players
players := []*models.Player{}
err = p.DB.SelectContext(ctx, &players, `SELECT * FROM players WHERE room_id = ?`, id)
if err != nil {
return nil, err
}
room.RedTeam.Color = string(models.UserTeamRed)
room.BlueTeam.Color = string(models.UserTeamBlue)
for _, player := range players {
if player.Team == models.UserTeamRed {
if player.Role == models.UserRoleMime {
room.RedTeam.Mime = player.Username
} else {
room.RedTeam.Guessers = append(room.RedTeam.Guessers, player.Username)
}
} else if player.Team == models.UserTeamBlue {
if player.Role == models.UserRoleMime {
room.BlueTeam.Mime = player.Username
} else {
room.BlueTeam.Guessers = append(room.BlueTeam.Guessers, player.Username)
}
}
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,
}
}
}
// Get word cards
wordCards := []*models.WordCard{}
err = p.DB.SelectContext(ctx, &wordCards, `SELECT * FROM word_cards WHERE room_id = ?`, id)
if err != nil {
return nil, err
}
room.Cards = wordCards
// Get actions
actions := []*models.Action{}
err = p.DB.SelectContext(ctx, &actions, `SELECT * FROM actions WHERE room_id = ? ORDER BY created_at ASC`, id)
if err != nil {
return nil, err
}
room.ActionHistory = actions
// Get settings
settings := &models.GameSettings{}
err = p.DB.GetContext(ctx, settings, `SELECT * FROM settings WHERE room_id = ?`, id)
if err != nil {
return nil, err
}
room.Settings = *settings
return room, nil
}