import json import sys import logging from tornado.options import define, options from griotte.websocket import WebSocket from griotte.config import Config import tornado.ioloop Config("DEFAULT") define("watchdog", default=0.1, help="Watchdog interval") if __name__ == "__main__": def on_message(channel, message): logging.info(" >>> On channel \"%s\" : %s" % (channel, message)) channels = () channels = options.parse_command_line() if not channels: logging.warning("No channel specified, watching meta.presence") channels.append("meta.presence") ws = WebSocket() for chan in channels: ws.add_listener(chan, on_message) ws.start(detach=False, watchdog_interval=options.watchdog)
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)
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)