105 lines
4.2 KiB
Python
105 lines
4.2 KiB
Python
import asyncio
|
|
|
|
from fastapi import APIRouter, Depends, HTTPException, Query
|
|
|
|
from api.contracts.captcha_schemas import (
|
|
CaptchaAbortRequest,
|
|
CaptchaActionResponse,
|
|
CaptchaExtendRequest,
|
|
CaptchaNotifyRequest,
|
|
CaptchaSolvedRequest,
|
|
CaptchaStatusResponse,
|
|
)
|
|
from api.mappers.captcha_mapper import CaptchaMapper
|
|
from api.routes.dependencies import get_task_service
|
|
from api.services.protocols import TaskServiceProtocol
|
|
|
|
router = APIRouter(prefix="/api/browser", tags=["browser-captcha"])
|
|
|
|
|
|
@router.post("/tasks/{task_id}/captcha/notify", response_model=CaptchaActionResponse, status_code=202)
|
|
async def captcha_notify(
|
|
task_id: str,
|
|
payload: CaptchaNotifyRequest,
|
|
service: TaskServiceProtocol = Depends(get_task_service),
|
|
) -> CaptchaActionResponse:
|
|
rec = await service.notify_captcha(
|
|
task_id=task_id,
|
|
kind=payload.captcha_kind,
|
|
reason=payload.reason,
|
|
view_url=payload.browser_view_url,
|
|
timeout_seconds=payload.timeout_seconds,
|
|
)
|
|
if rec is None:
|
|
raise HTTPException(status_code=404, detail="Task not found")
|
|
return CaptchaMapper.to_action(rec, message="captcha awaiting solution")
|
|
|
|
|
|
@router.get("/tasks/{task_id}/captcha", response_model=CaptchaStatusResponse)
|
|
async def captcha_status(
|
|
task_id: str,
|
|
service: TaskServiceProtocol = Depends(get_task_service),
|
|
) -> CaptchaStatusResponse:
|
|
rec = await service.get_task(task_id)
|
|
if rec is None:
|
|
raise HTTPException(status_code=404, detail="Task not found")
|
|
return CaptchaMapper.to_status(rec)
|
|
|
|
|
|
@router.get("/tasks/{task_id}/captcha/wait", response_model=CaptchaStatusResponse)
|
|
async def captcha_wait(
|
|
task_id: str,
|
|
timeout: float = Query(default=30.0, ge=0.1, le=600.0, description="long-poll cap, seconds"),
|
|
service: TaskServiceProtocol = Depends(get_task_service),
|
|
) -> CaptchaStatusResponse:
|
|
rec = await service.wait_captcha(task_id=task_id, timeout=timeout)
|
|
if rec is None:
|
|
raise HTTPException(status_code=404, detail="Task not found")
|
|
return CaptchaMapper.to_status(rec)
|
|
|
|
|
|
@router.post("/tasks/{task_id}/captcha/solved", response_model=CaptchaActionResponse)
|
|
async def captcha_solved(
|
|
task_id: str,
|
|
payload: CaptchaSolvedRequest | None = None,
|
|
service: TaskServiceProtocol = Depends(get_task_service),
|
|
) -> CaptchaActionResponse:
|
|
rec = await service.mark_captcha_solved(task_id=task_id, detector=(payload.detector if payload else None))
|
|
if rec is None:
|
|
raise HTTPException(status_code=404, detail="Task not found")
|
|
return CaptchaMapper.to_action(rec, message="captcha marked as solved")
|
|
|
|
|
|
@router.post("/tasks/{task_id}/captcha/timeout-prompt", response_model=CaptchaActionResponse)
|
|
async def captcha_timeout_prompt(
|
|
task_id: str,
|
|
service: TaskServiceProtocol = Depends(get_task_service),
|
|
) -> CaptchaActionResponse:
|
|
rec = await service.prompt_captcha_timeout(task_id=task_id)
|
|
if rec is None:
|
|
raise HTTPException(status_code=404, detail="Task not found")
|
|
return CaptchaMapper.to_action(rec, message="user must choose: extend or abort")
|
|
|
|
|
|
@router.post("/tasks/{task_id}/captcha/extend", response_model=CaptchaActionResponse)
|
|
async def captcha_extend(
|
|
task_id: str,
|
|
payload: CaptchaExtendRequest,
|
|
service: TaskServiceProtocol = Depends(get_task_service),
|
|
) -> CaptchaActionResponse:
|
|
rec = await service.extend_captcha(task_id=task_id, extra_seconds=payload.extra_seconds)
|
|
if rec is None:
|
|
raise HTTPException(status_code=404, detail="Task not found")
|
|
return CaptchaMapper.to_action(rec, message=f"captcha extended by {payload.extra_seconds}s")
|
|
|
|
|
|
@router.post("/tasks/{task_id}/captcha/abort", response_model=CaptchaActionResponse)
|
|
async def captcha_abort(
|
|
task_id: str,
|
|
payload: CaptchaAbortRequest | None = None,
|
|
service: TaskServiceProtocol = Depends(get_task_service),
|
|
) -> CaptchaActionResponse:
|
|
rec = await service.abort_captcha(task_id=task_id, reason=(payload.reason if payload else None))
|
|
if rec is None:
|
|
raise HTTPException(status_code=404, detail="Task not found")
|
|
return CaptchaMapper.to_action(rec, message="captcha aborted by user")
|