U
    ]g!                     @  s   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
mZmZmZ ddlmZ dd	lmZmZ ertd dlZG d
d dZG dd deeeZdS )    )annotationsN)TYPE_CHECKING)Version)OptionalRedisClientScriptPTupleTypeUnion   )get_package_data   )MovingWindowSupportStoragec                   @  s   e Zd ZU dZee dZee dZee dZee dZde	d< de	d	< d
Z
dddddZdddddddZd*dddddddddZddddddZdddddd Zd+ddddddd!d"d#Zddddd$d%Zddd&d'd(Zd)S ),RedisInteractorzresources/redis/lua_scriptsz/moving_window.luaz/acquire_moving_window.luaz/clear_keys.luaz/incr_expire.luazScriptP[Tuple[int, int]]lua_moving_windowzScriptP[bool]lua_acquire_windowZLIMITSstrkeyreturnc                 C  s   | j  d| S )N:)PREFIXselfr    r   8/tmp/pip-unpacked-wheel-kizsipjx/limits/storage/redis.pyprefixed_key    s    zRedisInteractor.prefixed_keyintzTuple[int, int])r   limitexpiryr   c                 C  s<   |  |}t }| |gt|| |g}|p:t|dfS )z
        returns the starting point and the number of entries in the moving
        window

        :param key: rate limit key
        :param expiry: expiry of entry
        :return: (start of window, number of acquired entries)
        r   )r   timer   r   )r   r   r   r    	timestampZwindowr   r   r   get_moving_window#   s    	
z!RedisInteractor.get_moving_windowFr   r   bool)r   r    
connectionelastic_expiryamountr   c                 C  s2   |  |}|||}|s"||kr.||| |S )a  
        increments the counter for a given rate limit key

        :param connection: Redis connection
        :param key: the key to increment
        :param expiry: amount in seconds for the key to expire in
        :param amount: the number to increment by
        )r   ZincrbyZexpire)r   r   r    r%   r&   r'   valuer   r   r   _incr2   s
    
zRedisInteractor._incr)r   r%   r   c                 C  s   |  |}t||pdS )zn
        :param connection: Redis connection
        :param key: the key to get the counter value for
        r   )r   r   getr   r   r%   r   r   r   _getJ   s    
zRedisInteractor._getNonec                 C  s   |  |}|| dS )zj
        :param key: the key to clear rate limits for
        :param connection: Redis connection
        N)r   deleter+   r   r   r   _clearS   s    
zRedisInteractor._clear)r   r   r    r%   r'   r   c                 C  s0   |  |}t }| |g||||g}t|S )a  
        :param key: rate limit key to acquire an entry in
        :param limit: amount of entries allowed
        :param expiry: expiry of the entry
        :param connection: Redis connection
        :param amount: the number of entries to acquire
        )r   r!   r   r$   )r   r   r   r    r%   r'   r"   Zacquiredr   r   r   _acquire_entry[   s    
zRedisInteractor._acquire_entryc                 C  s&   |  |}tt||dt  S )zg
        :param key: the key to get the expiry for
        :param connection: Redis connection
        r   )r   r   maxZttlr!   r+   r   r   r   _get_expiryp   s    
zRedisInteractor._get_expiry)r%   r   c                 C  s   z
|  W S    Y dS X dS )zY
        :param connection: Redis connection
        check if storage is healthy
        FN)Zping)r   r%   r   r   r   _checky   s    
zRedisInteractor._checkN)Fr   )r   )__name__
__module____qualname__ZRES_DIRr   SCRIPT_MOVING_WINDOWSCRIPT_ACQUIRE_MOVING_WINDOWSCRIPT_CLEAR_KEYSSCRIPT_INCR_EXPIRE__annotations__r   r   r#   r)   r,   r/   r0   r2   r3   r   r   r   r   r      s*   
  	 	r   c                      s   e Zd ZdZdddgZdediZd+dd	d
ddd fddZeddddZ	dddddZ
d,ddd
ddd fddZddd fddZddd fdd Zd-ddddd
d! fd"d#Zddd fd$d%Zd
d fd&d'Zd(dd)d*Z  ZS ).RedisStoragezR
    Rate limit storage with redis as backend.

    Depends on :pypi:`redis`.
    redisZrediss
