U
    h.                     @   s   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	m
Z
mZ d dlmZmZ d dlmZ d dlmZ eeZG dd	 d	ZG d
d dZG dd dZG dd dZdd Ze jdddZdS )    N)datetimetimezone)sleep)Any	AwaitableCallableUnion)RequestTokenErrTokenRenewalErr)IdentityProviderInterface)TokenResponsec                   @   s   e Zd ZdZdd Zeeeegdf e	f dddZ
e
jeeegdf e	f ddd	dZ
eeeegdf e	f dd
dZejeeegdf e	f ddddZdS )CredentialsListenerzz
    Listeners that will be notified on events related to credentials.
    Accepts callbacks and awaitable callbacks.
    c                 C   s   d | _ d | _d S N)_on_next	_on_errorself r   </tmp/pip-unpacked-wheel-4avdqdik/redis/auth/token_manager.py__init__   s    zCredentialsListener.__init__Nreturnc                 C   s   | j S r   r   r   r   r   r   on_next   s    zCredentialsListener.on_next)callbackr   c                 C   s
   || _ d S r   r   r   r   r   r   r   r      s    c                 C   s   | j S r   r   r   r   r   r   on_error!   s    zCredentialsListener.on_errorc                 C   s
   || _ d S r   r   r   r   r   r   r   %   s    )__name__
__module____qualname____doc__r   propertyr   r   r   r   r   setter	Exceptionr   r   r   r   r   r      s   "$"r   c                   @   s8   e Zd ZeedddZedddZedddZd	S )
RetryPolicymax_attemptsdelay_in_msc                 C   s   || _ || _d S r   r&   )r   r'   r(   r   r   r   r   +   s    zRetryPolicy.__init__r   c                 C   s   | j S )zW
        Retry attempts before exception will be thrown.

        :return: int
        )r'   r   r   r   r   get_max_attempts/   s    zRetryPolicy.get_max_attemptsc                 C   s   | j S )zI
        Delay between retries in seconds.

        :return: int
        )r(   r   r   r   r   get_delay_in_ms7   s    zRetryPolicy.get_delay_in_msN)r   r   r    intfloatr   r)   r*   r   r   r   r   r%   *   s   r%   c                   @   sX   e Zd ZeeeedddZedddZedddZedd	d
Z	edddZ
dS )TokenManagerConfig)expiration_refresh_ratiolower_refresh_bound_millis%token_request_execution_timeout_in_msretry_policyc                 C   s   || _ || _|| _|| _d S r   )_expiration_refresh_ratio_lower_refresh_bound_millis&_token_request_execution_timeout_in_ms_retry_policy)r   r.   r/   r0   r1   r   r   r   r   A   s
    zTokenManagerConfig.__init__r   c                 C   s   | j S )a&  
        Represents the ratio of a token's lifetime at which a refresh should be triggered. # noqa: E501
        For example, a value of 0.75 means the token should be refreshed
        when 75% of its lifetime has elapsed (or when 25% of its lifetime remains).

        :return: float
        )r2   r   r   r   r   get_expiration_refresh_ratioO   s    	z/TokenManagerConfig.get_expiration_refresh_ratioc                 C   s   | j S )a  
        Represents the minimum time in milliseconds before token expiration
        to trigger a refresh, in milliseconds.
        This value sets a fixed lower bound for when a token refresh should occur,
        regardless of the token's total lifetime.
        If set to 0 there will be no lower bound and the refresh will be triggered
        based on the expirationRefreshRatio only.

        :return: int
        )r3   r   r   r   r   get_lower_refresh_bound_millisZ   s    z1TokenManagerConfig.get_lower_refresh_bound_millisc                 C   s   | j S )z
        Represents the maximum time in milliseconds to wait
        for a token request to complete.

        :return: int
        )r4   r   r   r   r   )get_token_request_execution_timeout_in_msg   s    z<TokenManagerConfig.get_token_request_execution_timeout_in_msc                 C   s   | j S )z_
        Represents the retry policy for token requests.

        :return: RetryPolicy
        )r5   r   r   r   r   get_retry_policyp   s    z#TokenManagerConfig.get_retry_policyN)r   r   r    r,   r+   r%   r   r6   r7   r8   r9   r   r   r   r   r-   @   s   	r-   c                   @   s   e Zd ZeedddZdd Zd$eee	g df dd	d
Z
d%eeeee	g df dddZdd Zd&edddZd'edddZeeedddZedddZeedddZd(eejdd d!Zd)eejdd"d#ZdS )*TokenManager)identity_providerconfigc                 C   s(   || _ || _d | _d | _d | _d| _d S )Nr   )_idp_config_next_timer	_listener_init_timer_retries)r   r;   r<   r   r   r   r   z   s    zTokenManager.__init__c                 C   s   t d |   d S )NzToken manager are disposed)loggerinfostopr   r   r   r   __del__   s    
zTokenManager.__del__FN)listenerskip_initialr   c                 C   s   || _ zt }W n6 tk
rH   t }tjt|fdd}|  Y nX t	 }|
d| j||| _td t| |  | jS )NT)targetargsdaemonr   Token manager started)r@   asyncioget_running_loopRuntimeErrorZnew_event_loop	threadingThread_start_event_loop_in_threadstartEvent
call_later_renew_tokenrA   rC   rD   Zrun_coroutine_threadsafewaitresultrE   )r   rG   rH   loopthread
init_eventr   r   r   rS      s*         
zTokenManager.startr   )rG   block_for_initialinitial_delay_in_msrH   r   c                    sZ   || _ t }t }t|| j||}||d || _t	d |rT|
 I d H  | jS )N  rL   )r@   rM   rN   rT   _async_to_sync_wrapper_renew_token_asyncrU   rA   rC   rD   rW   rE   )r   rG   r\   r]   rH   rY   r[   wrappedr   r   r   start_async   s       
zTokenManager.start_asyncc                 C   s,   | j d k	r| j   | jd k	r(| j  d S r   )rA   cancelr?   r   r   r   r   rE      s    


zTokenManager.stopr   c              
   C   s   z| j |}W np tk
