o
    Àyð`-=  ã                   @   s”   d dl Z d dlZG dd„ deƒZG dd„ deƒZG dd„ deƒZG dd	„ d	eƒZG d
d„ deƒZG dd„ deƒZ	G dd„ deƒZ
G dd„ deƒZdS )é    Nc                       s   e Zd Z‡ fdd„Z‡  ZS )ÚRequestExceededExceptionc                    s,   || _ || _d||f }tt| ƒ |¡ dS )a   Error when requested amount exceeds what is allowed

        The request that raised this error should be retried after waiting
        the time specified by ``retry_time``.

        :type requested_amt: int
        :param requested_amt: The originally requested byte amount

        :type retry_time: float
        :param retry_time: The length in time to wait to retry for the
            requested amount
        z<Request amount %s exceeded the amount available. Retry in %sN)Úrequested_amtÚ
retry_timeÚsuperr   Ú__init__)Úselfr   r   Úmsg©Ú	__class__© ú6/usr/lib/python3/dist-packages/s3transfer/bandwidth.pyr      s   ÿÿz!RequestExceededException.__init__)Ú__name__Ú
__module__Ú__qualname__r   Ú__classcell__r   r   r	   r   r      s    r   c                   @   s   e Zd ZdZdS )ÚRequestTokenzDA token to pass as an identifier when consuming from the LeakyBucketN)r   r   r   Ú__doc__r   r   r   r   r   (   s    r   c                   @   s   e Zd Zdd„ Zdd„ ZdS )Ú	TimeUtilsc                 C   s   t   ¡ S )zgGet the current time back

        :rtype: float
        :returns: The current time in seconds
        )Útime©r   r   r   r   r   .   s   zTimeUtils.timec                 C   s
   t  |¡S )zwSleep for a designated time

        :type value: float
        :param value: The time to sleep for in seconds
        )r   Úsleep)r   Úvaluer   r   r   r   6   s   
zTimeUtils.sleepN)r   r   r   r   r   r   r   r   r   r   -   s    r   c                   @   s"   e Zd Zddd„Z	ddd„ZdS )	ÚBandwidthLimiterNc                 C   s$   || _ || _|du rtƒ | _dS dS )a  Limits bandwidth for shared S3 transfers

        :type leaky_bucket: LeakyBucket
        :param leaky_bucket: The leaky bucket to use limit bandwidth

        :type time_utils: TimeUtils
        :param time_utils: Time utility to use for interacting with time.
        N)Ú_leaky_bucketÚ_time_utilsr   )r   Úleaky_bucketÚ
time_utilsr   r   r   r   @   s
   	ÿzBandwidthLimiter.__init__Tc                 C   s"   t || j|| jƒ}|s| ¡  |S )aÎ  Wraps a fileobj in a bandwidth limited stream wrapper

        :type fileobj: file-like obj
        :param fileobj: The file-like obj to wrap

        :type transfer_coordinator: s3transfer.futures.TransferCoordinator
        param transfer_coordinator: The coordinator for the general transfer
            that the wrapped stream is a part of

        :type enabled: boolean
        :param enabled: Whether bandwidth limiting should be enabled to start
        )ÚBandwidthLimitedStreamr   r   Údisable_bandwidth_limiting)r   ÚfileobjÚtransfer_coordinatorÚenabledÚstreamr   r   r   Úget_bandwith_limited_streamN   s   þz,BandwidthLimiter.get_bandwith_limited_stream©N)T)r   r   r   r   r#   r   r   r   r   r   ?   s    
ÿr   c                   @   sr   e Zd Z	ddd„Zdd„ Zdd„ Zd	d
„ Zdd„ Zdd„ Zdd„ Z	ddd„Z
dd„ Zdd„ Zdd„ Zdd„ ZdS )r   Né   c                 C   sF   || _ || _|| _|| _|du rtƒ | _d| _tƒ | _d| _|| _	dS )a[  Limits bandwidth for reads on a wrapped stream

        :type fileobj: file-like object
        :param fileobj: The file like object to wrap

        :type leaky_bucket: LeakyBucket
        :param leaky_bucket: The leaky bucket to use to throttle reads on
            the stream

        :type transfer_coordinator: s3transfer.futures.TransferCoordinator
        param transfer_coordinator: The coordinator for the general transfer
            that the wrapped stream is a part of

        :type time_utils: TimeUtils
        :param time_utils: The time utility to use for interacting with time
        NTr   )
Ú_fileobjr   Ú_transfer_coordinatorr   r   Ú_bandwidth_limiting_enabledr   Ú_request_tokenÚ_bytes_seenÚ_bytes_threshold)r   r   r   r    r   Úbytes_thresholdr   r   r   r   e   s   
zBandwidthLimitedStream.__init__c                 C   ó
   d| _ dS )z0Enable bandwidth limiting on reads to the streamTN©r(   r   r   r   r   Úenable_bandwidth_limiting‚   ó   
z0BandwidthLimitedStream.enable_bandwidth_limitingc                 C   r-   )z1Disable bandwidth limiting on reads to the streamFNr.   r   r   r   r   r   †   r0   z1BandwidthLimitedStream.disable_bandwidth_limitingc                 C   sL   | j s	| j |¡S |  j|7  _| j| jk r| j |¡S |  ¡  | j |¡S )zhRead a specified amount

        Reads will only be throttled if bandwidth limiting is enabled.
        )r(   r&   Úreadr*   r+   Ú_consume_through_leaky_bucket)r   Úamountr   r   r   r1   Š   s   zBandwidthLimitedStream.readc              
   C   sj   | j js1z| j | j| j¡ d| _W d S  ty, } z| j |j	¡ W Y d }~nd }~ww | j jr| j j‚)Nr   )
r'   Ú	exceptionr   Úconsumer*   r)   r   r   r   r   )r   Úer   r   r   r2   ž   s   ÿ€ÿú	z4BandwidthLimitedStream._consume_through_leaky_bucketc                 C   ó   |   ¡  dS )z6Signal that data being read is being transferred to S3N)r/   r   r   r   r   Úsignal_transferring¯   ó   z*BandwidthLimitedStream.signal_transferringc                 C   r7   )z:Signal that data being read is not being transferred to S3N)r   r   r   r   r   Úsignal_not_transferring³   r9   z.BandwidthLimitedStream.signal_not_transferringr   c                 C   s   | j  ||¡ d S r$   )r&   Úseek)r   ÚwhereÚwhencer   r   r   r;   ·   s   zBandwidthLimitedStream.seekc                 C   s
   | j  ¡ S r$   )r&   Útellr   r   r   r   r>   º   s   
zBandwidthLimitedStream.tellc                 C   s"   | j r
| jr
|  ¡  | j ¡  d S r$   )r(   r*   r2   r&   Úcloser   r   r   r   r?   ½   s   zBandwidthLimitedStream.closec                 C   s   | S r$   r   r   r   r   r   Ú	__enter__Ç   s   z BandwidthLimitedStream.__enter__c                 O   s   |   ¡  d S r$   )r?   )r   ÚargsÚkwargsr   r   r   Ú__exit__Ê   s   zBandwidthLimitedStream.__exit__)Nr%   )r   )r   r   r   r   r/   r   r1   r2   r8   r:   r;   r>   r?   r@   rC   r   r   r   r   r   d   s    
ÿ

r   c                   @   sB   e Zd Z		ddd„Zdd„ Zdd„ Zdd	„ Zd
d„ Zdd„ ZdS )ÚLeakyBucketNc                 C   s^   t |ƒ| _|| _|du rtƒ | _t ¡ | _|| _|du r tƒ | _|| _	|du r-t
ƒ | _	dS dS )a9  A leaky bucket abstraction to limit bandwidth consumption

        :type rate: int
        :type rate: The maximum rate to allow. This rate is in terms of
            bytes per second.

        :type time_utils: TimeUtils
        :param time_utils: The time utility to use for interacting with time

        :type rate_tracker: BandwidthRateTracker
        :param rate_tracker: Tracks bandwidth consumption

        :type consumption_scheduler: ConsumptionScheduler
        :param consumption_scheduler: Schedules consumption retries when
            necessary
        N)ÚfloatÚ	_max_rater   r   Ú	threadingÚLockÚ_lockÚ_rate_trackerÚBandwidthRateTrackerÚ_consumption_schedulerÚConsumptionScheduler)r   Úmax_rater   Úrate_trackerÚconsumption_schedulerr   r   r   r   Ï   s   

ÿzLeakyBucket.__init__c                 C   s”   | j �= | j ¡ }| j |¡r|  |||¡W  d  ƒ S |  ||¡r+|  |||¡ n|  ||¡W  d  ƒ S W d  ƒ dS 1 sCw   Y  dS )ac  Consume an a requested amount

        :type amt: int
        :param amt: The amount of bytes to request to consume

        :type request_token: RequestToken
        :param request_token: The token associated to the consumption
            request that is used to identify the request. So if a
            RequestExceededException is raised the token should be used
            in subsequent retry consume() request.

        :raises RequestExceededException: If the consumption amount would
            exceed the maximum allocated bandwidth

        :rtype: int
        :returns: The amount consumed
        N)	rI   r   r   rL   Úis_scheduledÚ,_release_requested_amt_for_scheduled_requestÚ_projected_to_exceed_max_rateÚ!_raise_request_exceeded_exceptionÚ_release_requested_amt©r   ÚamtÚrequest_tokenÚtime_nowr   r   r   r5   í   s   
ÿýÿ
÷"úzLeakyBucket.consumec                 C   s   | j  ||¡}|| jkS r$   )rJ   Úget_projected_raterF   )r   rW   rY   Úprojected_rater   r   r   rS   
  s   
z)LeakyBucket._projected_to_exceed_max_ratec                 C   s   | j  |¡ |  ||¡S r$   )rL   Úprocess_scheduled_consumptionrU   rV   r   r   r   rR     s   ÿz8LeakyBucket._release_requested_amt_for_scheduled_requestc                 C   s*   |t | jƒ }| j |||¡}t||d�‚)N)r   r   )rE   rF   rL   Úschedule_consumptionr   )r   rW   rX   rY   Úallocated_timer   r   r   r   rT     s   ÿÿz-LeakyBucket._raise_request_exceeded_exceptionc                 C   s   | j  ||¡ |S r$   )rJ   Úrecord_consumption_rate)r   rW   rY   r   r   r   rU     s   z"LeakyBucket._release_requested_amt)NNN)	r   r   r   r   r5   rS   rR   rT   rU   r   r   r   r   rD   Î   s    
ÿrD   c                   @   s,   e Zd Zdd„ Zdd„ Zdd„ Zdd„ Zd	S )
rM   c                 C   s   i | _ d| _dS )z*Schedules when to consume a desired amountr   N)Ú _tokens_to_scheduled_consumptionÚ_total_waitr   r   r   r   r   !  s   
zConsumptionScheduler.__init__c                 C   s
   || j v S )zÙIndicates if a consumption request has been scheduled

        :type token: RequestToken
        :param token: The token associated to the consumption
            request that is used to identify the request.
        )r`   )r   Útokenr   r   r   rQ   &  s   
