Source code for bokeh.client.websocket

#-----------------------------------------------------------------------------
# Copyright (c) 2012 - 2017, Anaconda, Inc. All rights reserved.
#
# Powered by the Bokeh Development Team.
#
# The full license is in the file LICENSE.txt, distributed with this software.
#-----------------------------------------------------------------------------
''' Provide a low-level wrapper for Tornado Websockets that adds locking
and smooths some compatibility issues.

'''

#-----------------------------------------------------------------------------
# Boilerplate
#-----------------------------------------------------------------------------
from __future__ import absolute_import, division, print_function, unicode_literals

import logging
log = logging.getLogger(__name__)

from bokeh.util.api import public, internal ; public, internal

#-----------------------------------------------------------------------------
# Imports
#-----------------------------------------------------------------------------

# Standard library imports

# External imports
from tornado import gen, locks
from tornado.websocket import WebSocketError

# Bokeh imports

#-----------------------------------------------------------------------------
# Globals and constants
#-----------------------------------------------------------------------------

#-----------------------------------------------------------------------------
# Public API
#-----------------------------------------------------------------------------

#-----------------------------------------------------------------------------
# Internal API
#-----------------------------------------------------------------------------

@internal((1,0,0))
[docs]class WebSocketClientConnectionWrapper(object): ''' Used for compat across Tornado versions and to add write_lock''' def __init__(self, socket): if socket is None: raise ValueError("socket must not be None") self._socket = socket # write_lock allows us to lock the connection to send multiple # messages atomically. self.write_lock = locks.Lock() # Internal methods -------------------------------------------------------- @gen.coroutine @internal((1,0,0))
[docs] def write_message(self, message, binary=False, locked=True): ''' Write a message to the websocket after obtaining the appropriate Bokeh Document lock. ''' def write_message_unlocked(): if self._socket.protocol is None: # Tornado is maybe supposed to do this, but in fact it # tries to do _socket.protocol.write_message when protocol # is None and throws AttributeError or something. So avoid # trying to write to the closed socket. There doesn't seem # to be an obvious public function to check if the socket # is closed. raise WebSocketError("Connection to the server has been closed") future = self._socket.write_message(message, binary) # don't yield this future or we're blocking on ourselves! raise gen.Return(future) if locked: with (yield self.write_lock.acquire()): write_message_unlocked() else: write_message_unlocked()
@internal((1,0,0))
[docs] def close(self, code=None, reason=None): ''' Close the websocket. ''' return self._socket.close(code, reason)
@internal((1,0,0))
[docs] def read_message(self, callback=None): ''' Read a message from websocket and execute a callback. ''' return self._socket.read_message(callback)
#----------------------------------------------------------------------------- # Private API #----------------------------------------------------------------------------- #----------------------------------------------------------------------------- # Code #-----------------------------------------------------------------------------