
    kKj!                         d Z ddlZddlZddlmZmZ ddlmZmZ ddl	m
Z
mZ ddlZddlmZ ddlmZ dd	lmZmZmZ  G d
 de      Z G d d      Z G d d      Z G d de      Z G d de      Zy)zCRate limiting middleware for protecting FastMCP servers from abuse.    N)defaultdictdeque)	AwaitableCallable)Anycast)McpError)	ErrorData   )CallNext
MiddlewareMiddlewareContextc                   *     e Zd ZdZddef fdZ xZS )RateLimitErrorz)Error raised when rate limit is exceeded.messagec                 :    t         |   t        d|             y )Ni )coder   )super__init__r
   )selfr   	__class__s     x/Users/ahmed/devFolder/Ultron/claude-voice/.venv/lib/python3.12/site-packages/fastmcp/server/middleware/rate_limiting.pyr   zRateLimitError.__init__   s    @A    )zRate limit exceeded)__name__
__module____qualname____doc__strr   __classcell__)r   s   @r   r   r      s    3B B Br   r   c                   2    e Zd ZdZdedefdZd	dedefdZy)
TokenBucketRateLimiterz.Token bucket implementation for rate limiting.capacityrefill_ratec                     || _         || _        || _        t        j                         | _        t        j                         | _        y)zInitialize token bucket.

        Args:
            capacity: Maximum number of tokens in the bucket
            refill_rate: Tokens added per second
        N)r"   r#   tokenstimelast_refillanyioLock_lock)r   r"   r#   s      r   r   zTokenBucketRateLimiter.__init__   s5     !&99;ZZ\
r   r%   returnc                   K   | j                   4 d{    t        j                         }|| j                  z
  }t        | j                  | j
                  || j                  z  z         | _        || _        | j
                  |k\  r'| xj
                  |z  c_        	 ddd      d{    y	 ddd      d{    y7 7 7 	# 1 d{  7  sw Y   yxY ww)zTry to consume tokens from the bucket.

        Args:
            tokens: Number of tokens to consume

        Returns:
            True if tokens were available and consumed, False otherwise
        NTF)r*   r&   r'   minr"   r%   r#   )r   r%   nowelapseds       r   consumezTokenBucketRateLimiter.consume'   s      :::))+CD,,,G dmmT[[7TEUEU;U-UVDK"D{{f$v% ::  :::::::sc   CB?CBCC'C(C-C.C9C:CCCCCCCN)r   )	r   r   r   r   intfloatr   boolr0    r   r   r!   r!      s+    8" "5 "C  r   r!   c                   ,    e Zd ZdZdedefdZdefdZy)SlidingWindowRateLimiterz+Sliding window rate limiter implementation.max_requestswindow_secondsc                 p    || _         || _        t               | _        t	        j
                         | _        y)zInitialize sliding window rate limiter.

        Args:
            max_requests: Maximum requests allowed in the time window
            window_seconds: Time window in seconds
        N)r7   r8   r   requestsr(   r)   r*   )r   r7   r8   s      r   r   z!SlidingWindowRateLimiter.__init__A   s*     ),ZZ\
r   r+   c                    K   | j                   4 d{    t        j                         }|| j                  z
  }| j                  rK| j                  d   |k  r9| j                  j	                          | j                  r| j                  d   |k  r9t        | j                        | j                  k  r-| j                  j                  |       	 ddd      d{    y	 ddd      d{    y7 7 7 	# 1 d{  7  sw Y   yxY ww)zCheck if a request is allowed.Nr   TF)r*   r&   r8   r:   popleftlenr7   append)r   r.   cutoffs      r   
is_allowedz#SlidingWindowRateLimiter.is_allowedM   s     :::))+C4...F --DMM!$4v$=%%' --DMM!$4v$= 4==!D$5$55$$S) ::  :::::::si   DC3DA:C9>C9DC5D!C9"D-C7.D5D7D9D?D DDN)r   r   r   r   r1   r   r3   r@   r4   r   r   r6   r6   >   s$    5
"S 
"# 
"$ r   r6   c                       e Zd ZdZ	 	 	 	 ddededz  deegef   eege	e   f   z  dz  de
fdZded	efd
Zdeded	efdZy)RateLimitingMiddlewareaK  Middleware that implements rate limiting to prevent server abuse.

    Uses a token bucket algorithm by default, allowing for burst traffic
    while maintaining a sustainable long-term rate.

    Example:
        ```python
        from fastmcp.server.middleware.rate_limiting import RateLimitingMiddleware

        # Allow 10 requests per second with bursts up to 20
        rate_limiter = RateLimitingMiddleware(
            max_requests_per_second=10,
            burst_capacity=20
        )

        mcp = FastMCP("MyServer")
        mcp.add_middleware(rate_limiter)
        ```
    Nmax_requests_per_secondburst_capacityget_client_idglobal_limitc                      | _         |xs t        |dz         _        | _        | _        t         fd       _         j                  r&t         j                   j                          _        yy)a  Initialize rate limiting middleware.

        Args:
            max_requests_per_second: Sustained requests per second allowed
            burst_capacity: Maximum burst capacity. If None, defaults to 2x max_requests_per_second
            get_client_id: Function to extract client ID from context. Can be sync or async.
                If None, uses global limiting
            global_limit: If True, apply limit globally; if False, per-client
           c                  D    t         j                   j                        S N)r!   rD   rC   r   s   r   <lambda>z1RateLimitingMiddleware.__init__.<locals>.<lambda>   s    *##T%A%Ar   N)	rC   r1   rD   rE   rF   r   limitersr!   global_limiter)r   rC   rD   rE   rF   s   `    r   r   zRateLimitingMiddleware.__init__r   sw    $ (?$,P4Ka4O0P*( <G<
 "8##T%A%A#D r   contextr+   c                    K   | j                   r@| j                  |      }t        j                  |      rt        t        | d{         S |S y7 wz(Get client identifier for rate limiting.NglobalrE   inspectisawaitabler   r   r   rO   	client_ids      r   _get_client_identifierz-RateLimitingMiddleware._get_client_identifier   J     **73I""9-Cy11 "1   AAA
