
    Zǻi+                        d Z ddlmZ ddlZddlZddlmZ dZdZdZ	dZ
dZdZdZdZd	Zd
ZdZdZ G d de      Z G d d      Z G d d      Zy)aE  Minimal yamux (Yet Another Multiplexer) client for TCP tunneling.

Implements the client side of the yamux protocol as specified at
https://github.com/hashicorp/yamux/blob/master/spec.md

Only the subset needed for tunnel client operation is implemented:
opening streams, sending/receiving data, flow control, and keepalive.
    )annotationsN)Protocol                  z>BBHIIi   c                  $    e Zd ZddZddZddZy)_ReadWriteCloserc                     y N )selfns     V/opt/lhia/marcimex/agent/venv/lib/python3.12/site-packages/langsmith/sandbox/_yamux.pyreadz_ReadWriteCloser.read,           c                     y r   r   r   datas     r   writez_ReadWriteCloser.write.   r   r   c                     y r   r   r   s    r   closez_ReadWriteCloser.close0   r   r   Nr   intreturnbytesr   r    r   r   r   None)__name__
__module____qualname__r   r   r   r   r   r   r   r   +   s    (, r   r   c                  b    e Zd ZdZ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y)YamuxStreamzA single multiplexed stream within a yamux session.

    Streams are created via :meth:`YamuxSession.open_stream` and provide
    blocking read/write/close with per-stream flow control.
    c                    || _         || _        t               | _        t	        j
                         | _        d| _        d| _        t        | _
        t        | _        t	        j
                         | _        d| _        y )NF)_id_session	bytearray	_recv_buf	threading	Condition
_recv_cond_recv_closed_recv_error_INITIAL_WINDOW_SIZE_recv_window_send_window
_send_cond_send_closed)r   	stream_idsessions      r   __init__zYamuxStream.__init__?   sa    "#--/! 00#--/!r   c                    | j                   S r   )r*   r   s    r   r8   zYamuxStream.stream_idM   s    xxr   c                   d}| j                   5  | j                  sW| j                  sK| j                  s?| j                   j	                          | j                  s| j                  s| j                  s?| j                  r| j                  st        d      | j                  s
	 ddd       yt        |t        | j                              }t        | j                  d|       }| j                  d|= t        | j                  z
  }|t        dz  k\  r|}| xj                  |z  c_
        ddd       |dkD  r)	 | j                  j                  | j                  |       S S # 1 sw Y   9xY w# t        $ r Y S w xY w)zRead up to *n* bytes, blocking until data is available.

        Returns ``b""`` on EOF (FIN received).
        Raises :class:`ConnectionResetError` on RST.
        r   zyamux stream reset by peerNr   r   )r0   r-   r1   r2   waitConnectionResetErrorminlenr    r3   r4   r+   _send_window_updater*   	Exception)r   r   delta_to_sendsizer   consumeds         r   r   zYamuxStream.readQ   sP    __ 	.nnT->->tGWGW$$& nnT->->tGWGW *+GHH>>	. 	. q#dnn-.D./Duu%+d.?.??H/144 (!!X-!#	.& 111$((MJ t3	. 	.,  s+   A#E 30E ,A<E 6&E,  E),	E98E9c           	        | j                   rt        d      d}t        |      }|t        |      k  r| j                  5  | j
                  dk(  rB| j                   s6| j                  j                          | j
                  dk(  r| j                   s6| j                   rt        d      t        t        |      |z
  | j
                        }| xj
                  |z  c_        ddd       | j                  j                  | j                  t        |||z                 ||z  }|t        |      k  rt        |      S # 1 sw Y   ]xY w)z7Write *data*, blocking if the send window is exhausted.zyamux stream closed for writingr   N)r7   BrokenPipeError
memoryviewr@   r6   r5   r=   r?   r+   
_send_datar*   r    )r   r   offsetmvchunks        r   r   zYamuxStream.writet   s   !"CDDs4y  +''1,T5F5FOO((* ''1,T5F5F$$)*KLLCI.0A0AB!!U*!+ MM$$TXXuR%5P/QReOF s4y  4y+ +s   AD;AD;;Ec                   | j                   s8d| _         	 | j                  j                  t        t        | j
                  d       | j                  5  d| _        | j                  j                          ddd       | j                  5  | j                  j                          ddd       y# t        $ r Y qw xY w# 1 sw Y   HxY w# 1 sw Y   yxY w)z/Close the stream (sends FIN to the remote end).Tr   N)r7   r+   _send_frame
