Ë
    ÂXÕi2:  ã                  ó  — 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ZddlZddl	m
Z
 ddlmZmZmZ ddlmZ erddlmZmZ  ej(                  e«      ZdZdZdZd	Zd
ZdZdd„Zdd„Z G d„ d«      ZdZ dd„Z!d„ Z" G d„ d«      Z# G d„ d«      Z$y)a  TCP tunnel for accessing services running inside sandboxes.

Establishes a WebSocket connection to the daemon's ``/tunnel`` endpoint,
runs a yamux multiplexing session on top, and forwards local TCP connections
through yamux streams to the target port inside the sandbox.
é    )ÚannotationsN)ÚMapping)ÚTYPE_CHECKINGÚAnyÚOptional)Úmerge_headers)ÚYamuxSessionÚYamuxStreamé   é   é   z>BHc                ó`   — | j                  t        j                  t        t        |«      «       y)zAWrite the 3-byte connect header on a freshly opened yamux stream.N)ÚwriteÚstructÚpackÚ_CONNECT_HEADER_FMTÚPROTOCOL_VERSION)ÚstreamÚports     úe/root/rosshost/parking-map/parking-api/venv/lib/python3.12/site-packages/langsmith/sandbox/_tunnel.pyÚ_write_connect_headerr   (   s   € à
‡L�L”—‘Ô0Ô2BÀDÓIÕJó    c                óH   — | j                  d«      }|st        d«      ‚|d   S )z0Read the 1-byte status response from the daemon.r   z'tunnel: connection closed before statusr   )ÚreadÚConnectionError)r   Údatas     r   Ú_read_statusr   -   s'   € à�;‰;�q‹>€DÙÜÐGÓHÐHØ�‰7€Nr   c                  ó0   — e Zd ZdZdd„Zdd„Zd	d„Zd
d„Zy)Ú
_WSAdaptera
  Adapts the ``websockets`` message API to a byte-stream interface.

    yamux requires a plain read/write/close byte stream.  WebSocket is
    message-based, so this adapter buffers partially consumed messages on
    reads and sends one binary message per write.
    c                ób   — || _         t        «       | _        t        j                  «       | _        y ©N)Ú_wsÚ	bytearrayÚ_bufÚ	threadingÚLockÚ_write_lock)ÚselfÚwss     r   Ú__init__z_WSAdapter.__init__B   s!   € ØˆŒÜ“KˆŒ	Ü$Ÿ>™>Ó+ˆÕr   c                ó`  — t        | j                  «      |k  rn| j                  j                  «       }t	        |t
        «      r|j                  «       }| j                  j                  |«       t        | j                  «      |k  rŒnt        | j                  d | «      }| j                  d |…= |S r!   )	Úlenr$   r"   ÚrecvÚ
