a
    a*j(                     @  s   d dl mZ d dlZd dlZd dlmZ d dlmZm	Z	 d dl
mZ d dlmZmZ d dlmZ d dlmZmZmZmZmZ ed	d
G dd deeeZdS )    )annotationsN)Iterable)ceilfloor)versionadded)SlidingWindowCounterSupportStorage)TimestampedSlidingWindow)EmcacheClientPItemPOptionalTypeUnionz2.1)versionc                      s6  e Zd ZdZdgZdgZd:ddddd	 fd
dZeddddZddddZ	dddddZ
dddddZdddddZd;dddddd d!Zd<dd#ddddd$d%d&Zdd#dd'd(Zdddd)d*Zddd+d,Zd-dd.d/Zd=dddddd0d1d2Zddd3d4d5d6Zdddd#d3d7d8d9Z  ZS )>MemcachedStoragezW
    Rate limit storage with memcached as backend.

    Depends on :pypi:`emcache`
    zasync+memcachedemcacheFstrboolzUnion[float, str, bool]None)uriwrap_exceptionsoptionsreturnc                   s   t j|}g | _dd |j dD D ]\}}| j|t|f q,|| _	d| _
t j|fd|i| | jd j| _dS )a  
        :param uri: memcached location of the form
         ``async+memcached://host:port,host:port``
        :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:`emcache.Client`
        :raise ConfigurationError: when :pypi:`emcache` is not available
        c                 s  s    | ]}|  r|d V  qdS ):N)stripsplit).0loc r   X/var/www/html/assistant/venv/lib/python3.9/site-packages/limits/aio/storage/memcached.py	<genexpr>.   s   z,MemcachedStorage.__init__.<locals>.<genexpr>,Nr   r   )urllibparseurlparsehostsnetlocr   r   appendint_options_storagesuper__init__dependenciesmodule
dependency)selfr   r   r   parsedhostport	__class__r   r   r,      s    zMemcachedStorage.__init__z3Union[Type[Exception], tuple[Type[Exception], ...]])r   c                 C  s   | j j| j jfS N)r/   ZClusterNoAvailableNodesCommandErrorr0   r   r   r   base_exceptions8   s    z MemcachedStorage.base_exceptionsr
   c                   sD    j s4 jj fdd jD fi  jI d H  _  j s>J  j S )Nc                   s   g | ]\}} j ||qS r   )r/   ZMemcachedHostAddress)r   hpr8   r   r   
<listcomp>D       z0MemcachedStorage.get_storage.<locals>.<listcomp>)r*   r/   Zcreate_clientr%   r)   r8   r   r8   r   get_storageA   s    
zMemcachedStorage.get_storager(   )keyr   c                   s2   |   I dH |dI dH }|r.t|jp0dS )zB
        :param key: the key to get the counter value for
        Nutf-8r   )r>   getencoder(   value)r0   r?   itemr   r   r   rA   J   s     zMemcachedStorage.getzIterable[str]zdict[bytes, ItemP])keysr   c                   s$   |   I dH dd |D I dH S )zo
        Return multiple counters at once

        :param keys: the keys to get the counter values for
        Nc                 S  s   g | ]}| d qS )r@   )rB   )r   kr   r   r   r<   Y   r=   z-MemcachedStorage.get_many.<locals>.<listcomp>)r>   get_many)r0   rE   r   r   r   rG   R   s    zMemcachedStorage.get_manyc                   s$   |   I dH |dI dH  dS )z>
        :param key: the key to clear rate limits for
        Nr@   )r>   deleterB   r0   r?   r   r   r   clear\   s    zMemcachedStorage.clear   )r?   amountnoreplyr   c                   sV   |   I dH }|d}z|j|||dI dH p2d}W n | jjyP   d}Y n0 |S )a-  
        decrements the counter for a given rate limit key

        retursn 0 if the key doesn't exist or if noreply is set to True

        :param key: the key to decrement
        :param amount: the number to decrement by
        :param noreply: set to True to ignore the memcached response
        Nr@   rM   r   )r>   rB   Z	decrementr/   NotFoundCommandError)r0   r?   rL   rM   storage	limit_keyrC   r   r   r   decrb   s    


