Merge pull request #134 from mgibula/master
Add Publisher Confirms support
This commit is contained in:
commit
025fdb5530
37
README.md
37
README.md
|
|
@ -974,6 +974,42 @@ knows in the database world. It is not possible to wrap all sort of
|
||||||
operations in a transaction, they are only meaningful for publishing
|
operations in a transaction, they are only meaningful for publishing
|
||||||
and consuming.
|
and consuming.
|
||||||
|
|
||||||
|
PUBLISHER CONFIRMS
|
||||||
|
===================
|
||||||
|
|
||||||
|
RabbitMQ supports lightweight method of confirming that broker received and processed
|
||||||
|
a message. For this method to work, the channel needs to be put in so-called _confirm mode_.
|
||||||
|
This is done using confirmSelect() method. When channel is successfully put in
|
||||||
|
confirm mode, the server and client count messages (starting from 1) and server sends
|
||||||
|
acknowledgments for every message it processed (it can also acknowledge multiple message at
|
||||||
|
once).
|
||||||
|
|
||||||
|
If server is unable to process a message, it will send send negative acknowledgments. Both
|
||||||
|
positive and negative acknowledgments handling are implemented as callbacks for Channel object.
|
||||||
|
|
||||||
|
````c++
|
||||||
|
// setup confirm mode and ack/nack callbacks
|
||||||
|
channel.confirmSelect().onSuccess([&]() {
|
||||||
|
// from this moment onwards ack/nack confirmations are comming in
|
||||||
|
|
||||||
|
channel.publish("my-exchange", "my-key", "my first message");
|
||||||
|
// message counter is now 1, will call onAck/onNack with deliverTag=1
|
||||||
|
|
||||||
|
channel.publish("my-exchange", "my-key", "my second message");
|
||||||
|
// message counter is now 2, will call onAck/onNack with deliverTag=2
|
||||||
|
|
||||||
|
}).onAck([&](uint64_t deliverTag, bool multiple) {
|
||||||
|
// deliverTag is message number
|
||||||
|
// multiple is set to true, if all messages UP TO deliverTag have been processed
|
||||||
|
}).onNack([&](uint64 deliveryTag, bool multiple, bool requeue) {
|
||||||
|
// deliverTag is message number
|
||||||
|
// multiple is set to true, if all messages UP TO deliverTag have not been processed
|
||||||
|
// requeue is to be ignored
|
||||||
|
});
|
||||||
|
|
||||||
|
````
|
||||||
|
|
||||||
|
For more information, please see http://www.rabbitmq.com/confirms.html.
|
||||||
|
|
||||||
CONSUMING MESSAGES
|
CONSUMING MESSAGES
|
||||||
==================
|
==================
|
||||||
|
|
@ -1107,7 +1143,6 @@ need additional attention:
|
||||||
|
|
||||||
- ability to set up secure connections (or is this fully done on the IO level)
|
- ability to set up secure connections (or is this fully done on the IO level)
|
||||||
- login with other protocols than login/password
|
- login with other protocols than login/password
|
||||||
- publish confirms
|
|
||||||
|
|
||||||
We also need to add more safety checks so that strange or invalid data from
|
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
|
RabbitMQ does not break the library (although in reality RabbitMQ only sends
|
||||||
|
|
|
||||||
|
|
@ -70,6 +70,7 @@
|
||||||
#include "amqpcpp/deferredqueue.h"
|
#include "amqpcpp/deferredqueue.h"
|
||||||
#include "amqpcpp/deferreddelete.h"
|
#include "amqpcpp/deferreddelete.h"
|
||||||
#include "amqpcpp/deferredcancel.h"
|
#include "amqpcpp/deferredcancel.h"
|
||||||
|
#include "amqpcpp/deferredconfirm.h"
|
||||||
#include "amqpcpp/deferredget.h"
|
#include "amqpcpp/deferredget.h"
|
||||||
#include "amqpcpp/deferredpublisher.h"
|
#include "amqpcpp/deferredpublisher.h"
|
||||||
#include "amqpcpp/channelimpl.h"
|
#include "amqpcpp/channelimpl.h"
|
||||||
|
|
|
||||||
|
|
@ -77,6 +77,13 @@ using ReturnedCallback = std::function<void()>;
|
||||||
using MessageCallback = std::function<void(const Message &message, uint64_t deliveryTag, bool redelivered)>;
|
using MessageCallback = std::function<void(const Message &message, uint64_t deliveryTag, bool redelivered)>;
|
||||||
using BounceCallback = std::function<void(const Message &message, int16_t code, const std::string &description)>;
|
using BounceCallback = std::function<void(const Message &message, int16_t code, const std::string &description)>;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* When using publisher confirms, AckCallback is called when server confirms that message is received
|
||||||
|
* and processed. NackCallback is called otherwise.
|
||||||
|
*/
|
||||||
|
using AckCallback = std::function<void(uint64_t deliveryTag, bool multiple)>;
|
||||||
|
using NackCallback = std::function<void(uint64_t deliveryTag, bool multiple, bool requeue)>;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* End namespace
|
* End namespace
|
||||||
*/
|
*/
|
||||||
|
|
|
||||||
|
|
@ -127,6 +127,17 @@ public:
|
||||||
return _implementation->connected();
|
return _implementation->connected();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Put channel in a confirm mode (RabbitMQ specific)
|
||||||
|
*
|
||||||
|
* This function returns a deferred handler. Callbacks can be installed
|
||||||
|
* using onSuccess(), onError() and onFinalize() methods.
|
||||||
|
*/
|
||||||
|
DeferredConfirm &confirmSelect()
|
||||||
|
{
|
||||||
|
return _implementation->confirmSelect();
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Start a transaction
|
* Start a transaction
|
||||||
*
|
*
|
||||||
|
|
|
||||||
|
|
@ -42,6 +42,7 @@ class ConsumedMessage;
|
||||||
class ConnectionImpl;
|
class ConnectionImpl;
|
||||||
class DeferredDelete;
|
class DeferredDelete;
|
||||||
class DeferredCancel;
|
class DeferredCancel;
|
||||||
|
class DeferredConfirm;
|
||||||
class DeferredQueue;
|
class DeferredQueue;
|
||||||
class DeferredGet;
|
class DeferredGet;
|
||||||
class DeferredPublisher;
|
class DeferredPublisher;
|
||||||
|
|
@ -80,6 +81,12 @@ private:
|
||||||
*/
|
*/
|
||||||
std::shared_ptr<DeferredPublisher> _publisher;
|
std::shared_ptr<DeferredPublisher> _publisher;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Handler that deals with publisher confirms frames
|
||||||
|
* @var std::shared_ptr<DeferredConfirm>
|
||||||
|
*/
|
||||||
|
std::shared_ptr<DeferredConfirm> _confirm;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Handlers for all consumers that are active
|
* Handlers for all consumers that are active
|
||||||
* @var std::map<std::string,std::shared_ptr<DeferredConsumer>
|
* @var std::map<std::string,std::shared_ptr<DeferredConsumer>
|
||||||
|
|
@ -252,6 +259,11 @@ public:
|
||||||
return _state == state_connected || _state == state_ready;
|
return _state == state_connected || _state == state_ready;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Put channel in a confirm mode (RabbitMQ specific)
|
||||||
|
*/
|
||||||
|
DeferredConfirm &confirmSelect();
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Start a transaction
|
* Start a transaction
|
||||||
*/
|
*/
|
||||||
|
|
@ -715,6 +727,12 @@ public:
|
||||||
*/
|
*/
|
||||||
DeferredPublisher *publisher() const { return _publisher.get(); }
|
DeferredPublisher *publisher() const { return _publisher.get(); }
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Retrieve the deferred confirm that handles publisher confirms
|
||||||
|
* @return The deferred confirm object
|
||||||
|
*/
|
||||||
|
DeferredConfirm *confirm() const { return _confirm.get(); }
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* The channel class is its friend, thus can it instantiate this object
|
* The channel class is its friend, thus can it instantiate this object
|
||||||
*/
|
*/
|
||||||
|
|
|
||||||
|
|
@ -24,6 +24,8 @@ class BasicDeliverFrame;
|
||||||
class BasicGetOKFrame;
|
class BasicGetOKFrame;
|
||||||
class BasicHeaderFrame;
|
class BasicHeaderFrame;
|
||||||
class BasicReturnFrame;
|
class BasicReturnFrame;
|
||||||
|
class BasicAckFrame;
|
||||||
|
class BasicNackFrame;
|
||||||
class BodyFrame;
|
class BodyFrame;
|
||||||
class Channel;
|
class Channel;
|
||||||
class Connection;
|
class Connection;
|
||||||
|
|
|
||||||
|
|
@ -0,0 +1,118 @@
|
||||||
|
/**
|
||||||
|
* DeferredConfirm.h
|
||||||
|
*
|
||||||
|
* Deferred callback for RabbitMQ-specific publisher confirms mechanism.
|
||||||
|
*
|
||||||
|
* @author Marcin Gibula <m.gibula@gmail.com>
|
||||||
|
* @copyright 2018 Copernica BV
|
||||||
|
*/
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Include guard
|
||||||
|
*/
|
||||||
|
#pragma once
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Set up namespace
|
||||||
|
*/
|
||||||
|
namespace AMQP {
|
||||||
|
|
||||||
|
/**
|
||||||
|
* We extend from the default deferred and add extra functionality
|
||||||
|
*/
|
||||||
|
class DeferredConfirm : public Deferred
|
||||||
|
{
|
||||||
|
private:
|
||||||
|
/**
|
||||||
|
* Callback to execute when server confirms that message is processed
|
||||||
|
* @var AckCallback
|
||||||
|
*/
|
||||||
|
AckCallback _ackCallback;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Callback to execute when server sends negative acknowledgement
|
||||||
|
* @var NackCallback
|
||||||
|
*/
|
||||||
|
NackCallback _nackCallback;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Process an ACK frame
|
||||||
|
*
|
||||||
|
* @param frame The frame to process
|
||||||
|
*/
|
||||||
|
void process(BasicAckFrame &frame);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Process an ACK frame
|
||||||
|
*
|
||||||
|
* @param frame The frame to process
|
||||||
|
*/
|
||||||
|
void process(BasicNackFrame &frame);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* The channel implementation may call our
|
||||||
|
* private members and construct us
|
||||||
|
*/
|
||||||
|
friend class ChannelImpl;
|
||||||
|
friend class BasicAckFrame;
|
||||||
|
friend class BasicNackFrame;
|
||||||
|
|
||||||
|
public:
|
||||||
|
/**
|
||||||
|
* Protected constructor that can only be called
|
||||||
|
* from within the channel implementation
|
||||||
|
*
|
||||||
|
* Note: this constructor _should_ be protected, but because make_shared
|
||||||
|
* will then not work, we have decided to make it public after all,
|
||||||
|
* because the work-around would result in not-so-easy-to-read code.
|
||||||
|
*
|
||||||
|
* @param boolean are we already failed?
|
||||||
|
*/
|
||||||
|
DeferredConfirm(bool failed = false) : Deferred(failed) {}
|
||||||
|
|
||||||
|
public:
|
||||||
|
/**
|
||||||
|
* Register the function that is called when channel is put in publisher
|
||||||
|
* confirmed mode
|
||||||
|
* @param callback
|
||||||
|
*/
|
||||||
|
DeferredConfirm &onSuccess(const SuccessCallback &callback)
|
||||||
|
{
|
||||||
|
// call base
|
||||||
|
Deferred::onSuccess(callback);
|
||||||
|
|
||||||
|
// allow chaining
|
||||||
|
return *this;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Callback that is called when the broker confirmed message publication
|
||||||
|
* @param callback the callback to execute
|
||||||
|
*/
|
||||||
|
DeferredConfirm &onAck(const AckCallback &callback)
|
||||||
|
{
|
||||||
|
// store callback
|
||||||
|
_ackCallback = callback;
|
||||||
|
|
||||||
|
// allow chaining
|
||||||
|
return *this;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Callback that is called when the broker denied message publication
|
||||||
|
* @param callback the callback to execute
|
||||||
|
*/
|
||||||
|
DeferredConfirm &onNack(const NackCallback &callback)
|
||||||
|
{
|
||||||
|
// store callback
|
||||||
|
_nackCallback = callback;
|
||||||
|
|
||||||
|
// allow chaining
|
||||||
|
return *this;
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
/**
|
||||||
|
* End namespace
|
||||||
|
*/
|
||||||
|
}
|
||||||
|
|
@ -111,6 +111,13 @@ private:
|
||||||
*/
|
*/
|
||||||
bool processBasicFrame(ConnectionImpl *connection);
|
bool processBasicFrame(ConnectionImpl *connection);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Process a confirm frame
|
||||||
|
* @param connection
|
||||||
|
* @return bool
|
||||||
|
*/
|
||||||
|
bool processConfirmFrame(ConnectionImpl *connection);
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Process a transaction frame
|
* Process a transaction frame
|
||||||
* @param connection
|
* @param connection
|
||||||
|
|
|
||||||
|
|
@ -29,6 +29,8 @@ add_sources(
|
||||||
channelimpl.cpp
|
channelimpl.cpp
|
||||||
channelopenframe.h
|
channelopenframe.h
|
||||||
channelopenokframe.h
|
channelopenokframe.h
|
||||||
|
confirmselectframe.h
|
||||||
|
confirmselectokframe.h
|
||||||
connectioncloseframe.h
|
connectioncloseframe.h
|
||||||
connectioncloseokframe.h
|
connectioncloseokframe.h
|
||||||
connectionframe.h
|
connectionframe.h
|
||||||
|
|
@ -43,6 +45,7 @@ add_sources(
|
||||||
connectiontuneokframe.h
|
connectiontuneokframe.h
|
||||||
consumedmessage.h
|
consumedmessage.h
|
||||||
deferredcancel.cpp
|
deferredcancel.cpp
|
||||||
|
deferredconfirm.cpp
|
||||||
deferredconsumer.cpp
|
deferredconsumer.cpp
|
||||||
deferredreceiver.cpp
|
deferredreceiver.cpp
|
||||||
deferredextreceiver.cpp
|
deferredextreceiver.cpp
|
||||||
|
|
|
||||||
|
|
@ -110,6 +110,32 @@ public:
|
||||||
{
|
{
|
||||||
return _multiple.get(0);
|
return _multiple.get(0);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 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
|
||||||
|
auto channel = connection->channel(this->channel());
|
||||||
|
|
||||||
|
// channel does not exist
|
||||||
|
if(!channel) return false;
|
||||||
|
|
||||||
|
// get the current confirm
|
||||||
|
auto confirm = channel->confirm();
|
||||||
|
|
||||||
|
// if there is no deferred confirm, we can just as well stop
|
||||||
|
if (confirm == nullptr) return false;
|
||||||
|
|
||||||
|
// process the frame
|
||||||
|
confirm->process(*this);
|
||||||
|
|
||||||
|
// done
|
||||||
|
return true;
|
||||||
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
|
|
||||||
|
|
@ -108,6 +108,32 @@ public:
|
||||||
{
|
{
|
||||||
return _bits.get(1);
|
return _bits.get(1);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 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
|
||||||
|
auto channel = connection->channel(this->channel());
|
||||||
|
|
||||||
|
// channel does not exist
|
||||||
|
if(!channel) return false;
|
||||||
|
|
||||||
|
// get the current confirm
|
||||||
|
auto confirm = channel->confirm();
|
||||||
|
|
||||||
|
// if there is no deferred confirm, we can just as well stop
|
||||||
|
if (confirm == nullptr) return false;
|
||||||
|
|
||||||
|
// process the frame
|
||||||
|
confirm->process(*this);
|
||||||
|
|
||||||
|
// done
|
||||||
|
return true;
|
||||||
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
|
|
||||||
|
|
@ -14,6 +14,7 @@
|
||||||
#include "channelflowframe.h"
|
#include "channelflowframe.h"
|
||||||
#include "channelcloseokframe.h"
|
#include "channelcloseokframe.h"
|
||||||
#include "channelcloseframe.h"
|
#include "channelcloseframe.h"
|
||||||
|
#include "confirmselectframe.h"
|
||||||
#include "transactionselectframe.h"
|
#include "transactionselectframe.h"
|
||||||
#include "transactioncommitframe.h"
|
#include "transactioncommitframe.h"
|
||||||
#include "transactionrollbackframe.h"
|
#include "transactionrollbackframe.h"
|
||||||
|
|
@ -180,6 +181,27 @@ Deferred &ChannelImpl::resume()
|
||||||
return push(ChannelFlowFrame(_id, true));
|
return push(ChannelFlowFrame(_id, true));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Put channel in a confirm mode
|
||||||
|
*
|
||||||
|
* This function returns a deferred handler. Callbacks can be installed
|
||||||
|
* using onSuccess(), onError() and onFinalize() methods.
|
||||||
|
*/
|
||||||
|
DeferredConfirm &ChannelImpl::confirmSelect()
|
||||||
|
{
|
||||||
|
// the frame to send
|
||||||
|
ConfirmSelectFrame frame(_id);
|
||||||
|
|
||||||
|
// send the frame, and create deferred object
|
||||||
|
_confirm = std::make_shared<DeferredConfirm>(!send(frame));
|
||||||
|
|
||||||
|
// push to list
|
||||||
|
push(_confirm);
|
||||||
|
|
||||||
|
// done
|
||||||
|
return *_confirm;
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Start a transaction
|
* Start a transaction
|
||||||
*
|
*
|
||||||
|
|
|
||||||
|
|
@ -0,0 +1,56 @@
|
||||||
|
/**
|
||||||
|
* Class describing an AMQP confirm frame
|
||||||
|
*
|
||||||
|
* @author Marcin Gibula <m.gibula@gmail.com>
|
||||||
|
* @copyright 2017 Copernica BV
|
||||||
|
*/
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Set up namespace
|
||||||
|
*/
|
||||||
|
namespace AMQP {
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Class implementation
|
||||||
|
*/
|
||||||
|
class ConfirmFrame : public MethodFrame
|
||||||
|
{
|
||||||
|
protected:
|
||||||
|
/**
|
||||||
|
* Constructor
|
||||||
|
* @param channel channel identifier
|
||||||
|
* @param size frame size
|
||||||
|
*/
|
||||||
|
ConfirmFrame(uint16_t channel, uint32_t size) :
|
||||||
|
MethodFrame(channel, size)
|
||||||
|
{}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Constructor based on incoming frame
|
||||||
|
* @param frame
|
||||||
|
*/
|
||||||
|
ConfirmFrame(ReceivedFrame &frame) :
|
||||||
|
MethodFrame(frame)
|
||||||
|
{}
|
||||||
|
|
||||||
|
public:
|
||||||
|
/**
|
||||||
|
* Destructor
|
||||||
|
*/
|
||||||
|
virtual ~ConfirmFrame() {}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Class id
|
||||||
|
* @return uint16_t
|
||||||
|
*/
|
||||||
|
virtual uint16_t classID() const override
|
||||||
|
{
|
||||||
|
return 85;
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
/**
|
||||||
|
* end namespace
|
||||||
|
*/
|
||||||
|
}
|
||||||
|
|
||||||
|
|
@ -0,0 +1,88 @@
|
||||||
|
/**
|
||||||
|
* Class describing an AMQP confirm select frame
|
||||||
|
*
|
||||||
|
* @author Marcin Gibula <m.gibula@gmail.com>
|
||||||
|
* @copyright 2017 Copernica BV
|
||||||
|
*/
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Set up namespace
|
||||||
|
*/
|
||||||
|
namespace AMQP {
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Class implementation
|
||||||
|
*/
|
||||||
|
class ConfirmSelectFrame : public ConfirmFrame
|
||||||
|
{
|
||||||
|
private:
|
||||||
|
|
||||||
|
/**
|
||||||
|
* whether to wait for a response
|
||||||
|
* @var BooleanSet
|
||||||
|
*/
|
||||||
|
BooleanSet _noWait;
|
||||||
|
|
||||||
|
protected:
|
||||||
|
/**
|
||||||
|
* Encode a frame on a string buffer
|
||||||
|
*
|
||||||
|
* @param buffer buffer to write frame to
|
||||||
|
*/
|
||||||
|
virtual void fill(OutBuffer& buffer) const override
|
||||||
|
{
|
||||||
|
// call base
|
||||||
|
ConfirmFrame::fill(buffer);
|
||||||
|
|
||||||
|
// add boolean
|
||||||
|
_noWait.fill(buffer);
|
||||||
|
}
|
||||||
|
|
||||||
|
public:
|
||||||
|
/**
|
||||||
|
* Decode a confirm select frame from a received frame
|
||||||
|
*
|
||||||
|
* @param frame received frame to decode
|
||||||
|
*/
|
||||||
|
ConfirmSelectFrame(ReceivedFrame& frame) : ConfirmFrame(frame), _noWait(frame) {}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Construct a confirm select frame
|
||||||
|
*
|
||||||
|
* @param channel channel identifier
|
||||||
|
* @return newly created confirm select frame
|
||||||
|
*/
|
||||||
|
ConfirmSelectFrame(uint16_t channel, bool noWait = false) :
|
||||||
|
ConfirmFrame(channel, 1), //sizeof bool
|
||||||
|
_noWait(noWait)
|
||||||
|
{}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Destructor
|
||||||
|
*/
|
||||||
|
virtual ~ConfirmSelectFrame() {}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* return the method id
|
||||||
|
* @return uint16_t
|
||||||
|
*/
|
||||||
|
virtual uint16_t methodID() const override
|
||||||
|
{
|
||||||
|
return 10;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Return whether to wait for a response
|
||||||
|
* @return boolean
|
||||||
|
*/
|
||||||
|
bool noWait() const
|
||||||
|
{
|
||||||
|
return _noWait.get(0);
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
/**
|
||||||
|
* end namespace
|
||||||
|
*/
|
||||||
|
}
|
||||||
|
|
||||||
|
|
@ -0,0 +1,89 @@
|
||||||
|
/**
|
||||||
|
* Class describing an AMQP confirm select ok frame
|
||||||
|
*
|
||||||
|
* @author Marcin Gibula <m.gibula@gmail.com>
|
||||||
|
* @copyright 2017 Copernica BV
|
||||||
|
*/
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Set up namespace
|
||||||
|
*/
|
||||||
|
namespace AMQP {
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Class implementation
|
||||||
|
*/
|
||||||
|
class ConfirmSelectOKFrame : public ConfirmFrame
|
||||||
|
{
|
||||||
|
protected:
|
||||||
|
/**
|
||||||
|
* Encode a frame on a string buffer
|
||||||
|
*
|
||||||
|
* @param buffer buffer to write frame to
|
||||||
|
*/
|
||||||
|
virtual void fill(OutBuffer& buffer) const override
|
||||||
|
{
|
||||||
|
// call base
|
||||||
|
ConfirmFrame::fill(buffer);
|
||||||
|
}
|
||||||
|
|
||||||
|
public:
|
||||||
|
/**
|
||||||
|
* Constructor for an incoming frame
|
||||||
|
*
|
||||||
|
* @param frame received frame to decode
|
||||||
|
*/
|
||||||
|
ConfirmSelectOKFrame(ReceivedFrame& frame) :
|
||||||
|
ConfirmFrame(frame)
|
||||||
|
{}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Construct a confirm select ok frame
|
||||||
|
*
|
||||||
|
* @param channel channel identifier
|
||||||
|
* @return newly created confirm select ok frame
|
||||||
|
*/
|
||||||
|
ConfirmSelectOKFrame(uint16_t channel) :
|
||||||
|
ConfirmFrame(channel, 0)
|
||||||
|
{}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Destructor
|
||||||
|
*/
|
||||||
|
virtual ~ConfirmSelectOKFrame() {}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* return the method id
|
||||||
|
* @return uint16_t
|
||||||
|
*/
|
||||||
|
virtual uint16_t methodID() const override
|
||||||
|
{
|
||||||
|
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
|
||||||
|
auto channel = connection->channel(this->channel());
|
||||||
|
|
||||||
|
// channel does not exist
|
||||||
|
if(!channel) return false;
|
||||||
|
|
||||||
|
// report that the channel is open
|
||||||
|
if (channel->reportSuccess()) channel->onSynchronized();
|
||||||
|
|
||||||
|
// done
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
/**
|
||||||
|
* end namespace
|
||||||
|
*/
|
||||||
|
}
|
||||||
|
|
||||||
|
|
@ -0,0 +1,42 @@
|
||||||
|
/**
|
||||||
|
* DeferredConfirm.cpp
|
||||||
|
*
|
||||||
|
* Implementation file for the DeferredConfirm class
|
||||||
|
*
|
||||||
|
* @author Marcin Gibula <m.gibula@gmail.com>
|
||||||
|
* @copyright 2018 Copernica BV
|
||||||
|
*/
|
||||||
|
#include "includes.h"
|
||||||
|
#include "basicackframe.h"
|
||||||
|
#include "basicnackframe.h"
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Namespace
|
||||||
|
*/
|
||||||
|
namespace AMQP {
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Process an ACK frame
|
||||||
|
*
|
||||||
|
* @param frame The frame to process
|
||||||
|
*/
|
||||||
|
void DeferredConfirm::process(BasicAckFrame &frame)
|
||||||
|
{
|
||||||
|
if (_ackCallback) _ackCallback(frame.deliveryTag(), frame.multiple());
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Process a NACK frame
|
||||||
|
*
|
||||||
|
* @param frame The frame to process
|
||||||
|
*/
|
||||||
|
void DeferredConfirm::process(BasicNackFrame &frame)
|
||||||
|
{
|
||||||
|
if (_nackCallback) _nackCallback(frame.deliveryTag(), frame.multiple(), frame.requeue());
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* End namespace
|
||||||
|
*/
|
||||||
|
}
|
||||||
|
|
||||||
|
|
@ -72,6 +72,7 @@
|
||||||
#include "amqpcpp/deferredqueue.h"
|
#include "amqpcpp/deferredqueue.h"
|
||||||
#include "amqpcpp/deferreddelete.h"
|
#include "amqpcpp/deferreddelete.h"
|
||||||
#include "amqpcpp/deferredcancel.h"
|
#include "amqpcpp/deferredcancel.h"
|
||||||
|
#include "amqpcpp/deferredconfirm.h"
|
||||||
#include "amqpcpp/deferredget.h"
|
#include "amqpcpp/deferredget.h"
|
||||||
#include "amqpcpp/channelimpl.h"
|
#include "amqpcpp/channelimpl.h"
|
||||||
#include "amqpcpp/channel.h"
|
#include "amqpcpp/channel.h"
|
||||||
|
|
@ -93,6 +94,7 @@
|
||||||
#include "exchangeframe.h"
|
#include "exchangeframe.h"
|
||||||
#include "queueframe.h"
|
#include "queueframe.h"
|
||||||
#include "basicframe.h"
|
#include "basicframe.h"
|
||||||
|
#include "confirmframe.h"
|
||||||
#include "transactionframe.h"
|
#include "transactionframe.h"
|
||||||
|
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -7,6 +7,8 @@
|
||||||
*/
|
*/
|
||||||
#include "includes.h"
|
#include "includes.h"
|
||||||
#include "heartbeatframe.h"
|
#include "heartbeatframe.h"
|
||||||
|
#include "confirmselectframe.h"
|
||||||
|
#include "confirmselectokframe.h"
|
||||||
#include "connectionstartokframe.h"
|
#include "connectionstartokframe.h"
|
||||||
#include "connectionstartframe.h"
|
#include "connectionstartframe.h"
|
||||||
#include "connectionsecureframe.h"
|
#include "connectionsecureframe.h"
|
||||||
|
|
@ -336,6 +338,7 @@ bool ReceivedFrame::processMethodFrame(ConnectionImpl *connection)
|
||||||
case 40: return processExchangeFrame(connection);
|
case 40: return processExchangeFrame(connection);
|
||||||
case 50: return processQueueFrame(connection);
|
case 50: return processQueueFrame(connection);
|
||||||
case 60: return processBasicFrame(connection);
|
case 60: return processBasicFrame(connection);
|
||||||
|
case 85: return processConfirmFrame(connection);
|
||||||
case 90: return processTransactionFrame(connection);
|
case 90: return processTransactionFrame(connection);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -493,6 +496,27 @@ bool ReceivedFrame::processBasicFrame(ConnectionImpl *connection)
|
||||||
throw ProtocolException("unrecognized basic frame method " + std::to_string(methodID));
|
throw ProtocolException("unrecognized basic frame method " + std::to_string(methodID));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Process a confirm frame
|
||||||
|
* @param connection
|
||||||
|
* @return bool
|
||||||
|
*/
|
||||||
|
bool ReceivedFrame::processConfirmFrame(ConnectionImpl *connection)
|
||||||
|
{
|
||||||
|
// read the method id
|
||||||
|
uint16_t methodID = nextUint16();
|
||||||
|
|
||||||
|
// construct frame based on method id
|
||||||
|
switch (methodID)
|
||||||
|
{
|
||||||
|
case 10: return ConfirmSelectFrame(*this).process(connection);
|
||||||
|
case 11: return ConfirmSelectOKFrame(*this).process(connection);
|
||||||
|
}
|
||||||
|
|
||||||
|
// this is a problem
|
||||||
|
throw ProtocolException("unrecognized confirm frame method " + std::to_string(methodID));
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Process a transaction frame
|
* Process a transaction frame
|
||||||
* @param connection
|
* @param connection
|
||||||
|
|
|
||||||
Loading…
Reference in New Issue