Initial curated ServiceMap source from 7a0a61232d05ba9097432abef6f7f4102a64d0b8
This commit is contained in:
commit
105251b9c8
96 files changed
+23587
No files matched your search
@@ -0,0 +1,63 @@
|
||||
from __future__ import annotations
|
||||
|
||||
import asyncio
|
||||
import json
|
||||
from queue import Empty, Full, Queue
|
||||
from threading import Lock
|
||||
from typing import Any
|
||||
|
||||
|
||||
class EventBus:
|
||||
"""Small bounded fan-out bus used by the SSE endpoint.
|
||||
|
||||
Persistence is handled by SQLite; this bus only wakes currently connected
|
||||
clients. A queue per client keeps one slow browser from blocking probes or
|
||||
other subscribers.
|
||||
"""
|
||||
|
||||
def __init__(self, max_queue_size: int = 100) -> None:
|
||||
self.max_queue_size = max_queue_size
|
||||
self._subscribers: set[Queue[dict[str, Any]]] = set()
|
||||
self._lock = Lock()
|
||||
|
||||
def subscribe(self) -> Queue[dict[str, Any]]:
|
||||
queue: Queue[dict[str, Any]] = Queue(maxsize=self.max_queue_size)
|
||||
with self._lock:
|
||||
self._subscribers.add(queue)
|
||||
return queue
|
||||
|
||||
def unsubscribe(self, queue: Queue[dict[str, Any]]) -> None:
|
||||
with self._lock:
|
||||
self._subscribers.discard(queue)
|
||||
|
||||
def publish(self, payload: dict[str, Any]) -> None:
|
||||
with self._lock:
|
||||
subscribers = tuple(self._subscribers)
|
||||
for queue in subscribers:
|
||||
try:
|
||||
queue.put_nowait(payload)
|
||||
except Full:
|
||||
# Drop the oldest event for a lagging client, then retain the
|
||||
# newest state notification. The durable event journal remains
|
||||
# the source of truth if a client reconnects.
|
||||
try:
|
||||
queue.get_nowait()
|
||||
except Empty:
|
||||
pass
|
||||
try:
|
||||
queue.put_nowait(payload)
|
||||
except Full:
|
||||
pass
|
||||
event_bus = EventBus()
|
||||
|
||||
|
||||
def sse_payload(payload: dict[str, Any]) -> str:
|
||||
event_type = str(payload.get("event_type", "update"))
|
||||
return f"event: {event_type}\ndata: {json.dumps(payload, default=str)}\n\n"
|
||||
|
||||
|
||||
async def next_event(queue: Queue[dict[str, Any]], timeout: float = 15.0) -> dict[str, Any] | None:
|
||||
try:
|
||||
return await asyncio.to_thread(queue.get, True, timeout)
|
||||
except Empty:
|
||||
return None
|
||||
Reference in new issue
Block a user