a
   ꈾ5[                   @   sx   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dZdddZG dd deZ	G d	d
 d
eZ
G dd deZdS )    NTc                 C   sJ   t  | t j}|r |tj @ }n
|tjB }t  | t j| t|tj@  S )zl
    Set the given file-descriptor blocking or non-blocking.

    Returns the original blocking status.
    )fcntlZF_GETFLos
O_NONBLOCKZF_SETFLbool)fdblockingZold_flagZnew_flag r   0/usr/lib/python3.9/site-packages/dockerpty/io.pyset_blocking   s    
r
   c              
   C   s   g }zt | |||dd W S  t jyz } zBtjr<|jn|d }|tjkrbg g fW  Y d}~S |W Y d}~n
d}~0 0 dS )z
    Select the streams from `read_streams` that are ready for reading, and
    streams from `write_streams` ready for writing.

    Uses `select.select()` internally but only returns two lists of ready streams.
    r      N)builtin_selectselecterrorsixZPY3errnoEINTR)Zread_streamsZwrite_streamstimeoutZexception_streamsenor   r   r	   r   ,   s    
r   c                   @   sj   e Zd ZdZejejejgZdd Z	dd Z
dd Zdd	d
Zdd Zdd Zdd Zdd Zdd ZdS )Streamz
    Generic Stream class.

    This is a file-like abstraction on top of os.read() and os.write(), which
    add consistency to the reading of sockets and files alike.
    c                 C   s   || _ d| _d| _d| _dS )z}
        Initialize the Stream for the file descriptor `fd`.

        The `fd` object must have a `fileno()` method.
            FN)r   bufferclose_requestedclosed)selfr   r   r   r	   __init__W   s    zStream.__init__c                 C   s
   | j  S )z=
        Return the fileno() of the file descriptor.
        )r   filenor   r   r   r	   r   b   s    zStream.filenoc                 C   s,   t | jdr| j| dS t| j|S d S )NsetblockingT)hasattrr   r   r
   r   valuer   r   r	   r
   i   s    zStream.set_blocking   c              
   C   sj   z.t | jdr| j|W S t| j |W S  tyb } z|jtj	vrN|W Y d}~q d}~0 0 q dS )zU
        Return `n` bytes of data from the Stream, or None at end of stream.
        recvN)
r   r   r#   r   readr   EnvironmentErrorr   r   ERRNO_RECOVERABLE)r   nr   r   r   r	   r$   p   s    zStream.readc                 C   s&   |sdS |  j |7  _ |   t|S )z
        Write `data` to the Stream. Not all data may be written right away.
        Use select to find when the stream is writeable, and call do_write()
        to flush the internal buffer.
        N)r   do_writelenr   datar   r   r	   write   s
    zStream.writec              
   C   s   zfd}t | jdr"| j| j}nt| j | j}| j|d | _| jrbt| jdkrb| 	  |W S  t
y } z|jtjvr|W Y d}~q d}~0 0 q dS )zZ
        Flushes as much pending data from the internal write buffer as possible.
        r   sendN)r   r   r-   r   r   r,   r   r   r)   closer%   r   r   r&   )r   Zwrittenr   r   r   r	   r(      s    zStream.do_writec                 C   s   t | jdkS )zL
        Returns True if the stream has data waiting to be written.
        r   )r)   r   r   r   r   r	   needs_write   s    zStream.needs_writec                 C   sL   d| _ | jsHt| jdkrHd| _t| jdr8| j  nt| j  d S )NTr   r.   )	r   r   r)   r   r   r   r.   r   r   r   r   r   r	   r.      s    zStream.closec                 C   s   dj t| j| jdS )Nz{cls}({fd}))clsr   )formattype__name__r   r   r   r   r	   __repr__   s    zStream.__repr__N)r"   )r3   
__module____qualname____doc__r   r   ZEDEADLKZEWOULDBLOCKr&   r   r   r
   r$   r,   r(   r/   r.   r4   r   r   r   r	   r   F   s   
r   c                   @   sd   e Zd ZdZdd Zdd Zdd Zdd	d
Zdd Zdd Z	dd Z
dd ZdddZdd ZdS )Demuxera8  
    Wraps a multiplexed Stream to read in data demultiplexed.

    Docker multiplexes streams together when there is no PTY attached, by
    sending an 8-byte header, followed by a chunk of data.

    The first 4 bytes of the header denote the stream from which the data came
    (i.e. 0x01 = stdout, 0x02 = stderr). Only the first byte of these initial 4
    bytes is used.

    The next 4 bytes indicate the length of the following chunk of data as an
    integer in big endian format. This much data must be consumed before the
    next 8-byte header is read.
    c                 C   s   || _ d| _dS )zA
        Initialize a new Demuxer reading from `stream`.
        r   N)streamremain)r   r9   r   r   r	   r      s    zDemuxer.__init__c                 C   s
   | j  S )zn
        Returns the fileno() of the underlying Stream.

        This is useful for select() to work.
        )r9   r   r   r   r   r	   r      s    zDemuxer.filenoc                 C   s   | j |S N)r9   r
   r    r   r   r	   r
      s    zDemuxer.set_blockingr"   c                 C   sX   |  |}|dkrdS t }t||k rP| j|t| }|sF|S || }q|S dS )a  
        Read up to `n` bytes of data from the Stream, after demuxing.

        Less than `n` bytes of data may be returned depending on the available
        payload, but the number of bytes returned will never exceed `n`.

        Because demuxing involves scanning 8-byte headers, the actual amount of
        data read from the underlying stream may be greater than `n`.
        r   N)_next_packet_sizer   binary_typer)   r9   r$   )r   r'   sizer+   nxtr   r   r	   r$      s    

