diff --git a/.codeclimate.yml b/.codeclimate.yml index 5c6e916b0e52a4cc22177dd925b536243506da9d..493477c212be35db17ed3a2732477606ce80b57a 100644 --- a/.codeclimate.yml +++ b/.codeclimate.yml @@ -17,6 +17,7 @@ exclude_paths: - examples/** - tests/** - coolamqp/framing/definitions.py +- compile_definitions.py ratings: paths: - coolamqp/** diff --git a/.coveragerc b/.coveragerc index f24350cc6d75e2246462bc73bdf1e64e9bcb0e6d..17131187d3687dec32408c46e87f17a7d09df260 100644 --- a/.coveragerc +++ b/.coveragerc @@ -1,7 +1,8 @@ [run] branch=1 -include=coolamqp/* +include= + coolamqp/* omit= tests/* + compile_definitions.py coolamqp/framing/definitions.py - diff --git a/.travis.yml b/.travis.yml index 594b38acd6e5b3c9d8524fc0b7af0e191b2fd412..b6ed5188dcd8097310080c6b166877c1ec59aeb5 100644 --- a/.travis.yml +++ b/.travis.yml @@ -5,12 +5,11 @@ python: - "3.4" - "3.5" - "pypy" -cache: - directories: - - $HOME/build/smok-serwis/coolamqp/.eggs - - $HOME/.cache +cache: pip +before_script: + - pip install codeclimate-test-reporter script: - - python -m coolamqp.framing.compilation.compile_definitions + - python compile_definitions.py - python setup.py nosetests install: - pip install -r requirements.txt diff --git a/MANIFEST.in b/MANIFEST.in index 03852067743acecf0989e14f60bef02c90a7b19b..7b741275f0d1fedbd2b153e542ffe0df369d9a7a 100644 --- a/MANIFEST.in +++ b/MANIFEST.in @@ -1,3 +1,3 @@ include LICENSE include README.md -include requirements.txt \ No newline at end of file +include requirements.txt diff --git a/README.md b/README.md index 4cc74e14ef95fd10062166670cb3ef5348db9e68..49f7db9a17447b2c5cdd63e1f0d07e254cb9547c 100644 --- a/README.md +++ b/README.md @@ -1,15 +1,15 @@ CoolAMQP ======== -[](http://coolamqp.readthedocs.io/en/latest/?badge=latest) -[](https://badge.fury.io/py/CoolAMQP) [](https://travis-ci.org/smok-serwis/coolamqp) -[](https://codeclimate.com/github/smok-serwis/coolamqp) [](https://codeclimate.com/github/smok-serwis/coolamqp/coverage) -[]() +[](https://codeclimate.com/github/smok-serwis/coolamqp) +[](https://codeclimate.com/github/smok-serwis/coolamqp) +[](https://badge.fury.io/py/CoolAMQP) []() []() -[](https://codeclimate.com/github/smok-serwis/coolamqp) []() +[](http://coolamqp.readthedocs.io/en/latest/?badge=latest) +[]() A **magical** AMQP client, that uses **heavy sorcery** to achieve speeds that other AMQP clients cannot even hope to match. diff --git a/build.sh b/build.sh index ce455639ce740840f8dcabeefba1b952519c61af..7aa0c0b2699507ee2b4ecfbcb1ac39b6b62e987b 100644 --- a/build.sh +++ b/build.sh @@ -3,8 +3,7 @@ set -x set -e -python -m coolamqp.framing.compilation.compile_definitions -rm -f coolamqp/framing/compilation/compile_definitions.py +python compile_definitions.py python setup.py bdist bdist_wheel if [ $TRAVIS_BRANCH == "master" ]; then diff --git a/coolamqp/framing/compilation/compile_definitions.py b/compile_definitions.py similarity index 100% rename from coolamqp/framing/compilation/compile_definitions.py rename to compile_definitions.py diff --git a/coolamqp/attaches/channeler.py b/coolamqp/attaches/channeler.py index bf712755743c3da5c09e780b9a79219ef718624b..87f733907555e49b6a5b7b63901744c27af2e5d8 100644 --- a/coolamqp/attaches/channeler.py +++ b/coolamqp/attaches/channeler.py @@ -136,7 +136,7 @@ class Channeler(Attache): self.state = ST_OFFLINE if not isinstance(payload, (ChannelClose, ChannelCloseOk)) and ( - payload is not None): + payload is not None): # I do not know how to handle that! return @@ -217,7 +217,7 @@ class Channeler(Attache): To be called by on_close, when it needs to be notified just one more time. """ self.connection.watch_for_method(self.channel_id, ( - ChannelClose, ChannelCloseOk, BasicCancel, BasicCancelOk), + ChannelClose, ChannelCloseOk, BasicCancel, BasicCancelOk), self.on_close, on_fail=self.on_close) diff --git a/coolamqp/attaches/consumer.py b/coolamqp/attaches/consumer.py index 5deb6bb99cae36061922644f2c7b2e5f31f78eb6..d908b12aa091a95f3916a1977245269216655ad4 100644 --- a/coolamqp/attaches/consumer.py +++ b/coolamqp/attaches/consumer.py @@ -123,12 +123,7 @@ class Consumer(Channeler): self.attache_group = None # attache group this belongs to. # if this is not None, then it has an attribute # on_cancel_customer(Consumer instance) - if qos is not None: - if isinstance(qos, int): - qos = 0, qos - elif qos[0] is None: - qos = 0, qos[1] # prefetch_size=0=undefined - self.qos = qos + self.qos = _qosify(qos) self.qos_update_sent = False # QoS was not sent to server self.future_to_notify = future_to_notify @@ -291,7 +286,8 @@ class Consumer(Channeler): def on_delivery(self, sth): """ Callback for delivery-related shit - :param sth: AMQPMethodFrame WITH basic-deliver, AMQPHeaderFrame or AMQPBodyFrame + :param sth: AMQPMethodFrame WITH basic-deliver, AMQPHeaderFrame or + AMQPBodyFrame """ if self.receiver is None: @@ -305,7 +301,8 @@ class Consumer(Channeler): elif isinstance(sth, AMQPHeaderFrame): self.receiver.on_head(sth) - # No point in listening for more stuff, that's all the watches even listen for + # No point in listening for more stuff, that's all the watches + # even listen for def on_setup(self, payload): """Called with different kinds of frames - during setup""" @@ -394,7 +391,8 @@ class Consumer(Channeler): # Register watches for receiving shit # this is multi-shot by default - self.hb_watch = HeaderOrBodyWatch(self.channel_id, self.on_delivery) + self.hb_watch = HeaderOrBodyWatch(self.channel_id, + self.on_delivery) self.connection.watch(self.hb_watch) # multi-shot watches need manual cleanup! @@ -410,6 +408,15 @@ class Consumer(Channeler): self.set_qos(self.qos[0], self.qos[1]) +def _qosify(qos): + if qos is not None: + if isinstance(qos, int): + qos = 0, qos + elif qos[0] is None: + qos = 0, qos[1] # prefetch_size=0=undefined + return qos + + class MessageReceiver(object): """This is an object that is used to received messages. @@ -433,21 +440,28 @@ class MessageReceiver(object): self.bdeliver = None # payload of Basic-Deliver self.header = None # AMQPHeaderFrame if consumer.body_receive_mode == BodyReceiveMode.MEMORYVIEW: - self.body = None # None is an important sign - first piece of message + self.body = None # None is an important sign - first piece of + # message else: self.body = [] # list of payloads - self.data_to_go = None # set on receiving header, how much bytes we need yet + self.data_to_go = None # set on receiving header, how much bytes we + # need yet self.message_size = None # in bytes, of currently received message - self.offset = 0 # used only in MEMORYVIEW mode - pointer to self.body (which would be a buffer) + self.offset = 0 # used only in MEMORYVIEW mode - pointer to self.body + # (which would be a buffer) self.acks_pending = set() # list of things to ack/reject self.recv_mode = consumer.body_receive_mode - # if BYTES, pieces (as mvs) are received into .body and b''.join()ed at the end + # if BYTES, pieces (as mvs) are received into .body and b''.join()ed + # at the end # if MEMORYVIEW: - # upon first piece, if it's a single-frame message, it's returned at once - # if multiframe, self.body is made into a buffer and further are received into it - # if LIST_OF_MEMORYVIEW, pieces (as mvs) are stored into .body, and that's returned + # upon first piece, if it's a single-frame message, + # it's returned at once + # if multiframe, self.body is made into a buffer + # and further are received into it + # if LIST_OF_MEMORYVIEW, pieces (as mvs) are stored into .body, and + # that's returned def on_gone(self): """Called by Consumer to inform upon discarding this receiver""" @@ -457,7 +471,8 @@ class MessageReceiver(object): """ This crafts a constructor for confirming messages. - This should return a callable/0, whose calling will ACK or REJECT the message. + This should return a callable/0, whose calling will ACK or REJECT the + message. Calling it multiple times should have no ill effect. If this receiver is long gone, @@ -491,7 +506,8 @@ class MessageReceiver(object): self.state = 2 if self.header.body_size == 0: - # An empty message is no common guest. It won't have a BODY field though... + # An empty message is no common guest. It won't have a BODY field + # though... self.on_body(EMPTY_MEMORYVIEW) # trigger it manually def on_basic_deliver(self, payload): @@ -541,7 +557,8 @@ class MessageReceiver(object): # common case :) body = self.body[0].tobytes() else: - # since b''.join() with list comprehension and .tobytes() would create + # since b''.join() with list comprehension and .tobytes() + # would create # an extra copy of string bio = io.BytesIO() for mv in body: diff --git a/coolamqp/attaches/declarer.py b/coolamqp/attaches/declarer.py index 112a402da59e53623d83bc95e64d4d1cdae8b638..9e07baff9c2c56529ae415ef9b65d2b0177220d6 100644 --- a/coolamqp/attaches/declarer.py +++ b/coolamqp/attaches/declarer.py @@ -239,7 +239,7 @@ class Declarer(Channeler, Synchronized): To be called when it's possible that something can be done """ if (self.state != ST_ONLINE) or len(self.left_to_declare) == 0 or ( - self.in_process is not None): + self.in_process is not None): return self.in_process = self.left_to_declare.popleft() diff --git a/coolamqp/attaches/publisher.py b/coolamqp/attaches/publisher.py index 9915dbaf381c711cf8395f303d22b44accc46aa9..6d480f5b1df3a0d8daef9436b00f949959bc3c14 100644 --- a/coolamqp/attaches/publisher.py +++ b/coolamqp/attaches/publisher.py @@ -12,9 +12,9 @@ from __future__ import absolute_import, division, print_function import collections import logging -import warnings - +import struct import six +import warnings from coolamqp.framing.definitions import ChannelOpenOk, BasicPublish, Basic, \ BasicAck @@ -233,7 +233,8 @@ class Publisher(Channeler, Synchronized): def on_operational(self, operational): state = {True: u'up', False: u'down'}[operational] - mode = {Publisher.MODE_NOACK: u'noack', Publisher.MODE_CNPUB: u'cnpub'}[ + mode = \ + {Publisher.MODE_NOACK: u'noack', Publisher.MODE_CNPUB: u'cnpub'}[ self.mode] logger.info('Publisher %s is %s', mode, state) diff --git a/coolamqp/clustering/cluster.py b/coolamqp/clustering/cluster.py index 14262120343a8e28b74f3c8f8e1652c899913fb1..9f31d190bf9bbc4c01ecaf6c6f76ed7eb2e962e4 100644 --- a/coolamqp/clustering/cluster.py +++ b/coolamqp/clustering/cluster.py @@ -13,7 +13,8 @@ from coolamqp.attaches import Publisher, AttacheGroup, Consumer, Declarer from coolamqp.objects import Exchange from concurrent.futures import Future -from coolamqp.clustering.events import ConnectionLost, MessageReceived, NothingMuch +from coolamqp.clustering.events import ConnectionLost, MessageReceived, \ + NothingMuch logger = logging.getLogger(__name__) @@ -56,6 +57,7 @@ class Cluster(object): def decorated(): if not self.listener.terminating: on_fail() + self.on_fail = decorated else: self.on_fail = None @@ -101,8 +103,10 @@ class Cluster(object): """ fut = Future() fut.set_running_or_notify_cancel() # it's running right now - on_message = on_message or (lambda rmsg: self.events.put_nowait(MessageReceived(rmsg))) - con = Consumer(queue, on_message, future_to_notify=fut, *args, **kwargs) + on_message = on_message or ( + lambda rmsg: self.events.put_nowait(MessageReceived(rmsg))) + con = Consumer(queue, on_message, future_to_notify=fut, *args, + **kwargs) self.attache_group.add(con) return con, fut @@ -115,7 +119,8 @@ class Cluster(object): """ return self.decl.delete_queue(queue) - def publish(self, message, exchange=None, routing_key=u'', tx=None, confirm=None): + def publish(self, message, exchange=None, routing_key=u'', tx=None, + confirm=None): """ Publish a message. @@ -145,16 +150,20 @@ class Cluster(object): warnings.warn(u'Use confirm kwarg instead', DeprecationWarning) if confirm is not None: - raise RuntimeError(u'Using both tx= and confirm= at once does not make sense') + raise RuntimeError( + u'Using both tx= and confirm= at once does not make sense') elif confirm is not None: tx = confirm else: tx = False try: - return (self.pub_tr if tx else self.pub_na).publish(message, exchange, routing_key) + return (self.pub_tr if tx else self.pub_na).publish(message, + exchange, + routing_key) except Publisher.UnusablePublisher: - raise NotImplementedError(u'Sorry, this functionality is not yet implemented!') + raise NotImplementedError( + u'Sorry, this functionality is not yet implemented!') def start(self, wait=True): """ @@ -180,7 +189,8 @@ class Cluster(object): self.events = six.moves.queue.Queue() # for coolamqp.clustering.events.* - self.snr = SingleNodeReconnector(self.node, self.attache_group, self.listener) + self.snr = SingleNodeReconnector(self.node, self.attache_group, + self.listener) self.snr.on_fail.add(lambda: self.events.put_nowait(ConnectionLost())) if self.on_fail is not None: self.snr.on_fail.add(self.on_fail) diff --git a/coolamqp/exceptions.py b/coolamqp/exceptions.py index 8bee7fd14e36faa0066bddddd2ce47ab12406de8..0e4fcf979e6e04ac09021ac53df46a51a672c3f3 100644 --- a/coolamqp/exceptions.py +++ b/coolamqp/exceptions.py @@ -25,15 +25,11 @@ class AMQPError(CoolAMQPError): return self.reply_code in HARD_ERRORS def __str__(self): - return u'AMQP error %s: %s' % (self.reply_code, self.reply_text) + return 'AMQP error %s: %s' % (self.reply_code, self.reply_text) def __repr__(self): - return u'AMQPError(%s, %s, %s, %s)' % ( - repr(self.reply_code), - repr(self.reply_text), - repr(self.class_id), - repr(self.method_id), - ) + return 'AMQPError('+repr(self.reply_code)+', '+repr(self.reply_text)+ \ + ', '+repr(self.class_id)+', '+repr(self.method_id)+')' def __init__(self, *args): """ diff --git a/coolamqp/framing/base.py b/coolamqp/framing/base.py index 75f74c34614123d9ad76a4daec7043244f17edba..89f057568963c32c49f0bc38a7b2f22fa54fcae5 100644 --- a/coolamqp/framing/base.py +++ b/coolamqp/framing/base.py @@ -13,9 +13,9 @@ BASIC_TYPES = {u'bit': (None, None, "0", None), # special case u'short': (2, 'H', "b'\\x00\\x00'", 2), u'long': (4, 'I', "b'\\x00\\x00\\x00\\x00'", 4), u'longlong': ( - 8, 'Q', "b'\\x00\\x00\\x00\\x00\\x00\\x00\\x00\\x00'", 8), + 8, 'Q', "b'\\x00\\x00\\x00\\x00\\x00\\x00\\x00\\x00'", 8), u'timestamp': ( - 8, 'Q', "b'\\x00\\x00\\x00\\x00\\x00\\x00\\x00\\x00'", 8), + 8, 'Q', "b'\\x00\\x00\\x00\\x00\\x00\\x00\\x00\\x00'", 8), u'table': (None, None, "b'\\x00\\x00\\x00\\x00'", 4), # special case u'longstr': (None, None, "b'\\x00\\x00\\x00\\x00'", 4), diff --git a/coolamqp/framing/compilation/content_property.py b/coolamqp/framing/compilation/content_property.py index ce970fb028c7aa322a2c5df0b177883e49d49b72..3b94bc83cf5f50d3cd09daf8a047e7245e417cac 100644 --- a/coolamqp/framing/compilation/content_property.py +++ b/coolamqp/framing/compilation/content_property.py @@ -9,6 +9,32 @@ from coolamqp.framing.compilation.textcode_fields import get_counter, \ logger = logging.getLogger(__name__) +INIT_I = u'\n def __init__(self, %s):\n' +SLOTS_I = u'\n __slots__ = (%s)\n' +FROM_BUFFER_1 = u' def from_buffer(cls, buf, start_offset):\n ' \ + u'offset = start_offset + %s\n' +ASSIGN_A = u' self.%s = %s\n' +STARTER = u'''import struct +from coolamqp.framing.base import AMQPContentPropertyList + +class ParticularContentTypeList(AMQPContentPropertyList): + """ + For fields: +''' +ZPF_S = u''' + # A value for property flags that is used, assuming all bit fields are FALSE (0) + ZERO_PROPERTY_FLAGS = %s +''' +NB = u"raise NotImplementedError('I don't support bits in properties')" +INTER_X = u' * %s::%s' +BUF_WRITE_A = u'\n def write_to(self, buf):\n buf.write(' +RESERVED = u' (reserved)' +UNICO = u"u'%s'" +SPACER = u''' + """ +''' +GET_SIZE_HEADER = u'\n def get_size(self):\n' + def _compile_particular_content_property_list_class(zpf, fields): """ @@ -21,7 +47,7 @@ def _compile_particular_content_property_list_class(zpf, fields): from coolamqp.framing.compilation.utilities import format_field_name if any(field.basic_type == 'bit' for field in fields): - return u"raise NotImplementedError('I don't support bits in properties yet')" + return NB # Convert ZPF to a list of [if_exists::bool] even = True @@ -33,27 +59,23 @@ def _compile_particular_content_property_list_class(zpf, fields): if not even: p = p[:7] - zpf_bits.extend(map(lambda x: bool(int(x)), p)) + for x in p: + zpf_bits.append(bool(int(x))) zpf_length = len(zpf) - # 1 here does not mean that field is present. All bit fields are present, but 0 in a ZPF. Fix this. + # 1 here does not mean that field is present. All bit fields are present, + # but 0 in a ZPF. Fix this. zpf_bits = [zpf_bit or field.type == 'bit' for zpf_bit, field in zip(zpf_bits, fields)] - mod = [u'''import struct -from coolamqp.framing.base import AMQPContentPropertyList - -class ParticularContentTypeList(AMQPContentPropertyList): - """ - For fields: -'''] + mod = [STARTER] for field in fields: mod.append( - u' * %s::%s' % (format_field_name(field.name), field.type)) + INTER_X % (format_field_name(field.name), field.type)) if field.reserved: - mod.append(u' (reserved)') + mod.append(RESERVED) mod.append(u'\n') x = repr(six.binary_type(zpf)) @@ -63,38 +85,30 @@ class ParticularContentTypeList(AMQPContentPropertyList): present_fields = [field for field, present in zip(fields, zpf_bits) if present] - mod.append(u''' - """ -''') + mod.append(SPACER) if len(present_fields) == 0: slots = u'' else: slots = (u', '.join( - (u"u'%s'" % format_field_name(field.name) for field in + (UNICO % format_field_name(field.name) for field in present_fields))) + u', ' - mod.append(u''' - __slots__ = (%s) -''' % slots) + mod.append(SLOTS_I % slots) - mod.append(u''' - # A value for property flags that is used, assuming all bit fields are FALSE (0) - ZERO_PROPERTY_FLAGS = %s -''' % (x,)) + mod.append(ZPF_S % (x,)) + + FFN = u', '.join(format_field_name(field.name) for field in present_fields) if len(present_fields) > 0: - mod.append(u''' - def __init__(self, %s): -''' % (u', '.join(format_field_name(field.name) for field in present_fields))) + mod.append(INIT_I % (FFN,)) for field in present_fields: - mod.append(u' self.%s = %s\n'.replace(u'%s', format_field_name( + mod.append(ASSIGN_A.replace(u'%s', format_field_name( field.name))) # Let's do write_to - mod.append(u'\n def write_to(self, buf):\n') - mod.append(u' buf.write(') + mod.append(BUF_WRITE_A) repred_zpf = repr(zpf) if not repred_zpf.startswith(u'b'): repred_zpf = u'b' + repred_zpf @@ -107,17 +121,15 @@ class ParticularContentTypeList(AMQPContentPropertyList): # note that non-bit values mod.append(u' @classmethod\n') mod.append( - u' def from_buffer(cls, buf, start_offset):\n offset = start_offset + %s\n' % ( - zpf_length,)) + FROM_BUFFER_1 % ( + zpf_length,)) mod.append(get_from_buffer( present_fields , prefix='', indent_level=2)) - mod.append(u' return cls(%s)\n' % - u', '.join( - format_field_name(field.name) for field in present_fields)) + mod.append(u' return cls(%s)\n' % (FFN,)) # get_size - mod.append(u'\n def get_size(self):\n') + mod.append(GET_SIZE_HEADER) mod.append(get_counter(present_fields, prefix=u'self.', indent_level=2)[ :-1]) # skip eol mod.append(u' + %s\n' % (zpf_length,)) # account for pf length diff --git a/coolamqp/framing/compilation/textcode_fields.py b/coolamqp/framing/compilation/textcode_fields.py index 88d99d9ebe53ec6e88bfd3bff437d34ee32b570b..3a27ee44e6fdb94c9f1d24b3d3b65da6c6bd9094 100644 --- a/coolamqp/framing/compilation/textcode_fields.py +++ b/coolamqp/framing/compilation/textcode_fields.py @@ -66,7 +66,7 @@ def get_counter(fields, prefix=u'', indent_level=2): accumulator += int(math.ceil(bits / 8)) return (u' ' * indent_level) + u'return ' + ( - u' + '.join([str(accumulator)] + parts)) + u'\n' + u' + '.join([str(accumulator)] + parts)) + u'\n' def get_from_buffer(fields, prefix='', indent_level=2, remark=False): @@ -208,7 +208,7 @@ def get_serializer(fields, prefix='', indent_level=2): for bit_name, modif in zip(bits, range(8)): if bit_name != 'False': p.append('(' + bit_name + ' << %s)' % ( - modif,)) # yes you can << bools + modif,)) # yes you can << bools format_args.append(u' | '.join(p)) del bits[:] diff --git a/coolamqp/framing/compilation/utilities.py b/coolamqp/framing/compilation/utilities.py index dd93515cd22ab58f317ad93ba164210bfc0967a5..f647043dbe6885d8897df30377b692ed5a5b5726 100644 --- a/coolamqp/framing/compilation/utilities.py +++ b/coolamqp/framing/compilation/utilities.py @@ -11,13 +11,15 @@ from coolamqp.framing.base import BASIC_TYPES, DYNAMIC_BASIC_TYPES # docs may be None Constant = namedtuple('Constant', ( -'name', 'value', 'kind', 'docs')) # kind is AMQP constant class # value is int + 'name', 'value', 'kind', + 'docs')) # kind is AMQP constant class # value is int Field = namedtuple('Field', ( -'name', 'type', 'label', 'docs', 'reserved', 'basic_type')) # reserved is bool + 'name', 'type', 'label', 'docs', 'reserved', + 'basic_type')) # reserved is bool # synchronous is bool, constant is bool # repponse is a list of method.name Class_ = namedtuple('Class_', ( -'name', 'index', 'docs', 'methods', 'properties')) # label is int + 'name', 'index', 'docs', 'methods', 'properties')) # label is int Domain = namedtuple('Domain', ('name', 'type', 'elementary')) # elementary is bool diff --git a/coolamqp/framing/definitions.py b/coolamqp/framing/definitions.py index e472c3d376f2de66819fb6592677c6cfe8b5dd92..79be651e1d9bdea9225f6933ce8fd3e9d8bf207f 100644 --- a/coolamqp/framing/definitions.py +++ b/coolamqp/framing/definitions.py @@ -1,5 +1,6 @@ # coding=UTF-8 from __future__ import print_function, absolute_import + """ A Python version of the AMQP machine-readable specification. @@ -25,13 +26,17 @@ Only thing that isn't are field names in tables. import struct, collections, logging, six -from coolamqp.framing.base import AMQPClass, AMQPMethodPayload, AMQPContentPropertyList -from coolamqp.framing.field_table import enframe_table, deframe_table, frame_table_size -from coolamqp.framing.compilation.content_property import compile_particular_content_property_list_class +from coolamqp.framing.base import AMQPClass, AMQPMethodPayload, \ + AMQPContentPropertyList +from coolamqp.framing.field_table import enframe_table, deframe_table, \ + frame_table_size +from coolamqp.framing.compilation.content_property import \ + compile_particular_content_property_list_class logger = logging.getLogger(__name__) -Field = collections.namedtuple('Field', ('name', 'type', 'basic_type', 'reserved')) +Field = collections.namedtuple('Field', + ('name', 'type', 'basic_type', 'reserved')) # Core constants FRAME_METHOD = 1 @@ -53,67 +58,69 @@ FRAME_END_BYTE = b'\xce' REPLY_SUCCESS = 200 REPLY_SUCCESS_BYTE = b'\xc8' - # Indicates that the method completed successfully. This reply code is - # reserved for future use - the current protocol design does not use positive - # confirmation and reply codes are sent only in case of an error. +# Indicates that the method completed successfully. This reply code is +# reserved for future use - the current protocol design does not use positive +# confirmation and reply codes are sent only in case of an error. CONTENT_TOO_LARGE = 311 - # The client attempted to transfer content larger than the server could accept - # at the present time. The client may retry at a later time. +# The client attempted to transfer content larger than the server could accept +# at the present time. The client may retry at a later time. NO_CONSUMERS = 313 - # When the exchange cannot deliver to a consumer when the immediate flag is - # set. As a result of pending data on the queue or the absence of any - # consumers of the queue. +# When the exchange cannot deliver to a consumer when the immediate flag is +# set. As a result of pending data on the queue or the absence of any +# consumers of the queue. CONNECTION_FORCED = 320 - # An operator intervened to close the connection for some reason. The client - # may retry at some later date. +# An operator intervened to close the connection for some reason. The client +# may retry at some later date. INVALID_PATH = 402 - # The client tried to work with an unknown virtual host. +# The client tried to work with an unknown virtual host. ACCESS_REFUSED = 403 - # The client attempted to work with a server entity to which it has no - # access due to security settings. +# The client attempted to work with a server entity to which it has no +# access due to security settings. NOT_FOUND = 404 - # The client attempted to work with a server entity that does not exist. +# The client attempted to work with a server entity that does not exist. RESOURCE_LOCKED = 405 - # The client attempted to work with a server entity to which it has no - # access because another client is working with it. +# The client attempted to work with a server entity to which it has no +# access because another client is working with it. PRECONDITION_FAILED = 406 - # The client requested a method that was not allowed because some precondition - # failed. +# The client requested a method that was not allowed because some precondition +# failed. FRAME_ERROR = 501 - # The sender sent a malformed frame that the recipient could not decode. - # This strongly implies a programming error in the sending peer. +# The sender sent a malformed frame that the recipient could not decode. +# This strongly implies a programming error in the sending peer. SYNTAX_ERROR = 502 - # The sender sent a frame that contained illegal values for one or more - # fields. This strongly implies a programming error in the sending peer. +# The sender sent a frame that contained illegal values for one or more +# fields. This strongly implies a programming error in the sending peer. COMMAND_INVALID = 503 - # The client sent an invalid sequence of frames, attempting to perform an - # operation that was considered invalid by the server. This usually implies - # a programming error in the client. +# The client sent an invalid sequence of frames, attempting to perform an +# operation that was considered invalid by the server. This usually implies +# a programming error in the client. CHANNEL_ERROR = 504 - # The client attempted to work with a channel that had not been correctly - # opened. This most likely indicates a fault in the client layer. +# The client attempted to work with a channel that had not been correctly +# opened. This most likely indicates a fault in the client layer. UNEXPECTED_FRAME = 505 - # The peer sent a frame that was not expected, usually in the context of - # a content header and body. This strongly indicates a fault in the peer's - # content processing. +# The peer sent a frame that was not expected, usually in the context of +# a content header and body. This strongly indicates a fault in the peer's +# content processing. RESOURCE_ERROR = 506 - # The server could not complete the method because it lacked sufficient - # resources. This may be due to the client creating too many of some type - # of entity. +# The server could not complete the method because it lacked sufficient +# resources. This may be due to the client creating too many of some type +# of entity. NOT_ALLOWED = 530 - # The client tried to work with some entity in a manner that is prohibited - # by the server, due to security settings or by some other criteria. +# The client tried to work with some entity in a manner that is prohibited +# by the server, due to security settings or by some other criteria. NOT_IMPLEMENTED = 540 - # The client tried to use functionality that is not implemented in the - # server. +# The client tried to use functionality that is not implemented in the +# server. INTERNAL_ERROR = 541 - # The server could not complete the method because of an internal error. - # The server may require intervention by an operator in order to resume - # normal operations. - -HARD_ERRORS = [CONNECTION_FORCED, INVALID_PATH, FRAME_ERROR, SYNTAX_ERROR, COMMAND_INVALID, CHANNEL_ERROR, UNEXPECTED_FRAME, RESOURCE_ERROR, NOT_ALLOWED, NOT_IMPLEMENTED, INTERNAL_ERROR] -SOFT_ERRORS = [CONTENT_TOO_LARGE, NO_CONSUMERS, ACCESS_REFUSED, NOT_FOUND, RESOURCE_LOCKED, PRECONDITION_FAILED] +# The server could not complete the method because of an internal error. +# The server may require intervention by an operator in order to resume +# normal operations. +HARD_ERRORS = [CONNECTION_FORCED, INVALID_PATH, FRAME_ERROR, SYNTAX_ERROR, + COMMAND_INVALID, CHANNEL_ERROR, UNEXPECTED_FRAME, + RESOURCE_ERROR, NOT_ALLOWED, NOT_IMPLEMENTED, INTERNAL_ERROR] +SOFT_ERRORS = [CONTENT_TOO_LARGE, NO_CONSUMERS, ACCESS_REFUSED, NOT_FOUND, + RESOURCE_LOCKED, PRECONDITION_FAILED] DOMAIN_TO_BASIC_TYPE = { u'class-id': u'short', @@ -142,6 +149,7 @@ DOMAIN_TO_BASIC_TYPE = { u'table': None, } + class Connection(AMQPClass): """ The connection class provides methods for a client to establish a network connection to @@ -158,20 +166,20 @@ class ConnectionBlocked(AMQPMethodPayload): and does not accept new publishes. """ - __slots__ = (u'reason', ) + __slots__ = (u'reason',) NAME = u'connection.blocked' - INDEX = (10, 60) # (Class ID, Method ID) - BINARY_HEADER = b'\x00\x0A\x00\x3C' # CLASS ID + METHOD ID + INDEX = (10, 60) # (Class ID, Method ID) + BINARY_HEADER = b'\x00\x0A\x00\x3C' # CLASS ID + METHOD ID SENT_BY_CLIENT, SENT_BY_SERVER = True, True - IS_SIZE_STATIC = False # this means that argument part has always the same length + IS_SIZE_STATIC = False # this means that argument part has always the same length IS_CONTENT_STATIC = False # this means that argument part has always the same content # See constructor pydoc for details - FIELDS = [ + FIELDS = [ Field(u'reason', u'shortstr', u'shortstr', reserved=False), ] @@ -186,7 +194,7 @@ class ConnectionBlocked(AMQPMethodPayload): def write_arguments(self, buf): buf.write(struct.pack('!B', len(self.reason))) buf.write(self.reason) - + def get_size(self): return 1 + len(self.reason) @@ -195,7 +203,7 @@ class ConnectionBlocked(AMQPMethodPayload): offset = start_offset s_len, = struct.unpack_from('!B', buf, offset) offset += 1 - reason = buf[offset:offset+s_len] + reason = buf[offset:offset + s_len] offset += s_len return ConnectionBlocked(reason) @@ -209,20 +217,20 @@ class ConnectionClose(AMQPMethodPayload): a specific method, i.e. an exception. When a close is due to an exception, the sender provides the class and method id of the method which caused the exception. """ - __slots__ = (u'reply_code', u'reply_text', u'class_id', u'method_id', ) + __slots__ = (u'reply_code', u'reply_text', u'class_id', u'method_id',) NAME = u'connection.close' - INDEX = (10, 50) # (Class ID, Method ID) - BINARY_HEADER = b'\x00\x0A\x00\x32' # CLASS ID + METHOD ID + INDEX = (10, 50) # (Class ID, Method ID) + BINARY_HEADER = b'\x00\x0A\x00\x32' # CLASS ID + METHOD ID SENT_BY_CLIENT, SENT_BY_SERVER = True, True - IS_SIZE_STATIC = False # this means that argument part has always the same length + IS_SIZE_STATIC = False # this means that argument part has always the same length IS_CONTENT_STATIC = False # this means that argument part has always the same content # See constructor pydoc for details - FIELDS = [ + FIELDS = [ Field(u'reply-code', u'reply-code', u'short', reserved=False), Field(u'reply-text', u'reply-text', u'shortstr', reserved=False), Field(u'class-id', u'class-id', u'short', reserved=False), @@ -252,7 +260,7 @@ class ConnectionClose(AMQPMethodPayload): buf.write(struct.pack('!HB', self.reply_code, len(self.reply_text))) buf.write(self.reply_text) buf.write(struct.pack('!HH', self.class_id, self.method_id)) - + def get_size(self): return 7 + len(self.reply_text) @@ -261,7 +269,7 @@ class ConnectionClose(AMQPMethodPayload): offset = start_offset reply_code, s_len, = struct.unpack_from('!HB', buf, offset) offset += 3 - reply_text = buf[offset:offset+s_len] + reply_text = buf[offset:offset + s_len] offset += s_len class_id, method_id, = struct.unpack_from('!HH', buf, offset) offset += 4 @@ -279,12 +287,12 @@ class ConnectionCloseOk(AMQPMethodPayload): NAME = u'connection.close-ok' - INDEX = (10, 51) # (Class ID, Method ID) - BINARY_HEADER = b'\x00\x0A\x00\x33' # CLASS ID + METHOD ID + INDEX = (10, 51) # (Class ID, Method ID) + BINARY_HEADER = b'\x00\x0A\x00\x33' # CLASS ID + METHOD ID SENT_BY_CLIENT, SENT_BY_SERVER = True, True - IS_SIZE_STATIC = True # this means that argument part has always the same length + IS_SIZE_STATIC = True # this means that argument part has always the same length IS_CONTENT_STATIC = True # this means that argument part has always the same content STATIC_CONTENT = b'\x00\x00\x00\x04\x00\x0A\x00\x33\xCE' # spans LENGTH, CLASS ID, METHOD ID, ....., FRAME_END @@ -293,7 +301,6 @@ class ConnectionCloseOk(AMQPMethodPayload): Create frame connection.close-ok """ - @staticmethod def from_buffer(buf, start_offset): offset = start_offset @@ -309,20 +316,20 @@ class ConnectionOpen(AMQPMethodPayload): The server may apply arbitrary limits per virtual host, such as the number of each type of entity that may be used, per connection and/or in total. """ - __slots__ = (u'virtual_host', ) + __slots__ = (u'virtual_host',) NAME = u'connection.open' - INDEX = (10, 40) # (Class ID, Method ID) - BINARY_HEADER = b'\x00\x0A\x00\x28' # CLASS ID + METHOD ID + INDEX = (10, 40) # (Class ID, Method ID) + BINARY_HEADER = b'\x00\x0A\x00\x28' # CLASS ID + METHOD ID SENT_BY_CLIENT, SENT_BY_SERVER = True, False - IS_SIZE_STATIC = False # this means that argument part has always the same length + IS_SIZE_STATIC = False # this means that argument part has always the same length IS_CONTENT_STATIC = False # this means that argument part has always the same content # See constructor pydoc for details - FIELDS = [ + FIELDS = [ Field(u'virtual-host', u'path', u'shortstr', reserved=False), Field(u'reserved-1', u'shortstr', u'shortstr', reserved=True), Field(u'reserved-2', u'bit', u'bit', reserved=True), @@ -343,7 +350,7 @@ class ConnectionOpen(AMQPMethodPayload): buf.write(self.virtual_host) buf.write(b'\x00') buf.write(struct.pack('!B', 0)) - + def get_size(self): return 3 + len(self.virtual_host) @@ -352,11 +359,11 @@ class ConnectionOpen(AMQPMethodPayload): offset = start_offset s_len, = struct.unpack_from('!B', buf, offset) offset += 1 - virtual_host = buf[offset:offset+s_len] + virtual_host = buf[offset:offset + s_len] offset += s_len s_len, = struct.unpack_from('!B', buf, offset) offset += 1 - offset += s_len # reserved field! + offset += s_len # reserved field! offset += 1 return ConnectionOpen(virtual_host) @@ -371,17 +378,17 @@ class ConnectionOpenOk(AMQPMethodPayload): NAME = u'connection.open-ok' - INDEX = (10, 41) # (Class ID, Method ID) - BINARY_HEADER = b'\x00\x0A\x00\x29' # CLASS ID + METHOD ID + INDEX = (10, 41) # (Class ID, Method ID) + BINARY_HEADER = b'\x00\x0A\x00\x29' # CLASS ID + METHOD ID SENT_BY_CLIENT, SENT_BY_SERVER = False, True - IS_SIZE_STATIC = False # this means that argument part has always the same length + IS_SIZE_STATIC = False # this means that argument part has always the same length IS_CONTENT_STATIC = True # this means that argument part has always the same content STATIC_CONTENT = b'\x00\x00\x00\x04\x00\x0A\x00\x29\x00\xCE' # spans LENGTH, CLASS ID, METHOD ID, ....., FRAME_END # See constructor pydoc for details - FIELDS = [ + FIELDS = [ Field(u'reserved-1', u'shortstr', u'shortstr', reserved=True), ] @@ -390,13 +397,12 @@ class ConnectionOpenOk(AMQPMethodPayload): Create frame connection.open-ok """ - @staticmethod def from_buffer(buf, start_offset): offset = start_offset s_len, = struct.unpack_from('!B', buf, offset) offset += 1 - offset += s_len # reserved field! + offset += s_len # reserved field! return ConnectionOpenOk() @@ -408,28 +414,32 @@ class ConnectionStart(AMQPMethodPayload): protocol version that the server proposes, along with a list of security mechanisms which the client can use for authentication. """ - __slots__ = (u'version_major', u'version_minor', u'server_properties', u'mechanisms', u'locales', ) + __slots__ = ( + u'version_major', u'version_minor', u'server_properties', u'mechanisms', + u'locales',) NAME = u'connection.start' - INDEX = (10, 10) # (Class ID, Method ID) - BINARY_HEADER = b'\x00\x0A\x00\x0A' # CLASS ID + METHOD ID + INDEX = (10, 10) # (Class ID, Method ID) + BINARY_HEADER = b'\x00\x0A\x00\x0A' # CLASS ID + METHOD ID SENT_BY_CLIENT, SENT_BY_SERVER = False, True - IS_SIZE_STATIC = False # this means that argument part has always the same length + IS_SIZE_STATIC = False # this means that argument part has always the same length IS_CONTENT_STATIC = False # this means that argument part has always the same content # See constructor pydoc for details - FIELDS = [ + FIELDS = [ Field(u'version-major', u'octet', u'octet', reserved=False), Field(u'version-minor', u'octet', u'octet', reserved=False), - Field(u'server-properties', u'peer-properties', u'table', reserved=False), + Field(u'server-properties', u'peer-properties', u'table', + reserved=False), Field(u'mechanisms', u'longstr', u'longstr', reserved=False), Field(u'locales', u'longstr', u'longstr', reserved=False), ] - def __init__(self, version_major, version_minor, server_properties, mechanisms, locales): + def __init__(self, version_major, version_minor, server_properties, + mechanisms, locales): """ Create frame connection.start @@ -469,9 +479,10 @@ class ConnectionStart(AMQPMethodPayload): buf.write(self.mechanisms) buf.write(struct.pack('!I', len(self.locales))) buf.write(self.locales) - + def get_size(self): - return 10 + frame_table_size(self.server_properties) + len(self.mechanisms) + len(self.locales) + return 10 + frame_table_size(self.server_properties) + len( + self.mechanisms) + len(self.locales) @staticmethod def from_buffer(buf, start_offset): @@ -482,13 +493,14 @@ class ConnectionStart(AMQPMethodPayload): offset += delta s_len, = struct.unpack_from('!L', buf, offset) offset += 4 - mechanisms = buf[offset:offset+s_len] + mechanisms = buf[offset:offset + s_len] offset += s_len s_len, = struct.unpack_from('!L', buf, offset) offset += 4 - locales = buf[offset:offset+s_len] + locales = buf[offset:offset + s_len] offset += s_len - return ConnectionStart(version_major, version_minor, server_properties, mechanisms, locales) + return ConnectionStart(version_major, version_minor, server_properties, + mechanisms, locales) class ConnectionSecure(AMQPMethodPayload): @@ -499,20 +511,20 @@ class ConnectionSecure(AMQPMethodPayload): received sufficient information to authenticate each other. This method challenges the client to provide more information. """ - __slots__ = (u'challenge', ) + __slots__ = (u'challenge',) NAME = u'connection.secure' - INDEX = (10, 20) # (Class ID, Method ID) - BINARY_HEADER = b'\x00\x0A\x00\x14' # CLASS ID + METHOD ID + INDEX = (10, 20) # (Class ID, Method ID) + BINARY_HEADER = b'\x00\x0A\x00\x14' # CLASS ID + METHOD ID SENT_BY_CLIENT, SENT_BY_SERVER = False, True - IS_SIZE_STATIC = False # this means that argument part has always the same length + IS_SIZE_STATIC = False # this means that argument part has always the same length IS_CONTENT_STATIC = False # this means that argument part has always the same content # See constructor pydoc for details - FIELDS = [ + FIELDS = [ Field(u'challenge', u'longstr', u'longstr', reserved=False), ] @@ -530,7 +542,7 @@ class ConnectionSecure(AMQPMethodPayload): def write_arguments(self, buf): buf.write(struct.pack('!I', len(self.challenge))) buf.write(self.challenge) - + def get_size(self): return 4 + len(self.challenge) @@ -539,7 +551,7 @@ class ConnectionSecure(AMQPMethodPayload): offset = start_offset s_len, = struct.unpack_from('!L', buf, offset) offset += 4 - challenge = buf[offset:offset+s_len] + challenge = buf[offset:offset + s_len] offset += s_len return ConnectionSecure(challenge) @@ -550,21 +562,22 @@ class ConnectionStartOk(AMQPMethodPayload): This method selects a SASL security mechanism. """ - __slots__ = (u'client_properties', u'mechanism', u'response', u'locale', ) + __slots__ = (u'client_properties', u'mechanism', u'response', u'locale',) NAME = u'connection.start-ok' - INDEX = (10, 11) # (Class ID, Method ID) - BINARY_HEADER = b'\x00\x0A\x00\x0B' # CLASS ID + METHOD ID + INDEX = (10, 11) # (Class ID, Method ID) + BINARY_HEADER = b'\x00\x0A\x00\x0B' # CLASS ID + METHOD ID SENT_BY_CLIENT, SENT_BY_SERVER = True, False - IS_SIZE_STATIC = False # this means that argument part has always the same length + IS_SIZE_STATIC = False # this means that argument part has always the same length IS_CONTENT_STATIC = False # this means that argument part has always the same content # See constructor pydoc for details - FIELDS = [ - Field(u'client-properties', u'peer-properties', u'table', reserved=False), + FIELDS = [ + Field(u'client-properties', u'peer-properties', u'table', + reserved=False), Field(u'mechanism', u'shortstr', u'shortstr', reserved=False), Field(u'response', u'longstr', u'longstr', reserved=False), Field(u'locale', u'shortstr', u'shortstr', reserved=False), @@ -606,9 +619,10 @@ class ConnectionStartOk(AMQPMethodPayload): buf.write(self.response) buf.write(struct.pack('!B', len(self.locale))) buf.write(self.locale) - + def get_size(self): - return 6 + frame_table_size(self.client_properties) + len(self.mechanism) + len(self.response) + len(self.locale) + return 6 + frame_table_size(self.client_properties) + len( + self.mechanism) + len(self.response) + len(self.locale) @staticmethod def from_buffer(buf, start_offset): @@ -617,17 +631,18 @@ class ConnectionStartOk(AMQPMethodPayload): offset += delta s_len, = struct.unpack_from('!B', buf, offset) offset += 1 - mechanism = buf[offset:offset+s_len] + mechanism = buf[offset:offset + s_len] offset += s_len s_len, = struct.unpack_from('!L', buf, offset) offset += 4 - response = buf[offset:offset+s_len] + response = buf[offset:offset + s_len] offset += s_len s_len, = struct.unpack_from('!B', buf, offset) offset += 1 - locale = buf[offset:offset+s_len] + locale = buf[offset:offset + s_len] offset += s_len - return ConnectionStartOk(client_properties, mechanism, response, locale) + return ConnectionStartOk(client_properties, mechanism, response, + locale) class ConnectionSecureOk(AMQPMethodPayload): @@ -637,20 +652,20 @@ class ConnectionSecureOk(AMQPMethodPayload): This method attempts to authenticate, passing a block of SASL data for the security mechanism at the server side. """ - __slots__ = (u'response', ) + __slots__ = (u'response',) NAME = u'connection.secure-ok' - INDEX = (10, 21) # (Class ID, Method ID) - BINARY_HEADER = b'\x00\x0A\x00\x15' # CLASS ID + METHOD ID + INDEX = (10, 21) # (Class ID, Method ID) + BINARY_HEADER = b'\x00\x0A\x00\x15' # CLASS ID + METHOD ID SENT_BY_CLIENT, SENT_BY_SERVER = True, False - IS_SIZE_STATIC = False # this means that argument part has always the same length + IS_SIZE_STATIC = False # this means that argument part has always the same length IS_CONTENT_STATIC = False # this means that argument part has always the same content # See constructor pydoc for details - FIELDS = [ + FIELDS = [ Field(u'response', u'longstr', u'longstr', reserved=False), ] @@ -668,7 +683,7 @@ class ConnectionSecureOk(AMQPMethodPayload): def write_arguments(self, buf): buf.write(struct.pack('!I', len(self.response))) buf.write(self.response) - + def get_size(self): return 4 + len(self.response) @@ -677,7 +692,7 @@ class ConnectionSecureOk(AMQPMethodPayload): offset = start_offset s_len, = struct.unpack_from('!L', buf, offset) offset += 4 - response = buf[offset:offset+s_len] + response = buf[offset:offset + s_len] offset += s_len return ConnectionSecureOk(response) @@ -689,20 +704,20 @@ class ConnectionTune(AMQPMethodPayload): This method proposes a set of connection configuration values to the client. The client can accept and/or adjust these. """ - __slots__ = (u'channel_max', u'frame_max', u'heartbeat', ) + __slots__ = (u'channel_max', u'frame_max', u'heartbeat',) NAME = u'connection.tune' - INDEX = (10, 30) # (Class ID, Method ID) - BINARY_HEADER = b'\x00\x0A\x00\x1E' # CLASS ID + METHOD ID + INDEX = (10, 30) # (Class ID, Method ID) + BINARY_HEADER = b'\x00\x0A\x00\x1E' # CLASS ID + METHOD ID SENT_BY_CLIENT, SENT_BY_SERVER = False, True - IS_SIZE_STATIC = True # this means that argument part has always the same length + IS_SIZE_STATIC = True # this means that argument part has always the same length IS_CONTENT_STATIC = False # this means that argument part has always the same content # See constructor pydoc for details - FIELDS = [ + FIELDS = [ Field(u'channel-max', u'short', u'short', reserved=False), Field(u'frame-max', u'long', u'long', reserved=False), Field(u'heartbeat', u'short', u'short', reserved=False), @@ -732,15 +747,17 @@ class ConnectionTune(AMQPMethodPayload): self.heartbeat = heartbeat def write_arguments(self, buf): - buf.write(struct.pack('!HIH', self.channel_max, self.frame_max, self.heartbeat)) - + buf.write(struct.pack('!HIH', self.channel_max, self.frame_max, + self.heartbeat)) + def get_size(self): return 8 @staticmethod def from_buffer(buf, start_offset): offset = start_offset - channel_max, frame_max, heartbeat, = struct.unpack_from('!HIH', buf, offset) + channel_max, frame_max, heartbeat, = struct.unpack_from('!HIH', buf, + offset) offset += 8 return ConnectionTune(channel_max, frame_max, heartbeat) @@ -752,20 +769,20 @@ class ConnectionTuneOk(AMQPMethodPayload): This method sends the client's connection tuning parameters to the server. Certain fields are negotiated, others provide capability information. """ - __slots__ = (u'channel_max', u'frame_max', u'heartbeat', ) + __slots__ = (u'channel_max', u'frame_max', u'heartbeat',) NAME = u'connection.tune-ok' - INDEX = (10, 31) # (Class ID, Method ID) - BINARY_HEADER = b'\x00\x0A\x00\x1F' # CLASS ID + METHOD ID + INDEX = (10, 31) # (Class ID, Method ID) + BINARY_HEADER = b'\x00\x0A\x00\x1F' # CLASS ID + METHOD ID SENT_BY_CLIENT, SENT_BY_SERVER = True, False - IS_SIZE_STATIC = True # this means that argument part has always the same length + IS_SIZE_STATIC = True # this means that argument part has always the same length IS_CONTENT_STATIC = False # this means that argument part has always the same content # See constructor pydoc for details - FIELDS = [ + FIELDS = [ Field(u'channel-max', u'short', u'short', reserved=False), Field(u'frame-max', u'long', u'long', reserved=False), Field(u'heartbeat', u'short', u'short', reserved=False), @@ -795,15 +812,17 @@ class ConnectionTuneOk(AMQPMethodPayload): self.heartbeat = heartbeat def write_arguments(self, buf): - buf.write(struct.pack('!HIH', self.channel_max, self.frame_max, self.heartbeat)) - + buf.write(struct.pack('!HIH', self.channel_max, self.frame_max, + self.heartbeat)) + def get_size(self): return 8 @staticmethod def from_buffer(buf, start_offset): offset = start_offset - channel_max, frame_max, heartbeat, = struct.unpack_from('!HIH', buf, offset) + channel_max, frame_max, heartbeat, = struct.unpack_from('!HIH', buf, + offset) offset += 8 return ConnectionTuneOk(channel_max, frame_max, heartbeat) @@ -818,12 +837,12 @@ class ConnectionUnblocked(AMQPMethodPayload): NAME = u'connection.unblocked' - INDEX = (10, 61) # (Class ID, Method ID) - BINARY_HEADER = b'\x00\x0A\x00\x3D' # CLASS ID + METHOD ID + INDEX = (10, 61) # (Class ID, Method ID) + BINARY_HEADER = b'\x00\x0A\x00\x3D' # CLASS ID + METHOD ID SENT_BY_CLIENT, SENT_BY_SERVER = True, True - IS_SIZE_STATIC = True # this means that argument part has always the same length + IS_SIZE_STATIC = True # this means that argument part has always the same length IS_CONTENT_STATIC = True # this means that argument part has always the same content STATIC_CONTENT = b'\x00\x00\x00\x04\x00\x0A\x00\x3D\xCE' # spans LENGTH, CLASS ID, METHOD ID, ....., FRAME_END @@ -832,7 +851,6 @@ class ConnectionUnblocked(AMQPMethodPayload): Create frame connection.unblocked """ - @staticmethod def from_buffer(buf, start_offset): offset = start_offset @@ -858,20 +876,20 @@ class ChannelClose(AMQPMethodPayload): method, i.e. an exception. When a close is due to an exception, the sender provides the class and method id of the method which caused the exception. """ - __slots__ = (u'reply_code', u'reply_text', u'class_id', u'method_id', ) + __slots__ = (u'reply_code', u'reply_text', u'class_id', u'method_id',) NAME = u'channel.close' - INDEX = (20, 40) # (Class ID, Method ID) - BINARY_HEADER = b'\x00\x14\x00\x28' # CLASS ID + METHOD ID + INDEX = (20, 40) # (Class ID, Method ID) + BINARY_HEADER = b'\x00\x14\x00\x28' # CLASS ID + METHOD ID SENT_BY_CLIENT, SENT_BY_SERVER = True, True - IS_SIZE_STATIC = False # this means that argument part has always the same length + IS_SIZE_STATIC = False # this means that argument part has always the same length IS_CONTENT_STATIC = False # this means that argument part has always the same content # See constructor pydoc for details - FIELDS = [ + FIELDS = [ Field(u'reply-code', u'reply-code', u'short', reserved=False), Field(u'reply-text', u'reply-text', u'shortstr', reserved=False), Field(u'class-id', u'class-id', u'short', reserved=False), @@ -901,7 +919,7 @@ class ChannelClose(AMQPMethodPayload): buf.write(struct.pack('!HB', self.reply_code, len(self.reply_text))) buf.write(self.reply_text) buf.write(struct.pack('!HH', self.class_id, self.method_id)) - + def get_size(self): return 7 + len(self.reply_text) @@ -910,7 +928,7 @@ class ChannelClose(AMQPMethodPayload): offset = start_offset reply_code, s_len, = struct.unpack_from('!HB', buf, offset) offset += 3 - reply_text = buf[offset:offset+s_len] + reply_text = buf[offset:offset + s_len] offset += s_len class_id, method_id, = struct.unpack_from('!HH', buf, offset) offset += 4 @@ -928,12 +946,12 @@ class ChannelCloseOk(AMQPMethodPayload): NAME = u'channel.close-ok' - INDEX = (20, 41) # (Class ID, Method ID) - BINARY_HEADER = b'\x00\x14\x00\x29' # CLASS ID + METHOD ID + INDEX = (20, 41) # (Class ID, Method ID) + BINARY_HEADER = b'\x00\x14\x00\x29' # CLASS ID + METHOD ID SENT_BY_CLIENT, SENT_BY_SERVER = True, True - IS_SIZE_STATIC = True # this means that argument part has always the same length + IS_SIZE_STATIC = True # this means that argument part has always the same length IS_CONTENT_STATIC = True # this means that argument part has always the same content STATIC_CONTENT = b'\x00\x00\x00\x04\x00\x14\x00\x29\xCE' # spans LENGTH, CLASS ID, METHOD ID, ....., FRAME_END @@ -942,7 +960,6 @@ class ChannelCloseOk(AMQPMethodPayload): Create frame channel.close-ok """ - @staticmethod def from_buffer(buf, start_offset): offset = start_offset @@ -959,20 +976,20 @@ class ChannelFlow(AMQPMethodPayload): it can process. Note that this method is not intended for window control. It does not affect contents returned by Basic.Get-Ok methods. """ - __slots__ = (u'active', ) + __slots__ = (u'active',) NAME = u'channel.flow' - INDEX = (20, 20) # (Class ID, Method ID) - BINARY_HEADER = b'\x00\x14\x00\x14' # CLASS ID + METHOD ID + INDEX = (20, 20) # (Class ID, Method ID) + BINARY_HEADER = b'\x00\x14\x00\x14' # CLASS ID + METHOD ID SENT_BY_CLIENT, SENT_BY_SERVER = True, True - IS_SIZE_STATIC = True # this means that argument part has always the same length + IS_SIZE_STATIC = True # this means that argument part has always the same length IS_CONTENT_STATIC = False # this means that argument part has always the same content # See constructor pydoc for details - FIELDS = [ + FIELDS = [ Field(u'active', u'bit', u'bit', reserved=False), ] @@ -989,7 +1006,7 @@ class ChannelFlow(AMQPMethodPayload): def write_arguments(self, buf): buf.write(struct.pack('!B', (self.active << 0))) - + def get_size(self): return 1 @@ -1009,20 +1026,20 @@ class ChannelFlowOk(AMQPMethodPayload): Confirms to the peer that a flow command was received and processed. """ - __slots__ = (u'active', ) + __slots__ = (u'active',) NAME = u'channel.flow-ok' - INDEX = (20, 21) # (Class ID, Method ID) - BINARY_HEADER = b'\x00\x14\x00\x15' # CLASS ID + METHOD ID + INDEX = (20, 21) # (Class ID, Method ID) + BINARY_HEADER = b'\x00\x14\x00\x15' # CLASS ID + METHOD ID SENT_BY_CLIENT, SENT_BY_SERVER = True, True - IS_SIZE_STATIC = True # this means that argument part has always the same length + IS_SIZE_STATIC = True # this means that argument part has always the same length IS_CONTENT_STATIC = False # this means that argument part has always the same content # See constructor pydoc for details - FIELDS = [ + FIELDS = [ Field(u'active', u'bit', u'bit', reserved=False), ] @@ -1039,7 +1056,7 @@ class ChannelFlowOk(AMQPMethodPayload): def write_arguments(self, buf): buf.write(struct.pack('!B', (self.active << 0))) - + def get_size(self): return 1 @@ -1063,17 +1080,17 @@ class ChannelOpen(AMQPMethodPayload): NAME = u'channel.open' - INDEX = (20, 10) # (Class ID, Method ID) - BINARY_HEADER = b'\x00\x14\x00\x0A' # CLASS ID + METHOD ID + INDEX = (20, 10) # (Class ID, Method ID) + BINARY_HEADER = b'\x00\x14\x00\x0A' # CLASS ID + METHOD ID SENT_BY_CLIENT, SENT_BY_SERVER = True, False - IS_SIZE_STATIC = False # this means that argument part has always the same length + IS_SIZE_STATIC = False # this means that argument part has always the same length IS_CONTENT_STATIC = True # this means that argument part has always the same content STATIC_CONTENT = b'\x00\x00\x00\x05\x00\x14\x00\x0A\x00\xCE' # spans LENGTH, CLASS ID, METHOD ID, ....., FRAME_END # See constructor pydoc for details - FIELDS = [ + FIELDS = [ Field(u'reserved-1', u'shortstr', u'shortstr', reserved=True), ] @@ -1082,13 +1099,12 @@ class ChannelOpen(AMQPMethodPayload): Create frame channel.open """ - @staticmethod def from_buffer(buf, start_offset): offset = start_offset s_len, = struct.unpack_from('!B', buf, offset) offset += 1 - offset += s_len # reserved field! + offset += s_len # reserved field! return ChannelOpen() @@ -1102,17 +1118,17 @@ class ChannelOpenOk(AMQPMethodPayload): NAME = u'channel.open-ok' - INDEX = (20, 11) # (Class ID, Method ID) - BINARY_HEADER = b'\x00\x14\x00\x0B' # CLASS ID + METHOD ID + INDEX = (20, 11) # (Class ID, Method ID) + BINARY_HEADER = b'\x00\x14\x00\x0B' # CLASS ID + METHOD ID SENT_BY_CLIENT, SENT_BY_SERVER = False, True - IS_SIZE_STATIC = False # this means that argument part has always the same length + IS_SIZE_STATIC = False # this means that argument part has always the same length IS_CONTENT_STATIC = True # this means that argument part has always the same content STATIC_CONTENT = b'\x00\x00\x00\x05\x00\x14\x00\x0B\x00\x00\x00\x00\xCE' # spans LENGTH, CLASS ID, METHOD ID, ....., FRAME_END # See constructor pydoc for details - FIELDS = [ + FIELDS = [ Field(u'reserved-1', u'longstr', u'longstr', reserved=True), ] @@ -1121,13 +1137,12 @@ class ChannelOpenOk(AMQPMethodPayload): Create frame channel.open-ok """ - @staticmethod def from_buffer(buf, start_offset): offset = start_offset s_len, = struct.unpack_from('!L', buf, offset) offset += 4 - offset += s_len # reserved field! + offset += s_len # reserved field! return ChannelOpenOk() @@ -1147,20 +1162,21 @@ class ExchangeBind(AMQPMethodPayload): This method binds an exchange to an exchange. """ - __slots__ = (u'destination', u'source', u'routing_key', u'no_wait', u'arguments', ) + __slots__ = ( + u'destination', u'source', u'routing_key', u'no_wait', u'arguments',) NAME = u'exchange.bind' - INDEX = (40, 30) # (Class ID, Method ID) - BINARY_HEADER = b'\x00\x28\x00\x1E' # CLASS ID + METHOD ID + INDEX = (40, 30) # (Class ID, Method ID) + BINARY_HEADER = b'\x00\x28\x00\x1E' # CLASS ID + METHOD ID SENT_BY_CLIENT, SENT_BY_SERVER = True, False - IS_SIZE_STATIC = False # this means that argument part has always the same length + IS_SIZE_STATIC = False # this means that argument part has always the same length IS_CONTENT_STATIC = False # this means that argument part has always the same content # See constructor pydoc for details - FIELDS = [ + FIELDS = [ Field(u'reserved-1', u'short', u'short', reserved=True), Field(u'destination', u'exchange-name', u'shortstr', reserved=False), Field(u'source', u'exchange-name', u'shortstr', reserved=False), @@ -1207,24 +1223,25 @@ class ExchangeBind(AMQPMethodPayload): buf.write(self.routing_key) buf.write(struct.pack('!B', (self.no_wait << 0))) enframe_table(buf, self.arguments) - + def get_size(self): - return 6 + len(self.destination) + len(self.source) + len(self.routing_key) + frame_table_size(self.arguments) + return 6 + len(self.destination) + len(self.source) + len( + self.routing_key) + frame_table_size(self.arguments) @staticmethod def from_buffer(buf, start_offset): offset = start_offset s_len, = struct.unpack_from('!2xB', buf, offset) offset += 3 - destination = buf[offset:offset+s_len] + destination = buf[offset:offset + s_len] offset += s_len s_len, = struct.unpack_from('!B', buf, offset) offset += 1 - source = buf[offset:offset+s_len] + source = buf[offset:offset + s_len] offset += s_len s_len, = struct.unpack_from('!B', buf, offset) offset += 1 - routing_key = buf[offset:offset+s_len] + routing_key = buf[offset:offset + s_len] offset += s_len _bit, = struct.unpack_from('!B', buf, offset) offset += 0 @@ -1232,7 +1249,8 @@ class ExchangeBind(AMQPMethodPayload): offset += 1 arguments, delta = deframe_table(buf, offset) offset += delta - return ExchangeBind(destination, source, routing_key, no_wait, arguments) + return ExchangeBind(destination, source, routing_key, no_wait, + arguments) class ExchangeBindOk(AMQPMethodPayload): @@ -1245,12 +1263,12 @@ class ExchangeBindOk(AMQPMethodPayload): NAME = u'exchange.bind-ok' - INDEX = (40, 31) # (Class ID, Method ID) - BINARY_HEADER = b'\x00\x28\x00\x1F' # CLASS ID + METHOD ID + INDEX = (40, 31) # (Class ID, Method ID) + BINARY_HEADER = b'\x00\x28\x00\x1F' # CLASS ID + METHOD ID SENT_BY_CLIENT, SENT_BY_SERVER = False, True - IS_SIZE_STATIC = True # this means that argument part has always the same length + IS_SIZE_STATIC = True # this means that argument part has always the same length IS_CONTENT_STATIC = True # this means that argument part has always the same content STATIC_CONTENT = b'\x00\x00\x00\x04\x00\x28\x00\x1F\xCE' # spans LENGTH, CLASS ID, METHOD ID, ....., FRAME_END @@ -1259,7 +1277,6 @@ class ExchangeBindOk(AMQPMethodPayload): Create frame exchange.bind-ok """ - @staticmethod def from_buffer(buf, start_offset): offset = start_offset @@ -1273,20 +1290,22 @@ class ExchangeDeclare(AMQPMethodPayload): This method creates an exchange if it does not already exist, and if the exchange exists, verifies that it is of the correct and expected class. """ - __slots__ = (u'exchange', u'type_', u'passive', u'durable', u'auto_delete', u'internal', u'no_wait', u'arguments', ) + __slots__ = ( + u'exchange', u'type_', u'passive', u'durable', u'auto_delete', u'internal', + u'no_wait', u'arguments',) NAME = u'exchange.declare' - INDEX = (40, 10) # (Class ID, Method ID) - BINARY_HEADER = b'\x00\x28\x00\x0A' # CLASS ID + METHOD ID + INDEX = (40, 10) # (Class ID, Method ID) + BINARY_HEADER = b'\x00\x28\x00\x0A' # CLASS ID + METHOD ID SENT_BY_CLIENT, SENT_BY_SERVER = True, False - IS_SIZE_STATIC = False # this means that argument part has always the same length + IS_SIZE_STATIC = False # this means that argument part has always the same length IS_CONTENT_STATIC = False # this means that argument part has always the same content # See constructor pydoc for details - FIELDS = [ + FIELDS = [ Field(u'reserved-1', u'short', u'short', reserved=True), Field(u'exchange', u'exchange-name', u'shortstr', reserved=False), Field(u'type', u'shortstr', u'shortstr', reserved=False), @@ -1298,7 +1317,8 @@ class ExchangeDeclare(AMQPMethodPayload): Field(u'arguments', u'table', u'table', reserved=False), ] - def __init__(self, exchange, type_, passive, durable, auto_delete, internal, no_wait, arguments): + def __init__(self, exchange, type_, passive, durable, auto_delete, + internal, no_wait, arguments): """ Create frame exchange.declare @@ -1356,22 +1376,26 @@ class ExchangeDeclare(AMQPMethodPayload): buf.write(self.exchange) buf.write(struct.pack('!B', len(self.type_))) buf.write(self.type_) - buf.write(struct.pack('!B', (self.passive << 0) | (self.durable << 1) | (self.auto_delete << 2) | (self.internal << 3) | (self.no_wait << 4))) + buf.write(struct.pack('!B', + (self.passive << 0) | (self.durable << 1) | ( + self.auto_delete << 2) | (self.internal << 3) | ( + self.no_wait << 4))) enframe_table(buf, self.arguments) - + def get_size(self): - return 5 + len(self.exchange) + len(self.type_) + frame_table_size(self.arguments) + return 5 + len(self.exchange) + len(self.type_) + frame_table_size( + self.arguments) @staticmethod def from_buffer(buf, start_offset): offset = start_offset s_len, = struct.unpack_from('!2xB', buf, offset) offset += 3 - exchange = buf[offset:offset+s_len] + exchange = buf[offset:offset + s_len] offset += s_len s_len, = struct.unpack_from('!B', buf, offset) offset += 1 - type_ = buf[offset:offset+s_len] + type_ = buf[offset:offset + s_len] offset += s_len _bit, = struct.unpack_from('!B', buf, offset) offset += 0 @@ -1383,7 +1407,8 @@ class ExchangeDeclare(AMQPMethodPayload): offset += 1 arguments, delta = deframe_table(buf, offset) offset += delta - return ExchangeDeclare(exchange, type_, passive, durable, auto_delete, internal, no_wait, arguments) + return ExchangeDeclare(exchange, type_, passive, durable, auto_delete, + internal, no_wait, arguments) class ExchangeDelete(AMQPMethodPayload): @@ -1393,20 +1418,20 @@ class ExchangeDelete(AMQPMethodPayload): This method deletes an exchange. When an exchange is deleted all queue bindings on the exchange are cancelled. """ - __slots__ = (u'exchange', u'if_unused', u'no_wait', ) + __slots__ = (u'exchange', u'if_unused', u'no_wait',) NAME = u'exchange.delete' - INDEX = (40, 20) # (Class ID, Method ID) - BINARY_HEADER = b'\x00\x28\x00\x14' # CLASS ID + METHOD ID + INDEX = (40, 20) # (Class ID, Method ID) + BINARY_HEADER = b'\x00\x28\x00\x14' # CLASS ID + METHOD ID SENT_BY_CLIENT, SENT_BY_SERVER = True, False - IS_SIZE_STATIC = False # this means that argument part has always the same length + IS_SIZE_STATIC = False # this means that argument part has always the same length IS_CONTENT_STATIC = False # this means that argument part has always the same content # See constructor pydoc for details - FIELDS = [ + FIELDS = [ Field(u'reserved-1', u'short', u'short', reserved=True), Field(u'exchange', u'exchange-name', u'shortstr', reserved=False), Field(u'if-unused', u'bit', u'bit', reserved=False), @@ -1434,8 +1459,9 @@ class ExchangeDelete(AMQPMethodPayload): buf.write(b'\x00\x00') buf.write(struct.pack('!B', len(self.exchange))) buf.write(self.exchange) - buf.write(struct.pack('!B', (self.if_unused << 0) | (self.no_wait << 1))) - + buf.write( + struct.pack('!B', (self.if_unused << 0) | (self.no_wait << 1))) + def get_size(self): return 4 + len(self.exchange) @@ -1444,7 +1470,7 @@ class ExchangeDelete(AMQPMethodPayload): offset = start_offset s_len, = struct.unpack_from('!2xB', buf, offset) offset += 3 - exchange = buf[offset:offset+s_len] + exchange = buf[offset:offset + s_len] offset += s_len _bit, = struct.unpack_from('!B', buf, offset) offset += 0 @@ -1465,12 +1491,12 @@ class ExchangeDeclareOk(AMQPMethodPayload): NAME = u'exchange.declare-ok' - INDEX = (40, 11) # (Class ID, Method ID) - BINARY_HEADER = b'\x00\x28\x00\x0B' # CLASS ID + METHOD ID + INDEX = (40, 11) # (Class ID, Method ID) + BINARY_HEADER = b'\x00\x28\x00\x0B' # CLASS ID + METHOD ID SENT_BY_CLIENT, SENT_BY_SERVER = False, True - IS_SIZE_STATIC = True # this means that argument part has always the same length + IS_SIZE_STATIC = True # this means that argument part has always the same length IS_CONTENT_STATIC = True # this means that argument part has always the same content STATIC_CONTENT = b'\x00\x00\x00\x04\x00\x28\x00\x0B\xCE' # spans LENGTH, CLASS ID, METHOD ID, ....., FRAME_END @@ -1479,7 +1505,6 @@ class ExchangeDeclareOk(AMQPMethodPayload): Create frame exchange.declare-ok """ - @staticmethod def from_buffer(buf, start_offset): offset = start_offset @@ -1496,12 +1521,12 @@ class ExchangeDeleteOk(AMQPMethodPayload): NAME = u'exchange.delete-ok' - INDEX = (40, 21) # (Class ID, Method ID) - BINARY_HEADER = b'\x00\x28\x00\x15' # CLASS ID + METHOD ID + INDEX = (40, 21) # (Class ID, Method ID) + BINARY_HEADER = b'\x00\x28\x00\x15' # CLASS ID + METHOD ID SENT_BY_CLIENT, SENT_BY_SERVER = False, True - IS_SIZE_STATIC = True # this means that argument part has always the same length + IS_SIZE_STATIC = True # this means that argument part has always the same length IS_CONTENT_STATIC = True # this means that argument part has always the same content STATIC_CONTENT = b'\x00\x00\x00\x04\x00\x28\x00\x15\xCE' # spans LENGTH, CLASS ID, METHOD ID, ....., FRAME_END @@ -1510,7 +1535,6 @@ class ExchangeDeleteOk(AMQPMethodPayload): Create frame exchange.delete-ok """ - @staticmethod def from_buffer(buf, start_offset): offset = start_offset @@ -1523,20 +1547,21 @@ class ExchangeUnbind(AMQPMethodPayload): This method unbinds an exchange from an exchange. """ - __slots__ = (u'destination', u'source', u'routing_key', u'no_wait', u'arguments', ) + __slots__ = ( + u'destination', u'source', u'routing_key', u'no_wait', u'arguments',) NAME = u'exchange.unbind' - INDEX = (40, 40) # (Class ID, Method ID) - BINARY_HEADER = b'\x00\x28\x00\x28' # CLASS ID + METHOD ID + INDEX = (40, 40) # (Class ID, Method ID) + BINARY_HEADER = b'\x00\x28\x00\x28' # CLASS ID + METHOD ID SENT_BY_CLIENT, SENT_BY_SERVER = True, False - IS_SIZE_STATIC = False # this means that argument part has always the same length + IS_SIZE_STATIC = False # this means that argument part has always the same length IS_CONTENT_STATIC = False # this means that argument part has always the same content # See constructor pydoc for details - FIELDS = [ + FIELDS = [ Field(u'reserved-1', u'short', u'short', reserved=True), Field(u'destination', u'exchange-name', u'shortstr', reserved=False), Field(u'source', u'exchange-name', u'shortstr', reserved=False), @@ -1577,24 +1602,25 @@ class ExchangeUnbind(AMQPMethodPayload): buf.write(self.routing_key) buf.write(struct.pack('!B', (self.no_wait << 0))) enframe_table(buf, self.arguments) - + def get_size(self): - return 6 + len(self.destination) + len(self.source) + len(self.routing_key) + frame_table_size(self.arguments) + return 6 + len(self.destination) + len(self.source) + len( + self.routing_key) + frame_table_size(self.arguments) @staticmethod def from_buffer(buf, start_offset): offset = start_offset s_len, = struct.unpack_from('!2xB', buf, offset) offset += 3 - destination = buf[offset:offset+s_len] + destination = buf[offset:offset + s_len] offset += s_len s_len, = struct.unpack_from('!B', buf, offset) offset += 1 - source = buf[offset:offset+s_len] + source = buf[offset:offset + s_len] offset += s_len s_len, = struct.unpack_from('!B', buf, offset) offset += 1 - routing_key = buf[offset:offset+s_len] + routing_key = buf[offset:offset + s_len] offset += s_len _bit, = struct.unpack_from('!B', buf, offset) offset += 0 @@ -1602,7 +1628,8 @@ class ExchangeUnbind(AMQPMethodPayload): offset += 1 arguments, delta = deframe_table(buf, offset) offset += delta - return ExchangeUnbind(destination, source, routing_key, no_wait, arguments) + return ExchangeUnbind(destination, source, routing_key, no_wait, + arguments) class ExchangeUnbindOk(AMQPMethodPayload): @@ -1615,12 +1642,12 @@ class ExchangeUnbindOk(AMQPMethodPayload): NAME = u'exchange.unbind-ok' - INDEX = (40, 51) # (Class ID, Method ID) - BINARY_HEADER = b'\x00\x28\x00\x33' # CLASS ID + METHOD ID + INDEX = (40, 51) # (Class ID, Method ID) + BINARY_HEADER = b'\x00\x28\x00\x33' # CLASS ID + METHOD ID SENT_BY_CLIENT, SENT_BY_SERVER = False, True - IS_SIZE_STATIC = True # this means that argument part has always the same length + IS_SIZE_STATIC = True # this means that argument part has always the same length IS_CONTENT_STATIC = True # this means that argument part has always the same content STATIC_CONTENT = b'\x00\x00\x00\x04\x00\x28\x00\x33\xCE' # spans LENGTH, CLASS ID, METHOD ID, ....., FRAME_END @@ -1629,7 +1656,6 @@ class ExchangeUnbindOk(AMQPMethodPayload): Create frame exchange.unbind-ok """ - @staticmethod def from_buffer(buf, start_offset): offset = start_offset @@ -1656,20 +1682,21 @@ class QueueBind(AMQPMethodPayload): are bound to a direct exchange and subscription queues are bound to a topic exchange. """ - __slots__ = (u'queue', u'exchange', u'routing_key', u'no_wait', u'arguments', ) + __slots__ = ( + u'queue', u'exchange', u'routing_key', u'no_wait', u'arguments',) NAME = u'queue.bind' - INDEX = (50, 20) # (Class ID, Method ID) - BINARY_HEADER = b'\x00\x32\x00\x14' # CLASS ID + METHOD ID + INDEX = (50, 20) # (Class ID, Method ID) + BINARY_HEADER = b'\x00\x32\x00\x14' # CLASS ID + METHOD ID SENT_BY_CLIENT, SENT_BY_SERVER = True, False - IS_SIZE_STATIC = False # this means that argument part has always the same length + IS_SIZE_STATIC = False # this means that argument part has always the same length IS_CONTENT_STATIC = False # this means that argument part has always the same content # See constructor pydoc for details - FIELDS = [ + FIELDS = [ Field(u'reserved-1', u'short', u'short', reserved=True), Field(u'queue', u'queue-name', u'shortstr', reserved=False), Field(u'exchange', u'exchange-name', u'shortstr', reserved=False), @@ -1719,24 +1746,25 @@ class QueueBind(AMQPMethodPayload): buf.write(self.routing_key) buf.write(struct.pack('!B', (self.no_wait << 0))) enframe_table(buf, self.arguments) - + def get_size(self): - return 6 + len(self.queue) + len(self.exchange) + len(self.routing_key) + frame_table_size(self.arguments) + return 6 + len(self.queue) + len(self.exchange) + len( + self.routing_key) + frame_table_size(self.arguments) @staticmethod def from_buffer(buf, start_offset): offset = start_offset s_len, = struct.unpack_from('!2xB', buf, offset) offset += 3 - queue = buf[offset:offset+s_len] + queue = buf[offset:offset + s_len] offset += s_len s_len, = struct.unpack_from('!B', buf, offset) offset += 1 - exchange = buf[offset:offset+s_len] + exchange = buf[offset:offset + s_len] offset += s_len s_len, = struct.unpack_from('!B', buf, offset) offset += 1 - routing_key = buf[offset:offset+s_len] + routing_key = buf[offset:offset + s_len] offset += s_len _bit, = struct.unpack_from('!B', buf, offset) offset += 0 @@ -1757,12 +1785,12 @@ class QueueBindOk(AMQPMethodPayload): NAME = u'queue.bind-ok' - INDEX = (50, 21) # (Class ID, Method ID) - BINARY_HEADER = b'\x00\x32\x00\x15' # CLASS ID + METHOD ID + INDEX = (50, 21) # (Class ID, Method ID) + BINARY_HEADER = b'\x00\x32\x00\x15' # CLASS ID + METHOD ID SENT_BY_CLIENT, SENT_BY_SERVER = False, True - IS_SIZE_STATIC = True # this means that argument part has always the same length + IS_SIZE_STATIC = True # this means that argument part has always the same length IS_CONTENT_STATIC = True # this means that argument part has always the same content STATIC_CONTENT = b'\x00\x00\x00\x04\x00\x32\x00\x15\xCE' # spans LENGTH, CLASS ID, METHOD ID, ....., FRAME_END @@ -1771,7 +1799,6 @@ class QueueBindOk(AMQPMethodPayload): Create frame queue.bind-ok """ - @staticmethod def from_buffer(buf, start_offset): offset = start_offset @@ -1786,20 +1813,22 @@ class QueueDeclare(AMQPMethodPayload): specify various properties that control the durability of the queue and its contents, and the level of sharing for the queue. """ - __slots__ = (u'queue', u'passive', u'durable', u'exclusive', u'auto_delete', u'no_wait', u'arguments', ) + __slots__ = ( + u'queue', u'passive', u'durable', u'exclusive', u'auto_delete', u'no_wait', + u'arguments',) NAME = u'queue.declare' - INDEX = (50, 10) # (Class ID, Method ID) - BINARY_HEADER = b'\x00\x32\x00\x0A' # CLASS ID + METHOD ID + INDEX = (50, 10) # (Class ID, Method ID) + BINARY_HEADER = b'\x00\x32\x00\x0A' # CLASS ID + METHOD ID SENT_BY_CLIENT, SENT_BY_SERVER = True, False - IS_SIZE_STATIC = False # this means that argument part has always the same length + IS_SIZE_STATIC = False # this means that argument part has always the same length IS_CONTENT_STATIC = False # this means that argument part has always the same content # See constructor pydoc for details - FIELDS = [ + FIELDS = [ Field(u'reserved-1', u'short', u'short', reserved=True), Field(u'queue', u'queue-name', u'shortstr', reserved=False), Field(u'passive', u'bit', u'bit', reserved=False), @@ -1810,7 +1839,8 @@ class QueueDeclare(AMQPMethodPayload): Field(u'arguments', u'table', u'table', reserved=False), ] - def __init__(self, queue, passive, durable, exclusive, auto_delete, no_wait, arguments): + def __init__(self, queue, passive, durable, exclusive, auto_delete, + no_wait, arguments): """ Create frame queue.declare @@ -1862,9 +1892,12 @@ class QueueDeclare(AMQPMethodPayload): buf.write(b'\x00\x00') buf.write(struct.pack('!B', len(self.queue))) buf.write(self.queue) - buf.write(struct.pack('!B', (self.passive << 0) | (self.durable << 1) | (self.exclusive << 2) | (self.auto_delete << 3) | (self.no_wait << 4))) + buf.write(struct.pack('!B', + (self.passive << 0) | (self.durable << 1) | ( + self.exclusive << 2) | ( + self.auto_delete << 3) | (self.no_wait << 4))) enframe_table(buf, self.arguments) - + def get_size(self): return 4 + len(self.queue) + frame_table_size(self.arguments) @@ -1873,7 +1906,7 @@ class QueueDeclare(AMQPMethodPayload): offset = start_offset s_len, = struct.unpack_from('!2xB', buf, offset) offset += 3 - queue = buf[offset:offset+s_len] + queue = buf[offset:offset + s_len] offset += s_len _bit, = struct.unpack_from('!B', buf, offset) offset += 0 @@ -1885,7 +1918,8 @@ class QueueDeclare(AMQPMethodPayload): offset += 1 arguments, delta = deframe_table(buf, offset) offset += delta - return QueueDeclare(queue, passive, durable, exclusive, auto_delete, no_wait, arguments) + return QueueDeclare(queue, passive, durable, exclusive, auto_delete, + no_wait, arguments) class QueueDelete(AMQPMethodPayload): @@ -1896,20 +1930,20 @@ class QueueDelete(AMQPMethodPayload): to a dead-letter queue if this is defined in the server configuration, and all consumers on the queue are cancelled. """ - __slots__ = (u'queue', u'if_unused', u'if_empty', u'no_wait', ) + __slots__ = (u'queue', u'if_unused', u'if_empty', u'no_wait',) NAME = u'queue.delete' - INDEX = (50, 40) # (Class ID, Method ID) - BINARY_HEADER = b'\x00\x32\x00\x28' # CLASS ID + METHOD ID + INDEX = (50, 40) # (Class ID, Method ID) + BINARY_HEADER = b'\x00\x32\x00\x28' # CLASS ID + METHOD ID SENT_BY_CLIENT, SENT_BY_SERVER = True, False - IS_SIZE_STATIC = False # this means that argument part has always the same length + IS_SIZE_STATIC = False # this means that argument part has always the same length IS_CONTENT_STATIC = False # this means that argument part has always the same content # See constructor pydoc for details - FIELDS = [ + FIELDS = [ Field(u'reserved-1', u'short', u'short', reserved=True), Field(u'queue', u'queue-name', u'shortstr', reserved=False), Field(u'if-unused', u'bit', u'bit', reserved=False), @@ -1942,8 +1976,10 @@ class QueueDelete(AMQPMethodPayload): buf.write(b'\x00\x00') buf.write(struct.pack('!B', len(self.queue))) buf.write(self.queue) - buf.write(struct.pack('!B', (self.if_unused << 0) | (self.if_empty << 1) | (self.no_wait << 2))) - + buf.write(struct.pack('!B', + (self.if_unused << 0) | (self.if_empty << 1) | ( + self.no_wait << 2))) + def get_size(self): return 4 + len(self.queue) @@ -1952,7 +1988,7 @@ class QueueDelete(AMQPMethodPayload): offset = start_offset s_len, = struct.unpack_from('!2xB', buf, offset) offset += 3 - queue = buf[offset:offset+s_len] + queue = buf[offset:offset + s_len] offset += s_len _bit, = struct.unpack_from('!B', buf, offset) offset += 0 @@ -1970,20 +2006,20 @@ class QueueDeclareOk(AMQPMethodPayload): This method confirms a Declare method and confirms the name of the queue, essential for automatically-named queues. """ - __slots__ = (u'queue', u'message_count', u'consumer_count', ) + __slots__ = (u'queue', u'message_count', u'consumer_count',) NAME = u'queue.declare-ok' - INDEX = (50, 11) # (Class ID, Method ID) - BINARY_HEADER = b'\x00\x32\x00\x0B' # CLASS ID + METHOD ID + INDEX = (50, 11) # (Class ID, Method ID) + BINARY_HEADER = b'\x00\x32\x00\x0B' # CLASS ID + METHOD ID SENT_BY_CLIENT, SENT_BY_SERVER = False, True - IS_SIZE_STATIC = False # this means that argument part has always the same length + IS_SIZE_STATIC = False # this means that argument part has always the same length IS_CONTENT_STATIC = False # this means that argument part has always the same content # See constructor pydoc for details - FIELDS = [ + FIELDS = [ Field(u'queue', u'queue-name', u'shortstr', reserved=False), Field(u'message-count', u'message-count', u'long', reserved=False), Field(u'consumer-count', u'long', u'long', reserved=False), @@ -2010,7 +2046,7 @@ class QueueDeclareOk(AMQPMethodPayload): buf.write(struct.pack('!B', len(self.queue))) buf.write(self.queue) buf.write(struct.pack('!II', self.message_count, self.consumer_count)) - + def get_size(self): return 9 + len(self.queue) @@ -2019,7 +2055,7 @@ class QueueDeclareOk(AMQPMethodPayload): offset = start_offset s_len, = struct.unpack_from('!B', buf, offset) offset += 1 - queue = buf[offset:offset+s_len] + queue = buf[offset:offset + s_len] offset += s_len message_count, consumer_count, = struct.unpack_from('!II', buf, offset) offset += 8 @@ -2032,20 +2068,20 @@ class QueueDeleteOk(AMQPMethodPayload): This method confirms the deletion of a queue. """ - __slots__ = (u'message_count', ) + __slots__ = (u'message_count',) NAME = u'queue.delete-ok' - INDEX = (50, 41) # (Class ID, Method ID) - BINARY_HEADER = b'\x00\x32\x00\x29' # CLASS ID + METHOD ID + INDEX = (50, 41) # (Class ID, Method ID) + BINARY_HEADER = b'\x00\x32\x00\x29' # CLASS ID + METHOD ID SENT_BY_CLIENT, SENT_BY_SERVER = False, True - IS_SIZE_STATIC = True # this means that argument part has always the same length + IS_SIZE_STATIC = True # this means that argument part has always the same length IS_CONTENT_STATIC = False # this means that argument part has always the same content # See constructor pydoc for details - FIELDS = [ + FIELDS = [ Field(u'message-count', u'message-count', u'long', reserved=False), ] @@ -2060,7 +2096,7 @@ class QueueDeleteOk(AMQPMethodPayload): def write_arguments(self, buf): buf.write(struct.pack('!I', self.message_count)) - + def get_size(self): return 4 @@ -2079,20 +2115,20 @@ class QueuePurge(AMQPMethodPayload): This method removes all messages from a queue which are not awaiting acknowledgment. """ - __slots__ = (u'queue', u'no_wait', ) + __slots__ = (u'queue', u'no_wait',) NAME = u'queue.purge' - INDEX = (50, 30) # (Class ID, Method ID) - BINARY_HEADER = b'\x00\x32\x00\x1E' # CLASS ID + METHOD ID + INDEX = (50, 30) # (Class ID, Method ID) + BINARY_HEADER = b'\x00\x32\x00\x1E' # CLASS ID + METHOD ID SENT_BY_CLIENT, SENT_BY_SERVER = True, False - IS_SIZE_STATIC = False # this means that argument part has always the same length + IS_SIZE_STATIC = False # this means that argument part has always the same length IS_CONTENT_STATIC = False # this means that argument part has always the same content # See constructor pydoc for details - FIELDS = [ + FIELDS = [ Field(u'reserved-1', u'short', u'short', reserved=True), Field(u'queue', u'queue-name', u'shortstr', reserved=False), Field(u'no-wait', u'no-wait', u'bit', reserved=False), @@ -2114,7 +2150,7 @@ class QueuePurge(AMQPMethodPayload): buf.write(struct.pack('!B', len(self.queue))) buf.write(self.queue) buf.write(struct.pack('!B', (self.no_wait << 0))) - + def get_size(self): return 4 + len(self.queue) @@ -2123,7 +2159,7 @@ class QueuePurge(AMQPMethodPayload): offset = start_offset s_len, = struct.unpack_from('!2xB', buf, offset) offset += 3 - queue = buf[offset:offset+s_len] + queue = buf[offset:offset + s_len] offset += s_len _bit, = struct.unpack_from('!B', buf, offset) offset += 0 @@ -2138,20 +2174,20 @@ class QueuePurgeOk(AMQPMethodPayload): This method confirms the purge of a queue. """ - __slots__ = (u'message_count', ) + __slots__ = (u'message_count',) NAME = u'queue.purge-ok' - INDEX = (50, 31) # (Class ID, Method ID) - BINARY_HEADER = b'\x00\x32\x00\x1F' # CLASS ID + METHOD ID + INDEX = (50, 31) # (Class ID, Method ID) + BINARY_HEADER = b'\x00\x32\x00\x1F' # CLASS ID + METHOD ID SENT_BY_CLIENT, SENT_BY_SERVER = False, True - IS_SIZE_STATIC = True # this means that argument part has always the same length + IS_SIZE_STATIC = True # this means that argument part has always the same length IS_CONTENT_STATIC = False # this means that argument part has always the same content # See constructor pydoc for details - FIELDS = [ + FIELDS = [ Field(u'message-count', u'message-count', u'long', reserved=False), ] @@ -2166,7 +2202,7 @@ class QueuePurgeOk(AMQPMethodPayload): def write_arguments(self, buf): buf.write(struct.pack('!I', self.message_count)) - + def get_size(self): return 4 @@ -2184,20 +2220,20 @@ class QueueUnbind(AMQPMethodPayload): This method unbinds a queue from an exchange. """ - __slots__ = (u'queue', u'exchange', u'routing_key', u'arguments', ) + __slots__ = (u'queue', u'exchange', u'routing_key', u'arguments',) NAME = u'queue.unbind' - INDEX = (50, 50) # (Class ID, Method ID) - BINARY_HEADER = b'\x00\x32\x00\x32' # CLASS ID + METHOD ID + INDEX = (50, 50) # (Class ID, Method ID) + BINARY_HEADER = b'\x00\x32\x00\x32' # CLASS ID + METHOD ID SENT_BY_CLIENT, SENT_BY_SERVER = True, False - IS_SIZE_STATIC = False # this means that argument part has always the same length + IS_SIZE_STATIC = False # this means that argument part has always the same length IS_CONTENT_STATIC = False # this means that argument part has always the same content # See constructor pydoc for details - FIELDS = [ + FIELDS = [ Field(u'reserved-1', u'short', u'short', reserved=True), Field(u'queue', u'queue-name', u'shortstr', reserved=False), Field(u'exchange', u'exchange-name', u'shortstr', reserved=False), @@ -2234,24 +2270,25 @@ class QueueUnbind(AMQPMethodPayload): buf.write(struct.pack('!B', len(self.routing_key))) buf.write(self.routing_key) enframe_table(buf, self.arguments) - + def get_size(self): - return 5 + len(self.queue) + len(self.exchange) + len(self.routing_key) + frame_table_size(self.arguments) + return 5 + len(self.queue) + len(self.exchange) + len( + self.routing_key) + frame_table_size(self.arguments) @staticmethod def from_buffer(buf, start_offset): offset = start_offset s_len, = struct.unpack_from('!2xB', buf, offset) offset += 3 - queue = buf[offset:offset+s_len] + queue = buf[offset:offset + s_len] offset += s_len s_len, = struct.unpack_from('!B', buf, offset) offset += 1 - exchange = buf[offset:offset+s_len] + exchange = buf[offset:offset + s_len] offset += s_len s_len, = struct.unpack_from('!B', buf, offset) offset += 1 - routing_key = buf[offset:offset+s_len] + routing_key = buf[offset:offset + s_len] offset += s_len arguments, delta = deframe_table(buf, offset) offset += delta @@ -2268,12 +2305,12 @@ class QueueUnbindOk(AMQPMethodPayload): NAME = u'queue.unbind-ok' - INDEX = (50, 51) # (Class ID, Method ID) - BINARY_HEADER = b'\x00\x32\x00\x33' # CLASS ID + METHOD ID + INDEX = (50, 51) # (Class ID, Method ID) + BINARY_HEADER = b'\x00\x32\x00\x33' # CLASS ID + METHOD ID SENT_BY_CLIENT, SENT_BY_SERVER = False, True - IS_SIZE_STATIC = True # this means that argument part has always the same length + IS_SIZE_STATIC = True # this means that argument part has always the same length IS_CONTENT_STATIC = True # this means that argument part has always the same content STATIC_CONTENT = b'\x00\x00\x00\x04\x00\x32\x00\x33\xCE' # spans LENGTH, CLASS ID, METHOD ID, ....., FRAME_END @@ -2282,7 +2319,6 @@ class QueueUnbindOk(AMQPMethodPayload): Create frame queue.unbind-ok """ - @staticmethod def from_buffer(buf, start_offset): offset = start_offset @@ -2354,48 +2390,72 @@ class BasicContentPropertyList(AMQPContentPropertyList): :type reserved: binary type (max length 255) (AMQP as shortstr) """ zpf = bytearray([ - (('content_type' in kwargs) << 7) | (('content_encoding' in kwargs) << 6) | (('headers' in kwargs) << 5) | (('delivery_mode' in kwargs) << 4) | (('priority' in kwargs) << 3) | (('correlation_id' in kwargs) << 2) | (('reply_to' in kwargs) << 1) | int('expiration' in kwargs), - (('message_id' in kwargs) << 7) | (('timestamp' in kwargs) << 6) | (('type_' in kwargs) << 5) | (('user_id' in kwargs) << 4) | (('app_id' in kwargs) << 3) | (('reserved' in kwargs) << 2) + (('content_type' in kwargs) << 7) | ( + ('content_encoding' in kwargs) << 6) | ( + ('headers' in kwargs) << 5) | ( + ('delivery_mode' in kwargs) << 4) | ( + ('priority' in kwargs) << 3) | ( + ('correlation_id' in kwargs) << 2) | ( + ('reply_to' in kwargs) << 1) | int('expiration' in kwargs), + (('message_id' in kwargs) << 7) | ( + ('timestamp' in kwargs) << 6) | (('type_' in kwargs) << 5) | ( + ('user_id' in kwargs) << 4) | (('app_id' in kwargs) << 3) | ( + ('reserved' in kwargs) << 2) ]) zpf = six.binary_type(zpf) -# If you know in advance what properties you will be using, use typized constructors like -# -# runs once -# my_type = BasicContentPropertyList.typize('content_type', 'content_encoding') -# -# runs many times -# props = my_type('text/plain', 'utf8') -# -# instead of -# -# # runs many times -# props = BasicContentPropertyList(content_type='text/plain', content_encoding='utf8') -# -# This way you will be faster. -# -# If you do not know in advance what properties you will be using, it is correct to use -# this constructor. + # If you know in advance what properties you will be using, use typized constructors like + # + # runs once + # my_type = BasicContentPropertyList.typize('content_type', 'content_encoding') + # + # runs many times + # props = my_type('text/plain', 'utf8') + # + # instead of + # + # # runs many times + # props = BasicContentPropertyList(content_type='text/plain', content_encoding='utf8') + # + # This way you will be faster. + # + # If you do not know in advance what properties you will be using, it is correct to use + # this constructor. if zpf in BasicContentPropertyList.PARTICULAR_CLASSES: return BasicContentPropertyList.PARTICULAR_CLASSES[zpf](**kwargs) else: - logger.debug('Property field (BasicContentPropertyList:%s) not seen yet, compiling', repr(zpf)) - c = compile_particular_content_property_list_class(zpf, BasicContentPropertyList.FIELDS) + logger.debug( + 'Property field (BasicContentPropertyList:%s) not seen yet, compiling', + repr(zpf)) + c = compile_particular_content_property_list_class(zpf, + BasicContentPropertyList.FIELDS) BasicContentPropertyList.PARTICULAR_CLASSES[zpf] = c return c(**kwargs) @staticmethod def typize(*fields): zpf = bytearray([ - (('content_type' in fields) << 7) | (('content_encoding' in fields) << 6) | (('headers' in fields) << 5) | (('delivery_mode' in fields) << 4) | (('priority' in fields) << 3) | (('correlation_id' in fields) << 2) | (('reply_to' in fields) << 1) | int('expiration' in kwargs), - (('message_id' in fields) << 7) | (('timestamp' in fields) << 6) | (('type_' in fields) << 5) | (('user_id' in fields) << 4) | (('app_id' in fields) << 3) | (('reserved' in fields) << 2) + (('content_type' in fields) << 7) | ( + ('content_encoding' in fields) << 6) | ( + ('headers' in fields) << 5) | ( + ('delivery_mode' in fields) << 4) | ( + ('priority' in fields) << 3) | ( + ('correlation_id' in fields) << 2) | ( + ('reply_to' in fields) << 1) | int('expiration' in kwargs), + (('message_id' in fields) << 7) | ( + ('timestamp' in fields) << 6) | (('type_' in fields) << 5) | ( + ('user_id' in fields) << 4) | (('app_id' in fields) << 3) | ( + ('reserved' in fields) << 2) ]) zpf = six.binary_type(zpf) if zpf in BasicContentPropertyList.PARTICULAR_CLASSES: return BasicContentPropertyList.PARTICULAR_CLASSES[zpf] else: - logger.debug('Property field (BasicContentPropertyList:%s) not seen yet, compiling', repr(zpf)) - c = compile_particular_content_property_list_class(zpf, BasicContentPropertyList.FIELDS) + logger.debug( + 'Property field (BasicContentPropertyList:%s) not seen yet, compiling', + repr(zpf)) + c = compile_particular_content_property_list_class(zpf, + BasicContentPropertyList.FIELDS) BasicContentPropertyList.PARTICULAR_CLASSES[zpf] = c return c @@ -2413,12 +2473,17 @@ class BasicContentPropertyList(AMQPContentPropertyList): else: while buf[offset + pfl - 1] & 1: pfl += 2 - zpf = BasicContentPropertyList.zero_property_flags(buf[offset:offset+pfl]).tobytes() + zpf = BasicContentPropertyList.zero_property_flags( + buf[offset:offset + pfl]).tobytes() if zpf in BasicContentPropertyList.PARTICULAR_CLASSES: - return BasicContentPropertyList.PARTICULAR_CLASSES[zpf].from_buffer(buf, offset) + return BasicContentPropertyList.PARTICULAR_CLASSES[ + zpf].from_buffer(buf, offset) else: - logger.debug('Property field (BasicContentPropertyList:%s) not seen yet, compiling', repr(zpf)) - c = compile_particular_content_property_list_class(zpf, BasicContentPropertyList.FIELDS) + logger.debug( + 'Property field (BasicContentPropertyList:%s) not seen yet, compiling', + repr(zpf)) + c = compile_particular_content_property_list_class(zpf, + BasicContentPropertyList.FIELDS) BasicContentPropertyList.PARTICULAR_CLASSES[zpf] = c return c.from_buffer(buf, offset) @@ -2435,20 +2500,20 @@ class BasicAck(AMQPMethodPayload): The acknowledgement can be for a single message or a set of messages up to and including a specific message. """ - __slots__ = (u'delivery_tag', u'multiple', ) + __slots__ = (u'delivery_tag', u'multiple',) NAME = u'basic.ack' - INDEX = (60, 80) # (Class ID, Method ID) - BINARY_HEADER = b'\x00\x3C\x00\x50' # CLASS ID + METHOD ID + INDEX = (60, 80) # (Class ID, Method ID) + BINARY_HEADER = b'\x00\x3C\x00\x50' # CLASS ID + METHOD ID SENT_BY_CLIENT, SENT_BY_SERVER = True, True - IS_SIZE_STATIC = True # this means that argument part has always the same length + IS_SIZE_STATIC = True # this means that argument part has always the same length IS_CONTENT_STATIC = False # this means that argument part has always the same content # See constructor pydoc for details - FIELDS = [ + FIELDS = [ Field(u'delivery-tag', u'delivery-tag', u'longlong', reserved=False), Field(u'multiple', u'bit', u'bit', reserved=False), ] @@ -2472,7 +2537,7 @@ class BasicAck(AMQPMethodPayload): def write_arguments(self, buf): buf.write(struct.pack('!QB', self.delivery_tag, (self.multiple << 0))) - + def get_size(self): return 9 @@ -2494,20 +2559,22 @@ class BasicConsume(AMQPMethodPayload): messages from a specific queue. Consumers last as long as the channel they were declared on, or until the client cancels them. """ - __slots__ = (u'queue', u'consumer_tag', u'no_local', u'no_ack', u'exclusive', u'no_wait', u'arguments', ) + __slots__ = ( + u'queue', u'consumer_tag', u'no_local', u'no_ack', u'exclusive', + u'no_wait', u'arguments',) NAME = u'basic.consume' - INDEX = (60, 20) # (Class ID, Method ID) - BINARY_HEADER = b'\x00\x3C\x00\x14' # CLASS ID + METHOD ID + INDEX = (60, 20) # (Class ID, Method ID) + BINARY_HEADER = b'\x00\x3C\x00\x14' # CLASS ID + METHOD ID SENT_BY_CLIENT, SENT_BY_SERVER = True, False - IS_SIZE_STATIC = False # this means that argument part has always the same length + IS_SIZE_STATIC = False # this means that argument part has always the same length IS_CONTENT_STATIC = False # this means that argument part has always the same content # See constructor pydoc for details - FIELDS = [ + FIELDS = [ Field(u'reserved-1', u'short', u'short', reserved=True), Field(u'queue', u'queue-name', u'shortstr', reserved=False), Field(u'consumer-tag', u'consumer-tag', u'shortstr', reserved=False), @@ -2518,7 +2585,8 @@ class BasicConsume(AMQPMethodPayload): Field(u'arguments', u'table', u'table', reserved=False), ] - def __init__(self, queue, consumer_tag, no_local, no_ack, exclusive, no_wait, arguments): + def __init__(self, queue, consumer_tag, no_local, no_ack, exclusive, + no_wait, arguments): """ Create frame basic.consume @@ -2554,22 +2622,25 @@ class BasicConsume(AMQPMethodPayload): buf.write(self.queue) buf.write(struct.pack('!B', len(self.consumer_tag))) buf.write(self.consumer_tag) - buf.write(struct.pack('!B', (self.no_local << 0) | (self.no_ack << 1) | (self.exclusive << 2) | (self.no_wait << 3))) + buf.write(struct.pack('!B', + (self.no_local << 0) | (self.no_ack << 1) | ( + self.exclusive << 2) | (self.no_wait << 3))) enframe_table(buf, self.arguments) - + def get_size(self): - return 5 + len(self.queue) + len(self.consumer_tag) + frame_table_size(self.arguments) + return 5 + len(self.queue) + len(self.consumer_tag) + frame_table_size( + self.arguments) @staticmethod def from_buffer(buf, start_offset): offset = start_offset s_len, = struct.unpack_from('!2xB', buf, offset) offset += 3 - queue = buf[offset:offset+s_len] + queue = buf[offset:offset + s_len] offset += s_len s_len, = struct.unpack_from('!B', buf, offset) offset += 1 - consumer_tag = buf[offset:offset+s_len] + consumer_tag = buf[offset:offset + s_len] offset += s_len _bit, = struct.unpack_from('!B', buf, offset) offset += 0 @@ -2580,7 +2651,8 @@ class BasicConsume(AMQPMethodPayload): offset += 1 arguments, delta = deframe_table(buf, offset) offset += delta - return BasicConsume(queue, consumer_tag, no_local, no_ack, exclusive, no_wait, arguments) + return BasicConsume(queue, consumer_tag, no_local, no_ack, exclusive, + no_wait, arguments) class BasicCancel(AMQPMethodPayload): @@ -2602,20 +2674,20 @@ class BasicCancel(AMQPMethodPayload): capable of accepting the method, through some means of capability negotiation. """ - __slots__ = (u'consumer_tag', u'no_wait', ) + __slots__ = (u'consumer_tag', u'no_wait',) NAME = u'basic.cancel' - INDEX = (60, 30) # (Class ID, Method ID) - BINARY_HEADER = b'\x00\x3C\x00\x1E' # CLASS ID + METHOD ID + INDEX = (60, 30) # (Class ID, Method ID) + BINARY_HEADER = b'\x00\x3C\x00\x1E' # CLASS ID + METHOD ID SENT_BY_CLIENT, SENT_BY_SERVER = True, True - IS_SIZE_STATIC = False # this means that argument part has always the same length + IS_SIZE_STATIC = False # this means that argument part has always the same length IS_CONTENT_STATIC = False # this means that argument part has always the same content # See constructor pydoc for details - FIELDS = [ + FIELDS = [ Field(u'consumer-tag', u'consumer-tag', u'shortstr', reserved=False), Field(u'no-wait', u'no-wait', u'bit', reserved=False), ] @@ -2634,7 +2706,7 @@ class BasicCancel(AMQPMethodPayload): buf.write(struct.pack('!B', len(self.consumer_tag))) buf.write(self.consumer_tag) buf.write(struct.pack('!B', (self.no_wait << 0))) - + def get_size(self): return 2 + len(self.consumer_tag) @@ -2643,7 +2715,7 @@ class BasicCancel(AMQPMethodPayload): offset = start_offset s_len, = struct.unpack_from('!B', buf, offset) offset += 1 - consumer_tag = buf[offset:offset+s_len] + consumer_tag = buf[offset:offset + s_len] offset += s_len _bit, = struct.unpack_from('!B', buf, offset) offset += 0 @@ -2659,20 +2731,20 @@ class BasicConsumeOk(AMQPMethodPayload): The server provides the client with a consumer tag, which is used by the client for methods called on the consumer at a later stage. """ - __slots__ = (u'consumer_tag', ) + __slots__ = (u'consumer_tag',) NAME = u'basic.consume-ok' - INDEX = (60, 21) # (Class ID, Method ID) - BINARY_HEADER = b'\x00\x3C\x00\x15' # CLASS ID + METHOD ID + INDEX = (60, 21) # (Class ID, Method ID) + BINARY_HEADER = b'\x00\x3C\x00\x15' # CLASS ID + METHOD ID SENT_BY_CLIENT, SENT_BY_SERVER = False, True - IS_SIZE_STATIC = False # this means that argument part has always the same length + IS_SIZE_STATIC = False # this means that argument part has always the same length IS_CONTENT_STATIC = False # this means that argument part has always the same content # See constructor pydoc for details - FIELDS = [ + FIELDS = [ Field(u'consumer-tag', u'consumer-tag', u'shortstr', reserved=False), ] @@ -2688,7 +2760,7 @@ class BasicConsumeOk(AMQPMethodPayload): def write_arguments(self, buf): buf.write(struct.pack('!B', len(self.consumer_tag))) buf.write(self.consumer_tag) - + def get_size(self): return 1 + len(self.consumer_tag) @@ -2697,7 +2769,7 @@ class BasicConsumeOk(AMQPMethodPayload): offset = start_offset s_len, = struct.unpack_from('!B', buf, offset) offset += 1 - consumer_tag = buf[offset:offset+s_len] + consumer_tag = buf[offset:offset + s_len] offset += s_len return BasicConsumeOk(consumer_tag) @@ -2708,20 +2780,20 @@ class BasicCancelOk(AMQPMethodPayload): This method confirms that the cancellation was completed. """ - __slots__ = (u'consumer_tag', ) + __slots__ = (u'consumer_tag',) NAME = u'basic.cancel-ok' - INDEX = (60, 31) # (Class ID, Method ID) - BINARY_HEADER = b'\x00\x3C\x00\x1F' # CLASS ID + METHOD ID + INDEX = (60, 31) # (Class ID, Method ID) + BINARY_HEADER = b'\x00\x3C\x00\x1F' # CLASS ID + METHOD ID SENT_BY_CLIENT, SENT_BY_SERVER = True, True - IS_SIZE_STATIC = False # this means that argument part has always the same length + IS_SIZE_STATIC = False # this means that argument part has always the same length IS_CONTENT_STATIC = False # this means that argument part has always the same content # See constructor pydoc for details - FIELDS = [ + FIELDS = [ Field(u'consumer-tag', u'consumer-tag', u'shortstr', reserved=False), ] @@ -2736,7 +2808,7 @@ class BasicCancelOk(AMQPMethodPayload): def write_arguments(self, buf): buf.write(struct.pack('!B', len(self.consumer_tag))) buf.write(self.consumer_tag) - + def get_size(self): return 1 + len(self.consumer_tag) @@ -2745,7 +2817,7 @@ class BasicCancelOk(AMQPMethodPayload): offset = start_offset s_len, = struct.unpack_from('!B', buf, offset) offset += 1 - consumer_tag = buf[offset:offset+s_len] + consumer_tag = buf[offset:offset + s_len] offset += s_len return BasicCancelOk(consumer_tag) @@ -2759,20 +2831,21 @@ class BasicDeliver(AMQPMethodPayload): the server responds with Deliver methods as and when messages arrive for that consumer. """ - __slots__ = (u'consumer_tag', u'delivery_tag', u'redelivered', u'exchange', u'routing_key', ) + __slots__ = (u'consumer_tag', u'delivery_tag', u'redelivered', u'exchange', + u'routing_key',) NAME = u'basic.deliver' - INDEX = (60, 60) # (Class ID, Method ID) - BINARY_HEADER = b'\x00\x3C\x00\x3C' # CLASS ID + METHOD ID + INDEX = (60, 60) # (Class ID, Method ID) + BINARY_HEADER = b'\x00\x3C\x00\x3C' # CLASS ID + METHOD ID SENT_BY_CLIENT, SENT_BY_SERVER = False, True - IS_SIZE_STATIC = False # this means that argument part has always the same length + IS_SIZE_STATIC = False # this means that argument part has always the same length IS_CONTENT_STATIC = False # this means that argument part has always the same content # See constructor pydoc for details - FIELDS = [ + FIELDS = [ Field(u'consumer-tag', u'consumer-tag', u'shortstr', reserved=False), Field(u'delivery-tag', u'delivery-tag', u'longlong', reserved=False), Field(u'redelivered', u'redelivered', u'bit', reserved=False), @@ -2780,7 +2853,8 @@ class BasicDeliver(AMQPMethodPayload): Field(u'routing-key', u'shortstr', u'shortstr', reserved=False), ] - def __init__(self, consumer_tag, delivery_tag, redelivered, exchange, routing_key): + def __init__(self, consumer_tag, delivery_tag, redelivered, exchange, + routing_key): """ Create frame basic.deliver @@ -2803,20 +2877,23 @@ class BasicDeliver(AMQPMethodPayload): def write_arguments(self, buf): buf.write(struct.pack('!B', len(self.consumer_tag))) buf.write(self.consumer_tag) - buf.write(struct.pack('!QBB', self.delivery_tag, (self.redelivered << 0), len(self.exchange))) + buf.write( + struct.pack('!QBB', self.delivery_tag, (self.redelivered << 0), + len(self.exchange))) buf.write(self.exchange) buf.write(struct.pack('!B', len(self.routing_key))) buf.write(self.routing_key) - + def get_size(self): - return 12 + len(self.consumer_tag) + len(self.exchange) + len(self.routing_key) + return 12 + len(self.consumer_tag) + len(self.exchange) + len( + self.routing_key) @staticmethod def from_buffer(buf, start_offset): offset = start_offset s_len, = struct.unpack_from('!B', buf, offset) offset += 1 - consumer_tag = buf[offset:offset+s_len] + consumer_tag = buf[offset:offset + s_len] offset += s_len delivery_tag, _bit, = struct.unpack_from('!QB', buf, offset) offset += 8 @@ -2824,13 +2901,14 @@ class BasicDeliver(AMQPMethodPayload): offset += 1 s_len, = struct.unpack_from('!B', buf, offset) offset += 1 - exchange = buf[offset:offset+s_len] + exchange = buf[offset:offset + s_len] offset += s_len s_len, = struct.unpack_from('!B', buf, offset) offset += 1 - routing_key = buf[offset:offset+s_len] + routing_key = buf[offset:offset + s_len] offset += s_len - return BasicDeliver(consumer_tag, delivery_tag, redelivered, exchange, routing_key) + return BasicDeliver(consumer_tag, delivery_tag, redelivered, exchange, + routing_key) class BasicGet(AMQPMethodPayload): @@ -2841,20 +2919,20 @@ class BasicGet(AMQPMethodPayload): dialogue that is designed for specific types of application where synchronous functionality is more important than performance. """ - __slots__ = (u'queue', u'no_ack', ) + __slots__ = (u'queue', u'no_ack',) NAME = u'basic.get' - INDEX = (60, 70) # (Class ID, Method ID) - BINARY_HEADER = b'\x00\x3C\x00\x46' # CLASS ID + METHOD ID + INDEX = (60, 70) # (Class ID, Method ID) + BINARY_HEADER = b'\x00\x3C\x00\x46' # CLASS ID + METHOD ID SENT_BY_CLIENT, SENT_BY_SERVER = True, False - IS_SIZE_STATIC = False # this means that argument part has always the same length + IS_SIZE_STATIC = False # this means that argument part has always the same length IS_CONTENT_STATIC = False # this means that argument part has always the same content # See constructor pydoc for details - FIELDS = [ + FIELDS = [ Field(u'reserved-1', u'short', u'short', reserved=True), Field(u'queue', u'queue-name', u'shortstr', reserved=False), Field(u'no-ack', u'no-ack', u'bit', reserved=False), @@ -2876,7 +2954,7 @@ class BasicGet(AMQPMethodPayload): buf.write(struct.pack('!B', len(self.queue))) buf.write(self.queue) buf.write(struct.pack('!B', (self.no_ack << 0))) - + def get_size(self): return 4 + len(self.queue) @@ -2885,7 +2963,7 @@ class BasicGet(AMQPMethodPayload): offset = start_offset s_len, = struct.unpack_from('!2xB', buf, offset) offset += 3 - queue = buf[offset:offset+s_len] + queue = buf[offset:offset + s_len] offset += s_len _bit, = struct.unpack_from('!B', buf, offset) offset += 0 @@ -2902,20 +2980,21 @@ class BasicGetOk(AMQPMethodPayload): delivered by 'get-ok' must be acknowledged unless the no-ack option was set in the get method. """ - __slots__ = (u'delivery_tag', u'redelivered', u'exchange', u'routing_key', u'message_count', ) + __slots__ = (u'delivery_tag', u'redelivered', u'exchange', u'routing_key', + u'message_count',) NAME = u'basic.get-ok' - INDEX = (60, 71) # (Class ID, Method ID) - BINARY_HEADER = b'\x00\x3C\x00\x47' # CLASS ID + METHOD ID + INDEX = (60, 71) # (Class ID, Method ID) + BINARY_HEADER = b'\x00\x3C\x00\x47' # CLASS ID + METHOD ID SENT_BY_CLIENT, SENT_BY_SERVER = False, True - IS_SIZE_STATIC = False # this means that argument part has always the same length + IS_SIZE_STATIC = False # this means that argument part has always the same length IS_CONTENT_STATIC = False # this means that argument part has always the same content # See constructor pydoc for details - FIELDS = [ + FIELDS = [ Field(u'delivery-tag', u'delivery-tag', u'longlong', reserved=False), Field(u'redelivered', u'redelivered', u'bit', reserved=False), Field(u'exchange', u'exchange-name', u'shortstr', reserved=False), @@ -2923,7 +3002,8 @@ class BasicGetOk(AMQPMethodPayload): Field(u'message-count', u'message-count', u'long', reserved=False), ] - def __init__(self, delivery_tag, redelivered, exchange, routing_key, message_count): + def __init__(self, delivery_tag, redelivered, exchange, routing_key, + message_count): """ Create frame basic.get-ok @@ -2944,12 +3024,14 @@ class BasicGetOk(AMQPMethodPayload): self.message_count = message_count def write_arguments(self, buf): - buf.write(struct.pack('!QBB', self.delivery_tag, (self.redelivered << 0), len(self.exchange))) + buf.write( + struct.pack('!QBB', self.delivery_tag, (self.redelivered << 0), + len(self.exchange))) buf.write(self.exchange) buf.write(struct.pack('!B', len(self.routing_key))) buf.write(self.routing_key) buf.write(struct.pack('!I', self.message_count)) - + def get_size(self): return 15 + len(self.exchange) + len(self.routing_key) @@ -2962,15 +3044,16 @@ class BasicGetOk(AMQPMethodPayload): offset += 1 s_len, = struct.unpack_from('!B', buf, offset) offset += 1 - exchange = buf[offset:offset+s_len] + exchange = buf[offset:offset + s_len] offset += s_len s_len, = struct.unpack_from('!B', buf, offset) offset += 1 - routing_key = buf[offset:offset+s_len] + routing_key = buf[offset:offset + s_len] offset += s_len message_count, = struct.unpack_from('!I', buf, offset) offset += 4 - return BasicGetOk(delivery_tag, redelivered, exchange, routing_key, message_count) + return BasicGetOk(delivery_tag, redelivered, exchange, routing_key, + message_count) class BasicGetEmpty(AMQPMethodPayload): @@ -2984,17 +3067,17 @@ class BasicGetEmpty(AMQPMethodPayload): NAME = u'basic.get-empty' - INDEX = (60, 72) # (Class ID, Method ID) - BINARY_HEADER = b'\x00\x3C\x00\x48' # CLASS ID + METHOD ID + INDEX = (60, 72) # (Class ID, Method ID) + BINARY_HEADER = b'\x00\x3C\x00\x48' # CLASS ID + METHOD ID SENT_BY_CLIENT, SENT_BY_SERVER = False, True - IS_SIZE_STATIC = False # this means that argument part has always the same length + IS_SIZE_STATIC = False # this means that argument part has always the same length IS_CONTENT_STATIC = True # this means that argument part has always the same content STATIC_CONTENT = b'\x00\x00\x00\x0D\x00\x3C\x00\x48\x00\xCE' # spans LENGTH, CLASS ID, METHOD ID, ....., FRAME_END # See constructor pydoc for details - FIELDS = [ + FIELDS = [ Field(u'reserved-1', u'shortstr', u'shortstr', reserved=True), ] @@ -3003,13 +3086,12 @@ class BasicGetEmpty(AMQPMethodPayload): Create frame basic.get-empty """ - @staticmethod def from_buffer(buf, start_offset): offset = start_offset s_len, = struct.unpack_from('!B', buf, offset) offset += 1 - offset += s_len # reserved field! + offset += s_len # reserved field! return BasicGetEmpty() @@ -3024,20 +3106,20 @@ class BasicNack(AMQPMethodPayload): confirm mode of unhandled messages. If a publisher receives this method, it probably needs to republish the offending messages. """ - __slots__ = (u'delivery_tag', u'multiple', u'requeue', ) + __slots__ = (u'delivery_tag', u'multiple', u'requeue',) NAME = u'basic.nack' - INDEX = (60, 120) # (Class ID, Method ID) - BINARY_HEADER = b'\x00\x3C\x00\x78' # CLASS ID + METHOD ID + INDEX = (60, 120) # (Class ID, Method ID) + BINARY_HEADER = b'\x00\x3C\x00\x78' # CLASS ID + METHOD ID SENT_BY_CLIENT, SENT_BY_SERVER = True, True - IS_SIZE_STATIC = True # this means that argument part has always the same length + IS_SIZE_STATIC = True # this means that argument part has always the same length IS_CONTENT_STATIC = False # this means that argument part has always the same content # See constructor pydoc for details - FIELDS = [ + FIELDS = [ Field(u'delivery-tag', u'delivery-tag', u'longlong', reserved=False), Field(u'multiple', u'bit', u'bit', reserved=False), Field(u'requeue', u'bit', u'bit', reserved=False), @@ -3067,8 +3149,9 @@ class BasicNack(AMQPMethodPayload): self.requeue = requeue def write_arguments(self, buf): - buf.write(struct.pack('!QB', self.delivery_tag, (self.multiple << 0) | (self.requeue << 1))) - + buf.write(struct.pack('!QB', self.delivery_tag, + (self.multiple << 0) | (self.requeue << 1))) + def get_size(self): return 9 @@ -3091,20 +3174,20 @@ class BasicPublish(AMQPMethodPayload): to queues as defined by the exchange configuration and distributed to any active consumers when the transaction, if any, is committed. """ - __slots__ = (u'exchange', u'routing_key', u'mandatory', u'immediate', ) + __slots__ = (u'exchange', u'routing_key', u'mandatory', u'immediate',) NAME = u'basic.publish' - INDEX = (60, 40) # (Class ID, Method ID) - BINARY_HEADER = b'\x00\x3C\x00\x28' # CLASS ID + METHOD ID + INDEX = (60, 40) # (Class ID, Method ID) + BINARY_HEADER = b'\x00\x3C\x00\x28' # CLASS ID + METHOD ID SENT_BY_CLIENT, SENT_BY_SERVER = True, False - IS_SIZE_STATIC = False # this means that argument part has always the same length + IS_SIZE_STATIC = False # this means that argument part has always the same length IS_CONTENT_STATIC = False # this means that argument part has always the same content # See constructor pydoc for details - FIELDS = [ + FIELDS = [ Field(u'reserved-1', u'short', u'short', reserved=True), Field(u'exchange', u'exchange-name', u'shortstr', reserved=False), Field(u'routing-key', u'shortstr', u'shortstr', reserved=False), @@ -3147,8 +3230,9 @@ class BasicPublish(AMQPMethodPayload): buf.write(self.exchange) buf.write(struct.pack('!B', len(self.routing_key))) buf.write(self.routing_key) - buf.write(struct.pack('!B', (self.mandatory << 0) | (self.immediate << 1))) - + buf.write( + struct.pack('!B', (self.mandatory << 0) | (self.immediate << 1))) + def get_size(self): return 5 + len(self.exchange) + len(self.routing_key) @@ -3157,11 +3241,11 @@ class BasicPublish(AMQPMethodPayload): offset = start_offset s_len, = struct.unpack_from('!2xB', buf, offset) offset += 3 - exchange = buf[offset:offset+s_len] + exchange = buf[offset:offset + s_len] offset += s_len s_len, = struct.unpack_from('!B', buf, offset) offset += 1 - routing_key = buf[offset:offset+s_len] + routing_key = buf[offset:offset + s_len] offset += s_len _bit, = struct.unpack_from('!B', buf, offset) offset += 0 @@ -3181,20 +3265,20 @@ class BasicQos(AMQPMethodPayload): qos method could in principle apply to both peers, it is currently meaningful only for the server. """ - __slots__ = (u'prefetch_size', u'prefetch_count', u'global_', ) + __slots__ = (u'prefetch_size', u'prefetch_count', u'global_',) NAME = u'basic.qos' - INDEX = (60, 10) # (Class ID, Method ID) - BINARY_HEADER = b'\x00\x3C\x00\x0A' # CLASS ID + METHOD ID + INDEX = (60, 10) # (Class ID, Method ID) + BINARY_HEADER = b'\x00\x3C\x00\x0A' # CLASS ID + METHOD ID SENT_BY_CLIENT, SENT_BY_SERVER = True, False - IS_SIZE_STATIC = True # this means that argument part has always the same length + IS_SIZE_STATIC = True # this means that argument part has always the same length IS_CONTENT_STATIC = False # this means that argument part has always the same content # See constructor pydoc for details - FIELDS = [ + FIELDS = [ Field(u'prefetch-size', u'long', u'long', reserved=False), Field(u'prefetch-count', u'short', u'short', reserved=False), Field(u'global', u'bit', u'bit', reserved=False), @@ -3236,15 +3320,17 @@ class BasicQos(AMQPMethodPayload): self.global_ = global_ def write_arguments(self, buf): - buf.write(struct.pack('!IHB', self.prefetch_size, self.prefetch_count, (self.global_ << 0))) - + buf.write(struct.pack('!IHB', self.prefetch_size, self.prefetch_count, + (self.global_ << 0))) + def get_size(self): return 7 @staticmethod def from_buffer(buf, start_offset): offset = start_offset - prefetch_size, prefetch_count, _bit, = struct.unpack_from('!IHB', buf, offset) + prefetch_size, prefetch_count, _bit, = struct.unpack_from('!IHB', buf, + offset) offset += 6 global_ = bool(_bit >> 0) offset += 1 @@ -3263,12 +3349,12 @@ class BasicQosOk(AMQPMethodPayload): NAME = u'basic.qos-ok' - INDEX = (60, 11) # (Class ID, Method ID) - BINARY_HEADER = b'\x00\x3C\x00\x0B' # CLASS ID + METHOD ID + INDEX = (60, 11) # (Class ID, Method ID) + BINARY_HEADER = b'\x00\x3C\x00\x0B' # CLASS ID + METHOD ID SENT_BY_CLIENT, SENT_BY_SERVER = False, True - IS_SIZE_STATIC = True # this means that argument part has always the same length + IS_SIZE_STATIC = True # this means that argument part has always the same length IS_CONTENT_STATIC = True # this means that argument part has always the same content STATIC_CONTENT = b'\x00\x00\x00\x04\x00\x3C\x00\x0B\xCE' # spans LENGTH, CLASS ID, METHOD ID, ....., FRAME_END @@ -3277,7 +3363,6 @@ class BasicQosOk(AMQPMethodPayload): Create frame basic.qos-ok """ - @staticmethod def from_buffer(buf, start_offset): offset = start_offset @@ -3293,20 +3378,20 @@ class BasicReturn(AMQPMethodPayload): reply code and text provide information about the reason that the message was undeliverable. """ - __slots__ = (u'reply_code', u'reply_text', u'exchange', u'routing_key', ) + __slots__ = (u'reply_code', u'reply_text', u'exchange', u'routing_key',) NAME = u'basic.return' - INDEX = (60, 50) # (Class ID, Method ID) - BINARY_HEADER = b'\x00\x3C\x00\x32' # CLASS ID + METHOD ID + INDEX = (60, 50) # (Class ID, Method ID) + BINARY_HEADER = b'\x00\x3C\x00\x32' # CLASS ID + METHOD ID SENT_BY_CLIENT, SENT_BY_SERVER = False, True - IS_SIZE_STATIC = False # this means that argument part has always the same length + IS_SIZE_STATIC = False # this means that argument part has always the same length IS_CONTENT_STATIC = False # this means that argument part has always the same content # See constructor pydoc for details - FIELDS = [ + FIELDS = [ Field(u'reply-code', u'reply-code', u'short', reserved=False), Field(u'reply-text', u'reply-text', u'shortstr', reserved=False), Field(u'exchange', u'exchange-name', u'shortstr', reserved=False), @@ -3338,24 +3423,25 @@ class BasicReturn(AMQPMethodPayload): buf.write(self.exchange) buf.write(struct.pack('!B', len(self.routing_key))) buf.write(self.routing_key) - + def get_size(self): - return 5 + len(self.reply_text) + len(self.exchange) + len(self.routing_key) + return 5 + len(self.reply_text) + len(self.exchange) + len( + self.routing_key) @staticmethod def from_buffer(buf, start_offset): offset = start_offset reply_code, s_len, = struct.unpack_from('!HB', buf, offset) offset += 3 - reply_text = buf[offset:offset+s_len] + reply_text = buf[offset:offset + s_len] offset += s_len s_len, = struct.unpack_from('!B', buf, offset) offset += 1 - exchange = buf[offset:offset+s_len] + exchange = buf[offset:offset + s_len] offset += s_len s_len, = struct.unpack_from('!B', buf, offset) offset += 1 - routing_key = buf[offset:offset+s_len] + routing_key = buf[offset:offset + s_len] offset += s_len return BasicReturn(reply_code, reply_text, exchange, routing_key) @@ -3368,20 +3454,20 @@ class BasicReject(AMQPMethodPayload): cancel large incoming messages, or return untreatable messages to their original queue. """ - __slots__ = (u'delivery_tag', u'requeue', ) + __slots__ = (u'delivery_tag', u'requeue',) NAME = u'basic.reject' - INDEX = (60, 90) # (Class ID, Method ID) - BINARY_HEADER = b'\x00\x3C\x00\x5A' # CLASS ID + METHOD ID + INDEX = (60, 90) # (Class ID, Method ID) + BINARY_HEADER = b'\x00\x3C\x00\x5A' # CLASS ID + METHOD ID SENT_BY_CLIENT, SENT_BY_SERVER = True, False - IS_SIZE_STATIC = True # this means that argument part has always the same length + IS_SIZE_STATIC = True # this means that argument part has always the same length IS_CONTENT_STATIC = False # this means that argument part has always the same content # See constructor pydoc for details - FIELDS = [ + FIELDS = [ Field(u'delivery-tag', u'delivery-tag', u'longlong', reserved=False), Field(u'requeue', u'bit', u'bit', reserved=False), ] @@ -3401,7 +3487,7 @@ class BasicReject(AMQPMethodPayload): def write_arguments(self, buf): buf.write(struct.pack('!QB', self.delivery_tag, (self.requeue << 0))) - + def get_size(self): return 9 @@ -3423,20 +3509,20 @@ class BasicRecoverAsync(AMQPMethodPayload): specified channel. Zero or more messages may be redelivered. This method is deprecated in favour of the synchronous Recover/Recover-Ok. """ - __slots__ = (u'requeue', ) + __slots__ = (u'requeue',) NAME = u'basic.recover-async' - INDEX = (60, 100) # (Class ID, Method ID) - BINARY_HEADER = b'\x00\x3C\x00\x64' # CLASS ID + METHOD ID + INDEX = (60, 100) # (Class ID, Method ID) + BINARY_HEADER = b'\x00\x3C\x00\x64' # CLASS ID + METHOD ID SENT_BY_CLIENT, SENT_BY_SERVER = True, False - IS_SIZE_STATIC = True # this means that argument part has always the same length + IS_SIZE_STATIC = True # this means that argument part has always the same length IS_CONTENT_STATIC = False # this means that argument part has always the same content # See constructor pydoc for details - FIELDS = [ + FIELDS = [ Field(u'requeue', u'bit', u'bit', reserved=False), ] @@ -3454,7 +3540,7 @@ class BasicRecoverAsync(AMQPMethodPayload): def write_arguments(self, buf): buf.write(struct.pack('!B', (self.requeue << 0))) - + def get_size(self): return 1 @@ -3476,20 +3562,20 @@ class BasicRecover(AMQPMethodPayload): specified channel. Zero or more messages may be redelivered. This method replaces the asynchronous Recover. """ - __slots__ = (u'requeue', ) + __slots__ = (u'requeue',) NAME = u'basic.recover' - INDEX = (60, 110) # (Class ID, Method ID) - BINARY_HEADER = b'\x00\x3C\x00\x6E' # CLASS ID + METHOD ID + INDEX = (60, 110) # (Class ID, Method ID) + BINARY_HEADER = b'\x00\x3C\x00\x6E' # CLASS ID + METHOD ID SENT_BY_CLIENT, SENT_BY_SERVER = True, False - IS_SIZE_STATIC = True # this means that argument part has always the same length + IS_SIZE_STATIC = True # this means that argument part has always the same length IS_CONTENT_STATIC = False # this means that argument part has always the same content # See constructor pydoc for details - FIELDS = [ + FIELDS = [ Field(u'requeue', u'bit', u'bit', reserved=False), ] @@ -3507,7 +3593,7 @@ class BasicRecover(AMQPMethodPayload): def write_arguments(self, buf): buf.write(struct.pack('!B', (self.requeue << 0))) - + def get_size(self): return 1 @@ -3531,12 +3617,12 @@ class BasicRecoverOk(AMQPMethodPayload): NAME = u'basic.recover-ok' - INDEX = (60, 111) # (Class ID, Method ID) - BINARY_HEADER = b'\x00\x3C\x00\x6F' # CLASS ID + METHOD ID + INDEX = (60, 111) # (Class ID, Method ID) + BINARY_HEADER = b'\x00\x3C\x00\x6F' # CLASS ID + METHOD ID SENT_BY_CLIENT, SENT_BY_SERVER = False, True - IS_SIZE_STATIC = True # this means that argument part has always the same length + IS_SIZE_STATIC = True # this means that argument part has always the same length IS_CONTENT_STATIC = True # this means that argument part has always the same content STATIC_CONTENT = b'\x00\x00\x00\x04\x00\x3C\x00\x6F\xCE' # spans LENGTH, CLASS ID, METHOD ID, ....., FRAME_END @@ -3545,7 +3631,6 @@ class BasicRecoverOk(AMQPMethodPayload): Create frame basic.recover-ok """ - @staticmethod def from_buffer(buf, start_offset): offset = start_offset @@ -3580,12 +3665,12 @@ class TxCommit(AMQPMethodPayload): NAME = u'tx.commit' - INDEX = (90, 20) # (Class ID, Method ID) - BINARY_HEADER = b'\x00\x5A\x00\x14' # CLASS ID + METHOD ID + INDEX = (90, 20) # (Class ID, Method ID) + BINARY_HEADER = b'\x00\x5A\x00\x14' # CLASS ID + METHOD ID SENT_BY_CLIENT, SENT_BY_SERVER = True, False - IS_SIZE_STATIC = True # this means that argument part has always the same length + IS_SIZE_STATIC = True # this means that argument part has always the same length IS_CONTENT_STATIC = True # this means that argument part has always the same content STATIC_CONTENT = b'\x00\x00\x00\x04\x00\x5A\x00\x14\xCE' # spans LENGTH, CLASS ID, METHOD ID, ....., FRAME_END @@ -3594,7 +3679,6 @@ class TxCommit(AMQPMethodPayload): Create frame tx.commit """ - @staticmethod def from_buffer(buf, start_offset): offset = start_offset @@ -3612,12 +3696,12 @@ class TxCommitOk(AMQPMethodPayload): NAME = u'tx.commit-ok' - INDEX = (90, 21) # (Class ID, Method ID) - BINARY_HEADER = b'\x00\x5A\x00\x15' # CLASS ID + METHOD ID + INDEX = (90, 21) # (Class ID, Method ID) + BINARY_HEADER = b'\x00\x5A\x00\x15' # CLASS ID + METHOD ID SENT_BY_CLIENT, SENT_BY_SERVER = False, True - IS_SIZE_STATIC = True # this means that argument part has always the same length + IS_SIZE_STATIC = True # this means that argument part has always the same length IS_CONTENT_STATIC = True # this means that argument part has always the same content STATIC_CONTENT = b'\x00\x00\x00\x04\x00\x5A\x00\x15\xCE' # spans LENGTH, CLASS ID, METHOD ID, ....., FRAME_END @@ -3626,7 +3710,6 @@ class TxCommitOk(AMQPMethodPayload): Create frame tx.commit-ok """ - @staticmethod def from_buffer(buf, start_offset): offset = start_offset @@ -3646,12 +3729,12 @@ class TxRollback(AMQPMethodPayload): NAME = u'tx.rollback' - INDEX = (90, 30) # (Class ID, Method ID) - BINARY_HEADER = b'\x00\x5A\x00\x1E' # CLASS ID + METHOD ID + INDEX = (90, 30) # (Class ID, Method ID) + BINARY_HEADER = b'\x00\x5A\x00\x1E' # CLASS ID + METHOD ID SENT_BY_CLIENT, SENT_BY_SERVER = True, False - IS_SIZE_STATIC = True # this means that argument part has always the same length + IS_SIZE_STATIC = True # this means that argument part has always the same length IS_CONTENT_STATIC = True # this means that argument part has always the same content STATIC_CONTENT = b'\x00\x00\x00\x04\x00\x5A\x00\x1E\xCE' # spans LENGTH, CLASS ID, METHOD ID, ....., FRAME_END @@ -3660,7 +3743,6 @@ class TxRollback(AMQPMethodPayload): Create frame tx.rollback """ - @staticmethod def from_buffer(buf, start_offset): offset = start_offset @@ -3678,12 +3760,12 @@ class TxRollbackOk(AMQPMethodPayload): NAME = u'tx.rollback-ok' - INDEX = (90, 31) # (Class ID, Method ID) - BINARY_HEADER = b'\x00\x5A\x00\x1F' # CLASS ID + METHOD ID + INDEX = (90, 31) # (Class ID, Method ID) + BINARY_HEADER = b'\x00\x5A\x00\x1F' # CLASS ID + METHOD ID SENT_BY_CLIENT, SENT_BY_SERVER = False, True - IS_SIZE_STATIC = True # this means that argument part has always the same length + IS_SIZE_STATIC = True # this means that argument part has always the same length IS_CONTENT_STATIC = True # this means that argument part has always the same content STATIC_CONTENT = b'\x00\x00\x00\x04\x00\x5A\x00\x1F\xCE' # spans LENGTH, CLASS ID, METHOD ID, ....., FRAME_END @@ -3692,7 +3774,6 @@ class TxRollbackOk(AMQPMethodPayload): Create frame tx.rollback-ok """ - @staticmethod def from_buffer(buf, start_offset): offset = start_offset @@ -3710,12 +3791,12 @@ class TxSelect(AMQPMethodPayload): NAME = u'tx.select' - INDEX = (90, 10) # (Class ID, Method ID) - BINARY_HEADER = b'\x00\x5A\x00\x0A' # CLASS ID + METHOD ID + INDEX = (90, 10) # (Class ID, Method ID) + BINARY_HEADER = b'\x00\x5A\x00\x0A' # CLASS ID + METHOD ID SENT_BY_CLIENT, SENT_BY_SERVER = True, False - IS_SIZE_STATIC = True # this means that argument part has always the same length + IS_SIZE_STATIC = True # this means that argument part has always the same length IS_CONTENT_STATIC = True # this means that argument part has always the same content STATIC_CONTENT = b'\x00\x00\x00\x04\x00\x5A\x00\x0A\xCE' # spans LENGTH, CLASS ID, METHOD ID, ....., FRAME_END @@ -3724,7 +3805,6 @@ class TxSelect(AMQPMethodPayload): Create frame tx.select """ - @staticmethod def from_buffer(buf, start_offset): offset = start_offset @@ -3742,12 +3822,12 @@ class TxSelectOk(AMQPMethodPayload): NAME = u'tx.select-ok' - INDEX = (90, 11) # (Class ID, Method ID) - BINARY_HEADER = b'\x00\x5A\x00\x0B' # CLASS ID + METHOD ID + INDEX = (90, 11) # (Class ID, Method ID) + BINARY_HEADER = b'\x00\x5A\x00\x0B' # CLASS ID + METHOD ID SENT_BY_CLIENT, SENT_BY_SERVER = False, True - IS_SIZE_STATIC = True # this means that argument part has always the same length + IS_SIZE_STATIC = True # this means that argument part has always the same length IS_CONTENT_STATIC = True # this means that argument part has always the same content STATIC_CONTENT = b'\x00\x00\x00\x04\x00\x5A\x00\x0B\xCE' # spans LENGTH, CLASS ID, METHOD ID, ....., FRAME_END @@ -3756,7 +3836,6 @@ class TxSelectOk(AMQPMethodPayload): Create frame tx.select-ok """ - @staticmethod def from_buffer(buf, start_offset): offset = start_offset @@ -3795,20 +3874,20 @@ class ConfirmSelect(AMQPMethodPayload): The client can only use this method on a non-transactional channel. """ - __slots__ = (u'nowait', ) + __slots__ = (u'nowait',) NAME = u'confirm.select' - INDEX = (85, 10) # (Class ID, Method ID) - BINARY_HEADER = b'\x00\x55\x00\x0A' # CLASS ID + METHOD ID + INDEX = (85, 10) # (Class ID, Method ID) + BINARY_HEADER = b'\x00\x55\x00\x0A' # CLASS ID + METHOD ID SENT_BY_CLIENT, SENT_BY_SERVER = True, False - IS_SIZE_STATIC = True # this means that argument part has always the same length + IS_SIZE_STATIC = True # this means that argument part has always the same length IS_CONTENT_STATIC = False # this means that argument part has always the same content # See constructor pydoc for details - FIELDS = [ + FIELDS = [ Field(u'nowait', u'bit', u'bit', reserved=False), ] @@ -3825,7 +3904,7 @@ class ConfirmSelect(AMQPMethodPayload): def write_arguments(self, buf): buf.write(struct.pack('!B', (self.nowait << 0))) - + def get_size(self): return 1 @@ -3849,12 +3928,12 @@ class ConfirmSelectOk(AMQPMethodPayload): NAME = u'confirm.select-ok' - INDEX = (85, 11) # (Class ID, Method ID) - BINARY_HEADER = b'\x00\x55\x00\x0B' # CLASS ID + METHOD ID + INDEX = (85, 11) # (Class ID, Method ID) + BINARY_HEADER = b'\x00\x55\x00\x0B' # CLASS ID + METHOD ID SENT_BY_CLIENT, SENT_BY_SERVER = False, True - IS_SIZE_STATIC = True # this means that argument part has always the same length + IS_SIZE_STATIC = True # this means that argument part has always the same length IS_CONTENT_STATIC = True # this means that argument part has always the same content STATIC_CONTENT = b'\x00\x00\x00\x04\x00\x55\x00\x0B\xCE' # spans LENGTH, CLASS ID, METHOD ID, ....., FRAME_END @@ -3863,7 +3942,6 @@ class ConfirmSelectOk(AMQPMethodPayload): Create frame confirm.select-ok """ - @staticmethod def from_buffer(buf, start_offset): offset = start_offset @@ -3935,7 +4013,6 @@ IDENT_TO_METHOD = { (50, 10): QueueDeclare, } - BINARY_HEADER_TO_METHOD = { b'\x00\x5A\x00\x15': TxCommitOk, b'\x00\x3C\x00\x64': BasicRecoverAsync, @@ -4001,7 +4078,6 @@ BINARY_HEADER_TO_METHOD = { b'\x00\x32\x00\x0A': QueueDeclare, } - CLASS_ID_TO_CONTENT_PROPERTY_LIST = { 60: BasicContentPropertyList, } @@ -4041,7 +4117,7 @@ REPLY_REASONS_FOR = { # Methods that are replies for other, ie. ConnectionOpenOk: ConnectionOpen # a method may be a reply for ONE or NONE other methods # if a method has no replies, it will have an empty list as value here -REPLIES_FOR= { +REPLIES_FOR = { BasicGetEmpty: [], BasicRecoverOk: [], BasicReturn: [], diff --git a/coolamqp/framing/field_table.py b/coolamqp/framing/field_table.py index 2c31fdec30163b7d7da9aabdd84b546625930ce9..91be67d82ad38c2e144dc783fd1a79c2d69baa7f 100644 --- a/coolamqp/framing/field_table.py +++ b/coolamqp/framing/field_table.py @@ -70,14 +70,16 @@ FIELD_TYPES = { 'd': (8, '!d'), 'D': (5, None, enframe_decimal, deframe_decimal), # decimal-value 's': ( - None, None, enframe_shortstr, deframe_shortstr, lambda val: len(val) + 1), -# shortstr + None, None, enframe_shortstr, deframe_shortstr, + lambda val: len(val) + 1), + # shortstr 'S': ( - None, None, enframe_longstr, deframe_longstr, lambda val: len(val) + 4), -# longstr + None, None, enframe_longstr, deframe_longstr, + lambda val: len(val) + 4), + # longstr 'T': (8, '!Q'), 'V': (0, None, lambda buf, v: None, lambda buf, ofs: None, 0), -# rendered as None + # rendered as None } @@ -106,7 +108,8 @@ def deframe_field_value(buf, offset): # -> (value, type), bytes_consumed opt = FIELD_TYPES[field_type] if opt[1] is not None: - field_val, = struct.unpack_from(FIELD_TYPES[field_type][1], buf, offset) + field_val, = struct.unpack_from(FIELD_TYPES[field_type][1], buf, + offset) offset += opt[0] else: field_val, delta = opt[3](buf, offset) diff --git a/coolamqp/framing/frames.py b/coolamqp/framing/frames.py index 705ee8231f5a4b0b7d9c01fa44cb3e1d325dd703..d5b8736820f25977477bf2aa474a38085583d5b0 100644 --- a/coolamqp/framing/frames.py +++ b/coolamqp/framing/frames.py @@ -71,7 +71,8 @@ class AMQPHeaderFrame(AMQPFrame): def write_to(self, buf): buf.write(struct.pack('!BHLHHQ', FRAME_HEADER, self.channel, - 12 + self.properties.get_size(), self.class_id, 0, + 12 + self.properties.get_size(), self.class_id, + 0, self.body_size)) self.properties.write_to(buf) buf.write(FRAME_END_BYTE) @@ -83,7 +84,8 @@ class AMQPHeaderFrame(AMQPFrame): payload_as_buffer, 0) properties = CLASS_ID_TO_CONTENT_PROPERTY_LIST[class_id].from_buffer( payload_as_buffer, 12) - return AMQPHeaderFrame(channel, class_id, weight, body_size, properties) + return AMQPHeaderFrame(channel, class_id, weight, body_size, + properties) def get_size(self): # frame header is always 7, frame end is 1, content header is 12 + props @@ -104,7 +106,8 @@ class AMQPBodyFrame(AMQPFrame): self.data = data def write_to(self, buf): - buf.write(struct.pack('!BHL', FRAME_BODY, self.channel, len(self.data))) + buf.write( + struct.pack('!BHL', FRAME_BODY, self.channel, len(self.data))) buf.write(self.data) buf.write(FRAME_END_BYTE) diff --git a/coolamqp/objects.py b/coolamqp/objects.py index 45e176d037400a6be399f33825b8a642bd2d679b..c6f0f3473db957867f19fe3927e5711e6c55ff87 100644 --- a/coolamqp/objects.py +++ b/coolamqp/objects.py @@ -15,6 +15,18 @@ logger = logging.getLogger(__name__) EMPTY_PROPERTIES = MessageProperties() +def toutf8(q): + if isinstance(q, six.binary_type): + q = q.decode('utf8') + return q + + +def tobytes(q): + if isinstance(q, six.text_type): + q = q.encode('utf8') + return q + + class Callable(object): """ Add a bunch of callables to one list, and just invoke'm. @@ -41,7 +53,8 @@ class Message(object): """ An AMQP message. Has a binary body, and some properties. - Properties is a highly regularized class - see coolamqp.framing.definitions.BasicContentPropertyList + Properties is a highly regularized class - see + coolamqp.framing.definitions.BasicContentPropertyList for a list of possible properties. """ @@ -51,13 +64,15 @@ class Message(object): """ Create a Message object. - Please take care with passing empty bodies, as py-amqp has some failure on it. + Please take care with passing empty bodies, as py-amqp has some + failure on it. :param body: stream of octets :type body: anything with a buffer interface :param properties: AMQP properties to be sent along. default is 'no properties at all' - You can pass a dict - it will be passed to MessageProperties, + You can pass a dict - it will be passed to + MessageProperties, but it's slow - don't do that. :type properties: MessageProperties instance, None or a dict (SLOW!) """ @@ -85,7 +100,8 @@ class ReceivedMessage(Message): It additionally has an exchange name, routing key used, it's delivery tag, and methods for ack() or nack(). - Note that if the consumer that generated this message was no_ack, .ack() and .nack() are no-ops. + Note that if the consumer that generated this message was no_ack, .ack() + and .nack() are no-ops. """ def __init__(self, body, exchange_name, routing_key, @@ -95,19 +111,22 @@ class ReceivedMessage(Message): nack=None): """ :param body: message body. A stream of octets. - :type body: str (py2) or bytes (py3) or a list of memoryviews, if particular disabled-by-default option - is turned on. + :type body: str (py2) or bytes (py3) or a list of memoryviews, if + particular disabled-by-default option is turned on. :param exchange_name: name of exchange this message was submitted to :type exchange_name: memoryview :param routing_key: routing key with which this message was sent :type routing_key: memoryview :param properties: a suitable BasicContentPropertyList subinstance. - be prepared that value of properties that are strings will be memoryviews - :param delivery_tag: delivery tag assigned by AMQP broker to confirm this message - :param ack: a callable to call when you want to ack (via basic.ack) this message. None if received - by the no-ack mechanism - :param nack: a callable to call when you want to nack (via basic.reject) this message. None if received - by the no-ack mechanism + be prepared that value of properties that are + strings will be memoryviews + :param delivery_tag: delivery tag assigned by AMQP broker to confirm + this message + :param ack: a callable to call when you want to ack (via basic.ack) + this message. None if received by the no-ack mechanism + :param nack: a callable to call when you want to nack + (via basic.reject) this message. None if received by the no-ack + mechanism """ Message.__init__(self, body, properties=properties) @@ -130,13 +149,12 @@ class Exchange(object): def __init__(self, name=u'', type=b'direct', durable=True, auto_delete=False): """ - :type name: unicode is preferred, binary type will get decoded to unicode with utf8 + :type name: unicode is preferred, binary type will get decoded to + unicode with utf8 :param type: exchange type. binary/unicode """ - self.name = name.decode('utf8') if isinstance(name, - six.binary_type) else name # must be unicode - self.type = type.encode('utf8') if isinstance(type, - six.text_type) else type # must be bytes + self.name = toutf8(name) # must be unicode + self.type = tobytes(type) # must be bytes self.durable = durable self.auto_delete = auto_delete @@ -179,8 +197,7 @@ class Queue(object): :param exclusive: Is this queue exclusive? :param auto_delete: Is this queue auto_delete ? """ - self.name = name.encode('utf8') if isinstance(name, - six.text_type) else name #: public, must be bytes + self.name = tobytes(name) #: public, must be bytes # if name is '', this will be filled in with broker-generated name upon declaration self.durable = durable self.exchange = exchange @@ -257,7 +274,7 @@ class NodeDefinition(object): (six.text_type, six.binary_type)): connstr = args[0].decode('utf8') if isinstance(args[0], six.binary_type) else \ - args[0] + args[0] # AMQP connstring if not connstr.startswith(u'amqp://'): raise ValueError(u'should begin with amqp://') @@ -281,4 +298,4 @@ class NodeDefinition(object): def __str__(self): return six.text_type( b'amqp://%s:%s@%s/%s'.encode('utf8') % ( - self.host, self.port, self.user, self.virtual_host)) + self.host, self.port, self.user, self.virtual_host)) diff --git a/coolamqp/uplink/__init__.py b/coolamqp/uplink/__init__.py index 92f6f33a19cdf9c34c37003dea7b209378c12d0c..3a33a01192f7596f08040c76a9fed3c08f2ed9ec 100644 --- a/coolamqp/uplink/__init__.py +++ b/coolamqp/uplink/__init__.py @@ -15,5 +15,6 @@ from __future__ import absolute_import, division, print_function from coolamqp.uplink.connection import Connection, HeaderOrBodyWatch, \ MethodWatch, AnyWatch, FailWatch -from coolamqp.uplink.handshake import PUBLISHER_CONFIRMS, CONSUMER_CANCEL_NOTIFY +from coolamqp.uplink.handshake import PUBLISHER_CONFIRMS, \ + CONSUMER_CANCEL_NOTIFY from coolamqp.uplink.listener import ListenerThread diff --git a/coolamqp/uplink/connection/__init__.py b/coolamqp/uplink/connection/__init__.py index 8a07f01dcff33f918aa859559d29255aec4a4e9f..47cdf5eafbaa64c6704c8e9c53d02a4598f190cb 100644 --- a/coolamqp/uplink/connection/__init__.py +++ b/coolamqp/uplink/connection/__init__.py @@ -12,7 +12,7 @@ Connection is something that can: from __future__ import absolute_import, division, print_function from coolamqp.uplink.connection.connection import Connection -from coolamqp.uplink.connection.states import ST_OFFLINE, ST_CONNECTING, \ - ST_ONLINE from coolamqp.uplink.connection.watches import FailWatch, Watch, \ HeaderOrBodyWatch, MethodWatch, AnyWatch +from coolamqp.uplink.connection.states import ST_OFFLINE, ST_CONNECTING, \ + ST_ONLINE diff --git a/coolamqp/uplink/connection/connection.py b/coolamqp/uplink/connection/connection.py index 8c8e9266a16c1480e0bd3091e4d99c36233e2e59..688c28ffac5825180133b6d1586770ac24972089 100644 --- a/coolamqp/uplink/connection/connection.py +++ b/coolamqp/uplink/connection/connection.py @@ -12,7 +12,8 @@ from coolamqp.framing.frames import AMQPMethodFrame from coolamqp.uplink.handshake import Handshaker from coolamqp.framing.definitions import ConnectionClose, ConnectionCloseOk from coolamqp.uplink.connection.watches import MethodWatch, Watch -from coolamqp.uplink.connection.states import ST_ONLINE, ST_OFFLINE, ST_CONNECTING +from coolamqp.uplink.connection.states import ST_ONLINE, ST_OFFLINE, \ + ST_CONNECTING from coolamqp.objects import Callable logger = logging.getLogger(__name__) @@ -105,7 +106,8 @@ class Connection(object): while True: try: - sock.connect((self.node_definition.host, self.node_definition.port)) + sock.connect( + (self.node_definition.host, self.node_definition.port)) except socket.error as e: time.sleep(0.5) # Connection refused? Very bad things? else: @@ -120,7 +122,8 @@ class Connection(object): on_read=self.recvf.put, on_fail=self.on_fail) self.sendf = SendingFramer(self.listener_socket.send) - self.watch_for_method(0, (ConnectionClose, ConnectionCloseOk), self.on_connection_close) + self.watch_for_method(0, (ConnectionClose, ConnectionCloseOk), + self.on_connection_close) Handshaker(self, self.node_definition, self.on_connected) @@ -169,7 +172,8 @@ class Connection(object): if isinstance(payload, ConnectionClose): self.send([AMQPMethodFrame(0, ConnectionCloseOk())]) - logger.info(u'Broker closed our connection - code %s reason %s', payload.reply_code, + logger.info(u'Broker closed our connection - code %s reason %s', + payload.reply_code, payload.reply_text.tobytes().decode('utf8')) elif isinstance(payload, ConnectionCloseOk): @@ -233,7 +237,8 @@ class Connection(object): # print('watch',watch,'was cancelled') continue - if ((not watch_triggered) or (not watch.oneshot)) and (not watch.cancelled): + if ((not watch_triggered) or (not watch.oneshot)) and ( + not watch.cancelled): # Watch remains alive if it was NOT triggered, or it's NOT a oneshot alive_watches.append(watch) @@ -260,7 +265,8 @@ class Connection(object): # print('any watch', watch, 'was cancelled') continue - if ((not watch_triggered) or (not watch.oneshot)) and (not watch.cancelled): + if ((not watch_triggered) or (not watch.oneshot)) and ( + not watch.cancelled): # Watch remains alive if it was NOT triggered, or it's NOT a oneshot alive_watches.append(watch) @@ -315,7 +321,8 @@ class Connection(object): self.watch(mw) return mw - def method_and_watch(self, channel_id, method_payload, method_or_methods, callback): + def method_and_watch(self, channel_id, method_payload, method_or_methods, + callback): """ A syntactic sugar for diff --git a/coolamqp/uplink/connection/recv_framer.py b/coolamqp/uplink/connection/recv_framer.py index 5d41cf4ae581f079cd2628792d6b6abca396939b..4cdcb72df60092aa4c3c132392e0d1d1c7fc1dfb 100644 --- a/coolamqp/uplink/connection/recv_framer.py +++ b/coolamqp/uplink/connection/recv_framer.py @@ -67,7 +67,7 @@ class ReceivingFramer(object): def _extract(self, up_to): # return up to up_to bytes from current chunk, switch if necessary assert self.total_data_len >= up_to, 'Tried to extract %s but %s remaining' % ( - up_to, self.total_data_len) + up_to, self.total_data_len) if up_to >= len(self.chunks[0]): q = self.chunks.popleft() else: @@ -76,7 +76,7 @@ class ReceivingFramer(object): self.total_data_len -= len(q) assert len(q) <= up_to, 'extracted %s but %s was requested' % ( - len(q), up_to) + len(q), up_to) return q def _statemachine(self): @@ -88,14 +88,14 @@ class ReceivingFramer(object): self.frame_type = ord(self._extract(1)[0]) if self.frame_type not in ( - FRAME_HEARTBEAT, FRAME_HEADER, FRAME_METHOD, FRAME_BODY): + FRAME_HEARTBEAT, FRAME_HEADER, FRAME_METHOD, FRAME_BODY): raise ValueError('Invalid frame') return True # state rule 2 elif (self.frame_type == FRAME_HEARTBEAT) and ( - self.total_data_len >= AMQPHeartbeatFrame.LENGTH - 1): + self.total_data_len >= AMQPHeartbeatFrame.LENGTH - 1): data = b'' while len(data) < AMQPHeartbeatFrame.LENGTH - 1: data = data + self._extract( @@ -112,7 +112,8 @@ class ReceivingFramer(object): # state rule 3 elif (self.frame_type != FRAME_HEARTBEAT) and ( - self.frame_type is not None) and (self.frame_size is None) and ( + self.frame_type is not None) and ( + self.frame_size is None) and ( self.total_data_len > 6): hdr = b'' while len(hdr) < 6: @@ -124,7 +125,7 @@ class ReceivingFramer(object): # state rule 4 elif (self.frame_size is not None) and ( - self.total_data_len >= (self.frame_size + 1)): + self.total_data_len >= (self.frame_size + 1)): if len(self.chunks[0]) >= self.frame_size: # We can subslice it - it's very fast diff --git a/coolamqp/uplink/handshake.py b/coolamqp/uplink/handshake.py index f2e0d693cd26220584190d604ad745512a196c59..f1829f5bb34f942bb327544b4ae65035615dbac1 100644 --- a/coolamqp/uplink/handshake.py +++ b/coolamqp/uplink/handshake.py @@ -27,8 +27,8 @@ CLIENT_DATA = [ (b'copyright', (b'Copyright (C) 2016-2017 DMS Serwis', 'S')), ( b'information', ( - b'Licensed under the MIT License.\nSee https://github.com/smok-serwis/coolamqp for details', - 'S')), + b'Licensed under the MIT License.\nSee https://github.com/smok-serwis/coolamqp for details', + 'S')), (b'capabilities', ([(capa, (True, 't')) for capa in SUPPORTED_EXTENSIONS], 'F')), ] @@ -102,7 +102,7 @@ class Handshaker(object): self.connection.frame_max = payload.frame_max self.connection.heartbeat = min(payload.heartbeat, self.heartbeat) for channel in six.moves.xrange(1, ( - 65535 if payload.channel_max == 0 else payload.channel_max) + 1): + 65535 if payload.channel_max == 0 else payload.channel_max) + 1): self.connection.free_channels.append(channel) self.connection.watch_for_method(0, ConnectionOpenOk, diff --git a/coolamqp/uplink/heartbeat.py b/coolamqp/uplink/heartbeat.py index 4cb5a7aa0592104d732579ff9a8f72f6050764e8..66b0b7b591da8eeaa39e92b9c5053a4718858312 100644 --- a/coolamqp/uplink/heartbeat.py +++ b/coolamqp/uplink/heartbeat.py @@ -44,7 +44,7 @@ class Heartbeater(object): self.connection.send([AMQPHeartbeatFrame()], priority=True) if ( - monotonic.monotonic() - self.last_heartbeat_on) > 2 * self.heartbeat_interval: + monotonic.monotonic() - self.last_heartbeat_on) > 2 * self.heartbeat_interval: # closing because of heartbeat self.connection.send(None) diff --git a/docs/index.rst b/docs/index.rst index 3fdbdb2ea98cc4cb85404ad04ff5127cc146e789..55c87213879ea90ee040a9c965f75d6e9c6870c3 100644 --- a/docs/index.rst +++ b/docs/index.rst @@ -2,11 +2,11 @@ Welcome to CoolAMQP's documentation! ==================================== .. toctree:: - :maxdepth: 2 - :caption: Contents: +:maxdepth: 2 + :caption: Contents: - tutorial - caveats + tutorial + caveats Indices and tables diff --git a/resources/amqp0-9-1.extended.xml b/resources/amqp0-9-1.extended.xml index 7ba2d60d3bab985e47c48fa25e2b219bcbac1786..f7aca67cdaba8b9765f8636a86d1445cb2f5c308 100644 --- a/resources/amqp0-9-1.extended.xml +++ b/resources/amqp0-9-1.extended.xml @@ -156,3192 +156,3849 @@ --> -<amqp major = "0" minor = "9" revision = "1" - port = "5672" comment = "AMQ Protocol version 0-9-1"> - <!-- +<amqp major="0" minor="9" revision="1" + port="5672" comment="AMQ Protocol version 0-9-1"> + <!-- ====================================================== == CONSTANTS ====================================================== --> - <!-- Frame types --> - <constant name = "frame-method" value = "1" /> - <constant name = "frame-header" value = "2" /> - <constant name = "frame-body" value = "3" /> - <constant name = "frame-heartbeat" value = "8" /> - - <!-- Protocol constants --> - <constant name = "frame-min-size" value = "4096" /> - <constant name = "frame-end" value = "206" /> - - <!-- Reply codes --> - <constant name = "reply-success" value = "200"> - <doc> - Indicates that the method completed successfully. This reply code is - reserved for future use - the current protocol design does not use positive - confirmation and reply codes are sent only in case of an error. - </doc> - </constant> - - <constant name = "content-too-large" value = "311" class = "soft-error"> - <doc> - The client attempted to transfer content larger than the server could accept - at the present time. The client may retry at a later time. - </doc> - </constant> - - <constant name = "no-consumers" value = "313" class = "soft-error"> - <doc> - When the exchange cannot deliver to a consumer when the immediate flag is - set. As a result of pending data on the queue or the absence of any - consumers of the queue. - </doc> - </constant> - - <constant name = "connection-forced" value = "320" class = "hard-error"> - <doc> - An operator intervened to close the connection for some reason. The client - may retry at some later date. - </doc> - </constant> - - <constant name = "invalid-path" value = "402" class = "hard-error"> - <doc> - The client tried to work with an unknown virtual host. - </doc> - </constant> - - <constant name = "access-refused" value = "403" class = "soft-error"> - <doc> - The client attempted to work with a server entity to which it has no - access due to security settings. - </doc> - </constant> - - <constant name = "not-found" value = "404" class = "soft-error"> - <doc> - The client attempted to work with a server entity that does not exist. - </doc> - </constant> - - <constant name = "resource-locked" value = "405" class = "soft-error"> - <doc> - The client attempted to work with a server entity to which it has no - access because another client is working with it. - </doc> - </constant> - - <constant name = "precondition-failed" value = "406" class = "soft-error"> - <doc> - The client requested a method that was not allowed because some precondition - failed. - </doc> - </constant> - - <constant name = "frame-error" value = "501" class = "hard-error"> - <doc> - The sender sent a malformed frame that the recipient could not decode. - This strongly implies a programming error in the sending peer. - </doc> - </constant> - - <constant name = "syntax-error" value = "502" class = "hard-error"> - <doc> - The sender sent a frame that contained illegal values for one or more - fields. This strongly implies a programming error in the sending peer. - </doc> - </constant> - - <constant name = "command-invalid" value = "503" class = "hard-error"> - <doc> - The client sent an invalid sequence of frames, attempting to perform an - operation that was considered invalid by the server. This usually implies - a programming error in the client. - </doc> - </constant> - - <constant name = "channel-error" value = "504" class = "hard-error"> - <doc> - The client attempted to work with a channel that had not been correctly - opened. This most likely indicates a fault in the client layer. - </doc> - </constant> - - <constant name = "unexpected-frame" value = "505" class = "hard-error"> - <doc> - The peer sent a frame that was not expected, usually in the context of - a content header and body. This strongly indicates a fault in the peer's - content processing. - </doc> - </constant> - - <constant name = "resource-error" value = "506" class = "hard-error"> - <doc> - The server could not complete the method because it lacked sufficient - resources. This may be due to the client creating too many of some type - of entity. - </doc> - </constant> - - <constant name = "not-allowed" value = "530" class = "hard-error"> - <doc> - The client tried to work with some entity in a manner that is prohibited - by the server, due to security settings or by some other criteria. - </doc> - </constant> - - <constant name = "not-implemented" value = "540" class = "hard-error"> - <doc> - The client tried to use functionality that is not implemented in the - server. - </doc> - </constant> - - <constant name = "internal-error" value = "541" class = "hard-error"> - <doc> - The server could not complete the method because of an internal error. - The server may require intervention by an operator in order to resume - normal operations. - </doc> - </constant> - - <!-- - ====================================================== - == DOMAIN TYPES - ====================================================== - --> - - <domain name = "class-id" type = "short" /> - - <domain name = "consumer-tag" type = "shortstr" label = "consumer tag"> - <doc> - Identifier for the consumer, valid within the current channel. - </doc> - </domain> - - <domain name = "delivery-tag" type = "longlong" label = "server-assigned delivery tag"> - <doc> - The server-assigned and channel-specific delivery tag - </doc> - <rule name = "channel-local"> - <doc> - The delivery tag is valid only within the channel from which the message was - received. I.e. a client MUST NOT receive a message on one channel and then - acknowledge it on another. - </doc> - </rule> - <rule name = "non-zero"> - <doc> - The server MUST NOT use a zero value for delivery tags. Zero is reserved - for client use, meaning "all messages so far received". - </doc> - </rule> - </domain> - - <domain name = "exchange-name" type = "shortstr" label = "exchange name"> - <doc> - The exchange name is a client-selected string that identifies the exchange for - publish methods. - </doc> - <assert check = "length" value = "127" /> - <assert check = "regexp" value = "^[a-zA-Z0-9-_.:]*$" /> - </domain> - - <domain name = "method-id" type = "short" /> - - <domain name = "no-ack" type = "bit" label = "no acknowledgement needed"> - <doc> - If this field is set the server does not expect acknowledgements for - messages. That is, when a message is delivered to the client the server - assumes the delivery will succeed and immediately dequeues it. This - functionality may increase performance but at the cost of reliability. - Messages can get lost if a client dies before they are delivered to the - application. - </doc> - </domain> - - <domain name = "no-local" type = "bit" label = "do not deliver own messages"> - <doc> - If the no-local field is set the server will not send messages to the connection that - published them. - </doc> - </domain> - - <domain name = "no-wait" type = "bit" label = "do not send reply method"> - <doc> - If set, the server will not respond to the method. The client should not wait - for a reply method. If the server could not complete the method it will raise a - channel or connection exception. - </doc> - </domain> - - <domain name = "path" type = "shortstr"> - <doc> - Unconstrained. - </doc> - <assert check = "notnull" /> - <assert check = "length" value = "127" /> - </domain> - - <domain name = "peer-properties" type = "table"> - <doc> - This table provides a set of peer properties, used for identification, debugging, - and general information. - </doc> - </domain> - - <domain name = "queue-name" type = "shortstr" label = "queue name"> - <doc> - The queue name identifies the queue within the vhost. In methods where the queue - name may be blank, and that has no specific significance, this refers to the - 'current' queue for the channel, meaning the last queue that the client declared - on the channel. If the client did not declare a queue, and the method needs a - queue name, this will result in a 502 (syntax error) channel exception. - </doc> - <assert check = "length" value = "127" /> - <assert check = "regexp" value = "^[a-zA-Z0-9-_.:]*$" /> - </domain> - - <domain name = "redelivered" type = "bit" label = "message is being redelivered"> - <doc> - This indicates that the message has been previously delivered to this or - another client. - </doc> - <rule name = "implementation"> - <doc> - The server SHOULD try to signal redelivered messages when it can. When - redelivering a message that was not successfully acknowledged, the server - SHOULD deliver it to the original client if possible. - </doc> - <doc type = "scenario"> - Declare a shared queue and publish a message to the queue. Consume the - message using explicit acknowledgements, but do not acknowledge the - message. Close the connection, reconnect, and consume from the queue - again. The message should arrive with the redelivered flag set. - </doc> - </rule> - <rule name = "hinting"> - <doc> - The client MUST NOT rely on the redelivered field but should take it as a - hint that the message may already have been processed. A fully robust - client must be able to track duplicate received messages on non-transacted, - and locally-transacted channels. - </doc> - </rule> - </domain> - - <domain name = "message-count" type = "long" label = "number of messages in queue"> - <doc> - The number of messages in the queue, which will be zero for newly-declared - queues. This is the number of messages present in the queue, and committed - if the channel on which they were published is transacted, that are not - waiting acknowledgement. - </doc> - </domain> - - <domain name = "reply-code" type = "short" label = "reply code from server"> - <doc> - The reply code. The AMQ reply codes are defined as constants at the start - of this formal specification. - </doc> - <assert check = "notnull" /> - </domain> - - <domain name = "reply-text" type = "shortstr" label = "localised reply text"> - <doc> - The localised reply text. This text can be logged as an aid to resolving - issues. - </doc> - <assert check = "notnull" /> - </domain> - - <!-- Elementary domains --> - <domain name = "bit" type = "bit" label = "single bit" /> - <domain name = "octet" type = "octet" label = "single octet" /> - <domain name = "short" type = "short" label = "16-bit integer" /> - <domain name = "long" type = "long" label = "32-bit integer" /> - <domain name = "longlong" type = "longlong" label = "64-bit integer" /> - <domain name = "shortstr" type = "shortstr" label = "short string" /> - <domain name = "longstr" type = "longstr" label = "long string" /> - <domain name = "timestamp" type = "timestamp" label = "64-bit timestamp" /> - <domain name = "table" type = "table" label = "field table" /> - - <!-- == CONNECTION ======================================================= --> - - <class name = "connection" handler = "connection" index = "10" label = "work with socket connections"> - <doc> - The connection class provides methods for a client to establish a network connection to - a server, and for both peers to operate the connection thereafter. - </doc> - - <doc type = "grammar"> - connection = open-connection *use-connection close-connection - open-connection = C:protocol-header - S:START C:START-OK - *challenge - S:TUNE C:TUNE-OK - C:OPEN S:OPEN-OK - challenge = S:SECURE C:SECURE-OK - use-connection = *channel - close-connection = C:CLOSE S:CLOSE-OK - / S:CLOSE C:CLOSE-OK - </doc> - - <chassis name = "server" implement = "MUST" /> - <chassis name = "client" implement = "MUST" /> - - <!-- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - --> - - <method name = "start" synchronous = "1" index = "10" label = "start connection negotiation"> - <doc> - This method starts the connection negotiation process by telling the client the - protocol version that the server proposes, along with a list of security mechanisms - which the client can use for authentication. - </doc> - - <rule name = "protocol-name"> - <doc> - If the server cannot support the protocol specified in the protocol header, - it MUST respond with a valid protocol header and then close the socket - connection. - </doc> - <doc type = "scenario"> - The client sends a protocol header containing an invalid protocol name. - The server MUST respond by sending a valid protocol header and then closing - the connection. - </doc> - </rule> - <rule name = "server-support"> - <doc> - The server MUST provide a protocol version that is lower than or equal to - that requested by the client in the protocol header. - </doc> - <doc type = "scenario"> - The client requests a protocol version that is higher than any valid - implementation, e.g. 2.0. The server must respond with a protocol header - indicating its supported protocol version, e.g. 1.0. - </doc> - </rule> - <rule name = "client-support"> - <doc> - If the client cannot handle the protocol version suggested by the server - it MUST close the socket connection without sending any further data. - </doc> - <doc type = "scenario"> - The server sends a protocol version that is lower than any valid - implementation, e.g. 0.1. The client must respond by closing the - connection without sending any further data. - </doc> - </rule> - - <chassis name = "client" implement = "MUST" /> - <response name = "start-ok" /> - - <field name = "version-major" domain = "octet" label = "protocol major version"> - <doc> - The major version number can take any value from 0 to 99 as defined in the - AMQP specification. - </doc> - </field> - - <field name = "version-minor" domain = "octet" label = "protocol minor version"> - <doc> - The minor version number can take any value from 0 to 99 as defined in the - AMQP specification. - </doc> - </field> - - <field name = "server-properties" domain = "peer-properties" label = "server properties"> - <rule name = "required-fields"> - <doc> - The properties SHOULD contain at least these fields: "host", specifying the - server host name or address, "product", giving the name of the server product, - "version", giving the name of the server version, "platform", giving the name - of the operating system, "copyright", if appropriate, and "information", giving - other general information. - </doc> - <doc type = "scenario"> - Client connects to server and inspects the server properties. It checks for - the presence of the required fields. - </doc> - </rule> - </field> - - <field name = "mechanisms" domain = "longstr" label = "available security mechanisms"> - <doc> - A list of the security mechanisms that the server supports, delimited by spaces. - </doc> - <assert check = "notnull" /> - </field> - - <field name = "locales" domain = "longstr" label = "available message locales"> - <doc> - A list of the message locales that the server supports, delimited by spaces. The - locale defines the language in which the server will send reply texts. - </doc> - <rule name = "required-support"> - <doc> - The server MUST support at least the en_US locale. - </doc> - <doc type = "scenario"> - Client connects to server and inspects the locales field. It checks for - the presence of the required locale(s). - </doc> - </rule> - <assert check = "notnull" /> - </field> - </method> - - <method name = "start-ok" synchronous = "1" index = "11" - label = "select security mechanism and locale"> - <doc> - This method selects a SASL security mechanism. - </doc> - - <chassis name = "server" implement = "MUST" /> - - <field name = "client-properties" domain = "peer-properties" label = "client properties"> - <rule name = "required-fields"> - <!-- This rule is not testable from the client side --> - <doc> - The properties SHOULD contain at least these fields: "product", giving the name - of the client product, "version", giving the name of the client version, "platform", - giving the name of the operating system, "copyright", if appropriate, and - "information", giving other general information. - </doc> - </rule> - </field> - - <field name = "mechanism" domain = "shortstr" label = "selected security mechanism"> - <doc> - A single security mechanisms selected by the client, which must be one of those - specified by the server. - </doc> - <rule name = "security"> - <doc> - The client SHOULD authenticate using the highest-level security profile it - can handle from the list provided by the server. - </doc> - </rule> - <rule name = "validity"> - <doc> - If the mechanism field does not contain one of the security mechanisms - proposed by the server in the Start method, the server MUST close the - connection without sending any further data. - </doc> - <doc type = "scenario"> - Client connects to server and sends an invalid security mechanism. The - server must respond by closing the connection (a socket close, with no - connection close negotiation). - </doc> - </rule> - <assert check = "notnull" /> - </field> - - <field name = "response" domain = "longstr" label = "security response data"> - <doc> - A block of opaque data passed to the security mechanism. The contents of this - data are defined by the SASL security mechanism. - </doc> - <assert check = "notnull" /> - </field> - - <field name = "locale" domain = "shortstr" label = "selected message locale"> - <doc> - A single message locale selected by the client, which must be one of those - specified by the server. - </doc> - <assert check = "notnull" /> - </field> - </method> - - <!-- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - --> - - <method name = "secure" synchronous = "1" index = "20" label = "security mechanism challenge"> - <doc> - The SASL protocol works by exchanging challenges and responses until both peers have - received sufficient information to authenticate each other. This method challenges - the client to provide more information. - </doc> - - <chassis name = "client" implement = "MUST" /> - <response name = "secure-ok" /> - - <field name = "challenge" domain = "longstr" label = "security challenge data"> - <doc> - Challenge information, a block of opaque binary data passed to the security - mechanism. - </doc> - </field> - </method> - - <method name = "secure-ok" synchronous = "1" index = "21" label = "security mechanism response"> - <doc> - This method attempts to authenticate, passing a block of SASL data for the security - mechanism at the server side. - </doc> - - <chassis name = "server" implement = "MUST" /> - - <field name = "response" domain = "longstr" label = "security response data"> - <doc> - A block of opaque data passed to the security mechanism. The contents of this - data are defined by the SASL security mechanism. - </doc> - <assert check = "notnull" /> - </field> - </method> - - <!-- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - --> - - <method name = "tune" synchronous = "1" index = "30" - label = "propose connection tuning parameters"> - <doc> - This method proposes a set of connection configuration values to the client. The - client can accept and/or adjust these. - </doc> - - <chassis name = "client" implement = "MUST" /> + <!-- Frame types --> + <constant name="frame-method" value="1"/> + <constant name="frame-header" value="2"/> + <constant name="frame-body" value="3"/> + <constant name="frame-heartbeat" value="8"/> - <response name = "tune-ok" /> + <!-- Protocol constants --> + <constant name="frame-min-size" value="4096"/> + <constant name="frame-end" value="206"/> - <field name = "channel-max" domain = "short" label = "proposed maximum channels"> + <!-- Reply codes --> + <constant name="reply-success" value="200"> <doc> - Specifies highest channel number that the server permits. Usable channel numbers - are in the range 1..channel-max. Zero indicates no specified limit. + Indicates that the method completed successfully. This reply code is + reserved for future use - the current protocol design does not use + positive + confirmation and reply codes are sent only in case of an error. </doc> - </field> + </constant> - <field name = "frame-max" domain = "long" label = "proposed maximum frame size"> + <constant name="content-too-large" value="311" class="soft-error"> <doc> - The largest frame size that the server proposes for the connection, including - frame header and end-byte. The client can negotiate a lower value. Zero means - that the server does not impose any specific limit but may reject very large - frames if it cannot allocate resources for them. + The client attempted to transfer content larger than the server + could accept + at the present time. The client may retry at a later time. </doc> - <rule name = "minimum"> - <doc> - Until the frame-max has been negotiated, both peers MUST accept frames of up - to frame-min-size octets large, and the minimum negotiated value for frame-max - is also frame-min-size. - </doc> - <doc type = "scenario"> - Client connects to server and sends a large properties field, creating a frame - of frame-min-size octets. The server must accept this frame. - </doc> - </rule> - </field> + </constant> - <field name = "heartbeat" domain = "short" label = "desired heartbeat delay"> + <constant name="no-consumers" value="313" class="soft-error"> <doc> - The delay, in seconds, of the connection heartbeat that the server wants. - Zero means the server does not want a heartbeat. + When the exchange cannot deliver to a consumer when the immediate + flag is + set. As a result of pending data on the queue or the absence of any + consumers of the queue. </doc> - </field> - </method> - - <method name = "tune-ok" synchronous = "1" index = "31" - label = "negotiate connection tuning parameters"> - <doc> - This method sends the client's connection tuning parameters to the server. - Certain fields are negotiated, others provide capability information. - </doc> - - <chassis name = "server" implement = "MUST" /> + </constant> - <field name = "channel-max" domain = "short" label = "negotiated maximum channels"> + <constant name="connection-forced" value="320" class="hard-error"> <doc> - The maximum total number of channels that the client will use per connection. + An operator intervened to close the connection for some reason. The + client + may retry at some later date. </doc> - <rule name = "upper-limit"> - <doc> - If the client specifies a channel max that is higher than the value provided - by the server, the server MUST close the connection without attempting a - negotiated close. The server may report the error in some fashion to assist - implementors. - </doc> - </rule> - <assert check = "notnull" /> - <assert check = "le" method = "tune" field = "channel-max" /> - </field> + </constant> - <field name = "frame-max" domain = "long" label = "negotiated maximum frame size"> + <constant name="invalid-path" value="402" class="hard-error"> <doc> - The largest frame size that the client and server will use for the connection. - Zero means that the client does not impose any specific limit but may reject - very large frames if it cannot allocate resources for them. Note that the - frame-max limit applies principally to content frames, where large contents can - be broken into frames of arbitrary size. + The client tried to work with an unknown virtual host. </doc> - <rule name = "minimum"> - <doc> - Until the frame-max has been negotiated, both peers MUST accept frames of up - to frame-min-size octets large, and the minimum negotiated value for frame-max - is also frame-min-size. - </doc> - </rule> - <rule name = "upper-limit"> - <doc> - If the client specifies a frame max that is higher than the value provided - by the server, the server MUST close the connection without attempting a - negotiated close. The server may report the error in some fashion to assist - implementors. - </doc> - </rule> - </field> + </constant> - <field name = "heartbeat" domain = "short" label = "desired heartbeat delay"> + <constant name="access-refused" value="403" class="soft-error"> <doc> - The delay, in seconds, of the connection heartbeat that the client wants. Zero - means the client does not want a heartbeat. + The client attempted to work with a server entity to which it has no + access due to security settings. </doc> - </field> - </method> - - <!-- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - --> - - <method name = "open" synchronous = "1" index = "40" label = "open connection to virtual host"> - <doc> - This method opens a connection to a virtual host, which is a collection of - resources, and acts to separate multiple application domains within a server. - The server may apply arbitrary limits per virtual host, such as the number - of each type of entity that may be used, per connection and/or in total. - </doc> - - <chassis name = "server" implement = "MUST" /> - <response name = "open-ok" /> + </constant> - <field name = "virtual-host" domain = "path" label = "virtual host name"> + <constant name="not-found" value="404" class="soft-error"> <doc> - The name of the virtual host to work with. + The client attempted to work with a server entity that does not + exist. </doc> - <rule name = "separation"> - <doc> - If the server supports multiple virtual hosts, it MUST enforce a full - separation of exchanges, queues, and all associated entities per virtual - host. An application, connected to a specific virtual host, MUST NOT be able - to access resources of another virtual host. - </doc> - </rule> - <rule name = "security"> - <doc> - The server SHOULD verify that the client has permission to access the - specified virtual host. - </doc> - </rule> - </field> - <!-- Deprecated: "capabilities", must be zero --> - <field name = "reserved-1" type = "shortstr" reserved = "1" /> - <!-- Deprecated: "insist", must be zero --> - <field name = "reserved-2" type = "bit" reserved = "1" /> - </method> - - <method name = "open-ok" synchronous = "1" index = "41" label = "signal that connection is ready"> - <doc> - This method signals to the client that the connection is ready for use. - </doc> - <chassis name = "client" implement = "MUST" /> - <!-- Deprecated: "known-hosts", must be zero --> - <field name = "reserved-1" type = "shortstr" reserved = "1" /> - </method> - - <!-- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - --> - - <method name = "close" synchronous = "1" index = "50" label = "request a connection close"> - <doc> - This method indicates that the sender wants to close the connection. This may be - due to internal conditions (e.g. a forced shut-down) or due to an error handling - a specific method, i.e. an exception. When a close is due to an exception, the - sender provides the class and method id of the method which caused the exception. - </doc> - <rule name = "stability"> - <doc> - After sending this method, any received methods except Close and Close-OK MUST - be discarded. The response to receiving a Close after sending Close must be to - send Close-Ok. - </doc> - </rule> + </constant> - <chassis name = "client" implement = "MUST" /> - <chassis name = "server" implement = "MUST" /> - <response name = "close-ok" /> - - <field name = "reply-code" domain = "reply-code" /> - <field name = "reply-text" domain = "reply-text" /> - - <field name = "class-id" domain = "class-id" label = "failing method class"> + <constant name="resource-locked" value="405" class="soft-error"> <doc> - When the close is provoked by a method exception, this is the class of the - method. + The client attempted to work with a server entity to which it has no + access because another client is working with it. </doc> - </field> + </constant> - <field name = "method-id" domain = "method-id" label = "failing method ID"> - <doc> - When the close is provoked by a method exception, this is the ID of the method. - </doc> - </field> - </method> - - <method name = "close-ok" synchronous = "1" index = "51" label = "confirm a connection close"> - <doc> - This method confirms a Connection.Close method and tells the recipient that it is - safe to release resources for the connection and close the socket. - </doc> - <rule name = "reporting"> - <doc> - A peer that detects a socket closure without having received a Close-Ok - handshake method SHOULD log the error. - </doc> - </rule> - <chassis name = "client" implement = "MUST" /> - <chassis name = "server" implement = "MUST" /> - </method> - - <method name = "blocked" index = "60"> - <doc> - This method indicates that a connection has been blocked - and does not accept new publishes. - </doc> - <chassis name = "server" implement = "MUST"/> - <chassis name = "client" implement = "MUST"/> - <field name = "reason" domain = "shortstr" /> - </method> - <method name = "unblocked" index = "61"> - <doc> - This method indicates that a connection has been unblocked - and now accepts publishes. - </doc> - <chassis name = "server" implement = "MUST"/> - <chassis name = "client" implement = "MUST"/> - </method> - </class> - - <!-- == CHANNEL ========================================================== --> - - <class name = "channel" handler = "channel" index = "20" label = "work with channels"> - <doc> - The channel class provides methods for a client to establish a channel to a - server and for both peers to operate the channel thereafter. - </doc> - - <doc type = "grammar"> - channel = open-channel *use-channel close-channel - open-channel = C:OPEN S:OPEN-OK - use-channel = C:FLOW S:FLOW-OK - / S:FLOW C:FLOW-OK - / functional-class - close-channel = C:CLOSE S:CLOSE-OK - / S:CLOSE C:CLOSE-OK - </doc> - - <chassis name = "server" implement = "MUST" /> - <chassis name = "client" implement = "MUST" /> - - <!-- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - --> - - <method name = "open" synchronous = "1" index = "10" label = "open a channel for use"> - <doc> - This method opens a channel to the server. - </doc> - <rule name = "state" on-failure = "channel-error"> - <doc> - The client MUST NOT use this method on an already-opened channel. - </doc> - <doc type = "scenario"> - Client opens a channel and then reopens the same channel. - </doc> - </rule> - <chassis name = "server" implement = "MUST" /> - <response name = "open-ok" /> - <!-- Deprecated: "out-of-band", must be zero --> - <field name = "reserved-1" type = "shortstr" reserved = "1" /> - </method> - - <method name = "open-ok" synchronous = "1" index = "11" label = "signal that the channel is ready"> - <doc> - This method signals to the client that the channel is ready for use. - </doc> - <chassis name = "client" implement = "MUST" /> - <!-- Deprecated: "channel-id", must be zero --> - <field name = "reserved-1" type = "longstr" reserved = "1" /> - </method> - - <!-- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - --> - - <method name = "flow" synchronous = "1" index = "20" label = "enable/disable flow from peer"> - <doc> - This method asks the peer to pause or restart the flow of content data sent by - a consumer. This is a simple flow-control mechanism that a peer can use to avoid - overflowing its queues or otherwise finding itself receiving more messages than - it can process. Note that this method is not intended for window control. It does - not affect contents returned by Basic.Get-Ok methods. - </doc> - - <rule name = "initial-state"> + <constant name="precondition-failed" value="406" class="soft-error"> <doc> - When a new channel is opened, it is active (flow is active). Some applications - assume that channels are inactive until started. To emulate this behaviour a - client MAY open the channel, then pause it. + The client requested a method that was not allowed because some + precondition + failed. </doc> - </rule> + </constant> - <rule name = "bidirectional"> + <constant name="frame-error" value="501" class="hard-error"> <doc> - When sending content frames, a peer SHOULD monitor the channel for incoming - methods and respond to a Channel.Flow as rapidly as possible. + The sender sent a malformed frame that the recipient could not + decode. + This strongly implies a programming error in the sending peer. </doc> - </rule> + </constant> - <rule name = "throttling"> + <constant name="syntax-error" value="502" class="hard-error"> <doc> - A peer MAY use the Channel.Flow method to throttle incoming content data for - internal reasons, for example, when exchanging data over a slower connection. + The sender sent a frame that contained illegal values for one or + more + fields. This strongly implies a programming error in the sending + peer. </doc> - </rule> + </constant> - <rule name = "expected-behaviour"> + <constant name="command-invalid" value="503" class="hard-error"> <doc> - The peer that requests a Channel.Flow method MAY disconnect and/or ban a peer - that does not respect the request. This is to prevent badly-behaved clients - from overwhelming a server. + The client sent an invalid sequence of frames, attempting to perform + an + operation that was considered invalid by the server. This usually + implies + a programming error in the client. </doc> - </rule> + </constant> - <chassis name = "server" implement = "MUST" /> - <chassis name = "client" implement = "MUST" /> - - <response name = "flow-ok" /> - - <field name = "active" domain = "bit" label = "start/stop content frames"> - <doc> - If 1, the peer starts sending content frames. If 0, the peer stops sending - content frames. - </doc> - </field> - </method> - - <method name = "flow-ok" index = "21" label = "confirm a flow method"> - <doc> - Confirms to the peer that a flow command was received and processed. - </doc> - <chassis name = "server" implement = "MUST" /> - <chassis name = "client" implement = "MUST" /> - <field name = "active" domain = "bit" label = "current flow setting"> + <constant name="channel-error" value="504" class="hard-error"> <doc> - Confirms the setting of the processed flow method: 1 means the peer will start - sending or continue to send content frames; 0 means it will not. + The client attempted to work with a channel that had not been + correctly + opened. This most likely indicates a fault in the client layer. </doc> - </field> - </method> - - <!-- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - --> - - <method name = "close" synchronous = "1" index = "40" label = "request a channel close"> - <doc> - This method indicates that the sender wants to close the channel. This may be due to - internal conditions (e.g. a forced shut-down) or due to an error handling a specific - method, i.e. an exception. When a close is due to an exception, the sender provides - the class and method id of the method which caused the exception. - </doc> - <rule name = "stability"> - <doc> - After sending this method, any received methods except Close and Close-OK MUST - be discarded. The response to receiving a Close after sending Close must be to - send Close-Ok. - </doc> - </rule> - - <chassis name = "client" implement = "MUST" /> - <chassis name = "server" implement = "MUST" /> - <response name = "close-ok" /> + </constant> - <field name = "reply-code" domain = "reply-code" /> - <field name = "reply-text" domain = "reply-text" /> - - <field name = "class-id" domain = "class-id" label = "failing method class"> + <constant name="unexpected-frame" value="505" class="hard-error"> <doc> - When the close is provoked by a method exception, this is the class of the - method. + The peer sent a frame that was not expected, usually in the context + of + a content header and body. This strongly indicates a fault in the + peer's + content processing. </doc> - </field> + </constant> - <field name = "method-id" domain = "method-id" label = "failing method ID"> - <doc> - When the close is provoked by a method exception, this is the ID of the method. - </doc> - </field> - </method> - - <method name = "close-ok" synchronous = "1" index = "41" label = "confirm a channel close"> - <doc> - This method confirms a Channel.Close method and tells the recipient that it is safe - to release resources for the channel. - </doc> - <rule name = "reporting"> + <constant name="resource-error" value="506" class="hard-error"> <doc> - A peer that detects a socket closure without having received a Channel.Close-Ok - handshake method SHOULD log the error. - </doc> - </rule> - <chassis name = "client" implement = "MUST" /> - <chassis name = "server" implement = "MUST" /> - </method> - </class> - - <!-- == EXCHANGE ========================================================= --> - - <class name = "exchange" handler = "channel" index = "40" label = "work with exchanges"> - <doc> - Exchanges match and distribute messages across queues. Exchanges can be configured in - the server or declared at runtime. - </doc> - - <doc type = "grammar"> - exchange = C:DECLARE S:DECLARE-OK - / C:DELETE S:DELETE-OK - / C:BIND S:BIND-OK - / C:UNBIND S:UNBIND-OK - </doc> - - <chassis name = "server" implement = "MUST" /> - <chassis name = "client" implement = "MUST" /> - - <rule name = "required-types"> - <doc> - The server MUST implement these standard exchange types: fanout, direct. - </doc> - <doc type = "scenario"> - Client attempts to declare an exchange with each of these standard types. - </doc> - </rule> - <rule name = "recommended-types"> - <doc> - The server SHOULD implement these standard exchange types: topic, headers. - </doc> - <doc type = "scenario"> - Client attempts to declare an exchange with each of these standard types. - </doc> - </rule> - <rule name = "required-instances"> - <doc> - The server MUST, in each virtual host, pre-declare an exchange instance - for each standard exchange type that it implements, where the name of the - exchange instance, if defined, is "amq." followed by the exchange type name. - </doc> - <doc> - The server MUST, in each virtual host, pre-declare at least two direct - exchange instances: one named "amq.direct", the other with no public name - that serves as a default exchange for Publish methods. - </doc> - <doc type = "scenario"> - Client declares a temporary queue and attempts to bind to each required - exchange instance ("amq.fanout", "amq.direct", "amq.topic", and "amq.headers" - if those types are defined). - </doc> - </rule> - <rule name = "default-exchange"> - <doc> - The server MUST pre-declare a direct exchange with no public name to act as - the default exchange for content Publish methods and for default queue bindings. - </doc> - <doc type = "scenario"> - Client checks that the default exchange is active by specifying a queue - binding with no exchange name, and publishing a message with a suitable - routing key but without specifying the exchange name, then ensuring that - the message arrives in the queue correctly. - </doc> - </rule> - <rule name = "default-access"> - <doc> - The server MUST NOT allow clients to access the default exchange except - by specifying an empty exchange name in the Queue.Bind and content Publish - methods. - </doc> - </rule> - <rule name = "extensions"> - <doc> - The server MAY implement other exchange types as wanted. - </doc> - </rule> - - <!-- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - --> - - <method name = "declare" synchronous = "1" index = "10" label = "verify exchange exists, create if needed"> - <doc> - This method creates an exchange if it does not already exist, and if the exchange - exists, verifies that it is of the correct and expected class. - </doc> - <rule name = "minimum"> - <doc> - The server SHOULD support a minimum of 16 exchanges per virtual host and - ideally, impose no limit except as defined by available resources. - </doc> - <doc type = "scenario"> - The client declares as many exchanges as it can until the server reports - an error; the number of exchanges successfully declared must be at least - sixteen. + The server could not complete the method because it lacked + sufficient + resources. This may be due to the client creating too many of some + type + of entity. </doc> - </rule> - - <chassis name = "server" implement = "MUST" /> - <response name = "declare-ok" /> - - <!-- Deprecated: "ticket", must be zero --> - <field name = "reserved-1" type = "short" reserved = "1" /> - - <field name = "exchange" domain = "exchange-name"> - <rule name = "reserved" on-failure = "access-refused"> - <doc> - Exchange names starting with "amq." are reserved for pre-declared and - standardised exchanges. The client MAY declare an exchange starting with - "amq." if the passive option is set, or the exchange already exists. - </doc> - <doc type = "scenario"> - The client attempts to declare a non-existing exchange starting with - "amq." and with the passive option set to zero. - </doc> - </rule> - <rule name = "syntax" on-failure = "precondition-failed"> - <doc> - The exchange name consists of a non-empty sequence of these characters: - letters, digits, hyphen, underscore, period, or colon. - </doc> - <doc type = "scenario"> - The client attempts to declare an exchange with an illegal name. - </doc> - </rule> - <assert check = "notnull" /> - </field> - - <field name = "type" domain = "shortstr" label = "exchange type"> - <doc> - Each exchange belongs to one of a set of exchange types implemented by the - server. The exchange types define the functionality of the exchange - i.e. how - messages are routed through it. It is not valid or meaningful to attempt to - change the type of an existing exchange. - </doc> - <rule name = "typed" on-failure = "not-allowed"> - <doc> - Exchanges cannot be redeclared with different types. The client MUST not - attempt to redeclare an existing exchange with a different type than used - in the original Exchange.Declare method. - </doc> - <doc type = "scenario"> - TODO. - </doc> - </rule> - <rule name = "support" on-failure = "command-invalid"> - <doc> - The client MUST NOT attempt to declare an exchange with a type that the - server does not support. - </doc> - <doc type = "scenario"> - TODO. - </doc> - </rule> - </field> + </constant> - <field name = "passive" domain = "bit" label = "do not create exchange"> + <constant name="not-allowed" value="530" class="hard-error"> <doc> - If set, the server will reply with Declare-Ok if the exchange already - exists with the same name, and raise an error if not. The client can - use this to check whether an exchange exists without modifying the - server state. When set, all other method fields except name and no-wait - are ignored. A declare with both passive and no-wait has no effect. - Arguments are compared for semantic equivalence. + The client tried to work with some entity in a manner that is + prohibited + by the server, due to security settings or by some other criteria. </doc> - <rule name = "not-found"> - <doc> - If set, and the exchange does not already exist, the server MUST - raise a channel exception with reply code 404 (not found). - </doc> - <doc type = "scenario"> - TODO. - </doc> - </rule> - <rule name = "equivalent"> - <doc> - If not set and the exchange exists, the server MUST check that the - existing exchange has the same values for type, durable, and arguments - fields. The server MUST respond with Declare-Ok if the requested - exchange matches these fields, and MUST raise a channel exception if - not. - </doc> - <doc type = "scenario"> - TODO. - </doc> - </rule> - </field> + </constant> - <field name = "durable" domain = "bit" label = "request a durable exchange"> + <constant name="not-implemented" value="540" class="hard-error"> <doc> - If set when creating a new exchange, the exchange will be marked as durable. - Durable exchanges remain active when a server restarts. Non-durable exchanges - (transient exchanges) are purged if/when a server restarts. + The client tried to use functionality that is not implemented in the + server. </doc> - <rule name = "support"> - <doc> - The server MUST support both durable and transient exchanges. - </doc> - <doc type = "scenario"> - TODO. - </doc> - </rule> - </field> + </constant> - <field name = "auto-delete" domain = "bit" label = "auto-delete when unused"> + <constant name="internal-error" value="541" class="hard-error"> <doc> - If set, the exchange is deleted when all queues have - finished using it. + The server could not complete the method because of an internal + error. + The server may require intervention by an operator in order to + resume + normal operations. </doc> - <rule name = "amq_exchange_02"> - <doc> - The server SHOULD allow for a reasonable delay between the - point when it determines that an exchange is not being - used (or no longer used), and the point when it deletes - the exchange. At the least it must allow a client to - create an exchange and then bind a queue to it, with a - small but non-zero delay between these two actions. - </doc> - </rule> - <rule name = "amq_exchange_25"> - <doc> - The server MUST ignore the auto-delete field if the - exchange already exists. - </doc> - </rule> - </field> + </constant> - <field name = "internal" domain = "bit" label = "create internal exchange"> - <doc> - If set, the exchange may not be used directly by publishers, - but only when bound to other exchanges. Internal exchanges - are used to construct wiring that is not visible to - applications. - </doc> - </field> - - <field name = "no-wait" domain = "no-wait" /> - - <field name = "arguments" domain = "table" label = "arguments for declaration"> - <doc> - A set of arguments for the declaration. The syntax and semantics of these - arguments depends on the server implementation. - </doc> - </field> - </method> - - <method name = "declare-ok" synchronous = "1" index = "11" label = "confirm exchange declaration"> - <doc> - This method confirms a Declare method and confirms the name of the exchange, - essential for automatically-named exchanges. - </doc> - <chassis name = "client" implement = "MUST" /> - </method> - - <!-- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - --> - - <method name = "delete" synchronous = "1" index = "20" label = "delete an exchange"> - <doc> - This method deletes an exchange. When an exchange is deleted all queue bindings on - the exchange are cancelled. - </doc> - - <chassis name = "server" implement = "MUST" /> - <response name = "delete-ok" /> - - <!-- Deprecated: "ticket", must be zero --> - <field name = "reserved-1" type = "short" reserved = "1" /> - - <field name = "exchange" domain = "exchange-name"> - <rule name = "exists" on-failure = "not-found"> - <doc> - The client MUST NOT attempt to delete an exchange that does not exist. - </doc> - </rule> - <assert check = "notnull" /> - </field> - - <field name = "if-unused" domain = "bit" label = "delete only if unused"> - <doc> - If set, the server will only delete the exchange if it has no queue bindings. If - the exchange has queue bindings the server does not delete it but raises a - channel exception instead. - </doc> - <rule name = "in-use" on-failure = "precondition-failed"> - <doc> - The server MUST NOT delete an exchange that has bindings on it, if the if-unused - field is true. - </doc> - <doc type = "scenario"> - The client declares an exchange, binds a queue to it, then tries to delete it - setting if-unused to true. - </doc> - </rule> - </field> - - <field name = "no-wait" domain = "no-wait" /> - </method> - - <method name = "delete-ok" synchronous = "1" index = "21" - label = "confirm deletion of an exchange"> - <doc>This method confirms the deletion of an exchange.</doc> - <chassis name = "client" implement = "MUST" /> - </method> - - <!-- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - --> - - <method name = "bind" synchronous = "1" index = "30" - label = "bind exchange to an exchange"> - - <doc>This method binds an exchange to an exchange.</doc> - - <rule name = "duplicates"> - <doc> - A server MUST allow and ignore duplicate bindings - that is, - two or more bind methods for a specific exchanges, with - identical arguments - without treating these as an error. - </doc> - <doc type = "scenario"> - A client binds an exchange to an exchange. The client then - repeats the bind (with identical arguments). - </doc> - </rule> - - <rule name = "cyclical"> - <doc> - A server MUST allow cycles of exchange bindings to be - created including allowing an exchange to be bound to - itself. - </doc> - <doc type = "scenario"> - A client declares an exchange and binds it to itself. - </doc> - </rule> - - <rule name = "unique"> - <doc> - A server MUST not deliver the same message more than once to - a destination exchange, even if the topology of exchanges - and bindings results in multiple (even infinite) routes to - that exchange. - </doc> - <doc type = "scenario"> - A client declares an exchange and binds it using multiple - bindings to the amq.topic exchange. The client then - publishes a message to the amq.topic exchange that matches - all the bindings. - </doc> - </rule> - - <chassis name = "server" implement = "MUST"/> - - <response name = "bind-ok"/> - - <!-- Deprecated: "ticket", must be zero --> - <field name = "reserved-1" type = "short" reserved = "1"/> - - <field name = "destination" domain = "exchange-name" - label = "name of the destination exchange to bind to"> - <doc>Specifies the name of the destination exchange to bind.</doc> - <rule name = "exchange-existence" on-failure = "not-found"> - <doc> - A client MUST NOT be allowed to bind a non-existent - destination exchange. - </doc> - <doc type = "scenario"> - A client attempts to bind an undeclared exchange to an - exchange. - </doc> - </rule> - <rule name = "default-exchange"> - <doc> - The server MUST accept a blank exchange name to mean the - default exchange. - </doc> - <doc type = "scenario"> - The client declares an exchange and binds a blank exchange - name to it. - </doc> - </rule> - </field> - - <field name = "source" domain = "exchange-name" - label = "name of the source exchange to bind to"> - <doc>Specifies the name of the source exchange to bind.</doc> - <rule name = "exchange-existence" on-failure = "not-found"> - <doc> - A client MUST NOT be allowed to bind a non-existent source - exchange. - </doc> - <doc type = "scenario"> - A client attempts to bind an exchange to an undeclared - exchange. - </doc> - </rule> - <rule name = "default-exchange"> - <doc> - The server MUST accept a blank exchange name to mean the - default exchange. - </doc> - <doc type = "scenario"> - The client declares an exchange and binds it to a blank - exchange name. - </doc> - </rule> - </field> - - <field name = "routing-key" domain = "shortstr" - label = "message routing key"> - <doc> - Specifies the routing key for the binding. The routing key - is used for routing messages depending on the exchange - configuration. Not all exchanges use a routing key - refer - to the specific exchange documentation. - </doc> - </field> - - <field name = "no-wait" domain = "no-wait"/> - - <field name = "arguments" domain = "table" - label = "arguments for binding"> - <doc> - A set of arguments for the binding. The syntax and semantics - of these arguments depends on the exchange class. - </doc> - </field> - </method> - - <method name="bind-ok" synchronous="1" index="31" - label = "confirm bind successful"> - <doc>This method confirms that the bind was successful.</doc> - - <chassis name="client" implement="MUST"/> - </method> - - <!-- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - --> - - <method name = "unbind" synchronous = "1" index = "40" - label = "unbind an exchange from an exchange"> - <doc>This method unbinds an exchange from an exchange.</doc> - <rule name = "01"> - <doc>If a unbind fails, the server MUST raise a connection exception.</doc> - </rule> - <chassis name = "server" implement = "MUST"/> - <response name = "unbind-ok"/> - - <!-- Deprecated: "ticket", must be zero --> - <field name = "reserved-1" type = "short" reserved = "1"/> - - <field name = "destination" domain = "exchange-name"> - <doc>Specifies the name of the destination exchange to unbind.</doc> - <rule name = "must-exist" on-failure = "not-found"> - <doc> - The client MUST NOT attempt to unbind an exchange that - does not exist from an exchange. - </doc> - <doc type = "scenario"> - The client attempts to unbind a non-existent exchange from - an exchange. - </doc> - </rule> - <rule name = "default-exchange"> - <doc> - The server MUST accept a blank exchange name to mean the - default exchange. - </doc> - <doc type = "scenario"> - The client declares an exchange, binds a blank exchange - name to it, and then unbinds a blank exchange name from - it. - </doc> - </rule> - </field> - - <field name = "source" domain = "exchange-name"> - <doc>Specifies the name of the source exchange to unbind.</doc> - <rule name = "must-exist" on-failure = "not-found"> - <doc> - The client MUST NOT attempt to unbind an exchange from an - exchange that does not exist. - </doc> - <doc type = "scenario"> - The client attempts to unbind an exchange from a - non-existent exchange. - </doc> - </rule> - <rule name = "default-exchange"> - <doc> - The server MUST accept a blank exchange name to mean the - default exchange. - </doc> - <doc type = "scenario"> - The client declares an exchange, binds an exchange to a - blank exchange name, and then unbinds an exchange from a - black exchange name. - </doc> - </rule> - </field> - - <field name = "routing-key" domain = "shortstr" - label = "routing key of binding"> - <doc>Specifies the routing key of the binding to unbind.</doc> - </field> - - <field name = "no-wait" domain = "no-wait"/> - - <field name = "arguments" domain = "table" - label = "arguments of binding"> - <doc>Specifies the arguments of the binding to unbind.</doc> - </field> - </method> - - <method name = "unbind-ok" synchronous = "1" index = "51" - label = "confirm unbind successful"> - <doc>This method confirms that the unbind was successful.</doc> - <chassis name = "client" implement = "MUST"/> - </method> - - </class> - - <!-- == QUEUE ============================================================ --> - - <class name = "queue" handler = "channel" index = "50" label = "work with queues"> - <doc> - Queues store and forward messages. Queues can be configured in the server or created at - runtime. Queues must be attached to at least one exchange in order to receive messages - from publishers. - </doc> - - <doc type = "grammar"> - queue = C:DECLARE S:DECLARE-OK - / C:BIND S:BIND-OK - / C:UNBIND S:UNBIND-OK - / C:PURGE S:PURGE-OK - / C:DELETE S:DELETE-OK - </doc> - - <chassis name = "server" implement = "MUST" /> - <chassis name = "client" implement = "MUST" /> - - <!-- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - --> - - <method name = "declare" synchronous = "1" index = "10" label = "declare queue, create if needed"> - <doc> - This method creates or checks a queue. When creating a new queue the client can - specify various properties that control the durability of the queue and its - contents, and the level of sharing for the queue. - </doc> - - <rule name = "default-binding"> - <doc> - The server MUST create a default binding for a newly-declared queue to the - default exchange, which is an exchange of type 'direct' and use the queue - name as the routing key. - </doc> - <doc type = "scenario"> - Client declares a new queue, and then without explicitly binding it to an - exchange, attempts to send a message through the default exchange binding, - i.e. publish a message to the empty exchange, with the queue name as routing - key. - </doc> - </rule> - - <rule name = "minimum-queues"> - <doc> - The server SHOULD support a minimum of 256 queues per virtual host and ideally, - impose no limit except as defined by available resources. - </doc> - <doc type = "scenario"> - Client attempts to declare as many queues as it can until the server reports - an error. The resulting count must at least be 256. - </doc> - </rule> - - <chassis name = "server" implement = "MUST" /> - <response name = "declare-ok" /> - - <!-- Deprecated: "ticket", must be zero --> - <field name = "reserved-1" type = "short" reserved = "1" /> - - <field name = "queue" domain = "queue-name"> - <rule name = "default-name"> - <doc> - The queue name MAY be empty, in which case the server MUST create a new - queue with a unique generated name and return this to the client in the - Declare-Ok method. - </doc> - <doc type = "scenario"> - Client attempts to declare several queues with an empty name. The client then - verifies that the server-assigned names are unique and different. - </doc> - </rule> - <rule name = "reserved" on-failure = "access-refused"> - <doc> - Queue names starting with "amq." are reserved for pre-declared and - standardised queues. The client MAY declare a queue starting with - "amq." if the passive option is set, or the queue already exists. - </doc> - <doc type = "scenario"> - The client attempts to declare a non-existing queue starting with - "amq." and with the passive option set to zero. - </doc> - </rule> - <rule name = "syntax" on-failure = "precondition-failed"> - <doc> - The queue name can be empty, or a sequence of these characters: - letters, digits, hyphen, underscore, period, or colon. - </doc> - <doc type = "scenario"> - The client attempts to declare a queue with an illegal name. - </doc> - </rule> - </field> - - <field name = "passive" domain = "bit" label = "do not create queue"> - <doc> - If set, the server will reply with Declare-Ok if the queue already - exists with the same name, and raise an error if not. The client can - use this to check whether a queue exists without modifying the - server state. When set, all other method fields except name and no-wait - are ignored. A declare with both passive and no-wait has no effect. - Arguments are compared for semantic equivalence. - </doc> - <rule name = "passive" on-failure = "not-found"> - <doc> - The client MAY ask the server to assert that a queue exists without - creating the queue if not. If the queue does not exist, the server - treats this as a failure. - </doc> - <doc type = "scenario"> - Client declares an existing queue with the passive option and expects - the server to respond with a declare-ok. Client then attempts to declare - a non-existent queue with the passive option, and the server must close - the channel with the correct reply-code. - </doc> - </rule> - <rule name = "equivalent"> - <doc> - If not set and the queue exists, the server MUST check that the - existing queue has the same values for durable, exclusive, auto-delete, - and arguments fields. The server MUST respond with Declare-Ok if the - requested queue matches these fields, and MUST raise a channel exception - if not. - </doc> - <doc type = "scenario"> - TODO. - </doc> - </rule> - </field> - - <field name = "durable" domain = "bit" label = "request a durable queue"> - <doc> - If set when creating a new queue, the queue will be marked as durable. Durable - queues remain active when a server restarts. Non-durable queues (transient - queues) are purged if/when a server restarts. Note that durable queues do not - necessarily hold persistent messages, although it does not make sense to send - persistent messages to a transient queue. - </doc> - - <rule name = "persistence"> - <doc>The server MUST recreate the durable queue after a restart.</doc> - - <doc type = "scenario"> - Client declares a durable queue. The server is then restarted. The client - then attempts to send a message to the queue. The message should be successfully - delivered. - </doc> - </rule> - - <rule name = "types"> - <doc>The server MUST support both durable and transient queues.</doc> - <doc type = "scenario"> - A client declares two named queues, one durable and one transient. - </doc> - </rule> - </field> - - <field name = "exclusive" domain = "bit" label = "request an exclusive queue"> - <doc> - Exclusive queues may only be accessed by the current connection, and are - deleted when that connection closes. Passive declaration of an exclusive - queue by other connections are not allowed. - </doc> - - <rule name = "types"> - <doc> - The server MUST support both exclusive (private) and non-exclusive (shared) - queues. - </doc> - <doc type = "scenario"> - A client declares two named queues, one exclusive and one non-exclusive. - </doc> - </rule> - - <rule name = "exclusive" on-failure = "resource-locked"> - <doc> - The client MAY NOT attempt to use a queue that was declared as exclusive - by another still-open connection. - </doc> - <doc type = "scenario"> - One client declares an exclusive queue. A second client on a different - connection attempts to declare, bind, consume, purge, delete, or declare - a queue of the same name. - </doc> - </rule> - </field> - - <field name = "auto-delete" domain = "bit" label = "auto-delete queue when unused"> - <doc> - If set, the queue is deleted when all consumers have finished using it. The last - consumer can be cancelled either explicitly or because its channel is closed. If - there was no consumer ever on the queue, it won't be deleted. Applications can - explicitly delete auto-delete queues using the Delete method as normal. - </doc> - - <rule name = "pre-existence"> - <doc> - The server MUST ignore the auto-delete field if the queue already exists. - </doc> - <doc type = "scenario"> - Client declares two named queues, one as auto-delete and one explicit-delete. - Client then attempts to declare the two queues using the same names again, - but reversing the value of the auto-delete field in each case. Verify that the - queues still exist with the original auto-delete flag values. - </doc> - </rule> - </field> - - <field name = "no-wait" domain = "no-wait" /> - - <field name = "arguments" domain = "table" label = "arguments for declaration"> - <doc> - A set of arguments for the declaration. The syntax and semantics of these - arguments depends on the server implementation. - </doc> - </field> - </method> - - <method name = "declare-ok" synchronous = "1" index = "11" label = "confirms a queue definition"> - <doc> - This method confirms a Declare method and confirms the name of the queue, essential - for automatically-named queues. - </doc> - - <chassis name = "client" implement = "MUST" /> - - <field name = "queue" domain = "queue-name"> - <doc> - Reports the name of the queue. If the server generated a queue name, this field - contains that name. - </doc> - <assert check = "notnull" /> - </field> - - <field name = "message-count" domain = "message-count" /> - - <field name = "consumer-count" domain = "long" label = "number of consumers"> - <doc> - Reports the number of active consumers for the queue. Note that consumers can - suspend activity (Channel.Flow) in which case they do not appear in this count. - </doc> - </field> - </method> - - <!-- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - --> - - <method name = "bind" synchronous = "1" index = "20" label = "bind queue to an exchange"> - <doc> - This method binds a queue to an exchange. Until a queue is bound it will not - receive any messages. In a classic messaging model, store-and-forward queues - are bound to a direct exchange and subscription queues are bound to a topic - exchange. - </doc> - - <rule name = "duplicates"> - <doc> - A server MUST allow ignore duplicate bindings - that is, two or more bind - methods for a specific queue, with identical arguments - without treating these - as an error. - </doc> - <doc type = "scenario"> - A client binds a named queue to an exchange. The client then repeats the bind - (with identical arguments). - </doc> - </rule> - - <rule name = "unique"> - <doc> - A server MUST not deliver the same message more than once to a queue, even if - the queue has multiple bindings that match the message. - </doc> - <doc type = "scenario"> - A client declares a named queue and binds it using multiple bindings to the - amq.topic exchange. The client then publishes a message that matches all its - bindings. - </doc> - </rule> + <!-- + ====================================================== + == DOMAIN TYPES + ====================================================== + --> - <rule name = "transient-exchange"> - <doc> - The server MUST allow a durable queue to bind to a transient exchange. - </doc> - <doc type = "scenario"> - A client declares a transient exchange. The client then declares a named durable - queue and then attempts to bind the transient exchange to the durable queue. - </doc> - </rule> + <domain name="class-id" type="short"/> - <rule name = "durable-exchange"> + <domain name="consumer-tag" type="shortstr" label="consumer tag"> <doc> - Bindings of durable queues to durable exchanges are automatically durable - and the server MUST restore such bindings after a server restart. + Identifier for the consumer, valid within the current channel. </doc> - <doc type = "scenario"> - A server declares a named durable queue and binds it to a durable exchange. The - server is restarted. The client then attempts to use the queue/exchange combination. - </doc> - </rule> + </domain> - <rule name = "binding-count"> + <domain name="delivery-tag" type="longlong" + label="server-assigned delivery tag"> <doc> - The server SHOULD support at least 4 bindings per queue, and ideally, impose no - limit except as defined by available resources. - </doc> - <doc type = "scenario"> - A client declares a named queue and attempts to bind it to 4 different - exchanges. + The server-assigned and channel-specific delivery tag </doc> - </rule> - - <chassis name = "server" implement = "MUST" /> - - <response name = "bind-ok" /> - - <!-- Deprecated: "ticket", must be zero --> - <field name = "reserved-1" type = "short" reserved = "1" /> - - <field name = "queue" domain = "queue-name"> - <doc>Specifies the name of the queue to bind.</doc> - <rule name = "queue-known" on-failure = "not-found"> - <doc> - The client MUST either specify a queue name or have previously declared a - queue on the same channel - </doc> - <doc type = "scenario"> - The client opens a channel and attempts to bind an unnamed queue. - </doc> + <rule name="channel-local"> + <doc> + The delivery tag is valid only within the channel from which the + message was + received. I.e. a client MUST NOT receive a message on one + channel and then + acknowledge it on another. + </doc> </rule> - <rule name = "must-exist" on-failure = "not-found"> - <doc> - The client MUST NOT attempt to bind a queue that does not exist. - </doc> - <doc type = "scenario"> - The client attempts to bind a non-existent queue. - </doc> + <rule name="non-zero"> + <doc> + The server MUST NOT use a zero value for delivery tags. Zero is + reserved + for client use, meaning "all messages so far received". + </doc> </rule> - </field> - - <field name = "exchange" domain = "exchange-name" label = "name of the exchange to bind to"> - <rule name = "exchange-existence" on-failure = "not-found"> - <doc> - A client MUST NOT be allowed to bind a queue to a non-existent exchange. - </doc> - <doc type = "scenario"> - A client attempts to bind an named queue to a undeclared exchange. - </doc> - </rule> - <rule name = "default-exchange"> - <doc> - The server MUST accept a blank exchange name to mean the default exchange. - </doc> - <doc type = "scenario"> - The client declares a queue and binds it to a blank exchange name. - </doc> - </rule> - </field> + </domain> - <field name = "routing-key" domain = "shortstr" label = "message routing key"> + <domain name="exchange-name" type="shortstr" label="exchange name"> <doc> - Specifies the routing key for the binding. The routing key is used for routing - messages depending on the exchange configuration. Not all exchanges use a - routing key - refer to the specific exchange documentation. If the queue name - is empty, the server uses the last queue declared on the channel. If the - routing key is also empty, the server uses this queue name for the routing - key as well. If the queue name is provided but the routing key is empty, the - server does the binding with that empty routing key. The meaning of empty - routing keys depends on the exchange implementation. + The exchange name is a client-selected string that identifies the + exchange for + publish methods. </doc> - <rule name = "direct-exchange-key-matching"> - <doc> - If a message queue binds to a direct exchange using routing key K and a - publisher sends the exchange a message with routing key R, then the message - MUST be passed to the message queue if K = R. - </doc> - </rule> - </field> + <assert check="length" value="127"/> + <assert check="regexp" value="^[a-zA-Z0-9-_.:]*$"/> + </domain> - <field name = "no-wait" domain = "no-wait" /> + <domain name="method-id" type="short"/> - <field name = "arguments" domain = "table" label = "arguments for binding"> + <domain name="no-ack" type="bit" label="no acknowledgement needed"> <doc> - A set of arguments for the binding. The syntax and semantics of these arguments - depends on the exchange class. - </doc> - </field> - </method> - - <method name = "bind-ok" synchronous = "1" index = "21" label = "confirm bind successful"> - <doc>This method confirms that the bind was successful.</doc> - - <chassis name = "client" implement = "MUST" /> - </method> - - <!-- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - --> - - <method name = "unbind" synchronous = "1" index = "50" label = "unbind a queue from an exchange"> - <doc>This method unbinds a queue from an exchange.</doc> - <rule name = "01"> - <doc>If a unbind fails, the server MUST raise a connection exception.</doc> - </rule> - <chassis name="server" implement="MUST"/> - <response name="unbind-ok"/> - - <!-- Deprecated: "ticket", must be zero --> - <field name = "reserved-1" type = "short" reserved = "1" /> - - <field name = "queue" domain = "queue-name"> - <doc>Specifies the name of the queue to unbind.</doc> - <rule name = "queue-known" on-failure = "not-found"> - <doc> - The client MUST either specify a queue name or have previously declared a - queue on the same channel - </doc> - <doc type = "scenario"> - The client opens a channel and attempts to unbind an unnamed queue. - </doc> - </rule> - <rule name = "must-exist" on-failure = "not-found"> - <doc> - The client MUST NOT attempt to unbind a queue that does not exist. - </doc> - <doc type = "scenario"> - The client attempts to unbind a non-existent queue. - </doc> - </rule> - </field> - - <field name = "exchange" domain = "exchange-name"> - <doc>The name of the exchange to unbind from.</doc> - <rule name = "must-exist" on-failure = "not-found"> - <doc> - The client MUST NOT attempt to unbind a queue from an exchange that - does not exist. - </doc> - <doc type = "scenario"> - The client attempts to unbind a queue from a non-existent exchange. - </doc> - </rule> - <rule name = "default-exchange"> - <doc> - The server MUST accept a blank exchange name to mean the default exchange. - </doc> - <doc type = "scenario"> - The client declares a queue and binds it to a blank exchange name. - </doc> - </rule> - </field> - - <field name = "routing-key" domain = "shortstr" label = "routing key of binding"> - <doc>Specifies the routing key of the binding to unbind.</doc> - </field> - - <field name = "arguments" domain = "table" label = "arguments of binding"> - <doc>Specifies the arguments of the binding to unbind.</doc> - </field> - </method> - - <method name = "unbind-ok" synchronous = "1" index = "51" label = "confirm unbind successful"> - <doc>This method confirms that the unbind was successful.</doc> - <chassis name = "client" implement = "MUST"/> - </method> - - <!-- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - --> - - <method name = "purge" synchronous = "1" index = "30" label = "purge a queue"> - <doc> - This method removes all messages from a queue which are not awaiting - acknowledgment. - </doc> + If this field is set the server does not expect acknowledgements for + messages. That is, when a message is delivered to the client the + server + assumes the delivery will succeed and immediately dequeues it. This + functionality may increase performance but at the cost of + reliability. + Messages can get lost if a client dies before they are delivered to + the + application. + </doc> + </domain> - <rule name = "02"> + <domain name="no-local" type="bit" label="do not deliver own messages"> <doc> - The server MUST NOT purge messages that have already been sent to a client - but not yet acknowledged. + If the no-local field is set the server will not send messages to + the connection that + published them. </doc> - </rule> + </domain> - <rule name = "03"> + <domain name="no-wait" type="bit" label="do not send reply method"> <doc> - The server MAY implement a purge queue or log that allows system administrators - to recover accidentally-purged messages. The server SHOULD NOT keep purged - messages in the same storage spaces as the live messages since the volumes of - purged messages may get very large. + If set, the server will not respond to the method. The client should + not wait + for a reply method. If the server could not complete the method it + will raise a + channel or connection exception. </doc> - </rule> + </domain> - <chassis name = "server" implement = "MUST" /> - - <response name = "purge-ok" /> - - <!-- Deprecated: "ticket", must be zero --> - <field name = "reserved-1" type = "short" reserved = "1" /> - - <field name = "queue" domain = "queue-name"> - <doc>Specifies the name of the queue to purge.</doc> - <rule name = "queue-known" on-failure = "not-found"> - <doc> - The client MUST either specify a queue name or have previously declared a - queue on the same channel - </doc> - <doc type = "scenario"> - The client opens a channel and attempts to purge an unnamed queue. - </doc> - </rule> - <rule name = "must-exist" on-failure = "not-found"> - <doc> - The client MUST NOT attempt to purge a queue that does not exist. - </doc> - <doc type = "scenario"> - The client attempts to purge a non-existent queue. - </doc> - </rule> - </field> - - <field name = "no-wait" domain = "no-wait" /> - </method> - - <method name = "purge-ok" synchronous = "1" index = "31" label = "confirms a queue purge"> - <doc>This method confirms the purge of a queue.</doc> - - <chassis name = "client" implement = "MUST" /> - - <field name = "message-count" domain = "message-count"> + <domain name="path" type="shortstr"> <doc> - Reports the number of messages purged. + Unconstrained. </doc> - </field> - </method> - - <!-- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - --> + <assert check="notnull"/> + <assert check="length" value="127"/> + </domain> - <method name = "delete" synchronous = "1" index = "40" label = "delete a queue"> - <doc> - This method deletes a queue. When a queue is deleted any pending messages are sent - to a dead-letter queue if this is defined in the server configuration, and all - consumers on the queue are cancelled. - </doc> - - <rule name = "01"> + <domain name="peer-properties" type="table"> <doc> - The server SHOULD use a dead-letter queue to hold messages that were pending on - a deleted queue, and MAY provide facilities for a system administrator to move - these messages back to an active queue. + This table provides a set of peer properties, used for + identification, debugging, + and general information. </doc> - </rule> - - <chassis name = "server" implement = "MUST" /> - - <response name = "delete-ok" /> + </domain> - <!-- Deprecated: "ticket", must be zero --> - <field name = "reserved-1" type = "short" reserved = "1" /> - - <field name = "queue" domain = "queue-name"> - <doc>Specifies the name of the queue to delete.</doc> - <rule name = "queue-known" on-failure = "not-found"> - <doc> - The client MUST either specify a queue name or have previously declared a - queue on the same channel - </doc> - <doc type = "scenario"> - The client opens a channel and attempts to delete an unnamed queue. - </doc> - </rule> - <rule name = "must-exist" on-failure = "not-found"> - <doc> - The client MUST NOT attempt to delete a queue that does not exist. - </doc> - <doc type = "scenario"> - The client attempts to delete a non-existent queue. - </doc> - </rule> - </field> - - <field name = "if-unused" domain = "bit" label = "delete only if unused"> - <doc> - If set, the server will only delete the queue if it has no consumers. If the - queue has consumers the server does does not delete it but raises a channel - exception instead. - </doc> - <rule name = "in-use" on-failure = "precondition-failed"> - <doc> - The server MUST NOT delete a queue that has consumers on it, if the if-unused - field is true. - </doc> - <doc type = "scenario"> - The client declares a queue, and consumes from it, then tries to delete it - setting if-unused to true. - </doc> - </rule> - </field> - - <field name = "if-empty" domain = "bit" label = "delete only if empty"> + <domain name="queue-name" type="shortstr" label="queue name"> <doc> - If set, the server will only delete the queue if it has no messages. - </doc> - <rule name = "not-empty" on-failure = "precondition-failed"> - <doc> - The server MUST NOT delete a queue that has messages on it, if the - if-empty field is true. - </doc> - <doc type = "scenario"> - The client declares a queue, binds it and publishes some messages into it, - then tries to delete it setting if-empty to true. - </doc> - </rule> - </field> - - <field name = "no-wait" domain = "no-wait" /> - </method> - - <method name = "delete-ok" synchronous = "1" index = "41" label = "confirm deletion of a queue"> - <doc>This method confirms the deletion of a queue.</doc> - - <chassis name = "client" implement = "MUST" /> - - <field name = "message-count" domain = "message-count"> - <doc>Reports the number of messages deleted.</doc> - </field> - </method> - </class> - - <!-- == BASIC ============================================================ --> - - <class name = "basic" handler = "channel" index = "60" label = "work with basic content"> - <doc> - The Basic class provides methods that support an industry-standard messaging model. - </doc> - - <doc type = "grammar"> - basic = C:QOS S:QOS-OK - / C:CONSUME S:CONSUME-OK - / C:CANCEL S:CANCEL-OK - / C:PUBLISH content - / S:RETURN content - / S:DELIVER content - / C:GET ( S:GET-OK content / S:GET-EMPTY ) - / C:ACK - / S:ACK - / C:REJECT - / C:NACK - / S:NACK - / C:RECOVER-ASYNC - / C:RECOVER S:RECOVER-OK - </doc> - - <chassis name = "server" implement = "MUST" /> - <chassis name = "client" implement = "MAY" /> - - <rule name = "01"> - <doc> - The server SHOULD respect the persistent property of basic messages and - SHOULD make a best-effort to hold persistent basic messages on a reliable - storage mechanism. - </doc> - <doc type = "scenario"> - Send a persistent message to queue, stop server, restart server and then - verify whether message is still present. Assumes that queues are durable. - Persistence without durable queues makes no sense. - </doc> - </rule> - - <rule name = "02"> - <doc> - The server MUST NOT discard a persistent basic message in case of a queue - overflow. - </doc> - <doc type = "scenario"> - Declare a queue overflow situation with persistent messages and verify that - messages do not get lost (presumably the server will write them to disk). - </doc> - </rule> - - <rule name = "03"> - <doc> - The server MAY use the Channel.Flow method to slow or stop a basic message - publisher when necessary. - </doc> - <doc type = "scenario"> - Declare a queue overflow situation with non-persistent messages and verify - whether the server responds with Channel.Flow or not. Repeat with persistent - messages. - </doc> - </rule> - - <rule name = "04"> - <doc> - The server MAY overflow non-persistent basic messages to persistent - storage. - </doc> - <!-- Test scenario: untestable --> - </rule> - - <rule name = "05"> - <doc> - The server MAY discard or dead-letter non-persistent basic messages on a - priority basis if the queue size exceeds some configured limit. - </doc> - <!-- Test scenario: untestable --> - </rule> - - <rule name = "06"> - <doc> - The server MUST implement at least 2 priority levels for basic messages, - where priorities 0-4 and 5-9 are treated as two distinct levels. - </doc> - <doc type = "scenario"> - Send a number of priority 0 messages to a queue. Send one priority 9 - message. Consume messages from the queue and verify that the first message - received was priority 9. - </doc> - </rule> - - <rule name = "07"> - <doc> - The server MAY implement up to 10 priority levels. - </doc> - <doc type = "scenario"> - Send a number of messages with mixed priorities to a queue, so that all - priority values from 0 to 9 are exercised. A good scenario would be ten - messages in low-to-high priority. Consume from queue and verify how many - priority levels emerge. - </doc> - </rule> - - <rule name = "08"> - <doc> - The server MUST deliver messages of the same priority in order irrespective of - their individual persistence. - </doc> - <doc type = "scenario"> - Send a set of messages with the same priority but different persistence - settings to a queue. Consume and verify that messages arrive in same order - as originally published. - </doc> - </rule> - - <rule name = "09"> - <doc> - The server MUST support un-acknowledged delivery of Basic content, i.e. - consumers with the no-ack field set to TRUE. - </doc> - </rule> - - <rule name = "10"> - <doc> - The server MUST support explicitly acknowledged delivery of Basic content, - i.e. consumers with the no-ack field set to FALSE. - </doc> - <doc type = "scenario"> - Declare a queue and a consumer using explicit acknowledgements. Publish a - set of messages to the queue. Consume the messages but acknowledge only - half of them. Disconnect and reconnect, and consume from the queue. - Verify that the remaining messages are received. - </doc> - </rule> - - <!-- These are the properties for a Basic content --> - - <!-- MIME typing --> - <field name = "content-type" domain = "shortstr" label = "MIME content type" /> - <!-- MIME typing --> - <field name = "content-encoding" domain = "shortstr" label = "MIME content encoding" /> - <!-- For applications, and for header exchange routing --> - <field name = "headers" domain = "table" label = "message header field table" /> - <!-- For queues that implement persistence --> - <field name = "delivery-mode" domain = "octet" label = "non-persistent (1) or persistent (2)" /> - <!-- For queues that implement priorities --> - <field name = "priority" domain = "octet" label = "message priority, 0 to 9" /> - <!-- For application use, no formal behaviour --> - <field name = "correlation-id" domain = "shortstr" label = "application correlation identifier" /> - <!-- For application use, no formal behaviour but may hold the + The queue name identifies the queue within the vhost. In methods + where the queue + name may be blank, and that has no specific significance, this + refers to the + 'current' queue for the channel, meaning the last queue that the + client declared + on the channel. If the client did not declare a queue, and the + method needs a + queue name, this will result in a 502 (syntax error) channel + exception. + </doc> + <assert check="length" value="127"/> + <assert check="regexp" value="^[a-zA-Z0-9-_.:]*$"/> + </domain> + + <domain name="redelivered" type="bit" label="message is being redelivered"> + <doc> + This indicates that the message has been previously delivered to + this or + another client. + </doc> + <rule name="implementation"> + <doc> + The server SHOULD try to signal redelivered messages when it + can. When + redelivering a message that was not successfully acknowledged, + the server + SHOULD deliver it to the original client if possible. + </doc> + <doc type="scenario"> + Declare a shared queue and publish a message to the queue. + Consume the + message using explicit acknowledgements, but do not acknowledge + the + message. Close the connection, reconnect, and consume from the + queue + again. The message should arrive with the redelivered flag set. + </doc> + </rule> + <rule name="hinting"> + <doc> + The client MUST NOT rely on the redelivered field but should + take it as a + hint that the message may already have been processed. A fully + robust + client must be able to track duplicate received messages on + non-transacted, + and locally-transacted channels. + </doc> + </rule> + </domain> + + <domain name="message-count" type="long" + label="number of messages in queue"> + <doc> + The number of messages in the queue, which will be zero for + newly-declared + queues. This is the number of messages present in the queue, and + committed + if the channel on which they were published is transacted, that are + not + waiting acknowledgement. + </doc> + </domain> + + <domain name="reply-code" type="short" label="reply code from server"> + <doc> + The reply code. The AMQ reply codes are defined as constants at the + start + of this formal specification. + </doc> + <assert check="notnull"/> + </domain> + + <domain name="reply-text" type="shortstr" label="localised reply text"> + <doc> + The localised reply text. This text can be logged as an aid to + resolving + issues. + </doc> + <assert check="notnull"/> + </domain> + + <!-- Elementary domains --> + <domain name="bit" type="bit" label="single bit"/> + <domain name="octet" type="octet" label="single octet"/> + <domain name="short" type="short" label="16-bit integer"/> + <domain name="long" type="long" label="32-bit integer"/> + <domain name="longlong" type="longlong" label="64-bit integer"/> + <domain name="shortstr" type="shortstr" label="short string"/> + <domain name="longstr" type="longstr" label="long string"/> + <domain name="timestamp" type="timestamp" label="64-bit timestamp"/> + <domain name="table" type="table" label="field table"/> + + <!-- == CONNECTION ======================================================= --> + + <class name="connection" handler="connection" index="10" + label="work with socket connections"> + <doc> + The connection class provides methods for a client to establish a + network connection to + a server, and for both peers to operate the connection thereafter. + </doc> + + <doc type="grammar"> + connection = open-connection *use-connection close-connection + open-connection = C:protocol-header + S:START C:START-OK + *challenge + S:TUNE C:TUNE-OK + C:OPEN S:OPEN-OK + challenge = S:SECURE C:SECURE-OK + use-connection = *channel + close-connection = C:CLOSE S:CLOSE-OK + / S:CLOSE C:CLOSE-OK + </doc> + + <chassis name="server" implement="MUST"/> + <chassis name="client" implement="MUST"/> + + <!-- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - --> + + <method name="start" synchronous="1" index="10" + label="start connection negotiation"> + <doc> + This method starts the connection negotiation process by telling + the client the + protocol version that the server proposes, along with a list of + security mechanisms + which the client can use for authentication. + </doc> + + <rule name="protocol-name"> + <doc> + If the server cannot support the protocol specified in the + protocol header, + it MUST respond with a valid protocol header and then close + the socket + connection. + </doc> + <doc type="scenario"> + The client sends a protocol header containing an invalid + protocol name. + The server MUST respond by sending a valid protocol header + and then closing + the connection. + </doc> + </rule> + <rule name="server-support"> + <doc> + The server MUST provide a protocol version that is lower + than or equal to + that requested by the client in the protocol header. + </doc> + <doc type="scenario"> + The client requests a protocol version that is higher than + any valid + implementation, e.g. 2.0. The server must respond with a + protocol header + indicating its supported protocol version, e.g. 1.0. + </doc> + </rule> + <rule name="client-support"> + <doc> + If the client cannot handle the protocol version suggested + by the server + it MUST close the socket connection without sending any + further data. + </doc> + <doc type="scenario"> + The server sends a protocol version that is lower than any + valid + implementation, e.g. 0.1. The client must respond by closing + the + connection without sending any further data. + </doc> + </rule> + + <chassis name="client" implement="MUST"/> + <response name="start-ok"/> + + <field name="version-major" domain="octet" + label="protocol major version"> + <doc> + The major version number can take any value from 0 to 99 as + defined in the + AMQP specification. + </doc> + </field> + + <field name="version-minor" domain="octet" + label="protocol minor version"> + <doc> + The minor version number can take any value from 0 to 99 as + defined in the + AMQP specification. + </doc> + </field> + + <field name="server-properties" domain="peer-properties" + label="server properties"> + <rule name="required-fields"> + <doc> + The properties SHOULD contain at least these fields: + "host", specifying the + server host name or address, "product", giving the name + of the server product, + "version", giving the name of the server version, + "platform", giving the name + of the operating system, "copyright", if appropriate, + and "information", giving + other general information. + </doc> + <doc type="scenario"> + Client connects to server and inspects the server + properties. It checks for + the presence of the required fields. + </doc> + </rule> + </field> + + <field name="mechanisms" domain="longstr" + label="available security mechanisms"> + <doc> + A list of the security mechanisms that the server supports, + delimited by spaces. + </doc> + <assert check="notnull"/> + </field> + + <field name="locales" domain="longstr" + label="available message locales"> + <doc> + A list of the message locales that the server supports, + delimited by spaces. The + locale defines the language in which the server will send + reply texts. + </doc> + <rule name="required-support"> + <doc> + The server MUST support at least the en_US locale. + </doc> + <doc type="scenario"> + Client connects to server and inspects the locales + field. It checks for + the presence of the required locale(s). + </doc> + </rule> + <assert check="notnull"/> + </field> + </method> + + <method name="start-ok" synchronous="1" index="11" + label="select security mechanism and locale"> + <doc> + This method selects a SASL security mechanism. + </doc> + + <chassis name="server" implement="MUST"/> + + <field name="client-properties" domain="peer-properties" + label="client properties"> + <rule name="required-fields"> + <!-- This rule is not testable from the client side --> + <doc> + The properties SHOULD contain at least these fields: + "product", giving the name + of the client product, "version", giving the name of the + client version, "platform", + giving the name of the operating system, "copyright", if + appropriate, and + "information", giving other general information. + </doc> + </rule> + </field> + + <field name="mechanism" domain="shortstr" + label="selected security mechanism"> + <doc> + A single security mechanisms selected by the client, which + must be one of those + specified by the server. + </doc> + <rule name="security"> + <doc> + The client SHOULD authenticate using the highest-level + security profile it + can handle from the list provided by the server. + </doc> + </rule> + <rule name="validity"> + <doc> + If the mechanism field does not contain one of the + security mechanisms + proposed by the server in the Start method, the server + MUST close the + connection without sending any further data. + </doc> + <doc type="scenario"> + Client connects to server and sends an invalid security + mechanism. The + server must respond by closing the connection (a socket + close, with no + connection close negotiation). + </doc> + </rule> + <assert check="notnull"/> + </field> + + <field name="response" domain="longstr" + label="security response data"> + <doc> + A block of opaque data passed to the security mechanism. The + contents of this + data are defined by the SASL security mechanism. + </doc> + <assert check="notnull"/> + </field> + + <field name="locale" domain="shortstr" + label="selected message locale"> + <doc> + A single message locale selected by the client, which must + be one of those + specified by the server. + </doc> + <assert check="notnull"/> + </field> + </method> + + <!-- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - --> + + <method name="secure" synchronous="1" index="20" + label="security mechanism challenge"> + <doc> + The SASL protocol works by exchanging challenges and responses + until both peers have + received sufficient information to authenticate each other. This + method challenges + the client to provide more information. + </doc> + + <chassis name="client" implement="MUST"/> + <response name="secure-ok"/> + + <field name="challenge" domain="longstr" + label="security challenge data"> + <doc> + Challenge information, a block of opaque binary data passed + to the security + mechanism. + </doc> + </field> + </method> + + <method name="secure-ok" synchronous="1" index="21" + label="security mechanism response"> + <doc> + This method attempts to authenticate, passing a block of SASL + data for the security + mechanism at the server side. + </doc> + + <chassis name="server" implement="MUST"/> + + <field name="response" domain="longstr" + label="security response data"> + <doc> + A block of opaque data passed to the security mechanism. The + contents of this + data are defined by the SASL security mechanism. + </doc> + <assert check="notnull"/> + </field> + </method> + + <!-- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - --> + + <method name="tune" synchronous="1" index="30" + label="propose connection tuning parameters"> + <doc> + This method proposes a set of connection configuration values to + the client. The + client can accept and/or adjust these. + </doc> + + <chassis name="client" implement="MUST"/> + + <response name="tune-ok"/> + + <field name="channel-max" domain="short" + label="proposed maximum channels"> + <doc> + Specifies highest channel number that the server permits. + Usable channel numbers + are in the range 1..channel-max. Zero indicates no specified + limit. + </doc> + </field> + + <field name="frame-max" domain="long" + label="proposed maximum frame size"> + <doc> + The largest frame size that the server proposes for the + connection, including + frame header and end-byte. The client can negotiate a lower + value. Zero means + that the server does not impose any specific limit but may + reject very large + frames if it cannot allocate resources for them. + </doc> + <rule name="minimum"> + <doc> + Until the frame-max has been negotiated, both peers MUST + accept frames of up + to frame-min-size octets large, and the minimum + negotiated value for frame-max + is also frame-min-size. + </doc> + <doc type="scenario"> + Client connects to server and sends a large properties + field, creating a frame + of frame-min-size octets. The server must accept this + frame. + </doc> + </rule> + </field> + + <field name="heartbeat" domain="short" + label="desired heartbeat delay"> + <doc> + The delay, in seconds, of the connection heartbeat that the + server wants. + Zero means the server does not want a heartbeat. + </doc> + </field> + </method> + + <method name="tune-ok" synchronous="1" index="31" + label="negotiate connection tuning parameters"> + <doc> + This method sends the client's connection tuning parameters to + the server. + Certain fields are negotiated, others provide capability + information. + </doc> + + <chassis name="server" implement="MUST"/> + + <field name="channel-max" domain="short" + label="negotiated maximum channels"> + <doc> + The maximum total number of channels that the client will + use per connection. + </doc> + <rule name="upper-limit"> + <doc> + If the client specifies a channel max that is higher + than the value provided + by the server, the server MUST close the connection + without attempting a + negotiated close. The server may report the error in + some fashion to assist + implementors. + </doc> + </rule> + <assert check="notnull"/> + <assert check="le" method="tune" field="channel-max"/> + </field> + + <field name="frame-max" domain="long" + label="negotiated maximum frame size"> + <doc> + The largest frame size that the client and server will use + for the connection. + Zero means that the client does not impose any specific + limit but may reject + very large frames if it cannot allocate resources for them. + Note that the + frame-max limit applies principally to content frames, where + large contents can + be broken into frames of arbitrary size. + </doc> + <rule name="minimum"> + <doc> + Until the frame-max has been negotiated, both peers MUST + accept frames of up + to frame-min-size octets large, and the minimum + negotiated value for frame-max + is also frame-min-size. + </doc> + </rule> + <rule name="upper-limit"> + <doc> + If the client specifies a frame max that is higher than + the value provided + by the server, the server MUST close the connection + without attempting a + negotiated close. The server may report the error in + some fashion to assist + implementors. + </doc> + </rule> + </field> + + <field name="heartbeat" domain="short" + label="desired heartbeat delay"> + <doc> + The delay, in seconds, of the connection heartbeat that the + client wants. Zero + means the client does not want a heartbeat. + </doc> + </field> + </method> + + <!-- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - --> + + <method name="open" synchronous="1" index="40" + label="open connection to virtual host"> + <doc> + This method opens a connection to a virtual host, which is a + collection of + resources, and acts to separate multiple application domains + within a server. + The server may apply arbitrary limits per virtual host, such as + the number + of each type of entity that may be used, per connection and/or + in total. + </doc> + + <chassis name="server" implement="MUST"/> + <response name="open-ok"/> + + <field name="virtual-host" domain="path" label="virtual host name"> + <doc> + The name of the virtual host to work with. + </doc> + <rule name="separation"> + <doc> + If the server supports multiple virtual hosts, it MUST + enforce a full + separation of exchanges, queues, and all associated + entities per virtual + host. An application, connected to a specific virtual + host, MUST NOT be able + to access resources of another virtual host. + </doc> + </rule> + <rule name="security"> + <doc> + The server SHOULD verify that the client has permission + to access the + specified virtual host. + </doc> + </rule> + </field> + <!-- Deprecated: "capabilities", must be zero --> + <field name="reserved-1" type="shortstr" reserved="1"/> + <!-- Deprecated: "insist", must be zero --> + <field name="reserved-2" type="bit" reserved="1"/> + </method> + + <method name="open-ok" synchronous="1" index="41" + label="signal that connection is ready"> + <doc> + This method signals to the client that the connection is ready + for use. + </doc> + <chassis name="client" implement="MUST"/> + <!-- Deprecated: "known-hosts", must be zero --> + <field name="reserved-1" type="shortstr" reserved="1"/> + </method> + + <!-- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - --> + + <method name="close" synchronous="1" index="50" + label="request a connection close"> + <doc> + This method indicates that the sender wants to close the + connection. This may be + due to internal conditions (e.g. a forced shut-down) or due to + an error handling + a specific method, i.e. an exception. When a close is due to an + exception, the + sender provides the class and method id of the method which + caused the exception. + </doc> + <rule name="stability"> + <doc> + After sending this method, any received methods except Close + and Close-OK MUST + be discarded. The response to receiving a Close after + sending Close must be to + send Close-Ok. + </doc> + </rule> + + <chassis name="client" implement="MUST"/> + <chassis name="server" implement="MUST"/> + <response name="close-ok"/> + + <field name="reply-code" domain="reply-code"/> + <field name="reply-text" domain="reply-text"/> + + <field name="class-id" domain="class-id" + label="failing method class"> + <doc> + When the close is provoked by a method exception, this is + the class of the + method. + </doc> + </field> + + <field name="method-id" domain="method-id" + label="failing method ID"> + <doc> + When the close is provoked by a method exception, this is + the ID of the method. + </doc> + </field> + </method> + + <method name="close-ok" synchronous="1" index="51" + label="confirm a connection close"> + <doc> + This method confirms a Connection.Close method and tells the + recipient that it is + safe to release resources for the connection and close the + socket. + </doc> + <rule name="reporting"> + <doc> + A peer that detects a socket closure without having received + a Close-Ok + handshake method SHOULD log the error. + </doc> + </rule> + <chassis name="client" implement="MUST"/> + <chassis name="server" implement="MUST"/> + </method> + + <method name="blocked" index="60"> + <doc> + This method indicates that a connection has been blocked + and does not accept new publishes. + </doc> + <chassis name="server" implement="MUST"/> + <chassis name="client" implement="MUST"/> + <field name="reason" domain="shortstr"/> + </method> + <method name="unblocked" index="61"> + <doc> + This method indicates that a connection has been unblocked + and now accepts publishes. + </doc> + <chassis name="server" implement="MUST"/> + <chassis name="client" implement="MUST"/> + </method> + </class> + + <!-- == CHANNEL ========================================================== --> + + <class name="channel" handler="channel" index="20" + label="work with channels"> + <doc> + The channel class provides methods for a client to establish a + channel to a + server and for both peers to operate the channel thereafter. + </doc> + + <doc type="grammar"> + channel = open-channel *use-channel close-channel + open-channel = C:OPEN S:OPEN-OK + use-channel = C:FLOW S:FLOW-OK + / S:FLOW C:FLOW-OK + / functional-class + close-channel = C:CLOSE S:CLOSE-OK + / S:CLOSE C:CLOSE-OK + </doc> + + <chassis name="server" implement="MUST"/> + <chassis name="client" implement="MUST"/> + + <!-- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - --> + + <method name="open" synchronous="1" index="10" + label="open a channel for use"> + <doc> + This method opens a channel to the server. + </doc> + <rule name="state" on-failure="channel-error"> + <doc> + The client MUST NOT use this method on an already-opened + channel. + </doc> + <doc type="scenario"> + Client opens a channel and then reopens the same channel. + </doc> + </rule> + <chassis name="server" implement="MUST"/> + <response name="open-ok"/> + <!-- Deprecated: "out-of-band", must be zero --> + <field name="reserved-1" type="shortstr" reserved="1"/> + </method> + + <method name="open-ok" synchronous="1" index="11" + label="signal that the channel is ready"> + <doc> + This method signals to the client that the channel is ready for + use. + </doc> + <chassis name="client" implement="MUST"/> + <!-- Deprecated: "channel-id", must be zero --> + <field name="reserved-1" type="longstr" reserved="1"/> + </method> + + <!-- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - --> + + <method name="flow" synchronous="1" index="20" + label="enable/disable flow from peer"> + <doc> + This method asks the peer to pause or restart the flow of + content data sent by + a consumer. This is a simple flow-control mechanism that a peer + can use to avoid + overflowing its queues or otherwise finding itself receiving + more messages than + it can process. Note that this method is not intended for window + control. It does + not affect contents returned by Basic.Get-Ok methods. + </doc> + + <rule name="initial-state"> + <doc> + When a new channel is opened, it is active (flow is active). + Some applications + assume that channels are inactive until started. To emulate + this behaviour a + client MAY open the channel, then pause it. + </doc> + </rule> + + <rule name="bidirectional"> + <doc> + When sending content frames, a peer SHOULD monitor the + channel for incoming + methods and respond to a Channel.Flow as rapidly as + possible. + </doc> + </rule> + + <rule name="throttling"> + <doc> + A peer MAY use the Channel.Flow method to throttle incoming + content data for + internal reasons, for example, when exchanging data over a + slower connection. + </doc> + </rule> + + <rule name="expected-behaviour"> + <doc> + The peer that requests a Channel.Flow method MAY disconnect + and/or ban a peer + that does not respect the request. This is to prevent + badly-behaved clients + from overwhelming a server. + </doc> + </rule> + + <chassis name="server" implement="MUST"/> + <chassis name="client" implement="MUST"/> + + <response name="flow-ok"/> + + <field name="active" domain="bit" label="start/stop content frames"> + <doc> + If 1, the peer starts sending content frames. If 0, the peer + stops sending + content frames. + </doc> + </field> + </method> + + <method name="flow-ok" index="21" label="confirm a flow method"> + <doc> + Confirms to the peer that a flow command was received and + processed. + </doc> + <chassis name="server" implement="MUST"/> + <chassis name="client" implement="MUST"/> + <field name="active" domain="bit" label="current flow setting"> + <doc> + Confirms the setting of the processed flow method: 1 means + the peer will start + sending or continue to send content frames; 0 means it will + not. + </doc> + </field> + </method> + + <!-- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - --> + + <method name="close" synchronous="1" index="40" + label="request a channel close"> + <doc> + This method indicates that the sender wants to close the + channel. This may be due to + internal conditions (e.g. a forced shut-down) or due to an error + handling a specific + method, i.e. an exception. When a close is due to an exception, + the sender provides + the class and method id of the method which caused the + exception. + </doc> + <rule name="stability"> + <doc> + After sending this method, any received methods except Close + and Close-OK MUST + be discarded. The response to receiving a Close after + sending Close must be to + send Close-Ok. + </doc> + </rule> + + <chassis name="client" implement="MUST"/> + <chassis name="server" implement="MUST"/> + <response name="close-ok"/> + + <field name="reply-code" domain="reply-code"/> + <field name="reply-text" domain="reply-text"/> + + <field name="class-id" domain="class-id" + label="failing method class"> + <doc> + When the close is provoked by a method exception, this is + the class of the + method. + </doc> + </field> + + <field name="method-id" domain="method-id" + label="failing method ID"> + <doc> + When the close is provoked by a method exception, this is + the ID of the method. + </doc> + </field> + </method> + + <method name="close-ok" synchronous="1" index="41" + label="confirm a channel close"> + <doc> + This method confirms a Channel.Close method and tells the + recipient that it is safe + to release resources for the channel. + </doc> + <rule name="reporting"> + <doc> + A peer that detects a socket closure without having received + a Channel.Close-Ok + handshake method SHOULD log the error. + </doc> + </rule> + <chassis name="client" implement="MUST"/> + <chassis name="server" implement="MUST"/> + </method> + </class> + + <!-- == EXCHANGE ========================================================= --> + + <class name="exchange" handler="channel" index="40" + label="work with exchanges"> + <doc> + Exchanges match and distribute messages across queues. Exchanges can + be configured in + the server or declared at runtime. + </doc> + + <doc type="grammar"> + exchange = C:DECLARE S:DECLARE-OK + / C:DELETE S:DELETE-OK + / C:BIND S:BIND-OK + / C:UNBIND S:UNBIND-OK + </doc> + + <chassis name="server" implement="MUST"/> + <chassis name="client" implement="MUST"/> + + <rule name="required-types"> + <doc> + The server MUST implement these standard exchange types: fanout, + direct. + </doc> + <doc type="scenario"> + Client attempts to declare an exchange with each of these + standard types. + </doc> + </rule> + <rule name="recommended-types"> + <doc> + The server SHOULD implement these standard exchange types: + topic, headers. + </doc> + <doc type="scenario"> + Client attempts to declare an exchange with each of these + standard types. + </doc> + </rule> + <rule name="required-instances"> + <doc> + The server MUST, in each virtual host, pre-declare an exchange + instance + for each standard exchange type that it implements, where the + name of the + exchange instance, if defined, is "amq." followed by the + exchange type name. + </doc> + <doc> + The server MUST, in each virtual host, pre-declare at least two + direct + exchange instances: one named "amq.direct", the other with no + public name + that serves as a default exchange for Publish methods. + </doc> + <doc type="scenario"> + Client declares a temporary queue and attempts to bind to each + required + exchange instance ("amq.fanout", "amq.direct", "amq.topic", and + "amq.headers" + if those types are defined). + </doc> + </rule> + <rule name="default-exchange"> + <doc> + The server MUST pre-declare a direct exchange with no public + name to act as + the default exchange for content Publish methods and for default + queue bindings. + </doc> + <doc type="scenario"> + Client checks that the default exchange is active by specifying + a queue + binding with no exchange name, and publishing a message with a + suitable + routing key but without specifying the exchange name, then + ensuring that + the message arrives in the queue correctly. + </doc> + </rule> + <rule name="default-access"> + <doc> + The server MUST NOT allow clients to access the default exchange + except + by specifying an empty exchange name in the Queue.Bind and + content Publish + methods. + </doc> + </rule> + <rule name="extensions"> + <doc> + The server MAY implement other exchange types as wanted. + </doc> + </rule> + + <!-- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - --> + + <method name="declare" synchronous="1" index="10" + label="verify exchange exists, create if needed"> + <doc> + This method creates an exchange if it does not already exist, + and if the exchange + exists, verifies that it is of the correct and expected class. + </doc> + <rule name="minimum"> + <doc> + The server SHOULD support a minimum of 16 exchanges per + virtual host and + ideally, impose no limit except as defined by available + resources. + </doc> + <doc type="scenario"> + The client declares as many exchanges as it can until the + server reports + an error; the number of exchanges successfully declared must + be at least + sixteen. + </doc> + </rule> + + <chassis name="server" implement="MUST"/> + <response name="declare-ok"/> + + <!-- Deprecated: "ticket", must be zero --> + <field name="reserved-1" type="short" reserved="1"/> + + <field name="exchange" domain="exchange-name"> + <rule name="reserved" on-failure="access-refused"> + <doc> + Exchange names starting with "amq." are reserved for + pre-declared and + standardised exchanges. The client MAY declare an + exchange starting with + "amq." if the passive option is set, or the exchange + already exists. + </doc> + <doc type="scenario"> + The client attempts to declare a non-existing exchange + starting with + "amq." and with the passive option set to zero. + </doc> + </rule> + <rule name="syntax" on-failure="precondition-failed"> + <doc> + The exchange name consists of a non-empty sequence of + these characters: + letters, digits, hyphen, underscore, period, or colon. + </doc> + <doc type="scenario"> + The client attempts to declare an exchange with an + illegal name. + </doc> + </rule> + <assert check="notnull"/> + </field> + + <field name="type" domain="shortstr" label="exchange type"> + <doc> + Each exchange belongs to one of a set of exchange types + implemented by the + server. The exchange types define the functionality of the + exchange - i.e. how + messages are routed through it. It is not valid or + meaningful to attempt to + change the type of an existing exchange. + </doc> + <rule name="typed" on-failure="not-allowed"> + <doc> + Exchanges cannot be redeclared with different types. The + client MUST not + attempt to redeclare an existing exchange with a + different type than used + in the original Exchange.Declare method. + </doc> + <doc type="scenario"> + TODO. + </doc> + </rule> + <rule name="support" on-failure="command-invalid"> + <doc> + The client MUST NOT attempt to declare an exchange with + a type that the + server does not support. + </doc> + <doc type="scenario"> + TODO. + </doc> + </rule> + </field> + + <field name="passive" domain="bit" label="do not create exchange"> + <doc> + If set, the server will reply with Declare-Ok if the + exchange already + exists with the same name, and raise an error if not. The + client can + use this to check whether an exchange exists without + modifying the + server state. When set, all other method fields except name + and no-wait + are ignored. A declare with both passive and no-wait has no + effect. + Arguments are compared for semantic equivalence. + </doc> + <rule name="not-found"> + <doc> + If set, and the exchange does not already exist, the + server MUST + raise a channel exception with reply code 404 (not + found). + </doc> + <doc type="scenario"> + TODO. + </doc> + </rule> + <rule name="equivalent"> + <doc> + If not set and the exchange exists, the server MUST + check that the + existing exchange has the same values for type, durable, + and arguments + fields. The server MUST respond with Declare-Ok if the + requested + exchange matches these fields, and MUST raise a channel + exception if + not. + </doc> + <doc type="scenario"> + TODO. + </doc> + </rule> + </field> + + <field name="durable" domain="bit" + label="request a durable exchange"> + <doc> + If set when creating a new exchange, the exchange will be + marked as durable. + Durable exchanges remain active when a server restarts. + Non-durable exchanges + (transient exchanges) are purged if/when a server restarts. + </doc> + <rule name="support"> + <doc> + The server MUST support both durable and transient + exchanges. + </doc> + <doc type="scenario"> + TODO. + </doc> + </rule> + </field> + + <field name="auto-delete" domain="bit" + label="auto-delete when unused"> + <doc> + If set, the exchange is deleted when all queues have + finished using it. + </doc> + <rule name="amq_exchange_02"> + <doc> + The server SHOULD allow for a reasonable delay between + the + point when it determines that an exchange is not being + used (or no longer used), and the point when it deletes + the exchange. At the least it must allow a client to + create an exchange and then bind a queue to it, with a + small but non-zero delay between these two actions. + </doc> + </rule> + <rule name="amq_exchange_25"> + <doc> + The server MUST ignore the auto-delete field if the + exchange already exists. + </doc> + </rule> + </field> + + <field name="internal" domain="bit" + label="create internal exchange"> + <doc> + If set, the exchange may not be used directly by publishers, + but only when bound to other exchanges. Internal exchanges + are used to construct wiring that is not visible to + applications. + </doc> + </field> + + <field name="no-wait" domain="no-wait"/> + + <field name="arguments" domain="table" + label="arguments for declaration"> + <doc> + A set of arguments for the declaration. The syntax and + semantics of these + arguments depends on the server implementation. + </doc> + </field> + </method> + + <method name="declare-ok" synchronous="1" index="11" + label="confirm exchange declaration"> + <doc> + This method confirms a Declare method and confirms the name of + the exchange, + essential for automatically-named exchanges. + </doc> + <chassis name="client" implement="MUST"/> + </method> + + <!-- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - --> + + <method name="delete" synchronous="1" index="20" + label="delete an exchange"> + <doc> + This method deletes an exchange. When an exchange is deleted all + queue bindings on + the exchange are cancelled. + </doc> + + <chassis name="server" implement="MUST"/> + <response name="delete-ok"/> + + <!-- Deprecated: "ticket", must be zero --> + <field name="reserved-1" type="short" reserved="1"/> + + <field name="exchange" domain="exchange-name"> + <rule name="exists" on-failure="not-found"> + <doc> + The client MUST NOT attempt to delete an exchange that + does not exist. + </doc> + </rule> + <assert check="notnull"/> + </field> + + <field name="if-unused" domain="bit" label="delete only if unused"> + <doc> + If set, the server will only delete the exchange if it has + no queue bindings. If + the exchange has queue bindings the server does not delete + it but raises a + channel exception instead. + </doc> + <rule name="in-use" on-failure="precondition-failed"> + <doc> + The server MUST NOT delete an exchange that has bindings + on it, if the if-unused + field is true. + </doc> + <doc type="scenario"> + The client declares an exchange, binds a queue to it, + then tries to delete it + setting if-unused to true. + </doc> + </rule> + </field> + + <field name="no-wait" domain="no-wait"/> + </method> + + <method name="delete-ok" synchronous="1" index="21" + label="confirm deletion of an exchange"> + <doc>This method confirms the deletion of an exchange.</doc> + <chassis name="client" implement="MUST"/> + </method> + + <!-- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - --> + + <method name="bind" synchronous="1" index="30" + label="bind exchange to an exchange"> + + <doc>This method binds an exchange to an exchange.</doc> + + <rule name="duplicates"> + <doc> + A server MUST allow and ignore duplicate bindings - that is, + two or more bind methods for a specific exchanges, with + identical arguments - without treating these as an error. + </doc> + <doc type="scenario"> + A client binds an exchange to an exchange. The client then + repeats the bind (with identical arguments). + </doc> + </rule> + + <rule name="cyclical"> + <doc> + A server MUST allow cycles of exchange bindings to be + created including allowing an exchange to be bound to + itself. + </doc> + <doc type="scenario"> + A client declares an exchange and binds it to itself. + </doc> + </rule> + + <rule name="unique"> + <doc> + A server MUST not deliver the same message more than once to + a destination exchange, even if the topology of exchanges + and bindings results in multiple (even infinite) routes to + that exchange. + </doc> + <doc type="scenario"> + A client declares an exchange and binds it using multiple + bindings to the amq.topic exchange. The client then + publishes a message to the amq.topic exchange that matches + all the bindings. + </doc> + </rule> + + <chassis name="server" implement="MUST"/> + + <response name="bind-ok"/> + + <!-- Deprecated: "ticket", must be zero --> + <field name="reserved-1" type="short" reserved="1"/> + + <field name="destination" domain="exchange-name" + label="name of the destination exchange to bind to"> + <doc>Specifies the name of the destination exchange to bind. + </doc> + <rule name="exchange-existence" on-failure="not-found"> + <doc> + A client MUST NOT be allowed to bind a non-existent + destination exchange. + </doc> + <doc type="scenario"> + A client attempts to bind an undeclared exchange to an + exchange. + </doc> + </rule> + <rule name="default-exchange"> + <doc> + The server MUST accept a blank exchange name to mean the + default exchange. + </doc> + <doc type="scenario"> + The client declares an exchange and binds a blank + exchange + name to it. + </doc> + </rule> + </field> + + <field name="source" domain="exchange-name" + label="name of the source exchange to bind to"> + <doc>Specifies the name of the source exchange to bind.</doc> + <rule name="exchange-existence" on-failure="not-found"> + <doc> + A client MUST NOT be allowed to bind a non-existent + source + exchange. + </doc> + <doc type="scenario"> + A client attempts to bind an exchange to an undeclared + exchange. + </doc> + </rule> + <rule name="default-exchange"> + <doc> + The server MUST accept a blank exchange name to mean the + default exchange. + </doc> + <doc type="scenario"> + The client declares an exchange and binds it to a blank + exchange name. + </doc> + </rule> + </field> + + <field name="routing-key" domain="shortstr" + label="message routing key"> + <doc> + Specifies the routing key for the binding. The routing key + is used for routing messages depending on the exchange + configuration. Not all exchanges use a routing key - refer + to the specific exchange documentation. + </doc> + </field> + + <field name="no-wait" domain="no-wait"/> + + <field name="arguments" domain="table" + label="arguments for binding"> + <doc> + A set of arguments for the binding. The syntax and semantics + of these arguments depends on the exchange class. + </doc> + </field> + </method> + + <method name="bind-ok" synchronous="1" index="31" + label="confirm bind successful"> + <doc>This method confirms that the bind was successful.</doc> + + <chassis name="client" implement="MUST"/> + </method> + + <!-- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - --> + + <method name="unbind" synchronous="1" index="40" + label="unbind an exchange from an exchange"> + <doc>This method unbinds an exchange from an exchange.</doc> + <rule name="01"> + <doc>If a unbind fails, the server MUST raise a connection + exception. + </doc> + </rule> + <chassis name="server" implement="MUST"/> + <response name="unbind-ok"/> + + <!-- Deprecated: "ticket", must be zero --> + <field name="reserved-1" type="short" reserved="1"/> + + <field name="destination" domain="exchange-name"> + <doc>Specifies the name of the destination exchange to unbind. + </doc> + <rule name="must-exist" on-failure="not-found"> + <doc> + The client MUST NOT attempt to unbind an exchange that + does not exist from an exchange. + </doc> + <doc type="scenario"> + The client attempts to unbind a non-existent exchange + from + an exchange. + </doc> + </rule> + <rule name="default-exchange"> + <doc> + The server MUST accept a blank exchange name to mean the + default exchange. + </doc> + <doc type="scenario"> + The client declares an exchange, binds a blank exchange + name to it, and then unbinds a blank exchange name from + it. + </doc> + </rule> + </field> + + <field name="source" domain="exchange-name"> + <doc>Specifies the name of the source exchange to unbind.</doc> + <rule name="must-exist" on-failure="not-found"> + <doc> + The client MUST NOT attempt to unbind an exchange from + an + exchange that does not exist. + </doc> + <doc type="scenario"> + The client attempts to unbind an exchange from a + non-existent exchange. + </doc> + </rule> + <rule name="default-exchange"> + <doc> + The server MUST accept a blank exchange name to mean the + default exchange. + </doc> + <doc type="scenario"> + The client declares an exchange, binds an exchange to a + blank exchange name, and then unbinds an exchange from a + black exchange name. + </doc> + </rule> + </field> + + <field name="routing-key" domain="shortstr" + label="routing key of binding"> + <doc>Specifies the routing key of the binding to unbind.</doc> + </field> + + <field name="no-wait" domain="no-wait"/> + + <field name="arguments" domain="table" + label="arguments of binding"> + <doc>Specifies the arguments of the binding to unbind.</doc> + </field> + </method> + + <method name="unbind-ok" synchronous="1" index="51" + label="confirm unbind successful"> + <doc>This method confirms that the unbind was successful.</doc> + <chassis name="client" implement="MUST"/> + </method> + + </class> + + <!-- == QUEUE ============================================================ --> + + <class name="queue" handler="channel" index="50" label="work with queues"> + <doc> + Queues store and forward messages. Queues can be configured in the + server or created at + runtime. Queues must be attached to at least one exchange in order + to receive messages + from publishers. + </doc> + + <doc type="grammar"> + queue = C:DECLARE S:DECLARE-OK + / C:BIND S:BIND-OK + / C:UNBIND S:UNBIND-OK + / C:PURGE S:PURGE-OK + / C:DELETE S:DELETE-OK + </doc> + + <chassis name="server" implement="MUST"/> + <chassis name="client" implement="MUST"/> + + <!-- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - --> + + <method name="declare" synchronous="1" index="10" + label="declare queue, create if needed"> + <doc> + This method creates or checks a queue. When creating a new queue + the client can + specify various properties that control the durability of the + queue and its + contents, and the level of sharing for the queue. + </doc> + + <rule name="default-binding"> + <doc> + The server MUST create a default binding for a + newly-declared queue to the + default exchange, which is an exchange of type 'direct' and + use the queue + name as the routing key. + </doc> + <doc type="scenario"> + Client declares a new queue, and then without explicitly + binding it to an + exchange, attempts to send a message through the default + exchange binding, + i.e. publish a message to the empty exchange, with the queue + name as routing + key. + </doc> + </rule> + + <rule name="minimum-queues"> + <doc> + The server SHOULD support a minimum of 256 queues per + virtual host and ideally, + impose no limit except as defined by available resources. + </doc> + <doc type="scenario"> + Client attempts to declare as many queues as it can until + the server reports + an error. The resulting count must at least be 256. + </doc> + </rule> + + <chassis name="server" implement="MUST"/> + <response name="declare-ok"/> + + <!-- Deprecated: "ticket", must be zero --> + <field name="reserved-1" type="short" reserved="1"/> + + <field name="queue" domain="queue-name"> + <rule name="default-name"> + <doc> + The queue name MAY be empty, in which case the server + MUST create a new + queue with a unique generated name and return this to + the client in the + Declare-Ok method. + </doc> + <doc type="scenario"> + Client attempts to declare several queues with an empty + name. The client then + verifies that the server-assigned names are unique and + different. + </doc> + </rule> + <rule name="reserved" on-failure="access-refused"> + <doc> + Queue names starting with "amq." are reserved for + pre-declared and + standardised queues. The client MAY declare a queue + starting with + "amq." if the passive option is set, or the queue + already exists. + </doc> + <doc type="scenario"> + The client attempts to declare a non-existing queue + starting with + "amq." and with the passive option set to zero. + </doc> + </rule> + <rule name="syntax" on-failure="precondition-failed"> + <doc> + The queue name can be empty, or a sequence of these + characters: + letters, digits, hyphen, underscore, period, or colon. + </doc> + <doc type="scenario"> + The client attempts to declare a queue with an illegal + name. + </doc> + </rule> + </field> + + <field name="passive" domain="bit" label="do not create queue"> + <doc> + If set, the server will reply with Declare-Ok if the queue + already + exists with the same name, and raise an error if not. The + client can + use this to check whether a queue exists without modifying + the + server state. When set, all other method fields except name + and no-wait + are ignored. A declare with both passive and no-wait has no + effect. + Arguments are compared for semantic equivalence. + </doc> + <rule name="passive" on-failure="not-found"> + <doc> + The client MAY ask the server to assert that a queue + exists without + creating the queue if not. If the queue does not exist, + the server + treats this as a failure. + </doc> + <doc type="scenario"> + Client declares an existing queue with the passive + option and expects + the server to respond with a declare-ok. Client then + attempts to declare + a non-existent queue with the passive option, and the + server must close + the channel with the correct reply-code. + </doc> + </rule> + <rule name="equivalent"> + <doc> + If not set and the queue exists, the server MUST check + that the + existing queue has the same values for durable, + exclusive, auto-delete, + and arguments fields. The server MUST respond with + Declare-Ok if the + requested queue matches these fields, and MUST raise a + channel exception + if not. + </doc> + <doc type="scenario"> + TODO. + </doc> + </rule> + </field> + + <field name="durable" domain="bit" label="request a durable queue"> + <doc> + If set when creating a new queue, the queue will be marked + as durable. Durable + queues remain active when a server restarts. Non-durable + queues (transient + queues) are purged if/when a server restarts. Note that + durable queues do not + necessarily hold persistent messages, although it does not + make sense to send + persistent messages to a transient queue. + </doc> + + <rule name="persistence"> + <doc>The server MUST recreate the durable queue after a + restart. + </doc> + + <doc type="scenario"> + Client declares a durable queue. The server is then + restarted. The client + then attempts to send a message to the queue. The + message should be successfully + delivered. + </doc> + </rule> + + <rule name="types"> + <doc>The server MUST support both durable and transient + queues. + </doc> + <doc type="scenario"> + A client declares two named queues, one durable and one + transient. + </doc> + </rule> + </field> + + <field name="exclusive" domain="bit" + label="request an exclusive queue"> + <doc> + Exclusive queues may only be accessed by the current + connection, and are + deleted when that connection closes. Passive declaration of + an exclusive + queue by other connections are not allowed. + </doc> + + <rule name="types"> + <doc> + The server MUST support both exclusive (private) and + non-exclusive (shared) + queues. + </doc> + <doc type="scenario"> + A client declares two named queues, one exclusive and + one non-exclusive. + </doc> + </rule> + + <rule name="exclusive" on-failure="resource-locked"> + <doc> + The client MAY NOT attempt to use a queue that was + declared as exclusive + by another still-open connection. + </doc> + <doc type="scenario"> + One client declares an exclusive queue. A second client + on a different + connection attempts to declare, bind, consume, purge, + delete, or declare + a queue of the same name. + </doc> + </rule> + </field> + + <field name="auto-delete" domain="bit" + label="auto-delete queue when unused"> + <doc> + If set, the queue is deleted when all consumers have + finished using it. The last + consumer can be cancelled either explicitly or because its + channel is closed. If + there was no consumer ever on the queue, it won't be + deleted. Applications can + explicitly delete auto-delete queues using the Delete method + as normal. + </doc> + + <rule name="pre-existence"> + <doc> + The server MUST ignore the auto-delete field if the + queue already exists. + </doc> + <doc type="scenario"> + Client declares two named queues, one as auto-delete and + one explicit-delete. + Client then attempts to declare the two queues using the + same names again, + but reversing the value of the auto-delete field in each + case. Verify that the + queues still exist with the original auto-delete flag + values. + </doc> + </rule> + </field> + + <field name="no-wait" domain="no-wait"/> + + <field name="arguments" domain="table" + label="arguments for declaration"> + <doc> + A set of arguments for the declaration. The syntax and + semantics of these + arguments depends on the server implementation. + </doc> + </field> + </method> + + <method name="declare-ok" synchronous="1" index="11" + label="confirms a queue definition"> + <doc> + This method confirms a Declare method and confirms the name of + the queue, essential + for automatically-named queues. + </doc> + + <chassis name="client" implement="MUST"/> + + <field name="queue" domain="queue-name"> + <doc> + Reports the name of the queue. If the server generated a + queue name, this field + contains that name. + </doc> + <assert check="notnull"/> + </field> + + <field name="message-count" domain="message-count"/> + + <field name="consumer-count" domain="long" + label="number of consumers"> + <doc> + Reports the number of active consumers for the queue. Note + that consumers can + suspend activity (Channel.Flow) in which case they do not + appear in this count. + </doc> + </field> + </method> + + <!-- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - --> + + <method name="bind" synchronous="1" index="20" + label="bind queue to an exchange"> + <doc> + This method binds a queue to an exchange. Until a queue is bound + it will not + receive any messages. In a classic messaging model, + store-and-forward queues + are bound to a direct exchange and subscription queues are bound + to a topic + exchange. + </doc> + + <rule name="duplicates"> + <doc> + A server MUST allow ignore duplicate bindings - that is, two + or more bind + methods for a specific queue, with identical arguments - + without treating these + as an error. + </doc> + <doc type="scenario"> + A client binds a named queue to an exchange. The client then + repeats the bind + (with identical arguments). + </doc> + </rule> + + <rule name="unique"> + <doc> + A server MUST not deliver the same message more than once to + a queue, even if + the queue has multiple bindings that match the message. + </doc> + <doc type="scenario"> + A client declares a named queue and binds it using multiple + bindings to the + amq.topic exchange. The client then publishes a message that + matches all its + bindings. + </doc> + </rule> + + <rule name="transient-exchange"> + <doc> + The server MUST allow a durable queue to bind to a transient + exchange. + </doc> + <doc type="scenario"> + A client declares a transient exchange. The client then + declares a named durable + queue and then attempts to bind the transient exchange to + the durable queue. + </doc> + </rule> + + <rule name="durable-exchange"> + <doc> + Bindings of durable queues to durable exchanges are + automatically durable + and the server MUST restore such bindings after a server + restart. + </doc> + <doc type="scenario"> + A server declares a named durable queue and binds it to a + durable exchange. The + server is restarted. The client then attempts to use the + queue/exchange combination. + </doc> + </rule> + + <rule name="binding-count"> + <doc> + The server SHOULD support at least 4 bindings per queue, and + ideally, impose no + limit except as defined by available resources. + </doc> + <doc type="scenario"> + A client declares a named queue and attempts to bind it to 4 + different + exchanges. + </doc> + </rule> + + <chassis name="server" implement="MUST"/> + + <response name="bind-ok"/> + + <!-- Deprecated: "ticket", must be zero --> + <field name="reserved-1" type="short" reserved="1"/> + + <field name="queue" domain="queue-name"> + <doc>Specifies the name of the queue to bind.</doc> + <rule name="queue-known" on-failure="not-found"> + <doc> + The client MUST either specify a queue name or have + previously declared a + queue on the same channel + </doc> + <doc type="scenario"> + The client opens a channel and attempts to bind an + unnamed queue. + </doc> + </rule> + <rule name="must-exist" on-failure="not-found"> + <doc> + The client MUST NOT attempt to bind a queue that does + not exist. + </doc> + <doc type="scenario"> + The client attempts to bind a non-existent queue. + </doc> + </rule> + </field> + + <field name="exchange" domain="exchange-name" + label="name of the exchange to bind to"> + <rule name="exchange-existence" on-failure="not-found"> + <doc> + A client MUST NOT be allowed to bind a queue to a + non-existent exchange. + </doc> + <doc type="scenario"> + A client attempts to bind an named queue to a undeclared + exchange. + </doc> + </rule> + <rule name="default-exchange"> + <doc> + The server MUST accept a blank exchange name to mean the + default exchange. + </doc> + <doc type="scenario"> + The client declares a queue and binds it to a blank + exchange name. + </doc> + </rule> + </field> + + <field name="routing-key" domain="shortstr" + label="message routing key"> + <doc> + Specifies the routing key for the binding. The routing key + is used for routing + messages depending on the exchange configuration. Not all + exchanges use a + routing key - refer to the specific exchange documentation. + If the queue name + is empty, the server uses the last queue declared on the + channel. If the + routing key is also empty, the server uses this queue name + for the routing + key as well. If the queue name is provided but the routing + key is empty, the + server does the binding with that empty routing key. The + meaning of empty + routing keys depends on the exchange implementation. + </doc> + <rule name="direct-exchange-key-matching"> + <doc> + If a message queue binds to a direct exchange using + routing key K and a + publisher sends the exchange a message with routing key + R, then the message + MUST be passed to the message queue if K = R. + </doc> + </rule> + </field> + + <field name="no-wait" domain="no-wait"/> + + <field name="arguments" domain="table" + label="arguments for binding"> + <doc> + A set of arguments for the binding. The syntax and semantics + of these arguments + depends on the exchange class. + </doc> + </field> + </method> + + <method name="bind-ok" synchronous="1" index="21" + label="confirm bind successful"> + <doc>This method confirms that the bind was successful.</doc> + + <chassis name="client" implement="MUST"/> + </method> + + <!-- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - --> + + <method name="unbind" synchronous="1" index="50" + label="unbind a queue from an exchange"> + <doc>This method unbinds a queue from an exchange.</doc> + <rule name="01"> + <doc>If a unbind fails, the server MUST raise a connection + exception. + </doc> + </rule> + <chassis name="server" implement="MUST"/> + <response name="unbind-ok"/> + + <!-- Deprecated: "ticket", must be zero --> + <field name="reserved-1" type="short" reserved="1"/> + + <field name="queue" domain="queue-name"> + <doc>Specifies the name of the queue to unbind.</doc> + <rule name="queue-known" on-failure="not-found"> + <doc> + The client MUST either specify a queue name or have + previously declared a + queue on the same channel + </doc> + <doc type="scenario"> + The client opens a channel and attempts to unbind an + unnamed queue. + </doc> + </rule> + <rule name="must-exist" on-failure="not-found"> + <doc> + The client MUST NOT attempt to unbind a queue that does + not exist. + </doc> + <doc type="scenario"> + The client attempts to unbind a non-existent queue. + </doc> + </rule> + </field> + + <field name="exchange" domain="exchange-name"> + <doc>The name of the exchange to unbind from.</doc> + <rule name="must-exist" on-failure="not-found"> + <doc> + The client MUST NOT attempt to unbind a queue from an + exchange that + does not exist. + </doc> + <doc type="scenario"> + The client attempts to unbind a queue from a + non-existent exchange. + </doc> + </rule> + <rule name="default-exchange"> + <doc> + The server MUST accept a blank exchange name to mean the + default exchange. + </doc> + <doc type="scenario"> + The client declares a queue and binds it to a blank + exchange name. + </doc> + </rule> + </field> + + <field name="routing-key" domain="shortstr" + label="routing key of binding"> + <doc>Specifies the routing key of the binding to unbind.</doc> + </field> + + <field name="arguments" domain="table" label="arguments of binding"> + <doc>Specifies the arguments of the binding to unbind.</doc> + </field> + </method> + + <method name="unbind-ok" synchronous="1" index="51" + label="confirm unbind successful"> + <doc>This method confirms that the unbind was successful.</doc> + <chassis name="client" implement="MUST"/> + </method> + + <!-- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - --> + + <method name="purge" synchronous="1" index="30" label="purge a queue"> + <doc> + This method removes all messages from a queue which are not + awaiting + acknowledgment. + </doc> + + <rule name="02"> + <doc> + The server MUST NOT purge messages that have already been + sent to a client + but not yet acknowledged. + </doc> + </rule> + + <rule name="03"> + <doc> + The server MAY implement a purge queue or log that allows + system administrators + to recover accidentally-purged messages. The server SHOULD + NOT keep purged + messages in the same storage spaces as the live messages + since the volumes of + purged messages may get very large. + </doc> + </rule> + + <chassis name="server" implement="MUST"/> + + <response name="purge-ok"/> + + <!-- Deprecated: "ticket", must be zero --> + <field name="reserved-1" type="short" reserved="1"/> + + <field name="queue" domain="queue-name"> + <doc>Specifies the name of the queue to purge.</doc> + <rule name="queue-known" on-failure="not-found"> + <doc> + The client MUST either specify a queue name or have + previously declared a + queue on the same channel + </doc> + <doc type="scenario"> + The client opens a channel and attempts to purge an + unnamed queue. + </doc> + </rule> + <rule name="must-exist" on-failure="not-found"> + <doc> + The client MUST NOT attempt to purge a queue that does + not exist. + </doc> + <doc type="scenario"> + The client attempts to purge a non-existent queue. + </doc> + </rule> + </field> + + <field name="no-wait" domain="no-wait"/> + </method> + + <method name="purge-ok" synchronous="1" index="31" + label="confirms a queue purge"> + <doc>This method confirms the purge of a queue.</doc> + + <chassis name="client" implement="MUST"/> + + <field name="message-count" domain="message-count"> + <doc> + Reports the number of messages purged. + </doc> + </field> + </method> + + <!-- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - --> + + <method name="delete" synchronous="1" index="40" label="delete a queue"> + <doc> + This method deletes a queue. When a queue is deleted any pending + messages are sent + to a dead-letter queue if this is defined in the server + configuration, and all + consumers on the queue are cancelled. + </doc> + + <rule name="01"> + <doc> + The server SHOULD use a dead-letter queue to hold messages + that were pending on + a deleted queue, and MAY provide facilities for a system + administrator to move + these messages back to an active queue. + </doc> + </rule> + + <chassis name="server" implement="MUST"/> + + <response name="delete-ok"/> + + <!-- Deprecated: "ticket", must be zero --> + <field name="reserved-1" type="short" reserved="1"/> + + <field name="queue" domain="queue-name"> + <doc>Specifies the name of the queue to delete.</doc> + <rule name="queue-known" on-failure="not-found"> + <doc> + The client MUST either specify a queue name or have + previously declared a + queue on the same channel + </doc> + <doc type="scenario"> + The client opens a channel and attempts to delete an + unnamed queue. + </doc> + </rule> + <rule name="must-exist" on-failure="not-found"> + <doc> + The client MUST NOT attempt to delete a queue that does + not exist. + </doc> + <doc type="scenario"> + The client attempts to delete a non-existent queue. + </doc> + </rule> + </field> + + <field name="if-unused" domain="bit" label="delete only if unused"> + <doc> + If set, the server will only delete the queue if it has no + consumers. If the + queue has consumers the server does does not delete it but + raises a channel + exception instead. + </doc> + <rule name="in-use" on-failure="precondition-failed"> + <doc> + The server MUST NOT delete a queue that has consumers on + it, if the if-unused + field is true. + </doc> + <doc type="scenario"> + The client declares a queue, and consumes from it, then + tries to delete it + setting if-unused to true. + </doc> + </rule> + </field> + + <field name="if-empty" domain="bit" label="delete only if empty"> + <doc> + If set, the server will only delete the queue if it has no + messages. + </doc> + <rule name="not-empty" on-failure="precondition-failed"> + <doc> + The server MUST NOT delete a queue that has messages on + it, if the + if-empty field is true. + </doc> + <doc type="scenario"> + The client declares a queue, binds it and publishes some + messages into it, + then tries to delete it setting if-empty to true. + </doc> + </rule> + </field> + + <field name="no-wait" domain="no-wait"/> + </method> + + <method name="delete-ok" synchronous="1" index="41" + label="confirm deletion of a queue"> + <doc>This method confirms the deletion of a queue.</doc> + + <chassis name="client" implement="MUST"/> + + <field name="message-count" domain="message-count"> + <doc>Reports the number of messages deleted.</doc> + </field> + </method> + </class> + + <!-- == BASIC ============================================================ --> + + <class name="basic" handler="channel" index="60" + label="work with basic content"> + <doc> + The Basic class provides methods that support an industry-standard + messaging model. + </doc> + + <doc type="grammar"> + basic = C:QOS S:QOS-OK + / C:CONSUME S:CONSUME-OK + / C:CANCEL S:CANCEL-OK + / C:PUBLISH content + / S:RETURN content + / S:DELIVER content + / C:GET ( S:GET-OK content / S:GET-EMPTY ) + / C:ACK + / S:ACK + / C:REJECT + / C:NACK + / S:NACK + / C:RECOVER-ASYNC + / C:RECOVER S:RECOVER-OK + </doc> + + <chassis name="server" implement="MUST"/> + <chassis name="client" implement="MAY"/> + + <rule name="01"> + <doc> + The server SHOULD respect the persistent property of basic + messages and + SHOULD make a best-effort to hold persistent basic messages on a + reliable + storage mechanism. + </doc> + <doc type="scenario"> + Send a persistent message to queue, stop server, restart server + and then + verify whether message is still present. Assumes that queues are + durable. + Persistence without durable queues makes no sense. + </doc> + </rule> + + <rule name="02"> + <doc> + The server MUST NOT discard a persistent basic message in case + of a queue + overflow. + </doc> + <doc type="scenario"> + Declare a queue overflow situation with persistent messages and + verify that + messages do not get lost (presumably the server will write them + to disk). + </doc> + </rule> + + <rule name="03"> + <doc> + The server MAY use the Channel.Flow method to slow or stop a + basic message + publisher when necessary. + </doc> + <doc type="scenario"> + Declare a queue overflow situation with non-persistent messages + and verify + whether the server responds with Channel.Flow or not. Repeat + with persistent + messages. + </doc> + </rule> + + <rule name="04"> + <doc> + The server MAY overflow non-persistent basic messages to + persistent + storage. + </doc> + <!-- Test scenario: untestable --> + </rule> + + <rule name="05"> + <doc> + The server MAY discard or dead-letter non-persistent basic + messages on a + priority basis if the queue size exceeds some configured limit. + </doc> + <!-- Test scenario: untestable --> + </rule> + + <rule name="06"> + <doc> + The server MUST implement at least 2 priority levels for basic + messages, + where priorities 0-4 and 5-9 are treated as two distinct levels. + </doc> + <doc type="scenario"> + Send a number of priority 0 messages to a queue. Send one + priority 9 + message. Consume messages from the queue and verify that the + first message + received was priority 9. + </doc> + </rule> + + <rule name="07"> + <doc> + The server MAY implement up to 10 priority levels. + </doc> + <doc type="scenario"> + Send a number of messages with mixed priorities to a queue, so + that all + priority values from 0 to 9 are exercised. A good scenario would + be ten + messages in low-to-high priority. Consume from queue and verify + how many + priority levels emerge. + </doc> + </rule> + + <rule name="08"> + <doc> + The server MUST deliver messages of the same priority in order + irrespective of + their individual persistence. + </doc> + <doc type="scenario"> + Send a set of messages with the same priority but different + persistence + settings to a queue. Consume and verify that messages arrive in + same order + as originally published. + </doc> + </rule> + + <rule name="09"> + <doc> + The server MUST support un-acknowledged delivery of Basic + content, i.e. + consumers with the no-ack field set to TRUE. + </doc> + </rule> + + <rule name="10"> + <doc> + The server MUST support explicitly acknowledged delivery of + Basic content, + i.e. consumers with the no-ack field set to FALSE. + </doc> + <doc type="scenario"> + Declare a queue and a consumer using explicit acknowledgements. + Publish a + set of messages to the queue. Consume the messages but + acknowledge only + half of them. Disconnect and reconnect, and consume from the + queue. + Verify that the remaining messages are received. + </doc> + </rule> + + <!-- These are the properties for a Basic content --> + + <!-- MIME typing --> + <field name="content-type" domain="shortstr" label="MIME content type"/> + <!-- MIME typing --> + <field name="content-encoding" domain="shortstr" + label="MIME content encoding"/> + <!-- For applications, and for header exchange routing --> + <field name="headers" domain="table" + label="message header field table"/> + <!-- For queues that implement persistence --> + <field name="delivery-mode" domain="octet" + label="non-persistent (1) or persistent (2)"/> + <!-- For queues that implement priorities --> + <field name="priority" domain="octet" label="message priority, 0 to 9"/> + <!-- For application use, no formal behaviour --> + <field name="correlation-id" domain="shortstr" + label="application correlation identifier"/> + <!-- For application use, no formal behaviour but may hold the name of a private response queue, when used in request messages --> - <field name = "reply-to" domain = "shortstr" label = "address to reply to" /> - <!-- For implementation use, no formal behaviour --> - <field name = "expiration" domain = "shortstr" label = "message expiration specification" /> - <!-- For application use, no formal behaviour --> - <field name = "message-id" domain = "shortstr" label = "application message identifier" /> - <!-- For application use, no formal behaviour --> - <field name = "timestamp" domain = "timestamp" label = "message timestamp" /> - <!-- For application use, no formal behaviour --> - <field name = "type" domain = "shortstr" label = "message type name" /> - <!-- For application use, no formal behaviour --> - <field name = "user-id" domain = "shortstr" label = "creating user id" /> - <!-- For application use, no formal behaviour --> - <field name = "app-id" domain = "shortstr" label = "creating application id" /> - <!-- Deprecated, was old cluster-id property --> - <field name = "reserved" domain = "shortstr" label = "reserved, must be empty" /> - - <!-- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - --> - - <method name = "qos" synchronous = "1" index = "10" label = "specify quality of service"> - <doc> - This method requests a specific quality of service. The QoS can be specified for the - current channel or for all channels on the connection. The particular properties and - semantics of a qos method always depend on the content class semantics. Though the - qos method could in principle apply to both peers, it is currently meaningful only - for the server. - </doc> - - <chassis name = "server" implement = "MUST" /> - <response name = "qos-ok" /> - - <field name = "prefetch-size" domain = "long" label = "prefetch window in octets"> - <doc> - The client can request that messages be sent in advance so that when the client - finishes processing a message, the following message is already held locally, - rather than needing to be sent down the channel. Prefetching gives a performance - improvement. This field specifies the prefetch window size in octets. The server - will send a message in advance if it is equal to or smaller in size than the - available prefetch size (and also falls into other prefetch limits). May be set - to zero, meaning "no specific limit", although other prefetch limits may still - apply. The prefetch-size is ignored if the no-ack option is set. - </doc> - <rule name = "01"> - <doc> - The server MUST ignore this setting when the client is not processing any - messages - i.e. the prefetch size does not limit the transfer of single - messages to a client, only the sending in advance of more messages while - the client still has one or more unacknowledged messages. - </doc> - <doc type = "scenario"> - Define a QoS prefetch-size limit and send a single message that exceeds - that limit. Verify that the message arrives correctly. - </doc> - </rule> - </field> - - <field name = "prefetch-count" domain = "short" label = "prefetch window in messages"> - <doc> - Specifies a prefetch window in terms of whole messages. This field may be used - in combination with the prefetch-size field; a message will only be sent in - advance if both prefetch windows (and those at the channel and connection level) - allow it. The prefetch-count is ignored if the no-ack option is set. - </doc> - <rule name = "01"> - <doc> - The server may send less data in advance than allowed by the client's - specified prefetch windows but it MUST NOT send more. - </doc> - <doc type = "scenario"> - Define a QoS prefetch-size limit and a prefetch-count limit greater than - one. Send multiple messages that exceed the prefetch size. Verify that - no more than one message arrives at once. - </doc> - </rule> - </field> - - <field name = "global" domain = "bit" label = "apply to entire connection"> - <doc> - RabbitMQ has reinterpreted this field. The original - specification said: "By default the QoS settings apply to - the current channel only. If this field is set, they are - applied to the entire connection." Instead, RabbitMQ takes - global=false to mean that the QoS settings should apply - per-consumer (for new consumers on the channel; existing - ones being unaffected) and global=true to mean that the QoS - settings should apply per-channel. - </doc> - </field> - </method> - - <method name = "qos-ok" synchronous = "1" index = "11" label = "confirm the requested qos"> - <doc> - This method tells the client that the requested QoS levels could be handled by the - server. The requested QoS applies to all active consumers until a new QoS is - defined. - </doc> - <chassis name = "client" implement = "MUST" /> - </method> - - <!-- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - --> - - <method name = "consume" synchronous = "1" index = "20" label = "start a queue consumer"> - <doc> - This method asks the server to start a "consumer", which is a transient request for - messages from a specific queue. Consumers last as long as the channel they were - declared on, or until the client cancels them. - </doc> - - <rule name = "01"> - <doc> - The server SHOULD support at least 16 consumers per queue, and ideally, impose - no limit except as defined by available resources. - </doc> - <doc type = "scenario"> - Declare a queue and create consumers on that queue until the server closes the - connection. Verify that the number of consumers created was at least sixteen - and report the total number. - </doc> - </rule> - - <chassis name = "server" implement = "MUST" /> - <response name = "consume-ok" /> - - <!-- Deprecated: "ticket", must be zero --> - <field name = "reserved-1" type = "short" reserved = "1" /> - - <field name = "queue" domain = "queue-name"> - <doc>Specifies the name of the queue to consume from.</doc> - </field> - - <field name = "consumer-tag" domain = "consumer-tag"> - <doc> - Specifies the identifier for the consumer. The consumer tag is local to a - channel, so two clients can use the same consumer tags. If this field is - empty the server will generate a unique tag. - </doc> - <rule name = "01" on-failure = "not-allowed"> - <doc> - The client MUST NOT specify a tag that refers to an existing consumer. - </doc> - <doc type = "scenario"> - Attempt to create two consumers with the same non-empty tag, on the - same channel. - </doc> - </rule> - <rule name = "02" on-failure = "not-allowed"> - <doc> - The consumer tag is valid only within the channel from which the - consumer was created. I.e. a client MUST NOT create a consumer in one - channel and then use it in another. - </doc> - <doc type = "scenario"> - Attempt to create a consumer in one channel, then use in another channel, - in which consumers have also been created (to test that the server uses - unique consumer tags). - </doc> - </rule> - </field> - - <field name = "no-local" domain = "no-local" /> - - <field name = "no-ack" domain = "no-ack" /> - - <field name = "exclusive" domain = "bit" label = "request exclusive access"> - <doc> - Request exclusive consumer access, meaning only this consumer can access the - queue. - </doc> - - <rule name = "01" on-failure = "access-refused"> - <doc> - The client MAY NOT gain exclusive access to a queue that already has - active consumers. - </doc> - <doc type = "scenario"> - Open two connections to a server, and in one connection declare a shared - (non-exclusive) queue and then consume from the queue. In the second - connection attempt to consume from the same queue using the exclusive - option. - </doc> - </rule> - </field> - - <field name = "no-wait" domain = "no-wait" /> - - <field name = "arguments" domain = "table" label = "arguments for declaration"> - <doc> - A set of arguments for the consume. The syntax and semantics of these - arguments depends on the server implementation. - </doc> - </field> - </method> - - <method name = "consume-ok" synchronous = "1" index = "21" label = "confirm a new consumer"> - <doc> - The server provides the client with a consumer tag, which is used by the client - for methods called on the consumer at a later stage. - </doc> - <chassis name = "client" implement = "MUST" /> - <field name = "consumer-tag" domain = "consumer-tag"> - <doc> - Holds the consumer tag specified by the client or provided by the server. - </doc> - </field> - </method> - - <!-- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - --> - - <method name = "cancel" synchronous = "1" index = "30" label = "end a queue consumer"> - <doc> - This method cancels a consumer. This does not affect already delivered - messages, but it does mean the server will not send any more messages for - that consumer. The client may receive an arbitrary number of messages in - between sending the cancel method and receiving the cancel-ok reply. - - It may also be sent from the server to the client in the event - of the consumer being unexpectedly cancelled (i.e. cancelled - for any reason other than the server receiving the - corresponding basic.cancel from the client). This allows - clients to be notified of the loss of consumers due to events - such as queue deletion. Note that as it is not a MUST for - clients to accept this method from the server, it is advisable - for the broker to be able to identify those clients that are - capable of accepting the method, through some means of - capability negotiation. - </doc> - - <rule name = "01"> - <doc> - If the queue does not exist the server MUST ignore the cancel method, so - long as the consumer tag is valid for that channel. - </doc> - <doc type = "scenario"> - TODO. - </doc> - </rule> - - <chassis name = "server" implement = "MUST" /> - <chassis name = "client" implement = "SHOULD" /> - <response name = "cancel-ok" /> - - <field name = "consumer-tag" domain = "consumer-tag" /> - <field name = "no-wait" domain = "no-wait" /> - </method> - - <method name = "cancel-ok" synchronous = "1" index = "31" label = "confirm a cancelled consumer"> - <doc> - This method confirms that the cancellation was completed. - </doc> - <chassis name = "client" implement = "MUST" /> - <chassis name = "server" implement = "MAY" /> - <field name = "consumer-tag" domain = "consumer-tag" /> - </method> - - <!-- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - --> - - <method name = "publish" content = "1" index = "40" label = "publish a message"> - <doc> - This method publishes a message to a specific exchange. The message will be routed - to queues as defined by the exchange configuration and distributed to any active - consumers when the transaction, if any, is committed. - </doc> - - <chassis name = "server" implement = "MUST" /> - - <!-- Deprecated: "ticket", must be zero --> - <field name = "reserved-1" type = "short" reserved = "1" /> - - <field name = "exchange" domain = "exchange-name"> - <doc> - Specifies the name of the exchange to publish to. The exchange name can be - empty, meaning the default exchange. If the exchange name is specified, and that - exchange does not exist, the server will raise a channel exception. - </doc> - - <rule name = "must-exist" on-failure = "not-found"> - <doc> - The client MUST NOT attempt to publish a content to an exchange that - does not exist. - </doc> - <doc type = "scenario"> - The client attempts to publish a content to a non-existent exchange. - </doc> - </rule> - <rule name = "default-exchange"> - <doc> - The server MUST accept a blank exchange name to mean the default exchange. - </doc> - <doc type = "scenario"> - The client declares a queue and binds it to a blank exchange name. - </doc> - </rule> - <rule name = "02"> - <doc> - If the exchange was declared as an internal exchange, the server MUST raise - a channel exception with a reply code 403 (access refused). - </doc> - <doc type = "scenario"> - TODO. - </doc> - </rule> - - <rule name = "03"> - <doc> - The exchange MAY refuse basic content in which case it MUST raise a channel - exception with reply code 540 (not implemented). - </doc> - <doc type = "scenario"> - TODO. - </doc> - </rule> - </field> - - <field name = "routing-key" domain = "shortstr" label = "Message routing key"> - <doc> - Specifies the routing key for the message. The routing key is used for routing - messages depending on the exchange configuration. - </doc> - </field> - - <field name = "mandatory" domain = "bit" label = "indicate mandatory routing"> - <doc> - This flag tells the server how to react if the message cannot be routed to a - queue. If this flag is set, the server will return an unroutable message with a - Return method. If this flag is zero, the server silently drops the message. - </doc> - - <rule name = "01"> - <doc> - The server SHOULD implement the mandatory flag. - </doc> - <doc type = "scenario"> - TODO. - </doc> - </rule> - </field> - - <field name = "immediate" domain = "bit" label = "request immediate delivery"> - <doc> - This flag tells the server how to react if the message cannot be routed to a - queue consumer immediately. If this flag is set, the server will return an - undeliverable message with a Return method. If this flag is zero, the server - will queue the message, but with no guarantee that it will ever be consumed. - </doc> - - <rule name = "01"> - <doc> - The server SHOULD implement the immediate flag. - </doc> - <doc type = "scenario"> - TODO. - </doc> - </rule> - </field> - </method> - - <method name = "return" content = "1" index = "50" label = "return a failed message"> - <doc> - This method returns an undeliverable message that was published with the "immediate" - flag set, or an unroutable message published with the "mandatory" flag set. The - reply code and text provide information about the reason that the message was - undeliverable. - </doc> - - <chassis name = "client" implement = "MUST" /> - - <field name = "reply-code" domain = "reply-code" /> - <field name = "reply-text" domain = "reply-text" /> - - <field name = "exchange" domain = "exchange-name"> - <doc> - Specifies the name of the exchange that the message was originally published - to. May be empty, meaning the default exchange. - </doc> - </field> - - <field name = "routing-key" domain = "shortstr" label = "Message routing key"> - <doc> - Specifies the routing key name specified when the message was published. - </doc> - </field> - </method> - - <!-- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - --> - - <method name = "deliver" content = "1" index = "60" - label = "notify the client of a consumer message"> - <doc> - This method delivers a message to the client, via a consumer. In the asynchronous - message delivery model, the client starts a consumer using the Consume method, then - the server responds with Deliver methods as and when messages arrive for that - consumer. - </doc> - - <rule name = "01"> - <doc> - The server SHOULD track the number of times a message has been delivered to - clients and when a message is redelivered a certain number of times - e.g. 5 - times - without being acknowledged, the server SHOULD consider the message to be - unprocessable (possibly causing client applications to abort), and move the - message to a dead letter queue. - </doc> - <doc type = "scenario"> - TODO. - </doc> - </rule> - - <chassis name = "client" implement = "MUST" /> - - <field name = "consumer-tag" domain = "consumer-tag" /> - <field name = "delivery-tag" domain = "delivery-tag" /> - <field name = "redelivered" domain = "redelivered" /> - - <field name = "exchange" domain = "exchange-name"> - <doc> - Specifies the name of the exchange that the message was originally published to. - May be empty, indicating the default exchange. - </doc> - </field> - - <field name = "routing-key" domain = "shortstr" label = "Message routing key"> - <doc>Specifies the routing key name specified when the message was published.</doc> - </field> - </method> - - <!-- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - --> - - <method name = "get" synchronous = "1" index = "70" label = "direct access to a queue"> - <doc> - This method provides a direct access to the messages in a queue using a synchronous - dialogue that is designed for specific types of application where synchronous - functionality is more important than performance. - </doc> - - <response name = "get-ok" /> - <response name = "get-empty" /> - <chassis name = "server" implement = "MUST" /> - - <!-- Deprecated: "ticket", must be zero --> - <field name = "reserved-1" type = "short" reserved = "1" /> - - <field name = "queue" domain = "queue-name"> - <doc>Specifies the name of the queue to get a message from.</doc> - </field> - <field name = "no-ack" domain = "no-ack" /> - </method> - - <method name = "get-ok" synchronous = "1" content = "1" index = "71" - label = "provide client with a message"> - <doc> - This method delivers a message to the client following a get method. A message - delivered by 'get-ok' must be acknowledged unless the no-ack option was set in the - get method. - </doc> - - <chassis name = "client" implement = "MAY" /> - - <field name = "delivery-tag" domain = "delivery-tag" /> - <field name = "redelivered" domain = "redelivered" /> - <field name = "exchange" domain = "exchange-name"> - <doc> - Specifies the name of the exchange that the message was originally published to. - If empty, the message was published to the default exchange. - </doc> - </field> - - <field name = "routing-key" domain = "shortstr" label = "Message routing key"> - <doc>Specifies the routing key name specified when the message was published.</doc> - </field> - - <field name = "message-count" domain = "message-count" /> - </method> - - <method name = "get-empty" synchronous = "1" index = "72" - label = "indicate no messages available"> - <doc> - This method tells the client that the queue has no messages available for the - client. - </doc> - <chassis name = "client" implement = "MAY" /> - <!-- Deprecated: "cluster-id", must be empty --> - <field name = "reserved-1" type = "shortstr" reserved = "1" /> - </method> - - <!-- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - --> - - <method name = "ack" index = "80" label = "acknowledge one or more messages"> - <doc> - When sent by the client, this method acknowledges one or more - messages delivered via the Deliver or Get-Ok methods. - - When sent by server, this method acknowledges one or more - messages published with the Publish method on a channel in - confirm mode. - - The acknowledgement can be for a single message or a set of - messages up to and including a specific message. - </doc> - - <chassis name = "server" implement = "MUST" /> - <chassis name ="client" implement = "MUST"/> - - <field name = "delivery-tag" domain = "delivery-tag" /> - <field name = "multiple" domain = "bit" label = "acknowledge multiple messages"> - <doc> - If set to 1, the delivery tag is treated as "up to and - including", so that multiple messages can be acknowledged - with a single method. If set to zero, the delivery tag - refers to a single message. If the multiple field is 1, and - the delivery tag is zero, this indicates acknowledgement of - all outstanding messages. - </doc> - <rule name = "exists" on-failure = "precondition-failed"> - <doc> - A message MUST not be acknowledged more than once. The - receiving peer MUST validate that a non-zero delivery-tag - refers to a delivered message, and raise a channel - exception if this is not the case. On a transacted - channel, this check MUST be done immediately and not - delayed until a Tx.Commit. - </doc> - <doc type = "scenario"> - TODO. - </doc> - </rule> - </field> - </method> - - <!-- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - --> - - <method name = "reject" index = "90" label = "reject an incoming message"> - <doc> - This method allows a client to reject a message. It can be used to interrupt and - cancel large incoming messages, or return untreatable messages to their original - queue. - </doc> - - <rule name = "01"> - <doc> - The server SHOULD be capable of accepting and process the Reject method while - sending message content with a Deliver or Get-Ok method. I.e. the server should - read and process incoming methods while sending output frames. To cancel a - partially-send content, the server sends a content body frame of size 1 (i.e. - with no data except the frame-end octet). - </doc> - </rule> - - <rule name = "02"> - <doc> - The server SHOULD interpret this method as meaning that the client is unable to - process the message at this time. - </doc> - <doc type = "scenario"> - TODO. - </doc> - </rule> - - <rule name = "03"> - <doc> - The client MUST NOT use this method as a means of selecting messages to process. - </doc> - <doc type = "scenario"> - TODO. - </doc> - </rule> - - <chassis name = "server" implement = "MUST" /> - - <field name = "delivery-tag" domain = "delivery-tag" /> - - <field name = "requeue" domain = "bit" label = "requeue the message"> - <doc> - If requeue is true, the server will attempt to requeue the message. If requeue - is false or the requeue attempt fails the messages are discarded or dead-lettered. - </doc> - - <rule name = "01"> - <doc> - The server MUST NOT deliver the message to the same client within the - context of the current channel. The recommended strategy is to attempt to - deliver the message to an alternative consumer, and if that is not possible, - to move the message to a dead-letter queue. The server MAY use more - sophisticated tracking to hold the message on the queue and redeliver it to - the same client at a later stage. - </doc> - <doc type = "scenario"> - TODO. - </doc> - </rule> - </field> - </method> - - <!-- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - --> - - <method name = "recover-async" index = "100" label = "redeliver unacknowledged messages" - deprecated = "1"> - <doc> - This method asks the server to redeliver all unacknowledged messages on a - specified channel. Zero or more messages may be redelivered. This method - is deprecated in favour of the synchronous Recover/Recover-Ok. - </doc> - <rule name = "01"> - <doc> - The server MUST set the redelivered flag on all messages that are resent. - </doc> - <doc type = "scenario"> - TODO. - </doc> - </rule> - <chassis name = "server" implement = "MAY" /> - <field name = "requeue" domain = "bit" label = "requeue the message"> - <doc> - If this field is zero, the message will be redelivered to the original - recipient. If this bit is 1, the server will attempt to requeue the message, - potentially then delivering it to an alternative subscriber. - </doc> - </field> - </method> - - <!-- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - --> - - <method name = "recover" index = "110" label = "redeliver unacknowledged messages"> - <doc> - This method asks the server to redeliver all unacknowledged messages on a - specified channel. Zero or more messages may be redelivered. This method - replaces the asynchronous Recover. - </doc> - <rule name = "01"> - <doc> - The server MUST set the redelivered flag on all messages that are resent. - </doc> - <doc type = "scenario"> - TODO. - </doc> - </rule> - <chassis name = "server" implement = "MUST" /> - <field name = "requeue" domain = "bit" label = "requeue the message"> - <doc> - If this field is zero, the message will be redelivered to the original - recipient. If this bit is 1, the server will attempt to requeue the message, - potentially then delivering it to an alternative subscriber. - </doc> - </field> - </method> - - <method name = "recover-ok" synchronous = "1" index = "111" label = "confirm recovery"> - <doc> - This method acknowledges a Basic.Recover method. - </doc> - <chassis name = "client" implement = "MUST" /> - </method> - - <method name = "nack" index = "120" label = "reject one or more incoming messages"> - <doc> - This method allows a client to reject one or more incoming messages. It can be - used to interrupt and cancel large incoming messages, or return untreatable - messages to their original queue. - - This method is also used by the server to inform publishers on channels in - confirm mode of unhandled messages. If a publisher receives this method, it - probably needs to republish the offending messages. - </doc> - - <rule name = "01"> - <doc> - The server SHOULD be capable of accepting and processing the Nack method while - sending message content with a Deliver or Get-Ok method. I.e. the server should - read and process incoming methods while sending output frames. To cancel a - partially-send content, the server sends a content body frame of size 1 (i.e. - with no data except the frame-end octet). - </doc> - </rule> - - <rule name = "02"> - <doc> - The server SHOULD interpret this method as meaning that the client is unable to - process the message at this time. - </doc> - <doc type = "scenario"> - TODO. - </doc> - </rule> - - <rule name = "03"> - <doc> - The client MUST NOT use this method as a means of selecting messages to process. - </doc> - <doc type = "scenario"> - TODO. - </doc> - </rule> - - <rule name = "04"> - <doc> - A client publishing messages to a channel in confirm mode SHOULD be capable of accepting - and somehow handling the Nack method. - </doc> - <doc type = "scenario"> - TODO - </doc> - </rule> - - <chassis name = "server" implement = "MUST" /> - <chassis name = "client" implement = "MUST" /> - - <field name = "delivery-tag" domain = "delivery-tag" /> - - <field name = "multiple" domain = "bit" label = "reject multiple messages"> - <doc> - If set to 1, the delivery tag is treated as "up to and - including", so that multiple messages can be rejected - with a single method. If set to zero, the delivery tag - refers to a single message. If the multiple field is 1, and - the delivery tag is zero, this indicates rejection of - all outstanding messages. - </doc> - <rule name = "exists" on-failure = "precondition-failed"> - <doc> - A message MUST not be rejected more than once. The - receiving peer MUST validate that a non-zero delivery-tag - refers to an unacknowledged, delivered message, and - raise a channel exception if this is not the case. - </doc> - <doc type = "scenario"> - TODO. - </doc> - </rule> - </field> - - <field name = "requeue" domain = "bit" label = "requeue the message"> - <doc> - If requeue is true, the server will attempt to requeue the message. If requeue - is false or the requeue attempt fails the messages are discarded or dead-lettered. - Clients receiving the Nack methods should ignore this flag. - </doc> - - <rule name = "01"> - <doc> - The server MUST NOT deliver the message to the same client within the - context of the current channel. The recommended strategy is to attempt to - deliver the message to an alternative consumer, and if that is not possible, - to move the message to a dead-letter queue. The server MAY use more - sophisticated tracking to hold the message on the queue and redeliver it to - the same client at a later stage. - </doc> - <doc type = "scenario"> - TODO. - </doc> - </rule> - </field> - </method> - - </class> - - <!-- == TX =============================================================== --> - - <class name = "tx" handler = "channel" index = "90" label = "work with transactions"> - <doc> - The Tx class allows publish and ack operations to be batched into atomic - units of work. The intention is that all publish and ack requests issued - within a transaction will complete successfully or none of them will. - Servers SHOULD implement atomic transactions at least where all publish - or ack requests affect a single queue. Transactions that cover multiple - queues may be non-atomic, given that queues can be created and destroyed - asynchronously, and such events do not form part of any transaction. - Further, the behaviour of transactions with respect to the immediate and - mandatory flags on Basic.Publish methods is not defined. - </doc> - - <rule name = "not multiple queues"> - <doc> - Applications MUST NOT rely on the atomicity of transactions that - affect more than one queue. - </doc> - </rule> - <rule name = "not immediate"> - <doc> - Applications MUST NOT rely on the behaviour of transactions that - include messages published with the immediate option. - </doc> - </rule> - <rule name = "not mandatory"> - <doc> - Applications MUST NOT rely on the behaviour of transactions that - include messages published with the mandatory option. - </doc> - </rule> - - <doc type = "grammar"> - tx = C:SELECT S:SELECT-OK - / C:COMMIT S:COMMIT-OK - / C:ROLLBACK S:ROLLBACK-OK - </doc> - - <chassis name = "server" implement = "SHOULD" /> - <chassis name = "client" implement = "MAY" /> - - <!-- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - --> - - <method name = "select" synchronous = "1" index = "10" label = "select standard transaction mode"> - <doc> - This method sets the channel to use standard transactions. The client must use this - method at least once on a channel before using the Commit or Rollback methods. - </doc> - <chassis name = "server" implement = "MUST" /> - <response name = "select-ok" /> - </method> - - <method name = "select-ok" synchronous = "1" index = "11" label = "confirm transaction mode"> - <doc> - This method confirms to the client that the channel was successfully set to use - standard transactions. - </doc> - <chassis name = "client" implement = "MUST" /> - </method> - - <!-- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - --> - - <method name = "commit" synchronous = "1" index = "20" label = "commit the current transaction"> - <doc> - This method commits all message publications and acknowledgments performed in - the current transaction. A new transaction starts immediately after a commit. - </doc> - <chassis name = "server" implement = "MUST" /> - <response name = "commit-ok" /> - - <rule name = "transacted" on-failure = "precondition-failed"> - <doc> - The client MUST NOT use the Commit method on non-transacted channels. - </doc> - <doc type = "scenario"> - The client opens a channel and then uses Tx.Commit. - </doc> - </rule> - </method> - - <method name = "commit-ok" synchronous = "1" index = "21" label = "confirm a successful commit"> - <doc> - This method confirms to the client that the commit succeeded. Note that if a commit - fails, the server raises a channel exception. - </doc> - <chassis name = "client" implement = "MUST" /> - </method> - - <!-- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - --> - - <method name = "rollback" synchronous = "1" index = "30" - label = "abandon the current transaction"> - <doc> - This method abandons all message publications and acknowledgments performed in - the current transaction. A new transaction starts immediately after a rollback. - Note that unacked messages will not be automatically redelivered by rollback; - if that is required an explicit recover call should be issued. - </doc> - <chassis name = "server" implement = "MUST" /> - <response name = "rollback-ok" /> - - <rule name = "transacted" on-failure = "precondition-failed"> - <doc> - The client MUST NOT use the Rollback method on non-transacted channels. - </doc> - <doc type = "scenario"> - The client opens a channel and then uses Tx.Rollback. - </doc> - </rule> - </method> - - <method name = "rollback-ok" synchronous = "1" index = "31" label = "confirm successful rollback"> - <doc> - This method confirms to the client that the rollback succeeded. Note that if an - rollback fails, the server raises a channel exception. - </doc> - <chassis name = "client" implement = "MUST" /> - </method> - </class> - - <!-- == CONFIRM ========================================================== --> - - <class name = "confirm" handler = "channel" index = "85" label = "work with confirms"> - <doc> - The Confirm class allows publishers to put the channel in - confirm mode and subsequently be notified when messages have been - handled by the broker. The intention is that all messages - published on a channel in confirm mode will be acknowledged at - some point. By acknowledging a message the broker assumes - responsibility for it and indicates that it has done something - it deems reasonable with it. - - Unroutable mandatory or immediate messages are acknowledged - right after the Basic.Return method. Messages are acknowledged - when all queues to which the message has been routed - have either delivered the message and received an - acknowledgement (if required), or enqueued the message (and - persisted it if required). - - Published messages are assigned ascending sequence numbers, - starting at 1 with the first Confirm.Select method. The server - confirms messages by sending Basic.Ack methods referring to these - sequence numbers. - </doc> - - <rule name = "all messages acknowledged"> - <doc> - The server MUST acknowledge all messages received after the - channel was put into confirm mode. - </doc> - </rule> - - <rule name = "all queues"> - <doc> - The server MUST acknowledge a message only after it was - properly handled by all the queues it was delivered to. - </doc> - </rule> - - <rule name = "unroutable messages"> - <doc> - The server MUST acknowledge an unroutable mandatory or - immediate message only after it sends the Basic.Return. - </doc> - </rule> - - <rule name = "time guarantees"> - <doc> - No guarantees are made as to how soon a message is - acknowledged. Applications SHOULD NOT make assumptions about - this. - </doc> - </rule> - - <doc type = "grammar"> - confirm = C:SELECT S:SELECT-OK - </doc> - - <chassis name = "server" implement = "SHOULD" /> - <chassis name = "client" implement = "MAY" /> - - <!-- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - --> - - <method name="select" synchronous="1" index="10"> - select confirm mode (i.e. enable publisher acknowledgements) - <doc> - This method sets the channel to use publisher acknowledgements. - The client can only use this method on a non-transactional - channel. - </doc> - <chassis name="server" implement="MUST"/> - <response name="select-ok"/> - <field name = "nowait" type = "bit"> - do not send a reply method - <doc> - If set, the server will not respond to the method. The client should - not wait for a reply method. If the server could not complete the - method it will raise a channel or connection exception. - </doc> - </field> - </method> - - <method name="select-ok" synchronous="1" index="11"> - acknowledge confirm mode - <doc> - This method confirms to the client that the channel was successfully - set to use publisher acknowledgements. - </doc> - <chassis name="client" implement="MUST"/> - </method> - </class> + <field name="reply-to" domain="shortstr" label="address to reply to"/> + <!-- For implementation use, no formal behaviour --> + <field name="expiration" domain="shortstr" + label="message expiration specification"/> + <!-- For application use, no formal behaviour --> + <field name="message-id" domain="shortstr" + label="application message identifier"/> + <!-- For application use, no formal behaviour --> + <field name="timestamp" domain="timestamp" label="message timestamp"/> + <!-- For application use, no formal behaviour --> + <field name="type" domain="shortstr" label="message type name"/> + <!-- For application use, no formal behaviour --> + <field name="user-id" domain="shortstr" label="creating user id"/> + <!-- For application use, no formal behaviour --> + <field name="app-id" domain="shortstr" label="creating application id"/> + <!-- Deprecated, was old cluster-id property --> + <field name="reserved" domain="shortstr" + label="reserved, must be empty"/> + + <!-- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - --> + + <method name="qos" synchronous="1" index="10" + label="specify quality of service"> + <doc> + This method requests a specific quality of service. The QoS can + be specified for the + current channel or for all channels on the connection. The + particular properties and + semantics of a qos method always depend on the content class + semantics. Though the + qos method could in principle apply to both peers, it is + currently meaningful only + for the server. + </doc> + + <chassis name="server" implement="MUST"/> + <response name="qos-ok"/> + + <field name="prefetch-size" domain="long" + label="prefetch window in octets"> + <doc> + The client can request that messages be sent in advance so + that when the client + finishes processing a message, the following message is + already held locally, + rather than needing to be sent down the channel. Prefetching + gives a performance + improvement. This field specifies the prefetch window size + in octets. The server + will send a message in advance if it is equal to or smaller + in size than the + available prefetch size (and also falls into other prefetch + limits). May be set + to zero, meaning "no specific limit", although other + prefetch limits may still + apply. The prefetch-size is ignored if the no-ack option is + set. + </doc> + <rule name="01"> + <doc> + The server MUST ignore this setting when the client is + not processing any + messages - i.e. the prefetch size does not limit the + transfer of single + messages to a client, only the sending in advance of + more messages while + the client still has one or more unacknowledged + messages. + </doc> + <doc type="scenario"> + Define a QoS prefetch-size limit and send a single + message that exceeds + that limit. Verify that the message arrives correctly. + </doc> + </rule> + </field> + + <field name="prefetch-count" domain="short" + label="prefetch window in messages"> + <doc> + Specifies a prefetch window in terms of whole messages. This + field may be used + in combination with the prefetch-size field; a message will + only be sent in + advance if both prefetch windows (and those at the channel + and connection level) + allow it. The prefetch-count is ignored if the no-ack option + is set. + </doc> + <rule name="01"> + <doc> + The server may send less data in advance than allowed by + the client's + specified prefetch windows but it MUST NOT send more. + </doc> + <doc type="scenario"> + Define a QoS prefetch-size limit and a prefetch-count + limit greater than + one. Send multiple messages that exceed the prefetch + size. Verify that + no more than one message arrives at once. + </doc> + </rule> + </field> + + <field name="global" domain="bit" + label="apply to entire connection"> + <doc> + RabbitMQ has reinterpreted this field. The original + specification said: "By default the QoS settings apply to + the current channel only. If this field is set, they are + applied to the entire connection." Instead, RabbitMQ takes + global=false to mean that the QoS settings should apply + per-consumer (for new consumers on the channel; existing + ones being unaffected) and global=true to mean that the QoS + settings should apply per-channel. + </doc> + </field> + </method> + + <method name="qos-ok" synchronous="1" index="11" + label="confirm the requested qos"> + <doc> + This method tells the client that the requested QoS levels could + be handled by the + server. The requested QoS applies to all active consumers until + a new QoS is + defined. + </doc> + <chassis name="client" implement="MUST"/> + </method> + + <!-- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - --> + + <method name="consume" synchronous="1" index="20" + label="start a queue consumer"> + <doc> + This method asks the server to start a "consumer", which is a + transient request for + messages from a specific queue. Consumers last as long as the + channel they were + declared on, or until the client cancels them. + </doc> + + <rule name="01"> + <doc> + The server SHOULD support at least 16 consumers per queue, + and ideally, impose + no limit except as defined by available resources. + </doc> + <doc type="scenario"> + Declare a queue and create consumers on that queue until the + server closes the + connection. Verify that the number of consumers created was + at least sixteen + and report the total number. + </doc> + </rule> + + <chassis name="server" implement="MUST"/> + <response name="consume-ok"/> + + <!-- Deprecated: "ticket", must be zero --> + <field name="reserved-1" type="short" reserved="1"/> + + <field name="queue" domain="queue-name"> + <doc>Specifies the name of the queue to consume from.</doc> + </field> + + <field name="consumer-tag" domain="consumer-tag"> + <doc> + Specifies the identifier for the consumer. The consumer tag + is local to a + channel, so two clients can use the same consumer tags. If + this field is + empty the server will generate a unique tag. + </doc> + <rule name="01" on-failure="not-allowed"> + <doc> + The client MUST NOT specify a tag that refers to an + existing consumer. + </doc> + <doc type="scenario"> + Attempt to create two consumers with the same non-empty + tag, on the + same channel. + </doc> + </rule> + <rule name="02" on-failure="not-allowed"> + <doc> + The consumer tag is valid only within the channel from + which the + consumer was created. I.e. a client MUST NOT create a + consumer in one + channel and then use it in another. + </doc> + <doc type="scenario"> + Attempt to create a consumer in one channel, then use in + another channel, + in which consumers have also been created (to test that + the server uses + unique consumer tags). + </doc> + </rule> + </field> + + <field name="no-local" domain="no-local"/> + + <field name="no-ack" domain="no-ack"/> + + <field name="exclusive" domain="bit" + label="request exclusive access"> + <doc> + Request exclusive consumer access, meaning only this + consumer can access the + queue. + </doc> + + <rule name="01" on-failure="access-refused"> + <doc> + The client MAY NOT gain exclusive access to a queue that + already has + active consumers. + </doc> + <doc type="scenario"> + Open two connections to a server, and in one connection + declare a shared + (non-exclusive) queue and then consume from the queue. + In the second + connection attempt to consume from the same queue using + the exclusive + option. + </doc> + </rule> + </field> + + <field name="no-wait" domain="no-wait"/> + + <field name="arguments" domain="table" + label="arguments for declaration"> + <doc> + A set of arguments for the consume. The syntax and semantics + of these + arguments depends on the server implementation. + </doc> + </field> + </method> + + <method name="consume-ok" synchronous="1" index="21" + label="confirm a new consumer"> + <doc> + The server provides the client with a consumer tag, which is + used by the client + for methods called on the consumer at a later stage. + </doc> + <chassis name="client" implement="MUST"/> + <field name="consumer-tag" domain="consumer-tag"> + <doc> + Holds the consumer tag specified by the client or provided + by the server. + </doc> + </field> + </method> + + <!-- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - --> + + <method name="cancel" synchronous="1" index="30" + label="end a queue consumer"> + <doc> + This method cancels a consumer. This does not affect already + delivered + messages, but it does mean the server will not send any more + messages for + that consumer. The client may receive an arbitrary number of + messages in + between sending the cancel method and receiving the cancel-ok + reply. + + It may also be sent from the server to the client in the event + of the consumer being unexpectedly cancelled (i.e. cancelled + for any reason other than the server receiving the + corresponding basic.cancel from the client). This allows + clients to be notified of the loss of consumers due to events + such as queue deletion. Note that as it is not a MUST for + clients to accept this method from the server, it is advisable + for the broker to be able to identify those clients that are + capable of accepting the method, through some means of + capability negotiation. + </doc> + + <rule name="01"> + <doc> + If the queue does not exist the server MUST ignore the + cancel method, so + long as the consumer tag is valid for that channel. + </doc> + <doc type="scenario"> + TODO. + </doc> + </rule> + + <chassis name="server" implement="MUST"/> + <chassis name="client" implement="SHOULD"/> + <response name="cancel-ok"/> + + <field name="consumer-tag" domain="consumer-tag"/> + <field name="no-wait" domain="no-wait"/> + </method> + + <method name="cancel-ok" synchronous="1" index="31" + label="confirm a cancelled consumer"> + <doc> + This method confirms that the cancellation was completed. + </doc> + <chassis name="client" implement="MUST"/> + <chassis name="server" implement="MAY"/> + <field name="consumer-tag" domain="consumer-tag"/> + </method> + + <!-- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - --> + + <method name="publish" content="1" index="40" label="publish a message"> + <doc> + This method publishes a message to a specific exchange. The + message will be routed + to queues as defined by the exchange configuration and + distributed to any active + consumers when the transaction, if any, is committed. + </doc> + + <chassis name="server" implement="MUST"/> + + <!-- Deprecated: "ticket", must be zero --> + <field name="reserved-1" type="short" reserved="1"/> + + <field name="exchange" domain="exchange-name"> + <doc> + Specifies the name of the exchange to publish to. The + exchange name can be + empty, meaning the default exchange. If the exchange name is + specified, and that + exchange does not exist, the server will raise a channel + exception. + </doc> + + <rule name="must-exist" on-failure="not-found"> + <doc> + The client MUST NOT attempt to publish a content to an + exchange that + does not exist. + </doc> + <doc type="scenario"> + The client attempts to publish a content to a + non-existent exchange. + </doc> + </rule> + <rule name="default-exchange"> + <doc> + The server MUST accept a blank exchange name to mean the + default exchange. + </doc> + <doc type="scenario"> + The client declares a queue and binds it to a blank + exchange name. + </doc> + </rule> + <rule name="02"> + <doc> + If the exchange was declared as an internal exchange, + the server MUST raise + a channel exception with a reply code 403 (access + refused). + </doc> + <doc type="scenario"> + TODO. + </doc> + </rule> + + <rule name="03"> + <doc> + The exchange MAY refuse basic content in which case it + MUST raise a channel + exception with reply code 540 (not implemented). + </doc> + <doc type="scenario"> + TODO. + </doc> + </rule> + </field> + + <field name="routing-key" domain="shortstr" + label="Message routing key"> + <doc> + Specifies the routing key for the message. The routing key + is used for routing + messages depending on the exchange configuration. + </doc> + </field> + + <field name="mandatory" domain="bit" + label="indicate mandatory routing"> + <doc> + This flag tells the server how to react if the message + cannot be routed to a + queue. If this flag is set, the server will return an + unroutable message with a + Return method. If this flag is zero, the server silently + drops the message. + </doc> + + <rule name="01"> + <doc> + The server SHOULD implement the mandatory flag. + </doc> + <doc type="scenario"> + TODO. + </doc> + </rule> + </field> + + <field name="immediate" domain="bit" + label="request immediate delivery"> + <doc> + This flag tells the server how to react if the message + cannot be routed to a + queue consumer immediately. If this flag is set, the server + will return an + undeliverable message with a Return method. If this flag is + zero, the server + will queue the message, but with no guarantee that it will + ever be consumed. + </doc> + + <rule name="01"> + <doc> + The server SHOULD implement the immediate flag. + </doc> + <doc type="scenario"> + TODO. + </doc> + </rule> + </field> + </method> + + <method name="return" content="1" index="50" + label="return a failed message"> + <doc> + This method returns an undeliverable message that was published + with the "immediate" + flag set, or an unroutable message published with the + "mandatory" flag set. The + reply code and text provide information about the reason that + the message was + undeliverable. + </doc> + + <chassis name="client" implement="MUST"/> + + <field name="reply-code" domain="reply-code"/> + <field name="reply-text" domain="reply-text"/> + + <field name="exchange" domain="exchange-name"> + <doc> + Specifies the name of the exchange that the message was + originally published + to. May be empty, meaning the default exchange. + </doc> + </field> + + <field name="routing-key" domain="shortstr" + label="Message routing key"> + <doc> + Specifies the routing key name specified when the message + was published. + </doc> + </field> + </method> + + <!-- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - --> + + <method name="deliver" content="1" index="60" + label="notify the client of a consumer message"> + <doc> + This method delivers a message to the client, via a consumer. In + the asynchronous + message delivery model, the client starts a consumer using the + Consume method, then + the server responds with Deliver methods as and when messages + arrive for that + consumer. + </doc> + + <rule name="01"> + <doc> + The server SHOULD track the number of times a message has + been delivered to + clients and when a message is redelivered a certain number + of times - e.g. 5 + times - without being acknowledged, the server SHOULD + consider the message to be + unprocessable (possibly causing client applications to + abort), and move the + message to a dead letter queue. + </doc> + <doc type="scenario"> + TODO. + </doc> + </rule> + + <chassis name="client" implement="MUST"/> + + <field name="consumer-tag" domain="consumer-tag"/> + <field name="delivery-tag" domain="delivery-tag"/> + <field name="redelivered" domain="redelivered"/> + + <field name="exchange" domain="exchange-name"> + <doc> + Specifies the name of the exchange that the message was + originally published to. + May be empty, indicating the default exchange. + </doc> + </field> + + <field name="routing-key" domain="shortstr" + label="Message routing key"> + <doc>Specifies the routing key name specified when the message + was published. + </doc> + </field> + </method> + + <!-- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - --> + + <method name="get" synchronous="1" index="70" + label="direct access to a queue"> + <doc> + This method provides a direct access to the messages in a queue + using a synchronous + dialogue that is designed for specific types of application + where synchronous + functionality is more important than performance. + </doc> + + <response name="get-ok"/> + <response name="get-empty"/> + <chassis name="server" implement="MUST"/> + + <!-- Deprecated: "ticket", must be zero --> + <field name="reserved-1" type="short" reserved="1"/> + + <field name="queue" domain="queue-name"> + <doc>Specifies the name of the queue to get a message from. + </doc> + </field> + <field name="no-ack" domain="no-ack"/> + </method> + + <method name="get-ok" synchronous="1" content="1" index="71" + label="provide client with a message"> + <doc> + This method delivers a message to the client following a get + method. A message + delivered by 'get-ok' must be acknowledged unless the no-ack + option was set in the + get method. + </doc> + + <chassis name="client" implement="MAY"/> + + <field name="delivery-tag" domain="delivery-tag"/> + <field name="redelivered" domain="redelivered"/> + <field name="exchange" domain="exchange-name"> + <doc> + Specifies the name of the exchange that the message was + originally published to. + If empty, the message was published to the default exchange. + </doc> + </field> + + <field name="routing-key" domain="shortstr" + label="Message routing key"> + <doc>Specifies the routing key name specified when the message + was published. + </doc> + </field> + + <field name="message-count" domain="message-count"/> + </method> + + <method name="get-empty" synchronous="1" index="72" + label="indicate no messages available"> + <doc> + This method tells the client that the queue has no messages + available for the + client. + </doc> + <chassis name="client" implement="MAY"/> + <!-- Deprecated: "cluster-id", must be empty --> + <field name="reserved-1" type="shortstr" reserved="1"/> + </method> + + <!-- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - --> + + <method name="ack" index="80" label="acknowledge one or more messages"> + <doc> + When sent by the client, this method acknowledges one or more + messages delivered via the Deliver or Get-Ok methods. + + When sent by server, this method acknowledges one or more + messages published with the Publish method on a channel in + confirm mode. + + The acknowledgement can be for a single message or a set of + messages up to and including a specific message. + </doc> + + <chassis name="server" implement="MUST"/> + <chassis name="client" implement="MUST"/> + + <field name="delivery-tag" domain="delivery-tag"/> + <field name="multiple" domain="bit" + label="acknowledge multiple messages"> + <doc> + If set to 1, the delivery tag is treated as "up to and + including", so that multiple messages can be acknowledged + with a single method. If set to zero, the delivery tag + refers to a single message. If the multiple field is 1, and + the delivery tag is zero, this indicates acknowledgement of + all outstanding messages. + </doc> + <rule name="exists" on-failure="precondition-failed"> + <doc> + A message MUST not be acknowledged more than once. The + receiving peer MUST validate that a non-zero + delivery-tag + refers to a delivered message, and raise a channel + exception if this is not the case. On a transacted + channel, this check MUST be done immediately and not + delayed until a Tx.Commit. + </doc> + <doc type="scenario"> + TODO. + </doc> + </rule> + </field> + </method> + + <!-- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - --> + + <method name="reject" index="90" label="reject an incoming message"> + <doc> + This method allows a client to reject a message. It can be used + to interrupt and + cancel large incoming messages, or return untreatable messages + to their original + queue. + </doc> + + <rule name="01"> + <doc> + The server SHOULD be capable of accepting and process the + Reject method while + sending message content with a Deliver or Get-Ok method. + I.e. the server should + read and process incoming methods while sending output + frames. To cancel a + partially-send content, the server sends a content body + frame of size 1 (i.e. + with no data except the frame-end octet). + </doc> + </rule> + + <rule name="02"> + <doc> + The server SHOULD interpret this method as meaning that the + client is unable to + process the message at this time. + </doc> + <doc type="scenario"> + TODO. + </doc> + </rule> + + <rule name="03"> + <doc> + The client MUST NOT use this method as a means of selecting + messages to process. + </doc> + <doc type="scenario"> + TODO. + </doc> + </rule> + + <chassis name="server" implement="MUST"/> + + <field name="delivery-tag" domain="delivery-tag"/> + + <field name="requeue" domain="bit" label="requeue the message"> + <doc> + If requeue is true, the server will attempt to requeue the + message. If requeue + is false or the requeue attempt fails the messages are + discarded or dead-lettered. + </doc> + + <rule name="01"> + <doc> + The server MUST NOT deliver the message to the same + client within the + context of the current channel. The recommended strategy + is to attempt to + deliver the message to an alternative consumer, and if + that is not possible, + to move the message to a dead-letter queue. The server + MAY use more + sophisticated tracking to hold the message on the queue + and redeliver it to + the same client at a later stage. + </doc> + <doc type="scenario"> + TODO. + </doc> + </rule> + </field> + </method> + + <!-- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - --> + + <method name="recover-async" index="100" + label="redeliver unacknowledged messages" + deprecated="1"> + <doc> + This method asks the server to redeliver all unacknowledged + messages on a + specified channel. Zero or more messages may be redelivered. + This method + is deprecated in favour of the synchronous Recover/Recover-Ok. + </doc> + <rule name="01"> + <doc> + The server MUST set the redelivered flag on all messages + that are resent. + </doc> + <doc type="scenario"> + TODO. + </doc> + </rule> + <chassis name="server" implement="MAY"/> + <field name="requeue" domain="bit" label="requeue the message"> + <doc> + If this field is zero, the message will be redelivered to + the original + recipient. If this bit is 1, the server will attempt to + requeue the message, + potentially then delivering it to an alternative subscriber. + </doc> + </field> + </method> + + <!-- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - --> + + <method name="recover" index="110" + label="redeliver unacknowledged messages"> + <doc> + This method asks the server to redeliver all unacknowledged + messages on a + specified channel. Zero or more messages may be redelivered. + This method + replaces the asynchronous Recover. + </doc> + <rule name="01"> + <doc> + The server MUST set the redelivered flag on all messages + that are resent. + </doc> + <doc type="scenario"> + TODO. + </doc> + </rule> + <chassis name="server" implement="MUST"/> + <field name="requeue" domain="bit" label="requeue the message"> + <doc> + If this field is zero, the message will be redelivered to + the original + recipient. If this bit is 1, the server will attempt to + requeue the message, + potentially then delivering it to an alternative subscriber. + </doc> + </field> + </method> + + <method name="recover-ok" synchronous="1" index="111" + label="confirm recovery"> + <doc> + This method acknowledges a Basic.Recover method. + </doc> + <chassis name="client" implement="MUST"/> + </method> + + <method name="nack" index="120" + label="reject one or more incoming messages"> + <doc> + This method allows a client to reject one or more incoming + messages. It can be + used to interrupt and cancel large incoming messages, or return + untreatable + messages to their original queue. + + This method is also used by the server to inform publishers on + channels in + confirm mode of unhandled messages. If a publisher receives this + method, it + probably needs to republish the offending messages. + </doc> + + <rule name="01"> + <doc> + The server SHOULD be capable of accepting and processing the + Nack method while + sending message content with a Deliver or Get-Ok method. + I.e. the server should + read and process incoming methods while sending output + frames. To cancel a + partially-send content, the server sends a content body + frame of size 1 (i.e. + with no data except the frame-end octet). + </doc> + </rule> + + <rule name="02"> + <doc> + The server SHOULD interpret this method as meaning that the + client is unable to + process the message at this time. + </doc> + <doc type="scenario"> + TODO. + </doc> + </rule> + + <rule name="03"> + <doc> + The client MUST NOT use this method as a means of selecting + messages to process. + </doc> + <doc type="scenario"> + TODO. + </doc> + </rule> + + <rule name="04"> + <doc> + A client publishing messages to a channel in confirm mode + SHOULD be capable of accepting + and somehow handling the Nack method. + </doc> + <doc type="scenario"> + TODO + </doc> + </rule> + + <chassis name="server" implement="MUST"/> + <chassis name="client" implement="MUST"/> + + <field name="delivery-tag" domain="delivery-tag"/> + + <field name="multiple" domain="bit" + label="reject multiple messages"> + <doc> + If set to 1, the delivery tag is treated as "up to and + including", so that multiple messages can be rejected + with a single method. If set to zero, the delivery tag + refers to a single message. If the multiple field is 1, and + the delivery tag is zero, this indicates rejection of + all outstanding messages. + </doc> + <rule name="exists" on-failure="precondition-failed"> + <doc> + A message MUST not be rejected more than once. The + receiving peer MUST validate that a non-zero + delivery-tag + refers to an unacknowledged, delivered message, and + raise a channel exception if this is not the case. + </doc> + <doc type="scenario"> + TODO. + </doc> + </rule> + </field> + + <field name="requeue" domain="bit" label="requeue the message"> + <doc> + If requeue is true, the server will attempt to requeue the + message. If requeue + is false or the requeue attempt fails the messages are + discarded or dead-lettered. + Clients receiving the Nack methods should ignore this flag. + </doc> + + <rule name="01"> + <doc> + The server MUST NOT deliver the message to the same + client within the + context of the current channel. The recommended strategy + is to attempt to + deliver the message to an alternative consumer, and if + that is not possible, + to move the message to a dead-letter queue. The server + MAY use more + sophisticated tracking to hold the message on the queue + and redeliver it to + the same client at a later stage. + </doc> + <doc type="scenario"> + TODO. + </doc> + </rule> + </field> + </method> + + </class> + + <!-- == TX =============================================================== --> + + <class name="tx" handler="channel" index="90" + label="work with transactions"> + <doc> + The Tx class allows publish and ack operations to be batched into + atomic + units of work. The intention is that all publish and ack requests + issued + within a transaction will complete successfully or none of them + will. + Servers SHOULD implement atomic transactions at least where all + publish + or ack requests affect a single queue. Transactions that cover + multiple + queues may be non-atomic, given that queues can be created and + destroyed + asynchronously, and such events do not form part of any transaction. + Further, the behaviour of transactions with respect to the immediate + and + mandatory flags on Basic.Publish methods is not defined. + </doc> + + <rule name="not multiple queues"> + <doc> + Applications MUST NOT rely on the atomicity of transactions that + affect more than one queue. + </doc> + </rule> + <rule name="not immediate"> + <doc> + Applications MUST NOT rely on the behaviour of transactions that + include messages published with the immediate option. + </doc> + </rule> + <rule name="not mandatory"> + <doc> + Applications MUST NOT rely on the behaviour of transactions that + include messages published with the mandatory option. + </doc> + </rule> + + <doc type="grammar"> + tx = C:SELECT S:SELECT-OK + / C:COMMIT S:COMMIT-OK + / C:ROLLBACK S:ROLLBACK-OK + </doc> + + <chassis name="server" implement="SHOULD"/> + <chassis name="client" implement="MAY"/> + + <!-- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - --> + + <method name="select" synchronous="1" index="10" + label="select standard transaction mode"> + <doc> + This method sets the channel to use standard transactions. The + client must use this + method at least once on a channel before using the Commit or + Rollback methods. + </doc> + <chassis name="server" implement="MUST"/> + <response name="select-ok"/> + </method> + + <method name="select-ok" synchronous="1" index="11" + label="confirm transaction mode"> + <doc> + This method confirms to the client that the channel was + successfully set to use + standard transactions. + </doc> + <chassis name="client" implement="MUST"/> + </method> + + <!-- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - --> + + <method name="commit" synchronous="1" index="20" + label="commit the current transaction"> + <doc> + This method commits all message publications and acknowledgments + performed in + the current transaction. A new transaction starts immediately + after a commit. + </doc> + <chassis name="server" implement="MUST"/> + <response name="commit-ok"/> + + <rule name="transacted" on-failure="precondition-failed"> + <doc> + The client MUST NOT use the Commit method on non-transacted + channels. + </doc> + <doc type="scenario"> + The client opens a channel and then uses Tx.Commit. + </doc> + </rule> + </method> + + <method name="commit-ok" synchronous="1" index="21" + label="confirm a successful commit"> + <doc> + This method confirms to the client that the commit succeeded. + Note that if a commit + fails, the server raises a channel exception. + </doc> + <chassis name="client" implement="MUST"/> + </method> + + <!-- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - --> + + <method name="rollback" synchronous="1" index="30" + label="abandon the current transaction"> + <doc> + This method abandons all message publications and + acknowledgments performed in + the current transaction. A new transaction starts immediately + after a rollback. + Note that unacked messages will not be automatically redelivered + by rollback; + if that is required an explicit recover call should be issued. + </doc> + <chassis name="server" implement="MUST"/> + <response name="rollback-ok"/> + + <rule name="transacted" on-failure="precondition-failed"> + <doc> + The client MUST NOT use the Rollback method on + non-transacted channels. + </doc> + <doc type="scenario"> + The client opens a channel and then uses Tx.Rollback. + </doc> + </rule> + </method> + + <method name="rollback-ok" synchronous="1" index="31" + label="confirm successful rollback"> + <doc> + This method confirms to the client that the rollback succeeded. + Note that if an + rollback fails, the server raises a channel exception. + </doc> + <chassis name="client" implement="MUST"/> + </method> + </class> + + <!-- == CONFIRM ========================================================== --> + + <class name="confirm" handler="channel" index="85" + label="work with confirms"> + <doc> + The Confirm class allows publishers to put the channel in + confirm mode and subsequently be notified when messages have been + handled by the broker. The intention is that all messages + published on a channel in confirm mode will be acknowledged at + some point. By acknowledging a message the broker assumes + responsibility for it and indicates that it has done something + it deems reasonable with it. + + Unroutable mandatory or immediate messages are acknowledged + right after the Basic.Return method. Messages are acknowledged + when all queues to which the message has been routed + have either delivered the message and received an + acknowledgement (if required), or enqueued the message (and + persisted it if required). + + Published messages are assigned ascending sequence numbers, + starting at 1 with the first Confirm.Select method. The server + confirms messages by sending Basic.Ack methods referring to these + sequence numbers. + </doc> + + <rule name="all messages acknowledged"> + <doc> + The server MUST acknowledge all messages received after the + channel was put into confirm mode. + </doc> + </rule> + + <rule name="all queues"> + <doc> + The server MUST acknowledge a message only after it was + properly handled by all the queues it was delivered to. + </doc> + </rule> + + <rule name="unroutable messages"> + <doc> + The server MUST acknowledge an unroutable mandatory or + immediate message only after it sends the Basic.Return. + </doc> + </rule> + + <rule name="time guarantees"> + <doc> + No guarantees are made as to how soon a message is + acknowledged. Applications SHOULD NOT make assumptions about + this. + </doc> + </rule> + + <doc type="grammar"> + confirm = C:SELECT S:SELECT-OK + </doc> + + <chassis name="server" implement="SHOULD"/> + <chassis name="client" implement="MAY"/> + + <!-- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - --> + + <method name="select" synchronous="1" index="10"> + select confirm mode (i.e. enable publisher acknowledgements) + <doc> + This method sets the channel to use publisher acknowledgements. + The client can only use this method on a non-transactional + channel. + </doc> + <chassis name="server" implement="MUST"/> + <response name="select-ok"/> + <field name="nowait" type="bit"> + do not send a reply method + <doc> + If set, the server will not respond to the method. The + client should + not wait for a reply method. If the server could not + complete the + method it will raise a channel or connection exception. + </doc> + </field> + </method> + + <method name="select-ok" synchronous="1" index="11"> + acknowledge confirm mode + <doc> + This method confirms to the client that the channel was + successfully + set to use publisher acknowledgements. + </doc> + <chassis name="client" implement="MUST"/> + </method> + </class> </amqp> diff --git a/resources/amqp0-9-1.xml b/resources/amqp0-9-1.xml index da785eb3bed370d7c11852fce8ef7fe7f366f2f6..2d56a5eb8d7aa5e3846f62929c8668430ecef71e 100644 --- a/resources/amqp0-9-1.xml +++ b/resources/amqp0-9-1.xml @@ -140,2704 +140,3335 @@ --> -<amqp major = "0" minor = "9" revision = "1" - port = "5672" comment = "AMQ Protocol version 0-9-1"> - <!-- +<amqp major="0" minor="9" revision="1" + port="5672" comment="AMQ Protocol version 0-9-1"> + <!-- ====================================================== == CONSTANTS ====================================================== --> - <!-- Frame types --> - <constant name = "frame-method" value = "1" /> - <constant name = "frame-header" value = "2" /> - <constant name = "frame-body" value = "3" /> - <constant name = "frame-heartbeat" value = "8" /> - - <!-- Protocol constants --> - <constant name = "frame-min-size" value = "4096" /> - <constant name = "frame-end" value = "206" /> - - <!-- Reply codes --> - <constant name = "reply-success" value = "200"> - <doc> - Indicates that the method completed successfully. This reply code is - reserved for future use - the current protocol design does not use positive - confirmation and reply codes are sent only in case of an error. - </doc> - </constant> - - <constant name = "content-too-large" value = "311" class = "soft-error"> - <doc> - The client attempted to transfer content larger than the server could accept - at the present time. The client may retry at a later time. - </doc> - </constant> - - <constant name = "no-consumers" value = "313" class = "soft-error"> - <doc> - When the exchange cannot deliver to a consumer when the immediate flag is - set. As a result of pending data on the queue or the absence of any - consumers of the queue. - </doc> - </constant> - - <constant name = "connection-forced" value = "320" class = "hard-error"> - <doc> - An operator intervened to close the connection for some reason. The client - may retry at some later date. - </doc> - </constant> - - <constant name = "invalid-path" value = "402" class = "hard-error"> - <doc> - The client tried to work with an unknown virtual host. - </doc> - </constant> - - <constant name = "access-refused" value = "403" class = "soft-error"> - <doc> - The client attempted to work with a server entity to which it has no - access due to security settings. - </doc> - </constant> - - <constant name = "not-found" value = "404" class = "soft-error"> - <doc> - The client attempted to work with a server entity that does not exist. - </doc> - </constant> - - <constant name = "resource-locked" value = "405" class = "soft-error"> - <doc> - The client attempted to work with a server entity to which it has no - access because another client is working with it. - </doc> - </constant> - - <constant name = "precondition-failed" value = "406" class = "soft-error"> - <doc> - The client requested a method that was not allowed because some precondition - failed. - </doc> - </constant> - - <constant name = "frame-error" value = "501" class = "hard-error"> - <doc> - The sender sent a malformed frame that the recipient could not decode. - This strongly implies a programming error in the sending peer. - </doc> - </constant> - - <constant name = "syntax-error" value = "502" class = "hard-error"> - <doc> - The sender sent a frame that contained illegal values for one or more - fields. This strongly implies a programming error in the sending peer. - </doc> - </constant> - - <constant name = "command-invalid" value = "503" class = "hard-error"> - <doc> - The client sent an invalid sequence of frames, attempting to perform an - operation that was considered invalid by the server. This usually implies - a programming error in the client. - </doc> - </constant> - - <constant name = "channel-error" value = "504" class = "hard-error"> - <doc> - The client attempted to work with a channel that had not been correctly - opened. This most likely indicates a fault in the client layer. - </doc> - </constant> - - <constant name = "unexpected-frame" value = "505" class = "hard-error"> - <doc> - The peer sent a frame that was not expected, usually in the context of - a content header and body. This strongly indicates a fault in the peer's - content processing. - </doc> - </constant> - - <constant name = "resource-error" value = "506" class = "hard-error"> - <doc> - The server could not complete the method because it lacked sufficient - resources. This may be due to the client creating too many of some type - of entity. - </doc> - </constant> - - <constant name = "not-allowed" value = "530" class = "hard-error"> - <doc> - The client tried to work with some entity in a manner that is prohibited - by the server, due to security settings or by some other criteria. - </doc> - </constant> - - <constant name = "not-implemented" value = "540" class = "hard-error"> - <doc> - The client tried to use functionality that is not implemented in the - server. - </doc> - </constant> - - <constant name = "internal-error" value = "541" class = "hard-error"> - <doc> - The server could not complete the method because of an internal error. - The server may require intervention by an operator in order to resume - normal operations. - </doc> - </constant> - - <!-- - ====================================================== - == DOMAIN TYPES - ====================================================== - --> - - <domain name = "class-id" type = "short" /> - - <domain name = "consumer-tag" type = "shortstr" label = "consumer tag"> - <doc> - Identifier for the consumer, valid within the current channel. - </doc> - </domain> - - <domain name = "delivery-tag" type = "longlong" label = "server-assigned delivery tag"> - <doc> - The server-assigned and channel-specific delivery tag - </doc> - <rule name = "channel-local"> - <doc> - The delivery tag is valid only within the channel from which the message was - received. I.e. a client MUST NOT receive a message on one channel and then - acknowledge it on another. - </doc> - </rule> - <rule name = "non-zero"> - <doc> - The server MUST NOT use a zero value for delivery tags. Zero is reserved - for client use, meaning "all messages so far received". - </doc> - </rule> - </domain> - - <domain name = "exchange-name" type = "shortstr" label = "exchange name"> - <doc> - The exchange name is a client-selected string that identifies the exchange for - publish methods. - </doc> - <assert check = "length" value = "127" /> - <assert check = "regexp" value = "^[a-zA-Z0-9-_.:]*$" /> - </domain> - - <domain name = "method-id" type = "short" /> - - <domain name = "no-ack" type = "bit" label = "no acknowledgement needed"> - <doc> - If this field is set the server does not expect acknowledgements for - messages. That is, when a message is delivered to the client the server - assumes the delivery will succeed and immediately dequeues it. This - functionality may increase performance but at the cost of reliability. - Messages can get lost if a client dies before they are delivered to the - application. - </doc> - </domain> - - <domain name = "no-local" type = "bit" label = "do not deliver own messages"> - <doc> - If the no-local field is set the server will not send messages to the connection that - published them. - </doc> - </domain> - - <domain name = "no-wait" type = "bit" label = "do not send reply method"> - <doc> - If set, the server will not respond to the method. The client should not wait - for a reply method. If the server could not complete the method it will raise a - channel or connection exception. - </doc> - </domain> - - <domain name = "path" type = "shortstr"> - <doc> - Unconstrained. - </doc> - <assert check = "notnull" /> - <assert check = "length" value = "127" /> - </domain> - - <domain name = "peer-properties" type = "table"> - <doc> - This table provides a set of peer properties, used for identification, debugging, - and general information. - </doc> - </domain> - - <domain name = "queue-name" type = "shortstr" label = "queue name"> - <doc> - The queue name identifies the queue within the vhost. In methods where the queue - name may be blank, and that has no specific significance, this refers to the - 'current' queue for the channel, meaning the last queue that the client declared - on the channel. If the client did not declare a queue, and the method needs a - queue name, this will result in a 502 (syntax error) channel exception. - </doc> - <assert check = "length" value = "127" /> - <assert check = "regexp" value = "^[a-zA-Z0-9-_.:]*$" /> - </domain> - - <domain name = "redelivered" type = "bit" label = "message is being redelivered"> - <doc> - This indicates that the message has been previously delivered to this or - another client. - </doc> - <rule name = "implementation"> - <doc> - The server SHOULD try to signal redelivered messages when it can. When - redelivering a message that was not successfully acknowledged, the server - SHOULD deliver it to the original client if possible. - </doc> - <doc type = "scenario"> - Declare a shared queue and publish a message to the queue. Consume the - message using explicit acknowledgements, but do not acknowledge the - message. Close the connection, reconnect, and consume from the queue - again. The message should arrive with the redelivered flag set. - </doc> - </rule> - <rule name = "hinting"> - <doc> - The client MUST NOT rely on the redelivered field but should take it as a - hint that the message may already have been processed. A fully robust - client must be able to track duplicate received messages on non-transacted, - and locally-transacted channels. - </doc> - </rule> - </domain> - - <domain name = "message-count" type = "long" label = "number of messages in queue"> - <doc> - The number of messages in the queue, which will be zero for newly-declared - queues. This is the number of messages present in the queue, and committed - if the channel on which they were published is transacted, that are not - waiting acknowledgement. - </doc> - </domain> - - <domain name = "reply-code" type = "short" label = "reply code from server"> - <doc> - The reply code. The AMQ reply codes are defined as constants at the start - of this formal specification. - </doc> - <assert check = "notnull" /> - </domain> - - <domain name = "reply-text" type = "shortstr" label = "localised reply text"> - <doc> - The localised reply text. This text can be logged as an aid to resolving - issues. - </doc> - <assert check = "notnull" /> - </domain> - - <!-- Elementary domains --> - <domain name = "bit" type = "bit" label = "single bit" /> - <domain name = "octet" type = "octet" label = "single octet" /> - <domain name = "short" type = "short" label = "16-bit integer" /> - <domain name = "long" type = "long" label = "32-bit integer" /> - <domain name = "longlong" type = "longlong" label = "64-bit integer" /> - <domain name = "shortstr" type = "shortstr" label = "short string" /> - <domain name = "longstr" type = "longstr" label = "long string" /> - <domain name = "timestamp" type = "timestamp" label = "64-bit timestamp" /> - <domain name = "table" type = "table" label = "field table" /> - - <!-- == CONNECTION ======================================================= --> - - <class name = "connection" handler = "connection" index = "10" label = "work with socket connections"> - <doc> - The connection class provides methods for a client to establish a network connection to - a server, and for both peers to operate the connection thereafter. - </doc> - - <doc type = "grammar"> - connection = open-connection *use-connection close-connection - open-connection = C:protocol-header - S:START C:START-OK - *challenge - S:TUNE C:TUNE-OK - C:OPEN S:OPEN-OK - challenge = S:SECURE C:SECURE-OK - use-connection = *channel - close-connection = C:CLOSE S:CLOSE-OK - / S:CLOSE C:CLOSE-OK - </doc> - - <chassis name = "server" implement = "MUST" /> - <chassis name = "client" implement = "MUST" /> - - <!-- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - --> - - <method name = "start" synchronous = "1" index = "10" label = "start connection negotiation"> - <doc> - This method starts the connection negotiation process by telling the client the - protocol version that the server proposes, along with a list of security mechanisms - which the client can use for authentication. - </doc> - - <rule name = "protocol-name"> - <doc> - If the server cannot support the protocol specified in the protocol header, - it MUST respond with a valid protocol header and then close the socket - connection. - </doc> - <doc type = "scenario"> - The client sends a protocol header containing an invalid protocol name. - The server MUST respond by sending a valid protocol header and then closing - the connection. - </doc> - </rule> - <rule name = "server-support"> - <doc> - The server MUST provide a protocol version that is lower than or equal to - that requested by the client in the protocol header. - </doc> - <doc type = "scenario"> - The client requests a protocol version that is higher than any valid - implementation, e.g. 2.0. The server must respond with a protocol header - indicating its supported protocol version, e.g. 1.0. - </doc> - </rule> - <rule name = "client-support"> - <doc> - If the client cannot handle the protocol version suggested by the server - it MUST close the socket connection without sending any further data. - </doc> - <doc type = "scenario"> - The server sends a protocol version that is lower than any valid - implementation, e.g. 0.1. The client must respond by closing the - connection without sending any further data. - </doc> - </rule> + <!-- Frame types --> + <constant name="frame-method" value="1"/> + <constant name="frame-header" value="2"/> + <constant name="frame-body" value="3"/> + <constant name="frame-heartbeat" value="8"/> - <chassis name = "client" implement = "MUST" /> - <response name = "start-ok" /> + <!-- Protocol constants --> + <constant name="frame-min-size" value="4096"/> + <constant name="frame-end" value="206"/> - <field name = "version-major" domain = "octet" label = "protocol major version"> + <!-- Reply codes --> + <constant name="reply-success" value="200"> <doc> - The major version number can take any value from 0 to 99 as defined in the - AMQP specification. + Indicates that the method completed successfully. This reply code is + reserved for future use - the current protocol design does not use + positive + confirmation and reply codes are sent only in case of an error. </doc> - </field> + </constant> - <field name = "version-minor" domain = "octet" label = "protocol minor version"> + <constant name="content-too-large" value="311" class="soft-error"> <doc> - The minor version number can take any value from 0 to 99 as defined in the - AMQP specification. + The client attempted to transfer content larger than the server + could accept + at the present time. The client may retry at a later time. </doc> - </field> - - <field name = "server-properties" domain = "peer-properties" label = "server properties"> - <rule name = "required-fields"> - <doc> - The properties SHOULD contain at least these fields: "host", specifying the - server host name or address, "product", giving the name of the server product, - "version", giving the name of the server version, "platform", giving the name - of the operating system, "copyright", if appropriate, and "information", giving - other general information. - </doc> - <doc type = "scenario"> - Client connects to server and inspects the server properties. It checks for - the presence of the required fields. - </doc> - </rule> - </field> + </constant> - <field name = "mechanisms" domain = "longstr" label = "available security mechanisms"> + <constant name="no-consumers" value="313" class="soft-error"> <doc> - A list of the security mechanisms that the server supports, delimited by spaces. + When the exchange cannot deliver to a consumer when the immediate + flag is + set. As a result of pending data on the queue or the absence of any + consumers of the queue. </doc> - <assert check = "notnull" /> - </field> + </constant> - <field name = "locales" domain = "longstr" label = "available message locales"> + <constant name="connection-forced" value="320" class="hard-error"> <doc> - A list of the message locales that the server supports, delimited by spaces. The - locale defines the language in which the server will send reply texts. + An operator intervened to close the connection for some reason. The + client + may retry at some later date. </doc> - <rule name = "required-support"> - <doc> - The server MUST support at least the en_US locale. - </doc> - <doc type = "scenario"> - Client connects to server and inspects the locales field. It checks for - the presence of the required locale(s). - </doc> - </rule> - <assert check = "notnull" /> - </field> - </method> - - <method name = "start-ok" synchronous = "1" index = "11" - label = "select security mechanism and locale"> - <doc> - This method selects a SASL security mechanism. - </doc> - - <chassis name = "server" implement = "MUST" /> - - <field name = "client-properties" domain = "peer-properties" label = "client properties"> - <rule name = "required-fields"> - <!-- This rule is not testable from the client side --> - <doc> - The properties SHOULD contain at least these fields: "product", giving the name - of the client product, "version", giving the name of the client version, "platform", - giving the name of the operating system, "copyright", if appropriate, and - "information", giving other general information. - </doc> - </rule> - </field> + </constant> - <field name = "mechanism" domain = "shortstr" label = "selected security mechanism"> + <constant name="invalid-path" value="402" class="hard-error"> <doc> - A single security mechanisms selected by the client, which must be one of those - specified by the server. + The client tried to work with an unknown virtual host. </doc> - <rule name = "security"> - <doc> - The client SHOULD authenticate using the highest-level security profile it - can handle from the list provided by the server. - </doc> - </rule> - <rule name = "validity"> - <doc> - If the mechanism field does not contain one of the security mechanisms - proposed by the server in the Start method, the server MUST close the - connection without sending any further data. - </doc> - <doc type = "scenario"> - Client connects to server and sends an invalid security mechanism. The - server must respond by closing the connection (a socket close, with no - connection close negotiation). - </doc> - </rule> - <assert check = "notnull" /> - </field> + </constant> - <field name = "response" domain = "longstr" label = "security response data"> + <constant name="access-refused" value="403" class="soft-error"> <doc> - A block of opaque data passed to the security mechanism. The contents of this - data are defined by the SASL security mechanism. + The client attempted to work with a server entity to which it has no + access due to security settings. </doc> - <assert check = "notnull" /> - </field> + </constant> - <field name = "locale" domain = "shortstr" label = "selected message locale"> + <constant name="not-found" value="404" class="soft-error"> <doc> - A single message locale selected by the client, which must be one of those - specified by the server. + The client attempted to work with a server entity that does not + exist. </doc> - <assert check = "notnull" /> - </field> - </method> - - <!-- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - --> + </constant> - <method name = "secure" synchronous = "1" index = "20" label = "security mechanism challenge"> - <doc> - The SASL protocol works by exchanging challenges and responses until both peers have - received sufficient information to authenticate each other. This method challenges - the client to provide more information. - </doc> - - <chassis name = "client" implement = "MUST" /> - <response name = "secure-ok" /> - - <field name = "challenge" domain = "longstr" label = "security challenge data"> + <constant name="resource-locked" value="405" class="soft-error"> <doc> - Challenge information, a block of opaque binary data passed to the security - mechanism. + The client attempted to work with a server entity to which it has no + access because another client is working with it. </doc> - </field> - </method> - - <method name = "secure-ok" synchronous = "1" index = "21" label = "security mechanism response"> - <doc> - This method attempts to authenticate, passing a block of SASL data for the security - mechanism at the server side. - </doc> + </constant> - <chassis name = "server" implement = "MUST" /> - - <field name = "response" domain = "longstr" label = "security response data"> + <constant name="precondition-failed" value="406" class="soft-error"> <doc> - A block of opaque data passed to the security mechanism. The contents of this - data are defined by the SASL security mechanism. + The client requested a method that was not allowed because some + precondition + failed. </doc> - <assert check = "notnull" /> - </field> - </method> - - <!-- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - --> + </constant> - <method name = "tune" synchronous = "1" index = "30" - label = "propose connection tuning parameters"> - <doc> - This method proposes a set of connection configuration values to the client. The - client can accept and/or adjust these. - </doc> - - <chassis name = "client" implement = "MUST" /> - - <response name = "tune-ok" /> - - <field name = "channel-max" domain = "short" label = "proposed maximum channels"> + <constant name="frame-error" value="501" class="hard-error"> <doc> - Specifies highest channel number that the server permits. Usable channel numbers - are in the range 1..channel-max. Zero indicates no specified limit. + The sender sent a malformed frame that the recipient could not + decode. + This strongly implies a programming error in the sending peer. </doc> - </field> + </constant> - <field name = "frame-max" domain = "long" label = "proposed maximum frame size"> + <constant name="syntax-error" value="502" class="hard-error"> <doc> - The largest frame size that the server proposes for the connection, including - frame header and end-byte. The client can negotiate a lower value. Zero means - that the server does not impose any specific limit but may reject very large - frames if it cannot allocate resources for them. + The sender sent a frame that contained illegal values for one or + more + fields. This strongly implies a programming error in the sending + peer. </doc> - <rule name = "minimum"> - <doc> - Until the frame-max has been negotiated, both peers MUST accept frames of up - to frame-min-size octets large, and the minimum negotiated value for frame-max - is also frame-min-size. - </doc> - <doc type = "scenario"> - Client connects to server and sends a large properties field, creating a frame - of frame-min-size octets. The server must accept this frame. - </doc> - </rule> - </field> + </constant> - <field name = "heartbeat" domain = "short" label = "desired heartbeat delay"> + <constant name="command-invalid" value="503" class="hard-error"> <doc> - The delay, in seconds, of the connection heartbeat that the server wants. - Zero means the server does not want a heartbeat. + The client sent an invalid sequence of frames, attempting to perform + an + operation that was considered invalid by the server. This usually + implies + a programming error in the client. </doc> - </field> - </method> - - <method name = "tune-ok" synchronous = "1" index = "31" - label = "negotiate connection tuning parameters"> - <doc> - This method sends the client's connection tuning parameters to the server. - Certain fields are negotiated, others provide capability information. - </doc> + </constant> - <chassis name = "server" implement = "MUST" /> - - <field name = "channel-max" domain = "short" label = "negotiated maximum channels"> + <constant name="channel-error" value="504" class="hard-error"> <doc> - The maximum total number of channels that the client will use per connection. + The client attempted to work with a channel that had not been + correctly + opened. This most likely indicates a fault in the client layer. </doc> - <rule name = "upper-limit"> - <doc> - If the client specifies a channel max that is higher than the value provided - by the server, the server MUST close the connection without attempting a - negotiated close. The server may report the error in some fashion to assist - implementors. - </doc> - </rule> - <assert check = "notnull" /> - <assert check = "le" method = "tune" field = "channel-max" /> - </field> + </constant> - <field name = "frame-max" domain = "long" label = "negotiated maximum frame size"> + <constant name="unexpected-frame" value="505" class="hard-error"> <doc> - The largest frame size that the client and server will use for the connection. - Zero means that the client does not impose any specific limit but may reject - very large frames if it cannot allocate resources for them. Note that the - frame-max limit applies principally to content frames, where large contents can - be broken into frames of arbitrary size. + The peer sent a frame that was not expected, usually in the context + of + a content header and body. This strongly indicates a fault in the + peer's + content processing. </doc> - <rule name = "minimum"> - <doc> - Until the frame-max has been negotiated, both peers MUST accept frames of up - to frame-min-size octets large, and the minimum negotiated value for frame-max - is also frame-min-size. - </doc> - </rule> - <rule name = "upper-limit"> - <doc> - If the client specifies a frame max that is higher than the value provided - by the server, the server MUST close the connection without attempting a - negotiated close. The server may report the error in some fashion to assist - implementors. - </doc> - </rule> - </field> + </constant> - <field name = "heartbeat" domain = "short" label = "desired heartbeat delay"> + <constant name="resource-error" value="506" class="hard-error"> <doc> - The delay, in seconds, of the connection heartbeat that the client wants. Zero - means the client does not want a heartbeat. + The server could not complete the method because it lacked + sufficient + resources. This may be due to the client creating too many of some + type + of entity. </doc> - </field> - </method> - - <!-- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - --> + </constant> - <method name = "open" synchronous = "1" index = "40" label = "open connection to virtual host"> - <doc> - This method opens a connection to a virtual host, which is a collection of - resources, and acts to separate multiple application domains within a server. - The server may apply arbitrary limits per virtual host, such as the number - of each type of entity that may be used, per connection and/or in total. - </doc> - - <chassis name = "server" implement = "MUST" /> - <response name = "open-ok" /> - - <field name = "virtual-host" domain = "path" label = "virtual host name"> + <constant name="not-allowed" value="530" class="hard-error"> <doc> - The name of the virtual host to work with. + The client tried to work with some entity in a manner that is + prohibited + by the server, due to security settings or by some other criteria. </doc> - <rule name = "separation"> - <doc> - If the server supports multiple virtual hosts, it MUST enforce a full - separation of exchanges, queues, and all associated entities per virtual - host. An application, connected to a specific virtual host, MUST NOT be able - to access resources of another virtual host. - </doc> - </rule> - <rule name = "security"> - <doc> - The server SHOULD verify that the client has permission to access the - specified virtual host. - </doc> - </rule> - </field> - <!-- Deprecated: "capabilities", must be zero --> - <field name = "reserved-1" type = "shortstr" reserved = "1" /> - <!-- Deprecated: "insist", must be zero --> - <field name = "reserved-2" type = "bit" reserved = "1" /> - </method> - - <method name = "open-ok" synchronous = "1" index = "41" label = "signal that connection is ready"> - <doc> - This method signals to the client that the connection is ready for use. - </doc> - <chassis name = "client" implement = "MUST" /> - <!-- Deprecated: "known-hosts", must be zero --> - <field name = "reserved-1" type = "shortstr" reserved = "1" /> - </method> - - <!-- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - --> - - <method name = "close" synchronous = "1" index = "50" label = "request a connection close"> - <doc> - This method indicates that the sender wants to close the connection. This may be - due to internal conditions (e.g. a forced shut-down) or due to an error handling - a specific method, i.e. an exception. When a close is due to an exception, the - sender provides the class and method id of the method which caused the exception. - </doc> - <rule name = "stability"> - <doc> - After sending this method, any received methods except Close and Close-OK MUST - be discarded. The response to receiving a Close after sending Close must be to - send Close-Ok. - </doc> - </rule> - - <chassis name = "client" implement = "MUST" /> - <chassis name = "server" implement = "MUST" /> - <response name = "close-ok" /> - - <field name = "reply-code" domain = "reply-code" /> - <field name = "reply-text" domain = "reply-text" /> - - <field name = "class-id" domain = "class-id" label = "failing method class"> - <doc> - When the close is provoked by a method exception, this is the class of the - method. - </doc> - </field> - - <field name = "method-id" domain = "method-id" label = "failing method ID"> - <doc> - When the close is provoked by a method exception, this is the ID of the method. - </doc> - </field> - </method> - - <method name = "close-ok" synchronous = "1" index = "51" label = "confirm a connection close"> - <doc> - This method confirms a Connection.Close method and tells the recipient that it is - safe to release resources for the connection and close the socket. - </doc> - <rule name = "reporting"> - <doc> - A peer that detects a socket closure without having received a Close-Ok - handshake method SHOULD log the error. - </doc> - </rule> - <chassis name = "client" implement = "MUST" /> - <chassis name = "server" implement = "MUST" /> - </method> - </class> - - <!-- == CHANNEL ========================================================== --> - - <class name = "channel" handler = "channel" index = "20" label = "work with channels"> - <doc> - The channel class provides methods for a client to establish a channel to a - server and for both peers to operate the channel thereafter. - </doc> - - <doc type = "grammar"> - channel = open-channel *use-channel close-channel - open-channel = C:OPEN S:OPEN-OK - use-channel = C:FLOW S:FLOW-OK - / S:FLOW C:FLOW-OK - / functional-class - close-channel = C:CLOSE S:CLOSE-OK - / S:CLOSE C:CLOSE-OK - </doc> - - <chassis name = "server" implement = "MUST" /> - <chassis name = "client" implement = "MUST" /> - - <!-- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - --> - - <method name = "open" synchronous = "1" index = "10" label = "open a channel for use"> - <doc> - This method opens a channel to the server. - </doc> - <rule name = "state" on-failure = "channel-error"> - <doc> - The client MUST NOT use this method on an already-opened channel. - </doc> - <doc type = "scenario"> - Client opens a channel and then reopens the same channel. - </doc> - </rule> - <chassis name = "server" implement = "MUST" /> - <response name = "open-ok" /> - <!-- Deprecated: "out-of-band", must be zero --> - <field name = "reserved-1" type = "shortstr" reserved = "1" /> - </method> - - <method name = "open-ok" synchronous = "1" index = "11" label = "signal that the channel is ready"> - <doc> - This method signals to the client that the channel is ready for use. - </doc> - <chassis name = "client" implement = "MUST" /> - <!-- Deprecated: "channel-id", must be zero --> - <field name = "reserved-1" type = "longstr" reserved = "1" /> - </method> - - <!-- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - --> - - <method name = "flow" synchronous = "1" index = "20" label = "enable/disable flow from peer"> - <doc> - This method asks the peer to pause or restart the flow of content data sent by - a consumer. This is a simple flow-control mechanism that a peer can use to avoid - overflowing its queues or otherwise finding itself receiving more messages than - it can process. Note that this method is not intended for window control. It does - not affect contents returned by Basic.Get-Ok methods. - </doc> - - <rule name = "initial-state"> - <doc> - When a new channel is opened, it is active (flow is active). Some applications - assume that channels are inactive until started. To emulate this behaviour a - client MAY open the channel, then pause it. - </doc> - </rule> - - <rule name = "bidirectional"> - <doc> - When sending content frames, a peer SHOULD monitor the channel for incoming - methods and respond to a Channel.Flow as rapidly as possible. - </doc> - </rule> + </constant> - <rule name = "throttling"> + <constant name="not-implemented" value="540" class="hard-error"> <doc> - A peer MAY use the Channel.Flow method to throttle incoming content data for - internal reasons, for example, when exchanging data over a slower connection. + The client tried to use functionality that is not implemented in the + server. </doc> - </rule> - - <rule name = "expected-behaviour"> - <doc> - The peer that requests a Channel.Flow method MAY disconnect and/or ban a peer - that does not respect the request. This is to prevent badly-behaved clients - from overwhelming a server. - </doc> - </rule> - - <chassis name = "server" implement = "MUST" /> - <chassis name = "client" implement = "MUST" /> + </constant> - <response name = "flow-ok" /> - - <field name = "active" domain = "bit" label = "start/stop content frames"> - <doc> - If 1, the peer starts sending content frames. If 0, the peer stops sending - content frames. - </doc> - </field> - </method> - - <method name = "flow-ok" index = "21" label = "confirm a flow method"> - <doc> - Confirms to the peer that a flow command was received and processed. - </doc> - <chassis name = "server" implement = "MUST" /> - <chassis name = "client" implement = "MUST" /> - <field name = "active" domain = "bit" label = "current flow setting"> - <doc> - Confirms the setting of the processed flow method: 1 means the peer will start - sending or continue to send content frames; 0 means it will not. - </doc> - </field> - </method> - - <!-- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - --> - - <method name = "close" synchronous = "1" index = "40" label = "request a channel close"> - <doc> - This method indicates that the sender wants to close the channel. This may be due to - internal conditions (e.g. a forced shut-down) or due to an error handling a specific - method, i.e. an exception. When a close is due to an exception, the sender provides - the class and method id of the method which caused the exception. - </doc> - <rule name = "stability"> + <constant name="internal-error" value="541" class="hard-error"> <doc> - After sending this method, any received methods except Close and Close-OK MUST - be discarded. The response to receiving a Close after sending Close must be to - send Close-Ok. + The server could not complete the method because of an internal + error. + The server may require intervention by an operator in order to + resume + normal operations. </doc> - </rule> + </constant> - <chassis name = "client" implement = "MUST" /> - <chassis name = "server" implement = "MUST" /> - <response name = "close-ok" /> + <!-- + ====================================================== + == DOMAIN TYPES + ====================================================== + --> - <field name = "reply-code" domain = "reply-code" /> - <field name = "reply-text" domain = "reply-text" /> + <domain name="class-id" type="short"/> - <field name = "class-id" domain = "class-id" label = "failing method class"> + <domain name="consumer-tag" type="shortstr" label="consumer tag"> <doc> - When the close is provoked by a method exception, this is the class of the - method. + Identifier for the consumer, valid within the current channel. </doc> - </field> + </domain> - <field name = "method-id" domain = "method-id" label = "failing method ID"> + <domain name="delivery-tag" type="longlong" + label="server-assigned delivery tag"> <doc> - When the close is provoked by a method exception, this is the ID of the method. - </doc> - </field> - </method> - - <method name = "close-ok" synchronous = "1" index = "41" label = "confirm a channel close"> - <doc> - This method confirms a Channel.Close method and tells the recipient that it is safe - to release resources for the channel. - </doc> - <rule name = "reporting"> - <doc> - A peer that detects a socket closure without having received a Channel.Close-Ok - handshake method SHOULD log the error. - </doc> - </rule> - <chassis name = "client" implement = "MUST" /> - <chassis name = "server" implement = "MUST" /> - </method> - </class> - - <!-- == EXCHANGE ========================================================= --> - - <class name = "exchange" handler = "channel" index = "40" label = "work with exchanges"> - <doc> - Exchanges match and distribute messages across queues. Exchanges can be configured in - the server or declared at runtime. - </doc> - - <doc type = "grammar"> - exchange = C:DECLARE S:DECLARE-OK - / C:DELETE S:DELETE-OK - </doc> - - <chassis name = "server" implement = "MUST" /> - <chassis name = "client" implement = "MUST" /> - - <rule name = "required-types"> - <doc> - The server MUST implement these standard exchange types: fanout, direct. - </doc> - <doc type = "scenario"> - Client attempts to declare an exchange with each of these standard types. - </doc> - </rule> - <rule name = "recommended-types"> - <doc> - The server SHOULD implement these standard exchange types: topic, headers. - </doc> - <doc type = "scenario"> - Client attempts to declare an exchange with each of these standard types. - </doc> - </rule> - <rule name = "required-instances"> - <doc> - The server MUST, in each virtual host, pre-declare an exchange instance - for each standard exchange type that it implements, where the name of the - exchange instance, if defined, is "amq." followed by the exchange type name. - </doc> - <doc> - The server MUST, in each virtual host, pre-declare at least two direct - exchange instances: one named "amq.direct", the other with no public name - that serves as a default exchange for Publish methods. - </doc> - <doc type = "scenario"> - Client declares a temporary queue and attempts to bind to each required - exchange instance ("amq.fanout", "amq.direct", "amq.topic", and "amq.headers" - if those types are defined). - </doc> - </rule> - <rule name = "default-exchange"> - <doc> - The server MUST pre-declare a direct exchange with no public name to act as - the default exchange for content Publish methods and for default queue bindings. - </doc> - <doc type = "scenario"> - Client checks that the default exchange is active by specifying a queue - binding with no exchange name, and publishing a message with a suitable - routing key but without specifying the exchange name, then ensuring that - the message arrives in the queue correctly. - </doc> - </rule> - <rule name = "default-access"> - <doc> - The server MUST NOT allow clients to access the default exchange except - by specifying an empty exchange name in the Queue.Bind and content Publish - methods. - </doc> - </rule> - <rule name = "extensions"> - <doc> - The server MAY implement other exchange types as wanted. - </doc> - </rule> - - <!-- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - --> - - <method name = "declare" synchronous = "1" index = "10" label = "verify exchange exists, create if needed"> - <doc> - This method creates an exchange if it does not already exist, and if the exchange - exists, verifies that it is of the correct and expected class. - </doc> - <rule name = "minimum"> - <doc> - The server SHOULD support a minimum of 16 exchanges per virtual host and - ideally, impose no limit except as defined by available resources. - </doc> - <doc type = "scenario"> - The client declares as many exchanges as it can until the server reports - an error; the number of exchanges successfully declared must be at least - sixteen. + The server-assigned and channel-specific delivery tag </doc> - </rule> - - <chassis name = "server" implement = "MUST" /> - <response name = "declare-ok" /> - - <!-- Deprecated: "ticket", must be zero --> - <field name = "reserved-1" type = "short" reserved = "1" /> - - <field name = "exchange" domain = "exchange-name"> - <rule name = "reserved" on-failure = "access-refused"> - <doc> - Exchange names starting with "amq." are reserved for pre-declared and - standardised exchanges. The client MAY declare an exchange starting with - "amq." if the passive option is set, or the exchange already exists. - </doc> - <doc type = "scenario"> - The client attempts to declare a non-existing exchange starting with - "amq." and with the passive option set to zero. - </doc> + <rule name="channel-local"> + <doc> + The delivery tag is valid only within the channel from which the + message was + received. I.e. a client MUST NOT receive a message on one + channel and then + acknowledge it on another. + </doc> </rule> - <rule name = "syntax" on-failure = "precondition-failed"> - <doc> - The exchange name consists of a non-empty sequence of these characters: - letters, digits, hyphen, underscore, period, or colon. - </doc> - <doc type = "scenario"> - The client attempts to declare an exchange with an illegal name. - </doc> + <rule name="non-zero"> + <doc> + The server MUST NOT use a zero value for delivery tags. Zero is + reserved + for client use, meaning "all messages so far received". + </doc> </rule> - <assert check = "notnull" /> - </field> + </domain> - <field name = "type" domain = "shortstr" label = "exchange type"> + <domain name="exchange-name" type="shortstr" label="exchange name"> <doc> - Each exchange belongs to one of a set of exchange types implemented by the - server. The exchange types define the functionality of the exchange - i.e. how - messages are routed through it. It is not valid or meaningful to attempt to - change the type of an existing exchange. + The exchange name is a client-selected string that identifies the + exchange for + publish methods. </doc> - <rule name = "typed" on-failure = "not-allowed"> - <doc> - Exchanges cannot be redeclared with different types. The client MUST not - attempt to redeclare an existing exchange with a different type than used - in the original Exchange.Declare method. - </doc> - <doc type = "scenario"> - TODO. - </doc> - </rule> - <rule name = "support" on-failure = "command-invalid"> - <doc> - The client MUST NOT attempt to declare an exchange with a type that the - server does not support. - </doc> - <doc type = "scenario"> - TODO. - </doc> - </rule> - </field> + <assert check="length" value="127"/> + <assert check="regexp" value="^[a-zA-Z0-9-_.:]*$"/> + </domain> - <field name = "passive" domain = "bit" label = "do not create exchange"> - <doc> - If set, the server will reply with Declare-Ok if the exchange already - exists with the same name, and raise an error if not. The client can - use this to check whether an exchange exists without modifying the - server state. When set, all other method fields except name and no-wait - are ignored. A declare with both passive and no-wait has no effect. - Arguments are compared for semantic equivalence. - </doc> - <rule name = "not-found"> - <doc> - If set, and the exchange does not already exist, the server MUST - raise a channel exception with reply code 404 (not found). - </doc> - <doc type = "scenario"> - TODO. - </doc> - </rule> - <rule name = "equivalent"> - <doc> - If not set and the exchange exists, the server MUST check that the - existing exchange has the same values for type, durable, and arguments - fields. The server MUST respond with Declare-Ok if the requested - exchange matches these fields, and MUST raise a channel exception if - not. - </doc> - <doc type = "scenario"> - TODO. - </doc> - </rule> - </field> + <domain name="method-id" type="short"/> - <field name = "durable" domain = "bit" label = "request a durable exchange"> + <domain name="no-ack" type="bit" label="no acknowledgement needed"> <doc> - If set when creating a new exchange, the exchange will be marked as durable. - Durable exchanges remain active when a server restarts. Non-durable exchanges - (transient exchanges) are purged if/when a server restarts. + If this field is set the server does not expect acknowledgements for + messages. That is, when a message is delivered to the client the + server + assumes the delivery will succeed and immediately dequeues it. This + functionality may increase performance but at the cost of + reliability. + Messages can get lost if a client dies before they are delivered to + the + application. </doc> - <rule name = "support"> - <doc> - The server MUST support both durable and transient exchanges. - </doc> - <doc type = "scenario"> - TODO. - </doc> - </rule> - </field> - - <!-- Deprecated: "auto-delete", must be zero --> - <field name = "reserved-2" type = "bit" reserved = "1" /> - <!-- Deprecated: "internal", must be zero --> - <field name = "reserved-3" type = "bit" reserved = "1" /> - <field name = "no-wait" domain = "no-wait" /> + </domain> - <field name = "arguments" domain = "table" label = "arguments for declaration"> + <domain name="no-local" type="bit" label="do not deliver own messages"> <doc> - A set of arguments for the declaration. The syntax and semantics of these - arguments depends on the server implementation. + If the no-local field is set the server will not send messages to + the connection that + published them. </doc> - </field> - </method> - - <method name = "declare-ok" synchronous = "1" index = "11" label = "confirm exchange declaration"> - <doc> - This method confirms a Declare method and confirms the name of the exchange, - essential for automatically-named exchanges. - </doc> - <chassis name = "client" implement = "MUST" /> - </method> - - <!-- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - --> - - <method name = "delete" synchronous = "1" index = "20" label = "delete an exchange"> - <doc> - This method deletes an exchange. When an exchange is deleted all queue bindings on - the exchange are cancelled. - </doc> - - <chassis name = "server" implement = "MUST" /> - <response name = "delete-ok" /> - - <!-- Deprecated: "ticket", must be zero --> - <field name = "reserved-1" type = "short" reserved = "1" /> - - <field name = "exchange" domain = "exchange-name"> - <rule name = "exists" on-failure = "not-found"> - <doc> - The client MUST NOT attempt to delete an exchange that does not exist. - </doc> - </rule> - <assert check = "notnull" /> - </field> + </domain> - <field name = "if-unused" domain = "bit" label = "delete only if unused"> + <domain name="no-wait" type="bit" label="do not send reply method"> <doc> - If set, the server will only delete the exchange if it has no queue bindings. If - the exchange has queue bindings the server does not delete it but raises a - channel exception instead. + If set, the server will not respond to the method. The client should + not wait + for a reply method. If the server could not complete the method it + will raise a + channel or connection exception. </doc> - <rule name = "in-use" on-failure = "precondition-failed"> - <doc> - The server MUST NOT delete an exchange that has bindings on it, if the if-unused - field is true. - </doc> - <doc type = "scenario"> - The client declares an exchange, binds a queue to it, then tries to delete it - setting if-unused to true. - </doc> - </rule> - </field> - - <field name = "no-wait" domain = "no-wait" /> - </method> - - <method name = "delete-ok" synchronous = "1" index = "21" - label = "confirm deletion of an exchange"> - <doc>This method confirms the deletion of an exchange.</doc> - <chassis name = "client" implement = "MUST" /> - </method> - </class> - - <!-- == QUEUE ============================================================ --> - - <class name = "queue" handler = "channel" index = "50" label = "work with queues"> - <doc> - Queues store and forward messages. Queues can be configured in the server or created at - runtime. Queues must be attached to at least one exchange in order to receive messages - from publishers. - </doc> - - <doc type = "grammar"> - queue = C:DECLARE S:DECLARE-OK - / C:BIND S:BIND-OK - / C:UNBIND S:UNBIND-OK - / C:PURGE S:PURGE-OK - / C:DELETE S:DELETE-OK - </doc> - - <chassis name = "server" implement = "MUST" /> - <chassis name = "client" implement = "MUST" /> - - <!-- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - --> - - <method name = "declare" synchronous = "1" index = "10" label = "declare queue, create if needed"> - <doc> - This method creates or checks a queue. When creating a new queue the client can - specify various properties that control the durability of the queue and its - contents, and the level of sharing for the queue. - </doc> - - <rule name = "default-binding"> - <doc> - The server MUST create a default binding for a newly-declared queue to the - default exchange, which is an exchange of type 'direct' and use the queue - name as the routing key. - </doc> - <doc type = "scenario"> - Client declares a new queue, and then without explicitly binding it to an - exchange, attempts to send a message through the default exchange binding, - i.e. publish a message to the empty exchange, with the queue name as routing - key. - </doc> - </rule> + </domain> - <rule name = "minimum-queues"> + <domain name="path" type="shortstr"> <doc> - The server SHOULD support a minimum of 256 queues per virtual host and ideally, - impose no limit except as defined by available resources. + Unconstrained. </doc> - <doc type = "scenario"> - Client attempts to declare as many queues as it can until the server reports - an error. The resulting count must at least be 256. - </doc> - </rule> - - <chassis name = "server" implement = "MUST" /> - <response name = "declare-ok" /> - - <!-- Deprecated: "ticket", must be zero --> - <field name = "reserved-1" type = "short" reserved = "1" /> - - <field name = "queue" domain = "queue-name"> - <rule name = "default-name"> - <doc> - The queue name MAY be empty, in which case the server MUST create a new - queue with a unique generated name and return this to the client in the - Declare-Ok method. - </doc> - <doc type = "scenario"> - Client attempts to declare several queues with an empty name. The client then - verifies that the server-assigned names are unique and different. - </doc> - </rule> - <rule name = "reserved" on-failure = "access-refused"> - <doc> - Queue names starting with "amq." are reserved for pre-declared and - standardised queues. The client MAY declare a queue starting with - "amq." if the passive option is set, or the queue already exists. - </doc> - <doc type = "scenario"> - The client attempts to declare a non-existing queue starting with - "amq." and with the passive option set to zero. - </doc> - </rule> - <rule name = "syntax" on-failure = "precondition-failed"> - <doc> - The queue name can be empty, or a sequence of these characters: - letters, digits, hyphen, underscore, period, or colon. - </doc> - <doc type = "scenario"> - The client attempts to declare a queue with an illegal name. - </doc> - </rule> - </field> + <assert check="notnull"/> + <assert check="length" value="127"/> + </domain> - <field name = "passive" domain = "bit" label = "do not create queue"> + <domain name="peer-properties" type="table"> <doc> - If set, the server will reply with Declare-Ok if the queue already - exists with the same name, and raise an error if not. The client can - use this to check whether a queue exists without modifying the - server state. When set, all other method fields except name and no-wait - are ignored. A declare with both passive and no-wait has no effect. - Arguments are compared for semantic equivalence. + This table provides a set of peer properties, used for + identification, debugging, + and general information. </doc> - <rule name = "passive" on-failure = "not-found"> - <doc> - The client MAY ask the server to assert that a queue exists without - creating the queue if not. If the queue does not exist, the server - treats this as a failure. - </doc> - <doc type = "scenario"> - Client declares an existing queue with the passive option and expects - the server to respond with a declare-ok. Client then attempts to declare - a non-existent queue with the passive option, and the server must close - the channel with the correct reply-code. - </doc> - </rule> - <rule name = "equivalent"> - <doc> - If not set and the queue exists, the server MUST check that the - existing queue has the same values for durable, exclusive, auto-delete, - and arguments fields. The server MUST respond with Declare-Ok if the - requested queue matches these fields, and MUST raise a channel exception - if not. - </doc> - <doc type = "scenario"> - TODO. - </doc> - </rule> - </field> + </domain> - <field name = "durable" domain = "bit" label = "request a durable queue"> + <domain name="queue-name" type="shortstr" label="queue name"> <doc> - If set when creating a new queue, the queue will be marked as durable. Durable - queues remain active when a server restarts. Non-durable queues (transient - queues) are purged if/when a server restarts. Note that durable queues do not - necessarily hold persistent messages, although it does not make sense to send - persistent messages to a transient queue. + The queue name identifies the queue within the vhost. In methods + where the queue + name may be blank, and that has no specific significance, this + refers to the + 'current' queue for the channel, meaning the last queue that the + client declared + on the channel. If the client did not declare a queue, and the + method needs a + queue name, this will result in a 502 (syntax error) channel + exception. </doc> + <assert check="length" value="127"/> + <assert check="regexp" value="^[a-zA-Z0-9-_.:]*$"/> + </domain> - <rule name = "persistence"> - <doc>The server MUST recreate the durable queue after a restart.</doc> - - <doc type = "scenario"> - Client declares a durable queue. The server is then restarted. The client - then attempts to send a message to the queue. The message should be successfully - delivered. - </doc> - </rule> - - <rule name = "types"> - <doc>The server MUST support both durable and transient queues.</doc> - <doc type = "scenario"> - A client declares two named queues, one durable and one transient. - </doc> - </rule> - </field> - - <field name = "exclusive" domain = "bit" label = "request an exclusive queue"> + <domain name="redelivered" type="bit" label="message is being redelivered"> <doc> - Exclusive queues may only be accessed by the current connection, and are - deleted when that connection closes. Passive declaration of an exclusive - queue by other connections are not allowed. + This indicates that the message has been previously delivered to + this or + another client. </doc> - - <rule name = "types"> - <doc> - The server MUST support both exclusive (private) and non-exclusive (shared) - queues. - </doc> - <doc type = "scenario"> - A client declares two named queues, one exclusive and one non-exclusive. - </doc> + <rule name="implementation"> + <doc> + The server SHOULD try to signal redelivered messages when it + can. When + redelivering a message that was not successfully acknowledged, + the server + SHOULD deliver it to the original client if possible. + </doc> + <doc type="scenario"> + Declare a shared queue and publish a message to the queue. + Consume the + message using explicit acknowledgements, but do not acknowledge + the + message. Close the connection, reconnect, and consume from the + queue + again. The message should arrive with the redelivered flag set. + </doc> </rule> - - <rule name = "exclusive" on-failure = "resource-locked"> - <doc> - The client MAY NOT attempt to use a queue that was declared as exclusive - by another still-open connection. - </doc> - <doc type = "scenario"> - One client declares an exclusive queue. A second client on a different - connection attempts to declare, bind, consume, purge, delete, or declare - a queue of the same name. - </doc> + <rule name="hinting"> + <doc> + The client MUST NOT rely on the redelivered field but should + take it as a + hint that the message may already have been processed. A fully + robust + client must be able to track duplicate received messages on + non-transacted, + and locally-transacted channels. + </doc> </rule> - </field> - - <field name = "auto-delete" domain = "bit" label = "auto-delete queue when unused"> - <doc> - If set, the queue is deleted when all consumers have finished using it. The last - consumer can be cancelled either explicitly or because its channel is closed. If - there was no consumer ever on the queue, it won't be deleted. Applications can - explicitly delete auto-delete queues using the Delete method as normal. - </doc> - - <rule name = "pre-existence"> - <doc> - The server MUST ignore the auto-delete field if the queue already exists. - </doc> - <doc type = "scenario"> - Client declares two named queues, one as auto-delete and one explicit-delete. - Client then attempts to declare the two queues using the same names again, - but reversing the value of the auto-delete field in each case. Verify that the - queues still exist with the original auto-delete flag values. - </doc> + </domain> + + <domain name="message-count" type="long" + label="number of messages in queue"> + <doc> + The number of messages in the queue, which will be zero for + newly-declared + queues. This is the number of messages present in the queue, and + committed + if the channel on which they were published is transacted, that are + not + waiting acknowledgement. + </doc> + </domain> + + <domain name="reply-code" type="short" label="reply code from server"> + <doc> + The reply code. The AMQ reply codes are defined as constants at the + start + of this formal specification. + </doc> + <assert check="notnull"/> + </domain> + + <domain name="reply-text" type="shortstr" label="localised reply text"> + <doc> + The localised reply text. This text can be logged as an aid to + resolving + issues. + </doc> + <assert check="notnull"/> + </domain> + + <!-- Elementary domains --> + <domain name="bit" type="bit" label="single bit"/> + <domain name="octet" type="octet" label="single octet"/> + <domain name="short" type="short" label="16-bit integer"/> + <domain name="long" type="long" label="32-bit integer"/> + <domain name="longlong" type="longlong" label="64-bit integer"/> + <domain name="shortstr" type="shortstr" label="short string"/> + <domain name="longstr" type="longstr" label="long string"/> + <domain name="timestamp" type="timestamp" label="64-bit timestamp"/> + <domain name="table" type="table" label="field table"/> + + <!-- == CONNECTION ======================================================= --> + + <class name="connection" handler="connection" index="10" + label="work with socket connections"> + <doc> + The connection class provides methods for a client to establish a + network connection to + a server, and for both peers to operate the connection thereafter. + </doc> + + <doc type="grammar"> + connection = open-connection *use-connection close-connection + open-connection = C:protocol-header + S:START C:START-OK + *challenge + S:TUNE C:TUNE-OK + C:OPEN S:OPEN-OK + challenge = S:SECURE C:SECURE-OK + use-connection = *channel + close-connection = C:CLOSE S:CLOSE-OK + / S:CLOSE C:CLOSE-OK + </doc> + + <chassis name="server" implement="MUST"/> + <chassis name="client" implement="MUST"/> + + <!-- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - --> + + <method name="start" synchronous="1" index="10" + label="start connection negotiation"> + <doc> + This method starts the connection negotiation process by telling + the client the + protocol version that the server proposes, along with a list of + security mechanisms + which the client can use for authentication. + </doc> + + <rule name="protocol-name"> + <doc> + If the server cannot support the protocol specified in the + protocol header, + it MUST respond with a valid protocol header and then close + the socket + connection. + </doc> + <doc type="scenario"> + The client sends a protocol header containing an invalid + protocol name. + The server MUST respond by sending a valid protocol header + and then closing + the connection. + </doc> + </rule> + <rule name="server-support"> + <doc> + The server MUST provide a protocol version that is lower + than or equal to + that requested by the client in the protocol header. + </doc> + <doc type="scenario"> + The client requests a protocol version that is higher than + any valid + implementation, e.g. 2.0. The server must respond with a + protocol header + indicating its supported protocol version, e.g. 1.0. + </doc> + </rule> + <rule name="client-support"> + <doc> + If the client cannot handle the protocol version suggested + by the server + it MUST close the socket connection without sending any + further data. + </doc> + <doc type="scenario"> + The server sends a protocol version that is lower than any + valid + implementation, e.g. 0.1. The client must respond by closing + the + connection without sending any further data. + </doc> + </rule> + + <chassis name="client" implement="MUST"/> + <response name="start-ok"/> + + <field name="version-major" domain="octet" + label="protocol major version"> + <doc> + The major version number can take any value from 0 to 99 as + defined in the + AMQP specification. + </doc> + </field> + + <field name="version-minor" domain="octet" + label="protocol minor version"> + <doc> + The minor version number can take any value from 0 to 99 as + defined in the + AMQP specification. + </doc> + </field> + + <field name="server-properties" domain="peer-properties" + label="server properties"> + <rule name="required-fields"> + <doc> + The properties SHOULD contain at least these fields: + "host", specifying the + server host name or address, "product", giving the name + of the server product, + "version", giving the name of the server version, + "platform", giving the name + of the operating system, "copyright", if appropriate, + and "information", giving + other general information. + </doc> + <doc type="scenario"> + Client connects to server and inspects the server + properties. It checks for + the presence of the required fields. + </doc> + </rule> + </field> + + <field name="mechanisms" domain="longstr" + label="available security mechanisms"> + <doc> + A list of the security mechanisms that the server supports, + delimited by spaces. + </doc> + <assert check="notnull"/> + </field> + + <field name="locales" domain="longstr" + label="available message locales"> + <doc> + A list of the message locales that the server supports, + delimited by spaces. The + locale defines the language in which the server will send + reply texts. + </doc> + <rule name="required-support"> + <doc> + The server MUST support at least the en_US locale. + </doc> + <doc type="scenario"> + Client connects to server and inspects the locales + field. It checks for + the presence of the required locale(s). + </doc> + </rule> + <assert check="notnull"/> + </field> + </method> + + <method name="start-ok" synchronous="1" index="11" + label="select security mechanism and locale"> + <doc> + This method selects a SASL security mechanism. + </doc> + + <chassis name="server" implement="MUST"/> + + <field name="client-properties" domain="peer-properties" + label="client properties"> + <rule name="required-fields"> + <!-- This rule is not testable from the client side --> + <doc> + The properties SHOULD contain at least these fields: + "product", giving the name + of the client product, "version", giving the name of the + client version, "platform", + giving the name of the operating system, "copyright", if + appropriate, and + "information", giving other general information. + </doc> + </rule> + </field> + + <field name="mechanism" domain="shortstr" + label="selected security mechanism"> + <doc> + A single security mechanisms selected by the client, which + must be one of those + specified by the server. + </doc> + <rule name="security"> + <doc> + The client SHOULD authenticate using the highest-level + security profile it + can handle from the list provided by the server. + </doc> + </rule> + <rule name="validity"> + <doc> + If the mechanism field does not contain one of the + security mechanisms + proposed by the server in the Start method, the server + MUST close the + connection without sending any further data. + </doc> + <doc type="scenario"> + Client connects to server and sends an invalid security + mechanism. The + server must respond by closing the connection (a socket + close, with no + connection close negotiation). + </doc> + </rule> + <assert check="notnull"/> + </field> + + <field name="response" domain="longstr" + label="security response data"> + <doc> + A block of opaque data passed to the security mechanism. The + contents of this + data are defined by the SASL security mechanism. + </doc> + <assert check="notnull"/> + </field> + + <field name="locale" domain="shortstr" + label="selected message locale"> + <doc> + A single message locale selected by the client, which must + be one of those + specified by the server. + </doc> + <assert check="notnull"/> + </field> + </method> + + <!-- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - --> + + <method name="secure" synchronous="1" index="20" + label="security mechanism challenge"> + <doc> + The SASL protocol works by exchanging challenges and responses + until both peers have + received sufficient information to authenticate each other. This + method challenges + the client to provide more information. + </doc> + + <chassis name="client" implement="MUST"/> + <response name="secure-ok"/> + + <field name="challenge" domain="longstr" + label="security challenge data"> + <doc> + Challenge information, a block of opaque binary data passed + to the security + mechanism. + </doc> + </field> + </method> + + <method name="secure-ok" synchronous="1" index="21" + label="security mechanism response"> + <doc> + This method attempts to authenticate, passing a block of SASL + data for the security + mechanism at the server side. + </doc> + + <chassis name="server" implement="MUST"/> + + <field name="response" domain="longstr" + label="security response data"> + <doc> + A block of opaque data passed to the security mechanism. The + contents of this + data are defined by the SASL security mechanism. + </doc> + <assert check="notnull"/> + </field> + </method> + + <!-- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - --> + + <method name="tune" synchronous="1" index="30" + label="propose connection tuning parameters"> + <doc> + This method proposes a set of connection configuration values to + the client. The + client can accept and/or adjust these. + </doc> + + <chassis name="client" implement="MUST"/> + + <response name="tune-ok"/> + + <field name="channel-max" domain="short" + label="proposed maximum channels"> + <doc> + Specifies highest channel number that the server permits. + Usable channel numbers + are in the range 1..channel-max. Zero indicates no specified + limit. + </doc> + </field> + + <field name="frame-max" domain="long" + label="proposed maximum frame size"> + <doc> + The largest frame size that the server proposes for the + connection, including + frame header and end-byte. The client can negotiate a lower + value. Zero means + that the server does not impose any specific limit but may + reject very large + frames if it cannot allocate resources for them. + </doc> + <rule name="minimum"> + <doc> + Until the frame-max has been negotiated, both peers MUST + accept frames of up + to frame-min-size octets large, and the minimum + negotiated value for frame-max + is also frame-min-size. + </doc> + <doc type="scenario"> + Client connects to server and sends a large properties + field, creating a frame + of frame-min-size octets. The server must accept this + frame. + </doc> + </rule> + </field> + + <field name="heartbeat" domain="short" + label="desired heartbeat delay"> + <doc> + The delay, in seconds, of the connection heartbeat that the + server wants. + Zero means the server does not want a heartbeat. + </doc> + </field> + </method> + + <method name="tune-ok" synchronous="1" index="31" + label="negotiate connection tuning parameters"> + <doc> + This method sends the client's connection tuning parameters to + the server. + Certain fields are negotiated, others provide capability + information. + </doc> + + <chassis name="server" implement="MUST"/> + + <field name="channel-max" domain="short" + label="negotiated maximum channels"> + <doc> + The maximum total number of channels that the client will + use per connection. + </doc> + <rule name="upper-limit"> + <doc> + If the client specifies a channel max that is higher + than the value provided + by the server, the server MUST close the connection + without attempting a + negotiated close. The server may report the error in + some fashion to assist + implementors. + </doc> + </rule> + <assert check="notnull"/> + <assert check="le" method="tune" field="channel-max"/> + </field> + + <field name="frame-max" domain="long" + label="negotiated maximum frame size"> + <doc> + The largest frame size that the client and server will use + for the connection. + Zero means that the client does not impose any specific + limit but may reject + very large frames if it cannot allocate resources for them. + Note that the + frame-max limit applies principally to content frames, where + large contents can + be broken into frames of arbitrary size. + </doc> + <rule name="minimum"> + <doc> + Until the frame-max has been negotiated, both peers MUST + accept frames of up + to frame-min-size octets large, and the minimum + negotiated value for frame-max + is also frame-min-size. + </doc> + </rule> + <rule name="upper-limit"> + <doc> + If the client specifies a frame max that is higher than + the value provided + by the server, the server MUST close the connection + without attempting a + negotiated close. The server may report the error in + some fashion to assist + implementors. + </doc> + </rule> + </field> + + <field name="heartbeat" domain="short" + label="desired heartbeat delay"> + <doc> + The delay, in seconds, of the connection heartbeat that the + client wants. Zero + means the client does not want a heartbeat. + </doc> + </field> + </method> + + <!-- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - --> + + <method name="open" synchronous="1" index="40" + label="open connection to virtual host"> + <doc> + This method opens a connection to a virtual host, which is a + collection of + resources, and acts to separate multiple application domains + within a server. + The server may apply arbitrary limits per virtual host, such as + the number + of each type of entity that may be used, per connection and/or + in total. + </doc> + + <chassis name="server" implement="MUST"/> + <response name="open-ok"/> + + <field name="virtual-host" domain="path" label="virtual host name"> + <doc> + The name of the virtual host to work with. + </doc> + <rule name="separation"> + <doc> + If the server supports multiple virtual hosts, it MUST + enforce a full + separation of exchanges, queues, and all associated + entities per virtual + host. An application, connected to a specific virtual + host, MUST NOT be able + to access resources of another virtual host. + </doc> + </rule> + <rule name="security"> + <doc> + The server SHOULD verify that the client has permission + to access the + specified virtual host. + </doc> + </rule> + </field> + <!-- Deprecated: "capabilities", must be zero --> + <field name="reserved-1" type="shortstr" reserved="1"/> + <!-- Deprecated: "insist", must be zero --> + <field name="reserved-2" type="bit" reserved="1"/> + </method> + + <method name="open-ok" synchronous="1" index="41" + label="signal that connection is ready"> + <doc> + This method signals to the client that the connection is ready + for use. + </doc> + <chassis name="client" implement="MUST"/> + <!-- Deprecated: "known-hosts", must be zero --> + <field name="reserved-1" type="shortstr" reserved="1"/> + </method> + + <!-- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - --> + + <method name="close" synchronous="1" index="50" + label="request a connection close"> + <doc> + This method indicates that the sender wants to close the + connection. This may be + due to internal conditions (e.g. a forced shut-down) or due to + an error handling + a specific method, i.e. an exception. When a close is due to an + exception, the + sender provides the class and method id of the method which + caused the exception. + </doc> + <rule name="stability"> + <doc> + After sending this method, any received methods except Close + and Close-OK MUST + be discarded. The response to receiving a Close after + sending Close must be to + send Close-Ok. + </doc> + </rule> + + <chassis name="client" implement="MUST"/> + <chassis name="server" implement="MUST"/> + <response name="close-ok"/> + + <field name="reply-code" domain="reply-code"/> + <field name="reply-text" domain="reply-text"/> + + <field name="class-id" domain="class-id" + label="failing method class"> + <doc> + When the close is provoked by a method exception, this is + the class of the + method. + </doc> + </field> + + <field name="method-id" domain="method-id" + label="failing method ID"> + <doc> + When the close is provoked by a method exception, this is + the ID of the method. + </doc> + </field> + </method> + + <method name="close-ok" synchronous="1" index="51" + label="confirm a connection close"> + <doc> + This method confirms a Connection.Close method and tells the + recipient that it is + safe to release resources for the connection and close the + socket. + </doc> + <rule name="reporting"> + <doc> + A peer that detects a socket closure without having received + a Close-Ok + handshake method SHOULD log the error. + </doc> + </rule> + <chassis name="client" implement="MUST"/> + <chassis name="server" implement="MUST"/> + </method> + </class> + + <!-- == CHANNEL ========================================================== --> + + <class name="channel" handler="channel" index="20" + label="work with channels"> + <doc> + The channel class provides methods for a client to establish a + channel to a + server and for both peers to operate the channel thereafter. + </doc> + + <doc type="grammar"> + channel = open-channel *use-channel close-channel + open-channel = C:OPEN S:OPEN-OK + use-channel = C:FLOW S:FLOW-OK + / S:FLOW C:FLOW-OK + / functional-class + close-channel = C:CLOSE S:CLOSE-OK + / S:CLOSE C:CLOSE-OK + </doc> + + <chassis name="server" implement="MUST"/> + <chassis name="client" implement="MUST"/> + + <!-- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - --> + + <method name="open" synchronous="1" index="10" + label="open a channel for use"> + <doc> + This method opens a channel to the server. + </doc> + <rule name="state" on-failure="channel-error"> + <doc> + The client MUST NOT use this method on an already-opened + channel. + </doc> + <doc type="scenario"> + Client opens a channel and then reopens the same channel. + </doc> + </rule> + <chassis name="server" implement="MUST"/> + <response name="open-ok"/> + <!-- Deprecated: "out-of-band", must be zero --> + <field name="reserved-1" type="shortstr" reserved="1"/> + </method> + + <method name="open-ok" synchronous="1" index="11" + label="signal that the channel is ready"> + <doc> + This method signals to the client that the channel is ready for + use. + </doc> + <chassis name="client" implement="MUST"/> + <!-- Deprecated: "channel-id", must be zero --> + <field name="reserved-1" type="longstr" reserved="1"/> + </method> + + <!-- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - --> + + <method name="flow" synchronous="1" index="20" + label="enable/disable flow from peer"> + <doc> + This method asks the peer to pause or restart the flow of + content data sent by + a consumer. This is a simple flow-control mechanism that a peer + can use to avoid + overflowing its queues or otherwise finding itself receiving + more messages than + it can process. Note that this method is not intended for window + control. It does + not affect contents returned by Basic.Get-Ok methods. + </doc> + + <rule name="initial-state"> + <doc> + When a new channel is opened, it is active (flow is active). + Some applications + assume that channels are inactive until started. To emulate + this behaviour a + client MAY open the channel, then pause it. + </doc> + </rule> + + <rule name="bidirectional"> + <doc> + When sending content frames, a peer SHOULD monitor the + channel for incoming + methods and respond to a Channel.Flow as rapidly as + possible. + </doc> + </rule> + + <rule name="throttling"> + <doc> + A peer MAY use the Channel.Flow method to throttle incoming + content data for + internal reasons, for example, when exchanging data over a + slower connection. + </doc> + </rule> + + <rule name="expected-behaviour"> + <doc> + The peer that requests a Channel.Flow method MAY disconnect + and/or ban a peer + that does not respect the request. This is to prevent + badly-behaved clients + from overwhelming a server. + </doc> + </rule> + + <chassis name="server" implement="MUST"/> + <chassis name="client" implement="MUST"/> + + <response name="flow-ok"/> + + <field name="active" domain="bit" label="start/stop content frames"> + <doc> + If 1, the peer starts sending content frames. If 0, the peer + stops sending + content frames. + </doc> + </field> + </method> + + <method name="flow-ok" index="21" label="confirm a flow method"> + <doc> + Confirms to the peer that a flow command was received and + processed. + </doc> + <chassis name="server" implement="MUST"/> + <chassis name="client" implement="MUST"/> + <field name="active" domain="bit" label="current flow setting"> + <doc> + Confirms the setting of the processed flow method: 1 means + the peer will start + sending or continue to send content frames; 0 means it will + not. + </doc> + </field> + </method> + + <!-- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - --> + + <method name="close" synchronous="1" index="40" + label="request a channel close"> + <doc> + This method indicates that the sender wants to close the + channel. This may be due to + internal conditions (e.g. a forced shut-down) or due to an error + handling a specific + method, i.e. an exception. When a close is due to an exception, + the sender provides + the class and method id of the method which caused the + exception. + </doc> + <rule name="stability"> + <doc> + After sending this method, any received methods except Close + and Close-OK MUST + be discarded. The response to receiving a Close after + sending Close must be to + send Close-Ok. + </doc> + </rule> + + <chassis name="client" implement="MUST"/> + <chassis name="server" implement="MUST"/> + <response name="close-ok"/> + + <field name="reply-code" domain="reply-code"/> + <field name="reply-text" domain="reply-text"/> + + <field name="class-id" domain="class-id" + label="failing method class"> + <doc> + When the close is provoked by a method exception, this is + the class of the + method. + </doc> + </field> + + <field name="method-id" domain="method-id" + label="failing method ID"> + <doc> + When the close is provoked by a method exception, this is + the ID of the method. + </doc> + </field> + </method> + + <method name="close-ok" synchronous="1" index="41" + label="confirm a channel close"> + <doc> + This method confirms a Channel.Close method and tells the + recipient that it is safe + to release resources for the channel. + </doc> + <rule name="reporting"> + <doc> + A peer that detects a socket closure without having received + a Channel.Close-Ok + handshake method SHOULD log the error. + </doc> + </rule> + <chassis name="client" implement="MUST"/> + <chassis name="server" implement="MUST"/> + </method> + </class> + + <!-- == EXCHANGE ========================================================= --> + + <class name="exchange" handler="channel" index="40" + label="work with exchanges"> + <doc> + Exchanges match and distribute messages across queues. Exchanges can + be configured in + the server or declared at runtime. + </doc> + + <doc type="grammar"> + exchange = C:DECLARE S:DECLARE-OK + / C:DELETE S:DELETE-OK + </doc> + + <chassis name="server" implement="MUST"/> + <chassis name="client" implement="MUST"/> + + <rule name="required-types"> + <doc> + The server MUST implement these standard exchange types: fanout, + direct. + </doc> + <doc type="scenario"> + Client attempts to declare an exchange with each of these + standard types. + </doc> </rule> - </field> - - <field name = "no-wait" domain = "no-wait" /> - - <field name = "arguments" domain = "table" label = "arguments for declaration"> - <doc> - A set of arguments for the declaration. The syntax and semantics of these - arguments depends on the server implementation. - </doc> - </field> - </method> - - <method name = "declare-ok" synchronous = "1" index = "11" label = "confirms a queue definition"> - <doc> - This method confirms a Declare method and confirms the name of the queue, essential - for automatically-named queues. - </doc> - - <chassis name = "client" implement = "MUST" /> - - <field name = "queue" domain = "queue-name"> - <doc> - Reports the name of the queue. If the server generated a queue name, this field - contains that name. - </doc> - <assert check = "notnull" /> - </field> - - <field name = "message-count" domain = "message-count" /> - - <field name = "consumer-count" domain = "long" label = "number of consumers"> - <doc> - Reports the number of active consumers for the queue. Note that consumers can - suspend activity (Channel.Flow) in which case they do not appear in this count. - </doc> - </field> - </method> - - <!-- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - --> - - <method name = "bind" synchronous = "1" index = "20" label = "bind queue to an exchange"> - <doc> - This method binds a queue to an exchange. Until a queue is bound it will not - receive any messages. In a classic messaging model, store-and-forward queues - are bound to a direct exchange and subscription queues are bound to a topic - exchange. - </doc> - - <rule name = "duplicates"> - <doc> - A server MUST allow ignore duplicate bindings - that is, two or more bind - methods for a specific queue, with identical arguments - without treating these - as an error. - </doc> - <doc type = "scenario"> - A client binds a named queue to an exchange. The client then repeats the bind - (with identical arguments). - </doc> - </rule> - - <rule name = "unique"> - <doc> - A server MUST not deliver the same message more than once to a queue, even if - the queue has multiple bindings that match the message. - </doc> - <doc type = "scenario"> - A client declares a named queue and binds it using multiple bindings to the - amq.topic exchange. The client then publishes a message that matches all its - bindings. - </doc> - </rule> - - <rule name = "transient-exchange"> - <doc> - The server MUST allow a durable queue to bind to a transient exchange. - </doc> - <doc type = "scenario"> - A client declares a transient exchange. The client then declares a named durable - queue and then attempts to bind the transient exchange to the durable queue. - </doc> - </rule> - - <rule name = "durable-exchange"> - <doc> - Bindings of durable queues to durable exchanges are automatically durable - and the server MUST restore such bindings after a server restart. - </doc> - <doc type = "scenario"> - A server declares a named durable queue and binds it to a durable exchange. The - server is restarted. The client then attempts to use the queue/exchange combination. - </doc> - </rule> - - <rule name = "binding-count"> - <doc> - The server SHOULD support at least 4 bindings per queue, and ideally, impose no - limit except as defined by available resources. - </doc> - <doc type = "scenario"> - A client declares a named queue and attempts to bind it to 4 different - exchanges. - </doc> - </rule> - - <chassis name = "server" implement = "MUST" /> - - <response name = "bind-ok" /> - - <!-- Deprecated: "ticket", must be zero --> - <field name = "reserved-1" type = "short" reserved = "1" /> - - <field name = "queue" domain = "queue-name"> - <doc>Specifies the name of the queue to bind.</doc> - <rule name = "queue-known" on-failure = "not-found"> - <doc> - The client MUST either specify a queue name or have previously declared a - queue on the same channel - </doc> - <doc type = "scenario"> - The client opens a channel and attempts to bind an unnamed queue. - </doc> + <rule name="recommended-types"> + <doc> + The server SHOULD implement these standard exchange types: + topic, headers. + </doc> + <doc type="scenario"> + Client attempts to declare an exchange with each of these + standard types. + </doc> </rule> - <rule name = "must-exist" on-failure = "not-found"> - <doc> - The client MUST NOT attempt to bind a queue that does not exist. - </doc> - <doc type = "scenario"> - The client attempts to bind a non-existent queue. - </doc> + <rule name="required-instances"> + <doc> + The server MUST, in each virtual host, pre-declare an exchange + instance + for each standard exchange type that it implements, where the + name of the + exchange instance, if defined, is "amq." followed by the + exchange type name. + </doc> + <doc> + The server MUST, in each virtual host, pre-declare at least two + direct + exchange instances: one named "amq.direct", the other with no + public name + that serves as a default exchange for Publish methods. + </doc> + <doc type="scenario"> + Client declares a temporary queue and attempts to bind to each + required + exchange instance ("amq.fanout", "amq.direct", "amq.topic", and + "amq.headers" + if those types are defined). + </doc> </rule> - </field> - - <field name = "exchange" domain = "exchange-name" label = "name of the exchange to bind to"> - <rule name = "exchange-existence" on-failure = "not-found"> - <doc> - A client MUST NOT be allowed to bind a queue to a non-existent exchange. - </doc> - <doc type = "scenario"> - A client attempts to bind an named queue to a undeclared exchange. - </doc> + <rule name="default-exchange"> + <doc> + The server MUST pre-declare a direct exchange with no public + name to act as + the default exchange for content Publish methods and for default + queue bindings. + </doc> + <doc type="scenario"> + Client checks that the default exchange is active by specifying + a queue + binding with no exchange name, and publishing a message with a + suitable + routing key but without specifying the exchange name, then + ensuring that + the message arrives in the queue correctly. + </doc> </rule> - <rule name = "default-exchange"> - <doc> - The server MUST accept a blank exchange name to mean the default exchange. - </doc> - <doc type = "scenario"> - The client declares a queue and binds it to a blank exchange name. - </doc> + <rule name="default-access"> + <doc> + The server MUST NOT allow clients to access the default exchange + except + by specifying an empty exchange name in the Queue.Bind and + content Publish + methods. + </doc> </rule> - </field> - - <field name = "routing-key" domain = "shortstr" label = "message routing key"> - <doc> - Specifies the routing key for the binding. The routing key is used for routing - messages depending on the exchange configuration. Not all exchanges use a - routing key - refer to the specific exchange documentation. If the queue name - is empty, the server uses the last queue declared on the channel. If the - routing key is also empty, the server uses this queue name for the routing - key as well. If the queue name is provided but the routing key is empty, the - server does the binding with that empty routing key. The meaning of empty - routing keys depends on the exchange implementation. - </doc> - <rule name = "direct-exchange-key-matching"> - <doc> - If a message queue binds to a direct exchange using routing key K and a - publisher sends the exchange a message with routing key R, then the message - MUST be passed to the message queue if K = R. - </doc> + <rule name="extensions"> + <doc> + The server MAY implement other exchange types as wanted. + </doc> </rule> - </field> - <field name = "no-wait" domain = "no-wait" /> - - <field name = "arguments" domain = "table" label = "arguments for binding"> - <doc> - A set of arguments for the binding. The syntax and semantics of these arguments - depends on the exchange class. - </doc> - </field> - </method> - - <method name = "bind-ok" synchronous = "1" index = "21" label = "confirm bind successful"> - <doc>This method confirms that the bind was successful.</doc> - - <chassis name = "client" implement = "MUST" /> - </method> - - <!-- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - --> - - <method name = "unbind" synchronous = "1" index = "50" label = "unbind a queue from an exchange"> - <doc>This method unbinds a queue from an exchange.</doc> - <rule name = "01"> - <doc>If a unbind fails, the server MUST raise a connection exception.</doc> - </rule> - <chassis name="server" implement="MUST"/> - <response name="unbind-ok"/> - - <!-- Deprecated: "ticket", must be zero --> - <field name = "reserved-1" type = "short" reserved = "1" /> - - <field name = "queue" domain = "queue-name"> - <doc>Specifies the name of the queue to unbind.</doc> - <rule name = "queue-known" on-failure = "not-found"> - <doc> - The client MUST either specify a queue name or have previously declared a - queue on the same channel - </doc> - <doc type = "scenario"> - The client opens a channel and attempts to unbind an unnamed queue. - </doc> - </rule> - <rule name = "must-exist" on-failure = "not-found"> - <doc> - The client MUST NOT attempt to unbind a queue that does not exist. - </doc> - <doc type = "scenario"> - The client attempts to unbind a non-existent queue. - </doc> + <!-- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - --> + + <method name="declare" synchronous="1" index="10" + label="verify exchange exists, create if needed"> + <doc> + This method creates an exchange if it does not already exist, + and if the exchange + exists, verifies that it is of the correct and expected class. + </doc> + <rule name="minimum"> + <doc> + The server SHOULD support a minimum of 16 exchanges per + virtual host and + ideally, impose no limit except as defined by available + resources. + </doc> + <doc type="scenario"> + The client declares as many exchanges as it can until the + server reports + an error; the number of exchanges successfully declared must + be at least + sixteen. + </doc> + </rule> + + <chassis name="server" implement="MUST"/> + <response name="declare-ok"/> + + <!-- Deprecated: "ticket", must be zero --> + <field name="reserved-1" type="short" reserved="1"/> + + <field name="exchange" domain="exchange-name"> + <rule name="reserved" on-failure="access-refused"> + <doc> + Exchange names starting with "amq." are reserved for + pre-declared and + standardised exchanges. The client MAY declare an + exchange starting with + "amq." if the passive option is set, or the exchange + already exists. + </doc> + <doc type="scenario"> + The client attempts to declare a non-existing exchange + starting with + "amq." and with the passive option set to zero. + </doc> + </rule> + <rule name="syntax" on-failure="precondition-failed"> + <doc> + The exchange name consists of a non-empty sequence of + these characters: + letters, digits, hyphen, underscore, period, or colon. + </doc> + <doc type="scenario"> + The client attempts to declare an exchange with an + illegal name. + </doc> + </rule> + <assert check="notnull"/> + </field> + + <field name="type" domain="shortstr" label="exchange type"> + <doc> + Each exchange belongs to one of a set of exchange types + implemented by the + server. The exchange types define the functionality of the + exchange - i.e. how + messages are routed through it. It is not valid or + meaningful to attempt to + change the type of an existing exchange. + </doc> + <rule name="typed" on-failure="not-allowed"> + <doc> + Exchanges cannot be redeclared with different types. The + client MUST not + attempt to redeclare an existing exchange with a + different type than used + in the original Exchange.Declare method. + </doc> + <doc type="scenario"> + TODO. + </doc> + </rule> + <rule name="support" on-failure="command-invalid"> + <doc> + The client MUST NOT attempt to declare an exchange with + a type that the + server does not support. + </doc> + <doc type="scenario"> + TODO. + </doc> + </rule> + </field> + + <field name="passive" domain="bit" label="do not create exchange"> + <doc> + If set, the server will reply with Declare-Ok if the + exchange already + exists with the same name, and raise an error if not. The + client can + use this to check whether an exchange exists without + modifying the + server state. When set, all other method fields except name + and no-wait + are ignored. A declare with both passive and no-wait has no + effect. + Arguments are compared for semantic equivalence. + </doc> + <rule name="not-found"> + <doc> + If set, and the exchange does not already exist, the + server MUST + raise a channel exception with reply code 404 (not + found). + </doc> + <doc type="scenario"> + TODO. + </doc> + </rule> + <rule name="equivalent"> + <doc> + If not set and the exchange exists, the server MUST + check that the + existing exchange has the same values for type, durable, + and arguments + fields. The server MUST respond with Declare-Ok if the + requested + exchange matches these fields, and MUST raise a channel + exception if + not. + </doc> + <doc type="scenario"> + TODO. + </doc> + </rule> + </field> + + <field name="durable" domain="bit" + label="request a durable exchange"> + <doc> + If set when creating a new exchange, the exchange will be + marked as durable. + Durable exchanges remain active when a server restarts. + Non-durable exchanges + (transient exchanges) are purged if/when a server restarts. + </doc> + <rule name="support"> + <doc> + The server MUST support both durable and transient + exchanges. + </doc> + <doc type="scenario"> + TODO. + </doc> + </rule> + </field> + + <!-- Deprecated: "auto-delete", must be zero --> + <field name="reserved-2" type="bit" reserved="1"/> + <!-- Deprecated: "internal", must be zero --> + <field name="reserved-3" type="bit" reserved="1"/> + <field name="no-wait" domain="no-wait"/> + + <field name="arguments" domain="table" + label="arguments for declaration"> + <doc> + A set of arguments for the declaration. The syntax and + semantics of these + arguments depends on the server implementation. + </doc> + </field> + </method> + + <method name="declare-ok" synchronous="1" index="11" + label="confirm exchange declaration"> + <doc> + This method confirms a Declare method and confirms the name of + the exchange, + essential for automatically-named exchanges. + </doc> + <chassis name="client" implement="MUST"/> + </method> + + <!-- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - --> + + <method name="delete" synchronous="1" index="20" + label="delete an exchange"> + <doc> + This method deletes an exchange. When an exchange is deleted all + queue bindings on + the exchange are cancelled. + </doc> + + <chassis name="server" implement="MUST"/> + <response name="delete-ok"/> + + <!-- Deprecated: "ticket", must be zero --> + <field name="reserved-1" type="short" reserved="1"/> + + <field name="exchange" domain="exchange-name"> + <rule name="exists" on-failure="not-found"> + <doc> + The client MUST NOT attempt to delete an exchange that + does not exist. + </doc> + </rule> + <assert check="notnull"/> + </field> + + <field name="if-unused" domain="bit" label="delete only if unused"> + <doc> + If set, the server will only delete the exchange if it has + no queue bindings. If + the exchange has queue bindings the server does not delete + it but raises a + channel exception instead. + </doc> + <rule name="in-use" on-failure="precondition-failed"> + <doc> + The server MUST NOT delete an exchange that has bindings + on it, if the if-unused + field is true. + </doc> + <doc type="scenario"> + The client declares an exchange, binds a queue to it, + then tries to delete it + setting if-unused to true. + </doc> + </rule> + </field> + + <field name="no-wait" domain="no-wait"/> + </method> + + <method name="delete-ok" synchronous="1" index="21" + label="confirm deletion of an exchange"> + <doc>This method confirms the deletion of an exchange.</doc> + <chassis name="client" implement="MUST"/> + </method> + </class> + + <!-- == QUEUE ============================================================ --> + + <class name="queue" handler="channel" index="50" label="work with queues"> + <doc> + Queues store and forward messages. Queues can be configured in the + server or created at + runtime. Queues must be attached to at least one exchange in order + to receive messages + from publishers. + </doc> + + <doc type="grammar"> + queue = C:DECLARE S:DECLARE-OK + / C:BIND S:BIND-OK + / C:UNBIND S:UNBIND-OK + / C:PURGE S:PURGE-OK + / C:DELETE S:DELETE-OK + </doc> + + <chassis name="server" implement="MUST"/> + <chassis name="client" implement="MUST"/> + + <!-- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - --> + + <method name="declare" synchronous="1" index="10" + label="declare queue, create if needed"> + <doc> + This method creates or checks a queue. When creating a new queue + the client can + specify various properties that control the durability of the + queue and its + contents, and the level of sharing for the queue. + </doc> + + <rule name="default-binding"> + <doc> + The server MUST create a default binding for a + newly-declared queue to the + default exchange, which is an exchange of type 'direct' and + use the queue + name as the routing key. + </doc> + <doc type="scenario"> + Client declares a new queue, and then without explicitly + binding it to an + exchange, attempts to send a message through the default + exchange binding, + i.e. publish a message to the empty exchange, with the queue + name as routing + key. + </doc> + </rule> + + <rule name="minimum-queues"> + <doc> + The server SHOULD support a minimum of 256 queues per + virtual host and ideally, + impose no limit except as defined by available resources. + </doc> + <doc type="scenario"> + Client attempts to declare as many queues as it can until + the server reports + an error. The resulting count must at least be 256. + </doc> + </rule> + + <chassis name="server" implement="MUST"/> + <response name="declare-ok"/> + + <!-- Deprecated: "ticket", must be zero --> + <field name="reserved-1" type="short" reserved="1"/> + + <field name="queue" domain="queue-name"> + <rule name="default-name"> + <doc> + The queue name MAY be empty, in which case the server + MUST create a new + queue with a unique generated name and return this to + the client in the + Declare-Ok method. + </doc> + <doc type="scenario"> + Client attempts to declare several queues with an empty + name. The client then + verifies that the server-assigned names are unique and + different. + </doc> + </rule> + <rule name="reserved" on-failure="access-refused"> + <doc> + Queue names starting with "amq." are reserved for + pre-declared and + standardised queues. The client MAY declare a queue + starting with + "amq." if the passive option is set, or the queue + already exists. + </doc> + <doc type="scenario"> + The client attempts to declare a non-existing queue + starting with + "amq." and with the passive option set to zero. + </doc> + </rule> + <rule name="syntax" on-failure="precondition-failed"> + <doc> + The queue name can be empty, or a sequence of these + characters: + letters, digits, hyphen, underscore, period, or colon. + </doc> + <doc type="scenario"> + The client attempts to declare a queue with an illegal + name. + </doc> + </rule> + </field> + + <field name="passive" domain="bit" label="do not create queue"> + <doc> + If set, the server will reply with Declare-Ok if the queue + already + exists with the same name, and raise an error if not. The + client can + use this to check whether a queue exists without modifying + the + server state. When set, all other method fields except name + and no-wait + are ignored. A declare with both passive and no-wait has no + effect. + Arguments are compared for semantic equivalence. + </doc> + <rule name="passive" on-failure="not-found"> + <doc> + The client MAY ask the server to assert that a queue + exists without + creating the queue if not. If the queue does not exist, + the server + treats this as a failure. + </doc> + <doc type="scenario"> + Client declares an existing queue with the passive + option and expects + the server to respond with a declare-ok. Client then + attempts to declare + a non-existent queue with the passive option, and the + server must close + the channel with the correct reply-code. + </doc> + </rule> + <rule name="equivalent"> + <doc> + If not set and the queue exists, the server MUST check + that the + existing queue has the same values for durable, + exclusive, auto-delete, + and arguments fields. The server MUST respond with + Declare-Ok if the + requested queue matches these fields, and MUST raise a + channel exception + if not. + </doc> + <doc type="scenario"> + TODO. + </doc> + </rule> + </field> + + <field name="durable" domain="bit" label="request a durable queue"> + <doc> + If set when creating a new queue, the queue will be marked + as durable. Durable + queues remain active when a server restarts. Non-durable + queues (transient + queues) are purged if/when a server restarts. Note that + durable queues do not + necessarily hold persistent messages, although it does not + make sense to send + persistent messages to a transient queue. + </doc> + + <rule name="persistence"> + <doc>The server MUST recreate the durable queue after a + restart. + </doc> + + <doc type="scenario"> + Client declares a durable queue. The server is then + restarted. The client + then attempts to send a message to the queue. The + message should be successfully + delivered. + </doc> + </rule> + + <rule name="types"> + <doc>The server MUST support both durable and transient + queues. + </doc> + <doc type="scenario"> + A client declares two named queues, one durable and one + transient. + </doc> + </rule> + </field> + + <field name="exclusive" domain="bit" + label="request an exclusive queue"> + <doc> + Exclusive queues may only be accessed by the current + connection, and are + deleted when that connection closes. Passive declaration of + an exclusive + queue by other connections are not allowed. + </doc> + + <rule name="types"> + <doc> + The server MUST support both exclusive (private) and + non-exclusive (shared) + queues. + </doc> + <doc type="scenario"> + A client declares two named queues, one exclusive and + one non-exclusive. + </doc> + </rule> + + <rule name="exclusive" on-failure="resource-locked"> + <doc> + The client MAY NOT attempt to use a queue that was + declared as exclusive + by another still-open connection. + </doc> + <doc type="scenario"> + One client declares an exclusive queue. A second client + on a different + connection attempts to declare, bind, consume, purge, + delete, or declare + a queue of the same name. + </doc> + </rule> + </field> + + <field name="auto-delete" domain="bit" + label="auto-delete queue when unused"> + <doc> + If set, the queue is deleted when all consumers have + finished using it. The last + consumer can be cancelled either explicitly or because its + channel is closed. If + there was no consumer ever on the queue, it won't be + deleted. Applications can + explicitly delete auto-delete queues using the Delete method + as normal. + </doc> + + <rule name="pre-existence"> + <doc> + The server MUST ignore the auto-delete field if the + queue already exists. + </doc> + <doc type="scenario"> + Client declares two named queues, one as auto-delete and + one explicit-delete. + Client then attempts to declare the two queues using the + same names again, + but reversing the value of the auto-delete field in each + case. Verify that the + queues still exist with the original auto-delete flag + values. + </doc> + </rule> + </field> + + <field name="no-wait" domain="no-wait"/> + + <field name="arguments" domain="table" + label="arguments for declaration"> + <doc> + A set of arguments for the declaration. The syntax and + semantics of these + arguments depends on the server implementation. + </doc> + </field> + </method> + + <method name="declare-ok" synchronous="1" index="11" + label="confirms a queue definition"> + <doc> + This method confirms a Declare method and confirms the name of + the queue, essential + for automatically-named queues. + </doc> + + <chassis name="client" implement="MUST"/> + + <field name="queue" domain="queue-name"> + <doc> + Reports the name of the queue. If the server generated a + queue name, this field + contains that name. + </doc> + <assert check="notnull"/> + </field> + + <field name="message-count" domain="message-count"/> + + <field name="consumer-count" domain="long" + label="number of consumers"> + <doc> + Reports the number of active consumers for the queue. Note + that consumers can + suspend activity (Channel.Flow) in which case they do not + appear in this count. + </doc> + </field> + </method> + + <!-- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - --> + + <method name="bind" synchronous="1" index="20" + label="bind queue to an exchange"> + <doc> + This method binds a queue to an exchange. Until a queue is bound + it will not + receive any messages. In a classic messaging model, + store-and-forward queues + are bound to a direct exchange and subscription queues are bound + to a topic + exchange. + </doc> + + <rule name="duplicates"> + <doc> + A server MUST allow ignore duplicate bindings - that is, two + or more bind + methods for a specific queue, with identical arguments - + without treating these + as an error. + </doc> + <doc type="scenario"> + A client binds a named queue to an exchange. The client then + repeats the bind + (with identical arguments). + </doc> + </rule> + + <rule name="unique"> + <doc> + A server MUST not deliver the same message more than once to + a queue, even if + the queue has multiple bindings that match the message. + </doc> + <doc type="scenario"> + A client declares a named queue and binds it using multiple + bindings to the + amq.topic exchange. The client then publishes a message that + matches all its + bindings. + </doc> + </rule> + + <rule name="transient-exchange"> + <doc> + The server MUST allow a durable queue to bind to a transient + exchange. + </doc> + <doc type="scenario"> + A client declares a transient exchange. The client then + declares a named durable + queue and then attempts to bind the transient exchange to + the durable queue. + </doc> + </rule> + + <rule name="durable-exchange"> + <doc> + Bindings of durable queues to durable exchanges are + automatically durable + and the server MUST restore such bindings after a server + restart. + </doc> + <doc type="scenario"> + A server declares a named durable queue and binds it to a + durable exchange. The + server is restarted. The client then attempts to use the + queue/exchange combination. + </doc> + </rule> + + <rule name="binding-count"> + <doc> + The server SHOULD support at least 4 bindings per queue, and + ideally, impose no + limit except as defined by available resources. + </doc> + <doc type="scenario"> + A client declares a named queue and attempts to bind it to 4 + different + exchanges. + </doc> + </rule> + + <chassis name="server" implement="MUST"/> + + <response name="bind-ok"/> + + <!-- Deprecated: "ticket", must be zero --> + <field name="reserved-1" type="short" reserved="1"/> + + <field name="queue" domain="queue-name"> + <doc>Specifies the name of the queue to bind.</doc> + <rule name="queue-known" on-failure="not-found"> + <doc> + The client MUST either specify a queue name or have + previously declared a + queue on the same channel + </doc> + <doc type="scenario"> + The client opens a channel and attempts to bind an + unnamed queue. + </doc> + </rule> + <rule name="must-exist" on-failure="not-found"> + <doc> + The client MUST NOT attempt to bind a queue that does + not exist. + </doc> + <doc type="scenario"> + The client attempts to bind a non-existent queue. + </doc> + </rule> + </field> + + <field name="exchange" domain="exchange-name" + label="name of the exchange to bind to"> + <rule name="exchange-existence" on-failure="not-found"> + <doc> + A client MUST NOT be allowed to bind a queue to a + non-existent exchange. + </doc> + <doc type="scenario"> + A client attempts to bind an named queue to a undeclared + exchange. + </doc> + </rule> + <rule name="default-exchange"> + <doc> + The server MUST accept a blank exchange name to mean the + default exchange. + </doc> + <doc type="scenario"> + The client declares a queue and binds it to a blank + exchange name. + </doc> + </rule> + </field> + + <field name="routing-key" domain="shortstr" + label="message routing key"> + <doc> + Specifies the routing key for the binding. The routing key + is used for routing + messages depending on the exchange configuration. Not all + exchanges use a + routing key - refer to the specific exchange documentation. + If the queue name + is empty, the server uses the last queue declared on the + channel. If the + routing key is also empty, the server uses this queue name + for the routing + key as well. If the queue name is provided but the routing + key is empty, the + server does the binding with that empty routing key. The + meaning of empty + routing keys depends on the exchange implementation. + </doc> + <rule name="direct-exchange-key-matching"> + <doc> + If a message queue binds to a direct exchange using + routing key K and a + publisher sends the exchange a message with routing key + R, then the message + MUST be passed to the message queue if K = R. + </doc> + </rule> + </field> + + <field name="no-wait" domain="no-wait"/> + + <field name="arguments" domain="table" + label="arguments for binding"> + <doc> + A set of arguments for the binding. The syntax and semantics + of these arguments + depends on the exchange class. + </doc> + </field> + </method> + + <method name="bind-ok" synchronous="1" index="21" + label="confirm bind successful"> + <doc>This method confirms that the bind was successful.</doc> + + <chassis name="client" implement="MUST"/> + </method> + + <!-- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - --> + + <method name="unbind" synchronous="1" index="50" + label="unbind a queue from an exchange"> + <doc>This method unbinds a queue from an exchange.</doc> + <rule name="01"> + <doc>If a unbind fails, the server MUST raise a connection + exception. + </doc> + </rule> + <chassis name="server" implement="MUST"/> + <response name="unbind-ok"/> + + <!-- Deprecated: "ticket", must be zero --> + <field name="reserved-1" type="short" reserved="1"/> + + <field name="queue" domain="queue-name"> + <doc>Specifies the name of the queue to unbind.</doc> + <rule name="queue-known" on-failure="not-found"> + <doc> + The client MUST either specify a queue name or have + previously declared a + queue on the same channel + </doc> + <doc type="scenario"> + The client opens a channel and attempts to unbind an + unnamed queue. + </doc> + </rule> + <rule name="must-exist" on-failure="not-found"> + <doc> + The client MUST NOT attempt to unbind a queue that does + not exist. + </doc> + <doc type="scenario"> + The client attempts to unbind a non-existent queue. + </doc> + </rule> + </field> + + <field name="exchange" domain="exchange-name"> + <doc>The name of the exchange to unbind from.</doc> + <rule name="must-exist" on-failure="not-found"> + <doc> + The client MUST NOT attempt to unbind a queue from an + exchange that + does not exist. + </doc> + <doc type="scenario"> + The client attempts to unbind a queue from a + non-existent exchange. + </doc> + </rule> + <rule name="default-exchange"> + <doc> + The server MUST accept a blank exchange name to mean the + default exchange. + </doc> + <doc type="scenario"> + The client declares a queue and binds it to a blank + exchange name. + </doc> + </rule> + </field> + + <field name="routing-key" domain="shortstr" + label="routing key of binding"> + <doc>Specifies the routing key of the binding to unbind.</doc> + </field> + + <field name="arguments" domain="table" label="arguments of binding"> + <doc>Specifies the arguments of the binding to unbind.</doc> + </field> + </method> + + <method name="unbind-ok" synchronous="1" index="51" + label="confirm unbind successful"> + <doc>This method confirms that the unbind was successful.</doc> + <chassis name="client" implement="MUST"/> + </method> + + <!-- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - --> + + <method name="purge" synchronous="1" index="30" label="purge a queue"> + <doc> + This method removes all messages from a queue which are not + awaiting + acknowledgment. + </doc> + + <rule name="02"> + <doc> + The server MUST NOT purge messages that have already been + sent to a client + but not yet acknowledged. + </doc> + </rule> + + <rule name="03"> + <doc> + The server MAY implement a purge queue or log that allows + system administrators + to recover accidentally-purged messages. The server SHOULD + NOT keep purged + messages in the same storage spaces as the live messages + since the volumes of + purged messages may get very large. + </doc> + </rule> + + <chassis name="server" implement="MUST"/> + + <response name="purge-ok"/> + + <!-- Deprecated: "ticket", must be zero --> + <field name="reserved-1" type="short" reserved="1"/> + + <field name="queue" domain="queue-name"> + <doc>Specifies the name of the queue to purge.</doc> + <rule name="queue-known" on-failure="not-found"> + <doc> + The client MUST either specify a queue name or have + previously declared a + queue on the same channel + </doc> + <doc type="scenario"> + The client opens a channel and attempts to purge an + unnamed queue. + </doc> + </rule> + <rule name="must-exist" on-failure="not-found"> + <doc> + The client MUST NOT attempt to purge a queue that does + not exist. + </doc> + <doc type="scenario"> + The client attempts to purge a non-existent queue. + </doc> + </rule> + </field> + + <field name="no-wait" domain="no-wait"/> + </method> + + <method name="purge-ok" synchronous="1" index="31" + label="confirms a queue purge"> + <doc>This method confirms the purge of a queue.</doc> + + <chassis name="client" implement="MUST"/> + + <field name="message-count" domain="message-count"> + <doc> + Reports the number of messages purged. + </doc> + </field> + </method> + + <!-- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - --> + + <method name="delete" synchronous="1" index="40" label="delete a queue"> + <doc> + This method deletes a queue. When a queue is deleted any pending + messages are sent + to a dead-letter queue if this is defined in the server + configuration, and all + consumers on the queue are cancelled. + </doc> + + <rule name="01"> + <doc> + The server SHOULD use a dead-letter queue to hold messages + that were pending on + a deleted queue, and MAY provide facilities for a system + administrator to move + these messages back to an active queue. + </doc> + </rule> + + <chassis name="server" implement="MUST"/> + + <response name="delete-ok"/> + + <!-- Deprecated: "ticket", must be zero --> + <field name="reserved-1" type="short" reserved="1"/> + + <field name="queue" domain="queue-name"> + <doc>Specifies the name of the queue to delete.</doc> + <rule name="queue-known" on-failure="not-found"> + <doc> + The client MUST either specify a queue name or have + previously declared a + queue on the same channel + </doc> + <doc type="scenario"> + The client opens a channel and attempts to delete an + unnamed queue. + </doc> + </rule> + <rule name="must-exist" on-failure="not-found"> + <doc> + The client MUST NOT attempt to delete a queue that does + not exist. + </doc> + <doc type="scenario"> + The client attempts to delete a non-existent queue. + </doc> + </rule> + </field> + + <field name="if-unused" domain="bit" label="delete only if unused"> + <doc> + If set, the server will only delete the queue if it has no + consumers. If the + queue has consumers the server does does not delete it but + raises a channel + exception instead. + </doc> + <rule name="in-use" on-failure="precondition-failed"> + <doc> + The server MUST NOT delete a queue that has consumers on + it, if the if-unused + field is true. + </doc> + <doc type="scenario"> + The client declares a queue, and consumes from it, then + tries to delete it + setting if-unused to true. + </doc> + </rule> + </field> + + <field name="if-empty" domain="bit" label="delete only if empty"> + <doc> + If set, the server will only delete the queue if it has no + messages. + </doc> + <rule name="not-empty" on-failure="precondition-failed"> + <doc> + The server MUST NOT delete a queue that has messages on + it, if the + if-empty field is true. + </doc> + <doc type="scenario"> + The client declares a queue, binds it and publishes some + messages into it, + then tries to delete it setting if-empty to true. + </doc> + </rule> + </field> + + <field name="no-wait" domain="no-wait"/> + </method> + + <method name="delete-ok" synchronous="1" index="41" + label="confirm deletion of a queue"> + <doc>This method confirms the deletion of a queue.</doc> + + <chassis name="client" implement="MUST"/> + + <field name="message-count" domain="message-count"> + <doc>Reports the number of messages deleted.</doc> + </field> + </method> + </class> + + <!-- == BASIC ============================================================ --> + + <class name="basic" handler="channel" index="60" + label="work with basic content"> + <doc> + The Basic class provides methods that support an industry-standard + messaging model. + </doc> + + <doc type="grammar"> + basic = C:QOS S:QOS-OK + / C:CONSUME S:CONSUME-OK + / C:CANCEL S:CANCEL-OK + / C:PUBLISH content + / S:RETURN content + / S:DELIVER content + / C:GET ( S:GET-OK content / S:GET-EMPTY ) + / C:ACK + / C:REJECT + / C:RECOVER-ASYNC + / C:RECOVER S:RECOVER-OK + </doc> + + <chassis name="server" implement="MUST"/> + <chassis name="client" implement="MAY"/> + + <rule name="01"> + <doc> + The server SHOULD respect the persistent property of basic + messages and + SHOULD make a best-effort to hold persistent basic messages on a + reliable + storage mechanism. + </doc> + <doc type="scenario"> + Send a persistent message to queue, stop server, restart server + and then + verify whether message is still present. Assumes that queues are + durable. + Persistence without durable queues makes no sense. + </doc> </rule> - </field> - - <field name = "exchange" domain = "exchange-name"> - <doc>The name of the exchange to unbind from.</doc> - <rule name = "must-exist" on-failure = "not-found"> - <doc> - The client MUST NOT attempt to unbind a queue from an exchange that - does not exist. - </doc> - <doc type = "scenario"> - The client attempts to unbind a queue from a non-existent exchange. - </doc> - </rule> - <rule name = "default-exchange"> - <doc> - The server MUST accept a blank exchange name to mean the default exchange. - </doc> - <doc type = "scenario"> - The client declares a queue and binds it to a blank exchange name. - </doc> - </rule> - </field> - - <field name = "routing-key" domain = "shortstr" label = "routing key of binding"> - <doc>Specifies the routing key of the binding to unbind.</doc> - </field> - - <field name = "arguments" domain = "table" label = "arguments of binding"> - <doc>Specifies the arguments of the binding to unbind.</doc> - </field> - </method> - - <method name = "unbind-ok" synchronous = "1" index = "51" label = "confirm unbind successful"> - <doc>This method confirms that the unbind was successful.</doc> - <chassis name = "client" implement = "MUST"/> - </method> - - <!-- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - --> - - <method name = "purge" synchronous = "1" index = "30" label = "purge a queue"> - <doc> - This method removes all messages from a queue which are not awaiting - acknowledgment. - </doc> - - <rule name = "02"> - <doc> - The server MUST NOT purge messages that have already been sent to a client - but not yet acknowledged. - </doc> - </rule> - <rule name = "03"> - <doc> - The server MAY implement a purge queue or log that allows system administrators - to recover accidentally-purged messages. The server SHOULD NOT keep purged - messages in the same storage spaces as the live messages since the volumes of - purged messages may get very large. - </doc> - </rule> - - <chassis name = "server" implement = "MUST" /> - - <response name = "purge-ok" /> - - <!-- Deprecated: "ticket", must be zero --> - <field name = "reserved-1" type = "short" reserved = "1" /> - - <field name = "queue" domain = "queue-name"> - <doc>Specifies the name of the queue to purge.</doc> - <rule name = "queue-known" on-failure = "not-found"> - <doc> - The client MUST either specify a queue name or have previously declared a - queue on the same channel - </doc> - <doc type = "scenario"> - The client opens a channel and attempts to purge an unnamed queue. - </doc> - </rule> - <rule name = "must-exist" on-failure = "not-found"> - <doc> - The client MUST NOT attempt to purge a queue that does not exist. - </doc> - <doc type = "scenario"> - The client attempts to purge a non-existent queue. - </doc> + <rule name="02"> + <doc> + The server MUST NOT discard a persistent basic message in case + of a queue + overflow. + </doc> + <doc type="scenario"> + Declare a queue overflow situation with persistent messages and + verify that + messages do not get lost (presumably the server will write them + to disk). + </doc> </rule> - </field> - - <field name = "no-wait" domain = "no-wait" /> - </method> - - <method name = "purge-ok" synchronous = "1" index = "31" label = "confirms a queue purge"> - <doc>This method confirms the purge of a queue.</doc> - - <chassis name = "client" implement = "MUST" /> - <field name = "message-count" domain = "message-count"> - <doc> - Reports the number of messages purged. - </doc> - </field> - </method> - - <!-- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - --> - - <method name = "delete" synchronous = "1" index = "40" label = "delete a queue"> - <doc> - This method deletes a queue. When a queue is deleted any pending messages are sent - to a dead-letter queue if this is defined in the server configuration, and all - consumers on the queue are cancelled. - </doc> - - <rule name = "01"> - <doc> - The server SHOULD use a dead-letter queue to hold messages that were pending on - a deleted queue, and MAY provide facilities for a system administrator to move - these messages back to an active queue. - </doc> - </rule> - - <chassis name = "server" implement = "MUST" /> - - <response name = "delete-ok" /> - - <!-- Deprecated: "ticket", must be zero --> - <field name = "reserved-1" type = "short" reserved = "1" /> - - <field name = "queue" domain = "queue-name"> - <doc>Specifies the name of the queue to delete.</doc> - <rule name = "queue-known" on-failure = "not-found"> - <doc> - The client MUST either specify a queue name or have previously declared a - queue on the same channel - </doc> - <doc type = "scenario"> - The client opens a channel and attempts to delete an unnamed queue. - </doc> - </rule> - <rule name = "must-exist" on-failure = "not-found"> - <doc> - The client MUST NOT attempt to delete a queue that does not exist. - </doc> - <doc type = "scenario"> - The client attempts to delete a non-existent queue. - </doc> + <rule name="03"> + <doc> + The server MAY use the Channel.Flow method to slow or stop a + basic message + publisher when necessary. + </doc> + <doc type="scenario"> + Declare a queue overflow situation with non-persistent messages + and verify + whether the server responds with Channel.Flow or not. Repeat + with persistent + messages. + </doc> </rule> - </field> - <field name = "if-unused" domain = "bit" label = "delete only if unused"> - <doc> - If set, the server will only delete the queue if it has no consumers. If the - queue has consumers the server does does not delete it but raises a channel - exception instead. - </doc> - <rule name = "in-use" on-failure = "precondition-failed"> - <doc> - The server MUST NOT delete a queue that has consumers on it, if the if-unused - field is true. - </doc> - <doc type = "scenario"> - The client declares a queue, and consumes from it, then tries to delete it - setting if-unused to true. - </doc> + <rule name="04"> + <doc> + The server MAY overflow non-persistent basic messages to + persistent + storage. + </doc> + <!-- Test scenario: untestable --> </rule> - </field> - <field name = "if-empty" domain = "bit" label = "delete only if empty"> - <doc> - If set, the server will only delete the queue if it has no messages. - </doc> - <rule name = "not-empty" on-failure = "precondition-failed"> - <doc> - The server MUST NOT delete a queue that has messages on it, if the - if-empty field is true. - </doc> - <doc type = "scenario"> - The client declares a queue, binds it and publishes some messages into it, - then tries to delete it setting if-empty to true. - </doc> + <rule name="05"> + <doc> + The server MAY discard or dead-letter non-persistent basic + messages on a + priority basis if the queue size exceeds some configured limit. + </doc> + <!-- Test scenario: untestable --> </rule> - </field> - - <field name = "no-wait" domain = "no-wait" /> - </method> - - <method name = "delete-ok" synchronous = "1" index = "41" label = "confirm deletion of a queue"> - <doc>This method confirms the deletion of a queue.</doc> - - <chassis name = "client" implement = "MUST" /> - - <field name = "message-count" domain = "message-count"> - <doc>Reports the number of messages deleted.</doc> - </field> - </method> - </class> - - <!-- == BASIC ============================================================ --> - - <class name = "basic" handler = "channel" index = "60" label = "work with basic content"> - <doc> - The Basic class provides methods that support an industry-standard messaging model. - </doc> - - <doc type = "grammar"> - basic = C:QOS S:QOS-OK - / C:CONSUME S:CONSUME-OK - / C:CANCEL S:CANCEL-OK - / C:PUBLISH content - / S:RETURN content - / S:DELIVER content - / C:GET ( S:GET-OK content / S:GET-EMPTY ) - / C:ACK - / C:REJECT - / C:RECOVER-ASYNC - / C:RECOVER S:RECOVER-OK - </doc> - - <chassis name = "server" implement = "MUST" /> - <chassis name = "client" implement = "MAY" /> - - <rule name = "01"> - <doc> - The server SHOULD respect the persistent property of basic messages and - SHOULD make a best-effort to hold persistent basic messages on a reliable - storage mechanism. - </doc> - <doc type = "scenario"> - Send a persistent message to queue, stop server, restart server and then - verify whether message is still present. Assumes that queues are durable. - Persistence without durable queues makes no sense. - </doc> - </rule> - - <rule name = "02"> - <doc> - The server MUST NOT discard a persistent basic message in case of a queue - overflow. - </doc> - <doc type = "scenario"> - Declare a queue overflow situation with persistent messages and verify that - messages do not get lost (presumably the server will write them to disk). - </doc> - </rule> - - <rule name = "03"> - <doc> - The server MAY use the Channel.Flow method to slow or stop a basic message - publisher when necessary. - </doc> - <doc type = "scenario"> - Declare a queue overflow situation with non-persistent messages and verify - whether the server responds with Channel.Flow or not. Repeat with persistent - messages. - </doc> - </rule> - - <rule name = "04"> - <doc> - The server MAY overflow non-persistent basic messages to persistent - storage. - </doc> - <!-- Test scenario: untestable --> - </rule> - - <rule name = "05"> - <doc> - The server MAY discard or dead-letter non-persistent basic messages on a - priority basis if the queue size exceeds some configured limit. - </doc> - <!-- Test scenario: untestable --> - </rule> - - <rule name = "06"> - <doc> - The server MUST implement at least 2 priority levels for basic messages, - where priorities 0-4 and 5-9 are treated as two distinct levels. - </doc> - <doc type = "scenario"> - Send a number of priority 0 messages to a queue. Send one priority 9 - message. Consume messages from the queue and verify that the first message - received was priority 9. - </doc> - </rule> - - <rule name = "07"> - <doc> - The server MAY implement up to 10 priority levels. - </doc> - <doc type = "scenario"> - Send a number of messages with mixed priorities to a queue, so that all - priority values from 0 to 9 are exercised. A good scenario would be ten - messages in low-to-high priority. Consume from queue and verify how many - priority levels emerge. - </doc> - </rule> - - <rule name = "08"> - <doc> - The server MUST deliver messages of the same priority in order irrespective of - their individual persistence. - </doc> - <doc type = "scenario"> - Send a set of messages with the same priority but different persistence - settings to a queue. Consume and verify that messages arrive in same order - as originally published. - </doc> - </rule> - - <rule name = "09"> - <doc> - The server MUST support un-acknowledged delivery of Basic content, i.e. - consumers with the no-ack field set to TRUE. - </doc> - </rule> - - <rule name = "10"> - <doc> - The server MUST support explicitly acknowledged delivery of Basic content, - i.e. consumers with the no-ack field set to FALSE. - </doc> - <doc type = "scenario"> - Declare a queue and a consumer using explicit acknowledgements. Publish a - set of messages to the queue. Consume the messages but acknowledge only - half of them. Disconnect and reconnect, and consume from the queue. - Verify that the remaining messages are received. - </doc> - </rule> - - <!-- These are the properties for a Basic content --> - - <!-- MIME typing --> - <field name = "content-type" domain = "shortstr" label = "MIME content type" /> - <!-- MIME typing --> - <field name = "content-encoding" domain = "shortstr" label = "MIME content encoding" /> - <!-- For applications, and for header exchange routing --> - <field name = "headers" domain = "table" label = "message header field table" /> - <!-- For queues that implement persistence --> - <field name = "delivery-mode" domain = "octet" label = "non-persistent (1) or persistent (2)" /> - <!-- For queues that implement priorities --> - <field name = "priority" domain = "octet" label = "message priority, 0 to 9" /> - <!-- For application use, no formal behaviour --> - <field name = "correlation-id" domain = "shortstr" label = "application correlation identifier" /> - <!-- For application use, no formal behaviour but may hold the - name of a private response queue, when used in request messages --> - <field name = "reply-to" domain = "shortstr" label = "address to reply to" /> - <!-- For implementation use, no formal behaviour --> - <field name = "expiration" domain = "shortstr" label = "message expiration specification" /> - <!-- For application use, no formal behaviour --> - <field name = "message-id" domain = "shortstr" label = "application message identifier" /> - <!-- For application use, no formal behaviour --> - <field name = "timestamp" domain = "timestamp" label = "message timestamp" /> - <!-- For application use, no formal behaviour --> - <field name = "type" domain = "shortstr" label = "message type name" /> - <!-- For application use, no formal behaviour --> - <field name = "user-id" domain = "shortstr" label = "creating user id" /> - <!-- For application use, no formal behaviour --> - <field name = "app-id" domain = "shortstr" label = "creating application id" /> - <!-- Deprecated, was old cluster-id property --> - <field name = "reserved" domain = "shortstr" label = "reserved, must be empty" /> - - <!-- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - --> - - <method name = "qos" synchronous = "1" index = "10" label = "specify quality of service"> - <doc> - This method requests a specific quality of service. The QoS can be specified for the - current channel or for all channels on the connection. The particular properties and - semantics of a qos method always depend on the content class semantics. Though the - qos method could in principle apply to both peers, it is currently meaningful only - for the server. - </doc> - - <chassis name = "server" implement = "MUST" /> - <response name = "qos-ok" /> - - <field name = "prefetch-size" domain = "long" label = "prefetch window in octets"> - <doc> - The client can request that messages be sent in advance so that when the client - finishes processing a message, the following message is already held locally, - rather than needing to be sent down the channel. Prefetching gives a performance - improvement. This field specifies the prefetch window size in octets. The server - will send a message in advance if it is equal to or smaller in size than the - available prefetch size (and also falls into other prefetch limits). May be set - to zero, meaning "no specific limit", although other prefetch limits may still - apply. The prefetch-size is ignored if the no-ack option is set. - </doc> - <rule name = "01"> - <doc> - The server MUST ignore this setting when the client is not processing any - messages - i.e. the prefetch size does not limit the transfer of single - messages to a client, only the sending in advance of more messages while - the client still has one or more unacknowledged messages. - </doc> - <doc type = "scenario"> - Define a QoS prefetch-size limit and send a single message that exceeds - that limit. Verify that the message arrives correctly. - </doc> - </rule> - </field> - <field name = "prefetch-count" domain = "short" label = "prefetch window in messages"> - <doc> - Specifies a prefetch window in terms of whole messages. This field may be used - in combination with the prefetch-size field; a message will only be sent in - advance if both prefetch windows (and those at the channel and connection level) - allow it. The prefetch-count is ignored if the no-ack option is set. - </doc> - <rule name = "01"> - <doc> - The server may send less data in advance than allowed by the client's - specified prefetch windows but it MUST NOT send more. - </doc> - <doc type = "scenario"> - Define a QoS prefetch-size limit and a prefetch-count limit greater than - one. Send multiple messages that exceed the prefetch size. Verify that - no more than one message arrives at once. - </doc> + <rule name="06"> + <doc> + The server MUST implement at least 2 priority levels for basic + messages, + where priorities 0-4 and 5-9 are treated as two distinct levels. + </doc> + <doc type="scenario"> + Send a number of priority 0 messages to a queue. Send one + priority 9 + message. Consume messages from the queue and verify that the + first message + received was priority 9. + </doc> </rule> - </field> - - <field name = "global" domain = "bit" label = "apply to entire connection"> - <doc> - By default the QoS settings apply to the current channel only. If this field is - set, they are applied to the entire connection. - </doc> - </field> - </method> - - <method name = "qos-ok" synchronous = "1" index = "11" label = "confirm the requested qos"> - <doc> - This method tells the client that the requested QoS levels could be handled by the - server. The requested QoS applies to all active consumers until a new QoS is - defined. - </doc> - <chassis name = "client" implement = "MUST" /> - </method> - - <!-- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - --> - - <method name = "consume" synchronous = "1" index = "20" label = "start a queue consumer"> - <doc> - This method asks the server to start a "consumer", which is a transient request for - messages from a specific queue. Consumers last as long as the channel they were - declared on, or until the client cancels them. - </doc> - - <rule name = "01"> - <doc> - The server SHOULD support at least 16 consumers per queue, and ideally, impose - no limit except as defined by available resources. - </doc> - <doc type = "scenario"> - Declare a queue and create consumers on that queue until the server closes the - connection. Verify that the number of consumers created was at least sixteen - and report the total number. - </doc> - </rule> - - <chassis name = "server" implement = "MUST" /> - <response name = "consume-ok" /> - <!-- Deprecated: "ticket", must be zero --> - <field name = "reserved-1" type = "short" reserved = "1" /> - - <field name = "queue" domain = "queue-name"> - <doc>Specifies the name of the queue to consume from.</doc> - </field> - - <field name = "consumer-tag" domain = "consumer-tag"> - <doc> - Specifies the identifier for the consumer. The consumer tag is local to a - channel, so two clients can use the same consumer tags. If this field is - empty the server will generate a unique tag. - </doc> - <rule name = "01" on-failure = "not-allowed"> - <doc> - The client MUST NOT specify a tag that refers to an existing consumer. - </doc> - <doc type = "scenario"> - Attempt to create two consumers with the same non-empty tag, on the - same channel. - </doc> - </rule> - <rule name = "02" on-failure = "not-allowed"> - <doc> - The consumer tag is valid only within the channel from which the - consumer was created. I.e. a client MUST NOT create a consumer in one - channel and then use it in another. - </doc> - <doc type = "scenario"> - Attempt to create a consumer in one channel, then use in another channel, - in which consumers have also been created (to test that the server uses - unique consumer tags). - </doc> + <rule name="07"> + <doc> + The server MAY implement up to 10 priority levels. + </doc> + <doc type="scenario"> + Send a number of messages with mixed priorities to a queue, so + that all + priority values from 0 to 9 are exercised. A good scenario would + be ten + messages in low-to-high priority. Consume from queue and verify + how many + priority levels emerge. + </doc> </rule> - </field> - - <field name = "no-local" domain = "no-local" /> - - <field name = "no-ack" domain = "no-ack" /> - - <field name = "exclusive" domain = "bit" label = "request exclusive access"> - <doc> - Request exclusive consumer access, meaning only this consumer can access the - queue. - </doc> - <rule name = "01" on-failure = "access-refused"> - <doc> - The client MAY NOT gain exclusive access to a queue that already has - active consumers. - </doc> - <doc type = "scenario"> - Open two connections to a server, and in one connection declare a shared - (non-exclusive) queue and then consume from the queue. In the second - connection attempt to consume from the same queue using the exclusive - option. - </doc> + <rule name="08"> + <doc> + The server MUST deliver messages of the same priority in order + irrespective of + their individual persistence. + </doc> + <doc type="scenario"> + Send a set of messages with the same priority but different + persistence + settings to a queue. Consume and verify that messages arrive in + same order + as originally published. + </doc> </rule> - </field> - - <field name = "no-wait" domain = "no-wait" /> - - <field name = "arguments" domain = "table" label = "arguments for declaration"> - <doc> - A set of arguments for the consume. The syntax and semantics of these - arguments depends on the server implementation. - </doc> - </field> - </method> - - <method name = "consume-ok" synchronous = "1" index = "21" label = "confirm a new consumer"> - <doc> - The server provides the client with a consumer tag, which is used by the client - for methods called on the consumer at a later stage. - </doc> - <chassis name = "client" implement = "MUST" /> - <field name = "consumer-tag" domain = "consumer-tag"> - <doc> - Holds the consumer tag specified by the client or provided by the server. - </doc> - </field> - </method> - - <!-- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - --> - - <method name = "cancel" synchronous = "1" index = "30" label = "end a queue consumer"> - <doc> - This method cancels a consumer. This does not affect already delivered - messages, but it does mean the server will not send any more messages for - that consumer. The client may receive an arbitrary number of messages in - between sending the cancel method and receiving the cancel-ok reply. - </doc> - - <rule name = "01"> - <doc> - If the queue does not exist the server MUST ignore the cancel method, so - long as the consumer tag is valid for that channel. - </doc> - <doc type = "scenario"> - TODO. - </doc> - </rule> - - <chassis name = "server" implement = "MUST" /> - <response name = "cancel-ok" /> - - <field name = "consumer-tag" domain = "consumer-tag" /> - <field name = "no-wait" domain = "no-wait" /> - </method> - - <method name = "cancel-ok" synchronous = "1" index = "31" label = "confirm a cancelled consumer"> - <doc> - This method confirms that the cancellation was completed. - </doc> - <chassis name = "client" implement = "MUST" /> - <field name = "consumer-tag" domain = "consumer-tag" /> - </method> - - <!-- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - --> - - <method name = "publish" content = "1" index = "40" label = "publish a message"> - <doc> - This method publishes a message to a specific exchange. The message will be routed - to queues as defined by the exchange configuration and distributed to any active - consumers when the transaction, if any, is committed. - </doc> - - <chassis name = "server" implement = "MUST" /> - <!-- Deprecated: "ticket", must be zero --> - <field name = "reserved-1" type = "short" reserved = "1" /> - - <field name = "exchange" domain = "exchange-name"> - <doc> - Specifies the name of the exchange to publish to. The exchange name can be - empty, meaning the default exchange. If the exchange name is specified, and that - exchange does not exist, the server will raise a channel exception. - </doc> - - <rule name = "must-exist" on-failure = "not-found"> - <doc> - The client MUST NOT attempt to publish a content to an exchange that - does not exist. - </doc> - <doc type = "scenario"> - The client attempts to publish a content to a non-existent exchange. - </doc> - </rule> - <rule name = "default-exchange"> - <doc> - The server MUST accept a blank exchange name to mean the default exchange. - </doc> - <doc type = "scenario"> - The client declares a queue and binds it to a blank exchange name. - </doc> - </rule> - <rule name = "02"> - <doc> - If the exchange was declared as an internal exchange, the server MUST raise - a channel exception with a reply code 403 (access refused). - </doc> - <doc type = "scenario"> - TODO. - </doc> + <rule name="09"> + <doc> + The server MUST support un-acknowledged delivery of Basic + content, i.e. + consumers with the no-ack field set to TRUE. + </doc> </rule> - <rule name = "03"> - <doc> - The exchange MAY refuse basic content in which case it MUST raise a channel - exception with reply code 540 (not implemented). - </doc> - <doc type = "scenario"> - TODO. - </doc> + <rule name="10"> + <doc> + The server MUST support explicitly acknowledged delivery of + Basic content, + i.e. consumers with the no-ack field set to FALSE. + </doc> + <doc type="scenario"> + Declare a queue and a consumer using explicit acknowledgements. + Publish a + set of messages to the queue. Consume the messages but + acknowledge only + half of them. Disconnect and reconnect, and consume from the + queue. + Verify that the remaining messages are received. + </doc> </rule> - </field> - <field name = "routing-key" domain = "shortstr" label = "Message routing key"> - <doc> - Specifies the routing key for the message. The routing key is used for routing - messages depending on the exchange configuration. - </doc> - </field> - - <field name = "mandatory" domain = "bit" label = "indicate mandatory routing"> - <doc> - This flag tells the server how to react if the message cannot be routed to a - queue. If this flag is set, the server will return an unroutable message with a - Return method. If this flag is zero, the server silently drops the message. - </doc> - - <rule name = "01"> - <doc> - The server SHOULD implement the mandatory flag. - </doc> - <doc type = "scenario"> - TODO. - </doc> + <!-- These are the properties for a Basic content --> + + <!-- MIME typing --> + <field name="content-type" domain="shortstr" label="MIME content type"/> + <!-- MIME typing --> + <field name="content-encoding" domain="shortstr" + label="MIME content encoding"/> + <!-- For applications, and for header exchange routing --> + <field name="headers" domain="table" + label="message header field table"/> + <!-- For queues that implement persistence --> + <field name="delivery-mode" domain="octet" + label="non-persistent (1) or persistent (2)"/> + <!-- For queues that implement priorities --> + <field name="priority" domain="octet" label="message priority, 0 to 9"/> + <!-- For application use, no formal behaviour --> + <field name="correlation-id" domain="shortstr" + label="application correlation identifier"/> + <!-- For application use, no formal behaviour but may hold the + name of a private response queue, when used in request messages --> + <field name="reply-to" domain="shortstr" label="address to reply to"/> + <!-- For implementation use, no formal behaviour --> + <field name="expiration" domain="shortstr" + label="message expiration specification"/> + <!-- For application use, no formal behaviour --> + <field name="message-id" domain="shortstr" + label="application message identifier"/> + <!-- For application use, no formal behaviour --> + <field name="timestamp" domain="timestamp" label="message timestamp"/> + <!-- For application use, no formal behaviour --> + <field name="type" domain="shortstr" label="message type name"/> + <!-- For application use, no formal behaviour --> + <field name="user-id" domain="shortstr" label="creating user id"/> + <!-- For application use, no formal behaviour --> + <field name="app-id" domain="shortstr" label="creating application id"/> + <!-- Deprecated, was old cluster-id property --> + <field name="reserved" domain="shortstr" + label="reserved, must be empty"/> + + <!-- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - --> + + <method name="qos" synchronous="1" index="10" + label="specify quality of service"> + <doc> + This method requests a specific quality of service. The QoS can + be specified for the + current channel or for all channels on the connection. The + particular properties and + semantics of a qos method always depend on the content class + semantics. Though the + qos method could in principle apply to both peers, it is + currently meaningful only + for the server. + </doc> + + <chassis name="server" implement="MUST"/> + <response name="qos-ok"/> + + <field name="prefetch-size" domain="long" + label="prefetch window in octets"> + <doc> + The client can request that messages be sent in advance so + that when the client + finishes processing a message, the following message is + already held locally, + rather than needing to be sent down the channel. Prefetching + gives a performance + improvement. This field specifies the prefetch window size + in octets. The server + will send a message in advance if it is equal to or smaller + in size than the + available prefetch size (and also falls into other prefetch + limits). May be set + to zero, meaning "no specific limit", although other + prefetch limits may still + apply. The prefetch-size is ignored if the no-ack option is + set. + </doc> + <rule name="01"> + <doc> + The server MUST ignore this setting when the client is + not processing any + messages - i.e. the prefetch size does not limit the + transfer of single + messages to a client, only the sending in advance of + more messages while + the client still has one or more unacknowledged + messages. + </doc> + <doc type="scenario"> + Define a QoS prefetch-size limit and send a single + message that exceeds + that limit. Verify that the message arrives correctly. + </doc> + </rule> + </field> + + <field name="prefetch-count" domain="short" + label="prefetch window in messages"> + <doc> + Specifies a prefetch window in terms of whole messages. This + field may be used + in combination with the prefetch-size field; a message will + only be sent in + advance if both prefetch windows (and those at the channel + and connection level) + allow it. The prefetch-count is ignored if the no-ack option + is set. + </doc> + <rule name="01"> + <doc> + The server may send less data in advance than allowed by + the client's + specified prefetch windows but it MUST NOT send more. + </doc> + <doc type="scenario"> + Define a QoS prefetch-size limit and a prefetch-count + limit greater than + one. Send multiple messages that exceed the prefetch + size. Verify that + no more than one message arrives at once. + </doc> + </rule> + </field> + + <field name="global" domain="bit" + label="apply to entire connection"> + <doc> + By default the QoS settings apply to the current channel + only. If this field is + set, they are applied to the entire connection. + </doc> + </field> + </method> + + <method name="qos-ok" synchronous="1" index="11" + label="confirm the requested qos"> + <doc> + This method tells the client that the requested QoS levels could + be handled by the + server. The requested QoS applies to all active consumers until + a new QoS is + defined. + </doc> + <chassis name="client" implement="MUST"/> + </method> + + <!-- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - --> + + <method name="consume" synchronous="1" index="20" + label="start a queue consumer"> + <doc> + This method asks the server to start a "consumer", which is a + transient request for + messages from a specific queue. Consumers last as long as the + channel they were + declared on, or until the client cancels them. + </doc> + + <rule name="01"> + <doc> + The server SHOULD support at least 16 consumers per queue, + and ideally, impose + no limit except as defined by available resources. + </doc> + <doc type="scenario"> + Declare a queue and create consumers on that queue until the + server closes the + connection. Verify that the number of consumers created was + at least sixteen + and report the total number. + </doc> + </rule> + + <chassis name="server" implement="MUST"/> + <response name="consume-ok"/> + + <!-- Deprecated: "ticket", must be zero --> + <field name="reserved-1" type="short" reserved="1"/> + + <field name="queue" domain="queue-name"> + <doc>Specifies the name of the queue to consume from.</doc> + </field> + + <field name="consumer-tag" domain="consumer-tag"> + <doc> + Specifies the identifier for the consumer. The consumer tag + is local to a + channel, so two clients can use the same consumer tags. If + this field is + empty the server will generate a unique tag. + </doc> + <rule name="01" on-failure="not-allowed"> + <doc> + The client MUST NOT specify a tag that refers to an + existing consumer. + </doc> + <doc type="scenario"> + Attempt to create two consumers with the same non-empty + tag, on the + same channel. + </doc> + </rule> + <rule name="02" on-failure="not-allowed"> + <doc> + The consumer tag is valid only within the channel from + which the + consumer was created. I.e. a client MUST NOT create a + consumer in one + channel and then use it in another. + </doc> + <doc type="scenario"> + Attempt to create a consumer in one channel, then use in + another channel, + in which consumers have also been created (to test that + the server uses + unique consumer tags). + </doc> + </rule> + </field> + + <field name="no-local" domain="no-local"/> + + <field name="no-ack" domain="no-ack"/> + + <field name="exclusive" domain="bit" + label="request exclusive access"> + <doc> + Request exclusive consumer access, meaning only this + consumer can access the + queue. + </doc> + + <rule name="01" on-failure="access-refused"> + <doc> + The client MAY NOT gain exclusive access to a queue that + already has + active consumers. + </doc> + <doc type="scenario"> + Open two connections to a server, and in one connection + declare a shared + (non-exclusive) queue and then consume from the queue. + In the second + connection attempt to consume from the same queue using + the exclusive + option. + </doc> + </rule> + </field> + + <field name="no-wait" domain="no-wait"/> + + <field name="arguments" domain="table" + label="arguments for declaration"> + <doc> + A set of arguments for the consume. The syntax and semantics + of these + arguments depends on the server implementation. + </doc> + </field> + </method> + + <method name="consume-ok" synchronous="1" index="21" + label="confirm a new consumer"> + <doc> + The server provides the client with a consumer tag, which is + used by the client + for methods called on the consumer at a later stage. + </doc> + <chassis name="client" implement="MUST"/> + <field name="consumer-tag" domain="consumer-tag"> + <doc> + Holds the consumer tag specified by the client or provided + by the server. + </doc> + </field> + </method> + + <!-- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - --> + + <method name="cancel" synchronous="1" index="30" + label="end a queue consumer"> + <doc> + This method cancels a consumer. This does not affect already + delivered + messages, but it does mean the server will not send any more + messages for + that consumer. The client may receive an arbitrary number of + messages in + between sending the cancel method and receiving the cancel-ok + reply. + </doc> + + <rule name="01"> + <doc> + If the queue does not exist the server MUST ignore the + cancel method, so + long as the consumer tag is valid for that channel. + </doc> + <doc type="scenario"> + TODO. + </doc> + </rule> + + <chassis name="server" implement="MUST"/> + <response name="cancel-ok"/> + + <field name="consumer-tag" domain="consumer-tag"/> + <field name="no-wait" domain="no-wait"/> + </method> + + <method name="cancel-ok" synchronous="1" index="31" + label="confirm a cancelled consumer"> + <doc> + This method confirms that the cancellation was completed. + </doc> + <chassis name="client" implement="MUST"/> + <field name="consumer-tag" domain="consumer-tag"/> + </method> + + <!-- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - --> + + <method name="publish" content="1" index="40" label="publish a message"> + <doc> + This method publishes a message to a specific exchange. The + message will be routed + to queues as defined by the exchange configuration and + distributed to any active + consumers when the transaction, if any, is committed. + </doc> + + <chassis name="server" implement="MUST"/> + + <!-- Deprecated: "ticket", must be zero --> + <field name="reserved-1" type="short" reserved="1"/> + + <field name="exchange" domain="exchange-name"> + <doc> + Specifies the name of the exchange to publish to. The + exchange name can be + empty, meaning the default exchange. If the exchange name is + specified, and that + exchange does not exist, the server will raise a channel + exception. + </doc> + + <rule name="must-exist" on-failure="not-found"> + <doc> + The client MUST NOT attempt to publish a content to an + exchange that + does not exist. + </doc> + <doc type="scenario"> + The client attempts to publish a content to a + non-existent exchange. + </doc> + </rule> + <rule name="default-exchange"> + <doc> + The server MUST accept a blank exchange name to mean the + default exchange. + </doc> + <doc type="scenario"> + The client declares a queue and binds it to a blank + exchange name. + </doc> + </rule> + <rule name="02"> + <doc> + If the exchange was declared as an internal exchange, + the server MUST raise + a channel exception with a reply code 403 (access + refused). + </doc> + <doc type="scenario"> + TODO. + </doc> + </rule> + + <rule name="03"> + <doc> + The exchange MAY refuse basic content in which case it + MUST raise a channel + exception with reply code 540 (not implemented). + </doc> + <doc type="scenario"> + TODO. + </doc> + </rule> + </field> + + <field name="routing-key" domain="shortstr" + label="Message routing key"> + <doc> + Specifies the routing key for the message. The routing key + is used for routing + messages depending on the exchange configuration. + </doc> + </field> + + <field name="mandatory" domain="bit" + label="indicate mandatory routing"> + <doc> + This flag tells the server how to react if the message + cannot be routed to a + queue. If this flag is set, the server will return an + unroutable message with a + Return method. If this flag is zero, the server silently + drops the message. + </doc> + + <rule name="01"> + <doc> + The server SHOULD implement the mandatory flag. + </doc> + <doc type="scenario"> + TODO. + </doc> + </rule> + </field> + + <field name="immediate" domain="bit" + label="request immediate delivery"> + <doc> + This flag tells the server how to react if the message + cannot be routed to a + queue consumer immediately. If this flag is set, the server + will return an + undeliverable message with a Return method. If this flag is + zero, the server + will queue the message, but with no guarantee that it will + ever be consumed. + </doc> + + <rule name="01"> + <doc> + The server SHOULD implement the immediate flag. + </doc> + <doc type="scenario"> + TODO. + </doc> + </rule> + </field> + </method> + + <method name="return" content="1" index="50" + label="return a failed message"> + <doc> + This method returns an undeliverable message that was published + with the "immediate" + flag set, or an unroutable message published with the + "mandatory" flag set. The + reply code and text provide information about the reason that + the message was + undeliverable. + </doc> + + <chassis name="client" implement="MUST"/> + + <field name="reply-code" domain="reply-code"/> + <field name="reply-text" domain="reply-text"/> + + <field name="exchange" domain="exchange-name"> + <doc> + Specifies the name of the exchange that the message was + originally published + to. May be empty, meaning the default exchange. + </doc> + </field> + + <field name="routing-key" domain="shortstr" + label="Message routing key"> + <doc> + Specifies the routing key name specified when the message + was published. + </doc> + </field> + </method> + + <!-- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - --> + + <method name="deliver" content="1" index="60" + label="notify the client of a consumer message"> + <doc> + This method delivers a message to the client, via a consumer. In + the asynchronous + message delivery model, the client starts a consumer using the + Consume method, then + the server responds with Deliver methods as and when messages + arrive for that + consumer. + </doc> + + <rule name="01"> + <doc> + The server SHOULD track the number of times a message has + been delivered to + clients and when a message is redelivered a certain number + of times - e.g. 5 + times - without being acknowledged, the server SHOULD + consider the message to be + unprocessable (possibly causing client applications to + abort), and move the + message to a dead letter queue. + </doc> + <doc type="scenario"> + TODO. + </doc> + </rule> + + <chassis name="client" implement="MUST"/> + + <field name="consumer-tag" domain="consumer-tag"/> + <field name="delivery-tag" domain="delivery-tag"/> + <field name="redelivered" domain="redelivered"/> + + <field name="exchange" domain="exchange-name"> + <doc> + Specifies the name of the exchange that the message was + originally published to. + May be empty, indicating the default exchange. + </doc> + </field> + + <field name="routing-key" domain="shortstr" + label="Message routing key"> + <doc>Specifies the routing key name specified when the message + was published. + </doc> + </field> + </method> + + <!-- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - --> + + <method name="get" synchronous="1" index="70" + label="direct access to a queue"> + <doc> + This method provides a direct access to the messages in a queue + using a synchronous + dialogue that is designed for specific types of application + where synchronous + functionality is more important than performance. + </doc> + + <response name="get-ok"/> + <response name="get-empty"/> + <chassis name="server" implement="MUST"/> + + <!-- Deprecated: "ticket", must be zero --> + <field name="reserved-1" type="short" reserved="1"/> + + <field name="queue" domain="queue-name"> + <doc>Specifies the name of the queue to get a message from. + </doc> + </field> + <field name="no-ack" domain="no-ack"/> + </method> + + <method name="get-ok" synchronous="1" content="1" index="71" + label="provide client with a message"> + <doc> + This method delivers a message to the client following a get + method. A message + delivered by 'get-ok' must be acknowledged unless the no-ack + option was set in the + get method. + </doc> + + <chassis name="client" implement="MAY"/> + + <field name="delivery-tag" domain="delivery-tag"/> + <field name="redelivered" domain="redelivered"/> + <field name="exchange" domain="exchange-name"> + <doc> + Specifies the name of the exchange that the message was + originally published to. + If empty, the message was published to the default exchange. + </doc> + </field> + + <field name="routing-key" domain="shortstr" + label="Message routing key"> + <doc>Specifies the routing key name specified when the message + was published. + </doc> + </field> + + <field name="message-count" domain="message-count"/> + </method> + + <method name="get-empty" synchronous="1" index="72" + label="indicate no messages available"> + <doc> + This method tells the client that the queue has no messages + available for the + client. + </doc> + <chassis name="client" implement="MAY"/> + <!-- Deprecated: "cluster-id", must be empty --> + <field name="reserved-1" type="shortstr" reserved="1"/> + </method> + + <!-- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - --> + + <method name="ack" index="80" label="acknowledge one or more messages"> + <doc> + This method acknowledges one or more messages delivered via the + Deliver or Get-Ok + methods. The client can ask to confirm a single message or a set + of messages up to + and including a specific message. + </doc> + + <chassis name="server" implement="MUST"/> + + <field name="delivery-tag" domain="delivery-tag"/> + <field name="multiple" domain="bit" + label="acknowledge multiple messages"> + <doc> + If set to 1, the delivery tag is treated as "up to and + including", so that the + client can acknowledge multiple messages with a single + method. If set to zero, + the delivery tag refers to a single message. If the multiple + field is 1, and the + delivery tag is zero, tells the server to acknowledge all + outstanding messages. + </doc> + <rule name="exists" on-failure="precondition-failed"> + <doc> + The server MUST validate that a non-zero delivery-tag + refers to a delivered + message, and raise a channel exception if this is not + the case. On a transacted + channel, this check MUST be done immediately and not + delayed until a Tx.Commit. + Specifically, a client MUST not acknowledge the same + message more than once. + </doc> + <doc type="scenario"> + TODO. + </doc> + </rule> + </field> + </method> + + <!-- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - --> + + <method name="reject" index="90" label="reject an incoming message"> + <doc> + This method allows a client to reject a message. It can be used + to interrupt and + cancel large incoming messages, or return untreatable messages + to their original + queue. + </doc> + + <rule name="01"> + <doc> + The server SHOULD be capable of accepting and process the + Reject method while + sending message content with a Deliver or Get-Ok method. + I.e. the server should + read and process incoming methods while sending output + frames. To cancel a + partially-send content, the server sends a content body + frame of size 1 (i.e. + with no data except the frame-end octet). + </doc> + </rule> + + <rule name="02"> + <doc> + The server SHOULD interpret this method as meaning that the + client is unable to + process the message at this time. + </doc> + <doc type="scenario"> + TODO. + </doc> + </rule> + + <rule name="03"> + <doc> + The client MUST NOT use this method as a means of selecting + messages to process. + </doc> + <doc type="scenario"> + TODO. + </doc> + </rule> + + <chassis name="server" implement="MUST"/> + + <field name="delivery-tag" domain="delivery-tag"/> + + <field name="requeue" domain="bit" label="requeue the message"> + <doc> + If requeue is true, the server will attempt to requeue the + message. If requeue + is false or the requeue attempt fails the messages are + discarded or dead-lettered. + </doc> + + <rule name="01"> + <doc> + The server MUST NOT deliver the message to the same + client within the + context of the current channel. The recommended strategy + is to attempt to + deliver the message to an alternative consumer, and if + that is not possible, + to move the message to a dead-letter queue. The server + MAY use more + sophisticated tracking to hold the message on the queue + and redeliver it to + the same client at a later stage. + </doc> + <doc type="scenario"> + TODO. + </doc> + </rule> + </field> + </method> + + <!-- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - --> + + <method name="recover-async" index="100" + label="redeliver unacknowledged messages" + deprecated="1"> + <doc> + This method asks the server to redeliver all unacknowledged + messages on a + specified channel. Zero or more messages may be redelivered. + This method + is deprecated in favour of the synchronous Recover/Recover-Ok. + </doc> + <rule name="01"> + <doc> + The server MUST set the redelivered flag on all messages + that are resent. + </doc> + <doc type="scenario"> + TODO. + </doc> + </rule> + <chassis name="server" implement="MAY"/> + <field name="requeue" domain="bit" label="requeue the message"> + <doc> + If this field is zero, the message will be redelivered to + the original + recipient. If this bit is 1, the server will attempt to + requeue the message, + potentially then delivering it to an alternative subscriber. + </doc> + </field> + </method> + + <!-- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - --> + + <method name="recover" index="110" + label="redeliver unacknowledged messages"> + <doc> + This method asks the server to redeliver all unacknowledged + messages on a + specified channel. Zero or more messages may be redelivered. + This method + replaces the asynchronous Recover. + </doc> + <rule name="01"> + <doc> + The server MUST set the redelivered flag on all messages + that are resent. + </doc> + <doc type="scenario"> + TODO. + </doc> + </rule> + <chassis name="server" implement="MUST"/> + <field name="requeue" domain="bit" label="requeue the message"> + <doc> + If this field is zero, the message will be redelivered to + the original + recipient. If this bit is 1, the server will attempt to + requeue the message, + potentially then delivering it to an alternative subscriber. + </doc> + </field> + </method> + + <method name="recover-ok" synchronous="1" index="111" + label="confirm recovery"> + <doc> + This method acknowledges a Basic.Recover method. + </doc> + <chassis name="client" implement="MUST"/> + </method> + </class> + + <!-- == TX =============================================================== --> + + <class name="tx" handler="channel" index="90" + label="work with transactions"> + <doc> + The Tx class allows publish and ack operations to be batched into + atomic + units of work. The intention is that all publish and ack requests + issued + within a transaction will complete successfully or none of them + will. + Servers SHOULD implement atomic transactions at least where all + publish + or ack requests affect a single queue. Transactions that cover + multiple + queues may be non-atomic, given that queues can be created and + destroyed + asynchronously, and such events do not form part of any transaction. + Further, the behaviour of transactions with respect to the immediate + and + mandatory flags on Basic.Publish methods is not defined. + </doc> + + <rule name="not multiple queues"> + <doc> + Applications MUST NOT rely on the atomicity of transactions that + affect more than one queue. + </doc> </rule> - </field> - - <field name = "immediate" domain = "bit" label = "request immediate delivery"> - <doc> - This flag tells the server how to react if the message cannot be routed to a - queue consumer immediately. If this flag is set, the server will return an - undeliverable message with a Return method. If this flag is zero, the server - will queue the message, but with no guarantee that it will ever be consumed. - </doc> - - <rule name = "01"> - <doc> - The server SHOULD implement the immediate flag. - </doc> - <doc type = "scenario"> - TODO. - </doc> + <rule name="not immediate"> + <doc> + Applications MUST NOT rely on the behaviour of transactions that + include messages published with the immediate option. + </doc> </rule> - </field> - </method> - - <method name = "return" content = "1" index = "50" label = "return a failed message"> - <doc> - This method returns an undeliverable message that was published with the "immediate" - flag set, or an unroutable message published with the "mandatory" flag set. The - reply code and text provide information about the reason that the message was - undeliverable. - </doc> - - <chassis name = "client" implement = "MUST" /> - - <field name = "reply-code" domain = "reply-code" /> - <field name = "reply-text" domain = "reply-text" /> - - <field name = "exchange" domain = "exchange-name"> - <doc> - Specifies the name of the exchange that the message was originally published - to. May be empty, meaning the default exchange. - </doc> - </field> - - <field name = "routing-key" domain = "shortstr" label = "Message routing key"> - <doc> - Specifies the routing key name specified when the message was published. - </doc> - </field> - </method> - - <!-- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - --> - - <method name = "deliver" content = "1" index = "60" - label = "notify the client of a consumer message"> - <doc> - This method delivers a message to the client, via a consumer. In the asynchronous - message delivery model, the client starts a consumer using the Consume method, then - the server responds with Deliver methods as and when messages arrive for that - consumer. - </doc> - - <rule name = "01"> - <doc> - The server SHOULD track the number of times a message has been delivered to - clients and when a message is redelivered a certain number of times - e.g. 5 - times - without being acknowledged, the server SHOULD consider the message to be - unprocessable (possibly causing client applications to abort), and move the - message to a dead letter queue. - </doc> - <doc type = "scenario"> - TODO. - </doc> - </rule> - - <chassis name = "client" implement = "MUST" /> - - <field name = "consumer-tag" domain = "consumer-tag" /> - <field name = "delivery-tag" domain = "delivery-tag" /> - <field name = "redelivered" domain = "redelivered" /> - - <field name = "exchange" domain = "exchange-name"> - <doc> - Specifies the name of the exchange that the message was originally published to. - May be empty, indicating the default exchange. - </doc> - </field> - - <field name = "routing-key" domain = "shortstr" label = "Message routing key"> - <doc>Specifies the routing key name specified when the message was published.</doc> - </field> - </method> - - <!-- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - --> - - <method name = "get" synchronous = "1" index = "70" label = "direct access to a queue"> - <doc> - This method provides a direct access to the messages in a queue using a synchronous - dialogue that is designed for specific types of application where synchronous - functionality is more important than performance. - </doc> - - <response name = "get-ok" /> - <response name = "get-empty" /> - <chassis name = "server" implement = "MUST" /> - - <!-- Deprecated: "ticket", must be zero --> - <field name = "reserved-1" type = "short" reserved = "1" /> - - <field name = "queue" domain = "queue-name"> - <doc>Specifies the name of the queue to get a message from.</doc> - </field> - <field name = "no-ack" domain = "no-ack" /> - </method> - - <method name = "get-ok" synchronous = "1" content = "1" index = "71" - label = "provide client with a message"> - <doc> - This method delivers a message to the client following a get method. A message - delivered by 'get-ok' must be acknowledged unless the no-ack option was set in the - get method. - </doc> - - <chassis name = "client" implement = "MAY" /> - - <field name = "delivery-tag" domain = "delivery-tag" /> - <field name = "redelivered" domain = "redelivered" /> - <field name = "exchange" domain = "exchange-name"> - <doc> - Specifies the name of the exchange that the message was originally published to. - If empty, the message was published to the default exchange. - </doc> - </field> - - <field name = "routing-key" domain = "shortstr" label = "Message routing key"> - <doc>Specifies the routing key name specified when the message was published.</doc> - </field> - - <field name = "message-count" domain = "message-count" /> - </method> - - <method name = "get-empty" synchronous = "1" index = "72" - label = "indicate no messages available"> - <doc> - This method tells the client that the queue has no messages available for the - client. - </doc> - <chassis name = "client" implement = "MAY" /> - <!-- Deprecated: "cluster-id", must be empty --> - <field name = "reserved-1" type = "shortstr" reserved = "1" /> - </method> - - <!-- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - --> - - <method name = "ack" index = "80" label = "acknowledge one or more messages"> - <doc> - This method acknowledges one or more messages delivered via the Deliver or Get-Ok - methods. The client can ask to confirm a single message or a set of messages up to - and including a specific message. - </doc> - - <chassis name = "server" implement = "MUST" /> - - <field name = "delivery-tag" domain = "delivery-tag" /> - <field name = "multiple" domain = "bit" label = "acknowledge multiple messages"> - <doc> - If set to 1, the delivery tag is treated as "up to and including", so that the - client can acknowledge multiple messages with a single method. If set to zero, - the delivery tag refers to a single message. If the multiple field is 1, and the - delivery tag is zero, tells the server to acknowledge all outstanding messages. - </doc> - <rule name = "exists" on-failure = "precondition-failed"> - <doc> - The server MUST validate that a non-zero delivery-tag refers to a delivered - message, and raise a channel exception if this is not the case. On a transacted - channel, this check MUST be done immediately and not delayed until a Tx.Commit. - Specifically, a client MUST not acknowledge the same message more than once. - </doc> - <doc type = "scenario"> - TODO. - </doc> + <rule name="not mandatory"> + <doc> + Applications MUST NOT rely on the behaviour of transactions that + include messages published with the mandatory option. + </doc> </rule> - </field> - </method> - - <!-- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - --> - - <method name = "reject" index = "90" label = "reject an incoming message"> - <doc> - This method allows a client to reject a message. It can be used to interrupt and - cancel large incoming messages, or return untreatable messages to their original - queue. - </doc> - - <rule name = "01"> - <doc> - The server SHOULD be capable of accepting and process the Reject method while - sending message content with a Deliver or Get-Ok method. I.e. the server should - read and process incoming methods while sending output frames. To cancel a - partially-send content, the server sends a content body frame of size 1 (i.e. - with no data except the frame-end octet). - </doc> - </rule> - - <rule name = "02"> - <doc> - The server SHOULD interpret this method as meaning that the client is unable to - process the message at this time. - </doc> - <doc type = "scenario"> - TODO. - </doc> - </rule> - - <rule name = "03"> - <doc> - The client MUST NOT use this method as a means of selecting messages to process. - </doc> - <doc type = "scenario"> - TODO. - </doc> - </rule> - - <chassis name = "server" implement = "MUST" /> - - <field name = "delivery-tag" domain = "delivery-tag" /> - - <field name = "requeue" domain = "bit" label = "requeue the message"> - <doc> - If requeue is true, the server will attempt to requeue the message. If requeue - is false or the requeue attempt fails the messages are discarded or dead-lettered. - </doc> - <rule name = "01"> - <doc> - The server MUST NOT deliver the message to the same client within the - context of the current channel. The recommended strategy is to attempt to - deliver the message to an alternative consumer, and if that is not possible, - to move the message to a dead-letter queue. The server MAY use more - sophisticated tracking to hold the message on the queue and redeliver it to - the same client at a later stage. - </doc> - <doc type = "scenario"> - TODO. - </doc> - </rule> - </field> - </method> - - <!-- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - --> - - <method name = "recover-async" index = "100" label = "redeliver unacknowledged messages" - deprecated = "1"> - <doc> - This method asks the server to redeliver all unacknowledged messages on a - specified channel. Zero or more messages may be redelivered. This method - is deprecated in favour of the synchronous Recover/Recover-Ok. - </doc> - <rule name = "01"> - <doc> - The server MUST set the redelivered flag on all messages that are resent. - </doc> - <doc type = "scenario"> - TODO. - </doc> - </rule> - <chassis name = "server" implement = "MAY" /> - <field name = "requeue" domain = "bit" label = "requeue the message"> - <doc> - If this field is zero, the message will be redelivered to the original - recipient. If this bit is 1, the server will attempt to requeue the message, - potentially then delivering it to an alternative subscriber. - </doc> - </field> - </method> - - <!-- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - --> - - <method name = "recover" index = "110" label = "redeliver unacknowledged messages"> - <doc> - This method asks the server to redeliver all unacknowledged messages on a - specified channel. Zero or more messages may be redelivered. This method - replaces the asynchronous Recover. - </doc> - <rule name = "01"> - <doc> - The server MUST set the redelivered flag on all messages that are resent. - </doc> - <doc type = "scenario"> - TODO. - </doc> - </rule> - <chassis name = "server" implement = "MUST" /> - <field name = "requeue" domain = "bit" label = "requeue the message"> - <doc> - If this field is zero, the message will be redelivered to the original - recipient. If this bit is 1, the server will attempt to requeue the message, - potentially then delivering it to an alternative subscriber. - </doc> - </field> - </method> - - <method name = "recover-ok" synchronous = "1" index = "111" label = "confirm recovery"> - <doc> - This method acknowledges a Basic.Recover method. - </doc> - <chassis name = "client" implement = "MUST" /> - </method> - </class> - - <!-- == TX =============================================================== --> - - <class name = "tx" handler = "channel" index = "90" label = "work with transactions"> - <doc> - The Tx class allows publish and ack operations to be batched into atomic - units of work. The intention is that all publish and ack requests issued - within a transaction will complete successfully or none of them will. - Servers SHOULD implement atomic transactions at least where all publish - or ack requests affect a single queue. Transactions that cover multiple - queues may be non-atomic, given that queues can be created and destroyed - asynchronously, and such events do not form part of any transaction. - Further, the behaviour of transactions with respect to the immediate and - mandatory flags on Basic.Publish methods is not defined. - </doc> - - <rule name = "not multiple queues"> - <doc> - Applications MUST NOT rely on the atomicity of transactions that - affect more than one queue. - </doc> - </rule> - <rule name = "not immediate"> - <doc> - Applications MUST NOT rely on the behaviour of transactions that - include messages published with the immediate option. - </doc> - </rule> - <rule name = "not mandatory"> - <doc> - Applications MUST NOT rely on the behaviour of transactions that - include messages published with the mandatory option. - </doc> - </rule> - - <doc type = "grammar"> - tx = C:SELECT S:SELECT-OK - / C:COMMIT S:COMMIT-OK - / C:ROLLBACK S:ROLLBACK-OK - </doc> - - <chassis name = "server" implement = "SHOULD" /> - <chassis name = "client" implement = "MAY" /> - - <!-- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - --> - - <method name = "select" synchronous = "1" index = "10" label = "select standard transaction mode"> - <doc> - This method sets the channel to use standard transactions. The client must use this - method at least once on a channel before using the Commit or Rollback methods. - </doc> - <chassis name = "server" implement = "MUST" /> - <response name = "select-ok" /> - </method> - - <method name = "select-ok" synchronous = "1" index = "11" label = "confirm transaction mode"> - <doc> - This method confirms to the client that the channel was successfully set to use - standard transactions. - </doc> - <chassis name = "client" implement = "MUST" /> - </method> - - <!-- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - --> - - <method name = "commit" synchronous = "1" index = "20" label = "commit the current transaction"> - <doc> - This method commits all message publications and acknowledgments performed in - the current transaction. A new transaction starts immediately after a commit. - </doc> - <chassis name = "server" implement = "MUST" /> - <response name = "commit-ok" /> - - <rule name = "transacted" on-failure = "precondition-failed"> - <doc> - The client MUST NOT use the Commit method on non-transacted channels. - </doc> - <doc type = "scenario"> - The client opens a channel and then uses Tx.Commit. - </doc> - </rule> - </method> - - <method name = "commit-ok" synchronous = "1" index = "21" label = "confirm a successful commit"> - <doc> - This method confirms to the client that the commit succeeded. Note that if a commit - fails, the server raises a channel exception. - </doc> - <chassis name = "client" implement = "MUST" /> - </method> - - <!-- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - --> - - <method name = "rollback" synchronous = "1" index = "30" - label = "abandon the current transaction"> - <doc> - This method abandons all message publications and acknowledgments performed in - the current transaction. A new transaction starts immediately after a rollback. - Note that unacked messages will not be automatically redelivered by rollback; - if that is required an explicit recover call should be issued. - </doc> - <chassis name = "server" implement = "MUST" /> - <response name = "rollback-ok" /> - - <rule name = "transacted" on-failure = "precondition-failed"> - <doc> - The client MUST NOT use the Rollback method on non-transacted channels. - </doc> - <doc type = "scenario"> - The client opens a channel and then uses Tx.Rollback. - </doc> - </rule> - </method> - - <method name = "rollback-ok" synchronous = "1" index = "31" label = "confirm successful rollback"> - <doc> - This method confirms to the client that the rollback succeeded. Note that if an - rollback fails, the server raises a channel exception. - </doc> - <chassis name = "client" implement = "MUST" /> - </method> - </class> + <doc type="grammar"> + tx = C:SELECT S:SELECT-OK + / C:COMMIT S:COMMIT-OK + / C:ROLLBACK S:ROLLBACK-OK + </doc> + + <chassis name="server" implement="SHOULD"/> + <chassis name="client" implement="MAY"/> + + <!-- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - --> + + <method name="select" synchronous="1" index="10" + label="select standard transaction mode"> + <doc> + This method sets the channel to use standard transactions. The + client must use this + method at least once on a channel before using the Commit or + Rollback methods. + </doc> + <chassis name="server" implement="MUST"/> + <response name="select-ok"/> + </method> + + <method name="select-ok" synchronous="1" index="11" + label="confirm transaction mode"> + <doc> + This method confirms to the client that the channel was + successfully set to use + standard transactions. + </doc> + <chassis name="client" implement="MUST"/> + </method> + + <!-- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - --> + + <method name="commit" synchronous="1" index="20" + label="commit the current transaction"> + <doc> + This method commits all message publications and acknowledgments + performed in + the current transaction. A new transaction starts immediately + after a commit. + </doc> + <chassis name="server" implement="MUST"/> + <response name="commit-ok"/> + + <rule name="transacted" on-failure="precondition-failed"> + <doc> + The client MUST NOT use the Commit method on non-transacted + channels. + </doc> + <doc type="scenario"> + The client opens a channel and then uses Tx.Commit. + </doc> + </rule> + </method> + + <method name="commit-ok" synchronous="1" index="21" + label="confirm a successful commit"> + <doc> + This method confirms to the client that the commit succeeded. + Note that if a commit + fails, the server raises a channel exception. + </doc> + <chassis name="client" implement="MUST"/> + </method> + + <!-- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - --> + + <method name="rollback" synchronous="1" index="30" + label="abandon the current transaction"> + <doc> + This method abandons all message publications and + acknowledgments performed in + the current transaction. A new transaction starts immediately + after a rollback. + Note that unacked messages will not be automatically redelivered + by rollback; + if that is required an explicit recover call should be issued. + </doc> + <chassis name="server" implement="MUST"/> + <response name="rollback-ok"/> + + <rule name="transacted" on-failure="precondition-failed"> + <doc> + The client MUST NOT use the Rollback method on + non-transacted channels. + </doc> + <doc type="scenario"> + The client opens a channel and then uses Tx.Rollback. + </doc> + </rule> + </method> + + <method name="rollback-ok" synchronous="1" index="31" + label="confirm successful rollback"> + <doc> + This method confirms to the client that the rollback succeeded. + Note that if an + rollback fails, the server raises a channel exception. + </doc> + <chassis name="client" implement="MUST"/> + </method> + </class> </amqp> diff --git a/setup.cfg b/setup.cfg index be77f9a4977a5d19c733738ad8992edbff218e8d..9cf9e0219e37e5cdbdbb526f74d8def8495d518d 100644 --- a/setup.cfg +++ b/setup.cfg @@ -1,7 +1,7 @@ [metadata] description-file = README.md name = CoolAMQP -version = 0.92 +version = 0.93a1 license = MIT License classifiers = Programming Language :: Python @@ -21,6 +21,8 @@ description = Very fast pure-Python AMQP client author = DMS Serwis s.c. author_email = piotrm@dms-serwis.pl url = https://github.com/smok-serwis/coolamqp +platforms = + posix [pycodestyle] max-line-length=80 diff --git a/setup.py b/setup.py index b4158035a5f9f0278b07f33699ac8b197c38de40..7055a4d5d5d9aec07db985b5d910d9cb6bf4cf8b 100644 --- a/setup.py +++ b/setup.py @@ -1,28 +1,16 @@ #!/usr/bin/env python # coding=UTF-8 -from setuptools import setup +from setuptools import setup, find_packages setup(keywords=['amqp', 'rabbitmq', 'client', 'network', 'ha', 'high availability'], - packages=[ - 'coolamqp', - 'coolamqp.uplink', - 'coolamqp.uplink.connection', - 'coolamqp.uplink.listener', - 'coolamqp.clustering', - 'coolamqp.attaches', - 'coolamqp.framing', - 'coolamqp.framing.compilation', - ], + packages=find_packages(include=['coolamqp', 'coolamqp.*']), long_description=u'''Pure Python AMQP client, but with dynamic class generation and memoryviews FOR THE GODSPEED. Also, handles your reconnects and transactionality THE RIGHT WAY, though somewhat opinionated''', install_requires=['six', 'monotonic', 'futures'], - tests_require=["nose", 'coverage', 'codeclimate-test-reporter'], - test_suite='nose.collector', - platforms=[ - 'posix' - ] + tests_require=["nose", 'coverage'], + test_suite='nose.collector' ) diff --git a/tests/run.py b/tests/run.py index e574f3cff37721b4c3b6f73748aaf7b738bc28e3..8a9f1a004294088672771881725738d84092b5a0 100644 --- a/tests/run.py +++ b/tests/run.py @@ -1,23 +1,22 @@ # coding=UTF-8 from __future__ import absolute_import, division, print_function import time, logging, threading -from coolamqp.objects import Message, MessageProperties, NodeDefinition, Queue, Exchange +from coolamqp.objects import Message, MessageProperties, NodeDefinition, Queue, \ + Exchange from coolamqp.exceptions import AMQPError from coolamqp.clustering import Cluster import time - NODE = NodeDefinition('127.0.0.1', 'guest', 'guest', heartbeat=20) logging.basicConfig(level=logging.DEBUG) amqp = Cluster([NODE]) amqp.start(wait=True) - q = Queue(u'lolwut', auto_delete=True, exclusive=True) -c,f=amqp.consume(q, no_ack=True, body_receive_mode=1) +c, f = amqp.consume(q, no_ack=True, body_receive_mode=1) -#time.sleep(30) +# time.sleep(30) -#amqp.shutdown(True) +# amqp.shutdown(True) diff --git a/tests/test_clustering/__init__.py b/tests/test_clustering/__init__.py index 1c762b12fd99adc2f7d4e5137c5b872079457510..db0a0a6db68923bea6cabb6a4005abf5fdb90ffb 100644 --- a/tests/test_clustering/__init__.py +++ b/tests/test_clustering/__init__.py @@ -4,5 +4,3 @@ import six import logging logger = logging.getLogger(__name__) - - diff --git a/tests/test_clustering/test_a.py b/tests/test_clustering/test_a.py index 48c5e0dcb932f95b3317119ba028387da5e2806a..2f4fd62a40f247628f70fff5fc21bd6ce83fd029 100644 --- a/tests/test_clustering/test_a.py +++ b/tests/test_clustering/test_a.py @@ -7,7 +7,8 @@ import six import os import unittest import time, logging, threading, monotonic -from coolamqp.objects import Message, MessageProperties, NodeDefinition, Queue, ReceivedMessage, Exchange +from coolamqp.objects import Message, MessageProperties, NodeDefinition, Queue, \ + ReceivedMessage, Exchange from coolamqp.clustering import Cluster, MessageReceived, NothingMuch import time @@ -17,7 +18,6 @@ logging.basicConfig(level=logging.DEBUG) class TestA(unittest.TestCase): - def setUp(self): self.c = Cluster([NODE]) self.c.start() @@ -38,14 +38,15 @@ class TestA(unittest.TestCase): con, fut = self.c.consume(Queue(u'hello', exclusive=True)) fut.result() - data = six.binary_type(os.urandom(20*1024*1024+1423)) + data = six.binary_type(os.urandom(20 * 1024 * 1024 + 1423)) - self.c.publish(Message(data), routing_key=b'hello', confirm=True).result() + self.c.publish(Message(data), routing_key=b'hello', + confirm=True).result() -# rmsg = self.c.drain(3) -# rmsg.ack() + # rmsg = self.c.drain(3) + # rmsg.ack() -# self.assertEquals(rmsg.body, data) + # self.assertEquals(rmsg.body, data) def test_actually_waits(self): a = monotonic.monotonic() @@ -54,7 +55,6 @@ class TestA(unittest.TestCase): self.assertTrue(monotonic.monotonic() - a >= 4) - def test_set_qos_but_later(self): con, fut = self.c.consume(Queue(u'hello', exclusive=True)) @@ -68,23 +68,23 @@ class TestA(unittest.TestCase): time.sleep(1) self.assertEquals(con.qos, (0, 110)) - def test_anonymq(self): - q = Queue(exchange=Exchange(u'ooo', type=b'fanout', auto_delete=True), auto_delete=True) + q = Queue(exchange=Exchange(u'ooo', type=b'fanout', auto_delete=True), + auto_delete=True) c, f = self.c.consume(q) f.result() def test_send_recv_zerolen(self): - P = {'q': False} def ok(e): self.assertIsInstance(e, ReceivedMessage) P['q'] = True - con, fut = self.c.consume(Queue(u'hello', exclusive=True), on_message=ok, no_ack=True) + con, fut = self.c.consume(Queue(u'hello', exclusive=True), + on_message=ok, no_ack=True) fut.result() self.c.publish(Message(b''), routing_key=u'hello', tx=True).result() @@ -93,46 +93,48 @@ class TestA(unittest.TestCase): self.assertTrue(P['q']) def test_message_with_propos_confirm(self): - P = {'q': False} def ok(e): self.assertIsInstance(e, ReceivedMessage) self.assertEquals(e.body, b'hello') - #bcoz u can compare memoryviews to their providers :D + # bcoz u can compare memoryviews to their providers :D self.assertEquals(e.properties.content_type, b'text/plain') self.assertEquals(e.properties.content_encoding, b'utf8') P['q'] = True - con, fut = self.c.consume(Queue(u'hello', exclusive=True), on_message=ok, no_ack=True) + con, fut = self.c.consume(Queue(u'hello', exclusive=True), + on_message=ok, no_ack=True) fut.result() self.c.publish(Message(b'hello', properties={ 'content_type': b'text/plain', 'content_encoding': b'utf8' }), routing_key=u'hello', confirm=True).result() - self.assertRaises(RuntimeError, lambda: self.c.publish(Message(b'hello', properties={ - 'content_type': b'text/plain', - 'content_encoding': b'utf8' - }), routing_key=u'hello', confirm=True, tx=True).result()) + self.assertRaises(RuntimeError, + lambda: self.c.publish(Message(b'hello', properties={ + 'content_type': b'text/plain', + 'content_encoding': b'utf8' + }), routing_key=u'hello', confirm=True, + tx=True).result()) time.sleep(1) self.assertTrue(P['q']) def test_message_with_propos(self): - P = {'q': False} def ok(e): self.assertIsInstance(e, ReceivedMessage) self.assertEquals(e.body, b'hello') - #bcoz u can compare memoryviews to their providers :D + # bcoz u can compare memoryviews to their providers :D self.assertEquals(e.properties.content_type, b'text/plain') self.assertEquals(e.properties.content_encoding, b'utf8') P['q'] = True - con, fut = self.c.consume(Queue(u'hello', exclusive=True), on_message=ok, no_ack=True) + con, fut = self.c.consume(Queue(u'hello', exclusive=True), + on_message=ok, no_ack=True) fut.result() self.c.publish(Message(b'hello', properties={ 'content_type': b'text/plain', @@ -143,7 +145,6 @@ class TestA(unittest.TestCase): self.assertTrue(P['q']) - def test_send_recv_nonzerolen(self): """with callback function""" @@ -154,9 +155,11 @@ class TestA(unittest.TestCase): self.assertEquals(e.body, b'hello') P['q'] = True - con, fut = self.c.consume(Queue(u'hello', exclusive=True), on_message=ok, no_ack=True) + con, fut = self.c.consume(Queue(u'hello', exclusive=True), + on_message=ok, no_ack=True) fut.result() - self.c.publish(Message(b'hello'), routing_key=u'hello', tx=True).result() + self.c.publish(Message(b'hello'), routing_key=u'hello', + tx=True).result() time.sleep(1) @@ -208,12 +211,14 @@ class TestA(unittest.TestCase): self.assertEquals(b''.join(x.tobytes() for x in m.body), data) def test_consumer_cancel(self): - con, fut = self.c.consume(Queue(u'hello', exclusive=True, auto_delete=True)) + con, fut = self.c.consume( + Queue(u'hello', exclusive=True, auto_delete=True)) fut.result() con.cancel().result() def test_drain_1(self): - con, fut = self.c.consume(Queue(u'hello', exclusive=True, auto_delete=True)) + con, fut = self.c.consume( + Queue(u'hello', exclusive=True, auto_delete=True)) fut.result() self.c.publish(Message(b'ioi'), routing_key=u'hello') diff --git a/tests/test_clustering/test_double.py b/tests/test_clustering/test_double.py index ca6cbefdbf509dd612c33104ea0fdbbce9642eb8..c6ae6beaf8c9d5886fef2c2969b8a03365a86b1a 100644 --- a/tests/test_clustering/test_double.py +++ b/tests/test_clustering/test_double.py @@ -6,17 +6,17 @@ from __future__ import print_function, absolute_import, division import six import unittest import time, logging, threading -from coolamqp.objects import Message, MessageProperties, NodeDefinition, Queue, ReceivedMessage +from coolamqp.objects import Message, MessageProperties, NodeDefinition, Queue, \ + ReceivedMessage from coolamqp.clustering import Cluster + NODE = NodeDefinition('127.0.0.1', 'guest', 'guest', heartbeat=20) from coolamqp.exceptions import AMQPError, RESOURCE_LOCKED - logging.basicConfig(level=logging.DEBUG) class TestDouble(unittest.TestCase): - def setUp(self): self.c1 = Cluster([NODE]) self.c1.start() @@ -28,7 +28,8 @@ class TestDouble(unittest.TestCase): self.c1.shutdown() self.c2.shutdown() - @unittest.skip("Since RabbitMQ does not support queue deletion, you need to do this manually") + @unittest.skip( + "Since RabbitMQ does not support queue deletion, you need to do this manually") def test_ccn(self): """ Will consumer cancel itself after Consumer Cancel Notification? @@ -44,7 +45,7 @@ class TestDouble(unittest.TestCase): con1, fut1 = self.c1.consume(q1) fut1.result() -# self.c2.delete_queue(q1) #.result() + # self.c2.delete_queue(q1) #.result() time.sleep(30) self.assertTrue(con1.cancelled) @@ -57,7 +58,8 @@ class TestDouble(unittest.TestCase): fut.result() try: - con2, fut2 = self.c2.consume(q, fail_on_first_time_resource_locked=True) + con2, fut2 = self.c2.consume(q, + fail_on_first_time_resource_locked=True) fut2.result() except AMQPError as e: self.assertEquals(e.reply_code, RESOURCE_LOCKED) diff --git a/tests/test_clustering/test_exchanges.py b/tests/test_clustering/test_exchanges.py index 1a6e7a83f8e216fc5a163bd0168f82e4f678ccdc..65b028768191a656efcfd985a71f567ceb09fb77 100644 --- a/tests/test_clustering/test_exchanges.py +++ b/tests/test_clustering/test_exchanges.py @@ -3,12 +3,13 @@ from __future__ import print_function, absolute_import, division import six import unittest import time, logging, threading -from coolamqp.objects import Message, MessageProperties, NodeDefinition, Queue, ReceivedMessage, Exchange +from coolamqp.objects import Message, MessageProperties, NodeDefinition, Queue, \ + ReceivedMessage, Exchange from coolamqp.clustering import Cluster, MessageReceived, NothingMuch from coolamqp.exceptions import AMQPError import time -#todo handle bad auth +# todo handle bad auth NODE = NodeDefinition('127.0.0.1', 'guest', 'guest', heartbeat=20) logging.basicConfig(level=logging.DEBUG) @@ -28,8 +29,10 @@ class TestExchanges(unittest.TestCase): def test_fanout(self): x = Exchange(u'jola', type='direct', auto_delete=True) - c1, f1 = self.c.consume(Queue('one', exchange=x, exclusive=True), no_ack=True) - c2, f2 = self.c.consume(Queue('two', exchange=x, exclusive=True), no_ack=True) + c1, f1 = self.c.consume(Queue('one', exchange=x, exclusive=True), + no_ack=True) + c2, f2 = self.c.consume(Queue('two', exchange=x, exclusive=True), + no_ack=True) f1.result() f2.result() @@ -39,9 +42,3 @@ class TestExchanges(unittest.TestCase): self.assertIsInstance(self.c.drain(2), MessageReceived) self.assertIsInstance(self.c.drain(2), MessageReceived) self.assertIsInstance(self.c.drain(2), NothingMuch) - - - - - - diff --git a/tests/test_clustering/test_things.py b/tests/test_clustering/test_things.py index e158e0406194101802f96504a6ce9ef93612f33f..061bf436a2a81027d684e321f97dfe6e9a34d15a 100644 --- a/tests/test_clustering/test_things.py +++ b/tests/test_clustering/test_things.py @@ -4,19 +4,22 @@ from __future__ import print_function, absolute_import, division import six import unittest import time, logging, threading, monotonic, warnings -from coolamqp.objects import Message, MessageProperties, NodeDefinition, Queue, ReceivedMessage, Exchange +from coolamqp.objects import Message, MessageProperties, NodeDefinition, Queue, \ + ReceivedMessage, Exchange from coolamqp.clustering import Cluster, MessageReceived, NothingMuch import time + NODE = NodeDefinition('127.0.0.1', 'guest', 'guest', heartbeat=20) logging.basicConfig(level=logging.DEBUG) class TestConnecting(unittest.TestCase): - def test_on_fail(self): q = {'failed': False} - c = Cluster(NodeDefinition('127.0.0.1', 'xguest', 'xguest', heartbeat=20), on_fail=lambda: q.update(failed=True)) + c = Cluster( + NodeDefinition('127.0.0.1', 'xguest', 'xguest', heartbeat=20), + on_fail=lambda: q.update(failed=True)) c.start() time.sleep(5) c.shutdown() @@ -54,7 +57,7 @@ class TestConnecting(unittest.TestCase): user='guest', password='guest') - self.assertEquals(node.virtual_host, '/') # default + self.assertEquals(node.virtual_host, '/') # default def test_amqpconnstring_port(self): node = NodeDefinition('amqp://lol:lol@lol:4123/vhost') diff --git a/tests/test_exceptions.py b/tests/test_exceptions.py index 516ff965e963fb5e4feaf50475f7b0d2077122ea..33c11786d5aec6ad818b54e9dd2485671e723383 100644 --- a/tests/test_exceptions.py +++ b/tests/test_exceptions.py @@ -13,4 +13,3 @@ class TestExcs(unittest.TestCase): self.assertTrue(u'100' in str(e)) self.assertTrue(u'wtf' in str(e)) self.assertTrue(repr(e).startswith(u'AMQPError')) - diff --git a/tests/test_framing/test_compilation.py b/tests/test_framing/test_compilation.py index 51840518a40453d0bbbc9b88a13e6fec9d9f4e09..14d8bc8042f662a23fccf2d1f1660ed435cdf335 100644 --- a/tests/test_framing/test_compilation.py +++ b/tests/test_framing/test_compilation.py @@ -1,11 +1,12 @@ # coding=UTF-8 from __future__ import print_function, absolute_import, division -import six + import unittest class TestCompilation(unittest.TestCase): def test_comp(self): - from coolamqp.framing.compilation.compile_definitions import compile_definitions - compile_definitions(xml_file='resources/amqp0-9-1.extended.xml', out_file='/tmp/definitions.py') - + from compile_definitions import \ + compile_definitions + compile_definitions(xml_file='resources/amqp0-9-1.extended.xml', + out_file='/tmp/definitions.py') diff --git a/tests/test_objects.py b/tests/test_objects.py index e3a109d0ef84031ec3b61bed2fbebc59d73a8f50..f7e5569d0aee2945218cc2c03f6109420aabc914 100644 --- a/tests/test_objects.py +++ b/tests/test_objects.py @@ -10,7 +10,6 @@ from coolamqp.objects import NodeDefinition, MessageProperties class TestObjects(unittest.TestCase): def test_node_definition_from_amqp(self): - n1 = NodeDefinition(u'amqp://ala:ma@kota/psa') self.assertEquals(n1.user, u'ala') diff --git a/tests/utils.py b/tests/utils.py index 422c366707b99a82d48c9ffda46155bbf50a5938..17481f70a2f76883c6ca007f735b1f8d409af23f 100644 --- a/tests/utils.py +++ b/tests/utils.py @@ -6,7 +6,8 @@ import socket import collections import monotonic -from coolamqp import Cluster, ClusterNode, ConnectionUp, ConnectionDown, ConnectionUp, ConsumerCancelled +from coolamqp import Cluster, ClusterNode, ConnectionUp, ConnectionDown, \ + ConnectionUp, ConsumerCancelled from coolamqp.backends.base import AMQPBackend, ConnectionFailedError @@ -21,7 +22,7 @@ class CoolAMQPTestCase(unittest.TestCase): Base class for all CoolAMQP tests. Creates na AMQP connection, provides methods for easy interfacing, and other utils. """ - INIT_AMQP = True # override on child classes + INIT_AMQP = True # override on child classes def setUp(self): if self.INIT_AMQP: @@ -50,7 +51,7 @@ class CoolAMQPTestCase(unittest.TestCase): if type(q) in types: types.remove(type(q)) if len(types) > 0: - self.fail('Not found %s' % (''.join(map(str, types)), )) + self.fail('Not found %s' % (''.join(map(str, types)),)) def drainTo(self, type_, timeout, forbidden=[ConsumerCancelled]): """ @@ -72,7 +73,7 @@ class CoolAMQPTestCase(unittest.TestCase): q = self.amqp.drain(1) if isinstance(q, type_): return q - self.fail('Did not find %s' % (type_, )) + self.fail('Did not find %s' % (type_,)) def takes_less_than(self, max_time): """ @@ -87,14 +88,14 @@ class CoolAMQPTestCase(unittest.TestCase): return TakesLessThanCM(self, max_time) # ======failures - def single_fail_amqp(self): # insert single failure + def single_fail_amqp(self): # insert single failure sock = self.amqp.thread.backend.channel.connection.transport.sock self.amqp.thread.backend.channel.connection.transport.sock = FailbowlSocket() self.amqp.thread.backend.channel.connection = None # 'connection already closed' or sth like that sock.close() - def fail_amqp(self): # BROKER DEAD: SWITCH ON + def fail_amqp(self): # BROKER DEAD: SWITCH ON self.old_backend = self.amqp.backend self.amqp.backend = FailbowlBackend @@ -104,15 +105,15 @@ class CoolAMQPTestCase(unittest.TestCase): del self.old_backend def restart_rmq(self): # simulate a broker restart - self.fail_amqp() - self.single_fail_amqp() - time.sleep(3) - self.unfail_amqp() + self.fail_amqp() + self.single_fail_amqp() + time.sleep(3) + self.unfail_amqp() - self.drainTo([ConnectionDown, ConnectionUp], [5, 20]) + self.drainTo([ConnectionDown, ConnectionUp], [5, 20]) def new_amqp_connection(self, consume_connectionup=True): - return AMQPConnectionCM(self, consume_connectionup=consume_connectionup) + return AMQPConnectionCM(self, consume_connectionup=consume_connectionup) class TakesLessThanCM(object): @@ -122,7 +123,7 @@ class TakesLessThanCM(object): def __enter__(self, testCase, max_time): self.started_at = time.time() - return lambda: time.time() - self.started_at > self.max_time # is_late + return lambda: time.time() - self.started_at > self.max_time # is_late def __exit__(self, tp, v, tb): self.test.assertLess(time.time() - self.started_at, self.max_time) @@ -138,6 +139,7 @@ class AMQPConnectionCM(object): amqp2.consume(...) """ + def __init__(self, testCase, consume_connectionup): self.test = testCase self.consume_connectionup = consume_connectionup @@ -162,7 +164,7 @@ class FailbowlBackend(AMQPBackend): class FailbowlSocket(object): def __getattr__(self, item): def failbowl(*args, **kwargs): - time.sleep(1) # hang and fail + time.sleep(1) # hang and fail raise socket.error def sleeper(*args, **kwargs): @@ -172,4 +174,3 @@ class FailbowlSocket(object): return sleeper else: return failbowl -