#ifndef RPCCLIENT_H #define RPCCLIENT_H #include "precompiled.h" #include "unspentoutput.h" #include "balancestablemodel.h" #include "txtablemodel.h" #include "ui_mainwindow.h" #include "mainwindow.h" using json = nlohmann::json; struct TransactionItem { QString type; unsigned long datetime; QString address; QString txid; double amount; unsigned long confirmations; QString fromAddr; }; class RPC { public: RPC(QNetworkAccessManager* restclient, MainWindow* main); ~RPC(); void refresh(); // Refresh all transactions void refreshAddresses(); // Refresh wallet Z-addrs void refreshZECPrice(); void fillTxJsonParams(json& params, Tx tx); void sendZTransaction (json params, const std::function& cb); void watchTxStatus(); void addNewTxToWatch(Tx tx, const QString& newOpid); BalancesTableModel* getBalancesModel() { return balancesTableModel; } const QList* getAllZAddresses() { return zaddresses; } const QList* getUTXOs() { return utxos; } const QMap* getAllBalances() { return allBalances; } void reloadConnectionInfo(); void newZaddr (bool sapling, const std::function& cb); void newTaddr (const std::function& cb); // Batch method. Note: Because of the template, it has to be in the header file. template void getBatchRPC(const QList& payloads, std::function payloadGenerator, std::function*)> cb) { auto responses = new QMap(); // zAddr -> list of responses for each call. int totalSize = payloads.size(); for (auto item: payloads) { json payload = payloadGenerator(item); QNetworkReply *reply = restclient->post(request, QByteArray::fromStdString(payload.dump())); QObject::connect(reply, &QNetworkReply::finished, [=] { reply->deleteLater(); auto all = reply->readAll(); auto parsed = json::parse(all.toStdString(), nullptr, false); if (reply->error() != QNetworkReply::NoError) { qDebug() << QString::fromStdString(parsed.dump()); qDebug() << reply->errorString(); (*responses)[item] = json::object(); // Empty object } else { if (parsed.is_discarded()) { (*responses)[item] = json::object(); // Empty object } else { (*responses)[item] = parsed["result"]; } } }); } auto waitTimer = new QTimer(main); QObject::connect(waitTimer, &QTimer::timeout, [=]() { if (responses->size() == totalSize) { waitTimer->stop(); cb(responses); waitTimer->deleteLater(); } }); waitTimer->start(100); } private: void doRPC (const json& payload, const std::function& cb); void doSendRPC (const json& payload, const std::function& cb); void refreshBalances(); void refreshTransactions(); void refreshSentZTrans (); void refreshReceivedZTrans (QList zaddresses); bool processUnspent (const json& reply); void updateUI (bool anyUnconfirmed); void getInfoThenRefresh(); void getBalance(const std::function& cb); void getTransparentUnspent (const std::function& cb); void getZUnspent (const std::function& cb); void getTransactions (const std::function& cb); void getZAddresses (const std::function& cb); void handleConnectionError (const QString& error); void handleTxError (const QString& error); QNetworkAccessManager* restclient; QNetworkRequest request; QList* utxos = nullptr; QMap* allBalances = nullptr; QList* zaddresses = nullptr; QMap watchingOps; TxTableModel* transactionsTableModel = nullptr; BalancesTableModel* balancesTableModel = nullptr; QTimer* timer; QTimer* txTimer; QTimer* priceTimer; Ui::MainWindow* ui; MainWindow* main; // Current balance in the UI. If this number updates, then refresh the UI QString currentBalance; // First time warning flag for no connection bool firstTime = true; }; #endif // RPCCLIENT_H