37 lines
1.1 KiB
Python
37 lines
1.1 KiB
Python
import asyncio
|
|
from dataclasses import dataclass, field
|
|
from datetime import datetime, timezone
|
|
|
|
|
|
@dataclass(slots=True)
|
|
class WisperEvent:
|
|
role: str
|
|
text: str
|
|
timestamp: str = field(
|
|
default_factory=lambda: datetime.now(timezone.utc).isoformat(timespec="seconds")
|
|
)
|
|
|
|
def to_dict(self) -> dict[str, str]:
|
|
return {"role": self.role, "text": self.text, "timestamp": self.timestamp}
|
|
|
|
|
|
class WisperBus:
|
|
def __init__(self) -> None:
|
|
self._subscribers: set[asyncio.Queue[WisperEvent]] = set()
|
|
self._lock = asyncio.Lock()
|
|
|
|
async def subscribe(self) -> asyncio.Queue[WisperEvent]:
|
|
queue: asyncio.Queue[WisperEvent] = asyncio.Queue()
|
|
async with self._lock:
|
|
self._subscribers.add(queue)
|
|
return queue
|
|
|
|
async def unsubscribe(self, queue: asyncio.Queue[WisperEvent]) -> None:
|
|
async with self._lock:
|
|
self._subscribers.discard(queue)
|
|
|
|
async def publish(self, event: WisperEvent) -> None:
|
|
async with self._lock:
|
|
subscribers = list(self._subscribers)
|
|
for queue in subscribers:
|
|
queue.put_nowait(event)
|