U
    MfH                     @  s  d dl mZ 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lZd dl	Z	d dl
mZ d dlmZmZmZmZmZ d dlmZ ddlmZ ddlmZ dd	lmZ dd
lmZ ddlmZmZ ddlmZm Z m!Z! ddl"m#Z# ddlm$Z$m%Z%m&Z& ddl'm(Z( ddl)m*Z* ddddgZ+G dd de(Z,G dd dZ-d2ddddddddddeddddddddddd d!d"dd#d$d%d&d'd(ddd)d)dd*d+dd,d-dZ.d3d.dd/dd0d1dZ/dS )4    )annotationsN)TracebackType)AnyCallableOptionalSequenceType)	CloseCode   )ServerExtensionFactory) enable_server_permessage_deflate)validate_subprotocols)
USER_AGENT)RequestResponse)
CONNECTINGOPENEvent)ServerProtocol)
LoggerLikeOriginSubprotocol   )
Connection)Deadlineserve
unix_serveServerConnectionWebSocketServerc                      sx   e Zd ZdZddddddd fd	d
ZddedfddddddddZddd fddZdd fddZ  Z	S )r   a  
    Threaded implementation of a WebSocket server connection.

    :class:`ServerConnection` provides :meth:`recv` and :meth:`send` methods for
    receiving and sending messages.

    It supports iteration to receive messages::

        for message in websocket:
            process(message)

    The iterator exits normally when the connection is closed with close code
    1000 (OK) or 1001 (going away) or without a close code. It raises a
    :exc:`~websockets.exceptions.ConnectionClosedError` when the connection is
    closed with any other code.

    Args:
        socket: Socket connected to a WebSocket client.
        protocol: Sans-I/O connection.
        close_timeout: Timeout for closing the connection in seconds.

    
   close_timeoutsocket.socketr   Optional[float]None)socketprotocolr!   returnc                  s$   |  t  | _t j|||d d S )Nr    )	threadingr   request_rcvdsuper__init__)selfr%   r&   r!   	__class__ :/tmp/pip-unpacked-wheel-yzabpfcc/websockets/sync/server.pyr+   7   s    
zServerConnection.__init__NCOptional[Callable[[ServerConnection, Request], Optional[Response]]]MOptional[Callable[[ServerConnection, Request, Response], Optional[Response]]]Optional[str])process_requestprocess_responseserver_headertimeoutr'   c                 C  s  | j |s&|   | j  td| jdkrJ|   | j  td| jt	d2 d| _
|dk	rz|| | j| _
W nN tk
r } z0|| j_| jjddd | jtjjd| _
W 5 d}~X Y nX | j
dkr| j| j| _
|dk	r|| j
jd	< |dk	rxz|| | j| j
}W nP tk
rf } z0|| j_| jjddd | jtjjd| _
W 5 d}~X Y nX |dk	rx|| _
| j| j
 W 5 Q R X | jjtk	r| j| j |   | j  | jjdk	r| jjdS )
z1
        Perform the opening handshake.

        ztimed out during handshakeNz"connection closed during handshake)Zexpected_statezopening handshake failedTexc_infozLFailed to open a WebSocket connection.
See server log for more information.
Server)r)   waitZclose_socketZrecv_events_threadjoinTimeoutErrorrequestConnectionErrorZsend_contextr   response	Exceptionr&   Zhandshake_excloggererrorrejecthttp
HTTPStatusINTERNAL_SERVER_ERRORacceptheadersZsend_responsestater   r!   )r,   r4   r5   r6   r7   excr@   r/   r/   r0   	handshakeF   sV    






zServerConnection.handshaker   )eventr'   c                   s:   | j dkr*t|tst|| _ | j  nt | dS )z.
        Process one incoming event.

        N)r>   
isinstancer   AssertionErrorr)   setr*   process_event)r,   rM   r-   r/   r0   rQ      s
    
zServerConnection.process_eventr'   c                   s    zt   W 5 | j   X dS )zI
        Read incoming data from the socket and process events.

        N)r)   rP   r*   recv_eventsr,   r-   r/   r0   rS      s    zServerConnection.recv_events)
__name__
__module____qualname____doc__r+   r   rL   rQ   rS   __classcell__r/   r/   r-   r0   r      s   Qc                   @  sp   e Zd ZdZdddddddZd	d
ddZd	d
ddZdd
ddZd d
ddZdddd	dddZ	dS )r   a  
    WebSocket server returned by :func:`serve`.

    This class mirrors the API of :class:`~socketserver.BaseServer`, notably the
    :meth:`~socketserver.BaseServer.serve_forever` and
    :meth:`~socketserver.BaseServer.shutdown` methods, as well as the context
    manager protocol.

    Args:
        socket: Server socket listening for new connections.
        handler: Handler for one connection. Receives the socket and address
            returned by :meth:`~socket.socket.accept`.
        logger: Logger for this server.

    Nr"   z$Callable[[socket.socket, Any], None]Optional[LoggerLike])r%   handlerrB   c                 C  sB   || _ || _|d krtd}|| _tjdkr>t \| _	| _
