
    5iG                    N   U d Z ddlmZ ddlZddlZddlZddlZddlmZ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mZmZmZ er
ddlZddlmZ  ee      Zded<    G d de       Z!ddZ"ddZ#ddZ$ddZ%ddZ&d dZ'd!dZ(d"dZ) G d d      Z* G d d      Z+y)#a(  Uvicorn server wrappers for running Streamlit applications (using Starlette).

This module provides two classes for running Streamlit apps with uvicorn:

1. **UvicornServer** (async): For embedding in an existing event loop.
   Used by the `Server` class when `server.useStarlette=true`.

2. **UvicornRunner** (sync): For standalone CLI usage with blocking execution.
   Used by `run_asgi_app()` when running `st.App` via `streamlit run`.

Why Two Classes?
----------------
These classes serve different architectural needs:

- **UvicornServer** integrates with Streamlit's existing `Server` class architecture,
  which manages an event loop and coordinates multiple components (runtime, server,
  signal handlers). It uses `uvicorn.Server` with manual socket binding for fine-grained
  control and runs as a background task.

- **UvicornRunner** is designed for `st.App` mode where the app handles its own
  runtime lifecycle via ASGI lifespan. It uses `uvicorn.run()` which manages its own
  event loop and signal handlers - perfect for CLI "just run it" usage.
    )annotationsN)TYPE_CHECKINGAnyFinal)config)ConfigOption)
get_logger)get_max_message_size_bytes)create_starlette_app)DEFAULT_SERVER_ADDRESSDEFAULT_WEBSOCKET_PING_INTERVALDEFAULT_WEBSOCKET_PING_TIMEOUTMAX_PORT_SEARCH_RETRIES)Runtimer   _LOGGERc                      e Zd ZdZy)RetriesExceededErrorzGRaised when the server cannot find an available port after max retries.N)__name__
__module____qualname____doc__     y/home/obispo/Crisostomo_bridge/mision_env/lib/python3.12/site-packages/streamlit/web/server/starlette/starlette_server.pyr   r   C   s    Qr   r   c                 <    t        j                  d      xs t        S )z:Get the server address from config, with default fallback.server.address)r   
get_optionr   r   r   r   _get_server_addressr   L   s    -.H2HHr   c                 >    t        t        j                  d            S )z Get the server port from config.server.port)intr   r   r   r   r   _get_server_portr"   Q   s    v  /00r   c                 ,    t        j                  d      S )z?Check if the server port was explicitly configured by the user.r    )r   is_manually_setr   r   r   _is_port_manually_setr%   V   s    !!-00r   c                 Z    t        j                  d      } | duxr | j                  d      S )z;Check if the server address is configured as a Unix socket.r   Nzunix://)r   r   
startswith)addresss    r   _server_address_is_unix_socketr)   [   s.     01G$@7#5#5i#@@r   c                     t        j                  d      } t        j                  d      }t        |       t        |      k7  r*t        j	                  d       t        j                  d       | |fS )zValidate and return SSL configuration.

    Returns a tuple of (cert_file, key_file). Both are None if SSL is disabled,
    or both are set if SSL is enabled. Exits if only one is set.
    zserver.sslCertFilezserver.sslKeyFilezzOptions 'server.sslCertFile' and 'server.sslKeyFile' must be set together. Set missing options or delete existing options.   )r   r   boolr   errorsysexit)	cert_filekey_files     r   _validate_ssl_configr2   a   sb     !!"67I  !45H I$x.(O	
 	hr   c                 f    t        j                  d      } | t        |       }||fS t        t        fS )z|Get the WebSocket ping interval and timeout settings.

    Returns a tuple of (ping_interval, ping_timeout) in seconds.
    zserver.websocketPingInterval)r   r   r!   r   r   )configured_intervalintervals     r   _get_websocket_settingsr6   u   s>    
 !++,JK&*+!!*,JJJr   c            
         t               \  } }t               \  }}t               }t        j                  d      }| |d||||ddd	S )zGet common uvicorn configuration kwargs.

    Returns a dict of kwargs that can be passed to uvicorn.Config or uvicorn.run().
    Does NOT include app, host, or port - those must be provided separately.
    z!server.enableWebsocketCompressionautoFN)	ssl_certfilessl_keyfilewsws_ping_intervalws_ping_timeoutws_max_sizews_per_message_deflate
