v0.0.2: split api_bp into upload/process/download modules, Connection: close, upload tests (13 new, 106 total)
Deploy drhider / validate (push) Waiting to run

This commit is contained in:
2026-07-13 09:15:38 +04:00
parent 345448caa4
commit c35e8da357
7 changed files with 387 additions and 97 deletions
+6 -13
View File
@@ -1,20 +1,13 @@
"""
Регистрация всех blueprint'ов приложения.
Импортируется из site/app.py при создании Flask-приложения.
"""
from .main_bp import main_bp
from .health_bp import health_bp
from .api_bp import api_bp
from .upload_bp import upload_bp
from .process_bp import process_bp
from .download_bp import download_bp
def register_routes(app):
"""Зарегистрировать все blueprint'ы на Flask-приложении.
Args:
app: Экземпляр Flask-приложения
"""
app.register_blueprint(main_bp)
app.register_blueprint(health_bp)
app.register_blueprint(api_bp)
app.register_blueprint(upload_bp)
app.register_blueprint(process_bp)
app.register_blueprint(download_bp)
-83
View File
@@ -1,83 +0,0 @@
"""
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/<sid>", 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/<sid>", 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")
+21
View File
@@ -0,0 +1,21 @@
"""
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/<sid>", 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")
+47
View File
@@ -0,0 +1,47 @@
"""
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/<sid>", 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
+28
View File
@@ -0,0 +1,28 @@
"""
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)})