Esempio n. 1
0
def connect(login=None, passcode=None, headers=None, versions=None, host=None, heartBeats=None):
    """Create a **CONNECT** frame.
    
    :param login: The **login** header. The default is :obj:`None`, which means that no such header will be added.
    :param passcode: The **passcode** header. The default is :obj:`None`, which means that no such header will be added.
    :param headers: Additional STOMP headers.
    :param versions: A list of the STOMP versions we wish to support. The default is :obj:`None`, which means that we will offer the broker to accept any version prior or equal to the default STOMP protocol version.
    :param host: The **host** header which gives this client a human readable name on the broker side.
    :param heartBeats: A pair (client heart-beat, server heart-beat) of integer heart-beat intervals in ms. Both intervals must be non-negative. A client heart-beat of 0 means that no heart-beats will be sent by the client. Similarly, a server heart-beat of 0 means that the client does not expect heart-beats from the server.
    """
    headers = dict(headers or [])
    if login is not None:
        headers[StompSpec.LOGIN_HEADER] = login
    if passcode is not None:
        headers[StompSpec.PASSCODE_HEADER] = passcode
    versions = [StompSpec.VERSION_1_0] if (versions is None) else list(sorted(_version(v) for v in versions))
    if versions != [StompSpec.VERSION_1_0]:
        headers[StompSpec.ACCEPT_VERSION_HEADER] = ','.join(_version(version) for version in versions)
        if host is None:
            host = ''
        headers[StompSpec.HOST_HEADER] = host
    if heartBeats:
        if versions == [StompSpec.VERSION_1_0]:
            raise StompProtocolError('Heart-beating not supported (version %s)' % StompSpec.VERSION_1_0)
        try:
            heartBeats = tuple(int(t) for t in heartBeats)
            if not all(t >= 0 for t in heartBeats):
                raise
            heartBeats = '%d,%d' % heartBeats
        except:
            raise StompProtocolError('Invalid heart-beats (two non-negative integers required): %s' % str(heartBeats))
        headers[StompSpec.HEART_BEAT_HEADER] = heartBeats

    return StompFrame(StompSpec.CONNECT, headers)
Esempio n. 2
0
def connected(frame, versions=None):
    """Handle a **CONNECTED** frame.
    
    :param versions: The same **versions** parameter you used to create the **CONNECT** frame.
    """
    versions = [StompSpec.VERSION_1_0] if (versions is None) else list(sorted(_version(v) for v in versions))
    version = versions[-1]
    _checkCommand(frame, [StompSpec.CONNECTED])
    headers = frame.headers
    try:
        if version != StompSpec.VERSION_1_0:
            version = _version(headers.get(StompSpec.VERSION_HEADER, StompSpec.VERSION_1_0))
            if version not in versions:
                raise StompProtocolError('')
    except StompProtocolError:
        raise StompProtocolError('Server version incompatible with accepted versions %s [headers=%s]' % (versions, headers))

    session = headers.get(StompSpec.SESSION_HEADER)
    server = None if (version == StompSpec.VERSION_1_0) else headers.get(StompSpec.SERVER_HEADER)

    heartBeats = (0, 0)
    if (version != StompSpec.VERSION_1_0) and (StompSpec.HEART_BEAT_HEADER in headers):
        try:
            heartBeats = tuple(int(t) for t in headers[StompSpec.HEART_BEAT_HEADER].split(StompSpec.HEART_BEAT_SEPARATOR))
            if (len(heartBeats) != 2) or any((t < 0) for t in heartBeats):
                raise ValueError('')
        except:
            raise StompProtocolError('Invalid %s header (two comma-separated and non-negative integers required): %s' % (StompSpec.HEART_BEAT_HEADER, heartBeats))

    return version, server, session, heartBeats
