Exemplo n.º 1
0
class TestBuildFrame(TestCase):

    def setUp(self):
        self.protocol = StompProtocol()

    def test_build_frame_with_body(self):
        buf = self.protocol.build_frame('HELLO', {
            'from': 'me',
            'to': 'you'
        }, 'I Am The Walrus')

        self.assertEqual(
            buf,
            b'HELLO\n'
            b'from:me\n'
            b'to:you\n\n'
            b'I Am The Walrus'
            b'\x00')

    def test_build_frame_without_body(self):
        buf = self.protocol.build_frame('HI', {
            'from': '1',
            'to': '2'
        })

        self.assertEqual(
            buf,
            b'HI\n'
            b'from:1\n'
            b'to:2\n\n'
            b'\x00')
Exemplo n.º 2
0
class TestBuildFrame(TestCase):
    def setUp(self):
        self.protocol = StompProtocol()

    def test_build_frame_with_body(self):
        buf = self.protocol.build_frame("HELLO", {"from": "me", "to": "you"}, "I Am The Walrus")

        self.assertEqual(buf, b"HELLO\n" b"from:me\n" b"to:you\n\n" b"I Am The Walrus" b"\x00")

    def test_build_frame_without_body(self):
        buf = self.protocol.build_frame("HI", {"from": "1", "to": "2"})

        self.assertEqual(buf, b"HI\n" b"from:1\n" b"to:2\n\n" b"\x00")
Exemplo n.º 3
0
class TestBuildFrame(TestCase):
    def setUp(self):
        self.protocol = StompProtocol()

    def test_build_frame_with_body(self):
        buf = self.protocol.build_frame('HELLO', {
            'from': 'me',
            'to': 'you'
        }, 'I Am The Walrus')

        self.assertEqual(
            buf, b'HELLO\n'
            b'from:me\n'
            b'to:you\n\n'
            b'I Am The Walrus'
            b'\x00')

    def test_build_frame_without_body(self):
        buf = self.protocol.build_frame('HI', {'from': '1', 'to': '2'})

        self.assertEqual(buf, b'HI\n' b'from:1\n' b'to:2\n\n' b'\x00')
