126 lines
3.5 KiB
Python
126 lines
3.5 KiB
Python
"""ZED 分段录制 HTTP 控制(响应格式对齐 biomass:code/msg/data;不校验 ingest API Key)。"""
|
||
|
||
from __future__ import annotations
|
||
|
||
from typing import Any, Dict, Optional
|
||
|
||
from fastapi import APIRouter, Body, Depends
|
||
from pydantic import BaseModel, Field
|
||
from starlette.responses import JSONResponse
|
||
|
||
from app.services.zed_recording_control import (
|
||
start_zed_recording,
|
||
stop_zed_recording,
|
||
zed_recording_is_running,
|
||
)
|
||
from app.settings import Settings, get_settings
|
||
from app.state import app_state
|
||
|
||
router = APIRouter(prefix="/api/v1/zed/recording", tags=["zed-recording"])
|
||
|
||
|
||
def _ok(data: Dict[str, Any], msg: str = "成功") -> JSONResponse:
|
||
return JSONResponse(
|
||
content={
|
||
"code": 200,
|
||
"msg": msg,
|
||
"data": data,
|
||
}
|
||
)
|
||
|
||
|
||
def _err(
|
||
http_status: int,
|
||
*,
|
||
code: int,
|
||
msg: str,
|
||
data: Optional[Dict[str, Any]] = None,
|
||
) -> JSONResponse:
|
||
body: Dict[str, Any] = {"code": code, "msg": msg}
|
||
if data is not None:
|
||
body["data"] = data
|
||
return JSONResponse(status_code=http_status, content=body)
|
||
|
||
|
||
class ZedRecordingStartRequest(BaseModel):
|
||
"""可选覆盖分段时长;``fish_id`` 由服务端每次启动在库中递增分配。"""
|
||
|
||
segment_sec: Optional[float] = Field(
|
||
None,
|
||
ge=1.0,
|
||
description="每段时长(秒);缺省使用 ZED_SVO_SEGMENT_SEC",
|
||
)
|
||
|
||
|
||
@router.get("/status")
|
||
async def zed_recording_status() -> JSONResponse:
|
||
data: Dict[str, Any] = {"running": zed_recording_is_running()}
|
||
if app_state.zed_recording_fish_id is not None:
|
||
data["fish_id"] = app_state.zed_recording_fish_id
|
||
return _ok(data)
|
||
|
||
|
||
@router.post("/start")
|
||
async def zed_recording_start(
|
||
body: ZedRecordingStartRequest = Body(default_factory=ZedRecordingStartRequest),
|
||
settings: Settings = Depends(get_settings),
|
||
) -> JSONResponse:
|
||
ok, msg, fish_id, _ = start_zed_recording(
|
||
settings,
|
||
segment_sec=body.segment_sec,
|
||
)
|
||
if not ok:
|
||
if msg == "already_running":
|
||
return _err(
|
||
409,
|
||
code=409,
|
||
msg="已在录制中",
|
||
data={"ok": False, "message": "已在录制中"},
|
||
)
|
||
if msg.startswith("session_db_error:"):
|
||
return _err(
|
||
500,
|
||
code=500,
|
||
msg="写入录制会话失败",
|
||
data={"ok": False, "message": msg},
|
||
)
|
||
return _err(
|
||
500,
|
||
code=500,
|
||
msg="启动录制失败",
|
||
data={"ok": False, "message": msg},
|
||
)
|
||
|
||
return _ok(
|
||
{
|
||
"ok": True,
|
||
"message": "录制开始",
|
||
"fish_id": fish_id,
|
||
}
|
||
)
|
||
|
||
|
||
@router.post("/stop")
|
||
async def zed_recording_stop(settings: Settings = Depends(get_settings)) -> JSONResponse:
|
||
ok, msg, fish_id = stop_zed_recording(settings)
|
||
if not ok:
|
||
if msg == "not_running":
|
||
return _ok({"ok": False, "message": "未在录制"}, msg="未在录制")
|
||
if msg == "stop_timeout":
|
||
return _err(
|
||
504,
|
||
code=504,
|
||
msg="停止超时",
|
||
data={"ok": False, "message": "停止超时"},
|
||
)
|
||
return _err(
|
||
500,
|
||
code=500,
|
||
msg="停止录制失败",
|
||
data={"ok": False, "message": msg},
|
||
)
|
||
out: Dict[str, Any] = {"ok": True, "message": "录制停止"}
|
||
if fish_id is not None:
|
||
out["fish_id"] = fish_id
|
||
return _ok(out)
|