Ë
    úmxiöG  ã                  ó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__© ó    úf/home/htdocs/ttos/venv/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   € ä×ÑÐ-Ó.ÒHÔ2HÐ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Ó1€GØ˜$ÐÒ@ 7×#5Ñ#5°iÓ#@Ð@r   c                 óà   — t        j                  d«      } t        j                  d«      }t        | «      t        |«      k7  r*t        j	                  d«       t        j                  d«       | |fS )z½Validate 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Ó7€IÜ× Ñ Ð!4Ó5€Hô ˆ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 )zÏGet 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Ñ€IˆxÜ(?Ó(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—_‘_Ò$à�O‰OœF×/Ñ/´×1CÑ1CÀQÔGà�	‰	�7˜D�/Ô"Ø�‰�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;ˆÔÜ%Ÿm™m›oˆÔØ-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 availableú2Port %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                  r°t        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)zÌServe 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ð$/à$(§L¡L×$7Ñ$7�MØ(×/Ò/Ø%×*Ñ*Ô,Ø,9×,HÑ,HÈÓ,W�D—L‘LÔ)àŸ,™,×.Ñ.¸¿¹°~Ð.ÓF×FÐFØ—|‘|×/Ò/Ü,8Ð9PÓ,QÐ)Ø(×,Ñ,Ô.Øð/ØŸ<™<Ð3Ø"&§,¡,×"7Ñ"7ÀÇÁÀÐ"7Ó"O×OÐOð  Ÿ<™<Ð3Ø ŸL™L×.Ñ.Ô0Ø+/˜DœLØ×+Ñ+×/Ñ/Ô1ð )×,Ñ,Õ.ð/ %×(Ñ(Ô*àŸ,™,×0Ñ0Ó2×2Ñ2ð/ØŸ<™<Ð3Ø"&§,¡,×"7Ñ"7ÀÇÁÀÐ"7Ó"O×OÐOð  Ÿ<™<Ð3Ø ŸL™L×.Ñ.Ô0Ø+/˜DœLØ×+Ñ+×/Ñ/Ô1ð )×,Ñ,Õ.ð; Gùð& Púð  Ÿ<™<Ð3Ø ŸL™L×.Ñ.Ô0Ø+/˜DœLØ×+Ñ+×/Ñ/Ô1ð )×,Ñ,Õ.úð+ 3ùÜ$ò ð
 )*Ð%Øûðúð Pùð  Ÿ<™<Ð3Ø ŸL™L×.Ñ.Ô0Ø+/˜DœLØ×+Ñ+×/Ñ/Ô1ð )×,Ñ,Õ.ûð/ØŸ<™<Ð3Ø"&§,¡,×"7Ñ"7ÀÇÁÀÐ"7Ó"O×OÑOð  Ÿ<™<Ð3Ø ŸL™L×.Ñ.Ô0Ø+/˜DœLØ×+Ñ+×/Ñ/Ô1ð )×,Ñ,Õ.øð  Ÿ<™<Ð3Ø ŸL™L×.Ñ.Ô0Ø+/˜DœLØ×+Ñ+×/Ñ/Ô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ˆäÔ4°qÑ8Ó9ó m	ˆGØ" WÑ,ˆDà+˜WŸ^™^Øðà'Øñð !ñ	ˆNðÜ+Ø&ØØ"×*Ñ*ó �”ð2 *˜7Ÿ>™>¨.Ó9ˆDŒLÜ×Ñ˜m¨T´<×3TÑ3TÔUÜ�M‰MØ2Ø"Øôô  'Ÿ}™}›ÐØ6:Ð÷./ô` !(× 3Ñ 3Ù!Ó#Ð*:ô!ˆDÔð #×'Ñ'Ó)×)Ð)à Ð,Ø'Ð'ä�L‰LØ1Ø"Øôñ
 ð[m	ð^ Ð%Ø Ð ð &øôG #ò 	ÜðEóð ðûð	ûôH ò Ø!$�ð —9‘9¤×!1Ñ!1´5·<±<Ð @Ñ@Ü,Ô.ÜŸ™Ð&@À$ÔGÜŸ™ œÜ—M‘MØLÈdôð Ô"9Ò9Ü2ØBÀ4À&ð IRä6Ð7°zð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   € à�<‰<Ð#Ø'+ˆD�L‰LÕ$ð $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 rŠt+        «       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ˆô Ô4°qÑ8Ó9ò +	ˆGØ" WÑ,ˆDà˜Š{Ü×!Ñ!Ø! 4¬×)JÑ)Jôð!Ü—‘Ø6Ø&Øôð
 �—‘Ø—I‘Iðà+Øñð %ò	ñ ñ-+	øô #ò 	Üð7óð ðûð	ûôL ò ð —9‘9¤×!1Ñ!1´5·<±<Ð @Ñ@Ü,Ô.ÜŸ™Ð&@À$ÔGÜŸ™ œÜ—M‘MØLÈdôð Ô"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   