import logging from typing import Dict, Set import socketio logger = logging.getLogger(f'{__name__}.ConnectionManager') class ConnectionManager: """Manages WebSocket connections and rooms""" def __init__(self, sio: socketio.AsyncServer): self.sio = sio self.user_sessions: Dict[str, str] = {} # sid -> user_id self.game_rooms: Dict[str, Set[str]] = {} # game_id -> set of sids async def connect(self, sid: str, user_id: str) -> None: """Register a new connection""" self.user_sessions[sid] = user_id logger.info(f"User {user_id} connected with session {sid}") async def disconnect(self, sid: str) -> None: """Handle disconnection""" user_id = self.user_sessions.pop(sid, None) if user_id: logger.info(f"User {user_id} disconnected (session {sid})") # Remove from all game rooms for game_id, sids in self.game_rooms.items(): if sid in sids: sids.remove(sid) await self.broadcast_to_game( game_id, "user_disconnected", {"user_id": user_id} ) async def join_game(self, sid: str, game_id: str, role: str) -> None: """Add user to game room""" await self.sio.enter_room(sid, game_id) if game_id not in self.game_rooms: self.game_rooms[game_id] = set() self.game_rooms[game_id].add(sid) user_id = self.user_sessions.get(sid) logger.info(f"User {user_id} joined game {game_id} as {role}") await self.broadcast_to_game( game_id, "user_connected", {"user_id": user_id, "role": role} ) async def leave_game(self, sid: str, game_id: str) -> None: """Remove user from game room""" await self.sio.leave_room(sid, game_id) if game_id in self.game_rooms: self.game_rooms[game_id].discard(sid) user_id = self.user_sessions.get(sid) logger.info(f"User {user_id} left game {game_id}") async def broadcast_to_game( self, game_id: str, event: str, data: dict ) -> None: """Broadcast event to all users in game room""" await self.sio.emit(event, data, room=game_id) logger.debug(f"Broadcast {event} to game {game_id}") async def emit_to_user(self, sid: str, event: str, data: dict) -> None: """Emit event to specific user""" await self.sio.emit(event, data, room=sid) def get_game_participants(self, game_id: str) -> Set[str]: """Get all session IDs in game room""" return self.game_rooms.get(game_id, set())