79 lines
3.0 KiB
Python
79 lines
3.0 KiB
Python
"""Blueprint слоя закачки ссылок через ВМ-буфер."""
|
||
|
||
import logging
|
||
|
||
import requests
|
||
from flask import Blueprint, jsonify, request
|
||
|
||
from ..session import (MAX_FILE_BYTES, add_file, configure, create_session,
|
||
file_count, get_files)
|
||
from .config import PULL_RETRIES, PULL_RETRY_DELAY, VM_UPLOAD_PREFIX
|
||
from .pull_file import pull_file
|
||
from .safe_name import safe_name
|
||
|
||
|
||
log = logging.getLogger("upload.upload_refs")
|
||
|
||
|
||
def create_upload_refs_blueprint(cfg: dict) -> Blueprint:
|
||
"""Создать Blueprint с POST ``/upload_refs``."""
|
||
|
||
cfg = cfg or {}
|
||
prefix = cfg.get("apiPrefix", "/api")
|
||
vm_prefix = cfg.get("vmUploadUrl", VM_UPLOAD_PREFIX)
|
||
max_file_bytes = cfg.get("maxFileBytes", MAX_FILE_BYTES)
|
||
pull_retries = cfg.get("pullRetries", PULL_RETRIES)
|
||
pull_delay = cfg.get("pullRetryDelay", PULL_RETRY_DELAY)
|
||
pull_timeout = cfg.get("pullTimeout", 120)
|
||
configure(max_session_bytes=cfg.get("maxSessionBytes"))
|
||
|
||
blueprint = Blueprint("upload_refs", __name__, url_prefix=prefix)
|
||
|
||
@blueprint.route("/upload_refs", methods=["POST"])
|
||
def upload_refs():
|
||
data = request.get_json(silent=True) or {}
|
||
sid = data.get("session") or create_session()
|
||
refs = data.get("files") or []
|
||
if not isinstance(refs, list) or not refs:
|
||
return jsonify({"ok": False, "error": "No files"}), 400
|
||
|
||
added = 0
|
||
try:
|
||
with requests.Session() as client:
|
||
for ref in refs:
|
||
if not isinstance(ref, dict):
|
||
continue
|
||
name = safe_name(ref.get("name", ""))
|
||
url = ref.get("url")
|
||
if not name or not isinstance(url, str) or not url.startswith(vm_prefix):
|
||
continue
|
||
if (ref.get("size") or 0) > max_file_bytes:
|
||
_delete(client, url)
|
||
continue
|
||
content = pull_file(
|
||
client, url, max_file_bytes, pull_retries, pull_delay,
|
||
pull_timeout, sid=sid, name=name,
|
||
)
|
||
if not add_file(sid, name, content):
|
||
if get_files(sid) is None:
|
||
return jsonify({"ok": False, "error": "Session not found"}), 404
|
||
_delete(client, url)
|
||
continue
|
||
_delete(client, url)
|
||
added += 1
|
||
except Exception as error:
|
||
log.error("upload_refs: pull error sid=%s: %r", sid, error)
|
||
return jsonify({"ok": False, "error": "Pull failed: %s" % error}), 502
|
||
|
||
return jsonify({"ok": True, "session": sid, "count": file_count(sid)})
|
||
|
||
return blueprint
|
||
|
||
|
||
def _delete(client, url: str):
|
||
"""Удалить временный объект на ВМ, не ломая основной запрос при сбое."""
|
||
|
||
try:
|
||
client.delete(url, timeout=10)
|
||
except Exception:
|
||
log.warning("upload_refs: could not delete VM object url=%r", url) |