o
    ;i>                     @   sX  d dl Z d dlZd dlZd dlZ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mZ d dlmZ d dlmZmZmZm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  d d
l!m"Z" d dl#m$Z$ d dl%m&Z& d dl'm(Z( d dl)m*Z* ddl+m,Z, ddl-m-Z- ddl.m/Z/ ddl0m0Z0 ededZ1ededZ2ej3rd dl4Z5d dl6Z5dj7e*e8 e9 e: d; ej<_=G dd dZ>ej?ej@ejAejBejCgZDdZEeG dd dZFG dd  d ZGed!efd"d#ZHG d$d% d%e ZIeI ZJi fd&eKd'eLeKeKf d!ej<jMfd(d)ZNe/d*d+d,d-ej<jMfd.d/ZOej3r-d dl6Z5	dTd0d1d2e1d'ee d!ee2 fd3d4ZPed5d6G d7d8 d8ZQ	9dUd:d;d<e1d=eeR d!e2fd>d?ZSd@eTd!ee(jU fdAdBZVd@eTdCeWdDeKdEeRdFeXdGeKfdHdIZY	dTd:ejZdJ d<e1dKeQd'ee[e\eKeKf   d!e2f
dLdMZ]d!eRfdNdOZ^dPedQeKd!ee fdRdSZ_dS )V    N)AsyncIterator)	dataclassfield)cache)AnyOptionalSequenceTypeVar)Message)SymbolDatabase)	GRPCErrorStatus)StatusDetailsCodecBase)StreamTerminatedError)
H2Protocol)ConnectionError)api_pb2)__version__   )suppress_tb_frame)config   retry)loggerRequestType)boundResponseTypez.modal-client/{version} ({sys}; {py}/{py_ver})')versionsyspypy_verc                   @   s@   e Zd ZU eed< eed< eed< deddfddZdd	 ZdS )

Subchannelprotocol
created_atrequestsreturnNc                 C   s   || _ t | _d| _d S )Nr   )r#   timer$   r%   )selfr#    r)   K/home/ubuntu/.local/lib/python3.10/site-packages/modal/_utils/grpc_utils.py__init__8   s   

zSubchannel.__init__c                 C   s   t | jjdr| jjj S dS )Nconnection_lostT)hasattrr#   handlerr,   )r(   r)   r)   r*   	connected=   s   zSubchannel.connected)	__name__
__module____qualname__r   __annotations__floatintr+   r/   r)   r)   r)   r*   r"   3   s   
 r"   g      >@c                   @   s,   e Zd ZU eed< eed< eje ed< dS )RetryWarningMessagemessagewarning_intervalerrors_to_warn_forN)	r0   r1   r2   strr3   r5   typingListr   r)   r)   r)   r*   r6   N   s   
 r6   c                   @   sL   e Zd ZdZi fdddeeef fddZdedejj	fd	d
Z
dd ZdS )ConnectionManagera*  ConnectionManager is a helper class for sharing connections to the Modal server.

    It can create, cache, and close channels to the Modal server. This is useful since
    multiple ModalClientModal stubs may target the same server URL, in which case they
    should share the same connection.
    clientzmodal.client._Clientmetadatac                 C   s   || _ || _i | _d S N)_client	_metadata	_channels)r(   r>   r?   r)   r)   r*   r+   ]   s   
zConnectionManager.__init__
server_urlr&   c              
      sd   || j vr-t|| j| j |< zt| j | I d H  W n ty, } ztd|d }~ww | j | S )Nz&Could not connect to the Modal server.)rC   create_channelrB   connect_channelOSErrorr   )r(   rD   excr)   r)   r*   get_or_create_channelc   s   


z'ConnectionManager.get_or_create_channelc                 C   s&   | j  D ]}|  q| j   d S r@   )rC   valuescloseclear)r(   channelr)   r)   r*   rK   l   s   
zConnectionManager.closeN)r0   r1   r2   __doc__dictr:   r+   grpclibr>   ChannelrI   rK   r)   r)   r)   r*   r=   U   s
    	r=   r&   c                  C   s   ddl m}  |  S )Nr   Default)google.protobuf.symbol_databaserS   rR   r)   r)   r*   _sym_dbr   s   rU   c                   @   sT   e Zd ZdZdedee deee  de	fddZ