d S )Nzwebsockets.serverwin32)r%   r[   logging	getLoggerrB   sysplatformospipeshutdown_watchershutdown_notifier)r,   r%   r[   rB   r/   r/   r0   r+      s    

zWebSocketServer.__init__r$   rR   c                 C  s   t  }|| jt j tjdkr2|| jt j |  z| j	 \}}W n t
k
rd   Y qY nX tj| j||fd}|  q2dS )a  
        See :meth:`socketserver.BaseServer.serve_forever`.

        This method doesn't return. Calling :meth:`shutdown` from another thread
        stops the server.

        Typical use::

            with serve(...) as server:
                server.serve_forever()

        r\   )targetargsN)	selectorsDefaultSelectorregisterr%   
EVENT_READr_   r`   rc   selectrH   OSErrorr(   Threadr[   start)r,   Zpollersockaddrthreadr/   r/   r0   serve_forever   s    

zWebSocketServer.serve_foreverc                 C  s&   | j   tjdkr"t| jd dS )z@
        See :meth:`socketserver.BaseServer.shutdown`.

        r\      xN)r%   closer_   r`   ra   writerd   rT   r/   r/   r0   shutdown   s    

zWebSocketServer.shutdownintc                 C  s
   | j  S )z>
        See :meth:`socketserver.BaseServer.fileno`.

        )r%   filenorT   r/   r/   r0   rx      s    zWebSocketServer.filenoc                 C  s   | S Nr/   rT   r/   r/   r0   	__enter__   s    zWebSocketServer.__enter__zOptional[Type[BaseException]]zOptional[BaseException]zOptional[TracebackType])exc_type	exc_value	tracebackr'   c                 C  s   |    d S ry   )rv   )r,   r{   r|   r}   r/   r/   r0   __exit__   s    zWebSocketServer.__exit__)N)
