a
    a*j,                     @  s   d dl mZ d dlZd dl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 d dlmZmZmZ d dlmZmZmZmZmZmZmZmZmZ d d	lmZ G d
d deeeZ dS )    )annotationsN)Iterable)ceilfloor)
ModuleType)ConfigurationError)SlidingWindowCounterSupportStorageTimestampedSlidingWindow)	AnyCallableMemcachedClientPOptionalPRTypeUnioncast)get_dependencyc                      sL  e Zd ZdZdgZdgZdCddddd	 fd
dZeddddZdddddddZ	dddddddZ
eddddZddd d!d"Zd#d$d%d&d'Zddd d(d)ZdDdd,ddddd-d.d/Zdd,d d0d1Zddd d2d3Zddd4d5Zd6dd7d8ZdEdddddd9d:d;Zddd<d=d>d?Zdddd,d<d@dAdBZ  ZS )FMemcachedStoragez[
    Rate limit storage with memcached as backend.

    Depends on :pypi:`pymemcache`.
    Z	memcached
pymemcacheFstrboolz*Union[str, Callable[[], MemcachedClientP]]None)uriwrap_exceptionsoptionsreturnc                   s  t j|}g | _|j dD ],}|s,q"|d\}}| j|t|f q"|j	rl|jsl|j
sl|j	g| _| jd j| _t|dd| _t|dd| _tttttttf  gtf |d| j| _|| _t| jstd	| j t | _d
| j_ t! j"||d d
S )an  
        :param uri: memcached location of the form
         ``memcached://host:port,host:port``,
         ``memcached:///var/tmp/path/to/sock``
        :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:`pymemcache.client.base.PooledClient`
         or :class:`pymemcache.client.hash.HashClient` (if there are more than
         one hosts specified)
        :raise ConfigurationError: when :pypi:`pymemcache` is not available
        ,:r   libraryzpymemcache.clientcluster_libraryzpymemcache.client.hashclient_getterz7memcached prerequisite not available. please install %sN)r   )#urllibparseurlparsehostsnetlocstripsplitappendintpathportdependenciesmodule
dependencyr   popr    r!   r   r   r   listtupler   
get_clientr"   r   r   r   	threadinglocallocal_storagestoragesuper__init__)selfr   r   r   parsedlochostr-   	__class__ T/var/www/html/assistant/venv/lib/python3.9/site-packages/limits/storage/memcached.pyr:   *   s4    



zMemcachedStorage.__init__z3Union[Type[Exception], tuple[Type[Exception], ...]])r   c                 C  s   | j jS N)r0   ZMemcacheErrorr;   rA   rA   rB   base_exceptions]   s    z MemcachedStorage.base_exceptionsr   zlist[tuple[str, int]]r   )r/   r&   kwargsr   c                 K  s4   t tt|dkr"|j|fi |n|j|i |S )z
        returns a memcached client.

        :param module: the memcached module
        :param hosts: list of memcached hosts
           )r   r   lenZ
HashClientZPooledClient)r;   r/   r&   rF   rA   rA   rB   r4   c   s    

zMemcachedStorage.get_clientzCallable[P, R]zP.argszP.kwargsr   )funcargsrF   r   c                 O  s:   d|v r,t |}d|jv s,|js,|d ||i |S )Nnoreply)inspectgetfullargspecrJ   varkwr1   )r;   rI   rJ   rF   ZargspecrA   rA   rB   call_memcached_funcv   s
    

z$MemcachedStorage.call_memcached_funcc                 C  st   t | jdr| jjsftt| jdkr*| jn| jd }|sJtd| j | j	|| jfi | j
| j_tt| jjS )zQ
        lazily creates a memcached client instance using a thread local
        r8   rG   r   zUnable to import )hasattrr7   r8   r   rH   r&   r!   r    r   r"   r   r   r   )r;   r0   rA   rA   rB   r8      s    
