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)
Exemplo n.º 3
0
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_5_integration_stomp_1_1_heartbeat(self):
        version = StompSpec.VERSION_1_1
        if BROKER == 'apollo':
            print "Broker %s doesn't properly support heart-beating. Skipping test." % BROKER
            return

        port = 61612 if (BROKER == 'activemq') else PORT # stomp+nio on 61613 does not work properly, so use stomp on 61612
        client = Stomp(self.getConfig(StompSpec.VERSION_1_1, port))
        self.assertEquals(client.lastReceived, None)
        self.assertEquals(client.lastSent, None)

        heartBeatPeriod = 100
        try:
            client.connect(host=VIRTUALHOST, heartBeats=(heartBeatPeriod, heartBeatPeriod), versions=[version])
        except StompProtocolError as e:
            print 'Broker does not support STOMP protocol %s. Skipping this test case. [%s]' % (e, version)
            return

        self.assertTrue((time.time() - client.lastReceived) < 0.1)
        if not (client.serverHeartBeat and client.clientHeartBeat):
            print 'broker does not support heart-beating. disconnecting ...'
            client.disconnect()
            client.close()
            return

        serverHeartBeatInSeconds = client.serverHeartBeat / 1000.0
        clientHeartBeatInSeconds = client.clientHeartBeat / 1000.0

        start = time.time()
        while (time.time() - start) < (2.5 * max(serverHeartBeatInSeconds, clientHeartBeatInSeconds)):
            time.sleep(0.5 * min(serverHeartBeatInSeconds, clientHeartBeatInSeconds))
            client.canRead(0)
            self.assertTrue((time.time() - client.lastReceived) < (2.0 * serverHeartBeatInSeconds))
            if (time.time() - client.lastSent) > (0.5 * clientHeartBeatInSeconds):
                client.beat()
                self.assertTrue((time.time() - client.lastSent) < 0.1)

        start = time.time()
        try:
            while not client.canRead(0.5 * clientHeartBeatInSeconds):
                pass
        except StompConnectionError:
            self.assertTrue((time.time() - start) < (3.0 * clientHeartBeatInSeconds))
            self.assertTrue((time.time() - client.lastReceived) < (2.0 * serverHeartBeatInSeconds))
            self.assertTrue((time.time() - client.lastSent) > clientHeartBeatInSeconds)
        else:
            raise
        client.close()
Exemplo n.º 5
0
class ActiveMQSession(object):
    """
    Create a scoped session for every request and
    closes it when the request ends.
    """
    def __init__(self, stompconf):
        self.client = Stomp(stompconf)

    def process_resource(self, req, resp, resource, params):
        self.client.connect()
        resource.activemq_conn = self.client

    def process_response(self, req, resp, resource, req_succeeded):
        if hasattr(resource, 'activemq_conn'):
            self.client.disconnect()
            self.client.close()
    def test_5_integration_stomp_1_1_heartbeat(self):
        version = StompSpec.VERSION_1_1

        port = 61612 if (BROKER == 'activemq') else PORT # stomp+nio on 61613 does not work properly, so use stomp on 61612
        client = Stomp(self.getConfig(StompSpec.VERSION_1_1, port))
        self.assertEquals(client.lastReceived, None)
        self.assertEquals(client.lastSent, None)

        heartBeatPeriod = 100
        try:
            client.connect(host=VIRTUALHOST, heartBeats=(heartBeatPeriod, heartBeatPeriod), versions=[version])
        except StompProtocolError as e:
            print 'Broker does not support STOMP protocol %s. Skipping this test case. [%s]' % (e, version)
            return

        self.assertTrue((time.time() - client.lastReceived) < 0.1)
        if not (client.serverHeartBeat and client.clientHeartBeat):
            print 'broker does not support heart-beating. disconnecting ...'
            client.disconnect()
            client.close()
            return

        serverHeartBeatInSeconds = client.serverHeartBeat / 1000.0
        clientHeartBeatInSeconds = client.clientHeartBeat / 1000.0

        start = time.time()
        while (time.time() - start) < (2.5 * max(serverHeartBeatInSeconds, clientHeartBeatInSeconds)):
            time.sleep(0.5 * min(serverHeartBeatInSeconds, clientHeartBeatInSeconds))
            client.canRead(0)
            self.assertTrue((time.time() - client.lastReceived) < (2.0 * serverHeartBeatInSeconds))
            if (time.time() - client.lastSent) > (0.5 * clientHeartBeatInSeconds):
                client.beat()
                self.assertTrue((time.time() - client.lastSent) < 0.1)

        start = time.time()
        try:
            while not client.canRead(0.5 * clientHeartBeatInSeconds):
                pass
            if client.receiveFrame().command == StompSpec.ERROR:
                raise StompProtocolError()
        except (StompConnectionError, StompProtocolError):
            self.assertTrue((time.time() - start) < (3.0 * clientHeartBeatInSeconds))
            self.assertTrue((time.time() - client.lastReceived) < (2.0 * serverHeartBeatInSeconds))
            self.assertTrue((time.time() - client.lastSent) > clientHeartBeatInSeconds)
        else:
            raise
        client.close()
    def test_5_integration_stomp_1_1_heartbeat(self):
        version = StompSpec.VERSION_1_1

        client = Stomp(self.getConfig(StompSpec.VERSION_1_1))
        self.assertEqual(client.lastReceived, None)
        self.assertEqual(client.lastSent, None)

        heartBeatPeriod = 100
        try:
            client.connect(host=VIRTUALHOST, heartBeats=(heartBeatPeriod, heartBeatPeriod), versions=[version])
        except StompProtocolError as e:
            print('Broker does not support STOMP protocol %s. Skipping this test case. [%s]' % (e, version))
            return

        self.assertTrue((time.time() - client.lastReceived) < 0.1)
        if not (client.serverHeartBeat and client.clientHeartBeat):
            print('broker does not support heart-beating. disconnecting ...')
            client.disconnect()
            client.close()
            return

        serverHeartBeatInSeconds = client.serverHeartBeat / 1000.0
        clientHeartBeatInSeconds = client.clientHeartBeat / 1000.0

        start = time.time()
        while (time.time() - start) < (2.5 * max(serverHeartBeatInSeconds, clientHeartBeatInSeconds)):
            time.sleep(0.5 * min(serverHeartBeatInSeconds, clientHeartBeatInSeconds))
            client.canRead(0)
            self.assertTrue((time.time() - client.lastReceived) < (2.0 * serverHeartBeatInSeconds))
            if (time.time() - client.lastSent) > (0.5 * clientHeartBeatInSeconds):
                client.beat()
                self.assertTrue((time.time() - client.lastSent) < 0.1)

        start = time.time()
        try:
            while not client.canRead(0.5 * clientHeartBeatInSeconds):
                pass
            if client.receiveFrame().command == StompSpec.ERROR:
                raise StompProtocolError()
        except (StompConnectionError, StompProtocolError):
            self.assertTrue((time.time() - start) < (3.0 * clientHeartBeatInSeconds))
            self.assertTrue((time.time() - client.lastReceived) < (2.0 * serverHeartBeatInSeconds))
            self.assertTrue((time.time() - client.lastSent) > clientHeartBeatInSeconds)
        else:
            raise
        client.close()