Exemplo n.º 4
0
class TorStomp(object):

    VERSION = '1.1'

    def __init__(self, host='localhost', port=61613, connect_headers={},
                 on_error=None, on_disconnect=None, on_connect=None,
                 reconnect_max_attempts=-1, reconnect_timeout=1000):

        self.host = host
        self.port = port
        self.logger = logging.getLogger('TorStomp')

        self._connect_headers = connect_headers
        self._connect_headers['accept-version'] = self.VERSION
        self._heart_beat_handler = None
        self.connected = False
        self._disconnecting = False
        self._protocol = StompProtocol()
        self._subscriptions = {}
        self._last_subscribe_id = 0
        self._on_error = on_error
        self._on_disconnect = on_disconnect
        self._on_connect = on_connect

        self._reconnect_max_attempts = reconnect_max_attempts
        self._reconnect_timeout = timedelta(milliseconds=reconnect_timeout)
        self._reconnect_attempts = 0

    @gen.coroutine
    def connect(self):
        self.stream = self._build_io_stream()

        try:
            yield self.stream.connect((self.host, self.port))
            self.logger.info('Stomp connection estabilished')
        except socket.error as error:
            self.logger.error(
                '[attempt: %d] Connect error: %s', self._reconnect_attempts,
                error)
            self._schedule_reconnect()
            return

        self.stream.set_close_callback(self._on_disconnect_socket)
        self.stream.read_until_close(
            streaming_callback=self._on_data,
            callback=self._on_data)

        self.connected = True
        self._disconnecting = False
        self._reconnect_attempts = 0
        self._protocol.reset()

        yield self._send_frame('CONNECT', self._connect_headers)

        for subscription in self._subscriptions.values():
            yield self._send_subscribe_frame(subscription)

        if self._on_connect:
            self._on_connect()

    def subscribe(self, destination, ack='auto', extra_headers={},
                  callback=None):

        self._last_subscribe_id += 1

        subscription = Subscription(
            destination=destination,
            id=self._last_subscribe_id,
            ack=ack,
            extra_headers=extra_headers,
            callback=callback)

        self._subscriptions[str(self._last_subscribe_id)] = subscription

        if self.connected:
            self._send_subscribe_frame(subscription)

    def send(self, destination, body='', headers={}, send_content_length=True):
        headers['destination'] = destination

        if body:
            body = self._protocol._encode(body)

            # ActiveMQ determines the type of a message by the
            # inclusion of the content-length header
            if send_content_length:
                headers['content-length'] = len(body)

        return self._send_frame('SEND', headers, body)

    def ack(self, frame):
        headers = {
            'subscription': frame.headers['subscription'],
            'message-id': frame.headers['message-id']
        }

        return self._send_frame('ACK', headers)

    def nack(self, frame):
        headers = {
            'subscription': frame.headers['subscription'],
            'message-id': frame.headers['message-id']
        }

        return self._send_frame('NACK', headers)

    def _build_io_stream(self):
        s = socket.socket(socket.AF_INET, socket.SOCK_STREAM, 0)
        return IOStream(s)

    def _on_disconnect_socket(self):
        self._stop_scheduled_heart_beat()
        self.connected = False

        if self._disconnecting:
            self.logger.info('TCP connection end gracefully')
        else:
            self.logger.info('TCP connection unexpected end')
            self._schedule_reconnect()

        if self._on_disconnect:
            self._on_disconnect()

    def _schedule_reconnect(self):
        if self._reconnect_max_attempts == -1 or \
                self._reconnect_attempts < self._reconnect_max_attempts:

            self._reconnect_attempts += 1
            self._reconnect_timeout_handler = IOLoop.current().add_timeout(
                self._reconnect_timeout, self.connect)
        else:
            self.logger.error('All Connection attempts failed')

    def _on_data(self, data):
        if not data:
            return

        self._protocol.add_data(data)

        frames = self._protocol.pop_frames()
        if frames:
            self._received_frames(frames)

    def _send_frame(self, command, headers={}, body=''):
        buf = self._protocol.build_frame(command, headers, body)
        return self.stream.write(buf)

    def _set_connected(self, connected_frame):
        heartbeat = connected_frame.headers.get('heart-beat')

        if heartbeat:
            sx, sy = heartbeat.split(',')
            sx, sy = int(sx), int(sy)

            if sy:
                self._set_heart_beat(sy)

    def _set_heart_beat(self, time):
        self._heart_beat_delta = timedelta(milliseconds=time)
        self._stop_scheduled_heart_beat()

        self._do_heart_beat()

    def _schedule_heart_beat(self):
        self._heart_beat_handler = IOLoop.current().add_timeout(
            self._heart_beat_delta, self._do_heart_beat)

    def _stop_scheduled_heart_beat(self):
        if self._heart_beat_handler:
            IOLoop.current().remove_timeout(self._heart_beat_handler)

        self._heart_beat_handler = None

    def _do_heart_beat(self):
        self.logger.debug('Sending heartbeat')
        self.stream.write(b'\n')
        self._schedule_heart_beat()

    def _received_frames(self, frames):
        for frame in frames:
            if frame.command == 'MESSAGE':
                self._received_message_frame(frame)
            elif frame.command == 'CONNECTED':
                self._set_connected(frame)
            elif frame.command == 'ERROR':
                self._received_error_frame(frame)
            else:
                self._received_unhandled_frame(frame)

    def _received_message_frame(self, frame):
        subscription_header = frame.headers.get('subscription')

        subscription = self._subscriptions.get(subscription_header)

        if not subscription:
            self.logger.error(
                'Not found subscription %d' % subscription_header)
            return

        subscription.callback(frame, frame.body)

    def _received_error_frame(self, frame):
        message = frame.headers.get('message')

        self.logger.error('Received error: %s', message)
        self.logger.debug('Error detail %s', frame.body)

        if self._on_error:
            self._on_error(
                StompError(message, frame.body))

    def _received_unhandled_frame(self, frame):
        self.logger.warn('Received unhandled frame: %s', frame.command)

    def _send_subscribe_frame(self, subscription):
        headers = {
            'id': subscription.id,
            'destination': subscription.destination,
            'ack': subscription.ack
        }
        headers.update(subscription.extra_headers)

        return self._send_frame('SUBSCRIBE', headers)