use_colors
log_config)r2   r6   r
   r   r   )r0   r1   r<   r=   r>   r?   s         r   _get_uvicorn_config_kwargsrB      s`     /0Ix(?(A%o,.K#../RS ",*""8
 
r   c                (   d| v rt         j                  }nt         j                  }t        j                   |      }	 |j                  t         j                  t         j
                  d       |t         j                  k(  r/|j                  t         j                  t         j                  d       |j                  | |f       |j                  |       |j                  d       |j                  d       |S # t        $ r |j                           w xY w)a  Bind a non-blocking TCP socket to the given address and port.

    We pre-bind the socket ourselves (rather than letting uvicorn do it) to:

    1. Detect port conflicts before creating the uvicorn.Server instance
    2. Enable port retry logic when the configured port is already in use
    3. Have explicit control over socket options (SO_REUSEADDR, IPV6_V6ONLY)

    Parameters
    ----------
    address
        The IP address to bind to (e.g., "127.0.0.1" or "::").

    port
        The port number to bind to.

    backlog
        The maximum number of queued connections.

    Returns
    -------
    socket.socket
        A bound, listening, non-blocking socket.
    :)familyr+   r   FT)socketAF_INET6AF_INET
setsockopt
SOL_SOCKETSO_REUSEADDRIPPROTO_IPV6IPV6_V6ONLYbindlistensetblockingset_inheritableBaseExceptionclose)r(   portbacklogrE   socks        r   _bind_socketrW      s    2 g~=='D))6+>+>BV__$OOF//1C1CQG		7D/"GT" 

s   B8C6 6Dc                  :    e Zd ZdZddZddZddZed	d       Zy)
UvicornServeraR  Async uvicorn server for embedding in an existing event loop.

    This class is used by Streamlit's `Server` class when `server.useStarlette=true`.
    It wraps `uvicorn.Server` and provides:

    - `start()`: Async method that returns when the server is ready to accept connections
    - Background task execution: Server runs in background while caller continues
    - `stop()`: Gracefully signal the server to shut down
    - `stopped`: Event that fires when the server has fully stopped

    This async design allows the `Server` class to coordinate multiple components
    (runtime lifecycle, signal handlers, stop/stopped semantics) in its event loop.

    Parameters
    ----------
    runtime
        The Streamlit Runtime instance. Used to create the Starlette application
        via `create_starlette_app(runtime)`.

    Examples
    --------
    Used internally by Server._start_starlette():

    >>> server = UvicornServer(runtime)
    >>> await server.start()  # Returns when ready
    >>> # ... server running in background ...
    >>> server.stop()
    >>> await server.stopped.wait()
    c                n    || _         d | _        d | _        t        j                         | _        d | _        y N)_runtime_server_server_taskasyncioEvent_stopped_event_socket)selfruntimes     r   __init__zUvicornServer.__init__   s-    .27;%mmo-1r   c           	        K   	 ddl }t               rt        d      t	         j
                        }t               }t               }t               }d}t        t        dz         D ]   }||z   }	 |j                  |f||	d|}
	 t        ||	|
j                         _         |j4                  |
       _        t9        j:                  d|	t<        j>                         t(        j1                  d||	       tA        jB                         dd fd}tA        jD                   |       d       _#        jI                          d{    t(        jK                  d||	        y ||y# t        $ r}t        d      |d}~ww xY w# t        $ r}|}|j                   t         j"                  t         j$                  fv rqt'               r+t(        j+                  d|	       t-        j.                  d       t(        j1                  d|	       |t        k(  rt3        d	|	 d
t         d      |Y d}~΂ d}~ww xY w7 w)z=Start the server and return when ready to accept connections.r   Nztuvicorn is required for server.useStarlette but is not installed. Install it via `pip install streamlit[starlette]`.z8Unix sockets are not supported with Starlette currently.r+   hostrT   Port %s is not available2Port %s not available, trying to use the next one.z$Cannot start Streamlit server. Port zF is not available, and Streamlit was unable to find a free port after z
 attempts.r    z Starting uvicorn server on %s:%sc                   K   j                   j                  t        d      	 j                   j                  } | j                  s| j                          | j                  |       j                   _        j                   j                  j                  g       d{    j                   j                  rt        d      j                          	 	 j                   /j                   j                  j                  g       d{    j                  !j                  j                          d_        j                  j                          j                          yj                          j                   j                          d{    	 	 j                   /j                   j                  j                  g       d{    j                  !j                  j                          d_        j                  j                          j                          y7 7 '# j                  !j                  j                          d_        j                  j                          j                          w xY w7 # t        $ r}| d}~ww xY w7 # j                  !j                  j                          d_        j                  j                          j                          w xY w# 	 j                   0j                   j                  j                  g       d{  7   j                  !j                  j                          d_        j                  j                          j                          w # j                  !j                  j                          d_        j                  j                          j                          w xY wxY ww)zServe the application with proper lifecycle management.

                This ensures the server is shut down gracefully when the task is
                cancelled or an exception occurs.
                Nz Server or socket not initialized)socketszServer startup failed)r]   rb   RuntimeErrorr   loadedloadlifespan_classlifespanstartupshould_exitsetshutdownrS   ra   	main_looprR   )server_configerc   startup_completestartup_exceptions     r   serve_with_signalz.UvicornServer.start.<locals>.serve_with_signal>  s/     <<'4<<+?&'IJJ$/$(LL$7$7M(//%**,,9,H,H,WDLL),,..~.FFF||//,89P,Q)(,,./<<3"&,,"7"7"7"OOO  <<3 LL..0+/DL++//1 ),,./ %((*,,00222/<<3"&,,"7"7"7"OOO  <<3 LL..0+/DL++//1 ),,.; G& P  <<3 LL..0+/DL++//1 ),,.+ 3$ 
 )*% P  <<3 LL..0+/DL++//1 ),,./<<3"&,,"7"7"7"OOO  <<3 LL..0+/DL++//1 ),,.  <<3 LL..0+/DL++//1 ),,.s   $PA<J $H6%5J 6H< H9H< AP/-J JJ #6J0 J.J0 AP6J 9H< <AJPJ 	J+#J&&J++L .J0 0AL		PO>6N"MN"
AO>"AO;;O>>Pzuvicorn-server)namezUvicorn server started on %s:%sreturnNone)&uvicornModuleNotFoundErrorrm   r)   r   r\   r   r"   rB   ranger   ConfigrW   rU   rb   OSErrorerrno
EADDRINUSEEACCESr%   r   r-   r.   r/   debugr   Serverr]   r   
set_optionr   STREAMLIT_DEFINITIONr_   r`   create_taskr^   waitinfo)rc   r   excappconfigured_addressconfigured_portuvicorn_kwargslast_exceptionattemptrT   uvicorn_configr{   ry   rz   s   `           @@r   startzUvicornServer.start   sd    	 *+J  #4==1 12*,35/34q89 m	G"W,D+W^^' !	N+&"** 2 *7>>.9DLmT<3T3TUMM2"  '}}6:./` !( 3 3!#*:!D #''))) ,''LL1"
 [m	^ %   &G # 	E 	H  !$ 99!1!15<< @@,.&@$GMMLd "992B4& IR67zC  #	#
 %f *sf   I E0 A;I F#B%I H>	'I 0	F
9FF

I 	H;BH6/I 5H66H;;I c                @    | j                   d| j                   _        yy)zSignal the server to stop.NT)r]   rs   rc   s    r   stopzUvicornServer.stop  s    <<#'+DLL$ $r   c                    | j                   S )z7An event that is set when the server has fully stopped.)ra   r   s    r   stoppedzUvicornServer.stopped  s     """r   N)rd   r   r~   r   r}   )r~   zasyncio.Event)	r   r   r   r   re   r   r   propertyr   r   r   r   rY   rY      s,    <2H!T,
 # #r   rY   c                       e Zd ZdZddZddZy)UvicornRunnera  Sync uvicorn runner for standalone CLI usage.

    This class is used by `run_asgi_app()` when running `st.App` via `streamlit run`.
    It wraps `uvicorn.run()` which is a blocking call that:

    - Creates and manages its own event loop
    - Handles OS signals (SIGINT, SIGTERM) for graceful shutdown
    - Runs until the server exits

    This is ideal for `st.App` mode because:

    - The `st.App` handles its own runtime lifecycle via ASGI lifespan hooks
    - No external coordination is needed - uvicorn manages everything
    - Simple "run and block" semantics for CLI usage

    Parameters
    ----------
    app
        Either an ASGI app instance or an import string (e.g., "myapp:app").
        Import strings are preferred as they allow uvicorn to handle the import.

    Examples
    --------
    Used by bootstrap.run_asgi_app():

    >>> runner = UvicornRunner("myapp:app")
    >>> runner.run()  # Blocks until server exits
    c                    || _         y r[   )_app)rc   r   s     r   re   zUvicornRunner.__init__  s	    	r   c                <   	 ddl }t               rt        d      t	               }t               }t               }t        t        dz         D ]j  }||z   }|dkD  r%t        j                  d|t        j                         	 t        j                  d||        |j                  | j                   f||d|  y y# t        $ r}t        d      |d}~ww xY w# t"        $ r}|j$                  t$        j&                  t$        j(                  fv rt+               r+t        j-                  d	|       t/        j0                  d       t        j                  d
