refactor: deduplicate persistence, add upsert queries, throttle snake saves #4
@@ -4,8 +4,26 @@ import (
|
||||
"context"
|
||||
|
||||
"github.com/ryanhamamura/c4/db/repository"
|
||||
|
||||
"github.com/rs/zerolog/log"
|
||||
)
|
||||
|
||||
func (gi *GameInstance) save() error {
|
||||
err := saveGame(gi.queries, gi.game)
|
||||
if err != nil {
|
||||
log.Error().Err(err).Str("game_id", gi.game.ID).Msg("failed to save game")
|
||||
}
|
||||
return err
|
||||
}
|
||||
|
||||
func (gi *GameInstance) savePlayer(player *Player, slot int) error {
|
||||
err := saveGamePlayer(gi.queries, gi.game.ID, player, slot)
|
||||
if err != nil {
|
||||
log.Error().Err(err).Str("game_id", gi.game.ID).Int("slot", slot).Msg("failed to save game player")
|
||||
}
|
||||
return err
|
||||
}
|
||||
|
||||
// saveGame persists the game state via upsert.
|
||||
func saveGame(queries *repository.Queries, g *Game) error {
|
||||
var winnerUserID *string
|
||||
|
||||
@@ -49,7 +49,7 @@ func (gs *GameStore) Create() *GameInstance {
|
||||
gs.gamesMu.Unlock()
|
||||
|
||||
if gs.queries != nil {
|
||||
saveGame(gs.queries, gi.game) //nolint:errcheck
|
||||
gi.save() //nolint:errcheck
|
||||
}
|
||||
|
||||
return gi
|
||||
@@ -152,8 +152,8 @@ func (gi *GameInstance) Join(ps *PlayerSession) bool {
|
||||
}
|
||||
|
||||
if gi.queries != nil {
|
||||
saveGamePlayer(gi.queries, gi.game.ID, ps.Player, slot) //nolint:errcheck
|
||||
saveGame(gi.queries, gi.game) //nolint:errcheck
|
||||
gi.savePlayer(ps.Player, slot) //nolint:errcheck
|
||||
gi.save() //nolint:errcheck
|
||||
}
|
||||
|
||||
gi.notify()
|
||||
@@ -190,7 +190,7 @@ func (gi *GameInstance) CreateRematch(gs *GameStore) *GameInstance {
|
||||
gi.game.RematchGameID = &newID
|
||||
|
||||
if gi.queries != nil {
|
||||
if err := saveGame(gi.queries, gi.game); err != nil {
|
||||
if err := gi.save(); err != nil {
|
||||
gs.Delete(newID) //nolint:errcheck
|
||||
gi.game.RematchGameID = nil
|
||||
return nil
|
||||
@@ -224,7 +224,7 @@ func (gi *GameInstance) DropPiece(col int, playerColor int) bool {
|
||||
}
|
||||
|
||||
if gi.queries != nil {
|
||||
saveGame(gi.queries, gi.game) //nolint:errcheck
|
||||
gi.save() //nolint:errcheck
|
||||
}
|
||||
|
||||
gi.notify()
|
||||
|
||||
@@ -62,7 +62,7 @@ func (si *SnakeGameInstance) countdownPhase() {
|
||||
si.game.Status = StatusInProgress
|
||||
|
||||
if si.queries != nil {
|
||||
saveSnakeGame(si.queries, si.game) //nolint:errcheck
|
||||
si.save() //nolint:errcheck
|
||||
}
|
||||
si.gameMu.Unlock()
|
||||
si.notify()
|
||||
@@ -123,7 +123,7 @@ func (si *SnakeGameInstance) gamePhase() {
|
||||
if time.Since(lastInput) > inactivityLimit {
|
||||
si.game.Status = StatusFinished
|
||||
if si.queries != nil {
|
||||
saveSnakeGame(si.queries, si.game) //nolint:errcheck
|
||||
si.save() //nolint:errcheck
|
||||
}
|
||||
si.gameMu.Unlock()
|
||||
si.notify()
|
||||
@@ -193,7 +193,7 @@ func (si *SnakeGameInstance) gamePhase() {
|
||||
|
||||
// Throttle DB saves: persist on game over or every 2 seconds
|
||||
if si.queries != nil && (gameOver || time.Since(lastSave) >= 2*time.Second) {
|
||||
saveSnakeGame(si.queries, si.game) //nolint:errcheck
|
||||
si.save() //nolint:errcheck
|
||||
lastSave = time.Now()
|
||||
}
|
||||
|
||||
|
||||
@@ -4,8 +4,26 @@ import (
|
||||
"context"
|
||||
|
||||
"github.com/ryanhamamura/c4/db/repository"
|
||||
|
||||
"github.com/rs/zerolog/log"
|
||||
)
|
||||
|
||||
func (si *SnakeGameInstance) save() error {
|
||||
err := saveSnakeGame(si.queries, si.game)
|
||||
if err != nil {
|
||||
log.Error().Err(err).Str("game_id", si.game.ID).Msg("failed to save snake game")
|
||||
}
|
||||
return err
|
||||
}
|
||||
|
||||
func (si *SnakeGameInstance) savePlayer(player *Player) error {
|
||||
err := saveSnakePlayer(si.queries, si.game.ID, player)
|
||||
if err != nil {
|
||||
log.Error().Err(err).Str("game_id", si.game.ID).Msg("failed to save snake player")
|
||||
}
|
||||
return err
|
||||
}
|
||||
|
||||
// saveSnakeGame persists the snake game state via upsert.
|
||||
func saveSnakeGame(queries *repository.Queries, sg *SnakeGame) error {
|
||||
boardJSON := "{}"
|
||||
|
||||
@@ -62,7 +62,7 @@ func (ss *SnakeStore) Create(width, height int, mode GameMode, speed int) *Snake
|
||||
ss.gamesMu.Unlock()
|
||||
|
||||
if ss.queries != nil {
|
||||
saveSnakeGame(ss.queries, sg) //nolint:errcheck
|
||||
si.save() //nolint:errcheck
|
||||
}
|
||||
|
||||
return si
|
||||
@@ -206,8 +206,8 @@ func (si *SnakeGameInstance) Join(player *Player) bool {
|
||||
si.game.Players[slot] = player
|
||||
|
||||
if si.queries != nil {
|
||||
saveSnakePlayer(si.queries, si.game.ID, player) //nolint:errcheck
|
||||
saveSnakeGame(si.queries, si.game) //nolint:errcheck
|
||||
si.savePlayer(player) //nolint:errcheck
|
||||
si.save() //nolint:errcheck
|
||||
}
|
||||
|
||||
si.notify()
|
||||
@@ -293,7 +293,7 @@ func (si *SnakeGameInstance) CreateRematch() *SnakeGameInstance {
|
||||
si.game.RematchGameID = &newID
|
||||
|
||||
if si.queries != nil {
|
||||
saveSnakeGame(si.queries, si.game) //nolint:errcheck
|
||||
si.save() //nolint:errcheck
|
||||
}
|
||||
si.gameMu.Unlock()
|
||||
|
||||
|
||||
Reference in New Issue
Block a user