def process_frame(self, frame): """ Dispatches a received frame to the appropriate internal method. @param frame: The frame that was received. @type frame: L{coilmq.frame.StompFrame} """ cmd_method = frame.cmd.lower() if not cmd_method in VALID_COMMANDS: raise ProtocolError("Invalid STOMP command: %s" % frame.cmd) method = getattr(self, cmd_method, None) if not self.connected and method != self.connect: raise ProtocolError("Not connected.") try: transaction = frame.headers.get('transaction') if not transaction or method in (self.begin, self.commit, self.abort): method(frame) else: if not transaction in self.transactions: raise ProtocolError("Invalid transaction specified: %s" % transaction) self.transactions[transaction].append(frame) except Exception, e: self.log.error("Error processing STOMP frame: %s" % e) self.log.exception(e) try: self.connection.send_frame(ErrorFrame(str(e), str(e))) except Exception, e: self.log.error("Could not send error frame: %s" % e) self.log.exception(e)
def connect(self, frame, response=None): host = frame.headers.get('host') if not host: raise ProtocolError('"host" header is required') if host != socket.getfqdn(): raise ProtocolError( 'Virtual hosting is not supported or host is unknown') super(STOMP12, self).connect(frame, response)
def nack(self, frame): """ Handles the NACK command: Unacknowledges receipt of a message. For now, this is just a placeholder to implement this version of the protocol """ if not frame.headers.get('message-id'): raise ProtocolError("No message-id specified for NACK command.") if not frame.headers.get('subscription'): raise ProtocolError("No subscription specified for NACK command.")
def abort(self, frame): """ Handles ABORT command: Rolls back specified transaction. """ if not frame.transaction: raise ProtocolError("Missing transaction for ABORT command.") if not frame.transaction in self.transactions: raise ProtocolError("Invalid transaction: %s" % frame.transaction) self.queue_manager.resend_transaction_frames(self.connection, frame.transaction) del self.transactions[frame.transaction]
def ack(self, frame): """ Handles the ACK command: Acknowledges receipt of a message. """ if not frame.message_id: raise ProtocolError("No message-id specified for ACK command.") self.queue_manager.ack(self.connection, frame)
def commit(self, frame): """ Handles COMMIT command: Commits specified transaction. """ if not frame.transaction: raise ProtocolError("Missing transaction for COMMIT command.") if not frame.transaction in self.transactions: raise ProtocolError("Invalid transaction: %s" % frame.transaction) for tframe in self.transactions[frame.transaction]: del tframe.headers['transaction'] self.process_frame(tframe) self.queue_manager.clear_transaction_frames(self.connection, frame.transaction) del self.transactions[frame.transaction]
def begin(self, frame): """ Handles BEGING command: Starts a new transaction. """ if not frame.transaction: raise ProtocolError("Missing transaction for BEGIN command.") self.transactions[frame.transaction] = []
def process_frame(self, frame): """ Dispatches a received frame to the appropriate internal method. @param frame: The frame that was received. @type frame: C{stompclient.frame.Frame} """ cmd_method = frame.cmd.lower() if not cmd_method in VALID_COMMANDS: raise ProtocolError("Invalid STOMP command: {}".format(frame.cmd)) method = getattr(self, cmd_method, None) if not self.engine.connected and method not in (self.connect, self.stomp): raise ProtocolError("Not connected.") try: transaction = frame.headers.get('transaction') if not transaction or method in (self.begin, self.commit, self.abort): method(frame) else: if not transaction in self.engine.transactions: raise ProtocolError("Invalid transaction specified: %s" % transaction) self.engine.transactions[transaction].append(frame) except Exception as e: self.engine.log.error("Error processing STOMP frame: %s" % e) self.engine.log.exception(e) try: self.engine.connection.send_frame(ErrorFrame(str(e), str(e))) except Exception as e: # pragma: no cover self.engine.log.error("Could not send error frame: %s" % e) self.engine.log.exception(e) else: # The protocol is not especially clear here (not sure why I'm surprised) # about the expected behavior WRT receipts and errors. We will assume that # the RECEIPT frame should not be sent if there is an error frame. # Also we'll assume that a transaction should not preclude sending the receipt # frame. # import pdb; pdb.set_trace() if frame.headers.get('receipt') and method != self.connect: self.engine.connection.send_frame( ReceiptFrame(receipt=frame.headers.get('receipt')))
def unsubscribe(self, frame): """ Handle the UNSUBSCRIBE command: Removes this connection from destination. """ dest = frame.headers.get('destination') if not dest: raise ProtocolError('Missing destination for UNSUBSCRIBE command.') if dest.startswith('/queue/'): self.queue_manager.unsubscribe(self.connection, dest) else: self.topic_manager.unsubscribe(self.connection, dest)
def send(self, frame): """ Handle the SEND command: Delivers a message to a queue or topic (default). """ dest = frame.headers.get('destination') if not dest: raise ProtocolError('Missing destination for SEND command.') if dest.startswith('/queue/'): self.queue_manager.send(frame) else: self.topic_manager.send(frame)
def subscribe(self, frame): """ Handle the SUBSCRIBE command: Adds this connection to destination. """ ack = frame.headers.get('ack') reliable = ack and ack.lower() == 'client' self.connection.reliable_subscriber = reliable dest = frame.headers.get('destination') if not dest: raise ProtocolError('Missing destination for SUBSCRIBE command.') if dest.startswith('/queue/'): self.queue_manager.subscribe(self.connection, dest) else: self.topic_manager.subscribe(self.connection, dest)
def _negotiate_protocol(self, frame, response): client_versions = frame.headers.get('accept-version') if not client_versions: raise ProtocolError('No version specified') common = set(client_versions.split(',')) & self.SUPPORTED_VERSIONS if not common: versions = ','.join(self.SUPPORTED_VERSIONS) self.engine.connection.send_frame( Frame(frames.ERROR, headers={ 'version': versions, 'content-type': frames.TEXT_PLAIN }, body='Supported protocol versions are {0}'.format( versions))) else: response.headers['version'] = max(common) protocol_class = PROTOCOL_MAP[response.headers['version']] if type(self) is not protocol_class: self.engine.protocol = protocol_class(self.engine) self.engine.protocol.connect(frame, response=response)