chore: удалить неиспользуемый site/session.py, bump v0.0.76
Deploy drhider / validate (push) Canceled after 0s
Deploy drhider / validate (push) Canceled after 0s
This commit is contained in:
+1
-1
@@ -21,7 +21,7 @@ if _sys_path_root not in sys.path:
|
|||||||
sys.path.insert(0, _sys_path_root)
|
sys.path.insert(0, _sys_path_root)
|
||||||
|
|
||||||
# Версия приложения (меняется при изменениях)
|
# Версия приложения (меняется при изменениях)
|
||||||
VERSION = "0.0.75"
|
VERSION = "0.0.76"
|
||||||
|
|
||||||
|
|
||||||
def setup_logging():
|
def setup_logging():
|
||||||
|
|||||||
-230
@@ -1,230 +0,0 @@
|
|||||||
"""
|
|
||||||
Хранилище сессий в памяти с автоочисткой по TTL.
|
|
||||||
|
|
||||||
Использование:
|
|
||||||
sid = create_session()
|
|
||||||
add_file(sid, filename, content_bytes)
|
|
||||||
files = get_files(sid)
|
|
||||||
store_result(sid, zip_bytes)
|
|
||||||
zip_data = get_result(sid)
|
|
||||||
cleanup(sid)
|
|
||||||
"""
|
|
||||||
|
|
||||||
import uuid
|
|
||||||
import threading
|
|
||||||
import time
|
|
||||||
from typing import Dict, List, Tuple, Optional
|
|
||||||
|
|
||||||
# ═══════════════════════════════════════════════════════════════════════════
|
|
||||||
# Данные сессии
|
|
||||||
# ═══════════════════════════════════════════════════════════════════════════
|
|
||||||
|
|
||||||
TTL_SECONDS = 30 * 60 # 30 минут
|
|
||||||
|
|
||||||
# Максимальный объём одного файла и суммарный объём файлов в сессии (защита памяти)
|
|
||||||
MAX_FILE_BYTES = 50 * 1024 * 1024 # 50 MB на один файл
|
|
||||||
MAX_SESSION_BYTES = 500 * 1024 * 1024 # 500 MB суммарно на сессию
|
|
||||||
|
|
||||||
_sessions: Dict[str, dict] = {}
|
|
||||||
_lock = threading.Lock()
|
|
||||||
|
|
||||||
|
|
||||||
def _start_timer(sid: str):
|
|
||||||
"""Запустить таймер автоочистки сессии через TTL."""
|
|
||||||
|
|
||||||
def _clean():
|
|
||||||
with _lock:
|
|
||||||
_sessions.pop(sid, None)
|
|
||||||
|
|
||||||
timer = threading.Timer(TTL_SECONDS, _clean)
|
|
||||||
timer.daemon = True
|
|
||||||
timer.start()
|
|
||||||
return timer
|
|
||||||
|
|
||||||
|
|
||||||
def touch(sid: str):
|
|
||||||
"""Продлить жизнь сессии: перезапустить TTL-таймер (если сессия существует)."""
|
|
||||||
with _lock:
|
|
||||||
s = _sessions.get(sid)
|
|
||||||
if not s:
|
|
||||||
return
|
|
||||||
if s.get("timer"):
|
|
||||||
s["timer"].cancel()
|
|
||||||
s["timer"] = _start_timer(sid)
|
|
||||||
|
|
||||||
|
|
||||||
def pause_ttl(sid: str):
|
|
||||||
"""Приостановить TTL сессии (во время обработки): сессия живёт, пока идёт воркер."""
|
|
||||||
with _lock:
|
|
||||||
s = _sessions.get(sid)
|
|
||||||
if s and s.get("timer"):
|
|
||||||
s["timer"].cancel()
|
|
||||||
s["timer"] = None
|
|
||||||
|
|
||||||
|
|
||||||
def resume_ttl(sid: str):
|
|
||||||
"""Возобновить TTL сессии (после завершения обработки): результат доступен ещё TTL."""
|
|
||||||
with _lock:
|
|
||||||
s = _sessions.get(sid)
|
|
||||||
if not s:
|
|
||||||
return
|
|
||||||
if s.get("timer"):
|
|
||||||
s["timer"].cancel()
|
|
||||||
s["timer"] = _start_timer(sid)
|
|
||||||
|
|
||||||
|
|
||||||
def request_cancel(sid: str) -> bool:
|
|
||||||
"""Запросить мягкое прерывание обработки сессии.
|
|
||||||
|
|
||||||
Returns:
|
|
||||||
True если сессия существует и отмена запрошена, False если нет.
|
|
||||||
"""
|
|
||||||
with _lock:
|
|
||||||
s = _sessions.get(sid)
|
|
||||||
if not s:
|
|
||||||
return False
|
|
||||||
s["cancel"].set()
|
|
||||||
return True
|
|
||||||
|
|
||||||
|
|
||||||
def get_cancel_event(sid: str) -> Optional[threading.Event]:
|
|
||||||
"""Получить событие отмены сессии (или None, если сессии нет)."""
|
|
||||||
with _lock:
|
|
||||||
s = _sessions.get(sid)
|
|
||||||
return s["cancel"] if s else None
|
|
||||||
|
|
||||||
|
|
||||||
# ═══════════════════════════════════════════════════════════════════════════
|
|
||||||
# API
|
|
||||||
# ═══════════════════════════════════════════════════════════════════════════
|
|
||||||
|
|
||||||
def create_session() -> str:
|
|
||||||
"""Создать новую сессию.
|
|
||||||
|
|
||||||
Returns:
|
|
||||||
Уникальный идентификатор сессии (UUID).
|
|
||||||
"""
|
|
||||||
sid = uuid.uuid4().hex
|
|
||||||
with _lock:
|
|
||||||
_sessions[sid] = {
|
|
||||||
"files": [],
|
|
||||||
"result": None,
|
|
||||||
"cancel": threading.Event(),
|
|
||||||
"timer": _start_timer(sid),
|
|
||||||
}
|
|
||||||
return sid
|
|
||||||
|
|
||||||
|
|
||||||
def add_file(sid: str, filename: str, content: bytes) -> bool:
|
|
||||||
"""Добавить файл в сессию.
|
|
||||||
|
|
||||||
Args:
|
|
||||||
sid: Идентификатор сессии
|
|
||||||
filename: Имя файла
|
|
||||||
content: Бинарное содержимое
|
|
||||||
|
|
||||||
Returns:
|
|
||||||
True если сессия существует, False если нет.
|
|
||||||
"""
|
|
||||||
with _lock:
|
|
||||||
s = _sessions.get(sid)
|
|
||||||
if not s:
|
|
||||||
return False
|
|
||||||
total = sum(len(c) for _, c in s["files"])
|
|
||||||
if total + len(content) > MAX_SESSION_BYTES:
|
|
||||||
return False # превышен суммарный лимит сессии
|
|
||||||
s["files"].append((filename, content))
|
|
||||||
return True
|
|
||||||
|
|
||||||
|
|
||||||
def get_files(sid: str) -> Optional[List[Tuple[str, bytes]]]:
|
|
||||||
"""Получить все файлы сессии.
|
|
||||||
|
|
||||||
Args:
|
|
||||||
sid: Идентификатор сессии
|
|
||||||
|
|
||||||
Returns:
|
|
||||||
[(filename, content), ...] или None если сессия не найдена.
|
|
||||||
"""
|
|
||||||
with _lock:
|
|
||||||
s = _sessions.get(sid)
|
|
||||||
return list(s["files"]) if s else None
|
|
||||||
|
|
||||||
|
|
||||||
def file_count(sid: str) -> int:
|
|
||||||
"""Количество файлов в сессии."""
|
|
||||||
with _lock:
|
|
||||||
s = _sessions.get(sid)
|
|
||||||
return len(s["files"]) if s else 0
|
|
||||||
|
|
||||||
|
|
||||||
def store_result(sid: str, zip_data: bytes) -> bool:
|
|
||||||
"""Сохранить результат обработки.
|
|
||||||
|
|
||||||
Args:
|
|
||||||
sid: Идентификатор сессии
|
|
||||||
zip_data: ZIP-архив с результатом
|
|
||||||
|
|
||||||
Returns:
|
|
||||||
True если сессия существует, False если нет.
|
|
||||||
"""
|
|
||||||
with _lock:
|
|
||||||
s = _sessions.get(sid)
|
|
||||||
if not s:
|
|
||||||
return False
|
|
||||||
s["result"] = zip_data
|
|
||||||
return True
|
|
||||||
|
|
||||||
|
|
||||||
def get_result(sid: str) -> Optional[bytes]:
|
|
||||||
"""Получить результат обработки.
|
|
||||||
|
|
||||||
Args:
|
|
||||||
sid: Идентификатор сессии
|
|
||||||
|
|
||||||
Returns:
|
|
||||||
ZIP-архив или None если сессия не найдена/результат не готов.
|
|
||||||
"""
|
|
||||||
with _lock:
|
|
||||||
s = _sessions.get(sid)
|
|
||||||
return s["result"] if s else None
|
|
||||||
|
|
||||||
|
|
||||||
def cleanup(sid: str):
|
|
||||||
"""Удалить сессию."""
|
|
||||||
with _lock:
|
|
||||||
s = _sessions.pop(sid, None)
|
|
||||||
if s and s.get("timer"):
|
|
||||||
s["timer"].cancel()
|
|
||||||
|
|
||||||
|
|
||||||
def store_csv(sid: str, csv_str: str) -> bool:
|
|
||||||
"""Сохранить CSV с таблицей замен.
|
|
||||||
|
|
||||||
Args:
|
|
||||||
sid: Идентификатор сессии
|
|
||||||
csv_str: Строка CSV
|
|
||||||
|
|
||||||
Returns:
|
|
||||||
True если сессия существует, False если нет.
|
|
||||||
"""
|
|
||||||
with _lock:
|
|
||||||
s = _sessions.get(sid)
|
|
||||||
if not s:
|
|
||||||
return False
|
|
||||||
s["csv"] = csv_str
|
|
||||||
return True
|
|
||||||
|
|
||||||
|
|
||||||
def get_csv(sid: str) -> Optional[str]:
|
|
||||||
"""Получить CSV с таблицей замен.
|
|
||||||
|
|
||||||
Args:
|
|
||||||
sid: Идентификатор сессии
|
|
||||||
|
|
||||||
Returns:
|
|
||||||
Строка CSV или None если нет.
|
|
||||||
"""
|
|
||||||
with _lock:
|
|
||||||
s = _sessions.get(sid)
|
|
||||||
return s.get("csv") if s else None
|
|
||||||
Reference in New Issue
Block a user