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)
|