A	call_nextc                 P  K   | j                   r/| j                  j                          d{   }|s[t        d      | j	                  |       d{   }| j
                  |   }|j                          d{   }|st        d|        ||       d{   S 7 q7 M7 (7 
w)z Apply rate limiting to requests.NzGlobal rate limit exceededz Rate limit exceeded for client: )rF   rN   r0   r   rX   rM   )r   rO   r[   allowedrW   limiters         r   
on_requestz!RateLimitingMiddleware.on_request   s      //7799G$%ABB #99'BBImmI.G#OO--G$'G	{%STTw''' :
 C- (sE   *B&B%B&B &B&9B":B&B$B& B&"B&$B&)g      $@NNF)r   r   r   r   r2   r1   r   r   r   r   r3   r   rX   r   r   r_   r4   r   r   rB   rB   ]   s    , *.%) ""!&" d
"  !2 3S 89
%&	#6
78
	" "H4E # ((9 (h (SV (r   rB   c                   x    e Zd ZdZ	 	 ddededeegef   eegee   f   z  dz  fdZ	dedefd	Z
ded
edefdZy)#SlidingWindowRateLimitingMiddlewareaN  Middleware that implements sliding window rate limiting.

    Uses a sliding window approach which provides more precise rate limiting
    but uses more memory to track individual request timestamps.

    Example:
        ```python
        from fastmcp.server.middleware.rate_limiting import SlidingWindowRateLimitingMiddleware

        # Allow 100 requests per minute
        rate_limiter = SlidingWindowRateLimitingMiddleware(
            max_requests=100,
            window_minutes=1
        )

        mcp = FastMCP("MyServer")
        mcp.add_middleware(rate_limiter)
        ```
    Nr7   window_minutesrE   c                 \     | _         |dz   _        | _        t         fd       _        y)aO  Initialize sliding window rate limiting middleware.

        Args:
            max_requests: Maximum requests allowed in the time window
            window_minutes: Time window in minutes
            get_client_id: Function to extract client ID from context. Can be sync or async.
                If None, uses global limiting
        <   c                  D    t         j                   j                        S rJ   )r6   r7   r8   rK   s   r   rL   z>SlidingWindowRateLimitingMiddleware.__init__.<locals>.<lambda>   s    ,T->->@S@STr   N)r7   r8   rE   r   rM   )r   r7   rb   rE   s   `   r   r   z,SlidingWindowRateLimitingMiddleware.__init__   s4      ),r1* >IT>
r   rO   r+   c                    K   | j                   r@| j                  |      }t        j                  |      rt        t        | d{         S |S y7 wrQ   rS   rV   s      r   rX   z:SlidingWindowRateLimitingMiddleware._get_client_identifier   rY   rZ   r[   c                   K   | j                  |       d{   }| j                  |   }|j                          d{   }|s+t        d| j                   d| j
                  dz   d|        ||       d{   S 7 h7 C7 w)z/Apply sliding window rate limiting to requests.NzRate limit exceeded: z requests per rd   z minutes for client: )rX   rM   r@   r   r7   r8   )r   rO   r[   rW   r^   r]   s         r   r_   z.SlidingWindowRateLimitingMiddleware.on_request   s     55g>>	--	***,, '(9(9':.&&",--B9+O 
 w''' ? - (s1   BB &BB<B;B<BBB)r   N)r   r   r   r   r1   r   r   r   r   r   rX   r   r   r_   r4   r   r   ra   ra      s    .   

 
  !2 3S 89
%&	#6
78
	
24E # ((9 (h (SV (r   ra   )r   rT   r&   collectionsr   r   collections.abcr   r   typingr   r   r(   mcpr	   	mcp.typesr
   
middlewarer   r   r   r   r!   r6   rB   ra   r4   r   r   <module>rn      sf    I   * /     ? ?BX B$ $N >Q(Z Q(hC(* C(r   