diff --git a/lib/src/lib.rs b/lib/src/lib.rs index 733862e..c76bf1b 100644 --- a/lib/src/lib.rs +++ b/lib/src/lib.rs @@ -18,7 +18,7 @@ lazy_static! { // Initialize a new lightclient and store its value #[no_mangle] -pub extern fn initialze(dangerous: bool, server: *const c_char) -> *mut c_char { +pub extern fn litelib_initialze(dangerous: bool, server: *const c_char) -> *mut c_char { let server_str = unsafe { assert!(!server.is_null()); @@ -49,7 +49,7 @@ pub extern fn initialze(dangerous: bool, server: *const c_char) -> *mut c_char { } #[no_mangle] -pub extern fn execute(cmd: *const c_char) -> *mut c_char { +pub extern fn litelib_execute(cmd: *const c_char) -> *mut c_char { let cmd_str = unsafe { assert!(!cmd.is_null()); @@ -77,7 +77,7 @@ pub extern fn execute(cmd: *const c_char) -> *mut c_char { * back to rust, so it can be freed. Failure to call this function will result in a memory leak */ #[no_mangle] -pub extern fn rust_free_string(s: *mut c_char) { +pub extern fn litelib_rust_free_string(s: *mut c_char) { unsafe { if s.is_null() { return } CString::from_raw(s) diff --git a/lib/zecwalletlitelib.h b/lib/zecwalletlitelib.h index 48c8d4f..5c639da 100644 --- a/lib/zecwalletlitelib.h +++ b/lib/zecwalletlitelib.h @@ -1,4 +1,3 @@ - #ifndef _ZEC_PAPER_RUST_H #define _ZEC_PAPER_RUST_H @@ -6,9 +5,9 @@ extern "C"{ #endif -extern char * initialze (bool dangerous, const char* server); -extern char * execute (char* s); -extern void rust_free_string (char* s); +extern char * litelib_initialze (bool dangerous, const char* server); +extern char * litelib_execute (char* s); +extern void litelib_rust_free_string (char* s); #ifdef __cplusplus } diff --git a/src/connection.cpp b/src/connection.cpp index 020ad57..9fbdc12 100644 --- a/src/connection.cpp +++ b/src/connection.cpp @@ -5,6 +5,8 @@ #include "ui_createzcashconfdialog.h" #include "controller.h" +#include "../lib/zecwalletlitelib.h" + #include "precompiled.h" using json = nlohmann::json; @@ -32,15 +34,24 @@ void ConnectionLoader::loadConnection() { } void ConnectionLoader::doAutoConnect(bool tryEzcashdStart) { - // Priority 1: Ensure all params are present. - if (!verifyParams()) { - downloadParams([=]() { this->doAutoConnect(); }); - return; - } + auto config = std::shared_ptr(new ConnectionConfig()); + config->dangerous = true; + config->server = QString("https://127.0.0.1:9067"); + + // Initialize the library + main->logger->write(QObject::tr("Attempting to initialize")); + litelib_initialze(config->dangerous, config->server.toStdString()); + auto connection = makeConnection(config); + + // After the lib is initialized, try to do get info + connection->doRPC("info", [=](auto reply) { + // If success, set the connection + d->hide(); + main->logger->write("Connection is online."); + this->doRPCSetConnection(connection); + }, [=](auto err, auto errJson) {}); + - // Priority 2: Try to connect to detect zcash.conf and connect to it. - auto config = autoDetectZcashConf(); - main->logger->write(QObject::tr("Attempting autoconnect")); if (config.get() != nullptr) { auto connection = makeConnection(config); @@ -106,318 +117,6 @@ void ConnectionLoader::doAutoConnect(bool tryEzcashdStart) { } } -QString randomPassword() { - static const char alphanum[] = - "0123456789" - "ABCDEFGHIJKLMNOPQRSTUVWXYZ" - "abcdefghijklmnopqrstuvwxyz"; - - const int passwordLength = 10; - char* s = new char[passwordLength + 1]; - - for (int i = 0; i < passwordLength; ++i) { - s[i] = alphanum[randombytes_uniform(sizeof(alphanum))]; - } - - s[passwordLength] = 0; - return QString::fromStdString(s); -} - -/** - * This will create a new zcash.conf, download Zcash parameters. - */ -void ConnectionLoader::createZcashConf() { - main->logger->write("createZcashConf"); - - auto confLocation = zcashConfWritableLocation(); - QFileInfo fi(confLocation); - - QDialog d(main); - Ui_createZcashConf ui; - ui.setupUi(&d); - - QPixmap logo(":/img/res/zcashdlogo.gif"); - ui.lblTopIcon->setBasePixmap(logo.scaled(256, 256, Qt::KeepAspectRatio, Qt::SmoothTransformation)); - ui.btnPickDir->setEnabled(false); - - ui.grpAdvanced->setVisible(false); - QObject::connect(ui.btnAdvancedConfig, &QPushButton::toggled, [=](bool isVisible) { - ui.grpAdvanced->setVisible(isVisible); - ui.btnAdvancedConfig->setText(isVisible ? QObject::tr("Hide Advanced Config") : QObject::tr("Show Advanced Config")); - }); - - QObject::connect(ui.chkCustomDatadir, &QCheckBox::stateChanged, [=](int chked) { - if (chked == Qt::Checked) { - ui.btnPickDir->setEnabled(true); - } - else { - ui.btnPickDir->setEnabled(false); - } - }); - - QObject::connect(ui.btnPickDir, &QPushButton::clicked, [=]() { - auto datadir = QFileDialog::getExistingDirectory(main, QObject::tr("Choose data directory"), ui.lblDirName->text(), QFileDialog::ShowDirsOnly); - if (!datadir.isEmpty()) { - ui.lblDirName->setText(QDir::toNativeSeparators(datadir)); - } - }); - - // Show the dialog - QString datadir = ""; - bool useTor = false; - if (d.exec() == QDialog::Accepted) { - datadir = ui.lblDirName->text(); - useTor = ui.chkUseTor->isChecked(); - if (!ui.chkAllowInternet->isChecked()) { - Settings::getInstance()->setAllowFetchPrices(false); - Settings::getInstance()->setCheckForUpdates(false); - } - } - - main->logger->write("Creating file " + confLocation); - QDir().mkdir(fi.dir().absolutePath()); - - QFile file(confLocation); - if (!file.open(QIODevice::ReadWrite | QIODevice::Truncate)) { - main->logger->write("Could not create zcash.conf, returning"); - return; - } - - QTextStream out(&file); - - out << "server=1\n"; - out << "addnode=mainnet.z.cash\n"; - out << "rpcuser=zec-qt-wallet\n"; - out << "rpcpassword=" % randomPassword() << "\n"; - - // Fast sync override - if (ui.chkFastSync->isChecked()) { - out << "ibdskiptxverification=1\n"; - } - - // Datadir override - if (!datadir.isEmpty()) { - out << "datadir=" % datadir % "\n"; - } - - // Tor override - if (useTor) { - out << "proxy=127.0.0.1:9050\n"; - } - - file.close(); - - // Now that zcash.conf exists, try to autoconnect again - this->doAutoConnect(); -} - - -void ConnectionLoader::downloadParams(std::function cb) { - main->logger->write("Adding params to download queue"); - // Add all the files to the download queue - downloadQueue = new QQueue(); - client = new QNetworkAccessManager(main); - - downloadQueue->enqueue(QUrl("https://z.cash/downloads/sapling-output.params")); - downloadQueue->enqueue(QUrl("https://z.cash/downloads/sapling-spend.params")); - downloadQueue->enqueue(QUrl("https://z.cash/downloads/sprout-proving.key")); - downloadQueue->enqueue(QUrl("https://z.cash/downloads/sprout-verifying.key")); - downloadQueue->enqueue(QUrl("https://z.cash/downloads/sprout-groth16.params")); - - doNextDownload(cb); -} - -void ConnectionLoader::doNextDownload(std::function cb) { - auto fnSaveFileName = [&] (QUrl url) { - QString path = url.path(); - QString basename = QFileInfo(path).fileName(); - - return basename; - }; - - if (downloadQueue->isEmpty()) { - delete downloadQueue; - client->deleteLater(); - - main->logger->write("All Downloads done"); - this->showInformation(QObject::tr("All Downloads Finished Successfully!")); - cb(); - return; - } - - QUrl url = downloadQueue->dequeue(); - int filesRemaining = downloadQueue->size(); - - QString filename = fnSaveFileName(url); - QString paramsDir = zcashParamsDir(); - - if (QFile(QDir(paramsDir).filePath(filename)).exists()) { - main->logger->write(filename + " already exists, skipping"); - doNextDownload(cb); - - return; - } - - // The downloaded file is written to a new name, and then renamed when the operation completes. - currentOutput = new QFile(QDir(paramsDir).filePath(filename + ".part")); - - if (!currentOutput->open(QIODevice::WriteOnly)) { - main->logger->write("Couldn't open " + currentOutput->fileName() + " for writing"); - this->showError(QObject::tr("Couldn't download params. Please check the help site for more info.")); - } - main->logger->write("Downloading to " + filename); - qDebug() << "Downloading " << url << " to " << filename; - - QNetworkRequest request(url); - request.setAttribute(QNetworkRequest::FollowRedirectsAttribute, true); - currentDownload = client->get(request); - downloadTime.start(); - - // Download Progress - QObject::connect(currentDownload, &QNetworkReply::downloadProgress, [=] (auto done, auto total) { - // calculate the download speed - double speed = done * 1000.0 / downloadTime.elapsed(); - QString unit; - if (speed < 1024) { - unit = "bytes/sec"; - } else if (speed < 1024*1024) { - speed /= 1024; - unit = "kB/s"; - } else { - speed /= 1024*1024; - unit = "MB/s"; - } - - this->showInformation( - QObject::tr("Downloading ") % filename % (filesRemaining > 1 ? " ( +" % QString::number(filesRemaining) % QObject::tr(" more remaining )") : QString("")), - QString::number(done/1024/1024, 'f', 0) % QObject::tr("MB of ") % QString::number(total/1024/1024, 'f', 0) + QObject::tr("MB at ") % QString::number(speed, 'f', 2) % unit); - }); - - // Download Finished - QObject::connect(currentDownload, &QNetworkReply::finished, [=] () { - // Rename file - main->logger->write("Finished downloading " + filename); - currentOutput->rename(QDir(paramsDir).filePath(filename)); - - currentOutput->close(); - currentDownload->deleteLater(); - currentOutput->deleteLater(); - - if (currentDownload->error()) { - main->logger->write("Downloading " + filename + " failed"); - this->showError(QObject::tr("Downloading ") + filename + QObject::tr(" failed. Please check the help site for more info")); - } else { - doNextDownload(cb); - } - }); - - // Download new data available. - QObject::connect(currentDownload, &QNetworkReply::readyRead, [=] () { - currentOutput->write(currentDownload->readAll()); - }); -} - -bool ConnectionLoader::startEmbeddedZcashd() { - if (!Settings::getInstance()->useEmbedded()) - return false; - - main->logger->write("Trying to start embedded zcashd"); - - // Static because it needs to survive even after this method returns. - static QString processStdErrOutput; - - if (ezcashd != nullptr) { - if (ezcashd->state() == QProcess::NotRunning) { - if (!processStdErrOutput.isEmpty()) { - QMessageBox::critical(main, QObject::tr("zcashd error"), "zcashd said: " + processStdErrOutput, - QMessageBox::Ok); - } - return false; - } else { - return true; - } - } - - // Finally, start zcashd - QDir appPath(QCoreApplication::applicationDirPath()); -#ifdef Q_OS_LINUX - auto zcashdProgram = appPath.absoluteFilePath("zqw-zcashd"); - if (!QFile(zcashdProgram).exists()) { - zcashdProgram = appPath.absoluteFilePath("zcashd"); - } -#elif defined(Q_OS_DARWIN) - auto zcashdProgram = appPath.absoluteFilePath("zcashd"); -#else - auto zcashdProgram = appPath.absoluteFilePath("zcashd.exe"); -#endif - - if (!QFile(zcashdProgram).exists()) { - qDebug() << "Can't find zcashd at " << zcashdProgram; - main->logger->write("Can't find zcashd at " + zcashdProgram); - return false; - } - - ezcashd = new QProcess(main); - QObject::connect(ezcashd, &QProcess::started, [=] () { - //qDebug() << "zcashd started"; - }); - - QObject::connect(ezcashd, QOverload::of(&QProcess::finished), - [=](int, QProcess::ExitStatus) { - //qDebug() << "zcashd finished with code " << exitCode << "," << exitStatus; - }); - - QObject::connect(ezcashd, &QProcess::errorOccurred, [&] (auto) { - //qDebug() << "Couldn't start zcashd: " << error; - }); - - QObject::connect(ezcashd, &QProcess::readyReadStandardError, [=]() { - auto output = ezcashd->readAllStandardError(); - main->logger->write("zcashd stderr:" + output); - processStdErrOutput.append(output); - }); - -#ifdef Q_OS_LINUX - ezcashd->start(zcashdProgram); -#elif defined(Q_OS_DARWIN) - ezcashd->start(zcashdProgram); -#else - ezcashd->setWorkingDirectory(appPath.absolutePath()); - ezcashd->start("zcashd.exe"); -#endif // Q_OS_LINUX - - - return true; -} - -void ConnectionLoader::doManualConnect() { - auto config = loadFromSettings(); - - if (!config) { - // Nothing configured, show an error - QString explanation = QString() - % QObject::tr("A manual connection was requested, but the settings are not configured.\n\n" - "Please set the host/port and user/password in the Edit->Settings menu."); - - showError(explanation); - doRPCSetConnection(nullptr); - - return; - } - - auto connection = makeConnection(config); - refreshZcashdState(connection, [=] () { - QString explanation = QString() - % QObject::tr("Could not connect to zcashd configured in settings.\n\n" - "Please set the host/port and user/password in the Edit->Settings menu."); - - showError(explanation); - doRPCSetConnection(nullptr); - - return; - }); -} - void ConnectionLoader::doRPCSetConnection(Connection* conn) { rpc->setEZcashd(ezcashd); rpc->setConnection(conn); @@ -428,69 +127,7 @@ void ConnectionLoader::doRPCSetConnection(Connection* conn) { } Connection* ConnectionLoader::makeConnection(std::shared_ptr config) { - QNetworkAccessManager* client = new QNetworkAccessManager(main); - - QUrl myurl; - myurl.setScheme("http"); - myurl.setHost(config.get()->host); - myurl.setPort(config.get()->port.toInt()); - - QNetworkRequest* request = new QNetworkRequest(); - request->setUrl(myurl); - request->setHeader(QNetworkRequest::ContentTypeHeader, "text/plain"); - - QString userpass = config.get()->rpcuser % ":" % config.get()->rpcpassword; - QString headerData = "Basic " + userpass.toLocal8Bit().toBase64(); - request->setRawHeader("Authorization", headerData.toLocal8Bit()); - - return new Connection(main, client, request, config); -} - -void ConnectionLoader::refreshZcashdState(Connection* connection, std::function refused) { - json payload = { - {"jsonrpc", "1.0"}, - {"id", "someid"}, - {"method", "getinfo"} - }; - connection->doRPC(payload, - [=] (auto) { - // Success, hide the dialog if it was shown. - d->hide(); - main->logger->write("zcashd is online."); - this->doRPCSetConnection(connection); - }, - [=] (auto reply, auto res) { - // Failed, see what it is. - auto err = reply->error(); - //qDebug() << err << ":" << QString::fromStdString(res.dump()); - - if (err == QNetworkReply::NetworkError::ConnectionRefusedError) { - refused(); - } else if (err == QNetworkReply::NetworkError::AuthenticationRequiredError) { - main->logger->write("Authentication failed"); - QString explanation = QString() % - QObject::tr("Authentication failed. The username / password you specified was " - "not accepted by zcashd. Try changing it in the Edit->Settings menu"); - - this->showError(explanation); - } else if (err == QNetworkReply::NetworkError::InternalServerError && - !res.is_discarded()) { - // The server is loading, so just poll until it succeeds - QString status = QString::fromStdString(res["error"]["message"]); - { - static int dots = 0; - status = status.left(status.length() - 3) + QString(".").repeated(dots); - dots++; - if (dots > 3) - dots = 0; - } - this->showInformation(QObject::tr("Your zcashd is starting up. Please wait."), status); - main->logger->write("Waiting for zcashd to come online."); - // Refresh after one second - QTimer::singleShot(1000, [=]() { this->refreshZcashdState(connection, refused); }); - } - } - ); + return new Connection(main, config); } // Update the UI with the status @@ -522,204 +159,42 @@ void ConnectionLoader::showError(QString explanation) { d->close(); } -QString ConnectionLoader::locateZcashConfFile() { -#ifdef Q_OS_LINUX - auto confLocation = QStandardPaths::locate(QStandardPaths::HomeLocation, ".zcash/zcash.conf"); -#elif defined(Q_OS_DARWIN) - auto confLocation = QStandardPaths::locate(QStandardPaths::HomeLocation, "Library/Application Support/Zcash/zcash.conf"); -#else - auto confLocation = QStandardPaths::locate(QStandardPaths::AppDataLocation, "../../Zcash/zcash.conf"); -#endif - - main->logger->write("Found zcashconf at " + QDir::cleanPath(confLocation)); - return QDir::cleanPath(confLocation); -} - -QString ConnectionLoader::zcashConfWritableLocation() { -#ifdef Q_OS_LINUX - auto confLocation = QDir(QStandardPaths::writableLocation(QStandardPaths::HomeLocation)).filePath(".zcash/zcash.conf"); -#elif defined(Q_OS_DARWIN) - auto confLocation = QDir(QStandardPaths::writableLocation(QStandardPaths::HomeLocation)).filePath("Library/Application Support/Zcash/zcash.conf"); -#else - auto confLocation = QDir(QStandardPaths::writableLocation(QStandardPaths::AppDataLocation)).filePath("../../Zcash/zcash.conf"); -#endif - - main->logger->write("Found zcashconf at " + QDir::cleanPath(confLocation)); - return QDir::cleanPath(confLocation); -} - -QString ConnectionLoader::zcashParamsDir() { - #ifdef Q_OS_LINUX - auto paramsLocation = QDir(QDir(QStandardPaths::writableLocation(QStandardPaths::HomeLocation)).filePath(".zcash-params")); -#elif defined(Q_OS_DARWIN) - auto paramsLocation = QDir(QDir(QStandardPaths::writableLocation(QStandardPaths::HomeLocation)).filePath("Library/Application Support/ZcashParams")); -#else - auto paramsLocation = QDir(QDir(QStandardPaths::writableLocation(QStandardPaths::AppDataLocation)).filePath("../../ZcashParams")); -#endif - - if (!paramsLocation.exists()) { - main->logger->write("Creating params location at " + paramsLocation.absolutePath()); - QDir().mkpath(paramsLocation.absolutePath()); - } - - main->logger->write("Found Zcash params directory at " + paramsLocation.absolutePath()); - return paramsLocation.absolutePath(); -} - -bool ConnectionLoader::verifyParams() { - QDir paramsDir(zcashParamsDir()); - - if (!QFile(paramsDir.filePath("sapling-output.params")).exists()) return false; - if (!QFile(paramsDir.filePath("sapling-spend.params")).exists()) return false; - if (!QFile(paramsDir.filePath("sprout-proving.key")).exists()) return false; - if (!QFile(paramsDir.filePath("sprout-verifying.key")).exists()) return false; - if (!QFile(paramsDir.filePath("sprout-groth16.params")).exists()) return false; - - return true; -} - -/** - * Try to automatically detect a zcash.conf file in the correct location and load parameters - */ -std::shared_ptr ConnectionLoader::autoDetectZcashConf() { - auto confLocation = Settings::getInstance()->getZcashdConfLocation(); - - if (confLocation.isEmpty()) { - confLocation = locateZcashConfFile(); - } - - if (confLocation.isNull()) { - // No Zcash file, just return with nothing - return nullptr; - } - - QFile file(confLocation); - if (!file.open(QIODevice::ReadOnly)) { - qDebug() << file.errorString(); - return nullptr; - } - - QTextStream in(&file); - - auto zcashconf = new ConnectionConfig(); - zcashconf->host = "127.0.0.1"; - zcashconf->connType = ConnectionType::DetectedConfExternalZcashD; - zcashconf->usingZcashConf = true; - zcashconf->zcashDir = QFileInfo(confLocation).absoluteDir().absolutePath(); - zcashconf->zcashDaemon = false; - - Settings::getInstance()->setUsingZcashConf(confLocation); - - while (!in.atEnd()) { - QString line = in.readLine(); - auto s = line.indexOf("="); - QString name = line.left(s).trimmed().toLower(); - QString value = line.right(line.length() - s - 1).trimmed(); - - if (name == "rpcuser") { - zcashconf->rpcuser = value; - } - if (name == "rpcpassword") { - zcashconf->rpcpassword = value; - } - if (name == "rpcport") { - zcashconf->port = value; - } - if (name == "daemon" && value == "1") { - zcashconf->zcashDaemon = true; - } - if (name == "proxy") { - zcashconf->proxy = value; - } - if (name == "testnet" && - value == "1" && - zcashconf->port.isEmpty()) { - zcashconf->port = "18232"; - } - if (name == "ibdskiptxverification" && value == "1") { - zcashconf->skiptxverification = true; - } - } - - // If rpcport is not in the file, and it was not set by the testnet=1 flag, then go to default - if (zcashconf->port.isEmpty()) zcashconf->port = "8232"; - file.close(); - - // In addition to the zcash.conf file, also double check the params. - - return std::shared_ptr(zcashconf); -} - -/** - * Load connection settings from the UI, which indicates an unknown, external zcashd - */ -std::shared_ptr ConnectionLoader::loadFromSettings() { - // Load from the QT Settings. - QSettings s; - - auto host = s.value("connection/host").toString(); - auto port = s.value("connection/port").toString(); - auto username = s.value("connection/rpcuser").toString(); - auto password = s.value("connection/rpcpassword").toString(); +void Executor::run() { + const char* resp = litelib_execute(this->cmd.toStdString().c_str()); + QString reply = QString::fromStdString(resp); + litelib_rust_free_string(resp); - if (username.isEmpty() || password.isEmpty()) - return nullptr; + auto parsed = json::parse(reply.toStdString().c_str(), nullptr, false); - auto uiConfig = new ConnectionConfig{ host, port, username, password, false, false, false, "", "", ConnectionType::UISettingsZCashD}; - - return std::shared_ptr(uiConfig); + emit responseReady(parsed); } - - /*********************************************************************************** * Connection Class ************************************************************************************/ -Connection::Connection(MainWindow* m, QNetworkAccessManager* c, QNetworkRequest* r, - std::shared_ptr conf) { - this->restclient = c; - this->request = r; +Connection::Connection(MainWindow* m, std::shared_ptr conf) { this->config = conf; this->main = m; } -Connection::~Connection() { - delete restclient; - delete request; +Connection::~Connection() { } -void Connection::doRPC(const json& payload, const std::function& cb, +void Connection::doRPC(const QString cmd, const QString args, const std::function& cb, const std::function& ne) { if (shutdownInProgress) { // Ignoring RPC because shutdown in progress return; } - QNetworkReply *reply = restclient->post(*request, QByteArray::fromStdString(payload.dump())); - - QObject::connect(reply, &QNetworkReply::finished, [=] { - reply->deleteLater(); - if (shutdownInProgress) { - // Ignoring callback because shutdown in progress - return; - } - - if (reply->error() != QNetworkReply::NoError) { - auto parsed = json::parse(reply->readAll(), nullptr, false); - ne(reply, parsed); - - return; - } - - auto parsed = json::parse(reply->readAll(), nullptr, false); - if (parsed.is_discarded()) { - ne(reply, "Unknown error"); - } - - cb(parsed["result"]); - }); + // Create a runner. + auto runner = new Executor(cmd, args); + QObject::connect(runner, &Executor::responseReady, [=] (json resp) { + cb(resp); + }) + QThreadPool::globalInstance()->start(runner); } void Connection::doRPCWithDefaultErrorHandling(const json& payload, const std::function& cb) { diff --git a/src/connection.h b/src/connection.h index 51bac1f..aceead3 100644 --- a/src/connection.h +++ b/src/connection.h @@ -9,24 +9,9 @@ using json = nlohmann::json; class Controller; -enum ConnectionType { - DetectedConfExternalZcashD = 1, - UISettingsZCashD, - InternalZcashD -}; - struct ConnectionConfig { - QString host; - QString port; - QString rpcuser; - QString rpcpassword; - bool usingZcashConf; - bool zcashDaemon; - bool skiptxverification; - QString zcashDir; - QString proxy; - - ConnectionType connType; + QString server; + bool dangerous; }; class Connection; @@ -81,17 +66,35 @@ private: QTime downloadTime; }; +class Executor : public QRunnable { +public: + Executor(QString cmd, QString args) { + this->cmd = cmd; + this->args = args; + }; + + ~Executor() = default; + bool autoDelete() const { return true; } + + virtual void run(); + +signals: + void responseReady(json); + +private: + QString cmd; + QString args; +} + /** * Represents a connection to a zcashd. It may even start a new zcashd if needed. * This is also a UI class, so it may show a dialog waiting for the connection. */ -class Connection { +class Connection : public QObject { public: - Connection(MainWindow* m, QNetworkAccessManager* c, QNetworkRequest* r, std::shared_ptr conf); + Connection(MainWindow* m, std::shared_ptr conf); ~Connection(); - QNetworkAccessManager* restclient; - QNetworkRequest* request; std::shared_ptr config; MainWindow* main;