refactor: rename game package to connect4, drop Game prefix from types
All checks were successful
CI / Deploy / test (pull_request) Successful in 16s
CI / Deploy / lint (pull_request) Successful in 25s
CI / Deploy / deploy (pull_request) Has been skipped

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.
This commit is contained in:
Ryan Hamamura
2026-03-02 20:31:00 -10:00
parent f71acfc73e
commit 38eb9ee398
14 changed files with 125 additions and 127 deletions

View File

@@ -1,5 +1,5 @@
// Package game implements Connect 4 game logic, state management, and persistence.
package game
// Package connect4 implements Connect 4 game logic, state management, and persistence.
package connect4
// DropPiece attempts to drop a piece in the given column.
// Returns (row placed, success).

View File

@@ -1,4 +1,4 @@
package game
package connect4
import (
"context"
@@ -9,7 +9,7 @@ import (
"github.com/rs/zerolog/log"
)
func (gi *GameInstance) save() error {
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")
@@ -17,8 +17,8 @@ func (gi *GameInstance) save() error {
return err
}
func (gi *GameInstance) savePlayer(player *Player, slot int) error {
err := saveGamePlayer(gi.queries, gi.game.ID, player, slot)
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")
}
@@ -48,12 +48,12 @@ func saveGame(queries *repository.Queries, g *Game) error {
})
}
func saveGamePlayer(queries *repository.Queries, gameID string, player *Player, slot int) error {
func saveGamePlayer(queries *repository.Queries, gameID string, p *Player, slot int) error {
var userID, guestPlayerID *string
if player.UserID != nil {
userID = player.UserID
if p.UserID != nil {
userID = p.UserID
} else {
id := string(player.ID)
id := string(p.ID)
guestPlayerID = &id
}
@@ -61,8 +61,8 @@ func saveGamePlayer(queries *repository.Queries, gameID string, player *Player,
GameID: gameID,
UserID: userID,
GuestPlayerID: guestPlayerID,
Nickname: player.Nickname,
Color: int64(player.Color),
Nickname: p.Nickname,
Color: int64(p.Color),
Slot: int64(slot),
})
}
@@ -83,13 +83,11 @@ func loadGamePlayers(queries *repository.Queries, id string) ([]*Player, error)
return playersFromRows(rows), nil
}
// Domain ↔ DB mapping helpers.
func gameFromRow(row *repository.Game) (*Game, error) {
g := &Game{
ID: row.ID,
CurrentTurn: int(row.CurrentTurn),
Status: GameStatus(row.Status),
Status: Status(row.Status),
}
if err := g.BoardFromJSON(row.Board); err != nil {

View File

@@ -1,4 +1,4 @@
package game
package connect4
import (
"context"
@@ -12,67 +12,67 @@ type PlayerSession struct {
Player *Player
}
type GameStore struct {
games map[string]*GameInstance
type Store struct {
games map[string]*Instance
gamesMu sync.RWMutex
queries *repository.Queries
notifyFunc func(gameID string)
}
func NewGameStore(queries *repository.Queries) *GameStore {
return &GameStore{
games: make(map[string]*GameInstance),
func NewStore(queries *repository.Queries) *Store {
return &Store{
games: make(map[string]*Instance),
queries: queries,
}
}
func (gs *GameStore) SetNotifyFunc(f func(gameID string)) {
gs.notifyFunc = f
func (s *Store) SetNotifyFunc(f func(gameID string)) {
s.notifyFunc = f
}
func (gs *GameStore) makeNotify(gameID string) func() {
func (s *Store) makeNotify(gameID string) func() {
return func() {
if gs.notifyFunc != nil {
gs.notifyFunc(gameID)
if s.notifyFunc != nil {
s.notifyFunc(gameID)
}
}
}
func (gs *GameStore) Create() *GameInstance {
func (s *Store) Create() *Instance {
id := player.GenerateID(4)
gi := NewGameInstance(id)
gi.queries = gs.queries
gi.notify = gs.makeNotify(id)
gs.gamesMu.Lock()
gs.games[id] = gi
gs.gamesMu.Unlock()
gi := NewInstance(id)
gi.queries = s.queries
gi.notify = s.makeNotify(id)
s.gamesMu.Lock()
s.games[id] = gi
s.gamesMu.Unlock()
if gs.queries != nil {
if s.queries != nil {
gi.save() //nolint:errcheck
}
return gi
}
func (gs *GameStore) Get(id string) (*GameInstance, bool) {
gs.gamesMu.RLock()
gi, ok := gs.games[id]
gs.gamesMu.RUnlock()
func (s *Store) Get(id string) (*Instance, bool) {
s.gamesMu.RLock()
gi, ok := s.games[id]
s.gamesMu.RUnlock()
if ok {
return gi, true
}
if gs.queries == nil {
if s.queries == nil {
return nil, false
}
g, err := loadGame(gs.queries, id)
g, err := loadGame(s.queries, id)
if err != nil || g == nil {
return nil, false
}
players, _ := loadGamePlayers(gs.queries, id)
players, _ := loadGamePlayers(s.queries, id)
for _, p := range players {
switch p.Color {
case 1:
@@ -82,51 +82,51 @@ func (gs *GameStore) Get(id string) (*GameInstance, bool) {
}
}
gi = &GameInstance{
gi = &Instance{
game: g,
queries: gs.queries,
notify: gs.makeNotify(id),
queries: s.queries,
notify: s.makeNotify(id),
}
gs.gamesMu.Lock()
gs.games[id] = gi
gs.gamesMu.Unlock()
s.gamesMu.Lock()
s.games[id] = gi
s.gamesMu.Unlock()
return gi, true
}
func (gs *GameStore) Delete(id string) error {
gs.gamesMu.Lock()
delete(gs.games, id)
gs.gamesMu.Unlock()
func (s *Store) Delete(id string) error {
s.gamesMu.Lock()
delete(s.games, id)
s.gamesMu.Unlock()
if gs.queries != nil {
return gs.queries.DeleteGame(context.Background(), id)
if s.queries != nil {
return s.queries.DeleteGame(context.Background(), id)
}
return nil
}
type GameInstance struct {
type Instance struct {
game *Game
gameMu sync.RWMutex
notify func()
queries *repository.Queries
}
func NewGameInstance(id string) *GameInstance {
return &GameInstance{
func NewInstance(id string) *Instance {
return &Instance{
game: NewGame(id),
notify: func() {},
}
}
func (gi *GameInstance) ID() string {
func (gi *Instance) ID() string {
gi.gameMu.RLock()
defer gi.gameMu.RUnlock()
return gi.game.ID
}
func (gi *GameInstance) Join(ps *PlayerSession) bool {
func (gi *Instance) Join(ps *PlayerSession) bool {
gi.gameMu.Lock()
defer gi.gameMu.Unlock()
@@ -153,13 +153,13 @@ func (gi *GameInstance) Join(ps *PlayerSession) bool {
return true
}
func (gi *GameInstance) GetGame() *Game {
func (gi *Instance) GetGame() *Game {
gi.gameMu.RLock()
defer gi.gameMu.RUnlock()
return gi.game
}
func (gi *GameInstance) GetPlayerColor(pid player.ID) int {
func (gi *Instance) GetPlayerColor(pid player.ID) int {
gi.gameMu.RLock()
defer gi.gameMu.RUnlock()
for _, p := range gi.game.Players {
@@ -170,7 +170,7 @@ func (gi *GameInstance) GetPlayerColor(pid player.ID) int {
return 0
}
func (gi *GameInstance) CreateRematch(gs *GameStore) *GameInstance {
func (gi *Instance) CreateRematch(s *Store) *Instance {
gi.gameMu.Lock()
defer gi.gameMu.Unlock()
@@ -178,13 +178,13 @@ func (gi *GameInstance) CreateRematch(gs *GameStore) *GameInstance {
return nil
}
newGI := gs.Create()
newGI := s.Create()
newID := newGI.ID()
gi.game.RematchGameID = &newID
if gi.queries != nil {
if err := gi.save(); err != nil {
gs.Delete(newID) //nolint:errcheck
s.Delete(newID) //nolint:errcheck
gi.game.RematchGameID = nil
return nil
}
@@ -194,7 +194,7 @@ func (gi *GameInstance) CreateRematch(gs *GameStore) *GameInstance {
return newGI
}
func (gi *GameInstance) DropPiece(col int, playerColor int) bool {
func (gi *Instance) DropPiece(col int, playerColor int) bool {
gi.gameMu.Lock()
defer gi.gameMu.Unlock()

View File

@@ -1,4 +1,4 @@
package game
package connect4
import (
"encoding/json"
@@ -13,10 +13,10 @@ type Player struct {
Color int // 1 = Red, 2 = Yellow
}
type GameStatus int
type Status int
const (
StatusWaitingForPlayer GameStatus = iota
StatusWaitingForPlayer Status = iota
StatusInProgress
StatusWon
StatusDraw
@@ -27,7 +27,7 @@ type Game struct {
Board [6][7]int // 6 rows, 7 columns; 0=empty, 1=red, 2=yellow
Players [2]*Player // Index 0 = creator (Red), Index 1 = joiner (Yellow)
CurrentTurn int // 1 or 2 (matches player color)
Status GameStatus
Status Status
Winner *Player
WinningCells [][2]int // Coordinates of winning 4 cells for highlighting
RematchGameID *string // ID of the rematch game, if one was created

View File

@@ -3,11 +3,11 @@ package components
import (
"fmt"
"github.com/ryanhamamura/c4/game"
"github.com/ryanhamamura/c4/connect4"
"github.com/starfederation/datastar-go/datastar"
)
templ Board(g *game.Game, myColor int) {
templ Board(g *connect4.Game, myColor int) {
<div id="c4-board" class="board">
for col := 0; col < 7; col++ {
@column(g, col, myColor)
@@ -15,8 +15,8 @@ templ Board(g *game.Game, myColor int) {
</div>
}
templ column(g *game.Game, colIdx int, myColor int) {
if g.Status == game.StatusInProgress && myColor == g.CurrentTurn {
templ column(g *connect4.Game, colIdx int, myColor int) {
if g.Status == connect4.StatusInProgress && myColor == g.CurrentTurn {
<div
class="column clickable"
data-on:click={ datastar.PostSSE("/games/%s/drop?col=%d", g.ID, colIdx) }
@@ -34,14 +34,14 @@ templ column(g *game.Game, colIdx int, myColor int) {
}
}
templ cell(g *game.Game, row int, col int) {
templ cell(g *connect4.Game, row int, col int) {
<div class={ cellClass(g, row, col) }></div>
}
func cellClass(g *game.Game, row, col int) string {
func cellClass(g *connect4.Game, row, col int) string {
color := g.Board[row][col]
activeTurn := 0
if g.Status == game.StatusInProgress {
if g.Status == connect4.StatusInProgress {
activeTurn = g.CurrentTurn
}

View File

@@ -2,11 +2,11 @@ package components
import (
"github.com/ryanhamamura/c4/config"
"github.com/ryanhamamura/c4/game"
"github.com/ryanhamamura/c4/connect4"
"github.com/starfederation/datastar-go/datastar"
)
templ StatusBanner(g *game.Game, myColor int) {
templ StatusBanner(g *connect4.Game, myColor int) {
<div id="c4-status" class={ statusClass(g, myColor) }>
{ statusMessage(g, myColor) }
if g.IsFinished() {
@@ -30,7 +30,7 @@ templ StatusBanner(g *game.Game, myColor int) {
</div>
}
templ PlayerInfo(g *game.Game, myColor int) {
templ PlayerInfo(g *connect4.Game, myColor int) {
<div id="c4-players" class="flex gap-8 mb-2">
for _, info := range playerInfoPairs(g, myColor) {
<div class="flex items-center gap-2">
@@ -61,36 +61,36 @@ script copyToClipboard(url string) {
navigator.clipboard.writeText(url)
}
func statusClass(g *game.Game, myColor int) string {
func statusClass(g *connect4.Game, myColor int) string {
switch g.Status {
case game.StatusWaitingForPlayer:
case connect4.StatusWaitingForPlayer:
return "alert bg-base-200 text-xl font-bold"
case game.StatusInProgress:
case connect4.StatusInProgress:
if g.CurrentTurn == myColor {
return "alert alert-success text-xl font-bold"
}
return "alert bg-base-200 text-xl font-bold"
case game.StatusWon:
case connect4.StatusWon:
if g.Winner != nil && g.Winner.Color == myColor {
return "alert alert-success text-xl font-bold"
}
return "alert alert-error text-xl font-bold"
case game.StatusDraw:
case connect4.StatusDraw:
return "alert alert-warning text-xl font-bold"
}
return "alert bg-base-200 text-xl font-bold"
}
func statusMessage(g *game.Game, myColor int) string {
func statusMessage(g *connect4.Game, myColor int) string {
switch g.Status {
case game.StatusWaitingForPlayer:
case connect4.StatusWaitingForPlayer:
return "Waiting for opponent..."
case game.StatusInProgress:
case connect4.StatusInProgress:
if g.CurrentTurn == myColor {
return "Your turn!"
}
return opponentName(g, myColor) + "'s turn"
case game.StatusWon:
case connect4.StatusWon:
if g.Winner != nil && g.Winner.Color == myColor {
return "You win!"
}
@@ -98,13 +98,13 @@ func statusMessage(g *game.Game, myColor int) string {
return g.Winner.Nickname + " wins!"
}
return "Game over"
case game.StatusDraw:
case connect4.StatusDraw:
return "It's a draw!"
}
return ""
}
func opponentName(g *game.Game, myColor int) string {
func opponentName(g *connect4.Game, myColor int) string {
for _, p := range g.Players {
if p != nil && p.Color != myColor {
return p.Nickname
@@ -118,7 +118,7 @@ type playerInfoData struct {
Label string
}
func playerInfoPairs(g *game.Game, myColor int) []playerInfoData {
func playerInfoPairs(g *connect4.Game, myColor int) []playerInfoData {
var result []playerInfoData
var myName, oppName string

View File

@@ -13,10 +13,10 @@ import (
"github.com/ryanhamamura/c4/chat"
chatcomponents "github.com/ryanhamamura/c4/chat/components"
"github.com/ryanhamamura/c4/connect4"
"github.com/ryanhamamura/c4/db/repository"
"github.com/ryanhamamura/c4/features/c4game/components"
"github.com/ryanhamamura/c4/features/c4game/pages"
"github.com/ryanhamamura/c4/game"
"github.com/ryanhamamura/c4/sessions"
)
@@ -41,7 +41,7 @@ func c4ChatConfig(gameID string) chatcomponents.Config {
}
}
func HandleGamePage(store *game.GameStore, sm *scs.SessionManager, queries *repository.Queries) http.HandlerFunc {
func HandleGamePage(store *connect4.Store, sm *scs.SessionManager, queries *repository.Queries) http.HandlerFunc {
return func(w http.ResponseWriter, r *http.Request) {
gameID := chi.URLParam(r, "id")
@@ -57,14 +57,14 @@ func HandleGamePage(store *game.GameStore, sm *scs.SessionManager, queries *repo
// Auto-join if player has a nickname but isn't in the game yet
if nickname != "" && gi.GetPlayerColor(playerID) == 0 {
p := &game.Player{
p := &connect4.Player{
ID: playerID,
Nickname: nickname,
}
if userID != "" {
p.UserID = &userID
}
gi.Join(&game.PlayerSession{Player: p})
gi.Join(&connect4.PlayerSession{Player: p})
}
myColor := gi.GetPlayerColor(playerID)
@@ -93,7 +93,7 @@ func HandleGamePage(store *game.GameStore, sm *scs.SessionManager, queries *repo
}
}
func HandleGameEvents(store *game.GameStore, nc *nats.Conn, sm *scs.SessionManager, queries *repository.Queries) http.HandlerFunc {
func HandleGameEvents(store *connect4.Store, nc *nats.Conn, sm *scs.SessionManager, queries *repository.Queries) http.HandlerFunc {
return func(w http.ResponseWriter, r *http.Request) {
gameID := chi.URLParam(r, "id")
@@ -111,14 +111,14 @@ func HandleGameEvents(store *game.GameStore, nc *nats.Conn, sm *scs.SessionManag
))
chatCfg := c4ChatConfig(gameID)
room := chat.NewRoom(nc, "game.chat."+gameID, chat.LoadMessages(queries, gameID))
room := chat.NewRoom(nc, "connect4.chat."+gameID, chat.LoadMessages(queries, gameID))
// Send initial render
sendGameComponents(sse, gi, myColor, room, chatCfg)
// Subscribe to game state updates
gameCh := make(chan *nats.Msg, 64)
gameSub, err := nc.ChanSubscribe("game."+gameID, gameCh)
gameSub, err := nc.ChanSubscribe("connect4."+gameID, gameCh)
if err != nil {
return
}
@@ -152,7 +152,7 @@ func HandleGameEvents(store *game.GameStore, nc *nats.Conn, sm *scs.SessionManag
}
}
func HandleDropPiece(store *game.GameStore, sm *scs.SessionManager) http.HandlerFunc {
func HandleDropPiece(store *connect4.Store, sm *scs.SessionManager) http.HandlerFunc {
return func(w http.ResponseWriter, r *http.Request) {
gameID := chi.URLParam(r, "id")
@@ -181,7 +181,7 @@ func HandleDropPiece(store *game.GameStore, sm *scs.SessionManager) http.Handler
}
}
func HandleSendChat(store *game.GameStore, nc *nats.Conn, sm *scs.SessionManager, queries *repository.Queries) http.HandlerFunc {
func HandleSendChat(store *connect4.Store, nc *nats.Conn, sm *scs.SessionManager, queries *repository.Queries) http.HandlerFunc {
return func(w http.ResponseWriter, r *http.Request) {
gameID := chi.URLParam(r, "id")
@@ -230,7 +230,7 @@ func HandleSendChat(store *game.GameStore, nc *nats.Conn, sm *scs.SessionManager
}
chat.SaveMessage(queries, gameID, msg)
room := chat.NewRoom(nc, "game.chat."+gameID, nil)
room := chat.NewRoom(nc, "connect4.chat."+gameID, nil)
room.Send(msg)
sse := datastar.NewSSE(w, r)
@@ -238,7 +238,7 @@ func HandleSendChat(store *game.GameStore, nc *nats.Conn, sm *scs.SessionManager
}
}
func HandleSetNickname(store *game.GameStore, sm *scs.SessionManager) http.HandlerFunc {
func HandleSetNickname(store *connect4.Store, sm *scs.SessionManager) http.HandlerFunc {
return func(w http.ResponseWriter, r *http.Request) {
gameID := chi.URLParam(r, "id")
@@ -269,14 +269,14 @@ func HandleSetNickname(store *game.GameStore, sm *scs.SessionManager) http.Handl
userID := sessions.GetUserID(sm, r)
if gi.GetPlayerColor(playerID) == 0 {
p := &game.Player{
p := &connect4.Player{
ID: playerID,
Nickname: signals.Nickname,
}
if userID != "" {
p.UserID = &userID
}
gi.Join(&game.PlayerSession{Player: p})
gi.Join(&connect4.PlayerSession{Player: p})
}
sse := datastar.NewSSE(w, r)
@@ -284,7 +284,7 @@ func HandleSetNickname(store *game.GameStore, sm *scs.SessionManager) http.Handl
}
}
func HandleRematch(store *game.GameStore, sm *scs.SessionManager) http.HandlerFunc {
func HandleRematch(store *connect4.Store, sm *scs.SessionManager) http.HandlerFunc {
return func(w http.ResponseWriter, r *http.Request) {
gameID := chi.URLParam(r, "id")
@@ -304,7 +304,7 @@ func HandleRematch(store *game.GameStore, sm *scs.SessionManager) http.HandlerFu
}
// sendGameComponents patches all game-related SSE components.
func sendGameComponents(sse *datastar.ServerSentEventGenerator, gi *game.GameInstance, myColor int, room *chat.Room, chatCfg chatcomponents.Config) {
func sendGameComponents(sse *datastar.ServerSentEventGenerator, gi *connect4.Instance, myColor int, room *chat.Room, chatCfg chatcomponents.Config) {
g := gi.GetGame()
sse.PatchElementTempl(components.Board(g, myColor), datastar.WithSelectorID("c4-board")) //nolint:errcheck

View File

@@ -3,14 +3,14 @@ package pages
import (
"github.com/ryanhamamura/c4/chat"
chatcomponents "github.com/ryanhamamura/c4/chat/components"
"github.com/ryanhamamura/c4/connect4"
"github.com/ryanhamamura/c4/features/c4game/components"
sharedcomponents "github.com/ryanhamamura/c4/features/common/components"
"github.com/ryanhamamura/c4/features/common/layouts"
"github.com/ryanhamamura/c4/game"
"github.com/starfederation/datastar-go/datastar"
)
templ GamePage(g *game.Game, myColor int, messages []chat.Message, chatCfg chatcomponents.Config) {
templ GamePage(g *connect4.Game, myColor int, messages []chat.Message, chatCfg chatcomponents.Config) {
@layouts.Base("Connect 4") {
<main
class="flex flex-col items-center gap-4 p-4"
@@ -25,7 +25,7 @@ templ GamePage(g *game.Game, myColor int, messages []chat.Message, chatCfg chatc
@components.Board(g, myColor)
@chatcomponents.Chat(messages, chatCfg)
</div>
if g.Status == game.StatusWaitingForPlayer {
if g.Status == connect4.StatusWaitingForPlayer {
@components.InviteLink(g.ID)
}
</main>

View File

@@ -6,13 +6,13 @@ import (
"github.com/go-chi/chi/v5"
"github.com/nats-io/nats.go"
"github.com/ryanhamamura/c4/connect4"
"github.com/ryanhamamura/c4/db/repository"
"github.com/ryanhamamura/c4/game"
)
func SetupRoutes(
router chi.Router,
store *game.GameStore,
store *connect4.Store,
nc *nats.Conn,
sessions *scs.SessionManager,
queries *repository.Queries,

View File

@@ -4,7 +4,7 @@ import (
"fmt"
"time"
"github.com/ryanhamamura/c4/game"
"github.com/ryanhamamura/c4/connect4"
"github.com/starfederation/datastar-go/datastar"
)
@@ -46,10 +46,10 @@ templ gameListEntry(g GameListItem) {
}
func statusText(g GameListItem) string {
switch game.GameStatus(g.Status) {
case game.StatusWaitingForPlayer:
switch connect4.Status(g.Status) {
case connect4.StatusWaitingForPlayer:
return "Waiting for opponent"
case game.StatusInProgress:
case connect4.StatusInProgress:
if g.IsMyTurn {
return "Your turn!"
}
@@ -59,10 +59,10 @@ func statusText(g GameListItem) string {
}
func statusClass(g GameListItem) string {
switch game.GameStatus(g.Status) {
case game.StatusWaitingForPlayer:
switch connect4.Status(g.Status) {
case connect4.StatusWaitingForPlayer:
return "text-sm opacity-60"
case game.StatusInProgress:
case connect4.StatusInProgress:
if g.IsMyTurn {
return "text-sm text-success font-bold"
}

View File

@@ -7,10 +7,10 @@ import (
"strconv"
"time"
"github.com/ryanhamamura/c4/connect4"
"github.com/ryanhamamura/c4/db/repository"
lobbycomponents "github.com/ryanhamamura/c4/features/lobby/components"
"github.com/ryanhamamura/c4/features/lobby/pages"
"github.com/ryanhamamura/c4/game"
"github.com/ryanhamamura/c4/snake"
"github.com/alexedwards/scs/v2"
@@ -80,7 +80,7 @@ func HandleLobbyPage(queries *repository.Queries, sessions *scs.SessionManager,
}
// HandleCreateGame reads the nickname signal, creates a connect4 game, and redirects via SSE.
func HandleCreateGame(store *game.GameStore, sessions *scs.SessionManager) http.HandlerFunc {
func HandleCreateGame(store *connect4.Store, sessions *scs.SessionManager) http.HandlerFunc {
return func(w http.ResponseWriter, r *http.Request) {
type Signals struct {
Nickname string `json:"nickname"`
@@ -104,7 +104,7 @@ func HandleCreateGame(store *game.GameStore, sessions *scs.SessionManager) http.
}
// HandleDeleteGame deletes a connect4 game and redirects to the lobby.
func HandleDeleteGame(store *game.GameStore, sessions *scs.SessionManager) http.HandlerFunc {
func HandleDeleteGame(store *connect4.Store, sessions *scs.SessionManager) http.HandlerFunc {
return func(w http.ResponseWriter, r *http.Request) {
gameID := chi.URLParam(r, "id")
if gameID == "" {

View File

@@ -2,8 +2,8 @@
package lobby
import (
"github.com/ryanhamamura/c4/connect4"
"github.com/ryanhamamura/c4/db/repository"
"github.com/ryanhamamura/c4/game"
"github.com/ryanhamamura/c4/snake"
"github.com/alexedwards/scs/v2"
@@ -14,7 +14,7 @@ func SetupRoutes(
router chi.Router,
queries *repository.Queries,
sessions *scs.SessionManager,
store *game.GameStore,
store *connect4.Store,
snakeStore *snake.SnakeStore,
) {
router.Get("/", HandleLobbyPage(queries, sessions, snakeStore))

View File

@@ -12,9 +12,9 @@ import (
"time"
"github.com/ryanhamamura/c4/config"
"github.com/ryanhamamura/c4/connect4"
"github.com/ryanhamamura/c4/db"
"github.com/ryanhamamura/c4/db/repository"
"github.com/ryanhamamura/c4/game"
"github.com/ryanhamamura/c4/logging"
appnats "github.com/ryanhamamura/c4/nats"
"github.com/ryanhamamura/c4/router"
@@ -71,9 +71,9 @@ func run(ctx context.Context) error {
defer cleanupNATS()
// Game stores
store := game.NewGameStore(queries)
store := connect4.NewStore(queries)
store.SetNotifyFunc(func(gameID string) {
nc.Publish("game."+gameID, nil) //nolint:errcheck // best-effort notification
nc.Publish("connect4."+gameID, nil) //nolint:errcheck // best-effort notification
})
snakeStore := snake.NewSnakeStore(queries)

View File

@@ -8,12 +8,12 @@ import (
"sync"
"github.com/ryanhamamura/c4/config"
"github.com/ryanhamamura/c4/connect4"
"github.com/ryanhamamura/c4/db/repository"
"github.com/ryanhamamura/c4/features/auth"
"github.com/ryanhamamura/c4/features/c4game"
"github.com/ryanhamamura/c4/features/lobby"
"github.com/ryanhamamura/c4/features/snakegame"
"github.com/ryanhamamura/c4/game"
"github.com/ryanhamamura/c4/snake"
"github.com/alexedwards/scs/v2"
@@ -27,7 +27,7 @@ func SetupRoutes(
queries *repository.Queries,
sessions *scs.SessionManager,
nc *nats.Conn,
store *game.GameStore,
store *connect4.Store,
snakeStore *snake.SnakeStore,
assets embed.FS,
) {