Rename game/ -> connect4/ to avoid c4/game stutter. Drop redundant
Game prefix from exported types (GameStore -> Store, GameInstance ->
Instance, GameStatus -> Status). Rename NATS subjects from game.{id}
to connect4.{id}. URL routes unchanged.
127 lines
2.9 KiB
Go
127 lines
2.9 KiB
Go
package connect4
|
|
|
|
import (
|
|
"context"
|
|
|
|
"github.com/ryanhamamura/c4/db/repository"
|
|
"github.com/ryanhamamura/c4/player"
|
|
|
|
"github.com/rs/zerolog/log"
|
|
)
|
|
|
|
func (gi *Instance) 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 *Instance) savePlayer(p *Player, slot int) error {
|
|
err := saveGamePlayer(gi.queries, gi.game.ID, p, 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
|
|
if g.Winner != nil && g.Winner.UserID != nil {
|
|
winnerUserID = g.Winner.UserID
|
|
}
|
|
|
|
var winningCells *string
|
|
if wc := g.WinningCellsToJSON(); wc != "" {
|
|
winningCells = &wc
|
|
}
|
|
|
|
return queries.UpsertGame(context.Background(), repository.UpsertGameParams{
|
|
ID: g.ID,
|
|
Board: g.BoardToJSON(),
|
|
CurrentTurn: int64(g.CurrentTurn),
|
|
Status: int64(g.Status),
|
|
WinnerUserID: winnerUserID,
|
|
WinningCells: winningCells,
|
|
RematchGameID: g.RematchGameID,
|
|
})
|
|
}
|
|
|
|
func saveGamePlayer(queries *repository.Queries, gameID string, p *Player, slot int) error {
|
|
var userID, guestPlayerID *string
|
|
if p.UserID != nil {
|
|
userID = p.UserID
|
|
} else {
|
|
id := string(p.ID)
|
|
guestPlayerID = &id
|
|
}
|
|
|
|
return queries.CreateGamePlayer(context.Background(), repository.CreateGamePlayerParams{
|
|
GameID: gameID,
|
|
UserID: userID,
|
|
GuestPlayerID: guestPlayerID,
|
|
Nickname: p.Nickname,
|
|
Color: int64(p.Color),
|
|
Slot: int64(slot),
|
|
})
|
|
}
|
|
|
|
func loadGame(queries *repository.Queries, id string) (*Game, error) {
|
|
row, err := queries.GetGame(context.Background(), id)
|
|
if err != nil {
|
|
return nil, err
|
|
}
|
|
return gameFromRow(row)
|
|
}
|
|
|
|
func loadGamePlayers(queries *repository.Queries, id string) ([]*Player, error) {
|
|
rows, err := queries.GetGamePlayers(context.Background(), id)
|
|
if err != nil {
|
|
return nil, err
|
|
}
|
|
return playersFromRows(rows), nil
|
|
}
|
|
|
|
func gameFromRow(row *repository.Game) (*Game, error) {
|
|
g := &Game{
|
|
ID: row.ID,
|
|
CurrentTurn: int(row.CurrentTurn),
|
|
Status: Status(row.Status),
|
|
}
|
|
|
|
if err := g.BoardFromJSON(row.Board); err != nil {
|
|
return nil, err
|
|
}
|
|
|
|
if row.WinningCells != nil {
|
|
_ = g.WinningCellsFromJSON(*row.WinningCells)
|
|
}
|
|
|
|
if row.RematchGameID != nil {
|
|
g.RematchGameID = row.RematchGameID
|
|
}
|
|
|
|
return g, nil
|
|
}
|
|
|
|
func playersFromRows(rows []*repository.GamePlayer) []*Player {
|
|
players := make([]*Player, 0, len(rows))
|
|
for _, row := range rows {
|
|
p := &Player{
|
|
Nickname: row.Nickname,
|
|
Color: int(row.Color),
|
|
}
|
|
|
|
if row.UserID != nil {
|
|
p.UserID = row.UserID
|
|
p.ID = player.ID(*row.UserID)
|
|
} else if row.GuestPlayerID != nil {
|
|
p.ID = player.ID(*row.GuestPlayerID)
|
|
}
|
|
|
|
players = append(players, p)
|
|
}
|
|
return players
|
|
}
|