r } zR| j| j  k rl|  jd7  _t| j  d  | 	| W Y 
S |W 5 d }~X Y nX d| _t
|S N   r^   r   )r=   request_tokenr	   rB   r>   r9   r)   r   r*   acquire_tokenr   r   force_refreshtokener   r   r   rg      s    zTokenManager.acquire_tokenc              
      s   z| j |}W n~ tk
r } z`| j| j  k rz|  jd7  _t| j 	 d I d H  | 
|I d H  W Y 
S |W 5 d }~X Y nX d| _t|S rd   )r=   rf   r	   rB   r>   r9   r)   rM   r   r*   acquire_token_asyncr   rh   r   r   r   rl      s    
z TokenManager.acquire_token_async)expire_date
issue_dater   c                 C   s4   |  |}| ||}t||}|dk r,dS |d S )Nr   r^   )_delay_for_lower_refresh_delay_for_ratio_refreshmin)r   rm   rn   Zdelay_for_lower_refreshZdelay_for_ratio_refreshdelayr   r   r   _calculate_renewal_delay   s    

z%TokenManager._calculate_renewal_delay)rm   c                 C   s"   || j   ttj d  S Nr^   )r>   r7   r   nowr   utc	timestamp)r   rm   r   r   r   ro      s    z%TokenManager._delay_for_lower_refresh)rm   rn   c                 C   s6   || }||| j    }|| ttj d  S rt   )r>   r6   r   ru   r   rv   rw   )r   rm   rn   Z	token_ttlZrefresh_beforer   r   r   rp      s    z%TokenManager._delay_for_ratio_refresh)rH   r[   c              
   C   sF  z.z| jdd}| |  |  }|  rBtd| jj	dkrbt
d W W dS |sz| j	|  W n* tk
r } zt|W 5 d}~X Y nX |dkrW W ~dS t }||| j| _t
d| d |W W HS  tk
r, } z"| jjdkr|| j| W 5 d}~X Y nX W 5 |r@|   X dS )	zq
        Task to renew token from identity provider.
        Schedules renewal tasks based on token TTL.
        Tri   Requested token is expiredN@No registered callback for token renewal task. Renewal cancelledr    Next token renewal scheduled in  seconds)setrg   rs   	get_tokenget_expires_at_msget_received_at_ms
is_expiredr
   r@   r   rC   warningr$   rM   rN   rU   rV   r?   rD   r   )r   rH   r[   	token_resrr   rk   rY   r   r   r   rV      s<    




"zTokenManager._renew_tokenc              
      sZ  zBz| jddI dH }| |  |  }|  rHtd| jj	dkrht
d W W dS |sz| j	| I dH  W n* tk
r } zt|W 5 d}~X Y nX |dkrW W dS t }t|| j}t
d| d ||| W nH tk
r@ } z(| jjdkr|| j|I dH  W 5 d}~X Y nX W 5 |rT|   X dS )	zx
        Async task to renew tokens from identity provider.
        Schedules renewal tasks based on token TTL.
        Trx   Nry   rz   r   r{   r|   )r}   rl   rs   r~   r   r   r   r
   r@   r   rC   r   r$   rM   rN   r_   r`   rD   rU   r   )r   rH   r[   r   rr   rk   rY   ra   r   r   r   r`   (  s<    



(zTokenManager._renew_token_async)F)Fr   F)F)F)FN)FN)r   r   r    r   r-   r   rF   r   boolr   rS   r,   rb   rE   r   rg   rl   rs   ro   rp   rM   rT   rV   r`   r   r   r   r   r:   y   sL    
 
   
    /    r:   c                    s    fdd}|S )a  
    Wraps an asynchronous function so it can be used with loop.call_later.

    :param loop: The event loop in which the coroutine will be executed.
    :param coro_func: The coroutine function to wrap.
    :param args: Positional arguments to pass to the coroutine function.
    :param kwargs: Keyword arguments to pass to the coroutine function.
    :return: A regular function suitable for loop.call_later.
    c                      s   t j d d S )N)rY   )rM   Zensure_futurer   rJ   	coro_funckwargsrY   r   r   ra   b  s    z'_async_to_sync_wrapper.<locals>.wrappedr   )rY   r   rJ   r   ra   r   r   r   r_   W  s    r_   Z
event_loopc                 C   s   t |  |   dS )z
    Starts event loop in a thread.
    Used to be able to schedule tasks using loop.call_later.

    :param event_loop:
    :return:
    N)rM   Zset_event_loopZrun_foreverr   r   r   r   rR   i  s    
rR   )rM   loggingrP   r   r   timer   typingr   r   r   r   Zredis.auth.errr	   r
   Zredis.auth.idpr   Zredis.auth.tokenr   	getLoggerr   rC   r   r%   r-   r:   r_   ZAbstractEventLooprR   r   r   r   r   <module>   s    
9 _