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
|
||||
*/
|
||||
|
||||
#pragma once
|
||||
|
||||
// base C++ include files
|
||||
#include <vector>
|
||||
#include <string>
|
||||
|
|
|
|||
|
|
@ -22,24 +22,6 @@ private:
|
|||
*/
|
||||
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:
|
||||
/**
|
||||
* Construct an AMQP object based on full login data
|
||||
|
|
|
|||
|
|
@ -21,6 +21,18 @@ namespace AMQP {
|
|||
class ConnectionHandler
|
||||
{
|
||||
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
|
||||
*
|
||||
|
|
|
|||
|
|
@ -298,7 +298,7 @@ public:
|
|||
* The actual connection is a friend and can construct this class
|
||||
*/
|
||||
friend class Connection;
|
||||
|
||||
friend class ChannelImpl;
|
||||
};
|
||||
|
||||
/**
|
||||
|
|
|
|||
|
|
@ -56,11 +56,8 @@ private:
|
|||
*
|
||||
* @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
|
||||
if (_errorCallback) _errorCallback(_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)
|
||||
{
|
||||
// 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
|
||||
if (!send(frame))
|
||||
{
|
||||
// we can immediately put the handler in failed state
|
||||
handler._failed = true;
|
||||
handler->_failed = true;
|
||||
|
||||
// the frame could not be send
|
||||
// we should register an error
|
||||
// on the handler, but only after
|
||||
// a timeout, so a handler can
|
||||
// be attached first
|
||||
|
||||
// TODO
|
||||
// register an error on the deferred handler
|
||||
// after a timeout, so it gets called only
|
||||
// after a possible handler was installed.
|
||||
_connection->_handler->setTimeout(0, [handler, message]() {
|
||||
// emit an error on the handler
|
||||
handler->error(message);
|
||||
});
|
||||
}
|
||||
|
||||
// return the new handler
|
||||
return handler;
|
||||
return *handler;
|
||||
}
|
||||
|
||||
/**
|
||||
|
|
|
|||
Loading…
Reference in New Issue