Implemented deferred consumers and a setTimeout method on the connection handler for indicating immediate failures on deferred objects

This commit is contained in:
Martijn Otto 2014-04-14 14:10:57 +02:00
parent 3348e2881c
commit 1c0495378a
8 changed files with 151 additions and 80 deletions

View File

@ -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>

View File

@ -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

View File

@ -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
* *

View File

@ -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;
}; };
/** /**

View File

@ -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);

View File

@ -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
*/
}

View File

@ -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;
} }
/** /**