a
    a*jK                     @  s   d dl m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	m
Z
mZ d dl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
edddG dd dee	e
ZdS )    )annotationsN)versionaddedversionchanged)MovingWindowSupportSlidingWindowCounterSupportStorage)Optional	ParamSpecTypeTypeVarUnioncast)get_dependencyPRz2.1)versionz3.14.0zEAdded option to select custom collection names for windows & counters)r   reasonc                	      s*  e Zd ZdZddgZddgZd8d
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d9d
d"dd"d"d&d'd(Zddd)d*Zd
d"d"d+d,d-d.Zd:d
d"d"d"dd/d0d1Zd;d
d"d"d"dd/d2d3Zd
d"d4d5d6d7Z  ZS )<MongoDBStoragezS
    Rate limit storage with MongoDB as backend.

    Depends on :pypi:`motor`
    async+mongodbzasync+mongodb+srvmotor.motor_asynciopymongolimitscounterswindowsFstrboolzUnion[float, str, bool]None)uridatabase_namecounter_collection_namewindow_collection_namewrap_exceptionsoptionsreturnc                   s   | ddd}t j|fd|i| | jd | _| jd | _td\| _}| jjj	|fi || _
tj| j
_|| _||d| _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 counter_collection_name: The collection name to use for individual counters
         used in fixed window strategies
        :param window_collection_name: The collection name to use for sliding & moving window
         storage
        :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.errors)r   r   FN)replacesuper__init__dependencies
dependencyproxy_dependencyr   
lib_errorsmoduleZAsyncIOMotorClientstorageasyncioZget_running_loopZget_io_loop_MongoDBStorage__database_name#_MongoDBStorage__collection_mapping _MongoDBStorage__indices_created)selfr   r   r   r    r!   r"   _	__class__ V/var/www/html/assistant/venv/lib/python3.9/site-packages/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r2   r6   r6   r7   base_exceptions^   s    zMongoDBStorage.base_exceptionsc                 C  s   | j | jS r8   )r-   Zget_databaser/   r9   r6   r6   r7   databased   s    zMongoDBStorage.databasec                   sN   | j sDt| j| jd  jddd| j| jd  jdddI d H  d| _ d S )Nr   expireAtr   )ZexpireAfterSecondsr   T)r1   r.   gatherr;   r0   Zcreate_indexr9   r6   r6   r7   create_indicesh   s    
zMongoDBStorage.create_indiceszOptional[int]c                   sv   t t| j| jd  i | j| jd  i I dH }t| j| jd   | j| jd   I dH  tt|S )z^
        Delete all rate limit keys in the rate limit collections (counters, windows)
        r   r   N)	sumr.   r=   r;   r0   Zcount_documentsZdropr   int)r2   Znum_keysr6   r6   r7   resett   s    
zMongoDBStorage.reset)keyr#   c                   sB   t | j| jd  d|i| j| jd  d|iI dH  dS )z>
        :param key: the key to clear rate limits for
        r   _idr   N)r.   r=   r;   r0   Zfind_one_and_delete)r2   rB   r6   r6   r7   clear   s    zMongoDBStorage.clearfloatc                   sF   | j | jd  d|iI dH }|r,|d ntj jtjjd S )z;
        :param key: the key to get the expiry for
        r   rC   Nr<   tzinfo)	r;   r0   find_onedatetimenowr%   timezoneutc	timestampr2   rB   counterr6   r6   r7   
get_expiry   s    
zMongoDBStorage.get_expiryr@   c                   sH   | j | jd  j|dtjtjjiddgdI dH }|rD|d pFdS )zB
        :param key: the key to get the counter value for
        r   $gte)rC   r<   count)
projectionNr   )r;   r0   rH   rI   rJ   rK   rL   rN   r6   r6   r7   get   s    zMongoDBStorage.getr$   )rB   expiryelastic_expiryamountr#   c              	     s   |   I dH  tjtjjtj|d }| j| jd  jd|iddddd	gi|d
d|gididddd	gi||rv|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   rC   $set$condz$ltz	$expireAt$$NOW$addz$countifZthenelse)rR   r<   TrR   )upsertrS   return_document)r>   rI   rJ   rK   rL   	timedeltar;   r0   find_one_and_updater*   r,   ReturnDocumentAFTERr@   )r2   rB   rU   rV   rW   Z
expirationresponser6   r6   r7   incr   s:    




