B
    ]bq\                 @  s@  d dl mZ d dlZd dlZd dlZd dlmZmZmZm	Z	m
Z
 ddlmZmZmZmZmZmZ ddlmZ ddlmZmZmZmZmZmZmZmZmZ ddlmZm Z  dd	l!m"Z" dd
lm#Z#m$Z$m%Z% ddddgZ&e
ee ef Z'G dd dej(Z)e)j*Z*e)j+Z+G dd dej(Z,e,j-Z-e,j.Z.e,j/Z/e,j0Z0dZ1G dd dZ2dS )    )annotationsN)	GeneratorListOptionalTypeUnion   )ConnectionClosedConnectionClosedErrorConnectionClosedOKInvalidStatePayloadTooBigProtocolError)	Extension)	OK_CLOSE_CODES	OP_BINARYOP_CLOSEOP_CONTOP_PINGOP_PONGOP_TEXTCloseFrame)RequestResponse)StreamReader)
LoggerLikeOriginSubprotocol
ConnectionSideStateSEND_EOFc               @  s   e Zd ZdZed\ZZdS )r    z6A WebSocket connection is either a server or a client.   N)__name__
__module____qualname____doc__rangeSERVERCLIENT r+   r+   4lib/python3.7/site-packages/websockets/connection.pyr    ,   s   c               @  s    e Zd ZdZed\ZZZZdS )r!   z6A WebSocket connection is in one of these four states.   N)	r$   r%   r&   r'   r(   
CONNECTINGOPENCLOSINGCLOSEDr+   r+   r+   r,   r!   6   s       c               @  s  e Zd ZdZeddfdddddd	d
dZeddddZejdddddZeddddZ	eddddZ
eddddZdddddZddddZdddd d!d"ZdIdddd d$d%ZdJdddd d&d'ZdKdd)dd*d+d,Zdddd-d.Zdddd/d0ZdLd1d)dd*d2d3Zd4dd5d6Zd7dd8d9Zddd:d;Zd<dd=d>Zd<dd?d@ZdAddBdCdDZdAddBdEdFZdddGdHZdS )Mr   a5  
    Sans-I/O implementation of a WebSocket connection.

    Args:
        side: :attr:`~Side.CLIENT` or :attr:`~Side.SERVER`.
        state: initial state of the WebSocket connection.
        max_size: maximum size of incoming messages in bytes;
            :obj:`None` to disable the limit.
        logger: logger for this connection; depending on ``side``,
            defaults to ``logging.getLogger("websockets.client")``
            or ``logging.getLogger("websockets.server")``;
            see the :doc:`logging guide <../topics/logging>` for details.

    i   Nr    r!   zOptional[int]zOptional[LoggerLike]None)sidestatemax_sizeloggerreturnc             C  s   t  | _|d kr(td|j  }|| _|tj	| _
|| _|| _|| _d | _d| _d | _g | _d | _d | _d | _d | _d | _d| _t | _g | _g | _|  | _t| j d | _d S )Nzwebsockets.F) uuidZuuid4idloggingZ	getLoggernamelowerr7   ZisEnabledForDEBUGdebugr4   r5   r6   cur_sizeexpect_continuation_frameorigin
extensionsZsubprotocol
close_rcvd
close_sentclose_rcvd_then_senthandshake_exceof_sentr   readereventswritesparseparsernext
parser_exc)selfr4   r5   r6   r7   r+   r+   r,   __init__V   s0    
	

zConnection.__init__)r8   c             C  s   | j S )zm
        WebSocket connection state.

        Defined in 4.1, 4.2, 7.1.3, and 7.1.4 of :rfc:`6455`.

        )_state)rP   r+   r+   r,   r5      s    zConnection.state)r5   r8   c             C  s    | j r| j d|j || _d S )Nz= connection is %s)r?   r7   r<   rR   )rP   r5   r+   r+   r,   r5      s    c             C  s(   | j tk	rdS | jdkrdS | jjS dS )z
        `WebSocket close code`_.

        .. _WebSocket close code:
            https://www.rfc-editor.org/rfc/rfc6455.html#section-7.1.5

        :obj:`None` if the connection isn't closed yet.

        Ni  )r5   r1   rD   code)rP   r+   r+   r,   
