9#include <proton/default_container.hpp>
10#include <proton/delivery.hpp>
11#include <proton/message.hpp>
12#include <proton/messaging_handler.hpp>
13#include <proton/connection.hpp>
14#include <proton/connection_options.hpp>
15#include <proton/container.hpp>
16#include <proton/reconnect_options.hpp>
17#include <proton/tracker.hpp>
18#include <proton/source_options.hpp>
19#include <proton/work_queue.hpp>
22#include "cajun/json/reader.h"
23#include "cajun/json/writer.h"
24#include "cajun/json/elements.h"
26using proton::receiver_options;
27using proton::source_options;
29#define RESIPROCATE_SUBSYSTEM Subsystem::QPIDPROTON
35 std::chrono::duration<long int> maximumAge,
36 std::chrono::duration<long int> retryDelay)
37 : mMaximumAge(maximumAge),
38 mRetryDelay(retryDelay),
50 std::chrono::duration<long int> retryDelay)
51 : mRetryDelay(retryDelay),
57 StackLog(<<
"ProtonSenderBase::ProtonSenderBase : " <<
mUrl);
69 StackLog(<<
"QpidProtonThread::sendMessage added a message to the FIFO");
73 ErrLog(<<
"mFifo rejected the message");
85 StackLog(<<
"checking for a message");
86 while(mFifo.messageAvailable() && mSender.credit() > 0)
88 StackLog(<<
"doSend trying to send a message");
89 std::shared_ptr<Data> body(mFifo.getNext());
91 msg.body(body->c_str());
93 StackLog(<<
"doSend: mPending = " << ++mPending);
95 if(mFifo.messageAvailable())
97 StackLog(<<
"tick still has messages to send, but no credit remaining");
100 catch(
const std::exception& e)
102 ErrLog(<<
"failed to send a message: " << e.what());
108 : mRetryDelay(retryDelay),
118ProtonThreadBase::openReceiver(std::shared_ptr<ProtonReceiverBase> rx)
120 StackLog(<<
"calling open_receiver");
123 rx->mReceiver = mConnection.open_receiver(rx->mUrl);
124 rx->mWorkQueue = &rx->mReceiver.work_queue();
128 proton::reconnect_options rec;
129 rec.delay(proton::duration(std::chrono::milliseconds(rx->mRetryDelay).count()));
130 proton::connection_options co;
132 rx->mReceiver = mContainer->open_receiver(rx->mUrl, co);
137ProtonThreadBase::openSender(std::shared_ptr<ProtonSenderBase> tx)
139 StackLog(<<
"calling open_sender for " << tx->mUrl);
142 tx->mSender = mConnection.open_sender(tx->mUrl);
143 tx->mWorkQueue = &tx->mSender.work_queue();
148 proton::reconnect_options rec;
149 rec.delay(proton::duration(std::chrono::milliseconds(tx->mRetryDelay).count()));
150 proton::connection_options co;
152 tx->mSender = mContainer->open_sender(tx->mUrl, co);
159 mReceivers.push_back(rx);
169 mSenders.push_back(tx);
176std::shared_ptr<ProtonThreadBase::ProtonSenderBase>
179 std::shared_ptr<ProtonSenderBase> sender = std::make_shared<ProtonThreadBase::ProtonSenderBase>(replyTo);
188 for(
auto rb : mReceivers)
192 for(
auto sb : mSenders)
201 InfoLog(<<
"ProtonThreadBase::on_connection_open");
209 for(
auto rb : mReceivers)
211 if(rb->mReceiver == r)
213 InfoLog(<<
"receiver ready for queue " << rb->mUrl);
214 rb->mWorkQueue = &rb->mReceiver.work_queue();
218 ErrLog(<<
"unexpected receiver: " << r);
230 for(
auto sb : mSenders)
234 InfoLog(<<
"sender ready for queue " << sb->mUrl);
235 sb->mWorkQueue = &s.work_queue();
240 ErrLog(<<
"unexpected sender: " << s);
252 WarningLog(<<
"transport closed unexpectedly, reason: " << t.error());
258 const proton::receiver& r = d.receiver();
259 for(
auto rb : mReceivers)
261 if(rb->mReceiver == r)
263 const proton::timestamp::numeric_type& ct = m.creation_time().milliseconds();
264 StackLog(<<
"message creation time (ms): " << ct);
265 if(ct > 0 && rb->mMaximumAge > (std::chrono::duration<long int>::zero()))
267 const proton::timestamp::numeric_type threshold =
ResipClock::getTimeMs() - std::chrono::milliseconds(rb->mMaximumAge).count();
270 DebugLog(<<
"dropping a message because it is too old: " << threshold - ct <<
"ms");
279 ErrLog(<<
"unexpected receiver: " << r);
282std::unique_ptr<json::Object>
285 std::unique_ptr<json::Object> result;
290 _json = proton::get<std::string>(m.body());
292 catch(proton::conversion_error& ex)
294 ErrLog(<<
"failed to extract message body as string: " << ex.what());
297 StackLog(<<
"on_message received: " << _json);
298 std::stringstream stream;
302 json::Object* __json =
new json::Object();
305 ErrLog(<<
"failed to allocate new json::Object()");
308 result.reset(__json);
311 json::Reader::Read(*result, stream);
313 catch(json::Reader::ScanException& ex)
315 ErrLog(<<
"failed to scan JSON message: " << ex.what() <<
" message body: " << _json);
326 for(
auto sb : mSenders)
336ProtonThreadBase::checkSenderShutdown()
338 bool nothingOutstanding =
true;
339 for(
auto sb : mSenders)
341 if(sb->mFifo.messageAvailable() || sb->mPending > 0)
343 nothingOutstanding =
false;
349 StackLog(<<
"no more messages outstanding, shutting down");
358 for(
auto sb : mSenders)
360 if(sb->mSender == t.sender())
362 StackLog(<<
"on_tracker_accept: mPending = " << --sb->mPending);
366 if(checkSenderShutdown())
368 StackLog(<<
"no more messages outstanding, shutting down");
380 mContainer.reset(
new proton::container(*
this));
385 ErrLog(<<
"ProtonThreadBase::thread container threw " << e.what());
389 WarningLog(<<
"Proton container stopped unexpectedly, sleeping for " << std::chrono::milliseconds(mRetryDelay).count() <<
"ms before attempting to restart container");
390 std::this_thread::sleep_for(mRetryDelay);
394 InfoLog(<<
"ProtonThreadBase::thread container stopped");
402 DebugLog(<<
"shutdown already in progress!");
405 DebugLog(<<
"trying to shutdown the Qpid Proton container");
407 if(!checkSenderShutdown())
411 if(!mReceivers.empty())
413 if(mReceivers.front()->mWorkQueue)
415 mReceivers.front()->mWorkQueue->add(make_work(&ProtonThreadBase::doShutdown,
this));
422ProtonThreadBase::doShutdown()
#define WarningLog(args_)
An alternative to std::string, encapsulates an arbitrary buffer of bytes.
std::unique_ptr< json::Object > getBodyAsJSON(const proton::message &m)
ProtonReceiverBase(const std::string &u, std::chrono::duration< long int > maximumAge, std::chrono::duration< long int > retryDelay)
virtual ~ProtonReceiverBase()
virtual ~ProtonSenderBase()
void sendMessage(const resip::Data &msg)
ProtonSenderBase(const std::string &u, std::chrono::duration< long int > retryDelay=std::chrono::seconds(2))
void on_transport_error(proton::transport &t) override
void on_sender_close(proton::sender &) override
std::shared_ptr< ProtonSenderBase > getSenderForReply(const std::string &replyTo)
void on_sender_open(proton::sender &) override
void on_receiver_close(proton::receiver &) override
ProtonThreadBase(std::chrono::duration< long int > mRetryDelay=std::chrono::seconds(2))
void on_connection_open(proton::connection &conn) override
virtual ~ProtonThreadBase()
void addReceiver(std::shared_ptr< ProtonReceiverBase > rx)
void on_tracker_accept(proton::tracker &t) override
void on_container_start(proton::container &c) override
void on_receiver_open(proton::receiver &) override
void on_sendable(proton::sender &s) override
void addSender(std::shared_ptr< ProtonSenderBase > tx)
virtual void shutdown() override
virtual void thread() override
void on_message(proton::delivery &d, proton::message &m) override
static uint64_t getTimeMs()
Returns the current clock time in milliseconds.
dcm! – add UnusedChecking(_enum) below;