diff --git a/api/handler/handler.go b/api/handler/handler.go index 6615f86..b7382a1 100644 --- a/api/handler/handler.go +++ b/api/handler/handler.go @@ -1,24 +1,26 @@ package handler import ( - "log" "mchess_server/api" "mchess_server/chess" - lobbies "mchess_server/lobby_registry" - "mchess_server/usher" + "mchess_server/lobbies" "mchess_server/utils" "net/http" "sync" "github.com/gin-gonic/gin" "github.com/google/uuid" + "go.uber.org/ratelimit" ) var mut sync.Mutex +var limiter = ratelimit.New(10) + +func HostGameHandler(c *gin.Context) { + limiter.Take() -func HostPrivateGameHandler(c *gin.Context) { player := chess.NewPlayer(uuid.New()) - u := usher.GetUsher() + u := lobbies.GetUsher() mut.Lock() defer mut.Unlock() @@ -36,6 +38,8 @@ func HostPrivateGameHandler(c *gin.Context) { } func GetLobbyForPassphraseHandler(c *gin.Context) { + limiter.Take() + reqPassphrase := c.Param("phrase") if reqPassphrase == "" { c.IndentedJSON(http.StatusBadRequest, reqPassphrase) @@ -57,34 +61,17 @@ func GetLobbyForPassphraseHandler(c *gin.Context) { c.IndentedJSON(http.StatusOK, lobbyInfo) } -func RegisterForRandomGame(c *gin.Context) { - player := chess.NewPlayer(uuid.New()) - usher := usher.GetUsher() - - mut.Lock() - defer mut.Unlock() - lobby := usher.WelcomeNewPlayer(player) - usher.AddPlayerToLobbyAndStartGameIfFull(player, lobby) - - info := api.PlayerInfo{ - PlayerID: &player.Uuid, - LobbyID: &lobby.Uuid, - } - log.Println("responding with info ", info) - - c.Header("Access-Control-Allow-Origin", "*") - c.IndentedJSON(http.StatusOK, info) -} - +// TODO: this will be replaced by the JoinGameHandler() func JoinPrivateGame(c *gin.Context) { + limiter.Take() + req := api.PlayerInfo{} - log.Println(c.Request.Body) err := c.ShouldBindJSON(&req) if err != nil || req.Passphrase == nil || *req.Passphrase == "" { c.IndentedJSON(http.StatusNotFound, req) } - u := usher.GetUsher() + u := lobbies.GetUsher() if req.Passphrase != nil && *req.Passphrase != "" && @@ -126,3 +113,30 @@ func JoinPrivateGame(c *gin.Context) { c.Header("Access-Control-Allow-Origin", "*") c.IndentedJSON(http.StatusOK, info) } + +func JoinGameHandler(c *gin.Context) { + limiter.Take() + + id := c.Param("id") + idAsUUID, err := uuid.Parse(id) + if err != nil { + c.IndentedJSON(http.StatusBadRequest, nil) + return + } + + passphrase := api.Passphrase{} + c.ShouldBindJSON(&passphrase) + + u := lobbies.GetUsher() + lobby := u.GetLobbyByID(idAsUUID) + if lobby == nil { + c.IndentedJSON(http.StatusNotFound, nil) + return + } + + lobbyInfo := api.LobbyInfo{ + ID: &lobby.Uuid, + } + + c.IndentedJSON(http.StatusOK, lobbyInfo) +} diff --git a/api/handler/handler_test.go b/api/handler/handler_test.go index 8e69445..ff5fead 100644 --- a/api/handler/handler_test.go +++ b/api/handler/handler_test.go @@ -20,7 +20,7 @@ func Test_GetLobbyFromPassphraseHandler(t *testing.T) { t.Run("host a lobby", func(t *testing.T) { r1 := httptest.NewRecorder() ctx1, e1 := gin.CreateTestContext(r1) - e1.GET("/api/hostPrivate", HostPrivateGameHandler) + e1.GET("/api/hostPrivate", HostGameHandler) hostGameRequest, _ := http.NewRequest("GET", "/api/hostPrivate", nil) ctx1.Request = hostGameRequest diff --git a/api/websocket/connection.go b/api/handler/websocket.go similarity index 92% rename from api/websocket/connection.go rename to api/handler/websocket.go index be29d8c..5ca8d46 100644 --- a/api/websocket/connection.go +++ b/api/handler/websocket.go @@ -1,4 +1,4 @@ -package websocket +package handler import ( "context" @@ -8,7 +8,7 @@ import ( "mchess_server/api" "net/http" - lobbies "mchess_server/lobby_registry" + "mchess_server/lobbies" "github.com/gin-gonic/gin" gorillaws "github.com/gorilla/websocket" @@ -21,6 +21,8 @@ var upgrader = gorillaws.Upgrader{ } func RegisterWebSocketConnection(c *gin.Context) { + limiter.Take() + log.Println(c.Request) conn, err := upgrader.Upgrade(c.Writer, c.Request, nil) if err != nil { @@ -31,6 +33,8 @@ func RegisterWebSocketConnection(c *gin.Context) { } func waitForAndHandlePlayerID(ctx context.Context, conn *gorillaws.Conn) { + limiter.Take() + msgType, msg, err := conn.ReadMessage() if err != nil { errorMessage := fmt.Sprintf("Reading from websocket connection did not work: %s", err) @@ -70,3 +74,8 @@ func waitForAndHandlePlayerID(ctx context.Context, conn *gorillaws.Conn) { lobby.Game.SetWebsocketConnectionFor(ctx, player, conn) log.Println("player after setting connection: ", player) } + +func ConnectWsForGame(c *gin.Context) { + limiter.Take() + +} diff --git a/go.mod b/go.mod index 38fda34..3f129d6 100644 --- a/go.mod +++ b/go.mod @@ -9,6 +9,8 @@ require ( github.com/stretchr/testify v1.9.0 ) +require github.com/benbjohnson/clock v1.3.0 // indirect + require ( github.com/bytedance/sonic v1.11.6 // indirect github.com/bytedance/sonic/loader v0.1.1 // indirect @@ -32,6 +34,7 @@ require ( github.com/pmezard/go-difflib v1.0.0 // indirect github.com/twitchyliquid64/golang-asm v0.15.1 // indirect github.com/ugorji/go/codec v1.2.12 // indirect + go.uber.org/ratelimit v0.3.1 golang.org/x/arch v0.8.0 // indirect golang.org/x/crypto v0.23.0 // indirect golang.org/x/exp v0.0.0-20240506185415-9bf2ced13842 // indirect diff --git a/go.sum b/go.sum index 51dc3b8..d95f318 100644 --- a/go.sum +++ b/go.sum @@ -1,3 +1,5 @@ +github.com/benbjohnson/clock v1.3.0 h1:ip6w0uFQkncKQ979AypyG0ER7mqUSBdKLOgAle/AT8A= +github.com/benbjohnson/clock v1.3.0/go.mod h1:J11/hYXuz8f4ySSvYwY0FKfm+ezbsZBKZxNJlLklBHA= github.com/bytedance/sonic v1.11.6 h1:oUp34TzMlL+OY1OUWxHqsdkgC/Zfc85zGqw9siXjrc0= github.com/bytedance/sonic v1.11.6/go.mod h1:LysEHSvpvDySVdC2f87zGWf6CIKJcAvqab1ZaiQtds4= github.com/bytedance/sonic/loader v0.1.1 h1:c+e5Pt1k/cy5wMveRDyk2X4B9hF4g7an8N3zCYjJFNM= @@ -69,6 +71,8 @@ github.com/twitchyliquid64/golang-asm v0.15.1 h1:SU5vSMR7hnwNxj24w34ZyCi/FmDZTkS github.com/twitchyliquid64/golang-asm v0.15.1/go.mod h1:a1lVb/DtPvCB8fslRZhAngC2+aY1QWCk3Cedj/Gdt08= github.com/ugorji/go/codec v1.2.12 h1:9LC83zGrHhuUA9l16C9AHXAqEV/2wBQ4nkvumAE65EE= github.com/ugorji/go/codec v1.2.12/go.mod h1:UNopzCgEMSXjBc6AOMqYvWC1ktqTAfzJZUZgYf6w6lg= +go.uber.org/ratelimit v0.3.1 h1:K4qVE+byfv/B3tC+4nYWP7v/6SimcO7HzHekoMNBma0= +go.uber.org/ratelimit v0.3.1/go.mod h1:6euWsTB6U/Nb3X++xEUXA8ciPJvr19Q/0h1+oDcJhRk= golang.org/x/arch v0.0.0-20210923205945-b76863e36670/go.mod h1:5om86z9Hs0C8fWVUuoMHwpExlXzs5Tkyp9hOrfG7pp8= golang.org/x/arch v0.8.0 h1:3wRIsP3pM4yUptoR96otTUOXI367OS0+c9eeRi9doIc= golang.org/x/arch v0.8.0/go.mod h1:FEVrYAQjsQXMVJ1nsMoVVXPZg6p2JE2mx8psSWTDQys= diff --git a/lobby_registry/lobby.go b/lobbies/lobby.go similarity index 97% rename from lobby_registry/lobby.go rename to lobbies/lobby.go index d900002..d10285c 100644 --- a/lobby_registry/lobby.go +++ b/lobbies/lobby.go @@ -1,4 +1,4 @@ -package lobby_registry +package lobbies import ( "mchess_server/chess" diff --git a/lobby_registry/registry.go b/lobbies/registry.go similarity index 97% rename from lobby_registry/registry.go rename to lobbies/registry.go index 1412462..56d11dc 100644 --- a/lobby_registry/registry.go +++ b/lobbies/registry.go @@ -1,4 +1,4 @@ -package lobby_registry +package lobbies import ( "mchess_server/utils" diff --git a/lobbies/usher.go b/lobbies/usher.go new file mode 100644 index 0000000..38a0574 --- /dev/null +++ b/lobbies/usher.go @@ -0,0 +1,50 @@ +package lobbies + +import ( + "mchess_server/chess" + "mchess_server/utils" + + "github.com/google/uuid" +) + +type Usher struct { +} + +var usherInstance *Usher + +func newUsher() *Usher { + return &Usher{} +} + +func GetUsher() *Usher { + if usherInstance == nil { + usherInstance = newUsher() + } + return usherInstance +} + +func (u *Usher) WelcomeNewPlayer(player *chess.Player) *Lobby { + lobby := GetLobbyRegistry().GetLobbyForPlayer() + return lobby +} + +func (u *Usher) CreateNewPrivateLobby(player *chess.Player) *Lobby { + lobby := GetLobbyRegistry().CreateNewPrivateLobby() + return lobby +} + +func (u *Usher) FindExistingPrivateLobby(p utils.Passphrase) *Lobby { + lobby := GetLobbyRegistry().GetLobbyByPassphrase(p) + if lobby == nil || lobby.IsFull() { + return nil + } + return lobby +} + +func (*Usher) GetLobbyByID(id uuid.UUID) *Lobby { + return GetLobbyRegistry().GetLobbyByUUID(id) +} + +func (u *Usher) AddPlayerToLobbyAndStartGameIfFull(player *chess.Player, lobby *Lobby) { + lobby.AddPlayerAndStartGameIfFull(player) +} diff --git a/main.go b/main.go index 9cee4de..87ebd93 100644 --- a/main.go +++ b/main.go @@ -4,7 +4,6 @@ import ( "flag" "log" "mchess_server/api/handler" - "mchess_server/api/websocket" "github.com/gin-gonic/gin" ) @@ -24,11 +23,13 @@ func main() { } router := gin.Default() - router.GET("/api/random", handler.RegisterForRandomGame) - router.GET("/api/hostPrivate", handler.HostPrivateGameHandler) + router.GET("/api/hostPrivate", handler.HostGameHandler) router.POST("/api/joinPrivate", handler.JoinPrivateGame) - router.GET("/api/ws", websocket.RegisterWebSocketConnection) + router.GET("/api/ws", handler.RegisterWebSocketConnection) + router.GET("/api/getLobbyForPassphrase/:phrase", handler.GetLobbyForPassphraseHandler) + router.GET("/api/registerWsForGame/:id", handler.ConnectWsForGame) + router.POST("/api/joinGame/:id", handler.JoinGameHandler) if debugMode { log.Println("Starting service WITHOUT TLS") diff --git a/usher/usher.go b/usher/usher.go deleted file mode 100644 index cfbbd51..0000000 --- a/usher/usher.go +++ /dev/null @@ -1,45 +0,0 @@ -package usher - -import ( - "mchess_server/chess" - lobbies "mchess_server/lobby_registry" - "mchess_server/utils" -) - -type Usher struct { -} - -var instance *Usher - -func newUsher() *Usher { - return &Usher{} -} - -func GetUsher() *Usher { - if instance == nil { - instance = newUsher() - } - return instance -} - -func (u *Usher) WelcomeNewPlayer(player *chess.Player) *lobbies.Lobby { - lobby := lobbies.GetLobbyRegistry().GetLobbyForPlayer() - return lobby -} - -func (u *Usher) CreateNewPrivateLobby(player *chess.Player) *lobbies.Lobby { - lobby := lobbies.GetLobbyRegistry().CreateNewPrivateLobby() - return lobby -} - -func (u *Usher) FindExistingPrivateLobby(p utils.Passphrase) *lobbies.Lobby { - lobby := lobbies.GetLobbyRegistry().GetLobbyByPassphrase(p) - if lobby == nil || lobby.IsFull() { - return nil - } - return lobby -} - -func (u *Usher) AddPlayerToLobbyAndStartGameIfFull(player *chess.Player, lobby *lobbies.Lobby) { - lobby.AddPlayerAndStartGameIfFull(player) -}