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