isinstanceÚstrÚencodeÚextendÚbytes)r(   ÚnÚmsgÚresults       r   r   z_WSAdapter.readG   s„   € Ü�$—)‘)‹n˜qÒ Ø—(‘(—-‘-“/ˆCÜ˜#œsÔ#Ø—j‘j“l�Ø�I‰I×Ñ˜SÔ!ô	 �$—)‘)‹n˜qÓ ô �t—y‘y  !�}Ó%ˆØ�I‰I�b�q�bˆMØˆr   c                ó¤   — | j                   5  | j                  j                  |«       d d d «       t        |«      S # 1 sw Y   t        |«      S xY wr!   )r'   r"   Úsendr,   )r(   r   s     r   r   z_WSAdapter.writeR   s?   € Ø×Ññ 	 Ø�H‰H�M‰M˜$Ô÷	 ä�4‹yÐ÷	 ä�4‹yÐús	   �<¼Ac                óX   — 	 | j                   j                  «        y # t        $ r Y y w xY wr!   )r"   ÚcloseÚ	Exception©r(   s    r   r9   z_WSAdapter.closeW   s'   € ð	Ø�H‰H�N‰NÕøÜò 	Ùð	ús   ‚ �	)¨)N)r)   r   ÚreturnÚNone)r3   Úintr<   r2   )r   r2   r<   r>   ©r<   r=   )Ú__name__Ú
__module__Ú__qualname__Ú__doc__r*   r   r   r9   © r   r   r   r   :   s   „ ñó,ó
	óô
r   r   i @  c                ó4  ‡ ‡‡— t        j                  «       Šdˆˆ ˆfd„}dˆˆ ˆfd„}t        j                  |d¬«      }t        j                  |d¬«      }|j                  «        |j                  «        ‰j	                  «        	 ‰ j                  «        	 ‰j                  t        j                  «       	 ‰j                  «        |j                  d¬«       |j                  d¬«       y# t        $ r Y Œaw xY w# t        $ r Y ŒPw xY w# t        $ r Y ŒNw xY w)	z:Copy data bidirectionally until one side closes or errors.c                 óÈ   •— 	 	 ‰j                  t        «      } | sn‰j                  | «       Œ*	 ‰j	                  «        y # t        $ r Y Œw xY w# ‰j	                  «        w xY wr!   )r   Ú_BRIDGE_BUF_SIZEÚsendallr:   Úset©r   Údoner   Útcp_conns    €€€r   Ú_stream_to_tcpz_bridge.<locals>._stream_to_tcpi   sc   ø€ ð		ØØ—{‘{Ô#3Ó4�ÙØØ× Ñ  Ô&ð	 ð ð
 �H‰H�Jøô ò 	Ùð	ûð �H‰H�Júó(   ƒ+A  ®A Á 	AÁ	A ÁAÁA ÁA!c                 óÈ   •— 	 	 ‰j                  t        «      } | sn‰j                  | «       Œ*	 ‰j	                  «        y # t        $ r Y Œw xY w# ‰j	                  «        w xY wr!   )r-   rG   r   r:   rI   rJ   s    €€€r   Ú_tcp_to_streamz_bridge.<locals>._tcp_to_streamu   sa   ø€ ð		ØØ—}‘}Ô%5Ó6�ÙØØ—‘˜TÔ"ð	 ð ð
 �H‰H�Jøô ò 	Ùð	ûð �H‰H�JúrN   T)ÚtargetÚdaemoné   )ÚtimeoutNr?   )r%   ÚEventÚThreadÚstartÚwaitr9   r:   ÚshutdownÚsocketÚ	SHUT_RDWRÚOSErrorÚjoin)r   rL   rM   rP   Út1Út2rK   s   ``    @r   Ú_bridger`   e   sè   ú€ ä�?‰?Ó€D÷
÷
ô 
×	Ñ	 ¸Ô	=€BÜ	×	Ñ	 ¸Ô	=€BØ‡H�H„JØ‡H�H„Jà‡I�I„KðØ�‰ŒðØ×Ñœ&×*Ñ*Ô+ðØ�‰Ôð ‡G�G�A€GÔØ‡G�G�A€GÕøô ò Ùðûô ò Ùðûô ò Ùðús6   ÂC- ÂC< Â8D Ã-	C9Ã8C9Ã<	DÄDÄ	DÄDc                 óF   — 	 ddl m}  | S # t        $ r t        d«      d‚w xY w)z5Import websockets sync client or raise a clear error.r   )Úconnectz_TCP tunnel requires the 'websockets' package. Install it with: pip install 'langsmith[sandbox]'N)Úwebsockets.sync.clientrb   ÚImportError)Ú
ws_connects    r   Ú_ensure_websocketsrf   ž   s7   € ðÝ@àÐøÜò Üð@ó
ð ð	ðús   ‚
 Š c                  ó¸   — e Zd ZdZdZdZddddœ	 	 	 	 	 	 	 	 	 	 	 	 	 dd„Zedd	„«       Zedd
„«       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dd„Zdd„Zy)ÚTunnela  TCP tunnel to a port inside a sandbox.

    Opens a local TCP listener and forwards each accepted connection through
    a yamux-multiplexed WebSocket to the daemon, which dials the target port
    inside the sandbox.

    Typically used as a context manager::

        with sandbox.tunnel(remote_port=5432) as t:
            conn = psycopg2.connect(host="127.0.0.1", port=t.local_port)

    Or with explicit lifecycle::

        t = sandbox.tunnel(remote_port=5432)
        # ... use tunnel ...
        t.close()
    ç      à?g       @r   r   N©Ú
local_portÚmax_reconnectsÚheadersc               ó  — || _         || _        || _        || _        |xs || _        | j                  | _        || _        d | _        d | _        d | _	        d | _
        t        j                  «       | _        d| _        d| _        y )NF)Ú_dataplane_urlÚ_api_keyÚ_headersÚ_remote_portÚ_requested_local_portÚ_local_portÚ_max_reconnectsr"   Ú_yamuxÚ_server_socketÚ_accept_threadr%   r&   Ú_reconnect_lockÚ_closedÚ_started©r(   Údataplane_urlÚapi_keyÚremote_portrk   rl   rm   s          r   r*   zTunnel.__init__Á   s€   € ð ,ˆÔØˆŒØˆŒØ'ˆÔØ%/Ò%>°;ˆÔ"Ø×5Ñ5ˆÔØ-ˆÔàˆŒØ.2ˆŒØ7;ˆÔØ:>ˆÔÜ(Ÿ~™~Ó/ˆÔØˆŒØˆ�r   c                ó   — | j                   S )z&Local port the tunnel is listening on.)rt   r;   s    r   rk   zTunnel.local_portÛ   s   € ð ×ÑÐr   c                ó   — | j                   S )z4Port inside the sandbox that the tunnel connects to.)rr   r;   s    r   r   zTunnel.remote_portà   s   € ð × Ñ Ð r   c                ó   — | S r!   rD   r;   s    r   Ú	__enter__zTunnel.__enter__ç   s   € Øˆr   c                ó$   — | j                  «        y r!   )r9   )r(   Úargss     r   Ú__exit__zTunnel.__exit__ê   s   € Ø�
‰
�r   c                óŠ   — | j                   ry d| _         	 | j                  «        y # t        $ r | j                  «        ‚ w xY w)NT)r{   Ú	_do_startr:   r9   r;   s    r   Ú_startzTunnel._startï   s=   € Ø�=Š=ØØˆŒð	Ø�N‰NÕøÜò 	Ø�J‰JŒLØð	ús	   –' §Ac                ó‚  — | j                  «        t        j                  t        j                  t        j                  «      | _        | j                  j                  t        j                  t        j                  d«       | j                  }|dk7  rvt        j                  t        j                  t        j                  «      }	 |j                  d«       |j                  d|f«       |j                  «        t        d|› d�«      ‚| j                  j!                  d| j                  f«       | j                  j#                  d	«       | j                  j%                  «       d   | _        t)        j*                  | j,                  d
d¬«      | _        | j.                  j1                  «        y # t        $ r Y n@t        $ r5}dt        |«      v rndt        |«      j                  «       v r‚ 	 Y d }~nd }~ww xY w	 |j                  «        �Œ# t        $ r Y �Œw xY w# 	 |j                  «        w # t        $ r Y w w xY wxY w)Nr   r   ri   z	127.0.0.1zPort zE is already in use by another service. Choose a different local_port.zConnection refusedzalready in useé€   Tztunnel-accept)rQ   rR   Úname)Ú_connectrZ   ÚAF_INETÚSOCK_STREAMrw   Ú
setsockoptÚ
SOL_SOCKETÚSO_REUSEADDRrs   Ú
settimeoutrb   r9   r\   ÚConnectionRefusedErrorr/   ÚlowerÚbindÚlistenÚgetsocknamert   r%   rV   Ú_accept_looprx   rW   )r(   r   ÚprobeÚes       r   rˆ   zTunnel._do_startú   sÏ  € Ø�‰Œä$Ÿm™m¬F¯N©N¼F×<NÑ<NÓOˆÔØ×Ñ×&Ñ&¤v×'8Ñ'8¼&×:MÑ:MÈqÔQð
 ×)Ñ)ˆØ�1Š9Ü—M‘M¤&§.¡.´&×2DÑ2DÓEˆEðØ× Ñ  Ô%Ø—‘˜{¨DÐ1Ô2Ø—‘”ÜØ˜D˜6ð "5ð 6óð ð& 	×Ñ× Ñ  +¨t×/IÑ/IÐ!JÔKØ×Ñ×"Ñ" 3Ô'Ø×.Ñ.×:Ñ:Ó<¸QÑ?ˆÔä'×.Ñ.Ø×$Ñ$¨T¸ô
ˆÔð 	×Ñ×!Ñ!Õ#øô- *ò ÙÜò Ø'¬3¨q«6Ñ1ØØ%¬¨Q«¯©«Ñ7ØàÿøðúðØ—K‘K–MøÜò ÚðûðØ—K‘K•MøÜò Ùðýsm   ÃAF. Æ.	G6Æ7H Æ9G6Ç+G1Ç,H Ç1G6Ç6H Ç:H È	HÈHÈH>ÈH/È.H>È/	H;È8H>È:H;È;H>c                óh  — ddl m} | j                  }|r	 |j                  «        t        «       }| j                  «       }t        | j                  rd| j                  ind| j                  «      } |||ddd¬«      | _
        t        | j                  «      } ||«      | _        y# t        $ r Y ŒŠw xY w)z:Establish (or re-establish) the WebSocket + yamux session.r   )r	   z	X-Api-KeyNé   rS   )Úadditional_headersÚopen_timeoutÚclose_timeoutÚping_interval)Úlangsmith.sandbox._yamuxr	   rv   r9   r:   rf   Ú_build_ws_urlr   rp   rq   r"   r   )r(   r	   Ú	old_yamuxre   Úws_urlrm   Úadapters          r   r�   zTunnel._connect&  sª   € å9à—K‘Kˆ	ÙðØ—‘Ô!ô (Ó)ˆ
Ø×#Ñ#Ó%ˆÜØ,0¯MªMˆ[˜$Ÿ-™-Ñ(¸tØ�M‰Mó
ˆñ
 ØØ&ØØØô
ˆŒô ˜TŸX™XÓ&ˆÙ" 7Ó+ˆ�øô' ò Ùðús   –B% Â%	B1Â0B1c                óº  — ddl m} | j                  r"| j                  j                  s| j                  S | j                  5  | j                  r+| j                  j                  s| j                  cddd«       S d}t        | j                  «      D ]B  }	 | j                  «        t        j                  d|dz   «       | j                  c cddd«       S   |d| j                  › d�«      |‚# t        $ rY}|}|| j                  dz
  k  r;t        | j                  d|z  z  | j                  «      }t        j                  |«       Y d}~Œ¹d}~ww xY w# 1 sw Y   yxY w)	z4Return a live yamux session, reconnecting if needed.r   )ÚTunnelErrorNz tunnel: reconnected (attempt %d)r   r   ztunnel: reconnect failed after z	 attempts)Úlangsmith.sandbox._exceptionsr¨   rv   Ú	is_closedry   Úrangeru   r�   ÚloggerÚdebugr:   ÚminÚ_BACKOFF_BASEÚ_BACKOFF_MAXÚtimeÚsleep)r(   r¨   Úlast_errÚattemptÚexcÚdelays         r   Ú_ensure_sessionzTunnel._ensure_sessionC  s8  € å=à�;Š;˜tŸ{™{×4Ò4Ø—;‘;Ðà×!Ñ!ñ 	Ø�{Š{ 4§;¡;×#8Ò#8Ø—{‘{÷	ñ 	ð -1ˆHÜ  ×!5Ñ!5Ó6ò *�ð*Ø—M‘M”OÜ—L‘LÐ!CÀWÈqÁ[ÔQØŸ;™;Ñ&÷	ñ 	ð
*ñ Ø1°$×2FÑ2FÐ1GÀyÐQóàðøô !ò *Ø"�HØ ×!5Ñ!5¸Ñ!9Ò9Ü #Ø ×.Ñ.°!°W±*Ñ=Ø ×-Ñ-ó!˜ô Ÿ
™
 5Ô)ÿøð*ú÷	ð 	úsC   Á.EÁ9EÂ4C,ÃEÃEÃ,	EÃ5AE	ÅEÅ	EÅEÅEc                óæ   — | j                   ryd| _         | j                  r	 | j                  j                  «        | j                  r| j                  j                  «        yy# t        $ r Y Œ3w xY w)z.Shut down the tunnel, closing all connections.NT)rz   rw   r9   r\   rv   r;   s    r   r9   zTunnel.closea  se   € à�<Š<ØØˆŒà×ÒðØ×#Ñ#×)Ñ)Ô+ð �;Š;Ø�K‰K×ÑÕð øô ò Ùðús   ¢A$ Á$	A0Á/A0c                óö   — | j                   s^	 | j                  j                  «       \  }}t	        j
                  | j                  |fdd¬«      j                  «        | j                   sŒ]y y # t        $ r Y y w xY w)NTztunnel-bridge)rQ   r…   rR   rŒ   )rz   rw   Úacceptr\   r%   rV   Ú_handle_connrW   )r(   ÚconnÚ_s      r   r™   zTunnel._accept_loopr  sp   € Ø—,’,ðØ×-Ñ-×4Ñ4Ó6‘��aô ×ÑØ×(Ñ(Ø�WØØ$ô	÷
 ‰eŒgð —,•,øô ò Ùðús   ŽA, Á,	A8Á7A8c                ó´  — 	 | j                  «       }|j                  «       }t        || j                  «       t	        |«      }|t
        k(  rt        ||«       y |j                  «        |j                  «        |t        k(  r!t        j                  d| j                  «       y |t        k(  r!t        j                  d| j                  «       y |t        k(  rt        j                  dt        «       y t        j                  d|«       y # t        $ rF}t        j                  d|«       	 |j                  «        n# t         $ r Y nw xY wY d }~y Y d }~y d }~ww xY w)Nz%tunnel: port %d not allowed by daemonz3tunnel: nothing listening on port %d inside sandboxz.tunnel: protocol version mismatch (client v%d)ztunnel: unknown status %dz$tunnel: connection handler error: %s)r·   Úopen_streamr   rr   r   Ú	STATUS_OKr`   r9   ÚSTATUS_PORT_NOT_ALLOWEDr¬   ÚwarningÚSTATUS_DIAL_FAILEDÚSTATUS_UNSUPPORTED_VERSIONr   r:   r­   r\   )r(   rL   Úsessionr   Ústatusrµ   s         r   r»   zTunnel._handle_conn  s  € ð$	Ø×*Ñ*Ó,ˆGØ×(Ñ(Ó*ˆFÜ! &¨$×*;Ñ*;Ô<Ü! &Ó)ˆFàœÒ"Ü˜ Ô)Øà�L‰LŒNØ�N‰NÔàÔ0Ò0Ü—‘Ø;Ø×%Ñ%õð Ô-Ò-Ü—‘ØIØ×%Ñ%õð Ô5Ò5Ü—‘ØDÜ$õô
 —‘Ð:¸FÕCøäò 	Ü�L‰LÐ?ÀÔEðØ—‘Õ øÜò ÙðúÜô !ûð	úsU   ‚AD ÁA	D Â#)D Ã#D Ã1D Ä	EÄEÄ(D9Ä8EÄ9	EÅEÅEÅEÅEc                ó†   — | j                   j                  d«      }|j                  dd«      j                  dd«      }|› d�S )Nú/zhttps://zwss://zhttp://zws://z/tunnel)ro   ÚrstripÚreplace)r(   Úurls     r   r£   zTunnel._build_ws_url¦  sA   € Ø×!Ñ!×(Ñ(¨Ó-ˆØ�k‰k˜* hÓ/×7Ñ7¸	À7ÓKˆØ��gˆÐr   ©r}   r/   r~   zOptional[str]r   r>   rk   r>   rl   r>   rm   zOptional[Mapping[str, str]]r<   r=   ©r<   r>   )r<   rh   ©r…   Úobjectr<   r=   r?   )r<   r	   )rL   úsocket.socketr<   r=   )r<   r/   )r@   rA   rB   rC   r¯   r°   r*   Úpropertyrk   r   rƒ   r†   r‰   rˆ   r�   r·   r9   r™   r»   r£   rD   r   r   rh   rh   «   sÃ   „ ñð$ €MØ€Lð ØØ/3ñàðð ðð ð	ð ðð ðð -ðð 
óð4 ò ó ð ð ò!ó ð!óóó
	ó*$óX,ó:ó< ó"ó%ôNr   rh   c                  óx   — e Zd ZdZddddœ	 	 	 	 	 	 	 	 	 	 	 	 	 dd„Zedd„«       Zedd„«       Zdd	„Zdd
„Z	dd„Z
y)ÚAsyncTunnelaw  Async wrapper around :class:`Tunnel`.

    The underlying tunnel runs in background threads (TCP listener + bridges);
    async context-manager methods delegate to the sync tunnel via the event
    loop's executor.

    Usage::

        async with await sandbox.tunnel(remote_port=5432) as t:
            conn = await asyncpg.connect(host="127.0.0.1", port=t.local_port)
    r   r   Nrj   c               ó0   — t        ||||||¬«      | _        y )Nrj   )rh   Ú_tunnelr|   s          r   r*   zAsyncTunnel.__init__¾  s"   € ô ØØØØ!Ø)Øô
