Files
NaviGlassServer/server_context.py
2026-01-05 09:08:40 +08:00

99 lines
3.5 KiB
Python
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
# server_context.py
# -*- coding: utf-8 -*-
import asyncio
from typing import Dict, List, Set, Deque, Optional, Tuple, Any
from collections import deque
from concurrent.futures import ThreadPoolExecutor
from fastapi import WebSocket
class ServerContext:
"""
单例模式的服务器全局上下文
用于统一管理状态、资源引用和客户端连接,解决 app_main.py 中 global 变量混乱的问题。
"""
_instance = None
_lock = asyncio.Lock() # 异步锁,主要用于保护关键状态切换
def __new__(cls):
if cls._instance is None:
cls._instance = super(ServerContext, cls).__new__(cls)
cls._instance._initialized = False
return cls._instance
def __init__(self):
if self._initialized:
return
self._initialized = True
# ====== 1. WebSocket 客户端管理 ======
self.ui_clients: Dict[int, WebSocket] = {}
self.camera_viewers: Set[WebSocket] = set()
self.imu_ws_clients: Set[WebSocket] = set()
self.esp32_audio_ws: Optional[WebSocket] = None
self.esp32_camera_ws: Optional[WebSocket] = None
# ====== 2. 媒体数据缓冲 ======
self.current_partial: str = ""
self.recent_finals: List[str] = []
self.last_frames: Deque[Tuple[float, bytes]] = deque(maxlen=10)
# ====== 3. 业务状态标志 (State Flags) ======
# 盲道导航状态
self.navigation_active: bool = False
# 过马路导航状态
self.cross_street_active: bool = False
# Omni 对话状态
self.omni_conversation_active: bool = False
self.omni_previous_nav_state: Optional[str] = None
# YOLO 媒体流状态
self.yolomedia_running: bool = False
self.yolomedia_sending_frames: bool = False
# ====== 4. 核心组件引用 (Resources) ======
# 导航器实例
self.blind_path_navigator = None
self.cross_street_navigator = None
self.indoor_navigator = None
# 协调器
self.orchestrator = None
# 模型实例
self.yolo_seg_model = None
self.obstacle_detector = None
self.indoor_seg_model = None
# ====== 5. 异步处理资源 ======
# 帧处理线程池
self.frame_processing_executor = ThreadPoolExecutor(max_workers=3, thread_name_prefix="frame_proc")
# 异步帧处理状态
self.nav_processing_task: Optional[asyncio.Task] = None
self.nav_last_result_image: Any = None
self.nav_last_result_jpeg: Optional[bytes] = None
self.nav_pending_frame: Any = None
self.nav_processing_lock = asyncio.Lock()
self.nav_task_start_time: float = 0.0
def reset_navigation_state(self):
"""重置所有导航相关的状态标志"""
self.navigation_active = False
self.cross_street_active = False
self.omni_conversation_active = False
# 注意:这里不停止 orchestrator只是重置标志位
def add_ui_client(self, ws: WebSocket):
self.ui_clients[id(ws)] = ws
def remove_ui_client(self, ws: WebSocket):
self.ui_clients.pop(id(ws), None)
def get_ui_client_count(self) -> int:
return len(self.ui_clients)
# 全局访问点
ctx = ServerContext()