"""Server-Sent Events (SSE) utilities.""" from __future__ import annotations import json import queue import time from typing import Any, Generator def sse_stream( data_queue: queue.Queue, timeout: float = 1.0, keepalive_interval: float = 30.0, stop_check: callable = None ) -> Generator[str, None, None]: """ Generate SSE stream from a queue. Args: data_queue: Queue to read messages from timeout: Queue get timeout in seconds keepalive_interval: Seconds between keepalive messages stop_check: Optional callable that returns True to stop the stream Yields: SSE formatted strings """ last_keepalive = time.time() while True: # Check if we should stop if stop_check and stop_check(): break try: msg = data_queue.get(timeout=timeout) last_keepalive = time.time() yield format_sse(msg) except queue.Empty: # Send keepalive if enough time has passed now = time.time() if now - last_keepalive >= keepalive_interval: yield format_sse({'type': 'keepalive'}) last_keepalive = now def format_sse(data: dict[str, Any] | str, event: str | None = None) -> str: """ Format data as SSE message. Args: data: Data to send (will be JSON encoded if dict) event: Optional event name Returns: SSE formatted string """ if isinstance(data, dict): data = json.dumps(data) lines = [] if event: lines.append(f"event: {event}") lines.append(f"data: {data}") lines.append("") lines.append("") return '\n'.join(lines) def clear_queue(q: queue.Queue) -> int: """ Clear all items from a queue. Args: q: Queue to clear Returns: Number of items cleared """ count = 0 while True: try: q.get_nowait() count += 1 except queue.Empty: break return count