z!ConsumptionScheduler.is_scheduledc                 C   s&   |  j |7  _ | j |dœ| j|< | j S )a´  Schedules a wait time to be able to consume an amount

        :type amt: int
        :param amt: The amount of bytes scheduled to be consumed

        :type token: RequestToken
        :param token: The token associated to the consumption
            request that is used to identify the request.

        :type time_to_consume: float
        :param time_to_consume: The desired time it should take for that
            specific request amount to be consumed in regardless of previously
            scheduled consumption requests

        :rtype: float
        :returns: The amount of time to wait for the specific request before
            actually consuming the specified amount.
        )Úwait_durationÚtime_to_consume)ra   r`   )r   rW   rb   rd   r   r   r   r]   /  s
   þz)ConsumptionScheduler.schedule_consumptionc                 C   s&   | j  |¡}t| j|d  dƒ| _dS )zàProcesses a scheduled consumption request that has completed

        :type token: RequestToken
        :param token: The token associated to the consumption
            request that is used to identify the request.
        rd   r   N)r`   ÚpopÚmaxra   )r   rb   Úscheduled_retryr   r   r   r\   I  s   
ÿz2ConsumptionScheduler.process_scheduled_consumptionN)r   r   r   r   rQ   r]   r\   r   r   r   r   rM      s
    	rM   c                   @   sB   e Zd Zddd„Zedd„ ƒZdd„ Zdd	„ Zd
