web UI added and refactoring done

This commit is contained in:
Ayzen
2026-06-06 00:06:30 +03:00
parent 3c30a12d4a
commit af6005d68f
65 changed files with 3630 additions and 4720 deletions
+87
View File
@@ -0,0 +1,87 @@
"""HTTP and WebSocket routes for the embedded radar web UI.
Every handler is a thin shell over the :class:`WebController` (which forwards to
the AppWindow's existing buttons) and the :class:`RingBroadcaster` (the single
frame source). There is no ownership gating: the web UI lives inside the process
that already owns the hardware, so its controls are simply that process's buttons.
"""
from __future__ import annotations
import asyncio
import contextlib
from fastapi import APIRouter, Body, HTTPException, Request, WebSocket, WebSocketDisconnect
from python_app.webui.controller import WebController
from python_app.webui.streaming import RingBroadcaster
router = APIRouter()
def _controller(request: Request) -> WebController:
return request.app.state.controller
@router.get("/api/status")
async def get_status(request: Request) -> dict:
return _controller(request).status()
@router.post("/api/start")
async def post_start(request: Request) -> dict:
controller = _controller(request)
controller.start()
return controller.status()
@router.post("/api/single_capture")
async def post_single_capture(request: Request) -> dict:
controller = _controller(request)
controller.single_capture()
return controller.status()
@router.post("/api/stop")
async def post_stop(request: Request) -> dict:
controller = _controller(request)
controller.stop()
return controller.status()
@router.post("/api/tmp_reference")
async def post_tmp_reference(request: Request) -> dict:
controller = _controller(request)
controller.capture_tmp_reference()
return controller.status()
@router.get("/api/live_settings")
async def get_live_settings(request: Request) -> list:
return _controller(request).current_live_settings()
@router.post("/api/live_settings")
async def post_live_settings(request: Request, fields: dict = Body(default={})) -> list:
try:
return _controller(request).apply_live_settings(fields)
except ValueError as exc:
raise HTTPException(status_code=400, detail=str(exc)) from exc
@router.websocket("/ws")
async def ws(websocket: WebSocket) -> None:
"""Stream frames and status to one client until it disconnects."""
await websocket.accept()
broadcaster: RingBroadcaster = websocket.app.state.broadcaster
queue: asyncio.Queue[dict] = asyncio.Queue(maxsize=1)
broadcaster.register(queue)
try:
while True:
await websocket.send_json(await queue.get())
except WebSocketDisconnect:
pass
finally:
broadcaster.unregister(queue)
with contextlib.suppress(Exception):
await websocket.close()