diff options
| author | nsfisis <nsfisis@gmail.com> | 2024-07-28 19:42:05 +0900 |
|---|---|---|
| committer | nsfisis <nsfisis@gmail.com> | 2024-07-28 19:52:31 +0900 |
| commit | 22ddf340f0b0c8d0cd04c34d9fa1481a1fbf422f (patch) | |
| tree | fab36f8dc1a2be23e331752b3e3d35e10d797ecf /backend | |
| parent | 7bd55ee264f7eefda6c1f71865a2c6287d7e20fa (diff) | |
| download | iosdc-japan-2024-albatross-22ddf340f0b0c8d0cd04c34d9fa1481a1fbf422f.tar.gz iosdc-japan-2024-albatross-22ddf340f0b0c8d0cd04c34d9fa1481a1fbf422f.tar.zst iosdc-japan-2024-albatross-22ddf340f0b0c8d0cd04c34d9fa1481a1fbf422f.zip | |
refactor(backend): move game-related code to game module
Diffstat (limited to 'backend')
| -rw-r--r-- | backend/game/game.go (renamed from backend/game.go) | 151 | ||||
| -rw-r--r-- | backend/game/http.go | 56 | ||||
| -rw-r--r-- | backend/game/message.go (renamed from backend/message.go) | 2 | ||||
| -rw-r--r-- | backend/game/ws.go | 46 | ||||
| -rw-r--r-- | backend/main.go | 131 |
5 files changed, 226 insertions, 160 deletions
diff --git a/backend/game.go b/backend/game/game.go index a8f688e..9e63a1e 100644 --- a/backend/game.go +++ b/backend/game/game.go @@ -1,15 +1,86 @@ -package main +package game import ( + "context" "log" - "net/http" "time" "github.com/gorilla/websocket" + + "github.com/nsfisis/iosdc-2024-albatross/backend/api" + "github.com/nsfisis/iosdc-2024-albatross/backend/db" +) + +type gameState = api.GameState + +const ( + gameStateClosed gameState = api.Closed + gameStateWaitingEntries gameState = api.WaitingEntries + gameStateWaitingStart gameState = api.WaitingStart + gameStatePrepare gameState = api.Prepare + gameStateStarting gameState = api.Starting + gameStateGaming gameState = api.Gaming + gameStateFinished gameState = api.Finished ) +type game struct { + gameID int + state string + displayName string + durationSeconds int + startedAt *time.Time + problem *problem +} + +type problem struct { + problemID int + title string + description string +} + +// func startGame(game *Game) { +// if gameHubs[game.GameID] != nil { +// return +// } +// gameHubs[game.GameID] = NewGameHub(game) +// go gameHubs[game.GameID].Run() +// } + +/* +func handleGolfPost(w http.ResponseWriter, r *http.Request) { + var yourTeam string + waitingGolfGames := []Game{} + err := db.Select(&waitingGolfGames, "SELECT * FROM games WHERE type = $1 AND state = $2 ORDER BY created_at", gameTypeGolf, gameStateWaiting) + if err != nil { + http.Error(w, "Error getting games", http.StatusInternalServerError) + return + } + if len(waitingGolfGames) == 0 { + _, err = db.Exec("INSERT INTO games (type, state) VALUES ($1, $2)", gameTypeGolf, gameStateWaiting) + if err != nil { + http.Error(w, "Error creating game", http.StatusInternalServerError) + return + } + waitingGolfGames = []Game{} + err = db.Select(&waitingGolfGames, "SELECT * FROM games WHERE type = $1 AND state = $2 ORDER BY created_at", gameTypeGolf, gameStateWaiting) + if err != nil { + http.Error(w, "Error getting games", http.StatusInternalServerError) + return + } + yourTeam = "a" + startGame(&waitingGolfGames[0]) + } else { + yourTeam = "b" + db.Exec("UPDATE games SET state = $1 WHERE game_id = $2", gameStateReady, waitingGolfGames[0].GameID) + } + waitingGame := waitingGolfGames[0] + + http.Redirect(w, r, fmt.Sprintf("/golf/%d/%s/", waitingGame.GameID, yourTeam), http.StatusSeeOther) +} +*/ + type GameHub struct { - game *Game + game *game clients map[*GameClient]bool receive chan *MessageWithClient register chan *GameClient @@ -21,7 +92,7 @@ type GameHub struct { finishTime time.Time } -func NewGameHub(game *Game) *GameHub { +func NewGameHub(game *game) *GameHub { return &GameHub{ game: game, clients: make(map[*GameClient]bool), @@ -181,23 +252,6 @@ func (h *GameHub) closeWatcher(watcher *GameWatcher) { close(watcher.send) } -const ( - writeWait = 10 * time.Second - pongWait = 60 * time.Second - pingPeriod = (pongWait * 9) / 10 - maxMessageSize = 512 -) - -var ( - newline = []byte{'\n'} - space = []byte{' '} -) - -var upgrader = websocket.Upgrader{ - ReadBufferSize: 1024, - WriteBufferSize: 1024, -} - type GameClient struct { hub *GameHub conn *websocket.Conn @@ -263,32 +317,6 @@ func (c *GameClient) writePump() { } } -func serveWs(hub *GameHub, w http.ResponseWriter, r *http.Request, team string) error { - conn, err := upgrader.Upgrade(w, r, nil) - if err != nil { - return err - } - client := &GameClient{hub: hub, conn: conn, send: make(chan *Message), team: team} - client.hub.register <- client - - go client.writePump() - go client.readPump() - return nil -} - -func serveWsWatcher(hub *GameHub, w http.ResponseWriter, r *http.Request) error { - conn, err := upgrader.Upgrade(w, r, nil) - if err != nil { - return err - } - watcher := &GameWatcher{hub: hub, conn: conn, send: make(chan *Message)} - watcher.hub.registerWatcher <- watcher - - go watcher.writePump() - go watcher.readPump() - return nil -} - // Receives messages from the client and sends them to the hub. func (c *GameWatcher) readPump() { c.conn.SetReadLimit(maxMessageSize) @@ -326,3 +354,32 @@ func (c *GameWatcher) writePump() { } } } + +type GameHubs struct { + hubs map[int]*GameHub +} + +func NewGameHubs() *GameHubs { + return &GameHubs{ + hubs: make(map[int]*GameHub), + } +} + +func (hubs *GameHubs) Close() { + for _, hub := range hubs.hubs { + hub.Close() + } +} + +func (hubs *GameHubs) RestoreFromDB(ctx context.Context, q *db.Queries) error { + games, err := q.ListGames(ctx) + if err != nil { + return err + } + _ = games + return nil +} + +func (hubs *GameHubs) SockHandler() *sockHandler { + return newSockHandler(hubs) +} diff --git a/backend/game/http.go b/backend/game/http.go new file mode 100644 index 0000000..a5a7ded --- /dev/null +++ b/backend/game/http.go @@ -0,0 +1,56 @@ +package game + +import ( + "net/http" + "strconv" + + "github.com/labstack/echo/v4" +) + +type sockHandler struct { + hubs *GameHubs +} + +func newSockHandler(hubs *GameHubs) *sockHandler { + return &sockHandler{ + hubs: hubs, + } +} + +func (h *sockHandler) HandleSockGolfPlay(c echo.Context) error { + gameId := c.Param("gameId") + gameIdInt, err := strconv.Atoi(gameId) + if err != nil { + return echo.NewHTTPError(http.StatusBadRequest, "Invalid game id") + } + var foundHub *GameHub + for _, hub := range h.hubs.hubs { + if hub.game.gameID == gameIdInt { + foundHub = hub + break + } + } + if foundHub == nil { + return echo.NewHTTPError(http.StatusNotFound, "Game not found") + } + return servePlayerWs(foundHub, c.Response(), c.Request(), "a") +} + +func (h *sockHandler) HandleSockGolfWatch(c echo.Context) error { + gameId := c.Param("gameId") + gameIdInt, err := strconv.Atoi(gameId) + if err != nil { + return echo.NewHTTPError(http.StatusBadRequest, "Invalid game id") + } + var foundHub *GameHub + for _, hub := range h.hubs.hubs { + if hub.game.gameID == gameIdInt { + foundHub = hub + break + } + } + if foundHub == nil { + return echo.NewHTTPError(http.StatusNotFound, "Game not found") + } + return serveWatcherWs(foundHub, c.Response(), c.Request()) +} diff --git a/backend/message.go b/backend/game/message.go index f466a8f..7d1a166 100644 --- a/backend/message.go +++ b/backend/game/message.go @@ -1,4 +1,4 @@ -package main +package game import ( "encoding/json" diff --git a/backend/game/ws.go b/backend/game/ws.go new file mode 100644 index 0000000..2ed17af --- /dev/null +++ b/backend/game/ws.go @@ -0,0 +1,46 @@ +package game + +import ( + "net/http" + "time" + + "github.com/gorilla/websocket" +) + +const ( + writeWait = 10 * time.Second + pongWait = 60 * time.Second + pingPeriod = (pongWait * 9) / 10 + maxMessageSize = 512 +) + +var upgrader = websocket.Upgrader{ + ReadBufferSize: 1024, + WriteBufferSize: 1024, +} + +func servePlayerWs(hub *GameHub, w http.ResponseWriter, r *http.Request, team string) error { + conn, err := upgrader.Upgrade(w, r, nil) + if err != nil { + return err + } + client := &GameClient{hub: hub, conn: conn, send: make(chan *Message), team: team} + client.hub.register <- client + + go client.writePump() + go client.readPump() + return nil +} + +func serveWatcherWs(hub *GameHub, w http.ResponseWriter, r *http.Request) error { + conn, err := upgrader.Upgrade(w, r, nil) + if err != nil { + return err + } + watcher := &GameWatcher{hub: hub, conn: conn, send: make(chan *Message)} + watcher.hub.registerWatcher <- watcher + + go watcher.writePump() + go watcher.readPump() + return nil +} diff --git a/backend/main.go b/backend/main.go index 46c7ed8..379fe8d 100644 --- a/backend/main.go +++ b/backend/main.go @@ -5,7 +5,6 @@ import ( "fmt" "log" "net/http" - "strconv" "github.com/jackc/pgx/v5" "github.com/labstack/echo/v4" @@ -14,70 +13,9 @@ import ( "github.com/nsfisis/iosdc-2024-albatross/backend/api" "github.com/nsfisis/iosdc-2024-albatross/backend/db" + "github.com/nsfisis/iosdc-2024-albatross/backend/game" ) -const ( - gameTypeGolf = "golf" -) - -const ( - gameStateWaiting = "waiting" - gameStateReady = "ready" - gameStatePlaying = "playing" - gameStateFinished = "finished" -) - -type Game struct { - GameID int `db:"game_id"` - // "golf" - Type string `db:"type"` - CreatedAt string `db:"created_at"` - State string `db:"state"` -} - -var gameHubs = map[int]*GameHub{} - -func startGame(game *Game) { - if gameHubs[game.GameID] != nil { - return - } - gameHubs[game.GameID] = NewGameHub(game) - go gameHubs[game.GameID].Run() -} - -/* -func handleGolfPost(w http.ResponseWriter, r *http.Request) { - var yourTeam string - waitingGolfGames := []Game{} - err := db.Select(&waitingGolfGames, "SELECT * FROM games WHERE type = $1 AND state = $2 ORDER BY created_at", gameTypeGolf, gameStateWaiting) - if err != nil { - http.Error(w, "Error getting games", http.StatusInternalServerError) - return - } - if len(waitingGolfGames) == 0 { - _, err = db.Exec("INSERT INTO games (type, state) VALUES ($1, $2)", gameTypeGolf, gameStateWaiting) - if err != nil { - http.Error(w, "Error creating game", http.StatusInternalServerError) - return - } - waitingGolfGames = []Game{} - err = db.Select(&waitingGolfGames, "SELECT * FROM games WHERE type = $1 AND state = $2 ORDER BY created_at", gameTypeGolf, gameStateWaiting) - if err != nil { - http.Error(w, "Error getting games", http.StatusInternalServerError) - return - } - yourTeam = "a" - startGame(&waitingGolfGames[0]) - } else { - yourTeam = "b" - db.Exec("UPDATE games SET state = $1 WHERE game_id = $2", gameStateReady, waitingGolfGames[0].GameID) - } - waitingGame := waitingGolfGames[0] - - http.Redirect(w, r, fmt.Sprintf("/golf/%d/%s/", waitingGame.GameID, yourTeam), http.StatusSeeOther) -} -*/ - func main() { var err error config, err := NewConfigFromEnv() @@ -105,59 +43,28 @@ func main() { e.Use(middleware.Logger()) e.Use(middleware.Recover()) - { - apiGroup := e.Group("/api") - apiGroup.Use(oapimiddleware.OapiRequestValidator(openApiSpec)) - apiHandler := api.NewHandler(queries) - api.RegisterHandlers(apiGroup, api.NewStrictHandler(apiHandler, []api.StrictMiddlewareFunc{ - api.NewJWTMiddleware(), - })) - } + apiGroup := e.Group("/api") + apiGroup.Use(oapimiddleware.OapiRequestValidator(openApiSpec)) + apiHandler := api.NewHandler(queries) + api.RegisterHandlers(apiGroup, api.NewStrictHandler(apiHandler, []api.StrictMiddlewareFunc{ + api.NewJWTMiddleware(), + })) - e.GET("/sock/golf/:gameId/watch", func(c echo.Context) error { - gameId := c.Param("gameId") - gameIdInt, err := strconv.Atoi(gameId) - if err != nil { - return echo.NewHTTPError(http.StatusBadRequest, "Invalid game id") - } - var hub *GameHub - for _, h := range gameHubs { - if h.game.GameID == gameIdInt { - hub = h - break - } - } - if hub == nil { - return echo.NewHTTPError(http.StatusNotFound, "Game not found") - } - return serveWsWatcher(hub, c.Response(), c.Request()) + gameHubs := game.NewGameHubs() + err = gameHubs.RestoreFromDB(ctx, queries) + if err != nil { + log.Fatalf("Error restoring game hubs from db %v", err) + } + defer gameHubs.Close() + sockGroup := e.Group("/sock") + sockHandler := gameHubs.SockHandler() + sockGroup.GET("/golf/:gameId/watch", func(c echo.Context) error { + return sockHandler.HandleSockGolfWatch(c) }) - - e.GET("/sock/golf/:gameId/play", func(c echo.Context) error { - gameId := c.Param("gameId") - gameIdInt, err := strconv.Atoi(gameId) - if err != nil { - return echo.NewHTTPError(http.StatusBadRequest, "Invalid game id") - } - var hub *GameHub - for _, h := range gameHubs { - if h.game.GameID == gameIdInt { - hub = h - break - } - } - if hub == nil { - return echo.NewHTTPError(http.StatusNotFound, "Game not found") - } - return serveWs(hub, c.Response(), c.Request(), "a") + sockGroup.GET("/golf/:gameId/play", func(c echo.Context) error { + return sockHandler.HandleSockGolfPlay(c) }) - defer func() { - for _, hub := range gameHubs { - hub.Close() - } - }() - if err := e.Start(":80"); err != http.ErrServerClosed { log.Fatal(err) } |
