B
    @\9                 @   s   d Z ddlmZmZmZmZ ddlZee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 d	dlmZmZm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Z%G dd de&Z'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.

    )absolute_importdivisionprint_functionunicode_literalsN)
quote_plus)gen)HTTPRequest)IOLoop)websocket_connectWebSocketError   )Protocol)MessageErrorProtocolErrorValidationError)Receiver   )NOT_YET_CONNECTEDCONNECTED_BEFORE_ACKCONNECTED_AFTER_ACKDISCONNECTEDWAITING_FOR_REPLY) WebSocketClientConnectionWrapper)ClientConnectionc               @   s  e Zd ZdZd6ddZedd Zedd Zed	d
 Zdd Z	d7ddZ
dd Zdd Zdd Zdd Zdd Zejdd Zdd Zejdd Zejd d! Zd"d# Zejd$d% Zejd&d' Zd(d) Zd*d+ Zd,d- Zd.d/ Zejd0d1 Zejd2d3 Zejd4d5 ZdS )8r   zs A Bokeh low-level class used to implement ``ClientSession``; use ``ClientSession`` to connect to the server.

    Nc             C   sZ   || _ || _|| _td| _t| j| _d| _t | _	|dkrDt
 }|| _d| _d| _dS )z6 Opens a websocket connection to the server.

        z1.0N)_url_session
_argumentsr   	_protocolr   	_receiver_socketr   _stater	   _loop_until_predicate_server_info)selfZsessionZwebsocket_urlio_loopZ	arguments r&   6lib/python3.7/site-packages/bokeh/client/connection.py__init__A   s    
zClientConnection.__init__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'   	connectedV   s    zClientConnection.connectedc             C   s   | j S )z2 The Tornado ``IOLoop`` this connection is using. )r!   )r$   r&   r&   r'   r%   ^   s    zClientConnection.io_loopc             C   s   | j S )z1 The URL of the websocket this Connection is to. )r   )r$   r&   r&   r'   urld   s    zClientConnection.urlc                s    fdd}  | d S )Nc                  s   t  jtpt  jtS )N)r)   r    r   r   r&   )r$   r&   r'   connected_or_closedl   s    z5ClientConnection.connect.<locals>.connected_or_closed)_loop_until)r$   r,   r&   )r$   r'   connectk   s    zClientConnection.connectclosedc             C   s   | j dk	r| j d| dS )z* Close the Websocket connection.

        Ni  )r   close)r$   whyr&   r&   r'   r0   r   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_info)r$   r&   r&   r'   force_roundtripy   s    z ClientConnection.force_roundtripc                s8   t  jtr   t  _n 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.

        c                  s   t  jtS )N)r)   r    r   r&   )r$   r&   r'   r/      s    z2ClientConnection.loop_until_closed.<locals>.closedN)r)   r    r   _tell_session_about_disconnectr   r-   )r$   r/   r&   )r$   r'   loop_until_closed   s
    	
z"ClientConnection.loop_until_closedc             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-REQNzConnection to server was lostmsgtypeERRORzFailed to pull document: text)r   create_send_message_wait_for_replyRuntimeErrorheadercontentZpush_to_document)r$   documentmsgreplyr&   r&   r'   pull_doc   s    

zClientConnection.pull_docc             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-DOCNzConnection to server was lostr6   r7   zFailed to push document: r8   )r   r9   r:   r;   r<   r=   )r$   r>   r?   r@   r&   r&   r'   push_doc   s    

zClientConnection.push_docc             C   s   | j dkr|  | _ | j S )zq Ask for information about the server.

        Returns:
            A dictionary of server attributes.

        N)r#   r2   )r$   r&   r&   r'   request_server_info   s    

z$ClientConnection.request_server_infoc          
   c   s   | j d krtd| n\y || j V }td|| W n: tk
rr } ztd| | jdd W d d }~X Y nX td 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)r1   )	r   loginfosenddebugr   r0   r   Return)r$   messageZsenter&   r&   r'   send_message   s    
zClientConnection.send_messagec             C   sX   d| j | jjf }| jd k	rTx6| j D ](\}}|dtt|tt|7 }q(W |S )Nz1%s?bokeh-protocol-version=1.0&bokeh-session-id=%sz&{}={})r   r   idr   itemsformatr   str)r$   versioned_urlkeyvaluer&   r&   r'   _versioned_url   s
    
$zClientConnection._versioned_urlc          
   c   s   |   }t|}yt|V }t|| _W n. tk
rV } ztd| W d d }~X Y nX | jd krn|  V  n| 	t
 V  d S )NzFailed to connect to server: %r)rS   r   r
   r   r   	ExceptionrD   rE   _transition_to_disconnected_transitionr   )r$   rP   ZrequestZsocketrJ   r&   r&   r'   _connect_async   s    