zMemcachedStorage.storager+   )keyr   c                 C  s   t | j|dS )zB
        :param key: the key to get the counter value for
        0)r+   r8   getr;   rQ   rA   rA   rB   rS      s    zMemcachedStorage.getzIterable[str]zdict[str, Any])keysr   c                 C  s   | j |S )zo
        Return multiple counters at once

        :param keys: the keys to get the counter values for
        )r8   get_many)r;   rU   rA   rA   rB   rV      s    zMemcachedStorage.get_manyc                 C  s   | j | dS )z>
        :param key: the key to clear rate limits for
        N)r8   deleterT   rA   rA   rB   clear   s    zMemcachedStorage.clearrG   Tfloat)rQ   expiryelastic_expiryamountset_expiration_keyr   c                 C  s  | j | jj||dd}|durj|rf|  | jj|t| |rf| j | jj| ||t  t|dd |S | j | jj||t|dds| j||p|}|r|  | jj|t| |r| j | jj| ||t  t|dd |S |r| j | jj| ||t  t|dd |S 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: set the expiration key with the expiration time if needed. If set to False, the key will still expire, but memcached cannot provide the expiration time.
        FrK   N)ZexpirerK   )	rO   r8   incrtouchr   set_expiration_keytimeadd)r;   rQ   rZ   r[   r\   r]   valuerA   rA   rB   r_      sJ    


zMemcachedStorage.incrc                 C  s   t | j| |pt S )z;
        :param key: the key to get the expiry for
        )rY   r8   rS   rb   rc   rT   rA   rA   rB   
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/expiresrA   rT   rA   rA   rB   rb      s    z MemcachedStorage._expiration_keyc                 C  s*   z|  | jjd 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``
        zlimiter-checkTFN)rO   r8   rS   rD   rA   rA   rB   check   s
    zMemcachedStorage.checkzOptional[int]c                 C  s   t d S rC   )NotImplementedErrorrD   rA   rA   rB   reset  s    zMemcachedStorage.reset)rQ   limitrZ   r\   r   c                 C  s   ||krdS t   }| |||\}}| j||||d\}}	}
}||	 | |
 }t|| |krddS | j|d| |dd}
td|	t   |  }|| | |
 }t||kr| j| jj||dd dS dS d S )NF)now   )r\   r]   r   Tr^   )	rc   sliding_window_keys_get_sliding_window_infor   r_   minrO   r8   Zdecr)r;   rQ   rj   rZ   r\   rk   previous_keycurrent_keyprevious_countprevious_ttlcurrent_count_Zweighted_countZactualised_previous_ttlrA   rA   rB   acquire_sliding_window_entry  s2    z-MemcachedStorage.acquire_sliding_window_entryztuple[int, float, int, float])rQ   rZ   r   c                 C  s*   t   }| |||\}}| ||||S rC   )rc   rm   rn   )r;   rQ   rZ   rk   rp   rq   rA   rA   rB   get_sliding_window.  s    z#MemcachedStorage.get_sliding_window)rp   rq   rZ   rk   r   c           
      C  s~   |  ||g}t||dt||d }}|dkrBtd}nd|| | d  | }d|| d  | | }	||||	fS )Nr   rG   )rV   r+   rS   rY   )
r;   rp   rq   rZ   rk   resultrr   rt   rs   Zcurrent_ttlrA   rA   rB   rn   5  s    
z)MemcachedStorage._get_sliding_window_info)F)FrG   T)rG   )__name__
__module____qualname____doc__ZSTORAGE_SCHEMEZDEPENDENCIESr:   propertyrE   r4   rO   r8   rS   rV   rX   r_   rf   rb   rg   ri   rv   rw   rn   __classcell__rA   rA   r?   rB   r      s4    3
   >	 )r   )!
__future__r   rL   r5   rc   urllib.parser#   collections.abcr   mathr   r   typesr   Zlimits.errorsr   Zlimits.storage.baser   r	   r
   Zlimits.typingr   r   r   r   r   r   r   r   r   Zlimits.utilr   r   rA   rA   rA   rB   <module>   s   ,