From 491b49f6335911e20af2249edf2cc36084f6ca95 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E2=80=9CNaeel=E2=80=9D?= Date: Mon, 13 Jul 2026 10:04:15 +0400 Subject: [PATCH] =?UTF-8?q?v0.0.1:=20revert=20to=20v7.0.0=20code=20?= =?UTF-8?q?=E2=80=94=20api=5Fbp=20unified,=20no=20Connection=20close,=20ve?= =?UTF-8?q?rsion=20reset?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- site/app.py | 2 +- site/routes/__init__.py | 13 +++--- site/routes/api_bp.py | 83 ++++++++++++++++++++++++++++++++++++++ site/routes/download_bp.py | 21 ---------- site/routes/process_bp.py | 47 --------------------- site/routes/upload_bp.py | 28 ------------- tests/test_upload.py | 14 ++----- 7 files changed, 94 insertions(+), 114 deletions(-) create mode 100644 site/routes/api_bp.py delete mode 100644 site/routes/download_bp.py delete mode 100644 site/routes/process_bp.py delete mode 100644 site/routes/upload_bp.py diff --git a/site/app.py b/site/app.py index 36cba82..7c3e7b1 100644 --- a/site/app.py +++ b/site/app.py @@ -20,7 +20,7 @@ if _sys_path_root not in sys.path: sys.path.insert(0, _sys_path_root) # Версия приложения (меняется при изменениях) -VERSION = "0.0.3" +VERSION = "0.0.1" def create_app(): diff --git a/site/routes/__init__.py b/site/routes/__init__.py index a475b5b..2b542c3 100644 --- a/site/routes/__init__.py +++ b/site/routes/__init__.py @@ -1,13 +1,14 @@ from .main_bp import main_bp from .health_bp import health_bp -from .upload_bp import upload_bp -from .process_bp import process_bp -from .download_bp import download_bp +from .api_bp import api_bp def register_routes(app): + """Зарегистрировать все blueprint'ы на Flask-приложении. + + Args: + app: Экземпляр Flask-приложения + """ app.register_blueprint(main_bp) app.register_blueprint(health_bp) - app.register_blueprint(upload_bp) - app.register_blueprint(process_bp) - app.register_blueprint(download_bp) + app.register_blueprint(api_bp) diff --git a/site/routes/api_bp.py b/site/routes/api_bp.py new file mode 100644 index 0000000..a32b301 --- /dev/null +++ b/site/routes/api_bp.py @@ -0,0 +1,83 @@ +""" +Blueprint: API DrHider. + +Three endpoints: +- POST /api/upload — upload one file -> {session_id} +- POST /api/process/{sid} — process all session files -> {status:"done"} +- GET /api/download/{sid} — download ZIP +""" + +import io +import zipfile +import traceback +from flask import Blueprint, request, send_file, jsonify + +from drhider import obfuscate_files, LLMClient +from drhider.builder import build_zip, build_mapping_csv +from session import create_session, add_file, get_files, store_result, get_result, cleanup, file_count + +api_bp = Blueprint("api", __name__, url_prefix="/api") + + +@api_bp.route("/upload", methods=["POST"]) +def upload(): + """Upload one file to session.""" + sid = request.form.get("session", "") + if not sid: + sid = create_session() + uploaded = request.files.getlist("files") + if not uploaded: + return jsonify({"ok": False, "error": "No file"}), 400 + f = uploaded[0] + if not f.filename: + return jsonify({"ok": False, "error": "No filename"}), 400 + ok = add_file(sid, f.filename, f.read()) + if not ok: + return jsonify({"ok": False, "error": "Session not found"}), 404 + return jsonify({"ok": True, "session": sid, "count": file_count(sid)}) + + +@api_bp.route("/process/", methods=["POST"]) +def process(sid): + """Process all session files one by one -> ZIP.""" + files = get_files(sid) + if files is None: + return jsonify({"ok": False, "error": "Session not found"}), 404 + if not files: + return jsonify({"ok": False, "error": "No files"}), 400 + try: + llm = LLMClient() + all_results = [] + all_mapping = {} + for fname, content in files: + zip_data, _csv = obfuscate_files([(fname, content, "")], llm_client=llm) + with zipfile.ZipFile(io.BytesIO(zip_data)) as zf: + for name in zf.namelist(): + if name == "mapping.csv": + csv_text = zf.read(name).decode("utf-8") + lines = csv_text.strip().split("\n") + if len(lines) > 1: + for line in lines[1:]: + parts = line.split(",", 2) + if len(parts) >= 3: + all_mapping[parts[1]] = parts[2] + elif not name.endswith("/"): + all_results.append((name, zf.read(name))) + csv_str = build_mapping_csv(all_mapping) if all_mapping else "" + final_zip = build_zip(all_results, mapping_csv=csv_str) + store_result(sid, final_zip) + return jsonify({"ok": True, "status": "done", "files": len(all_results)}) + except Exception as e: + traceback.print_exc() + return jsonify({"ok": False, "error": str(e)}), 500 + + +@api_bp.route("/download/", methods=["GET"]) +def download(sid): + """Download result and cleanup session.""" + zip_data = get_result(sid) + if zip_data is None: + return jsonify({"ok": False, "error": "Not found"}), 404 + cleanup(sid) + return send_file(io.BytesIO(zip_data), mimetype="application/zip", + as_attachment=True, download_name="drhider_output.zip") diff --git a/site/routes/download_bp.py b/site/routes/download_bp.py deleted file mode 100644 index 623b6b6..0000000 --- a/site/routes/download_bp.py +++ /dev/null @@ -1,21 +0,0 @@ -""" -GET /api/download/{sid} — скачать ZIP и удалить сессию. - -После этого вызова — всё чисто, памяти ноль. -""" - -import io -from flask import Blueprint, send_file, jsonify -from session import get_result, cleanup - -download_bp = Blueprint("download", __name__, url_prefix="/api") - - -@download_bp.route("/download/", methods=["GET"]) -def download(sid): - zip_data = get_result(sid) - if zip_data is None: - return jsonify({"ok": False, "error": "Not found"}), 404 - cleanup(sid) - return send_file(io.BytesIO(zip_data), mimetype="application/zip", - as_attachment=True, download_name="drhider_output.zip") diff --git a/site/routes/process_bp.py b/site/routes/process_bp.py deleted file mode 100644 index 06062d5..0000000 --- a/site/routes/process_bp.py +++ /dev/null @@ -1,47 +0,0 @@ -""" -POST /api/process/{sid} — обработать ВСЕ файлы сессии по одному. - -Блокирует до завершения. Результат сохраняется в сессии. -""" - -import io, zipfile, traceback -from flask import Blueprint, jsonify -from drhider import obfuscate_files, LLMClient -from drhider.builder import build_zip, build_mapping_csv -from session import get_files, store_result - -process_bp = Blueprint("process", __name__, url_prefix="/api") - - -@process_bp.route("/process/", methods=["POST"]) -def process(sid): - files = get_files(sid) - if files is None: - return jsonify({"ok": False, "error": "Session not found"}), 404 - if not files: - return jsonify({"ok": False, "error": "No files"}), 400 - try: - llm = LLMClient() - all_results = [] - all_mapping = {} - for fname, content in files: - zip_data, _csv = obfuscate_files([(fname, content, "")], llm_client=llm) - with zipfile.ZipFile(io.BytesIO(zip_data)) as zf: - for name in zf.namelist(): - if name == "mapping.csv": - csv_text = zf.read(name).decode("utf-8") - lines = csv_text.strip().split("\n") - if len(lines) > 1: - for line in lines[1:]: - parts = line.split(",", 2) - if len(parts) >= 3: - all_mapping[parts[1]] = parts[2] - elif not name.endswith("/"): - all_results.append((name, zf.read(name))) - csv_str = build_mapping_csv(all_mapping) if all_mapping else "" - final_zip = build_zip(all_results, mapping_csv=csv_str) - store_result(sid, final_zip) - return jsonify({"ok": True, "status": "done", "files": len(all_results)}) - except Exception as e: - traceback.print_exc() - return jsonify({"ok": False, "error": str(e)}), 500 diff --git a/site/routes/upload_bp.py b/site/routes/upload_bp.py deleted file mode 100644 index 0ac0ce6..0000000 --- a/site/routes/upload_bp.py +++ /dev/null @@ -1,28 +0,0 @@ -""" -POST /api/upload — загрузить ОДИН файл. - -Каждый вызов — новое соединение, передал → закрыл. -Сессия связывает файлы через session_id. -""" - -from flask import Blueprint, request, jsonify -from session import create_session, add_file, file_count - -upload_bp = Blueprint("upload", __name__, url_prefix="/api") - - -@upload_bp.route("/upload", methods=["POST"]) -def upload(): - sid = request.form.get("session", "") - if not sid: - sid = create_session() - uploaded = request.files.getlist("files") - if not uploaded: - return jsonify({"ok": False, "error": "No file"}), 400 - f = uploaded[0] - if not f.filename: - return jsonify({"ok": False, "error": "No filename"}), 400 - ok = add_file(sid, f.filename, f.read()) - if not ok: - return jsonify({"ok": False, "error": "Session not found"}), 404 - return jsonify({"ok": True, "session": sid, "count": file_count(sid)}) diff --git a/tests/test_upload.py b/tests/test_upload.py index 105b785..8fdb5cb 100644 --- a/tests/test_upload.py +++ b/tests/test_upload.py @@ -15,18 +15,10 @@ import gc # Настраиваем пути _site = os.path.join(os.path.dirname(__file__), "..", "site") sys.path.insert(0, _site) -sys.path.insert(0, os.path.join(os.path.dirname(__file__), "..")) +sys.path.insert(0, os.path.dirname(_site)) # project root for drhider from flask import Flask - -# Импортируем напрямую, минуя routes/__init__.py (process_bp тянет drhider) -import importlib.util -_spec = importlib.util.spec_from_file_location( - "upload_bp", os.path.join(_site, "routes", "upload_bp.py") -) -_upload_mod = importlib.util.module_from_spec(_spec) -_spec.loader.exec_module(_upload_mod) -upload_bp = _upload_mod.upload_bp +from routes.api_bp import api_bp # ═══════════════════════════════════════════════════════════════════════════ @@ -36,7 +28,7 @@ upload_bp = _upload_mod.upload_bp def _new_client(): """Создать свежий тестовый клиент.""" app = Flask(__name__) - app.register_blueprint(upload_bp) + app.register_blueprint(api_bp) return app.test_client()