/** * Deferred.h * * Class describing a set of actions that could * possibly happen in the future that can be * caught. * * @copyright 2014 - 2020 Copernica BV */ /** * Include guard */ #pragma once /** * Dependencies */ #include #include #include "callbacks.h" /** * Set up namespace */ namespace AMQP { // forward declaration class ChannelImpl; /** * Class definition */ class Deferred { private: /** * Callback to execute either way * @var FinalizeCallback */ FinalizeCallback _finalizeCallback; protected: /** * Callback to execute on success * @var SuccessCallback */ SuccessCallback _successCallback; /** * Callback to execute on failure * @var ErrorCallback */ ErrorCallback _errorCallback; /** * Pointer to the next deferred object * @var Deferred */ std::shared_ptr _next; /** * Do we already know we failed? * @var bool */ bool _failed; /** * The next deferred object * @return Deferred */ const std::shared_ptr &next() const { return _next; } /** * Indicate success * @return Deferred Next deferred result */ virtual const std::shared_ptr &reportSuccess() const { // execute callbacks if registered if (_successCallback) _successCallback(); // 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 const std::shared_ptr &reportSuccess(const std::string &name, uint32_t messagecount, uint32_t consumercount) const { // make sure compilers dont complain about unused parameters (void) name; (void) messagecount; (void) consumercount; // 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 const std::shared_ptr &reportSuccess(uint32_t messagecount) const { // make sure compilers dont complain about unused parameters (void) messagecount; // this is the same as a regular success message return reportSuccess(); } /** * Report success for a get operation * * @param messagecount Number of messages left in the queue * @param deliveryTag Delivery tag of the message coming in * @param redelivered Was the message redelivered? */ virtual const std::shared_ptr &reportSuccess(uint32_t messagecount, uint64_t deliveryTag, bool redelivered) { // make sure compilers dont complain about unused parameters (void) messagecount; (void) deliveryTag; (void) redelivered; // 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 const std::shared_ptr &reportSuccess(const std::string &name) { // make sure compilers dont complain about unused parameters (void) name; // 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 */ const std::shared_ptr &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); // return the next deferred result return _next; } /** * Add a pointer to the next deferred result * @param deferred */ void add(const std::shared_ptr &deferred) { // store pointer _next = deferred; } /** * Remove this object from the chain of deferreds */ void unchain() { // we no longer need the next pointer _next = nullptr; } /** * The channel implementation may call our * private members and construct us */ friend class ChannelImpl; friend class Tagger; 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 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() { // report to the finalize callback if (_finalizeCallback) _finalizeCallback(); } /** * Cast to a boolean */ operator bool () const { 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) { // if the object is already in a failed state, we call the callback right away if (_failed) callback(); // otherwise we store callback until it's time for the call else _finalizeCallback = callback; // allow chaining return *this; } }; /** * End namespace */ }