Exemplo n.º 1
0
class Handler:
    def __init__(self):

        # Check is class name is properly constructed
        # like SomethingHandler
        if (self.__class__.__name__[-7:] != 'Handler'):
            raise ValueError(
                "Wrong handler class name : must be [something]Handler")

        self._handler_name = (self.__class__.__name__)[0:-7].lower()
        self._config = Config(self._handler_name)

        logging.debug("Initializing Handler's base for %s" %
                      self._handler_name)
        setproctitle("griotte-%s" % self._handler_name)

        self._ws = WebSocket()
        self._ws.add_listener("%s.command.ping" % self._handler_name,
                              self.ping)
        logging.debug("Added ping listener for %s" % self._handler_name)

        # Install signal handlers that child class can override
        signal.signal(signal.SIGINT, self._signal)
        signal.signal(signal.SIGTERM, self._signal)
        signal.signal(signal.SIGUSR1, self._signal)
        signal.signal(signal.SIGHUP, self._signal)

    def _signal(self, signum, frame):
        pass

    def ping(self, channel, message):
        self._ws.send("%s.event.pong" % self._handler_name,
                      {"handler": self._handler_name})
        logging.debug("%s sending pong" % self._handler_name)

    def send_event(self, event, data):
        self._ws.send("%s.event.%s" % (self._handler_name, event), data)

    def add_listener(self, command, full_path=False, callback=None):
        if callback is None:
            callback = getattr(self, "_wscb_%s" % command.split(".")[-1])

        if full_path:
            path = command
        else:
            path = "%s.command.%s" % (self._handler_name, command)

        self._ws.add_listener(path, callback)
Exemplo n.º 2
0
class Handler:
    def __init__(self):

        # Check is class name is properly constructed
        # like SomethingHandler
        if (self.__class__.__name__[-7:] != 'Handler'):
            raise ValueError("Wrong handler class name : must be [something]Handler")

        self._handler_name = (self.__class__.__name__)[0:-7].lower()
        self._config = Config(self._handler_name)

        logging.debug("Initializing Handler's base for %s" % self._handler_name)
        setproctitle("griotte-%s" % self._handler_name)

        self._ws = WebSocket()
        self._ws.add_listener("%s.command.ping" % self._handler_name, self.ping)
        logging.debug("Added ping listener for %s" % self._handler_name)

        # Install signal handlers that child class can override
        signal.signal(signal.SIGINT, self._signal)
        signal.signal(signal.SIGTERM, self._signal)
        signal.signal(signal.SIGUSR1, self._signal)
        signal.signal(signal.SIGHUP, self._signal)

    def _signal(self, signum, frame):
        pass

    def ping(self, channel, message):
        self._ws.send("%s.event.pong" % self._handler_name, { "handler": self._handler_name })
        logging.debug("%s sending pong" % self._handler_name)

    def send_event(self, event, data):
        self._ws.send("%s.event.%s" % (self._handler_name, event), data)

    def add_listener(self, command, full_path=False, callback=None):
        if callback is None:
            callback = getattr(self, "_wscb_%s" % command.split(".")[-1])

        if full_path:
            path = command
        else:
            path = "%s.command.%s" % (self._handler_name, command)

        self._ws.add_listener(path, callback)
Exemplo n.º 3
0
    class __Expecter:
        """ Utility class that sends and receives data over websocket for server-side blocks

        """
        def __init__(self, uri=None):
            self._ws = WebSocket(uri=uri)
            self._ws.start(watchdog_interval=2)
            self._subscriptions = {}

        def send_expect(self, channel_out, channel_in, data='{}', flush=False):
            """ Sends a message over websocket and waits for a reply

            A combination of :py:func:`send` and :py:func:`expect`

            :param channel_out: The channel to write to
            :type channel: str

            :param channel_in: The channel to listen to
            :type channel: str

            :param data: The data to send
            :type data: str -- json encoded

            :param flush: Whether the incoming queue must be flushed before handling message (set to True to prevent receiving past messages )
            :type flush: bool
            """

            self._subscribe(channel_in)

            if flush:
                self._flush_queue(channel_in)

            self._ws.send(channel_out, data)
            return self._subscriptions[channel_in].get()

        def send(self, channel, data='{}'):
            """ Sends a message over websocket

            Utility function that wraps websocket message sending and takes care of
            opening a websocket if needed

            :param channel: The channel to write to
            :type channel: str.

            :param data: The data to send
            :type data: str -- json encoded

            :param flush: Whether the incoming queue must be flushed before handling message (set to True to prevent receiving past messages )
            :type flush: bool
            """

            logging.debug("sending message on %s" % channel)
            self._ws.send(channel, data)

        def expect(self, channel, flush=False):
            """ Expects a message on a channel

            Blocks until the message arrives and returns the 'data' part of the message

            :param channel: Channel to listen to
            :type channel: str

            :param flush: Whether the incoming queue must be flushed before handling message (set to True to prevent receiving past messages )
            :type flush: bool

            :rtype: dict -- the message we got on the wire
            """

            self._subscribe(channel)

            if flush:
                self._flush_queue(channel)

            data = self._subscriptions[channel].get()
            logging.debug("got message on %s" % channel)

            #self._unsubscribe(channel)

            return data

        def quit(self):
            self._unsubscribe_all()
            self._ws.stop()

        def on_message(self, channel, data):
            try:
                self._subscriptions[channel].put(data)
            except KeyError:
                # Clients can watch wildcard channels
                for watched_channel in self._subscriptions:
                    if fnmatch.fnmatch(channel, watched_channel):
                        # We had a match for watched_channel key
                        # We have to iterate over client list for this channel
                        self._subscriptions[watched_channel].put(data)
                        return

                logging.error(
                    "Received a message for a channel we didn't subscribe to (%s)"
                    % channel)

        def _flush_queue(self, channel):
            logging.debug("Flushing queue for channel %s" % channel)

            try:
                while not self._subscriptions[channel].empty():
                    self._subscriptions[channel].get()
                    logging.debug("flushed one message")
            except Empty:
                return

        def _subscribe(self, channel):
            if channel in self._subscriptions:
                return False

            self._subscriptions[channel] = Queue()

            logging.debug("subscribing to channel %s" % channel)
            self._ws.add_listener(channel, self.on_message)

            return True

        def _unsubscribe(self, channel):
            if channel not in self._subscriptions:
                return

            logging.debug("unsubscribing from channel %s" % channel)

            self._ws.remove_listener(channel)

            logging.debug("removing channel %s" % channel)
            self._subscriptions.pop(channel)

        def _unsubscribe_all(self):
            for channel in self._subscriptions.copy().keys():
                self._unsubscribe(channel)
