From 65dc2ebd242763c968ecb64639969ced99889224 Mon Sep 17 00:00:00 2001 From: Marco Date: Sat, 11 May 2024 12:03:24 +0200 Subject: [PATCH] Replace old websocket library with the gorilla one --- {handler => api/handler}/handler.go | 0 {handler => api/handler}/handler_test.go | 0 api/websocket/connection.go | 72 ++++++++++++++++++++++++ chess/game.go | 4 +- chess/player.go | 6 +- connection/type.go | 20 ++++--- go.mod | 2 +- go.sum | 2 + main.go | 58 +------------------ 9 files changed, 96 insertions(+), 68 deletions(-) rename {handler => api/handler}/handler.go (100%) rename {handler => api/handler}/handler_test.go (100%) create mode 100644 api/websocket/connection.go diff --git a/handler/handler.go b/api/handler/handler.go similarity index 100% rename from handler/handler.go rename to api/handler/handler.go diff --git a/handler/handler_test.go b/api/handler/handler_test.go similarity index 100% rename from handler/handler_test.go rename to api/handler/handler_test.go diff --git a/api/websocket/connection.go b/api/websocket/connection.go new file mode 100644 index 0000000..be29d8c --- /dev/null +++ b/api/websocket/connection.go @@ -0,0 +1,72 @@ +package websocket + +import ( + "context" + "encoding/json" + "fmt" + "log" + "mchess_server/api" + "net/http" + + lobbies "mchess_server/lobby_registry" + + "github.com/gin-gonic/gin" + gorillaws "github.com/gorilla/websocket" +) + +var upgrader = gorillaws.Upgrader{ + CheckOrigin: func(r *http.Request) bool { + return true + }, +} + +func RegisterWebSocketConnection(c *gin.Context) { + log.Println(c.Request) + conn, err := upgrader.Upgrade(c.Writer, c.Request, nil) + if err != nil { + log.Println(err) + return + } + go waitForAndHandlePlayerID(c, conn) +} + +func waitForAndHandlePlayerID(ctx context.Context, conn *gorillaws.Conn) { + msgType, msg, err := conn.ReadMessage() + if err != nil { + errorMessage := fmt.Sprintf("Reading from websocket connection did not work: %s", err) + log.Println(errorMessage) + conn.Close() + return + } + + log.Println("read from websocket endpoint: ", msgType, string(msg), err) + + var info api.PlayerInfo + err = json.Unmarshal(msg, &info) + if err != nil { + errorMessage := fmt.Sprintf("Unmarshaling message did not work: %s", err) + log.Println(errorMessage) + conn.WriteMessage(msgType, []byte(errorMessage)) + conn.Close() + return + } + + lobby := lobbies.GetLobbyRegistry().GetLobbyByUUID(*info.LobbyID) + if lobby == nil { + conn.WriteMessage(msgType, []byte("lobby not found")) + conn.Close() + return + } + + player, found := lobby.GetPlayerByUUID(*info.PlayerID) + if !found { + conn.WriteMessage(msgType, []byte("player not found")) + conn.Close() + return + } + if player.Conn.HasWebsocketConnection() { + player.Conn.Close("closing existing connection") + } + lobby.Game.SetWebsocketConnectionFor(ctx, player, conn) + log.Println("player after setting connection: ", player) +} diff --git a/chess/game.go b/chess/game.go index b8df92b..f082098 100644 --- a/chess/game.go +++ b/chess/game.go @@ -8,7 +8,7 @@ import ( "mchess_server/types" "github.com/google/uuid" - "nhooyr.io/websocket" + gorillaws "github.com/gorilla/websocket" ) type Game struct { @@ -211,6 +211,6 @@ func (game Game) broadcastGameEnd(reason GameEndedReason) error { func (game *Game) playerDisconnected(p *Player) { } -func (game *Game) SetWebsocketConnectionFor(ctx context.Context, p *Player, ws *websocket.Conn) { +func (game *Game) SetWebsocketConnectionFor(ctx context.Context, p *Player, ws *gorillaws.Conn) { p.SetWebsocketConnectionAndSendBoardState(ctx, ws, game.board.PGN(), game.board.colorToMove) } diff --git a/chess/player.go b/chess/player.go index c9b593e..d674377 100644 --- a/chess/player.go +++ b/chess/player.go @@ -10,7 +10,7 @@ import ( "mchess_server/types" "github.com/google/uuid" - "nhooyr.io/websocket" + gorillaws "github.com/gorilla/websocket" ) type Player struct { @@ -34,13 +34,13 @@ func (p Player) hasWebsocketConnection() bool { return p.Conn.HasWebsocketConnection() } -func (p *Player) SetWebsocketConnection(ctx context.Context, ws *websocket.Conn) { +func (p *Player) SetWebsocketConnection(ctx context.Context, ws *gorillaws.Conn) { p.Conn.SetWebsocketConnection(ws) } func (p *Player) SetWebsocketConnectionAndSendBoardState( ctx context.Context, - ws *websocket.Conn, + ws *gorillaws.Conn, boardPosition string, turnColor types.ChessColor, ) { diff --git a/connection/type.go b/connection/type.go index 4b073ee..3b0babd 100644 --- a/connection/type.go +++ b/connection/type.go @@ -3,13 +3,15 @@ package connection import ( "context" "log" + "sync" - "nhooyr.io/websocket" + gorillaws "github.com/gorilla/websocket" ) type Connection struct { - ws *websocket.Conn + ws *gorillaws.Conn wsConnectionEstablished chan bool + wsWriteLock sync.Mutex ctx context.Context buffer MessageBuffer disconnectCallback func() @@ -28,7 +30,7 @@ func NewConnection(options ...func(*Connection)) *Connection { return &connection } -func WithWebsocket(ws *websocket.Conn) func(*Connection) { +func WithWebsocket(ws *gorillaws.Conn) func(*Connection) { return func(c *Connection) { c.ws = ws } @@ -56,7 +58,7 @@ func (conn *Connection) HasWebsocketConnection() bool { return conn.ws != nil } -func (conn *Connection) SetWebsocketConnection(ws *websocket.Conn) { +func (conn *Connection) SetWebsocketConnection(ws *gorillaws.Conn) { if ws == nil { return } @@ -70,7 +72,7 @@ func (conn *Connection) SetWebsocketConnection(ws *websocket.Conn) { go func() { for { - _, msg, err := conn.ws.Read(conn.ctx) + _, msg, err := conn.ws.ReadMessage() if err != nil { log.Println("while reading from websocket: %w", err) if conn.disconnectCallback != nil { @@ -84,12 +86,15 @@ func (conn *Connection) SetWebsocketConnection(ws *websocket.Conn) { } func (conn *Connection) Write(msg []byte) error { + conn.wsWriteLock.Lock() + defer conn.wsWriteLock.Unlock() + if conn.ws == nil { //if ws is not yet set, we wait for it <-conn.wsConnectionEstablished } log.Printf("Writing message: %s", string(msg)) - return conn.ws.Write(conn.ctx, websocket.MessageText, msg) + return conn.ws.WriteMessage(gorillaws.TextMessage, msg) } func (conn *Connection) Read() ([]byte, error) { @@ -103,6 +108,7 @@ func (conn *Connection) Read() ([]byte, error) { } func (conn *Connection) Close(msg string) { - conn.ws.Close(websocket.StatusCode(400), msg) + conn.ws.WriteMessage(gorillaws.TextMessage, []byte(msg)) + conn.ws.Close() conn.ws = nil } diff --git a/go.mod b/go.mod index 901fad6..38fda34 100644 --- a/go.mod +++ b/go.mod @@ -7,7 +7,6 @@ require ( github.com/google/uuid v1.6.0 github.com/samber/lo v1.39.0 github.com/stretchr/testify v1.9.0 - nhooyr.io/websocket v1.8.11 ) require ( @@ -22,6 +21,7 @@ require ( github.com/go-playground/universal-translator v0.18.1 // indirect github.com/go-playground/validator/v10 v10.20.0 // indirect github.com/goccy/go-json v0.10.2 // indirect + github.com/gorilla/websocket v1.5.1 github.com/json-iterator/go v1.1.12 // indirect github.com/klauspost/cpuid/v2 v2.2.7 // indirect github.com/leodido/go-urn v1.4.0 // indirect diff --git a/go.sum b/go.sum index 81cc336..2f8f041 100644 --- a/go.sum +++ b/go.sum @@ -46,6 +46,8 @@ github.com/google/go-cmp v0.6.0/go.mod h1:17dUlkBOakJ0+DkrSSNjCkIjxS6bF9zb3elmeN github.com/google/gofuzz v1.0.0/go.mod h1:dBl0BpW6vV/+mYPU4Po3pmUjxk6FQPldtuIdl/M65Eg= github.com/google/uuid v1.6.0 h1:NIvaJDMOsjHA8n1jAhLSgzrAzy1Hgr+hNrb57e+94F0= github.com/google/uuid v1.6.0/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo= +github.com/gorilla/websocket v1.5.1 h1:gmztn0JnHVt9JZquRuzLw3g4wouNVzKL15iLr/zn/QY= +github.com/gorilla/websocket v1.5.1/go.mod h1:x3kM2JMyaluk02fnUJpQuwD2dCS5NDG2ZHL0uE0tcaY= github.com/json-iterator/go v1.1.12 h1:PV8peI4a0ysnczrg+LtxykD8LfKY9ML6u2jnxaEnrnM= github.com/json-iterator/go v1.1.12/go.mod h1:e30LSqwooZae/UwlEbR2852Gd8hjQvJoHmT4TnhNGBo= github.com/klauspost/cpuid/v2 v2.0.9/go.mod h1:FInQzS24/EEf25PyTYn52gqo7WaD8xa0213Md/qVLRg= diff --git a/main.go b/main.go index 5c7eb8f..9cee4de 100644 --- a/main.go +++ b/main.go @@ -1,17 +1,12 @@ package main import ( - "context" - "encoding/json" "flag" - "fmt" "log" - "mchess_server/api" - "mchess_server/handler" - lobbies "mchess_server/lobby_registry" + "mchess_server/api/handler" + "mchess_server/api/websocket" "github.com/gin-gonic/gin" - "nhooyr.io/websocket" ) var cert_path = "/etc/letsencrypt/live/chess.sw-gross.de/" @@ -32,7 +27,7 @@ func main() { router.GET("/api/random", handler.RegisterForRandomGame) router.GET("/api/hostPrivate", handler.HostPrivateGameHandler) router.POST("/api/joinPrivate", handler.JoinPrivateGame) - router.GET("/api/ws", registerWebSocketConnection) + router.GET("/api/ws", websocket.RegisterWebSocketConnection) router.GET("/api/getLobbyForPassphrase/:phrase", handler.GetLobbyForPassphraseHandler) if debugMode { @@ -45,50 +40,3 @@ func main() { log.Fatal(router.RunTLS("chess.sw-gross.de:9999", cert_file, key_file)) } } - -func registerWebSocketConnection(c *gin.Context) { - webSocketConn, err := websocket.Accept(c.Writer, c.Request, &websocket.AcceptOptions{OriginPatterns: []string{"chess.sw-gross.de", "localhost:*"}}) - if err != nil { - log.Println(err) - return - } - go waitForAndHandlePlayerID(c, webSocketConn) -} - -func waitForAndHandlePlayerID(ctx context.Context, conn *websocket.Conn) { - msgType, msg, err := conn.Read(ctx) - if err != nil { - errorMessage := fmt.Sprintf("Reading from websocket connection did not work: %s", err) - log.Println(errorMessage) - conn.Close(websocket.StatusCode(400), errorMessage) - return - } - - log.Println("read from websocket endpoint: ", msgType, string(msg), err) - - var info api.PlayerInfo - err = json.Unmarshal(msg, &info) - if err != nil { - errorMessage := fmt.Sprintf("Unmarshaling message did not work: %s", err) - log.Println(errorMessage) - conn.Close(websocket.StatusCode(400), errorMessage) - return - } - - lobby := lobbies.GetLobbyRegistry().GetLobbyByUUID(*info.LobbyID) - if lobby == nil { - conn.Close(websocket.StatusCode(400), "lobby not found") - return - } - - player, found := lobby.GetPlayerByUUID(*info.PlayerID) - if !found { - conn.Close(websocket.StatusCode(400), "player not found") - return - } - if player.Conn.HasWebsocketConnection() { - player.Conn.Close("closing existing connection") - } - lobby.Game.SetWebsocketConnectionFor(ctx, player, conn) - log.Println("player after setting connection: ", player) -}