diff --git a/chess/game.go b/chess/game.go index df94680..800357a 100644 --- a/chess/game.go +++ b/chess/game.go @@ -7,6 +7,7 @@ import ( "mchess_server/types" "github.com/google/uuid" + "github.com/samber/lo" ) type Game struct { @@ -15,6 +16,7 @@ type Game struct { players []*Player currentTurnPlayer *Player gameState int + isBeingHandled bool } const ( @@ -57,16 +59,28 @@ func (game *Game) prepare() { game.players[0].color = types.White game.players[1].color = types.Black + game.players[0].SetDisconnectCallback(game.playerDisconnected) + game.players[1].SetDisconnectCallback(game.playerDisconnected) + err := game.notifyPlayersAboutGameStart() if err != nil { return } } +func (game *Game) StartHandling() { + if game.isBeingHandled { + return + } + + game.isBeingHandled = true + go game.Handle() +} + func (game *Game) Handle() { defer game.killGame() - game.prepare() + game.prepare() var receivedMove types.Move var err error @@ -161,3 +175,11 @@ func (game Game) broadcastMove(move types.Move) error { } return nil } + +func (game *Game) playerDisconnected(p *Player) { + log.Println(string(p.color), " disconnected") + playerLeft := lo.Filter(game.players, func(player *Player, _ int) bool { + return player.color != p.color + }) + game.players = playerLeft +} diff --git a/chess/player.go b/chess/player.go index 353da54..8202fac 100644 --- a/chess/player.go +++ b/chess/player.go @@ -6,7 +6,7 @@ import ( "errors" "log" "mchess_server/api" - conn "mchess_server/connection" + "mchess_server/connection" "mchess_server/types" "github.com/google/uuid" @@ -14,18 +14,22 @@ import ( ) type Player struct { - Uuid uuid.UUID - Conn *conn.Connection - InGame bool - color types.ChessColor + Uuid uuid.UUID + Conn *connection.Connection + InGame bool + color types.ChessColor + disconnectCallback func(p *Player) } func NewPlayer(uuid uuid.UUID) *Player { - return &Player{ - Uuid: uuid, - Conn: conn.NewConnection(conn.WithContext(context.Background())), + player := &Player{ + Uuid: uuid, + Conn: connection.NewConnection( + connection.WithContext(context.Background())), InGame: false, } + + return player } func (p Player) HasWebsocketConnection() bool { @@ -36,6 +40,16 @@ func (p *Player) SetWebsocketConnection(ctx context.Context, ws *websocket.Conn) p.Conn.SetWebsocketConnection(ws) } +func (p *Player) SetDisconnectCallback(cb func(*Player)) { + // Todo: Fucking complicated + p.Conn.SetDisconnectCallback(p.PlayerDisconnectedCallback) + p.disconnectCallback = cb +} + +func (p *Player) PlayerDisconnectedCallback() { + p.disconnectCallback(p) +} + func (p *Player) SendMoveAndPosition(move types.Move, boardPosition string) error { messageToSend, err := json.Marshal(api.WebsocketMessage{ Type: api.MoveMessage, diff --git a/connection/type.go b/connection/type.go index b61ae3a..b4c6ebd 100644 --- a/connection/type.go +++ b/connection/type.go @@ -12,6 +12,7 @@ type Connection struct { wsConnectionEstablished chan bool ctx context.Context buffer MessageBuffer + disconnectCallback func() } func NewConnection(options ...func(*Connection)) *Connection { @@ -39,6 +40,18 @@ func WithContext(ctx context.Context) func(*Connection) { } } +func WithDisconnectCallback(cb func()) func(*Connection) { + return func(c *Connection) { + if cb != nil { + c.disconnectCallback = cb + } + } +} + +func (conn *Connection) SetDisconnectCallback(cb func()) { + conn.disconnectCallback = cb +} + func (conn *Connection) HasWebsocketConnection() bool { return conn.ws != nil } @@ -57,7 +70,14 @@ func (conn *Connection) SetWebsocketConnection(ws *websocket.Conn) { go func() { for { - _, msg, _ := conn.ws.Read(conn.ctx) + _, msg, err := conn.ws.Read(conn.ctx) + if err != nil { + log.Println("while reading from websocket: %w", err) + if conn.disconnectCallback != nil { + conn.disconnectCallback() + } + return + } conn.buffer.Insert(string(msg)) } }() diff --git a/lobby_registry/lobby.go b/lobby_registry/lobby.go index d47cb3b..d900002 100644 --- a/lobby_registry/lobby.go +++ b/lobby_registry/lobby.go @@ -32,7 +32,7 @@ func newEmptyLobbyWithPassphrase() *Lobby { func (l *Lobby) AddPlayerAndStartGameIfFull(player *chess.Player) { l.Game.AddPlayersToGame(player) if l.IsFull() { - go l.Game.Handle() + l.Game.StartHandling() } }