65 lines
1.9 KiB
Python
65 lines
1.9 KiB
Python
|
|
"""События домена и подписка модулей (задел; пока 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
|
||
|
|
|
||
|
|
|
||
|
|
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) -> None:
|
||
|
|
ev = AlertReceived(alert=alert, raw_payload_ref=raw_payload_ref)
|
||
|
|
await self.publish(ev)
|