Handle reconnection

reconnection works now if the rejoining player enters the passphrase
again.

Some bugs are still happening:
1. The rejoining client is not told the state of the board
2. Invalid moves are not handled by the client (not sure why though)
3. The still-connected client should be told, that the opponent
   disconnected. Then the client should show the passphrase again
This commit is contained in:
Marco 2023-11-27 00:12:42 +01:00
parent efefa4ced5
commit cce0aa8162
4 changed files with 67 additions and 11 deletions

View File

@ -7,6 +7,7 @@ import (
"mchess_server/types" "mchess_server/types"
"github.com/google/uuid" "github.com/google/uuid"
"github.com/samber/lo"
) )
type Game struct { type Game struct {
@ -15,6 +16,7 @@ type Game struct {
players []*Player players []*Player
currentTurnPlayer *Player currentTurnPlayer *Player
gameState int gameState int
isBeingHandled bool
} }
const ( const (
@ -57,12 +59,24 @@ func (game *Game) prepare() {
game.players[0].color = types.White game.players[0].color = types.White
game.players[1].color = types.Black game.players[1].color = types.Black
game.players[0].SetDisconnectCallback(game.playerDisconnected)
game.players[1].SetDisconnectCallback(game.playerDisconnected)
err := game.notifyPlayersAboutGameStart() err := game.notifyPlayersAboutGameStart()
if err != nil { if err != nil {
return return
} }
} }
func (game *Game) StartHandling() {
if game.isBeingHandled {
return
}
game.isBeingHandled = true
go game.Handle()
}
func (game *Game) Handle() { func (game *Game) Handle() {
defer game.killGame() defer game.killGame()
@ -161,3 +175,11 @@ func (game Game) broadcastMove(move types.Move) error {
} }
return nil 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
}

View File

@ -6,7 +6,7 @@ import (
"errors" "errors"
"log" "log"
"mchess_server/api" "mchess_server/api"
conn "mchess_server/connection" "mchess_server/connection"
"mchess_server/types" "mchess_server/types"
"github.com/google/uuid" "github.com/google/uuid"
@ -15,17 +15,21 @@ import (
type Player struct { type Player struct {
Uuid uuid.UUID Uuid uuid.UUID
Conn *conn.Connection Conn *connection.Connection
InGame bool InGame bool
color types.ChessColor color types.ChessColor
disconnectCallback func(p *Player)
} }
func NewPlayer(uuid uuid.UUID) *Player { func NewPlayer(uuid uuid.UUID) *Player {
return &Player{ player := &Player{
Uuid: uuid, Uuid: uuid,
Conn: conn.NewConnection(conn.WithContext(context.Background())), Conn: connection.NewConnection(
connection.WithContext(context.Background())),
InGame: false, InGame: false,
} }
return player
} }
func (p Player) HasWebsocketConnection() bool { func (p Player) HasWebsocketConnection() bool {
@ -36,6 +40,16 @@ func (p *Player) SetWebsocketConnection(ctx context.Context, ws *websocket.Conn)
p.Conn.SetWebsocketConnection(ws) 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 { func (p *Player) SendMoveAndPosition(move types.Move, boardPosition string) error {
messageToSend, err := json.Marshal(api.WebsocketMessage{ messageToSend, err := json.Marshal(api.WebsocketMessage{
Type: api.MoveMessage, Type: api.MoveMessage,

View File

@ -12,6 +12,7 @@ type Connection struct {
wsConnectionEstablished chan bool wsConnectionEstablished chan bool
ctx context.Context ctx context.Context
buffer MessageBuffer buffer MessageBuffer
disconnectCallback func()
} }
func NewConnection(options ...func(*Connection)) *Connection { 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 { func (conn *Connection) HasWebsocketConnection() bool {
return conn.ws != nil return conn.ws != nil
} }
@ -57,7 +70,14 @@ func (conn *Connection) SetWebsocketConnection(ws *websocket.Conn) {
go func() { go func() {
for { 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)) conn.buffer.Insert(string(msg))
} }
}() }()

View File

@ -32,7 +32,7 @@ func newEmptyLobbyWithPassphrase() *Lobby {
func (l *Lobby) AddPlayerAndStartGameIfFull(player *chess.Player) { func (l *Lobby) AddPlayerAndStartGameIfFull(player *chess.Player) {
l.Game.AddPlayersToGame(player) l.Game.AddPlayersToGame(player)
if l.IsFull() { if l.IsFull() {
go l.Game.Handle() l.Game.StartHandling()
} }
} }