a
    JDf.                     @  s2  U d Z ddlmZ ddlZeeZddlZddlm	Z	m
Z
mZmZmZmZ ddlm  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 e	rddlmZmZ ddl m!Z! dZ"G dd deZ#G dd deZ$edZ%e&e'e
f Z(de)d< e*e$e+f Z,de)d< G dd deZ-G dd de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.

    )annotationsN)TYPE_CHECKINGAnyClassVarGeneric	TypedDictTypeVar   )serialize_json)Buffer
Serialized)ID   )MessageErrorProtocolError)NotRequired	TypeAlias) WebSocketClientConnectionWrapper)Messagec                   @  s.   e Zd ZU ded< ded< ded< ded< d	S )
Headerr   msgidstrmsgtypezNotRequired[ID]reqidzNotRequired[int]num_buffersN__name__
__module____qualname____annotations__ r    r    c/nfs/NAS7/SABIOD/METHODE/ermites/ermites_venv/lib/python3.9/site-packages/bokeh/protocol/message.pyr   d   s   
r   c                   @  s   e Zd ZU ded< dS )BufferHeaderr   idNr   r    r    r    r!   r"   j   s   
r"   Contentr   Metadata	BufferRefc                   @  s   e Zd ZdS )EmptyN)r   r   r   r    r    r    r!   r'   s   s   r'   c                   @  s  e Zd ZU dZded< ded< ded< ded	< ded
< ded< ded< ded< dddddddZddddZedddddddZdddddZ	d d!dd"d#d$Z
dKd&d'd(d)d*d+ZedLd-dd.d/d0Zd&d(d1d2d3Zed'dd4d5Zed6dd7d8Zeddd9d:Zejddd;d<d:Zeddd=d>Zeddd?d@Zejddd;dAd@ZedddBdCZedddDdEZejddd;dFdEZedddGdHZedddIdJZd,S )Mr   z The Message base class encapsulates creating, assembling, and
    validating the integrity of Bokeh Server messages. Additionally, it
    provide hooks

    zClassVar[str]r   r   _headerz
str | None_header_jsonr$   _content_content_jsonr%   	_metadata_metadata_jsonzlist[Buffer]_buffersNone)headermetadatacontentreturnc                 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)r0   r1   r2   r.   )selfr0   r1   r2   r    r    r!   __init__   s    zMessage.__init__r   )r3   c                 C  s   d| j d| jS )NzMessage z
 content: )r   r2   r4   r    r    r!   __repr__   s    zMessage.__repr__zMessage[Content])header_jsonmetadata_jsoncontent_jsonr3   c                 C  s   zt |}W n ty(   tdY n0 zt |}W n tyR   tdY n0 zt |}W n ty|   tdY n0 | |||}||_||_||_|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)jsonloads
ValueErrorr   r)   r-   r+   )clsr8   r9   r:   r0   r1   r2   msgr    r    r!   assemble   s"    zMessage.assembler   )bufferr3   c                 C  s>   d| j v r| j d  d7  < n
d| j d< d| _| j| 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

        r   r   N)r(   r)   r.   append)r4   rA   r    r    r!   
add_buffer   s
    

zMessage.add_bufferr"   bytes)
buf_headerbuf_payloadr3   c                 C  sD   | j dd}|t| jkr*td| | jt|d | 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 r#   N)r0   getlenr.   r   rB   r   )r4   rE   rF   r   r    r    r!   assemble_buffer   s    zMessage.assemble_bufferTr   boolint)connlockedr3   c                   sv   |du rt dd}| jD ]V}t|j}| }|j||dI dH  |j|d|dI dH  |t|t| 7 }q|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   rM   T)binaryrM   )r=   r.   r;   dumpsrefto_byteswrite_messagerH   )r4   rL   rM   sentrA   r0   payloadr    r    r!   write_buffers   s    
zMessage.write_buffersNz	ID | None)
request_idr3   c                 C  s&   t t | jd}|du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

        )r   r   Nr   )r   bkserialZmake_idr   )r>   rW   r0   r    r    r!   create_header  s    zMessage.create_header)rL   r3   c                   s   |du rt d|j I dH  d}|j| jddI dH  |t| j7 }|j| jddI dH  |t| j7 }|j| jddI dH  |t| j7 }|| j|ddI dH 7 }|W  d   S 1 s0    Y  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   FrN   )	r=   Z
write_lockacquirerS   r8   rH   r9   r:   rV   )r4   rL   rT   r    r    r!   send&  s    
zMessage.sendc                 C  s6   | j duo4| jduo4| jdu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   )r0   r1   r2   rG   rH   r.   r6   r    r    r!   completeI  s    
zMessage.completezSerialized[Content]c                 C  s   t | j| jS N)r   r2   buffersr6   r    r    r!   rU   V  s    zMessage.payloadc                 C  s   | j S r]   )r(   r6   r    r    r!   r0   \  s    zMessage.header)valuer3   c                 C  s   || _ d | _d S r]   )r(   r)   r4   r_   r    r    r!   r0   `  s    c                 C  s   | j st| j| _ | j S r]   )r)   r;   rP   r0   r6   r    r    r!   r8   e  s    zMessage.header_jsonc                 C  s   | j S r]   )r*   r6   r    r    r!   r2   m  s    zMessage.contentc                 C  s   || _ d | _d S r]   )r*   r+   r`   r    r    r!   r2   q  s    c                 C  s   | j st| j| _ | j S r]   )r+   r
   rU   r6   r    r    r!   r:   v  s    zMessage.content_jsonc                 C  s   | j S r]   )r,   r6   r    r    r!   r1   ~  s    zMessage.metadatac                 C  s   || _ d | _d S r]   )r,   r-   r`   r    r    r!   r1     s    c                 C  s   | j st| j| _ | j S r]   )r-   r;   rP   r1   r6   r    r    r!   r9     s    zMessage.metadata_jsonc                 C  s
   t | jS r]   )listr.   r6   r    r    r!   r^     s    zMessage.buffers)T)N)r   r   r   __doc__r   r5   r7   classmethodr@   rC   rI   rV   rY   r[   propertyr\   rU   r0   setterr8   r2   r:   r1   r9   r^   r    r    r    r!   r   v   sV   
)#r   )/rb   
__future__r   logging	getLoggerr   logr;   typingr   r   r   r   r   r   Zbokeh.util.serializationutilZserializationrX   Zcore.json_encoderr
   Zcore.serializationr   r   Z
core.typesr   
exceptionsr   r   Ztyping_extensionsr   r   Zclient.websocketr   __all__r   r"   r$   dictr   r%   r   tuplerD   r&   r'   r   r    r    r    r!   <module>   s*   +
 