zMemcachedStorage.decrTfloat)r?   expiryelastic_expiryrL   set_expiration_keyr   c           
        s  |   I dH }|d}| | }d}	zj|||I dH p@|}	|r|j|t|dI dH  |r|j|t|t  dt|ddI dH  |	W S  | j	j
y   |   I dH }z\|j||  t|dI dH  |r|j|t|t  dt|ddI dH  |}	W n | j	jy   |   I dH }|||I dH pJ|}	|r|j|t|dI dH  |r|j|t|t  dt|ddI dH  Y n0 |	 Y S 0 dS )a  
        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 elastic_expiry: whether to keep extending the rate limit
         window every hit.
        :param amount: the number to increment by
        :param set_expiration_key: if set to False, the expiration time won't be stored but the key will still expire
        Nr@   )exptimeF)rW   rM   )r>   rB   _expiration_key	incrementtouchr   setr   timer/   rO   addZNotStoredStorageCommandError)
r0   r?   rT   rU   rL   rV   rP   rQ   Z
expire_keyrC   r   r   r   incrt   sR    
 zMemcachedStorage.incrc                   s@   |   I dH }|| |dI dH }|r8t|jp>t S )z;
        :param key: the key to get the expiry for
        Nr@   )r>   rA   rX   rB   rS   rC   r\   )r0   r?   rP   rD   r   r   r   
get_expiry   s    zMemcachedStorage.get_expiryc                 C  s   |d S )z
        Return the expiration key for the given counter key.

        Memcached doesn't natively return the expiration time or TTL for a given key,
        so we implement the expiration time on a separate key.
        z/expiresr   rI   r   r   r   rX      s    z MemcachedStorage._expiration_keyc                   s8   z$|   I dH }|dI dH  W dS    Y dS 0 dS )zq
        Check if storage is healthy by calling the ``get`` command
        on the key ``limiter-check``
        Ns   limiter-checkTF)r>   rA   )r0   rP   r   r   r   check   s    zMemcachedStorage.checkzOptional[int]c                   s   t d S r6   )NotImplementedErrorr8   r   r   r   reset   s    zMemcachedStorage.reset)r?   limitrT   rL   r   c                   s   ||krdS t   }| |||\}}| ||||I d H \}}	}
}t   }||	 | |
 }t|| |krpdS | j|d| |ddI d H }
t   }td|	||  }|| | |
 }t||kr| j||ddI d H  dS dS d S )NF   )rL   rV   r   TrN   )r\   sliding_window_keys_get_sliding_window_infor   r^   maxrR   )r0   r?   rc   rT   rL   nowprevious_keycurrent_keyprevious_countprevious_ttlcurrent_count_t0Zweighted_countt1Zactualised_previous_ttlr   r   r   acquire_sliding_window_entry   s2    z-MemcachedStorage.acquire_sliding_window_entryztuple[int, float, int, float])r?   rT   r   c                   s0   t   }| |||\}}| ||||I d H S r6   )r\   re   rf   )r0   r?   rT   rh   ri   rj   r   r   r   get_sliding_window   s
    z#MemcachedStorage.get_sliding_window)ri   rj   rT   rh   r   c                   s   |  ||gI d H }||d}||d}|rBt|jpDd}|rTt|jpVd}	|	dkrjtd}
nd|| | d  | }
d|| d  | | }|	|
||fS )Nr@   r   rK   )rG   rA   rB   r(   rC   rS   )r0   ri   rj   rT   rh   resultZraw_previous_countZraw_current_countrm   rk   rl   Zcurrent_ttlr   r   r   rf     s    
z)MemcachedStorage._get_sliding_window_info)F)rK   F)FrK   T)rK   )__name__
__module____qualname____doc__ZSTORAGE_SCHEMEZDEPENDENCIESr,   propertyr9   r>   rA   rG   rJ   rR   r^   r_   rX   r`   rb   rq   rr   rf   __classcell__r   r   r4   r   r      s0    	
   >		 )	r   )
__future__r   r\   urllib.parser"   collections.abcr   mathr   r   Zdeprecated.sphinxr   Zlimits.aio.storage.baser   r   Zlimits.storage.baser	   Zlimits.typingr
   r   r   r   r   r   r   r   r   r   <module>   s   