from __future__ import annotations import hashlib from datetime import datetime, timedelta from .types import SmsSession class AliyunSmsSessionManager: def __init__(self, ttl_minutes: int = 5): self._sessions: dict[str, SmsSession] = {} self._phone_to_session: dict[str, str] = {} self._ttl = timedelta(minutes=ttl_minutes) def resolve_session(self, phone_number: str) -> SmsSession: now = datetime.now() existing_id = self._phone_to_session.get(phone_number) if existing_id: session = self._sessions.get(existing_id) if session and not session.is_expired: session.touch() return session session_id = _generate_session_id(phone_number, now) session = SmsSession( session_id=session_id, phone_number=phone_number, ttl_minutes=int(self._ttl.total_seconds() / 60), last_activity=now, ) self._sessions[session_id] = session self._phone_to_session[phone_number] = session_id self._evict_expired() return session def get_session(self, phone_number: str) -> SmsSession | None: session_id = self._phone_to_session.get(phone_number) if session_id: return self._sessions.get(session_id) return None def close_session(self, phone_number: str): session_id = self._phone_to_session.pop(phone_number, None) if session_id: self._sessions.pop(session_id, None) def _evict_expired(self): expired_ids = [sid for sid, s in self._sessions.items() if s.is_expired] for sid in expired_ids: session = self._sessions.pop(sid) self._phone_to_session.pop(session.phone_number, None) def _generate_session_id(phone_number: str, now: datetime) -> str: raw = f"{phone_number}:{now.isoformat()}" return hashlib.sha256(raw.encode()).hexdigest()[:16]