Exemplo n.º 4
0
    class __Expecter:
        """ Utility class that sends and receives data over websocket for server-side blocks

        """
        def __init__(self, uri=None):
            self._ws = WebSocket(uri=uri)
            self._ws.start(watchdog_interval=2)
            self._subscriptions = {}

        def send_expect(self, channel_out, channel_in, data='{}', flush=False):
            """ Sends a message over websocket and waits for a reply

            A combination of :py:func:`send` and :py:func:`expect`

            :param channel_out: The channel to write to
            :type channel: str

            :param channel_in: The channel to listen to
            :type channel: str

            :param data: The data to send
            :type data: str -- json encoded

            :param flush: Whether the incoming queue must be flushed before handling message (set to True to prevent receiving past messages )
            :type flush: bool
            """

            self._subscribe(channel_in)

            if flush:
                self._flush_queue(channel_in)

            self._ws.send(channel_out, data)
            return self._subscriptions[channel_in].get()

        def send(self, channel, data = '{}'):
            """ Sends a message over websocket

            Utility function that wraps websocket message sending and takes care of
            opening a websocket if needed

            :param channel: The channel to write to
            :type channel: str.

            :param data: The data to send
            :type data: str -- json encoded

            :param flush: Whether the incoming queue must be flushed before handling message (set to True to prevent receiving past messages )
            :type flush: bool
            """

            logging.debug("sending message on %s" % channel)
            self._ws.send(channel, data)

        def expect(self, channel, flush=False):
            """ Expects a message on a channel

            Blocks until the message arrives and returns the 'data' part of the message

            :param channel: Channel to listen to
            :type channel: str

            :param flush: Whether the incoming queue must be flushed before handling message (set to True to prevent receiving past messages )
            :type flush: bool

            :rtype: dict -- the message we got on the wire
            """

            self._subscribe(channel)

            if flush:
                self._flush_queue(channel)

            data = self._subscriptions[channel].get()
            logging.debug("got message on %s" % channel)

            #self._unsubscribe(channel)

            return data

        def quit(self):
            self._unsubscribe_all()
            self._ws.stop()

        def on_message(self, channel, data):
            try:
                self._subscriptions[channel].put(data)
            except KeyError:
                # Clients can watch wildcard channels
                for watched_channel in self._subscriptions:
                    if fnmatch.fnmatch(channel, watched_channel):
                    # We had a match for watched_channel key
                    # We have to iterate over client list for this channel
                        self._subscriptions[watched_channel].put(data)
                        return

                logging.error("Received a message for a channel we didn't subscribe to (%s)" % channel)

        def _flush_queue(self, channel):
            logging.debug("Flushing queue for channel %s" % channel)

            try:
                while not self._subscriptions[channel].empty():
                    self._subscriptions[channel].get()
                    logging.debug("flushed one message")
            except Empty:
                return

        def _subscribe(self, channel):
            if channel in self._subscriptions:
                return False

            self._subscriptions[channel] = Queue()

            logging.debug("subscribing to channel %s" % channel)
            self._ws.add_listener(channel, self.on_message)

            return True

        def _unsubscribe(self, channel):
            if channel not in self._subscriptions:
                return

            logging.debug("unsubscribing from channel %s" % channel)

            self._ws.remove_listener(channel)

            logging.debug("removing channel %s" % channel)
            self._subscriptions.pop(channel)

        def _unsubscribe_all(self):
            for channel in self._subscriptions.copy().keys():
                self._unsubscribe(channel)