U
    ~ 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.
    )fcntlZF_GETFLos
O_NONBLOCKZF_SETFLbool)fdZblockingZold_flagZnew_flag r   ./usr/lib/python3/dist-packages/dockerpty/io.pyset_blocking   s    
r	   c              
   C   sz   g }zt | |||dd W S  t jk
rt } z6tjr>|jn|d }|tjkr`g g f W Y 
S |W 5 d}~X Y nX 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_streamsZtimeoutZexception_streamseZ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   sh   z.t | jdr| j|W S t| j |W S  tk
r` } z|jtj	krP|W 5 d}~X Y q X 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
k
r } z|jtjkr|W 5 d}~X Y q X 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   )r0   
__module____qualname____doc__r   r   ZEDEADLKZEWOULDBLOCKr#   r   r   r	   r!   r)   r%   r,   r+   r1   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   r6   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.
        )r6   r   r   r   r   r   r      s    zDemuxer.filenoc                 C   s   | j |S N)r6   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&   r6   r!   )r   r$   sizer(   nxtr   r   r   r!      s    

zDemuxer.readc                 C   s   | j |S )z6
        Delegates the the underlying Stream.
        )r6   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   r6   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   r6   r%   r   r   r   r   r%   
  s    
zDemuxer.do_writec                 C   s
   | j  S )r=   )r6   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 krpdS t|dkrtd|\}}t||}|| | _ |S )Nr      z>BxxxL)	r7   minr   r:   r&   r6   r!   structZunpack)r   r$   r;   r(   r<   __Zactualr   r   r   r9     s"    



zDemuxer._next_packet_sizec                 C   s   dj t| j| jdS )Nz{cls}({stream}))r-   r6   )r.   r/   r0   r6   r   r   r   r   r1   3  s    zDemuxer.__repr__N)r   )r   )r0   r2   r3   r4   r   r   r	   r!   r)   r,   r%   r+   r9   r1   r   r   r   r   r5      s   	



r5   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   rC   rD   rF   rG   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()`.
        )rC   r   r   r   r   r   r   X  s    zPump.filenoc                 C   s   | j |S r8   )rC   r	   r   r   r   r   r	   a  s    zPump.set_blockingr   c              
   C   s   zJ| j |}|dks"t|dkr>d| _| jr8| j  W dS | j|W S  tk
r| } z|j	t	j
krl|W 5 d}~X Y nX 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)rC   r!   r&   rE   rG   rD   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,   )rF   rE   r   rD   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-   rC   rD   )r.   r/   r0   rC   rD   r   r   r   r   r1     s
    zPump.__repr__N)TT)r   )
r0   r2   r3   r4   r   r   r	   rI   rJ   r1   r   r   r   r   rB   8  s     
	

rB   )T)r   )r   r   r   r@   r   r   r   r	   objectr   r5   rB   r   r   r   r   <module>   s   

v|