close_code   s
    

zConnection.close_codezOptional[str]c             C  s(   | j tk	rdS | jdkrdS | jjS dS )z
        `WebSocket close reason`_.

        .. _WebSocket close reason:
            https://www.rfc-editor.org/rfc/rfc6455.html#section-7.1.6

        :obj:`None` if the connection isn't closed yet.

        N )r5   r1   rD   reason)rP   r+   r+   r,   close_reason   s
    

zConnection.close_reasonr	   c             C  sf   | j tkstd| jdk	rD| jdk	rD| jjtkrD| jjtkrDt}nt}|| j| j| j	}| j
|_|S )a  
        Exception to raise when trying to interact with a closed connection.

        Don't raise this exception while the connection :attr:`state`
        is :attr:`~websockets.connection.State.CLOSING`; wait until
        it's :attr:`~websockets.connection.State.CLOSED`.

        Indeed, the exception includes the close code and reason, which are
        known only once the connection is closed.

        Raises:
            AssertionError: if the connection isn't closed yet.

        zconnection isn't closed yetN)r5   r1   AssertionErrorrD   rE   rS   r   r   r
   rF   rO   	__cause__)rP   exc_typeexcr+   r+   r,   	close_exc   s    

zConnection.close_excbytes)datar8   c             C  s   | j | t| j dS )aH  
        Receive data from the network.

        After calling this method:

        - You must call :meth:`data_to_send` and send this data to the network.
        - You should call :meth:`events_received` and process resulting events.

        Raises:
            EOFError: if :meth:`receive_eof` was called earlier.

        N)rI   Z	feed_datarN   rM   )rP   r^   r+   r+   r,   receive_data   s    zConnection.receive_datac             C  s   | j   t| j dS )aw  
        Receive the end of the data stream from the network.

        After calling this method:

        - You must call :meth:`data_to_send` and send this data to the network.
        - You aren't expected to call :meth:`events_received`; it won't return
          any new events.

        Raises:
            EOFError: if :meth:`receive_eof` was called earlier.

        N)rI   Zfeed_eofrN   rM   )rP   r+   r+   r,   receive_eof  s    
zConnection.receive_eofbool)r^   finr8   c             C  s,   | j std| | _ | tt|| dS )a  
        Send a `Continuation frame`_.

        .. _Continuation frame:
            https://datatracker.ietf.org/doc/html/rfc6455#section-5.6

        Parameters:
            data: payload containing the same kind of data
                as the initial frame.
            fin: FIN bit; set it to :obj:`True` if this is the last frame
                of a fragmented message and to :obj:`False` otherwise.

        Raises:
            ProtocolError: if a fragmented message isn't in progress.

        zunexpected continuation frameN)rA   r   
send_framer   r   )rP   r^   rb   r+   r+   r,   send_continuation  s    zConnection.send_continuationTc             C  s,   | j rtd| | _ | tt|| dS )a  
        Send a `Text frame`_.

        .. _Text frame:
            https://datatracker.ietf.org/doc/html/rfc6455#section-5.6

        Parameters:
            data: payload containing text encoded with UTF-8.
            fin: FIN bit; set it to :obj:`False` if this is the first frame of
                a fragmented message.

        Raises:
            ProtocolError: if a fragmented message is in progress.

        zexpected a continuation frameN)rA   r   rc   r   r   )rP   r^   rb   r+   r+   r,   	send_text,  s    zConnection.send_textc             C  s,   | j rtd| | _ | tt|| dS )a  
        Send a `Binary frame`_.

        .. _Binary frame:
            https://datatracker.ietf.org/doc/html/rfc6455#section-5.6

        Parameters:
            data: payload containing arbitrary binary data.
            fin: FIN bit; set it to :obj:`False` if this is the first frame of
                a fragmented message.

        Raises:
            ProtocolError: if a fragmented message is in progress.

        zexpected a continuation frameN)rA   r   rc   r   r   )rP   r^   rb   r+   r+   r,   send_binaryA  s    zConnection.send_binaryrU   str)rS   rV   r8   c             C  sh   | j rtd|dkr6|dkr&tdtdd}d}nt||}| }| tt| || _t| _	dS )a  
        Send a `Close frame`_.

        .. _Close frame:
            https://datatracker.ietf.org/doc/html/rfc6455#section-5.5.1

        Parameters:
            code: close code.
            reason: close reason.

        Raises:
            ProtocolError: if a fragmented message is being sent, if the code
                isn't valid, or if a reason is provided without a code

        zexpected a continuation frameNrU   z#cannot send a reason without a codei  r2   )
