Fulcrum/Controller.cpp
Calin Culianu f4091bb005
Devised a scheme for asynch messaging to bitcoind
And added some test code in Controller to use the scheme.

It's very asynchronous.  Needs some tuning long term to see how it deals
with load and perhaps throttle the requests if we know bitcoind is under
load.

But for right now, for testing, it should work ok.

Also in this commit small nits, plus bugfix to RPC::Message factory
methods (I forgot to populate some instance properties when constructing
the objects).

Additionally, we were registering the qMetaType wrong for RPC::Message
and RPC::Message::Id (this has been fixed).
2019-11-18 14:32:48 +02:00

81 lines
3.3 KiB
C++

#include "Controller.h"
Controller::Controller(const std::shared_ptr<Options> &o)
: Mgr(nullptr), options(o)
{
setObjectName("Controller");
_thread.setObjectName(objectName());
}
Controller::~Controller() { Debug(__FUNCTION__); cleanup(); }
auto Controller::stats() const -> Stats
{
auto st = srvmgr->statsSafe();
Util::updateMap(st, bitcoindmgr->statsSafe());
return st;
}
void Controller::startup()
{
bitcoindmgr = std::make_unique<BitcoinDMgr>(options->bitcoind.first, options->bitcoind.second, options->rpcuser, options->rpcpassword);
{
// some setup code that waits for bitcoind to be ready before kicking off our "process" method
auto waitForBitcoinD = [this] {
auto constexpr waitTimer = "wait4bitcoind", callProcessTimer = "callProcess";
int constexpr msgPeriod = 10000, // 10sec
smallDelay = 100;
stopTimer(callProcessTimer);
callOnTimerSoon(msgPeriod, waitTimer, []{ Log("Waiting for bitcoind..."); return true; }, false, Qt::TimerType::VeryCoarseTimer);
// connection to kick off our 'process' method once the first auth is received
auto connPtr = std::make_shared<QMetaObject::Connection>();
*connPtr = connect(bitcoindmgr.get(), &BitcoinDMgr::gotFirstGoodConnection, this, [this, connPtr](quint64 id) mutable {
if (connPtr) {
stopTimer(waitTimer);
if (!disconnect(*connPtr)) Fatal() << "Failed to disconnect 'authenticated' signal! FIXME!"; // this should never happen but if it does, app quits.
connPtr.reset(); // clear connPtr right away to 1. delte it asap and 2. so we are guaranteed not to reenter this block for this connection should there be a spurious signal emitted.
Debug() << "Auth recvd from bicoind with id: " << id << ", proceeding with processing ...";
callOnTimerSoonNoRepeat(smallDelay, callProcessTimer, [this]{process();}, true);
}
});
};
waitForBitcoinD();
conns += connect(bitcoindmgr.get(), &BitcoinDMgr::allConnectionsLost, this, waitForBitcoinD);
}
bitcoindmgr->startup(); // may throw
srvmgr = std::make_unique<SrvMgr>(options->interfaces, nullptr /* we are not parent so it won't follow us to our thread*/);
srvmgr->startup(); // may throw Exception, waits for servers to bind
start(); // start our thread
}
void Controller::cleanup()
{
stop();
if (srvmgr) { Log("Stopping SrvMgr ... "); srvmgr->cleanup(); srvmgr.reset(); }
if (bitcoindmgr) { Log("Stopping BitcoinDMgr ... "); bitcoindmgr->cleanup(); bitcoindmgr.reset(); }
sm.reset();
}
struct Controller::StateMachine
{
// TODO: put state stuff here
};
void Controller::process()
{
Debug() << "Process called...";
if (!sm) sm = std::make_unique<StateMachine>(); // create statemachine if doest not exist
bitcoindmgr->submitRequest(this, IdMixin::newId(), "getmempoolinfo", {}, [](auto resp){ // testing
Trace() << resp.id.toString() << ": result reply: " << resp.toJsonString();
}, [](auto resp){
Trace() << resp.id.toString() << ": error response: " << resp.toJsonString();
}, [](auto id, auto msg) {
Warning() << id.toString() << ": FAIL: " << msg;
});
}