"""События домена и подписка модулей (задел; пока in-memory).""" from __future__ import annotations from collections.abc import Awaitable, Callable from dataclasses import dataclass, field from datetime import datetime, timezone from typing import Protocol from uuid import UUID from onguard24.domain.entities import Alert @dataclass class DomainEvent: """Базовый тип события.""" name: str = "domain.generic" occurred_at: datetime = field(default_factory=lambda: datetime.now(timezone.utc)) @dataclass class AlertReceived(DomainEvent): """Алерт принят в систему (после нормализации).""" name: str = "alert.received" alert: Alert | None = None raw_payload_ref: UUID | None = None grafana_org_slug: str | None = None service_name: str | None = None Handler = Callable[[DomainEvent], Awaitable[None]] class Module(Protocol): """Модуль (schedules, contacts, …) может подписаться на события.""" @property def name(self) -> str: ... async def on_event(self, event: DomainEvent) -> None: ... class EventBus(Protocol): async def publish(self, event: DomainEvent) -> None: ... def subscribe(self, event_name: str, handler: Handler) -> None: ... class InMemoryEventBus: """Простая шина для тестов и раннего прототипа.""" def __init__(self) -> None: self._subs: dict[str, list[Handler]] = {} def subscribe(self, event_name: str, handler: Handler) -> None: self._subs.setdefault(event_name, []).append(handler) async def publish(self, event: DomainEvent) -> None: for h in self._subs.get(event.name, []): await h(event) async def publish_alert_received( self, alert: Alert, raw_payload_ref: UUID | None = None, *, grafana_org_slug: str | None = None, service_name: str | None = None, ) -> None: ev = AlertReceived( alert=alert, raw_payload_ref=raw_payload_ref, grafana_org_slug=grafana_org_slug, service_name=service_name, ) await self.publish(ev)