Ejemplo n.º 1
0
    def initialize(self):
        _path = msg.join_path(self._path, 'initialize')
        msg.code_debug(
            _path, 'New connection established! {0} '
            '({0.request.remote_ip})'.format(self))

        self.local_pub_sub = OwnerPubSub(name='local_pub_sub')

        self.ws_pub_sub = OwnerPubSub(name='ws_pub_sub',
                                      send_function=self.write_message)
        self.ws_objects = {
            ws_class: ws_class(self)
            for ws_class in self.ws_classes
        }

        self.__class__.clients.add(self)
        self.__class__.client_count += 1

        self.clean_closed = False
        self.ping_timeout_handle = None
Ejemplo n.º 2
0
    def initialize(self):
        _path = msg.join_path(self._path, "initialize")
        msg.code_debug(_path, "New connection established! {0} " "({0.request.remote_ip})".format(self))

        self.local_pub_sub = OwnerPubSub(name="local_pub_sub")

        self.ws_pub_sub = OwnerPubSub(name="ws_pub_sub", send_function=self.write_message)
        self.ws_objects = {ws_class: ws_class(self) for ws_class in self.ws_classes}

        self.__class__.clients.add(self)
        self.__class__.client_count += 1

        self.clean_closed = False
        self.ping_timeout_handle = None
Ejemplo n.º 3
0
class MSGHandler(WebSocketHandler):

    """Serve the WebSocket clients.

    An instance of this class is created every time a
    client connects using WebSocket. The instances of this
    class deliver messages to a group of objects
    specialized in attending a group of messages.
    """

    _path = msg.join_path(_path, 'MSGHandler')

    ws_classes = []
    clients = set()
    client_count = 0    # Total clients that have connected

    @classmethod
    @coroutine
    def stop(cls):
        for client in cls.clients.copy():
            yield client.end()

    def initialize(self):
        _path = msg.join_path(self._path, 'initialize')
        msg.code_debug(
            _path,
            'New connection established! {0} '
            '({0.request.remote_ip})'.format(self)
        )

        self.local_pub_sub = OwnerPubSub(
            name='local_pub_sub')

        self.ws_pub_sub = OwnerPubSub(
            name='ws_pub_sub',
            send_function=self.write_message
        )
        self.ws_objects = {
            ws_class: ws_class(self)
            for ws_class in self.ws_classes}

        self.__class__.clients.add(self)
        self.__class__.client_count += 1

        self.clean_closed = False
        self.ping_timeout_handle = None

    def open(self):
        IOLoop.current().spawn_callback(self.on_pong, b'1')

    @classmethod
    def add_class(cls, wsclass):
        cls.ws_classes.append(wsclass)

    @classmethod
    def broadcast(cls, message):
        for client in cls.clients:
            client.ws_pub_sub.send_message(message)

    def on_message(self, message):
        """Process messages when they arrive.

        :param str message:
            The received message. This should be a valid
            json document.
        """
        try:
            # Throws ValueError
            message = json.loads(message)

            self.ws_pub_sub.execute_actions(message)

        except NoActionForMsgTypeError:
            self.send_error(
                'noActionForMsgType',
                message,
                "The client has sent a message for which "
                "there is no associated action."
            )
            msg.no_action_for_msg_type(_path, message)

        except (NotDictError, NoMessageTypeError,
                ValueError):
            self.send_malformed_message_error(message)
            msg.malformed_message(_path, message)

    @coroutine
    def on_pong(self, data):
        """Clear the timeout, sleep, and send a new ping.

        .. todo::
            *   Document the times used in this method.
                The calculations are in my black notebook
                XD.
        """
        try:
            if self.ping_timeout_handle is not None:
                IOLoop.current().remove_timeout(
                    self.ping_timeout_handle)

            yield sleep(conf.ping_sleep)

            self.ping(b'1')
            self.ping_timeout_handle = \
                IOLoop.current().call_later(
                    conf.ping_timeout, self.close)

        except WebSocketClosedError:
            pass

        except:
            raise

    def send_error(self, critical_type, message,
                   description):
        self.ws_pub_sub.send_message(
            {'type': 'critical',
             'critical_type': critical_type,
             'message': message,
             'description': description}
        )

    send_malformed_message_error = partialmethod(
        send_error,
        'malformedMessage',
        description="The client has sent a message which "
                    "either isn't in JSON format, is not a "
                    "single JSON object, does not have a "
                    "'type' field or at least one "
                    "attribute is not consistent with the "
                    "others."
    )

    def write_message(self, message, binary=False):
        try:
            super().write_message(message, binary)

        except WebSocketClosedError:
            if not self.clean_closed:
                raise

    @coroutine
    def end(self):
        """Clean up the associated objects

        This coroutine calls :meth:`src.wsclass.WSClass.end`
        for all objects in ``self.ws_objects`` and it
        removes ``self`` from ``self.__class__.clients``.

        This coroutine is setup to be called when
        the WebSocket connection closes or when the program
        ends.
        """
        try:
            exceptions = []
            for ws_object in self.ws_objects.values():
                try:
                    yield ws_object.end()
                except:
                    exceptions.append(
                        exc_info()
                    )

            for exception in exceptions:
                print_exception(*exception)

            self.__class__.clients.discard(self)

            msg.code_debug(
                msg.join_path(
                    __name__, self.end.__qualname__),
                'Connection closed! {0} '
                '({0.request.remote_ip})'.format(self)
            )

        except:
            raise

    @coroutine
    def on_close(self):
        try:
            yield self.end()

        except:
            raise
