o
    ;iUX                     @   sb  d dl Z d dlmZ d dlmZmZmZmZmZ d dl	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mZ d d	lmZ d
dlmZmZ dZG dd dZdeedef ef fddZdd Zdedef dede fddZ!de"fddZ#dede$de%ddfd d!Z&d"d# Z'd$e	j(ddfd%d&Z)d$e	j(ddfd'd(Z*d-d)d*Z+dede$fd+d,Z,dS ).    N)AsyncGenerator)AnyCallableNoReturnOptionalcast)TaskContext)MAX_OBJECT_SIZE_BYTES)parse_major_minor_version)logger)ExecutionErrorInvalidError)stop_fetching_inputs   )current_attempt_tokencurrent_function_call_idg      @c                   @   sl   e Zd ZU ejed< ejed< ejed< dZeed< dZ	eed< dd Z
d	d
 Zdd Zdd Zdd ZdS )LifespanManager_startup	_shutdown_queueF_has_run_init_lifespan_supportedc                 C   s   || _ || _d S N)asgi_appstate)selfr   r    r   G/home/ubuntu/.local/lib/python3.10/site-packages/modal/_runtime/asgi.py__init__   s   
zLifespanManager.__init__c                    s4   | j st | _t | _t | _d| _ d S d S NT)r   asyncioQueuer   Futurer   r   r   r   r   r   ensure_init#   s   



zLifespanManager.ensure_initc              
      sT     I d H   fdd} fdd}z d jd||I d H  W nf ty } zZ jsTtd|   j sB j	d   j
 sM j
	d  W Y d }~d S tjd| d	d
  j sk jtd  j
 s j
td W Y d }~d S W Y d }~d S d }~ww td  j s j	d   j
 s j
	d  d S d S )Nc                      s   d _  j I d H S r   )r   r   getr   r#   r   r   receive1   s   z0LifespanManager.background_task.<locals>.receivec                    s   | d dkr j d  d S | d dkr j td d S | d dkr- jd  d S | d dkr= jtd d S td| d  )	Ntypelifespan.startup.completezlifespan.startup.failedzASGI lifespan startup failedlifespan.shutdown.completezlifespan.shutdown.failedzASGI lifespan shutdown failedUnexpected message type: )r   
set_resultset_exceptionr   r   messager#   r   r   send5   s   z-LifespanManager.background_task.<locals>.sendlifespan)r'   r   zHASGI lifespan task exited before receiving any messages with exception:
zError in ASGI lifespan task: T)exc_infoz!ASGI lifespan task exited startupz"ASGI lifespan task exited shutdownz@ASGI Lifespan protocol is probably not supported by this library)r$   r   r   	Exceptionr   r   infor   doner+   r   errorr,   r   )r   r&   r/   er   r#   r   background_task.   s8    






zLifespanManager.background_taskc                    0   |   I d H  | jddi | jI d H  d S )Nr'   lifespan.startup)r$   r   
put_nowaitr   r#   r   r   r   lifespan_startupX      z LifespanManager.lifespan_startupc                    r8   )Nr'   lifespan.shutdown)r$   r   r:   r   r#   r   r   r   lifespan_shutdown]   r<   z!LifespanManager.lifespan_shutdownN)__name__
__module____qualname__r    r"   __annotations__r!   r   boolr   r   r$   r7   r;   r>   r   r   r   r   r      s   
 


*r   return.c                    s"   i  fdd}|t  fS )Nc           	   	     s  dv r	t dt	d< t t  sJ dtdtdfddfdd fd	d
}fdd}t 4 I d H l}||  fdd}|||}d }	 | }ztj	||gtj
dI d H \}}W n
 tjy   Y n&w ||v r| V  n|  ||v r s V   r|  nqeW d   I d H  d S 1 I d H sw   Y  d S )Nr   zUnexpected state in ASGI scopez<internal error: function_call_id not set in asgi_app() scoper   c                      sN   d dkr  ddiI d H  d S d dkr%  ddiI d H  d S d S )Nr'   httphttp.disconnect	websocketwebsocket.disconnectputr   )messages_to_appscoper   r   disconnect_apps   s   z4asgi_app_wrapper.<locals>.fn.<locals>.disconnect_appc                      sp   d dkr dddI d H   dddI d H  nd d	kr0 d
dddI d H    I d H  d S )Nr'   rE   http.response.starti  )r'   statushttp.response.bodys7   Missing request, possibly due to expiry or cancellation)r'   bodyrG   websocket.closei  z7Missing request, possibly due to expiry or cancellation)r'   codereasonrI   r   )rM   messages_from_apprL   r   r   handle_first_input_timeouty   s    
z@asgi_app_wrapper.<locals>.fn.<locals>.handle_first_input_timeoutc               	      s   j  } t|  }ztt|tI d H }W n7 tjy.   |	 s-|
    tjtfy@    I d H  Y d S  tyT   td  I d H  Y d S w |I d H  | 2 z3 d H W }|I d H  q_6 d S )Nz"Internal error in asgi_app_wrapper)get_data_inaior    create_task	__anext__shieldwait_forFIRST_MESSAGE_TIMEOUT_SECONDSCancelledErrorr4   cancelTimeoutErrorStopAsyncIterationr2   r   	exceptionrJ   )message_genfirst_message_taskfirst_messager.   )attempt_tokencontainer_io_managerrM   function_call_idrV   rK   r   r   fetch_data_in   s.   