dedee de	defd	d
ZdS )CustomProtoStatusDetailsCodeczgrpclib compatible details codec.

    The server can encode the details using `google.rpc.Status` using grpclib's default codec and this custom codec
    can decode it into a `api_pb2.RPCStatus`.
    statusr7   detailsr&   c                 C   sB   t j|j|pdd}|d ur|D ]}|j }|| q| S )N )coder7   )r   	RPCStatusvaluerX   addPackSerializeToString)r(   rW   r7   rX   details_protodetaildetail_containerr)   r)   r*   encode   s   
z$CustomProtoStatusDetailsCodec.encodedatac           
   	   C   sx   t  }tj|}g }|jD ]+}tt ||	 }| }	|
|	 ||	 W d    n1 s4w   Y  q|S r@   )rU   r   r[   
FromStringrX   
contextlibsuppress	Exception	GetSymbolTypeNameUnpackappend)
r(   rW   r7   rd   sym_dbr`   rX   rb   msg_typera   r)   r)   r*   decode   s   

z$CustomProtoStatusDetailsCodec.decodeN)r0   r1   r2   rN   r   r   r:   r   r
   bytesrc   r   ro   r)   r)   r)   r*   rV   y   s(    

rV   rD   r?   c                    s<  t j| }tjjddd}|jdkrtjj|j	|t
d}nP|jdv rf|j}|d}dt|  kr7dks>n J d	| |jd
}|d }t|dkrTt|d n|rXdnd}	tjj||	||t
d}ntd|j |jdkrv|j	n|j}td| d|j  dtjjddf fdd}
tj|tjj|
 |S )zCreates a grpclib.Channel to be used by a GRPC stub.

    The given metadata dict is injected into all outgoing requests on this channel.
    i   )http2_connection_window_sizehttp2_stream_window_sizeunix)pathr   status_details_codec)httphttps:r   r   zInvalid target location: sr   i  P   )sslr   ru   zUnknown scheme: zConnecting to z using scheme eventr&   Nc                    s4      D ]	\}}|| j|< qtd| j  d S )NzSending request to )itemsr?   r   debugmethod_name)r|   kvr?   r)   r*   send_request   s   z$create_channel.<locals>.send_request)urllibparseurlparserP   r   Configurationschemer>   rQ   rt   custom_detail_codecnetlocsplitlenendswithr5   rh   r   r~   eventsSendRequestlisten)rD   r?   or   rM   targetpartsr{   hostportr   r)   r   r*   rE      s*   


&$rE      皙?)
n_attempts
base_delayrM   c                    s   |   I dH  dS )zHConnect to socket and raise exceptions when there is a connection issue.N)__connect__)rM   r)   r)   r*   rF      s   rF   methodz@modal._grpc_client.UnaryStreamWrapper[RequestType, ResponseType]requestc                 C  s(   |  ||2 z	3 d H W }|V  q6 d S r@   )unary_stream)r   r   r?   itemr)   r)   r*   r      s   r   T)frozenc                   @   s   e Zd ZU dZeed< dZeed< dZeed< dZe	e
 ed< eed	Zeed
< dZe	e ed< dZe	e ed< dZeed< dZe	e ed< dS )Retryr   r   r   	max_delayr   delay_factor   max_retries)default_factoryadditional_status_codesNattempt_timeouttotal_timeoutg       @attempt_timeout_floorwarning_message)r0   r1   r2   r   r4   r3   r   r   r   r   r5   r   listr   r   r   r   r   r6   r)   r)   r)   r*   r      s   
 r   r   fn:grpclib.client.UnaryUnaryMethod[RequestType, ResponseType]reqr   c                    s   t | |t|ddI dH S )zMinimum API version of _retry_transient_errors that works with grpclib.client.UnaryUnaryMethod.

    Used by modal server.
    )r   r   N)_retry_transient_errorsr   )r   r   r   r)   r)   r*   retry_transient_errors   s   	r   rH   c                 C   s8   t | tr| js
dS | jD ]}t |tjr|  S qdS )zGet server retry policy.N)
isinstancer   rX   r   RPCRetryPolicy)rH   entryr)   r)   r*   get_server_retry_policy   s   
r   final_attemptfn_name	n_retriesdelayidempotency_keyc                 C   s   t  K |r:tdt|  d|d|d| d|dd  d t| tr,tt| t| tj	r8tt| | t| t
rGd	t| vrG| W d   n1 sQw   Y  td
t|  d|d|d| d|dd  d dS )zBProcess exception before retry, used by `_retry_transient_errors`.zFinal attempt failed with z n_retries=z delay=z for z (N   )_write_appdatazRetryable failure )r   r   r~   reprr   rG   r   r:   asyncioTimeoutErrorAttributeError)rH   r   r   r   r   r   r)   r)   r*   process_exception_before_retry	  s   	.
:r   )z?modal._grpc_client.UnaryUnaryWrapper[RequestType, ResponseType]r   r   c                    s  ddl }t| |jjr| j}nt| tjjr| }ntd|j	}d}d}g t
|j}	tt }
t }d}|jdurC||j }nd}|pHg dtt fg }	 d|
fdt|fdt|fg|}|dkru|d	tt | f |dkr|d
tt | f g }|jdur||j |dur|t|t  |j |rt|}nd}z!t  ||||dI dH W  d   W S 1 sw   Y  W n: ttttjtfy } z&td}|dkrvt|trvt| }rv|j }t }|jduo
|| | |jk}|duo|| | |k}|p|}t  t!||| j"|||
 W d   n	1 s6w   Y  t }|du sK|| t#krd|}t$%d|j& t'j( |j) t'j( d|dd |d7 }t*|I dH  W Y d}~qRt|tr|j&|	vr||j+dur||j+krd}n|durt | |j |krd}nd}t  t!||| j"|||
 W d   n	1 sw   Y  |d7 }|j,r||j,j- dkrt|tr|j&|j,j.v rt$%|j,j) t*|I dH  t||j/ |j0}W Y d}~nd}~ww qS)zwRetry on transient gRPC failures with back-off until max_retries is reached.
    If max_retries is None, retry forever.r   Nz[Only modal._grpc_client.UnaryUnaryWrapper and grpclib.client.UnaryUnaryMethod are supportedzx-modal-timestampTzx-idempotency-keyzx-retry-attemptzx-throttle-retry-attemptzx-retry-delayzx-throttle-retry-delay)r?   timeoutmax_throttle_waitzWarning: Received zWill retry in z0.2fz	 seconds.r   F)1modal._grpc_clientr   _grpc_clientUnaryUnaryWrapperdirectrP   r>   UnaryUnaryMethod
ValueErrorr   RETRYABLE_GRPC_STATUS_CODESr   r:   uuiduuid4r'   r   rl   r   maxr   minr   r   r   rG   r   r   r   r   getr   retry_after_secsr   name"SERVER_RETRY_WARNING_TIME_INTERVALr   warningrW   oslinesepr7   sleepr   r   r8   r9   r   r   )r   r   r   r?   modalfn_callabler   r   n_throttled_retriesstatus_codesr   t0last_server_retry_warning_timetotal_deadlineattempt_metadatatimeoutsr   rH   r   server_retry_policyserver_delaynowtotal_timeout_will_be_reachedmax_throttle_will_be_reachedr   r)   r)   r*   r   )  s   




(




"r   c                  C   sb   t ttjtj} | d | tjtjd | 	 d W  d   S 1 s*w   Y  dS )z
    Find a free TCP port, useful for testing.

    WARN: if a returned free port is not bound immediately by the caller, that same port
    may be returned in subsequent calls to this function, potentially creating port collisions.
    )rY   r   r   N)
rf   closingsocketAF_INETSOCK_STREAMbind
setsockopt
SOL_SOCKETSO_REUSEADDRgetsockname)ry   r)   r)   r*   find_free_port  s
   

$r   r7   oneof_groupc                 C   s    |  |}|d u rd S t| |S r@   )
WhichOneofgetattr)r7   r   oneof_fieldr)   r)   r*   get_proto_oneof  s   

r   r@   )r   )`r   rf   r   platformr   r'   r;   urllib.parser   r   collections.abcr   dataclassesr   r   	functoolsr   r   r   r   r	   grpclib.clientrP   grpclib.configgrpclib.eventsgoogle.protobuf.messager
   rT   r   r   r   grpclib.encoding.baser   grpclib.exceptionsr   grpclib.protocolr   modal.exceptionr   modal_protor   modal_versionr   
_tracebackr   r   async_utilsr   r   r   r   TYPE_CHECKINGr   r   modal.clientformatsystempython_implementationpython_versionlowerr>   
USER_AGENTr"   DEADLINE_EXCEEDEDUNAVAILABLE	CANCELLEDINTERNALUNKNOWNr   r   r6   r=   rU   rV   r   r:   rO   rQ   rE   rF   r   r   r5   r   rh   r   r   boolr4   r   Unionr   tupler   r   r   r)   r)   r)   r*   <module>   s   (


,



'
 