redis+unixz3.0NFr   z)Optional[redis.connection.ConnectionPool]r$   zUnion[float, str, bool]r-   )uriconnection_poolwrap_exceptionsoptionsr   c                   sp   t  j|fd|i| | jd j| _|dd}|sJ| jj|f|| _n| jjf d|i|| _| 	| dS )aa  
        :param uri: uri of the form ``redis://[:password]@host:port``,
         ``redis://[:password]@host:port/db``,
         ``rediss://[:password]@host:port``, ``redis+unix:///path/to/sock`` etc.
         This uri is passed directly to :func:`redis.from_url` except for the
         case of ``redis+unix://`` where it is replaced with ``unix://``.
        :param connection_pool: if provided, the redis client is initialized with
         the connection pool and any other params passed as :paramref:`options`
        :param wrap_exceptions: Whether to wrap storage exceptions in
         :exc:`limits.errors.StorageError` before raising it.
        :param options: all remaining keyword arguments are passed
         directly to the constructor of :class:`redis.Redis`
        :raise ConfigurationError: when the :pypi:`redis` library is not available
        rA   r=   r>   unixr@   N)
super__init__Zdependenciesmodule
dependencyreplaceZfrom_urlstorageZRedisinitialize_storage)r   r?   r@   rA   rB   	__class__r   r   rE      s    
zRedisStorage.__init__z3Union[Type[Exception], Tuple[Type[Exception], ...]])r   c                 C  s   | j jS N)rG   Z
RedisErrorr   r   r   r   base_exceptions   s    zRedisStorage.base_exceptions)_urir   c                 C  sD   | j | j| _| j | j| _| j | j| _| j tj	| _
d S rM   )rI   Zregister_scriptr7   r   r8   r   r9   lua_clear_keysr<   r:   lua_incr_expire)r   rP   r   r   r   rJ      s    zRedisStorage.initialize_storager   r   )r   r    r&   r'   r   c                   s>   |rt  ||| j||S | |}t| |g||gS dS )z
        increments the counter for a given rate limit key

        :param key: the key to increment
        :param expiry: amount in seconds for the key to expire in
        :param amount: the number to increment by
        N)rD   r)   rI   r   r   rR   )r   r   r    r&   r'   rK   r   r   incr   s    
zRedisStorage.incrr   c                   s   t  || jS )zB
        :param key: the key to get the counter value for
        )rD   r,   rI   r   rK   r   r   r*      s    zRedisStorage.getc                   s   t  || jS )z>
        :param key: the key to clear rate limits for
        )rD   r/   rI   r   rK   r   r   clear   s    zRedisStorage.clear)r   r   r    r'   r   c                   s   t  |||| j|S )z
        :param key: rate limit key to acquire an entry in
        :param limit: amount of entries allowed
        :param expiry: expiry of the entry
        :param amount: the number to increment by
        )rD   r0   rI   )r   r   r   r    r'   rK   r   r   acquire_entry   s    zRedisStorage.acquire_entryc                   s   t  || jS )z;
        :param key: the key to get the expiry for
        )rD   r2   rI   r   rK   r   r   
get_expiry   s    zRedisStorage.get_expiryc                   s   t  | jS )z-
        check if storage is healthy
        )rD   r3   rI   rN   rK   r   r   check   s    zRedisStorage.checkzOptional[int]c                 C  s   |  d}t| |gS )aX  
        This function calls a Lua Script to delete keys prefixed with
        ``self.PREFIX`` in blocks of 5000.

        .. warning::
           This operation was designed to be fast, but was not tested
           on a large production based system. Be careful with its usage as it
           could be slow on very large data sets.

        *)r   r   rQ   )r   prefixr   r   r   reset   s    
zRedisStorage.reset)NF)Fr   )r   )r4   r5   r6   __doc__ZSTORAGE_SCHEMEr   ZDEPENDENCIESrE   propertyrO   rJ   rS   r*   rT   rU   rV   rW   rZ   __classcell__r   r   rK   r   r<      s$   
  "   
r<   )
__future__r   r!   typingr   Zpackaging.versionr   Zlimits.typingr   r   r   r   r	   r
   utilr   baser   r   r=   r   r<   r   r   r   r   <module>   s    s