def test_6_integration_stomp_1_1_encoding_and_escaping_headers(self): if BROKER == 'rabbitmq': print('Broker does not support unicode characters. Skipping this test case.') return version = StompSpec.VERSION_1_1 client = Stomp(self.getConfig(version)) try: client.connect(host=VIRTUALHOST, versions=[version]) except StompProtocolError as e: print('Broker does not support STOMP protocol %s. Skipping this test case. [%s]' % (e, version)) return key = b'fen\xc3\xaatre'.decode('utf-8') value = b'\xc2\xbfqu\xc3\xa9 tal?'.decode('utf-8') headers = {key: value} client.send(self.DESTINATION, body=b'test message 1', headers=headers) self.assertFalse(client.canRead(self.TIMEOUT)) token = client.subscribe(self.DESTINATION, {StompSpec.ID_HEADER: 4711, StompSpec.ACK_HEADER: StompSpec.ACK_CLIENT_INDIVIDUAL}) self.assertTrue(client.canRead(self.TIMEOUT)) frame = client.receiveFrame() client.ack(frame) self.assertEqual(frame.version, version) self.assertEqual(frame.headers[key], headers[key]) self.assertFalse(client.canRead(self.TIMEOUT)) client.unsubscribe(token) client.disconnect(receipt='4712')
def main(): logging.basicConfig() logging.getLogger().setLevel(logging.WARN) client = Stomp(stomp_config) client.connect() client.send(stomp_queue, body=stomp_body) client.subscribe(stomp_queue, {StompSpec.ACK_HEADER: StompSpec.ACK_CLIENT, 'activemq.prefetchSize': 1}) if client.canRead(timeout=5): frame = client.receiveFrame() print 'Got %s' % frame.info() client.ack(frame) frame_body = str(frame.body) if frame_body == stomp_body: print "OK: Message received" status = 'ok' else: print "WARNING: Incorrect message body; is %s, should be %s" % (frame_body, stomp_body) status = 'warning' else: print "CRITICAL: Timed out while trying to collect the message" status = 'critical' client.disconnect() client.close(flush=True) return exit_codes[status]
def test_6_integration_stomp_1_1_encoding_and_escaping_headers(self): if BROKER == 'rabbitmq': print 'Broker does not support unicode characters. Skipping this test case.' return version = StompSpec.VERSION_1_1 client = Stomp(self.getConfig(version)) try: client.connect(host=VIRTUALHOST, versions=[version]) except StompProtocolError as e: print 'Broker does not support STOMP protocol %s. Skipping this test case. [%s]' % (e, version) return specialCharactersHeader = u'fen\xeatre:\r\n' headers = {specialCharactersHeader: u'\xbfqu\xe9 tal?, s\xfc\xdf'} client.send(self.DESTINATION, body='test message 1', headers=headers) self.assertFalse(client.canRead(self.TIMEOUT)) token = client.subscribe(self.DESTINATION, {StompSpec.ID_HEADER: 4711, StompSpec.ACK_HEADER: StompSpec.ACK_CLIENT_INDIVIDUAL}) self.assertTrue(client.canRead(self.TIMEOUT)) frame = client.receiveFrame() client.ack(frame) self.assertEquals(frame.version, version) self.assertEquals(frame.headers[specialCharactersHeader], headers[specialCharactersHeader]) self.assertFalse(client.canRead(self.TIMEOUT)) client.unsubscribe(token) client.disconnect(receipt='4712')
def recv_stomp (): config = StompConfig (stomp_uri) client = Stomp (config) client.connect () client.subscribe (stomp_source, {StompSpec.ACK_HEADER: StompSpec.ACK_CLIENT_INDIVIDUAL}) frame = client.receiveFrame () print "Received: {}".format (frame.info ()) client.ack (frame) client.disconnect ()
def main(): parser = argparse.ArgumentParser() parser.add_argument('-a', action='store_true', default=False, help='client ack') parser.add_argument('-b', action='store_true', default=False, help='write body only') parser.add_argument('-d', nargs=1, required=True, help='destination', metavar='dest') parser.add_argument('-f', nargs=1, required=True, help='file with recorded msgs', metavar='file') parser.add_argument('-n', nargs=1, default=False, help='number of msgs', metavar='int') parser.add_argument('-r', action='store_true', default=False, help='reconnect') parser.add_argument('-s', nargs=1, required=True, help='broker', metavar='broker') parser.add_argument('-t', nargs=1, default=False, help='recv msg every sec', metavar='float') args = parser.parse_args() broker = 'tcp://%s:6163' % (args.s[0]) config = StompConfig(broker) client = Stomp(config) if not args.r: client.connect() if args.a: client.subscribe(args.d[0], {StompSpec.ACK_HEADER: StompSpec.ACK_CLIENT_INDIVIDUAL}) else: client.subscribe(args.d[0], {StompSpec.ACK_HEADER: StompSpec.ACK_AUTO}) try: consumed = 0 while True: if args.r: client.connect() if args.a: client.subscribe(args.d[0], {StompSpec.ACK_HEADER: StompSpec.ACK_CLIENT_INDIVIDUAL}) else: client.subscribe(args.d[0], {StompSpec.ACK_HEADER: StompSpec.ACK_AUTO}) if args.t: time.sleep(float(args.t[0])) else: time.sleep(1) fo = open(args.f[0], 'a+') frame = client.receiveFrame() consumed += 1 if args.b: fo.write(frame.body+'\n') else: fo.write(frame.info()+'\n') fo.close() if args.a: client.ack(frame) if args.r: client.disconnect() if args.n: if consumed == int(args.n[0]): raise KeyboardInterrupt except KeyboardInterrupt: client.stop() client.disconnect() raise SystemExit(1) except stompest.error.StompProtocolError: pass
def test_1_integration(self): config = self.getConfig(StompSpec.VERSION_1_0) client = Stomp(config) client.connect(host=VIRTUALHOST) client.send(self.DESTINATION, b'test message 1') client.send(self.DESTINATION, b'test message 2') self.assertFalse(client.canRead(self.TIMEOUT)) client.subscribe(self.DESTINATION, {StompSpec.ACK_HEADER: StompSpec.ACK_CLIENT_INDIVIDUAL}) self.assertTrue(client.canRead(self.TIMEOUT)) client.ack(client.receiveFrame()) self.assertTrue(client.canRead(self.TIMEOUT)) client.ack(client.receiveFrame()) self.assertFalse(client.canRead(self.TIMEOUT))
def test_3_socket_failure_and_replay(self): client = Stomp(self.getConfig(StompSpec.VERSION_1_0)) client.connect(host=VIRTUALHOST) headers = {StompSpec.ACK_HEADER: StompSpec.ACK_CLIENT_INDIVIDUAL} token = client.subscribe(self.DESTINATION, headers) client.sendFrame(StompFrame(StompSpec.DISCONNECT)) # DISCONNECT frame is out-of-band, as far as the session is concerned -> unexpected disconnect self.assertRaises(StompConnectionError, client.receiveFrame) client.connect(host=VIRTUALHOST) client.send(self.DESTINATION, b'test message 1') client.ack(client.receiveFrame()) client.unsubscribe(token) headers = {StompSpec.ID_HEADER: 'bla', StompSpec.ACK_HEADER: StompSpec.ACK_CLIENT_INDIVIDUAL} client.subscribe(self.DESTINATION, headers) headers[StompSpec.DESTINATION_HEADER] = self.DESTINATION client.sendFrame(StompFrame(StompSpec.DISCONNECT)) # DISCONNECT frame is out-of-band, as far as the session is concerned -> unexpected disconnect self.assertRaises(StompConnectionError, client.receiveFrame) client.connect(host=VIRTUALHOST) client.send(self.DESTINATION, b'test message 2') client.ack(client.receiveFrame()) client.unsubscribe((StompSpec.ID_HEADER, 'bla')) client.disconnect()
def _test_4_integration_stomp(self, version): client = Stomp(self.getConfig(version)) try: client.connect(host=VIRTUALHOST, versions=[version]) except StompProtocolError as e: print('Broker does not support STOMP protocol %s. Skipping this test case. [%s]' % (e, version)) return client.send(self.DESTINATION, b'test message 1') client.send(self.DESTINATION, b'test message 2') self.assertFalse(client.canRead(self.TIMEOUT)) token = client.subscribe(self.DESTINATION, {StompSpec.ID_HEADER: 4711, StompSpec.ACK_HEADER: StompSpec.ACK_CLIENT_INDIVIDUAL}) self.assertTrue(client.canRead(self.TIMEOUT)) client.ack(client.receiveFrame()) self.assertTrue(client.canRead(self.TIMEOUT)) client.ack(client.receiveFrame()) self.assertFalse(client.canRead(self.TIMEOUT)) client.unsubscribe(token) client.send(self.DESTINATION, b'test message 3', receipt='4711') self.assertTrue(client.canRead(self.TIMEOUT)) self.assertEqual(client.receiveFrame(), StompFrame(StompSpec.RECEIPT, {StompSpec.RECEIPT_ID_HEADER: '4711'})) self.assertFalse(client.canRead(self.TIMEOUT)) client.subscribe(self.DESTINATION, {StompSpec.ID_HEADER: 4711, StompSpec.ACK_HEADER: StompSpec.ACK_CLIENT_INDIVIDUAL}) self.assertTrue(client.canRead(self.TIMEOUT)) client.ack(client.receiveFrame()) self.assertFalse(client.canRead(self.TIMEOUT)) client.disconnect(receipt='4712') self.assertEqual(client.receiveFrame(), StompFrame(StompSpec.RECEIPT, {StompSpec.RECEIPT_ID_HEADER: '4712'})) self.assertRaises(StompConnectionError, client.receiveFrame) client.connect(host=VIRTUALHOST) client.disconnect(receipt='4711') self.assertEqual(client.receiveFrame(), StompFrame(StompSpec.RECEIPT, {StompSpec.RECEIPT_ID_HEADER: '4711'})) client.close() self.assertRaises(StompConnectionError, client.canRead, 0)
def test_4_integration_stomp_1_1(self): if StompSpec.VERSION_1_1 not in commands.versions(VERSION): print 'This broker does not support STOMP protocol version 1.1' return client = Stomp(self.getConfig(StompSpec.VERSION_1_1)) client.connect(host=VIRTUALHOST) client.send(self.DESTINATION, 'test message 1') client.send(self.DESTINATION, 'test message 2') self.assertFalse(client.canRead(self.TIMEOUT)) token = client.subscribe(self.DESTINATION, {StompSpec.ID_HEADER: 4711, StompSpec.ACK_HEADER: 'client-individual'}) self.assertTrue(client.canRead(self.TIMEOUT)) client.ack(client.receiveFrame()) self.assertTrue(client.canRead(self.TIMEOUT)) client.ack(client.receiveFrame()) self.assertFalse(client.canRead(self.TIMEOUT)) client.unsubscribe(token) client.send(self.DESTINATION, 'test message 3', receipt='4711') self.assertTrue(client.canRead(self.TIMEOUT)) self.assertEquals(client.receiveFrame(), StompFrame(StompSpec.RECEIPT, {'receipt-id': '4711'})) self.assertFalse(client.canRead(self.TIMEOUT)) client.subscribe(self.DESTINATION, {StompSpec.ID_HEADER: 4711, StompSpec.ACK_HEADER: 'client-individual'}) self.assertTrue(client.canRead(self.TIMEOUT)) client.ack(client.receiveFrame()) self.assertFalse(client.canRead(self.TIMEOUT)) client.disconnect(receipt='4712') self.assertEquals(client.receiveFrame(), StompFrame(StompSpec.RECEIPT, {'receipt-id': '4712'})) self.assertRaises(StompConnectionError, client.receiveFrame) client.connect(host=VIRTUALHOST) client.disconnect(receipt='4711') self.assertEquals(client.receiveFrame(), StompFrame(StompSpec.RECEIPT, {'receipt-id': '4711'})) client.close() self.assertRaises(StompConnectionError, client.canRead, 0)
def run(self): if(processgid > 0): os.setgid(processgid) if(processuid > 0): os.setuid(processuid) config = StompConfig('tcp://%(HOST)s:%(PORT)s' % ActiveMQ) topic = "/topic/%(FILESYNCTOPIC)s" % ActiveMQ client = Stomp(config) self.logger = logging.getLogger('nfssync') self.logger.setLevel(logging.DEBUG) handler = TimedRotatingFileHandler(LOGFILE, when='midnight', interval=1, backupCount=30) formatter = logging.Formatter('%(asctime)s - %(name)s - %(levelname)s - %(message)s') handler.setFormatter(formatter) self.logger.addHandler(handler) try: client.connect() client.subscribe(topic, {StompSpec.ACK_HEADER: StompSpec.ACK_CLIENT_INDIVIDUAL}) while True: frame = client.receiveFrame() subdir = frame.body srcpath = os.path.join(ActiveMQ['SRCDIR'], subdir) dstpath = os.path.dirname(os.path.join(ActiveMQ['DSTDIR'], subdir)) self.logger.info("Syncing %s to %s" % (srcpath,dstpath)) if(not os.path.exists(srcpath)): msg = "Source %s does not exist" % srcpath self.logger.error(msg) proxy_email(email_subject_error, msg) client.ack(frame) continue elif(not os.path.isdir(srcpath)): msg = "Source %s is not a directory" % srcpath self.logger.error(msg) proxy_email(email_subject_error, msg) client.ack(frame) continue elif(not os.path.exists(dstpath)): msg = "Destination %s does not exist" % dstpath self.logger.warning(msg) proxy_email(email_subject_warning, msg) os.umask(0) os.makedirs(dstpath, 0777) cmd = "rsync -avzq --delete %s %s" % (srcpath,dstpath) if(call(cmd, shell=True) > 0): msg = "Sync %s failed" % cmd self.logger.error(msg) proxy_email(email_subject, msg) client.ack(frame) except Exception, e: msg = "Exception in %s: %s" % (sys.argv[0], str(e)) self.logger.error(msg) proxy_email(email_subject_error, msg) exit(1)
def test_2_transaction(self): config = self.getConfig(StompSpec.VERSION_1_0) client = Stomp(config) client.connect(host=VIRTUALHOST) client.subscribe(self.DESTINATION, {StompSpec.ACK_HEADER: StompSpec.ACK_CLIENT_INDIVIDUAL}) self.assertFalse(client.canRead(self.TIMEOUT)) with client.transaction(4711) as transaction: self.assertEqual(transaction, '4711') client.send(self.DESTINATION, b'test message', {StompSpec.TRANSACTION_HEADER: transaction}) self.assertFalse(client.canRead(0)) self.assertTrue(client.canRead(self.TIMEOUT)) frame = client.receiveFrame() self.assertEqual(frame.body, b'test message') client.ack(frame) with client.transaction(4713, receipt='4712') as transaction: self.assertEqual(transaction, '4713') self.assertEqual(client.receiveFrame(), StompFrame(StompSpec.RECEIPT, {StompSpec.RECEIPT_ID_HEADER: '4712-begin'})) client.send(self.DESTINATION, b'test message', {StompSpec.TRANSACTION_HEADER: transaction}) client.send(self.DESTINATION, b'test message without transaction') self.assertTrue(client.canRead(self.TIMEOUT)) frame = client.receiveFrame() self.assertEqual(frame.body, b'test message without transaction') client.ack(frame) self.assertFalse(client.canRead(0)) frames = [client.receiveFrame() for _ in range(2)] frames = list(sorted(frames, key=lambda f: f.command)) frame = frames[0] client.ack(frame) self.assertEqual(frame.body, b'test message') frame = frames[1] self.assertEqual(frame, StompFrame(StompSpec.RECEIPT, {StompSpec.RECEIPT_ID_HEADER: '4712-commit'})) try: with client.transaction(4714) as transaction: self.assertEqual(transaction, '4714') client.send(self.DESTINATION, b'test message', {StompSpec.TRANSACTION_HEADER: transaction}) raise RuntimeError('poof') except RuntimeError as e: self.assertEqual(str(e), 'poof') else: raise self.assertFalse(client.canRead(self.TIMEOUT)) client.disconnect()
class StompClient(BaseComponent): """ Send and Receive messages from a STOMP queue """ channel = "stomp" def init(self, host, port, username=None, password=None, connect_timeout=3, connected_timeout=3, version=StompSpec.VERSION_1_2, accept_versions=["1.0", "1.1", "1.2"], heartbeats=(0, 0), ssl_context=None, use_ssl=True, key_file=None, cert_file=None, ca_certs=None, ssl_version=ssl.PROTOCOL_SSLv23, key_file_password=None, proxy_host=None, proxy_port=None, proxy_user=None, proxy_password=None, channel=channel): """ Initialize StompClient. Called after __init__ """ self.channel = channel if proxy_host: LOG.info("Connect to %s:%s through proxy %s:%d", host, port, proxy_host, proxy_port) else: LOG.info("Connect to %s:%s", host, port) if use_ssl and not ssl_context: ssl_params = dict(key_file=key_file, cert_file=cert_file, ca_certs=ca_certs, ssl_version=ssl_version, password=key_file_password) LOG.info("Request to use old-style socket wrapper: %s", ssl_params) ssl_context = ssl_params if use_ssl: uri = "ssl://%s:%s" % (host, port) else: uri = "tcp://%s:%s" % (host, port) # Configure failover options so it only tries to connect once self._stomp_server = "failover:(%s)?maxReconnectAttempts=1,startupMaxReconnectAttempts=1" % uri self._stomp_config = StompConfig(uri=self._stomp_server, sslContext=ssl_context, version=version, login=username, passcode=password) self._heartbeats = heartbeats self._accept_versions = accept_versions self._connect_timeout = connect_timeout self._connected_timeout = connected_timeout Stomp._transportFactory = EnhancedStompFrameTransport Stomp._transportFactory.proxy_host = proxy_host Stomp._transportFactory.proxy_port = proxy_port Stomp._transportFactory.proxy_user = proxy_user Stomp._transportFactory.proxy_password = proxy_password self._client = Stomp(self._stomp_config) self._subscribed = {} self.server_heartbeat = None self.client_heartbeat = None self.ALLOWANCE = 2 # multiplier for heartbeat timeouts @property def connected(self): if self._client.session: return self._client.session.state == StompSession.CONNECTED else: return False @property def subscribed(self): return self._subscribed.keys() @property def stomp_logger(self): return LOG_CATEGORY @handler("disconnect") def _disconnect(self, receipt=None): if self.connected: self._client.disconnect(receipt=receipt) self._client.close(flush=True) self.fire(disconnected(reconnect=False)) self._subscribed = {} return "disconnected" def start_heartbeats(self): LOG.info("Client HB: %s Server HB: %s", self._client.clientHeartBeat, self._client.serverHeartBeat) if self._client.clientHeartBeat: if self.client_heartbeat: # Timer already exists, just reset it self.client_heartbeat.reset() else: LOG.info("Client will send heartbeats to server") # Send heartbeats at 80% of agreed rate self.client_heartbeat = Timer((self._client.clientHeartBeat / 1000.0) * 0.8, client_heartbeat(), persist=True) self.client_heartbeat.register(self) else: LOG.info("No Client heartbeats will be sent") if self._client.serverHeartBeat: if self.server_heartbeat: # Timer already exists, just reset it self.server_heartbeat.reset() else: LOG.info("Requested heartbeats from server.") # Allow a grace period on server heartbeats self.server_heartbeat = Timer((self._client.serverHeartBeat / 1000.0) * self.ALLOWANCE, server_heartbeat(), persist=True) self.server_heartbeat.register(self) else: LOG.info("Expecting no heartbeats from Server") @handler("connect") def connect(self, event, host=None, *args, **kwargs): """ connect to Stomp server """ LOG.info("Connect to Stomp...") try: self._client.connect(heartBeats=self._heartbeats, host=host, versions=self._accept_versions, connectTimeout=self._connect_timeout, connectedTimeout=self._connected_timeout) LOG.info("State after Connection Attempt: %s", self._client.session.state) if self.connected: LOG.info("Connected to %s", self._stomp_server) self.fire(connected()) self.start_heartbeats() return "success" except StompConnectionError: LOG.debug(traceback.format_exc()) self.fire(connection_failed(self._stomp_server)) event.success = False return "fail" @handler("server_heartbeat") def check_server_heartbeat(self, event): """ Confirm that heartbeat from server hasn't timed out """ now = time.time() last = self._client.lastReceived or 0 if last: elapsed = now - last else: elapsed = -1 LOG.debug("Last received data %d seconds ago", elapsed) if ((self._client.serverHeartBeat / 1000.0) * self.ALLOWANCE + last) < now: LOG.error("Server heartbeat timeout. %d seconds since last heartbeat. Disconnecting.", elapsed) event.success = False self.fire(heartbeat_timeout()) if self.connected: self._client.disconnect() # TODO: Try to auto-reconnect? @handler("client_heartbeat") def send_heartbeat(self, event): if self.connected: LOG.debug("Sending heartbeat") try: self._client.beat() except StompConnectionError: event.success = False self.fire(disconnected()) @handler("generate_events") def generate_events(self, event): if not self.connected: return try: if self._client.canRead(1): frame = self._client.receiveFrame() LOG.debug("Recieved frame %s", frame) self.fire(message(frame)) except StompConnectionError: self.fire(disconnected()) @handler("send") def send(self, event, destination, body, headers=None, receipt=None): LOG.debug("send()") if not self.connected: LOG.error("Can't send when Stomp is disconnected") self.fire(on_stomp_error(None, Exception("Message send attempted with stomp disconnected"))) event.success = False return try: self._client.send(destination, body=body.encode('utf-8'), headers=headers, receipt=receipt) LOG.debug("Message sent") except StompConnectionError as err: event.success = False self.fire(disconnected()) except StompError as err: LOG.error("Error sending ack") event.success = False self.fire(on_stomp_error(None, err)) @handler("subscribe") def _subscribe(self, event, destination, ack=ACK_CLIENT_INDIVIDUAL): if ack not in ACK_MODES: raise ValueError("Invalid client ack mode specified") LOG.info("Subscribe to message destination %s", destination) try: # Set ID to match destination name for easy reference later frame, token = self._client.subscribe(destination, headers={StompSpec.ACK_HEADER: ack, 'id': destination}) self._subscribed[destination] = token except StompConnectionError as err: event.success = False self.fire(disconnected()) except StompError as err: event.success = False LOG.debug(traceback.format_exc()) self.fire(on_stomp_error(None, err)) @handler("unsubscribe") def _unsubscribe(self, event, destination): if destination not in self._subscribed: LOG.error("Unsubscribe Request Ignored. Not subscribed to %s", destination) return try: token = self._subscribed.pop(destination) frame = self._client.unsubscribe(token) LOG.debug("Unsubscribed: %s", frame) except StompConnectionError as err: event.success = False self.fire(disconnected()) except StompError as err: LOG.error("Error sending ack") event.success = False self.fire(on_stomp_error(frame, err)) @handler("message") def on_message(self, event, headers, message): LOG.info("Stomp message received") @handler("ack") def ack_frame(self, event, frame): LOG.debug("ack_frame()") try: self._client.ack(frame) LOG.debug("Ack Sent") except StompConnectionError as err: LOG.error("Error sending ack") event.success = False self.fire(disconnected()) except StompError as err: LOG.error("Error sending ack") event.success = False self.fire(on_stomp_error(frame, err)) def get_subscription(self, frame): """ Get subscription from frame """ LOG.info(self._subscribed) _, token = self._client.message(frame) return self._subscribed[token]
class Client(object): def __init__(self): self.stompest = None self.greenlet = None self.subscriptions = {} self._last_id = 0 def _next_id(self): self._last_id += 1 return self._last_id def connect(self): if not self.stompest: CONFIG, EXTRA = _get_config() self._hostname = EXTRA.get('hostname', None) self.stompest = Stomp(CONFIG) if self.stompest.session.state != StompSession.DISCONNECTED: return while True: try: self.stompest.connect(host=self._hostname) logger.info('Connected') break except StompConnectTimeout: continue if not self.greenlet: self.greenlet = gevent.spawn(self._run) def _run(self): while True: try: frame = self.stompest.receiveFrame() self.stompest.ack(frame) if frame.command == 'ERROR': logger.error(frame.info()) elif frame.command == 'MESSAGE': token = self.stompest.message(frame) if self.subscriptions.get(token): subscription = self.subscriptions[token] subscription.call(frame) else: logger.error( "Received a message for %s (%s) but there was no matching subscription." % (frame.headers.get(StompSpec.DESTINATION_HEADER, '???'), token)) else: logger.warning("Unknown frame: %s" % frame.info()) # @todo Handle receipts except (gevent.GreenletExit, KeyboardInterrupt): # @todo Include a receipt in the disconnect. And instead of breaking right away wait for the # receipt frame before disconnecting and consider waiting on any greenlets we started. self.stompest.disconnect() break except StompConnectionError: # We've been disconnected from the server. Try reconnecting to it. self.connect() def on(self, destination, callback): self.connect() token = self.stompest.subscribe( destination, { StompSpec.ACK_HEADER: StompSpec.ACK_CLIENT_INDIVIDUAL, StompSpec.ID_HEADER: self._next_id(), }) subscription = Subscription(conn=self, destination=destination, token=token, callback=callback) self.subscriptions[subscription.token] = subscription # @todo consider adding optional support for additional custom headers def send(self, cmd, destination): self.connect() body = json.dumps(cmd) headers = {} headers[ StompSpec.CONTENT_TYPE_HEADER] = 'application/json;charset=UTF-8' self.stompest.send(destination, body, headers) def join(self): try: self.connect() except (gevent.GreenletExit, KeyboardInterrupt): return try: gevent.joinall([self.greenlet]) except KeyboardInterrupt: self.greenlet.kill(block=True)
from stompest.config import StompConfig from stompest.protocol import StompSpec from stompest.sync import Stomp CONFIG = StompConfig('tcp://localhost:61613') QUEUE = '/queue/test' if __name__ == '__main__': client = Stomp(CONFIG) client.connect() client.subscribe(QUEUE, {StompSpec.ACK_HEADER: StompSpec.ACK_CLIENT_INDIVIDUAL}) while True: frame = client.receiveFrame() print('Got %s' % frame.info()) client.ack(frame) client.disconnect()
class JMSClient(object): """Class JMSClient """ _mh = None _client = None _host = None _port = None _user = None _passw = None _verbose = None _is_connected = None def __init__(self, verbose=False): """Class constructor Called when the object is initialized Args: verbose (bool): verbose mode """ try: self._mh = MasterHead.get_head() self._verbose = verbose if (self._verbose): basicConfig() getLogger().setLevel(DEBUG) except StompError as ex: self._mh.demsg('htk_on_error', ex, self._mh.fromhere()) @property def client(self): """ STOMP client property getter """ return self._client @property def host(self): """ server host property getter """ return self._host @property def port(self): """ server port property getter """ return self._port @property def user(self): """ username property getter """ return self._user @property def passw(self): """ user password property getter """ return self._passw @property def verbose(self): """ verbose mode property getter """ return self._verbose @property def is_connected(self): """ is_connected property getter """ return self._is_connected def connect(self, host, port=61613, user=None, passw=None, timeout=10): """Method connects to server Args: host (str): hostname port (str): port user (str): username passw (str): password timeout (int): timeout Returns: bool: result Raises: event: jms_before_connect event: jms_after_connected """ try: msg = 'host:{0}, port:{1}, user:{2}, passw:{3}, timeout:{4}'.format( host, port, user, passw, timeout) self._mh.demsg('htk_on_debug_info', self._mh._trn.msg( 'htk_jms_connecting', msg), self._mh.fromhere()) ev = event.Event( 'jms_before_connect', host, port, user, passw, timeout) if (self._mh.fire_event(ev) > 0): host = ev.argv(0) port = ev.argv(1) user = ev.argv(2) passw = ev.argv(3) timeout = ev.argv(4) self._host = host self._port = port self._user = user self._passw = passw if (ev.will_run_default()): self._client = Stomp(StompConfig('tcp://{0}:{1}'.format(self._host, self._port), login=self._user, passcode=self._passw)) self._client.connect( connectTimeout=timeout, connectedTimeout=timeout) self._is_connected = True self._mh.demsg('htk_on_debug_info', self._mh._trn.msg( 'htk_jms_connected'), self._mh.fromhere()) ev = event.Event('jms_after_connect') self._mh.fire_event(ev) return True except StompError as ex: self._mh.demsg('htk_on_error', ex, self._mh.fromhere()) return False def disconnect(self): """Method disconnects from server Args: none Returns: bool: result """ try: self._mh.demsg('htk_on_debug_info', self._mh._trn.msg( 'htk_jms_disconnecting'), self._mh.fromhere()) if (not self._is_connected): self._mh.demsg('htk_on_warning', self._mh._trn.msg( 'htk_jms_not_connected'), self._mh.fromhere()) return False else: self._client.disconnect() self._client.close() self._is_connected = False self._mh.demsg('htk_on_debug_info', self._mh._trn.msg( 'htk_jms_disconnected'), self._mh.fromhere()) return True except StompError as ex: self._mh.demsg('htk_on_error', ex, self._mh.fromhere()) return False def send(self, destination_name, message, destination_type='queue', headers={}): """Method sends message JMS headers - JMSCorrelationID, JMSExpiration, JMSDeliveryMode, JMSPriority, JMSReplyTo, JMSType Args: destination_name (str): queue|topic name message (str): message destination_type (str): queue|topic headers (dict): JMS headers, key - title, value - string Returns: bool: result Raises: event: jms_before_send event: jms_after_send """ try: msg = 'destination_name:{0}, message:{1}, destination_type:{2}, headers:{3}'.format( destination_name, message, destination_type, headers) self._mh.demsg('htk_on_debug_info', self._mh._trn.msg( 'htk_jms_sending_msg', msg), self._mh.fromhere()) if (not self._is_connected): self._mh.demsg('htk_on_warning', self._mh._trn.msg( 'htk_jms_not_connected'), self._mh.fromhere()) return False ev = event.Event( 'jms_before_send', destination_name, message, destination_type, headers) if (self._mh.fire_event(ev) > 0): destination_name = ev.argv(0) message = ev.argv(1) destination_type = ev.argv(2) headers = ev.argv(3) if (ev.will_run_default()): headers_new = {} for key, value in headers.items(): if (key in mapping): headers_new[mapping[key]] = value self._client.send('/{0}/{1}'.format(destination_type, destination_name), message if ( version_info[0] == 2) else message.encode('utf-8'), headers_new) self._mh.demsg('htk_on_debug_info', self._mh._trn.msg( 'htk_jms_msg_sent'), self._mh.fromhere()) ev = event.Event('jms_after_send') self._mh.fire_event(ev) return True except StompError as ex: self._mh.demsg('htk_on_error', ex, self._mh.fromhere()) return False def receive(self, destination_name, cnt=1): """Method receives messages Args: destination_name (str): queue name cnt (int): count of messages Returns: list: messages as dictionary {'message', JMS headers} Raises: event: jms_before_receive event: jms_after_receive """ try: msg = 'destination_name:{0}, count:{1}'.format( destination_name, cnt) self._mh.demsg('htk_on_debug_info', self._mh._trn.msg( 'htk_jms_receiving_msg', msg), self._mh.fromhere()) if (not self._is_connected): self._mh.demsg('htk_on_warning', self._mh._trn.msg( 'htk_jms_not_connected'), self._mh.fromhere()) return None ev = event.Event('jms_before_receive', destination_name, cnt) if (self._mh.fire_event(ev) > 0): destination_name = ev.argv(0) cnt = ev.argv(1) if (ev.will_run_default()): token = self._client.subscribe('/queue/{0}'.format(destination_name), {StompSpec.ACK_HEADER: StompSpec.ACK_CLIENT_INDIVIDUAL}) msgs = [] i = 0 while (i < cnt and self._client.canRead(1)): frame = self._client.receiveFrame() if (frame.command != 'MESSAGE'): break self._client.ack(frame) msgs.append(frame) i = i + 1 self._client.unsubscribe(token) messages = [] for msg in msgs: message = {} message['message'] = msg.body.decode() for header in msg.rawHeaders: if (header[0] in mapping.values()): message[ list(mapping.keys())[list(mapping.values()).index(header[0])]] = header[1] messages.append(message) self._mh.demsg('htk_on_debug_info', self._mh._trn.msg( 'htk_jms_msg_received', len(messages)), self._mh.fromhere()) ev = event.Event('jms_after_receive') self._mh.fire_event(ev) return messages except StompError as ex: self._mh.demsg('htk_on_error', ex, self._mh.fromhere()) return None def browse(self, destination_name, cnt=100, jms_correlation_id=None, jms_type=None): """Method browses queue Args: destination_name (str): queue name cnt (int): count of messages jms_correlation_id (str): requested JMSCorrelationID jms_type (str): requested JMSType Returns: list: messages as dictionary {'message', JMS headers} Raises: event: jms_before_browse event: jms_after_browse """ try: msg = 'destination_name:{0}, count:{1}, jms_correlation_id:{2}, jms_type:{3}'.format( destination_name, cnt, jms_correlation_id, jms_type) self._mh.demsg('htk_on_debug_info', self._mh._trn.msg( 'htk_jms_browsing', msg), self._mh.fromhere()) if (not self._is_connected): self._mh.demsg('htk_on_warning', self._mh._trn.msg( 'htk_jms_not_connected'), self._mh.fromhere()) return None ev = event.Event( 'jms_before_browse', destination_name, cnt, jms_correlation_id, jms_type) if (self._mh.fire_event(ev) > 0): destination_name = ev.argv(0) cnt = ev.argv(1) jms_correlation_id = ev.argv(2) jms_type = ev.argv(3) if (ev.will_run_default()): token = self._client.subscribe('/queue/{0}'.format(destination_name), {StompSpec.ACK_HEADER: StompSpec.ACK_CLIENT_INDIVIDUAL}) msgs = [] i = 0 while (i < cnt and self._client.canRead(1)): frame = self._client.receiveFrame() correlation_id = None type = None for header in frame.rawHeaders: if (header[0] == 'correlation-id'): correlation_id = header[1] elif (header[0] == 'type'): type = header[1] if ((jms_correlation_id == None or jms_correlation_id == correlation_id) and (jms_type == None or jms_type == type)): msgs.append(frame) i = i + 1 self._client.unsubscribe(token) messages = [] for msg in msgs: message = {} message['message'] = msg.body.decode() for header in msg.rawHeaders: if (header[0] in mapping.values()): message[ list(mapping.keys())[list(mapping.values()).index(header[0])]] = header[1] messages.append(message) self._mh.demsg('htk_on_debug_info', self._mh._trn.msg( 'htk_jms_msg_received', len(messages)), self._mh.fromhere()) ev = event.Event('jms_after_browse') self._mh.fire_event(ev) return messages except StompError as ex: self._mh.demsg('htk_on_error', ex, self._mh.fromhere()) return None
from stompest.config import StompConfig from stompest.sync import Stomp server = "hostname" port = "61613" vhost = "yourvhost" login = "******" passcode = "password" destination = "/queue/test" #There're more options other than /queue/... while True: try: client = Stomp(StompConfig("tcp://" + server + ":" + port, login = login, passcode = passcode, version = "1.2")) client.connect(versions = ["1.2"], host = vhost, heartBeats = (0, 60000)) #CONNECT subscription = client.subscribe(destination, {"ack": "client", "id": "0"}) #SUBSCRIBE while True: frame = client.receiveFrame() try: print frame.body client.ack(frame) #ACK except: print "Error: Can't handle message received, NACKing" client.nack(frame) #NACK except Exception, e: #reconnect on exception print "Exception handled, reconnecting...\nDetail:\n%s" % e try: client.disconnect() except: pass time.sleep(5)
class Client(object): def __init__(self): self.stompest = None self.greenlet = None self.subscriptions = {} self._last_id = 0 def _next_id(self): self._last_id += 1 return self._last_id def connect(self): if not self.stompest: CONFIG, EXTRA = _get_config() self._hostname = EXTRA.get('hostname', None) self.stompest = Stomp(CONFIG) if self.stompest.session.state != StompSession.DISCONNECTED: return while True: try: self.stompest.connect(host=self._hostname) logger.info('Connected') break except StompConnectTimeout: continue if not self.greenlet: self.greenlet = gevent.spawn(self._run) def _run(self): while True: try: frame = self.stompest.receiveFrame() self.stompest.ack(frame) if frame.command == 'ERROR': logger.error(frame.info()) elif frame.command == 'MESSAGE': token = self.stompest.message(frame) if self.subscriptions.get(token): subscription = self.subscriptions[token] subscription.call(frame) else: logger.error("Received a message for %s (%s) but there was no matching subscription." % (frame.headers.get(StompSpec.DESTINATION_HEADER, '???'), token)) else: logger.warning("Unknown frame: %s" % frame.info()) # @todo Handle receipts except (gevent.GreenletExit, KeyboardInterrupt): # @todo Include a receipt in the disconnect. And instead of breaking right away wait for the # receipt frame before disconnecting and consider waiting on any greenlets we started. self.stompest.disconnect() break except StompConnectionError: # We've been disconnected from the server. Try reconnecting to it. self.connect() def on(self, destination, callback): self.connect() token = self.stompest.subscribe(destination, { StompSpec.ACK_HEADER: StompSpec.ACK_CLIENT_INDIVIDUAL, StompSpec.ID_HEADER: self._next_id(), }) subscription = Subscription( conn=self, destination=destination, token=token, callback=callback ) self.subscriptions[subscription.token] = subscription; # @todo consider adding optional support for additional custom headers def send(self, cmd, destination): self.connect() body = json.dumps(cmd) headers = {} headers[StompSpec.CONTENT_TYPE_HEADER] = 'application/json;charset=UTF-8' self.stompest.send(destination, body, headers) def join(self): try: self.connect() except (gevent.GreenletExit, KeyboardInterrupt): return try: gevent.joinall([self.greenlet]) except KeyboardInterrupt: self.greenlet.kill(block=True)
from stompest.config import StompConfig from stompest.protocol import StompSpec from stompest.sync import Stomp CONFIG = StompConfig('tcp://localhost:61613', version=StompSpec.VERSION_1_1) QUEUE = '/queue/test' if __name__ == '__main__': client = Stomp(CONFIG) client.connect(heartBeats=(0, 10000)) client.subscribe(QUEUE, {StompSpec.ID_HEADER: 1, StompSpec.ACK_HEADER: StompSpec.ACK_CLIENT_INDIVIDUAL}) client.send(QUEUE, 'test message 1') client.send(QUEUE, 'test message 2') while True: frame = client.receiveFrame() print 'Got %s' % frame.info() client.ack(frame) client.disconnect()
class StompClient(BaseComponent): """ Send and Receive messages from a STOMP queue """ channel = "stomp" def init(self, host, port, username=None, password=None, connect_timeout=3, connected_timeout=3, version=StompSpec.VERSION_1_2, accept_versions=["1.0", "1.1", "1.2"], heartbeats=(0, 0), ssl_context=None, use_ssl=True, key_file=None, cert_file=None, ca_certs=None, ssl_version=ssl.PROTOCOL_SSLv23, key_file_password=None, proxy_host=None, proxy_port=None, proxy_user=None, proxy_password=None, channel=channel): """ Initialize StompClient. Called after __init__ """ self.channel = channel if proxy_host: LOG.info("Connect to %s:%s through proxy %s:%d", host, port, proxy_host, proxy_port) else: LOG.info("Connect to %s:%s", host, port) if use_ssl and not ssl_context: ssl_params = dict(key_file=key_file, cert_file=cert_file, ca_certs=ca_certs, ssl_version=ssl_version, password=key_file_password) LOG.info("Request to use old-style socket wrapper: %s", ssl_params) ssl_context = ssl_params if use_ssl: uri = "ssl://%s:%s" % (host, port) else: uri = "tcp://%s:%s" % (host, port) # Configure failover options so it only tries to connect once self._stomp_server = "failover:(%s)?maxReconnectAttempts=1,startupMaxReconnectAttempts=1" % uri self._stomp_config = StompConfig(uri=self._stomp_server, sslContext=ssl_context, version=version, login=username, passcode=password) self._heartbeats = heartbeats self._accept_versions = accept_versions self._connect_timeout = connect_timeout self._connected_timeout = connected_timeout Stomp._transportFactory = EnhancedStompFrameTransport Stomp._transportFactory.proxy_host = proxy_host Stomp._transportFactory.proxy_port = proxy_port Stomp._transportFactory.proxy_user = proxy_user Stomp._transportFactory.proxy_password = proxy_password self._client = Stomp(self._stomp_config) self._subscribed = {} self.server_heartbeat = None self.client_heartbeat = None self.ALLOWANCE = 2 # multiplier for heartbeat timeouts @property def connected(self): if self._client.session: return self._client.session.state == StompSession.CONNECTED else: return False @property def subscribed(self): return self._subscribed.keys() @property def stomp_logger(self): return LOG_CATEGORY @handler("disconnect") def _disconnect(self, receipt=None): if self.connected: self._client.disconnect(receipt=receipt) self._client.close(flush=True) self.fire(disconnected(reconnect=False)) self._subscribed = {} return "disconnected" def start_heartbeats(self): LOG.info("Client HB: %s Server HB: %s", self._client.clientHeartBeat, self._client.serverHeartBeat) if self._client.clientHeartBeat: if self.client_heartbeat: # Timer already exists, just reset it self.client_heartbeat.reset() else: LOG.info("Client will send heartbeats to server") # Send heartbeats at 80% of agreed rate self.client_heartbeat = Timer( (self._client.clientHeartBeat / 1000.0) * 0.8, client_heartbeat(), persist=True) self.client_heartbeat.register(self) else: LOG.info("No Client heartbeats will be sent") if self._client.serverHeartBeat: if self.server_heartbeat: # Timer already exists, just reset it self.server_heartbeat.reset() else: LOG.info("Requested heartbeats from server.") # Allow a grace period on server heartbeats self.server_heartbeat = Timer( (self._client.serverHeartBeat / 1000.0) * self.ALLOWANCE, server_heartbeat(), persist=True) self.server_heartbeat.register(self) else: LOG.info("Expecting no heartbeats from Server") @handler("connect") def connect(self, event, host=None, *args, **kwargs): """ connect to Stomp server """ LOG.info("Connect to Stomp...") try: self._client.connect(heartBeats=self._heartbeats, host=host, versions=self._accept_versions, connectTimeout=self._connect_timeout, connectedTimeout=self._connected_timeout) LOG.info("State after Connection Attempt: %s", self._client.session.state) if self.connected: LOG.info("Connected to %s", self._stomp_server) self.fire(connected()) self.start_heartbeats() return "success" except StompConnectionError as err: LOG.debug(traceback.format_exc()) self.fire(connection_failed(self._stomp_server)) event.success = False return "fail" @handler("server_heartbeat") def check_server_heartbeat(self, event): """ Confirm that heartbeat from server hasn't timed out """ now = time.time() last = self._client.lastReceived or 0 if last: elapsed = now - last else: elapsed = -1 LOG.debug("Last received data %d seconds ago", elapsed) if ((self._client.serverHeartBeat / 1000.0) * self.ALLOWANCE + last) < now: LOG.error( "Server heartbeat timeout. %d seconds since last heartbeat. Disconnecting.", elapsed) event.success = False self.fire(heartbeat_timeout()) if self.connected: self._client.disconnect() # TODO: Try to auto-reconnect? @handler("client_heartbeat") def send_heartbeat(self, event): if self.connected: LOG.debug("Sending heartbeat") try: self._client.beat() except StompConnectionError as err: event.success = False self.fire(disconnected()) @handler("generate_events") def generate_events(self, event): if not self.connected: return try: if self._client.canRead(1): frame = self._client.receiveFrame() LOG.debug("Recieved frame %s", frame) self.fire(message(frame)) except StompConnectionError as err: self.fire(disconnected()) @handler("send") def send(self, event, destination, body, headers=None, receipt=None): LOG.debug("send()") if not self.connected: LOG.error("Can't send when Stomp is disconnected") self.fire( on_stomp_error( None, Exception( "Message send attempted with stomp disconnected"))) event.success = False return try: self._client.send(destination, body=body.encode('utf-8'), headers=headers, receipt=receipt) LOG.debug("Message sent") except StompConnectionError as err: event.success = False self.fire(disconnected()) except StompError as err: LOG.error("Error sending ack") event.success = False self.fire(on_stomp_error(None, err)) @handler("subscribe") def _subscribe(self, event, destination, ack=ACK_CLIENT_INDIVIDUAL): if ack not in ACK_MODES: raise ValueError("Invalid client ack mode specified") LOG.info("Subscribe to message destination %s", destination) try: # Set ID to match destination name for easy reference later frame, token = self._client.subscribe(destination, headers={ StompSpec.ACK_HEADER: ack, 'id': destination }) self._subscribed[destination] = token except StompConnectionError as err: event.success = False self.fire(disconnected()) except StompError as err: event.success = False LOG.debug(traceback.format_exc()) self.fire(on_stomp_error(None, err)) @handler("unsubscribe") def _unsubscribe(self, event, destination): if destination not in self._subscribed: LOG.error("Unsubscribe Request Ignored. Not subscribed to %s", destination) return try: token = self._subscribed.pop(destination) frame = self._client.unsubscribe(token) LOG.debug("Unsubscribed: %s", frame) except StompConnectionError as err: event.success = False self.fire(disconnected()) except StompError as err: LOG.error("Error sending ack") event.success = False self.fire(on_stomp_error(frame, err)) @handler("message") def on_message(self, event, headers, message): LOG.info("Stomp message received") @handler("ack") def ack_frame(self, event, frame): LOG.debug("ack_frame()") try: self._client.ack(frame) LOG.debug("Ack Sent") except StompConnectionError as err: LOG.error("Error sending ack") event.success = False self.fire(disconnected()) except StompError as err: LOG.error("Error sending ack") event.success = False self.fire(on_stomp_error(frame, err)) def get_subscription(self, frame): """ Get subscription from frame """ LOG.info(self._subscribed) _, token = self._client.message(frame) return self._subscribed[token]