101 lines
3.3 KiB
Python
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()
|