U
    /eA                     @  sH  d Z ddlmZ ddlZeeZddl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 dd	l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l!m"Z" ddl#m$Z$m%Z%m&Z&m'Z'm(Z(m)Z)m*Z* ddl+m,Z, er,ddl-m.Z. ddl/m0Z0 ddl1m2Z2 ddl3m4Z4 ddl5m6Z6 dZ7G dd dZ8e"  dS )z Implements a very low level facility for communicating with a Bokeh
Server.

Users will always want to use :class:`~bokeh.client.session.ClientSession`
instead for standard usage.

    )annotationsN)TYPE_CHECKINGAnyCallableDictList)HTTPClientErrorHTTPRequest)IOLoop)WebSocketErrorwebsocket_connect   )ID)Protocol)MessageErrorProtocolErrorValidationError)Receiver)format_url_query_arguments)fixup_windows_event_loop_policy   )CONNECTED_AFTER_ACKCONNECTED_BEFORE_ACKDISCONNECTEDNOT_YET_CONNECTEDWAITING_FOR_REPLYErrorReasonState) WebSocketClientConnectionWrapper)Document)DocumentChangedEvent)Message)
ServerInfo)ClientSession)ClientConnectionc                   @  s  e Zd ZU dZded< ded< ded< d[d
ddddddddZeddddZeddddZe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$Zd\ddd&d'd(Zddd)d*Zddd+d,Zd-dd.d/d0Zd-d1d.d2d3Zd4dd5d6Zd1dd7d8d9Zddd:d;Zddd<d=Zd>dd?d@dAZdddBdCZdDddEdFZd1dDd7dGdHZdIdJddKdLdMZd4ddNdOZdddPdQZdddRdSdTZdUddVdWdXZdddYdZZ dS )]r$   zR A low-level class used to connect to a Bokeh server.

    .. autoclasstoc::

    r   _stater
   _loopzCallable[[], bool] | None_until_predicateN  @r#   strzIOLoop | NonezDict[str, str] | NoneintNone)sessionwebsocket_urlio_loop	argumentsmax_message_sizereturnc                 C  s^   || _ || _|| _|| _t | _t| j| _d| _t	 | _
|dk	rF|nt | _d| _d| _dS )z6 Opens a websocket connection to the server.

        N)_url_session
_arguments_max_message_sizer   	_protocolr   	_receiver_socketr   r%   r
   r&   r'   _server_info)selfr,   r-   r.   r/   r0    r;   ;/tmp/pip-unpacked-wheel-f5fndrjf/bokeh/client/connection.py__init__]   s    zClientConnection.__init__boolr1   c                 C  s   t | jtS )zg Whether we've connected the Websocket and have exchanged initial
        handshake messages.

        )
isinstancer%   r   r:   r;   r;   r<   	connectedr   s    zClientConnection.connectedc                 C  s   | j S )z2 The Tornado ``IOLoop`` this connection is using. )r&   rA   r;   r;   r<   r.   z   s    zClientConnection.io_loopc                 C  s   | j S )z1 The URL of the websocket this Connection is to. )r2   rA   r;   r;   r<   url   s    zClientConnection.urlzErrorReason | Nonec                 C  s   t | jtsdS | jjS )zX The reason of the connection loss encoded as a ``DISCONNECTED.ErrorReason`` enum value N)r@   r%   r   error_reasonrA   r;   r;   r<   rD      s    zClientConnection.error_reasonz
int | Nonec                 C  s   t | jtsdS | jjS )zv If there was an error that caused a disconnect, this property holds
        the error code. None otherwise.

        r   )r@   r%   r   
error_coderA   r;   r;   r<   rE      s    zClientConnection.error_codec                 C  s   t | jtsdS | jjS )z If there was an error that caused a disconnect, this property holds
        the error detail. Empty string otherwise.

         )r@   r%   r   error_detailrA   r;   r;   r<   rG      s    zClientConnection.error_detailc                   s    dd fdd}  | d S )Nr>   r?   c                     s   t  jtpt  jtS N)r@   r%   r   r   r;   rA   r;   r<   connected_or_closed   s    z5ClientConnection.connect.<locals>.connected_or_closed)_loop_until)r:   rI   r;   rA   r<   connect   s    zClientConnection.connectclosed)whyr1   c                 C  s   | j dk	r| j d| dS )z* Close the Websocket connection.

        Ni  )r8   close)r:   rM   r;   r;   r<   rN      s    
