Implemented deferred consumers and a setTimeout method on the connection handler for indicating immediate failures on deferred objects
This commit is contained in:
parent
3348e2881c
commit
1c0495378a
|
|
@ -6,6 +6,8 @@
|
||||||
* @documentation public
|
* @documentation public
|
||||||
*/
|
*/
|
||||||
|
|
||||||
|
#pragma once
|
||||||
|
|
||||||
// base C++ include files
|
// base C++ include files
|
||||||
#include <vector>
|
#include <vector>
|
||||||
#include <string>
|
#include <string>
|
||||||
|
|
|
||||||
|
|
@ -22,24 +22,6 @@ private:
|
||||||
*/
|
*/
|
||||||
ConnectionImpl _implementation;
|
ConnectionImpl _implementation;
|
||||||
|
|
||||||
/**
|
|
||||||
* Function to execute code after a certain timeout.
|
|
||||||
*
|
|
||||||
* If the timeout is 0, the code is supposed to be run
|
|
||||||
* in the next iteration of the event loop.
|
|
||||||
*
|
|
||||||
* This is a simple placeholder function that will just
|
|
||||||
* execute the code immediately, it should be overridden
|
|
||||||
* by the timeout function the used event loop has.
|
|
||||||
*
|
|
||||||
* @param timeout the amount of time to wait
|
|
||||||
* @param callback the callback to execute after the timeout
|
|
||||||
*/
|
|
||||||
std::function<void(double timeout, const std::function<void()>)> _timeoutHandler = [](double timeout, const std::function<void()>& callback) {
|
|
||||||
// execute callback immediately
|
|
||||||
callback();
|
|
||||||
};
|
|
||||||
|
|
||||||
public:
|
public:
|
||||||
/**
|
/**
|
||||||
* Construct an AMQP object based on full login data
|
* Construct an AMQP object based on full login data
|
||||||
|
|
|
||||||
|
|
@ -21,6 +21,18 @@ namespace AMQP {
|
||||||
class ConnectionHandler
|
class ConnectionHandler
|
||||||
{
|
{
|
||||||
public:
|
public:
|
||||||
|
/**
|
||||||
|
* Set a function to be executed after a given timeout.
|
||||||
|
*
|
||||||
|
* This function is not strictly necessary to implement. If you
|
||||||
|
* do not implement it, certain channel methods that fail
|
||||||
|
* immediately will not be reported.
|
||||||
|
*
|
||||||
|
* @param timeout number of seconds to wait
|
||||||
|
* @param callback function to execute once time runs out
|
||||||
|
*/
|
||||||
|
virtual void setTimeout(double seconds, const std::function<void()>& callback) {}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Method that is called when data needs to be sent over the network
|
* Method that is called when data needs to be sent over the network
|
||||||
*
|
*
|
||||||
|
|
|
||||||
|
|
@ -298,7 +298,7 @@ public:
|
||||||
* The actual connection is a friend and can construct this class
|
* The actual connection is a friend and can construct this class
|
||||||
*/
|
*/
|
||||||
friend class Connection;
|
friend class Connection;
|
||||||
|
friend class ChannelImpl;
|
||||||
};
|
};
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
|
|
||||||
|
|
@ -56,11 +56,8 @@ private:
|
||||||
*
|
*
|
||||||
* @param error description of the error that occured
|
* @param error description of the error that occured
|
||||||
*/
|
*/
|
||||||
void error(const std::string& error)
|
void error(const std::string& error) const
|
||||||
{
|
{
|
||||||
// we are now in a failed state
|
|
||||||
_failed = true;
|
|
||||||
|
|
||||||
// execute callbacks if registered
|
// execute callbacks if registered
|
||||||
if (_errorCallback) _errorCallback(_channel, error);
|
if (_errorCallback) _errorCallback(_channel, error);
|
||||||
if (_finalizeCallback) _finalizeCallback(_channel, error);
|
if (_finalizeCallback) _finalizeCallback(_channel, error);
|
||||||
|
|
|
||||||
|
|
@ -0,0 +1,76 @@
|
||||||
|
/**
|
||||||
|
* 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<const std::string&>
|
||||||
|
{
|
||||||
|
private:
|
||||||
|
/**
|
||||||
|
* Callback to execute when a message arrives
|
||||||
|
*/
|
||||||
|
std::function<void(Channel *channel, const Message &message, uint64_t deliveryTag, const std::string &consumerTag, bool redelivered)> _messageCallback;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Process a message
|
||||||
|
*
|
||||||
|
* @param message the message to process
|
||||||
|
* @param deliveryTag the message delivery tag
|
||||||
|
* @param consumerTag the tag we are consuming under
|
||||||
|
* @param is this a redelivered message?
|
||||||
|
*/
|
||||||
|
void message(const Message &message, uint64_t deliveryTag, const std::string &consumerTag, bool redelivered) const
|
||||||
|
{
|
||||||
|
// do we have a valid callback
|
||||||
|
if (_messageCallback) _messageCallback(_channel, message, deliveryTag, consumerTag, redelivered);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 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 we operate under
|
||||||
|
* @param boolea are we already failed?
|
||||||
|
*/
|
||||||
|
DeferredConsumer(Channel *channel, bool failed = false) :
|
||||||
|
Deferred(channel, failed)
|
||||||
|
{}
|
||||||
|
public:
|
||||||
|
/**
|
||||||
|
* Register a function to be called when a message arrives
|
||||||
|
*
|
||||||
|
* Only one callback can be registered. Successive calls
|
||||||
|
* to this function will clear callbacks registered before.
|
||||||
|
*
|
||||||
|
* @param callback the callback to execute
|
||||||
|
*/
|
||||||
|
DeferredConsumer& onReceived(const std::function<void(Channel *channel, const Message &message, uint64_t deliveryTag, const std::string &consumerTag, bool redelivered)>& callback)
|
||||||
|
{
|
||||||
|
// store callback
|
||||||
|
_messageCallback = callback;
|
||||||
|
return *this;
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
/**
|
||||||
|
* End namespace
|
||||||
|
*/
|
||||||
|
}
|
||||||
|
|
@ -540,25 +540,27 @@ template <typename... Arguments>
|
||||||
Deferred<Arguments...>& ChannelImpl::send(const Frame &frame, const char *message)
|
Deferred<Arguments...>& ChannelImpl::send(const Frame &frame, const char *message)
|
||||||
{
|
{
|
||||||
// create a new deferred handler and get a pointer to it
|
// create a new deferred handler and get a pointer to it
|
||||||
auto &handler = _callbacks.push_back(Deferred<Arguments...>(_parent));
|
// note: cannot use auto here or the lambda below chokes
|
||||||
|
// when compiling under gcc 4.8
|
||||||
|
Deferred<Arguments...> *handler = &_callbacks.push_back(Deferred<Arguments...>(_parent));
|
||||||
|
|
||||||
// send the frame over the channel
|
// send the frame over the channel
|
||||||
if (!send(frame))
|
if (!send(frame))
|
||||||
{
|
{
|
||||||
// we can immediately put the handler in failed state
|
// we can immediately put the handler in failed state
|
||||||
handler._failed = true;
|
handler->_failed = true;
|
||||||
|
|
||||||
// the frame could not be send
|
// register an error on the deferred handler
|
||||||
// we should register an error
|
// after a timeout, so it gets called only
|
||||||
// on the handler, but only after
|
// after a possible handler was installed.
|
||||||
// a timeout, so a handler can
|
_connection->_handler->setTimeout(0, [handler, message]() {
|
||||||
// be attached first
|
// emit an error on the handler
|
||||||
|
handler->error(message);
|
||||||
// TODO
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
// return the new handler
|
// return the new handler
|
||||||
return handler;
|
return *handler;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
|
|
||||||
Loading…
Reference in New Issue