zClientConnection._connect_asyncc             c   sZ   |   V }|d kr|  V  n8|jdkr@td | j| ntd| |  V  d S )Nz	PATCH-DOCz"Got PATCH-DOC, applying to sessionzIgnoring %r)_pop_messagerU   r6   rD   rG   r   Z_handle_patch_next)r$   rI   r&   r&   r'   _handle_messages  s    


z!ClientConnection._handle_messagesc             C   sF   || _ y| j| j | j  W n tk
r@   | d Y nX d S )Nzuser interruption)r"   r!   Zadd_callbackrY   startKeyboardInterruptr0   )r$   Z	predicater&   r&   r'   r-     s    zClientConnection._loop_untilc             c   sl   | j d k	rF|   rFtd| jjj| j j d | _ | j  t	d n"td| jjj  | j
| V  d S )Nz4Stopping client loop in state %s due to True from %szRunning state )r"   rD   rG   r    	__class____name__r!   stopr   rH   run)r$   r&   r&   r'   rY     s    
zClientConnection._nextc          
   c   s   x| j d krtd d }y| j  V }W n. tk
rX } ztd| W d d }~X Y nX |d krvtd td y2| j	|V }|d k	rtd|  t|W q t
ttfk
r } z tjd|dd | jdd W d d }~X Y qX qW d S )	NzError reading from socket %rzConnection closed by serverzReceived message %rz%rT)exc_infoz!error parsing message from server)r1   )r   r   rH   Zread_messagerT   rD   rG   rE   r   Zconsumer   r   r   errorr0   )r$   ZfragmentrJ   rI   r&   r&   r'   rX   )  s&    



zClientConnection._pop_messagec                sp   t |jd  _g fdd} j ||  fdd} |  fdd} | jS )NZmsgidc                s     |  d S )N)append)Zfuture)send_resultr&   r'   message_sentI  s    zCClientConnection._send_message_wait_for_reply.<locals>.message_sentc                  s   t dkp jkS )Nr   )lenr    r&   )r$   rd   waiterr&   r'    have_send_result_or_disconnectedM  s    zWClientConnection._send_message_wait_for_reply.<locals>.have_send_result_or_disconnectedc                  s    j kpjd k	S )N)r    r@   r&   )r$   rg   r&   r'   have_reply_or_disconnectedQ  s    zQClientConnection._send_message_wait_for_reply.<locals>.have_reply_or_disconnected)r   r<   r    r!   Z
add_futurerK   r-   r@   )r$   rI   re   rh   ri   r&   )r$   rd   rg   r'   r:   D  s    

z-ClientConnection._send_message_wait_for_replyc             C   sL   ddl m} t|dr*t|j|r*d |j_| jjd|gdd}| | d S )Nr   )ColumnDataChangedEventhintz	PATCH-DOCF)Zuse_buffers)	Zbokeh.document.eventsrj   hasattrr)   rk   Zcolsr   r9   rK   )r$   Z
session_idZeventrj   r?   r&   r&   r'   _send_patch_documentW  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)r   r9   r:   r;   r=   )r$   r?   r@   r&   r&   r'   r2   c  s
    
z*ClientConnection._send_request_server_infoc             C   s   | j r| j   d S )N)r   Z_notify_disconnected)r$   r&   r&   r'   r4   j  s    z/ClientConnection._tell_session_about_disconnectc             c   s&   t d|jj  || _|  V  d S )Nztransitioning to state )rD   rG   r]   r^   r    rY   )r$   Z	new_stater&   r&   r'   rV   n  s    zClientConnection._transitionc             c   s   |    | t V  d S )N)r4   rV   r   )r$   r&   r&   r'   rU   t  s    z,ClientConnection._transition_to_disconnectedc             c   sX   |   V }|r4|jdkr4td| | t V  n |d krH|  V  ntd| d S )NZACKzReceived %rzReceived %r instead of ACK)rX   r6   rD   rG   rV   r   rU   r   )r$   rI   r&   r&   r'   _wait_for_acky  s    
zClientConnection._wait_for_ack)NN)r/   ) r^   
__module____qualname____doc__r(   propertyr*   r%   r+   r.   r0   r3   r5   rA   rB   rC   r   	coroutinerK   rS   rW   rZ   r-   rY   rX   r:   rm   r2   r4   rV   rU   rn   r&   r&   r&   r'   r   <   s4   

"r   )(rq   Z
__future__r   r   r   r   ZloggingZ	getLoggerr^   rD   Zsix.moves.urllib.parser   Ztornador   Ztornado.httpclientr   Ztornado.ioloopr	   Ztornado.websocketr
   r   Zprotocolr   Zprotocol.exceptionsr   r   r   Zprotocol.receiverr   Zstatesr   r   r   r   r   Z	websocketr   __all__objectr   r&   r&   r&   r'   <module>   s   
	