We cleaned up the code a good bit. It's much clearer what's going on
and no funny business now. No race conditions! We leverage Qt's atomic
signal/slot disconnects on object destruction to manage everything for
us.
Templates are fun. Decided to reduce boilerplate by making task
creation inside the Controller class be done by a template member
function which acts like a task factory. It surrounds the construction
of the task with some boilerplate (namely, inserting the task in the
tasks map, connecting an optional errored signal, and starting the
task).
Also in this commit various nits and subtle bugs prevented.
Refactored the 'Stats' mechanism to return a generic QVariant rather
than QVariantMap, which is more flexible.
Misc. other nits.
Set maxcur to 16, spinning up 3 bitcoind threads.
Seems to have brought header synch down from 170s to 71s on my mainnet
node here locally. Not bad!
Also fixed a bug where selecting bitcoind nodes was failing if >2 nodes.
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).
Playing with lambdas. Detects when bitcoind goes down. Initial code --
can put hooks in the detection for eg. stopping block processing or
starting it, etc.
Controller will manage BitcoinD and perhaps synching to bitcoind. It can
"see" all the servers as well as bitcoind.
Also refactored things a little bit and added some more startup sanity
checks.
Finally, after 20 years, I figured out how to do this. Diamond-patter
multiple inheritence is tricky. Downcasting from a Base to a Derived
must be unambiguous, for one (thus you need virtual when inheriting the
base).
Secondly -- it must all be public all the way down to the concrete
class!
This is subtle. I suppose the Base cannot see the Derived class
inherits it per C++ rules if not publicly inherited. TIL.
https://en.cppreference.com/w/cpp/language/dynamic_cast#Explanation
Also wrote a virtual methd 'getStats()' for AbstractConnection which
puts some basic stats into a QVariantMap for the /stats endpoint.
Subclasses can call the base implementation and add their own stats to
the returned map.
Also in this commit: misc refactoring and nits
Basically it's not called on app exit. We made it so it's not so crucial
it be called for cleanup.
Also added some preliminary stats to the http /stats endpoint for the
BitcoinD instances.