z3asgi_app_wrapper.<locals>.fn.<locals>.fetch_data_inc           	         s   | d dkr[t d }d| }d| }t| dd}||kr"|}n|}||kr[ttd||}|d d	 D ]}| d |||  } d|d
dI d H  q6| d |d	 d  | d<  | I d H  d S )Nr'   rP   i      2   rQ       r   Tr'   rQ   	more_body)r	   lenr%   listrangerJ   )	msgbody_chunk_sizebody_chunk_limits3_chunk_sizesize
chunk_sizeindicesichunk)rU   r   r   r/      s    z*asgi_app_wrapper.<locals>.fn.<locals>.sendc                      s      I d H S r   )r%   r   )rK   r   r   r&      s   z-asgi_app_wrapper.<locals>.fn.<locals>.receiveTreturn_when)r   dictr   r   r    r!   r   rY   r%   waitFIRST_COMPLETEDr^   resultr_   empty
get_nowait)	rL   ri   r/   tcr&   app_taskpop_taskr4   pendingr   rg   r   )rf   rM   rh   rV   rU   rK   rL   r   fnf   sH   

#"
.zasgi_app_wrapper.<locals>.fn)r   )r   rg   r   r   r   r   asgi_app_wrapperc   s    r   c                 C   s$   ddl m} || ddd}t||S )Nr   )WSGIMiddlewarei'  r   )workerssend_queue_size)modal._vendor.a2wsgi_wsgir   r   )wsgi_apprg   r   r   r   r   r   wsgi_app_wrapper   s   
r   r   methoddocsc              
   C   s   zddl m} ddlm} W n ty! } zd}t||d}~ww ||r'dndd}|j|dgd	dgdgd
 |jd| |gd |S )z1Return a FastAPI app wrapping a function handler.r   )FastAPI)CORSMiddlewarezModal functions decorated with `fastapi_endpoint` require FastAPI to be installed in the modal.Image. Please update your Image definition code, e.g. with `.pip_install("fastapi[standard]")`.Nz/openapi.json)openapi_url*T)allow_originsallow_credentialsallow_methodsallow_headers/)methods)fastapir   fastapi.middleware.corsr   ImportErrorr   add_middlewareadd_api_route)r   r   r   r   r   excr.   appr   r   r   magic_fastapi_app   s&   
