Merge pull request #486

faacd3d start daemon automatically and detached (Jaquee)
This commit is contained in:
Riccardo Spagni 2017-02-24 16:04:13 +02:00
commit 2ca2376d45
No known key found for this signature in database
GPG key ID: 55432DF31CCD4FCD
11 changed files with 103 additions and 115 deletions

View file

@ -39,12 +39,14 @@ Window {
id: root id: root
modality: Qt.ApplicationModal modality: Qt.ApplicationModal
flags: Qt.Window | Qt.FramelessWindowHint flags: Qt.Window | Qt.FramelessWindowHint
property int countDown: 5;
signal rejected() signal rejected()
signal started(); signal started();
function open() { function open() {
show() show()
countDown = 5;
timer.start();
} }
// TODO: implement without hardcoding sizes // TODO: implement without hardcoding sizes
@ -61,15 +63,29 @@ Window {
//anchors {fill: parent; margins: 16 } //anchors {fill: parent; margins: 16 }
Layout.alignment: Qt.AlignHCenter Layout.alignment: Qt.AlignHCenter
Label { Timer {
text: qsTr("Daemon doesn't appear to be running") id: timer
interval: 1000;
running: false;
repeat: true
onTriggered: {
countDown--;
if(countDown < 0){
running = false;
// Start daemon
root.close()
appWindow.startDaemon(persistentSettings.daemonFlags);
root.started();
}
}
}
Text {
text: qsTr("Starting Monero daemon in %1 seconds").arg(countDown);
font.pixelSize: 18
Layout.alignment: Qt.AlignHCenter Layout.alignment: Qt.AlignHCenter
Layout.columnSpan: 2
Layout.fillWidth: true Layout.fillWidth: true
horizontalAlignment: Text.AlignHCenter horizontalAlignment: Text.AlignHCenter
font.pixelSize: 24
font.family: "Arial"
color: "#555555"
} }
} }
@ -81,57 +97,39 @@ Window {
MoneroComponents.StandardButton { MoneroComponents.StandardButton {
id: okButton id: okButton
width: 120 visible:false
fontSize: 14 fontSize: 14
shadowReleasedColor: "#FF4304" shadowReleasedColor: "#FF4304"
shadowPressedColor: "#B32D00" shadowPressedColor: "#B32D00"
releasedColor: "#FF6C3C" releasedColor: "#FF6C3C"
pressedColor: "#FF4304" pressedColor: "#FF4304"
text: qsTr("Start daemon") text: qsTr("Start daemon (%1)").arg(countDown)
KeyNavigation.tab: cancelButton KeyNavigation.tab: cancelButton
onClicked: { onClicked: {
timer.stop();
root.close() root.close()
appWindow.startDaemon(daemonFlags.text); appWindow.startDaemon(persistentSettings.daemonFlags);
root.started() root.started()
} }
} }
MoneroComponents.StandardButton { MoneroComponents.StandardButton {
id: cancelButton id: cancelButton
width: 120
fontSize: 14 fontSize: 14
shadowReleasedColor: "#FF4304" shadowReleasedColor: "#FF4304"
shadowPressedColor: "#B32D00" shadowPressedColor: "#B32D00"
releasedColor: "#FF6C3C" releasedColor: "#FF6C3C"
pressedColor: "#FF4304" pressedColor: "#FF4304"
text: qsTr("Cancel") text: qsTr("Use custom settings")
onClicked: { onClicked: {
timer.stop();
root.close() root.close()
root.rejected() root.rejected()
} }
} }
} }
RowLayout {
id: advancedRow
MoneroComponents.Label {
id: daemonFlagsLabel
color: "#4A4949"
text: qsTr("Daemon startup flags") + translationManager.emptyString
fontSize: 16
}
MoneroComponents.LineEdit {
id: daemonFlags
Layout.preferredWidth: 200
Layout.fillWidth: true
text: appWindow.persistentSettings.daemonFlags;
placeholderText: qsTr("(optional)")
}
}
} }
} }

View file

