U
    ]g#                     @  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
 d dlmZ d dlmZmZmZmZmZmZmZmZ ddlmZ d	d
lmZmZ G dd deeeZeddG dd deZdS )    )annotationsN)ABCabstractmethod)Anycast)versionadded)DictMongoClientMongoCollectionMongoDatabaseOptionalTupleTypeUnion   )get_dependency   )MovingWindowSupportStoragec                      sD  e Zd ZdZdgZd9dddddd	 fd
dZeddddZeddddZeddddZ	eddddZ
eddddddZedd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d:dd'dd'd'd-d.d/Zddd0d1Zdd'd'd2d3d4d5Zd;dd'd'd'dd6d7d8Z  ZS )<MongoDBStorageBasezV
    Rate limit storage with MongoDB as backend.

    Depends on :pypi:`pymongo`.
    pymongolimitsFstrboolUnion[int, str, bool]None)uridatabase_namewrap_exceptionsoptionsreturnc                   sP   t  j|fd|i| || _| jd j| _td\| _}|| _|| _	d| _
dS )av  
        :param uri: uri of the form ``mongodb://[user:password]@host:port?...``,
         This uri is passed directly to :class:`~pymongo.mongo_client.MongoClient`
        :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:`~pymongo.mongo_client.MongoClient`
        :raise ConfigurationError: when the :pypi:`pymongo` library is not available
        r   r   zpymongo.errorsN)super__init___database_nameZdependenciesmodulelibr   
lib_errors_storage_uri_storage_options_storage)selfr   r   r   r   _	__class__ :/tmp/pip-unpacked-wheel-kizsipjx/limits/storage/mongodb.pyr"   #   s    zMongoDBStorageBase.__init__r	   )r    c                 C  s,   | j d kr&| j| jf| j| _ |   | j S N)r)   _init_mongo_clientr'   r(   (_MongoDBStorageBase__initialize_databaser*   r.   r.   r/   storage>   s    
zMongoDBStorageBase.storager   c                 C  s   | j | j S r0   )r4   r#   r3   r.   r.   r/   	_databaseG   s    zMongoDBStorageBase._databaser
   c                 C  s
   | j d S )Ncountersr5   r3   r.   r.   r/   r6   K   s    zMongoDBStorageBase.countersc                 C  s
   | j d S )Nwindowsr7   r3   r.   r.   r/   r8   O   s    zMongoDBStorageBase.windowsOptional[str]r   r   r    c                 K  s
   t  d S r0   )NotImplementedErrorr*   r   r   r.   r.   r/   r1   S   s    z%MongoDBStorageBase._init_mongo_clientz3Union[Type[Exception], Tuple[Type[Exception], ...]]c                 C  s   | j jS r0   )r&   ZPyMongoErrorr3   r.   r.   r/   base_exceptionsY   s    z"MongoDBStorageBase.base_exceptionsc                 C  s$   | j jddd | jjddd d S )NexpireAtr   )ZexpireAfterSeconds)r6   Zcreate_indexr8   r3   r.   r.   r/   Z__initialize_database_   s    z(MongoDBStorageBase.__initialize_databasezOptional[int]c                 C  s4   | j i | ji  }| j   | j  t|S )z^
        Delete all rate limit keys in the rate limit collections (counters, windows)
        )r6   Zcount_documentsr8   Zdropint)r*   Znum_keysr.   r.   r/   resetc   s    

zMongoDBStorageBase.reset)keyr    c                 C  s$   | j d|i | jd|i dS )z>
        :param key: the key to clear rate limits for
        _idN)r6   Zfind_one_and_deleter8   )r*   rA   r.   r.   r/   clearm   s    zMongoDBStorageBase.clearr?   c                 C  s:   | j d|i}|r|d ntjtjj}t| S )z;
        :param key: the key to get the expiry for
        rB   r>   )	r6   find_onedatetimenowtimezoneutccalendartimegm	timetuple)r*   rA   counterexpiryr.   r.   r/   
get_expiryt   s    
zMongoDBStorageBase.get_expiryc                 C  s8   | j j|dtjtjjiddgd}|r4|d p6dS )zB
        :param key: the key to get the counter value for
        $gte)rB   r>   count)
projectionr   )r6   rD   rE   rF   rG   rH   )r*   rA   rL   r.   r.   r/   get   s    zMongoDBStorageBase.getr   )rA   rM   elastic_expiryamountr    c              
   C  s   t j t jjt j|d }t| jjd|idddddgi|dd	|gid
iddddgi||r`|ndd
idigddg| jj	j
dd S )z
        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 amount: the number to increment by
        secondsrB   $setz$condz$ltz	$expireAtz$$NOWz$addz$count)ifZthenelse)rP   r>   TrP   )upsertrQ   Zreturn_document)rE   rF   rG   rH   	timedeltar?   r6   Zfind_one_and_updater%   ZReturnDocumentZAFTER)r*   rA   rM   rS   rT   Z
expirationr.   r.   r/   incr   s:    




zMongoDBStorageBase.incrc                 C  s$   z| j   W dS    Y dS X dS )zm
        Check if storage is healthy by calling :meth:`pymongo.mongo_client.MongoClient.server_info`
        TFN)r4   Zserver_infor3   r.   r.   r/   check   s
    
zMongoDBStorageBase.checkzTuple[int, int])rA   limitrM   r    c                 C  s   t   }t| 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}|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 key: rate limit key
        :param expiry: expiry of entry
        :return: (start of window, number of acquired entries)
        z$matchrB   z$projectentriesz$filterz$entriesentryrO   z$$entry)inputasZcondz$unwindz$groupz$_idz$minz$sumr   )rB   minrP   r   rc   rP   )timelistr8   Z	aggregater?   )r*   rA   r^   rM   	timestampresultr.   r.   r/   get_moving_window   s6    	
z$MongoDBStorageBase.get_moving_window)rA   r^   rM   rT   r    c                 C  s   ||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d
|d||  dd|| iii|dd W dS  | 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
        Fz$pushr_   r   )$eachz	$positionz$slicer>   rU   rW   ri   rB   z
entries.%dz$notrO   T)rZ   N)rd   rE   rF   rG   rH   r[   r8   Z
update_oner%   errorsZDuplicateKeyError)r*   rA   r^   rM   rT   rf   Zupdatesr.   r.   r/   acquire_entry   s6     
 
 
z MongoDBStorageBase.acquire_entry)r   F)Fr   )r   )__name__
__module____qualname____doc__ZDEPENDENCIESr"   propertyr4   r5   r6   r8   r   r1   r=   r2   r@   rC   rN   rR   r\   r]   rh   rk   __classcell__r.   r.   r,   r/   r      s8     
   -*r   z2.1)versionc                   @  s&   e Zd ZddgZddddddZd	S )
MongoDBStorageZmongodbzmongodb+srvr9   r   r	   r:   c                 K  s   t t| jj|f|S r0   )r   r	   r%   r<   r.   r.   r/   r1     s    z!MongoDBStorage._init_mongo_clientN)rl   rm   rn   ZSTORAGE_SCHEMEr1   r.   r.   r.   r/   rs     s   rs   )
__future__r   rI   rE   rd   abcr   r   typingr   r   Zdeprecated.sphinxr   Zlimits.typingr   r	   r
   r   r   r   r   r   utilr   baser   r   r   rs   r.   r.   r.   r/   <module>   s   (   