from fastapi import Request, Response from caainp_csm.plan_csm import PlanState, Constraints, Step import json COOKIE_KEY = "CAAINP-NAVIGATION-COOKIE" def plan_to_dict(plan: PlanState) -> dict: """PlanState를 JSON 직렬화 가능한 dict로 변환""" return { "constraints": { "use_elevator_only": plan.constraints.use_elevator_only, "avoid_stairs": plan.constraints.avoid_stairs, "forbidden_nodes": plan.constraints.forbidden_nodes, "via_rooms": plan.constraints.via_rooms, }, "steps": [ { "step_id": s.step_id, "goal_type": s.goal_type, "goal_room": s.goal_room, "allowed_moves": s.allowed_moves, "description_ko": s.description_ko, "target_nodes": s.target_nodes, "route_nodes": s.route_nodes, } for s in plan.steps ], "current_step": plan.current_step, "steps_status": plan.steps_status, "step_targets": {str(k): v for k, v in plan.step_targets.items()}, "in_target_count": plan.in_target_count, } def dict_to_plan(data: dict) -> PlanState: """dict를 PlanState 객체로 복원""" constraints = Constraints( use_elevator_only=data["constraints"]["use_elevator_only"], avoid_stairs=data["constraints"]["avoid_stairs"], forbidden_nodes=data["constraints"]["forbidden_nodes"], via_rooms=data["constraints"]["via_rooms"], ) steps = [ Step( step_id=s["step_id"], goal_type=s["goal_type"], goal_room=s["goal_room"], allowed_moves=s["allowed_moves"], description_ko=s["description_ko"], target_nodes=s["target_nodes"], route_nodes=s["route_nodes"], ) for s in data["steps"] ] # steps_status의 키를 int로 복원 steps_status = {int(k): v for k, v in data["steps_status"].items()} # step_targets의 키를 int로 복원 step_targets = {int(k): v for k, v in data["step_targets"].items()} return PlanState( constraints=constraints, steps=steps, current_step=data["current_step"], steps_status=steps_status, step_targets=step_targets, in_target_count=data["in_target_count"], ) def get_nav_state_from_cookie(request: Request) -> tuple[PlanState, int] | None: """쿠키에서 네비게이션 상태를 읽어서 반환""" cookies = dict(request.cookies) nav_state_cookie = cookies.get(COOKIE_KEY) if not nav_state_cookie: return None try: nav_state = json.loads(nav_state_cookie) plan_dict = nav_state.get("plan") prev_node = nav_state.get("prev_node") plan = dict_to_plan(plan_dict) return plan, prev_node except (json.JSONDecodeError, KeyError, TypeError): return None def save_nav_state_to_cookie(response: Response, plan: PlanState, prev_node: int) -> None: """네비게이션 상태(plan, prev_node)를 쿠키에 저장""" nav_state = { "plan": plan_to_dict(plan), "prev_node": prev_node, } response.set_cookie( key=COOKIE_KEY, value=json.dumps(nav_state), max_age=3600, httponly=True, samesite="lax" ) def clear_nav_cookie(response: Response) -> None: """네비게이션 쿠키 삭제""" response.delete_cookie(COOKIE_KEY)