Esempio n. 3
0
def stomp(login=None, passcode=None, headers=None, versions=None, host=None, heartBeats=None):
    """Create a **STOMP** frame. Not supported in STOMP protocol 1.0, synonymous to :func:`connect` for STOMP protocol 1.1 and higher.
    """
    if (versions is None) or (list(versions) == [StompSpec.VERSION_1_0]):
        raise StompProtocolError('Unsupported command (version %s): %s' % (StompSpec.VERSION_1_0, StompSpec.STOMP))
    frame = connect(login=login, passcode=passcode, headers=headers, versions=versions, host=host, heartBeats=heartBeats)
    return StompFrame(StompSpec.STOMP, frame.headers, frame.body)
Esempio n. 4
0
def beat(version=None):
    """Create a STOMP heart-beat.
    """
    version = _version(version)
    if version == StompSpec.VERSION_1_0:
        raise StompProtocolError('Heart-beating not supported (version %s)' % version)

    return StompHeartBeat()
Esempio n. 5
0
 def receipt(self, frame):
     """Handle a **RECEIPT** frame. Returns the receipt id which you can use to match this receipt to the command that requested it."""
     self.__check('receipt', [self.CONNECTED, self.DISCONNECTING])
     receipt = commands.receipt(frame)
     try:
         self._receipts.remove(receipt)
     except KeyError:
         raise StompProtocolError('Unexpected receipt: %s' % receipt)
     return receipt
Esempio n. 6
0
 def unsubscribe(self, token, receipt=None):
     """Create an **UNSUBSCRIBE** frame and lose track of the subscription assiocated to it."""
     self.__check('unsubscribe', [self.CONNECTED])
     frame = commands.unsubscribe(token, receipt, version=self.version)
     try:
         self._subscriptions.pop(token)
     except KeyError:
         raise StompProtocolError('No such subscription [%s=%s]' % token)
     self._receipt(receipt)
     return frame
Esempio n. 7
0
    def message(self, frame):
        """Handle a **MESSAGE** frame. Returns a token which you can use to match this message to its subscription.

        .. seealso :: The :meth:`subscribe` method.
        """
        self.__check('message', [self.CONNECTED])
        token = commands.message(frame)
        if token not in self._subscriptions:
            raise StompProtocolError('No such subscription [%s=%s]' % token)
        return token
Esempio n. 8
0
    def version(cls, version=None):
        """Check whether **version** is a valid STOMP protocol version.

        :param version: A candidate version, or :obj:`None` (which is equivalent to the value of :attr:`StompSpec.DEFAULT_VERSION`).
        """
        if version is None:
            version = cls.DEFAULT_VERSION
        if version not in cls.VERSIONS:
            raise StompProtocolError('Version is not supported [%s]' % version)
        return version
Esempio n. 9
0
    def subscribe(self, destination, headers=None, receipt=None, context=None):
        """Create a **SUBSCRIBE** frame and keep track of the subscription assiocated to it. This method returns a token which you have to keep if you wish to match incoming **MESSAGE** frames to this subscription with :meth:`message` or to :meth:`unsubscribe` later.

        :param context: An arbitrary context object which you can use to store any information related to the subscription at hand.
        """
        self.__check('subscribe', [self.CONNECTED])
        frame, token = commands.subscribe(destination, headers, receipt, version=self.version)
        if token in self._subscriptions:
            raise StompProtocolError('Already subscribed [%s=%s]' % token)
        self._receipt(receipt)
        self._subscriptions[token] = (self._nextSubscription(), destination, copy.deepcopy(headers), receipt, context)
        return frame, token
Esempio n. 10
0
def nack(frame, transactions=None, receipt=None):
    """Create a **NACK** frame for a received **MESSAGE** frame.
    
    :param frame: The :class:`~.frame.StompFrame` object representing the **MESSAGE** frame we wish to nack.
    :param transactions: The ids of currently active transactions --- only if the **frame** is part of one of these transactions, the **transaction** header is included in the NACK frame.
    :param receipt: See :func:`disconnect`.
    """
    version = frame.version
    if version == StompSpec.VERSION_1_0:
        raise StompProtocolError('%s not supported (version %s)' % (StompSpec.NACK, version))
    frame = StompFrame(StompSpec.NACK, _ackHeaders(frame, transactions), version=frame.version)
    _addReceiptHeader(frame, receipt)
    return frame