rA   r   r   	serializerc   r   r   rE   r0   r5   )rP   rS   rV   closer^   r+   r+   r,   
send_closeV  s    

zConnection.send_closec             C  s   |  tt| dS )z
        Send a `Ping frame`_.

        .. _Ping frame:
            https://datatracker.ietf.org/doc/html/rfc6455#section-5.5.2

        Parameters:
            data: payload containing arbitrary binary data.

        N)rc   r   r   )rP   r^   r+   r+   r,   	send_pingv  s    zConnection.send_pingc             C  s   |  tt| dS )z
        Send a `Pong frame`_.

        .. _Pong frame:
            https://datatracker.ietf.org/doc/html/rfc6455#section-5.5.3

        Parameters:
            data: payload containing arbitrary binary data.

        N)rc   r   r   )rP   r^   r+   r+   r,   	send_pong  s    zConnection.send_pongintc             C  sp   | j tkr@|dkr@t||}| }| tt| || _t| _ | j	t
krX| jsX|   |  | _t| j dS )a?  
        `Fail the WebSocket connection`_.

        .. _Fail the WebSocket connection:
            https://datatracker.ietf.org/doc/html/rfc6455#section-7.1.7

        Parameters:
            code: close code
            reason: close reason

        Raises:
            ProtocolError: if the code isn't valid.
        i  N)r5   r/   r   rh   rc   r   r   rE   r0   r4   r)   rH   send_eofdiscardrM   rN   )rP   rS   rV   ri   r^   r+   r+   r,   fail  s    


zConnection.failzList[Event]c             C  s   | j g  }| _ |S )a7  
        Fetch events generated from data received from the network.

        Call this method immediately after any of the ``receive_*()`` methods.

        Process resulting events, likely by passing them to the application.

        Returns:
            List[Event]: Events read from the connection.
        )rJ   )rP   rJ   r+   r+   r,   events_received  s    zConnection.events_receivedzList[bytes]c             C  s   | j g  }| _ |S )a  
        Obtain data to send to the network.

        Call this method immediately after any of the ``receive_*()``,
        ``send_*()``, or :meth:`fail` methods.

        Write resulting data to the connection.

        The empty bytestring :data:`~websockets.connection.SEND_EOF` signals
        the end of the data stream. When you receive it, half-close the TCP
        connection.

        Returns:
            List[bytes]: Data to write to the connection.

        )rK   )rP   rK   r+   r+   r,   data_to_send  s    zConnection.data_to_sendc             C  s   | j tkp| jdk	S )a  
        Tell if the TCP connection is expected to close soon.

        Call this method immediately after any of the ``receive_*()`` or
        :meth:`fail` methods.

        If it returns :obj:`True`, schedule closing the TCP connection after a
        short timeout if the other side hasn't already closed it.

        Returns:
            bool: Whether the TCP connection is expected to close soon.

        N)r5   r0   rG   )rP   r+   r+   r,   close_expected  s    zConnection.close_expectedzGenerator[(None, None, None)]c          
   c  s  yx| j  E dH r.| jr&| jd td| jdkr>d}n| jdkrP| j}n| j| j }tj| j j	| j