_TYPE_DATA	_FLAG_FINr*   rB   r0   r1   
notify_allr6   r   s    r   r   zYamuxStream.close   s       $D))*i1M __ 	) $DOO&&(	) __ 	)OO&&(	) 	)  	) 	)	) 	)s)   0B+ "B:C+	B76B7:CCc                    | j                   5  | j                  j                  |       | xj                  t	        |      z  c_        | j                   j                          d d d        y # 1 sw Y   y xY wr   )r0   r-   extendr4   r@   rQ   r   s     r   _receive_datazYamuxStream._receive_data   sU    __ 	)NN!!$'T*OO&&(	) 	) 	)s   AA**A3c                    | j                   5  d| _        | j                   j                          d d d        y # 1 sw Y   y xY wNT)r0   r1   rQ   r   s    r   _receive_finzYamuxStream._receive_fin   s6    __ 	) $DOO&&(	) 	) 	)s	   "8Ac                   | j                   5  d| _        | j                   j                          d d d        | j                  5  d| _        | j                  j                          d d d        y # 1 sw Y   @xY w# 1 sw Y   y xY wrV   )r0   r2   rQ   r6   r7   r   s    r   _receive_rstzYamuxStream._receive_rst   sq    __ 	)#DOO&&(	) __ 	) $DOO&&(	) 	)	) 	)	) 	)s   "A."A:.A7:Bc                    | j                   5  | xj                  |z  c_        | j                   j                          d d d        y # 1 sw Y   y xY wr   )r6   r5   rQ   )r   deltas     r   _update_send_windowzYamuxStream._update_send_window   s?    __ 	)&OO&&(	) 	) 	)s   0AAN)r8   r   r9   YamuxSessionr   r#   )r   r   r   r!   r"   )r   r    r   r#   )r[   r   r   r#   )r$   r%   r&   __doc__r:   propertyr8   r   r   r   rT   rW   rY   r\   r   r   r   r(   r(   8   sD    "  !F,)"))
))r   r(   c                      e Zd ZdZ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)r]   a  Client-side yamux session over a byte-stream connection.

    The connection must implement ``read(n) -> bytes``, ``write(data) -> int``,
    and ``close() -> None``.  Typically this is a :class:`_WSAdapter` wrapping
    a WebSocket.

    Usage::

        session = YamuxSession(conn)
        stream = session.open_stream()
        stream.write(b"hello")
        data = stream.read(1024)
        stream.close()
        session.close()
    c                   || _         i | _        d| _        t        j                         | _        t        j                         | _        d| _        t        j                         | _	        t        j                  | j                  dd      | _        | j                  j                          t        j                  | j                  dd      | _        | j                  j                          y )Nr   FTzyamux-reader)targetdaemonnamezyamux-keepalive)_conn_streams_next_stream_idr.   Lock_lock_write_lock_closedEvent_shutdown_eventThread
_read_loop_reader_threadstart_keepalive_loop_keepalive_thread)r   conns     r   r:   zYamuxSession.__init__   s    
02 ^^%
$>>+(0'..??4n
 	!!#!*!1!1'';L"
 	$$&r   c                    | j                   S r   )rk   r   s    r   	is_closedzYamuxSession.is_closed   s    ||r   c                &   | j                   5  | j                  rt        d      | j                  }| xj                  dz  c_        t	        ||       }|| j
                  |<   ddd       | j                  t        t        d       S # 1 sw Y   'xY w)zgOpen a new multiplexed stream.

        Raises :class:`RuntimeError` if the session is closed.
        zyamux session is closedr   Nr   )	ri   rk   RuntimeErrorrg   r(   rf   rN   _TYPE_WINDOW_UPDATE	_FLAG_SYN)r   r8   streams      r   open_streamzYamuxSession.open_stream   s    
 ZZ 	.||"#<==,,I  A%  D1F'-DMM)$	. 	,iAF	. 	.s   ABBc                   | j                   ryd| _         | j                  j                          	 | j                  t        ddd       | j                  5  | j                  j                         D ]  }|j                           	 ddd       	 | j                  j                          y# t
        $ r Y lw xY w# 1 sw Y   4xY w# t
        $ r Y yw xY w)z"Close the session and all streams.NTr   )rk   rm   setrN   _TYPE_GO_AWAYrB   ri   rf   valuesrY   re   r   )r   r{   s     r   r   zYamuxSession.close   s    <<  "	]Aq!4 ZZ 	&--..0 &##%&	&	JJ  			& 	&  		s/   B) 0B8C )	B54B58C	CCc                    t        j                  t        t        ||||      }| j                  5  | j
                  j                  |       d d d        y # 1 sw Y   y xY wr   )structpack_HEADER_FMT_VERSIONrj   re   r   )r   msg_typeflagsr8   lengthhdrs         r   rN   zYamuxSession._send_frame  sL     kk+x5)VT 	"JJS!	" 	" 	"s   AAc           
         t        j                  t        t        t        d|t        |            }| j                  5  | j                  j                  ||z          d d d        y # 1 sw Y   y xY wNr   )	r   r   r   r   rO   r@   rj   re   r   )r   r8   r   r   s       r   rI   zYamuxSession._send_data  sR    kk+xQ	3t9U 	)JJS4Z(	) 	) 	)s   A$$A-c                4    | j                  t        d||       y r   )rN   ry   )r   r8   r[   s      r   rA   z YamuxSession._send_window_update  s    ,aEBr   c                   	 | j                   s| j                  j                  t              }t	        |      t        k  rnt        j                  t        |      \  }}}}}|t        k(  r| j                  |||       nC|t        k(  r| j                  |||       n&|t        k(  r| j                  ||       n
