Merge remote-tracking branch 'upstream/master'
This commit is contained in:
commit
b41e2edc52
595
README.md
595
README.md
|
|
@ -1,27 +1,27 @@
|
|||
AMQP-CPP
|
||||
========
|
||||
|
||||
AMQP-CPP is a C++ library for communicating with a RabbitMQ message broker. The
|
||||
library can be used to parse incoming data from a RabbitMQ server, and to
|
||||
AMQP-CPP is a C++ library for communicating with a RabbitMQ message broker. The
|
||||
library can be used to parse incoming data from a RabbitMQ server, and to
|
||||
generate frames that can be sent to a RabbitMQ server.
|
||||
|
||||
Unlike all other AMQP libraries, this AMQP-CPP library does not make a connection to
|
||||
RabbitMQ by itself, nor does it create sockets and/or performs IO operations. As
|
||||
a user of this library, you first need to set up a socket connection
|
||||
to RabbitMQ by yourself, and implement a certain interface that you pass to the
|
||||
RabbitMQ by itself, nor does it create sockets and/or performs IO operations. As
|
||||
a user of this library, you first need to set up a socket connection
|
||||
to RabbitMQ by yourself, and implement a certain interface that you pass to the
|
||||
AMQP-CPP library and that the library will use for IO operations.
|
||||
|
||||
This architecture makes the library extremely flexible: it does not rely on
|
||||
operating system specific IO calls, and it can be easily integrated into any
|
||||
event loop. It is fully asynchronous and does not do any blocking (system) calls,
|
||||
event loop. It is fully asynchronous and does not do any blocking (system) calls,
|
||||
so it can be used in high performance applications without the need for threads.
|
||||
|
||||
|
||||
ABOUT
|
||||
=====
|
||||
|
||||
This library is created and maintained by Copernica (www.copernica.com), and is
|
||||
used inside the MailerQ (www.mailerq.com) application, MailerQ is a tool for
|
||||
This library is created and maintained by Copernica (www.copernica.com), and is
|
||||
used inside the MailerQ (www.mailerq.com) application, MailerQ is a tool for
|
||||
sending large volumes of email, using AMQP message queues.
|
||||
|
||||
|
||||
|
|
@ -42,34 +42,34 @@ class MyConnectionHandler : public AMQP::ConnectionHandler
|
|||
{
|
||||
/**
|
||||
* Method that is called by the AMQP library every time it has data
|
||||
* available that should be sent to RabbitMQ.
|
||||
* @param connection pointer to the main connection object
|
||||
* available that should be sent to RabbitMQ.
|
||||
* @param connection pointer to the main connection object
|
||||
* @param data memory buffer with the data that should be sent to RabbitMQ
|
||||
* @param size size of the buffer
|
||||
*/
|
||||
virtual void onData(AMQP::Connection *connection, const char *data, size_t size)
|
||||
{
|
||||
// @todo
|
||||
// @todo
|
||||
// Add your own implementation, for example by doing a call to the
|
||||
// send() system call. But be aware that the send() call may not
|
||||
// send all data at once, so you also need to take care of buffering
|
||||
// the bytes that could not immediately be sent, and try to send
|
||||
// the bytes that could not immediately be sent, and try to send
|
||||
// them again when the socket becomes writable again
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Method that is called by the AMQP library when the login attempt
|
||||
* succeeded. After this method has been called, the connection is ready
|
||||
* Method that is called by the AMQP library when the login attempt
|
||||
* succeeded. After this method has been called, the connection is ready
|
||||
* to use.
|
||||
* @param connection The connection that can now be used
|
||||
*/
|
||||
virtual void onConnected(Connection *connection)
|
||||
virtual void onConnected(AMQP::Connection *connection)
|
||||
{
|
||||
// @todo
|
||||
// add your own implementation, for example by creating a channel
|
||||
// add your own implementation, for example by creating a channel
|
||||
// instance, and start publishing or consuming
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Method that is called by the AMQP library when a fatal error occurs
|
||||
* on the connection, for example because data received from RabbitMQ
|
||||
|
|
@ -77,13 +77,24 @@ class MyConnectionHandler : public AMQP::ConnectionHandler
|
|||
* @param connection The connection on which the error occured
|
||||
* @param message A human readable error message
|
||||
*/
|
||||
virtual void onError(Connection *connection, const std::string &message)
|
||||
virtual void onError(AMQP::Connection *connection, const char *message)
|
||||
{
|
||||
// @todo
|
||||
// add your own implementation, for example by reporting the error
|
||||
// to the user of your program, log the error, and destruct the
|
||||
// to the user of your program, log the error, and destruct the
|
||||
// connection object because it is no longer in a usable state
|
||||
}
|
||||
|
||||
/**
|
||||
* Method that is called when the connection was closed. This is the
|
||||
* counter part of a call to Connection::close() and it confirms that the
|
||||
* connection was correctly closed.
|
||||
*
|
||||
* @param connection The connection that was closed and that is now unusable
|
||||
*/
|
||||
virtual void onClosed(AMQP::Connection *connection) {}
|
||||
|
||||
|
||||
};
|
||||
````
|
||||
After you've implemented the ConnectionHandler class, you can start using
|
||||
|
|
@ -108,18 +119,18 @@ channel.bindQueue("my-exchange", "my-queue");
|
|||
A number of remarks about the example above. First you may have noticed that we've
|
||||
created all objects on the stack. You are of course also free to create them
|
||||
on the heap with the C++ operator 'new'. That works just as well, and is in real
|
||||
life code probably more useful as you normally want to keep your handlers, connection
|
||||
life code probably more useful as you normally want to keep your handlers, connection
|
||||
and channel objects around for a much longer time.
|
||||
|
||||
But more importantly, you can see in the example above that we have created the
|
||||
channel object directly after we made the connection object, and we also
|
||||
But more importantly, you can see in the example above that we have created the
|
||||
channel object directly after we made the connection object, and we also
|
||||
started declaring exchanges and queues right away. However, under the hood, a handshake
|
||||
protocol is executed between the server and the client when the Connection
|
||||
object is first created. During this handshake procedure it is not permitted to send
|
||||
other instructions (like opening a channel or declaring a queue). It would therefore have been better
|
||||
if we had first waited for the connection to be ready (implement the MyConnectionHandler::onConnected() method),
|
||||
and create the channel object only then. But this is not strictly necessary.
|
||||
The methods that are called before the handshake is completed are cached by the
|
||||
other instructions (like opening a channel or declaring a queue). It would therefore have been better
|
||||
if we had first waited for the connection to be ready (implement the MyConnectionHandler::onConnected() method),
|
||||
and create the channel object only then. But this is not strictly necessary.
|
||||
The methods that are called before the handshake is completed are cached by the
|
||||
AMQP library and will be executed the moment the handshake is completed and the
|
||||
connection becomes ready for use.
|
||||
|
||||
|
|
@ -128,17 +139,17 @@ PARSING INCOMING DATA
|
|||
=====================
|
||||
|
||||
The ConnectionHandler class has a method onData() that is called by the library
|
||||
every time that it wants to send out data. We've explained that it is up to you to
|
||||
implement that method. But what about data in the other direction? How does the
|
||||
every time that it wants to send out data. We've explained that it is up to you to
|
||||
implement that method. But what about data in the other direction? How does the
|
||||
library receive data back from RabbitMQ?
|
||||
|
||||
As we've explained above, the AMQP-CPP library does not do any IO by itself
|
||||
and it is therefore of course also not possible for the library to receive data from
|
||||
a socket. It is again up to you to do this. If, for example, you notice in your
|
||||
event loop that the socket that is connected with the RabbitMQ server becomes
|
||||
readable, you should read out that data (for example by using the recv() system
|
||||
call), and pass the received bytes to the AMQP-CPP library. This is done by
|
||||
calling the parse() method in the Connection object.
|
||||
The AMQP-CPP library does not do any IO by itself and it is therefore of course
|
||||
also not possible for the library to receive data from a socket. It is again up
|
||||
to you to do this. If, for example, you notice in your event loop that the socket
|
||||
that is connected with the RabbitMQ server becomes readable, you should read out
|
||||
that socket (for example by using the recv() system call), and pass the received
|
||||
bytes to the AMQP-CPP library. This is done by calling the parse() method in the
|
||||
Connection object.
|
||||
|
||||
The Connection::parse() method gets two parameters, a pointer to a buffer of
|
||||
data received from RabbitMQ, and a parameter that holds the size of this buffer.
|
||||
|
|
@ -147,15 +158,15 @@ The code snippet below comes from the Connection.h C++ header file.
|
|||
````c++
|
||||
/**
|
||||
* Parse data that was recevied from RabbitMQ
|
||||
*
|
||||
* Every time that data comes in from RabbitMQ, you should call this method to parse
|
||||
* the incoming data, and let it handle by the AMQP-CPP library. This method returns the number
|
||||
* of bytes that were processed.
|
||||
*
|
||||
* If not all bytes could be processed because it only contained a partial frame, you should
|
||||
* call this same method later on when more data is available. The AMQP-CPP library does not do
|
||||
* any buffering, so it is up to the caller to ensure that the old data is also passed in that
|
||||
* later call.
|
||||
* Every time that data comes in from RabbitMQ, you should call this method to parse
|
||||
* the incoming data, and let it handle by the AMQP-CPP library. This method returns
|
||||
* the number of bytes that were processed.
|
||||
*
|
||||
* If not all bytes could be processed because it only contained a partial frame,
|
||||
* you should call this same method later on when more data is available. The
|
||||
* AMQP-CPP library does not do any buffering, so it is up to the caller to ensure
|
||||
* that the old data is also passed in that later call.
|
||||
*
|
||||
* @param buffer buffer to decode
|
||||
* @param size size of the buffer to decode
|
||||
|
|
@ -167,39 +178,123 @@ size_t parse(char *buffer, size_t size)
|
|||
}
|
||||
````
|
||||
|
||||
You should do all the book keeping for the buffer yourselves. If you for example
|
||||
call the Connection::parse() method with a buffer of 100 bytes, and the method
|
||||
returns that only 60 bytes were processed, you should later call the method again,
|
||||
with a buffer filled with the remaining 40 bytes. If the method returns 0, you should
|
||||
make a new call to parse() when more data is available, with a buffer that contains
|
||||
both the old data, and the new data.
|
||||
|
||||
|
||||
CHANNELS
|
||||
========
|
||||
|
||||
In the example you saw that we created a channel object. A channel is a virtual
|
||||
connection over a single TCP connection, and it is possible to create many channels
|
||||
that all use the same TCP connection.
|
||||
In the example we created a channel object. A channel is a virtual connection over
|
||||
a single TCP connection, and it is possible to create many channels that all use
|
||||
the same TCP connection.
|
||||
|
||||
AMQP instructions are always sent over a channel, so before you can send the first
|
||||
command to the RabbitMQ server, you first need a channel object. The channel
|
||||
AMQP instructions are always sent over a channel, so before you can send the first
|
||||
command to the RabbitMQ server, you first need a channel object. The channel
|
||||
object has many methods to send instructions to the RabbitMQ server. It for
|
||||
example has methods to declare queues and exchanges, to bind and unbind them,
|
||||
and to publish and consume messages. You can best take a look at the channel.h
|
||||
C++ header file for a list of all available methods. Every method in it is well
|
||||
example has methods to declare queues and exchanges, to bind and unbind them,
|
||||
and to publish and consume messages. You can best take a look at the channel.h
|
||||
C++ header file for a list of all available methods. Every method in it is well
|
||||
documented.
|
||||
|
||||
The constructor of the Channel object accepts two parameters: the connection object,
|
||||
and a pointer to a ChannelHandler object. In the example we did
|
||||
not use this ChannelHandler object. However, in normal circumstances, you should
|
||||
always pass a pointer to a ChannelHandler object every time you construct a channel.
|
||||
The constructor of the Channel object accepts one parameter: the connection object.
|
||||
Unlike the connection it does not accept a handler. Instead of a handler object,
|
||||
(almost) every method of the Channel class returns an instance of the 'Deferred'
|
||||
class. This object can be used to install handlers that will be called in case
|
||||
of success or failure.
|
||||
|
||||
Just like the ConnectionHandler class, the ChannelHandler class is a base class that
|
||||
you can extend to override the virtual methods you need. The AMQP library
|
||||
will call these methods to inform you that an operation on the channel has succeeded
|
||||
or has failed.
|
||||
|
||||
For example, if you call the channel.declareQueue() method, the AMQP-CPP library will
|
||||
send a message to the RabbitMQ message broker to ask it to declare the
|
||||
For example, if you call the channel.declareExchange() method, the AMQP-CPP library
|
||||
will send a message to the RabbitMQ message broker to ask it to declare the
|
||||
queue. However, because all operations in the library are asynchronous, the
|
||||
declareQueue() method immediately returns 'true', although it is at that time
|
||||
not yet known whether the queue was correctly declared. Only after a while,
|
||||
after the instruction has reached the server, and the confirmation from the server
|
||||
has been sent back to the client, your ChannelHandler::onQueueDeclared()
|
||||
method will be called to inform you that the operation was succesful.
|
||||
declareExchange() method can not return 'true' or 'false' to inform you whether
|
||||
the operation was succesful or not. Only after a while, after the instruction
|
||||
has reached the RabbitMQ server, and the confirmation from the server has been
|
||||
sent back to the client, the library can report the result of the declareExchange()
|
||||
call.
|
||||
|
||||
To prevent any blocking calls, the channel.declareExchange() method returns a
|
||||
'Deferred' result object, on which you can set callback functions that will be
|
||||
called when the operation succeeds or fails.
|
||||
|
||||
````c++
|
||||
// create a channel
|
||||
Channel myChannel(&connection);
|
||||
|
||||
// declare an exchange, and install callbacks for success and failure
|
||||
myChannel.declareExchange("my-exchange")
|
||||
|
||||
.onSuccess([]() {
|
||||
// by now the exchange is created
|
||||
})
|
||||
|
||||
.onError([](const char *message) {
|
||||
// something went wrong creating the exchange
|
||||
});
|
||||
````
|
||||
|
||||
As you can see in the above example, we call the declareExchange() method, and
|
||||
treat its return value as an object, on which we immediately install a lambda
|
||||
callback function to handle success, and to handle failure.
|
||||
|
||||
Installing the callback methods is optional. If you're not interested in the
|
||||
result of an operation, you do not have to install a callback for it. Next
|
||||
to the onSuccess() and onError() callbacks that can be installed, you can also
|
||||
install a onFinalize() method that gets called directly after the onSuccess()
|
||||
and onError() methods, and that can be used to set a callback that should
|
||||
run in either case: when the operation succeeds or when it fails.
|
||||
|
||||
The signature for the onError() method is always the same: it gets one parameter
|
||||
with a human readable error message. The onSuccess() function has a different
|
||||
signature depending on the method that you call. Most onSuccess() functions
|
||||
(like the one we showed for the declareExchange() method) do not get any
|
||||
parameters at all. Some specific onSuccess callbacks receive extra parameters
|
||||
with additional information.
|
||||
|
||||
|
||||
CHANNEL CALLBACKS
|
||||
=================
|
||||
|
||||
As explained, most channel methods return a 'Deferred' object on which you can
|
||||
install callbacks using the Deferred::onError() and Deferred::onSuccess() methods.
|
||||
|
||||
The callbacks that you install on a Deferred object, only apply to one specific
|
||||
operation. If you want to install a generic error callback for the entire channel,
|
||||
you can so so by using the Channel::onError() method. Next to the Channel::onError()
|
||||
method, you can also install a callback to be notified when the channel is ready
|
||||
for sending the first instruction to RabbitMQ.
|
||||
|
||||
````c++
|
||||
// create a channel
|
||||
Channel myChannel(&connection);
|
||||
|
||||
// install a generic channel-error handler that will be called for every
|
||||
// error that occurs on the channel
|
||||
myChannel.onError([](const char *message) {
|
||||
|
||||
// report error
|
||||
std::cout << "channel error: " << message << std::endl;
|
||||
});
|
||||
|
||||
// install a generic callback that will be called when the channel is ready
|
||||
// for sending the first instruction
|
||||
myChannel.onReady([]() {
|
||||
|
||||
// send the first instructions (like publishing messages)
|
||||
});
|
||||
````
|
||||
|
||||
In theory, you should wait for the onReady() callback to be called before you
|
||||
send any other instructions over the channel. In practice however, the AMQP library
|
||||
caches all instructions that were sent too early, so that you can use the
|
||||
channel object right after it was constructed.
|
||||
|
||||
|
||||
CHANNEL ERRORS
|
||||
==============
|
||||
|
||||
It is important to realize that any error that occurs on a channel, will
|
||||
invalidate the entire channel,. including all subsequent instructions that
|
||||
|
|
@ -207,76 +302,32 @@ were already sent over it. This means that if you call multiple methods in a row
|
|||
and the first method fails, all subsequent methods will not be executed either:
|
||||
|
||||
````c++
|
||||
Channel myChannel(connection, &myHandler);
|
||||
Channel myChannel(&connection);
|
||||
myChannel.declareQueue("my-queue");
|
||||
myChannel.declareExchange("my-exchange");
|
||||
````
|
||||
|
||||
If the first declareQueue() call fails in the example above, your ChannelHandler::onError()
|
||||
method will be called after a while to report this failure. And although the
|
||||
second instruction to declare an exchange has already been sent to the server, it will be
|
||||
ignored because the channel was already in an invalid state after the first failure.
|
||||
If the first declareQueue() call fails in the example above, the second
|
||||
myChannel.declareExchange() method will not be executed, even when this
|
||||
second instruction was already sent to the server. The second instruction will be
|
||||
ignored by the RabbitMQ server because the channel was already in an invalid
|
||||
state after the first failure.
|
||||
|
||||
You can overcome this by using multiple channels:
|
||||
|
||||
````c++
|
||||
Channel channel1(connection, &myHandler);
|
||||
Channel channel2(connection, &myHandler);
|
||||
Channel channel1(&connection);
|
||||
Channel channel2(&connection);
|
||||
channel1.declareQueue("my-queue");
|
||||
channel2.declareQueue("my-exchange");
|
||||
channel2.declareExchange("my-exchange");
|
||||
````
|
||||
|
||||
Now, if an error occurs with declaring the queue, it will not have
|
||||
consequences for the other call. But this comes at a small price:
|
||||
setting up the extra channel requires and extra instruction to be sent to the
|
||||
RabbitMQ server, so some extra bytes are sent over the network,
|
||||
and some additional resources in both the client application and the
|
||||
RabbitMQ server are used (although this is all very limited).
|
||||
Now, if an error occurs with declaring the queue, it will not have consequences
|
||||
for the other call. But this comes at a small price: setting up the extra channel
|
||||
requires and extra instruction to be sent to the RabbitMQ server, so some extra
|
||||
bytes are sent over the network, and some additional resources in both the client
|
||||
application and the RabbitMQ server are used (although this is all very limited).
|
||||
|
||||
Let's get back to the ChannelHandler class. It has many methods that you can
|
||||
implement - all of which are optional. All methods in it have a default empty implementation,
|
||||
so you can choose to only override the ones that you are interested in. When you're
|
||||
writing a consumer application for example, you probably are only interested in
|
||||
errors that occur, and in incoming messages:
|
||||
|
||||
````c++
|
||||
#include <amqpcpp.h>
|
||||
|
||||
class MyChannelHandler : public AMQP::ChannelHandler
|
||||
{
|
||||
public:
|
||||
/**
|
||||
* Method that is called when an error occurs on the channel, and
|
||||
* the channel ends up in an error state
|
||||
* @param channel the channel on which the error occured
|
||||
* @param message human readable error message
|
||||
*/
|
||||
virtual void onError(AMQP::Channel *channel, const std::string &message)
|
||||
{
|
||||
// @todo
|
||||
// do something with the error message (like reporting it to the end-user)
|
||||
// and destruct the channel object because it now no longer is usable
|
||||
}
|
||||
|
||||
/**
|
||||
* Method that is called when a message has been received on a channel
|
||||
* This message will be called for every message that is received after
|
||||
* you started consuming. Make sure you acknowledge the messages when its
|
||||
* safe to remove them from RabbitMQ (unless you set no-ack option when you
|
||||
* started the consumer)
|
||||
* @param channel the channel on which the consumer was started
|
||||
* @param message the consumed message
|
||||
* @param deliveryTag the delivery tag, you need this to acknowledge the message
|
||||
* @param consumerTag the consumer identifier that was used to retrieve this message
|
||||
* @param redelivered is this a redelivered message?
|
||||
*/
|
||||
virtual void onReceived(AMQP::Channel *channel, const AMQP::Message &message, uint64_t deliveryTag, const std::string &consumerTag, bool redelivered)
|
||||
{
|
||||
// @todo
|
||||
// do something with the incoming message
|
||||
}
|
||||
};
|
||||
````
|
||||
|
||||
FLAGS AND TABLES
|
||||
================
|
||||
|
|
@ -290,47 +341,64 @@ tables are used by many methods.
|
|||
````c++
|
||||
/**
|
||||
* Declare a queue
|
||||
*
|
||||
*
|
||||
* If you do not supply a name, a name will be assigned by the server.
|
||||
*
|
||||
*
|
||||
* The flags can be a combination of the following values:
|
||||
*
|
||||
*
|
||||
* - durable queue survives a broker restart
|
||||
* - autodelete queue is automatically removed when all connected consumers are gone
|
||||
* - passive only check if the queue exist
|
||||
* - exclusive the queue only exists for this connection, and is automatically removed when connection is gone
|
||||
*
|
||||
*
|
||||
* @param name name of the queue
|
||||
* @param flags combination of flags
|
||||
* @param arguments optional arguments
|
||||
*/
|
||||
bool declareQueue(const std::string &name, int flags, const AMQP::Table &arguments);
|
||||
bool declareQueue(const std::string &name, const AMQP::Table &arguments);
|
||||
bool declareQueue(const std::string &name, int flags = 0);
|
||||
bool declareQueue(int flags, const AMQP::Table &arguments);
|
||||
bool declareQueue(const AMQP::Table &arguments);
|
||||
bool declareQueue(int flags = 0);
|
||||
DeferredQueue &declareQueue(const std::string &name, int flags, const Table &arguments);
|
||||
DeferredQueue &declareQueue(const std::string &name, const Table &arguments);
|
||||
DeferredQueue &declareQueue(const std::string &name, int flags = 0);
|
||||
DeferredQueue &declareQueue(int flags, const Table &arguments);
|
||||
DeferredQueue &declareQueue(const Table &arguments);
|
||||
DeferredQueue &declareQueue(int flags = 0);
|
||||
````
|
||||
|
||||
As you can see, the method comes in many forms, and it is up to you to choose
|
||||
the one that is most appropriate. We now take a look at the most complete
|
||||
the one that is most appropriate. We now take a look at the most complete
|
||||
one, the method with three parameters.
|
||||
|
||||
Many methods in the Channel class accept an integer parameter named 'flags'.
|
||||
This is a variable in which you can set a number of options, by summing up
|
||||
all the options that are described in the documentation. If you for example
|
||||
want to create a durable, auto-deleted queue, you can pass in the value
|
||||
AMQP::durable + AMQP::autodelete.
|
||||
All above methods returns a 'DeferredQueue' object. The DeferredQueue class
|
||||
extends from the AMQP::Deferred class and allows you to install a more powerful
|
||||
onSuccess() callback function. The 'onSuccess' method for the declareQueue()
|
||||
function gets three arguments:
|
||||
|
||||
````c++
|
||||
// create a custom callback
|
||||
auto callback = [](const std::string &name, int msgcount, int consumercount) {
|
||||
|
||||
// @todo add your own implementation
|
||||
|
||||
}
|
||||
|
||||
// declare the queue, and install the callback that is called on success
|
||||
channel.declareQueue("myQueue").onSuccess(callback);
|
||||
````
|
||||
|
||||
Just like many others methods in the Channel class, the declareQueue() method
|
||||
accept an integer parameter named 'flags'. This is a variable in which you can
|
||||
set method-specific options, by summing up all the options that are described in
|
||||
the documentation above the method. If you for example want to create a durable,
|
||||
auto-deleted queue, you can pass in the value AMQP::durable + AMQP::autodelete.
|
||||
|
||||
The declareQueue() method also accepts a parameter named 'arguments', which is of type
|
||||
Table. This Table object can be used as an associative array to send additional
|
||||
options to RabbitMQ, that are often custom RabbitMQ extensions to the AMQP
|
||||
options to RabbitMQ, that are often custom RabbitMQ extensions to the AMQP
|
||||
standard. For a list of all supported arguments, take a look at the documentation
|
||||
on the RabbitMQ website. With every new RabbitMQ release more features, and
|
||||
supported arguments are added.
|
||||
|
||||
The Table class is a very powerful class that enables you to build
|
||||
complicated, deeply nested structures full of strings, arrays and even other
|
||||
The Table class is a very powerful class that enables you to build
|
||||
complicated, deeply nested structures full of strings, arrays and even other
|
||||
tables. In reality, you only need strings and integers.
|
||||
|
||||
````c++
|
||||
|
|
@ -353,14 +421,14 @@ exchange to publish to, the routing key to use, and the actual message that
|
|||
you're publishing - all these parameters are standard C++ strings.
|
||||
|
||||
More extended versions of the publish() method exist that accept additional
|
||||
arguments, and that enable you to publish entire Envelope objects, which are
|
||||
objects that contain the message plus a list of optional meta information like
|
||||
the content-type, content-encoding, priority, expire time and more. None of these
|
||||
meta fields are interpreted by this library, and also the RabbitMQ ignores most
|
||||
of them, but the AMQP protocol defines them, and they are free for you to use.
|
||||
For an extensive list of the fields that are supported, take a look at the MetaData.h
|
||||
header file (MetaData is the base class for Envelope). You should also check the
|
||||
RabbitMQ documentation to find out if an envelope header is interpreted by the
|
||||
arguments, and that enable you to publish entire Envelope objects. An envelope
|
||||
is an object that contains the message plus a list of optional meta information like
|
||||
the content-type, content-encoding, priority, expire time and more. None of these
|
||||
meta fields are interpreted by this library, and also the RabbitMQ ignores most
|
||||
of them, but the AMQP protocol defines them, and they are free for you to use.
|
||||
For an extensive list of the fields that are supported, take a look at the MetaData.h
|
||||
header file (MetaData is the base class for Envelope). You should also check the
|
||||
RabbitMQ documentation to find out if an envelope header is interpreted by the
|
||||
RabbitMQ server (at the time of this writing, only the expire time is being used).
|
||||
|
||||
The following snippet is copied from the Channel.h header file and lists all
|
||||
|
|
@ -370,17 +438,20 @@ in almost any form:
|
|||
````c++
|
||||
/**
|
||||
* Publish a message to an exchange
|
||||
*
|
||||
*
|
||||
* The following flags can be used
|
||||
*
|
||||
* - mandatory if set, an unroutable message will be reported to the channel handler with the onReturned method
|
||||
* - immediate if set, a message that could not immediately be consumed is returned to the onReturned method
|
||||
*
|
||||
*
|
||||
* - mandatory if set, an unroutable message will be reported to the
|
||||
* channel handler with the onReturned method
|
||||
*
|
||||
* - immediate if set, a message that could not immediately be consumed
|
||||
* is returned to the onReturned method
|
||||
*
|
||||
* If either of the two flags is set, and the message could not immediately
|
||||
* be published, the message is returned by the server to the client. If you
|
||||
* want to catch such returned messages, you need to implement the
|
||||
* want to catch such returned messages, you need to implement the
|
||||
* ChannelHandler::onReturned() method.
|
||||
*
|
||||
*
|
||||
* @param exchange the exchange to publish to
|
||||
* @param routingkey the routing key
|
||||
* @param flags optional flags (see above)
|
||||
|
|
@ -396,18 +467,40 @@ bool publish(const std::string &exchange, const std::string &routingKey, int fla
|
|||
bool publish(const std::string &exchange, const std::string &routingKey, const char *message, size_t size);
|
||||
````
|
||||
|
||||
Published messages are normally not confirmed by the server, hence there is no
|
||||
ChannelHandler::onPublished() method that you can implement to find out if
|
||||
a message was correctly received by the server. That's by design in the
|
||||
AMQP protocol, to not unnecessarily slow down message publishing. As long
|
||||
as no error is reported via the ChannelHandler::onError() method, you can safely
|
||||
Published messages are normally not confirmed by the server, and the RabbitMQ
|
||||
will not send a report back to inform us whether the message was succesfully
|
||||
published or not. Therefore the publish method does also not return a Deferred
|
||||
object.
|
||||
|
||||
As long as no error is reported via the Channel::onError() method, you can safely
|
||||
assume that your messages were delivered.
|
||||
|
||||
If you use the flags parameter to set either the option 'mandatory' or
|
||||
'immediate', a message that could not be routed or directly delivered to a consumer
|
||||
is sent back to the client, and ends up in the ChannelHandler::onReturned()
|
||||
method. At the time of this writing however, the 'immediate' option does not
|
||||
seem to be supported by RabbitMQ.
|
||||
This can of course be a problem when you are publishing many messages. If you get
|
||||
an error halfway through there is no way to know for sure how many messages made
|
||||
it to the broker and how many should be republished. If this is important, you can
|
||||
wrap the publish commands inside a transaction. In this case, if an error occurs,
|
||||
the transaction is automatically rolled back by RabbitMQ and none of the messages
|
||||
are actually published.
|
||||
|
||||
````c++
|
||||
// start a transaction
|
||||
channel.startTransaction();
|
||||
|
||||
// publish a number of messages
|
||||
channel.publish("my-exchange", "my-key", "my first message");
|
||||
channel.publish("my-exchange", "my-key", "another message");
|
||||
|
||||
// commit the transactions, and set up callbacks that are called when
|
||||
// the transaction was successful or not
|
||||
channel.commitTransaction()
|
||||
.onSuccess([]() {
|
||||
// all messages were successfully published
|
||||
})
|
||||
.onError([]() {
|
||||
// none of the messages were published
|
||||
// now we have to do it all over again
|
||||
});
|
||||
````
|
||||
|
||||
|
||||
CONSUMING MESSAGES
|
||||
|
|
@ -421,108 +514,117 @@ Just like the publish() method that we just described, the consume() method also
|
|||
comes in many forms. The first parameter is always the name of the queue you like
|
||||
to consume from. The subsequent parameters are an optional consumer tag, flags and
|
||||
a table with custom arguments. The first additional parameter, the consumer tag,
|
||||
is nothing more than a string identifier that will be passed with every consumed message.
|
||||
This can be useful if you call the consume() methods a number of times to consume
|
||||
from multiple queues, and you would like to know from which consume call the received messages came.
|
||||
is nothing more than a string identifier that you can use when you want to stop
|
||||
consuming.
|
||||
|
||||
The full documentation from the C++ Channel.h headerfile looks like this:
|
||||
|
||||
````c++
|
||||
/**
|
||||
* Tell the RabbitMQ server that we're ready to consume messages
|
||||
*
|
||||
*
|
||||
* After this method is called, RabbitMQ starts delivering messages to the client
|
||||
* application. The consume tag is a string identifier that will be passed to
|
||||
* each received message, so that you can associate incoming messages with a
|
||||
* each received message, so that you can associate incoming messages with a
|
||||
* consumer. If you do not specify a consumer tag, the server will assign one
|
||||
* for you.
|
||||
*
|
||||
*
|
||||
* The following flags are supported:
|
||||
*
|
||||
* - nolocal if set, messages published on this channel are not also consumed
|
||||
* - noack if set, consumed messages do not have to be acked, this happens automatically
|
||||
* - exclusive request exclusive access, only this consumer can access the queue
|
||||
* - nowait the server does not have to send a response back that consuming is active
|
||||
*
|
||||
* The method ChannelHandler::onConsumerStarted() will be called when the
|
||||
* consumer has started (unless the nowait option was set, in which case
|
||||
* no confirmation method is called)
|
||||
*
|
||||
*
|
||||
* - nolocal if set, messages published on this channel are
|
||||
* not also consumed
|
||||
*
|
||||
* - noack if set, consumed messages do not have to be acked,
|
||||
* this happens automatically
|
||||
*
|
||||
* - exclusive request exclusive access, only this consumer can
|
||||
* access the queue
|
||||
*
|
||||
* The method ChannelHandler::onConsumerStarted() will be called when the
|
||||
* consumer has started.
|
||||
*
|
||||
* @param queue the queue from which you want to consume
|
||||
* @param tag a consumer tag that will be associated with this consume operation
|
||||
* @param flags additional flags
|
||||
* @param arguments additional arguments
|
||||
* @return bool
|
||||
*/
|
||||
bool consume(const std::string &queue, const std::string &tag, int flags, const AMQP::Table &arguments);
|
||||
bool consume(const std::string &queue, const std::string &tag, int flags = 0);
|
||||
bool consume(const std::string &queue, const std::string &tag, const AMQP::Table &arguments);
|
||||
bool consume(const std::string &queue, int flags, const AMQP::Table &arguments);
|
||||
bool consume(const std::string &queue, int flags = 0);
|
||||
bool consume(const std::string &queue, const AMQP::Table &arguments);
|
||||
DeferredConsumer &consume(const std::string &queue, const std::string &tag, int flags, const AMQP::Table &arguments);
|
||||
DeferredConsumer &consume(const std::string &queue, const std::string &tag, int flags = 0);
|
||||
DeferredConsumer &consume(const std::string &queue, const std::string &tag, const AMQP::Table &arguments);
|
||||
DeferredConsumer &consume(const std::string &queue, int flags, const AMQP::Table &arguments);
|
||||
DeferredConsumer &consume(const std::string &queue, int flags = 0);
|
||||
DeferredConsumer &consume(const std::string &queue, const AMQP::Table &arguments);
|
||||
````
|
||||
|
||||
In your ChannelHandler you can override the onConsumerStarted() method, that will be
|
||||
first called before any messages are sent to you. Most users choose not to override this
|
||||
method, because there is not much useful to do in it. After the consumer has started, however,
|
||||
messages are starting to be sent from RabbitMQ to your client application, and they are all
|
||||
passed to the ChannelHandler::onReceived() method. This method is thus very important to implement.
|
||||
As you can see, the consume method returns a DeferredConsumer. This object is a
|
||||
regular Deferred, with additions. The onSuccess() method of a
|
||||
DeferredConsumer is slightly different than the onSuccess() method of a regular
|
||||
Deferred object: one extra parameter will be supplied to your callback function
|
||||
with the consumer tag.
|
||||
|
||||
The onSuccess() callback will be called when the consume operation _has started_,
|
||||
but not when messages are actually consumed. For this you will have to install
|
||||
a different callback, using the onReceived() method.
|
||||
|
||||
````c++
|
||||
class MyChannelHandler : public AMQP::ChannelHandler
|
||||
{
|
||||
/**
|
||||
* Method that is called when a message has been received on a channel
|
||||
* This message will be called for every message that is received after
|
||||
* you started consuming. Make sure you acknowledge the messages when its
|
||||
* safe to remove them from RabbitMQ (unless you set no-ack option when you
|
||||
* started the consumer)
|
||||
* @param channel the channel on which the consumer was started
|
||||
* @param message the consumed message
|
||||
* @param deliveryTag the delivery tag, you need this to acknowledge the message
|
||||
* @param consumerTag the consumer identifier that was used to retrieve this message
|
||||
* @param redelivered is this a redelivered message?
|
||||
*/
|
||||
virtual void onReceived(AMQP::Channel *channel, const AMQP::Message &message, uint64_t deliveryTag, const std::string &consumerTag, bool redelivered)
|
||||
{
|
||||
// @todo
|
||||
// add your own processing
|
||||
|
||||
|
||||
// after the message was processed, acknowledge it
|
||||
channel->ack(deliveryTag);
|
||||
}
|
||||
// callback function that is called when the consume operation starts
|
||||
auto startCb = [](const std::string &consumertag) {
|
||||
|
||||
std::cout << "consume operation started" << std::endl;
|
||||
};
|
||||
|
||||
// callback function that is called when the consume operation failed
|
||||
auto errorCb = [](const char *message) {
|
||||
|
||||
std::cout << "consume operation failed" << std::endl;
|
||||
}
|
||||
|
||||
// callback operation when a message was received
|
||||
auto messageCb = [&channel](const AMQP::Message &message, uint64_t deliveryTag, bool redelivered) {
|
||||
|
||||
std::cout << "message received" << std::endl;
|
||||
|
||||
// acknowledge the message
|
||||
channel.ack(deliveryTag);
|
||||
}
|
||||
|
||||
// start consuming from the queue, and install the callbacks
|
||||
channel.consume("my-queue")
|
||||
.onSuccess(startCb)
|
||||
.onError(errorCb)
|
||||
.onReceived(messageCb);
|
||||
|
||||
````
|
||||
|
||||
The Message object holds all information of the delivered message: the actual content,
|
||||
all meta information from the envelope (in fact, the Message class is derived from the Envelope class),
|
||||
and even the name of the exchange and the routing key that were used when the message was originally
|
||||
published. For a full list of all information in the Message class, you best have a look at the
|
||||
The Message object holds all information of the delivered message: the actual
|
||||
content, all meta information from the envelope (in fact, the Message class is
|
||||
derived from the Envelope class), and even the name of the exchange and the
|
||||
routing key that were used when the message was originally published. For a full
|
||||
list of all information in the Message class, you best have a look at the
|
||||
message.h, envelope.h and metadata.h header files.
|
||||
|
||||
Another important parameter to the onReceived() method is the deliveryTag parameter. This is a
|
||||
unique identifier that you need to acknowledge an incoming message. RabbitMQ only removes the
|
||||
message after it has been acknowledged, so that if your application crashes while it was busy
|
||||
processing the message, the message does not get lost but remains in the queue. But this means that
|
||||
after you've processed the message, you must inform RabbitMQ about it by calling the Channel:ack()
|
||||
method. This method is very simple and takes in its simplest form only one parameter: the
|
||||
Another important parameter to the onReceived() method is the deliveryTag parameter.
|
||||
This is a unique identifier that you need to acknowledge an incoming message.
|
||||
RabbitMQ only removes the message after it has been acknowledged, so that if your
|
||||
application crashes while it was busy processing the message, the message does
|
||||
not get lost but remains in the queue. But this means that after you've processed
|
||||
the message, you must inform RabbitMQ about it by calling the Channel:ack() method.
|
||||
This method is very simple and takes in its simplest form only one parameter: the
|
||||
deliveryTag of the message.
|
||||
|
||||
The consumerTag that you see in the onReceived method() is the same string identifier that was
|
||||
passed to the Channel::consume() method.
|
||||
Consuming messages is a continuous process. RabbitMQ keeps sending messages, until
|
||||
you stop the consumer, which can be done by calling the Channel::cancel() method.
|
||||
If you close the channel, or the entire TCP connection, consuming also stops.
|
||||
|
||||
Consuming messages is a continuous process. RabbitMQ keeps sending messages, until you stop
|
||||
the consumer, which can be done by calling the Channel::cancel() method. If you close the channel,
|
||||
or the entire TCP connection, consuming also stops.
|
||||
|
||||
RabbitMQ throttles the number of messages that are delivered to you, to prevent that your application
|
||||
is flooded with messages from the queue, and to spread out the messages over multiple consumers.
|
||||
This is done with a setting called quality-of-service (QOS). The QOS setting is a numeric value which
|
||||
holds the number of unacknowledged messages that you are allowed to have. RabbitMQ stops sending
|
||||
additional messages when the number of unacknowledges messages has reached this limit, and only
|
||||
sends additional messages when an earlier message gets acknowledged. To change the QOS, you can
|
||||
simple call Channel::setQos().
|
||||
RabbitMQ throttles the number of messages that are delivered to you, to prevent
|
||||
that your application is flooded with messages from the queue, and to spread out
|
||||
the messages over multiple consumers. This is done with a setting called
|
||||
quality-of-service (QOS). The QOS setting is a numeric value which holds the number
|
||||
of unacknowledged messages that you are allowed to have. RabbitMQ stops sending
|
||||
additional messages when the number of unacknowledges messages has reached this
|
||||
limit, and only sends additional messages when an earlier message gets acknowledged.
|
||||
To change the QOS, you can simple call Channel::setQos().
|
||||
|
||||
|
||||
WORK IN PROGRESS
|
||||
|
|
@ -534,11 +636,12 @@ need additional attention:
|
|||
- ability to set up secure connections (or is this fully done on the IO level)
|
||||
- login with other protocols than login/password
|
||||
- publish confirms
|
||||
- returned messages
|
||||
|
||||
We also need to add more safety checks so that strange or invalid data from
|
||||
RabbitMQ does not break the library (although in reality RabbitMQ only sends
|
||||
We also need to add more safety checks so that strange or invalid data from
|
||||
RabbitMQ does not break the library (although in reality RabbitMQ only sends
|
||||
valid data). Also, when we now receive an answer from RabbitMQ that does not
|
||||
match the request that we sent before, we do not report an error (this is also
|
||||
match the request that we sent before, we do not report an error (this is also
|
||||
an issue that only occurs in theory).
|
||||
|
||||
It would be nice to have sample implementations for the ConnectionHandler
|
||||
|
|
|
|||
13
amqpcpp.h
13
amqpcpp.h
|
|
@ -6,6 +6,8 @@
|
|||
* @documentation public
|
||||
*/
|
||||
|
||||
#pragma once
|
||||
|
||||
// base C++ include files
|
||||
#include <vector>
|
||||
#include <string>
|
||||
|
|
@ -16,6 +18,9 @@
|
|||
#include <limits>
|
||||
#include <cstddef>
|
||||
#include <cstring>
|
||||
#include <stdexcept>
|
||||
#include <utility>
|
||||
#include <iostream>
|
||||
|
||||
// base C include files
|
||||
#include <stdint.h>
|
||||
|
|
@ -29,6 +34,7 @@
|
|||
#include <amqpcpp/receivedframe.h>
|
||||
#include <amqpcpp/outbuffer.h>
|
||||
#include <amqpcpp/watchable.h>
|
||||
#include <amqpcpp/monitor.h>
|
||||
|
||||
// amqp types
|
||||
#include <amqpcpp/field.h>
|
||||
|
|
@ -48,7 +54,12 @@
|
|||
// mid level includes
|
||||
#include <amqpcpp/exchangetype.h>
|
||||
#include <amqpcpp/flags.h>
|
||||
#include <amqpcpp/channelhandler.h>
|
||||
#include <amqpcpp/callbacks.h>
|
||||
#include <amqpcpp/deferred.h>
|
||||
#include <amqpcpp/deferredconsumer.h>
|
||||
#include <amqpcpp/deferredqueue.h>
|
||||
#include <amqpcpp/deferreddelete.h>
|
||||
#include <amqpcpp/deferredcancel.h>
|
||||
#include <amqpcpp/channelimpl.h>
|
||||
#include <amqpcpp/channel.h>
|
||||
#include <amqpcpp/login.h>
|
||||
|
|
|
|||
|
|
@ -1,6 +1,7 @@
|
|||
#pragma once
|
||||
/**
|
||||
* AMQP field array
|
||||
*
|
||||
*
|
||||
* @copyright 2014 Copernica BV
|
||||
*/
|
||||
|
||||
|
|
@ -20,7 +21,7 @@ private:
|
|||
* @typedef
|
||||
*/
|
||||
typedef std::vector<std::shared_ptr<Field>> FieldArray;
|
||||
|
||||
|
||||
/**
|
||||
* The actual fields
|
||||
* @var FieldArray
|
||||
|
|
@ -30,7 +31,7 @@ private:
|
|||
public:
|
||||
/**
|
||||
* Constructor to construct an array from a received frame
|
||||
*
|
||||
*
|
||||
* @param frame received frame
|
||||
*/
|
||||
Array(ReceivedFrame &frame);
|
||||
|
|
@ -61,9 +62,9 @@ public:
|
|||
* Create a new instance of this object
|
||||
* @return Field*
|
||||
*/
|
||||
virtual Field *clone() const override
|
||||
virtual std::shared_ptr<Field> clone() const override
|
||||
{
|
||||
return new Array(*this);
|
||||
return std::make_shared<Array>(*this);
|
||||
}
|
||||
|
||||
/**
|
||||
|
|
@ -82,8 +83,20 @@ public:
|
|||
*/
|
||||
Array set(uint8_t index, const Field &value)
|
||||
{
|
||||
// copy to a new pointer and store it
|
||||
_fields[index] = std::shared_ptr<Field>(value.clone());
|
||||
// construct a shared pointer
|
||||
auto ptr = value.clone();
|
||||
|
||||
// should we overwrite an existing record?
|
||||
if (index >= _fields.size())
|
||||
{
|
||||
// append index
|
||||
_fields.push_back(ptr);
|
||||
}
|
||||
else
|
||||
{
|
||||
// overwrite pointer
|
||||
_fields[index] = ptr;
|
||||
}
|
||||
|
||||
// allow chaining
|
||||
return *this;
|
||||
|
|
@ -97,7 +110,26 @@ public:
|
|||
* @param index field index
|
||||
* @return Field
|
||||
*/
|
||||
const Field &get(uint8_t index);
|
||||
const Field &get(uint8_t index) const;
|
||||
|
||||
/**
|
||||
* Get number of elements on this array
|
||||
*
|
||||
* @return array size
|
||||
*/
|
||||
uint32_t count() const;
|
||||
|
||||
/**
|
||||
* Remove last element from array
|
||||
*/
|
||||
void pop_back();
|
||||
|
||||
/**
|
||||
* Add field to end of array
|
||||
*
|
||||
* @param value
|
||||
*/
|
||||
void push_back(const Field &value);
|
||||
|
||||
/**
|
||||
* Get a field
|
||||
|
|
@ -109,9 +141,19 @@ public:
|
|||
{
|
||||
return ArrayFieldProxy(this, index);
|
||||
}
|
||||
|
||||
/**
|
||||
* Get a const field
|
||||
* @param index field index
|
||||
* @return Field
|
||||
*/
|
||||
const Field &operator[](uint8_t index) const
|
||||
{
|
||||
return get(index);
|
||||
}
|
||||
|
||||
/**
|
||||
* Write encoded payload to the given buffer.
|
||||
* Write encoded payload to the given buffer.
|
||||
* @param buffer
|
||||
*/
|
||||
virtual void fill(OutBuffer& buffer) const override;
|
||||
|
|
@ -125,6 +167,45 @@ public:
|
|||
{
|
||||
return 'A';
|
||||
}
|
||||
|
||||
/**
|
||||
* Output the object to a stream
|
||||
* @param std::ostream
|
||||
*/
|
||||
virtual void output(std::ostream &stream) const
|
||||
{
|
||||
// prefix
|
||||
stream << "array(";
|
||||
|
||||
// is this the first iteration
|
||||
bool first = true;
|
||||
|
||||
// loop through all members
|
||||
for (auto &iter : _fields)
|
||||
{
|
||||
// split with comma
|
||||
if (!first) stream << ",";
|
||||
|
||||
// show output
|
||||
stream << *iter;
|
||||
|
||||
// no longer first iter
|
||||
first = false;
|
||||
}
|
||||
|
||||
// postfix
|
||||
stream << ")";
|
||||
}
|
||||
|
||||
/**
|
||||
* Cast to array
|
||||
* @return Array
|
||||
*/
|
||||
virtual operator const Array& () const override
|
||||
{
|
||||
// this already is an array, so no cast is necessary
|
||||
return *this;
|
||||
}
|
||||
};
|
||||
|
||||
/**
|
||||
|
|
|
|||
|
|
@ -1,3 +1,4 @@
|
|||
#pragma once
|
||||
/**
|
||||
* BooleanSet.h
|
||||
*
|
||||
|
|
@ -77,9 +78,25 @@ public:
|
|||
* Extending from field forces us to implement a clone function.
|
||||
* @return shared_ptr
|
||||
*/
|
||||
virtual Field *clone() const override
|
||||
virtual std::shared_ptr<Field> clone() const override
|
||||
{
|
||||
return new BooleanSet(*this);
|
||||
return std::make_shared<BooleanSet>(*this);
|
||||
}
|
||||
|
||||
/**
|
||||
* Output the object to a stream
|
||||
* @param std::ostream
|
||||
*/
|
||||
virtual void output(std::ostream &stream) const override
|
||||
{
|
||||
// prefix
|
||||
stream << "booleanset(";
|
||||
|
||||
// the members
|
||||
for (int i=0; i<8; i++) stream << (i == 0 ? "" : ",") << (get(i) ? 1 : 0);
|
||||
|
||||
// postfix
|
||||
stream << ")";
|
||||
}
|
||||
|
||||
/**
|
||||
|
|
|
|||
|
|
@ -0,0 +1,32 @@
|
|||
/**
|
||||
* Callbacks.h
|
||||
*
|
||||
* Class storing deferred callbacks of different type.
|
||||
*
|
||||
* @copyright 2014 Copernica BV
|
||||
*/
|
||||
|
||||
/**
|
||||
* Set up namespace
|
||||
*/
|
||||
namespace AMQP {
|
||||
|
||||
/**
|
||||
* All the callbacks that are supported
|
||||
*
|
||||
* When someone registers a callback function for certain events, it should
|
||||
* match one of the following signatures.
|
||||
*/
|
||||
using SuccessCallback = std::function<void()>;
|
||||
using ErrorCallback = std::function<void(const char *message)>;
|
||||
using FinalizeCallback = std::function<void()>;
|
||||
using MessageCallback = std::function<void(const Message &message, uint64_t deliveryTag, bool redelivered)>;
|
||||
using QueueCallback = std::function<void(const std::string &name, uint32_t messagecount, uint32_t consumercount)>;
|
||||
using DeleteCallback = std::function<void(uint32_t deletedmessages)>;
|
||||
using ConsumeCallback = std::function<void(const std::string &consumer)>;
|
||||
using CancelCallback = std::function<void(const std::string &consumer)>;
|
||||
|
||||
/**
|
||||
* End namespace
|
||||
*/
|
||||
}
|
||||
|
|
@ -1,6 +1,7 @@
|
|||
#pragma once
|
||||
/**
|
||||
* Class describing a (mid-level) AMQP channel implementation
|
||||
*
|
||||
*
|
||||
* @copyright 2014 Copernica BV
|
||||
*/
|
||||
|
||||
|
|
@ -25,9 +26,8 @@ public:
|
|||
/**
|
||||
* Construct a channel object
|
||||
* @param connection
|
||||
* @param handler
|
||||
*/
|
||||
Channel(Connection *connection, ChannelHandler *handler) : _implementation(this, connection, handler) {}
|
||||
Channel(Connection *connection) : _implementation(this, connection) {}
|
||||
|
||||
/**
|
||||
* Destructor
|
||||
|
|
@ -35,27 +35,55 @@ public:
|
|||
virtual ~Channel() {}
|
||||
|
||||
/**
|
||||
* Pause deliveries on a channel
|
||||
*
|
||||
* This will stop all incoming messages
|
||||
*
|
||||
* This method returns true if the request to pause has been sent to the
|
||||
* broker. This does not necessarily mean that the channel is already
|
||||
* paused.
|
||||
*
|
||||
* @return bool
|
||||
* Callback that is called when the channel was succesfully created.
|
||||
*
|
||||
* Only one callback can be registered. Calling this function multiple
|
||||
* times will remove the old callback.
|
||||
*
|
||||
* @param callback the callback to execute
|
||||
*/
|
||||
bool pause()
|
||||
void onReady(const SuccessCallback &callback)
|
||||
{
|
||||
// store callback in implementation
|
||||
_implementation._readyCallback = callback;
|
||||
}
|
||||
|
||||
/**
|
||||
* Callback that is called when an error occurs.
|
||||
*
|
||||
* Only one error callback can be registered. Calling this function
|
||||
* multiple times will remove the old callback.
|
||||
*
|
||||
* @param callback the callback to execute
|
||||
*/
|
||||
void onError(const ErrorCallback &callback)
|
||||
{
|
||||
// store callback in implementation
|
||||
_implementation._errorCallback = callback;
|
||||
}
|
||||
|
||||
/**
|
||||
* Pause deliveries on a channel
|
||||
*
|
||||
* This will stop all incoming messages
|
||||
*
|
||||
* This function returns a deferred handler. Callbacks can be installed
|
||||
* using onSuccess(), onError() and onFinalize() methods.
|
||||
*/
|
||||
Deferred &pause()
|
||||
{
|
||||
return _implementation.pause();
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Resume a paused channel
|
||||
*
|
||||
* @return bool
|
||||
*
|
||||
* This will resume incoming messages
|
||||
*
|
||||
* This function returns a deferred handler. Callbacks can be installed
|
||||
* using onSuccess(), onError() and onFinalize() methods.
|
||||
*/
|
||||
bool resume()
|
||||
Deferred &resume()
|
||||
{
|
||||
return _implementation.resume();
|
||||
}
|
||||
|
|
@ -68,312 +96,340 @@ public:
|
|||
{
|
||||
return _implementation.connected();
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Start a transaction
|
||||
* @return bool
|
||||
*
|
||||
* This function returns a deferred handler. Callbacks can be installed
|
||||
* using onSuccess(), onError() and onFinalize() methods.
|
||||
*/
|
||||
bool startTransaction()
|
||||
Deferred &startTransaction()
|
||||
{
|
||||
return _implementation.startTransaction();
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Commit the current transaction
|
||||
* @return bool
|
||||
*
|
||||
* This function returns a deferred handler. Callbacks can be installed
|
||||
* using onSuccess(), onError() and onFinalize() methods.
|
||||
*/
|
||||
bool commitTransaction()
|
||||
Deferred &commitTransaction()
|
||||
{
|
||||
return _implementation.commitTransaction();
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Rollback the current transaction
|
||||
* @return bool
|
||||
*
|
||||
* This function returns a deferred handler. Callbacks can be installed
|
||||
* using onSuccess(), onError() and onFinalize() methods.
|
||||
*/
|
||||
bool rollbackTransaction()
|
||||
Deferred &rollbackTransaction()
|
||||
{
|
||||
return _implementation.rollbackTransaction();
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Declare an exchange
|
||||
*
|
||||
*
|
||||
* If an empty name is supplied, a name will be assigned by the server.
|
||||
*
|
||||
*
|
||||
* The following flags can be used for the exchange:
|
||||
*
|
||||
*
|
||||
* - durable exchange survives a broker restart
|
||||
* - autodelete exchange is automatically removed when all connected queues are removed
|
||||
* - passive only check if the exchange exist
|
||||
*
|
||||
*
|
||||
* @param name name of the exchange
|
||||
* @param type exchange type
|
||||
* @param flags exchange flags
|
||||
* @param arguments additional arguments
|
||||
* @return bool
|
||||
*
|
||||
* This function returns a deferred handler. Callbacks can be installed
|
||||
* using onSuccess(), onError() and onFinalize() methods.
|
||||
*/
|
||||
bool declareExchange(const std::string &name, ExchangeType type, int flags, const Table &arguments) { return _implementation.declareExchange(name, type, flags, arguments); }
|
||||
bool declareExchange(const std::string &name, ExchangeType type, const Table &arguments) { return _implementation.declareExchange(name, type, 0, arguments); }
|
||||
bool declareExchange(const std::string &name, ExchangeType type = fanout, int flags = 0) { return _implementation.declareExchange(name, type, flags, Table()); }
|
||||
bool declareExchange(ExchangeType type, int flags, const Table &arguments) { return _implementation.declareExchange(std::string(), type, flags, arguments); }
|
||||
bool declareExchange(ExchangeType type, const Table &arguments) { return _implementation.declareExchange(std::string(), type, 0, arguments); }
|
||||
bool declareExchange(ExchangeType type = fanout, int flags = 0) { return _implementation.declareExchange(std::string(), type, flags, Table()); }
|
||||
|
||||
Deferred &declareExchange(const std::string &name, ExchangeType type, int flags, const Table &arguments) { return _implementation.declareExchange(name, type, flags, arguments); }
|
||||
Deferred &declareExchange(const std::string &name, ExchangeType type, const Table &arguments) { return _implementation.declareExchange(name, type, 0, arguments); }
|
||||
Deferred &declareExchange(const std::string &name, ExchangeType type = fanout, int flags = 0) { return _implementation.declareExchange(name, type, flags, Table()); }
|
||||
Deferred &declareExchange(ExchangeType type, int flags, const Table &arguments) { return _implementation.declareExchange(std::string(), type, flags, arguments); }
|
||||
Deferred &declareExchange(ExchangeType type, const Table &arguments) { return _implementation.declareExchange(std::string(), type, 0, arguments); }
|
||||
Deferred &declareExchange(ExchangeType type = fanout, int flags = 0) { return _implementation.declareExchange(std::string(), type, flags, Table()); }
|
||||
|
||||
/**
|
||||
* Remove an exchange
|
||||
*
|
||||
*
|
||||
* The following flags can be used for the exchange:
|
||||
*
|
||||
*
|
||||
* - ifunused only delete if no queues are connected
|
||||
|
||||
* @param name name of the exchange to remove
|
||||
* @param flags optional flags
|
||||
* @return bool
|
||||
*
|
||||
* This function returns a deferred handler. Callbacks can be installed
|
||||
* using onSuccess(), onError() and onFinalize() methods.
|
||||
*/
|
||||
bool removeExchange(const std::string &name, int flags = 0) { return _implementation.removeExchange(name, flags); }
|
||||
|
||||
Deferred &removeExchange(const std::string &name, int flags = 0) { return _implementation.removeExchange(name, flags); }
|
||||
|
||||
/**
|
||||
* Bind two exchanges to each other
|
||||
*
|
||||
* The following flags can be used for the exchange
|
||||
*
|
||||
* - nowait do not wait on response
|
||||
*
|
||||
*
|
||||
* @param source the source exchange
|
||||
* @param target the target exchange
|
||||
* @param routingkey the routing key
|
||||
* @param flags optional flags
|
||||
* @param arguments additional bind arguments
|
||||
* @return bool
|
||||
*
|
||||
* This function returns a deferred handler. Callbacks can be installed
|
||||
* using onSuccess(), onError() and onFinalize() methods.
|
||||
*/
|
||||
bool bindExchange(const std::string &source, const std::string &target, const std::string &routingkey, int flags, const Table &arguments) { return _implementation.bindExchange(source, target, routingkey, flags, arguments); }
|
||||
bool bindExchange(const std::string &source, const std::string &target, const std::string &routingkey, const Table &arguments) { return _implementation.bindExchange(source, target, routingkey, 0, arguments); }
|
||||
bool bindExchange(const std::string &source, const std::string &target, const std::string &routingkey, int flags = 0) { return _implementation.bindExchange(source, target, routingkey, flags, Table()); }
|
||||
|
||||
Deferred &bindExchange(const std::string &source, const std::string &target, const std::string &routingkey, const Table &arguments) { return _implementation.bindExchange(source, target, routingkey, arguments); }
|
||||
Deferred &bindExchange(const std::string &source, const std::string &target, const std::string &routingkey) { return _implementation.bindExchange(source, target, routingkey, Table()); }
|
||||
|
||||
/**
|
||||
* Unbind two exchanges from one another
|
||||
*
|
||||
* The following flags can be used for the exchange
|
||||
*
|
||||
* - nowait do not wait on response
|
||||
*
|
||||
*
|
||||
* @param target the target exchange
|
||||
* @param source the source exchange
|
||||
* @param routingkey the routing key
|
||||
* @param flags optional flags
|
||||
* @param arguments additional unbind arguments
|
||||
* @return bool
|
||||
*
|
||||
* This function returns a deferred handler. Callbacks can be installed
|
||||
* using onSuccess(), onError() and onFinalize() methods.
|
||||
*/
|
||||
bool unbindExchange(const std::string &target, const std::string &source, const std::string &routingkey, int flags, const Table &arguments) { return _implementation.unbindExchange(target, source, routingkey, flags, arguments); }
|
||||
bool unbindExchange(const std::string &target, const std::string &source, const std::string &routingkey, const Table &arguments) { return _implementation.unbindExchange(target, source, routingkey, 0, arguments); }
|
||||
bool unbindExchange(const std::string &target, const std::string &source, const std::string &routingkey, int flags = 0) { return _implementation.unbindExchange(target, source, routingkey, flags, Table()); }
|
||||
|
||||
Deferred &unbindExchange(const std::string &target, const std::string &source, const std::string &routingkey, const Table &arguments) { return _implementation.unbindExchange(target, source, routingkey, arguments); }
|
||||
Deferred &unbindExchange(const std::string &target, const std::string &source, const std::string &routingkey) { return _implementation.unbindExchange(target, source, routingkey, Table()); }
|
||||
|
||||
/**
|
||||
* Declare a queue
|
||||
*
|
||||
*
|
||||
* If you do not supply a name, a name will be assigned by the server.
|
||||
*
|
||||
*
|
||||
* The flags can be a combination of the following values:
|
||||
*
|
||||
*
|
||||
* - durable queue survives a broker restart
|
||||
* - autodelete queue is automatically removed when all connected consumers are gone
|
||||
* - passive only check if the queue exist
|
||||
* - exclusive the queue only exists for this connection, and is automatically removed when connection is gone
|
||||
*
|
||||
*
|
||||
* @param name name of the queue
|
||||
* @param flags combination of flags
|
||||
* @param arguments optional arguments
|
||||
*
|
||||
* This function returns a deferred handler. Callbacks can be installed
|
||||
* using onSuccess(), onError() and onFinalize() methods.
|
||||
*
|
||||
* The onSuccess() callback that you can install should have the following signature:
|
||||
*
|
||||
* void myCallback(AMQP::Channel *channel, const std::string &name, uint32_t messageCount, uint32_t consumerCount);
|
||||
*
|
||||
* For example: channel.declareQueue("myqueue").onSuccess([](AMQP::Channel *channel, const std::string &name, uint32_t messageCount, uint32_t consumerCount) {
|
||||
*
|
||||
* std::cout << "Queue '" << name << "' has been declared with " << messageCount << " messages and " << consumerCount << " consumers" << std::endl;
|
||||
*
|
||||
* });
|
||||
*/
|
||||
bool declareQueue(const std::string &name, int flags, const Table &arguments) { return _implementation.declareQueue(name, flags, arguments); }
|
||||
bool declareQueue(const std::string &name, const Table &arguments) { return _implementation.declareQueue(name, 0, arguments); }
|
||||
bool declareQueue(const std::string &name, int flags = 0) { return _implementation.declareQueue(name, flags, Table()); }
|
||||
bool declareQueue(int flags, const Table &arguments) { return _implementation.declareQueue(std::string(), flags, arguments); }
|
||||
bool declareQueue(const Table &arguments) { return _implementation.declareQueue(std::string(), 0, arguments); }
|
||||
bool declareQueue(int flags = 0) { return _implementation.declareQueue(std::string(), flags, Table()); }
|
||||
DeferredQueue &declareQueue(const std::string &name, int flags, const Table &arguments) { return _implementation.declareQueue(name, flags, arguments); }
|
||||
DeferredQueue &declareQueue(const std::string &name, const Table &arguments) { return _implementation.declareQueue(name, 0, arguments); }
|
||||
DeferredQueue &declareQueue(const std::string &name, int flags = 0) { return _implementation.declareQueue(name, flags, Table()); }
|
||||
DeferredQueue &declareQueue(int flags, const Table &arguments) { return _implementation.declareQueue(std::string(), flags, arguments); }
|
||||
DeferredQueue &declareQueue(const Table &arguments) { return _implementation.declareQueue(std::string(), 0, arguments); }
|
||||
DeferredQueue &declareQueue(int flags = 0) { return _implementation.declareQueue(std::string(), flags, Table()); }
|
||||
|
||||
/**
|
||||
* Bind a queue to an exchange
|
||||
*
|
||||
* The following flags can be used for the exchange
|
||||
*
|
||||
* - nowait do not wait on response
|
||||
*
|
||||
*
|
||||
* @param exchange the source exchange
|
||||
* @param queue the target queue
|
||||
* @param routingkey the routing key
|
||||
* @param flags additional flags
|
||||
* @param arguments additional bind arguments
|
||||
* @return bool
|
||||
*
|
||||
* This function returns a deferred handler. Callbacks can be installed
|
||||
* using onSuccess(), onError() and onFinalize() methods.
|
||||
*/
|
||||
bool bindQueue(const std::string &exchange, const std::string &queue, const std::string &routingkey, int flags, const Table &arguments) { return _implementation.bindQueue(exchange, queue, routingkey, flags, arguments); }
|
||||
bool bindQueue(const std::string &exchange, const std::string &queue, const std::string &routingkey, const Table &arguments) { return _implementation.bindQueue(exchange, queue, routingkey, 0, arguments); }
|
||||
bool bindQueue(const std::string &exchange, const std::string &queue, const std::string &routingkey, int flags = 0) { return _implementation.bindQueue(exchange, queue, routingkey, flags, Table()); }
|
||||
|
||||
Deferred &bindQueue(const std::string &exchange, const std::string &queue, const std::string &routingkey, const Table &arguments) { return _implementation.bindQueue(exchange, queue, routingkey, arguments); }
|
||||
Deferred &bindQueue(const std::string &exchange, const std::string &queue, const std::string &routingkey) { return _implementation.bindQueue(exchange, queue, routingkey, Table()); }
|
||||
|
||||
/**
|
||||
* Unbind a queue from an exchange
|
||||
* @param exchange the source exchange
|
||||
* @param queue the target queue
|
||||
* @param routingkey the routing key
|
||||
* @param arguments additional bind arguments
|
||||
* @return bool
|
||||
*
|
||||
* This function returns a deferred handler. Callbacks can be installed
|
||||
* using onSuccess(), onError() and onFinalize() methods.
|
||||
*/
|
||||
bool unbindQueue(const std::string &exchange, const std::string &queue, const std::string &routingkey, const Table &arguments) { return _implementation.unbindQueue(exchange, queue, routingkey, arguments); }
|
||||
bool unbindQueue(const std::string &exchange, const std::string &queue, const std::string &routingkey) { return _implementation.unbindQueue(exchange, queue, routingkey, Table()); }
|
||||
|
||||
Deferred &unbindQueue(const std::string &exchange, const std::string &queue, const std::string &routingkey, const Table &arguments) { return _implementation.unbindQueue(exchange, queue, routingkey, arguments); }
|
||||
Deferred &unbindQueue(const std::string &exchange, const std::string &queue, const std::string &routingkey) { return _implementation.unbindQueue(exchange, queue, routingkey, Table()); }
|
||||
|
||||
/**
|
||||
* Purge a queue
|
||||
*
|
||||
* The following flags can be used for the exchange
|
||||
*
|
||||
* - nowait do not wait on response
|
||||
*
|
||||
*
|
||||
* @param name name of the queue
|
||||
* @param flags additional flags
|
||||
* @return bool
|
||||
*
|
||||
* This function returns a deferred handler. Callbacks can be installed
|
||||
* using onSuccess(), onError() and onFinalize() methods.
|
||||
*
|
||||
* The onSuccess() callback that you can install should have the following signature:
|
||||
*
|
||||
* void myCallback(AMQP::Channel *channel, uint32_t messageCount);
|
||||
*
|
||||
* For example: channel.declareQueue("myqueue").onSuccess([](AMQP::Channel *channel, uint32_t messageCount) {
|
||||
*
|
||||
* std::cout << "Queue purged, all " << messageCount << " messages removed" << std::endl;
|
||||
*
|
||||
* });
|
||||
*/
|
||||
bool purgeQueue(const std::string &name, int flags = 0){ return _implementation.purgeQueue(name, flags); }
|
||||
|
||||
DeferredDelete &purgeQueue(const std::string &name){ return _implementation.purgeQueue(name); }
|
||||
|
||||
/**
|
||||
* Remove a queue
|
||||
*
|
||||
*
|
||||
* The following flags can be used for the exchange:
|
||||
*
|
||||
*
|
||||
* - ifunused only delete if no consumers are connected
|
||||
* - ifempty only delete if the queue is empty
|
||||
*
|
||||
* @param name name of the queue to remove
|
||||
* @param flags optional flags
|
||||
* @return bool
|
||||
*
|
||||
* This function returns a deferred handler. Callbacks can be installed
|
||||
* using onSuccess(), onError() and onFinalize() methods.
|
||||
*
|
||||
* The onSuccess() callback that you can install should have the following signature:
|
||||
*
|
||||
* void myCallback(AMQP::Channel *channel, uint32_t messageCount);
|
||||
*
|
||||
* For example: channel.removeQueue("myqueue").onSuccess([](AMQP::Channel *channel, uint32_t messageCount) {
|
||||
*
|
||||
* std::cout << "Queue deleted, along with " << messageCount << " messages" << std::endl;
|
||||
*
|
||||
* });
|
||||
*/
|
||||
bool removeQueue(const std::string &name, int flags = 0) { return _implementation.removeQueue(name, flags); }
|
||||
|
||||
DeferredDelete &removeQueue(const std::string &name, int flags = 0) { return _implementation.removeQueue(name, flags); }
|
||||
|
||||
/**
|
||||
* Publish a message to an exchange
|
||||
*
|
||||
* The following flags can be used
|
||||
*
|
||||
* - mandatory if set, an unroutable message will be reported to the channel handler with the onReturned method
|
||||
* - immediate if set, a message that could not immediately be consumed is returned to the onReturned method
|
||||
*
|
||||
* If either of the two flags is set, and the message could not immediately
|
||||
* be published, the message is returned by the server to the client. If you
|
||||
* want to catch such returned messages, you need to implement the
|
||||
* ChannelHandler::onReturned() method.
|
||||
*
|
||||
*
|
||||
* @param exchange the exchange to publish to
|
||||
* @param routingkey the routing key
|
||||
* @param flags optional flags (see above)
|
||||
* @param envelope the full envelope to send
|
||||
* @param message the message to send
|
||||
* @param size size of the message
|
||||
*/
|
||||
bool publish(const std::string &exchange, const std::string &routingKey, int flags, const Envelope &envelope) { return _implementation.publish(exchange, routingKey, flags, envelope); }
|
||||
bool publish(const std::string &exchange, const std::string &routingKey, const Envelope &envelope) { return _implementation.publish(exchange, routingKey, 0, envelope); }
|
||||
bool publish(const std::string &exchange, const std::string &routingKey, int flags, const std::string &message) { return _implementation.publish(exchange, routingKey, flags, Envelope(message)); }
|
||||
bool publish(const std::string &exchange, const std::string &routingKey, const std::string &message) { return _implementation.publish(exchange, routingKey, 0, Envelope(message)); }
|
||||
bool publish(const std::string &exchange, const std::string &routingKey, int flags, const char *message, size_t size) { return _implementation.publish(exchange, routingKey, flags, Envelope(message, size)); }
|
||||
bool publish(const std::string &exchange, const std::string &routingKey, const char *message, size_t size) { return _implementation.publish(exchange, routingKey, 0, Envelope(message, size)); }
|
||||
|
||||
bool publish(const std::string &exchange, const std::string &routingKey, const Envelope &envelope) { return _implementation.publish(exchange, routingKey, envelope); }
|
||||
bool publish(const std::string &exchange, const std::string &routingKey, const std::string &message) { return _implementation.publish(exchange, routingKey, Envelope(message)); }
|
||||
bool publish(const std::string &exchange, const std::string &routingKey, const char *message, size_t size) { return _implementation.publish(exchange, routingKey, Envelope(message, size)); }
|
||||
|
||||
/**
|
||||
* Set the Quality of Service (QOS) for this channel
|
||||
*
|
||||
* When you consume messages, every single messages needs to be ack'ed to inform
|
||||
*
|
||||
* When you consume messages, every single message needs to be ack'ed to inform
|
||||
* the RabbitMQ server that is has been received. The Qos setting specifies the
|
||||
* number of unacked messages that may exist in the client application. The server
|
||||
* stops delivering more messages if the number of unack'ed messages has reached
|
||||
* the prefetchCount
|
||||
*
|
||||
*
|
||||
* @param prefetchCount maximum number of messages to prefetch
|
||||
* @return bool whether the Qos frame is sent.
|
||||
*/
|
||||
bool setQos(uint16_t prefetchCount)
|
||||
Deferred &setQos(uint16_t prefetchCount)
|
||||
{
|
||||
return _implementation.setQos(prefetchCount);
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Tell the RabbitMQ server that we're ready to consume messages
|
||||
*
|
||||
*
|
||||
* After this method is called, RabbitMQ starts delivering messages to the client
|
||||
* application. The consume tag is a string identifier that will be passed to
|
||||
* each received message, so that you can associate incoming messages with a
|
||||
* each received message, so that you can associate incoming messages with a
|
||||
* consumer. If you do not specify a consumer tag, the server will assign one
|
||||
* for you.
|
||||
*
|
||||
*
|
||||
* The following flags are supported:
|
||||
*
|
||||
*
|
||||
* - nolocal if set, messages published on this channel are not also consumed
|
||||
* - noack if set, consumed messages do not have to be acked, this happens automatically
|
||||
* - exclusive request exclusive access, only this consumer can access the queue
|
||||
* - nowait the server does not have to send a response back that consuming is active
|
||||
*
|
||||
* The method ChannelHandler::onConsumerStarted() will be called when the
|
||||
* consumer has started (unless the nowait option was set, in which case
|
||||
* no confirmation method is called)
|
||||
*
|
||||
*
|
||||
* @param queue the queue from which you want to consume
|
||||
* @param tag a consumer tag that will be associated with this consume operation
|
||||
* @param flags additional flags
|
||||
* @param arguments additional arguments
|
||||
* @return bool
|
||||
*
|
||||
* This function returns a deferred handler. Callbacks can be installed
|
||||
* using onSuccess(), onError() and onFinalize() methods.
|
||||
*
|
||||
* The onSuccess() callback that you can install should have the following signature:
|
||||
*
|
||||
* void myCallback(AMQP::Channel *channel, const std::string& tag);
|
||||
*
|
||||
* For example: channel.consume("myqueue").onSuccess([](AMQP::Channel *channel, const std::string& tag) {
|
||||
*
|
||||
* std::cout << "Started consuming under tag " << tag << std::endl;
|
||||
*
|
||||
* });
|
||||
*/
|
||||
bool consume(const std::string &queue, const std::string &tag, int flags, const Table &arguments) { return _implementation.consume(queue, tag, flags, arguments); }
|
||||
bool consume(const std::string &queue, const std::string &tag, int flags = 0) { return _implementation.consume(queue, tag, flags, Table()); }
|
||||
bool consume(const std::string &queue, const std::string &tag, const Table &arguments) { return _implementation.consume(queue, tag, 0, arguments); }
|
||||
bool consume(const std::string &queue, int flags, const Table &arguments) { return _implementation.consume(queue, std::string(), flags, arguments); }
|
||||
bool consume(const std::string &queue, int flags = 0) { return _implementation.consume(queue, std::string(), flags, Table()); }
|
||||
bool consume(const std::string &queue, const Table &arguments) { return _implementation.consume(queue, std::string(), 0, arguments); }
|
||||
|
||||
DeferredConsumer &consume(const std::string &queue, const std::string &tag, int flags, const Table &arguments) { return _implementation.consume(queue, tag, flags, arguments); }
|
||||
DeferredConsumer &consume(const std::string &queue, const std::string &tag, int flags = 0) { return _implementation.consume(queue, tag, flags, Table()); }
|
||||
DeferredConsumer &consume(const std::string &queue, const std::string &tag, const Table &arguments) { return _implementation.consume(queue, tag, 0, arguments); }
|
||||
DeferredConsumer &consume(const std::string &queue, int flags, const Table &arguments) { return _implementation.consume(queue, std::string(), flags, arguments); }
|
||||
DeferredConsumer &consume(const std::string &queue, int flags = 0) { return _implementation.consume(queue, std::string(), flags, Table()); }
|
||||
DeferredConsumer &consume(const std::string &queue, const Table &arguments) { return _implementation.consume(queue, std::string(), 0, arguments); }
|
||||
|
||||
/**
|
||||
* Cancel a running consume call
|
||||
*
|
||||
*
|
||||
* If you want to stop a running consumer, you can use this method with the consumer tag
|
||||
*
|
||||
* The following flags are supported:
|
||||
*
|
||||
* - nowait the server does not have to send a response back that the consumer has been cancelled
|
||||
*
|
||||
* The method ChannelHandler::onConsumerStopped() will be called when the consumer
|
||||
* was succesfully stopped (unless the nowait option was used, in which case no
|
||||
* confirmation method is called)
|
||||
*
|
||||
*
|
||||
* @param tag the consumer tag
|
||||
* @param flags optional additional flags
|
||||
* @return bool
|
||||
*
|
||||
* This function returns a deferred handler. Callbacks can be installed
|
||||
* using onSuccess(), onError() and onFinalize() methods.
|
||||
*
|
||||
* The onSuccess() callback that you can install should have the following signature:
|
||||
*
|
||||
* void myCallback(AMQP::Channel *channel, const std::string& tag);
|
||||
*
|
||||
* For example: channel.cancel("myqueue").onSuccess([](AMQP::Channel *channel, const std::string& tag) {
|
||||
*
|
||||
* std::cout << "Stopped consuming under tag " << tag << std::endl;
|
||||
*
|
||||
* });
|
||||
*/
|
||||
bool cancel(const std::string &tag, int flags = 0) { return _implementation.cancel(tag, flags); }
|
||||
|
||||
DeferredCancel &cancel(const std::string &tag) { return _implementation.cancel(tag); }
|
||||
|
||||
/**
|
||||
* Acknoldge a received message
|
||||
*
|
||||
* When a message is received in the ChannelHandler::onReceived() method,
|
||||
* you must acknoledge it so that RabbitMQ removes it from the queue (unless
|
||||
*
|
||||
* When a message is received in the DeferredConsumer::onReceived() method,
|
||||
* you must acknowledge it so that RabbitMQ removes it from the queue (unless
|
||||
* you are consuming with the noack option). This method can be used for
|
||||
* this acknoledging.
|
||||
*
|
||||
* this acknowledging.
|
||||
*
|
||||
* The following flags are supported:
|
||||
*
|
||||
* - multiple acknoledge multiple messages: all un-acked messages that were earlier delivered are acknowledged too
|
||||
*
|
||||
*
|
||||
* - multiple acknowledge multiple messages: all un-acked messages that were earlier delivered are acknowledged too
|
||||
*
|
||||
* @param deliveryTag the unique delivery tag of the message
|
||||
* @param flags optional flags
|
||||
* @return bool
|
||||
*/
|
||||
bool ack(uint64_t deliveryTag, int flags=0) { return _implementation.ack(deliveryTag, flags); }
|
||||
|
||||
|
||||
/**
|
||||
* Reject or nack a message
|
||||
*
|
||||
* When a message was received in the ChannelHandler::onReceived() method,
|
||||
* and you don't want to acknoledge it, you can also choose to reject it by
|
||||
* calling this reject method.
|
||||
*
|
||||
*
|
||||
* When a message was received in the DeferredConsumer::onReceived() method,
|
||||
* and you don't want to acknowledge it, you can also choose to reject it by
|
||||
* calling this reject method.
|
||||
*
|
||||
* The following flags are supported:
|
||||
*
|
||||
*
|
||||
* - multiple reject multiple messages: all un-acked messages that were earlier delivered are unacked too
|
||||
* - requeue if set, the message is put back in the queue, otherwise it is dead-lettered/removed
|
||||
*
|
||||
*
|
||||
* @param deliveryTag the unique delivery tag of the message
|
||||
* @param flags optional flags
|
||||
* @return bool
|
||||
|
|
@ -382,27 +438,28 @@ public:
|
|||
|
||||
/**
|
||||
* Recover all messages that were not yet acked
|
||||
*
|
||||
* This method asks the server to redeliver all unacknowledged messages on a specified
|
||||
*
|
||||
* This method asks the server to redeliver all unacknowledged messages on a specified
|
||||
* channel. Zero or more messages may be redelivered.
|
||||
*
|
||||
*
|
||||
* The following flags are supported:
|
||||
*
|
||||
*
|
||||
* - requeue if set, the server will requeue the messages, so the could also end up with at different consumer
|
||||
*
|
||||
*
|
||||
* @param flags
|
||||
* @return bool
|
||||
*
|
||||
* This function returns a deferred handler. Callbacks can be installed
|
||||
* using onSuccess(), onError() and onFinalize() methods.
|
||||
*/
|
||||
bool recover(int flags = 0) { return _implementation.recover(flags); }
|
||||
Deferred &recover(int flags = 0) { return _implementation.recover(flags); }
|
||||
|
||||
/**
|
||||
* Close the current channel
|
||||
* @return bool
|
||||
*
|
||||
* This function returns a deferred handler. Callbacks can be installed
|
||||
* using onSuccess(), onError() and onFinalize() methods.
|
||||
*/
|
||||
bool close()
|
||||
{
|
||||
return _implementation.close();
|
||||
}
|
||||
Deferred &close() { return _implementation.close(); }
|
||||
|
||||
/**
|
||||
* Get the channel we're working on
|
||||
|
|
|
|||
|
|
@ -1,208 +0,0 @@
|
|||
/**
|
||||
* ChannelHandler.h
|
||||
*
|
||||
* Interface that should be implemented by a user of the AMQP library,
|
||||
* and that is passed to the Connection::createChannel() method.
|
||||
*
|
||||
* This interface contains a number of methods that are called when
|
||||
* the channel changes state.
|
||||
*
|
||||
* @copyright 2014 Copernica BV
|
||||
*/
|
||||
|
||||
/**
|
||||
* Set up namespace
|
||||
*/
|
||||
namespace AMQP {
|
||||
|
||||
/**
|
||||
* Class definition
|
||||
*/
|
||||
class ChannelHandler
|
||||
{
|
||||
public:
|
||||
/**
|
||||
* Method that is called when the channel was succesfully created.
|
||||
* @param channel the channel that is ready
|
||||
*/
|
||||
virtual void onReady(Channel *channel) {}
|
||||
|
||||
/**
|
||||
* An error has occured on the channel
|
||||
* The channel is no longer usable after an error has occured on it.
|
||||
* @param channel the channel on which the error occured
|
||||
* @param message human readable error message
|
||||
*/
|
||||
virtual void onError(Channel *channel, const std::string &message) {}
|
||||
|
||||
/**
|
||||
* Method that is called when the channel was paused
|
||||
* This is the result of a call to Channel::pause()
|
||||
* @param channel the channel that is now paused
|
||||
*/
|
||||
virtual void onPaused(Channel *channel) {}
|
||||
|
||||
/**
|
||||
* Method that is called when the channel was resumed
|
||||
* This is the result of a call to Channel::resume()
|
||||
* @param channel the channel that is no longer paused
|
||||
*/
|
||||
virtual void onResumed(Channel *channel) {}
|
||||
|
||||
/**
|
||||
* Method that is called when a channel is closed
|
||||
* This is the result of a call to Channel::close()
|
||||
* @param channel the channel that is closed
|
||||
*/
|
||||
virtual void onClosed(Channel *channel) {}
|
||||
|
||||
/**
|
||||
* Method that is called when a transaction was started
|
||||
* This is the result of a call to Channel::startTransaction()
|
||||
* @param channel the channel on which the transaction was started
|
||||
*/
|
||||
virtual void onTransactionStarted(Channel *channel) {}
|
||||
|
||||
/**
|
||||
* Method that is called when a transaction was committed
|
||||
* This is the result of a call to Channel::commitTransaction()
|
||||
* @param channel the channel on which the transaction was committed
|
||||
*/
|
||||
virtual void onTransactionCommitted(Channel *channel) {}
|
||||
|
||||
/**
|
||||
* Method that is called when a transaction was rolled back
|
||||
* This is the result of a call to Channel::rollbackTransaction()
|
||||
* @param channel the channel on which the transaction was rolled back
|
||||
*/
|
||||
virtual void onTransactionRolledBack(Channel *channel) {}
|
||||
|
||||
/**
|
||||
* Method that is called when an exchange is bound
|
||||
* This is the result of a call to Channel::bindExchange()
|
||||
* @param channel the channel on which the exchange was bound
|
||||
*/
|
||||
virtual void onExchangeBound(Channel *channel) {}
|
||||
|
||||
/**
|
||||
* Method that is called when an exchange is unbound
|
||||
* This is the result of a call to Channel::unbindExchange()
|
||||
* @param channel the channel on which the exchange was unbound
|
||||
*/
|
||||
virtual void onExchangeUnbound(Channel *channel) {}
|
||||
|
||||
/**
|
||||
* Method that is called when an exchange is deleted
|
||||
* This is the result of a call to Channel::deleteExchange()
|
||||
* @param channel the channel on which the exchange was deleted
|
||||
*/
|
||||
virtual void onExchangeDeleted(Channel *channel) {}
|
||||
|
||||
/**
|
||||
* Mehod that is called when an exchange is declared
|
||||
* This is the result of a call to Channel::declareExchange()
|
||||
* @param channel the channel on which the exchange was declared
|
||||
*/
|
||||
virtual void onExchangeDeclared(Channel *channel) {}
|
||||
|
||||
/**
|
||||
* Method that is called when a queue is declared
|
||||
* This is the result of a call to Channel::declareQueue()
|
||||
* @param channel the channel on which the queue was declared
|
||||
* @param name name of the queue
|
||||
* @param messageCount number of messages in queue
|
||||
* @param consumerCount number of active consumers
|
||||
*/
|
||||
virtual void onQueueDeclared(Channel *channel, const std::string &name, uint32_t messageCount, uint32_t consumerCount) {}
|
||||
|
||||
/**
|
||||
* Method that is called when a queue is bound
|
||||
* This is the result of a call to Channel::bindQueue()
|
||||
* @param channel the channel on which the queue was bound
|
||||
*/
|
||||
virtual void onQueueBound(Channel *channel) {}
|
||||
|
||||
/**
|
||||
* Method that is called when a queue is deleted
|
||||
* This is the result of a call to Channel::deleteQueue()
|
||||
* @param channel the channel on which the queue was deleted
|
||||
* @param messageCount number of messages deleted along with the queue
|
||||
*/
|
||||
virtual void onQueueDeleted(Channel *channel, uint32_t messageCount) {}
|
||||
|
||||
/**
|
||||
* Method that is called when a queue is unbound
|
||||
* This is the result of a call to Channel::unbindQueue()
|
||||
* @param channel the channel on which the queue was unbound
|
||||
*/
|
||||
virtual void onQueueUnbound(Channel *channel) {}
|
||||
|
||||
/**
|
||||
* Method that is called when a queue is purged
|
||||
* This is the result of a call to Channel::purgeQueue()
|
||||
* @param channel the channel on which the queue was emptied
|
||||
* @param messageCount number of message purged
|
||||
*/
|
||||
virtual void onQueuePurged(Channel *channel, uint32_t messageCount) {}
|
||||
|
||||
/**
|
||||
* Method that is called when the quality-of-service was changed
|
||||
* This is the result of a call to Channel::setQos()
|
||||
* @param channel the channel on which the qos was set
|
||||
*/
|
||||
virtual void onQosSet(Channel *channel) {}
|
||||
|
||||
/**
|
||||
* Method that is called when a consumer was started
|
||||
* This is the result of a call to Channel::consume()
|
||||
* @param channel the channel on which the consumer was started
|
||||
* @param tag the consumer tag
|
||||
*/
|
||||
virtual void onConsumerStarted(Channel *channel, const std::string &tag) {}
|
||||
|
||||
/**
|
||||
* Method that is called when a consumer was stopped
|
||||
* This is the result of a call to Channel::cancel()
|
||||
* @param channel the channel on which the consumer was stopped
|
||||
* @param tag the consumer tag
|
||||
*/
|
||||
virtual void onConsumerStopped(Channel *channel, const std::string &tag) {}
|
||||
|
||||
/**
|
||||
* Method that is called when a message has been received on a channel
|
||||
* This message will be called for every message that is received after
|
||||
* you started consuming. Make sure you acknowledge the messages when its
|
||||
* safe to remove them from RabbitMQ (unless you set no-ack option when you
|
||||
* started the consumer)
|
||||
* @param channel the channel on which the consumer was started
|
||||
* @param message the consumed message
|
||||
* @param deliveryTag the delivery tag, you need this to acknowledge the message
|
||||
* @param consumerTag the consumer identifier that was used to retrieve this message
|
||||
* @param redelivered is this a redelivered message?
|
||||
*/
|
||||
virtual void onReceived(Channel *channel, const Message &message, uint64_t deliveryTag, const std::string &consumerTag, bool redelivered) {}
|
||||
|
||||
/**
|
||||
* Method that is called when a message you tried to publish was returned
|
||||
* by the server. This only happens when the 'mandatory' or 'immediate' flag
|
||||
* was set with the Channel::publish() call.
|
||||
* @param channel the channel on which the message was returned
|
||||
* @param message the returned message
|
||||
* @param code the reply code
|
||||
* @param text human readable reply reason
|
||||
*/
|
||||
virtual void onReturned(Channel *channel, const Message &message, int16_t code, const std::string &text) {}
|
||||
|
||||
/**
|
||||
* Method that is called when the server starts recovering messages
|
||||
* This is the result of a call to Channel::recover()
|
||||
* @param channel the channel on which the recover method was called
|
||||
*/
|
||||
virtual void onRecovering(Channel *channel) {}
|
||||
|
||||
};
|
||||
|
||||
/**
|
||||
* End of namespace
|
||||
*/
|
||||
}
|
||||
|
|
@ -1,3 +1,4 @@
|
|||
#pragma once
|
||||
/**
|
||||
* ChannelImpl.h
|
||||
*
|
||||
|
|
@ -13,6 +14,11 @@
|
|||
*/
|
||||
namespace AMQP {
|
||||
|
||||
/**
|
||||
* Forward declarations
|
||||
*/
|
||||
class ConsumedMessage;
|
||||
|
||||
/**
|
||||
* Class definition
|
||||
*/
|
||||
|
|
@ -32,11 +38,38 @@ private:
|
|||
ConnectionImpl *_connection;
|
||||
|
||||
/**
|
||||
* The handler that is notified about events
|
||||
* @var MyChannelHandler
|
||||
* Callback when the channel is ready
|
||||
* @var SuccessCallback
|
||||
*/
|
||||
ChannelHandler *_handler;
|
||||
|
||||
SuccessCallback _readyCallback;
|
||||
|
||||
/**
|
||||
* Callback when the channel errors out
|
||||
* @var ErrorCallback
|
||||
*/
|
||||
ErrorCallback _errorCallback;
|
||||
|
||||
/**
|
||||
* Callbacks for all consumers that are active
|
||||
* @var std::map<std::string,MessageCallback>
|
||||
*/
|
||||
std::map<std::string,MessageCallback> _consumers;
|
||||
|
||||
/**
|
||||
* Pointer to the oldest deferred result (the first one that is going
|
||||
* to be executed)
|
||||
*
|
||||
* @var Deferred
|
||||
*/
|
||||
std::unique_ptr<Deferred> _oldestCallback = nullptr;
|
||||
|
||||
/**
|
||||
* Pointer to the newest deferred result (the last one to be added).
|
||||
*
|
||||
* @var Deferred
|
||||
*/
|
||||
Deferred *_newestCallback = nullptr;
|
||||
|
||||
/**
|
||||
* The channel number
|
||||
* @var uint16_t
|
||||
|
|
@ -52,31 +85,52 @@ private:
|
|||
state_closing,
|
||||
state_closed
|
||||
} _state = state_connected;
|
||||
|
||||
|
||||
/**
|
||||
* Is a transaction now active?
|
||||
* @var bool
|
||||
* The frames that still need to be send out
|
||||
*
|
||||
* We store the data as well as whether they
|
||||
* should be handled synchronously.
|
||||
*/
|
||||
bool _transaction = false;
|
||||
|
||||
std::queue<std::pair<bool, OutBuffer>> _queue;
|
||||
|
||||
/**
|
||||
* Are we currently operating in synchronous mode?
|
||||
*/
|
||||
bool _synchronous = false;
|
||||
|
||||
/**
|
||||
* The message that is now being received
|
||||
* @var MessageImpl
|
||||
* @var ConsumedMessage
|
||||
*/
|
||||
MessageImpl *_message = nullptr;
|
||||
ConsumedMessage *_message = nullptr;
|
||||
|
||||
/**
|
||||
* Construct a channel object
|
||||
*
|
||||
*
|
||||
* Note that the constructor is private, and that the Channel class is
|
||||
* a friend. By doing this we ensure that nobody can instantiate this
|
||||
* object, and that it can thus only be used inside the library.
|
||||
*
|
||||
*
|
||||
* @param parent the public channel object
|
||||
* @param connection pointer to the connection
|
||||
* @param handler handler that is notified on events
|
||||
*/
|
||||
ChannelImpl(Channel *parent, Connection *connection, ChannelHandler *handler = nullptr);
|
||||
ChannelImpl(Channel *parent, Connection *connection);
|
||||
|
||||
/**
|
||||
* Push a deferred result
|
||||
* @param result The deferred result
|
||||
* @return Deferred The object just pushed
|
||||
*/
|
||||
Deferred &push(Deferred *deferred);
|
||||
|
||||
/**
|
||||
* Send a framen and push a deferred result
|
||||
* @param frame The frame to send
|
||||
* @return Deferred The object just pushed
|
||||
*/
|
||||
Deferred &push(const Frame &frame);
|
||||
|
||||
|
||||
public:
|
||||
/**
|
||||
|
|
@ -95,23 +149,23 @@ public:
|
|||
|
||||
/**
|
||||
* Pause deliveries on a channel
|
||||
*
|
||||
*
|
||||
* This will stop all incoming messages
|
||||
*
|
||||
* This method returns true if the request to pause has been sent to the
|
||||
* broker. This does not necessarily mean that the channel is already
|
||||
* paused.
|
||||
*
|
||||
* @return bool
|
||||
*
|
||||
* This function returns a deferred handler. Callbacks can be installed
|
||||
* using onSuccess(), onError() and onFinalize() methods.
|
||||
*/
|
||||
bool pause();
|
||||
|
||||
Deferred &pause();
|
||||
|
||||
/**
|
||||
* Resume a paused channel
|
||||
*
|
||||
* @return bool
|
||||
*
|
||||
* This will resume incoming messages
|
||||
*
|
||||
* This function returns a deferred handler. Callbacks can be installed
|
||||
* using onSuccess(), onError() and onFinalize() methods.
|
||||
*/
|
||||
bool resume();
|
||||
Deferred &resume();
|
||||
|
||||
/**
|
||||
* Is the channel connected?
|
||||
|
|
@ -121,138 +175,177 @@ public:
|
|||
{
|
||||
return _state == state_connected;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Start a transaction
|
||||
* @return bool
|
||||
*/
|
||||
bool startTransaction();
|
||||
|
||||
Deferred &startTransaction();
|
||||
|
||||
/**
|
||||
* Commit the current transaction
|
||||
* @return bool
|
||||
*
|
||||
* This function returns a deferred handler. Callbacks can be installed
|
||||
* using onSuccess(), onError() and onFinalize() methods.
|
||||
*/
|
||||
bool commitTransaction();
|
||||
|
||||
Deferred &commitTransaction();
|
||||
|
||||
/**
|
||||
* Rollback the current transaction
|
||||
* @return bool
|
||||
*
|
||||
* This function returns a deferred handler. Callbacks can be installed
|
||||
* using onSuccess(), onError() and onFinalize() methods.
|
||||
*/
|
||||
bool rollbackTransaction();
|
||||
|
||||
Deferred &rollbackTransaction();
|
||||
|
||||
/**
|
||||
* declare an exchange
|
||||
*
|
||||
* @param name name of the exchange to declare
|
||||
* @param type type of exchange
|
||||
* @param flags additional settings for the exchange
|
||||
* @param arguments additional arguments
|
||||
* @return bool
|
||||
*
|
||||
* This function returns a deferred handler. Callbacks can be installed
|
||||
* using onSuccess(), onError() and onFinalize() methods.
|
||||
*/
|
||||
bool declareExchange(const std::string &name, ExchangeType type, int flags, const Table &arguments);
|
||||
|
||||
Deferred &declareExchange(const std::string &name, ExchangeType type, int flags, const Table &arguments);
|
||||
|
||||
/**
|
||||
* bind two exchanges
|
||||
|
||||
* @param source exchange which binds to target
|
||||
* @param target exchange to bind to
|
||||
* @param routingKey routing key
|
||||
* @param glags additional flags
|
||||
* @param arguments additional arguments for binding
|
||||
* @return bool
|
||||
*
|
||||
* This function returns a deferred handler. Callbacks can be installed
|
||||
* using onSuccess(), onError() and onFinalize() methods.
|
||||
*/
|
||||
bool bindExchange(const std::string &source, const std::string &target, const std::string &routingkey, int flags, const Table &arguments);
|
||||
|
||||
Deferred &bindExchange(const std::string &source, const std::string &target, const std::string &routingkey, const Table &arguments);
|
||||
|
||||
/**
|
||||
* unbind two exchanges
|
||||
|
||||
* @param source the source exchange
|
||||
* @param target the target exchange
|
||||
* @param routingkey the routing key
|
||||
* @param flags optional flags
|
||||
* @param arguments additional unbind arguments
|
||||
* @return bool
|
||||
*
|
||||
* This function returns a deferred handler. Callbacks can be installed
|
||||
* using onSuccess(), onError() and onFinalize() methods.
|
||||
*/
|
||||
bool unbindExchange(const std::string &source, const std::string &target, const std::string &routingkey, int flags, const Table &arguments);
|
||||
|
||||
Deferred &unbindExchange(const std::string &source, const std::string &target, const std::string &routingkey, const Table &arguments);
|
||||
|
||||
/**
|
||||
* remove an exchange
|
||||
*
|
||||
* @param name name of the exchange to remove
|
||||
* @param flags additional settings for deleting the exchange
|
||||
* @return bool
|
||||
*
|
||||
* This function returns a deferred handler. Callbacks can be installed
|
||||
* using onSuccess(), onError() and onFinalize() methods.
|
||||
*/
|
||||
bool removeExchange(const std::string &name, int flags);
|
||||
|
||||
Deferred &removeExchange(const std::string &name, int flags);
|
||||
|
||||
/**
|
||||
* declare a queue
|
||||
* @param name queue name
|
||||
* @param flags additional settings for the queue
|
||||
* @param arguments additional arguments
|
||||
* @return bool
|
||||
*
|
||||
* This function returns a deferred handler. Callbacks can be installed
|
||||
* using onSuccess(), onError() and onFinalize() methods.
|
||||
*/
|
||||
bool declareQueue(const std::string &name, int flags, const Table &arguments);
|
||||
|
||||
DeferredQueue &declareQueue(const std::string &name, int flags, const Table &arguments);
|
||||
|
||||
/**
|
||||
* Bind a queue to an exchange
|
||||
*
|
||||
* @param exchangeName name of the exchange to bind to
|
||||
* @param queueName name of the queue
|
||||
* @param routingkey routingkey
|
||||
* @param flags additional flags
|
||||
* @param arguments additional arguments
|
||||
* @return bool
|
||||
*
|
||||
* This function returns a deferred handler. Callbacks can be installed
|
||||
* using onSuccess(), onError() and onFinalize() methods.
|
||||
*/
|
||||
bool bindQueue(const std::string &exchangeName, const std::string &queueName, const std::string &routingkey, int flags, const Table &arguments);
|
||||
Deferred &bindQueue(const std::string &exchangeName, const std::string &queueName, const std::string &routingkey, const Table &arguments);
|
||||
|
||||
/**
|
||||
* Unbind a queue from an exchange
|
||||
*
|
||||
* @param exchange the source exchange
|
||||
* @param queue the target queue
|
||||
* @param routingkey the routing key
|
||||
* @param arguments additional bind arguments
|
||||
* @return bool
|
||||
*
|
||||
* This function returns a deferred handler. Callbacks can be installed
|
||||
* using onSuccess(), onError() and onFinalize() methods.
|
||||
*/
|
||||
bool unbindQueue(const std::string &exchangeName, const std::string &queueName, const std::string &routingkey, const Table &arguments);
|
||||
|
||||
Deferred &unbindQueue(const std::string &exchangeName, const std::string &queueName, const std::string &routingkey, const Table &arguments);
|
||||
|
||||
/**
|
||||
* Purge a queue
|
||||
* @param queue queue to purge
|
||||
* @param flags additional flags
|
||||
* @return bool
|
||||
*
|
||||
* This function returns a deferred handler. Callbacks can be installed
|
||||
* using onSuccess(), onError() and onFinalize() methods.
|
||||
*
|
||||
* The onSuccess() callback that you can install should have the following signature:
|
||||
*
|
||||
* void myCallback(AMQP::Channel *channel, uint32_t messageCount);
|
||||
*
|
||||
* For example: channel.declareQueue("myqueue").onSuccess([](AMQP::Channel *channel, uint32_t messageCount) {
|
||||
*
|
||||
* std::cout << "Queue purged, all " << messageCount << " messages removed" << std::endl;
|
||||
*
|
||||
* });
|
||||
*/
|
||||
bool purgeQueue(const std::string &name, int flags);
|
||||
|
||||
DeferredDelete &purgeQueue(const std::string &name);
|
||||
|
||||
/**
|
||||
* Remove a queue
|
||||
* @param queue queue to remove
|
||||
* @param flags additional flags
|
||||
* @return bool
|
||||
*
|
||||
* This function returns a deferred handler. Callbacks can be installed
|
||||
* using onSuccess(), onError() and onFinalize() methods.
|
||||
*
|
||||
* The onSuccess() callback that you can install should have the following signature:
|
||||
*
|
||||
* void myCallback(AMQP::Channel *channel, uint32_t messageCount);
|
||||
*
|
||||
* For example: channel.declareQueue("myqueue").onSuccess([](AMQP::Channel *channel, uint32_t messageCount) {
|
||||
*
|
||||
* std::cout << "Queue deleted, along with " << messageCount << " messages" << std::endl;
|
||||
*
|
||||
* });
|
||||
*/
|
||||
bool removeQueue(const std::string &name, int flags);
|
||||
DeferredDelete &removeQueue(const std::string &name, int flags);
|
||||
|
||||
/**
|
||||
* Publish a message to an exchange
|
||||
*
|
||||
* The following flags can be used
|
||||
*
|
||||
* - mandatory if set, an unroutable message will be reported to the channel handler with the onReturned method
|
||||
* - immediate if set, a message that could not immediately be consumed is returned to the onReturned method
|
||||
*
|
||||
*
|
||||
* If the mandatory or immediate flag is set, and the message could not immediately
|
||||
* be published, the message will be returned to the client, and will eventually
|
||||
* end up in your ChannelHandler::onReturned() method.
|
||||
*
|
||||
* end up in your onReturned() handler method.
|
||||
*
|
||||
* @param exchange the exchange to publish to
|
||||
* @param routingkey the routing key
|
||||
* @param flags optional flags (see above)
|
||||
* @param envelope the full envelope to send
|
||||
* @param message the message to send
|
||||
* @param size size of the message
|
||||
*/
|
||||
bool publish(const std::string &exchange, const std::string &routingKey, int flags, const Envelope &envelope);
|
||||
|
||||
bool publish(const std::string &exchange, const std::string &routingKey, const Envelope &envelope);
|
||||
|
||||
/**
|
||||
* Set the Quality of Service (QOS) of the entire connection
|
||||
* @param prefetchCount maximum number of messages to prefetch
|
||||
* @return bool whether the Qos frame is sent.
|
||||
*
|
||||
* This function returns a deferred handler. Callbacks can be installed
|
||||
* using onSuccess(), onError() and onFinalize() methods.
|
||||
*/
|
||||
bool setQos(uint16_t prefetchCount);
|
||||
Deferred &setQos(uint16_t prefetchCount);
|
||||
|
||||
/**
|
||||
* Tell the RabbitMQ server that we're ready to consume messages
|
||||
|
|
@ -260,20 +353,43 @@ public:
|
|||
* @param tag a consumer tag that will be associated with this consume operation
|
||||
* @param flags additional flags
|
||||
* @param arguments additional arguments
|
||||
* @return bool
|
||||
*
|
||||
* This function returns a deferred handler. Callbacks can be installed
|
||||
* using onSuccess(), onError() and onFinalize() methods.
|
||||
*
|
||||
* The onSuccess() callback that you can install should have the following signature:
|
||||
*
|
||||
* void myCallback(AMQP::Channel *channel, const std::string& tag);
|
||||
*
|
||||
* For example: channel.declareQueue("myqueue").onSuccess([](AMQP::Channel *channel, const std::string& tag) {
|
||||
*
|
||||
* std::cout << "Started consuming under tag " << tag << std::endl;
|
||||
*
|
||||
* });
|
||||
*/
|
||||
bool consume(const std::string &queue, const std::string &tag, int flags, const Table &arguments);
|
||||
|
||||
DeferredConsumer& consume(const std::string &queue, const std::string &tag, int flags, const Table &arguments);
|
||||
|
||||
/**
|
||||
* Cancel a running consumer
|
||||
* @param tag the consumer tag
|
||||
* @param flags optional flags
|
||||
* @return bool
|
||||
*
|
||||
* This function returns a deferred handler. Callbacks can be installed
|
||||
* using onSuccess(), onError() and onFinalize() methods.
|
||||
*
|
||||
* The onSuccess() callback that you can install should have the following signature:
|
||||
*
|
||||
* void myCallback(AMQP::Channel *channel, const std::string& tag);
|
||||
*
|
||||
* For example: channel.declareQueue("myqueue").onSuccess([](AMQP::Channel *channel, const std::string& tag) {
|
||||
*
|
||||
* std::cout << "Started consuming under tag " << tag << std::endl;
|
||||
*
|
||||
* });
|
||||
*/
|
||||
bool cancel(const std::string &tag, int flags);
|
||||
DeferredCancel &cancel(const std::string &tag);
|
||||
|
||||
/**
|
||||
* Acknoledge a message
|
||||
* Acknowledge a message
|
||||
* @param deliveryTag the delivery tag
|
||||
* @param flags optional flags
|
||||
* @return bool
|
||||
|
|
@ -287,19 +403,23 @@ public:
|
|||
* @return bool
|
||||
*/
|
||||
bool reject(uint64_t deliveryTag, int flags);
|
||||
|
||||
|
||||
/**
|
||||
* Recover messages that were not yet ack'ed
|
||||
* @param flags optional flags
|
||||
* @return bool
|
||||
*
|
||||
* This function returns a deferred handler. Callbacks can be installed
|
||||
* using onSuccess(), onError() and onFinalize() methods.
|
||||
*/
|
||||
bool recover(int flags);
|
||||
|
||||
Deferred &recover(int flags);
|
||||
|
||||
/**
|
||||
* Close the current channel
|
||||
* @return bool
|
||||
*
|
||||
* This function returns a deferred handler. Callbacks can be installed
|
||||
* using onSuccess(), onError() and onFinalize() methods.
|
||||
*/
|
||||
bool close();
|
||||
Deferred &close();
|
||||
|
||||
/**
|
||||
* Get the channel we're working on
|
||||
|
|
@ -309,204 +429,185 @@ public:
|
|||
{
|
||||
return _id;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Send a frame over the channel
|
||||
* @param frame frame to send
|
||||
* @return bool was frame succesfully sent?
|
||||
*/
|
||||
bool send(const Frame &frame);
|
||||
|
||||
|
||||
/**
|
||||
* Report to the handler that the channel is closed
|
||||
* Signal the channel that a synchronous operation
|
||||
* was completed. After this operation, waiting
|
||||
* frames can be sent out.
|
||||
*/
|
||||
void reportClosed()
|
||||
{
|
||||
// change state
|
||||
_state = state_closed;
|
||||
|
||||
// inform handler
|
||||
if (_handler) _handler->onClosed(_parent);
|
||||
}
|
||||
|
||||
/**
|
||||
* Report to the handler that the channel is paused
|
||||
*/
|
||||
void reportPaused()
|
||||
{
|
||||
// inform handler
|
||||
if (_handler) _handler->onPaused(_parent);
|
||||
}
|
||||
|
||||
/**
|
||||
* Report to the handler that the channel is resumed
|
||||
*/
|
||||
void reportResumed()
|
||||
{
|
||||
// inform handler
|
||||
if (_handler) _handler->onResumed(_parent);
|
||||
}
|
||||
|
||||
void synchronized();
|
||||
|
||||
/**
|
||||
* Report to the handler that the channel is opened
|
||||
*/
|
||||
void reportReady()
|
||||
{
|
||||
// callbacks could destroy us, so monitor it
|
||||
Monitor monitor(this);
|
||||
|
||||
// inform handler
|
||||
if (_handler) _handler->onReady(_parent);
|
||||
if (_readyCallback) _readyCallback();
|
||||
|
||||
// if the monitor is still valid, we exit synchronous mode now
|
||||
if (monitor.valid()) synchronized();
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Report an error message on a channel
|
||||
* @param message
|
||||
* Report to the handler that the channel is closed
|
||||
*
|
||||
* Returns whether the channel object is still valid
|
||||
*/
|
||||
void reportError(const std::string &message)
|
||||
bool reportClosed()
|
||||
{
|
||||
// change state
|
||||
_state = state_closed;
|
||||
|
||||
|
||||
// and pass on to the reportSuccess() method which will call the
|
||||
// appropriate deferred object to report the successful operation
|
||||
return reportSuccess();
|
||||
|
||||
// technically, we should exit synchronous method now
|
||||
// since the synchronous channel close frame has been
|
||||
// acknowledged by the server.
|
||||
//
|
||||
// but since the channel was just closed, there is no
|
||||
// real point in doing this, as we cannot send frames
|
||||
// out anymore.
|
||||
}
|
||||
|
||||
/**
|
||||
* Report success
|
||||
*
|
||||
* Returns whether the channel object is still valid
|
||||
*/
|
||||
template <typename... Arguments>
|
||||
bool reportSuccess(Arguments ...parameters)
|
||||
{
|
||||
// skip if there is no oldest callback
|
||||
if (!_oldestCallback) return true;
|
||||
|
||||
// we are going to call callbacks that could destruct the channel
|
||||
Monitor monitor(this);
|
||||
|
||||
// call the callback
|
||||
auto *next = _oldestCallback->reportSuccess(std::forward<Arguments>(parameters)...);
|
||||
|
||||
// leap out if channel no longer exists
|
||||
if (!monitor.valid()) return false;
|
||||
|
||||
// set the oldest callback
|
||||
_oldestCallback.reset(next);
|
||||
|
||||
// if there was no next callback, the newest callback was just used
|
||||
if (!next) _newestCallback = nullptr;
|
||||
|
||||
// we are still valid
|
||||
return true;
|
||||
}
|
||||
|
||||
/**
|
||||
* Report an error message on a channel
|
||||
* @param message the error message
|
||||
* @param notifyhandler should the channel-wide handler also be called?
|
||||
*/
|
||||
void reportError(const char *message, bool notifyhandler = true)
|
||||
{
|
||||
// change state
|
||||
_state = state_closed;
|
||||
|
||||
// we are going to call callbacks that could destruct the channel
|
||||
Monitor monitor(this);
|
||||
|
||||
// call the oldest
|
||||
if (_oldestCallback)
|
||||
{
|
||||
// call the callback
|
||||
auto *next = _oldestCallback->reportError(message);
|
||||
|
||||
// leap out if channel no longer exists
|
||||
if (!monitor.valid()) return;
|
||||
|
||||
// set the oldest callback
|
||||
_oldestCallback.reset(next);
|
||||
}
|
||||
|
||||
// clean up all deferred other objects
|
||||
while (_oldestCallback)
|
||||
{
|
||||
// call the callback
|
||||
auto *next = _oldestCallback->reportError("Channel is in error state");
|
||||
|
||||
// leap out if channel no longer exists
|
||||
if (!monitor.valid()) return;
|
||||
|
||||
// set the oldest callback
|
||||
_oldestCallback.reset(next);
|
||||
}
|
||||
|
||||
// all callbacks have been processed, so we also can reset the pointer to the newest
|
||||
_newestCallback = nullptr;
|
||||
|
||||
// inform handler
|
||||
if (_handler) _handler->onError(_parent, message);
|
||||
if (notifyhandler && _errorCallback) _errorCallback(message);
|
||||
}
|
||||
|
||||
/**
|
||||
* Report that the exchange is succesfully declared
|
||||
* Install a consumer callback
|
||||
* @param consumertag The consumer tag
|
||||
* @param callback The callback to be called
|
||||
*/
|
||||
void reportExchangeDeclared()
|
||||
void install(const std::string &consumertag, const MessageCallback &callback)
|
||||
{
|
||||
if (_handler) _handler->onExchangeDeclared(_parent);
|
||||
}
|
||||
|
||||
/**
|
||||
* Report that the exchange is succesfully deleted
|
||||
*/
|
||||
void reportExchangeDeleted()
|
||||
{
|
||||
if (_handler) _handler->onExchangeDeleted(_parent);
|
||||
}
|
||||
|
||||
/**
|
||||
* Report that the exchange is bound
|
||||
*/
|
||||
void reportExchangeBound()
|
||||
{
|
||||
if (_handler) _handler->onExchangeBound(_parent);
|
||||
}
|
||||
|
||||
/**
|
||||
* Report that the exchange is unbound
|
||||
*/
|
||||
void reportExchangeUnbound()
|
||||
{
|
||||
if (_handler) _handler->onExchangeUnbound(_parent);
|
||||
}
|
||||
|
||||
/**
|
||||
* Report that the queue was succesfully declared
|
||||
* @param queueName name of the queue which was declared
|
||||
* @param messagecount number of messages currently in the queue
|
||||
* @param consumerCount number of active consumers in the queue
|
||||
*/
|
||||
void reportQueueDeclared(const std::string &queueName, uint32_t messageCount, uint32_t consumerCount)
|
||||
{
|
||||
if (_handler) _handler->onQueueDeclared(_parent, queueName, messageCount, consumerCount);
|
||||
}
|
||||
|
||||
/**
|
||||
* Report that a queue was succesfully bound
|
||||
*/
|
||||
void reportQueueBound()
|
||||
{
|
||||
if (_handler) _handler->onQueueBound(_parent);
|
||||
}
|
||||
|
||||
/**
|
||||
* Report that a queue was succesfully unbound
|
||||
*/
|
||||
void reportQueueUnbound()
|
||||
{
|
||||
if (_handler) _handler->onQueueUnbound(_parent);
|
||||
}
|
||||
|
||||
/**
|
||||
* Report that a queue was succesfully deleted
|
||||
* @param messageCount number of messages left in queue, now deleted
|
||||
*/
|
||||
void reportQueueDeleted(uint32_t messageCount)
|
||||
{
|
||||
if (_handler) _handler->onQueueDeleted(_parent, messageCount);
|
||||
}
|
||||
|
||||
/**
|
||||
* Report that a queue was succesfully purged
|
||||
* @param messageCount number of messages purged
|
||||
*/
|
||||
void reportQueuePurged(uint32_t messageCount)
|
||||
{
|
||||
if (_handler) _handler->onQueuePurged(_parent, messageCount);
|
||||
}
|
||||
|
||||
/**
|
||||
* Report that the qos has been set
|
||||
*/
|
||||
void reportQosSet()
|
||||
{
|
||||
if (_handler) _handler->onQosSet(_parent);
|
||||
}
|
||||
|
||||
/**
|
||||
* Report that a consumer has started
|
||||
* @param tag the consumer tag
|
||||
*/
|
||||
void reportConsumerStarted(const std::string &tag)
|
||||
{
|
||||
if (_handler) _handler->onConsumerStarted(_parent, tag);
|
||||
// install the callback if it is assigned
|
||||
if (callback) _consumers[consumertag] = callback;
|
||||
|
||||
// otherwise we erase the previously set callback
|
||||
else _consumers.erase(consumertag);
|
||||
}
|
||||
|
||||
/**
|
||||
* Report that a consumer has stopped
|
||||
* @param tag the consumer tag
|
||||
* Uninstall a consumer callback
|
||||
* @param consumertag The consumer tag
|
||||
*/
|
||||
void reportConsumerStopped(const std::string &tag)
|
||||
void uninstall(const std::string &consumertag)
|
||||
{
|
||||
if (_handler) _handler->onConsumerStopped(_parent, tag);
|
||||
// erase the callback
|
||||
_consumers.erase(consumertag);
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Report that a message was received
|
||||
*/
|
||||
void reportMessage();
|
||||
|
||||
/**
|
||||
* Report that the recover operation has started
|
||||
*/
|
||||
void reportRecovering()
|
||||
{
|
||||
if (_handler) _handler->onRecovering(_parent);
|
||||
}
|
||||
|
||||
/**
|
||||
* Create an incoming message
|
||||
* @param frame
|
||||
* @return MessageImpl
|
||||
* @return ConsumedMessage
|
||||
*/
|
||||
MessageImpl *message(const BasicDeliverFrame &frame);
|
||||
MessageImpl *message(const BasicReturnFrame &frame);
|
||||
|
||||
ConsumedMessage *message(const BasicDeliverFrame &frame);
|
||||
|
||||
/**
|
||||
* Retrieve the current incoming message
|
||||
* @return MessageImpl
|
||||
* @return ConsumedMessage
|
||||
*/
|
||||
MessageImpl *message()
|
||||
ConsumedMessage *message()
|
||||
{
|
||||
return _message;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* The channel class is its friend, thus can it instantiate this object
|
||||
*/
|
||||
friend class Channel;
|
||||
|
||||
|
||||
};
|
||||
|
||||
/**
|
||||
|
|
|
|||
|
|
@ -1,3 +1,4 @@
|
|||
#pragma once
|
||||
/**
|
||||
* Classes.h
|
||||
*
|
||||
|
|
|
|||
|
|
@ -1,3 +1,4 @@
|
|||
#pragma once
|
||||
/**
|
||||
* Class describing a mid-level Amqp connection
|
||||
*
|
||||
|
|
@ -74,7 +75,7 @@ public:
|
|||
* @param size size of the buffer to decode
|
||||
* @return number of bytes that were processed
|
||||
*/
|
||||
size_t parse(char *buffer, size_t size)
|
||||
size_t parse(const char *buffer, size_t size)
|
||||
{
|
||||
return _implementation.parse(buffer, size);
|
||||
}
|
||||
|
|
|
|||
|
|
@ -1,9 +1,10 @@
|
|||
#pragma once
|
||||
/**
|
||||
* ConnectionHandler.h
|
||||
*
|
||||
* Interface that should be implemented by the caller of the library and
|
||||
* that is passed to the AMQP connection. This interface contains all sorts
|
||||
* of methods that are called when data needs to be sent, or when the
|
||||
* of methods that are called when data needs to be sent, or when the
|
||||
* AMQP connection ends up in a broken state.
|
||||
*
|
||||
* @copyright 2014 Copernica BV
|
||||
|
|
@ -23,7 +24,7 @@ public:
|
|||
/**
|
||||
* Method that is called when data needs to be sent over the network
|
||||
*
|
||||
* Note that the AMQP library does no buffering by itself. This means
|
||||
* Note that the AMQP library does no buffering by itself. This means
|
||||
* that this method should always send out all data or do the buffering
|
||||
* itself.
|
||||
*
|
||||
|
|
@ -32,48 +33,49 @@ public:
|
|||
* @param size Size of the buffer
|
||||
*/
|
||||
virtual void onData(Connection *connection, const char *buffer, size_t size) = 0;
|
||||
|
||||
|
||||
/**
|
||||
* When the connection ends up in an error state this method is called.
|
||||
* This happens when data comes in that does not match the AMQP protocol
|
||||
*
|
||||
*
|
||||
* After this method is called, the connection no longer is in a valid
|
||||
* state and can no longer be used.
|
||||
*
|
||||
*
|
||||
* This method has an empty default implementation, although you are very
|
||||
* much advised to implement it. Because when an error occurs, the connection
|
||||
* much advised to implement it. When an error occurs, the connection
|
||||
* is no longer usable, so you probably want to know.
|
||||
*
|
||||
*
|
||||
* @param connection The connection that entered the error state
|
||||
* @param message Error message
|
||||
*/
|
||||
virtual void onError(Connection *connection, const std::string &message) {}
|
||||
|
||||
virtual void onError(Connection *connection, const char *message) {}
|
||||
|
||||
/**
|
||||
* Method that is called when the login attempt succeeded. After this method
|
||||
* was called, the connection is ready to use. This is the first method
|
||||
* is called, the connection is ready to use. This is the first method
|
||||
* that is normally called after you've constructed the connection object.
|
||||
*
|
||||
*
|
||||
* According to the AMQP protocol, you must wait for the connection to become
|
||||
* ready (and this onConnected method to be called) before you can start
|
||||
* using the Connection object. However, this AMQP library will cache all
|
||||
* methods that you call before the connection is ready, so in reality there
|
||||
* is no real reason to wait.
|
||||
* is no real reason to wait for this method to be called before you send
|
||||
* the first instructions.
|
||||
*
|
||||
* @param connection The connection that can now be used
|
||||
*/
|
||||
virtual void onConnected(Connection *connection) {}
|
||||
|
||||
|
||||
/**
|
||||
* Method that is called when the connection was closed.
|
||||
*
|
||||
*
|
||||
* This is the counter part of a call to Connection::close() and it confirms
|
||||
* that the connection was correctly closed.
|
||||
*
|
||||
*
|
||||
* @param connection The connection that was closed and that is now unusable
|
||||
*/
|
||||
virtual void onClosed(Connection *connection) {}
|
||||
|
||||
|
||||
};
|
||||
|
||||
/**
|
||||
|
|
|
|||
|
|
@ -1,10 +1,11 @@
|
|||
#pragma once
|
||||
/**
|
||||
* Connection implementation
|
||||
*
|
||||
* This is the implementation of the connection - a class that can only be
|
||||
* constructed by the connection class itselves and that has all sorts of
|
||||
* methods that are only useful inside the library
|
||||
*
|
||||
*
|
||||
* @copyright 2014 Copernica BV
|
||||
*/
|
||||
|
||||
|
|
@ -43,13 +44,13 @@ protected:
|
|||
state_closing, // connection is busy closing (we have sent the close frame)
|
||||
state_closed // connection is closed
|
||||
} _state = state_protocol;
|
||||
|
||||
|
||||
/**
|
||||
* Has the close() method been called?
|
||||
* @var bool
|
||||
*/
|
||||
bool _closed = false;
|
||||
|
||||
|
||||
/**
|
||||
* All channels that are active
|
||||
* @var map
|
||||
|
|
@ -61,13 +62,13 @@ protected:
|
|||
* @var uint16_t
|
||||
*/
|
||||
uint16_t _nextFreeChannel = 1;
|
||||
|
||||
|
||||
/**
|
||||
* Max number of channels (0 for unlimited)
|
||||
* @var uint16_t
|
||||
*/
|
||||
uint16_t _maxChannels = 0;
|
||||
|
||||
|
||||
/**
|
||||
* Max frame size
|
||||
* @var uint32_t
|
||||
|
|
@ -79,19 +80,19 @@ protected:
|
|||
* @var Login
|
||||
*/
|
||||
Login _login;
|
||||
|
||||
|
||||
/**
|
||||
* Vhost to connect to
|
||||
* @var string
|
||||
*/
|
||||
std::string _vhost;
|
||||
|
||||
|
||||
/**
|
||||
* Queued messages that should be sent after the connection has been established
|
||||
* @var queue
|
||||
*/
|
||||
std::queue<OutBuffer> _queue;
|
||||
|
||||
|
||||
/**
|
||||
* Helper method to send the close frame
|
||||
* Return value tells if the connection is still valid
|
||||
|
|
@ -99,17 +100,16 @@ protected:
|
|||
*/
|
||||
bool sendClose();
|
||||
|
||||
|
||||
private:
|
||||
/**
|
||||
* Construct an AMQP object based on full login data
|
||||
*
|
||||
*
|
||||
* The first parameter is a handler object. This handler class is
|
||||
* an interface that should be implemented by the caller.
|
||||
*
|
||||
*
|
||||
* Note that the constructor is private to ensure that nobody can construct
|
||||
* this class, only the real Connection class via a friend construct
|
||||
*
|
||||
*
|
||||
* @param parent Parent connection object
|
||||
* @param handler Connection handler
|
||||
* @param login Login data
|
||||
|
|
@ -131,7 +131,7 @@ public:
|
|||
// must be busy doing the connection handshake, or already connected
|
||||
return _state == state_handshake || _state == state_connected;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Mark the protocol as being ok
|
||||
*/
|
||||
|
|
@ -140,7 +140,7 @@ public:
|
|||
// move on to handshake state
|
||||
if (_state == state_protocol) _state = state_handshake;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Are we fully connected?
|
||||
* @return bool
|
||||
|
|
@ -150,12 +150,12 @@ public:
|
|||
// state must be connected
|
||||
return _state == state_connected;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Mark the connection as connected
|
||||
*/
|
||||
void setConnected();
|
||||
|
||||
|
||||
/**
|
||||
* Retrieve the login data
|
||||
* @return Login
|
||||
|
|
@ -164,7 +164,7 @@ public:
|
|||
{
|
||||
return _login;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Retrieve the vhost
|
||||
* @return string
|
||||
|
|
@ -184,7 +184,7 @@ public:
|
|||
_maxChannels = channels;
|
||||
_maxFrame = size;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* The max frame size
|
||||
* @return uint32_t
|
||||
|
|
@ -193,7 +193,7 @@ public:
|
|||
{
|
||||
return _maxFrame;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* The max payload size for body frames
|
||||
* @return uint32_t
|
||||
|
|
@ -203,7 +203,7 @@ public:
|
|||
// 8 bytes for header and end-of-frame byte
|
||||
return _maxFrame - 8;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Add a channel to the connection, and return the channel ID that it
|
||||
* is allowed to use, or 0 when no more ID's are available
|
||||
|
|
@ -211,16 +211,16 @@ public:
|
|||
* @return uint16_t
|
||||
*/
|
||||
uint16_t add(ChannelImpl *channel);
|
||||
|
||||
|
||||
/**
|
||||
* Remove a channel
|
||||
* @param channel
|
||||
*/
|
||||
void remove(ChannelImpl *channel);
|
||||
|
||||
|
||||
/**
|
||||
* Parse the buffer into a recognized frame
|
||||
*
|
||||
*
|
||||
* Every time that data comes in on the connection, you should call this method to parse
|
||||
* the incoming data, and let it handle by the AMQP library. This method returns the number
|
||||
* of bytes that were processed.
|
||||
|
|
@ -234,7 +234,7 @@ public:
|
|||
* @param size size of the buffer to decode
|
||||
* @return number of bytes that were processed
|
||||
*/
|
||||
size_t parse(char *buffer, size_t size);
|
||||
size_t parse(const char *buffer, size_t size);
|
||||
|
||||
/**
|
||||
* Close the connection
|
||||
|
|
@ -245,21 +245,28 @@ public:
|
|||
|
||||
/**
|
||||
* Send a frame over the connection
|
||||
*
|
||||
*
|
||||
* This is an internal method that you normally do not have to call yourself
|
||||
*
|
||||
*
|
||||
* @param frame the frame to send
|
||||
* @return bool
|
||||
*/
|
||||
bool send(const Frame &frame);
|
||||
|
||||
/**
|
||||
* Send buffered data over the connection
|
||||
*
|
||||
* @param buffer the buffer with data to send
|
||||
*/
|
||||
bool send(OutBuffer &&buffer);
|
||||
|
||||
/**
|
||||
* Get a channel by its identifier
|
||||
*
|
||||
*
|
||||
* This method only works if you had already created the channel before.
|
||||
* This is an internal method that you will not need if you cache the channel
|
||||
* object.
|
||||
*
|
||||
*
|
||||
* @param number channel identifier
|
||||
* @return channel the channel object, or nullptr if not yet created
|
||||
*/
|
||||
|
|
@ -273,15 +280,28 @@ public:
|
|||
* Report an error message
|
||||
* @param message
|
||||
*/
|
||||
void reportError(const std::string &message)
|
||||
void reportError(const char *message)
|
||||
{
|
||||
// set connection state to closed
|
||||
_state = state_closed;
|
||||
|
||||
// monitor because every callback could invalidate the connection
|
||||
Monitor monitor(this);
|
||||
|
||||
// all deferred result objects in the channels should report this error too
|
||||
for (auto &iter : _channels)
|
||||
{
|
||||
// report the errors
|
||||
iter.second->reportError(message, false);
|
||||
|
||||
// leap out if no longer valid
|
||||
if (!monitor.valid()) return;
|
||||
}
|
||||
|
||||
// inform handler
|
||||
_handler->onError(_parent, message);
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Report that the connection is closed
|
||||
*/
|
||||
|
|
@ -289,7 +309,7 @@ public:
|
|||
{
|
||||
// change state
|
||||
_state = state_closed;
|
||||
|
||||
|
||||
// inform the handler
|
||||
_handler->onClosed(_parent);
|
||||
}
|
||||
|
|
@ -298,7 +318,7 @@ public:
|
|||
* The actual connection is a friend and can construct this class
|
||||
*/
|
||||
friend class Connection;
|
||||
|
||||
friend class ChannelImpl;
|
||||
};
|
||||
|
||||
/**
|
||||
|
|
|
|||
|
|
@ -1,3 +1,4 @@
|
|||
#pragma once
|
||||
/**
|
||||
* Decimal field type for AMQP
|
||||
*
|
||||
|
|
@ -82,9 +83,19 @@ public:
|
|||
* Create a new identical instance of this object
|
||||
* @return Field*
|
||||
*/
|
||||
virtual Field *clone() const override
|
||||
virtual std::shared_ptr<Field> clone() const override
|
||||
{
|
||||
return new DecimalField(_places, _number);
|
||||
return std::make_shared<DecimalField>(_places, _number);
|
||||
}
|
||||
|
||||
/**
|
||||
* Output the object to a stream
|
||||
* @param std::ostream
|
||||
*/
|
||||
virtual void output(std::ostream &stream) const override
|
||||
{
|
||||
// output floating point value
|
||||
stream << "decimal(" << _number / pow(10, _places) << ")";
|
||||
}
|
||||
|
||||
/**
|
||||
|
|
|
|||
|
|
@ -0,0 +1,252 @@
|
|||
/**
|
||||
* Deferred.h
|
||||
*
|
||||
* Class describing a set of actions that could
|
||||
* possibly happen in the future that can be
|
||||
* caught.
|
||||
*
|
||||
* @copyright 2014 Copernica BV
|
||||
*/
|
||||
|
||||
/**
|
||||
* Set up namespace
|
||||
*/
|
||||
namespace AMQP {
|
||||
|
||||
// forward declaration
|
||||
class ChannelImpl;
|
||||
class Callbacks;
|
||||
|
||||
/**
|
||||
* Class definition
|
||||
*/
|
||||
class Deferred
|
||||
{
|
||||
protected:
|
||||
/**
|
||||
* Callback to execute on success
|
||||
* @var SuccessCallback
|
||||
*/
|
||||
SuccessCallback _successCallback;
|
||||
|
||||
/**
|
||||
* Callback to execute on failure
|
||||
* @var ErrorCallback
|
||||
*/
|
||||
ErrorCallback _errorCallback;
|
||||
|
||||
/**
|
||||
* Callback to execute either way
|
||||
* @var FinalizeCallback
|
||||
*/
|
||||
FinalizeCallback _finalizeCallback;
|
||||
|
||||
/**
|
||||
* Pointer to the next deferred object
|
||||
* @var Deferred
|
||||
*/
|
||||
Deferred *_next = nullptr;
|
||||
|
||||
/**
|
||||
* Do we already know we failed?
|
||||
* @var bool
|
||||
*/
|
||||
bool _failed;
|
||||
|
||||
|
||||
/**
|
||||
* The next deferred object
|
||||
* @return Deferred
|
||||
*/
|
||||
Deferred *next() const
|
||||
{
|
||||
return _next;
|
||||
}
|
||||
|
||||
/**
|
||||
* Indicate success
|
||||
* @return Deferred Next deferred result
|
||||
*/
|
||||
Deferred *reportSuccess() const
|
||||
{
|
||||
// execute callbacks if registered
|
||||
if (_successCallback) _successCallback();
|
||||
if (_finalizeCallback) _finalizeCallback();
|
||||
|
||||
// return the next deferred result
|
||||
return _next;
|
||||
}
|
||||
|
||||
/**
|
||||
* Report success for queue declared messages
|
||||
* @param name Name of the new queue
|
||||
* @param messagecount Number of messages in the queue
|
||||
* @param consumercount Number of consumers linked to the queue
|
||||
* @return Deferred Next deferred result
|
||||
*/
|
||||
virtual Deferred *reportSuccess(const std::string &name, uint32_t messagecount, uint32_t consumercount) const
|
||||
{
|
||||
// this is the same as a regular success message
|
||||
return reportSuccess();
|
||||
}
|
||||
|
||||
/**
|
||||
* Report success for frames that report delete operations
|
||||
* @param messagecount Number of messages that were deleted
|
||||
* @return Deferred
|
||||
*/
|
||||
virtual Deferred *reportSuccess(uint32_t messagecount) const
|
||||
{
|
||||
// this is the same as a regular success message
|
||||
return reportSuccess();
|
||||
}
|
||||
|
||||
/**
|
||||
* Report success for frames that report cancel operations
|
||||
* @param name Consumer tag that is cancelled
|
||||
* @return Deferred
|
||||
*/
|
||||
virtual Deferred *reportSuccess(const std::string &name) const
|
||||
{
|
||||
// this is the same as a regular success message
|
||||
return reportSuccess();
|
||||
}
|
||||
|
||||
/**
|
||||
* Indicate failure
|
||||
* @param error Description of the error that occured
|
||||
* @return Deferred Next deferred result
|
||||
*/
|
||||
Deferred *reportError(const char *error)
|
||||
{
|
||||
// from this moment on the object should be listed as failed
|
||||
_failed = true;
|
||||
|
||||
// execute callbacks if registered
|
||||
if (_errorCallback) _errorCallback(error);
|
||||
if (_finalizeCallback) _finalizeCallback();
|
||||
|
||||
// return the next deferred result
|
||||
return _next;
|
||||
}
|
||||
|
||||
/**
|
||||
* Add a pointer to the next deferred result
|
||||
* @param deferred
|
||||
*/
|
||||
void add(Deferred *deferred)
|
||||
{
|
||||
// store pointer
|
||||
_next = deferred;
|
||||
}
|
||||
|
||||
/**
|
||||
* The channel implementation may call our
|
||||
* private members and construct us
|
||||
*/
|
||||
friend class ChannelImpl;
|
||||
friend class Callbacks;
|
||||
|
||||
protected:
|
||||
/**
|
||||
* Protected constructor that can only be called
|
||||
* from within the channel implementation
|
||||
*
|
||||
* @param failed are we already failed?
|
||||
*/
|
||||
Deferred(bool failed = false) : _failed(failed) {}
|
||||
|
||||
public:
|
||||
/**
|
||||
* Deleted copy and move constructors
|
||||
*/
|
||||
Deferred(const Deferred &that) = delete;
|
||||
Deferred(Deferred &&that) = delete;
|
||||
|
||||
/**
|
||||
* Destructor
|
||||
*/
|
||||
virtual ~Deferred() {}
|
||||
|
||||
/**
|
||||
* Cast to a boolean
|
||||
*/
|
||||
operator bool ()
|
||||
{
|
||||
return !_failed;
|
||||
}
|
||||
|
||||
/**
|
||||
* Register a function to be called
|
||||
* if and when the operation succesfully
|
||||
* completes.
|
||||
*
|
||||
* Only one callback can be registered at a time.
|
||||
* Successive calls to this function will clear
|
||||
* callbacks registered before.
|
||||
*
|
||||
* @param callback the callback to execute
|
||||
*/
|
||||
Deferred &onSuccess(const SuccessCallback &callback)
|
||||
{
|
||||
// store callback
|
||||
_successCallback = callback;
|
||||
|
||||
// allow chaining
|
||||
return *this;
|
||||
}
|
||||
|
||||
/**
|
||||
* Register a function to be called
|
||||
* if and when the operation fails.
|
||||
*
|
||||
* Only one callback can be registered at a time.
|
||||
* Successive calls to this function will clear
|
||||
* callbacks registered before.
|
||||
*
|
||||
* @param callback the callback to execute
|
||||
*/
|
||||
Deferred &onError(const ErrorCallback &callback)
|
||||
{
|
||||
// store callback
|
||||
_errorCallback = callback;
|
||||
|
||||
// if the object is already in a failed state, we call the callback right away
|
||||
if (_failed) callback("Frame could not be sent");
|
||||
|
||||
// allow chaining
|
||||
return *this;
|
||||
}
|
||||
|
||||
/**
|
||||
* Register a function to be called
|
||||
* if and when the operation completes
|
||||
* or fails. This function will be called
|
||||
* either way.
|
||||
*
|
||||
* In the case of success, the provided
|
||||
* error parameter will be an empty string.
|
||||
*
|
||||
* Only one callback can be registered at at time.
|
||||
* Successive calls to this function will clear
|
||||
* callbacks registered before.
|
||||
*
|
||||
* @param callback the callback to execute
|
||||
*/
|
||||
Deferred &onFinalize(const FinalizeCallback &callback)
|
||||
{
|
||||
// store callback
|
||||
_finalizeCallback = callback;
|
||||
|
||||
// if the object is already in a failed state, we call the callback right away
|
||||
if (_failed) callback();
|
||||
|
||||
// allow chaining
|
||||
return *this;
|
||||
}
|
||||
};
|
||||
|
||||
/**
|
||||
* End namespace
|
||||
*/
|
||||
}
|
||||
|
|
@ -0,0 +1,94 @@
|
|||
/**
|
||||
* DeferredCancel.h
|
||||
*
|
||||
* Deferred callback for instructions that cancel a running consumer. This
|
||||
* deferred object allows one to register a callback that also gets the
|
||||
* consumer tag as one of its parameters.
|
||||
*
|
||||
* @copyright 2014 Copernica BV
|
||||
*/
|
||||
|
||||
/**
|
||||
* Set up namespace
|
||||
*/
|
||||
namespace AMQP {
|
||||
|
||||
/**
|
||||
* We extend from the default deferred and add extra functionality
|
||||
*/
|
||||
class DeferredCancel : public Deferred
|
||||
{
|
||||
private:
|
||||
/**
|
||||
* Pointer to the channel
|
||||
* @var ChannelImpl
|
||||
*/
|
||||
ChannelImpl *_channel;
|
||||
|
||||
/**
|
||||
* Callback to execute when the instruction is completed
|
||||
* @var CancelCallback
|
||||
*/
|
||||
CancelCallback _cancelCallback;
|
||||
|
||||
/**
|
||||
* Report success for frames that report cancel operations
|
||||
* @param name Consumer tag that is cancelled
|
||||
* @return Deferred
|
||||
*/
|
||||
virtual Deferred *reportSuccess(const std::string &name) const override;
|
||||
|
||||
/**
|
||||
* The channel implementation may call our
|
||||
* private members and construct us
|
||||
*/
|
||||
friend class ChannelImpl;
|
||||
friend class ConsumedMessage;
|
||||
|
||||
protected:
|
||||
/**
|
||||
* Protected constructor that can only be called
|
||||
* from within the channel implementation
|
||||
*
|
||||
* @param channel Pointer to the channel
|
||||
* @param failed Are we already failed?
|
||||
*/
|
||||
DeferredCancel(ChannelImpl *channel, bool failed = false) :
|
||||
Deferred(failed), _channel(channel) {}
|
||||
|
||||
public:
|
||||
/**
|
||||
* Register a function to be called when the cancel operation succeeded
|
||||
*
|
||||
* Only one callback can be registered. Successive calls
|
||||
* to this function will clear callbacks registered before.
|
||||
*
|
||||
* @param callback the callback to execute
|
||||
*/
|
||||
DeferredCancel &onSuccess(const CancelCallback &callback)
|
||||
{
|
||||
// store callback
|
||||
_cancelCallback = callback;
|
||||
|
||||
// allow chaining
|
||||
return *this;
|
||||
}
|
||||
|
||||
/**
|
||||
* Register the function that is called when the cancel operation succeeded
|
||||
* @param callback
|
||||
*/
|
||||
DeferredCancel &onSuccess(const SuccessCallback &callback)
|
||||
{
|
||||
// call base
|
||||
Deferred::onSuccess(callback);
|
||||
|
||||
// allow chaining
|
||||
return *this;
|
||||
}
|
||||
};
|
||||
|
||||
/**
|
||||
* End namespace
|
||||
*/
|
||||
}
|
||||
|
|
@ -0,0 +1,123 @@
|
|||
/**
|
||||
* DeferredConsumer.h
|
||||
*
|
||||
* Deferred callback for consumers
|
||||
*
|
||||
* @copyright 2014 Copernica BV
|
||||
*/
|
||||
|
||||
/**
|
||||
* Set up namespace
|
||||
*/
|
||||
namespace AMQP {
|
||||
|
||||
/**
|
||||
* We extend from the default deferred and add extra functionality
|
||||
*/
|
||||
class DeferredConsumer : public Deferred
|
||||
{
|
||||
private:
|
||||
/**
|
||||
* The channel to which the consumer is linked
|
||||
* @var ChannelImpl
|
||||
*/
|
||||
ChannelImpl *_channel;
|
||||
|
||||
/**
|
||||
* Callback to execute when a message arrives
|
||||
* @var ConsumeCallback
|
||||
*/
|
||||
ConsumeCallback _consumeCallback;
|
||||
|
||||
/**
|
||||
* Callback for incoming messages
|
||||
* @var MessageCallback
|
||||
*/
|
||||
MessageCallback _messageCallback;
|
||||
|
||||
|
||||
/**
|
||||
* Report success for frames that report start consumer operations
|
||||
* @param name Consumer tag that is started
|
||||
* @return Deferred
|
||||
*/
|
||||
virtual Deferred *reportSuccess(const std::string &name) const override;
|
||||
|
||||
/**
|
||||
* The channel implementation may call our
|
||||
* private members and construct us
|
||||
*/
|
||||
friend class ChannelImpl;
|
||||
friend class ConsumedMessage;
|
||||
|
||||
protected:
|
||||
/**
|
||||
* Protected constructor that can only be called
|
||||
* from within the channel implementation
|
||||
*
|
||||
* @param channel the channel implementation
|
||||
* @param failed are we already failed?
|
||||
*/
|
||||
DeferredConsumer(ChannelImpl *channel, bool failed = false) :
|
||||
Deferred(failed), _channel(channel) {}
|
||||
|
||||
public:
|
||||
/**
|
||||
* Register the function that is called when the consumer starts
|
||||
* @param callback
|
||||
*/
|
||||
DeferredConsumer &onSuccess(const ConsumeCallback &callback)
|
||||
{
|
||||
// store the callback
|
||||
_consumeCallback = callback;
|
||||
|
||||
// allow chaining
|
||||
return *this;
|
||||
}
|
||||
|
||||
/**
|
||||
* Register the function that is called when the consumer starts
|
||||
* @param callback
|
||||
*/
|
||||
DeferredConsumer &onSuccess(const SuccessCallback &callback)
|
||||
{
|
||||
// call base
|
||||
Deferred::onSuccess(callback);
|
||||
|
||||
// allow chaining
|
||||
return *this;
|
||||
}
|
||||
|
||||
/**
|
||||
* Register a function to be called when a message arrives
|
||||
* This fuction is also available as onMessage() because I always forget which name I gave to it
|
||||
* @param callback the callback to execute
|
||||
*/
|
||||
DeferredConsumer &onReceived(const MessageCallback &callback)
|
||||
{
|
||||
// store callback
|
||||
_messageCallback = callback;
|
||||
|
||||
// allow chaining
|
||||
return *this;
|
||||
}
|
||||
|
||||
/**
|
||||
* Register a function to be called when a message arrives
|
||||
* This fuction is also available as onMessage() because I always forget which name I gave to it
|
||||
* @param callback the callback to execute
|
||||
*/
|
||||
DeferredConsumer &onMessage(const MessageCallback &callback)
|
||||
{
|
||||
// store callback
|
||||
_messageCallback = callback;
|
||||
|
||||
// allow chaining
|
||||
return *this;
|
||||
}
|
||||
};
|
||||
|
||||
/**
|
||||
* End namespace
|
||||
*/
|
||||
}
|
||||
|
|
@ -0,0 +1,99 @@
|
|||
/**
|
||||
* DeferredDelete.h
|
||||
*
|
||||
* Deferred callback for instructions that delete or purge queues, and that
|
||||
* want to report the number of deleted messages.
|
||||
*
|
||||
* @copyright 2014 Copernica BV
|
||||
*/
|
||||
|
||||
/**
|
||||
* Set up namespace
|
||||
*/
|
||||
namespace AMQP {
|
||||
|
||||
/**
|
||||
* We extend from the default deferred and add extra functionality
|
||||
*/
|
||||
class DeferredDelete : public Deferred
|
||||
{
|
||||
private:
|
||||
/**
|
||||
* Callback to execute when the instruction is completed
|
||||
* @var DeleteCallback
|
||||
*/
|
||||
DeleteCallback _deleteCallback;
|
||||
|
||||
/**
|
||||
* Report success for queue delete and queue purge messages
|
||||
* @param messagecount Number of messages that were deleted
|
||||
* @return Deferred Next deferred result
|
||||
*/
|
||||
virtual Deferred *reportSuccess(uint32_t messagecount) const override
|
||||
{
|
||||
// skip if no special callback was installed
|
||||
if (!_deleteCallback) return Deferred::reportSuccess();
|
||||
|
||||
// call the callback
|
||||
_deleteCallback(messagecount);
|
||||
|
||||
// call finalize callback
|
||||
if (_finalizeCallback) _finalizeCallback();
|
||||
|
||||
// return next object
|
||||
return _next;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* The channel implementation may call our
|
||||
* private members and construct us
|
||||
*/
|
||||
friend class ChannelImpl;
|
||||
friend class ConsumedMessage;
|
||||
|
||||
protected:
|
||||
/**
|
||||
* Protected constructor that can only be called
|
||||
* from within the channel implementation
|
||||
*
|
||||
* @param boolean are we already failed?
|
||||
*/
|
||||
DeferredDelete(bool failed = false) : Deferred(failed) {}
|
||||
|
||||
public:
|
||||
/**
|
||||
* Register a function to be called when the queue is deleted or purged
|
||||
*
|
||||
* Only one callback can be registered. Successive calls
|
||||
* to this function will clear callbacks registered before.
|
||||
*
|
||||
* @param callback the callback to execute
|
||||
*/
|
||||
DeferredDelete &onSuccess(const DeleteCallback &callback)
|
||||
{
|
||||
// store callback
|
||||
_deleteCallback = callback;
|
||||
|
||||
// allow chaining
|
||||
return *this;
|
||||
}
|
||||
|
||||
/**
|
||||
* Register the function that is called when the queue is deleted or purged
|
||||
* @param callback
|
||||
*/
|
||||
DeferredDelete &onSuccess(const SuccessCallback &callback)
|
||||
{
|
||||
// call base
|
||||
Deferred::onSuccess(callback);
|
||||
|
||||
// allow chaining
|
||||
return *this;
|
||||
}
|
||||
};
|
||||
|
||||
/**
|
||||
* End namespace
|
||||
*/
|
||||
}
|
||||
|
|
@ -0,0 +1,99 @@
|
|||
/**
|
||||
* DeferredQueue.h
|
||||
*
|
||||
* Deferred callback for "declare-queue" instructions.
|
||||
*
|
||||
* @copyright 2014 Copernica BV
|
||||
*/
|
||||
|
||||
/**
|
||||
* Set up namespace
|
||||
*/
|
||||
namespace AMQP {
|
||||
|
||||
/**
|
||||
* We extend from the default deferred and add extra functionality
|
||||
*/
|
||||
class DeferredQueue : public Deferred
|
||||
{
|
||||
private:
|
||||
/**
|
||||
* Callback to execute when the queue is declared
|
||||
* @var QueueCallback
|
||||
*/
|
||||
QueueCallback _queueCallback;
|
||||
|
||||
/**
|
||||
* Report success for queue declared messages
|
||||
* @param name Name of the new queue
|
||||
* @param messagecount Number of messages in the queue
|
||||
* @param consumercount Number of consumers linked to the queue
|
||||
* @return Deferred Next deferred result
|
||||
*/
|
||||
virtual Deferred *reportSuccess(const std::string &name, uint32_t messagecount, uint32_t consumercount) const override
|
||||
{
|
||||
// skip if no special callback was installed
|
||||
if (!_queueCallback) return Deferred::reportSuccess();
|
||||
|
||||
// call the queue callback
|
||||
_queueCallback(name, messagecount, consumercount);
|
||||
|
||||
// call finalize callback
|
||||
if (_finalizeCallback) _finalizeCallback();
|
||||
|
||||
// return next object
|
||||
return _next;
|
||||
}
|
||||
|
||||
/**
|
||||
* The channel implementation may call our
|
||||
* private members and construct us
|
||||
*/
|
||||
friend class ChannelImpl;
|
||||
friend class ConsumedMessage;
|
||||
|
||||
protected:
|
||||
/**
|
||||
* Protected constructor that can only be called
|
||||
* from within the channel implementation
|
||||
*
|
||||
* @param boolea are we already failed?
|
||||
*/
|
||||
DeferredQueue(bool failed = false) : Deferred(failed) {}
|
||||
|
||||
public:
|
||||
/**
|
||||
* Register a function to be called when the queue is declared
|
||||
*
|
||||
* Only one callback can be registered. Successive calls
|
||||
* to this function will clear callbacks registered before.
|
||||
*
|
||||
* @param callback the callback to execute
|
||||
*/
|
||||
DeferredQueue &onSuccess(const QueueCallback &callback)
|
||||
{
|
||||
// store callback
|
||||
_queueCallback = callback;
|
||||
|
||||
// allow chaining
|
||||
return *this;
|
||||
}
|
||||
|
||||
/**
|
||||
* Register the function that is called when the queue is declared
|
||||
* @param callback
|
||||
*/
|
||||
DeferredQueue &onSuccess(const SuccessCallback &callback)
|
||||
{
|
||||
// call base
|
||||
Deferred::onSuccess(callback);
|
||||
|
||||
// allow chaining
|
||||
return *this;
|
||||
}
|
||||
};
|
||||
|
||||
/**
|
||||
* End namespace
|
||||
*/
|
||||
}
|
||||
|
|
@ -1,3 +1,4 @@
|
|||
#pragma once
|
||||
/**
|
||||
* EntityImpl.h
|
||||
*
|
||||
|
|
|
|||
|
|
@ -1,3 +1,4 @@
|
|||
#pragma once
|
||||
/**
|
||||
* Envelope.h
|
||||
*
|
||||
|
|
|
|||
|
|
@ -1,3 +1,4 @@
|
|||
#pragma once
|
||||
/**
|
||||
* ExchangeType.h
|
||||
*
|
||||
|
|
|
|||
|
|
@ -1,3 +1,4 @@
|
|||
#pragma once
|
||||
/**
|
||||
* Available field types for AMQP
|
||||
*
|
||||
|
|
@ -36,7 +37,7 @@ public:
|
|||
* Create a new instance on the heap of this object, identical to the object passed
|
||||
* @return Field*
|
||||
*/
|
||||
virtual Field *clone() const = 0;
|
||||
virtual std::shared_ptr<Field> clone() const = 0;
|
||||
|
||||
/**
|
||||
* Get the size this field will take when
|
||||
|
|
@ -58,9 +59,44 @@ public:
|
|||
*/
|
||||
virtual char typeID() const = 0;
|
||||
|
||||
/**
|
||||
* Output the object to a stream
|
||||
* @param std::ostream
|
||||
*/
|
||||
virtual void output(std::ostream &stream) const = 0;
|
||||
|
||||
/**
|
||||
* Casting operators
|
||||
* @return mixed
|
||||
*/
|
||||
virtual operator const std::string& () const;
|
||||
virtual operator const char * () const { return nullptr; }
|
||||
virtual operator uint8_t () const { return 0; }
|
||||
virtual operator uint16_t () const { return 0; }
|
||||
virtual operator uint32_t () const { return 0; }
|
||||
virtual operator uint64_t () const { return 0; }
|
||||
virtual operator int8_t () const { return 0; }
|
||||
virtual operator int16_t () const { return 0; }
|
||||
virtual operator int32_t () const { return 0; }
|
||||
virtual operator int64_t () const { return 0; }
|
||||
virtual operator float () const { return 0; }
|
||||
virtual operator double () const { return 0; }
|
||||
virtual operator const Array& () const;
|
||||
virtual operator const Table& () const;
|
||||
};
|
||||
|
||||
/**
|
||||
* Custom output stream operator
|
||||
* @param stream
|
||||
* @param field
|
||||
* @return ostream
|
||||
*/
|
||||
inline std::ostream &operator<<(std::ostream &stream, const Field &field)
|
||||
{
|
||||
field.output(stream);
|
||||
return stream;
|
||||
}
|
||||
|
||||
/**
|
||||
* end namespace
|
||||
*/
|
||||
|
|
|
|||
|
|
@ -1,3 +1,4 @@
|
|||
#pragma once
|
||||
/**
|
||||
* Field proxy. Returned by the table. Can be casted to the
|
||||
* relevant native type (std::string or numeric)
|
||||
|
|
@ -195,199 +196,49 @@ public:
|
|||
// cast to a string
|
||||
return operator=(std::string(value));
|
||||
}
|
||||
|
||||
/**
|
||||
* Assign an array value
|
||||
* @param value
|
||||
* @return FieldProxy
|
||||
*/
|
||||
FieldProxy &operator=(const Array &value)
|
||||
{
|
||||
// assign value and allow chaining
|
||||
_source->set(_index, value);
|
||||
return *this;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get boolean value
|
||||
* @return BooleanSet
|
||||
* Assign a table value
|
||||
* @param value
|
||||
* @return FieldProxy
|
||||
*/
|
||||
operator BooleanSet ()
|
||||
FieldProxy &operator=(const Table &value)
|
||||
{
|
||||
// the value
|
||||
BooleanSet value;
|
||||
|
||||
// retrieve the value
|
||||
_source->get(_index, value);
|
||||
|
||||
// return the result
|
||||
return value;
|
||||
// assign value and allow chaining
|
||||
_source->set(_index, value);
|
||||
return *this;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the underlying field
|
||||
* @return Field
|
||||
*/
|
||||
const Field &get() const
|
||||
{
|
||||
return _source->get(_index);
|
||||
}
|
||||
|
||||
/**
|
||||
* Get a boolean
|
||||
* @return bool
|
||||
*/
|
||||
operator bool ()
|
||||
template <typename TARGET>
|
||||
operator TARGET () const
|
||||
{
|
||||
// the value
|
||||
BooleanSet value;
|
||||
|
||||
// retrieve the value
|
||||
_source->get(_index, value);
|
||||
|
||||
// return the result
|
||||
return value.value();
|
||||
}
|
||||
|
||||
/**
|
||||
* Get numeric value
|
||||
* @return int8_t
|
||||
*/
|
||||
operator int8_t ()
|
||||
{
|
||||
// the value
|
||||
Octet value;
|
||||
|
||||
// retrieve the value
|
||||
_source->get(_index, value);
|
||||
|
||||
// return the result
|
||||
return value.value();
|
||||
}
|
||||
|
||||
/**
|
||||
* Get numeric value
|
||||
* @return uint8_t
|
||||
*/
|
||||
operator uint8_t ()
|
||||
{
|
||||
// the value
|
||||
UOctet value;
|
||||
|
||||
// retrieve the value
|
||||
_source->get(_index, value);
|
||||
|
||||
// return the result
|
||||
return value.value();
|
||||
}
|
||||
|
||||
/**
|
||||
* Get numeric value
|
||||
* @return int16_t
|
||||
*/
|
||||
operator int16_t ()
|
||||
{
|
||||
// the value
|
||||
Short value;
|
||||
|
||||
// retrieve the value
|
||||
_source->get(_index, value);
|
||||
|
||||
// return the result
|
||||
return value.value();
|
||||
}
|
||||
|
||||
/**
|
||||
* Get numeric value
|
||||
* @return uint16_t
|
||||
*/
|
||||
operator uint16_t ()
|
||||
{
|
||||
// the value
|
||||
UShort value;
|
||||
|
||||
// retrieve the value
|
||||
_source->get(_index, value);
|
||||
|
||||
// return the result
|
||||
return value.value();
|
||||
}
|
||||
|
||||
/**
|
||||
* Get numeric value
|
||||
* @return int32_t
|
||||
*/
|
||||
operator int32_t ()
|
||||
{
|
||||
// the value
|
||||
Long value;
|
||||
|
||||
// retrieve the value
|
||||
_source->get(_index, value);
|
||||
|
||||
// return the result
|
||||
return value.value();
|
||||
}
|
||||
|
||||
/**
|
||||
* Get numeric value
|
||||
* @return uint32_t
|
||||
*/
|
||||
operator uint32_t ()
|
||||
{
|
||||
// the value
|
||||
ULong value;
|
||||
|
||||
// retrieve the value
|
||||
_source->get(_index, value);
|
||||
|
||||
// return the result
|
||||
return value.value();
|
||||
}
|
||||
|
||||
/**
|
||||
* Get numeric value
|
||||
* @return int64_t
|
||||
*/
|
||||
operator int64_t ()
|
||||
{
|
||||
// the value
|
||||
Long value;
|
||||
|
||||
// retrieve the value
|
||||
_source->get(_index, value);
|
||||
|
||||
// return the result
|
||||
return value.value();
|
||||
}
|
||||
|
||||
/**
|
||||
* Get numeric value
|
||||
* @return uint64_t
|
||||
*/
|
||||
operator uint64_t ()
|
||||
{
|
||||
// the value
|
||||
ULong value;
|
||||
|
||||
// retrieve the value
|
||||
_source->get(_index, value);
|
||||
|
||||
// return the result
|
||||
return value.value();
|
||||
}
|
||||
|
||||
/**
|
||||
* Get decimal value
|
||||
* @return DecimalField
|
||||
*/
|
||||
operator DecimalField ()
|
||||
{
|
||||
// the value
|
||||
DecimalField value;
|
||||
|
||||
// retrieve the value
|
||||
_source->get(_index, value);
|
||||
|
||||
// return the result
|
||||
return value.value();
|
||||
}
|
||||
|
||||
/**
|
||||
* Get string value
|
||||
* @return string
|
||||
*/
|
||||
operator std::string ()
|
||||
{
|
||||
// it has to be either a short or a long string
|
||||
ShortString shortValue;
|
||||
LongString longValue;
|
||||
|
||||
// try to retrieve the value
|
||||
if (_source->get(_index, shortValue)) return shortValue.value();
|
||||
if (_source->get(_index, longValue)) return longValue.value();
|
||||
|
||||
// no valid string found
|
||||
return std::string("");
|
||||
return _source->get(_index);
|
||||
}
|
||||
};
|
||||
|
||||
|
|
@ -395,6 +246,30 @@ public:
|
|||
typedef FieldProxy<Table, std::string> AssociativeFieldProxy;
|
||||
typedef FieldProxy<Array, uint8_t> ArrayFieldProxy;
|
||||
|
||||
/**
|
||||
* Custom output stream operator
|
||||
* @param stream
|
||||
* @param field
|
||||
* @return ostream
|
||||
*/
|
||||
inline std::ostream &operator<<(std::ostream &stream, const AssociativeFieldProxy &field)
|
||||
{
|
||||
// get underlying field, and output that
|
||||
return stream << field.get();
|
||||
}
|
||||
|
||||
/**
|
||||
* Custom output stream operator
|
||||
* @param stream
|
||||
* @param field
|
||||
* @return ostream
|
||||
*/
|
||||
inline std::ostream &operator<<(std::ostream &stream, const ArrayFieldProxy &field)
|
||||
{
|
||||
// get underlying field, and output that
|
||||
return stream << field.get();
|
||||
}
|
||||
|
||||
/**
|
||||
* end namespace
|
||||
*/
|
||||
|
|
|
|||
|
|
@ -1,3 +1,4 @@
|
|||
#pragma once
|
||||
/**
|
||||
* AmqpFlags.h
|
||||
*
|
||||
|
|
@ -25,7 +26,6 @@ extern const int global;
|
|||
extern const int nolocal;
|
||||
extern const int noack;
|
||||
extern const int exclusive;
|
||||
extern const int nowait;
|
||||
extern const int mandatory;
|
||||
extern const int immediate;
|
||||
extern const int redelivered;
|
||||
|
|
|
|||
|
|
@ -1,3 +1,4 @@
|
|||
#pragma once
|
||||
/**
|
||||
* The login information to access a server
|
||||
*
|
||||
|
|
|
|||
|
|
@ -1,3 +1,4 @@
|
|||
#pragma once
|
||||
/**
|
||||
* Message.h
|
||||
*
|
||||
|
|
|
|||
|
|
@ -1,3 +1,4 @@
|
|||
#pragma once
|
||||
/**
|
||||
* MetaData.h
|
||||
*
|
||||
|
|
|
|||
|
|
@ -1,3 +1,4 @@
|
|||
#pragma once
|
||||
/**
|
||||
* Numeric field types for AMQP
|
||||
*
|
||||
|
|
@ -77,10 +78,10 @@ public:
|
|||
* Create a new instance of this object
|
||||
* @return Field*
|
||||
*/
|
||||
virtual Field *clone() const override
|
||||
virtual std::shared_ptr<Field> clone() const override
|
||||
{
|
||||
// create a new copy of ourselves and return it
|
||||
return new NumericField(_value);
|
||||
return std::make_shared<NumericField>(_value);
|
||||
}
|
||||
|
||||
/**
|
||||
|
|
@ -99,7 +100,7 @@ public:
|
|||
* Get the value
|
||||
* @return mixed
|
||||
*/
|
||||
operator T () const
|
||||
virtual operator T () const override
|
||||
{
|
||||
return _value;
|
||||
}
|
||||
|
|
@ -156,6 +157,16 @@ public:
|
|||
{
|
||||
return F;
|
||||
}
|
||||
|
||||
/**
|
||||
* Output the object to a stream
|
||||
* @param std::ostream
|
||||
*/
|
||||
virtual void output(std::ostream &stream) const override
|
||||
{
|
||||
// show
|
||||
stream << "numeric(" << value() << ")";
|
||||
}
|
||||
};
|
||||
|
||||
/**
|
||||
|
|
|
|||
|
|
@ -1,3 +1,4 @@
|
|||
#pragma once
|
||||
/**
|
||||
* OutBuffer.h
|
||||
*
|
||||
|
|
@ -23,7 +24,7 @@ private:
|
|||
* @var char*
|
||||
*/
|
||||
char *_buffer;
|
||||
|
||||
|
||||
/**
|
||||
* Pointer to the buffer to be filled
|
||||
* @var char*
|
||||
|
|
@ -35,13 +36,13 @@ private:
|
|||
* @var size_t
|
||||
*/
|
||||
size_t _size;
|
||||
|
||||
|
||||
/**
|
||||
* The total capacity of the out buffer
|
||||
* @var size_t
|
||||
*/
|
||||
size_t _capacity;
|
||||
|
||||
|
||||
|
||||
public:
|
||||
/**
|
||||
|
|
@ -55,7 +56,7 @@ public:
|
|||
_capacity = capacity;
|
||||
_buffer = _current = new char[capacity];
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Copy constructor
|
||||
* @param that
|
||||
|
|
@ -67,11 +68,11 @@ public:
|
|||
_capacity = that._capacity;
|
||||
_buffer = new char[_capacity];
|
||||
_current = _buffer + _size;
|
||||
|
||||
|
||||
// copy memory
|
||||
memcpy(_buffer, that._buffer, _size);
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Move constructor
|
||||
* @param that
|
||||
|
|
@ -83,7 +84,7 @@ public:
|
|||
_capacity = that._capacity;
|
||||
_buffer = that._buffer;
|
||||
_current = that._current;
|
||||
|
||||
|
||||
// reset the other object
|
||||
that._size = 0;
|
||||
that._capacity = 0;
|
||||
|
|
@ -94,7 +95,7 @@ public:
|
|||
/**
|
||||
* Destructor
|
||||
*/
|
||||
virtual ~OutBuffer()
|
||||
virtual ~OutBuffer()
|
||||
{
|
||||
if (_buffer) delete[] _buffer;
|
||||
}
|
||||
|
|
@ -103,7 +104,7 @@ public:
|
|||
* Get access to the internal buffer
|
||||
* @return const char*
|
||||
*/
|
||||
const char *data()
|
||||
const char *data() const
|
||||
{
|
||||
return _buffer;
|
||||
}
|
||||
|
|
@ -112,7 +113,7 @@ public:
|
|||
* Current size of the output buffer
|
||||
* @return size_t
|
||||
*/
|
||||
size_t size()
|
||||
size_t size() const
|
||||
{
|
||||
return _size;
|
||||
}
|
||||
|
|
|
|||
|
|
@ -1,3 +1,4 @@
|
|||
#pragma once
|
||||
/**
|
||||
* ReceivedFrame.h
|
||||
*
|
||||
|
|
|
|||
|
|
@ -1,3 +1,4 @@
|
|||
#pragma once
|
||||
/**
|
||||
* String field types for amqp
|
||||
*
|
||||
|
|
@ -57,10 +58,10 @@ public:
|
|||
* Create a new instance of this object
|
||||
* @return Field*
|
||||
*/
|
||||
virtual Field *clone() const override
|
||||
virtual std::shared_ptr<Field> clone() const override
|
||||
{
|
||||
// create a new copy of ourselves and return it
|
||||
return new StringField(_data);
|
||||
return std::make_shared<StringField>(_data);
|
||||
}
|
||||
|
||||
/**
|
||||
|
|
@ -95,7 +96,7 @@ public:
|
|||
* Get the value
|
||||
* @return string
|
||||
*/
|
||||
operator const std::string& () const
|
||||
virtual operator const std::string& () const override
|
||||
{
|
||||
return _data;
|
||||
}
|
||||
|
|
@ -144,6 +145,16 @@ public:
|
|||
{
|
||||
return F;
|
||||
}
|
||||
|
||||
/**
|
||||
* Output the object to a stream
|
||||
* @param std::ostream
|
||||
*/
|
||||
virtual void output(std::ostream &stream) const override
|
||||
{
|
||||
// show
|
||||
stream << "string(" << value() << ")";
|
||||
}
|
||||
};
|
||||
|
||||
/**
|
||||
|
|
|
|||
|
|
@ -1,3 +1,4 @@
|
|||
#pragma once
|
||||
/**
|
||||
* AMQP field table
|
||||
*
|
||||
|
|
@ -75,9 +76,9 @@ public:
|
|||
* Create a new instance on the heap of this object, identical to the object passed
|
||||
* @return Field*
|
||||
*/
|
||||
virtual Field *clone() const override
|
||||
virtual std::shared_ptr<Field> clone() const override
|
||||
{
|
||||
return new Table(*this);
|
||||
return std::make_shared<Table>(*this);
|
||||
}
|
||||
|
||||
/**
|
||||
|
|
@ -95,7 +96,7 @@ public:
|
|||
Table set(const std::string& name, const Field &value)
|
||||
{
|
||||
// copy to a new pointer and store it
|
||||
_fields[name] = std::shared_ptr<Field>(value.clone());
|
||||
_fields[name] = value.clone();
|
||||
|
||||
// allow chaining
|
||||
return *this;
|
||||
|
|
@ -109,7 +110,7 @@ public:
|
|||
* @param name field name
|
||||
* @return the field value
|
||||
*/
|
||||
const Field &get(const std::string &name);
|
||||
const Field &get(const std::string &name) const;
|
||||
|
||||
/**
|
||||
* Get a field
|
||||
|
|
@ -121,6 +122,36 @@ public:
|
|||
return AssociativeFieldProxy(this, name);
|
||||
}
|
||||
|
||||
/**
|
||||
* Get a field
|
||||
*
|
||||
* @param name field name
|
||||
*/
|
||||
AssociativeFieldProxy operator[](const char *name)
|
||||
{
|
||||
return AssociativeFieldProxy(this, name);
|
||||
}
|
||||
|
||||
/**
|
||||
* Get a const field
|
||||
*
|
||||
* @param name field name
|
||||
*/
|
||||
const Field &operator[](const std::string& name) const
|
||||
{
|
||||
return get(name);
|
||||
}
|
||||
|
||||
/**
|
||||
* Get a const field
|
||||
*
|
||||
* @param name field name
|
||||
*/
|
||||
const Field &operator[](const char *name) const
|
||||
{
|
||||
return get(name);
|
||||
}
|
||||
|
||||
/**
|
||||
* Write encoded payload to the given buffer.
|
||||
* @param buffer
|
||||
|
|
@ -135,6 +166,46 @@ public:
|
|||
{
|
||||
return 'F';
|
||||
}
|
||||
|
||||
/**
|
||||
* Output the object to a stream
|
||||
* @param std::ostream
|
||||
*/
|
||||
virtual void output(std::ostream &stream) const
|
||||
{
|
||||
// prefix
|
||||
stream << "table(";
|
||||
|
||||
// is this the first iteration
|
||||
bool first = true;
|
||||
|
||||
// loop through all members
|
||||
for (auto &iter : _fields)
|
||||
{
|
||||
// split with comma
|
||||
if (!first) stream << ",";
|
||||
|
||||
// show output
|
||||
stream << iter.first << ":" << *iter.second;
|
||||
|
||||
// no longer first iter
|
||||
first = false;
|
||||
}
|
||||
|
||||
// postfix
|
||||
stream << ")";
|
||||
}
|
||||
|
||||
/**
|
||||
* Cast to table
|
||||
* @return Table
|
||||
*/
|
||||
virtual operator const Table& () const override
|
||||
{
|
||||
// this already is an array, so no cast is necessary
|
||||
return *this;
|
||||
}
|
||||
|
||||
};
|
||||
|
||||
/**
|
||||
|
|
|
|||
|
|
@ -1,3 +1,4 @@
|
|||
#pragma once
|
||||
/**
|
||||
* Watchable.h
|
||||
*
|
||||
|
|
|
|||
|
|
@ -1,6 +1,6 @@
|
|||
CPP = g++
|
||||
RM = rm -f
|
||||
CPPFLAGS = -Wall -c -I. -O2 -flto -std=c++11 -g
|
||||
CPPFLAGS = -Wall -c -I. -g -std=c++11 -g
|
||||
LD = g++
|
||||
LD_FLAGS = -Wall -shared -O2
|
||||
SHARED_LIB = libamqpcpp.so
|
||||
|
|
@ -25,7 +25,7 @@ clean:
|
|||
${RM} *.obj *~* ${SHARED_OBJECTS} ${STATIC_OBJECTS} ${SHARED_LIB} ${STATIC_LIB}
|
||||
|
||||
${SHARED_OBJECTS}:
|
||||
${CPP} ${CPPFLAGS} -fpic -o $@ ${@:%.o=%.cpp}
|
||||
${CPP} ${CPPFLAGS} -flto -fpic -o $@ ${@:%.o=%.cpp}
|
||||
|
||||
${STATIC_OBJECTS}:
|
||||
${CPP} ${CPPFLAGS} -o $@ ${@:%.s.o=%.cpp}
|
||||
|
|
|
|||
|
|
@ -1,8 +1,8 @@
|
|||
/**
|
||||
* Array.cpp
|
||||
*
|
||||
*
|
||||
* Implementation of an array
|
||||
*
|
||||
*
|
||||
*/
|
||||
#include "includes.h"
|
||||
|
||||
|
|
@ -23,7 +23,7 @@ Array::Array(ReceivedFrame &frame)
|
|||
{
|
||||
// one byte less for the field type
|
||||
charsToRead -= 1;
|
||||
|
||||
|
||||
// read the field type and construct the field
|
||||
Field *field = Field::decode(frame);
|
||||
if (!field) continue;
|
||||
|
|
@ -58,11 +58,11 @@ Array::Array(const Array &array)
|
|||
* @param index field index
|
||||
* @return Field
|
||||
*/
|
||||
const Field &Array::get(uint8_t index)
|
||||
const Field &Array::get(uint8_t index) const
|
||||
{
|
||||
// used if index does not exist
|
||||
static ShortString empty;
|
||||
|
||||
|
||||
// check whether we have that many elements
|
||||
if (index >= _fields.size()) return empty;
|
||||
|
||||
|
|
@ -70,9 +70,36 @@ const Field &Array::get(uint8_t index)
|
|||
return *_fields[index];
|
||||
}
|
||||
|
||||
/**
|
||||
* Number of entries in the array
|
||||
* @return uint32_t
|
||||
*/
|
||||
uint32_t Array::count() const
|
||||
{
|
||||
return _fields.size();
|
||||
}
|
||||
|
||||
/**
|
||||
* Remove a field from the array
|
||||
*/
|
||||
void Array::pop_back()
|
||||
{
|
||||
_fields.pop_back();
|
||||
}
|
||||
|
||||
/**
|
||||
* Add a field to the array
|
||||
* @param value
|
||||
*/
|
||||
void Array::push_back(const Field& value)
|
||||
{
|
||||
_fields.push_back(std::shared_ptr<Field>(value.clone()));
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the size this field will take when
|
||||
* encoded in the AMQP wire-frame format
|
||||
* @return size_t
|
||||
*/
|
||||
size_t Array::size() const
|
||||
{
|
||||
|
|
@ -80,11 +107,11 @@ size_t Array::size() const
|
|||
size_t size = 4;
|
||||
|
||||
// iterate over all elements
|
||||
for (auto iter(_fields.begin()); iter != _fields.end(); ++iter)
|
||||
for (auto item : _fields)
|
||||
{
|
||||
// add the size of the field type and size of element
|
||||
size += sizeof((*iter)->typeID());
|
||||
size += (*iter)->size();
|
||||
size += sizeof(item->typeID());
|
||||
size += item->size();
|
||||
}
|
||||
|
||||
// return the result
|
||||
|
|
@ -92,16 +119,20 @@ size_t Array::size() const
|
|||
}
|
||||
|
||||
/**
|
||||
* Write encoded payload to the given buffer.
|
||||
* Write encoded payload to the given buffer.
|
||||
* @param buffer
|
||||
*/
|
||||
void Array::fill(OutBuffer& buffer) const
|
||||
{
|
||||
// store total size for all elements
|
||||
buffer.add(static_cast<uint32_t>(size()-4));
|
||||
|
||||
// iterate over all elements
|
||||
for (auto iter(_fields.begin()); iter != _fields.end(); ++iter)
|
||||
for (auto item : _fields)
|
||||
{
|
||||
// encode the element type and element
|
||||
buffer.add((*iter)->typeID());
|
||||
(*iter)->fill(buffer);
|
||||
buffer.add((uint8_t)item->typeID());
|
||||
item->fill(buffer);
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -1,6 +1,6 @@
|
|||
/**
|
||||
* Class describing a basic acknowledgement frame
|
||||
*
|
||||
*
|
||||
* @copyright 2014 Copernica BV
|
||||
*/
|
||||
|
||||
|
|
@ -38,10 +38,10 @@ protected:
|
|||
{
|
||||
// call base
|
||||
BasicFrame::fill(buffer);
|
||||
|
||||
|
||||
// add the delivery tag
|
||||
buffer.add(_deliveryTag);
|
||||
|
||||
|
||||
// add the booleans
|
||||
_multiple.fill(buffer);
|
||||
}
|
||||
|
|
@ -54,25 +54,36 @@ public:
|
|||
* @param deliveryTag server-assigned and channel specific delivery tag
|
||||
* @param multiple acknowledge mutiple messages
|
||||
*/
|
||||
BasicAckFrame(uint16_t channel, uint64_t deliveryTag, bool multiple = false) :
|
||||
BasicAckFrame(uint16_t channel, uint64_t deliveryTag, bool multiple = false) :
|
||||
BasicFrame(channel, 9),
|
||||
_deliveryTag(deliveryTag),
|
||||
_multiple(multiple) {}
|
||||
|
||||
|
||||
/**
|
||||
* Construct based on received frame
|
||||
* @param frame
|
||||
*/
|
||||
BasicAckFrame(ReceivedFrame &frame) :
|
||||
BasicAckFrame(ReceivedFrame &frame) :
|
||||
BasicFrame(frame),
|
||||
_deliveryTag(frame.nextUint64()),
|
||||
_multiple(frame) {}
|
||||
|
||||
|
||||
/**
|
||||
* Destructor
|
||||
*/
|
||||
virtual ~BasicAckFrame() {}
|
||||
|
||||
/**
|
||||
* Is this a synchronous frame?
|
||||
*
|
||||
* After a synchronous frame no more frames may be
|
||||
* sent until the accompanying -ok frame arrives
|
||||
*/
|
||||
virtual bool synchronous() const override
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
/**
|
||||
* Return the method ID
|
||||
* @return uint16_t
|
||||
|
|
|
|||
|
|
@ -67,7 +67,19 @@ public:
|
|||
* Destructor
|
||||
*/
|
||||
virtual ~BasicCancelFrame() {}
|
||||
|
||||
|
||||
/**
|
||||
* Is this a synchronous frame?
|
||||
*
|
||||
* After a synchronous frame no more frames may be
|
||||
* sent until the accompanying -ok frame arrives
|
||||
*/
|
||||
bool synchronous() const override
|
||||
{
|
||||
// we are synchronous when the nowait option is not used
|
||||
return !noWait();
|
||||
}
|
||||
|
||||
/**
|
||||
* Return the consumertag, which is specified by the client or provided by the server
|
||||
* @return string
|
||||
|
|
@ -90,7 +102,7 @@ public:
|
|||
* Return whether to wait for a response
|
||||
* @return boolean
|
||||
*/
|
||||
const bool noWait()
|
||||
const bool noWait() const
|
||||
{
|
||||
return _noWait.get(0);
|
||||
}
|
||||
|
|
|
|||
|
|
@ -1,6 +1,6 @@
|
|||
/**
|
||||
* Class describing a basic cancel ok frame
|
||||
*
|
||||
*
|
||||
* @copyright 2014 Copernica BV
|
||||
*/
|
||||
|
||||
|
|
@ -42,7 +42,7 @@ public:
|
|||
*
|
||||
* @param frame received frame
|
||||
*/
|
||||
BasicCancelOKFrame(ReceivedFrame &frame) :
|
||||
BasicCancelOKFrame(ReceivedFrame &frame) :
|
||||
BasicFrame(frame),
|
||||
_consumerTag(frame)
|
||||
{}
|
||||
|
|
@ -89,13 +89,13 @@ public:
|
|||
{
|
||||
// we need the appropriate channel
|
||||
ChannelImpl *channel = connection->channel(this->channel());
|
||||
|
||||
|
||||
// channel does not exist
|
||||
if (!channel) return false;
|
||||
|
||||
if (!channel) return false;
|
||||
|
||||
// report
|
||||
channel->reportConsumerStopped(consumerTag());
|
||||
|
||||
if (channel->reportSuccess<const std::string&>(consumerTag())) channel->synchronized();
|
||||
|
||||
// done
|
||||
return true;
|
||||
}
|
||||
|
|
|
|||
|
|
@ -111,6 +111,18 @@ public:
|
|||
*/
|
||||
virtual ~BasicConsumeFrame() {}
|
||||
|
||||
/**
|
||||
* Is this a synchronous frame?
|
||||
*
|
||||
* After a synchronous frame no more frames may be
|
||||
* sent until the accompanying -ok frame arrives
|
||||
*/
|
||||
bool synchronous() const override
|
||||
{
|
||||
// we are synchronous when the nowait option is not set
|
||||
return !noWait();
|
||||
}
|
||||
|
||||
/**
|
||||
* Return the method ID
|
||||
* @return uint16_t
|
||||
|
|
|
|||
|
|
@ -1,6 +1,6 @@
|
|||
/**
|
||||
* Class describing a basic consume ok frame
|
||||
*
|
||||
*
|
||||
* @copyright 2014 Copernica BV
|
||||
*/
|
||||
|
||||
|
|
@ -52,7 +52,7 @@ public:
|
|||
*
|
||||
* @param frame received frame
|
||||
*/
|
||||
BasicConsumeOKFrame(ReceivedFrame &frame) :
|
||||
BasicConsumeOKFrame(ReceivedFrame &frame) :
|
||||
BasicFrame(frame),
|
||||
_consumerTag(frame)
|
||||
{}
|
||||
|
|
@ -89,13 +89,13 @@ public:
|
|||
{
|
||||
// we need the appropriate channel
|
||||
ChannelImpl *channel = connection->channel(this->channel());
|
||||
|
||||
|
||||
// channel does not exist
|
||||
if (!channel) return false;
|
||||
|
||||
if (!channel) return false;
|
||||
|
||||
// report
|
||||
channel->reportConsumerStarted(consumerTag());
|
||||
|
||||
if (channel->reportSuccess(consumerTag())) channel->synchronized();
|
||||
|
||||
// done
|
||||
return true;
|
||||
}
|
||||
|
|
|
|||
|
|
@ -120,6 +120,17 @@ public:
|
|||
return _routingKey;
|
||||
}
|
||||
|
||||
/**
|
||||
* Is this a synchronous frame?
|
||||
*
|
||||
* After a synchronous frame no more frames may be
|
||||
* sent until the accompanying -ok frame arrives
|
||||
*/
|
||||
virtual bool synchronous() const override
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
/**
|
||||
* Return the method ID
|
||||
* @return uint16_t
|
||||
|
|
|
|||
|
|
@ -94,6 +94,17 @@ public:
|
|||
*/
|
||||
virtual ~BasicPublishFrame() {}
|
||||
|
||||
/**
|
||||
* Is this a synchronous frame?
|
||||
*
|
||||
* After a synchronous frame no more frames may be
|
||||
* sent until the accompanying -ok frame arrives
|
||||
*/
|
||||
bool synchronous() const override
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
/**
|
||||
* Return the name of the exchange to publish to
|
||||
* @return string
|
||||
|
|
|
|||
|
|
@ -1,6 +1,6 @@
|
|||
/**
|
||||
* Class describing a basic QOS frame
|
||||
*
|
||||
*
|
||||
* @copyright 2014 Copernica BV
|
||||
*/
|
||||
|
||||
|
|
@ -32,7 +32,7 @@ public:
|
|||
* @param channel channel we're working on
|
||||
*/
|
||||
BasicQosOKFrame(uint16_t channel) : BasicFrame(channel, 0) {}
|
||||
|
||||
|
||||
/**
|
||||
* Constructor based on incoming data
|
||||
* @param frame
|
||||
|
|
@ -52,7 +52,7 @@ public:
|
|||
{
|
||||
return 11;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Process the frame
|
||||
* @param connection The connection over which it was received
|
||||
|
|
@ -62,13 +62,13 @@ public:
|
|||
{
|
||||
// we need the appropriate channel
|
||||
ChannelImpl *channel = connection->channel(this->channel());
|
||||
|
||||
|
||||
// channel does not exist
|
||||
if (!channel) return false;
|
||||
|
||||
if (!channel) return false;
|
||||
|
||||
// report
|
||||
channel->reportQosSet();
|
||||
|
||||
if (channel->reportSuccess()) channel->synchronized();
|
||||
|
||||
// done
|
||||
return true;
|
||||
}
|
||||
|
|
|
|||
|
|
@ -62,6 +62,17 @@ public:
|
|||
*/
|
||||
virtual ~BasicRecoverAsyncFrame() {}
|
||||
|
||||
/**
|
||||
* Is this a synchronous frame?
|
||||
*
|
||||
* After a synchronous frame no more frames may be
|
||||
* sent until the accompanying -ok frame arrives
|
||||
*/
|
||||
virtual bool synchronous() const override
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
/**
|
||||
* Return the method ID
|
||||
* @return uint16_t
|
||||
|
|
|
|||
|
|
@ -62,6 +62,17 @@ public:
|
|||
*/
|
||||
virtual ~BasicRecoverFrame() {}
|
||||
|
||||
/**
|
||||
* Is this a synchronous frame?
|
||||
*
|
||||
* After a synchronous frame no more frames may be
|
||||
* sent until the accompanying -ok frame arrives
|
||||
*/
|
||||
bool synchronous() const override
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
/**
|
||||
* Return the method ID
|
||||
* @return uint16_t
|
||||
|
|
|
|||
|
|
@ -1,6 +1,6 @@
|
|||
/**
|
||||
* Class describing a basic recover-async frame
|
||||
*
|
||||
*
|
||||
* @copyright 2014 Copernica BV
|
||||
*/
|
||||
|
||||
|
|
@ -57,7 +57,7 @@ public:
|
|||
{
|
||||
return 111;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Process the frame
|
||||
* @param connection The connection over which it was received
|
||||
|
|
@ -67,17 +67,17 @@ public:
|
|||
{
|
||||
// we need the appropriate channel
|
||||
ChannelImpl *channel = connection->channel(this->channel());
|
||||
|
||||
|
||||
// channel does not exist
|
||||
if (!channel) return false;
|
||||
|
||||
if (!channel) return false;
|
||||
|
||||
// report
|
||||
channel->reportRecovering();
|
||||
|
||||
channel->reportSuccess();
|
||||
|
||||
// done
|
||||
return true;
|
||||
}
|
||||
|
||||
|
||||
|
||||
};
|
||||
|
||||
|
|
|
|||
|
|
@ -73,6 +73,17 @@ public:
|
|||
*/
|
||||
virtual ~BasicRejectFrame() {}
|
||||
|
||||
/**
|
||||
* Is this a synchronous frame?
|
||||
*
|
||||
* After a synchronous frame no more frames may be
|
||||
* sent until the accompanying -ok frame arrives
|
||||
*/
|
||||
bool synchronous() const override
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
/**
|
||||
* Return the method ID
|
||||
* @return uint16_t
|
||||
|
|
|
|||
|
|
@ -92,6 +92,17 @@ public:
|
|||
*/
|
||||
virtual ~BasicReturnFrame() {}
|
||||
|
||||
/**
|
||||
* Is this a synchronous frame?
|
||||
*
|
||||
* After a synchronous frame no more frames may be
|
||||
* sent until the accompanying -ok frame arrives
|
||||
*/
|
||||
virtual bool synchronous() const override
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
/**
|
||||
* Return the name of the exchange to publish to
|
||||
* @return string
|
||||
|
|
@ -144,17 +155,8 @@ public:
|
|||
*/
|
||||
virtual bool process(ConnectionImpl *connection) override
|
||||
{
|
||||
// we need the appropriate channel
|
||||
ChannelImpl *channel = connection->channel(this->channel());
|
||||
|
||||
// channel does not exist
|
||||
if (!channel) return false;
|
||||
|
||||
// construct the message
|
||||
channel->message(*this);
|
||||
|
||||
// done
|
||||
return true;
|
||||
// we no longer support returned messages
|
||||
return false;
|
||||
}
|
||||
};
|
||||
|
||||
|
|
|
|||
|
|
@ -156,7 +156,7 @@ public:
|
|||
if (!channel) return false;
|
||||
|
||||
// report to the handler
|
||||
channel->reportError(text());
|
||||
channel->reportError(_text.value().c_str());
|
||||
|
||||
// done
|
||||
return true;
|
||||
|
|
|
|||
|
|
@ -1,6 +1,6 @@
|
|||
/**
|
||||
* Class describing a channel close acknowledgement frame
|
||||
*
|
||||
*
|
||||
* @copyright 2014 Copernica BV
|
||||
*/
|
||||
|
||||
|
|
@ -67,13 +67,13 @@ public:
|
|||
{
|
||||
// we need the appropriate channel
|
||||
ChannelImpl *channel = connection->channel(this->channel());
|
||||
|
||||
|
||||
// channel does not exist
|
||||
if (!channel) return false;
|
||||
|
||||
if (!channel) return false;
|
||||
|
||||
// report that the channel is closed
|
||||
channel->reportClosed();
|
||||
|
||||
if (channel->reportClosed()) channel->synchronized();
|
||||
|
||||
// done
|
||||
return true;
|
||||
}
|
||||
|
|
|
|||
|
|
@ -88,14 +88,13 @@ public:
|
|||
{
|
||||
// we need the appropriate channel
|
||||
ChannelImpl *channel = connection->channel(this->channel());
|
||||
|
||||
|
||||
// channel does not exist
|
||||
if (!channel) return false;
|
||||
|
||||
// is the flow active?
|
||||
if (active()) channel->reportResumed();
|
||||
else channel->reportPaused();
|
||||
|
||||
if (!channel) return false;
|
||||
|
||||
// report success for the call
|
||||
if (channel->reportSuccess()) channel->synchronized();
|
||||
|
||||
// done
|
||||
return true;
|
||||
}
|
||||
|
|
|
|||
|
|
@ -36,6 +36,7 @@
|
|||
#include "basicackframe.h"
|
||||
#include "basicnackframe.h"
|
||||
#include "basicrecoverframe.h"
|
||||
#include "basicrejectframe.h"
|
||||
|
||||
/**
|
||||
* Set up namespace
|
||||
|
|
@ -48,28 +49,24 @@ namespace AMQP {
|
|||
* @param connection
|
||||
* @param handler
|
||||
*/
|
||||
ChannelImpl::ChannelImpl(Channel *parent, Connection *connection, ChannelHandler *handler) :
|
||||
ChannelImpl::ChannelImpl(Channel *parent, Connection *connection) :
|
||||
_parent(parent),
|
||||
_connection(&connection->_implementation),
|
||||
_handler(handler)
|
||||
_connection(&connection->_implementation)
|
||||
{
|
||||
// add the channel to the connection
|
||||
_id = _connection->add(this);
|
||||
|
||||
|
||||
// check if the id is valid
|
||||
if (_id == 0)
|
||||
{
|
||||
// this is invalid
|
||||
_state = state_closed;
|
||||
|
||||
// invalid id, this channel can not exist
|
||||
handler->onError(_parent, "Max number of channels reached");
|
||||
}
|
||||
else
|
||||
{
|
||||
// busy connecting
|
||||
_state = state_connected;
|
||||
|
||||
|
||||
// valid id, send a channel open frame
|
||||
send(ChannelOpenFrame(_id));
|
||||
}
|
||||
|
|
@ -80,106 +77,143 @@ ChannelImpl::ChannelImpl(Channel *parent, Connection *connection, ChannelHandler
|
|||
*/
|
||||
ChannelImpl::~ChannelImpl()
|
||||
{
|
||||
// remove incoming message
|
||||
// remove incoming message
|
||||
if (_message) delete _message;
|
||||
_message = nullptr;
|
||||
|
||||
|
||||
// remove this channel from the connection (but not if the connection is already destructed)
|
||||
if (_connection) _connection->remove(this);
|
||||
|
||||
|
||||
// close the channel now
|
||||
close();
|
||||
|
||||
// destruct deferred results
|
||||
while (_oldestCallback) _oldestCallback.reset(_oldestCallback->next());
|
||||
}
|
||||
|
||||
/**
|
||||
* Push a deferred result
|
||||
* @param result The deferred object to push
|
||||
*/
|
||||
Deferred &ChannelImpl::push(Deferred *deferred)
|
||||
{
|
||||
// do we already have an oldest?
|
||||
if (!_oldestCallback) _oldestCallback.reset(deferred);
|
||||
|
||||
// do we already have a newest?
|
||||
if (_newestCallback) _newestCallback->add(deferred);
|
||||
|
||||
// store newest callback
|
||||
_newestCallback = deferred;
|
||||
|
||||
// done
|
||||
return *deferred;
|
||||
}
|
||||
|
||||
/**
|
||||
* Send a frame and push a deferred result
|
||||
* @param frame The frame to send
|
||||
*/
|
||||
Deferred &ChannelImpl::push(const Frame &frame)
|
||||
{
|
||||
// send the frame, and push the result
|
||||
return push(new Deferred(send(frame)));
|
||||
}
|
||||
|
||||
/**
|
||||
* Pause deliveries on a channel
|
||||
*
|
||||
*
|
||||
* This will stop all incoming messages
|
||||
*
|
||||
* This method returns true if the request to pause has been sent to the
|
||||
* broker. This does not necessarily mean that the channel is already
|
||||
* paused.
|
||||
*
|
||||
* @return bool
|
||||
*
|
||||
* This function returns a deferred handler. Callbacks can be installed
|
||||
* using onSuccess(), onError() and onFinalize() methods.
|
||||
*/
|
||||
bool ChannelImpl::pause()
|
||||
Deferred &ChannelImpl::pause()
|
||||
{
|
||||
// send a flow frame
|
||||
return send(ChannelFlowFrame(_id, false));
|
||||
// send a channel flow frame
|
||||
return push(ChannelFlowFrame(_id, false));
|
||||
}
|
||||
|
||||
/**
|
||||
* Resume a paused channel
|
||||
*
|
||||
* @return bool
|
||||
*
|
||||
* This will resume incoming messages
|
||||
*
|
||||
* This function returns a deferred handler. Callbacks can be installed
|
||||
* using onSuccess(), onError() and onFinalize() methods.
|
||||
*/
|
||||
bool ChannelImpl::resume()
|
||||
Deferred &ChannelImpl::resume()
|
||||
{
|
||||
// send a flow frame
|
||||
return send(ChannelFlowFrame(_id, true));
|
||||
// send a channel flow frame
|
||||
return push(ChannelFlowFrame(_id, true));
|
||||
}
|
||||
|
||||
/**
|
||||
* Start a transaction
|
||||
* @return bool
|
||||
*
|
||||
* This function returns a deferred handler. Callbacks can be installed
|
||||
* using onSuccess(), onError() and onFinalize() methods.
|
||||
*/
|
||||
bool ChannelImpl::startTransaction()
|
||||
Deferred &ChannelImpl::startTransaction()
|
||||
{
|
||||
// send a flow frame
|
||||
return send(TransactionSelectFrame(_id));
|
||||
}
|
||||
// send a transaction frame
|
||||
return push(TransactionSelectFrame(_id));
|
||||
}
|
||||
|
||||
/**
|
||||
* Commit the current transaction
|
||||
* @return bool
|
||||
*
|
||||
* This function returns a deferred handler. Callbacks can be installed
|
||||
* using onSuccess(), onError() and onFinalize() methods.
|
||||
*/
|
||||
bool ChannelImpl::commitTransaction()
|
||||
Deferred &ChannelImpl::commitTransaction()
|
||||
{
|
||||
// send a flow frame
|
||||
return send(TransactionCommitFrame(_id));
|
||||
// send a transaction frame
|
||||
return push(TransactionCommitFrame(_id));
|
||||
}
|
||||
|
||||
/**
|
||||
* Rollback the current transaction
|
||||
* @return bool
|
||||
*
|
||||
* This function returns a deferred handler. Callbacks can be installed
|
||||
* using onSuccess(), onError() and onFinalize() methods.
|
||||
*/
|
||||
bool ChannelImpl::rollbackTransaction()
|
||||
Deferred &ChannelImpl::rollbackTransaction()
|
||||
{
|
||||
// send a flow frame
|
||||
return send(TransactionRollbackFrame(_id));
|
||||
// send a transaction frame
|
||||
return push(TransactionRollbackFrame(_id));
|
||||
}
|
||||
|
||||
/**
|
||||
* Close the current channel
|
||||
* @return bool
|
||||
*
|
||||
* This function returns a deferred handler. Callbacks can be installed
|
||||
* using onSuccess(), onError() and onFinalize() methods.
|
||||
*/
|
||||
bool ChannelImpl::close()
|
||||
Deferred &ChannelImpl::close()
|
||||
{
|
||||
// channel could be dead after send operation, we need to monitor that
|
||||
Monitor monitor(this);
|
||||
// send a channel close frame
|
||||
auto &handler = push(ChannelCloseFrame(_id));
|
||||
|
||||
// send a flow frame
|
||||
if (!send(ChannelCloseFrame(_id))) return false;
|
||||
|
||||
// leap out if channel was destructed
|
||||
if (!monitor.valid()) return true;
|
||||
|
||||
// now it is closing
|
||||
_state = state_closing;
|
||||
// was the frame sent and are we still alive?
|
||||
if (handler) _state = state_closing;
|
||||
|
||||
// done
|
||||
return true;
|
||||
return handler;
|
||||
}
|
||||
|
||||
/**
|
||||
* declare an exchange
|
||||
|
||||
* @param name name of the exchange to declare
|
||||
* @param type type of exchange
|
||||
* @param flags additional settings for the exchange
|
||||
* @param arguments additional arguments
|
||||
* @return bool
|
||||
*
|
||||
* This function returns a deferred handler. Callbacks can be installed
|
||||
* using onSuccess(), onError() and onFinalize() methods.
|
||||
*/
|
||||
bool ChannelImpl::declareExchange(const std::string &name, ExchangeType type, int flags, const Table &arguments)
|
||||
Deferred &ChannelImpl::declareExchange(const std::string &name, ExchangeType type, int flags, const Table &arguments)
|
||||
{
|
||||
// convert exchange type
|
||||
std::string exchangeType;
|
||||
|
|
@ -189,49 +223,56 @@ bool ChannelImpl::declareExchange(const std::string &name, ExchangeType type, in
|
|||
if (type == ExchangeType::headers)exchangeType = "headers";
|
||||
|
||||
// send declare exchange frame
|
||||
return send(ExchangeDeclareFrame(_id, name, exchangeType, flags & passive, flags & durable, flags & nowait, arguments));
|
||||
return push(ExchangeDeclareFrame(_id, name, exchangeType, flags & passive, flags & durable, false, arguments));
|
||||
}
|
||||
|
||||
/**
|
||||
* bind an exchange
|
||||
*
|
||||
* @param source exchange which binds to target
|
||||
* @param target exchange to bind to
|
||||
* @param routingKey routing key
|
||||
* @param flags additional flags
|
||||
* @param arguments additional arguments for binding
|
||||
* @return bool
|
||||
*
|
||||
* This function returns a deferred handler. Callbacks can be installed
|
||||
* using onSuccess(), onError() and onFinalize() methods.
|
||||
*/
|
||||
bool ChannelImpl::bindExchange(const std::string &source, const std::string &target, const std::string &routingkey, int flags, const Table &arguments)
|
||||
Deferred &ChannelImpl::bindExchange(const std::string &source, const std::string &target, const std::string &routingkey, const Table &arguments)
|
||||
{
|
||||
// send exchange bind frame
|
||||
return send(ExchangeBindFrame(_id, target, source, routingkey, flags & nowait, arguments));
|
||||
return push(ExchangeBindFrame(_id, target, source, routingkey, false, arguments));
|
||||
}
|
||||
|
||||
/**
|
||||
* unbind two exchanges
|
||||
*
|
||||
* @param source the source exchange
|
||||
* @param target the target exchange
|
||||
* @param routingkey the routing key
|
||||
* @param flags optional flags
|
||||
* @param arguments additional unbind arguments
|
||||
* @return bool
|
||||
*
|
||||
* This function returns a deferred handler. Callbacks can be installed
|
||||
* using onSuccess(), onError() and onFinalize() methods.
|
||||
*/
|
||||
bool ChannelImpl::unbindExchange(const std::string &source, const std::string &target, const std::string &routingkey, int flags, const Table &arguments)
|
||||
Deferred &ChannelImpl::unbindExchange(const std::string &source, const std::string &target, const std::string &routingkey, const Table &arguments)
|
||||
{
|
||||
// send exchange unbind frame
|
||||
return send(ExchangeUnbindFrame(_id, target, source, routingkey, flags & nowait, arguments));
|
||||
return push(ExchangeUnbindFrame(_id, target, source, routingkey, false, arguments));
|
||||
}
|
||||
|
||||
/**
|
||||
* remove an exchange
|
||||
*
|
||||
* @param name name of the exchange to remove
|
||||
* @param flags additional settings for deleting the exchange
|
||||
* @return bool
|
||||
*
|
||||
* This function returns a deferred handler. Callbacks can be installed
|
||||
* using onSuccess(), onError() and onFinalize() methods.
|
||||
*/
|
||||
bool ChannelImpl::removeExchange(const std::string &name, int flags)
|
||||
Deferred &ChannelImpl::removeExchange(const std::string &name, int flags)
|
||||
{
|
||||
// send delete exchange frame
|
||||
return send(ExchangeDeleteFrame(_id, name, flags & ifunused, flags & nowait));
|
||||
return push(ExchangeDeleteFrame(_id, name, flags & ifunused, false));
|
||||
}
|
||||
|
||||
/**
|
||||
|
|
@ -239,127 +280,178 @@ bool ChannelImpl::removeExchange(const std::string &name, int flags)
|
|||
* @param name queue name
|
||||
* @param flags additional settings for the queue
|
||||
* @param arguments additional arguments
|
||||
* @return bool
|
||||
*
|
||||
* This function returns a deferred handler. Callbacks can be installed
|
||||
* using onSuccess(), onError() and onFinalize() methods.
|
||||
*/
|
||||
bool ChannelImpl::declareQueue(const std::string &name, int flags, const Table &arguments)
|
||||
DeferredQueue &ChannelImpl::declareQueue(const std::string &name, int flags, const Table &arguments)
|
||||
{
|
||||
// the frame to send
|
||||
QueueDeclareFrame frame(_id, name, flags & passive, flags & durable, flags & exclusive, flags & autodelete, false, arguments);
|
||||
|
||||
// send the queuedeclareframe
|
||||
return send(QueueDeclareFrame(_id, name, flags & passive, flags & durable, flags & exclusive, flags & autodelete, flags & nowait, arguments));
|
||||
auto *result = new DeferredQueue(send(frame));
|
||||
|
||||
// add the deferred result
|
||||
push(result);
|
||||
|
||||
// done
|
||||
return *result;
|
||||
}
|
||||
|
||||
/**
|
||||
* Bind a queue to an exchange
|
||||
*
|
||||
* @param exchangeName name of the exchange to bind to
|
||||
* @param queueName name of the queue
|
||||
* @param routingkey routingkey
|
||||
* @param flags additional flags
|
||||
* @param arguments additional arguments
|
||||
* @return bool
|
||||
*
|
||||
* This function returns a deferred handler. Callbacks can be installed
|
||||
* using onSuccess(), onError() and onFinalize() methods.
|
||||
*/
|
||||
bool ChannelImpl::bindQueue(const std::string &exchangeName, const std::string &queueName, const std::string &routingkey, int flags, const Table &arguments)
|
||||
Deferred &ChannelImpl::bindQueue(const std::string &exchangeName, const std::string &queueName, const std::string &routingkey, const Table &arguments)
|
||||
{
|
||||
// send the bind queue frame
|
||||
return send(QueueBindFrame(_id, queueName, exchangeName, routingkey, flags & nowait, arguments));
|
||||
return push(QueueBindFrame(_id, queueName, exchangeName, routingkey, false, arguments));
|
||||
}
|
||||
|
||||
/**
|
||||
* Unbind a queue from an exchange
|
||||
*
|
||||
* @param exchange the source exchange
|
||||
* @param queue the target queue
|
||||
* @param routingkey the routing key
|
||||
* @param arguments additional bind arguments
|
||||
* @return bool
|
||||
*
|
||||
* This function returns a deferred handler. Callbacks can be installed
|
||||
* using onSuccess(), onError() and onFinalize() methods.
|
||||
*/
|
||||
bool ChannelImpl::unbindQueue(const std::string &exchange, const std::string &queue, const std::string &routingkey, const Table &arguments)
|
||||
Deferred &ChannelImpl::unbindQueue(const std::string &exchange, const std::string &queue, const std::string &routingkey, const Table &arguments)
|
||||
{
|
||||
// send the unbind queue frame
|
||||
return send(QueueUnbindFrame(_id, queue, exchange, routingkey, arguments));
|
||||
return push(QueueUnbindFrame(_id, queue, exchange, routingkey, arguments));
|
||||
}
|
||||
|
||||
/**
|
||||
* Purge a queue
|
||||
* @param queue queue to purge
|
||||
* @param flags additional flags
|
||||
* @return bool
|
||||
*
|
||||
* This function returns a deferred handler. Callbacks can be installed
|
||||
* using onSuccess(), onError() and onFinalize() methods.
|
||||
*
|
||||
* The onSuccess() callback that you can install should have the following signature:
|
||||
*
|
||||
* void myCallback(AMQP::Channel *channel, uint32_t messageCount);
|
||||
*
|
||||
* For example: channel.declareQueue("myqueue").onSuccess([](AMQP::Channel *channel, uint32_t messageCount) {
|
||||
*
|
||||
* std::cout << "Queue purged, all " << messageCount << " messages removed" << std::endl;
|
||||
*
|
||||
* });
|
||||
*/
|
||||
bool ChannelImpl::purgeQueue(const std::string &name, int flags)
|
||||
DeferredDelete &ChannelImpl::purgeQueue(const std::string &name)
|
||||
{
|
||||
// send the queue purge frame
|
||||
return send(QueuePurgeFrame(_id, name, flags & nowait));
|
||||
// the frame to send
|
||||
QueuePurgeFrame frame(_id, name, false);
|
||||
|
||||
// send the frame, and create deferred object
|
||||
auto *deferred = new DeferredDelete(send(frame));
|
||||
|
||||
// push to list
|
||||
push(deferred);
|
||||
|
||||
// done
|
||||
return *deferred;
|
||||
}
|
||||
|
||||
/**
|
||||
* Remove a queue
|
||||
* @param queue queue to remove
|
||||
* @param flags additional flags
|
||||
* @return bool
|
||||
*
|
||||
* This function returns a deferred handler. Callbacks can be installed
|
||||
* using onSuccess(), onError() and onFinalize() methods.
|
||||
*
|
||||
* The onSuccess() callback that you can install should have the following signature:
|
||||
*
|
||||
* void myCallback(AMQP::Channel *channel, uint32_t messageCount);
|
||||
*
|
||||
* For example: channel.declareQueue("myqueue").onSuccess([](AMQP::Channel *channel, uint32_t messageCount) {
|
||||
*
|
||||
* std::cout << "Queue deleted, along with " << messageCount << " messages" << std::endl;
|
||||
*
|
||||
* });
|
||||
*/
|
||||
bool ChannelImpl::removeQueue(const std::string &name, int flags)
|
||||
DeferredDelete &ChannelImpl::removeQueue(const std::string &name, int flags)
|
||||
{
|
||||
// send the remove queue frame
|
||||
return send(QueueDeleteFrame(_id, name, flags & ifunused, flags & ifempty, flags & nowait));
|
||||
// the frame to send
|
||||
QueueDeleteFrame frame(_id, name, flags & ifunused, flags & ifempty, false);
|
||||
|
||||
// send the frame, and create deferred object
|
||||
auto *deferred = new DeferredDelete(send(frame));
|
||||
|
||||
// push to list
|
||||
push(deferred);
|
||||
|
||||
// done
|
||||
return *deferred;
|
||||
}
|
||||
|
||||
/**
|
||||
* Publish a message to an exchange
|
||||
*
|
||||
* The following flags can be used
|
||||
*
|
||||
* - mandatory if set, an unroutable message will be reported to the channel handler with the onReturned method
|
||||
* - immediate if set, a message that could not immediately be consumed is returned to the onReturned method
|
||||
*
|
||||
*
|
||||
* @param exchange the exchange to publish to
|
||||
* @param routingkey the routing key
|
||||
* @param flags optional flags (see above)
|
||||
* @param envelope the full envelope to send
|
||||
* @param message the message to send
|
||||
* @param size size of the message
|
||||
*/
|
||||
bool ChannelImpl::publish(const std::string &exchange, const std::string &routingKey, int flags, const Envelope &envelope)
|
||||
bool ChannelImpl::publish(const std::string &exchange, const std::string &routingKey, const Envelope &envelope)
|
||||
{
|
||||
// we are going to send out multiple frames, each one will trigger a call to the handler,
|
||||
// which in turn could destruct the channel object, we need to monitor that
|
||||
Monitor monitor(this);
|
||||
|
||||
|
||||
// @todo do not copy the entire buffer to individual frames
|
||||
|
||||
|
||||
// send the publish frame
|
||||
if (!send(BasicPublishFrame(_id, exchange, routingKey, flags & mandatory, flags & immediate))) return false;
|
||||
|
||||
if (!send(BasicPublishFrame(_id, exchange, routingKey))) return false;
|
||||
|
||||
// channel still valid?
|
||||
if (!monitor.valid()) return false;
|
||||
|
||||
// send header
|
||||
if (!send(BasicHeaderFrame(_id, envelope))) return false;
|
||||
|
||||
|
||||
// channel and connection still valid?
|
||||
if (!monitor.valid() || !_connection) return false;
|
||||
|
||||
|
||||
// the max payload size is the max frame size minus the bytes for headers and trailer
|
||||
uint32_t maxpayload = _connection->maxPayload();
|
||||
uint32_t bytessent = 0;
|
||||
|
||||
|
||||
// the buffer
|
||||
const char *data = envelope.body();
|
||||
uint32_t bytesleft = envelope.bodySize();
|
||||
|
||||
|
||||
// split up the body in multiple frames depending on the max frame size
|
||||
while (bytesleft > 0)
|
||||
{
|
||||
// size of this chunk
|
||||
uint32_t chunksize = std::min(maxpayload, bytesleft);
|
||||
|
||||
|
||||
// send out a body frame
|
||||
if (!send(BodyFrame(_id, data + bytessent, chunksize))) return false;
|
||||
|
||||
|
||||
// channel still valid?
|
||||
if (!monitor.valid()) return false;
|
||||
|
||||
|
||||
// update counters
|
||||
bytessent += chunksize;
|
||||
bytesleft -= chunksize;
|
||||
}
|
||||
|
||||
|
||||
// done
|
||||
return true;
|
||||
}
|
||||
|
|
@ -367,12 +459,14 @@ bool ChannelImpl::publish(const std::string &exchange, const std::string &routin
|
|||
/**
|
||||
* Set the Quality of Service (QOS) for this channel
|
||||
* @param prefetchCount maximum number of messages to prefetch
|
||||
* @return bool whether the Qos frame is sent.
|
||||
*
|
||||
* This function returns a deferred handler. Callbacks can be installed
|
||||
* using onSuccess(), onError() and onFinalize() methods.
|
||||
*/
|
||||
bool ChannelImpl::setQos(uint16_t prefetchCount)
|
||||
Deferred &ChannelImpl::setQos(uint16_t prefetchCount)
|
||||
{
|
||||
// send a qos frame
|
||||
return send(BasicQosFrame(_id, prefetchCount, false));
|
||||
return push(BasicQosFrame(_id, prefetchCount, false));
|
||||
}
|
||||
|
||||
/**
|
||||
|
|
@ -381,27 +475,69 @@ bool ChannelImpl::setQos(uint16_t prefetchCount)
|
|||
* @param tag a consumer tag that will be associated with this consume operation
|
||||
* @param flags additional flags
|
||||
* @param arguments additional arguments
|
||||
* @return bool
|
||||
*
|
||||
* This function returns a deferred handler. Callbacks can be installed
|
||||
* using onSuccess(), onError() and onFinalize() methods.
|
||||
*
|
||||
* The onSuccess() callback that you can install should have the following signature:
|
||||
*
|
||||
* void myCallback(AMQP::Channel *channel, const std::string& tag);
|
||||
*
|
||||
* For example: channel.declareQueue("myqueue").onSuccess([](AMQP::Channel *channel, const std::string& tag) {
|
||||
*
|
||||
* std::cout << "Started consuming under tag " << tag << std::endl;
|
||||
*
|
||||
* });
|
||||
*/
|
||||
bool ChannelImpl::consume(const std::string &queue, const std::string &tag, int flags, const Table &arguments)
|
||||
DeferredConsumer& ChannelImpl::consume(const std::string &queue, const std::string &tag, int flags, const Table &arguments)
|
||||
{
|
||||
// send a consume frame
|
||||
return send(BasicConsumeFrame(_id, queue, tag, flags & nolocal, flags & noack, flags & exclusive, flags & nowait, arguments));
|
||||
// the frame to send
|
||||
BasicConsumeFrame frame(_id, queue, tag, flags & nolocal, flags & noack, flags & exclusive, false, arguments);
|
||||
|
||||
// send the frame, and create deferred object
|
||||
auto *deferred = new DeferredConsumer(this, send(frame));
|
||||
|
||||
// push to list
|
||||
push(deferred);
|
||||
|
||||
// done
|
||||
return *deferred;
|
||||
}
|
||||
|
||||
/**
|
||||
* Cancel a running consumer
|
||||
* @param tag the consumer tag
|
||||
* @param flags optional flags
|
||||
*
|
||||
* This function returns a deferred handler. Callbacks can be installed
|
||||
* using onSuccess(), onError() and onFinalize() methods.
|
||||
*
|
||||
* The onSuccess() callback that you can install should have the following signature:
|
||||
*
|
||||
* void myCallback(AMQP::Channel *channel, const std::string& tag);
|
||||
*
|
||||
* For example: channel.declareQueue("myqueue").onSuccess([](AMQP::Channel *channel, const std::string& tag) {
|
||||
*
|
||||
* std::cout << "Started consuming under tag " << tag << std::endl;
|
||||
*
|
||||
* });
|
||||
*/
|
||||
bool ChannelImpl::cancel(const std::string &tag, int flags)
|
||||
DeferredCancel &ChannelImpl::cancel(const std::string &tag)
|
||||
{
|
||||
// send a cancel frame
|
||||
return send(BasicCancelFrame(_id, tag, flags & nowait));
|
||||
// the cancel frame to send
|
||||
BasicCancelFrame frame(_id, tag, false);
|
||||
|
||||
// send the frame, and create deferred object
|
||||
auto *deferred = new DeferredCancel(this, send(frame));
|
||||
|
||||
// push to list
|
||||
push(deferred);
|
||||
|
||||
// done
|
||||
return *deferred;
|
||||
}
|
||||
|
||||
/**
|
||||
* Acknoledge a message
|
||||
* Acknowledge a message
|
||||
* @param deliveryTag the delivery tag
|
||||
* @param flags optional flags
|
||||
* @return bool
|
||||
|
|
@ -420,19 +556,30 @@ bool ChannelImpl::ack(uint64_t deliveryTag, int flags)
|
|||
*/
|
||||
bool ChannelImpl::reject(uint64_t deliveryTag, int flags)
|
||||
{
|
||||
// send a nack frame
|
||||
return send(BasicNackFrame(_id, deliveryTag, flags & multiple, flags & requeue));
|
||||
// should we reject multiple messages?
|
||||
if (flags & multiple)
|
||||
{
|
||||
// send a nack frame
|
||||
return send(BasicNackFrame(_id, deliveryTag, true, flags & requeue));
|
||||
}
|
||||
else
|
||||
{
|
||||
// send a reject frame
|
||||
return send(BasicRejectFrame(_id, deliveryTag, flags & requeue));
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Recover un-acked messages
|
||||
* @param flags optional flags
|
||||
* @return bool
|
||||
*
|
||||
* This function returns a deferred handler. Callbacks can be installed
|
||||
* using onSuccess(), onError() and onFinalize() methods.
|
||||
*/
|
||||
bool ChannelImpl::recover(int flags)
|
||||
Deferred &ChannelImpl::recover(int flags)
|
||||
{
|
||||
// send a nack frame
|
||||
return send(BasicRecoverFrame(_id, flags & requeue));
|
||||
return push(BasicRecoverFrame(_id, flags & requeue));
|
||||
}
|
||||
|
||||
/**
|
||||
|
|
@ -444,11 +591,57 @@ bool ChannelImpl::send(const Frame &frame)
|
|||
{
|
||||
// skip if channel is not connected
|
||||
if (_state != state_connected || !_connection) return false;
|
||||
|
||||
|
||||
// are we currently in synchronous mode or are there
|
||||
// other frames waiting for their turn to be sent?
|
||||
if (_synchronous || !_queue.empty())
|
||||
{
|
||||
// we need to wait until the synchronous frame has
|
||||
// been processed, so queue the frame until it was
|
||||
_queue.emplace(frame.synchronous(), frame.buffer());
|
||||
|
||||
// it was of course not actually sent but we pretend
|
||||
// that it was, because no error occured
|
||||
return true;
|
||||
}
|
||||
|
||||
// enter synchronous mode if necessary
|
||||
_synchronous = frame.synchronous();
|
||||
|
||||
// send to tcp connection
|
||||
return _connection->send(frame);
|
||||
}
|
||||
|
||||
/**
|
||||
* Signal the channel that a synchronous operation
|
||||
* was completed. After this operation, waiting
|
||||
* frames can be sent out.
|
||||
*/
|
||||
void ChannelImpl::synchronized()
|
||||
{
|
||||
// we are no longer waiting for synchronous operations
|
||||
_synchronous = false;
|
||||
|
||||
// we need to monitor the channel for validity
|
||||
Monitor monitor(this);
|
||||
|
||||
// send all frames while not in synchronous mode
|
||||
while (monitor.valid() && !_synchronous && !_queue.empty())
|
||||
{
|
||||
// retrieve the first buffer and synchronous
|
||||
auto pair = std::move(_queue.front());
|
||||
|
||||
// remove from the list
|
||||
_queue.pop();
|
||||
|
||||
// mark as synchronous if necessary
|
||||
_synchronous = pair.first;
|
||||
|
||||
// send it over the connection
|
||||
_connection->send(std::move(pair.second));
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Report the received message
|
||||
*/
|
||||
|
|
@ -456,49 +649,41 @@ void ChannelImpl::reportMessage()
|
|||
{
|
||||
// skip if there is no message
|
||||
if (!_message) return;
|
||||
|
||||
|
||||
// look for the consumer
|
||||
auto iter = _consumers.find(_message->consumer());
|
||||
if (iter == _consumers.end()) return;
|
||||
|
||||
// is this a valid callback method
|
||||
if (!iter->second) return;
|
||||
|
||||
// after the report the channel may be destructed, monitor that
|
||||
Monitor monitor(this);
|
||||
|
||||
// do we have a handler?
|
||||
if (_handler) _message->report(_parent, _handler);
|
||||
|
||||
|
||||
// call the callback
|
||||
_message->report(iter->second);
|
||||
|
||||
// skip if channel was destructed
|
||||
if (!monitor.valid()) return;
|
||||
|
||||
|
||||
// no longer need the message
|
||||
delete _message;
|
||||
_message = nullptr;
|
||||
delete _message; _message = nullptr;
|
||||
}
|
||||
|
||||
/**
|
||||
* Create an incoming message
|
||||
* @param frame
|
||||
* @return MessageImpl
|
||||
* @return ConsumedMessage
|
||||
*/
|
||||
MessageImpl *ChannelImpl::message(const BasicDeliverFrame &frame)
|
||||
ConsumedMessage *ChannelImpl::message(const BasicDeliverFrame &frame)
|
||||
{
|
||||
// it should not be possible that a message already exists, but lets check it anyhow
|
||||
// destruct if message is already set
|
||||
if (_message) delete _message;
|
||||
|
||||
|
||||
// construct a message
|
||||
return _message = new ConsumedMessage(frame);
|
||||
}
|
||||
|
||||
/**
|
||||
* Create an incoming message
|
||||
* @param frame
|
||||
* @return MessageImpl
|
||||
*/
|
||||
MessageImpl *ChannelImpl::message(const BasicReturnFrame &frame)
|
||||
{
|
||||
// it should not be possible that a message already exists, but lets check it anyhow
|
||||
if (_message) delete _message;
|
||||
|
||||
// construct a message
|
||||
return _message = new ReturnedMessage(frame);
|
||||
}
|
||||
|
||||
/**
|
||||
* End of namespace
|
||||
*/
|
||||
|
|
|
|||
|
|
@ -157,7 +157,7 @@ public:
|
|||
|
||||
// no need to check for a channel, the error is connection wide
|
||||
// report the error on the connection
|
||||
connection->reportError(text());
|
||||
connection->reportError(text().c_str());
|
||||
|
||||
// done
|
||||
return true;
|
||||
|
|
|
|||
|
|
@ -17,13 +17,13 @@ namespace AMQP {
|
|||
|
||||
/**
|
||||
* Construct an AMQP object based on full login data
|
||||
*
|
||||
*
|
||||
* The first parameter is a handler object. This handler class is
|
||||
* an interface that should be implemented by the caller.
|
||||
*
|
||||
*
|
||||
* Note that the constructor is private to ensure that nobody can construct
|
||||
* this class, only the real Connection class via a friend construct
|
||||
*
|
||||
*
|
||||
* @param parent Parent connection object
|
||||
* @param handler Connection handler
|
||||
* @param login Login data
|
||||
|
|
@ -42,7 +42,7 @@ ConnectionImpl::~ConnectionImpl()
|
|||
{
|
||||
// close the connection in a nice fashion
|
||||
close();
|
||||
|
||||
|
||||
// invalidate all channels, so they will no longer call methods on this channel object
|
||||
for (auto iter = _channels.begin(); iter != _channels.end(); iter++) iter->second->invalidate();
|
||||
}
|
||||
|
|
@ -57,20 +57,20 @@ uint16_t ConnectionImpl::add(ChannelImpl *channel)
|
|||
{
|
||||
// check if we have exceeded the limit already
|
||||
if (_maxChannels > 0 && _channels.size() >= _maxChannels) return 0;
|
||||
|
||||
|
||||
// keep looping to find an id that is not in use
|
||||
while (true)
|
||||
{
|
||||
// is this id in use?
|
||||
if (_nextFreeChannel > 0 && _channels.find(_nextFreeChannel) == _channels.end()) break;
|
||||
|
||||
|
||||
// id is in use, move on
|
||||
_nextFreeChannel++;
|
||||
}
|
||||
|
||||
|
||||
// we have a new channel
|
||||
_channels[_nextFreeChannel] = channel;
|
||||
|
||||
|
||||
// done
|
||||
return _nextFreeChannel++;
|
||||
}
|
||||
|
|
@ -90,7 +90,7 @@ void ConnectionImpl::remove(ChannelImpl *channel)
|
|||
|
||||
/**
|
||||
* Parse the buffer into a recognized frame
|
||||
*
|
||||
*
|
||||
* Every time that data comes in on the connection, you should call this method to parse
|
||||
* the incoming data, and let it handle by the AMQP library. This method returns the number
|
||||
* of bytes that were processed.
|
||||
|
|
@ -104,17 +104,17 @@ void ConnectionImpl::remove(ChannelImpl *channel)
|
|||
* @param size size of the buffer to decode
|
||||
* @return number of bytes that were processed
|
||||
*/
|
||||
size_t ConnectionImpl::parse(char *buffer, size_t size)
|
||||
size_t ConnectionImpl::parse(const char *buffer, size_t size)
|
||||
{
|
||||
// do not parse if already in an error state
|
||||
if (_state == state_closed) return 0;
|
||||
|
||||
|
||||
// number of bytes processed
|
||||
size_t processed = 0;
|
||||
|
||||
|
||||
// create a monitor object that checks if the connection still exists
|
||||
Monitor monitor(this);
|
||||
|
||||
|
||||
// keep looping until we have processed all bytes, and the monitor still
|
||||
// indicates that the connection is in a valid state
|
||||
while (size > 0 && monitor.valid())
|
||||
|
|
@ -131,7 +131,7 @@ size_t ConnectionImpl::parse(char *buffer, size_t size)
|
|||
|
||||
// number of bytes processed
|
||||
size_t bytes = receivedFrame.totalSize();
|
||||
|
||||
|
||||
// add bytes
|
||||
processed += bytes; size -= bytes; buffer += bytes;
|
||||
}
|
||||
|
|
@ -139,12 +139,12 @@ size_t ConnectionImpl::parse(char *buffer, size_t size)
|
|||
{
|
||||
// something terrible happened on the protocol (like data out of range)
|
||||
reportError(exception.what());
|
||||
|
||||
|
||||
// done
|
||||
return processed;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
// done
|
||||
return processed;
|
||||
}
|
||||
|
|
@ -161,13 +161,13 @@ bool ConnectionImpl::close()
|
|||
|
||||
// mark that the object is closed
|
||||
_closed = true;
|
||||
|
||||
|
||||
// if still busy with handshake, we delay closing for a while
|
||||
if (_state == state_handshake || _state == state_protocol) return true;
|
||||
|
||||
// perform the close operation
|
||||
sendClose();
|
||||
|
||||
|
||||
// done
|
||||
return true;
|
||||
}
|
||||
|
|
@ -181,26 +181,26 @@ bool ConnectionImpl::sendClose()
|
|||
{
|
||||
// after the send operation the object could be dead
|
||||
Monitor monitor(this);
|
||||
|
||||
|
||||
// loop over all channels
|
||||
for (auto iter = _channels.begin(); iter != _channels.end(); iter++)
|
||||
{
|
||||
// close the channel
|
||||
iter->second->close();
|
||||
|
||||
|
||||
// we could be dead now
|
||||
if (!monitor.valid()) return false;
|
||||
}
|
||||
|
||||
|
||||
// send the close frame
|
||||
send(ConnectionCloseFrame(0, "shutdown"));
|
||||
|
||||
|
||||
// leap out if object no longer is alive
|
||||
if (!monitor.valid()) return false;
|
||||
|
||||
|
||||
// we're in a new state
|
||||
_state = state_closing;
|
||||
|
||||
|
||||
// done
|
||||
return true;
|
||||
}
|
||||
|
|
@ -213,35 +213,29 @@ void ConnectionImpl::setConnected()
|
|||
// store connected state
|
||||
_state = state_connected;
|
||||
|
||||
// if the close operation was already called, we do that again now again
|
||||
// so that the actual messages to close down the connection and the channel
|
||||
// are appended to the queue
|
||||
// if the close method was called before, the frame was not
|
||||
// sent. append it to the end of the queue to make sure we
|
||||
// are correctly closed down.
|
||||
if (_closed && !sendClose()) return;
|
||||
|
||||
|
||||
// we're going to call the handler, which can destruct the connection,
|
||||
// so we must monitor if the queue object is still valid after calling
|
||||
Monitor monitor(this);
|
||||
|
||||
|
||||
// inform handler
|
||||
_handler->onConnected(_parent);
|
||||
|
||||
// leap out if the connection no longer exists
|
||||
if (!monitor.valid()) return;
|
||||
|
||||
|
||||
// empty the queue of messages
|
||||
while (!_queue.empty())
|
||||
while (monitor.valid() && !_queue.empty())
|
||||
{
|
||||
// get the next message
|
||||
OutBuffer buffer(std::move(_queue.front()));
|
||||
|
||||
// remove it from the queue
|
||||
_queue.pop();
|
||||
|
||||
|
||||
// send it
|
||||
_handler->onData(_parent, buffer.data(), buffer.size());
|
||||
|
||||
// leap out if the connection was destructed
|
||||
if (!monitor.valid()) return;
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -254,18 +248,12 @@ bool ConnectionImpl::send(const Frame &frame)
|
|||
{
|
||||
// its not possible to send anything if closed or closing down
|
||||
if (_state == state_closing || _state == state_closed) return false;
|
||||
|
||||
|
||||
// we need an output buffer
|
||||
OutBuffer buffer(frame.totalSize());
|
||||
|
||||
// fill the buffer
|
||||
frame.fill(buffer);
|
||||
|
||||
// append an end of frame byte (but not when still negotiating the protocol)
|
||||
if (frame.needsSeparator()) buffer.add((uint8_t)206);
|
||||
|
||||
OutBuffer buffer(frame.buffer());
|
||||
|
||||
// are we still setting up the connection?
|
||||
if ((_state == state_connected && _queue.size() == 0) || frame.partOfHandshake())
|
||||
if ((_state == state_connected && _queue.empty()) || frame.partOfHandshake())
|
||||
{
|
||||
// send the buffer
|
||||
_handler->onData(_parent, buffer.data(), buffer.size());
|
||||
|
|
@ -275,7 +263,33 @@ bool ConnectionImpl::send(const Frame &frame)
|
|||
// the connection is still being set up, so we need to delay the message sending
|
||||
_queue.push(std::move(buffer));
|
||||
}
|
||||
|
||||
|
||||
// done
|
||||
return true;
|
||||
}
|
||||
|
||||
/**
|
||||
* Send buffered data over the connection
|
||||
*
|
||||
* @param buffer the buffer with data to send
|
||||
*/
|
||||
bool ConnectionImpl::send(OutBuffer &&buffer)
|
||||
{
|
||||
// this only works when we are already connected
|
||||
if (_state != state_connected) return false;
|
||||
|
||||
// are we waiting for other frames to be sent before us?
|
||||
if (_queue.empty())
|
||||
{
|
||||
// send it directly
|
||||
_handler->onData(_parent, buffer.data(), buffer.size());
|
||||
}
|
||||
else
|
||||
{
|
||||
// add to the list of waiting buffers
|
||||
_queue.push(std::move(buffer));
|
||||
}
|
||||
|
||||
// done
|
||||
return true;
|
||||
}
|
||||
|
|
|
|||
|
|
@ -26,7 +26,7 @@ private:
|
|||
* @var uint64_t
|
||||
*/
|
||||
uint64_t _deliveryTag;
|
||||
|
||||
|
||||
/**
|
||||
* Is this a redelivered message?
|
||||
* @var bool
|
||||
|
|
@ -39,25 +39,33 @@ public:
|
|||
* Constructor
|
||||
* @param frame
|
||||
*/
|
||||
ConsumedMessage(const BasicDeliverFrame &frame) :
|
||||
MessageImpl(frame.exchange(), frame.routingKey()),
|
||||
ConsumedMessage(const BasicDeliverFrame &frame) :
|
||||
MessageImpl(frame.exchange(), frame.routingKey()),
|
||||
_consumerTag(frame.consumerTag()), _deliveryTag(frame.deliveryTag()), _redelivered(frame.redelivered())
|
||||
{}
|
||||
|
||||
|
||||
/**
|
||||
* Destructor
|
||||
*/
|
||||
virtual ~ConsumedMessage() {}
|
||||
|
||||
|
||||
/**
|
||||
* Retrieve the consumer tag
|
||||
* @return std::string
|
||||
*/
|
||||
const std::string &consumer() const
|
||||
{
|
||||
return _consumerTag;
|
||||
}
|
||||
|
||||
/**
|
||||
* Report to the handler
|
||||
* @param channel
|
||||
* @param handler
|
||||
* @param callback
|
||||
*/
|
||||
virtual void report(Channel *channel, ChannelHandler *handler) override
|
||||
void report(const MessageCallback &callback) const
|
||||
{
|
||||
// report to the handler
|
||||
handler->onReceived(channel, *this, _deliveryTag, _consumerTag, _redelivered);
|
||||
// send ourselves to the consumer
|
||||
if (callback) callback(*this, _deliveryTag, _redelivered);
|
||||
}
|
||||
};
|
||||
|
||||
|
|
|
|||
|
|
@ -0,0 +1,42 @@
|
|||
/**
|
||||
* DeferredCancel.cpp
|
||||
*
|
||||
* Implementation file for the DeferredCancel class
|
||||
*
|
||||
* @copyright 2014 Copernica BV
|
||||
*/
|
||||
#include "includes.h"
|
||||
|
||||
/**
|
||||
* Namespace
|
||||
*/
|
||||
namespace AMQP {
|
||||
|
||||
/**
|
||||
* Report success for frames that report cancel operations
|
||||
* @param name Consumer tag that is cancelled
|
||||
* @return Deferred
|
||||
*/
|
||||
Deferred *DeferredCancel::reportSuccess(const std::string &name) const
|
||||
{
|
||||
// in the channel, we should uninstall the consumer
|
||||
_channel->uninstall(name);
|
||||
|
||||
// skip if no special callback was installed
|
||||
if (!_cancelCallback) return Deferred::reportSuccess();
|
||||
|
||||
// call the callback
|
||||
_cancelCallback(name);
|
||||
|
||||
// call finalize callback
|
||||
if (_finalizeCallback) _finalizeCallback();
|
||||
|
||||
// return next object
|
||||
return _next;
|
||||
}
|
||||
|
||||
/**
|
||||
* End namespace
|
||||
*/
|
||||
}
|
||||
|
||||
|
|
@ -0,0 +1,41 @@
|
|||
/**
|
||||
* DeferredConsumer.cpp
|
||||
*
|
||||
* Implementation file for the DeferredConsumer class
|
||||
*
|
||||
* @copyright 2014 Copernica BV
|
||||
*/
|
||||
#include "includes.h"
|
||||
|
||||
/**
|
||||
* Namespace
|
||||
*/
|
||||
namespace AMQP {
|
||||
|
||||
/**
|
||||
* Report success for frames that report start consumer operations
|
||||
* @param name Consumer tag that is started
|
||||
* @return Deferred
|
||||
*/
|
||||
Deferred *DeferredConsumer::reportSuccess(const std::string &name) const
|
||||
{
|
||||
// we now know the name, so we can install the message callback on the channel
|
||||
_channel->install(name, _messageCallback);
|
||||
|
||||
// skip if no special callback was installed
|
||||
if (!_consumeCallback) return Deferred::reportSuccess();
|
||||
|
||||
// call the callback
|
||||
_consumeCallback(name);
|
||||
|
||||
// call finalize callback
|
||||
if (_finalizeCallback) _finalizeCallback();
|
||||
|
||||
// return next object
|
||||
return _next;
|
||||
}
|
||||
|
||||
/**
|
||||
* End namespace
|
||||
*/
|
||||
}
|
||||
|
|
@ -22,12 +22,6 @@ protected:
|
|||
* @param what
|
||||
*/
|
||||
explicit Exception(const std::string &what) : runtime_error(what) {}
|
||||
|
||||
public:
|
||||
/**
|
||||
* Destructor
|
||||
*/
|
||||
virtual ~Exception() {}
|
||||
};
|
||||
|
||||
/**
|
||||
|
|
|
|||
|
|
@ -1,6 +1,6 @@
|
|||
/**
|
||||
* Exchangebindframe.h
|
||||
*
|
||||
*
|
||||
* @copyright 2014 Copernica BV
|
||||
*/
|
||||
|
||||
|
|
@ -26,25 +26,25 @@ private:
|
|||
* @var ShortString
|
||||
*/
|
||||
ShortString _destination;
|
||||
|
||||
|
||||
/**
|
||||
* Exchange which is bound
|
||||
* Exchange which is bound
|
||||
* @var ShortString
|
||||
*/
|
||||
ShortString _source;
|
||||
|
||||
|
||||
/**
|
||||
* Routing key
|
||||
* @var ShortString
|
||||
*/
|
||||
ShortString _routingKey;
|
||||
|
||||
|
||||
/**
|
||||
* contains: nowait do not wait on response
|
||||
* @var booleanset
|
||||
*/
|
||||
BooleanSet _bools;
|
||||
|
||||
|
||||
/**
|
||||
* Additional arguments
|
||||
* @var Table
|
||||
|
|
@ -61,7 +61,7 @@ protected:
|
|||
{
|
||||
// call base
|
||||
ExchangeFrame::fill(buffer);
|
||||
|
||||
|
||||
buffer.add(_reserved);
|
||||
_destination.fill(buffer);
|
||||
_source.fill(buffer);
|
||||
|
|
@ -70,13 +70,13 @@ protected:
|
|||
_arguments.fill(buffer);
|
||||
}
|
||||
|
||||
public:
|
||||
public:
|
||||
/**
|
||||
* Constructor based on incoming data
|
||||
*
|
||||
*
|
||||
* @param frame received frame to decode
|
||||
*/
|
||||
ExchangeBindFrame(ReceivedFrame &frame) :
|
||||
ExchangeBindFrame(ReceivedFrame &frame) :
|
||||
ExchangeFrame(frame),
|
||||
_reserved(frame.nextUint16()),
|
||||
_destination(frame),
|
||||
|
|
@ -102,8 +102,19 @@ public:
|
|||
_bools(noWait),
|
||||
_arguments(arguments)
|
||||
{}
|
||||
|
||||
|
||||
|
||||
/**
|
||||
* Is this a synchronous frame?
|
||||
*
|
||||
* After a synchronous frame no more frames may be
|
||||
* sent until the accompanying -ok frame arrives
|
||||
*/
|
||||
bool synchronous() const override
|
||||
{
|
||||
// we are synchronous when the nowait option has not been set
|
||||
return !noWait();
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the destination exchange
|
||||
* @return string
|
||||
|
|
@ -112,7 +123,7 @@ public:
|
|||
{
|
||||
return _destination;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Get the source exchange
|
||||
* @return string
|
||||
|
|
@ -121,7 +132,7 @@ public:
|
|||
{
|
||||
return _source;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Get the routing key
|
||||
* @return string
|
||||
|
|
@ -130,7 +141,7 @@ public:
|
|||
{
|
||||
return _routingKey;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Get the method id
|
||||
* @return uint16_t
|
||||
|
|
@ -139,7 +150,7 @@ public:
|
|||
{
|
||||
return 30;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Get the additional arguments
|
||||
* @return Table
|
||||
|
|
@ -148,12 +159,12 @@ public:
|
|||
{
|
||||
return _arguments;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Get the nowait bool
|
||||
* @return bool
|
||||
*/
|
||||
bool noWait()
|
||||
bool noWait() const
|
||||
{
|
||||
return _bools.get(0);
|
||||
}
|
||||
|
|
|
|||
|
|
@ -1,6 +1,6 @@
|
|||
/**
|
||||
* Exchangebindokframe.h
|
||||
*
|
||||
*
|
||||
* @copyright 2014 Copernica BV
|
||||
*/
|
||||
|
||||
|
|
@ -8,7 +8,7 @@
|
|||
* Set up namespace
|
||||
*/
|
||||
namespace AMQP {
|
||||
|
||||
|
||||
/**
|
||||
* Class definition
|
||||
*/
|
||||
|
|
@ -29,10 +29,10 @@ protected:
|
|||
public:
|
||||
/**
|
||||
* Constructor based on incoming data
|
||||
*
|
||||
*
|
||||
* @param frame received frame to decode
|
||||
*/
|
||||
ExchangeBindOKFrame(ReceivedFrame &frame) :
|
||||
ExchangeBindOKFrame(ReceivedFrame &frame) :
|
||||
ExchangeFrame(frame)
|
||||
{}
|
||||
|
||||
|
|
@ -47,12 +47,12 @@ public:
|
|||
ExchangeBindOKFrame(uint16_t channel) :
|
||||
ExchangeFrame(channel, 0)
|
||||
{}
|
||||
|
||||
|
||||
virtual uint16_t methodID() const override
|
||||
{
|
||||
return 31;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Process the frame
|
||||
* @param connection The connection over which it was received
|
||||
|
|
@ -62,17 +62,17 @@ public:
|
|||
{
|
||||
// check if we have a channel
|
||||
ChannelImpl *channel = connection->channel(this->channel());
|
||||
|
||||
|
||||
// channel does not exist
|
||||
if(!channel) return false;
|
||||
|
||||
// report to handler
|
||||
channel->reportExchangeBound();
|
||||
|
||||
if (channel->reportSuccess()) channel->synchronized();
|
||||
|
||||
// done
|
||||
return true;
|
||||
}
|
||||
};
|
||||
|
||||
|
||||
// end namespace
|
||||
}
|
||||
|
|
|
|||
|
|
@ -106,6 +106,18 @@ public:
|
|||
*/
|
||||
virtual ~ExchangeDeclareFrame() {}
|
||||
|
||||
/**
|
||||
* Is this a synchronous frame?
|
||||
*
|
||||
* After a synchronous frame no more frames may be
|
||||
* sent until the accompanying -ok frame arrives
|
||||
*/
|
||||
bool synchronous() const override
|
||||
{
|
||||
// we are synchronous without the nowait option
|
||||
return !noWait();
|
||||
}
|
||||
|
||||
/**
|
||||
* Method id
|
||||
* @return uint16_t
|
||||
|
|
|
|||
|
|
@ -1,6 +1,6 @@
|
|||
/**
|
||||
* Class describing an AMQP exchange declare ok frame
|
||||
*
|
||||
*
|
||||
* @copyright 2014 Copernica BV
|
||||
*/
|
||||
|
||||
|
|
@ -55,7 +55,7 @@ public:
|
|||
{
|
||||
return 11;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Process the frame
|
||||
* @param connection The connection over which it was received
|
||||
|
|
@ -65,13 +65,13 @@ public:
|
|||
{
|
||||
// we need the appropriate channel
|
||||
ChannelImpl *channel = connection->channel(this->channel());
|
||||
|
||||
|
||||
// channel does not exist
|
||||
if(!channel) return false;
|
||||
|
||||
|
||||
// report exchange declare ok
|
||||
channel->reportExchangeDeclared();
|
||||
|
||||
if (channel->reportSuccess()) channel->synchronized();
|
||||
|
||||
// done
|
||||
return true;
|
||||
}
|
||||
|
|
|
|||
|
|
@ -83,6 +83,18 @@ public:
|
|||
*/
|
||||
virtual ~ExchangeDeleteFrame() {}
|
||||
|
||||
/**
|
||||
* Is this a synchronous frame?
|
||||
*
|
||||
* After a synchronous frame no more frames may be
|
||||
* sent until the accompanying -ok frame arrives
|
||||
*/
|
||||
bool synchronous() const override
|
||||
{
|
||||
// we are synchronous without the nowait option
|
||||
return !noWait();
|
||||
}
|
||||
|
||||
/**
|
||||
* returns the method id
|
||||
* @return uint16_t
|
||||
|
|
|
|||
|
|
@ -1,6 +1,6 @@
|
|||
/**
|
||||
* Class describing an AMQP exchange delete ok frame
|
||||
*
|
||||
*
|
||||
* @copyright 2014 Copernica BV
|
||||
*/
|
||||
|
||||
|
|
@ -32,7 +32,7 @@ public:
|
|||
*
|
||||
* @param frame received frame
|
||||
*/
|
||||
ExchangeDeleteOKFrame(ReceivedFrame &frame) :
|
||||
ExchangeDeleteOKFrame(ReceivedFrame &frame) :
|
||||
ExchangeFrame(frame)
|
||||
{}
|
||||
|
||||
|
|
@ -56,7 +56,7 @@ public:
|
|||
{
|
||||
return 21;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Process the frame
|
||||
* @param connection The connection over which it was received
|
||||
|
|
@ -66,13 +66,13 @@ public:
|
|||
{
|
||||
// check if we have a channel
|
||||
ChannelImpl *channel = connection->channel(this->channel());
|
||||
|
||||
|
||||
// channel does not exist
|
||||
if(!channel) return false;
|
||||
|
||||
|
||||
// report to handler
|
||||
channel->reportExchangeDeleted();
|
||||
|
||||
if (channel->reportSuccess()) channel->synchronized();
|
||||
|
||||
// done
|
||||
return true;
|
||||
}
|
||||
|
|
|
|||
|
|
@ -8,7 +8,7 @@
|
|||
* Set up namespace
|
||||
*/
|
||||
namespace AMQP {
|
||||
|
||||
|
||||
/**
|
||||
* Class definition
|
||||
*/
|
||||
|
|
@ -26,31 +26,31 @@ private:
|
|||
* @var ShortString
|
||||
*/
|
||||
ShortString _destination;
|
||||
|
||||
|
||||
/**
|
||||
* Exchange which is bound
|
||||
* Exchange which is bound
|
||||
* @var ShortString
|
||||
*/
|
||||
ShortString _source;
|
||||
|
||||
|
||||
/**
|
||||
* Routing key
|
||||
* @var ShortString
|
||||
*/
|
||||
ShortString _routingKey;
|
||||
|
||||
|
||||
/**
|
||||
* contains: nowait do not wait on response
|
||||
* @var booleanset
|
||||
*/
|
||||
BooleanSet _bools;
|
||||
|
||||
|
||||
/**
|
||||
* Additional arguments
|
||||
* @var Table
|
||||
*/
|
||||
Table _arguments;
|
||||
|
||||
|
||||
protected:
|
||||
/**
|
||||
* Encode a frame on a string buffer
|
||||
|
|
@ -61,7 +61,7 @@ protected:
|
|||
{
|
||||
// call base
|
||||
ExchangeFrame::fill(buffer);
|
||||
|
||||
|
||||
buffer.add(_reserved);
|
||||
_destination.fill(buffer);
|
||||
_source.fill(buffer);
|
||||
|
|
@ -73,10 +73,10 @@ protected:
|
|||
public:
|
||||
/**
|
||||
* Constructor based on incoming data
|
||||
*
|
||||
*
|
||||
* @param frame received frame to decode
|
||||
*/
|
||||
ExchangeUnbindFrame(ReceivedFrame &frame) :
|
||||
ExchangeUnbindFrame(ReceivedFrame &frame) :
|
||||
ExchangeFrame(frame),
|
||||
_reserved(frame.nextUint16()),
|
||||
_destination(frame),
|
||||
|
|
@ -102,8 +102,19 @@ public:
|
|||
_bools(noWait),
|
||||
_arguments(arguments)
|
||||
{}
|
||||
|
||||
|
||||
|
||||
/**
|
||||
* Is this a synchronous frame?
|
||||
*
|
||||
* After a synchronous frame no more frames may be
|
||||
* sent until the accompanying -ok frame arrives
|
||||
*/
|
||||
bool synchronous() const override
|
||||
{
|
||||
// we are synchronous without the nowait option
|
||||
return !noWait();
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the destination exchange
|
||||
* @return string
|
||||
|
|
@ -112,7 +123,7 @@ public:
|
|||
{
|
||||
return _destination;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Get the source exchange
|
||||
* @return string
|
||||
|
|
@ -121,7 +132,7 @@ public:
|
|||
{
|
||||
return _source;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Get the routing key
|
||||
* @return string
|
||||
|
|
@ -130,7 +141,7 @@ public:
|
|||
{
|
||||
return _routingKey;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Get the method id
|
||||
* @return uint16_t
|
||||
|
|
@ -139,7 +150,7 @@ public:
|
|||
{
|
||||
return 40;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Get the additional arguments
|
||||
* @return Table
|
||||
|
|
@ -148,16 +159,16 @@ public:
|
|||
{
|
||||
return _arguments;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Get the nowait bool
|
||||
* @return bool
|
||||
*/
|
||||
bool noWait()
|
||||
bool noWait() const
|
||||
{
|
||||
return _bools.get(0);
|
||||
}
|
||||
|
||||
|
||||
};
|
||||
// leave namespace
|
||||
}
|
||||
|
|
|
|||
|
|
@ -1,5 +1,5 @@
|
|||
/**
|
||||
* Exchangeunbindokframe.h
|
||||
* Exchangeunbindokframe.h
|
||||
*
|
||||
* @copyright 2014 Copernica BV
|
||||
*/
|
||||
|
|
@ -9,7 +9,7 @@
|
|||
* Set up namespace
|
||||
*/
|
||||
namespace AMQP {
|
||||
|
||||
|
||||
/**
|
||||
* Class definition
|
||||
*/
|
||||
|
|
@ -30,10 +30,10 @@ protected:
|
|||
public:
|
||||
/**
|
||||
* Constructor based on incoming data
|
||||
*
|
||||
*
|
||||
* @param frame received frame to decode
|
||||
*/
|
||||
ExchangeUnbindOKFrame(ReceivedFrame &frame) :
|
||||
ExchangeUnbindOKFrame(ReceivedFrame &frame) :
|
||||
ExchangeFrame(frame)
|
||||
{}
|
||||
|
||||
|
|
@ -48,12 +48,12 @@ public:
|
|||
ExchangeUnbindOKFrame(uint16_t channel) :
|
||||
ExchangeFrame(channel, 0)
|
||||
{}
|
||||
|
||||
|
||||
virtual uint16_t methodID() const override
|
||||
{
|
||||
return 51;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Process the frame
|
||||
* @param connection The connection over which it was received
|
||||
|
|
@ -63,17 +63,17 @@ public:
|
|||
{
|
||||
// check if we have a channel
|
||||
ChannelImpl *channel = connection->channel(this->channel());
|
||||
|
||||
|
||||
// channel does not exist
|
||||
if(!channel) return false;
|
||||
|
||||
// report to handler
|
||||
channel->reportExchangeUnbound();
|
||||
|
||||
if (channel->reportSuccess()) channel->synchronized();
|
||||
|
||||
// done
|
||||
return true;
|
||||
}
|
||||
};
|
||||
|
||||
|
||||
// end namespace
|
||||
}
|
||||
|
|
|
|||
|
|
@ -45,6 +45,45 @@ Field *Field::decode(ReceivedFrame &frame)
|
|||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Cast to string
|
||||
* @return std::string
|
||||
*/
|
||||
Field::operator const std::string& () const
|
||||
{
|
||||
// static empty string
|
||||
static std::string empty;
|
||||
|
||||
// return it
|
||||
return empty;
|
||||
}
|
||||
|
||||
/**
|
||||
* Cast to array
|
||||
* @return Array
|
||||
*/
|
||||
Field::operator const Array& () const
|
||||
{
|
||||
// static empty array
|
||||
static Array empty;
|
||||
|
||||
// return it
|
||||
return empty;
|
||||
}
|
||||
|
||||
/**
|
||||
* Cast to object
|
||||
* @return Array
|
||||
*/
|
||||
Field::operator const Table& () const
|
||||
{
|
||||
// static empty table
|
||||
static Table empty;
|
||||
|
||||
// return it
|
||||
return empty;
|
||||
}
|
||||
|
||||
/**
|
||||
* End of namespace
|
||||
*/
|
||||
|
|
|
|||
51
src/frame.h
51
src/frame.h
|
|
@ -1,9 +1,9 @@
|
|||
/**
|
||||
* Frame.h
|
||||
*
|
||||
*
|
||||
* Base class for frames. This base class can not be constructed from outside
|
||||
* the library, and is only used internally.
|
||||
*
|
||||
*
|
||||
* @copyright 2014 Copernica BV
|
||||
*/
|
||||
|
||||
|
|
@ -11,7 +11,7 @@
|
|||
* Set up namespace
|
||||
*/
|
||||
namespace AMQP {
|
||||
|
||||
|
||||
/**
|
||||
* Class definition
|
||||
*/
|
||||
|
|
@ -19,11 +19,11 @@ class Frame
|
|||
{
|
||||
protected:
|
||||
/**
|
||||
* Protected constructor to ensure that no objects are created from
|
||||
* Protected constructor to ensure that no objects are created from
|
||||
* outside the library
|
||||
*/
|
||||
Frame() {}
|
||||
|
||||
|
||||
public:
|
||||
/**
|
||||
* Destructor
|
||||
|
|
@ -35,40 +35,67 @@ public:
|
|||
* @return uint32_t
|
||||
*/
|
||||
virtual uint32_t totalSize() const = 0;
|
||||
|
||||
|
||||
/**
|
||||
* Fill an output buffer
|
||||
* @param buffer
|
||||
*/
|
||||
virtual void fill(OutBuffer &buffer) const = 0;
|
||||
|
||||
|
||||
/**
|
||||
* Is this a frame that is part of the connection setup?
|
||||
* @return bool
|
||||
*/
|
||||
virtual bool partOfHandshake() const { return false; }
|
||||
|
||||
|
||||
/**
|
||||
* Does this frame need an end-of-frame seperator?
|
||||
* @return bool
|
||||
*/
|
||||
virtual bool needsSeparator() const { return true; }
|
||||
|
||||
|
||||
/**
|
||||
* Is this a synchronous frame?
|
||||
*
|
||||
* After a synchronous frame no more frames may be
|
||||
* sent until the accompanying -ok frame arrives
|
||||
*/
|
||||
virtual bool synchronous() const { return false; }
|
||||
|
||||
/**
|
||||
* Retrieve the buffer in AMQP wire-format for
|
||||
* sending over the socket connection
|
||||
*/
|
||||
OutBuffer buffer() const
|
||||
{
|
||||
// we need an output buffer
|
||||
OutBuffer buffer(totalSize());
|
||||
|
||||
// fill the buffer
|
||||
fill(buffer);
|
||||
|
||||
// append an end of frame byte (but not when still negotiating the protocol)
|
||||
if (needsSeparator()) buffer.add((uint8_t)206);
|
||||
|
||||
// return the created buffer
|
||||
return buffer;
|
||||
}
|
||||
|
||||
/**
|
||||
* Process the frame
|
||||
* @param connection The connection over which it was received
|
||||
* @return bool Was it succesfully processed?
|
||||
*/
|
||||
virtual bool process(ConnectionImpl *connection)
|
||||
virtual bool process(ConnectionImpl *connection)
|
||||
{
|
||||
// this is an exception
|
||||
throw ProtocolException("unimplemented frame");
|
||||
|
||||
|
||||
// unreachable
|
||||
return false;
|
||||
}
|
||||
};
|
||||
|
||||
|
||||
/**
|
||||
* End of namespace
|
||||
*/
|
||||
|
|
|
|||
|
|
@ -11,7 +11,6 @@
|
|||
#include "../amqpcpp.h"
|
||||
|
||||
// classes that are very commonly used
|
||||
#include "monitor.h"
|
||||
#include "exception.h"
|
||||
#include "protocolexception.h"
|
||||
#include "frame.h"
|
||||
|
|
|
|||
|
|
@ -20,10 +20,10 @@ class MessageImpl : public Message
|
|||
private:
|
||||
/**
|
||||
* How many bytes have been received?
|
||||
* @var uint64_t
|
||||
* @var uint64_t
|
||||
*/
|
||||
uint64_t _received;
|
||||
|
||||
|
||||
/**
|
||||
* Was the buffer allocated by us?
|
||||
* @var bool
|
||||
|
|
@ -36,8 +36,8 @@ protected:
|
|||
* @param exchange
|
||||
* @param routingKey
|
||||
*/
|
||||
MessageImpl(const std::string &exchange, const std::string &routingKey) :
|
||||
Message(exchange, routingKey),
|
||||
MessageImpl(const std::string &exchange, const std::string &routingKey) :
|
||||
Message(exchange, routingKey),
|
||||
_received(0), _selfAllocated(false)
|
||||
{}
|
||||
|
||||
|
|
@ -45,12 +45,12 @@ public:
|
|||
/**
|
||||
* Destructor
|
||||
*/
|
||||
virtual ~MessageImpl()
|
||||
virtual ~MessageImpl()
|
||||
{
|
||||
// clear up memory if it was self allocated
|
||||
if (_selfAllocated) delete[] _body;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Set the body size
|
||||
* This field is set when the header is received
|
||||
|
|
@ -60,7 +60,7 @@ public:
|
|||
{
|
||||
_bodySize = size;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Append data
|
||||
* @param buffer incoming data
|
||||
|
|
@ -84,27 +84,20 @@ public:
|
|||
// it does not yet fit, do we have to allocate?
|
||||
if (!_body) _body = new char[_bodySize];
|
||||
_selfAllocated = true;
|
||||
|
||||
|
||||
// prevent that size is too big
|
||||
if (size > _bodySize - _received) size = _bodySize - _received;
|
||||
|
||||
|
||||
// append data
|
||||
memcpy((char *)(_body + _received), buffer, size);
|
||||
|
||||
|
||||
// we have more data now
|
||||
_received += size;
|
||||
|
||||
|
||||
// done
|
||||
return _received >= _bodySize;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Report to the handler
|
||||
* @param channel
|
||||
* @param handler
|
||||
*/
|
||||
virtual void report(Channel *channel, ChannelHandler *handler) = 0;
|
||||
};
|
||||
|
||||
/**
|
||||
|
|
|
|||
|
|
@ -49,6 +49,14 @@ public:
|
|||
*/
|
||||
virtual ~MethodFrame() {}
|
||||
|
||||
/**
|
||||
* Is this a synchronous frame?
|
||||
*
|
||||
* After a synchronous frame no more frames may be
|
||||
* sent until the accompanying -ok frame arrives
|
||||
*/
|
||||
bool synchronous() const override { return true; }
|
||||
|
||||
/**
|
||||
* Get the message type
|
||||
* @return uint8_t
|
||||
|
|
@ -79,9 +87,6 @@ public:
|
|||
{
|
||||
// this is an exception
|
||||
throw ProtocolException("unimplemented frame type " + std::to_string(type()) + " class " + std::to_string(classID()) + " method " + std::to_string(methodID()));
|
||||
|
||||
// unreachable
|
||||
return false;
|
||||
}
|
||||
};
|
||||
|
||||
|
|
|
|||
|
|
@ -23,11 +23,6 @@ public:
|
|||
* @param what
|
||||
*/
|
||||
explicit ProtocolException(const std::string &what) : Exception(what) {}
|
||||
|
||||
/**
|
||||
* Destructor
|
||||
*/
|
||||
virtual ~ProtocolException() {}
|
||||
};
|
||||
|
||||
/**
|
||||
|
|
|
|||
|
|
@ -110,6 +110,18 @@ public:
|
|||
_arguments(frame)
|
||||
{}
|
||||
|
||||
/**
|
||||
* Is this a synchronous frame?
|
||||
*
|
||||
* After a synchronous frame no more frames may be
|
||||
* sent until the accompanying -ok frame arrives
|
||||
*/
|
||||
bool synchronous() const override
|
||||
{
|
||||
// we are synchronous without the nowait option
|
||||
return !noWait();
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the method id
|
||||
* @return uint16_t
|
||||
|
|
|
|||
|
|
@ -1,6 +1,6 @@
|
|||
/**
|
||||
* Class describing an AMQP queue bind ok frame
|
||||
*
|
||||
*
|
||||
* @copyright 2014 Copernica BV
|
||||
*/
|
||||
|
||||
|
|
@ -54,7 +54,7 @@ public:
|
|||
{
|
||||
return 21;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Process the frame
|
||||
* @param connection The connection over which it was received
|
||||
|
|
@ -64,13 +64,13 @@ public:
|
|||
{
|
||||
// check if we have a channel
|
||||
ChannelImpl *channel = connection->channel(this->channel());
|
||||
|
||||
|
||||
// channel does not exist
|
||||
if(!channel) return false;
|
||||
|
||||
|
||||
// report to handler
|
||||
channel->reportQueueBound();
|
||||
|
||||
if (channel->reportSuccess()) channel->synchronized();
|
||||
|
||||
// done
|
||||
return true;
|
||||
}
|
||||
|
|
|
|||
|
|
@ -98,6 +98,18 @@ public:
|
|||
_arguments(frame)
|
||||
{}
|
||||
|
||||
/**
|
||||
* Is this a synchronous frame?
|
||||
*
|
||||
* After a synchronous frame no more frames may be
|
||||
* sent until the accompanying -ok frame arrives
|
||||
*/
|
||||
bool synchronous() const override
|
||||
{
|
||||
// we are synchronous without the nowait option
|
||||
return !noWait();
|
||||
}
|
||||
|
||||
/**
|
||||
* returns the method id
|
||||
* @return string
|
||||
|
|
@ -156,7 +168,7 @@ public:
|
|||
* returns whether to wait for a response
|
||||
* @return bool
|
||||
*/
|
||||
bool noWait()
|
||||
bool noWait() const
|
||||
{
|
||||
return _bools.get(4);
|
||||
}
|
||||
|
|
|
|||
|
|
@ -1,6 +1,6 @@
|
|||
/**
|
||||
* Class describing an AMQP queue declare ok frame
|
||||
*
|
||||
*
|
||||
* @copyright 2014 Copernica BV
|
||||
*/
|
||||
|
||||
|
|
@ -70,7 +70,7 @@ public:
|
|||
|
||||
/**
|
||||
* Constructor based on incoming data
|
||||
* @param frame received frame
|
||||
* @param frame received frame
|
||||
*/
|
||||
QueueDeclareOKFrame(ReceivedFrame &frame) :
|
||||
QueueFrame(frame),
|
||||
|
|
@ -91,7 +91,7 @@ public:
|
|||
{
|
||||
return 11;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Queue name
|
||||
* @return string
|
||||
|
|
@ -105,7 +105,7 @@ public:
|
|||
* Number of messages
|
||||
* @return int32_t
|
||||
*/
|
||||
int32_t messageCount() const
|
||||
uint32_t messageCount() const
|
||||
{
|
||||
return _messageCount;
|
||||
}
|
||||
|
|
@ -114,11 +114,11 @@ public:
|
|||
* Number of consumers
|
||||
* @return int32_t
|
||||
*/
|
||||
int32_t consumerCount() const
|
||||
uint32_t consumerCount() const
|
||||
{
|
||||
return _consumerCount;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Process the frame
|
||||
* @param connection The connection over which it was received
|
||||
|
|
@ -128,13 +128,13 @@ public:
|
|||
{
|
||||
// check if we have a channel
|
||||
ChannelImpl *channel = connection->channel(this->channel());
|
||||
|
||||
|
||||
// what if channel doesn't exist?
|
||||
if (!channel) return false;
|
||||
|
||||
// report to the handler
|
||||
channel->reportQueueDeclared(this->name(), this->messageCount(), this->consumerCount());
|
||||
|
||||
|
||||
// report success
|
||||
if (channel->reportSuccess(name(), messageCount(), consumerCount())) channel->synchronized();
|
||||
|
||||
// done
|
||||
return true;
|
||||
}
|
||||
|
|
|
|||
|
|
@ -85,6 +85,18 @@ public:
|
|||
_bools(frame)
|
||||
{}
|
||||
|
||||
/**
|
||||
* Is this a synchronous frame?
|
||||
*
|
||||
* After a synchronous frame no more frames may be
|
||||
* sent until the accompanying -ok frame arrives
|
||||
*/
|
||||
bool synchronous() const override
|
||||
{
|
||||
// we are synchronous without the nowait option
|
||||
return !noWait();
|
||||
}
|
||||
|
||||
/**
|
||||
* returns the method id
|
||||
* @returns uint16_t
|
||||
|
|
|
|||
|
|
@ -1,6 +1,6 @@
|
|||
/**
|
||||
* Class describing an AMQP queue delete frame
|
||||
*
|
||||
*
|
||||
* @copyright 2014 Copernica BV
|
||||
*/
|
||||
|
||||
|
|
@ -79,7 +79,7 @@ public:
|
|||
{
|
||||
return _messageCount;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Process the frame
|
||||
* @param connection The connection over which it was received
|
||||
|
|
@ -89,13 +89,13 @@ public:
|
|||
{
|
||||
// check if we have a channel
|
||||
ChannelImpl *channel = connection->channel(this->channel());
|
||||
|
||||
|
||||
// channel does not exist
|
||||
if(!channel) return false;
|
||||
|
||||
|
||||
// report queue deletion success
|
||||
channel->reportQueueDeleted(this->messageCount());
|
||||
|
||||
if (channel->reportSuccess(this->messageCount())) channel->synchronized();
|
||||
|
||||
// done
|
||||
return true;
|
||||
}
|
||||
|
|
@ -105,4 +105,4 @@ public:
|
|||
* end namespace
|
||||
*/
|
||||
}
|
||||
|
||||
|
||||
|
|
|
|||
|
|
@ -1,6 +1,6 @@
|
|||
/**
|
||||
* Class describing an AMQP queue purge frame
|
||||
*
|
||||
*
|
||||
* @copyright 2014 Copernica BV
|
||||
*/
|
||||
|
||||
|
|
@ -27,7 +27,7 @@ private:
|
|||
ShortString _name;
|
||||
|
||||
/**
|
||||
* Do not wait on response
|
||||
* Do not wait on response
|
||||
* @var BooleanSet
|
||||
*/
|
||||
BooleanSet _noWait;
|
||||
|
|
@ -37,7 +37,7 @@ protected:
|
|||
* Encode the frame into a buffer
|
||||
*
|
||||
* @param buffer buffer to write frame to
|
||||
*/
|
||||
*/
|
||||
virtual void fill(OutBuffer& buffer) const override
|
||||
{
|
||||
// call base
|
||||
|
|
@ -63,13 +63,13 @@ public:
|
|||
* @param noWait Do not wait on response
|
||||
*
|
||||
* @return newly created Queuepurgeframe
|
||||
*/
|
||||
*/
|
||||
QueuePurgeFrame(uint16_t channel, const std::string& name, bool noWait = false) :
|
||||
QueueFrame(channel, name.length() + 4), // 1 extra for string length, 1 for bool, 2 for deprecated field
|
||||
_name(name),
|
||||
_noWait(noWait)
|
||||
{}
|
||||
|
||||
|
||||
/**
|
||||
* Constructor based on received data
|
||||
* @param frame received frame
|
||||
|
|
@ -80,11 +80,23 @@ public:
|
|||
_name(frame),
|
||||
_noWait(frame)
|
||||
{}
|
||||
|
||||
|
||||
/**
|
||||
* Is this a synchronous frame?
|
||||
*
|
||||
* After a synchronous frame no more frames may be
|
||||
* sent until the accompanying -ok frame arrives
|
||||
*/
|
||||
bool synchronous() const override
|
||||
{
|
||||
// we are synchronous without the nowait option
|
||||
return !noWait();
|
||||
}
|
||||
|
||||
/**
|
||||
* The method ID
|
||||
* @return method id
|
||||
*/
|
||||
*/
|
||||
virtual uint16_t methodID() const override
|
||||
{
|
||||
return 30;
|
||||
|
|
|
|||
|
|
@ -1,6 +1,6 @@
|
|||
/**
|
||||
* Class describing an AMQP queue purge frame
|
||||
*
|
||||
*
|
||||
* @copyright 2014 Copernica BV
|
||||
*/
|
||||
|
||||
|
|
@ -35,7 +35,7 @@ protected:
|
|||
// add fields
|
||||
buffer.add(_messageCount);
|
||||
}
|
||||
|
||||
|
||||
public:
|
||||
/**
|
||||
* Construct a queuepurgeokframe
|
||||
|
|
@ -79,7 +79,7 @@ public:
|
|||
{
|
||||
return _messageCount;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Process the frame
|
||||
* @param connection The connection over which it was received
|
||||
|
|
@ -89,13 +89,13 @@ public:
|
|||
{
|
||||
// check if we have a channel
|
||||
ChannelImpl *channel = connection->channel(this->channel());
|
||||
|
||||
|
||||
// channel does not exist
|
||||
if(!channel) return false;
|
||||
|
||||
// report queue purge success
|
||||
channel->reportQueuePurged(this->messageCount());
|
||||
|
||||
if (channel->reportSuccess(this->messageCount())) channel->synchronized();
|
||||
|
||||
// done
|
||||
return true;
|
||||
}
|
||||
|
|
|
|||
|
|
@ -1,6 +1,6 @@
|
|||
/**
|
||||
* Class describing an AMQP queue unbind ok frame
|
||||
*
|
||||
*
|
||||
* @copyright 2014 Copernica BV
|
||||
*/
|
||||
|
||||
|
|
@ -24,7 +24,7 @@ protected:
|
|||
{
|
||||
// call base
|
||||
QueueFrame::fill(buffer);
|
||||
}
|
||||
}
|
||||
public:
|
||||
/**
|
||||
* Decode a queueunbindokframe from a received frame
|
||||
|
|
@ -58,7 +58,7 @@ public:
|
|||
{
|
||||
return 51;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Process the frame
|
||||
* @param connection The connection over which it was received
|
||||
|
|
@ -68,13 +68,13 @@ public:
|
|||
{
|
||||
// check if we have a channel
|
||||
ChannelImpl *channel = connection->channel(this->channel());
|
||||
|
||||
|
||||
// channel does not exist
|
||||
if(!channel) return false;
|
||||
|
||||
|
||||
// report queue unbind success
|
||||
channel->reportQueueUnbound();
|
||||
|
||||
if (channel->reportSuccess()) channel->synchronized();
|
||||
|
||||
// done
|
||||
return true;
|
||||
}
|
||||
|
|
|
|||
|
|
@ -66,6 +66,7 @@
|
|||
#include "transactionrollbackframe.h"
|
||||
#include "transactionrollbackokframe.h"
|
||||
#include "messageimpl.h"
|
||||
#include "consumedmessage.h"
|
||||
#include "bodyframe.h"
|
||||
#include "basicheaderframe.h"
|
||||
#include "framecheck.h"
|
||||
|
|
|
|||
|
|
@ -24,7 +24,7 @@ private:
|
|||
* @var int16_t
|
||||
*/
|
||||
int16_t _replyCode;
|
||||
|
||||
|
||||
/**
|
||||
* The reply message
|
||||
* @var string
|
||||
|
|
@ -40,22 +40,11 @@ public:
|
|||
ReturnedMessage(const BasicReturnFrame &frame) :
|
||||
MessageImpl(frame.exchange(), frame.routingKey()),
|
||||
_replyCode(frame.replyCode()), _replyText(frame.replyText()) {}
|
||||
|
||||
|
||||
/**
|
||||
* Destructor
|
||||
*/
|
||||
virtual ~ReturnedMessage() {}
|
||||
|
||||
/**
|
||||
* Report to the handler
|
||||
* @param channel
|
||||
* @param handler
|
||||
*/
|
||||
virtual void report(Channel *channel, ChannelHandler *handler) override
|
||||
{
|
||||
// report to the handler
|
||||
handler->onReturned(channel, *this, _replyCode, _replyText);
|
||||
}
|
||||
};
|
||||
|
||||
/**
|
||||
|
|
|
|||
|
|
@ -97,7 +97,7 @@ Table &Table::operator=(Table &&table)
|
|||
* @param name field name
|
||||
* @return the field value
|
||||
*/
|
||||
const Field &Table::get(const std::string &name)
|
||||
const Field &Table::get(const std::string &name) const
|
||||
{
|
||||
// we need an empty string
|
||||
static ShortString empty;
|
||||
|
|
@ -145,7 +145,7 @@ size_t Table::size() const
|
|||
void Table::fill(OutBuffer& buffer) const
|
||||
{
|
||||
// add size
|
||||
buffer.add((uint32_t) size()-4);
|
||||
buffer.add(static_cast<uint32_t>(size()-4));
|
||||
|
||||
// loop through the fields
|
||||
for (auto iter(_fields.begin()); iter != _fields.end(); ++iter)
|
||||
|
|
|
|||
|
|
@ -59,6 +59,26 @@ public:
|
|||
{
|
||||
return 21;
|
||||
}
|
||||
|
||||
/**
|
||||
* Process the frame
|
||||
* @param connection The connection over which it was received
|
||||
* @return bool Was it succesfully processed?
|
||||
*/
|
||||
virtual bool process(ConnectionImpl *connection) override
|
||||
{
|
||||
// we need the appropriate channel
|
||||
ChannelImpl *channel = connection->channel(this->channel());
|
||||
|
||||
// channel does not exist
|
||||
if(!channel) return false;
|
||||
|
||||
// report that the channel is open
|
||||
if (channel->reportSuccess()) channel->synchronized();
|
||||
|
||||
// done
|
||||
return true;
|
||||
}
|
||||
};
|
||||
|
||||
/**
|
||||
|
|
|
|||
|
|
@ -58,7 +58,27 @@ public:
|
|||
virtual uint16_t methodID() const override
|
||||
{
|
||||
return 31;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Process the frame
|
||||
* @param connection The connection over which it was received
|
||||
* @return bool Was it succesfully processed?
|
||||
*/
|
||||
virtual bool process(ConnectionImpl *connection) override
|
||||
{
|
||||
// we need the appropriate channel
|
||||
ChannelImpl *channel = connection->channel(this->channel());
|
||||
|
||||
// channel does not exist
|
||||
if(!channel) return false;
|
||||
|
||||
// report that the channel is open
|
||||
if (channel->reportSuccess()) channel->synchronized();
|
||||
|
||||
// done
|
||||
return true;
|
||||
}
|
||||
};
|
||||
|
||||
/**
|
||||
|
|
|
|||
|
|
@ -59,6 +59,26 @@ public:
|
|||
{
|
||||
return 11;
|
||||
}
|
||||
|
||||
/**
|
||||
* Process the frame
|
||||
* @param connection The connection over which it was received
|
||||
* @return bool Was it succesfully processed?
|
||||
*/
|
||||
virtual bool process(ConnectionImpl *connection) override
|
||||
{
|
||||
// we need the appropriate channel
|
||||
ChannelImpl *channel = connection->channel(this->channel());
|
||||
|
||||
// channel does not exist
|
||||
if(!channel) return false;
|
||||
|
||||
// report that the channel is open
|
||||
if (channel->reportSuccess()) channel->synchronized();
|
||||
|
||||
// done
|
||||
return true;
|
||||
}
|
||||
};
|
||||
|
||||
/**
|
||||
|
|
|
|||
|
|
@ -1,6 +1,6 @@
|
|||
CPP = g++
|
||||
CPP = g++
|
||||
CPPFLAGS = -Wall -c -I. -O2 -flto -std=c++11 -g
|
||||
LD = g++
|
||||
LD = g++
|
||||
LDFLAGS = -lamqpcpp -lcopernica_event -lcopernica_network -lev
|
||||
RESULT = a.out
|
||||
SOURCES = $(wildcard *.cpp)
|
||||
|
|
@ -16,4 +16,3 @@ clean:
|
|||
|
||||
${OBJECTS}:
|
||||
${CPP} ${CPPFLAGS} -o $@ ${@:%.o=%.cpp}
|
||||
|
||||
|
|
|
|||
|
|
@ -1,2 +1,2 @@
|
|||
I'm sorry, the test case makes use of the closed source Copernica libraries. Maybe someone
|
||||
is willing to provide a test case based on plain system calls?
|
||||
is willing to provide a test case based on plain system calls?
|
||||
Binary file not shown.
|
|
@ -51,5 +51,4 @@ int main(int argc, const char *argv[])
|
|||
// done
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
|
@ -84,13 +84,41 @@ void MyConnection::onConnected(Network::TcpSocket *socket)
|
|||
|
||||
// create amqp connection, and a new channel
|
||||
_connection = new AMQP::Connection(this, AMQP::Login("guest", "guest"), "/");
|
||||
_channel = new AMQP::Channel(_connection, this);
|
||||
_channel = new AMQP::Channel(_connection);
|
||||
|
||||
// install a handler when channel is in error
|
||||
_channel->onError([](const char *message) {
|
||||
|
||||
std::cout << "channel error " << message << std::endl;
|
||||
});
|
||||
|
||||
// install a handler when channel is ready
|
||||
_channel->onReady([]() {
|
||||
|
||||
std::cout << "channel ready" << std::endl;
|
||||
});
|
||||
|
||||
// we declare a queue, an exchange and we publish a message
|
||||
_channel->declareQueue("my_queue");
|
||||
// _channel->declareQueue("my_queue", AMQP::autodelete);
|
||||
_channel->declareExchange("my_exchange", AMQP::direct);
|
||||
_channel->bindQueue("my_exchange", "my_queue", "key");
|
||||
_channel->declareQueue("my_queue").onSuccess([this]() {
|
||||
std::cout << "queue declared" << std::endl;
|
||||
|
||||
// start consuming
|
||||
_channel->consume("my_queue").onReceived([](const AMQP::Message &message, uint64_t deliveryTag, bool redelivered) {
|
||||
std::cout << "received: " << message.message() << std::endl;
|
||||
});
|
||||
});
|
||||
|
||||
// declare an exchange
|
||||
_channel->declareExchange("my_exchange", AMQP::direct).onSuccess([]() {
|
||||
std::cout << "exchange declared" << std::endl;
|
||||
});
|
||||
|
||||
// bind queue and exchange
|
||||
_channel->bindQueue("my_exchange", "my_queue", "key").onSuccess([this]() {
|
||||
std::cout << "queue bound to exchange" << std::endl;
|
||||
|
||||
_channel->publish("my_exchange", "key", "just a message");
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
|
|
@ -183,7 +211,7 @@ void MyConnection::onData(AMQP::Connection *connection, const char *buffer, size
|
|||
* @param connection The connection that entered the error state
|
||||
* @param message Error message
|
||||
*/
|
||||
void MyConnection::onError(AMQP::Connection *connection, const std::string &message)
|
||||
void MyConnection::onError(AMQP::Connection *connection, const char *message)
|
||||
{
|
||||
// report error
|
||||
std::cout << "AMQP Connection error: " << message << std::endl;
|
||||
|
|
@ -201,263 +229,6 @@ void MyConnection::onConnected(AMQP::Connection *connection)
|
|||
std::cout << "AMQP login success" << std::endl;
|
||||
|
||||
// create channel if it does not yet exist
|
||||
if (!_channel) _channel = new AMQP::Channel(connection, this);
|
||||
}
|
||||
|
||||
/**
|
||||
* Method that is called when the channel was succesfully created.
|
||||
* Only after the channel was created, you can use it for subsequent messages over it
|
||||
* @param channel
|
||||
*/
|
||||
void MyConnection::onReady(AMQP::Channel *channel)
|
||||
{
|
||||
// show
|
||||
std::cout << "AMQP channel ready, id: " << (int) channel->id() << std::endl;
|
||||
}
|
||||
|
||||
/**
|
||||
* An error has occured on the channel
|
||||
* @param channel
|
||||
* @param message
|
||||
*/
|
||||
|
||||
void MyConnection::onError(AMQP::Channel *channel, const std::string &message)
|
||||
{
|
||||
// show
|
||||
std::cout << "AMQP channel error, id: " << (int) channel->id() << " - message: " << message << std::endl;
|
||||
|
||||
// main channel cause an error, get rid of if
|
||||
delete _channel;
|
||||
|
||||
// reset pointer
|
||||
_channel = nullptr;
|
||||
}
|
||||
|
||||
/**
|
||||
* Method that is called when the channel was paused
|
||||
* @param channel
|
||||
*/
|
||||
void MyConnection::onPaused(AMQP::Channel *channel)
|
||||
{
|
||||
// show
|
||||
std::cout << "AMQP channel paused" << std::endl;
|
||||
}
|
||||
|
||||
/**
|
||||
* Method that is called when the channel was resumed
|
||||
* @param channel
|
||||
*/
|
||||
void MyConnection::onResumed(AMQP::Channel *channel)
|
||||
{
|
||||
// show
|
||||
std::cout << "AMQP channel resumed" << std::endl;
|
||||
}
|
||||
|
||||
/**
|
||||
* Method that is called when a channel is closed
|
||||
* @param channel
|
||||
*/
|
||||
void MyConnection::onClosed(AMQP::Channel *channel)
|
||||
{
|
||||
// show
|
||||
std::cout << "AMQP channel closed" << std::endl;
|
||||
}
|
||||
|
||||
/**
|
||||
* Method that is called when a transaction was started
|
||||
* @param channel
|
||||
*/
|
||||
void MyConnection::onTransactionStarted(AMQP::Channel *channel)
|
||||
{
|
||||
// show
|
||||
std::cout << "AMQP transaction started" << std::endl;
|
||||
}
|
||||
|
||||
/**
|
||||
* Method that is called when a transaction was committed
|
||||
* @param channel
|
||||
*/
|
||||
void MyConnection::onTransactionCommitted(AMQP::Channel *channel)
|
||||
{
|
||||
// show
|
||||
std::cout << "AMQP transaction committed" << std::endl;
|
||||
}
|
||||
|
||||
/**
|
||||
* Method that is called when a transaction was rolled back
|
||||
* @param channel
|
||||
*/
|
||||
void MyConnection::onTransactionRolledBack(AMQP::Channel *channel)
|
||||
{
|
||||
// show
|
||||
std::cout << "AMQP transaction rolled back" << std::endl;
|
||||
}
|
||||
|
||||
/**
|
||||
* Mehod that is called when an exchange is declared
|
||||
* @param channel
|
||||
*/
|
||||
void MyConnection::onExchangeDeclared(AMQP::Channel *channel)
|
||||
{
|
||||
// show
|
||||
std::cout << "AMQP exchange declared" << std::endl;
|
||||
}
|
||||
|
||||
/**
|
||||
* Method that is called when an exchange is bound
|
||||
* @param channel
|
||||
*/
|
||||
void MyConnection::onExchangeBound(AMQP::Channel *channel)
|
||||
{
|
||||
// show
|
||||
std::cout << "AMQP Exchange bound" << std::endl;
|
||||
}
|
||||
|
||||
/**
|
||||
* Method that is called when an exchange is unbound
|
||||
* @param channel
|
||||
*/
|
||||
void MyConnection::onExchangeUnbound(AMQP::Channel *channel)
|
||||
{
|
||||
// show
|
||||
std::cout << "AMQP Exchange unbound" << std::endl;
|
||||
}
|
||||
|
||||
/**
|
||||
* Method that is called when an exchange is deleted
|
||||
* @param channel
|
||||
*/
|
||||
void MyConnection::onExchangeDeleted(AMQP::Channel *channel)
|
||||
{
|
||||
// show
|
||||
std::cout << "AMQP Exchange deleted" << std::endl;
|
||||
}
|
||||
|
||||
/**
|
||||
* Method that is called when a queue is declared
|
||||
* @param channel
|
||||
* @param name name of the queue
|
||||
* @param messageCount number of messages in queue
|
||||
* @param consumerCount number of active consumers
|
||||
*/
|
||||
void MyConnection::onQueueDeclared(AMQP::Channel *channel, const std::string &name, uint32_t messageCount, uint32_t consumerCount)
|
||||
{
|
||||
// show
|
||||
std::cout << "AMQP Queue declared" << std::endl;
|
||||
}
|
||||
|
||||
/**
|
||||
* Method that is called when a queue is bound
|
||||
* @param channel
|
||||
* @param
|
||||
*/
|
||||
void MyConnection::onQueueBound(AMQP::Channel *channel)
|
||||
{
|
||||
// show
|
||||
std::cout << "AMQP Queue bound" << std::endl;
|
||||
|
||||
// _connection->setQos(10);
|
||||
// _channel->setQos(1);
|
||||
|
||||
|
||||
_channel->publish("my_exchange", "invalid-key", AMQP::mandatory, "this is the message");
|
||||
// _channel->consume("my_queue");
|
||||
}
|
||||
|
||||
/**
|
||||
* Method that is called when a queue is deleted
|
||||
* @param channel
|
||||
* @param messageCount number of messages deleted along with the queue
|
||||
*/
|
||||
void MyConnection::onQueueDeleted(AMQP::Channel *channel, uint32_t messageCount)
|
||||
{
|
||||
// show
|
||||
std::cout << "AMQP Queue deleted" << std::endl;
|
||||
}
|
||||
|
||||
/**
|
||||
* Method that is called when a queue is unbound
|
||||
* @param channel
|
||||
*/
|
||||
void MyConnection::onQueueUnbound(AMQP::Channel *channel)
|
||||
{
|
||||
// show
|
||||
std::cout << "AMQP Queue unbound" << std::endl;
|
||||
}
|
||||
|
||||
/**
|
||||
* Method that is called when a queue is purged
|
||||
* @param messageCount number of message purged
|
||||
*/
|
||||
void MyConnection::onQueuePurged(AMQP::Channel *channel, uint32_t messageCount)
|
||||
{
|
||||
// show
|
||||
std::cout << "AMQP Queue purged" << std::endl;
|
||||
}
|
||||
|
||||
/**
|
||||
* Method that is called when the quality-of-service was changed
|
||||
* This is the result of a call to Channel::setQos()
|
||||
*/
|
||||
void MyConnection::onQosSet(AMQP::Channel *channel)
|
||||
{
|
||||
// show
|
||||
std::cout << "AMQP Qos set" << std::endl;
|
||||
}
|
||||
|
||||
/**
|
||||
* Method that is called when a consumer was started
|
||||
* This is the result of a call to Channel::consume()
|
||||
* @param channel the channel on which the consumer was started
|
||||
* @param tag the consumer tag
|
||||
*/
|
||||
void MyConnection::onConsumerStarted(AMQP::Channel *channel, const std::string &tag)
|
||||
{
|
||||
// show
|
||||
std::cout << "AMQP consumer started" << std::endl;
|
||||
}
|
||||
|
||||
/**
|
||||
* Method that is called when a message has been received on a channel
|
||||
* @param channel the channel on which the consumer was started
|
||||
* @param message the consumed message
|
||||
* @param deliveryTag the delivery tag, you need this to acknowledge the message
|
||||
* @param consumerTag the consumer identifier that was used to retrieve this message
|
||||
* @param redelivered is this a redelivered message?
|
||||
*/
|
||||
void MyConnection::onReceived(AMQP::Channel *channel, const AMQP::Message &message, uint64_t deliveryTag, const std::string &consumerTag, bool redelivered)
|
||||
{
|
||||
// show
|
||||
std::cout << "AMQP consumed: " << message.message() << std::endl;
|
||||
|
||||
// ack the message
|
||||
channel->ack(deliveryTag);
|
||||
}
|
||||
|
||||
/**
|
||||
* Method that is called when a message you tried to publish was returned
|
||||
* by the server. This only happens when the 'mandatory' or 'immediate' flag
|
||||
* was set with the Channel::publish() call.
|
||||
* @param channel the channel on which the message was returned
|
||||
* @param message the returned message
|
||||
* @param code the reply code
|
||||
* @param text human readable reply reason
|
||||
*/
|
||||
void MyConnection::onReturned(AMQP::Channel *channel, const AMQP::Message &message, int16_t code, const std::string &text)
|
||||
{
|
||||
// show
|
||||
std::cout << "AMQP message returned: " << text << std::endl;
|
||||
}
|
||||
|
||||
/**
|
||||
* Method that is called when a consumer was stopped
|
||||
* This is the result of a call to Channel::cancel()
|
||||
* @param channel the channel on which the consumer was stopped
|
||||
* @param tag the consumer tag
|
||||
*/
|
||||
void MyConnection::onConsumerStopped(AMQP::Channel *channel, const std::string &tag)
|
||||
{
|
||||
// show
|
||||
std::cout << "AMQP consumer stopped" << std::endl;
|
||||
if (!_channel) _channel = new AMQP::Channel(connection);
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -11,7 +11,6 @@
|
|||
*/
|
||||
class MyConnection :
|
||||
public AMQP::ConnectionHandler,
|
||||
public AMQP::ChannelHandler,
|
||||
public Network::TcpHandler
|
||||
{
|
||||
private:
|
||||
|
|
@ -93,7 +92,7 @@ private:
|
|||
* @param connection The connection that entered the error state
|
||||
* @param message Error message
|
||||
*/
|
||||
virtual void onError(AMQP::Connection *connection, const std::string &message) override;
|
||||
virtual void onError(AMQP::Connection *connection, const char *message) override;
|
||||
|
||||
/**
|
||||
* Method that is called when the login attempt succeeded. After this method
|
||||
|
|
@ -103,163 +102,6 @@ private:
|
|||
*/
|
||||
virtual void onConnected(AMQP::Connection *connection) override;
|
||||
|
||||
/**
|
||||
* Method that is called when the channel was succesfully created.
|
||||
* Only after the channel was created, you can use it for subsequent messages over it
|
||||
* @param channel
|
||||
*/
|
||||
virtual void onReady(AMQP::Channel *channel) override;
|
||||
|
||||
/**
|
||||
* An error has occured on the channel
|
||||
* @param channel
|
||||
* @param message
|
||||
*/
|
||||
virtual void onError(AMQP::Channel *channel, const std::string &message) override;
|
||||
|
||||
/**
|
||||
* Method that is called when the channel was paused
|
||||
* @param channel
|
||||
*/
|
||||
virtual void onPaused(AMQP::Channel *channel) override;
|
||||
|
||||
/**
|
||||
* Method that is called when the channel was resumed
|
||||
* @param channel
|
||||
*/
|
||||
virtual void onResumed(AMQP::Channel *channel) override;
|
||||
|
||||
/**
|
||||
* Method that is called when a channel is closed
|
||||
* @param channel
|
||||
*/
|
||||
virtual void onClosed(AMQP::Channel *channel) override;
|
||||
|
||||
/**
|
||||
* Method that is called when a transaction was started
|
||||
* @param channel
|
||||
*/
|
||||
virtual void onTransactionStarted(AMQP::Channel *channel) override;
|
||||
|
||||
/**
|
||||
* Method that is called when a transaction was committed
|
||||
* @param channel
|
||||
*/
|
||||
virtual void onTransactionCommitted(AMQP::Channel *channel) override;
|
||||
|
||||
/**
|
||||
* Method that is called when a transaction was rolled back
|
||||
* @param channel
|
||||
*/
|
||||
virtual void onTransactionRolledBack(AMQP::Channel *channel) override;
|
||||
|
||||
/**
|
||||
* Method that is called when an exchange is bound
|
||||
* @param channel
|
||||
*/
|
||||
virtual void onExchangeBound(AMQP::Channel *channel) override;
|
||||
|
||||
/**
|
||||
* Method that is called when an exchange is unbound
|
||||
* @param channel
|
||||
*/
|
||||
virtual void onExchangeUnbound(AMQP::Channel *channel) override;
|
||||
|
||||
/**
|
||||
* Method that is called when an exchange is deleted
|
||||
* @param channel
|
||||
*/
|
||||
virtual void onExchangeDeleted(AMQP::Channel *channel) override;
|
||||
|
||||
/**
|
||||
* Mehod that is called when an exchange is declared
|
||||
* @param channel
|
||||
*/
|
||||
virtual void onExchangeDeclared(AMQP::Channel *channel) override;
|
||||
|
||||
/**
|
||||
* Method that is called when a queue is declared
|
||||
* @param channel
|
||||
* @param name name of the queue
|
||||
* @param messageCount number of messages in queue
|
||||
* @param consumerCount number of active consumers
|
||||
*/
|
||||
virtual void onQueueDeclared(AMQP::Channel *channel, const std::string &name, uint32_t messageCount, uint32_t consumerCount) override;
|
||||
|
||||
/**
|
||||
* Method that is called when a queue is bound
|
||||
* @param channel
|
||||
* @param
|
||||
*/
|
||||
virtual void onQueueBound(AMQP::Channel *channel) override;
|
||||
|
||||
/**
|
||||
* Method that is called when a queue is deleted
|
||||
* @param channel
|
||||
* @param messageCount number of messages deleted along with the queue
|
||||
*/
|
||||
virtual void onQueueDeleted(AMQP::Channel *channel, uint32_t messageCount) override;
|
||||
|
||||
/**
|
||||
* Method that is called when a queue is unbound
|
||||
* @param channel
|
||||
*/
|
||||
virtual void onQueueUnbound(AMQP::Channel *channel) override;
|
||||
|
||||
/**
|
||||
* Method that is called when a queue is purged
|
||||
* @param messageCount number of message purged
|
||||
*/
|
||||
virtual void onQueuePurged(AMQP::Channel *channel, uint32_t messageCount) override;
|
||||
|
||||
/**
|
||||
* Method that is called when the quality-of-service was changed
|
||||
* This is the result of a call to Channel::setQos()
|
||||
*/
|
||||
virtual void onQosSet(AMQP::Channel *channel) override;
|
||||
|
||||
/**
|
||||
* Method that is called when a consumer was started
|
||||
* This is the result of a call to Channel::consume()
|
||||
* @param channel the channel on which the consumer was started
|
||||
* @param tag the consumer tag
|
||||
*/
|
||||
virtual void onConsumerStarted(AMQP::Channel *channel, const std::string &tag) override;
|
||||
|
||||
/**
|
||||
* Method that is called when a consumer was stopped
|
||||
* This is the result of a call to Channel::cancel()
|
||||
* @param channel the channel on which the consumer was stopped
|
||||
* @param tag the consumer tag
|
||||
*/
|
||||
virtual void onConsumerStopped(AMQP::Channel *channel, const std::string &tag) override;
|
||||
|
||||
/**
|
||||
* Method that is called when a message has been received on a channel
|
||||
* This message will be called for every message that is received after
|
||||
* you started consuming. Make sure you acknowledge the messages when its
|
||||
* safe to remove them from RabbitMQ (unless you set no-ack option when you
|
||||
* started the consumer)
|
||||
* @param channel the channel on which the consumer was started
|
||||
* @param message the consumed message
|
||||
* @param deliveryTag the delivery tag, you need this to acknowledge the message
|
||||
* @param consumerTag the consumer identifier that was used to retrieve this message
|
||||
* @param redelivered is this a redelivered message?
|
||||
*/
|
||||
virtual void onReceived(AMQP::Channel *channel, const AMQP::Message &message, uint64_t deliveryTag, const std::string &consumerTag, bool redelivered) override;
|
||||
|
||||
/**
|
||||
* Method that is called when a message you tried to publish was returned
|
||||
* by the server. This only happens when the 'mandatory' or 'immediate' flag
|
||||
* was set with the Channel::publish() call.
|
||||
* @param channel the channel on which the message was returned
|
||||
* @param message the returned message
|
||||
* @param code the reply code
|
||||
* @param text human readable reply reason
|
||||
*/
|
||||
virtual void onReturned(AMQP::Channel *channel, const AMQP::Message &message, int16_t code, const std::string &text) override;
|
||||
|
||||
|
||||
public:
|
||||
/**
|
||||
* Constructor
|
||||
|
|
@ -274,4 +116,3 @@ public:
|
|||
|
||||
|
||||
};
|
||||
|
||||
|
|
|
|||
|
|
@ -0,0 +1,19 @@
|
|||
#include <iostream>
|
||||
#include <amqpcpp.h>
|
||||
|
||||
|
||||
int main()
|
||||
{
|
||||
AMQP::Array x;
|
||||
|
||||
x[0] = "abc";
|
||||
x[1] = "xyz";
|
||||
|
||||
std::cout << x << std::endl;
|
||||
std::cout << x[0] << std::endl;
|
||||
std::cout << x[1] << std::endl;
|
||||
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
Loading…
Reference in New Issue