rU   rV   rW   rX   r+   rr   rv   rx   rz   r~   r/   r/   r/   r0   r      s    	Fdeflater   i   )ro   ssl_contextunixpathorigins
extensionssubprotocolsselect_subprotocolr4   r5   r6   compressionopen_timeoutr!   max_sizerB   create_connectionz"Callable[[ServerConnection], None]r3   zOptional[int]zOptional[socket.socket]zOptional[ssl.SSLContext]boolz$Optional[Sequence[Optional[Origin]]]z*Optional[Sequence[ServerExtensionFactory]]zOptional[Sequence[Subprotocol]]zTOptional[Callable[[ServerConnection, Sequence[Subprotocol]], Optional[Subprotocol]]]r1   r2   r#   rZ   z Optional[Type[ServerConnection]])r[   hostportro   r   r   r   r   r   r   r   r4   r5   r6   r   r   r!   r   rB   r   r'   c                  s   dk	rt  |dkr"tn|dk	r8td| dkrDt|dkrrr|dkr`tdtj|tjd}qt||f}n|dk	rtddk	rj|ddd	}d
ddd 	
fdd}t	||S )aH  
    Create a WebSocket server listening on ``host`` and ``port``.

    Whenever a client connects, the server creates a :class:`ServerConnection`,
    performs the opening handshake, and delegates to the ``handler``.

    The handler receives a :class:`ServerConnection` instance, which you can use
    to send and receive messages.

    Once the handler completes, either normally or with an exception, the server
    performs the closing handshake and closes the connection.

    :class:`WebSocketServer` mirrors the API of
    :class:`~socketserver.BaseServer`. Treat it as a context manager to ensure
    that it will be closed and call the :meth:`~WebSocketServer.serve_forever`
    method to serve requests::

        def handler(websocket):
            ...

        with websockets.sync.server.serve(handler, ...) as server:
            server.serve_forever()

    Args:
        handler: Connection handler. It receives the WebSocket connection,
            which is a :class:`ServerConnection`, in argument.
        host: Network interfaces the server binds to.
            See :func:`~socket.create_server` for details.
        port: TCP port the server listens on.
            See :func:`~socket.create_server` for details.
        sock: Preexisting TCP socket. ``sock`` replaces ``host`` and ``port``.
            You may call :func:`socket.create_server` to create a suitable TCP
            socket.
        ssl_context: Configuration for enabling TLS on the connection.
        origins: Acceptable values of the ``Origin`` header, for defending
            against Cross-Site WebSocket Hijacking attacks. Include :obj:`None`
            in the list if the lack of an origin is acceptable.
        extensions: List of supported extensions, in order in which they
            should be negotiated and run.
        subprotocols: List of supported subprotocols, in order of decreasing
            preference.
        select_subprotocol: Callback for selecting a subprotocol among
            those supported by the client and the server. It receives a
            :class:`ServerConnection` (not a
            :class:`~websockets.server.ServerProtocol`!) instance and a list of
            subprotocols offered by the client. Other than the first argument,
            it has the same behavior as the
            :meth:`ServerProtocol.select_subprotocol
            <websockets.server.ServerProtocol.select_subprotocol>` method.
        process_request: Intercept the request during the opening handshake.
            Return an HTTP response to force the response or :obj:`None` to
            continue normally. When you force an HTTP 101 Continue response,
            the handshake is successful. Else, the connection is aborted.
        process_response: Intercept the response during the opening handshake.
            Return an HTTP response to force the response or :obj:`None` to
            continue normally. When you force an HTTP 101 Continue response,
            the handshake is successful. Else, the connection is aborted.
        server_header: Value of  the ``Server`` response header.
            It defaults to ``"Python/x.y.z websockets/X.Y"``. Setting it to
            :obj:`None` removes the header.
        compression: The "permessage-deflate" extension is enabled by default.
            Set ``compression`` to :obj:`None` to disable it. See the
            :doc:`compression guide <../../topics/compression>` for details.
        open_timeout: Timeout for opening connections in seconds.
            :obj:`None` disables the timeout.
        close_timeout: Timeout for closing connections in seconds.
            :obj:`None` disables the timeout.
        max_size: Maximum size of incoming messages in bytes.
            :obj:`None` disables the limit.
        logger: Logger for this server.
            It defaults to ``logging.getLogger("websockets.server")``. See the
            :doc:`logging guide <../../topics/logging>` for details.
        create_connection: Factory for the :class:`ServerConnection` managing
            the connection. Set it to a wrapper or a subclass to customize
            connection handling.
    Nr   zunsupported compression: zmissing path argument)familyz(path and sock arguments are incompatibleTF)server_sidedo_handshake_on_connectr"   r   r$   )ro   rp   r'   c              	     s.  t }zs | tjtjd d k	rX| |  t| tj	sFt
|   | d  d }d k	r|dddd fdd}t|td}d k	st
| |d	  	
|  W n tk
r   |   Y d S X z  W n2 tk
r    |jjd
dd  tj Y n
X    d S )NTr   zSequence[Subprotocol]zOptional[Subprotocol])r&   r   r'   c                   s$   d k	st |  jkst  |S ry   )rO   r&   )r&   r   )
connectionr   r/   r0   protocol_select_subprotocol  s    z@serve.<locals>.conn_handler.<locals>.protocol_select_subprotocol)r   r   r   r   rJ   r   rB   r    zconnection handler failedr8   )r   
setsockoptr%   IPPROTO_TCPTCP_NODELAY
settimeoutr7   rN   ssl	SSLSocketrO   do_handshaker   r   rL   rA   rt   rB   rC   r	   INTERNAL_ERROR)ro   rp   deadliner   r&   r!   r   r   r[   rB   r   r   r   r4   r5   r   r6   r   r   r   )r   r0   conn_handler  sV    
	zserve.<locals>.conn_handler)
r   r   
ValueErrorr   	TypeErrorr%   create_serverAF_UNIXwrap_socketr   )r[   r   r   ro   r   r   r   r   r   r   r   r4   r5   r6   r   r   r!   r   rB   r   r   r/   r   r0   r   	  s0    {
	2Tz!Callable[[ServerConnection], Any]r   )r[   r   kwargsr'   c                 K  s   t | f|dd|S )a  
    Create a WebSocket server listening on a Unix socket.

    This function is identical to :func:`serve`, except the ``host`` and
    ``port`` arguments are replaced by ``path``. It's only available on Unix.

    It's useful for deploying a server behind a reverse proxy such as nginx.

    Args:
        handler: Connection handler. It receives the WebSocket connection,
            which is a :class:`ServerConnection`, in argument.
        path: File system path to the Unix socket.

    T)r   r   )r   )r[   r   r   r/   r/   r0   r     s    )NN)N)0
__future__r   rE   r]   ra   rg   r%   r   r_   r(   typesr   typingr   r   r   r   r   Zwebsockets.framesr	   Zextensions.baser   Zextensions.permessage_deflater   rI   r   r   Zhttp11r   r   r&   r   r   r   serverr   r   r   r   r   r   utilsr   __all__r   r   r   r   r/   r/   r/   r0   <module>   sb    Z  : y 