Some more changes for the new game handling api and also rate limiting #13
@ -1,24 +1,26 @@
|
|||||||
package handler
|
package handler
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"log"
|
|
||||||
"mchess_server/api"
|
"mchess_server/api"
|
||||||
"mchess_server/chess"
|
"mchess_server/chess"
|
||||||
lobbies "mchess_server/lobby_registry"
|
"mchess_server/lobbies"
|
||||||
"mchess_server/usher"
|
|
||||||
"mchess_server/utils"
|
"mchess_server/utils"
|
||||||
"net/http"
|
"net/http"
|
||||||
"sync"
|
"sync"
|
||||||
|
|
||||||
"github.com/gin-gonic/gin"
|
"github.com/gin-gonic/gin"
|
||||||
"github.com/google/uuid"
|
"github.com/google/uuid"
|
||||||
|
"go.uber.org/ratelimit"
|
||||||
)
|
)
|
||||||
|
|
||||||
var mut sync.Mutex
|
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())
|
player := chess.NewPlayer(uuid.New())
|
||||||
u := usher.GetUsher()
|
u := lobbies.GetUsher()
|
||||||
|
|
||||||
mut.Lock()
|
mut.Lock()
|
||||||
defer mut.Unlock()
|
defer mut.Unlock()
|
||||||
@ -36,6 +38,8 @@ func HostPrivateGameHandler(c *gin.Context) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
func GetLobbyForPassphraseHandler(c *gin.Context) {
|
func GetLobbyForPassphraseHandler(c *gin.Context) {
|
||||||
|
limiter.Take()
|
||||||
|
|
||||||
reqPassphrase := c.Param("phrase")
|
reqPassphrase := c.Param("phrase")
|
||||||
if reqPassphrase == "" {
|
if reqPassphrase == "" {
|
||||||
c.IndentedJSON(http.StatusBadRequest, reqPassphrase)
|
c.IndentedJSON(http.StatusBadRequest, reqPassphrase)
|
||||||
@ -57,34 +61,17 @@ func GetLobbyForPassphraseHandler(c *gin.Context) {
|
|||||||
c.IndentedJSON(http.StatusOK, lobbyInfo)
|
c.IndentedJSON(http.StatusOK, lobbyInfo)
|
||||||
}
|
}
|
||||||
|
|
||||||
func RegisterForRandomGame(c *gin.Context) {
|
// TODO: this will be replaced by the JoinGameHandler()
|
||||||
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)
|
|
||||||
}
|
|
||||||
|
|
||||||
func JoinPrivateGame(c *gin.Context) {
|
func JoinPrivateGame(c *gin.Context) {
|
||||||
|
limiter.Take()
|
||||||
|
|
||||||
req := api.PlayerInfo{}
|
req := api.PlayerInfo{}
|
||||||
log.Println(c.Request.Body)
|
|
||||||
err := c.ShouldBindJSON(&req)
|
err := c.ShouldBindJSON(&req)
|
||||||
if err != nil || req.Passphrase == nil || *req.Passphrase == "" {
|
if err != nil || req.Passphrase == nil || *req.Passphrase == "" {
|
||||||
c.IndentedJSON(http.StatusNotFound, req)
|
c.IndentedJSON(http.StatusNotFound, req)
|
||||||
}
|
}
|
||||||
|
|
||||||
u := usher.GetUsher()
|
u := lobbies.GetUsher()
|
||||||
|
|
||||||
if req.Passphrase != nil &&
|
if req.Passphrase != nil &&
|
||||||
*req.Passphrase != "" &&
|
*req.Passphrase != "" &&
|
||||||
@ -126,3 +113,30 @@ func JoinPrivateGame(c *gin.Context) {
|
|||||||
c.Header("Access-Control-Allow-Origin", "*")
|
c.Header("Access-Control-Allow-Origin", "*")
|
||||||
c.IndentedJSON(http.StatusOK, info)
|
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)
|
||||||
|
}
|
||||||
|
@ -20,7 +20,7 @@ func Test_GetLobbyFromPassphraseHandler(t *testing.T) {
|
|||||||
t.Run("host a lobby", func(t *testing.T) {
|
t.Run("host a lobby", func(t *testing.T) {
|
||||||
r1 := httptest.NewRecorder()
|
r1 := httptest.NewRecorder()
|
||||||
ctx1, e1 := gin.CreateTestContext(r1)
|
ctx1, e1 := gin.CreateTestContext(r1)
|
||||||
e1.GET("/api/hostPrivate", HostPrivateGameHandler)
|
e1.GET("/api/hostPrivate", HostGameHandler)
|
||||||
hostGameRequest, _ := http.NewRequest("GET", "/api/hostPrivate", nil)
|
hostGameRequest, _ := http.NewRequest("GET", "/api/hostPrivate", nil)
|
||||||
ctx1.Request = hostGameRequest
|
ctx1.Request = hostGameRequest
|
||||||
|
|
||||||
|
@ -1,4 +1,4 @@
|
|||||||
package websocket
|
package handler
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"context"
|
"context"
|
||||||
@ -8,7 +8,7 @@ import (
|
|||||||
"mchess_server/api"
|
"mchess_server/api"
|
||||||
"net/http"
|
"net/http"
|
||||||
|
|
||||||
lobbies "mchess_server/lobby_registry"
|
"mchess_server/lobbies"
|
||||||
|
|
||||||
"github.com/gin-gonic/gin"
|
"github.com/gin-gonic/gin"
|
||||||
gorillaws "github.com/gorilla/websocket"
|
gorillaws "github.com/gorilla/websocket"
|
||||||
@ -21,6 +21,8 @@ var upgrader = gorillaws.Upgrader{
|
|||||||
}
|
}
|
||||||
|
|
||||||
func RegisterWebSocketConnection(c *gin.Context) {
|
func RegisterWebSocketConnection(c *gin.Context) {
|
||||||
|
limiter.Take()
|
||||||
|
|
||||||
log.Println(c.Request)
|
log.Println(c.Request)
|
||||||
conn, err := upgrader.Upgrade(c.Writer, c.Request, nil)
|
conn, err := upgrader.Upgrade(c.Writer, c.Request, nil)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
@ -31,6 +33,8 @@ func RegisterWebSocketConnection(c *gin.Context) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
func waitForAndHandlePlayerID(ctx context.Context, conn *gorillaws.Conn) {
|
func waitForAndHandlePlayerID(ctx context.Context, conn *gorillaws.Conn) {
|
||||||
|
limiter.Take()
|
||||||
|
|
||||||
msgType, msg, err := conn.ReadMessage()
|
msgType, msg, err := conn.ReadMessage()
|
||||||
if err != nil {
|
if err != nil {
|
||||||
errorMessage := fmt.Sprintf("Reading from websocket connection did not work: %s", err)
|
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)
|
lobby.Game.SetWebsocketConnectionFor(ctx, player, conn)
|
||||||
log.Println("player after setting connection: ", player)
|
log.Println("player after setting connection: ", player)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func ConnectWsForGame(c *gin.Context) {
|
||||||
|
limiter.Take()
|
||||||
|
|
||||||
|
}
|
3
go.mod
3
go.mod
@ -9,6 +9,8 @@ require (
|
|||||||
github.com/stretchr/testify v1.9.0
|
github.com/stretchr/testify v1.9.0
|
||||||
)
|
)
|
||||||
|
|
||||||
|
require github.com/benbjohnson/clock v1.3.0 // indirect
|
||||||
|
|
||||||
require (
|
require (
|
||||||
github.com/bytedance/sonic v1.11.6 // indirect
|
github.com/bytedance/sonic v1.11.6 // indirect
|
||||||
github.com/bytedance/sonic/loader v0.1.1 // 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/pmezard/go-difflib v1.0.0 // indirect
|
||||||
github.com/twitchyliquid64/golang-asm v0.15.1 // indirect
|
github.com/twitchyliquid64/golang-asm v0.15.1 // indirect
|
||||||
github.com/ugorji/go/codec v1.2.12 // 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/arch v0.8.0 // indirect
|
||||||
golang.org/x/crypto v0.23.0 // indirect
|
golang.org/x/crypto v0.23.0 // indirect
|
||||||
golang.org/x/exp v0.0.0-20240506185415-9bf2ced13842 // indirect
|
golang.org/x/exp v0.0.0-20240506185415-9bf2ced13842 // indirect
|
||||||
|
4
go.sum
4
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 h1:oUp34TzMlL+OY1OUWxHqsdkgC/Zfc85zGqw9siXjrc0=
|
||||||
github.com/bytedance/sonic v1.11.6/go.mod h1:LysEHSvpvDySVdC2f87zGWf6CIKJcAvqab1ZaiQtds4=
|
github.com/bytedance/sonic v1.11.6/go.mod h1:LysEHSvpvDySVdC2f87zGWf6CIKJcAvqab1ZaiQtds4=
|
||||||
github.com/bytedance/sonic/loader v0.1.1 h1:c+e5Pt1k/cy5wMveRDyk2X4B9hF4g7an8N3zCYjJFNM=
|
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/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 h1:9LC83zGrHhuUA9l16C9AHXAqEV/2wBQ4nkvumAE65EE=
|
||||||
github.com/ugorji/go/codec v1.2.12/go.mod h1:UNopzCgEMSXjBc6AOMqYvWC1ktqTAfzJZUZgYf6w6lg=
|
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.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 h1:3wRIsP3pM4yUptoR96otTUOXI367OS0+c9eeRi9doIc=
|
||||||
golang.org/x/arch v0.8.0/go.mod h1:FEVrYAQjsQXMVJ1nsMoVVXPZg6p2JE2mx8psSWTDQys=
|
golang.org/x/arch v0.8.0/go.mod h1:FEVrYAQjsQXMVJ1nsMoVVXPZg6p2JE2mx8psSWTDQys=
|
||||||
|
@ -1,4 +1,4 @@
|
|||||||
package lobby_registry
|
package lobbies
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"mchess_server/chess"
|
"mchess_server/chess"
|
@ -1,4 +1,4 @@
|
|||||||
package lobby_registry
|
package lobbies
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"mchess_server/utils"
|
"mchess_server/utils"
|
50
lobbies/usher.go
Normal file
50
lobbies/usher.go
Normal file
@ -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)
|
||||||
|
}
|
9
main.go
9
main.go
@ -4,7 +4,6 @@ import (
|
|||||||
"flag"
|
"flag"
|
||||||
"log"
|
"log"
|
||||||
"mchess_server/api/handler"
|
"mchess_server/api/handler"
|
||||||
"mchess_server/api/websocket"
|
|
||||||
|
|
||||||
"github.com/gin-gonic/gin"
|
"github.com/gin-gonic/gin"
|
||||||
)
|
)
|
||||||
@ -24,11 +23,13 @@ func main() {
|
|||||||
}
|
}
|
||||||
|
|
||||||
router := gin.Default()
|
router := gin.Default()
|
||||||
router.GET("/api/random", handler.RegisterForRandomGame)
|
router.GET("/api/hostPrivate", handler.HostGameHandler)
|
||||||
router.GET("/api/hostPrivate", handler.HostPrivateGameHandler)
|
|
||||||
router.POST("/api/joinPrivate", handler.JoinPrivateGame)
|
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/getLobbyForPassphrase/:phrase", handler.GetLobbyForPassphraseHandler)
|
||||||
|
router.GET("/api/registerWsForGame/:id", handler.ConnectWsForGame)
|
||||||
|
router.POST("/api/joinGame/:id", handler.JoinGameHandler)
|
||||||
|
|
||||||
if debugMode {
|
if debugMode {
|
||||||
log.Println("Starting service WITHOUT TLS")
|
log.Println("Starting service WITHOUT TLS")
|
||||||
|
@ -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)
|
|
||||||
}
|
|
Loading…
Reference in New Issue
Block a user