| | |
| | """ |
| | Módulo Enterprise Session Manager |
| | |
| | Gerencia o ciclo de vida das sessões de usuário de forma robusta e thread-safe. |
| | Armazena dados detalhados da sessão, incluindo contexto, métricas de uso e |
| | preferências do usuário, com expiração baseada em inatividade. |
| | """ |
| |
|
| | import uuid |
| | import time |
| | import logging |
| | import threading |
| | from datetime import datetime, timezone |
| | from typing import Dict, Any, Optional, Literal |
| |
|
| |
|
| | |
| | logger = logging.getLogger(f"superezio_enterprise.{__name__}") |
| |
|
| | |
| | SessionMetric = Literal["messages_sent", "commands_executed", "errors_encountered"] |
| |
|
| |
|
| | class EnterpriseSessionManager: |
| | """ |
| | Gerenciador de sessões em memória, implementado como um singleton thread-safe. |
| | |
| | As sessões mantêm o estado do usuário e expiram após um período de inatividade |
| | configurável (session_ttl_seconds). Cada sessão contém metadados, contexto, |
| | métricas de interação e preferências do usuário. |
| | """ |
| |
|
| | _instance = None |
| | _lock = threading.Lock() |
| |
|
| | def __new__(cls, *args, **kwargs): |
| | if not cls._instance: |
| | with cls._lock: |
| | if not cls._instance: |
| | cls._instance = super().__new__(cls) |
| | return cls._instance |
| |
|
| | def __init__(self, session_ttl_seconds: int = 1800): |
| | if hasattr(self, "_initialized") and self._initialized: |
| | return |
| |
|
| | self.sessions: Dict[str, Dict[str, Any]] = {} |
| | self._last_activity_ts: Dict[str, float] = {} |
| | self.session_ttl = session_ttl_seconds |
| | self._lock = threading.RLock() |
| | self._initialized = True |
| | logger.info( |
| | "EnterpriseSessionManager (Singleton) inicializado com TTL de %ds.", |
| | self.session_ttl, |
| | ) |
| |
|
| | def create_session(self, user_id: str, initial_prefs: Optional[Dict] = None) -> str: |
| | """ |
| | Cria uma nova sessão para um usuário e retorna o ID da sessão. |
| | """ |
| | session_id = f"sess-{uuid.uuid4()}" |
| | now = datetime.now(timezone.utc) |
| | with self._lock: |
| | self.sessions[session_id] = { |
| | "user_id": user_id, |
| | "created_at": now, |
| | "last_activity": now, |
| | "context": {}, |
| | "metrics": { |
| | "messages_sent": 0, |
| | "commands_executed": 0, |
| | "errors_encountered": 0, |
| | }, |
| | "preferences": { |
| | "theme": "dark", |
| | "language": "pt-BR", |
| | **(initial_prefs or {}), |
| | }, |
| | } |
| | self._last_activity_ts[session_id] = time.monotonic() |
| | logger.info("Sessão criada: %s para o usuário '%s'.", session_id, user_id) |
| | return session_id |
| |
|
| | def get_session(self, session_id: str) -> Optional[Dict[str, Any]]: |
| | """ |
| | Recupera uma sessão se ela existir e não tiver expirado devido à inatividade. |
| | Atualiza o timestamp de última atividade da sessão. |
| | """ |
| | if not session_id: |
| | return None |
| |
|
| | with self._lock: |
| | if session_id not in self.sessions: |
| | return None |
| |
|
| | |
| | if ( |
| | time.monotonic() - self._last_activity_ts.get(session_id, 0) |
| | > self.session_ttl |
| | ): |
| | logger.warning("Sessão %s expirou devido à inatividade.", session_id) |
| | self.invalidate_session(session_id) |
| | return None |
| |
|
| | |
| | self.sessions[session_id]["last_activity"] = datetime.now(timezone.utc) |
| | self._last_activity_ts[session_id] = time.monotonic() |
| | logger.debug("Sessão %s acessada com sucesso.", session_id) |
| | return self.sessions[session_id] |
| |
|
| | def update_session_metric( |
| | self, session_id: str, metric: SessionMetric, increment: int = 1 |
| | ) -> bool: |
| | """ |
| | Atualiza uma métrica específica dentro de uma sessão válida. |
| | """ |
| | with self._lock: |
| | session = self.get_session(session_id) |
| | if session and metric in session["metrics"]: |
| | session["metrics"][metric] += increment |
| | logger.debug( |
| | "Métrica '%s' na sessão %s atualizada para %d.", |
| | metric, |
| | session_id, |
| | session["metrics"][metric], |
| | ) |
| | return True |
| | elif session: |
| | logger.warning( |
| | "Métrica desconhecida '%s' para a sessão %s.", metric, session_id |
| | ) |
| | return False |
| |
|
| | def invalidate_session(self, session_id: str) -> None: |
| | """Remove uma sessão do gerenciador.""" |
| | with self._lock: |
| | if session_id in self.sessions: |
| | del self.sessions[session_id] |
| | del self._last_activity_ts[session_id] |
| | logger.info("Sessão %s foi invalidada e removida.", session_id) |
| |
|
| |
|
| | |
| | |
| | session_manager = EnterpriseSessionManager() |
| |
|