U
    ]g$                     @  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mZ d dl	m
Z
 d dlmZmZ d dlmZmZmZmZmZmZmZ d dlmZ edZed	Ze
d
dG dd deeZdS )    )annotationsN)Anycast)versionadded)MovingWindowSupportStorage)DictOptional	ParamSpecTupleTypeTypeVarUnion)get_dependencyPRz2.1)versionc                      s   e Zd ZdZddgZddgZd/ddd	d
dd fddZeddddZedd Z	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d0ddd	ddd#d$d%Zd	dd&d'Zdddd(d)d*d+Zd1ddddd	d,d-d.Z  ZS )2MongoDBStoragezS
    Rate limit storage with MongoDB as backend.

    Depends on :pypi:`motor`
    async+mongodbzasync+mongodb+srvmotor.motor_asynciopymongolimitsFstrboolzUnion[float, str, bool]None)uridatabase_namewrap_exceptionsoptionsreturnc                   sz   | ddd}t j|fd|i| | jd | _| jd | _td\| _}| jjj	|f|| _
tj| j
_|| _d| _d	S )
a  
        :param uri: uri of the form ``async+mongodb://[user:password]@host:port?...``,
         This uri is passed directly to :class:`~motor.motor_asyncio.AsyncIOMotorClient`
        :param database_name: The database to use for storing the rate limit
         collections.
        :param wrap_exceptions: Whether to wrap storage exceptions in
         :exc:`limits.errors.StorageError` before raising it.
        :param options: all remaining keyword arguments are passed
         to the constructor of :class:`~motor.motor_asyncio.AsyncIOMotorClient`
        :raise ConfigurationError: when the :pypi:`motor` or :pypi:`pymongo` are
         not available
        r   Zmongodb   r   r   r   zpymongo.errorsFN)replacesuper__init__Zdependencies
dependencyproxy_dependencyr   
lib_errorsmoduleZAsyncIOMotorClientstorageasyncioZget_running_loopZget_io_loop_MongoDBStorage__database_name _MongoDBStorage__indices_created)selfr   r   r   r   _	__class__ >/tmp/pip-unpacked-wheel-kizsipjx/limits/aio/storage/mongodb.pyr#   "   s    
zMongoDBStorage.__init__z3Union[Type[Exception], Tuple[Type[Exception], ...]])r   c                 C  s   | j jS N)r&   ZPyMongoErrorr,   r0   r0   r1   base_exceptionsG   s    zMongoDBStorage.base_exceptionsc                 C  s   | j | jS r2   )r(   Zget_databaser*   r3   r0   r0   r1   databaseM   s    zMongoDBStorage.databasec                   s>   | j s4t| jjjddd| jjjdddI d H  d| _ d S )NexpireAtr   )ZexpireAfterSecondsT)r+   r)   gatherr5   countersZcreate_indexwindowsr3   r0   r0   r1   create_indicesQ   s    
zMongoDBStorage.create_indiceszOptional[int]c                   sV   t t| jji | jji I dH }t| jj | jj I dH  tt	|S )z^
        Delete all rate limit keys in the rate limit collections (counters, windows)
        N)
sumr)   r7   r5   r8   Zcount_documentsr9   Zdropr   int)r,   Znum_keysr0   r0   r1   resetY   s    
 

zMongoDBStorage.reset)keyr   c                   s2   t | jjd|i| jjd|iI dH  dS )z>
        :param key: the key to clear rate limits for
        _idN)r)   r7   r5   r8   Zfind_one_and_deleter9   )r,   r>   r0   r0   r1   cleari   s    zMongoDBStorage.clearr<   c                   sB   | j jd|iI dH }|r$|d ntjtjj}t|	 S )z;
        :param key: the key to get the expiry for
        r?   Nr6   )
r5   r8   find_onedatetimenowtimezoneutccalendartimegm	timetuple)r,   r>   counterexpiryr0   r0   r1   
get_expiryr   s    
zMongoDBStorage.get_expiryc                   s@   | j jj|dtjtjjiddgdI dH }|r<|d p>dS )zB
        :param key: the key to get the counter value for
        $gte)r?   r6   count)
projectionNr   )r5   r8   rA   rB   rC   rD   rE   )r,   r>   rI   r0   r0   r1   get   s    zMongoDBStorage.getr    )r>   rJ   elastic_expiryamountr   c              	     s   |   I dH  tjtjjtj|d }| jjjd|idddddgi|d	d
|gididdddgi||rn|nddidigddg| j	j
jjdI dH }t|d 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
        Nsecondsr?   $setz$condz$ltz	$expireAtz$$NOWz$addz$count)ifZthenelse)rM   r6   TrM   )upsertrN   Zreturn_document)r:   rB   rC   rD   rE   	timedeltar5   r8   Zfind_one_and_updater%   r'   ZReturnDocumentZAFTERr<   )r,   r>   rJ   rP   rQ   Z
expirationresponser0   r0   r1   incr   s6    




zMongoDBStorage.incrc                   s*   z| j  I dH  W dS    Y dS X dS )z{
        Check if storage is healthy by calling
        :meth:`motor.motor_asyncio.AsyncIOMotorClient.server_info`
        NTF)r(   Zserver_infor3   r0   r0   r1   check   s
    zMongoDBStorage.checkzTuple[int, int])r>   limitrJ   r   c                   s   t   }| jjdd|iiddddddd	|| gid
iiiddiddddiddidigjddI dH }|rt|d d |d d fS t|dfS )z
        returns the starting point and the number of entries in the moving
        window

        :param str key: rate limit key
        :param int expiry: expiry of entry
        :return: (start of window, number of acquired entries)
        z$matchr?   z$projectentriesz$filterz$entriesentryrL   z$$entry)inputasZcondz$unwindz$groupz$_idz$minz$sumr    )r?   minrM   )lengthNr   ra   rM   )timer5   r9   Z	aggregateZto_listr<   )r,   r>   r\   rJ   	timestampresultr0   r0   r1   get_moving_window   s6    
z MongoDBStorage.get_moving_window)r>   r\   rJ   rQ   r   c                   s   |   I dH  ||krdS t }zddg d|dii}dtjtjjtj|d i|d	< |g| |d d d
< | jjj	d|d||  dd|| iii|ddI dH  W dS  | j
jjjk
r   Y dS X d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 of entries to acquire
        NFz$pushr]   r   )$eachz	$positionz$slicer6   rR   rT   rg   r?   z
entries.%dz$notrL   T)rW   )r:   rc   rB   rC   rD   rE   rX   r5   r9   Z
update_oner%   r'   errorsZDuplicateKeyError)r,   r>   r\   rJ   rQ   rd   Zupdatesr0   r0   r1   acquire_entry   s8    	 
 
 
zMongoDBStorage.acquire_entry)r   F)Fr    )r    )__name__
__module____qualname____doc__ZSTORAGE_SCHEMEZDEPENDENCIESr#   propertyr4   r5   r:   r=   r@   rK   rO   rZ   r[   rf   ri   __classcell__r0   r0   r.   r1   r      s,     %
	   /+ r   )
__future__r   r)   rF   rB   rc   typingr   r   Zdeprecated.sphinxr   Zlimits.aio.storage.baser   r   Zlimits.typingr   r	   r
   r   r   r   r   Zlimits.utilr   r   r   r   r0   r0   r0   r1   <module>   s   $