diff --git a/api/move.go b/api/move.go index e5ce602..3438ee3 100644 --- a/api/move.go +++ b/api/move.go @@ -1,11 +1,33 @@ package api -type Coordinate struct { - Col int `json:"col"` - Row int `json:"row"` +import "local/m/mchess_server/types" + +type WebsocketMessage struct { + Type MessageType `json:"messageType"` + Move *types.Move `json:"move,omitempty"` + Color *Color `json:"color,omitempty"` } -type Move struct { - StartSquare Coordinate `json:"startSquare"` - EndSquare Coordinate `json:"endSquare"` +type MessageType string + +const ( + MoveMessage MessageType = "move" + ColorDetermined MessageType = "colorDetermined" +) + +type Color string + +const ( + Black Color = "black" + White Color = "white" +) + +func (m WebsocketMessage) IsValidMove() bool { + if m.Type != MoveMessage { + return false + } + if m.Move == nil { + return false + } + return true } diff --git a/chess/game.go b/chess/game.go index f97ed56..46d8d4d 100644 --- a/chess/game.go +++ b/chess/game.go @@ -3,6 +3,7 @@ package chess import ( "encoding/json" "local/m/mchess_server/api" + "local/m/mchess_server/types" "log" "time" @@ -48,30 +49,26 @@ func (game *Game) Handle() { return } + err := game.notifyPlayersAboutGameStart() + if err != nil { + return + } + gameState := PlayerToMove game.currentTurnPlayer = game.GetPlayer1() - var move api.Move - var receivedMessage []byte - var err error + var receivedMove types.Move for { switch gameState { case PlayerToMove: - _, receivedMessage, err = game.currentTurnPlayer.ReadMessageFromPlayer() + receivedMove, err = game.currentTurnPlayer.ReadMove() if err != nil { log.Println("Error while reading message:", err) - // At the moment, we return when there is an error while reading a message. - // This means, the game just ends uncontrolled return } - err = json.Unmarshal(receivedMessage, &move) - log.Println("Player ", game.currentTurnPlayer, " moved:\n", move) + log.Println("Player ", game.currentTurnPlayer, " moved:\n", receivedMove) - if err != nil { - log.Println("Game: ", game.id, err) - continue - } gameState = CheckPlayerChange case CheckPlayerChange: @@ -81,18 +78,13 @@ func (game *Game) Handle() { game.currentTurnPlayer = game.players[0] } - err := game.GetPlayer1().WriteMessageToPlayer(receivedMessage) + err = game.broadcastMove(receivedMove) if err != nil { - log.Println("Error during message writing:", err) - continue + log.Println("Error broadcasting move ", err) + return } - err = game.GetPlayer2().WriteMessageToPlayer(receivedMessage) - if err != nil { - log.Println("Error during message writing:", err) - continue - } - gameState = PlayerToMove + gameState = PlayerToMove } log.Println("GameState = ", gameState) @@ -128,3 +120,35 @@ func (game *Game) waitForWebsocketConnections() bool { } return true } + +func (game Game) notifyPlayersAboutGameStart() error { + white := api.White + black := api.Black + colorDeterminedPlayer1, err := json.Marshal(api.WebsocketMessage{Type: api.ColorDetermined, Color: &white}) + if err != nil { + log.Println("Error marshalling 'colorDetermined' message for player 1", err) + return err + } + colorDeterminedPlayer2, err := json.Marshal(api.WebsocketMessage{Type: api.ColorDetermined, Color: &black}) + if err != nil { + log.Println("Error marshalling 'colorDetermined' message for player 2", err) + return err + } + + game.GetPlayer1().writeMessage(colorDeterminedPlayer1) + game.GetPlayer2().writeMessage(colorDeterminedPlayer2) + return nil +} + +func (game Game) broadcastMove(move types.Move) error { + err := game.GetPlayer1().SendMove(move) + if err != nil { + return err + } + + err = game.GetPlayer2().SendMove(move) + if err != nil { + return err + } + return nil +} diff --git a/chess/player.go b/chess/player.go index a978f4e..220a8f3 100644 --- a/chess/player.go +++ b/chess/player.go @@ -2,6 +2,10 @@ package chess import ( "context" + "encoding/json" + "errors" + "local/m/mchess_server/api" + "local/m/mchess_server/types" "log" "time" @@ -32,15 +36,52 @@ func (p *Player) SetConnection(ctx context.Context, conn *websocket.Conn) { p.wsConnEstablished <- true } -func (p *Player) WriteMessageToPlayer(msg []byte) error { - log.Printf("Writing message: %s to player %d", string(msg), p.Uuid) +func (p *Player) SendMove(move types.Move) error { + messageToSend, err := json.Marshal(api.WebsocketMessage{ + Type: api.MoveMessage, + Move: &move, + }) + if err != nil { + log.Println("Error while marshalling: ", err) + return err + } + + err = p.writeMessage(messageToSend) + if err != nil { + log.Println("Error during message writing:", err) + return err + } + return nil +} + +func (p *Player) writeMessage(msg []byte) error { + log.Printf("Writing message: %s to player %s", string(msg), p.Uuid.String()) return p.Conn.Write(p.context, websocket.MessageText, msg) } -func (p *Player) ReadMessageFromPlayer() (websocket.MessageType, []byte, error) { +func (p *Player) ReadMove() (types.Move, error) { + _, receivedMessage, err := p.readMessage() + if err != nil { + return types.Move{}, err + } + + var msg api.WebsocketMessage + err = json.Unmarshal(receivedMessage, &msg) + if err != nil { + return types.Move{}, err + } + + if !msg.IsValidMove() { + return types.Move{}, errors.New("not a valid move") + } + + return *msg.Move, nil +} + +func (p *Player) readMessage() (websocket.MessageType, []byte, error) { msgType, msg, err := p.Conn.Read(p.context) - log.Printf("Reading message: %s (with messagetype %d) from player %d", string(msg), msgType, p.Uuid) + log.Printf("Reading message: %s from player %s", string(msg), p.Uuid.String()) return msgType, msg, err } diff --git a/main.go b/main.go index 97c7608..1b6cb7d 100644 --- a/main.go +++ b/main.go @@ -66,7 +66,7 @@ func registerForRandomGame(c *gin.Context) { } func registerWebSocketConnection(c *gin.Context) { - webSocketConn, err := websocket.Accept(c.Writer, c.Request, &websocket.AcceptOptions{OriginPatterns: []string{"chess.sw-gross.de"}}) + webSocketConn, err := websocket.Accept(c.Writer, c.Request, &websocket.AcceptOptions{OriginPatterns: []string{"chess.sw-gross.de", "localhost:*"}}) if err != nil { log.Println(err) return diff --git a/types/chess_types.go b/types/chess_types.go new file mode 100644 index 0000000..8f5744d --- /dev/null +++ b/types/chess_types.go @@ -0,0 +1,11 @@ +package types + +type Coordinate struct { + Col int `json:"col"` + Row int `json:"row"` +} + +type Move struct { + StartSquare Coordinate `json:"startSquare"` + EndSquare Coordinate `json:"endSquare"` +}