from __future__ import annotations import json import re import time from datetime import datetime, timezone from pathlib import Path from typing import Any from .models import EventRecord class EventEmitter: """Writes atomic JSON event files to the events directory.""" def __init__(self, events_dir: Path, node_name: str) -> None: self._events_dir = events_dir self._node_name = node_name self._seq = 0 events_dir.mkdir(parents=True, exist_ok=True) def _make_id(self, event_type: str, service: str) -> str: # Sequence suffix guarantees uniqueness even when multiple events of the # same type are emitted within the same millisecond. self._seq += 1 ts = int(time.time()) svc_slug = re.sub(r"[^a-z0-9]", "-", (service or "ha").lower())[:32].strip("-") return f"evt-{self._node_name}-{ts}-{event_type}-{svc_slug}-{self._seq}" def emit( self, event_type: str, severity: str, service: str, message: str, payload: dict[str, Any] | None = None, ) -> str: event_id = self._make_id(event_type, service) record = EventRecord( id=event_id, timestamp=int(time.time()), date=datetime.now(timezone.utc).isoformat(), type=event_type, severity=severity, node=self._node_name, service=service, message=message, payload=payload or {}, ) path = self._events_dir / f"{event_id}.json" tmp = path.with_suffix(".tmp") tmp.write_text(json.dumps(record.model_dump(), indent=2)) tmp.rename(path) return event_id