def verify_destination_metrics_collection(self, destination_type): from stomp import Connection self.render_config_template(modules=[self.get_activemq_module_config(destination_type)]) proc = self.start_beat(home=self.beat_path) destination_name = ''.join(random.choice(string.ascii_lowercase) for i in range(10)) conn = Connection([self.get_stomp_host_port()]) conn.start() conn.connect(wait=True) conn.send('/{}/{}'.format(destination_type, destination_name), 'first message') conn.send('/{}/{}'.format(destination_type, destination_name), 'second message') self.wait_until(lambda: self.destination_metrics_collected(destination_type, destination_name)) proc.check_kill_and_wait() self.assert_no_logged_warnings() output = self.read_output_json() passed = False for evt in output: if self.all_messages_enqueued(evt, destination_type, destination_name): assert 0 < evt['activemq'][destination_type]['messages']['size']['avg'] self.assert_fields_are_documented(evt) passed = True conn.disconnect() assert passed
def write_to_active_mq(self, message): rospy.loginfo(str(datetime.datetime.now()) + ': Posting to ActiveMQ ' + str(message)) conn = Connection(host_and_ports=[(AntennaConstants.ACTIVE_MQ_HOST, AntennaConstants.ACTIVE_MQ_PORT)]) conn.start() conn.connect(AntennaConstants.ACTIVE_MQ_USER, AntennaConstants.ACTIVE_MQ_PASS, wait=True) conn.send(body=json.dumps(message), destination=AntennaConstants.ACTIVE_MQ_TOPIC_OUT) conn.disconnect()
def getMessagesFromMQChannel(self, messageToPost): class MyListener(ConnectionListener): def __init__(self, conn): self.conn = conn def on_error(self, headers, message): print('received an error "%s"' % message) def on_message(self, headers, message): print('received a message "%s"' % message) for x in range(10): print(x) time.sleep(1) print('processed message') def on_disconnected(self): print('disconnected') connect_and_subscribe(self.conn) def connect_and_subscribe(conn): conn.connect('admin', 'admin', wait=True) conn.subscribe(destination='/queue/restdemo_queue', id=1, ack='auto') hosts = [('127.0.0.1', 61613)] conn = Connection(host_and_ports=hosts) conn.set_listener('', PrintingListener()) #conn.set_listener('', MyListener(conn)) conn.connect('admin', 'admin', wait=True) conn.subscribe(destination='/queue/restdemo_queue', id=1, ack='auto') conn.send(body=messageToPost, destination='/queue/restdemo_queue') time.sleep(2) conn.disconnect()
class RemoteBroker: def __init__(self, hostname, port, request_queue_name, response_queue_name, request_timeout_millis): hosts = [(hostname, port)] connect_timeout = 10 self.conn = Connection(host_and_ports=hosts, timeout=connect_timeout) self.conn.start() self.conn.connect(wait=True) self.request_queue_name = request_queue_name self.response_queue_name = response_queue_name self.request_timeout_millis = request_timeout_millis self._timer = None def acknowledge(self, headers): self.conn.ack(headers['message-id'], headers['subscription']) def publish(self, response): self.conn.send(body=json.dumps(response, separators=(',', ':')), destination=self.response_queue_name) def subscribe(self, handling_strategy, audit): listener = Listener(self, handling_strategy, self.start_timer, self.stop_timer, audit) self.conn.set_listener('listener', listener) self.conn.subscribe(destination=self.request_queue_name, id=1, ack='client-individual') self.start_timer() def respond_to(self, headers, response): self.acknowledge(headers) self.publish( OrderedDict([('result', response.result), ('error', None), ('id', response.id)])) def stop(self): self.conn.unsubscribe(1) self.conn.remove_listener('listener') def close(self): self.conn.disconnect() def is_connected(self): return self.conn.is_connected() def stop_timer(self): if self._timer is not None: self._timer.cancel() def start_timer(self): self._timer = Timer(self.request_timeout_millis / 1000.00, self.close) self._timer.start()
def test_subscribe_send_Topic(self): class MyListener(): def __init__(self): #hosts = [('127.0.0.1', 61613)] #conn = Connection(host_and_ports=hosts) #self.conn = conn print("MyListener __init__") def on_error(self, message): print('received an error "%s"' % message) def on_message(self, message): print('received a message on topic "%s"' % message) TestMQ.topic_messageReceived.append(message) for x in range(2): print(x) time.sleep(1) def on_disconnected(self): print('disconnected') #connect_and_subscribe(self.conn) print("test_subscribe_send_Topic()") hosts = [('127.0.0.1', 61613)] conn1 = Connection(host_and_ports=hosts) conn2 = Connection(host_and_ports=hosts) topic_listener1 = MyListener topic_listener2 = MyListener conn1.set_listener('', topic_listener1) conn2.set_listener('', topic_listener2) conn1.connect('admin', 'admin', wait=True) conn2.connect('admin', 'admin', wait=True) conn1.subscribe(destination='/topic/restdemo_topic', id=1, ack='auto') conn2.subscribe(destination='/topic/restdemo_topic', id=1, ack='auto') conn1.send(body='This is a message sent to restdemo_topic from test case', destination='/topic/restdemo_topic') time.sleep(4) conn1.disconnect() conn2.disconnect() #for i in range( len(TestMQ.topic_messageReceived)): #print("TestMQ.messageReceived = " + TestMQ.topic_messageReceived[i]) self.assertEqual(len(TestMQ.topic_messageReceived), 2)
class StompCLI(ConnectionListener): def __init__(self, host='localhost', port=61613, user='', passcode=''): self.c = Connection([(host, port)], user, passcode) self.c.set_listener('', self) self.c.start() def __print_async(self, frame_type, headers, body): print "\r \r", print frame_type for header_key in headers.keys(): print '%s: %s' % (header_key, headers[header_key]) print print body print '> ', sys.stdout.flush() def on_connecting(self, host_and_port): self.c.connect(wait=True) def on_disconnected(self): print "lost connection" def on_message(self, headers, body): self.__print_async("MESSAGE", headers, body) def on_error(self, headers, body): self.__print_async("ERROR", headers, body) def on_receipt(self, headers, body): self.__print_async("RECEIPT", headers, body) def on_connected(self, headers, body): print 'connected' self.__print_async("CONNECTED", headers, body) def ack(self, args): ''' Usage: ack <message-id> [transaction-id] Required Parameters: message-id - the id of the message being acknowledged Optional Parameters: transaction-id - the acknowledgement should be a part of the named transaction Description: The command 'ack' is used to acknowledge consumption of a message from a subscription using client acknowledgment. When a client has issued a 'subscribe' with the ack flag set to client, any messages received from that destination will not be considered to have been consumed (by the server) until the message has been acknowledged. ''' if len(args) < 3: self.c.ack(message_id=args[1]) else: self.c.ack(message_id=args[1], transaction=args[2]) def abort(self, args): ''' Usage: abort <transaction-id> Required Parameters: transaction-id - the transaction to abort Description: Roll back a transaction in progress. ''' self.c.abort(transaction=args[1]) def begin(self, args): ''' Usage: begin Description: Start a transaction. Transactions in this case apply to sending and acknowledging - any messages sent or acknowledged during a transaction will be handled atomically based on the transaction. ''' print 'transaction id: %s' % self.c.begin() def commit(self, args): ''' Usage: commit <transaction-id> Required Parameters: transaction-id - the transaction to commit Description: Commit a transaction in progress. ''' if len(args) < 2: print 'expecting: commit <transid>' else: print 'committing %s' % args[1] self.c.commit(transaction=args[1]) def disconnect(self, args): ''' Usage: disconnect Description: Gracefully disconnect from the server. ''' try: self.c.disconnect() except NotConnectedException: pass # ignore if no longer connected def send(self, args): ''' Usage: send <destination> <message> Required Parameters: destination - where to send the message message - the content to send Description: Sends a message to a destination in the messaging system. ''' if len(args) < 3: print 'expecting: send <destination> <message>' else: self.c.send(destination=args[1], message=' '.join(args[2:])) def sendtrans(self, args): ''' Usage: sendtrans <destination> <transaction-id> <message> Required Parameters: destination - where to send the message transaction-id - the id of the transaction in which to enlist this message message - the content to send Description: Sends a message to a destination in the message system, using a specified transaction. ''' if len(args) < 3: print 'expecting: sendtrans <destination> <transaction-id> <message>' else: self.c.send(destination=args[1], message="%s\n" % ' '.join(args[3:]), transaction=args[2]) def subscribe(self, args): ''' Usage: subscribe <destination> [ack] Required Parameters: destination - the name to subscribe to Optional Parameters: ack - how to handle acknowledgements for a message; either automatically (auto) or manually (client) Description: Register to listen to a given destination. Like send, the subscribe command requires a destination header indicating which destination to subscribe to. The ack parameter is optional, and defaults to auto. ''' if len(args) < 2: print 'expecting: subscribe <destination> [ack]' elif len(args) > 2: print 'subscribing to "%s" with acknowledge set to "%s"' % ( args[1], args[2]) self.c.subscribe(destination=args[1], ack=args[2]) else: print 'subscribing to "%s" with auto acknowledge' % args[1] self.c.subscribe(destination=args[1], ack='auto') def unsubscribe(self, args): ''' Usage: unsubscribe <destination> Required Parameters: destination - the name to unsubscribe from Description: Remove an existing subscription - so that the client no longer receive messages from that destination. ''' if len(args) < 2: print 'expecting: unsubscribe <destination>' else: print 'unsubscribing from "%s"' % args[1] self.c.unsubscribe(destination=args[1]) def stats(self, args): ''' Usage: stats [on|off] Description: Record statistics on messages sent, received, errors, etc. If no argument (on|off) is specified, dump the current statistics. ''' if len(args) < 2: stats = self.c.get_listener('stats') if stats: print stats else: print 'No stats available' elif args[1] == 'on': self.c.set_listener('stats', StatsListener()) elif args[1] == 'off': self.c.remove_listener('stats') else: print 'expecting: stats [on|off]' def help(self, args): ''' Usage: help [command] Description: Display info on a specified command, or a list of available commands ''' if len(args) == 1: print 'Usage: help <command>, where command is one of the following:' print ' ' for f in dir(self): if f.startswith('_') or f.startswith('on_') or f == 'c': continue else: print '%s ' % f, print '' return elif not hasattr(self, args[1]): print 'There is no command "%s"' % args[1] return func = getattr(self, args[1]) if hasattr(func, '__doc__') and getattr(func, '__doc__') is not None: print func.__doc__ else: print 'There is no help for command "%s"' % args[1]
class NotificationReceiver(object): """ A class for receiving HMC notifications that are published to particular HMC notification topics. **Experimental:** This class is considered experimental at this point, and its API may change incompatibly as long as it is experimental. Creating an object of this class establishes a JMS session with the HMC and subscribes for the specified HMC notification topic(s). Notification topic strings are created by the HMC in context of a particular client session (i.e. :class:`~zhmcclient.Session` object). However, these topic strings can be used by any JMS message listener that knows the topic string and that authenticates under some valid HMC userid. The HMC userid used by the JMS listener does not need to be the one that was used for the client session in which the notification topic was originally created. """ def __init__(self, topic_names, host, userid, password, port=DEFAULT_STOMP_PORT): """ Parameters: topic_names (:term:`string` or list/tuple thereof): Name(s) of the HMC notification topic(s). Must not be `None`. host (:term:`string`): HMC host. For valid formats, see the :attr:`~zhmcclient.Session.host` property. Must not be `None`. userid (:term:`string`): Userid of the HMC user to be used. Must not be `None`. password (:term:`string`): Password of the HMC user to be used. Must not be `None`. port (:term:`integer`): STOMP TCP port. Defaults to :attr:`~zhmcclient._constants.DEFAULT_STOMP_PORT`. """ if not isinstance(topic_names, (list, tuple)): topic_names = [topic_names] self._topic_names = topic_names self._host = host self._port = port self._userid = userid self._password = password # Wait timeout to honor keyboard interrupts after this time: self._wait_timeout = 10.0 # seconds # Subscription ID. We use some value that allows to identify on the # HMC that this is the zhmcclient, but otherwise we are not using # this value ourselves. self._sub_id = 'zhmcclient.%s' % id(self) # Sync variables for thread-safe handover between listener thread and # receiver thread: self._handover_dict = {} self._handover_cond = threading.Condition() # Lazy importing for stomp, because it is so slow (ca. 5 sec) if 'Stomp_Connection' not in globals(): from stomp import Connection as Stomp_Connection self._conn = Stomp_Connection([(self._host, self._port)], use_ssl="SSL") listener = _NotificationListener(self._handover_dict, self._handover_cond) self._conn.set_listener('', listener) self._conn.connect(self._userid, self._password, wait=True) for topic_name in self._topic_names: dest = "/topic/" + topic_name self._conn.subscribe(destination=dest, id=self._sub_id, ack='auto') @logged_api_call def notifications(self): """ Generator method that yields all HMC notifications (= JMS messages) received by this notification receiver. Example:: desired_topic_types = ('security-notification', 'audit-notification') topics = session.get_notification_topics() topic_names = [t['topic-name'] for t in topics if t['topic-type'] in desired_topic_types] receiver = zhmcclient.NotificationReceiver( topic_names, hmc, userid, password) for headers, message in receiver.notifications(): . . . # processing of topic-specific message format Yields: : A tuple (headers, message) representing one HMC notification, with: * headers (dict): The notification header fields. Some important header fields (dict items) are: * 'notification-type' (string): The HMC notification type (e.g. 'os-message', 'job-completion', or others). * 'session-sequence-nr' (string): The sequence number of this HMC notification within the session created by this notification receiver object. This number starts at 0 when this receiver object is created, and is incremented each time an HMC notification is published to this receiver. * 'class' (string): The class name of the HMC resource publishing the HMC notification (e.g. 'partition'). * 'object-id' (string) or 'element-id' (string): The ID of the HMC resource publishing the HMC notification. For a complete list of notification header fields, see section "Message format" in chapter 4. "Asynchronous notification" in the :term:`HMC API` book. * message (:term:`JSON object`): Body of the HMC notification, converted into a JSON object. The properties of the JSON object vary by notification type. For a description of the JSON properties, see the sub-sections for each notification type within section "Notification message formats" in chapter 4. "Asynchronous notification" in the :term:`HMC API` book. """ while True: with self._handover_cond: # serialize body via lock # Wait until MessageListener has a new notification while len(self._handover_dict) == 0: self._handover_cond.wait(self._wait_timeout) if self._handover_dict['headers'] is None: return # Process the notification yield (self._handover_dict['headers'], self._handover_dict['message']) # Indicate to MessageListener that we are ready for next # notification del self._handover_dict['headers'] del self._handover_dict['message'] self._handover_cond.notifyAll() @logged_api_call def close(self): """ Disconnect and close the JMS session with the HMC. This implicitly unsubscribes from the notification topic this receiver was created for, and causes the :meth:`~zhmcclient.NotificationReceiver.notifications` method to stop its iterations. """ self._conn.disconnect()
class Consumer(ConnectionListener): def __init__(self, host_and_ports, topic, handler, username=None, password=None): self.topic = topic self.host_and_ports = host_and_ports self.handler = handler self.username = username self.password = password self.should_reconnect = True self.conn = Connection(host_and_ports) self.conn.set_listener('', self) self.logger = logging.getLogger(Consumer.__name__) # a random value self.subscription_id = 95 def _connect_and_subscribe(self, ack='auto'): conn = self.conn try: self.logger.info('tring to connect AMQ: ' + str(self.host_and_ports)) conn.connect(self.username, self.password, wait=True) conn.subscribe(destination=self.topic, id=self.subscription_id, ack=ack) except ConnectFailedException as e: self.logger.exception('failed to connect AMQ: ' + str(self.host_and_ports)) def _disconnect(self): self.conn.disconnect() def on_disconnected(self): # TODO: if exception occurs here, will the listener exit? self.logger.warn('connection to amq %s is closed unexpectedly' % str(self.host_and_ports)) while self.should_reconnect: try: self._connect_and_subscribe() except ConnectFailedException as e: self.logger.exception('failed to reconnect to amq: ' + str(self.host_and_ports)) time.sleep(5) else: break def on_message(self, headers, message): # TODO: should we validate the message format and field type here? # TODO: if exception occurs and not ack, will the same message trigger # this method again? try: msg = json.loads(message) self.handler.handle(msg) except: self.logger.exception('failed to process message: ' + message) else: msg_id = headers['message-id'] self.conn.ack(msg_id, self.subscription_id) def start(self, ack='auto'): """ :param ack: either auto, client or client-individual """ self.should_reconnect = True self._connect_and_subscribe(ack) def stop(self): self.should_reconnect = False self._disconnect()
class EventListener(ConnectionListener): def __init__(self, host_and_ports, topic, username=None, password=None): self.topic = topic self.host_and_ports = host_and_ports self.username = username self.password = password self.should_reconnect = True self.conn = Connection(host_and_ports) self.conn.set_listener('', self) self.logger = logging.getLogger(EventListener.__name__) self.subscription_id = 94 def _connect_and_subscribe(self, ack='auto'): conn = self.conn try: self.logger.info('tring to connect AMQ: ' + str(self.host_and_ports)) conn.connect(self.username, self.password, wait=True) conn.subscribe(destination=self.topic, id=self.subscription_id, ack=ack) except ConnectFailedException as e: self.logger.exception( 'failed to connect AMQ: ' + str(self.host_and_ports) ) def _disconnect(self): self.conn.disconnect() def start_listening(self, reactor, stat_driver, ack='auto'): """ :param ack: either auto, client or client-individual """ self.should_reconnect = True self.reactor = reactor self.stat_driver = stat_driver self._connect_and_subscribe(ack) def stop_listening(self): self.should_reconnect = False self._disconnect() def on_connecting(self, host_and_port): pass def on_disconnected(self): # TODO: if exception occurs here, will the listener exit? self.logger.warn( 'connection to amq %s is closed unexpectedly' % str(self.host_and_ports) ) while self.should_reconnect: try: self._connect_and_subscribe() except ConnectFailedException as e: self.logger.exception( 'failed to reconnect to amq: ' + str(self.host_and_ports) ) time.sleep(5) else: break def on_message(self, headers, message): # TODO: should we validate the message format and field type here? try: event = Event.from_json(message) self.stat_driver.add_event(event) self.reactor.dispatch_event(event) except: self.logger.exception('failed to process message: ' + message) else: msg_id = headers['message-id'] self.conn.ack(msg_id, self.subscription_id) def on_ggGerror(self, headers, message): print('received an error "%s"' % message)
class TestMq(unittest.TestCase): def setUp(self): self.topic = 'testEventListening' self.host_and_ports = mq.host_and_ports self.listener = EventListener(self.host_and_ports, self.topic) reactor = Mock() self.listener.start_listening(reactor) self.sender_client = Connection(self.host_and_ports) self.sender_client.start() self.sender_client.connect(wait=True) def tearDown(self): self.sender_client.disconnect() self.listener.stop_listening() def _send(self, topic, msg): self.sender_client.send(body=msg, destination=topic) def test_msg_receiving(self): listener = self.listener with patch.object(listener, 'on_message') as on_message: on_message.return_value = None self.assertTrue(listener.on_message.call_count == 0) self._send(self.topic, 'this is a test msg') time.sleep(1) self.assertTrue(listener.on_message.call_count == 1) self._send(self.topic, 'this is a test msg') time.sleep(1) self.assertTrue(listener.on_message.call_count == 2) def test_reconnect(self): # ensure it's connecting to AMQ self.test_msg_receiving() se = ConnectFailedException, with patch.object(self.listener, '_connect_and_subscribe', side_effect=se) as m: self.assertTrue(m.call_count == 0) self.listener.conn.disconnect() time.sleep(1) self.assertTrue(m.call_count == 1) time.sleep(6) self.assertTrue(m.call_count == 2) time.sleep(1) # ensure reconnecting is successful self.test_msg_receiving() def test_qos(self): topic = 'topic_for_ack' cnt_msg = 5 listener = EventListener(self.host_and_ports, topic) listener.start_listening('client') for i in xrange(cnt_msg): self._send(topic, 'msg for testing ack') listener.stop_listening() def se(headers, msg): msg_id = headers['message-id'] listener.conn.ack(msg_id, listener.subscription_id) with patch.object(listener, 'on_message', side_effect=se) as m: listener.start_listening('client') time.sleep(1) self.assertTrue(m.call_count == cnt_msg) listener.stop_listening() time.sleep(1) with patch.object(listener, 'on_message', side_effect=se) as m: listener.start_listening('client') time.sleep(1) self.assertTrue(m.call_count == 0) listener.stop_listening()
class StompCLI(ConnectionListener): def __init__(self, host='localhost', port=61613, user='', passcode=''): self.c = Connection([(host, port)], user, passcode) self.c.set_listener('', self) self.c.start() def __print_async(self, frame_type, headers, body): print "\r \r", print frame_type for header_key in headers.keys(): print '%s: %s' % (header_key, headers[header_key]) print print body print '> ', sys.stdout.flush() def on_connecting(self, host_and_port): self.c.connect(wait=True) def on_disconnected(self): print "lost connection" def on_message(self, headers, body): self.__print_async("MESSAGE", headers, body) def on_error(self, headers, body): self.__print_async("ERROR", headers, body) def on_receipt(self, headers, body): self.__print_async("RECEIPT", headers, body) def on_connected(self, headers, body): print 'connected' self.__print_async("CONNECTED", headers, body) def ack(self, args): ''' Usage: ack <message-id> [transaction-id] Required Parameters: message-id - the id of the message being acknowledged Optional Parameters: transaction-id - the acknowledgement should be a part of the named transaction Description: The command 'ack' is used to acknowledge consumption of a message from a subscription using client acknowledgment. When a client has issued a 'subscribe' with the ack flag set to client, any messages received from that destination will not be considered to have been consumed (by the server) until the message has been acknowledged. ''' if len(args) < 3: self.c.ack(message_id=args[1]) else: self.c.ack(message_id=args[1], transaction=args[2]) def abort(self, args): ''' Usage: abort <transaction-id> Required Parameters: transaction-id - the transaction to abort Description: Roll back a transaction in progress. ''' self.c.abort(transaction=args[1]) def begin(self, args): ''' Usage: begin Description: Start a transaction. Transactions in this case apply to sending and acknowledging - any messages sent or acknowledged during a transaction will be handled atomically based on the transaction. ''' print 'transaction id: %s' % self.c.begin() def commit(self, args): ''' Usage: commit <transaction-id> Required Parameters: transaction-id - the transaction to commit Description: Commit a transaction in progress. ''' if len(args) < 2: print 'expecting: commit <transid>' else: print 'committing %s' % args[1] self.c.commit(transaction=args[1]) def disconnect(self, args): ''' Usage: disconnect Description: Gracefully disconnect from the server. ''' try: self.c.disconnect() except NotConnectedException: pass # ignore if no longer connected def send(self, args): ''' Usage: send <destination> <message> Required Parameters: destination - where to send the message message - the content to send Description: Sends a message to a destination in the messaging system. ''' if len(args) < 3: print 'expecting: send <destination> <message>' else: self.c.send(destination=args[1], message=' '.join(args[2:])) def sendreply(self, args): ''' Usage: sendreply <destination> <correlation-id> <message> Required Parameters: destination - where to send the message correlation-id - the correlating identifier to send with the response message - the content to send Description: Sends a reply message to a destination in the messaging system. ''' if len(args) < 4: print 'expecting: sendreply <destination> <correlation-id> <message>' else: self.c.send(destination=args[1], message="%s\n" % ' '.join(args[3:]), headers={'correlation-id': args[2]}) def sendtrans(self, args): ''' Usage: sendtrans <destination> <transaction-id> <message> Required Parameters: destination - where to send the message transaction-id - the id of the transaction in which to enlist this message message - the content to send Description: Sends a message to a destination in the message system, using a specified transaction. ''' if len(args) < 3: print 'expecting: sendtrans <destination> <transaction-id> <message>' else: self.c.send(destination=args[1], message="%s\n" % ' '.join(args[3:]), transaction=args[2]) def subscribe(self, args): ''' Usage: subscribe <destination> [ack] Required Parameters: destination - the name to subscribe to Optional Parameters: ack - how to handle acknowledgements for a message; either automatically (auto) or manually (client) Description: Register to listen to a given destination. Like send, the subscribe command requires a destination header indicating which destination to subscribe to. The ack parameter is optional, and defaults to auto. ''' if len(args) < 2: print 'expecting: subscribe <destination> [ack]' elif len(args) > 2: print 'subscribing to "%s" with acknowledge set to "%s"' % (args[1], args[2]) self.c.subscribe(destination=args[1], ack=args[2]) else: print 'subscribing to "%s" with auto acknowledge' % args[1] self.c.subscribe(destination=args[1], ack='auto') def unsubscribe(self, args): ''' Usage: unsubscribe <destination> Required Parameters: destination - the name to unsubscribe from Description: Remove an existing subscription - so that the client no longer receive messages from that destination. ''' if len(args) < 2: print 'expecting: unsubscribe <destination>' else: print 'unsubscribing from "%s"' % args[1] self.c.unsubscribe(destination=args[1]) def stats(self, args): ''' Usage: stats [on|off] Description: Record statistics on messages sent, received, errors, etc. If no argument (on|off) is specified, dump the current statistics. ''' if len(args) < 2: stats = self.c.get_listener('stats') if stats: print stats else: print 'No stats available' elif args[1] == 'on': self.c.set_listener('stats', StatsListener()) elif args[1] == 'off': self.c.remove_listener('stats') else: print 'expecting: stats [on|off]' def help(self, args): ''' Usage: help [command] Description: Display info on a specified command, or a list of available commands ''' if len(args) == 1: print 'Usage: help <command>, where command is one of the following:' print ' ' for f in dir(self): if f.startswith('_') or f.startswith('on_') or f == 'c': continue else: print '%s ' % f, print '' return elif not hasattr(self, args[1]): print 'There is no command "%s"' % args[1] return func = getattr(self, args[1]) if hasattr(func, '__doc__') and getattr(func, '__doc__') is not None: print func.__doc__ else: print 'There is no help for command "%s"' % args[1]