
    kKjn                        d Z ddlmZ ddlZddlZddlmZ ddlmZ ddl	m
Z
  e
e      ZdZdZe G d	 d
             Z G d d      Zy)a  In-memory cache for token verification results.

Provides a generic TTL-based cache for ``AccessToken`` objects, designed to
reduce repeated network calls during opaque-token verification.  Only
*successful* verifications should be cached; errors and failures must be
retried on every request.

Example:
    ```python
    from fastmcp.utilities.token_cache import TokenCache

    cache = TokenCache(ttl_seconds=300, max_size=10000)

    # On cache miss, call the upstream verifier and store the result.
    hit, token = cache.get(raw_token)
    if not hit:
        token = await _call_upstream(raw_token)
        if token is not None:
            cache.set(raw_token, token)
    ```
    )annotationsN)	dataclass)AccessToken)
get_loggeri'  <   c                  &    e Zd ZU dZded<   ded<   y)_CacheEntryz=A cached token result with its absolute expiration timestamp.r   resultfloat
expires_atN)__name__
__module____qualname____doc____annotations__     n/Users/ahmed/devFolder/Ultron/claude-voice/.venv/lib/python3.12/site-packages/fastmcp/utilities/token_cache.pyr	   r	   &   s    Gr   r	   c                  v    e Zd ZdZddd	 	 	 	 	 ddZedd       ZddZddZe	dd       Z
dd	Zdd
ZddZy)
TokenCachea  TTL-based in-memory cache for ``AccessToken`` objects.

    Features:
    - SHA-256 hashed cache keys (fixed size, regardless of token length).
    - Per-entry TTL that respects both the configured ``ttl_seconds`` and the
      token's own ``expires_at`` claim (whichever is sooner).
    - Bounded size with FIFO eviction when the cache is full.
    - Periodic cleanup of expired entries to prevent unbounded growth.
    - Defensive deep copies on both store and retrieve to prevent
      callers from mutating cached values.

    Caching is disabled when ``ttl_seconds`` is ``None`` or ``0``, or
    when ``max_size`` is ``0``.  Negative values raise ``ValueError``.
    N)ttl_secondsmax_sizec                   ||dk  rt        d|       ||dk  rt        d|       |xs d| _        ||nt        | _        i | _        t        j                         | _        y)a  Initialise the cache.

        Args:
            ttl_seconds: How long cached entries remain valid, in seconds.
                ``None`` or ``0`` disables caching entirely.
            max_size: Upper bound on the number of entries.  When the limit is
                reached, expired entries are swept first; if still full the
                oldest entry is evicted.  Defaults to 10 000.
        Nr   z,cache_ttl_seconds must be non-negative, got z)max_cache_size must be non-negative, got )
ValueError_ttlDEFAULT_MAX_CACHE_SIZE	_max_size_entriestime	monotonic_last_cleanup)selfr   r   s      r   __init__zTokenCache.__init__>   sy     "{Q>{mL  HqLH
STT$1	%-%9?U02!^^-r   c                B    | j                   dkD  xr | j                  dkD  S )z!Return whether caching is active.r   )r   r   )r"   s    r   enabledzTokenCache.enabledX   s      yy1}3!!33r   c                   | j                   sy| j                  |      }| j                  j                  |      }|y|j                  t        j
                         k  r| j                  |= yd|j                  j                  d      fS )a
  Look up a cached verification result.

        Returns:
            ``(True, AccessToken)`` on a cache hit, ``(False, None)`` on a miss
            or when caching is disabled.  The returned ``AccessToken`` is a deep
            copy that is safe to mutate.
        )FNTdeep)r%   _hash_tokenr   getr   r   r
   
model_copy)r"   token	cache_keyentrys       r   r*   zTokenCache.get_   sz     || $$U+	!!),= diik)i( ell--4-899r   c                   | j                   sy| j                  |      }| j                          || j                  vr| j	                          t        j
                         | j                  z   }|j                  rt        |t        |j                              }t        |j                  d      |      | j                  |<   y)a  Store a *successful* verification result.

        Only successful verifications should be cached.  Failures (inactive
        tokens, missing scopes, HTTP errors, timeouts) must **not** be cached
        so that transient problems do not produce sticky false negatives.
        NTr'   )r
   r   )r%   r)   _maybe_cleanupr   _enforce_size_limitr   r   r   minr   r	   r+   )r"   r,   r
   r-   r   s        r   setzTokenCache.setv   s     ||$$U+	DMM)$$&YY[499,
Zv/@/@)ABJ#.$$$$/!$
i r   c                f    t        j                  | j                  d            j                         S )z)Return the SHA-256 hex digest of *token*.zutf-8)hashlibsha256encode	hexdigest)r,   s    r   r)   zTokenCache._hash_token   s%     ~~ell734>>@@r   c                   t        j                          }| j                  j                         D cg c]  \  }}|j                  |k  s| }}}|D ]  }| j                  |=  |r t        j                  dt        |             yyc c}}w )z)Remove all entries whose TTL has elapsed.z#Cleaned up %d expired cache entriesN)r   r   itemsr   loggerdebuglen)r"   nowkvexpiredkeys         r   _cleanup_expiredzTokenCache._cleanup_expired   sv    iik!%!4!4!6M!6A!,,:L1!6MCc" LL>GM  Ns   B
Bc                    t        j                         }|| j                  z
  t        kD  r| j	                          || _        yy)z;Run ``_cleanup_expired`` at most once per cleanup interval.N)r   r    r!   _CLEANUP_INTERVALrC   )r"   r>   s     r   r0   zTokenCache._maybe_cleanup   s;    nn###&77!!#!$D 8r   c                   t        | j                        | j                  k  ry| j                          t        | j                        | j                  k\  r,t	        t        | j                              }| j                  |= yy)z0Ensure there is room for at least one new entry.N)r=   r   r   rC   nextiter)r"   
oldest_keys     r   r1   zTokenCache._enforce_size_limit   s_    t}}.t}}/d4==12Jj) 0r   )r   
int | Noner   rJ   returnNone)rK   bool)r,   strrK   ztuple[bool, AccessToken | None])r,   rN   r
   r   rK   rL   )r,   rN   rK   rN   )rK   rL   )r   r   r   r   r#   propertyr%   r*   r3   staticmethodr)   rC   r0   r1   r   r   r   r   r   .   sv    $ #'#	.  . 	.
 
.4 4 4:.
6 A AN%*r   r   )r   
__future__r   r5   r   dataclassesr   fastmcp.server.auth.authr   fastmcp.utilities.loggingr   r   r;   r   rE   r	   r   r   r   r   <module>rU      sY   , #   ! 0 0	H	     * *r   