zDemuxer.readc                 C   s   | j |S )z6
        Delegates the the underlying Stream.
        )r9   r,   r*   r   r   r	   r,      s    zDemuxer.writec                 C   s   t | jdr| j S dS )1
        Delegates to underlying Stream.
        r/   F)r   r9   r/   r   r   r   r	   r/      s    
zDemuxer.needs_writec                 C   s   t | jdr| j S dS )r@   r(   F)r   r9   r(   r   r   r   r	   r(   
  s    
zDemuxer.do_writec                 C   s
   | j  S )r@   )r9   r.   r   r   r   r	   r.     s    zDemuxer.closer   c                 C   s   d}| j dkr*t|| j }|  j |8  _ nvt }t|dk rd| jdt| }|sZdS || }q2|d u rpdS t|dkrtd|\}}t||}|| | _ |S )Nr      z>BxxxL)	r:   minr   r=   r)   r9   r$   structunpack)r   r'   r>   r+   r?   __actualr   r   r	   r<     s"    



zDemuxer._next_packet_sizec                 C   s   dj t| j| jdS )Nz{cls}({stream}))r0   r9   )r1   r2   r3   r9   r   r   r   r	   r4   3  s    zDemuxer.__repr__N)r"   )r   )r3   r5   r6   r7   r   r   r
   r$   r,   r/   r(   r.   r<   r4   r   r   r   r	   r8      s   	



r8   c                   @   sD   e Zd ZdZdddZdd Zdd Zdd
dZdd Zdd Z	dS )Pumpa  
    Stream pump class.

    A Pump wraps two Streams, reading from one and and writing its data into
    the other, much like a pipe but manually managed.

    This abstraction is used to facilitate piping data between the file
    descriptors associated with the tty and those associated with a container's
    allocated pty.

    Pumps are selectable based on the 'read' end of the pipe.
    Tc                 C   s"   || _ || _d| _|| _|| _dS )z
        Initialize a Pump with a Stream to read from and another to write to.

        `wait_for_output` is a flag that says that we need to wait for EOF
        on the from_stream in order to consider this pump as "done".
        FN)from_stream	to_streameofwait_for_outputpropagate_close)r   rH   rI   rK   rL   r   r   r	   r   F  s
    zPump.__init__c                 C   s
   | j  S )z
        Returns the `fileno()` of the reader end of the Pump.

        This is useful to allow Pumps to function with `select()`.
        )rH   r   r   r   r   r	   r   X  s    zPump.filenoc                 C   s   | j |S r;   )rH   r
   r    r   r   r	   r
   a  s    zPump.set_blockingr"   c              
   C   s   zJ| j |}|du s"t|dkr>d| _| jr8| j  W dS | j|W S  ty~ } z|j	t	j
krj|W Y d}~n
d}~0 0 dS )z
        Flush `n` bytes of data from the reader Stream to the writer Stream.

        Returns the number of bytes that were actually flushed. A return value
        of zero is not an error.

        If EOF has been reached, `None` is returned.
        Nr   T)rH   r$   r)   rJ   rL   rI   r.   r,   OSErrorr   ZEPIPE)r   r'   r$   r   r   r   r	   flushd  s    

z
Pump.flushc                 C   s&   | j  s| jo$t| jdo"| j  S )z
        Returns True if the read stream is done (either it's returned EOF or
        the pump doesn't have wait_for_output set), and the write
        side does not have pending bytes to send.
        r/   )rK   rJ   r   rI   r/   r   r   r   r	   is_done|  s    zPump.is_donec                 C   s   dj t| j| j| jdS )Nz){cls}(from={from_stream}, to={to_stream}))r0   rH   rI   )r1   r2   r3   rH   rI   r   r   r   r	   r4     s
    zPump.__repr__N)TT)r"   )
r3   r5   r6   r7   r   r   r
   rN   rO   r4   r   r   r   r	   rG   8  s     
	

rG   )T)r   )r   r   r   rC   r   r   r   r
   objectr   r8   rG   r   r   r   r	   <module>   s   

v|