zClientConnection.closec                 C  s   |    dS )a   Force a round-trip request/reply to the server, sometimes needed to
        avoid race conditions. Mostly useful for testing.

        Outside of test suites, this method hurts performance and should not be
        needed.

        Returns:
           None

        N)_send_request_server_inforA   r;   r;   r<   force_roundtrip   s    z ClientConnection.force_roundtripc                   s>   t  jtr   t  _ndd fdd} | dS )a6   Execute a blocking loop that runs and executes event callbacks
        until the connection is closed (e.g. by hitting Ctrl-C).

        While this method can be used to run Bokeh application code "outside"
        the Bokeh server, this practice is HIGHLY DISCOURAGED for any real
        use case.

        r>   r?   c                     s   t  jtS rH   )r@   r%   r   r;   rA   r;   r<   rL      s    z2ClientConnection.loop_until_closed.<locals>.closedN)r@   r%   r   _tell_session_about_disconnectr   rJ   )r:   rL   r;   rA   r<   loop_until_closed   s
    	
z"ClientConnection.loop_until_closedr   )documentr1   c                 C  sX   | j d}| |}|dkr(tdn,|jd dkrJtd|jd  n
|| dS )z Pull a document from the server, overwriting the passed-in document

        Args:
            document : (Document)
              The document to overwrite with server content.

        Returns:
            None

        zPULL-DOC-REQNConnection to server was lostmsgtypeERRORzFailed to pull document: text)r6   create_send_message_wait_for_replyRuntimeErrorheadercontentZpush_to_documentr:   rS   msgreplyr;   r;   r<   pull_doc   s    

zClientConnection.pull_docMessage[Any]c                 C  sT   | j d|}| |}|dkr*tdn&|jd dkrLtd|jd  n|S dS )z Push a document to the server, overwriting any existing server-side doc.

        Args:
            document : (Document)
                A Document to push to the server

        Returns:
            The server reply

        zPUSH-DOCNrT   rU   rV   zFailed to push document: rW   )r6   rX   rY   rZ   r[   r\   r]   r;   r;   r<   push_doc   s    

zClientConnection.push_docr"   c                 C  s   | j dkr|  | _ | j S )zq Ask for information about the server.

        Returns:
            A dictionary of server attributes.

        N)r9   rO   rA   r;   r;   r<   request_server_info   s    

