v2: чанки 30KB + MD5, /v2/chunk + /v2/finalize, Redis, worker, v2.0

This commit is contained in:
2026-06-17 23:14:34 +04:00
parent 562c27879e
commit c28baa446b
6 changed files with 416 additions and 19 deletions
+75
View File
@@ -0,0 +1,75 @@
"""v2/chunk_api.py — Приём чанков по 30KB, финализация."""
import sys, os, base64, hashlib, logging
sys.path.insert(0, os.path.join(os.path.dirname(__file__), '..', 'site'))
import db, mimeutil
sys.path.insert(0, os.path.dirname(__file__))
import init as v2
from flask import Blueprint, request, jsonify
bp = Blueprint("v2", __name__, url_prefix="/v2")
@bp.route("/chunk", methods=["POST"])
def receive_chunk():
body = request.get_json(silent=True) or {}
if not body.get("upload_id") or not body.get("data"):
return jsonify({"ok": False, "error": "missing fields"}), 400
try:
v2.store_chunk(body["upload_id"], int(body.get("index", 0)), body["data"])
return jsonify({"ok": True, "received": int(body.get("index", 0))})
except Exception as e:
return jsonify({"ok": False, "error": str(e)}), 500
@bp.route("/finalize", methods=["POST"])
def finalize_upload():
body = request.get_json(silent=True) or {}
upload_id = body.get("upload_id", "")
filename = body.get("filename", "")
total = int(body.get("total", 0))
checksum = body.get("checksum", "")
if not all([upload_id, filename, total]):
return jsonify({"ok": False, "error": "missing fields"}), 400
chunks = v2.get_chunks(upload_id)
if len(chunks) != total:
return jsonify({"ok": False, "error": f"expected {total}, got {len(chunks)}"}), 409
try:
file_bytes = b"".join(base64.b64decode(c) for c in chunks)
except Exception as e:
return jsonify({"ok": False, "error": f"decode: {e}"}), 422
if checksum and hashlib.md5(file_bytes).hexdigest() != checksum:
return jsonify({"ok": False, "error": "checksum mismatch"}), 422
mime = mimeutil.guess_mime(filename) or "application/octet-stream"
# Сохранить в БД
conn, err = db.connect()
if err:
return jsonify({"ok": False, "error": f"db: {err}"}), 500
try:
cur = conn.cursor()
cur.execute(
"INSERT INTO contracts (number, client) VALUES (%s,%s) RETURNING id",
("б" + __import__("datetime").datetime.now().strftime("%Y%m%d-%H%M"), ""),
)
cid = cur.fetchone()[0]
cur.execute(
"INSERT INTO documents (filename, mime_type, original_bytes, status) VALUES (%s,%s,%s,'uploaded')",
(filename, mime, file_bytes),
)
cur.execute("SELECT id FROM documents WHERE filename=%s ORDER BY created_at DESC LIMIT 1", (filename,))
doc_id = cur.fetchone()[0]
cur.execute("INSERT INTO supplements (contract_id, document_id, type) VALUES (%s,%s,'initial')", (str(cid), str(doc_id)))
conn.commit()
cur.close()
finally:
db.put_conn(conn)
v2.delete_chunks(upload_id)
v2.push_finalize({"doc_id": str(doc_id), "filename": filename, "mime_type": mime})
return jsonify({"ok": True, "contract_id": str(cid), "doc_id": str(doc_id)})