o
    ~ vU"+                     @   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.
    )fcntlF_GETFLos
O_NONBLOCKF_SETFLbool)fdblockingold_flagnew_flag r   ./usr/lib/python3/dist-packages/dockerpty/io.pyset_blocking   s   
r   c              
   C   sp   g }zt | |||dd W S  t jy7 } ztjr|jn|d }|tjkr1g g fW  Y d}~S |d}~ww )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sixPY3errnoEINTR)read_streamswrite_streamstimeoutexception_streamsenor   r   r   r   ,   s"   
r   c                   @   sl   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   
   | j  S )z=
        Return the fileno() of the file descriptor.
        )r   filenor"   r   r   r   r%   b      
zStream.filenoc                 C   s(   t | jdr| j| dS t| j|S )NsetblockingT)hasattrr   r(   r   r"   valuer   r   r   r   i   s   zStream.set_blocking   c              
   C   sh   	 zt | jdr| j|W S t| j |W S  ty2 } z|jtj	vr(|W Y d}~nd}~ww q)zU
        Return `n` bytes of data from the Stream, or None at end of stream.
        T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   	 z3d}t | jdr| j| j}n
t| j | j}| j|d | _| jr2t| jdkr2| 	  |W S  t
yN } z|jtjvrD|W Y d}~nd}~ww q)zZ
        Flushes as much pending data from the internal write buffer as possible.
        Tr   sendN)r)   r   r7   r   r   r6   r%   r    r3   closer/   r   r   r0   )r"   writtenr   r   r   r   r2      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   )r3   r   r&   r   r   r   needs_write   s   zStream.needs_writec                 C   sV   d| _ | js't| jdkr)d| _t| jdr| j  d S t| j  d S d S d S )NTr   r8   )	r    r!   r3   r   r)   r   r8   r   r%   r&   r   r   r   r8      s   zStream.closec                 C      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,   )r?   
__module____qualname____doc__r   r   EDEADLKEWOULDBLOCKr0   r#   r%   r   r.   r6   r2   r:   r8   r@   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"   rH   r   r   r   r#      s   
zDemuxer.__init__c                 C   r$   )zn
        Returns the fileno() of the underlying Stream.

        This is useful for select() to work.
        )rH   r%   r&   r   r   r   r%         
zDemuxer.filenoc                 C      | j |S N)rH   r   r*   r   r   r   r         zDemuxer.set_blockingr,   c                 C   s^   |  |}|dkrdS t }t||k r-| j|t| }|s#|S || }t||k s|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_typer3   rH   r.   )r"   r1   sizer5   nxtr   r   r   r.      s   
zDemuxer.readc                 C   rK   )z6
        Delegates the the underlying Stream.
        )rH   r6   r4   r   r   r   r6      s   zDemuxer.writec                 C      t | jdr| j S dS )1
        Delegates to underlying Stream.
        r:   F)r)   rH   r:   r&   r   r   r   r:         
zDemuxer.needs_writec                 C   rR   )rS   r2   F)r)   rH   r2   r&   r   r   r   r2   
  rT   zDemuxer.do_writec                 C   r$   )rS   )rH   r8   r&   r   r   r   r8     r'   zDemuxer.closer   c                 C   s   d}| j dkrt|| j }|  j |8  _ |S t }t|dk r8| jdt| }|s.dS || }t|dk s |d u r>dS t|dkrVtd|\}}t||}|| | _ |S )Nr      z>BxxxL)	rI   minr   rO   r3   rH   r.   structunpack)r"   r1   rP   r5   rQ   __actualr   r   r   rN     s&   


zDemuxer._next_packet_sizec                 C   r;   )Nz{cls}({stream}))r<   rH   )r=   r>   r?   rH   r&   r   r   r   r@   3  s   zDemuxer.__repr__NrA   r   )r?   rB   rC   rD   r#   r%   r   r.   r6   r:   r2   r8   rN   r@   r   r   r   r   rG      s    	



rG   c                   @   sH   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"   r]   r^   r`   ra   r   r   r   r#   F  s
   
zPump.__init__c                 C   r$   )z
        Returns the `fileno()` of the reader end of the Pump.

        This is useful to allow Pumps to function with `select()`.
        )r]   r%   r&   r   r   r   r%   X  rJ   zPump.filenoc                 C   rK   rL   )r]   r   r*   r   r   r   r   a  rM   zPump.set_blockingr,   c              
   C   s   z%| j |}|du st|dkrd| _| jr| j  W dS | j|W S  ty@ } z|j	t	j
kr5|W Y d}~dS d}~ww )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)r]   r.   r3   r_   ra   r^   r8   r6   OSErrorr   EPIPE)r"   r1   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:   )r`   r_   r)   r^   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}))r<   r]   r^   )r=   r>   r?   r]   r^   r&   r   r   r   r@     s
   zPump.__repr__N)TTrA   )
r?   rB   rC   rD   r#   r%   r   rd   re   r@   r   r   r   r   r\   8  s    
	

r\   )Tr[   )r   r   r   rW   r   r   r   r   objectr   rG   r\   r   r   r   r   <module>   s   

v|