U
    ]g                     @   sb   d dl 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 eddG dd deZdS )	    N)versionadded)Storage)EmcacheClientPOptionalTupleTypeUnionz2.1)versionc                       s   e Zd ZdZdgZdgZdeeee	eef dd fddZ
eeee eee d	f f d
ddZed
ddZeedddZeddddZdeeeeedddZeedddZed
ddZee d
ddZ  ZS ) MemcachedStoragezW
    Rate limit storage with memcached as backend.

    Depends on :pypi:`emcache`
    zasync+memcachedemcacheFN)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   @/tmp/pip-unpacked-wheel-kizsipjx/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__Zdependenciesmodule
dependency)selfr   r   r   parsedhostport	__class__r   r   r#      s    zMemcachedStorage.__init__.)r   c                 C   s   | j j| j jfS N)r%   ZClusterNoAvailableNodesCommandErrorr&   r   r   r   base_exceptions3   s    z MemcachedStorage.base_exceptionsc                    s@    j s0 jj fdd jD f jI d H  _  j s:t j S )Nc                    s   g | ]\}} j ||qS r   )r%   ZMemcachedHostAddress)r   hpr.   r   r   
<listcomp>?   s     z0MemcachedStorage.get_storage.<locals>.<listcomp>)r!   r%   Zcreate_clientr   r    AssertionErrorr.   r   r.   r   get_storage<   s    
zMemcachedStorage.get_storage)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   )r4   getencoder   value)r&   r5   itemr   r   r   r7   E   s     zMemcachedStorage.getc                    s$   |   I dH |dI dH  dS )z>
        :param key: the key to clear rate limits for
        Nr6   )r4   deleter8   )r&   r5   r   r   r   clearN   s    zMemcachedStorage.clear   )r5   expiryelastic_expiryamountr   c           
         s  |   I dH }|d}| d }d}z |j||  |dI dH  W n* | jjk
rt   d}|   I dH }Y nX |s|||I dH p|}	|r|j||dI dH  |j|t|t		  d|ddI dH  |	S |j|t|t		  d|ddI dH  |S )aD  
        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
        Nr6   /expiresT)exptimeF)rB   Znoreply)
r4   r8   addr%   ZNotStoredStorageCommandError	incrementtouchsetstrtime)
r&   r5   r>   r?   r@   storageZ	limit_keyZ
expire_keyaddedr9   r   r   r   incrT   s6    
 zMemcachedStorage.incrc                    sB   |   I dH }|| d I dH }t|r8t|jp>t S )z;
        :param key: the key to get the expiry for
        NrA   )r4   r7   r8   r   floatr9   rH   )r&   r5   rI   r:   r   r   r   
get_expiry   s    zMemcachedStorage.get_expiryc                    s8   z$|   I dH }|dI dH  W dS    Y dS X dS )zq
        Check if storage is healthy by calling the ``get`` command
        on the key ``limiter-check``
        Ns   limiter-checkTF)r4   r7   )r&   rI   r   r   r   check   s    zMemcachedStorage.checkc                    s   t d S r,   )NotImplementedErrorr.   r   r   r   reset   s    zMemcachedStorage.reset)F)Fr=   )__name__
__module____qualname____doc__ZSTORAGE_SCHEMEZDEPENDENCIESrG   boolr   rL   r#   propertyr   	Exceptionr   r/   r   r4   r   r7   r<   rK   rM   rN   r   rP   __classcell__r   r   r*   r   r
   
   s8    		      -	r
   )rH   urllib.parser   Zdeprecated.sphinxr   Zlimits.aio.storage.baser   Zlimits.typingr   r   r   r   r   r
   r   r   r   r   <module>   s   