rebuild
This commit is contained in:
75
server.py
75
server.py
@@ -77,6 +77,7 @@ server_stats = None
|
||||
stats_lock = None
|
||||
cleanup_task = None
|
||||
templates = None
|
||||
admin_frame_queues = None
|
||||
|
||||
# Администраторы
|
||||
ADMINS = [
|
||||
@@ -571,6 +572,7 @@ async def lifespan(app: FastAPI):
|
||||
admin_websockets = {}
|
||||
video_queues = {}
|
||||
command_queues = {}
|
||||
admin_frame_queues = {}
|
||||
room_stats = {}
|
||||
server_stats = {
|
||||
"total_rooms": 0,
|
||||
@@ -1072,6 +1074,17 @@ async def client_websocket_endpoint(websocket: WebSocket, room_id: str, password
|
||||
print(f"[WebSocket Client] ⚠️ {client_id}: video queue is FULL, dropping frame")
|
||||
else:
|
||||
print(f"[WebSocket Client] ❌ {client_id}: video_queue not found!")
|
||||
# Также пробуем переслать тот же байтовый кадр администраторам, если кто-то смотрит
|
||||
try:
|
||||
if admin_frame_queues is not None and client_id in admin_frame_queues:
|
||||
aq = admin_frame_queues[client_id]
|
||||
try:
|
||||
aq.put_nowait(message)
|
||||
except asyncio.QueueFull:
|
||||
# Если очередь админа переполнена, пропускаем кадр
|
||||
pass
|
||||
except Exception:
|
||||
pass
|
||||
|
||||
elif isinstance(message, str):
|
||||
try:
|
||||
@@ -1113,6 +1126,12 @@ async def client_websocket_endpoint(websocket: WebSocket, room_id: str, password
|
||||
|
||||
if video_processor:
|
||||
video_processor.stop()
|
||||
# Очищаем очередь админа, чтобы фреймы перестали отправляться
|
||||
try:
|
||||
if admin_frame_queues is not None and client_id in admin_frame_queues:
|
||||
del admin_frame_queues[client_id]
|
||||
except Exception:
|
||||
pass
|
||||
print(f"[WebSocket Client] ✓ VideoProcessor stopped for {client_id}")
|
||||
print(f"[WebSocket Client] ===== END OF CONNECTION =====\n")
|
||||
|
||||
@@ -1191,26 +1210,60 @@ async def admin_websocket_endpoint(websocket: WebSocket, session_id: str):
|
||||
|
||||
async def _stream_client_to_admin(client_id: str, admin_session_id: str):
|
||||
"""Потоковая передача видео от клиента к администратору"""
|
||||
global admin_frame_queues, admin_websockets, clients, stats_lock
|
||||
|
||||
if client_id not in clients or admin_session_id not in admin_websockets:
|
||||
return
|
||||
|
||||
|
||||
try:
|
||||
await admin_websockets[admin_session_id].send_text(json.dumps({
|
||||
"type": "stream_started",
|
||||
"client_id": client_id
|
||||
}))
|
||||
|
||||
ws = admin_websockets[admin_session_id]
|
||||
# Уведомляем админа о старте стрима
|
||||
await ws.send_text(json.dumps({"type": "stream_started", "client_id": client_id}))
|
||||
|
||||
with stats_lock:
|
||||
if client_id in clients:
|
||||
client = clients[client_id]
|
||||
await admin_websockets[admin_session_id].send_text(json.dumps({
|
||||
await ws.send_text(json.dumps({
|
||||
"type": "stream_info",
|
||||
"message": f"Streaming from client {client_id}",
|
||||
"quality": client["video_settings"]["quality"],
|
||||
"ip": client["ip_address"],
|
||||
"connected_at": client["connected_at"]
|
||||
"quality": client.get("video_settings", {}).get("quality"),
|
||||
"ip": client.get("ip_address"),
|
||||
"connected_at": client.get("connected_at")
|
||||
}))
|
||||
|
||||
|
||||
# Подготовим очередь для пересылки байтов администраторам
|
||||
if admin_frame_queues is None:
|
||||
return
|
||||
|
||||
if client_id not in admin_frame_queues:
|
||||
# Создаём очередь для этого клиента, если её нет
|
||||
admin_frame_queues[client_id] = asyncio.Queue(maxsize=128)
|
||||
|
||||
aq = admin_frame_queues[client_id]
|
||||
print(f"[WebSocket] Started streaming frames to admin {admin_session_id} for client {client_id}")
|
||||
|
||||
# Цикл чтения кадров из очереди и отправки их админу
|
||||
# Выходим только если очередь удалена (клиент отключился) или произойдёт исключение
|
||||
try:
|
||||
while client_id in admin_frame_queues:
|
||||
try:
|
||||
# Пытаемся получить кадр с таймаутом, чтобы периодически проверять наличие очереди
|
||||
frame_bytes = await asyncio.wait_for(aq.get(), timeout=2.0)
|
||||
try:
|
||||
await ws.send_bytes(frame_bytes)
|
||||
except Exception as e:
|
||||
print(f"[WebSocket] Error sending bytes to admin {admin_session_id}: {e}")
|
||||
break
|
||||
except asyncio.TimeoutError:
|
||||
# Таймаут OK — просто продолжаем ждать
|
||||
continue
|
||||
except asyncio.CancelledError:
|
||||
break
|
||||
except Exception as e:
|
||||
print(f"[WebSocket] Error in admin frame loop: {e}")
|
||||
finally:
|
||||
print(f"[WebSocket] Stopped streaming frames to admin {admin_session_id} for client {client_id}")
|
||||
|
||||
except Exception as e:
|
||||
print(f"[WebSocket] Error streaming to admin: {e}")
|
||||
|
||||
|
||||
Reference in New Issue
Block a user