o
    ;i                     @   sn   d dl Z d dlZd dlZd dlZd dlZd dlmZ d dlmZ d dlm	Z	m
Z
 ddlmZ G dd dZdS )	    N)Any)ExecutionError)api_pb2modal_api_grpc   )loggerc                   @   sv   e Zd ZdZdZdZdddZdefd	d
Zdd Z	de
jfddZededeeef fddZdd Zdd ZdS )_AuthTokenManagerz>Handles fetching and refreshing of the input plane auth token.i,  i  stubmodal_api_grpc.ModalClientModalc                 C   s   || _ d| _d| _d | _d S )N g        )_stub_token_expiry_lock)selfr	    r   S/home/ubuntu/.local/lib/python3.10/site-packages/modal/_utils/auth_token_manager.py__init__   s   
z_AuthTokenManager.__init__returnc                    s\   | j r|  r|  I dH  | j S |  r+|  I dH }| r$| j S |  I dH  | j S )an  
        When called, the AuthTokenManager can be in one of three states:
        1. Has a valid cached token. It is returned to the caller.
        2. Has no cached token, or the token is expired. We fetch a new one and cache it. If `get_token` is called
        concurrently by multiple coroutines, all requests will block until the token has been fetched. But only one
        coroutine will actually make a request to the control plane to fetch the new token. This ensures we do not hit
        the control plane with more requests than needed.
        3. Has a valid cached token, but it is going to expire in the next 5 minutes. In this case we fetch a new token
        and cache it. If `get_token` is called concurrently, only one request will fetch the new token, and the others
        will be given the old (but still valid) token - i.e. they will not block.
        N)r   _is_expired_refresh_token_needs_refresh	_get_locklocked)r   lockr   r   r   	get_token   s   z_AuthTokenManager.get_tokenc              	      s   |   I dH }|4 I dH S | jr"|  s"	 W d  I dH  dS | jt I dH }|js4td|j| _| 	|j
d }rIt|| _ntd t | j | _W d  I dH  dS 1 I dH sgw   Y  dS )z
        Fetch a new token from the control plane. If called concurrently, only one coroutine will make a request for a
        new token. The others will block on a lock, until the first coroutine has fetched the new token.
        NzUInternal error: Did not receive auth token from server. Please contact Modal support.expz-x-modal-auth-token does not contain exp field)r   r   r   r   AuthTokenGetr   AuthTokenGetRequesttokenr   _decode_jwtgetfloatr   r   warningtimeDEFAULT_EXPIRY_OFFSET)r   r   respr   r   r   r   r   8   s"   
.z _AuthTokenManager._refresh_tokenc                    s   | j d u rt | _ | j S N)r   asyncioLockr   r   r   r   r   T   s   

z_AuthTokenManager._get_lockr   c              
   C   s^   z|  dd }dt| d  }t|| }t|W S  ty. } ztd|d}~ww )z
        Decodes a JWT into a dict without verifying signature. We do this manually instead of using a library to avoid
        adding another dependency to the client.
        .r   =   zFInternal error: Cannot parse auth token. Please contact Modal support.N)splitlenbase64urlsafe_b64decodejsonloads	Exception
ValueError)r   payloadpaddingdecoded_byteser   r   r   r    ]   s   
z_AuthTokenManager._decode_jwtc                 C   s   t   | j| j kS r'   )r$   r   REFRESH_WINDOWr*   r   r   r   r   k   s   z _AuthTokenManager._needs_refreshc                 C   s   t   | jkS r'   )r$   r   r*   r   r   r   r   n   s   z_AuthTokenManager._is_expiredN)r	   r
   )__name__
__module____qualname____doc__r:   r%   r   strr   r   r(   r)   r   staticmethoddictr   r    r   r   r   r   r   r   r      s    
	r   )r(   r0   r2   r$   typingr   modal.exceptionr   modal_protor   r   r   r   r   r   r   r   <module>   s   