mirror of
https://github.com/xinnan-tech/xiaozhi-esp32-server.git
synced 2026-07-21 22:53:56 +08:00
107 lines
3.0 KiB
Python
107 lines
3.0 KiB
Python
import json
|
|
import logging
|
|
import queue
|
|
import threading
|
|
import time
|
|
from typing import Any
|
|
|
|
logger = logging.getLogger(__name__)
|
|
|
|
|
|
class WakewordEventBridge:
|
|
def __init__(self) -> None:
|
|
self._clients: list[queue.Queue[str]] = []
|
|
self._clients_lock = threading.Lock()
|
|
self._running = True
|
|
|
|
@property
|
|
def is_running(self) -> bool:
|
|
return self._running
|
|
|
|
def build_ready_message(self) -> str:
|
|
return self.build_message(
|
|
"bridge_connected",
|
|
{"status": "ready"},
|
|
)
|
|
|
|
def publish_detected(self, wake_word: str) -> None:
|
|
self.publish(
|
|
"wake_word_detected",
|
|
{
|
|
"wake_word": wake_word,
|
|
"timestamp": time.time(),
|
|
},
|
|
)
|
|
|
|
def publish(self, event_type: str, payload: dict[str, Any] | None = None) -> None:
|
|
if not self._running:
|
|
return
|
|
|
|
message = self.build_message(event_type, payload or {})
|
|
with self._clients_lock:
|
|
clients = list(self._clients)
|
|
|
|
stale_clients: list[queue.Queue[str]] = []
|
|
for client_queue in clients:
|
|
try:
|
|
client_queue.put_nowait(message)
|
|
except queue.Full:
|
|
stale_clients.append(client_queue)
|
|
|
|
if stale_clients:
|
|
with self._clients_lock:
|
|
for client_queue in stale_clients:
|
|
if client_queue in self._clients:
|
|
self._clients.remove(client_queue)
|
|
|
|
def add_client(self) -> queue.Queue[str]:
|
|
client_queue: queue.Queue[str] = queue.Queue(maxsize=16)
|
|
with self._clients_lock:
|
|
self._clients.append(client_queue)
|
|
return client_queue
|
|
|
|
def build_message(
|
|
self,
|
|
event_type: str,
|
|
payload: dict[str, Any] | None = None,
|
|
request_id: str | None = None,
|
|
success: bool = True,
|
|
error: str | None = None,
|
|
) -> str:
|
|
message: dict[str, Any] = {
|
|
"type": event_type,
|
|
"requestId": request_id,
|
|
"success": success,
|
|
"payload": payload or {},
|
|
}
|
|
if error:
|
|
message["error"] = error
|
|
return json.dumps(message, ensure_ascii=False)
|
|
|
|
def remove_client(self, client_queue: queue.Queue[str]) -> None:
|
|
with self._clients_lock:
|
|
if client_queue in self._clients:
|
|
self._clients.remove(client_queue)
|
|
|
|
def publish_service_ready(self) -> None:
|
|
self.publish("service_ready", {"status": "ready"})
|
|
|
|
def publish_service_stopping(self) -> None:
|
|
self.publish("service_stopping", {"status": "stopping"})
|
|
|
|
def close(self) -> None:
|
|
if not self._running:
|
|
return
|
|
|
|
self.publish_service_stopping()
|
|
self._running = False
|
|
with self._clients_lock:
|
|
clients = list(self._clients)
|
|
self._clients.clear()
|
|
|
|
for client_queue in clients:
|
|
try:
|
|
client_queue.put_nowait("__bridge_closed__")
|
|
except queue.Full:
|
|
pass
|