o
    i+                     @   s   U d Z ddlZddlZddlmZ ddlmZmZmZm	Z	 ddl
mZ ddlmZ eeZG dd dZdae	e ed	< d
efddZdddZdS )a  
Rate limiting for Veena3 TTS API.

Implements sliding window rate limiting with in-memory storage.
Supports optional Redis backend for distributed rate limiting.

Usage:
    from veena3modal.api.rate_limiter import get_rate_limiter
    
    limiter = get_rate_limiter()
    allowed, remaining, reset_after = limiter.check(api_key_hash)
    if not allowed:
        return 429 response with Retry-After header
    N)defaultdict)DictListTupleOptional)Lock)
get_loggerc                
   @   s   e Zd ZdZ			ddededefddZd	ed
eeee	f fddZ
de	d
dfddZdddZdedede	d
eeef fddZd	ed
dfddZdS )RateLimitera?  
    In-memory sliding window rate limiter.
    
    Thread-safe implementation with automatic cleanup of old entries.
    
    Attributes:
        requests_per_minute: Maximum requests allowed per window
        window_seconds: Window size in seconds (default: 60)
        enabled: Whether rate limiting is active
    <   Trequests_per_minutewindow_secondsenabledc                 C   s8   || _ || _|| _tt| _t | _t | _	d| _
dS )z
        Initialize rate limiter.
        
        Args:
            requests_per_minute: Max requests per window
            window_seconds: Window size in seconds
            enabled: If False, all requests are allowed
        r
   N)r   r   r   r   list	_requestsr   _locktime_last_cleanup_cleanup_interval)selfr   r   r    r   7/home/ubuntu/veenaModal/veena3modal/api/rate_limiter.py__init__'   s   


zRateLimiter.__init__keyreturnc                    s  | j s	d| jdfS t }|| j  | jk  fdd| j| D | j|< t| j| }|| jkrU| j| r=t| j| n|}|| j | }ddtd|fW  d   S | j| 	| | j| d }|| j
 | jkrt|   || _
d|dfW  d   S 1 sw   Y  dS )	a  
        Check if request is allowed under rate limit.
        
        Args:
            key: Unique identifier (API key hash, user ID, IP)
        
        Returns:
            Tuple of (allowed, remaining, reset_after_seconds)
            - allowed: True if request should proceed
            - remaining: Number of requests remaining in window
            - reset_after: Seconds until window resets (only meaningful if blocked)
        Tg        c                       g | ]}| kr|qS r   r   .0tswindow_startr   r   
<listcomp>T   s
    z%RateLimiter.check.<locals>.<listcomp>Fr   N   )r   r   r   r   r   r   lenminmaxappendr   r   _do_cleanup)r   r   nowcurrent_countoldest_in_windowreset_after	remainingr   r   r   check?   s*   



$zRateLimiter.checkr   Nc                    sZ   g }| j  D ]\}} fdd|D }|s|| q|| j |< q|D ]}| j |= q$dS )z%Remove entries older than the window.c                    r   r   r   r   r   r   r   r    q   s    z+RateLimiter._do_cleanup.<locals>.<listcomp>N)r   itemsr%   )r   r   keys_to_remover   
timestampsvalidr   r   r   r&   l   s   
zRateLimiter._do_cleanupc                 C   sH   t   }|| j }| j | | W d   dS 1 sw   Y  dS )zZ
        Manual cleanup trigger for testing.
        Removes all expired entries.
        N)r   r   r   r&   )r   r'   r   r   r   r   cleanupz   s
   
"zRateLimiter.cleanupallowedr+   r*   c                 C   s6   t | jt td|d}|st t|d |d< |S )a'  
        Get rate limit headers for HTTP response.
        
        Args:
            allowed: Whether request was allowed
            remaining: Remaining requests in window
            reset_after: Seconds until reset
        
        Returns:
            Dict of header name -> value
        r   )zX-RateLimit-LimitzX-RateLimit-Remainingr!   zRetry-After)strr   r$   int)r   r2   r+   r*   headersr   r   r   get_headers   s   zRateLimiter.get_headersc                 C   sN   | j  || jv r| j|= W d   dS W d   dS 1 s w   Y  dS )z0Reset rate limit for a specific key (admin use).N)r   r   )r   r   r   r   r   reset   s   

"zRateLimiter.reset)r
   r
   Tr   N)__name__
__module____qualname____doc__r4   boolr   r3   r   floatr,   r&   r1   r   r6   r7   r   r   r   r   r	      s2    
-


r	   _rate_limiterr   c                  C   sT   t du r(ttjdd} tjdd dk}t| |da tjd| |dd t S )	a  
    Get the singleton rate limiter instance.
    
    Configuration via environment variables:
    - RATE_LIMIT_REQUESTS_PER_MINUTE: Max requests (default: 60)
    - RATE_LIMIT_ENABLED: "true"/"false" (default: true)
    
    Returns:
        Configured RateLimiter instance
    NRATE_LIMIT_REQUESTS_PER_MINUTE60RATE_LIMIT_ENABLEDtruer   r   rate_limiter_initialized)extra)	r?   r4   osenvirongetlowerr	   loggerinforD   r   r   r   get_rate_limiter   s   rM   c                   C   s   da dS )z"Reset the singleton (for testing).N)r?   r   r   r   r   reset_rate_limiter   s   rN   r8   )r<   r   rG   collectionsr   typingr   r   r   r   	threadingr   veena3modal.shared.loggingr   r9   rK   r	   r?   __annotations__rM   rN   r   r   r   r   <module>   s     !