59 lines
1.9 KiB
Python
59 lines
1.9 KiB
Python
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]
|