the consumer message callback can now also be installed via the Deferred objects, and it is no longer passed a consumer tag, because it already is obvious what the consumer tag is supposed to be
This commit is contained in:
parent
921f24ae06
commit
745ab512a5
|
|
@ -20,9 +20,10 @@ namespace AMQP {
|
||||||
using SuccessCallback = std::function<void()>;
|
using SuccessCallback = std::function<void()>;
|
||||||
using ErrorCallback = std::function<void(const char *message)>;
|
using ErrorCallback = std::function<void(const char *message)>;
|
||||||
using FinalizeCallback = std::function<void()>;
|
using FinalizeCallback = std::function<void()>;
|
||||||
using ConsumeCallback = std::function<void(const Message &message, uint64_t deliveryTag, const std::string &consumerTag, bool redelivered)>;
|
using MessageCallback = std::function<void(const Message &message, uint64_t deliveryTag, bool redelivered)>;
|
||||||
using QueueCallback = std::function<void(const std::string &name, uint32_t messagecount, uint32_t consumercount)>;
|
using QueueCallback = std::function<void(const std::string &name, uint32_t messagecount, uint32_t consumercount)>;
|
||||||
using DeleteCallback = std::function<void(uint32_t deletedmessages)>;
|
using DeleteCallback = std::function<void(uint32_t deletedmessages)>;
|
||||||
|
using ConsumeCallback = std::function<void(const std::string &consumer)>;
|
||||||
using CancelCallback = std::function<void(const std::string &consumer)>;
|
using CancelCallback = std::function<void(const std::string &consumer)>;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
|
|
||||||
|
|
@ -14,6 +14,11 @@
|
||||||
*/
|
*/
|
||||||
namespace AMQP {
|
namespace AMQP {
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Forward declarations
|
||||||
|
*/
|
||||||
|
class ConsumedMessage;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Class definition
|
* Class definition
|
||||||
*/
|
*/
|
||||||
|
|
@ -45,11 +50,10 @@ private:
|
||||||
ErrorCallback _errorCallback;
|
ErrorCallback _errorCallback;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Callback to execute when a message arrives
|
* Callbacks for all consumers that are active
|
||||||
*
|
* @var std::map<std::string,MessageCallback>
|
||||||
* @todo do this different??
|
|
||||||
*/
|
*/
|
||||||
std::unique_ptr<DeferredConsumer> _consumer;
|
std::map<std::string,MessageCallback> _consumers;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Pointer to the oldest deferred result (the first one that is going
|
* Pointer to the oldest deferred result (the first one that is going
|
||||||
|
|
@ -84,9 +88,9 @@ private:
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* The message that is now being received
|
* The message that is now being received
|
||||||
* @var MessageImpl
|
* @var ConsumedMessage
|
||||||
*/
|
*/
|
||||||
MessageImpl *_message = nullptr;
|
ConsumedMessage *_message = nullptr;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Construct a channel object
|
* Construct a channel object
|
||||||
|
|
@ -491,6 +495,20 @@ public:
|
||||||
// @todo destruct oldest callback
|
// @todo destruct oldest callback
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Install a consumer callback
|
||||||
|
* @param consumertag The consumer tag
|
||||||
|
* @param callback The callback to be called
|
||||||
|
*/
|
||||||
|
void install(const std::string &consumertag, const MessageCallback &callback)
|
||||||
|
{
|
||||||
|
// install the callback if it is assigned
|
||||||
|
if (callback) _consumers[consumertag] = callback;
|
||||||
|
|
||||||
|
// otherwise we erase the previously set callback
|
||||||
|
else _consumers.erase(consumertag);
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Report that a message was received
|
* Report that a message was received
|
||||||
*/
|
*/
|
||||||
|
|
@ -499,34 +517,19 @@ public:
|
||||||
/**
|
/**
|
||||||
* Create an incoming message
|
* Create an incoming message
|
||||||
* @param frame
|
* @param frame
|
||||||
* @return MessageImpl
|
* @return ConsumedMessage
|
||||||
*/
|
*/
|
||||||
MessageImpl *message(const BasicDeliverFrame &frame);
|
ConsumedMessage *message(const BasicDeliverFrame &frame);
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Retrieve the current incoming message
|
* Retrieve the current incoming message
|
||||||
* @return MessageImpl
|
* @return ConsumedMessage
|
||||||
*/
|
*/
|
||||||
MessageImpl *message()
|
ConsumedMessage *message()
|
||||||
{
|
{
|
||||||
return _message;
|
return _message;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
|
||||||
* Report that the consumer has started
|
|
||||||
*
|
|
||||||
* @param consumerTag the tag under which we are now consuming
|
|
||||||
*/
|
|
||||||
void reportConsumerStarted(const std::string& consumerTag)
|
|
||||||
{
|
|
||||||
// if we do not have a consumer, something is very wrong
|
|
||||||
if (!_consumer) reportError("Received basic consume ok frame, but no consumer was found");
|
|
||||||
|
|
||||||
// otherwise, we now report the consumer as started
|
|
||||||
// @todo look at this implementation
|
|
||||||
//else _consumer->success(consumerTag);
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* The channel class is its friend, thus can it instantiate this object
|
* The channel class is its friend, thus can it instantiate this object
|
||||||
*/
|
*/
|
||||||
|
|
|
||||||
|
|
@ -17,25 +17,31 @@ namespace AMQP {
|
||||||
class DeferredConsumer : public Deferred
|
class DeferredConsumer : public Deferred
|
||||||
{
|
{
|
||||||
private:
|
private:
|
||||||
|
/**
|
||||||
|
* The channel to which the consumer is linked
|
||||||
|
* @var ChannelImpl
|
||||||
|
*/
|
||||||
|
ChannelImpl *_channel;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Callback to execute when a message arrives
|
* Callback to execute when a message arrives
|
||||||
* @var ConsumeCallbacl
|
* @var ConsumeCallback
|
||||||
*/
|
*/
|
||||||
ConsumeCallback _consumeCallback;
|
ConsumeCallback _consumeCallback;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Process a message
|
* Callback for incoming messages
|
||||||
*
|
* @var MessageCallback
|
||||||
* @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
|
MessageCallback _messageCallback;
|
||||||
{
|
|
||||||
// do we have a valid callback
|
|
||||||
if (_consumeCallback) _consumeCallback(message, deliveryTag, consumerTag, redelivered);
|
/**
|
||||||
}
|
* Report success for frames that report start consumer operations
|
||||||
|
* @param name Consumer tag that is started
|
||||||
|
* @return Deferred
|
||||||
|
*/
|
||||||
|
virtual Deferred *reportSuccess(const std::string &name) const override;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* The channel implementation may call our
|
* The channel implementation may call our
|
||||||
|
|
@ -49,23 +55,36 @@ protected:
|
||||||
* Protected constructor that can only be called
|
* Protected constructor that can only be called
|
||||||
* from within the channel implementation
|
* from within the channel implementation
|
||||||
*
|
*
|
||||||
* @param boolea are we already failed?
|
* @param channel the channel implementation
|
||||||
|
* @param failed are we already failed?
|
||||||
*/
|
*/
|
||||||
DeferredConsumer(bool failed = false) : Deferred(failed) {}
|
DeferredConsumer(ChannelImpl *channel, bool failed = false) :
|
||||||
|
Deferred(failed), _channel(channel) {}
|
||||||
|
|
||||||
public:
|
public:
|
||||||
|
/**
|
||||||
|
* Register the function that is called when the consumer starts
|
||||||
|
* @param callback
|
||||||
|
*/
|
||||||
|
DeferredConsumer &onSuccess(const ConsumeCallback &callback)
|
||||||
|
{
|
||||||
|
// store the callback
|
||||||
|
_consumeCallback = callback;
|
||||||
|
|
||||||
|
// allow chaining
|
||||||
|
return *this;
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Register a function to be called when a message arrives
|
* 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
|
* @param callback the callback to execute
|
||||||
*/
|
*/
|
||||||
DeferredConsumer& onReceived(const ConsumeCallback &callback)
|
DeferredConsumer& onReceived(const MessageCallback &callback)
|
||||||
{
|
{
|
||||||
// store callback
|
// store callback
|
||||||
_consumeCallback = callback;
|
_messageCallback = callback;
|
||||||
|
|
||||||
|
// allow chaining
|
||||||
return *this;
|
return *this;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -94,7 +94,7 @@ public:
|
||||||
if (!channel) return false;
|
if (!channel) return false;
|
||||||
|
|
||||||
// report
|
// report
|
||||||
channel->reportConsumerStarted(consumerTag());
|
channel->reportSuccess(consumerTag());
|
||||||
|
|
||||||
// done
|
// done
|
||||||
return true;
|
return true;
|
||||||
|
|
|
||||||
|
|
@ -487,21 +487,17 @@ Deferred &ChannelImpl::setQos(uint16_t prefetchCount)
|
||||||
*/
|
*/
|
||||||
DeferredConsumer& ChannelImpl::consume(const std::string &queue, const std::string &tag, int flags, const Table &arguments)
|
DeferredConsumer& ChannelImpl::consume(const std::string &queue, const std::string &tag, int flags, const Table &arguments)
|
||||||
{
|
{
|
||||||
// create the deferred consumer
|
// the frame to send
|
||||||
_consumer = std::unique_ptr<DeferredConsumer>(new DeferredConsumer(false));
|
BasicConsumeFrame frame(_id, queue, tag, flags & nolocal, flags & noack, flags & exclusive, flags & nowait, arguments);
|
||||||
|
|
||||||
// can we send the basic consume frame?
|
// send the frame, and create deferred object
|
||||||
if (!send(BasicConsumeFrame(_id, queue, tag, flags & nolocal, flags & noack, flags & exclusive, flags & nowait, arguments)))
|
auto *deferred = new DeferredConsumer(this, send(frame));
|
||||||
{
|
|
||||||
// we set the consumer to be failed immediately
|
// push to list
|
||||||
_consumer->_failed = true;
|
push(deferred, "Cannot send basic consume frame");
|
||||||
|
|
||||||
// we should call the error function later
|
// done
|
||||||
// TODO
|
return *deferred;
|
||||||
}
|
|
||||||
|
|
||||||
// return the consumer
|
|
||||||
return *_consumer;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
|
@ -611,44 +607,39 @@ Deferred &ChannelImpl::send(const Frame &frame, const char *message)
|
||||||
*/
|
*/
|
||||||
void ChannelImpl::reportMessage()
|
void ChannelImpl::reportMessage()
|
||||||
{
|
{
|
||||||
// @todo what does this method do?
|
|
||||||
|
|
||||||
// skip if there is no message
|
// skip if there is no message
|
||||||
if (!_message) return;
|
if (!_message) return;
|
||||||
|
|
||||||
// do we even have a consumer?
|
// look for the consumer
|
||||||
if (!_consumer)
|
auto iter = _consumers.find(_message->consumer());
|
||||||
{
|
if (iter == _consumers.end()) return;
|
||||||
// this should not be possible: receiving a message without doing a consume() call
|
|
||||||
reportError("Received message without having a consumer");
|
// is this a valid callback method
|
||||||
}
|
if (!iter->second) return;
|
||||||
else
|
|
||||||
{
|
|
||||||
// after the report the channel may be destructed, monitor that
|
|
||||||
Monitor monitor(this);
|
|
||||||
|
|
||||||
// send message to the consumer
|
// after the report the channel may be destructed, monitor that
|
||||||
_message->report(*_consumer);
|
Monitor monitor(this);
|
||||||
|
|
||||||
// skip if channel was destructed
|
// call the callback
|
||||||
if (!monitor.valid()) return;
|
_message->report(iter->second);
|
||||||
}
|
|
||||||
|
// skip if channel was destructed
|
||||||
|
if (!monitor.valid()) return;
|
||||||
|
|
||||||
// no longer need the message
|
// no longer need the message
|
||||||
delete _message;
|
delete _message; _message = nullptr;
|
||||||
_message = nullptr;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Create an incoming message
|
* Create an incoming message
|
||||||
* @param frame
|
* @param frame
|
||||||
* @return MessageImpl
|
* @return ConsumedMessage
|
||||||
*/
|
*/
|
||||||
MessageImpl *ChannelImpl::message(const BasicDeliverFrame &frame)
|
ConsumedMessage *ChannelImpl::message(const BasicDeliverFrame &frame)
|
||||||
{
|
{
|
||||||
// it should not be possible that a message already exists, but lets check it anyhow
|
// destruct if message is already set
|
||||||
if (_message) delete _message;
|
if (_message) delete _message;
|
||||||
|
|
||||||
// construct a message
|
// construct a message
|
||||||
return _message = new ConsumedMessage(frame);
|
return _message = new ConsumedMessage(frame);
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -50,13 +50,22 @@ public:
|
||||||
virtual ~ConsumedMessage() {}
|
virtual ~ConsumedMessage() {}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Report to the handler
|
* Retrieve the consumer tag
|
||||||
* @param consumer
|
* @return std::string
|
||||||
*/
|
*/
|
||||||
virtual void report(const DeferredConsumer& consumer) override
|
const std::string &consumer() const
|
||||||
|
{
|
||||||
|
return _consumerTag;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Report to the handler
|
||||||
|
* @param callback
|
||||||
|
*/
|
||||||
|
void report(const MessageCallback &callback) const
|
||||||
{
|
{
|
||||||
// send ourselves to the consumer
|
// send ourselves to the consumer
|
||||||
consumer.message(*this, _deliveryTag, _consumerTag, _redelivered);
|
if (callback) callback(*this, _deliveryTag, _redelivered);
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -0,0 +1,43 @@
|
||||||
|
/**
|
||||||
|
* DeferredConsumer.cpp
|
||||||
|
*
|
||||||
|
* Implementation file for the DeferredConsumer class
|
||||||
|
*
|
||||||
|
* @copyright 2014 Copernica BV
|
||||||
|
*/
|
||||||
|
#include "includes.h"
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Namespace
|
||||||
|
*/
|
||||||
|
namespace AMQP {
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Report success for frames that report start consumer operations
|
||||||
|
* @param name Consumer tag that is started
|
||||||
|
* @return Deferred
|
||||||
|
*/
|
||||||
|
Deferred *DeferredConsumer::reportSuccess(const std::string &name) const
|
||||||
|
{
|
||||||
|
// we now know the name, so we can install the message callback on the channel
|
||||||
|
_channel->install(name, _messageCallback);
|
||||||
|
|
||||||
|
// @todo when a consumer stops, we should uninstall the message callback
|
||||||
|
|
||||||
|
// skip if no special callback was installed
|
||||||
|
if (!_consumeCallback) return Deferred::reportSuccess();
|
||||||
|
|
||||||
|
// call the callback
|
||||||
|
_consumeCallback(name);
|
||||||
|
|
||||||
|
// call finalize callback
|
||||||
|
if (_finalizeCallback) _finalizeCallback();
|
||||||
|
|
||||||
|
// return next object
|
||||||
|
return _next;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* End namespace
|
||||||
|
*/
|
||||||
|
}
|
||||||
|
|
@ -98,12 +98,6 @@ public:
|
||||||
return _received >= _bodySize;
|
return _received >= _bodySize;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
|
||||||
* Report to the handler
|
|
||||||
* @param consumer
|
|
||||||
*/
|
|
||||||
virtual void report(const DeferredConsumer& consumer) = 0;
|
|
||||||
};
|
};
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
|
|
||||||
|
|
@ -66,6 +66,7 @@
|
||||||
#include "transactionrollbackframe.h"
|
#include "transactionrollbackframe.h"
|
||||||
#include "transactionrollbackokframe.h"
|
#include "transactionrollbackokframe.h"
|
||||||
#include "messageimpl.h"
|
#include "messageimpl.h"
|
||||||
|
#include "consumedmessage.h"
|
||||||
#include "bodyframe.h"
|
#include "bodyframe.h"
|
||||||
#include "basicheaderframe.h"
|
#include "basicheaderframe.h"
|
||||||
#include "framecheck.h"
|
#include "framecheck.h"
|
||||||
|
|
|
||||||
|
|
@ -45,15 +45,6 @@ public:
|
||||||
* Destructor
|
* Destructor
|
||||||
*/
|
*/
|
||||||
virtual ~ReturnedMessage() {}
|
virtual ~ReturnedMessage() {}
|
||||||
|
|
||||||
/**
|
|
||||||
* Report to the handler
|
|
||||||
* @param consumer
|
|
||||||
*/
|
|
||||||
virtual void report(const DeferredConsumer& consumer) override
|
|
||||||
{
|
|
||||||
// we no longer support returned messages
|
|
||||||
}
|
|
||||||
};
|
};
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
|
|
||||||
Loading…
Reference in New Issue