zMongoDBStorage.incrc                   s*   z| j  I dH  W dS    Y dS 0 dS )z{
        Check if storage is healthy by calling
        :meth:`motor.motor_asyncio.AsyncIOMotorClient.server_info`
        NTF)r-   Zserver_infor9   r6   r6   r7   check   s
    zMongoDBStorage.checkztuple[float, int])rB   limitrU   r#   c                   s   t   }| j| jd  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  }r|d d |d d fS |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)
        r   z$matchrC   z$projectentriesz$filterz$entriesentryrQ   z$$entry)inputasZcondz$unwindz$groupz$_idz$minz$sumr$   )rC   minrR   )lengthNr   ro   rR   )timer;   r0   Z	aggregateZto_list)r2   rB   rj   rU   rM   resultr6   r6   r7   get_moving_window   s6    

z MongoDBStorage.get_moving_window)rB   rj   rU   rW   r#   c                   s   |   I dH  ||krdS t }z~d|g| d|didtjtjjtj|d id}| j| jd	  j	d
|d||  dd|| iii|ddI dH  W dS  | j
jjjy   Y dS 0 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
        NFrk   r   )z$eachz	$positionz$slicer<   rX   )z$pushrZ   r   rC   zentries.z$notrQ   T)ra   )r>   rq   rI   rJ   rK   rL   rc   r;   r0   Z
update_oner*   r,   errorsZDuplicateKeyError)r2   rB   rj   rU   rW   rM   Zupdatesr6   r6   r7   acquire_entry  s8    	
	zMongoDBStorage.acquire_entryc                   s  |   I d H  |d }| j| jd  jd|idddddd	d
gi|gidddgidddgidiiiddddd	d
gi|giddddgididddd	d
gi|giddd	dgidd	|gidd
d| gidid	dididdddddddddd	dd
|gigigi|gigidgiiiidddddd|gi|gidd|giddiiiddddd|gi|giiiddgig| jjjjddI d H }tt	|d S )N  r   rC   rZ   previousCountr[   $lte	$subtract
$expiresAtr\   $ifNull$currentCountr   $previousCountr^   z$gtr]      )currentCount	expiresAtZcurWeightedCountz$floorz	$multiplyz$dividez$maxr   z$curWeightedCountZ	_acquiredz$unsetT)rb   ra   )
r>   r;   r0   rd   r*   r,   re   rf   r   r   )r2   rB   rj   rU   rW   	expiry_msrr   r6   r6   r7   acquire_sliding_window_entryG  s    







#&

q
yz+MongoDBStorage.acquire_sliding_window_entryztuple[int, float, int, float])rB   rU   r#   c              
     s4  |d }| j | jd  jd|idddddd	gi|gid
ddgid
ddgididdddd	gi|gidd
ddgididdddd	gi|gidd|giddidig| jjjjg ddI d H  }r0|dr|d jt	j
jd nt }td|t  }td|d r|| nd}|d ||d |fS dS )Nrv   r   rC   rZ   r[   rx   ry   rz   r\   r{   r|   r   r}   r^   r]   )rw   r   r   )r   rw   r   )rb   rS   r   rF   rw   r   )r           r   r   )r;   r0   rd   r*   r,   re   rf   rT   r%   rI   rK   rL   rM   rq   max)r2   rB   rU   r   rr   Z
expires_atZcurrent_ttlZprev_ttlr6   r6   r7   get_sliding_window  sl    






*
3z!MongoDBStorage.get_sliding_window)r   r   r   F)Fr$   )r$   )r$   )__name__
__module____qualname____doc__ZSTORAGE_SCHEMEZDEPENDENCIESr'   propertyr:   r;   r>   rA   rD   rP   rT   rh   ri   rs   ru   r   r   __classcell__r6   r6   r4   r7   r      s6        /
 1, 1  r   )
__future__r   r.   rI   rq   Zdeprecated.sphinxr   r   Zlimits.aio.storage.baser   r   r   Zlimits.typingr   r	   r
   r   r   r   Zlimits.utilr   r   r   r   r6   r6   r6   r7   <module>   s    