r   ifnamec                 C   sX   ddl }ddl}ddl}||j|j}||| d|d| dd dd S )z@Get the IP address associated with a network interface in Linux.r   Ni  256s   rj      )	fcntlsocketstructAF_INET
SOCK_DGRAM	inet_ntoaioctlfilenopack)r   r   r   r   sr   r   r   get_ip_address  s   r   hostporttimeoutc             
   C   s   ddl }ddl}| }	 z|j| |f|d 	 W d   W dS 1 s%w   Y  W n( tyS } z|d | | |krItd| d|W Y d}~nd}~ww q)z>Wait until a web server port starts accepting TCP connections.r   NT)r   g{Gz?zWaited too long for port z to start accepting connections. Make sure the web server is bound to 0.0.0.0 (rather than localhost or 127.0.0.1), or adjust `startup_timeout`.)r   time	monotoniccreate_connectionOSErrorsleepr`   )r   r   r   r   r   
start_timeexr   r   r   wait_for_web_server  s(   &

r   c                 C   s   d }d| v rfd| v rf| d d }t | d D ]!\}}|d dkr7|d u r&|}|d  d}||v r7|   S q|d ur[|g| d | d  d }dd| f| d |< | S | d d| f | S )Nheadersclientr   s   X-Forwarded-Forr   z, )	enumeratedecodesplitjoinencodeappend)rL   first_x_forwarded_for_idxclient_hostidxheadervaluesr   r   r   _add_forwarded_for_header,  s"   
 r   sessionc              
      sp  t |}dttd f ffdd}|d }|dr%|d|d   7 }z#| j|d |dd	 |d
 D |d tjjv r>d n| ddI d H  W n$ t	yR   Y d S  tj
yl } zt|jt	rgW Y d }~d S  d }~ww d fdd}dtf fdd}t 4 I d H %}	|	| }
|	| }tj|
|gtjdI d H  W d   I d H  d S 1 I d H sw   Y  d S )NrD   c                    sl   	   I d H } | d dkr"|  dd}|r|V  |  dds!d S n| d dkr,td	td
| d  q)NTr'   zhttp.requestrQ   rl   ro   FrF   zDisconnect message receivedr*   )r%   ConnectionAbortedErrorr   )r.   rQ   )r&   r   r   request_generatorV  s   z._proxy_http_request.<locals>.request_generatorpathquery_string?r   c                 S       g | ]\}}|  |  fqS r   r   .0kvr   r   r   
<listcomp>l       z'_proxy_http_request.<locals>.<listcomp>r   F)r   urlr   dataallow_redirectsc                     sx   d j dd  j D d} | I d H   j 2 z3 d H W }d|dd} | I d H  q6 ddiI d H  d S )	NrN   c                 S   r   r   )r   r   r   r   r   r   {  r   z>_proxy_http_request.<locals>.send_response.<locals>.<listcomp>)r'   rO   r   rP   Trn   r'   )rO   r   itemscontentiter_any)rs   r   )proxy_responser/   r   r   send_responsew  s   z*_proxy_http_request.<locals>.send_responsec                     s@   	  I d H } | d dkr j d ur j jd ur j j  q)NTr'   rF   )
connection	transportabortr-   )r   r&   r   r   listen_for_disconnect  s   
z2_proxy_http_request.<locals>.listen_for_disconnectr|   rD   N)r   r   bytesr%   r   requestaiohttpClientRequestGET_METHODSr   ClientConnectionError
isinstance	__cause__r   r   rY   r    r   r   )r   rL   r&   r/   r   r   r6   r   r   r   send_response_taskdisconnect_taskr   )r   r&   r/   r   _proxy_http_requestQ  s:   

.r   c              
      sJ    I d H }|d dkrd S |d dkrt d|d  |d }|dr1|d|d   7 }| j|dd	 |d
 D |dg d4 I d H P fdd}fdd}t 4 I d H $}|| }	|| }
tj|	|
gtjdI d H  W d   I d H  n1 I d H sw   Y  W d   I d H  d S 1 I d H sw   Y  d S )Nr'   rH   zwebsocket.connectr*   r   r   r   c                 S   r   r   r   r   r   r   r   r     r   z,_proxy_websocket_request.<locals>.<listcomp>r   subprotocols)r   r   	protocolsc                     s   	   I d H } | d dkrj | dddI d H  d S | d dkrG| dd ur5| d I d H  n| d	d urF| d	 I d H  n	td
| d  q)NTr'   rH   rS   i  )rS   zwebsocket.receivetextr   r*   )closer%   send_str
send_bytesr   )client_message)r&   upstream_wsr   r   client_to_upstream  s   z4_proxy_websocket_request.<locals>.client_to_upstreamc                     s   dj d}  | I d H  	  I d H }|jtjjkr>ddi} |jd ur5ttj|jj	| d< |j
| d<  | I d H  d S |jtjjkrQ d|jd	I d H  n|jtjjkrd d|jd
I d H  n	 q)Nzwebsocket.accept)r'   subprotocolTr'   rR   rS   rT   zwebsocket.send)r'   r   )r'   r   )protocolr&   r'   r   	WSMsgTypeclosedr   r   WSCloseCodevalueextrar   binary)rs   upstream_message)r/   r   r   r   upstream_to_client  s(   

z4_proxy_websocket_request.<locals>.upstream_to_clientr|   )	r   r%   r   
ws_connectr   rY   r    r   r   )r   rL   r&   r/   re   r   r   r  r   client_to_upstream_taskupstream_to_client_taskr   )r&   r/   r   r   _proxy_websocket_request  s.   

*.r	  c              	      s   d }	 | I d H }|d dkrJ|d u r@t j| ft  t jd dddt jddd	tt jd
kr6tdddni }||d d< |ddiI d H  n%|d dkrf|d ur[| I d H  |ddiI d H  d S t	d|d  q)NTr'   r9   )totalFi   i  )limit)
cookie_jarr   auto_decompressread_bufsize	connector)   	      )max_line_sizemax_field_sizer   r   r(   r=   r)   r*   )
r   ClientSessionDummyCookieJarClientTimeoutTCPConnectorr
   __version__r~   r   r   )base_urlrL   r&   r/   r   r.   r   r   r   _proxy_lifespan_request  sB   
r  c                    sD   d|  k r
dk sn t d| d|  d|   fdd}|S )zRReturn an ASGI app that proxies requests to a web server running on the same host.r   r  zInvalid port number: zhttp://:c              
      s   zI| d dkrt  | ||I d H  W d S | d dkr,t| d d | ||I d H  W d S | d dkrCt| d d | ||I d H  W d S td|  d tjyi } ztd	|  t  W Y d }~d S d }~ww )
Nr'   r0   rE   r   r   rG   zScope z is not understoodz8Terminating runner due to @web_server connection issue: )	r  r   r	  NotImplementedErrorr   ClientConnectorErrorr   warningr   )rL   r&   r/   r   r  r   r   web_server_proxy_app  s   ""z.web_server_proxy.<locals>.web_server_proxy_app)r   )r   r   r!  r   r   r   web_server_proxy  s
   r"  r   )-r    collections.abcr   typingr   r   r   r   r   r   modal._utils.async_utilsr   modal._utils.blob_utilsr	   modal._utils.package_utilsr
   modal.configr   modal.exceptionr   r   modal.experimentalr   execution_contextr   r   r]   r   tupler   r   strrC   r   r   r   intfloatr   r   r  r   r	  r  r"  r   r   r   r   <module>   s0   K %B
<'