Exemplo n.º 8
0
from stompest.config import StompConfig
from stompest.sync import Stomp

user = os.getenv('APOLLO_USER') or 'admin'
password = os.getenv('APOLLO_PASSWORD') or 'password'
host = os.getenv('APOLLO_HOST') or 'localhost'
port = int(os.getenv('APOLLO_PORT') or 61613)
destination = sys.argv[1:2] or ['/topic/event']
destination = destination[0]

messages = 10000
data = 'Hello World from Python'

config = StompConfig('tcp://%s:%d' % (host, port), login=user, passcode=password, version='1.1')
client = Stomp(config)
client.connect(host='mybroker')

count = 0
start = time.time()

for _ in xrange(messages):
    client.send(destination=destination, body=data, headers={'persistent': 'false'})
    count += 1

diff = time.time() - start
print 'Sent %s frames in %f seconds' % (count, diff)
  
client.disconnect(receipt='bye')
client.receiveFrame()
client.close()
Exemplo n.º 9
0
import time

from stompest.config import StompConfig
from stompest.sync import Stomp

user = os.getenv('APOLLO_USER') or 'admin'
password = os.getenv('APOLLO_PASSWORD') or 'password'
host = os.getenv('APOLLO_HOST') or 'localhost'
port = int(os.getenv('APOLLO_PORT') or 61613)
destination = sys.argv[1:2] or ['/topic/event']
destination = destination[0]

data = 'Hello World from Python'

config = StompConfig('tcp://%s:%d' % (host, port), login=user, passcode=password, version='1.1')
client = Stomp(config)
client.connect(host='mybroker')

print 'Enter SHUTDOWN to exist.'

while data != 'SHUTDOWN':
   data = str(raw_input('Enter message to send to %s:' % destination))
   client.send(destination=destination, body=data, headers={'persistent': 'false'})

# Send the 'SHUTDOWN' message to stop all listeners.
client.send(destination=destination, body=data, headers={'persistent': 'false'})
  
client.disconnect(receipt='bye')
client.receiveFrame()
client.close()
Exemplo n.º 10
0
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]
Exemplo n.º 11
0
client.send(destination=destination, body="scai.fhg.de/voc/ccg", headers=headers)

for i in queries:
    client.send(destination=destination, body="scai.fhg.de/concept/" + str(i), headers=headers)

print u"# ErasmusMC ontology file".encode('utf-8')
print u"VR 0.0".encode('utf-8')
print u"ON CCG_Ontology".encode('utf-8')
print u"--".encode('utf-8')

