gonets/SRV/storage/session_storage.py

158 lines
6.6 KiB
Python
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

# storage/session_storage.py
import json
import os
import uuid
import logging
from typing import Optional, Dict
from datetime import datetime, timedelta
logging.basicConfig(level=logging.INFO)
logger = logging.getLogger(__name__)
class SessionStorage:
def __init__(self, file_path: str = "/etc/gonets/sessions.json"):
self.file_path = file_path
self._ensure_file_exists()
def _ensure_file_exists(self):
try:
logger.info(f"Проверка существования файла {self.file_path}")
if not os.path.exists(self.file_path):
logger.info(f"Создание директории {os.path.dirname(self.file_path)}")
os.makedirs(os.path.dirname(self.file_path), exist_ok=True)
logger.info(f"Создание файла {self.file_path}")
with open(self.file_path, "w") as f:
json.dump({"sessions": {}}, f)
os.chmod(self.file_path, 0o600)
logger.info(f"Создан файл {self.file_path}")
else:
logger.info(f"Файл {self.file_path} уже существует")
except Exception as e:
logger.error(
f"Ошибка при создании файла {self.file_path}: {type(e).__name__} - {str(e)}"
)
raise
def _read_data(self) -> Dict:
try:
with open(self.file_path, "r") as f:
return json.load(f)
except Exception as e:
logger.error(
f"Ошибка при чтении файла {self.file_path}: {type(e).__name__} - {str(e)}"
)
raise
def _write_data(self, data: Dict):
try:
with open(self.file_path, "w") as f:
json.dump(data, f, indent=2)
except Exception as e:
logger.error(
f"Ошибка при записи файла {self.file_path}: {type(e).__name__} - {str(e)}"
)
raise
def create_session(self, username: str, token: str, client_id: str) -> str:
"""Создаёт новую сессию и возвращает session_id"""
try:
self.clean_expired_sessions()
data = self._read_data()
session_id = str(uuid.uuid4())
created_at = datetime.utcnow().isoformat()
expiry = (datetime.utcnow() + timedelta(minutes=30)).isoformat()
data["sessions"][session_id] = {
"username": username,
"token": token,
"client_id": client_id,
"created_at": created_at,
"expiry": expiry,
}
self._write_data(data)
logger.info(
f"Сессия создана для пользователя {username} с session_id {session_id}"
)
return session_id
except Exception as e:
logger.error(
f"Ошибка при создании сессии для {username}: {type(e).__name__} - {str(e)}"
)
raise
def get_latest_session(self, client_id: str) -> Optional[Dict]:
"""Получает последнюю активную сессию для client_id"""
try:
self.clean_expired_sessions()
data = self._read_data()
latest_session = None
latest_time = None
for session_id, session in data["sessions"].items():
if session["client_id"] == client_id:
expiry = datetime.fromisoformat(session["expiry"])
if datetime.utcnow() > expiry:
logger.info(f"Сессия {session_id} истекла")
del data["sessions"][session_id]
continue
created_at = datetime.fromisoformat(session["created_at"])
if latest_time is None or created_at > latest_time:
latest_time = created_at
latest_session = session
latest_session["session_id"] = session_id
if latest_session:
logger.info(f"Найдена сессия для client_id {client_id}")
return latest_session
logger.info(f"Сессия для client_id {client_id} не найдена")
self._write_data(data)
return None
except Exception as e:
logger.error(
f"Ошибка при получении сессии для client_id {client_id}: {type(e).__name__} - {str(e)}"
)
raise
def delete_session(self, session_id: str):
"""Удаляет сессию по session_id"""
try:
self.clean_expired_sessions()
data = self._read_data()
if session_id in data["sessions"]:
del data["sessions"][session_id]
self._write_data(data)
logger.info(f"Сессия с session_id {session_id} удалена")
except Exception as e:
logger.error(
f"Ошибка при удалении сессии {session_id}: {type(e).__name__} - {str(e)}"
)
raise
def clean_expired_sessions(self):
"""Удаляет все истекшие сессии из хранилища"""
try:
data = self._read_data()
expired_sessions = []
current_time = datetime.utcnow()
# Находим истекшие сессии
for session_id, session in list(data["sessions"].items()):
expiry = datetime.fromisoformat(session["expiry"])
if current_time > expiry:
expired_sessions.append(session_id)
# Удаляем истекшие сессии
for session_id in expired_sessions:
del data["sessions"][session_id]
logger.info(f"Удалена истекшая сессия с session_id {session_id}")
# Записываем обновлённые данные
if expired_sessions:
self._write_data(data)
logger.info(f"Удалено {len(expired_sessions)} истекших сессий")
else:
logger.debug("Истекшие сессии не найдены")
except Exception as e:
logger.error(
f"Ошибка при очистке истекших сессий: {type(e).__name__} - {str(e)}"
)
raise