σ
mάJ]c           @` s±   d  Z  d d l m Z m Z m Z m Z d d l Z e j e  Z	 d d l
 m Z m Z d d l m Z d d l j j Z d d l m Z m Z d Z d	 e f d
     YZ d S(   uΦ   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.

i    (   t   absolute_importt   divisiont   print_functiont   unicode_literalsN(   t   json_decodet   json_encode(   t   geni   (   t   MessageErrort   ProtocolErroru   Messaget   Messagec           B` s(  e  Z d  Z d   Z d   Z e d    Z d   Z d   Z e	 j
 e d   Z e d d   Z e	 j
 d    Z e d	    Z e d
    Z e j d    Z e d    Z e d    Z e j d    Z e d    Z e d    Z e j d    Z e d    Z e d    Z RS(   u    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(   u€   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(   t   headert   metadatat   contentt   _buffers(   t   selfR
   R   R   (    (    s5   lib/python2.7/site-packages/bokeh/protocol/message.pyt   __init__\   s    			c         C` s   d |  j  |  j |  j f S(   Nu$   Message %r (revision %d) content: %r(   t   msgtypet   revisionR   (   R   (    (    s5   lib/python2.7/site-packages/bokeh/protocol/message.pyt   __repr__s   s    c         C` sΑ   y t  |  } Wn t k
 r/ t d   n Xy t  |  } Wn t k
 r_ t d   n Xy t  |  } Wn t k
 r t d   n X|  | | |  } | | _ | | _ | | _ | S(   u   Creates a new message, assembled from JSON fragments.

        Args:
            header_json (``JSON``) :

            metadata_json (``JSON``) :

            content_json (``JSON``) :

        Returns:
            Message subclass

        Raises:
            MessageError

        u   header could not be decodedu   metadata could not be decodedu   content could not be decoded(   R   t
   ValueErrorR   t   _header_jsont   _metadata_jsont   _content_json(   t   clst   header_jsont   metadata_jsont   content_jsonR
   R   R   t   msg(    (    s5   lib/python2.7/site-packages/bokeh/protocol/message.pyt   assemblev   s"    			c         C` sU   d |  j  k r% |  j  d c d 7<n d |  j  d <d |  _ |  j j | | f  d S(   u   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

        u   num_buffersi   N(   t   _headert   NoneR   R   t   append(   R   t
   buf_headert   buf_payload(    (    s5   lib/python2.7/site-packages/bokeh/protocol/message.pyt
   add_buffer    s
    	c         C` s^   |  j  j d d  t |  j  k rD t d t |  j  d    n  |  j j | | f  d S(   u    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
        u   num_buffersi    u$   too many buffers received expecting N(   R
   t   gett   lenR   R   t   strR   (   R   R    R!   (    (    s5   lib/python2.7/site-packages/bokeh/protocol/message.pyt   assemble_buffer·   s    $ c         c` s   | d k r t d   n  d } x_ |  j D]T \ } } | j | d | V| j | d t d | V| t |  t |  7} q+ Wt j |   d S(   ua   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

        u'   Cannot write_buffers to connection Nonei    t   lockedt   binaryN(   R   R   R   t   write_messaget   TrueR$   R   t   Return(   R   t   connR'   t   sentR
   t   payload(    (    s5   lib/python2.7/site-packages/bokeh/protocol/message.pyt   write_buffersΛ   s    c         C` s:   i t  j   d 6|  j d 6} | d k	 r6 | | d <n  | S(   uί    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

        u   msgidu   msgtypeu   reqidN(   t   bkserialt   make_idR   R   (   R   t
   request_idR
   (    (    s5   lib/python2.7/site-packages/bokeh/protocol/message.pyt   create_headerγ   s    c      	   c` sγ   | d k r t d   n  | j j   V² d } | j |  j d t V| t |  j  7} | j |  j d t V| t |  j  7} | j |  j	 d t V| t |  j	  7} | |  j
 | d t V7} t j |   Wd QXd S(   uΖ    Send the message on the given connection.

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

        Returns:
            int : number of bytes sent

        u   Cannot send to connection Nonei    R'   N(   R   R   t
   write_lockt   acquireR)   R   t   FalseR$   R   R   R/   R   R+   (   R   R,   R-   (    (    s5   lib/python2.7/site-packages/bokeh/protocol/message.pyt   sendχ   s    c         C` sO   |  j  d k	 oN |  j d k	 oN |  j d k	 oN |  j  j d d  t |  j  k S(   u    Returns whether all required parts of a message are present.

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

        u   num_buffersi    N(   R
   R   R   R   R#   R$   R   (   R   (    (    s5   lib/python2.7/site-packages/bokeh/protocol/message.pyt   complete  s    c         C` s   |  j  S(   N(   R   (   R   (    (    s5   lib/python2.7/site-packages/bokeh/protocol/message.pyR
   *  s    c         C` s   | |  _  d  |  _ d  S(   N(   R   R   R   (   R   t   value(    (    s5   lib/python2.7/site-packages/bokeh/protocol/message.pyR
   .  s    	c         C` s%   |  j  s t |  j  |  _  n  |  j  S(   N(   R   R   R
   (   R   (    (    s5   lib/python2.7/site-packages/bokeh/protocol/message.pyR   3  s    	c         C` s   |  j  S(   N(   t   _content(   R   (    (    s5   lib/python2.7/site-packages/bokeh/protocol/message.pyR   ;  s    c         C` s   | |  _  d  |  _ d  S(   N(   R:   R   R   (   R   R9   (    (    s5   lib/python2.7/site-packages/bokeh/protocol/message.pyR   ?  s    	c         C` s%   |  j  s t |  j  |  _  n  |  j  S(   N(   R   R   R   (   R   (    (    s5   lib/python2.7/site-packages/bokeh/protocol/message.pyR   D  s    	c         C` s   |  j  S(   N(   t	   _metadata(   R   (    (    s5   lib/python2.7/site-packages/bokeh/protocol/message.pyR   L  s    c         C` s   | |  _  d  |  _ d  S(   N(   R;   R   R   (   R   R9   (    (    s5   lib/python2.7/site-packages/bokeh/protocol/message.pyR   P  s    	c         C` s%   |  j  s t |  j  |  _  n  |  j  S(   N(   R   R   R   (   R   (    (    s5   lib/python2.7/site-packages/bokeh/protocol/message.pyR   U  s    	c         C` s   |  j  S(   N(   R   (   R   (    (    s5   lib/python2.7/site-packages/bokeh/protocol/message.pyt   buffers]  s    N(   t   __name__t
   __module__t   __doc__R   R   t   classmethodR   R"   R&   R   t	   coroutineR*   R/   R   R3   R7   t   propertyR8   R
   t   setterR   R   R   R   R   R<   (    (    (    s5   lib/python2.7/site-packages/bokeh/protocol/message.pyR	   U   s,   		*		$(   u   Message(   R?   t
   __future__R    R   R   R   t   loggingt	   getLoggerR=   t   logt   tornado.escapeR   R   t   tornadoR   t   bokeh.util.serializationt   utilt   serializationR0   t
   exceptionsR   R   t   __all__t   objectR	   (    (    (    s5   lib/python2.7/site-packages/bokeh/protocol/message.pyt   <module>-   s   "	