64 lines
1.9 KiB
Python
64 lines
1.9 KiB
Python
from __future__ import annotations
|
|
|
|
import asyncio
|
|
from typing import Any
|
|
|
|
from fastapi import APIRouter, HTTPException, Query, WebSocket, status
|
|
from fastapi.encoders import jsonable_encoder
|
|
from fastapi.websockets import WebSocketDisconnect
|
|
from sqlmodel import Session
|
|
|
|
from app.api.deps import CurrentUser, SessionDep, resolve_user_from_token
|
|
from app.core.db import engine
|
|
from app.mqtt.telemetry import build_telemetry_snapshot
|
|
|
|
router = APIRouter(prefix="/telemetry", tags=["telemetry"])
|
|
STREAM_INTERVAL_SECONDS = 1.0
|
|
|
|
|
|
@router.get("/latest")
|
|
def read_telemetry_latest(
|
|
session: SessionDep,
|
|
_current_user: CurrentUser,
|
|
device_id: str | None = None,
|
|
limit: int = Query(default=50, ge=1, le=200),
|
|
) -> dict[str, Any]:
|
|
"""
|
|
Return the latest parsed GNSS telemetry snapshot.
|
|
"""
|
|
return build_telemetry_snapshot(session=session, device_id=device_id, limit=limit)
|
|
|
|
|
|
@router.websocket("/ws")
|
|
async def telemetry_websocket(
|
|
websocket: WebSocket,
|
|
token: str | None = Query(default=None),
|
|
device_id: str | None = Query(default=None),
|
|
limit: int = Query(default=50, ge=1, le=200),
|
|
) -> None:
|
|
if not token:
|
|
await websocket.close(code=status.WS_1008_POLICY_VIOLATION)
|
|
return
|
|
|
|
with Session(engine) as session:
|
|
try:
|
|
resolve_user_from_token(session=session, token=token)
|
|
except HTTPException:
|
|
await websocket.close(code=status.WS_1008_POLICY_VIOLATION)
|
|
return
|
|
|
|
await websocket.accept()
|
|
|
|
try:
|
|
while True:
|
|
with Session(engine) as session:
|
|
payload = build_telemetry_snapshot(
|
|
session=session,
|
|
device_id=device_id,
|
|
limit=limit,
|
|
)
|
|
await websocket.send_json(jsonable_encoder(payload))
|
|
await asyncio.sleep(STREAM_INTERVAL_SECONDS)
|
|
except (WebSocketDisconnect, RuntimeError):
|
|
return
|