260705_2
This commit is contained in:
@@ -0,0 +1,133 @@
|
||||
"""B05 경로 설계 FastAPI 라우터."""
|
||||
|
||||
import asyncio
|
||||
import logging
|
||||
from pathlib import Path
|
||||
from uuid import UUID
|
||||
|
||||
from fastapi import APIRouter
|
||||
from fastapi.responses import JSONResponse
|
||||
|
||||
from B03_FileInput.B03_FileInput_Repository import get_project_storage_relative_path
|
||||
from B05_wf2_Route.B05_wf2_Route_Engine import run_route_design
|
||||
from B05_wf2_Route.B05_wf2_Route_Repository import (
|
||||
confirm_route,
|
||||
create_route,
|
||||
create_route_statistics,
|
||||
get_latest_route,
|
||||
insert_route_points,
|
||||
)
|
||||
from B05_wf2_Route.B05_wf2_Route_Schema import (
|
||||
RouteConfirmResponse,
|
||||
RouteSolveRequest,
|
||||
RouteSolveResponse,
|
||||
)
|
||||
from common_util.common_util_storage import resolve_stored_project_path
|
||||
from config.config_db import get_db_pool
|
||||
|
||||
logger = logging.getLogger(__name__)
|
||||
router = APIRouter(prefix="/api/projects", tags=["B05 Route Design"])
|
||||
|
||||
|
||||
@router.post("/{project_id}/route/solve", response_model=RouteSolveResponse)
|
||||
async def solve_route(
|
||||
project_id: UUID, request: RouteSolveRequest
|
||||
) -> RouteSolveResponse | JSONResponse:
|
||||
"""경로 탐색을 실행하고 결과를 GeoJSON 저장 + DB 기록한다."""
|
||||
pool = get_db_pool()
|
||||
try:
|
||||
async with pool.acquire() as connection:
|
||||
stored_path = await get_project_storage_relative_path(connection, project_id)
|
||||
project_root = Path(resolve_stored_project_path(stored_path))
|
||||
|
||||
# 무거운 경로 탐색은 이벤트 루프를 막지 않도록 별도 스레드에서 실행.
|
||||
design = await asyncio.to_thread(
|
||||
run_route_design,
|
||||
project_root,
|
||||
request.filter_key,
|
||||
request.method,
|
||||
request.smooth,
|
||||
request.points_data(),
|
||||
request.options(),
|
||||
request.algorithm,
|
||||
)
|
||||
solver = design["solver_result"]
|
||||
metrics = solver["metrics"]
|
||||
|
||||
await connection.begin()
|
||||
try:
|
||||
route_id = await create_route(
|
||||
connection,
|
||||
project_id=project_id,
|
||||
surface_model_id=request.surface_model_id,
|
||||
total_length_m=metrics.get("length_m"),
|
||||
start_chainage_m=0.0,
|
||||
end_chainage_m=metrics.get("length_m"),
|
||||
grade_percent=design["grade_percent"],
|
||||
constraints=design["constraints"],
|
||||
algorithm_params=design["algorithm_params"],
|
||||
route_data_path=design["route_data_path"],
|
||||
)
|
||||
await insert_route_points(connection, route_id, design["render_points"])
|
||||
stats = design["statistics"]
|
||||
await create_route_statistics(
|
||||
connection,
|
||||
route_id=route_id,
|
||||
min_slope=stats["min_slope"],
|
||||
max_slope=stats["max_slope"],
|
||||
mean_slope=stats["mean_slope"],
|
||||
cost_score=stats["cost_score"],
|
||||
)
|
||||
await connection.commit()
|
||||
except Exception:
|
||||
await connection.rollback()
|
||||
raise
|
||||
|
||||
return RouteSolveResponse(
|
||||
project_id=str(project_id),
|
||||
route_id=route_id,
|
||||
total_length_m=metrics.get("length_m", 0.0),
|
||||
metrics=metrics,
|
||||
required_points_ok=solver["required_points_ok"],
|
||||
route_data_path=design["route_data_path"],
|
||||
)
|
||||
except LookupError as exc:
|
||||
return JSONResponse(status_code=404, content={"status": "error", "message": str(exc)})
|
||||
except FileNotFoundError as exc:
|
||||
return JSONResponse(status_code=404, content={"status": "error", "message": str(exc)})
|
||||
except (OSError, ValueError) as exc:
|
||||
return JSONResponse(status_code=400, content={"status": "error", "message": str(exc)})
|
||||
except Exception:
|
||||
logger.exception("B05 경로 탐색 실패: project_id=%s", project_id)
|
||||
return JSONResponse(
|
||||
status_code=500,
|
||||
content={"status": "error", "message": "경로 탐색 처리 중 오류가 발생했습니다."},
|
||||
)
|
||||
|
||||
|
||||
@router.post("/{project_id}/route/confirm", response_model=RouteConfirmResponse)
|
||||
async def confirm_latest_route(project_id: UUID) -> RouteConfirmResponse | JSONResponse:
|
||||
"""프로젝트의 최신 경로를 확정(CONFIRMED)한다."""
|
||||
pool = get_db_pool()
|
||||
try:
|
||||
async with pool.acquire() as connection:
|
||||
latest = await get_latest_route(connection, project_id)
|
||||
if not latest:
|
||||
return JSONResponse(
|
||||
status_code=404,
|
||||
content={"status": "error", "message": "확정할 경로가 없습니다."},
|
||||
)
|
||||
await connection.begin()
|
||||
try:
|
||||
await confirm_route(connection, latest["id"])
|
||||
await connection.commit()
|
||||
except Exception:
|
||||
await connection.rollback()
|
||||
raise
|
||||
return RouteConfirmResponse(project_id=str(project_id), route_id=latest["id"])
|
||||
except Exception:
|
||||
logger.exception("B05 경로 확정 실패: project_id=%s", project_id)
|
||||
return JSONResponse(
|
||||
status_code=500,
|
||||
content={"status": "error", "message": "경로 확정 처리 중 오류가 발생했습니다."},
|
||||
)
|
||||
Reference in New Issue
Block a user