aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authortyropro <[email protected]>2026-05-05 23:48:33 +0100
committertyropro <[email protected]>2026-05-05 23:50:32 +0100
commit69ee7ccac2cd0bae3b0c7bd42902a4c0738a01ba (patch)
tree1f890c7cf1a79a745de92628c36dd0b19f4b970d
parentac2d210cd139ee7f84182ec4351a35cf245a9fa8 (diff)
refactor: moved all code to an internal module
-rw-r--r--internal/api/api.go77
-rw-r--r--internal/api/game.go (renamed from game.go)4
-rw-r--r--internal/api/lobbies.go (renamed from lobbies.go)38
-rw-r--r--internal/api/players.go (renamed from players.go)4
-rw-r--r--internal/api/rooms.go (renamed from rooms.go)2
-rw-r--r--internal/api/state.go (renamed from state.go)4
-rw-r--r--internal/api/ws.go (renamed from ws.go)6
-rw-r--r--internal/status/status.go (renamed from status/status.go)4
-rw-r--r--main.go101
9 files changed, 123 insertions, 117 deletions
diff --git a/internal/api/api.go b/internal/api/api.go
new file mode 100644
index 0000000..640577f
--- /dev/null
+++ b/internal/api/api.go
@@ -0,0 +1,77 @@
+package api
+
+import (
+ "os"
+
+ "github.com/gin-gonic/gin"
+ _ "github.com/joho/godotenv/autoload" // for .env
+)
+
+func Run() {
+ staging_mode, release_mode, auto_load_state := getEnv()
+
+ if release_mode {
+ gin.SetMode(gin.ReleaseMode)
+ }
+
+ lobby_manager := NewLobbyManager()
+ ws_manager := NewWsManager()
+
+ if auto_load_state {
+ lobby_manager.AutoLoadState()
+ }
+
+ router := setupRouter(lobby_manager, ws_manager)
+
+ // only allow loopback connections on dev
+ if staging_mode || release_mode {
+ router.Run(":8080")
+ } else {
+ router.Run("127.0.0.1:8080")
+ }
+}
+
+func getEnv() (bool, bool, bool) {
+ staging_mode := os.Getenv("MODE") == "staging"
+ release_mode := os.Getenv("MODE") == "release"
+ auto_load_state := os.Getenv("AUTO_LOAD_STATE") == "true"
+
+ return staging_mode, release_mode, auto_load_state
+}
+
+func setupRouter(lobby_manager *LobbyManager, ws_manager *WsManager) *gin.Engine {
+ router := gin.Default()
+
+ // server endpoints
+ router.POST("/state/save", save_state_endpoint(lobby_manager))
+ router.POST("/state/load", load_state_endpoint(lobby_manager))
+
+ // lobby endpoints
+ router.GET("/lobbies", get_lobbies(lobby_manager))
+ router.GET("/lobbies/:lobby_uuid", get_lobby(lobby_manager))
+
+ router.POST("/lobbies", create_lobby(lobby_manager))
+
+ // players endpoints
+ router.GET("/lobbies/:lobby_uuid/players", get_players(lobby_manager))
+ router.GET("/lobbies/:lobby_uuid/players/:player_uuid", get_player(lobby_manager))
+ router.GET("/lobbies/:lobby_uuid/players/:player_uuid/valid_moves/:origin_x/:origin_y/:dice_roll", get_player_moves(lobby_manager))
+
+ router.POST("/lobbies/:lobby_uuid/players/:name", create_player(lobby_manager))
+
+ router.DELETE("/lobbies/:lobby_uuid/players/:player_uuid", delete_player(lobby_manager))
+
+ // game endpoints
+ router.POST("/lobbies/:lobby_uuid/game", create_game(lobby_manager))
+ router.POST("/lobbies/:lobby_uuid/suggest", make_suggestion(lobby_manager))
+ router.POST("/lobbies/:lobby_uuid/accuse", make_accusation(lobby_manager))
+ router.POST("/lobbies/:lobby_uuid/roll/:player_uuid", roll_dice(lobby_manager))
+
+ router.DELETE("/lobbies/:lobby_uuid/game", delete_game(lobby_manager))
+
+ // ws endpoints
+ router.GET("/lobbies/:lobby_uuid/ws/:player_uuid", ws_handler(ws_manager, lobby_manager))
+ router.GET("/lobbies/:lobby_uuid/broadcast/:message", broadcast_handler(ws_manager, lobby_manager))
+
+ return router
+}
diff --git a/game.go b/internal/api/game.go
index 57adff2..da15474 100644
--- a/game.go
+++ b/internal/api/game.go
@@ -1,7 +1,7 @@
-package main
+package api
import (
- "cluedo-backend/status"
+ "cluedo-backend/internal/status"
"math/rand/v2"
"net/http"
diff --git a/lobbies.go b/internal/api/lobbies.go
index de0b617..3776ffb 100644
--- a/lobbies.go
+++ b/internal/api/lobbies.go
@@ -1,7 +1,8 @@
-package main
+package api
import (
- "cluedo-backend/status"
+ "cluedo-backend/internal/status"
+ "log"
"net/http"
"sync"
@@ -97,35 +98,56 @@ type GetLobbyResponse struct {
PlayerCount int `json:"player_count"`
}
+func (m *LobbyManager) AutoLoadState() error {
+ log.Println("Attempting to load state from file.")
+
+ lobby_state, err := load_state_from_file()
+ if err != nil {
+ log.Println("Failed to load state from file. Skipping.")
+ return err
+ }
+
+ m.mu.Lock()
+ defer m.mu.Unlock()
+
+ m.Lobbies = lobby_state
+
+ log.Println("Loaded state from file.")
+
+ return nil
+}
+
// for use with websockets as the lock only needs to stay on momentarily
-func (m *LobbyManager) CheckLobbyExists(lobby_uuid string) (*Lobby, *errResp) {
+func (m *LobbyManager) CheckLobbyExists(lobby_uuid string) (*Lobby, *status.ErrorResponse) {
m.mu.RLock()
defer m.mu.RUnlock()
lobby, ok := m.Lobbies[lobby_uuid]
if !ok {
- return nil, &errResp{Msg: "Lobby not found"} // TODO: change this to standardised error system
+ err_resp := status.NewErrorResponse(status.LobbyNotFound)
+ return nil, &err_resp
}
return &lobby, nil
}
-func (m *LobbyManager) CheckPlayerExists(lobby_uuid string, player_uuid string) (*Player, *errResp) {
+func (m *LobbyManager) CheckPlayerExists(lobby_uuid string, player_uuid string) (*Player, *status.ErrorResponse) {
m.mu.RLock()
defer m.mu.RUnlock()
lobby, ok := m.Lobbies[lobby_uuid]
- // TODO: change this to standardised error system
if !ok {
- return nil, &errResp{Msg: "Lobby not found"}
+ err_resp := status.NewErrorResponse(status.LobbyNotFound)
+ return nil, &err_resp
}
player, ok := lobby.Players[player_uuid]
if !ok {
- return nil, &errResp{Msg: "Player not found"}
+ err_resp := status.NewErrorResponse(status.PlayerNotFound)
+ return nil, &err_resp
}
return &player, nil
diff --git a/players.go b/internal/api/players.go
index d0ffd6a..5b3ddcd 100644
--- a/players.go
+++ b/internal/api/players.go
@@ -1,7 +1,7 @@
-package main
+package api
import (
- "cluedo-backend/status"
+ "cluedo-backend/internal/status"
"net/http"
"slices"
"strconv"
diff --git a/rooms.go b/internal/api/rooms.go
index 16cb378..efb2673 100644
--- a/rooms.go
+++ b/internal/api/rooms.go
@@ -1,4 +1,4 @@
-package main
+package api
type Room struct {
Name string `json:"name"`
diff --git a/state.go b/internal/api/state.go
index ebf634e..9baeddf 100644
--- a/state.go
+++ b/internal/api/state.go
@@ -1,7 +1,7 @@
-package main
+package api
import (
- "cluedo-backend/status"
+ "cluedo-backend/internal/status"
"encoding/json"
"net/http"
"os"
diff --git a/ws.go b/internal/api/ws.go
index 75ab9fd..f8d7252 100644
--- a/ws.go
+++ b/internal/api/ws.go
@@ -1,4 +1,4 @@
-package main
+package api
import (
"fmt"
@@ -10,6 +10,10 @@ import (
"github.com/gorilla/websocket"
)
+type errResp struct {
+ Msg string `json:"msg"`
+}
+
// websocket manager
type WsManager struct {
clients map[string]*websocket.Conn // player uuid links to a ws connection (this leads to only 1 ws connection being valid at once)
diff --git a/status/status.go b/internal/status/status.go
index b15ff53..85981c6 100644
--- a/status/status.go
+++ b/internal/status/status.go
@@ -30,7 +30,7 @@ type ErrorResponse struct {
Type ErrorStatus `json:"type"`
}
-func newErrorResponse(error_status ErrorStatus) ErrorResponse {
+func NewErrorResponse(error_status ErrorStatus) ErrorResponse {
return ErrorResponse{
Type: error_status,
}
@@ -78,7 +78,7 @@ func getHttpStatusCode(error_status ErrorStatus) int {
}
func GenerateErrorResponse(status ErrorStatus) (int, ErrorResponse) {
- response := newErrorResponse(status)
+ response := NewErrorResponse(status)
http_status_code := getHttpStatusCode(status)
diff --git a/main.go b/main.go
index 0eafb72..398d4eb 100644
--- a/main.go
+++ b/main.go
@@ -1,106 +1,9 @@
package main
import (
- "log"
- "os"
-
- "github.com/gin-gonic/gin"
-
- _ "github.com/joho/godotenv/autoload" // for .env
+ "cluedo-backend/internal/api"
)
-type errResp struct {
- Msg string `json:"msg"`
-}
-
func main() {
- staging_mode, release_mode, auto_load_state := getEnv()
-
- // keep debug gin mode when in dev mode or staging
- if release_mode {
- gin.SetMode(gin.ReleaseMode)
- }
-
- lobby_manager := NewLobbyManager()
-
- if auto_load_state {
- log.Println("Attempting to load state from file.")
- lobby_state, err := load_state_from_file()
- if err == nil {
- // we define this anonymous function so that the
- // defer block gets called after we exit the scope
- // of this function
- func() {
- lobby_manager.mu.Lock()
- defer lobby_manager.mu.Unlock()
-
- lobby_manager.Lobbies = lobby_state
- }()
-
- log.Println("Loaded state from file.")
- } else {
- log.Println("Failed to load state from file. Skipping.")
- }
- }
-
- ws_manager := NewWsManager()
- router := setupRouter(lobby_manager, ws_manager)
-
- // only allow loopback connections on dev
- if staging_mode || release_mode {
- router.Run(":8080")
- } else {
- router.Run("127.0.0.1:8080")
- }
-}
-
-func getEnv() (bool, bool, bool) {
- staging_mode := os.Getenv("MODE") == "staging"
- release_mode := os.Getenv("MODE") == "release"
- auto_load_state := os.Getenv("AUTO_LOAD_STATE") == "true"
-
- return staging_mode, release_mode, auto_load_state
-}
-
-func setupRouter(lobby_manager *LobbyManager, ws_manager *WsManager) *gin.Engine {
- router := gin.Default()
-
- // server endpoints
- router.POST("/state/save", save_state_endpoint(lobby_manager))
- router.POST("/state/load", load_state_endpoint(lobby_manager))
-
- // lobby endpoints
- router.GET("/lobbies", get_lobbies(lobby_manager))
- router.GET("/lobbies/:lobby_uuid", get_lobby(lobby_manager))
-
- router.POST("/lobbies", create_lobby(lobby_manager))
-
- // players endpoints
- router.GET("/lobbies/:lobby_uuid/players", get_players(lobby_manager))
- router.GET("/lobbies/:lobby_uuid/players/:player_uuid", get_player(lobby_manager))
- router.GET("/lobbies/:lobby_uuid/players/:player_uuid/valid_moves/:origin_x/:origin_y/:dice_roll", get_player_moves(lobby_manager))
-
- router.POST("/lobbies/:lobby_uuid/players/:name", create_player(lobby_manager))
-
- router.DELETE("/lobbies/:lobby_uuid/players/:player_uuid", delete_player(lobby_manager))
-
- // game endpoints
- router.POST("/lobbies/:lobby_uuid/game", create_game(lobby_manager))
- router.POST("/lobbies/:lobby_uuid/suggest", make_suggestion(lobby_manager))
- router.POST("/lobbies/:lobby_uuid/accuse", make_accusation(lobby_manager))
- router.POST("/lobbies/:lobby_uuid/roll/:player_uuid", roll_dice(lobby_manager))
-
- router.DELETE("/lobbies/:lobby_uuid/game", delete_game(lobby_manager))
-
- // ws endpoints
- router.GET("/lobbies/:lobby_uuid/ws/:player_uuid", ws_handler(ws_manager, lobby_manager))
- router.GET("/lobbies/:lobby_uuid/broadcast/:message", broadcast_handler(ws_manager, lobby_manager))
-
- return router
-}
-
-func NewErrResp(msg string) errResp {
- return errResp{
- Msg: msg,
- }
+ api.Run()
}