SmartEDT/backend/api/routes.py

72 lines
2.7 KiB
Python
Raw Normal View History

"""基础业务路由(仿真/设备/文件下载等)。
该文件保留项目早期的示例接口与基础能力
- 健康检查
- 设备连接状态示例
- 启停仿真
- 文件下载带目录穿越保护
"""
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