Merge pull request #492

8021037 pause refresh while starting daemon + startup timeout (Jaquee)
df60c81 add start/pauseRefresh() (Jaquee)
2ed59f4 Daemon manager improvements (Jaquee)
This commit is contained in:
Riccardo Spagni 2017-02-27 22:29:33 +02:00
commit 75bb620cb6
No known key found for this signature in database
GPG key ID: 55432DF31CCD4FCD
6 changed files with 130 additions and 14 deletions

View file

@ -236,7 +236,6 @@ ApplicationWindow {
} }
function connectWallet(wallet) { function connectWallet(wallet) {
showProcessingSplash("Please wait...")
currentWallet = wallet currentWallet = wallet
updateSyncing(false) updateSyncing(false)
@ -342,9 +341,6 @@ ApplicationWindow {
function onWalletRefresh() { function onWalletRefresh() {
console.log(">>> wallet refreshed") console.log(">>> wallet refreshed")
if (splash.visible) {
hideProcessingSplash()
}
// Daemon connected // Daemon connected
leftPanel.networkStatus.connected = currentWallet.connected() leftPanel.networkStatus.connected = currentWallet.connected()
@ -385,6 +381,9 @@ ApplicationWindow {
} }
function startDaemon(flags){ function startDaemon(flags){
// Pause refresh while starting daemon
currentWallet.pauseRefresh();
appWindow.showProcessingSplash(qsTr("Waiting for daemon to start...")) appWindow.showProcessingSplash(qsTr("Waiting for daemon to start..."))
daemonManager.start(flags, persistentSettings.testnet); daemonManager.start(flags, persistentSettings.testnet);
persistentSettings.daemonFlags = flags persistentSettings.daemonFlags = flags
@ -399,6 +398,9 @@ ApplicationWindow {
console.log("daemon started"); console.log("daemon started");
daemonRunning = true; daemonRunning = true;
hideProcessingSplash(); hideProcessingSplash();
currentWallet.connected(true);
// resume refresh
currentWallet.startRefresh();
} }
function onDaemonStopped(){ function onDaemonStopped(){
console.log("daemon stopped"); console.log("daemon stopped");
@ -407,6 +409,19 @@ ApplicationWindow {
currentWallet.connected(true); currentWallet.connected(true);
} }
function onDaemonStartFailure(){
console.log("daemon start failed");
hideProcessingSplash();
// resume refresh
currentWallet.startRefresh();
daemonRunning = false;
informationPopup.title = qsTr("Daemon failed to start") + translationManager.emptyString;
informationPopup.text = qsTr("Please check your wallet and daemon log for errors. You can also try to start %1 manually.").arg((isWindows)? "monerod.exe" : "monerod")
informationPopup.icon = StandardIcon.Critical
informationPopup.onCloseCallback = null
informationPopup.open();
}
function onWalletNewBlock(blockHeight, targetHeight) { function onWalletNewBlock(blockHeight, targetHeight) {
// Update progress bar // Update progress bar
var remaining = targetHeight - blockHeight; var remaining = targetHeight - blockHeight;
@ -769,6 +784,7 @@ ApplicationWindow {
walletManager.walletClosed.connect(onWalletClosed); walletManager.walletClosed.connect(onWalletClosed);
daemonManager.daemonStarted.connect(onDaemonStarted); daemonManager.daemonStarted.connect(onDaemonStarted);
daemonManager.daemonStartFailure.connect(onDaemonStartFailure);
daemonManager.daemonStopped.connect(onDaemonStopped); daemonManager.daemonStopped.connect(onDaemonStopped);
if(!walletsFound()) { if(!walletsFound()) {
@ -1239,6 +1255,7 @@ ApplicationWindow {
} }
onClosing: { onClosing: {
// Close wallet non async on exit // Close wallet non async on exit
daemonManager.exit();
walletManager.closeWallet(); walletManager.closeWallet();
} }

View file

@ -407,7 +407,7 @@ Rectangle {
console.log("Settings page loaded"); console.log("Settings page loaded");
initSettings(); initSettings();
viewOnly = currentWallet.viewOnly; viewOnly = currentWallet.viewOnly;
daemonManager.running(persistentSettings.testnet) appWindow.daemonRunning = daemonManager.running(persistentSettings.testnet)
} }
// fires only once // fires only once

View file

@ -7,6 +7,11 @@
#include <QtConcurrent/QtConcurrent> #include <QtConcurrent/QtConcurrent>
#include <QApplication> #include <QApplication>
#include <QProcess> #include <QProcess>
#include <QTime>
namespace {
static const int DAEMON_START_TIMEOUT_SECONDS = 30;
}
DaemonManager * DaemonManager::m_instance = nullptr; DaemonManager * DaemonManager::m_instance = nullptr;
QStringList DaemonManager::m_clArgs; QStringList DaemonManager::m_clArgs;
@ -69,23 +74,93 @@ bool DaemonManager::start(const QString &flags, bool testnet)
if (!started) { if (!started) {
qDebug() << "Daemon start error: " + m_daemon->errorString(); qDebug() << "Daemon start error: " + m_daemon->errorString();
} else { emit daemonStartFailure();
emit daemonStarted(); return false;
} }
return started; // Start start watcher
QFuture<bool> future = QtConcurrent::run(this, &DaemonManager::startWatcher, testnet);
QFutureWatcher<bool> * watcher = new QFutureWatcher<bool>();
connect(watcher, &QFutureWatcher<bool>::finished,
this, [this, watcher]() {
QFuture<bool> future = watcher->future();
watcher->deleteLater();
if(future.result())
emit daemonStarted();
else
emit daemonStartFailure();
});
watcher->setFuture(future);
return true;
} }
bool DaemonManager::stop(bool testnet) bool DaemonManager::stop(bool testnet)
{ {
QString message; QString message;
bool stopped = sendCommand("exit",testnet,message); sendCommand("exit",testnet,message);
qDebug() << message; qDebug() << message;
if(stopped)
// Start stop watcher - Will kill if not shutting down
QFuture<bool> future = QtConcurrent::run(this, &DaemonManager::stopWatcher, testnet);
QFutureWatcher<bool> * watcher = new QFutureWatcher<bool>();
connect(watcher, &QFutureWatcher<bool>::finished,
this, [this, watcher]() {
QFuture<bool> future = watcher->future();
watcher->deleteLater();
if(future.result()) {
emit daemonStopped(); emit daemonStopped();
return stopped; }
});
watcher->setFuture(future);
return true;
} }
bool DaemonManager::startWatcher(bool testnet) const
{
// Check if daemon is started every 2 seconds
QTime timer;
timer.restart();
while(true && !m_app_exit && timer.elapsed() / 1000 < DAEMON_START_TIMEOUT_SECONDS ) {
QThread::sleep(2);
if(!running(testnet)) {
qDebug() << "daemon not running. checking again in 2 seconds.";
} else {
qDebug() << "daemon is started. Waiting 5 seconds to let daemon catch up";
QThread::sleep(5);
return true;
}
}
return false;
}
bool DaemonManager::stopWatcher(bool testnet) const
{
// Check if daemon is running every 2 seconds. Kill if still running after 10 seconds
int counter = 0;
while(true && !m_app_exit) {
QThread::sleep(2);
counter++;
if(running(testnet)) {
qDebug() << "Daemon still running. " << counter;
if(counter >= 5) {
qDebug() << "Killing it! ";
#ifdef Q_OS_WIN
QProcess::execute("taskkill /F /IM monerod.exe");
#else
QProcess::execute("pkill monerod");
#endif
}
} else
return true;
}
return false;
}
void DaemonManager::stateChanged(QProcess::ProcessState state) void DaemonManager::stateChanged(QProcess::ProcessState state)
{ {
qDebug() << "STATE CHANGED: " << state; qDebug() << "STATE CHANGED: " << state;
@ -124,10 +199,8 @@ bool DaemonManager::running(bool testnet) const
// `./monerod status` returns BUSY when syncing. // `./monerod status` returns BUSY when syncing.
// Treat busy as connected, until fixed upstream. // Treat busy as connected, until fixed upstream.
if (status.contains("Height:") || status.contains("BUSY") ) { if (status.contains("Height:") || status.contains("BUSY") ) {
emit daemonStarted();
return true; return true;
} }
emit daemonStopped();
return false; return false;
} }
bool DaemonManager::sendCommand(const QString &cmd,bool testnet) const bool DaemonManager::sendCommand(const QString &cmd,bool testnet) const
@ -155,6 +228,12 @@ bool DaemonManager::sendCommand(const QString &cmd,bool testnet, QString &messag
return started; return started;
} }
void DaemonManager::exit()
{
qDebug("DaemonManager: exit()");
m_app_exit = true;
}
DaemonManager::DaemonManager(QObject *parent) DaemonManager::DaemonManager(QObject *parent)
: QObject(parent) : QObject(parent)
{ {

View file

@ -20,12 +20,17 @@ public:
Q_INVOKABLE bool running(bool testnet) const; Q_INVOKABLE bool running(bool testnet) const;
// Send daemon command from qml and prints output in console window. // Send daemon command from qml and prints output in console window.
Q_INVOKABLE bool sendCommand(const QString &cmd, bool testnet) const; Q_INVOKABLE bool sendCommand(const QString &cmd, bool testnet) const;
Q_INVOKABLE void exit();
private: private:
bool sendCommand(const QString &cmd, bool testnet, QString &message) const; bool sendCommand(const QString &cmd, bool testnet, QString &message) const;
bool startWatcher(bool testnet) const;
bool stopWatcher(bool testnet) const;
signals: signals:
void daemonStarted() const; void daemonStarted() const;
void daemonStopped() const; void daemonStopped() const;
void daemonStartFailure() const;
void daemonConsoleUpdated(QString message) const; void daemonConsoleUpdated(QString message) const;
public slots: public slots:
@ -41,6 +46,7 @@ private:
bool initialized = false; bool initialized = false;
QString m_monerod; QString m_monerod;
bool m_has_daemon = true; bool m_has_daemon = true;
bool m_app_exit = false;
}; };

View file

@ -302,6 +302,16 @@ int Wallet::autoRefreshInterval() const
return m_walletImpl->autoRefreshInterval(); return m_walletImpl->autoRefreshInterval();
} }
void Wallet::startRefresh() const
{
m_walletImpl->startRefresh();
}
void Wallet::pauseRefresh() const
{
m_walletImpl->pauseRefresh();
}
PendingTransaction *Wallet::createTransaction(const QString &dst_addr, const QString &payment_id, PendingTransaction *Wallet::createTransaction(const QString &dst_addr, const QString &payment_id,
quint64 amount, quint32 mixin_count, quint64 amount, quint32 mixin_count,
PendingTransaction::Priority priority) PendingTransaction::Priority priority)

View file

@ -146,6 +146,10 @@ public:
//! return auto-refresh interval in seconds //! return auto-refresh interval in seconds
Q_INVOKABLE int autoRefreshInterval() const; Q_INVOKABLE int autoRefreshInterval() const;
// pause/resume refresh
Q_INVOKABLE void startRefresh() const;
Q_INVOKABLE void pauseRefresh() const;
//! creates transaction //! creates transaction
Q_INVOKABLE PendingTransaction * createTransaction(const QString &dst_addr, const QString &payment_id, Q_INVOKABLE PendingTransaction * createTransaction(const QString &dst_addr, const QString &payment_id,
quint64 amount, quint32 mixin_count, quint64 amount, quint32 mixin_count,