diff --git a/frontend/app.py b/frontend/app.py index b05b61c..7975776 100644 --- a/frontend/app.py +++ b/frontend/app.py @@ -20,6 +20,7 @@ from logging.handlers import RotatingFileHandler import os import shutil import subprocess +import threading import time import uuid from pathlib import Path @@ -262,17 +263,7 @@ async def upload_raw(request: Request): if free_gb < 50: logger.warning("Low disk: %.1f GB free — download may fail", free_gb) - # Try to get file size via HEAD request (for speed estimation) - content_length = 0 - try: - head_resp = http_requests.head(url, timeout=10, allow_redirects=True) - cl = head_resp.headers.get("Content-Length") - if cl: - content_length = int(cl) - logger.info("Download size from HEAD: %.1f GiB", content_length / (1024**3)) - except Exception: - logger.info("Could not determine download size (HEAD failed — will skip ETA check)") - + # Start wget immediately (HEAD request for size happens in background) logger.info("Starting background download: %s → %s", url, dest) try: proc = subprocess.Popen( @@ -288,10 +279,22 @@ async def upload_raw(request: Request): "vmid": vmid, "vm_name": vm_name, "start_time": time.time(), - "content_length": content_length, + "content_length": 0, "_last_logged_bytes": 0, } + # Fire-and-forget HEAD request to get file size for ETA (non-blocking) + def _fetch_content_length(): + try: + head_resp = http_requests.head(url, timeout=5, allow_redirects=True) + cl = head_resp.headers.get("Content-Length") + if cl and filename in _active_downloads: + _active_downloads[filename]["content_length"] = int(cl) + logger.info("Download size from HEAD: %.1f GiB", int(cl) / (1024**3)) + except Exception: + pass + threading.Thread(target=_fetch_content_length, daemon=True).start() + return JSONResponse({ "phase": "downloading", "filename": filename,