z$ClientConnection.request_server_info)messager1   c              
     s|   | j d krtd| n`z$|| j I d H }td|| W n: tk
rv } ztd| | jdd W 5 d }~X Y nX d S )Nz-We're disconnected, so not sending message %rzSent %r [%d bytes]z#Error sending message to server: %rzreceived error while sendingrM   )r8   loginfosenddebugr   rN   )r:   rd   senter;   r;   r<   send_message  s    
zClientConnection.send_messagec              
     s   t | j| j}t|}z,t|d| jjg| jdI d H }t|| _	W nr t
k
r } z(| ttj|j|jI d H  W Y d S d }~X Y n. tk
r } ztd| W 5 d }~X Y nX | j	d kr| ttjd dI d H  n| t I d H  d S )NZbokeh)Zsubprotocolsr0   zFailed to connect to server: %rzSocket invalid.)r   r2   r4   r	   r   r3   tokenr5   r   r8   r   _transition_to_disconnectedr   r   
HTTP_ERRORcoderd   	Exceptionrf   rg   ZNETWORK_ERROR_transitionr   )r:   Zformatted_urlrequestsocketrk   r;   r;   r<   _connect_async#  s    
zClientConnection._connect_asyncc                   sr   |   I d H }|d kr2| ttjddI d H  n<|jdkrTtd | j	| ntd| | 
 I d H  d S )N  Internal server error.	PATCH-DOCz"Got PATCH-DOC, applying to sessionzIgnoring %r)_pop_messagern   r   r   ro   rU   rf   ri   r3   Z_handle_patch_nextr:   rd   r;   r;   r<   _handle_messages4  s    

z!ClientConnection._handle_messageszCallable[[], bool])	predicater1   c                 C  sF   || _ z| j| j | j  W n tk
r@   | d Y nX d S )Nzuser interruption)r'   r&   add_callbackrz   startKeyboardInterruptrN   )r:   r}   r;   r;   r<   rJ   A  s    zClientConnection._loop_untilc                   sh   | j d k	r>|   r>td| jjj| j j d | _ | j  d S td| jjj  | j| I d H  d S )Nz4Stopping client loop in state %s due to True from %szRunning state )	r'   rf   ri   r%   	__class____name__r&   stoprunrA   r;   r;   r<   rz   L  s     
zClientConnection._nextzMessage[Any] | Nonec              
     s   | j d krd S d }z| j  I d H }W n. tk
rT } ztd| W 5 d }~X Y nX |d krltd d S z2| j|I d H }|d k	rtd|  |W S W q  tt	t
fk
r } z tjd|dd | jdd W 5 d }~X Y q X q d S )	NzError reading from socket %rzConnection closed by serverzReceived message %rz%rT)exc_infoz!error parsing message from serverre   )r8   Zread_messagerq   rf   ri   rg   r7   consumer   r   r   errorrN   )r:   fragmentrk   rd   r;   r;   r<   ry   W  s$    


zClientConnection._pop_messagec                   s   t |jd  _g dddd fdd} j|| dd	 fd
d} | dd	 fdd} | jS )Nmsgidra   z
List[None]r+   )rd   send_resultr1   c                   s     | I d H }|| d S rH   )rl   append)rd   r   resultrA   r;   r<   handle_messagev  s    zEClientConnection._send_message_wait_for_reply.<locals>.handle_messager>   r?   c                     s   t dkp jkS )Nr   )lenr%   r;   r:   r   waiterr;   r<    have_send_result_or_disconnected{  s    zWClientConnection._send_message_wait_for_reply.<locals>.have_send_result_or_disconnectedc                     s    j kpjd k	S rH   )r%   r_   r;   )r:   r   r;   r<   have_reply_or_disconnected  s    zQClientConnection._send_message_wait_for_reply.<locals>.have_reply_or_disconnected)r   r[   r%   r&   r~   rJ   r_   )r:   rd   r   r   r   r;   r   r<   rY   q  s    

z-ClientConnection._send_message_wait_for_replyr   r    )
session_ideventr1   c                 C  sR   ddl m} t|dr*t|j|r*d |j_| jjd|gdd}| j	| j
| d S )Nr   )ColumnDataChangedEventhintrx   F)Zuse_buffers)Zbokeh.document.eventsr   hasattrr@   r   colsr6   rX   r&   r~   rl   )r:   r   r   r   r^   r;   r;   r<   _send_patch_document  s
    z%ClientConnection._send_patch_documentc                 C  s,   | j d}| |}|d kr&td|jS )NzSERVER-INFO-REQz<Did not get a reply to server info request before disconnect)r6   rX   rY   rZ   r\   )r:   r^   r_   r;   r;   r<   rO     s
    
z*ClientConnection._send_request_server_infoc                 C  s   | j r| j   d S rH   )r3   Z_notify_disconnectedrA   r;   r;   r<   rQ     s    z/ClientConnection._tell_session_about_disconnect)	new_stater1   c                   s,   t d|jj  || _|  I d H  d S )Nztransitioning to state )rf   ri   r   r   r%   rz   )r:   r   r;   r;   r<   rr     s    zClientConnection._transitionr   )	dis_stater1   c                   s   |    | |I d H  d S rH   )rQ   rr   )r:   r   r;   r;   r<   rn     s    z,ClientConnection._transition_to_disconnectedc                   sx   |   I d H }|r@|jdkr@td| | t I d H  n4|d krd| ttj	ddI d H  nt
d|dd S )NZACKz	Received rv   rw   z instead of ACK)ry   rU   rf   ri   rr   r   rn   r   r   ro   r   r{   r;   r;   r<   _wait_for_ack  s    zClientConnection._wait_for_ack)NNr(   )rL   )!r   
__module____qualname____doc____annotations__r=   propertyrB   r.   rC   rD   rE   rG   rK   rN   rP   rR   r`   rb   rc   rl   ru   r|   rJ   rz   ry   rY   r   rO   rQ   rr   rn   r   r;   r;   r;   r<   r$   R   sP   
    	!r$   )9r   
__future__r   logging	getLoggerr   rf   typingr   r   r   r   r   Ztornado.httpclientr   r	   Ztornado.ioloopr
   Ztornado.websocketr   r   Z
core.typesr   protocolr   Zprotocol.exceptionsr   r   r   Zprotocol.receiverr   Zutil.stringr   Zutil.tornador   Zstatesr   r   r   r   r   r   r   Z	websocketr   rS   r   Zdocument.eventsr    Zprotocol.messager!   Z#protocol.messages.server_info_replyr"   r,   r#   __all__r$   r;   r;   r;   r<   <module>   s4   
	$	  g