SmartEDT/backend/api/routes.py

72 lines
2.7 KiB
Python
Raw Permalink Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

"""基础业务路由(仿真/设备/文件下载等)。
该文件保留项目早期的示例接口与基础能力:
- 健康检查
- 设备连接状态(示例)
- 启停仿真
- 文件下载(带目录穿越保护)
"""
from __future__ import annotations
from pathlib import Path
from fastapi import APIRouter, Depends, HTTPException
from fastapi.responses import FileResponse
from backend.api.schemas import HealthResponse, SimulationStartRequest, SimulationStartResponse, SimulationStopResponse
from backend.services.simulation_manager import SimulationManager
from backend.utils import safe_join
def get_router(simulation_manager: SimulationManager, file_root: Path) -> APIRouter:
"""构造基础业务路由。
说明此项目采用“router 工厂函数”风格,通过参数注入 service/配置,而不是全局依赖容器。
"""
router = APIRouter()
@router.get("/health", response_model=HealthResponse)
async def health() -> HealthResponse:
"""健康检查(用于容器编排/负载均衡探活)。"""
return HealthResponse()
@router.get("/api/devices")
async def devices():
"""返回设备列表(当前为示例数据,反映仿真运行时状态)。"""
runtime = simulation_manager.current()
return {
"data": [
{
"device_id": "controlbox_01",
"device_type": "mock_vehicle",
"connected": bool(runtime and runtime.status == "running"),
}
]
}
@router.post("/api/simulation/start", response_model=SimulationStartResponse)
async def start_simulation(body: SimulationStartRequest) -> SimulationStartResponse:
"""启动仿真。"""
simulation_id = await simulation_manager.start(body.model_dump())
return SimulationStartResponse(simulation_id=simulation_id)
@router.post("/api/simulation/{simulation_id}/stop", response_model=SimulationStopResponse)
async def stop_simulation(simulation_id: str) -> SimulationStopResponse:
"""停止仿真。"""
await simulation_manager.stop(simulation_id)
return SimulationStopResponse(simulation_id=simulation_id, status="stopped")
@router.get("/files/{file_path:path}")
async def files(file_path: str):
"""下载文件(相对 file_root并校验路径合法性。"""
try:
resolved = safe_join(file_root, file_path)
except ValueError:
raise HTTPException(status_code=400, detail="invalid path")
if not resolved.exists() or not resolved.is_file():
raise HTTPException(status_code=404, detail="not found")
return FileResponse(str(resolved))
return router