Exemplo n.º 5
0
class TorStomp(object):

    VERSION = '1.1'

    def __init__(self,
                 host='localhost',
                 port=61613,
                 connect_headers={},
                 on_error=None,
                 on_disconnect=None,
                 on_connect=None,
                 reconnect_max_attempts=-1,
                 reconnect_timeout=1000):

        self.host = host
        self.port = port
        self.logger = logging.getLogger('TorStomp')

        self._connect_headers = connect_headers
        self._connect_headers['accept-version'] = self.VERSION
        self._heart_beat_handler = None
        self.connected = False
        self._disconnecting = False
        self._protocol = StompProtocol()
        self._subscriptions = {}
        self._last_subscribe_id = 0
        self._on_error = on_error
        self._on_disconnect = on_disconnect
        self._on_connect = on_connect

        self._reconnect_max_attempts = reconnect_max_attempts
        self._reconnect_timeout = timedelta(milliseconds=reconnect_timeout)
        self._reconnect_attempts = 0

    @gen.coroutine
    def connect(self):
        self.stream = self._build_io_stream()

        try:
            yield self.stream.connect((self.host, self.port))
            self.logger.info('Stomp connection estabilished')
        except socket.error as error:
            self.logger.error('[attempt: %d] Connect error: %s',
                              self._reconnect_attempts, error)
            self._schedule_reconnect()
            return

        self.stream.set_close_callback(self._on_disconnect_socket)
        self.stream.read_until_close(streaming_callback=self._on_data,
                                     callback=self._on_data)

        self.connected = True
        self._disconnecting = False
        self._reconnect_attempts = 0
        self._protocol.reset()

        yield self._send_frame('CONNECT', self._connect_headers)

        for subscription in self._subscriptions.values():
            yield self._send_subscribe_frame(subscription)

        if self._on_connect:
            self._on_connect()

    def subscribe(self,
                  destination,
                  ack='auto',
                  extra_headers={},
                  callback=None):

        self._last_subscribe_id += 1

        subscription = Subscription(destination=destination,
                                    id=self._last_subscribe_id,
                                    ack=ack,
                                    extra_headers=extra_headers,
                                    callback=callback)

        self._subscriptions[str(self._last_subscribe_id)] = subscription

        if self.connected:
            self._send_subscribe_frame(subscription)

    def send(self, destination, body='', headers={}, send_content_length=True):
        headers['destination'] = destination

        if body:
            body = self._protocol._encode(body)

            # ActiveMQ determines the type of a message by the
            # inclusion of the content-length header
            if send_content_length:
                headers['content-length'] = len(body)

        return self._send_frame('SEND', headers, body)

    def ack(self, frame):
        headers = {
            'subscription': frame.headers['subscription'],
            'message-id': frame.headers['message-id']
        }

        return self._send_frame('ACK', headers)

    def nack(self, frame):
        headers = {
            'subscription': frame.headers['subscription'],
            'message-id': frame.headers['message-id']
        }

        return self._send_frame('NACK', headers)

    def _build_io_stream(self):
        s = socket.socket(socket.AF_INET, socket.SOCK_STREAM, 0)
        return IOStream(s)

    def _on_disconnect_socket(self):
        self._stop_scheduled_heart_beat()
        self.connected = False

        if self._disconnecting:
            self.logger.info('TCP connection end gracefully')
        else:
            self.logger.info('TCP connection unexpected end')
            self._schedule_reconnect()

        if self._on_disconnect:
            self._on_disconnect()

    def _schedule_reconnect(self):
        if self._reconnect_max_attempts == -1 or \
                self._reconnect_attempts < self._reconnect_max_attempts:

            self._reconnect_attempts += 1
            self._reconnect_timeout_handler = IOLoop.current().add_timeout(
                self._reconnect_timeout, self.connect)
        else:
            self.logger.error('All Connection attempts failed')

    def _on_data(self, data):
        if not data:
            return

        self._protocol.add_data(data)

        frames = self._protocol.pop_frames()
        if frames:
            self._received_frames(frames)

    def _send_frame(self, command, headers={}, body=''):
        buf = self._protocol.build_frame(command, headers, body)
        return self.stream.write(buf)

    def _set_connected(self, connected_frame):
        heartbeat = connected_frame.headers.get('heart-beat')

        if heartbeat:
            sx, sy = heartbeat.split(',')
            sx, sy = int(sx), int(sy)

            if sy:
                self._set_heart_beat(sy)

    def _set_heart_beat(self, time):
        self._heart_beat_delta = timedelta(milliseconds=time)
        self._stop_scheduled_heart_beat()

        self._do_heart_beat()

    def _schedule_heart_beat(self):
        self._heart_beat_handler = IOLoop.current().add_timeout(
            self._heart_beat_delta, self._do_heart_beat)

    def _stop_scheduled_heart_beat(self):
        if self._heart_beat_handler:
            IOLoop.current().remove_timeout(self._heart_beat_handler)

        self._heart_beat_handler = None

    def _do_heart_beat(self):
        self.logger.debug('Sending heartbeat')
        self.stream.write(b'\n')
        self._schedule_heart_beat()

    def _received_frames(self, frames):
        for frame in frames:
            if frame.command == 'MESSAGE':
                self._received_message_frame(frame)
            elif frame.command == 'CONNECTED':
                self._set_connected(frame)
            elif frame.command == 'ERROR':
                self._received_error_frame(frame)
            else:
                self._received_unhandled_frame(frame)

    def _received_message_frame(self, frame):
        subscription_header = frame.headers.get('subscription')

        subscription = self._subscriptions.get(subscription_header)

        if not subscription:
            self.logger.error('Not found subscription %d' %
                              subscription_header)
            return

        subscription.callback(frame, frame.body)

    def _received_error_frame(self, frame):
        message = frame.headers.get('message')

        self.logger.error('Received error: %s', message)
        self.logger.debug('Error detail %s', frame.body)

        if self._on_error:
            self._on_error(StompError(message, frame.body))

    def _received_unhandled_frame(self, frame):
        self.logger.warn('Received unhandled frame: %s', frame.command)

    def _send_subscribe_frame(self, subscription):
        headers = {
            'id': subscription.id,
            'destination': subscription.destination,
            'ack': subscription.ack
        }
        headers.update(subscription.extra_headers)

        return self._send_frame('SUBSCRIBE', headers)