o
    i                     @   s   d Z ddlZddlmZmZ ddlmZ ddl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 deZG dd dZG dd dZG dd deZG dd deZdS )zCRate limiting middleware for protecting FastMCP servers from abuse.    N)defaultdictdeque)Callable)Any)McpError)	ErrorData   )CallNext
MiddlewareMiddlewareContextc                       s(   e Zd ZdZddef fddZ  ZS )RateLimitErrorz)Error raised when rate limit is exceeded.Rate limit exceededmessagec                    s   t  td|d d S )Ni )coder   )super__init__r   )selfr   	__class__ m/var/www/html/karishye-ai-python/venv/lib/python3.10/site-packages/fastmcp/server/middleware/rate_limiting.pyr      s   zRateLimitError.__init__)r   )__name__
__module____qualname____doc__strr   __classcell__r   r   r   r   r      s    r   c                   @   s6   e Zd ZdZdedefddZddedefd	d
ZdS )TokenBucketRateLimiterz.Token bucket implementation for rate limiting.capacityrefill_ratec                 C   s*   || _ || _|| _t | _t | _dS )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   r   r   r   r      s
   
zTokenBucketRateLimiter.__init__r   r    returnc              	      s   | j 4 I dH > t }|| j }t| j| j|| j  | _|| _| j|kr:|  j|8  _	 W d  I dH  dS 	 W d  I dH  dS 1 I dH sLw   Y  dS )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elapsedr   r   r   consume&   s   	

0zTokenBucketRateLimiter.consumeN)r   )	r   r   r   r   intfloatr   boolr*   r   r   r   r   r      s    r   c                   @   s0   e Zd ZdZdedefddZdefddZd	S )
SlidingWindowRateLimiterz+Sliding window rate limiter implementation.max_requestswindow_secondsc                 C   s"   || _ || _t | _t | _dS )zInitialize sliding window rate limiter.

        Args:
            max_requests: Maximum requests allowed in the time window
            window_seconds: Time window in seconds
        N)r/   r0   r   requestsr#   r$   r%   )r   r/   r0   r   r   r   r   @   s   z!SlidingWindowRateLimiter.__init__r&   c              	      s   | j 4 I dH I t }|| j }| jr+| jd |k r+| j  | jr+| jd |k st| j| jk rE| j| 	 W d  I dH  dS 	 W d  I dH  dS 1 I dH sWw   Y  dS )zCheck if a request is allowed.Nr   TF)r%   r!   r0   r1   popleftlenr/   append)r   r(   cutoffr   r   r   
is_allowedL   s   

0z#SlidingWindowRateLimiter.is_allowedN)r   r   r   r   r+   r   r-   r6   r   r   r   r   r.   =   s    r.   c                	   @   sn   e Zd ZdZ				ddededB deegef dB de	fd	d
Z
dedefddZdededefddZdS )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)
        ```
          $@NFmax_requests_per_secondburst_capacityget_client_idglobal_limitc                    sT   | _ |p
t|d  _| _| _t fdd _ jr(t j j  _dS dS )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. If None, uses global limiting
            global_limit: If True, apply limit globally; if False, per-client
           c                         t  j jS N)r   r:   r9   r   r   r   r   <lambda>   s    z1RateLimitingMiddleware.__init__.<locals>.<lambda>N)	r9   r+   r:   r;   r<   r   limitersr   global_limiter)r   r9   r:   r;   r<   r   r@   r   r   q   s   

zRateLimitingMiddleware.__init__contextr&   c                 C      | j r|  |S dS z(Get client identifier for rate limiting.globalr;   r   rD   r   r   r   _get_client_identifier      
z-RateLimitingMiddleware._get_client_identifier	call_nextc                    sh   | j r| j I dH }|stdn| |}| j| }| I dH }|s-td| ||I dH S )z Apply rate limiting to requests.NzGlobal rate limit exceededz Rate limit exceeded for client: )r<   rC   r*   r   rJ   rB   )r   rD   rL   allowed	client_idlimiterr   r   r   
on_request   s   

z!RateLimitingMiddleware.on_request)r8   NNF)r   r   r   r   r,   r+   r   r   r   r-   r   rJ   r	   r   rP   r   r   r   r   r7   \   s"    
!r7   c                	   @   sb   e Zd ZdZ		ddededeegef dB fddZd	ed
efddZ	d	ede
d
efddZdS )#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)
        ```
    r   Nr/   window_minutesr;   c                    s,   | _ |d  _| _t fdd _dS )a
  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
        <   c                      r>   r?   )r.   r/   r0   r   r@   r   r   rA      s    z>SlidingWindowRateLimitingMiddleware.__init__.<locals>.<lambda>N)r/   r0   r;   r   rB   )r   r/   rR   r;   r   r@   r   r      s   


z,SlidingWindowRateLimitingMiddleware.__init__rD   r&   c                 C   rE   rF   rH   rI   r   r   r   rJ      rK   z:SlidingWindowRateLimitingMiddleware._get_client_identifierrL   c                    sX   |  |}| j| }| I dH }|s%td| j d| jd  d| ||I dH S )z/Apply sliding window rate limiting to requests.NzRate limit exceeded: z requests per rS   z minutes for client: )rJ   rB   r6   r   r/   r0   )r   rD   rL   rN   rO   rM   r   r   r   rP      s   


z.SlidingWindowRateLimitingMiddleware.on_request)r   N)r   r   r   r   r+   r   r   r   r   rJ   r	   r   rP   r   r   r   r   rQ      s    
rQ   )r   r!   collectionsr   r   collections.abcr   typingr   r#   mcpr   	mcp.typesr   
middlewarer	   r
   r   r   r   r.   r7   rQ   r   r   r   r   <module>   s    'N