Esempio n. 11
0
    def begin(self, transaction=None, receipt=None):
        """Create a **BEGIN** frame and begin an abstract STOMP transaction.

        :param transaction: See :meth:`transaction`.

        .. note :: If you try and begin a pending transaction twice, this will result in a :class:`~.stompest.error.StompProtocolError`.
        """
        self.__check('begin', [self.CONNECTED])
        frame = commands.begin(transaction, receipt, version=self.version)
        if transaction in self._transactions:
            raise StompProtocolError('Transaction already active: %s' % transaction)
        self._transactions.add(transaction)
        self._receipt(receipt)
        return frame
Esempio n. 12
0
    def commit(self, transaction, receipt=None):
        """Send a **COMMIT** command to commit a STOMP transaction.

        :param transaction: See :meth:`transaction`.

        .. note :: If you try and commit a transaction which is not pending, this will result in a :class:`~.stompest.error.StompProtocolError`.
        """
        self.__check('commit', [self.CONNECTED])
        frame = commands.commit(transaction, receipt, version=self.version)
        try:
            self._transactions.remove(transaction)
        except KeyError:
            raise StompProtocolError('Transaction unknown: %s' % transaction)
        self._receipt(receipt)
        return frame
Esempio n. 13
0
 def _connect(self, headers, versions, host, heartBeats, timeout):
     frame = self.session.connect(self._config.login, self._config.passcode,
                                  headers, versions, host, heartBeats)
     self.sendFrame(frame)
     if not self.canRead(timeout):
         self.session.disconnect()
         raise StompProtocolError(
             'STOMP session connect failed [timeout=%s]' % timeout)
     frame = self.receiveFrame()
     self.session.connected(frame)
     self.log.info('Connected to stomp broker [session=%s, version=%s]' %
                   (self.session.id, self.session.version))
     self._transport.setVersion(self.session.version)
     for (destination, headers, receipt, _) in self.session.replay():
         self.log.info('Replaying subscription %s' % headers)
         self.subscribe(destination, headers, receipt)
Esempio n. 14
0
 def _versions(self, versions):
     if versions and (set(versions) - set(commands.versions(self.version))):
         raise StompProtocolError('Invalid versions: %s [version=%s]' % (versions, self.version))
     self.__versions = versions
Esempio n. 15
0
 def __check(self, command, states):
     if self._check and (self.state not in states):
         raise StompProtocolError('Cannot handle command %s in state %s (only in states %s)' % (repr(command), repr(self.state), ', '.join(map(repr, states))))
Esempio n. 16
0
 def _receipt(self, receipt):
     if not receipt:
         return
     if receipt in self._receipts:
         raise StompProtocolError('Duplicate receipt: %s' % receipt)
     self._receipts.add(receipt)
Esempio n. 17
0
def _addReceiptHeader(frame, receipt):
    if not receipt:
        return
    if not isinstance(receipt, basestring):
        raise StompProtocolError('Invalid receipt (not a string): %s' % repr(receipt))
    frame.headers[StompSpec.RECEIPT_HEADER] = str(receipt)
Esempio n. 18
0
def _checkCommand(frame, commands=None):
    if frame.command not in (commands or StompSpec.COMMANDS):
        raise StompProtocolError('Cannot handle command: %s [expected=%s, headers=%s]' % (frame.command, ', '.join(commands), frame.headers))
Esempio n. 19
0
def _checkHeader(frame, header):
    try:
        return frame.headers[header]
    except KeyError:
        raise StompProtocolError('Invalid %s frame (%s header mandatory in version %s) [headers=%s]' % (frame.command, header, frame.version, frame.headers))
    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()