def consume(self, queue, consumer, consumer_tag='', no_local=False, no_ack=True, exclusive=False, nowait=True, ticket=None, cb=None): ''' Start a queue consumer. If `cb` is supplied, will be called when broker confirms that consumer is registered. ''' nowait = nowait and self.allow_nowait() and not cb if nowait and consumer_tag == '': consumer_tag = self._generate_consumer_tag() args = Writer() args.write_short(ticket or self.default_ticket).\ write_shortstr(queue).\ write_shortstr(consumer_tag).\ write_bits( no_local, no_ack, exclusive, nowait ).\ write_table({}) # unused according to spec self.send_frame(MethodFrame(self.channel_id, 60, 20, args)) if not nowait: self._pending_consumers.append((consumer, cb)) self.channel.add_synchronous_cb(self._recv_consume_ok) else: self._consumer_cb[consumer_tag] = consumer
def declare( self, exchange, type, passive=False, durable=False, auto_delete=True, internal=False, nowait=True, arguments=None, ticket=None, cb=None, ): """ Declare the exchange. exchange - The name of the exchange to declare type - One of """ nowait = nowait and self.allow_nowait() and not cb args = Writer() args.write_short(ticket or self.default_ticket).write_shortstr(exchange).write_shortstr(type).write_bits( passive, durable, auto_delete, internal, nowait ).write_table(arguments or {}) self.send_frame(MethodFrame(self.channel_id, 40, 10, args)) if not nowait: self._declare_cb.append(cb) self.channel.add_synchronous_cb(self._recv_declare_ok)
def close(self, reply_code=0, reply_text='', class_id=0, method_id=0): ''' Close this channel. Caller has the option of specifying the reason for closure and the class and method ids of the current frame in which an error occurred. If in the event of an exception, the channel will be marked as immediately closed. If channel is already closed, call is ignored. ''' if self._closed: return self._close_info = { 'reply_code' : reply_code, 'reply_text' : reply_text, 'class_id' : class_id, 'method_id' : method_id } # exception likely due to race condition as connection is closing try: args = Writer() args.write_short( reply_code ) args.write_shortstr( reply_text ) args.write_short( class_id ) args.write_short( method_id ) self.send_frame( MethodFrame(self.channel_id, 20, 40, args) ) self.channel.add_synchronous_cb( self._recv_close_ok ) except: self.logger.error("Failed to close channel %d", self.channel_id, exc_info=True) # Immediately set the closed flag so that no more frames can be sent self._closed = True
def consume(self, queue, consumer, consumer_tag='', no_local=False, no_ack=True, exclusive=False, nowait=True, ticket=None): ''' start a queue consumer. ''' if nowait and consumer_tag == '': consumer_tag = self._generate_consumer_tag() args = Writer() args.write_short(ticket or self.default_ticket).\ write_shortstr(queue).\ write_shortstr(consumer_tag).\ write_bits( no_local, no_ack, exclusive, nowait ).\ write_table({}) # unused according to spec self.send_frame(MethodFrame(self.channel_id, 60, 20, args)) if not nowait: self.channel.add_synchronous_cb(self._recv_consume_ok) self._pending_consumers.append(consumer) else: self._consumer_cb[consumer_tag] = consumer
def nack(self, delivery_tag, multiple=False, requeue=False): '''Send a nack to the broker.''' args = Writer() args.write_longlong(delivery_tag).\ write_bits(multiple, requeue) self.send_frame(MethodFrame(self.channel_id, 60, 120, args))
def declare(self, exchange, type, passive=False, durable=False, nowait=True, arguments=None, ticket=None, cb=None): """ Declare the exchange. exchange - The name of the exchange to declare type - One of """ nowait = nowait and self.allow_nowait() and not cb args = Writer() args.write_short(ticket or self.default_ticket).\ write_shortstr(exchange).\ write_shortstr(type).\ write_bits(passive, durable, False, False, nowait).\ write_table(arguments or {}) self.send_frame(MethodFrame(self.channel_id, 40, 10, args)) if not nowait: self._declare_cb.append(cb) self.channel.add_synchronous_cb(self._recv_declare_ok)
def test_write_short_at(self): w = Writer(bytearray('\x00' * 6)) assert_true(w is w.write_short_at(2**16 - 1, 2)) assert_equals(bytearray('\x00\x00\xff\xff\x00\x00'), w._output_buffer) assert_raises(ValueError, w.write_short_at, -1, 2) assert_raises(ValueError, w.write_short_at, 2**16, 3)
def test_field_table(self): w = Writer() expect( w.write_table ).args( {'foo':'bar'} ).side_effect( lambda: w._output_buffer.extend('tdata') ) w._field_table( {'foo':'bar'} ) assert_equals( 'Ftdata', w._output_buffer )
def declare(self, queue='', passive=False, durable=False, exclusive=False, auto_delete=True, nowait=True, arguments={}, ticket=None, cb=None): ''' Declare a queue. By default is asynchronoous but will be synchronous if nowait=False or a callback is defined. In synchronous mode, returns (message_count, consumer_count) queue - The name of the queue cb - An optional method which will be called with (queue_name, msg_count, consumer_count) if nowait=False ''' nowait = nowait and self.allow_nowait() and not cb args = Writer() args.write_short(ticket or self.default_ticket).\ write_shortstr(queue).\ write_bits(passive, durable, exclusive, auto_delete, nowait).\ write_table(arguments) self.send_frame(MethodFrame(self.channel_id, 50, 10, args)) if not nowait: self._declare_cb.append(cb) return self.channel.add_synchronous_cb(self._recv_declare_ok)
def bind(self, queue, exchange, routing_key='', nowait=True, arguments={}, ticket=None, cb=None): ''' bind to a queue. ''' # If a callback is defined, then we have to use synchronous transactions. if cb: nowait = False args = Writer() args.write_short(ticket or self.default_ticket).\ write_shortstr(queue).\ write_shortstr(exchange).\ write_shortstr(routing_key).\ write_bit(nowait).\ write_table(arguments) self.send_frame(MethodFrame(self.channel_id, 50, 20, args)) if not nowait: self.channel.add_synchronous_cb(self._recv_bind_ok) self._bind_cb.append(cb)
def test_write_short_at(self): w = Writer(bytearray("\x00" * 6)) assert_true(w is w.write_short_at(2 ** 16 - 1, 2)) assert_equals(bytearray("\x00\x00\xff\xff\x00\x00"), w._output_buffer) assert_raises(ValueError, w.write_short_at, -1, 2) assert_raises(ValueError, w.write_short_at, 2 ** 16, 3)
def cancel(self, consumer_tag='', nowait=True, consumer=None, cb=None): ''' Cancel a consumer. Can choose to delete based on a consumer tag or the function which is consuming. If deleting by function, take care to only use a consumer once per channel. ''' if consumer: for (tag,func) in self._consumer_cb.iteritems(): if func==consumer: consumer_tag = tag break nowait = nowait and self.allow_nowait() and not cb args = Writer() args.write_shortstr(consumer_tag).\ write_bit(nowait) self.send_frame( MethodFrame(self.channel_id, 60, 30, args) ) if not nowait: self._cancel_cb.append( cb ) self.channel.add_synchronous_cb( self._recv_cancel_ok ) else: try: del self._consumer_cb[consumer_tag] except KeyError: self.logger.warning( 'no callback registered for consumer tag " %s "', consumer_tag )
def test_field_table(self): w = Writer() expect(w.write_table).args({'foo': 'bar'}).side_effect( lambda *args: w._output_buffer.extend('tdata')) w._field_table({'foo': 'bar'}) assert_equals('Ftdata', w._output_buffer)
def bind(self, queue, exchange, routing_key='', nowait=True, arguments={}, ticket=None, cb=None): ''' bind to a queue. ''' nowait = nowait and self.allow_nowait() and not cb args = Writer() args.write_short(ticket or self.default_ticket).\ write_shortstr(queue).\ write_shortstr(exchange).\ write_shortstr(routing_key).\ write_bit(nowait).\ write_table(arguments) self.send_frame(MethodFrame(self.channel_id, 50, 20, args)) if not nowait: self._bind_cb.append(cb) self.channel.add_synchronous_cb(self._recv_bind_ok)
def _send_close(self): args = Writer() args.write_short(self.connection._close_info['reply_code']) args.write_shortstr(self.connection._close_info['reply_text'][:255]) args.write_short(self.connection._close_info['class_id']) args.write_short(self.connection._close_info['method_id']) self.send_frame(MethodFrame(self.channel_id, 10, 50, args))
def unbind(self, exchange, source, routing_key='', nowait=True, arguments={}, ticket=None, cb=None): ''' Unbind an exchange from another. ''' nowait = nowait and self.allow_nowait() and not cb args = Writer() args.write_short(ticket or self.default_ticket).\ write_shortstr(exchange).\ write_shortstr(source).\ write_shortstr(routing_key).\ write_bit(nowait).\ write_table(arguments or {}) self.send_frame(MethodFrame(self.channel_id, 40, 40, args)) if not nowait: self._unbind_cb.append(cb) self.channel.add_synchronous_cb(self._recv_unbind_ok)
def close(self, reply_code=0, reply_text='', class_id=0, method_id=0): ''' Close this channel. Caller has the option of specifying the reason for closure and the class and method ids of the current frame in which an error occurred. If in the event of an exception, the channel will be marked as immediately closed. If channel is already closed, call is ignored. ''' if not getattr(self, 'channel', None) or self.channel._closed: return self.channel._close_info = { 'reply_code': reply_code, 'reply_text': reply_text, 'class_id': class_id, 'method_id': method_id } # exceptions here likely due to race condition as connection is closing # cap the reply_text we send because it may be arbitrarily long try: args = Writer() args.write_short(reply_code) args.write_shortstr(reply_text[:255]) args.write_short(class_id) args.write_short(method_id) self.send_frame(MethodFrame(self.channel_id, 20, 40, args)) self.channel.add_synchronous_cb(self._recv_close_ok) finally: # Immediately set the closed flag so that no more frames can be sent # NOTE: in synchronous mode, by the time this is called we will have # already run self.channel._closed_cb and so the channel reference is # gone. if self.channel: self.channel._closed = True
def consume(self, queue, consumer, consumer_tag='', no_local=False, no_ack=True, exclusive=False, nowait=True, ticket=None, cb=None): ''' Start a queue consumer. If `cb` is supplied, will be called when broker confirms that consumer is registered. ''' nowait = nowait and self.allow_nowait() and not cb if nowait and consumer_tag == '': consumer_tag = self._generate_consumer_tag() args = Writer() args.write_short(ticket or self.default_ticket).\ write_shortstr(queue).\ write_shortstr(consumer_tag).\ write_bits(no_local, no_ack, exclusive, nowait).\ write_table({}) # unused according to spec self.send_frame(MethodFrame(self.channel_id, 60, 20, args)) if not nowait: self._pending_consumers.append((consumer, cb)) self.channel.add_synchronous_cb(self._recv_consume_ok) else: self._consumer_cb[consumer_tag] = consumer
def declare( self, queue="", passive=False, durable=False, exclusive=False, auto_delete=True, nowait=True, arguments={}, ticket=None, cb=None, ): """ Declare a queue. By default is asynchronoous but will be synchronous if nowait=False or a callback is defined. queue - The name of the queue cb - An optional method which will be called with (queue_name, msg_count, consumer_count) if nowait=False """ # If a callback is defined, then we have to use synchronous transactions. if cb: nowait = False args = Writer() args.write_short(ticket or self.default_ticket).write_shortstr(queue).write_bits( passive, durable, exclusive, auto_delete, nowait ).write_table(arguments) self.send_frame(MethodFrame(self.channel_id, 50, 10, args)) if not nowait: self.channel.add_synchronous_cb(self._recv_declare_ok) self._declare_cb.append(cb)
def test_write_long_at(self): w = Writer( bytearray('\x00'*8) ) assert_true( w is w.write_long_at(2**32-1,2) ) assert_equals( bytearray('\x00\x00\xff\xff\xff\xff\x00\x00'), w._output_buffer ) assert_raises( ValueError, w.write_long_at, -1, 2 ) assert_raises( ValueError, w.write_long_at, 2**32, 3 )
def test_write_field_supports_subclasses(self): class SubString(str): pass w = Writer() w._write_field(SubString('foo')) assert_equals('S\x00\x00\x00\x03foo', w._output_buffer)
def test_write_long(self): w = Writer() assert_true( w is w.write_long(0) ) assert_true( w is w.write_long(2**32-2) ) assert_equals( bytearray('\x00\x00\x00\x00\xff\xff\xff\xfe'), w._output_buffer ) assert_raises( ValueError, w.write_long, -1 ) assert_raises( ValueError, w.write_long, 2**32 )
def _send_flow(self, active): ''' Send a flow control command. ''' args = Writer() args.write_bit(active) self.send_frame(MethodFrame(self.channel_id, 20, 20, args)) self.channel.add_synchronous_cb(self._recv_flow_ok)
def test_write_short(self): w = Writer() assert_true( w is w.write_short(0) ) assert_true( w is w.write_short(2**16-2) ) assert_equals( bytearray('\x00\x00\xff\xfe'), w._output_buffer ) assert_raises( ValueError, w.write_short, -1 ) assert_raises( ValueError, w.write_short, 2**16 )
def test_write_octet(self): w = Writer() assert_true( w is w.write_octet(0) ) assert_true( w is w.write_octet(255) ) assert_equals( bytearray('\x00\xff'), w._output_buffer ) assert_raises( ValueError, w.write_octet, -1 ) assert_raises( ValueError, w.write_octet, 2**8 )
def open(self): ''' Open the channel for communication. ''' args = Writer() args.write_shortstr('') self.send_frame(MethodFrame(self.channel_id, 20, 10, args)) self.channel.add_synchronous_cb(self._recv_open_ok)
def test_write_short(self): w = Writer() assert_true(w is w.write_short(0)) assert_true(w is w.write_short(2**16 - 2)) assert_equals(bytearray('\x00\x00\xff\xfe'), w._output_buffer) assert_raises(ValueError, w.write_short, -1) assert_raises(ValueError, w.write_short, 2**16)
def _send_start_ok(self): '''Send the start_ok message.''' args = Writer() args.write_table(self.connection._properties) args.write_shortstr(self.connection._login_method) args.write_longstr(self.connection._login_response) args.write_shortstr(self.connection._locale) self.send_frame(MethodFrame(self.channel_id, 10, 11, args))
def test_write_octet(self): w = Writer() assert_true(w is w.write_octet(0)) assert_true(w is w.write_octet(255)) assert_equals(bytearray('\x00\xff'), w._output_buffer) assert_raises(ValueError, w.write_octet, -1) assert_raises(ValueError, w.write_octet, 2**8)
def reject(self, delivery_tag, requeue=False): ''' Reject a message. ''' args = Writer() args.write_longlong( delivery_tag ).\ write_bit( requeue ) self.send_frame( MethodFrame(self.channel_id, 60, 90, args) )
def test_write_field(self): w = Writer() unknown = mock() expect( w._field_none ).args( unknown ) w._write_field( unknown ) Writer.field_type_map[type(unknown)] = unknown expect( unknown ).args( w, unknown ) w._write_field( unknown )
def test_write_bits(self): w = Writer() assert_true( w is w.write_bits(False,True) ) assert_equals( bytearray('\x02'), w._output_buffer ) w = Writer() assert_true( w is w.write_bits(False,False,True,True,True) ) assert_equals( bytearray('\x1c'), w._output_buffer ) assert_raises( ValueError, w.write_bits, *((True,)*9) )
def test_write_long(self): w = Writer() assert_true(w is w.write_long(0)) assert_true(w is w.write_long(2**32 - 2)) assert_equals(bytearray('\x00\x00\x00\x00\xff\xff\xff\xfe'), w._output_buffer) assert_raises(ValueError, w.write_long, -1) assert_raises(ValueError, w.write_long, 2**32)
def test_write_table(self): w = Writer() expect( w._write_item ).args( 'a', 'foo' ).any_order().side_effect( lambda: (setattr(w,'_pos',20), w._output_buffer.extend('afoo')) ) expect( w._write_item ).args( 'b', 'bar' ).any_order().side_effect( lambda: (setattr(w,'_pos',20), w._output_buffer.extend('bbar')) ) assert_true( w is w.write_table({'a':'foo','b':'bar'}) ) assert_equals( '\x00\x00\x00\x08', w._output_buffer[:4] ) assert_equals( 12, len(w._output_buffer) )
def recover_async(self, requeue=False): ''' Redeliver all unacknowledged messaages on this channel. This method is deprecated in favour of the synchronous recover/recover-ok ''' args = Writer() args.write_bit( requeue ) self.send_frame( MethodFrame(self.channel_id, 60, 100, args) )
def ack(self, delivery_tag, multiple=False): ''' Acknowledge delivery of a message. If multiple=True, acknowledge up-to and including delivery_tag. ''' args = Writer() args.write_longlong(delivery_tag).\ write_bit(multiple) self.send_frame( MethodFrame(self.channel_id, 60, 80, args) )
def test_return_msg(self): args = Writer() args.write_short(3) args.write_shortstr('reply_text') args.write_shortstr('exchange') args.write_shortstr('routing_key') expect(mock(basic_class, 'MethodFrame')).args(42, 60, 50, args).returns('frame') expect(self.klass.send_frame).args('frame') self.klass.return_msg(3, 'reply_text', 'exchange', 'routing_key')
def test_write_table(self): w = Writer() expect(w._write_item).args('a', 'foo').any_order().side_effect( lambda *args: (setattr(w, '_pos', 20), w._output_buffer.extend('afoo'))) expect(w._write_item).args('b', 'bar').any_order().side_effect( lambda *args: (setattr(w, '_pos', 20), w._output_buffer.extend('bbar'))) assert_true(w is w.write_table({'a': 'foo', 'b': 'bar'})) assert_equals('\x00\x00\x00\x08', w._output_buffer[:4]) assert_equals(12, len(w._output_buffer))
def _send_close(self): args = Writer() args.write_short( self.connection._close_info['reply_code'] ) args.write_shortstr( self.connection._close_info['reply_text'][:255] ) args.write_short( self.connection._close_info['class_id'] ) args.write_short( self.connection._close_info['method_id'] ) self.send_frame( MethodFrame(self.channel_id, 10, 50, args) )
def close(self, reply_code=0, reply_text='', class_id=0, method_id=0): ''' Close this channel. Caller has the option of specifying the reason for closure and the class and method ids of the current frame in which an error occurred. If in the event of an exception, the channel will be marked as immediately closed. If channel is already closed, call is ignored. ''' if not getattr(self, 'channel', None) or self.channel._closed: return self.channel._close_info = { 'reply_code' : reply_code, 'reply_text' : reply_text, 'class_id' : class_id, 'method_id' : method_id } # exceptions here likely due to race condition as connection is closing # cap the reply_text we send because it may be arbitrarily long try: args = Writer() args.write_short( reply_code ) args.write_shortstr( reply_text[:255] ) args.write_short( class_id ) args.write_short( method_id ) self.send_frame( MethodFrame(self.channel_id, 20, 40, args) ) self.channel.add_synchronous_cb( self._recv_close_ok ) finally: # Immediately set the closed flag so that no more frames can be sent # NOTE: in synchronous mode, by the time this is called we will have # already run self.channel._closed_cb and so the channel reference is # gone. if self.channel: self.channel._closed = True
def close(self, reply_code=0, reply_text='', class_id=0, method_id=0): ''' Close this channel. Caller has the option of specifying the reason for closure and the class and method ids of the current frame in which an error occurred. If in the event of an exception, the channel will be marked as immediately closed. If channel is already closed, call is ignored. ''' if self._closed: return self._close_info = { 'reply_code' : reply_code, 'reply_text' : reply_text, 'class_id' : class_id, 'method_id' : method_id } try: args = Writer() args.write_short( reply_code ) args.write_shortstr( reply_text ) args.write_short( class_id ) args.write_short( method_id ) self.send_frame( MethodFrame(self.channel_id, 20, 40, args) ) self.channel.add_synchronous_cb( self._recv_close_ok ) except: self.logger.error("Failed to close channel %d", self.channel_id, exc_info=True) # Immediately set the closed flag so that no more frames can be sent self._closed = True
def qos(self, prefetch_size=0, prefetch_count=0, is_global=False): ''' Set QoS on this channel. ''' args = Writer() args.write_long(prefetch_size).\ write_short(prefetch_count).\ write_bit(is_global) self.send_frame( MethodFrame(self.channel_id, 60, 10, args) ) self.channel.add_synchronous_cb( self._recv_qos_ok )
def write_frame(self, buf): ''' Write the frame into an existing buffer. ''' writer = Writer( buf ) writer.write_octet( self.type() ).\ write_short(self.channel_id).\ write_long( len(self._payload) ).\ write( self._payload ).\ write_octet( 0xce )
def _send_tune_ok(self): args = Writer() args.write_short(self.connection._channel_max) args.write_long(self.connection._frame_max) if self.connection._heartbeat: args.write_short(self.connection._heartbeat) else: args.write_short(0) self.send_frame(MethodFrame(self.channel_id, 10, 31, args))
def _send_start_ok(self): '''Send the start_ok message.''' args = Writer() args.write_table(self.connection._properties) args.write_shortstr(self.connection._login_method) args.write_longstr(self.connection._login_response) args.write_shortstr(self.connection._locale) self.send_frame( MethodFrame(self.channel_id, 10, 11, args) )
def _recv_flow(self, method_frame): ''' Receive a flow control command from the broker ''' self.channel._active = method_frame.args.read_bit() args = Writer() args.write_bit(self.channel.active) self.send_frame(MethodFrame(self.channel_id, 20, 21, args)) if self._flow_control_cb is not None: self._flow_control_cb()
def unbind(self, queue, exchange, routing_key="", arguments={}, ticket=None, cb=None): """ Unbind a queue from an exchange. This is always synchronous. """ args = Writer() args.write_short(ticket or self.default_ticket).write_shortstr(queue).write_shortstr(exchange).write_shortstr( routing_key ).write_table(arguments) self.send_frame(MethodFrame(self.channel_id, 50, 50, args)) self.channel.add_synchronous_cb(self._recv_unbind_ok) self._unbind_cb.append(cb)
def test_write_table(self): w = Writer() expect(w._write_item).args("a", "foo").any_order().side_effect( lambda: (setattr(w, "_pos", 20), w._output_buffer.extend("afoo")) ) expect(w._write_item).args("b", "bar").any_order().side_effect( lambda: (setattr(w, "_pos", 20), w._output_buffer.extend("bbar")) ) assert_true(w is w.write_table({"a": "foo", "b": "bar"})) assert_equals("\x00\x00\x00\x08", w._output_buffer[:4]) assert_equals(12, len(w._output_buffer))
def return_msg(self, reply_code, reply_text, exchange, routing_key): ''' Return a failed message. Not named "return" because python interpreter can't deal with that. ''' args = Writer() args.write_short( reply_code ).\ write_shortstr( reply_text ).\ write_shortstr( exchange ).\ write_shortstr( routing_key ) self.send_frame( MethodFrame(self.channel_id, 60, 50, args) )
def recover(self, requeue=False, cb=None): ''' Ask server to redeliver all unacknowledged messages. ''' args = Writer() args.write_bit( requeue ) # The XML spec is incorrect; this method is always synchronous # http://lists.rabbitmq.com/pipermail/rabbitmq-discuss/2011-January/010738.html self._recover_cb.append( cb ) self.send_frame( MethodFrame(self.channel_id, 60, 110, args) ) self.channel.add_synchronous_cb( self._recv_recover_ok )