"""SP-4 — Windows insta-render → NAS internal webhook. POST /api/internal/insta/update - X-Internal-Key 인증 필수 - task DB row update (status, progress, result_path, error) - result_path는 nginx 서빙 경로 (예: /media/insta/{slate_id}/01.png) - succeeded 시 params에서 slate_id 추출 → result_id 세팅 """ from __future__ import annotations import json import logging from typing import Optional from fastapi import APIRouter, Depends, HTTPException from pydantic import BaseModel, Field from . import db from .auth import verify_internal_key logger = logging.getLogger(__name__) router = APIRouter() class UpdatePayload(BaseModel): task_id: str status: str = Field(..., description="processing|succeeded|failed") progress: int = Field(..., ge=0, le=100) result_path: Optional[str] = None error: Optional[str] = None @router.post( "/api/internal/insta/update", dependencies=[Depends(verify_internal_key)], ) def insta_update(payload: UpdatePayload): task = db.get_task(payload.task_id) if task is None: raise HTTPException(404, f"task not found: {payload.task_id}") result_id = None if payload.status == "succeeded": try: # DB stores params (not input_data) from create_task params_data = json.loads(task.get("params") or "{}") result_id = params_data.get("slate_id") except (ValueError, TypeError): pass db.update_task( payload.task_id, payload.status, payload.progress, message=payload.result_path or "", result_id=result_id, error=payload.error, ) # succeeded 시 slate_status도 'rendered'로 갱신 (cutover 후 NAS가 처리) if payload.status == "succeeded" and result_id is not None: try: db.update_slate_status(result_id, "rendered") except Exception: logger.exception("update_slate_status %s 실패 (무시)", result_id) logger.info( "internal/insta/update task=%s status=%s progress=%d", payload.task_id, payload.status, payload.progress, ) return {"ok": True}