tk|| jdE dH }| jr| jd| | | qW W n, tk
r } z| dt| || _W dd}~X Y n tk
r } z| dt| || _W dd}~X Y n tk
rX } z$| d|j d	|j  || _W dd}~X Y n| tk
r } z| d
t| || _W dd}~X Y nD tk
r } z$| jjddd | d || _W dd}~X Y nX dV  tddS )z
        Parse incoming data into frames.

        :meth:`receive_data` and :meth:`receive_eof` run this generator
        coroutine until it needs more data or reaches EOF.

        Nz< EOFzunexpected end of stream)maskr6   rC   z< %si  i  i  z at position i  zparser failedT)exc_infoi  z"parse() shouldn't step after error)rI   at_eofr?   r7   EOFErrorr6   r@   r   rL   Z
read_exactr4   r)   rC   
recv_framer   rp   rg   rO   UnicodeDecodeErrorrV   startr   	ExceptionerrorrX   )rP   r6   framer[   r+   r+   r,   rL     sJ    


zConnection.parsec             c  sp   | j tk| jkstx| j E dH s2| j  qW | jrF| jd | j t	krX| 
  t| _dV  tddS )z
        Discard incoming data.

        This coroutine replaces :meth:`parse`:

        - after receiving a close frame, during a normal closure (1.4);
        - after sending a close frame, during an abnormal closure (7.1.7).

        Nz< EOFz"discard() shouldn't step after EOF)r4   r)   rH   rX   rI   rv   ro   r?   r7   r*   rn   r1   r5   )rP   r+   r+   r,   ro   =  s    
zConnection.discardr   )r}   r8   c             C  sz  |j tks|j tkrD| jdk	r&td|jr4d| _nt|j| _n&|j tkr| jdkr`td|jrnd| _n|  jt|j7  _n|j t	krt
t|j}| | n|j tkrn|j tkrXt|j| _| jtkr| jdk	std| _| jdk	rtd| jtkr.| t
t|j | j| _d| _t| _| jtkrB|   |  | _t| j ntd|j d| j| dS )	z-
        Process an incoming frame.

        Nzexpected a continuation framezunexpected continuation frameFzincomplete fragmented messageTzunexpected opcode: Z02x)Zopcoder   r   r@   r   rb   lenr^   r   r   r   r   rc   r   r   rL   rD   r5   r0   rE   rX   rF   r/   r4   r)   rn   ro   rM   rN   rJ   append)rP   r}   Z
pong_framer+   r+   r,   rx   [  sF    







zConnection.recv_framec             C  sT   | j tk	rtd| j j d| jr2| jd| | j|j| j	t
k| jd d S )Nz#cannot write to a WebSocket in the z statez> %s)rt   rC   )r5   r/   r   r<   r?   r7   rK   r   rh   r4   r*   rC   )rP   r}   r+   r+   r,   rc     s    
zConnection.send_framec             C  s2   | j r
td| _ | jr"| jd | jt d S )NTz> EOF)rH   rX   r?   r7   rK   r   r"   )rP   r+   r+   r,   rn     s
    
zConnection.send_eof)T)T)NrU   )rU   )r$   r%   r&   r'   r/   rQ   propertyr5   setterrT   rW   r\   r_   r`   rd   re   rf   rj   rk   rl   rp   rq   rr   rs   rL   ro   rx   rc   rn   r+   r+   r+   r,   r   F   s4   >
& +DR)3Z
__future__r   enumr;   r9   typingr   r   r   r   r   
exceptionsr	   r
   r   r   r   r   rC   r   Zframesr   r   r   r   r   r   r   r   r   Zhttp11r   r   Zstreamsr   r   r   r   __all__ZEventIntEnumr    r)   r*   r!   r.   r/   r0   r1   r"   r   r+   r+   r+   r,   <module>   s2    ,