ˆ�r   c                ó.   — | j                   j                  S r!   )rÕ   rk   r;   s    r   rk   zAsyncTunnel.local_portÑ  s   € à�|‰|×&Ñ&Ð&r   c                ó.   — | j                   j                  S r!   )rÕ   r   r;   s    r   r   zAsyncTunnel.remote_portÕ  s   € à�|‰|×'Ñ'Ð'r   c              ƒ  ó–   K  — t        j                  «       }|j                  d | j                  j                  «      ƒ d {  –—†  | S 7 Œ­wr!   )ÚasyncioÚget_running_loopÚrun_in_executorrÕ   r‰   )r(   Úloops     r   Ú
__aenter__zAsyncTunnel.__aenter__Ù  s>   è ø€ Ü×'Ñ'Ó)ˆØ×"Ñ" 4¨¯©×)<Ñ)<Ó=×=Ð=Øˆð 	>ús   ‚>A	Á AÁA	c              ‡  ó”   K  — t        j                  «       }|j                  d | j                  j                  «      ƒ d {  –—†  y 7 Œ­wr!   )rÙ   rÚ   rÛ   rÕ   r9   )r(   r…   rÜ   s      r   Ú	__aexit__zAsyncTunnel.__aexit__Þ  s4   è ø€ Ü×'Ñ'Ó)ˆØ×"Ñ" 4¨¯©×);Ñ);Ó<×<Ò<ús   ‚>AÁ AÁAc                ó8   — | j                   j                  «        y)z;Shut down the tunnel (sync, safe to call from any context).N)rÕ   r9   r;   s    r   r9   zAsyncTunnel.closeâ  s   € à�‰×ÑÕr   rÌ   rÍ   )r<   rÓ   rÎ   r?   )r@   rA   rB   rC   r*   rÑ   rk   r   rÝ   rß   r9   rD   r   r   rÓ   rÓ   ±  s’   „ ñ
ð$ ØØ/3ñ
àð
ð ð
ð ð	
ð ð
ð ð
ð -ð
ð 
ó
ð& ò'ó ð'ð ò(ó ð(óó
=ôr   rÓ   )r   r
   r   r>   r<   r=   )r   r
   r<   r>   )r   r
   rL   rÐ   r<   r=   )%rC   Ú
__future__r   rÙ   ÚloggingrZ   r   r%   r±   Úcollections.abcr   Útypingr   r   r   Úlangsmith.sandbox._helpersr   r¢   r	   r
   Ú	getLoggerr@   r¬   r   rÀ   rÁ   rÃ   rÄ   r   r   r   r   rG   r`   rf   rh   rÓ   rD   r   r   ú<module>rç      sª   ðñõ #ã Û Û Û Û Û Ý #ß /Ñ /å 4áßBà	ˆ×	Ñ	˜8Ó	$€ð Ð à€	ØÐ ØÐ Ø!Ð àÐ óKó
÷!ñ !ðP Ð ó1òr
÷~ñ ~÷L3ò 3r   