|       |t        k(  r0t        j-                  d|t               t/        j0                  d       Y d}~J d}~ww xY w)a  Run the server synchronously (blocking until exit).

        This method blocks until the server exits, either from a signal
        (Ctrl+C, SIGTERM) or an error. It handles port retry automatically
        if the configured port is not available.
        r   NzLuvicorn is required for running st.App. Install it with: pip install uvicornz5Unix sockets are not supported with st.App currently.r+   r    z Starting uvicorn runner on %s:%srg   ri   rj   zxCannot start Streamlit server. Port %s is not available, and Streamlit was unable to find a free port after %s attempts.)r   r   rm   r)   r   r"   rB   r   r   r   r   r   r   r   r   runr   r   r   r   r   r%   r-   r.   r/   )rc   r   r   r   r   r   r   rT   s           r   r   zUvicornRunner.run  s   	 *+VWW 12*,35 4q89 +	G"W,D{!!!4)J)J!6&
 II+ %	 -+	 # 	7 	L   99!1!15<< @@,.&@$GMMLd "99+ !3 )s6   B9 >7C9	CCC	FB0FFFN)r   strr~   r   r}   )r   r   r   r   re   r   r   r   r   r   r     s    :Cr   r   )r~   r   )r~   r!   )r~   r,   )r~   ztuple[str | None, str | None])r~   ztuple[int, int])r~   zdict[str, Any])r(   r   rT   r!   rU   r!   r~   zsocket.socket),r   
__future__r   r_   r   rF   r.   typingr   r   r   	streamlitr   streamlit.config_optionr   streamlit.loggerr	   streamlit.runtime.runtime_utilr
   ,streamlit.web.server.starlette.starlette_appr   6streamlit.web.server.starlette.starlette_server_configr   r   r   r   r   streamlit.runtimer   r   r   __annotations__	Exceptionr   r   r"   r%   r)   r2   r6   rB   rW   rY   r   r   r   r   <module>r      s   0 #    
 , ,  0 ' E M  )H% %R9 RI
1
1
A(K0-jx# x#vd dr   