#----------------------------------------------------------------------------- # Copyright (c) 2012 - 2019, Anaconda, Inc., and Bokeh Contributors. # All rights reserved. # # The full license is in the file LICENSE.txt, distributed with this software. #----------------------------------------------------------------------------- ''' Encapsulate handling of all Bokeh Protocol messages a Bokeh server may receive. ''' #----------------------------------------------------------------------------- # Boilerplate #----------------------------------------------------------------------------- from __future__ import absolute_import, division, print_function, unicode_literals import logging log = logging.getLogger(__name__) #----------------------------------------------------------------------------- # Imports #----------------------------------------------------------------------------- # Standard library imports # External imports from tornado import gen # Bokeh imports from .session import ServerSession from ..protocol.exceptions import ProtocolError #----------------------------------------------------------------------------- # Globals and constants #----------------------------------------------------------------------------- __all__ = ( 'ProtocolHandler', ) #----------------------------------------------------------------------------- # General API #----------------------------------------------------------------------------- [docs]class ProtocolHandler(object): ''' A Bokeh server may be expected to receive any of the following protocol messages: * ``EVENT`` * ``PATCH-DOC`` * ``PULL-DOC-REQ`` * ``PUSH-DOC`` * ``SERVER-INFO-REQ`` The job of ``ProtocolHandler`` is to direct incoming messages to the right specialized handler for each message type. When the server receives a new message on a connection it will call ``handler`` with the message and the connection that the message arrived on. Most messages are ultimately handled by the ``ServerSession`` class, but some simpler messages types such as ``SERVER-INFO-REQ`` may be handled directly by ``ProtocolHandler``. Any unexpected messages will result in a ``ProtocolError``. ''' def __init__(self): self._handlers = dict() self._handlers['PULL-DOC-REQ'] = ServerSession.pull self._handlers['PUSH-DOC'] = ServerSession.push self._handlers['PATCH-DOC'] = ServerSession.patch self._handlers['SERVER-INFO-REQ'] = self._server_info_req self._handlers['EVENT'] = ServerSession.event [docs] @gen.coroutine def handle(self, message, connection): ''' Delegate a received message to the appropriate handler. Args: message (Message) : The message that was receive that needs to be handled connection (ServerConnection) : The connection that received this message Raises: ProtocolError ''' handler = self._handlers.get((message.msgtype, message.revision)) if handler is None: handler = self._handlers.get(message.msgtype) if handler is None: raise ProtocolError("%s not expected on server" % message) try: work = yield handler(message, connection) except Exception as e: log.error("error handling message\n message: %r \n error: %r", message, e, exc_info=True) work = connection.error(message, repr(e)) raise gen.Return(work) @gen.coroutine def _server_info_req(self, message, connection): raise gen.Return(connection.protocol.create('SERVER-INFO-REPLY', message.header['msgid'])) #----------------------------------------------------------------------------- # Dev API #----------------------------------------------------------------------------- #----------------------------------------------------------------------------- # Private API #----------------------------------------------------------------------------- #----------------------------------------------------------------------------- # Code #-----------------------------------------------------------------------------