Source code for duck.http.session.session_storage_connector
"""
Module containing SessionConnector class which can be used to connect to
session storage to perform operations like get, set, update, delete, clear, etc.
"""
import os
import uuid
from typing import Callable
from duck.settings import SETTINGS
from duck.settings.loaded import SettingsLoaded
from duck.utils.caching import CacheBase, InMemoryCache
[docs]
def get_session_storage_connector():
"""
Returns the session storage connector object.
"""
return SettingsLoaded.SESSION_STORAGE_CONNECTOR.getresult()
[docs]
class SessionStorageConnectorError(Exception):
"""
Raised when errors related to the session storage connector arises
"""
[docs]
class SessionStorageConnector:
"""
This class is used to connect to the session storage and perform almost all the operations on the session storage
"""
_instance = None
_initialized = False
CACHED_SESSIONS = InMemoryCache(maxkeys=1024 * 4)
"""
In Memory cache for sessions.
"""
def __init__(self, session_storage_cls: Callable):
"""
Initialize SessionStorageConnector
Args:
session_storage_cls (Callable): Class to initialize the session storage object
"""
if self.__class__._initialized:
if session_storage_cls is not self.session_storage_cls:
raise SessionStorageConnectorError(
"SessionStorageConnector already initialized with a different session storage class."
)
return
self.session_dir = SETTINGS["SESSION_DIR"]
self.session_storage_cls = session_storage_cls
if self.session_dir:
os.makedirs(self.session_dir, exist_ok=True)
try:
self._session_storage = session_storage_cls()
except TypeError:
self._session_storage = session_storage_cls(self.session_dir)
self.__class__._initialized = True
[docs]
@staticmethod
def generate_session_id() -> str:
"""
Retrieve a random generated session ID.
"""
return str(uuid.uuid4())
[docs]
def set_session(
self,
session_id: str,
data: dict,
expiry: int | float = None
):
"""
Set the session data.
"""
if expiry:
self._session_storage.set(session_id, data, expiry)
else:
self._session_storage.set(session_id, data)
# Update cache in memory also - only if not in memory cache is used
if not issubclass(self.session_storage_cls, InMemoryCache):
self.CACHED_SESSIONS.set(session_id, data, expiry=expiry)
[docs]
def update_session(self, session_id: str, data: dict):
"""
Update the session data.
"""
prev_data = self.get_session(session_id) or {}
prev_data.update(data)
self.set_session(session_id, prev_data)
[docs]
def get_session(self, session_id: str):
"""
Get the session data.
"""
# Get session from cache - only if not in memory cache is used
if not issubclass(self.session_storage_cls, InMemoryCache):
session = self.CACHED_SESSIONS.get(session_id)
if session is not None:
return session
# Get session from real storage
return self._session_storage.get(session_id)
[docs]
def delete_session(self, session_id: str):
"""
Delete session data.
"""
self._session_storage.delete(session_id)
[docs]
def clear_all_sessions(self):
"""
Clear all session data.
"""
self._session_storage.clear()
[docs]
def save(self):
"""
Saves the current sessions to session storage.
"""
self._session_storage.save()
[docs]
def close(self):
"""
Close the session storage.
"""
self._session_storage.close()
[docs]
def __new__(cls, session_storage_cls: CacheBase):
from duck.meta import Meta
if cls._instance is None:
Meta.set_metadata("SESSION_STORAGE_SET", True)
cls._instance = super().__new__(cls)
return cls._instance