feat: unify card runtime and event-driven web ui
This commit is contained in:
parent
0edf8c3fef
commit
4dfb7ca3cc
105 changed files with 17382 additions and 8505 deletions
47
ui_event_bus.py
Normal file
47
ui_event_bus.py
Normal file
|
|
@ -0,0 +1,47 @@
|
|||
from __future__ import annotations
|
||||
|
||||
import asyncio
|
||||
import uuid
|
||||
from collections.abc import Iterable
|
||||
from typing import Any
|
||||
|
||||
|
||||
class UiEventBus:
|
||||
def __init__(self) -> None:
|
||||
self._lock = asyncio.Lock()
|
||||
self._subscribers: dict[str, tuple[str, asyncio.Queue[dict[str, Any]]]] = {}
|
||||
|
||||
async def subscribe(self, chat_id: str) -> tuple[str, asyncio.Queue[dict[str, Any]]]:
|
||||
queue: asyncio.Queue[dict[str, Any]] = asyncio.Queue(maxsize=64)
|
||||
subscription_id = uuid.uuid4().hex
|
||||
async with self._lock:
|
||||
self._subscribers[subscription_id] = (chat_id, queue)
|
||||
return subscription_id, queue
|
||||
|
||||
async def unsubscribe(self, subscription_id: str) -> None:
|
||||
async with self._lock:
|
||||
self._subscribers.pop(subscription_id, None)
|
||||
|
||||
async def publish(
|
||||
self,
|
||||
payload: dict[str, Any],
|
||||
*,
|
||||
chat_id: str | None = None,
|
||||
broadcast: bool = False,
|
||||
) -> None:
|
||||
async with self._lock:
|
||||
targets = list(self._iter_target_queues(chat_id=chat_id, broadcast=broadcast))
|
||||
for queue in targets:
|
||||
while queue.full():
|
||||
try:
|
||||
queue.get_nowait()
|
||||
except asyncio.QueueEmpty:
|
||||
break
|
||||
queue.put_nowait(dict(payload))
|
||||
|
||||
def _iter_target_queues(
|
||||
self, *, chat_id: str | None, broadcast: bool
|
||||
) -> Iterable[asyncio.Queue[dict[str, Any]]]:
|
||||
for subscriber_chat_id, queue in self._subscribers.values():
|
||||
if broadcast or subscriber_chat_id == chat_id:
|
||||
yield queue
|
||||
Loading…
Add table
Add a link
Reference in a new issue