Ejemplo n.º 4
0
from .common import db


_path = 'src.db.message_broker'

_coll_name = 'messages'
_coll = db[_coll_name]
cursor = None


@coroutine
def _send_message(message):
    yield _coll.insert(message)

_ps = OwnerPubSub(
    name='db_pub_sub',
    send_function=_send_message
)

# METHOD ALIASES:
register = _ps.register
send_message = _ps.send_message
remove_owner = _ps.remove_owner


@coroutine
def _tailable_iteration(function: 'callable'=None,
                        stop: bool=True,
                        sleep: int=0):
    """Iterates through a tailable cursor.

    .. todo::
Ejemplo n.º 5
0
class MSGHandler(WebSocketHandler):
    """Serve the WebSocket clients.

    An instance of this class is created every time a
    client connects using WebSocket. The instances of this
    class deliver messages to a group of objects
    specialized in attending a group of messages.
    """

    _path = msg.join_path(_path, 'MSGHandler')

    ws_classes = []
    clients = set()
    client_count = 0  # Total clients that have connected

    @classmethod
    @coroutine
    def stop(cls):
        for client in cls.clients.copy():
            yield client.end()

    def initialize(self):
        _path = msg.join_path(self._path, 'initialize')
        msg.code_debug(
            _path, 'New connection established! {0} '
            '({0.request.remote_ip})'.format(self))

        self.local_pub_sub = OwnerPubSub(name='local_pub_sub')

        self.ws_pub_sub = OwnerPubSub(name='ws_pub_sub',
                                      send_function=self.write_message)
        self.ws_objects = {
            ws_class: ws_class(self)
            for ws_class in self.ws_classes
        }

        self.__class__.clients.add(self)
        self.__class__.client_count += 1

        self.clean_closed = False
        self.ping_timeout_handle = None

    def open(self):
        IOLoop.current().spawn_callback(self.on_pong, b'1')

    @classmethod
    def add_class(cls, wsclass):
        cls.ws_classes.append(wsclass)

    @classmethod
    def broadcast(cls, message):
        for client in cls.clients:
            client.ws_pub_sub.send_message(message)

    def on_message(self, message):
        """Process messages when they arrive.

        :param str message:
            The received message. This should be a valid
            json document.
        """
        try:
            # Throws ValueError
            message = json.loads(message)

            self.ws_pub_sub.execute_actions(message)

        except NoActionForMsgTypeError:
            self.send_error(
                'noActionForMsgType', message,
                "The client has sent a message for which "
                "there is no associated action.")
            msg.no_action_for_msg_type(_path, message)

        except (NotDictError, NoMessageTypeError, ValueError):
            self.send_malformed_message_error(message)
            msg.malformed_message(_path, message)

    @coroutine
    def on_pong(self, data):
        """Clear the timeout, sleep, and send a new ping.

        .. todo::
            *   Document the times used in this method.
                The calculations are in my black notebook
                XD.
        """
        try:
            if self.ping_timeout_handle is not None:
                IOLoop.current().remove_timeout(self.ping_timeout_handle)

            yield sleep(conf.ping_sleep)

            self.ping(b'1')
            self.ping_timeout_handle = \
                IOLoop.current().call_later(
                    conf.ping_timeout, self.close)

        except WebSocketClosedError:
            pass

        except:
            raise

    def send_error(self, critical_type, message, description):
        self.ws_pub_sub.send_message({
            'type': 'critical',
            'critical_type': critical_type,
            'message': message,
            'description': description
        })

    send_malformed_message_error = partialmethod(
        send_error,
        'malformedMessage',
        description="The client has sent a message which "
        "either isn't in JSON format, is not a "
        "single JSON object, does not have a "
        "'type' field or at least one "
        "attribute is not consistent with the "
        "others.")

    def write_message(self, message, binary=False):
        try:
            super().write_message(message, binary)

        except WebSocketClosedError:
            if not self.clean_closed:
                raise

    @coroutine
    def end(self):
        """Clean up the associated objects

        This coroutine calls :meth:`src.wsclass.WSClass.end`
        for all objects in ``self.ws_objects`` and it
        removes ``self`` from ``self.__class__.clients``.

        This coroutine is setup to be called when
        the WebSocket connection closes or when the program
        ends.
        """
        try:
            exceptions = []
            for ws_object in self.ws_objects.values():
                try:
                    yield ws_object.end()
                except:
                    exceptions.append(exc_info())

            for exception in exceptions:
                print_exception(*exception)

            self.__class__.clients.discard(self)

            msg.code_debug(
                msg.join_path(__name__, self.end.__qualname__),
                'Connection closed! {0} '
                '({0.request.remote_ip})'.format(self))

        except:
            raise

    @coroutine
    def on_close(self):
        try:
            yield self.end()

        except:
            raise