Fix V2 race conditions, auth gaps, serialization bugs, and async stats
Phase 1 - Critical Fixes: - Add game_lock (asyncio.Lock) to Room class for serializing mutations - Wrap all game action handlers in lock to prevent race conditions - Split Card.to_dict into to_dict (full data) and to_client_dict (hidden) - Fix CardState.from_dict to handle missing rank/suit gracefully - Fix GameOptions reconstruction in recovery_service (dict -> object) - Extend state cache TTL from 4h to 24h, add touch_game method Phase 2 - Security: - Add optional WebSocket authentication via token query param - Use authenticated user ID/name when available - Add auth support to spectator WebSocket endpoint Phase 3 - Performance: - Make stats processing async (fire-and-forget) to avoid blocking game completion notifications Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
This commit is contained in:
@@ -140,17 +140,36 @@ class Card:
|
||||
"""
|
||||
Convert card to dictionary for JSON serialization.
|
||||
|
||||
Always includes full card data (rank/suit/face_up) for server-side
|
||||
caching and event sourcing. Use to_client_dict() for client views
|
||||
that should hide face-down cards.
|
||||
|
||||
Args:
|
||||
reveal: If True, show card details even if face-down.
|
||||
reveal: Ignored for backwards compatibility. Use to_client_dict() instead.
|
||||
|
||||
Returns:
|
||||
Dict with full card info (suit, rank, face_up).
|
||||
"""
|
||||
return {
|
||||
"suit": self.suit.value,
|
||||
"rank": self.rank.value,
|
||||
"face_up": self.face_up,
|
||||
}
|
||||
|
||||
def to_client_dict(self) -> dict:
|
||||
"""
|
||||
Convert card to dictionary for client display.
|
||||
|
||||
Hides card details if face-down to prevent cheating.
|
||||
|
||||
Returns:
|
||||
Dict with card info, or just {face_up: False} if hidden.
|
||||
"""
|
||||
if self.face_up or reveal:
|
||||
if self.face_up:
|
||||
return {
|
||||
"suit": self.suit.value,
|
||||
"rank": self.rank.value,
|
||||
"face_up": self.face_up,
|
||||
"face_up": True,
|
||||
}
|
||||
return {"face_up": False}
|
||||
|
||||
@@ -390,7 +409,9 @@ class Player:
|
||||
Returns:
|
||||
List of card dictionaries.
|
||||
"""
|
||||
return [card.to_dict(reveal) for card in self.cards]
|
||||
if reveal:
|
||||
return [card.to_dict() for card in self.cards]
|
||||
return [card.to_client_dict() for card in self.cards]
|
||||
|
||||
|
||||
class GamePhase(Enum):
|
||||
|
||||
Reference in New Issue
Block a user