@timeout(1)
def receiveFrames():
    frame = clientConsumer.receiveFrame()

    xml = ElementTree.fromstring(frame.body)
    modelText = xml.find('docelem').find('model').text
    if (modelText is not None):
        print unicode(modelText).encode('utf-8')
        print u"--".encode('utf-8')

for reply in queries:
    receiveFrames()

client.disconnect(receipt='bye')
client.receiveFrame()
client.close()
clientConsumer.disconnect(receipt='bye')
clientConsumer.receiveFrame()
clientConsumer.close()
Exemplo n.º 12
0
class StompClient(BaseComponent):

    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,  # means 'latest available'
            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.last_heartbeat = 0
        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 socket_connected(self):
        try:
            if self._client._transport:
                return True
        except:
            pass
        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, flush=True, reconnect=False):
        try:
            if flush:
                self._subscribed = {}
            if self.connected:
                self._client.disconnect(receipt=receipt)
        except Exception as e:
            LOG.error("Failed to disconnect client")
        try:
            self.fire(Disconnected(reconnect=reconnect))
            self._client.close(flush=flush)
        except Exception as e:
            LOG.error("Failed to close client connection")

        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,
                    ClientHeartbeat(),
                    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,
                    ServerHeartbeat(),
                    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.debug("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(ConnectionFailed(self._stomp_server))
            event.success = False
        return "fail"

    @handler("ServerHeartbeat")
    def check_server_heartbeat(self, event):
        """ Confirm that heartbeat from server hasn't timed out """
        now = time.time()
        self.last_heartbeat = self._client.lastReceived or self.last_heartbeat
        if self.last_heartbeat:
            elapsed = now - self.last_heartbeat
        else:
            elapsed = -1
        if ((self._client.serverHeartBeat / 1000.0) * self.ALLOWANCE +
                self.last_heartbeat) < now:
            LOG.error(
                "Server heartbeat timeout. %d seconds since last heartbeat.",
                elapsed)
            event.success = False
            self.fire(HeartbeatTimeout())

    @handler("ClientHeartbeat")
    def send_heartbeat(self, event):
        if self.connected:
            LOG.debug("Sending heartbeat")
            try:
                self._client.beat()
            except (StompConnectionError, StompError) as err:
                event.success = False
                self.fire(OnStompError(None, err))

    @handler("generate_events")
    def generate_events(self, event):
        event.reduce_time_left(0.1)
        if not self.connected:
            return
        try:
            if self._client.canRead(0):
                frame = self._client.receiveFrame()
                LOG.debug("Recieved frame %s", frame)
                if frame.command == StompSpec.ERROR:
                    self.fire(OnStompError(frame, None))
                else:
                    self.fire(Message(frame))
        except (StompConnectionError, StompError) as err:
            LOG.error("Failed attempt to generate events.")
            self.fire(OnStompError(None, err))

    @handler("Send")
    def send(self, event, destination, body, headers=None, receipt=None):
        LOG.debug("send()")
        try:
            self._client.send(destination,
                              body=body.encode('utf-8'),
                              headers=headers,
                              receipt=receipt)
            LOG.debug("Message sent")
        except (StompConnectionError, StompError) as err:
            LOG.error("Error sending frame")
            event.success = False
            self.fire(OnStompError(None, err))
            raise  # To fire Send_failure event

    @handler("Subscribe")
    def _subscribe(self,
                   event,
                   destination,
                   additional_headers=None,
                   ack=ACK_CLIENT_INDIVIDUAL):
        if ack not in ACK_MODES:
            raise ValueError("Invalid client ack mode specified")
        if destination in self._client.session._subscriptions:
            LOG.debug("Ignoring subscribe request to %s. Already subscribed.",
                      destination)
        LOG.info("Subscribe to message destination %s", destination)
        try:
            headers = {StompSpec.ACK_HEADER: ack, 'id': destination}
            if additional_headers:
                headers.update(additional_headers)

            # Set ID to match destination name for easy reference later
            frame, token = self._client.subscribe(destination, headers)
            self._subscribed[destination] = token
        except (StompConnectionError, StompError) as err:
            LOG.error("Failed to subscribe to queue.")
            event.success = False
            LOG.debug(traceback.format_exc())
            self.fire(OnStompError(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, StompError) as err:
            event.success = False
            LOG.error("Unsubscribe Failed.")
            self.fire(OnStompError(frame, err))

    @handler("Message")
    def on_message(self, event, headers, message):
        LOG.debug("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, StompError) as err:
            LOG.error("Error sending ack")
            event.success = False
            self.fire(OnStompError(frame, err))
            raise  # To fire Ack_failure event

    def get_subscription(self, frame):
        """ Get subscription from frame """
        _, token = self._client.message(frame)
        return self._subscribed[token]
Exemplo n.º 13
0
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