|t        k(  rn| j                   s| j                   sgd| _         | j                   j#                          | j$                  5  | j&                  j)                         D ]  }|j+                           	 d d d        y y # t        $ r Y w xY w# 1 sw Y   y xY w# | j                   ssd| _         | j                   j#                          | j$                  5  | j&                  j)                         D ]  }|j+                           	 d d d        w # 1 sw Y   w xY ww xY wrV   )rk   re   r   _HEADER_SIZEr@   r   unpackr   rO   _handle_datary   _handle_window_update
_TYPE_PING_handle_pingr   rB   rm   r~   ri   rf   r   rY   )r   	hdr_bytes_verr   r   r8   r   r{   s           r   ro   zYamuxSession._read_loop  s   	.ll JJOOL9	y>L0;A==<8hy& z)%%eY?!44..uiH+%%eV4.! ll( <<#$$((*ZZ ."&--"6"6"8 .++-.. .    		. . <<#$$((*ZZ ."&--"6"6"8 .++-.. . .  sH   C
E 0E	E
E EE E:G0G	GGGc                R   |dkD  r| j                   j                  |      nd}| j                  5  | j                  j	                  |      }d d d        y |r|j                  |       |t        z  r|j                          |t        z  r|j                          y y # 1 sw Y   SxY w)Nr   r   )
re   r   ri   rf   getrT   rP   rW   	_FLAG_RSTrY   )r   r   r8   r   payloadr{   s         r   r   zYamuxSession._handle_data6  s    -3aZ$**//&)SZZ 	2]]&&y1F	2>  )9!9! 	2 	2s   BB&c                   | j                   5  | j                  j                  |      }d d d        y |dkD  r|j                  |       |t        z  r|j                          |t        z  r|j                          y y # 1 sw Y   VxY wr   )ri   rf   r   r\   rP   rW   r   rY   )r   r   r8   r   r{   s        r   r   z"YamuxSession._handle_window_updateE  s|    ZZ 	2]]&&y1F	2>A:&&v.9!9! 	2 	2s   A>>Bc                p    |t         z  r	 | j                  t        t        d|       y y # t        $ r Y y w xY wr   )rz   rN   r   	_FLAG_ACKrB   )r   r   opaques      r   r   zYamuxSession._handle_pingR  s<    9  Y6B   s   ) 	55c                    d}| j                   j                  d      s?|dz  }	 | j                  t        t        d|       | j                   j                  d      s>y y # t
        $ r Y y w xY w)Nr      r   )rm   r=   rN   r   rz   rB   )r   ping_ids     r   rr   zYamuxSession._keepalive_loop[  sg    &&++B/qLG  Y7C &&++B/  s   A 	A*)A*N)rt   r   r   r#   )r   bool)r   r(   r"   )
r   r   r   r   r8   r   r   r   r   r#   )r8   r   r   r    r   r#   )r8   r   r[   r   r   r#   )r   r   r8   r   r   r   r   r#   )r   r   r   r   r   r#   )r$   r%   r&   r^   r:   r_   rv   r|   r   rN   rI   rA   ro   r   r   r   rr   r   r   r   r]   r]      s{     '&   .""$'"47"AD"	")
C
.:""r   r]   )r^   
__future__r   r   r.   typingr   r   rO   ry   r   r   rz   r   rP   r   r   r   r3   r   r(   r]   r   r   r   <module>r      s}    #    
 
				! !x !y) y)Bi ir   