""" Event system for decoupled communication between server components. """ from abc import ABC from typing import Protocol, Dict, List import asyncio from shared.logger import logger class Event(ABC): """Base event class""" pass class EventHandler(Protocol): """Protocol for event handlers""" async def handle(self, event: Event) -> None: ... class EventBus: """Central event bus for publishing and subscribing to events""" def __init__(self): self._handlers: Dict[type[Event], List[EventHandler]] = {} self._logger = logger def subscribe(self, event_type: type[Event], handler: EventHandler): """Subscribe a handler to an event type""" if event_type not in self._handlers: self._handlers[event_type] = [] self._handlers[event_type].append(handler) self._logger.debug(f"Subscribed handler for {event_type.__name__}") async def publish(self, event: Event): """Publish an event to all subscribed handlers""" event_type = type(event) if event_type in self._handlers: self._logger.debug(f"Publishing {event_type.__name__} to {len(self._handlers[event_type])} handlers") # Run all handlers concurrently tasks = [] for handler in self._handlers[event_type]: tasks.append(self._handle_event_safely(handler, event)) if tasks: await asyncio.gather(*tasks, return_exceptions=True) async def _handle_event_safely(self, handler: EventHandler, event: Event): """Handle an event with error catching""" try: await handler.handle(event) except Exception as e: self._logger.error(f"Error handling event {type(event).__name__}: {e}") # Event types class SessionJoinedLobby(Event): """Event fired when a session joins a lobby""" def __init__(self, session_id: str, lobby_id: str, session_name: str): self.session_id = session_id self.lobby_id = lobby_id self.session_name = session_name class SessionLeftLobby(Event): """Event fired when a session leaves a lobby""" def __init__(self, session_id: str, lobby_id: str, session_name: str): self.session_id = session_id self.lobby_id = lobby_id self.session_name = session_name class UserNameChanged(Event): """Event fired when a user changes their name""" def __init__(self, session_id: str, old_name: str, new_name: str, lobby_ids: List[str]): self.session_id = session_id self.old_name = old_name self.new_name = new_name self.lobby_ids = lobby_ids class ChatMessageSent(Event): """Event fired when a chat message is sent""" def __init__(self, session_id: str, lobby_id: str, message: str, sender_name: str): self.session_id = session_id self.lobby_id = lobby_id self.message = message self.sender_name = sender_name class SessionDisconnected(Event): """Event fired when a session disconnects""" def __init__(self, session_id: str, session_name: str, lobby_ids: List[str]): self.session_id = session_id self.session_name = session_name self.lobby_ids = lobby_ids # Global event bus instance event_bus = EventBus()