47 lines
1.5 KiB
Python
47 lines
1.5 KiB
Python
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
|