From c48d93642a2f6a86532870aca1b452da44039ee4 Mon Sep 17 00:00:00 2001 From: malmert Date: Sun, 1 Mar 2026 08:57:11 +0100 Subject: [PATCH] file blob --- backend/src/api/packet_scripting_api.py | 28 ++++++++++++++++++++----- 1 file changed, 23 insertions(+), 5 deletions(-) diff --git a/backend/src/api/packet_scripting_api.py b/backend/src/api/packet_scripting_api.py index f788f96..2e1a540 100644 --- a/backend/src/api/packet_scripting_api.py +++ b/backend/src/api/packet_scripting_api.py @@ -3,7 +3,7 @@ NFQUEUE Python-Scripting API Router Endpoints: - POST /scripts -> upload script (multipart): script file, optional requirements file, required 'name' form field - GET /scripts -> list scripts - - GET /scripts/{name} -> download script + - GET /scripts/{name} -> download script (binary blob) - POST /scripts/{name}/enable -> enable systemd service for script on given qnum - POST /scripts/{name}/disable -> disable service for script on qnum - DELETE /scripts/{name} -> disable all or a specific qnum service(s) and delete script + venv + requirements @@ -445,6 +445,8 @@ async def upload_script( """ Upload a script with supplied 'name' and optional requirements file. On pip/venv install failure, cleanup uploaded files and venv and return 500 with details. + + NOTE: This endpoint is multipart/form-data (UploadFile), so Swagger UI will show file upload widgets. """ # validate name try: @@ -542,9 +544,23 @@ def list_scripts() -> List[ScriptInfo]: return out -@router.get("/{name}") -def download_script(name: str): - # dynamic route - placed after /status and /{name}/status +@router.get( + "/{name}", + response_class=FileResponse, + responses={ + 200: { + "content": {"application/octet-stream": {"schema": {"type": "string", "format": "binary"}}}, + "description": "Python script file (binary).", + }, + 404: {"description": "Not found"}, + 400: {"description": "Invalid name"}, + }, +) +def download_script(name: str) -> FileResponse: + """ + Download a script as a binary file. Clients should request raw bytes (blob). + Swagger/OpenAPI will document the response as binary. + """ try: validate_name(name) except ValueError as e: @@ -554,7 +570,9 @@ def download_script(name: str): logger.warning("Download requested for missing script %s", name) raise HTTPException(status_code=404, detail="not found") logger.info("Download script %s", name) - return FileResponse(path, media_type="text/x-python", filename=f"{name}.py") + + # Return generic octet-stream so clients treat as binary blob. + return FileResponse(path, media_type="application/octet-stream", filename=f"{name}.py") @router.post("/{name}/enable", response_model=OperationResult)