Freeze-Fixed
This commit is contained in:
@@ -1,19 +1,21 @@
|
||||
import hashlib
|
||||
import hmac
|
||||
import io
|
||||
import os
|
||||
import re
|
||||
import secrets
|
||||
import shutil
|
||||
import tempfile
|
||||
import time
|
||||
import zipfile
|
||||
from pathlib import Path
|
||||
from typing import List
|
||||
|
||||
from fastapi import APIRouter, Depends, FastAPI, HTTPException, Request, UploadFile, File
|
||||
from fastapi.responses import FileResponse, StreamingResponse
|
||||
from fastapi.responses import FileResponse
|
||||
from fastapi.staticfiles import StaticFiles
|
||||
from pydantic import BaseModel
|
||||
from starlette.background import BackgroundTask
|
||||
from starlette.concurrency import run_in_threadpool
|
||||
from starlette.middleware.sessions import SessionMiddleware
|
||||
|
||||
PROJECTS_DIR = Path(os.environ.get("PROJECTS_DIR", "/data/projects")).resolve()
|
||||
@@ -180,13 +182,19 @@ async def upload_files(name: str, files: List[UploadFile] = File(...)):
|
||||
continue
|
||||
filename = safe_filename(upload.filename)
|
||||
dest = path / filename
|
||||
with open(dest, "wb") as out:
|
||||
shutil.copyfileobj(upload.file, out)
|
||||
# Run the actual (blocking) disk copy in a worker thread so a large
|
||||
# file doesn't freeze the whole server for the duration of the copy.
|
||||
await run_in_threadpool(_copy_upload_to_disk, upload.file, dest)
|
||||
saved.append(filename)
|
||||
|
||||
return {"saved": saved, "skipped": skipped}
|
||||
|
||||
|
||||
def _copy_upload_to_disk(src_file, dest_path: Path) -> None:
|
||||
with open(dest_path, "wb") as out:
|
||||
shutil.copyfileobj(src_file, out, length=4 * 1024 * 1024)
|
||||
|
||||
|
||||
@api.get("/projects/{name}/files/{filename}")
|
||||
def get_file(name: str, filename: str):
|
||||
path = safe_project_path(name)
|
||||
@@ -199,10 +207,13 @@ def get_file(name: str, filename: str):
|
||||
@api.get("/download-all")
|
||||
def download_all_projects():
|
||||
projects = [p for p in PROJECTS_DIR.iterdir() if p.is_dir()]
|
||||
files_found = False
|
||||
|
||||
buffer = io.BytesIO()
|
||||
with zipfile.ZipFile(buffer, "w", zipfile.ZIP_DEFLATED) as zf:
|
||||
tmp = tempfile.NamedTemporaryFile(delete=False, suffix=".zip")
|
||||
tmp_path = Path(tmp.name)
|
||||
tmp.close()
|
||||
|
||||
files_found = False
|
||||
with zipfile.ZipFile(tmp_path, "w", zipfile.ZIP_DEFLATED) as zf:
|
||||
for project in projects:
|
||||
for f in project.iterdir():
|
||||
if f.is_file() and f.suffix.lower() in ALLOWED_EXTENSIONS:
|
||||
@@ -210,13 +221,14 @@ def download_all_projects():
|
||||
files_found = True
|
||||
|
||||
if not files_found:
|
||||
tmp_path.unlink(missing_ok=True)
|
||||
raise HTTPException(404, "No files to download")
|
||||
|
||||
buffer.seek(0)
|
||||
return StreamingResponse(
|
||||
buffer,
|
||||
return FileResponse(
|
||||
tmp_path,
|
||||
media_type="application/zip",
|
||||
headers={"Content-Disposition": 'attachment; filename="alle-projekte.zip"'},
|
||||
filename="alle-projekte.zip",
|
||||
background=BackgroundTask(lambda: tmp_path.unlink(missing_ok=True)),
|
||||
)
|
||||
|
||||
|
||||
@@ -230,17 +242,19 @@ def download_project(name: str):
|
||||
if not files:
|
||||
raise HTTPException(404, "Project has no files to download")
|
||||
|
||||
buffer = io.BytesIO()
|
||||
with zipfile.ZipFile(buffer, "w", zipfile.ZIP_DEFLATED) as zf:
|
||||
tmp = tempfile.NamedTemporaryFile(delete=False, suffix=".zip")
|
||||
tmp_path = Path(tmp.name)
|
||||
tmp.close()
|
||||
|
||||
with zipfile.ZipFile(tmp_path, "w", zipfile.ZIP_DEFLATED) as zf:
|
||||
for f in files:
|
||||
zf.write(f, arcname=f.name)
|
||||
buffer.seek(0)
|
||||
|
||||
zip_filename = f"{name}.zip"
|
||||
return StreamingResponse(
|
||||
buffer,
|
||||
return FileResponse(
|
||||
tmp_path,
|
||||
media_type="application/zip",
|
||||
headers={"Content-Disposition": f'attachment; filename="{zip_filename}"'},
|
||||
filename=f"{name}.zip",
|
||||
background=BackgroundTask(lambda: tmp_path.unlink(missing_ok=True)),
|
||||
)
|
||||
|
||||
|
||||
|
||||
Reference in New Issue
Block a user