implement cancellation handling in CaptureService and Database, update job states accordingly
This commit is contained in:
+14
-14
@@ -66,7 +66,7 @@ async def secure_headers(_: Request, call_next: Any) -> Response:
|
||||
|
||||
|
||||
@app.get("/", response_class=HTMLResponse)
|
||||
async def index(request: Request) -> Response:
|
||||
def index(request: Request) -> Response:
|
||||
return templates.TemplateResponse(
|
||||
request=request,
|
||||
name="index.html",
|
||||
@@ -75,7 +75,7 @@ async def index(request: Request) -> Response:
|
||||
|
||||
|
||||
@app.get("/api/health")
|
||||
async def health() -> dict[str, Any]:
|
||||
def health() -> dict[str, Any]:
|
||||
return {
|
||||
"status": "ok",
|
||||
"worker_enabled": settings.worker_enabled,
|
||||
@@ -85,7 +85,7 @@ async def health() -> dict[str, Any]:
|
||||
|
||||
|
||||
@app.get("/api/capabilities")
|
||||
async def capabilities() -> dict[str, Any]:
|
||||
def capabilities() -> dict[str, Any]:
|
||||
return {
|
||||
"defaults": {
|
||||
"max_pages": min(150, settings.max_pages_cap),
|
||||
@@ -113,12 +113,12 @@ async def capabilities() -> dict[str, Any]:
|
||||
|
||||
|
||||
@app.get("/api/stats")
|
||||
async def public_stats() -> dict[str, int]:
|
||||
def public_stats() -> dict[str, int]:
|
||||
return database.public_stats()
|
||||
|
||||
|
||||
@app.post("/api/captures", status_code=status.HTTP_202_ACCEPTED)
|
||||
async def create_capture(payload: CaptureRequest, request: Request) -> dict[str, Any]:
|
||||
def create_capture(payload: CaptureRequest, request: Request) -> dict[str, Any]:
|
||||
owner_token = _owner_token(request)
|
||||
config = _validated_config(payload)
|
||||
rules = NetworkRules(
|
||||
@@ -135,18 +135,18 @@ async def create_capture(payload: CaptureRequest, request: Request) -> dict[str,
|
||||
|
||||
|
||||
@app.get("/api/captures")
|
||||
async def list_captures(request: Request) -> dict[str, list[dict[str, Any]]]:
|
||||
def list_captures(request: Request) -> dict[str, list[dict[str, Any]]]:
|
||||
owner_token = _owner_token(request)
|
||||
return {"items": [_public_job(job) for job in database.list_owned_jobs(owner_token)]}
|
||||
|
||||
|
||||
@app.get("/api/captures/{job_id}")
|
||||
async def get_capture(job_id: str, request: Request) -> dict[str, Any]:
|
||||
def get_capture(job_id: str, request: Request) -> dict[str, Any]:
|
||||
return _require_owned_job(job_id, _owner_token(request))
|
||||
|
||||
|
||||
@app.post("/api/captures/{job_id}/cancel")
|
||||
async def cancel_capture(job_id: str, request: Request) -> dict[str, Any]:
|
||||
def cancel_capture(job_id: str, request: Request) -> dict[str, Any]:
|
||||
_require_owned_job(job_id, _owner_token(request))
|
||||
job = database.request_cancel(job_id)
|
||||
if not job:
|
||||
@@ -155,7 +155,7 @@ async def cancel_capture(job_id: str, request: Request) -> dict[str, Any]:
|
||||
|
||||
|
||||
@app.delete("/api/captures/{job_id}")
|
||||
async def delete_capture(job_id: str, request: Request) -> dict[str, Any]:
|
||||
def delete_capture(job_id: str, request: Request) -> dict[str, Any]:
|
||||
job = _owned_job(job_id, _owner_token(request))
|
||||
if job["state"] in {"queued", "running"}:
|
||||
cancelled = database.request_cancel(job_id)
|
||||
@@ -174,7 +174,7 @@ async def delete_capture(job_id: str, request: Request) -> dict[str, Any]:
|
||||
|
||||
|
||||
@app.get("/api/captures/{job_id}/report")
|
||||
async def capture_report(job_id: str, request: Request) -> JSONResponse:
|
||||
def capture_report(job_id: str, request: Request) -> JSONResponse:
|
||||
job = _owned_job(job_id, _owner_token(request))
|
||||
if job["state"] != "ready" or not job.get("report_path"):
|
||||
raise HTTPException(status_code=409, detail="A capture report is not available yet.")
|
||||
@@ -185,7 +185,7 @@ async def capture_report(job_id: str, request: Request) -> JSONResponse:
|
||||
|
||||
|
||||
@app.get("/api/captures/{job_id}/download")
|
||||
async def download_capture(job_id: str, request: Request) -> FileResponse:
|
||||
def download_capture(job_id: str, request: Request) -> FileResponse:
|
||||
job = _owned_job(job_id, _owner_token(request))
|
||||
if job["state"] != "ready" or not job.get("artifact_path"):
|
||||
raise HTTPException(status_code=409, detail="The archive is not available yet.")
|
||||
@@ -201,7 +201,7 @@ async def download_capture(job_id: str, request: Request) -> FileResponse:
|
||||
|
||||
|
||||
@app.get("/api/captures/{job_id}/events")
|
||||
async def capture_events(request: Request, job_id: str) -> StreamingResponse:
|
||||
def capture_events(request: Request, job_id: str) -> StreamingResponse:
|
||||
_owned_job(job_id, _owner_token(request, allow_query=True))
|
||||
after_header = request.headers.get("last-event-id", "0")
|
||||
try:
|
||||
@@ -221,13 +221,13 @@ async def _event_stream(request: Request, job_id: str, after_id: int) -> AsyncIt
|
||||
while True:
|
||||
if await request.is_disconnected():
|
||||
return
|
||||
events = database.get_events(job_id, last_id)
|
||||
events = await asyncio.to_thread(database.get_events, job_id, last_id)
|
||||
for event in events:
|
||||
last_id = int(event["id"])
|
||||
payload = json.dumps(event["payload"], separators=(",", ":"))
|
||||
yield f"id: {last_id}\nevent: {event['kind']}\ndata: {payload}\n\n"
|
||||
|
||||
job = database.get_job(job_id)
|
||||
job = await asyncio.to_thread(database.get_job, job_id)
|
||||
if not job or job["state"] in terminal_states:
|
||||
terminal = json.dumps({"state": job["state"] if job else "missing"})
|
||||
yield f"event: terminal\ndata: {terminal}\n\n"
|
||||
|
||||
Reference in New Issue
Block a user