B
    @\)                 @   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mZ ddlmZ ddlm  mZ ddlmZmZ dZG d	d
 d
eZdS )a   Provide a base class for all Bokeh Server Protocol message types.

Boker messages are comprised of a sequence of JSON fragments. Specified as
Python JSON-like data, messages have the general form:

.. code-block:: python

    [
        # these are required
        b'{header}',        # serialized header dict
        b'{metadata}',      # serialized metadata dict
        b'{content},        # serialized content dict

        # these are optional, and come in pairs; header contains num_buffers
        b'{buf_header}',    # serialized buffer header dict
        b'array'            # raw buffer payload data
        ...
    ]

The ``header`` fragment will have the form:

.. code-block:: python

    header = {
        # these are required
        'msgid'       : <str> # a unique id for the message
        'msgtype'     : <str> # a message type, e.g. 'ACK', 'PATCH-DOC', etc

        # these are optional
        'num_buffers' : <int> # the number of additional buffers, if any
    }

The ``metadata`` fragment may contain any arbitrary information. It is not
processed by Bokeh for any purpose, but may be useful for external
monitoring or instrumentation tools.

The ``content`` fragment is defined by the specific message type.

    )absolute_importdivisionprint_functionunicode_literalsN)json_decodejson_encode)gen   )MessageErrorProtocolError)Messagec               @   s   e Zd ZdZdd Zdd Zedd Zdd	 Zd
d Z	e
jd'ddZed(ddZe
jdd Zedd Zedd Zejdd Zedd Zedd Zejdd Zedd Zed d! Zejd"d! Zed#d$ Zed%d& ZdS ))r   z The Message base class encapsulates creating, assembling, and
    validating the integrity of Bokeh Server messages. Additionally, it
    provide hooks

    c             C   s   || _ || _|| _g | _dS )a   Initialize a new message from header, metadata, and content
        dictionaries.

        To assemble a message from existing JSON fragments, use the
        ``assemble`` method.

        To create new messages with automatically generated headers,
        use subclass ``create`` methods.

        Args:
            header (JSON-like) :

            metadata (JSON-like) :

            content (JSON-like) :

        N)headermetadatacontent_buffers)selfr   r   r    r   5lib/python3.7/site-packages/bokeh/protocol/message.py__init__\   s    zMessage.__init__c             C   s   d| j | j| jf S )Nz$Message %r (revision %d) content: %r)msgtypeZrevisionr   )r   r   r   r   __repr__s   s    zMessage.__repr__c             C   s   yt |}W n tk
r(   tdY nX yt |}W n tk
rR   tdY nX yt |}W n tk
r|   tdY nX | |||}||_||_||_|S )a   Creates a new message, assembled from JSON fragments.

        Args:
            header_json (``JSON``) :

            metadata_json (``JSON``) :

            content_json (``JSON``) :

        Returns:
            Message subclass

        Raises:
            MessageError

        zheader could not be decodedzmetadata could not be decodedzcontent could not be decoded)r   
ValueErrorr
   _header_json_metadata_json_content_json)clsheader_jsonmetadata_jsoncontent_jsonr   r   r   msgr   r   r   assemblev   s"    zMessage.assemblec             C   sB   d| j kr| j d  d7  < n
d| j d< d| _| j||f dS )a   Associate a buffer header and payload with this message.

        Args:
            buf_header (``JSON``) : a buffer header
            buf_payload (``JSON`` or bytes) : a buffer payload

        Returns:
            None

        Raises:
            MessageError

        num_buffersr	   N)_headerr   r   append)r   
buf_headerbuf_payloadr   r   r   
add_buffer   s
    

zMessage.add_bufferc             C   sB   | j ddt| jkr.tdt| j d  | j||f dS )a   Add a buffer header and payload that we read from the socket.

        This differs from add_buffer() because we're validating vs.
        the header's num_buffers, instead of filling in the header.

        Args:
            buf_header (``JSON``) : a buffer header
            buf_payload (``JSON`` or bytes) : a buffer payload

        Returns:
            None

        Raises:
            ProtocolError
        r!   r   z$too many buffers received expecting N)r   getlenr   r   strr#   )r   r$   r%   r   r   r   assemble_buffer   s    zMessage.assemble_bufferTc             c   sl   |dkrt dd}xH| jD ]>\}}|j||dV  |j|d|dV  |t|t| 7 }qW t|dS )aa   Write any buffer headers and payloads to the given connection.

        Args:
            conn (object) :
                May be any object with a ``write_message`` method. Typically,
                a Tornado ``WSHandler`` or ``WebSocketClientConnection``

            locked (bool) :

        Returns:
            int : number of bytes sent

        Nz'Cannot write_buffers to connection Noner   )lockedT)Zbinaryr+   )r   r   write_messager(   r   Return)r   connr+   sentr   Zpayloadr   r   r   write_buffers   s    zMessage.write_buffersNc             C   s$   t  | jd}|dk	r ||d< |S )z Return a message header fragment dict.

        Args:
            request_id (str or None) :
                Message ID of the message this message replies to

        Returns:
            dict : a message header

        )Zmsgidr   NZreqid)bkserialZmake_idr   )r   Z
request_idr   r   r   r   create_header   s
    
zMessage.create_headerc          	   c   s   |dkrt d|j V  d}|j| jddV  |t| j7 }|j| jddV  |t| j7 }|j| jddV  |t| j7 }|| j|ddV 7 }t	
|W dQ R X dS )z Send the message on the given connection.

        Args:
            conn (WebSocketHandler) : a WebSocketHandler to send messages

        Returns:
            int : number of bytes sent

        NzCannot send to connection Noner   F)r+   )r   Z
write_lockacquirer,   r   r(   r   r   r0   r   r-   )r   r.   r/   r   r   r   send   s    zMessage.sendc             C   s6   | j dk	o4| jdk	o4| jdk	o4| j ddt| jkS )z Returns whether all required parts of a message are present.

        Returns:
            bool : True if the message is complete, False otherwise

        Nr!   r   )r   r   r   r'   r(   r   )r   r   r   r   complete  s    


zMessage.completec             C   s   | j S )N)r"   )r   r   r   r   r   *  s    zMessage.headerc             C   s   || _ d | _d S )N)r"   r   )r   valuer   r   r   r   .  s    c             C   s   | j st| j| _ | j S )N)r   r   r   )r   r   r   r   r   3  s    zMessage.header_jsonc             C   s   | j S )N)_content)r   r   r   r   r   ;  s    zMessage.contentc             C   s   || _ d | _d S )N)r7   r   )r   r6   r   r   r   r   ?  s    c             C   s   | j st| j| _ | j S )N)r   r   r   )r   r   r   r   r   D  s    zMessage.content_jsonc             C   s   | j S )N)	_metadata)r   r   r   r   r   L  s    zMessage.metadatac             C   s   || _ d | _d S )N)r8   r   )r   r6   r   r   r   r   P  s    c             C   s   | j st| j| _ | j S )N)r   r   r   )r   r   r   r   r   U  s    zMessage.metadata_jsonc             C   s   | j S )N)r   )r   r   r   r   buffers]  s    zMessage.buffers)T)N)__name__
__module____qualname____doc__r   r   classmethodr    r&   r*   r   	coroutiner0   r2   r4   propertyr5   r   setterr   r   r   r   r   r9   r   r   r   r   r   U   s,   *$r   )r=   Z
__future__r   r   r   r   ZloggingZ	getLoggerr:   logZtornado.escaper   r   Ztornador   Zbokeh.util.serializationutilZserializationr1   
exceptionsr
   r   __all__objectr   r   r   r   r   <module>-   s   
	