Source code for genro_asgi.session.session

# Copyright 2025 Softwell S.r.l.
# Licensed under the Apache License, Version 2.0

"""Server-managed session with metadata, Bag data, and auth context.

A Session groups request-scoped state under a unique ID with expiry tracking.
SessionMiddleware creates or reconnects sessions via cookies and attaches
them to ``scope["session"]``. Each session holds an Avatar for the
authenticated user and a Bag for arbitrary application data.
"""

from __future__ import annotations

import time
from typing import Any

from genro_bag import Bag

from .avatar import Avatar

__all__ = ["Session"]


[docs] class Session: """Server-managed session with meta, data (Bag), and auth snapshot. Attributes: _id: Unique session token. _meta: Server-managed metadata (created_at, last_access, ttl). _data: Application data as Bag. _auth: Auth snapshot from session creation. """ __slots__ = ("_id", "_meta", "_data", "_auth", "_avatar")
[docs] def __init__(self, session_id: str, auth: dict[str, Any] | None, ttl: int) -> None: """Initialize session. Args: session_id: Unique session token. auth: Auth dict snapshot from authentication, or None. ttl: Time-to-live in seconds. """ now = time.time() self._id = session_id self._meta: dict[str, Any] = { "created_at": now, "last_access": now, "ttl": ttl, } self._data = Bag() self._auth = auth self._avatar = Avatar(auth=auth)
@property def id(self) -> str: """Unique session token.""" return self._id @property def meta(self) -> dict[str, Any]: """Server-managed metadata: created_at, last_access, ttl.""" return self._meta @property def data(self) -> Bag: """Application data as Bag.""" return self._data @property def auth(self) -> dict[str, Any] | None: """Auth snapshot from session creation.""" return self._auth @property def avatar(self) -> Avatar: """User identity avatar built from auth snapshot.""" return self._avatar
[docs] def touch(self) -> None: """Update last_access timestamp.""" self._meta["last_access"] = time.time()
[docs] def is_expired(self) -> bool: """Check if session has exceeded its TTL.""" ttl: int = self._meta["ttl"] if ttl <= 0: return True last_access: float = self._meta["last_access"] return bool((time.time() - last_access) > ttl)
if __name__ == "__main__": pass