from dataclasses import dataclass, field from typing import Any, Awaitable, Callable, Dict, List, Tuple from core.error_handler import capture_errors from core.logger import get_logger logger = get_logger("core.events") EventHandler = Callable[["Event"], Awaitable[None]] @dataclass class Event: name: str payload: Dict[str, Any] = field(default_factory=dict) cancelled: bool = False def cancel(self) -> None: self.cancelled = True class EventDispatcher: def __init__(self) -> None: self._handlers: Dict[str, List[Tuple[int, EventHandler]]] = {} def on(self, event_name: str, handler: EventHandler, priority: int = 50) -> None: handlers = self._handlers.setdefault(event_name, []) handlers.append((priority, capture_errors(handler))) handlers.sort(key=lambda item: item[0]) def off(self, event_name: str, handler: EventHandler) -> None: if event_name not in self._handlers: return self._handlers[event_name] = [ item for item in self._handlers[event_name] if item[1] != handler ] async def emit(self, event_name: str, **payload: Any) -> Event: event = Event(name=event_name, payload=payload) handlers = list(self._handlers.get(event_name, [])) for _, handler in handlers: await handler(event) if event.cancelled: logger.debug("Event %s cancelled", event_name) break return event