2025-09-08 13:02:57 -07:00

101 lines
3.3 KiB
Python

"""
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()