From a4a26f04d4c06dd1402318ec218204ac5d8b70cb Mon Sep 17 00:00:00 2001 From: minie4 Date: Tue, 11 Mar 2025 12:32:36 +0100 Subject: [PATCH] fix(backend): fix crash when trying to update player data concurrently --- backend/api/websocket.go | 25 +++++++++++++++++++++++++ backend/db/serializable_types.go | 1 + backend/game/game.go | 1 + backend/types/types.go | 4 ++++ 4 files changed, 31 insertions(+) diff --git a/backend/api/websocket.go b/backend/api/websocket.go index 60b739a..abacc4f 100644 --- a/backend/api/websocket.go +++ b/backend/api/websocket.go @@ -93,6 +93,9 @@ func onPlayerJoin(client *socket.Socket, room *types.Room, player *types.Player) }) client.On("UpdatePlayer", func(datas ...any) { + player.Mutex.Lock() + defer player.Mutex.Unlock() + updatePlayerRequest := types.C2S_UpdatePlayer{} unpackData(datas, &updatePlayerRequest) if updatePlayerRequest.PlayerId != player.PlayerId && !player.HasPermissionBit(types.PermissionHost) { @@ -114,6 +117,10 @@ func onPlayerJoin(client *socket.Socket, room *types.Room, player *types.Player) } slog.Debug("Updating player data", "roomId", room.RoomId, "playerId", updatePlayerRequest.PlayerId, "username", targetPlayer.Username, "request", updatePlayerRequest) + if player != targetPlayer { + targetPlayer.Mutex.Lock() + defer targetPlayer.Mutex.Unlock() + } if updatePlayerRequest.Username != nil { if room.IsUsernameAvailable(*updatePlayerRequest.Username) { targetPlayer.Username = *updatePlayerRequest.Username @@ -133,6 +140,9 @@ func onPlayerJoin(client *socket.Socket, room *types.Room, player *types.Player) }) client.On("KickPlayer", func(datas ...any) { + player.Mutex.Lock() + defer player.Mutex.Unlock() + kickPlayerRequest := types.C2S_KickPlayer{} unpackData(datas, &kickPlayerRequest) if !player.HasPermissionBit(types.PermissionHost) { @@ -153,6 +163,9 @@ func onPlayerJoin(client *socket.Socket, room *types.Room, player *types.Player) return } + if player == targetPlayer { + player.Mutex.Unlock() + } if room.RemovePlayer(*targetPlayer) { slog.Debug("Player was kicked from room", "playerId", player.PlayerId, "targetPlayerId", kickPlayerRequest.PlayerId, "roomId", room.RoomId) if targetPlayer.Connection.IsConnected && targetPlayer.Connection.Socket != nil { @@ -163,6 +176,9 @@ func onPlayerJoin(client *socket.Socket, room *types.Room, player *types.Player) }) } } + if player == targetPlayer { + player.Mutex.Lock() + } game.OnRoomUpdate(room) }) @@ -187,6 +203,9 @@ func onPlayerJoin(client *socket.Socket, room *types.Room, player *types.Player) }) client.On("DrawCard", func(datas ...any) { + player.Mutex.Lock() + defer player.Mutex.Unlock() + if !verifyPlayerIsActivePlayer(room, player) { return } @@ -199,6 +218,9 @@ func onPlayerJoin(client *socket.Socket, room *types.Room, player *types.Player) }) client.On("PlayCard", func(datas ...any) { + player.Mutex.Lock() + defer player.Mutex.Unlock() + if !verifyPlayerIsActivePlayer(room, player) { return } @@ -240,6 +262,9 @@ func onPlayerJoin(client *socket.Socket, room *types.Room, player *types.Player) }) client.On("UpdatePlayedCard", func(datas ...any) { + player.Mutex.Lock() + defer player.Mutex.Unlock() + if !verifyPlayerIsActivePlayer(room, player) { return } diff --git a/backend/db/serializable_types.go b/backend/db/serializable_types.go index a44cdca..6169b7d 100644 --- a/backend/db/serializable_types.go +++ b/backend/db/serializable_types.go @@ -28,6 +28,7 @@ func (serializable *SerializablePlayer) ToPlayer(cardDeckId int) types.Player { Permissions: serializable.Permissions, Connection: types.WebsocketConnection{IsConnected: false}, Cards: cards, + Mutex: &sync.Mutex{}, } player.ResetInactivity() return player diff --git a/backend/game/game.go b/backend/game/game.go index 33967b6..f8582d7 100644 --- a/backend/game/game.go +++ b/backend/game/game.go @@ -87,6 +87,7 @@ func JoinRoom(room *types.Room, requestedUsername string) *types.Player { Connection: types.WebsocketConnection{ IsConnected: false, }, + Mutex: &sync.Mutex{}, } player.ResetInactivity() room.AppendPlayer(player) diff --git a/backend/types/types.go b/backend/types/types.go index 4312ee9..0aaacf7 100644 --- a/backend/types/types.go +++ b/backend/types/types.go @@ -35,6 +35,7 @@ type Player struct { Cards []Card `json:"-"` Connection WebsocketConnection `bson:"-" json:"-"` InactivityTimeout int `bson:"-" json:"-"` + Mutex *sync.Mutex } func (player *Player) ResetInactivity() { @@ -93,6 +94,9 @@ func (room *Room) AppendPlayer(player *Player) { func (room *Room) RemovePlayer(target Player) bool { room.PlayersMutex.Lock() defer room.PlayersMutex.Unlock() + target.Mutex.Lock() + defer target.Mutex.Unlock() + return room.RemovePlayerUnsafe(target) }