a
    %ik                     @   s   d Z ddlmZ ddlmZmZ ddlmZ ddlmZ G dd dZeej	dd	Z
eejd
d	ZeedddZeedddZdS )z\
Rate limiting for expensive operations.

Uses token bucket algorithm to prevent API abuse.
    )defaultdict)datetime	timedelta)Dict)configc                   @   sN   e Zd ZdZeedddZeedddZeeddd	Z	ed
ddZ
dS )RateLimiterz
    Token bucket rate limiter.

    Usage:
        limiter = RateLimiter(max_requests=60, window_seconds=3600)
        if limiter.is_allowed('user_123'):
            # Allow request
        else:
            # Reject (rate limited)
    max_requestswindow_secondsc                 C   s    || _ t|d| _tt| _dS )z
        Initialize rate limiter.

        Args:
            max_requests: Maximum requests allowed in window
            window_seconds: Time window in seconds
        )secondsN)r	   r   windowr   listrequests)selfr	   r
    r   -/var/www/lichun.app/lichun/ws/rate_limiter.py__init__   s    zRateLimiter.__init__)
identifierreturnc                    sj   t  }|| j   fdd| j| D | j|< t| j| | jkrVtd|  dS | j| | dS )z
        Check if request is allowed.

        Args:
            identifier: User ID or other identifier

        Returns:
            True if allowed, False if rate limited
        c                    s   g | ]}| kr|qS r   r   .0Zreq_timecutoffr   r   
<listcomp>3   s   z*RateLimiter.is_allowed.<locals>.<listcomp>zRate limit exceeded for FT)r   nowr   r   lenr	   printappendr   r   r   r   r   r   
is_allowed%   s    


zRateLimiter.is_allowedc                    sJ   t  }|| j   fdd| j| D | j|< td| jt| j|  S )z
        Get remaining requests in current window.

        Args:
            identifier: User ID or other identifier

        Returns:
            Number of requests remaining
        c                    s   g | ]}| kr|qS r   r   r   r   r   r   r   O   s   z-RateLimiter.get_remaining.<locals>.<listcomp>r   )r   r   r   r   maxr	   r   r   r   r   r   get_remainingA   s    


zRateLimiter.get_remaining)r   c                 C   s   || j v r| j |= dS )zReset rate limit for identifierN)r   )r   r   r   r   r   resetV   s    
zRateLimiter.resetN)__name__
__module____qualname____doc__intr   strboolr   r!   r"   r   r   r   r   r      s
   r   i  r   <   )user_idr   c                 C   s0   t | s,t | }td|  d|  dS dS )z
    Check if user can make OpenAI request.

    Args:
        user_id: User ID

    Returns:
        True if allowed, False if rate limited
    zOpenAI rate limit exceeded for z. Remaining: FT)openai_limiterr   r!   r   )r+   	remainingr   r   r   check_openai_rate_limith   s
    


r.   c                 C   s    t | std|   dS dS )z
    Check if user can send WebSocket message.

    Args:
        user_id: User ID

    Returns:
        True if allowed, False if rate limited
    z"WebSocket rate limit exceeded for FT)websocket_limiterr   r   )r+   r   r   r   check_websocket_rate_limity   s    

r0   N)r&   collectionsr   r   r   typingr   r   r   OPENAI_MAX_REQUESTS_PER_HOURr,   !WEBSOCKET_MAX_MESSAGES_PER_MINUTEr/   r(   r)   r.   r0   r   r   r   r   <module>   s   P