From 6be365473c9fcc2aa9116fb08f4b429b7daa39d9 Mon Sep 17 00:00:00 2001 From: Grail Finder Date: Fri, 4 Jul 2025 13:32:59 +0300 Subject: [PATCH] Feat: settings repo --- crons/main.go | 6 +++++ handlers/game.go | 2 +- handlers/timer.go | 30 ++++++++++++++---------- migrations/001_initial_schema.up.sql | 1 + models/main.go | 2 +- repos/actions_test.go | 5 +++- repos/main.go | 6 +++++ repos/rooms.go | 4 ---- repos/settings.go | 35 ++++++++++++++++++++++++++++ 9 files changed, 72 insertions(+), 19 deletions(-) create mode 100644 repos/settings.go diff --git a/crons/main.go b/crons/main.go index 28c8273..d5fd1fd 100644 --- a/crons/main.go +++ b/crons/main.go @@ -65,6 +65,9 @@ func (cm *CronManager) CleanupRooms() { if err := cm.repo.RoomDeleteByID(ctx, room.ID); err != nil { cm.log.Error("failed to delete empty room", "room_id", room.ID, "err", err) } + if err := cm.repo.SettingsDeleteByRoomID(ctx, room.ID); err != nil { + cm.log.Error("failed to delete settings for empty room", "room_id", room.ID, "err", err) + } continue } @@ -92,6 +95,9 @@ func (cm *CronManager) CleanupRooms() { if err := cm.repo.RoomDeleteByID(ctx, room.ID); err != nil { cm.log.Error("failed to delete room after creator left", "room_id", room.ID, "err", err) } + if err := cm.repo.SettingsDeleteByRoomID(ctx, room.ID); err != nil { + cm.log.Error("failed to delete settings after creator left", "room_id", room.ID, "err", err) + } } } diff --git a/handlers/game.go b/handlers/game.go index 7db0a38..4633272 100644 --- a/handlers/game.go +++ b/handlers/game.go @@ -200,7 +200,7 @@ func HandleStartGame(w http.ResponseWriter, r *http.Request) { // Save action history action.RoomID = fi.Room.ID action.CreatedAt = time.Now() - if err := repo.CreateAction(ctx, fi.Room.ID, &action); err != nil { + if err := repo.CreateAction(ctx, &action); err != nil { if err := tx.Rollback(); err != nil { log.Error("failed to rollback transaction", "error", err) } diff --git a/handlers/timer.go b/handlers/timer.go index 6cc8fe1..fca39f2 100644 --- a/handlers/timer.go +++ b/handlers/timer.go @@ -28,19 +28,25 @@ func StartTurnTimer(roomID string, duration time.Duration) { done := make(chan bool) timers[roomID] = &roomTimer{ticker: ticker, done: done} go func() { + settings, err := repo.SettingsGetByRoomID(context.Background(), roomID) + if err != nil { + log.Error("failed to get settings by room id", "error", err) + StopTurnTimer(roomID) + return + } for { select { case <-done: return case <-ticker.C: - room, err := repo.RoomGetByID(context.Background(), roomID) - if err != nil { - log.Error("failed to get room by id", "error", err) - StopTurnTimer(roomID) - return - } - if room.Settings.TurnSecondsLeft <= 0 { + if settings.TurnSecondsLeft <= 0 { log.Info("turn time is over", "room_id", roomID) + room, err := repo.RoomGetByID(context.Background(), roomID) + if err != nil { + log.Error("failed to get room by id", "error", err) + StopTurnTimer(roomID) + return + } room.ChangeTurn() room.MimeDone = false if err := repo.RoomUpdate(context.Background(), room); err != nil { @@ -51,11 +57,11 @@ func StartTurnTimer(roomID string, duration time.Duration) { StopTurnTimer(roomID) return } - room.Settings.TurnSecondsLeft-- - // if err := saveRoom(room); err != nil { - // log.Error("failed to save room", "error", err) - // } - notify(models.NotifyRoomUpdatePrefix+room.ID, "") + settings.TurnSecondsLeft-- + if err := repo.SettingsUpdate(context.Background(), settings); err != nil { + log.Error("failed to update settings", "error", err) + } + notify(models.NotifyRoomUpdatePrefix+roomID, "") } } }() diff --git a/migrations/001_initial_schema.up.sql b/migrations/001_initial_schema.up.sql index fc9a960..18b6d77 100644 --- a/migrations/001_initial_schema.up.sql +++ b/migrations/001_initial_schema.up.sql @@ -65,6 +65,7 @@ CREATE TABLE settings ( language TEXT NOT NULL DEFAULT 'en', room_pass TEXT NOT NULL DEFAULT '', turn_time INTEGER NOT NULL DEFAULT 60, -- seconds + turn_seconds_left INTEGER NOT NULL DEFAULT 0, created_at TIMESTAMP NOT NULL DEFAULT CURRENT_TIMESTAMP, FOREIGN KEY (room_id) REFERENCES rooms(id) ON DELETE CASCADE ); diff --git a/models/main.go b/models/main.go index d31be32..9e0a41e 100644 --- a/models/main.go +++ b/models/main.go @@ -390,7 +390,7 @@ type GameSettings struct { RoomID string `db:"room_id"` Language string `json:"language" example:"en" form:"language" db:"language"` RoomPass string `json:"room_pass" db:"room_pass"` - TurnSecondsLeft uint32 `db:"-"` + TurnSecondsLeft uint32 `db:"turn_seconds_left"` RoundTime uint32 `json:"round_time" db:"turn_time"` CreatedAt time.Time `db:"created_at"` } diff --git a/repos/actions_test.go b/repos/actions_test.go index 13fe4d0..28d4fc6 100644 --- a/repos/actions_test.go +++ b/repos/actions_test.go @@ -50,9 +50,10 @@ func TestActionsRepo_CreateAction(t *testing.T) { WordColor: "red", Number: "3", CreatedAt: time.Now(), + RoomID: roomID, } - err := repo.CreateAction(context.Background(), roomID, action) + err := repo.CreateAction(context.Background(), action) assert.NoError(t, err) var retrievedAction models.Action @@ -75,6 +76,7 @@ func TestActionsRepo_ListActions(t *testing.T) { Word: "apple", WordColor: "red", Number: "3", + RoomID: roomID, CreatedAt: time.Now().Add(-2 * time.Second), } action2 := &models.Action{ @@ -84,6 +86,7 @@ func TestActionsRepo_ListActions(t *testing.T) { Word: "banana", WordColor: "blue", Number: "0", + RoomID: roomID, CreatedAt: time.Now().Add(-1 * time.Second), } diff --git a/repos/main.go b/repos/main.go index 6cd19bf..399da79 100644 --- a/repos/main.go +++ b/repos/main.go @@ -17,6 +17,7 @@ type AllRepos interface { PlayersRepo SessionsRepo WordCardsRepo + SettingsRepo InitTx(ctx context.Context) (context.Context, *sqlx.Tx, error) } @@ -32,6 +33,11 @@ func NewRepoProvider(pathToDB string) *RepoProvider { slog.Error("Unable to connect to database", "error", err) os.Exit(1) } + _, err = db.Exec("PRAGMA foreign_keys = ON;") + if err != nil { + slog.Error("Unable to enable foreign keys", "error", err) + os.Exit(1) + } slog.Info("Successfully connected to database") rp := &RepoProvider{ DB: db, diff --git a/repos/rooms.go b/repos/rooms.go index 838da24..f1fa7c0 100644 --- a/repos/rooms.go +++ b/repos/rooms.go @@ -60,10 +60,6 @@ func (p *RepoProvider) RoomDeleteByID(ctx context.Context, id string) error { func (p *RepoProvider) RoomUpdate(ctx context.Context, r *models.Room) error { db := getDB(ctx, p.DB) _, err := 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) - if err != nil { - return err - } - _, err = db.ExecContext(ctx, `UPDATE settings SET language = ?, room_pass = ?, turn_time = ? WHERE room_id = ?`, r.Settings.Language, r.Settings.RoomPass, r.Settings.RoundTime, r.ID) return err } diff --git a/repos/settings.go b/repos/settings.go new file mode 100644 index 0000000..2249ce0 --- /dev/null +++ b/repos/settings.go @@ -0,0 +1,35 @@ +package repos + +import ( + "context" + "gralias/models" + + "github.com/jmoiron/sqlx" +) + +type SettingsRepo interface { + SettingsGetByRoomID(ctx context.Context, roomID string) (*models.GameSettings, error) + SettingsUpdate(ctx context.Context, settings *models.GameSettings) error + SettingsDeleteByRoomID(ctx context.Context, roomID string) error +} + +func (p *RepoProvider) SettingsGetByRoomID(ctx context.Context, roomID string) (*models.GameSettings, error) { + settings := &models.GameSettings{} + err := sqlx.GetContext(ctx, p.DB, settings, `SELECT * FROM settings WHERE room_id = ?`, roomID) + if err != nil { + return nil, err + } + return settings, nil +} + +func (p *RepoProvider) SettingsUpdate(ctx context.Context, s *models.GameSettings) error { + db := getDB(ctx, p.DB) + _, err := db.ExecContext(ctx, `UPDATE settings SET language = ?, room_pass = ?, turn_time = ?, turn_seconds_left = ? WHERE room_id = ?`, s.Language, s.RoomPass, s.RoundTime, s.TurnSecondsLeft, s.RoomID) + return err +} + +func (p *RepoProvider) SettingsDeleteByRoomID(ctx context.Context, roomID string) error { + db := getDB(ctx, p.DB) + _, err := db.ExecContext(ctx, `DELETE FROM settings WHERE room_id = ?`, roomID) + return err +}