Exemplo n.º 1
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)
Exemplo n.º 2
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))
Exemplo n.º 3
0
def _addReceiptHeader(frame, receipt):
    if not receipt:
        return
    try:
        frame.headers[StompSpec.RECEIPT_HEADER] = textType(receipt)
    except:
        raise StompProtocolError('Invalid receipt (not a string): %s' %
                                 repr(receipt))
Exemplo n.º 4
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)
Exemplo 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 = stompest.protocol.commands.receipt(frame)
     try:
         self._receipts.remove(receipt)
     except KeyError:
         raise StompProtocolError('Unexpected receipt: %s' % receipt)
     return receipt
Exemplo n.º 6
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()
Exemplo n.º 7
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
Exemplo 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
Exemplo n.º 9
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 = stompest.protocol.commands.message(frame)
     if token not in self._subscriptions:
         raise StompProtocolError('No such subscription [%s=%s]' % token)
     return token
Exemplo n.º 10
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
Exemplo n.º 11
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 = stompest.protocol.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
Exemplo 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
Exemplo n.º 13
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
Exemplo n.º 14
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
Exemplo n.º 15
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.close()
         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)
    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()
Exemplo n.º 17
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)
Exemplo n.º 18
0
 def _receipt(self, receipt):
     if not receipt:
         return
     if receipt in self._receipts:
         raise StompProtocolError('Duplicate receipt: %s' % receipt)
     self._receipts.add(receipt)
Exemplo n.º 19
0
 def onError(self, connection, frame):
     connection.disconnect(failure=StompProtocolError('Received %s' %
                                                      frame.info()))
Exemplo n.º 20
0
 def onError(self, connection, frame):
     self.onConnectionLost(
         connection,
         StompProtocolError('While trying to connect, received %s' %
                            frame.info()))
Exemplo n.º 21
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))
Exemplo n.º 22
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))))
Exemplo n.º 23
0
 def _versions(self, versions):
     if versions and (set(versions) - set(
             stompest.protocol.commands.versions(self.version))):
         raise StompProtocolError('Invalid versions: %s [version=%s]' %
                                  (versions, self.version))
     self.__versions = versions
Exemplo n.º 24
0
 def onError(self, connection, frame):
     reason = StompProtocolError('Received %s' % frame.info())
     reason.frame = frame
     connection.disconnect(reason=reason)