Files
BanGUI/backend/app/utils/session_cache.py
Lukas 53cdd63b6a Add no-op session cache when session cache is disabled
Use NoOpSessionCache in backend/app/main.py and dynamically switch cache implementation in backend/app/dependencies.py so disabled cache mode remains safe while get_session_cache always returns a valid object.
2026-04-14 12:14:50 +02:00

74 lines
2.1 KiB
Python

"""Pluggable session cache abstraction.
This module defines a cache interface for authenticated sessions and a default
process-local in-memory implementation. The backend can swap the cache
implementation without changing the authentication dependency logic.
"""
from __future__ import annotations
import time
from typing import TYPE_CHECKING, Protocol
if TYPE_CHECKING: # pragma: no cover
from app.models.auth import Session
class SessionCache(Protocol):
"""Interface for session token validation cache backends."""
def get(self, token: str) -> Session | None:
"""Return the cached session for *token*, or ``None`` if missing."""
def set(self, token: str, session: Session, ttl_seconds: float) -> None:
"""Cache the validated *session* for *token* for *ttl_seconds*."""
def invalidate(self, token: str) -> None:
"""Remove *token* from the cache if it exists."""
def clear(self) -> None:
"""Remove all entries from the cache."""
class InMemorySessionCache:
"""A process-local session cache implementation."""
def __init__(self) -> None:
self._entries: dict[str, tuple[Session, float]] = {}
def get(self, token: str) -> Session | None:
entry = self._entries.get(token)
if entry is None:
return None
session, expires_at = entry
if time.monotonic() >= expires_at:
self._entries.pop(token, None)
return None
return session
def set(self, token: str, session: Session, ttl_seconds: float) -> None:
self._entries[token] = (session, time.monotonic() + ttl_seconds)
def invalidate(self, token: str) -> None:
self._entries.pop(token, None)
def clear(self) -> None:
self._entries.clear()
class NoOpSessionCache:
"""A no-op session cache used when caching is disabled."""
def get(self, token: str) -> Session | None:
return None
def set(self, token: str, session: Session, ttl_seconds: float) -> None:
return None
def invalidate(self, token: str) -> None:
return None
def clear(self) -> None:
return None