|
|
@@ -787,23 +787,45 @@ def api_upload_finish(upload_id):
|
|
|
|
|
|
@app.route("/api/v1/archives/<name>/download")
|
|
|
def api_archive_download(name):
|
|
|
- """Téléchargement direct d'une archive via sudo cat (pour pull inter-instances)."""
|
|
|
+ """Téléchargement d'une archive via sudo rsync vers /tmp (pour pull inter-instances)."""
|
|
|
+ from flask import Response, stream_with_context
|
|
|
+ from jobs.utils import sudo_exists
|
|
|
+
|
|
|
backup_dir = app.config["YUNOHOST_BACKUP_DIR"]
|
|
|
archive_path = os.path.join(backup_dir, name + ".tar")
|
|
|
- from jobs.utils import sudo_exists
|
|
|
if not sudo_exists(archive_path):
|
|
|
return jsonify({"error": "archive introuvable"}), 404
|
|
|
|
|
|
- result = subprocess.run(["sudo", "cat", archive_path], capture_output=True, timeout=3600)
|
|
|
- if result.returncode != 0:
|
|
|
- return jsonify({"error": "lecture échouée"}), 500
|
|
|
+ tmp_path = f"/tmp/backupmanager_dl_{name}.tar"
|
|
|
+ try:
|
|
|
+ result = subprocess.run(
|
|
|
+ ["sudo", "rsync", archive_path, tmp_path],
|
|
|
+ capture_output=True, text=True, timeout=3600,
|
|
|
+ )
|
|
|
+ if result.returncode != 0:
|
|
|
+ return jsonify({"error": result.stderr.strip()}), 500
|
|
|
|
|
|
- from flask import Response
|
|
|
- return Response(
|
|
|
- result.stdout,
|
|
|
- mimetype="application/octet-stream",
|
|
|
- headers={"Content-Disposition": f'attachment; filename="{name}.tar"'},
|
|
|
- )
|
|
|
+ def stream_and_cleanup():
|
|
|
+ try:
|
|
|
+ with open(tmp_path, "rb") as f:
|
|
|
+ while True:
|
|
|
+ chunk = f.read(1024 * 1024)
|
|
|
+ if not chunk:
|
|
|
+ break
|
|
|
+ yield chunk
|
|
|
+ finally:
|
|
|
+ if os.path.exists(tmp_path):
|
|
|
+ os.unlink(tmp_path)
|
|
|
+
|
|
|
+ return Response(
|
|
|
+ stream_with_context(stream_and_cleanup()),
|
|
|
+ mimetype="application/octet-stream",
|
|
|
+ headers={"Content-Disposition": f'attachment; filename="{name}.tar"'},
|
|
|
+ )
|
|
|
+ except Exception as exc:
|
|
|
+ if os.path.exists(tmp_path):
|
|
|
+ os.unlink(tmp_path)
|
|
|
+ return jsonify({"error": str(exc)}), 500
|
|
|
|
|
|
|
|
|
@app.route("/api/v1/archives/upload/<upload_id>", methods=["DELETE"])
|