"""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)