@ -61,7 +61,7 @@ Window {
id: messageTitle id: messageTitle
text: "Please wait..." text: "Please wait..."
font { font {
pointSize: 22 pixelSize: 22
} }
horizontalAlignment: Text.AlignHCenter horizontalAlignment: Text.AlignHCenter
Layout.alignment: Qt.AlignVCenter | Qt.AlignHCenter Layout.alignment: Qt.AlignVCenter | Qt.AlignHCenter
@ -72,7 +72,7 @@ Window {
Text { Text {
id: heightProgress id: heightProgress
font { font {
pointSize: 18 pixelSize: 18
} }
horizontalAlignment: Text.AlignHCenter horizontalAlignment: Text.AlignHCenter
Layout.alignment: Qt.AlignVCenter | Qt.AlignHCenter Layout.alignment: Qt.AlignVCenter | Qt.AlignHCenter

View file

@ -142,7 +142,6 @@ int main(int argc, char *argv[])
// Exclude daemon manager from IOS // Exclude daemon manager from IOS
#ifndef Q_OS_IOS #ifndef Q_OS_IOS
DaemonManager * daemonManager = DaemonManager::instance(&arguments); DaemonManager * daemonManager = DaemonManager::instance(&arguments);
QObject::connect(&app, SIGNAL(aboutToQuit()), daemonManager, SLOT(closing()));
engine.rootContext()->setContextProperty("daemonManager", daemonManager); engine.rootContext()->setContextProperty("daemonManager", daemonManager);
#endif #endif

View file

@ -147,6 +147,11 @@ ApplicationWindow {
function mousePressed(obj, mouseX, mouseY) {} function mousePressed(obj, mouseX, mouseY) {}
function mouseReleased(obj, mouseX, mouseY) {} function mouseReleased(obj, mouseX, mouseY) {}
function loadPage(page) {
middlePanel.state = page;
leftPanel.selectItem(page);
}
function openWalletFromFile(){ function openWalletFromFile(){
persistentSettings.restore_height = 0 persistentSettings.restore_height = 0
restoreHeight = 0; restoreHeight = 0;
@ -274,7 +279,7 @@ ApplicationWindow {
leftPanel.progressBar.visible = (status === Wallet.ConnectionStatus_Connected) && !daemonSynced leftPanel.progressBar.visible = (status === Wallet.ConnectionStatus_Connected) && !daemonSynced
// If wallet isnt connected and no daemon is running - Ask // If wallet isnt connected and no daemon is running - Ask
if(!walletInitialized && status === Wallet.ConnectionStatus_Disconnected && !daemonManager.running()){ if(!walletInitialized && status === Wallet.ConnectionStatus_Disconnected && !daemonManager.running(persistentSettings.testnet)){
daemonManagerDialog.open(); daemonManagerDialog.open();
} }
// initialize transaction history once wallet is initialized first time; // initialize transaction history once wallet is initialized first time;
@ -341,7 +346,7 @@ ApplicationWindow {
} }
// Daemon connected // Daemon connected
leftPanel.networkStatus.connected = currentWallet.connected leftPanel.networkStatus.connected = currentWallet.connected()
// Check daemon status // Check daemon status
var dCurrentBlock = currentWallet.daemonBlockChainHeight(); var dCurrentBlock = currentWallet.daemonBlockChainHeight();
@ -352,9 +357,9 @@ ApplicationWindow {
daemonSynced = dCurrentBlock >= dTargetBlock daemonSynced = dCurrentBlock >= dTargetBlock
// Update daemon sync progress // Update daemon sync progress
leftPanel.progressBar.updateProgress(dCurrentBlock,dTargetBlock); leftPanel.progressBar.updateProgress(dCurrentBlock,dTargetBlock);
leftPanel.progressBar.visible = !daemonSynced && currentWallet.connected !== Wallet.ConnectionStatus_Disconnected leftPanel.progressBar.visible = !daemonSynced && currentWallet.connected() !== Wallet.ConnectionStatus_Disconnected
// Update wallet sync progress // Update wallet sync progress
updateSyncing((currentWallet.connected !== Wallet.ConnectionStatus_Disconnected) && !daemonSynced) updateSyncing((currentWallet.connected() !== Wallet.ConnectionStatus_Disconnected) && !daemonSynced)
// Update transfer page status // Update transfer page status
middlePanel.updateStatus(); middlePanel.updateStatus();
@ -380,23 +385,25 @@ ApplicationWindow {
function startDaemon(flags){ function startDaemon(flags){
appWindow.showProcessingSplash(qsTr("Waiting for daemon to start...")) appWindow.showProcessingSplash(qsTr("Waiting for daemon to start..."))
daemonManager.start(flags); daemonManager.start(flags, persistentSettings.testnet);
persistentSettings.daemonFlags = flags persistentSettings.daemonFlags = flags
} }
function stopDaemon(){ function stopDaemon(){
appWindow.showProcessingSplash(qsTr("Waiting for daemon to stop...")) appWindow.showProcessingSplash(qsTr("Waiting for daemon to stop..."))
daemonManager.stop(); daemonManager.stop(persistentSettings.testnet);
} }
function onDaemonStarted(){ function onDaemonStarted(){
console.log("daemon started"); console.log("daemon started");
daemonRunning = true; daemonRunning = true;
hideProcessingSplash();
} }
function onDaemonStopped(){ function onDaemonStopped(){
console.log("daemon stopped"); console.log("daemon stopped");
hideProcessingSplash(); hideProcessingSplash();
daemonRunning = false; daemonRunning = false;
currentWallet.connected(true);
} }
function onWalletNewBlock(blockHeight, targetHeight) { function onWalletNewBlock(blockHeight, targetHeight) {
@ -438,7 +445,7 @@ ApplicationWindow {
if (transaction.status !== PendingTransaction.Status_Ok) { if (transaction.status !== PendingTransaction.Status_Ok) {
console.error("Can't create transaction: ", transaction.errorString); console.error("Can't create transaction: ", transaction.errorString);
informationPopup.title = qsTr("Error") + translationManager.emptyString; informationPopup.title = qsTr("Error") + translationManager.emptyString;
if (currentWallet.connected == Wallet.ConnectionStatus_WrongVersion) if (currentWallet.connected() == Wallet.ConnectionStatus_WrongVersion)
informationPopup.text = qsTr("Can't create transaction: Wrong daemon version: ") + transaction.errorString informationPopup.text = qsTr("Can't create transaction: Wrong daemon version: ") + transaction.errorString
else else
informationPopup.text = qsTr("Can't create transaction: ") + transaction.errorString informationPopup.text = qsTr("Can't create transaction: ") + transaction.errorString
@ -871,6 +878,9 @@ ApplicationWindow {
DaemonManagerDialog { DaemonManagerDialog {
id: daemonManagerDialog id: daemonManagerDialog
onRejected: {
loadPage("Settings");
}
} }
@ -1224,8 +1234,6 @@ ApplicationWindow {
onClosing: { onClosing: {
// Close wallet non async on exit // Close wallet non async on exit
walletManager.closeWallet(); walletManager.closeWallet();
// Stop daemon and pool miner
daemonManager.stop();
} }
function checkUpdates() { function checkUpdates() {

View file

@ -96,7 +96,7 @@ Rectangle {
setTrackingLineText("-") setTrackingLineText("-")
return return
} }
if (appWindow.currentWallet.connected == Wallet.ConnectionStatus_Disconnected) { if (appWindow.currentWallet.connected() == Wallet.ConnectionStatus_Disconnected) {
setTrackingLineText(qsTr("WARNING: no connection to daemon")) setTrackingLineText(qsTr("WARNING: no connection to daemon"))
return return
} }

View file

@ -171,23 +171,10 @@ Rectangle {
} }
} }
StandardButton {
visible: true
id: daemonConsolePopupButton
text: qsTr("Show log") + translationManager.emptyString
shadowReleasedColor: "#FF4304"
shadowPressedColor: "#B32D00"
releasedColor: "#FF6C3C"
pressedColor: "#FF4304"
onClicked: {
daemonConsolePopup.open();
}
}
StandardButton { StandardButton {
visible: true visible: true
id: daemonStatusButton id: daemonStatusButton
text: qsTr("Status") + translationManager.emptyString text: qsTr("Show status") + translationManager.emptyString
shadowReleasedColor: "#FF4304" shadowReleasedColor: "#FF4304"
shadowPressedColor: "#B32D00" shadowPressedColor: "#B32D00"
releasedColor: "#FF6C3C" releasedColor: "#FF6C3C"
@ -420,6 +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)
} }
// fires only once // fires only once

View file

@ -700,7 +700,7 @@ Rectangle {
} }
pageRoot.enabled = false; pageRoot.enabled = false;
switch (currentWallet.connected) { switch (currentWallet.connected()) {
case Wallet.ConnectionStatus_Disconnected: case Wallet.ConnectionStatus_Disconnected:
statusText.text = qsTr("Wallet is not connected to daemon.") + "<br>" + root.startLinkText statusText.text = qsTr("Wallet is not connected to daemon.") + "<br>" + root.startLinkText
break break

View file

@ -23,10 +23,14 @@ DaemonManager *DaemonManager::instance(const QStringList *args)
return m_instance; return m_instance;
} }
bool DaemonManager::start(const QString &flags) bool DaemonManager::start(const QString &flags, bool testnet)
{ {
// prepare command line arguments and pass to monerod // prepare command line arguments and pass to monerod
QStringList arguments; QStringList arguments;
arguments << "--detach";
if(testnet)
arguments << "--testnet";
foreach (const QString &str, m_clArgs) { foreach (const QString &str, m_clArgs) {
qDebug() << QString(" [%1] ").arg(str); qDebug() << QString(" [%1] ").arg(str);
if (!str.isEmpty()) if (!str.isEmpty())
@ -53,8 +57,7 @@ bool DaemonManager::start(const QString &flags)
connect (m_daemon, SIGNAL(readyReadStandardError()), this, SLOT(printError())); connect (m_daemon, SIGNAL(readyReadStandardError()), this, SLOT(printError()));
// Start monerod // Start monerod
m_daemon->start(m_monerod, arguments); bool started = m_daemon->startDetached(m_monerod, arguments);
bool started = m_daemon->waitForStarted();
// add state changed listener // add state changed listener
connect(m_daemon,SIGNAL(stateChanged(QProcess::ProcessState)),this,SLOT(stateChanged(QProcess::ProcessState))); connect(m_daemon,SIGNAL(stateChanged(QProcess::ProcessState)),this,SLOT(stateChanged(QProcess::ProcessState)));
@ -68,16 +71,14 @@ bool DaemonManager::start(const QString &flags)
return started; return started;
} }
bool DaemonManager::stop() bool DaemonManager::stop(bool testnet)
{ {
if (initialized) { QString message;
qDebug() << "stopping daemon"; bool stopped = sendCommand("exit",testnet,message);
// we can't use QProcess::terminate() on windows console process qDebug() << message;
// write exit command to stdin if(stopped)
m_daemon->write("exit\n"); emit daemonStopped();
} return stopped;
return true;
} }
void DaemonManager::stateChanged(QProcess::ProcessState state) void DaemonManager::stateChanged(QProcess::ProcessState state)
@ -110,40 +111,42 @@ void DaemonManager::printError()
} }
} }
bool DaemonManager::running() const bool DaemonManager::running(bool testnet) const
{ {
if (initialized) { QString status;
qDebug() << m_daemon->state(); sendCommand("status",testnet, status);
qDebug() << QProcess::NotRunning; qDebug() << status;
// m_daemon->write("status\n"); // `./monerod status` returns BUSY when syncing.
return m_daemon->state() > QProcess::NotRunning; // Treat busy as connected, until fixed upstream.
} if (status.contains("Height:") || status.contains("BUSY") ) {
return false; emit daemonStarted();
}
bool DaemonManager::sendCommand(const QString &cmd,bool testnet)
{
// If daemon is started by GUI - interactive mode
if (initialized && running()) {
m_daemon->write(cmd.toUtf8() +"\n");
return true; return true;
} }
emit daemonStopped();
return false;
}
bool DaemonManager::sendCommand(const QString &cmd,bool testnet) const
{
QString message;
return sendCommand(cmd, testnet, message);
}
// else send external command bool DaemonManager::sendCommand(const QString &cmd,bool testnet, QString &message) const
{
QProcess p; QProcess p;
QString external_cmd = m_monerod + " " + cmd; QString external_cmd = m_monerod + " " + cmd;
qDebug() << "sending external cmd: " << external_cmd;
// Add nestnet flag if needed // Add testnet flag if needed
if (testnet) if (testnet)
external_cmd += " --testnet"; external_cmd += " --testnet";
external_cmd += "\n"; external_cmd += "\n";
p.start(external_cmd); p.start(external_cmd);
bool started = p.waitForFinished(-1);
QString p_stdout = p.readAllStandardOutput();
qDebug() << p_stdout;
emit daemonConsoleUpdated(p_stdout);
bool started = p.waitForFinished(-1);
message = p.readAllStandardOutput();
emit daemonConsoleUpdated(message);
return started; return started;
} }
@ -163,13 +166,3 @@ DaemonManager::DaemonManager(QObject *parent)
m_has_daemon = false; m_has_daemon = false;
} }
} }
void DaemonManager::closing()
{
qDebug() << __FUNCTION__;
stop();
// Wait for daemon to stop before exiting (max 10 secs)
if (initialized) {
m_daemon->waitForFinished(10000);
}
}

View file

@ -13,26 +13,27 @@ public:
static DaemonManager * instance(const QStringList *args); static DaemonManager * instance(const QStringList *args);
Q_INVOKABLE bool start(const QString &flags); Q_INVOKABLE bool start(const QString &flags, bool testnet);
Q_INVOKABLE bool stop(); Q_INVOKABLE bool stop(bool testnet);
// return true if daemon process is started // return true if daemon process is started
Q_INVOKABLE bool running() const; Q_INVOKABLE bool running(bool testnet) const;
Q_INVOKABLE bool sendCommand(const QString &cmd, bool testnet); // Send daemon command from qml and prints output in console window.
Q_INVOKABLE bool sendCommand(const QString &cmd, bool testnet) const;
private:
bool sendCommand(const QString &cmd, bool testnet, QString &message) const;
signals: signals:
void daemonStarted(); void daemonStarted() const;
void daemonStopped(); void daemonStopped() const;
void daemonConsoleUpdated(QString message); void daemonConsoleUpdated(QString message) const;
public slots: public slots:
void printOutput(); void printOutput();
void printError(); void printError();
void closing();
void stateChanged(QProcess::ProcessState state); void stateChanged(QProcess::ProcessState state);
private: private:
explicit DaemonManager(QObject *parent = 0); explicit DaemonManager(QObject *parent = 0);
static DaemonManager * m_instance; static DaemonManager * m_instance;
static QStringList m_clArgs; static QStringList m_clArgs;

View file

@ -20,7 +20,7 @@
#include <QMutexLocker> #include <QMutexLocker>
namespace { namespace {
static const int DAEMON_BLOCKCHAIN_HEIGHT_CACHE_TTL_SECONDS = 10; static const int DAEMON_BLOCKCHAIN_HEIGHT_CACHE_TTL_SECONDS = 5;
static const int DAEMON_BLOCKCHAIN_TARGET_HEIGHT_CACHE_TTL_SECONDS = 60; static const int DAEMON_BLOCKCHAIN_TARGET_HEIGHT_CACHE_TTL_SECONDS = 60;
static const int WALLET_CONNECTION_STATUS_CACHE_TTL_SECONDS = 5; static const int WALLET_CONNECTION_STATUS_CACHE_TTL_SECONDS = 5;
} }
@ -118,6 +118,7 @@ void Wallet::updateConnectionStatusAsync()
if (newStatus != m_connectionStatus || !m_initialized) { if (newStatus != m_connectionStatus || !m_initialized) {
m_initialized = true; m_initialized = true;
m_connectionStatus = newStatus; m_connectionStatus = newStatus;
qDebug() << "NEW STATUS " << newStatus;
emit connectionStatusChanged(newStatus); emit connectionStatusChanged(newStatus);
} }
// Release lock // Release lock

View file

@ -28,7 +28,7 @@ class Wallet : public QObject
Q_PROPERTY(QString seedLanguage READ getSeedLanguage) Q_PROPERTY(QString seedLanguage READ getSeedLanguage)
Q_PROPERTY(Status status READ status) Q_PROPERTY(Status status READ status)
Q_PROPERTY(bool testnet READ testnet) Q_PROPERTY(bool testnet READ testnet)
Q_PROPERTY(ConnectionStatus connected READ connected) // Q_PROPERTY(ConnectionStatus connected READ connected)
Q_PROPERTY(bool synchronized READ synchronized) Q_PROPERTY(bool synchronized READ synchronized)
Q_PROPERTY(QString errorString READ errorString) Q_PROPERTY(QString errorString READ errorString)
Q_PROPERTY(QString address READ address) Q_PROPERTY(QString address READ address)
@ -77,7 +77,7 @@ public:
bool testnet() const; bool testnet() const;
//! returns whether the wallet is connected, and version status //! returns whether the wallet is connected, and version status
ConnectionStatus connected(bool forceCheck = false); Q_INVOKABLE ConnectionStatus connected(bool forceCheck = false);
void updateConnectionStatusAsync(); void updateConnectionStatusAsync();
//! returns true if wallet was ever synchronized //! returns true if wallet was ever synchronized