d„ Zdd„ Z	dS )rK   çš™™™™™é?c                 C   s   || _ d| _d| _dS )a’  Tracks the rate of bandwidth consumption

        :type a: float
        :param a: The constant to use in calculating the exponentional moving
            average of the bandwidth rate. Specifically it is used in the
            following calculation:

            current_rate = alpha * new_rate + (1 - alpha) * current_rate

            This value of this constant should be between 0 and 1.
        N)Ú_alphaÚ
_last_timeÚ_current_rate)r   Úalphar   r   r   r   V  s   
zBandwidthRateTracker.__init__c                 C   s   | j du rdS | jS )zmThe current transfer rate

        :rtype: float
        :returns: The current tracked transfer rate
        Nç        )rj   rk   r   r   r   r   Úcurrent_ratef  s   
z!BandwidthRateTracker.current_ratec                 C   s   | j du rdS |  ||¡S )aZ  Get the projected rate using a provided amount and time

        :type amt: int
        :param amt: The proposed amount to consume

        :type time_at_consumption: float
        :param time_at_consumption: The proposed time to consume at

        :rtype: float
        :returns: The consumption rate if that amt and time were consumed
        Nrm   )rj   Ú*_calculate_exponential_moving_average_rate©r   rW   Útime_at_consumptionr   r   r   rZ   q  s
   
ÿz'BandwidthRateTracker.get_projected_ratec                 C   s2   | j du r|| _ d| _dS |  ||¡| _|| _ dS )a  Record the consumption rate based off amount and time point

        :type amt: int
        :param amt: The amount that got consumed

        :type time_at_consumption: float
        :param time_at_consumption: The time at which the amount was consumed
        Nrm   )rj   rk   ro   rp   r   r   r   r_   ‚  s   
	ÿ
z,BandwidthRateTracker.record_consumption_ratec                 C   s"   || j  }|dkrtdƒS || S )Nr   Úinf)rj   rE   )r   rW   rq   Ú
time_deltar   r   r   Ú_calculate_rate“  s   
z$BandwidthRateTracker._calculate_ratec                 C   s&   |   ||¡}| j| d| j | j  S )Né   )rt   ri   rk   )r   rW   rq   Únew_rater   r   r   ro   �  s   z?BandwidthRateTracker._calculate_exponential_moving_average_rateN)rh   )
r   r   r   r   Úpropertyrn   rZ   r_   rt   ro   r   r   r   r   rK   U  s    



rK   )r   rG   Ú	Exceptionr   Úobjectr   r   r   r   rD   rM   rK   r   r   r   r   Ú<module>   s   %jR5