mirror of
https://github.com/monero-project/monero-gui.git
synced 2024-12-23 03:59:38 +00:00
Wallet: rework wallet refreshing
This commit is contained in:
parent
d3943ca2a9
commit
39d9d7d071
5 changed files with 100 additions and 45 deletions
2
main.qml
2
main.qml
|
@ -1895,7 +1895,7 @@ ApplicationWindow {
|
||||||
repeat: true
|
repeat: true
|
||||||
running: persistentSettings.autosave
|
running: persistentSettings.autosave
|
||||||
onTriggered: {
|
onTriggered: {
|
||||||
if (currentWallet) {
|
if (currentWallet && !currentWallet.refreshing) {
|
||||||
currentWallet.storeAsync(function(success) {
|
currentWallet.storeAsync(function(success) {
|
||||||
if (success) {
|
if (success) {
|
||||||
appWindow.showStatusMessage(qsTr("Autosaved the wallet"), 3);
|
appWindow.showStatusMessage(qsTr("Autosaved the wallet"), 3);
|
||||||
|
|
|
@ -27,6 +27,11 @@
|
||||||
// THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
// THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||||
|
|
||||||
#include "Wallet.h"
|
#include "Wallet.h"
|
||||||
|
|
||||||
|
#include <chrono>
|
||||||
|
#include <stdexcept>
|
||||||
|
#include <thread>
|
||||||
|
|
||||||
#include "PendingTransaction.h"
|
#include "PendingTransaction.h"
|
||||||
#include "UnsignedTransaction.h"
|
#include "UnsignedTransaction.h"
|
||||||
#include "TransactionHistory.h"
|
#include "TransactionHistory.h"
|
||||||
|
@ -50,6 +55,8 @@
|
||||||
#include <QVector>
|
#include <QVector>
|
||||||
#include <QMutexLocker>
|
#include <QMutexLocker>
|
||||||
|
|
||||||
|
#include "qt/ScopeGuard.h"
|
||||||
|
|
||||||
namespace {
|
namespace {
|
||||||
static const int DAEMON_BLOCKCHAIN_HEIGHT_CACHE_TTL_SECONDS = 5;
|
static const int DAEMON_BLOCKCHAIN_HEIGHT_CACHE_TTL_SECONDS = 5;
|
||||||
static const int DAEMON_BLOCKCHAIN_TARGET_HEIGHT_CACHE_TTL_SECONDS = 30;
|
static const int DAEMON_BLOCKCHAIN_TARGET_HEIGHT_CACHE_TTL_SECONDS = 30;
|
||||||
|
@ -124,6 +131,19 @@ bool Wallet::disconnected() const
|
||||||
return m_disconnected;
|
return m_disconnected;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
bool Wallet::refreshing() const
|
||||||
|
{
|
||||||
|
return m_refreshing;
|
||||||
|
}
|
||||||
|
|
||||||
|
void Wallet::refreshingSet(bool value)
|
||||||
|
{
|
||||||
|
if (m_refreshing.exchange(value) != value)
|
||||||
|
{
|
||||||
|
emit refreshingChanged();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
void Wallet::setConnectionStatus(ConnectionStatus value)
|
void Wallet::setConnectionStatus(ConnectionStatus value)
|
||||||
{
|
{
|
||||||
if (m_connectionStatus == value)
|
if (m_connectionStatus == value)
|
||||||
|
@ -196,7 +216,7 @@ void Wallet::storeAsync(const QJSValue &callback, const QString &path /* = "" */
|
||||||
{
|
{
|
||||||
const auto future = m_scheduler.run(
|
const auto future = m_scheduler.run(
|
||||||
[this, path] {
|
[this, path] {
|
||||||
QMutexLocker locker(&m_storeMutex);
|
QMutexLocker locker(&m_asyncMutex);
|
||||||
|
|
||||||
return QJSValueList({m_walletImpl->store(path.toStdString())});
|
return QJSValueList({m_walletImpl->store(path.toStdString())});
|
||||||
},
|
},
|
||||||
|
@ -263,7 +283,7 @@ void Wallet::initAsync(
|
||||||
emit walletCreationHeightChanged();
|
emit walletCreationHeightChanged();
|
||||||
qDebug() << "init async finished - starting refresh";
|
qDebug() << "init async finished - starting refresh";
|
||||||
connected(true);
|
connected(true);
|
||||||
m_walletImpl->startRefresh();
|
startRefresh();
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
if (future.first)
|
if (future.first)
|
||||||
|
@ -466,41 +486,37 @@ bool Wallet::importKeyImages(const QString& path)
|
||||||
return m_walletImpl->importKeyImages(path.toStdString());
|
return m_walletImpl->importKeyImages(path.toStdString());
|
||||||
}
|
}
|
||||||
|
|
||||||
bool Wallet::refresh()
|
bool Wallet::refresh(bool historyAndSubaddresses /* = true */)
|
||||||
{
|
{
|
||||||
bool result = m_walletImpl->refresh();
|
refreshingSet(true);
|
||||||
m_history->refresh(currentSubaddressAccount());
|
const auto cleanup = sg::make_scope_guard([this]() noexcept {
|
||||||
m_subaddress->refresh(currentSubaddressAccount());
|
refreshingSet(false);
|
||||||
m_subaddressAccount->getAll();
|
});
|
||||||
if (result)
|
|
||||||
emit updated();
|
{
|
||||||
return result;
|
QMutexLocker locker(&m_asyncMutex);
|
||||||
|
|
||||||
|
bool result = m_walletImpl->refresh();
|
||||||
|
if (historyAndSubaddresses)
|
||||||
|
{
|
||||||
|
m_history->refresh(currentSubaddressAccount());
|
||||||
|
m_subaddress->refresh(currentSubaddressAccount());
|
||||||
|
m_subaddressAccount->getAll();
|
||||||
|
}
|
||||||
|
if (result)
|
||||||
|
emit updated();
|
||||||
|
return result;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void Wallet::refreshAsync()
|
void Wallet::startRefresh()
|
||||||
{
|
{
|
||||||
qDebug() << "refresh async";
|
m_refreshEnabled = true;
|
||||||
m_walletImpl->refreshAsync();
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void Wallet::setAutoRefreshInterval(int seconds)
|
void Wallet::pauseRefresh()
|
||||||
{
|
{
|
||||||
m_walletImpl->setAutoRefreshInterval(seconds);
|
m_refreshEnabled = false;
|
||||||
}
|
|
||||||
|
|
||||||
int Wallet::autoRefreshInterval() const
|
|
||||||
{
|
|
||||||
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,
|
||||||
|
@ -874,6 +890,8 @@ bool Wallet::parse_uri(const QString &uri, QString &address, QString &payment_id
|
||||||
|
|
||||||
bool Wallet::rescanSpent()
|
bool Wallet::rescanSpent()
|
||||||
{
|
{
|
||||||
|
QMutexLocker locker(&m_asyncMutex);
|
||||||
|
|
||||||
return m_walletImpl->rescanSpent();
|
return m_walletImpl->rescanSpent();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -1041,6 +1059,8 @@ Wallet::Wallet(Monero::Wallet *w, QObject *parent)
|
||||||
, m_subaddressModel(nullptr)
|
, m_subaddressModel(nullptr)
|
||||||
, m_subaddressAccount(nullptr)
|
, m_subaddressAccount(nullptr)
|
||||||
, m_subaddressAccountModel(nullptr)
|
, m_subaddressAccountModel(nullptr)
|
||||||
|
, m_refreshEnabled(false)
|
||||||
|
, m_refreshing(false)
|
||||||
, m_scheduler(this)
|
, m_scheduler(this)
|
||||||
{
|
{
|
||||||
m_history = new TransactionHistory(m_walletImpl->history(), this);
|
m_history = new TransactionHistory(m_walletImpl->history(), this);
|
||||||
|
@ -1058,6 +1078,8 @@ Wallet::Wallet(Monero::Wallet *w, QObject *parent)
|
||||||
m_connectionStatusRunning = false;
|
m_connectionStatusRunning = false;
|
||||||
m_daemonUsername = "";
|
m_daemonUsername = "";
|
||||||
m_daemonPassword = "";
|
m_daemonPassword = "";
|
||||||
|
|
||||||
|
startRefreshThread();
|
||||||
}
|
}
|
||||||
|
|
||||||
Wallet::~Wallet()
|
Wallet::~Wallet()
|
||||||
|
@ -1090,3 +1112,32 @@ Wallet::~Wallet()
|
||||||
m_walletListener = NULL;
|
m_walletListener = NULL;
|
||||||
qDebug("m_walletImpl deleted");
|
qDebug("m_walletImpl deleted");
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void Wallet::startRefreshThread()
|
||||||
|
{
|
||||||
|
const auto future = m_scheduler.run([this] {
|
||||||
|
static constexpr const size_t refreshIntervalSec = 10;
|
||||||
|
static constexpr const size_t intervalResolutionMs = 100;
|
||||||
|
|
||||||
|
auto last = std::chrono::steady_clock::now();
|
||||||
|
while (!m_scheduler.stopping())
|
||||||
|
{
|
||||||
|
if (m_refreshEnabled)
|
||||||
|
{
|
||||||
|
const auto now = std::chrono::steady_clock::now();
|
||||||
|
const auto elapsed = std::chrono::duration_cast<std::chrono::seconds>(now - last).count();
|
||||||
|
if (elapsed >= refreshIntervalSec)
|
||||||
|
{
|
||||||
|
refresh(false);
|
||||||
|
last = std::chrono::steady_clock::now();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
std::this_thread::sleep_for(std::chrono::milliseconds(intervalResolutionMs));
|
||||||
|
}
|
||||||
|
});
|
||||||
|
if (!future.first)
|
||||||
|
{
|
||||||
|
throw std::runtime_error("failed to start auto refresh thread");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
|
@ -63,6 +63,7 @@ class Wallet : public QObject, public PassprasePrompter
|
||||||
{
|
{
|
||||||
Q_OBJECT
|
Q_OBJECT
|
||||||
Q_PROPERTY(bool disconnected READ disconnected NOTIFY disconnectedChanged)
|
Q_PROPERTY(bool disconnected READ disconnected NOTIFY disconnectedChanged)
|
||||||
|
Q_PROPERTY(bool refreshing READ refreshing NOTIFY refreshingChanged)
|
||||||
Q_PROPERTY(QString seed READ getSeed)
|
Q_PROPERTY(QString seed READ getSeed)
|
||||||
Q_PROPERTY(QString seedLanguage READ getSeedLanguage)
|
Q_PROPERTY(QString seedLanguage READ getSeedLanguage)
|
||||||
Q_PROPERTY(Status status READ status)
|
Q_PROPERTY(Status status READ status)
|
||||||
|
@ -207,20 +208,11 @@ public:
|
||||||
Q_INVOKABLE bool importKeyImages(const QString& path);
|
Q_INVOKABLE bool importKeyImages(const QString& path);
|
||||||
|
|
||||||
//! refreshes the wallet
|
//! refreshes the wallet
|
||||||
Q_INVOKABLE bool refresh();
|
Q_INVOKABLE bool refresh(bool historyAndSubaddresses = true);
|
||||||
|
|
||||||
//! refreshes the wallet asynchronously
|
|
||||||
Q_INVOKABLE void refreshAsync();
|
|
||||||
|
|
||||||
//! setup auto-refresh interval in seconds
|
|
||||||
Q_INVOKABLE void setAutoRefreshInterval(int seconds);
|
|
||||||
|
|
||||||
//! return auto-refresh interval in seconds
|
|
||||||
Q_INVOKABLE int autoRefreshInterval() const;
|
|
||||||
|
|
||||||
// pause/resume refresh
|
// pause/resume refresh
|
||||||
Q_INVOKABLE void startRefresh() const;
|
Q_INVOKABLE void startRefresh();
|
||||||
Q_INVOKABLE void pauseRefresh() const;
|
Q_INVOKABLE void pauseRefresh();
|
||||||
|
|
||||||
//! 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,
|
||||||
|
@ -394,6 +386,7 @@ signals:
|
||||||
void currentSubaddressAccountChanged() const;
|
void currentSubaddressAccountChanged() const;
|
||||||
void disconnectedChanged() const;
|
void disconnectedChanged() const;
|
||||||
void proxyAddressChanged() const;
|
void proxyAddressChanged() const;
|
||||||
|
void refreshingChanged() const;
|
||||||
|
|
||||||
private:
|
private:
|
||||||
Wallet(QObject * parent = nullptr);
|
Wallet(QObject * parent = nullptr);
|
||||||
|
@ -421,9 +414,12 @@ private:
|
||||||
const QString& proxyAddress);
|
const QString& proxyAddress);
|
||||||
|
|
||||||
bool disconnected() const;
|
bool disconnected() const;
|
||||||
|
bool refreshing() const;
|
||||||
|
void refreshingSet(bool value);
|
||||||
void setConnectionStatus(ConnectionStatus value);
|
void setConnectionStatus(ConnectionStatus value);
|
||||||
QString getProxyAddress() const;
|
QString getProxyAddress() const;
|
||||||
void setProxyAddress(QString address);
|
void setProxyAddress(QString address);
|
||||||
|
void startRefreshThread();
|
||||||
|
|
||||||
private:
|
private:
|
||||||
friend class WalletManager;
|
friend class WalletManager;
|
||||||
|
@ -454,15 +450,17 @@ private:
|
||||||
mutable SubaddressModel * m_subaddressModel;
|
mutable SubaddressModel * m_subaddressModel;
|
||||||
SubaddressAccount * m_subaddressAccount;
|
SubaddressAccount * m_subaddressAccount;
|
||||||
mutable SubaddressAccountModel * m_subaddressAccountModel;
|
mutable SubaddressAccountModel * m_subaddressAccountModel;
|
||||||
|
QMutex m_asyncMutex;
|
||||||
QMutex m_connectionStatusMutex;
|
QMutex m_connectionStatusMutex;
|
||||||
bool m_connectionStatusRunning;
|
bool m_connectionStatusRunning;
|
||||||
QString m_daemonUsername;
|
QString m_daemonUsername;
|
||||||
QString m_daemonPassword;
|
QString m_daemonPassword;
|
||||||
QString m_proxyAddress;
|
QString m_proxyAddress;
|
||||||
mutable QMutex m_proxyMutex;
|
mutable QMutex m_proxyMutex;
|
||||||
|
std::atomic<bool> m_refreshEnabled;
|
||||||
|
std::atomic<bool> m_refreshing;
|
||||||
WalletListenerImpl *m_walletListener;
|
WalletListenerImpl *m_walletListener;
|
||||||
FutureScheduler m_scheduler;
|
FutureScheduler m_scheduler;
|
||||||
QMutex m_storeMutex;
|
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
||||||
|
|
|
@ -65,6 +65,11 @@ QPair<bool, QFuture<QJSValueList>> FutureScheduler::run(std::function<QJSValueLi
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
|
bool FutureScheduler::stopping() const noexcept
|
||||||
|
{
|
||||||
|
return Stopping;
|
||||||
|
}
|
||||||
|
|
||||||
bool FutureScheduler::add() noexcept
|
bool FutureScheduler::add() noexcept
|
||||||
{
|
{
|
||||||
QMutexLocker locker(&Mutex);
|
QMutexLocker locker(&Mutex);
|
||||||
|
|
|
@ -23,6 +23,7 @@ public:
|
||||||
|
|
||||||
QPair<bool, QFuture<void>> run(std::function<void()> function) noexcept;
|
QPair<bool, QFuture<void>> run(std::function<void()> function) noexcept;
|
||||||
QPair<bool, QFuture<QJSValueList>> run(std::function<QJSValueList()> function, const QJSValue &callback);
|
QPair<bool, QFuture<QJSValueList>> run(std::function<QJSValueList()> function, const QJSValue &callback);
|
||||||
|
bool stopping() const noexcept;
|
||||||
|
|
||||||
private:
|
private:
|
||||||
bool add() noexcept;
|
bool add() noexcept;
|
||||||
|
@ -59,7 +60,7 @@ private:
|
||||||
size_t Alive;
|
size_t Alive;
|
||||||
QWaitCondition Condition;
|
QWaitCondition Condition;
|
||||||
QMutex Mutex;
|
QMutex Mutex;
|
||||||
bool Stopping;
|
std::atomic<bool> Stopping;
|
||||||
};
|
};
|
||||||
|
|
||||||
#endif // FUTURE_SCHEDULER_H
|
#endif // FUTURE_SCHEDULER_H
|
||||||
|
|
Loading…
Reference in a new issue