From c38e864c92b7958099d74048fdfc88a5d3b40dcc Mon Sep 17 00:00:00 2001
From: isanae <14251494+isanae@users.noreply.github.com>
Date: Sun, 7 Jul 2019 17:48:48 -0400
Subject: set the progress dialog's parent to main window as soon as it's
available
---
src/nxmaccessmanager.h | 5 ++++-
1 file changed, 4 insertions(+), 1 deletion(-)
(limited to 'src/nxmaccessmanager.h')
diff --git a/src/nxmaccessmanager.h b/src/nxmaccessmanager.h
index 1bdeae40..16dde612 100644
--- a/src/nxmaccessmanager.h
+++ b/src/nxmaccessmanager.h
@@ -41,6 +41,8 @@ public:
~NXMAccessManager();
+ void setTopLevelWidget(QWidget* w);
+
bool validated() const;
bool validateAttempted() const;
@@ -94,9 +96,10 @@ protected:
QIODevice *device);
private:
+ QWidget* m_TopLevel;
QTimer m_ValidateTimeout;
QNetworkReply *m_ValidateReply;
- QProgressDialog *m_ProgressDialog { nullptr };
+ mutable QProgressDialog* m_ProgressDialog;
QString m_MOVersion;
--
cgit v1.3.1
From ea7ad772bbd971e398869d9b74b38d62c814bb02 Mon Sep 17 00:00:00 2001
From: isanae <14251494+isanae@users.noreply.github.com>
Date: Sun, 7 Jul 2019 18:07:10 -0400
Subject: moved progress dialog to its own class
---
src/nxmaccessmanager.cpp | 111 ++++++++++++++++++++++++++---------------------
src/nxmaccessmanager.h | 22 +++++++++-
2 files changed, 82 insertions(+), 51 deletions(-)
(limited to 'src/nxmaccessmanager.h')
diff --git a/src/nxmaccessmanager.cpp b/src/nxmaccessmanager.cpp
index 5c72d3e2..4d9b2a92 100644
--- a/src/nxmaccessmanager.cpp
+++ b/src/nxmaccessmanager.cpp
@@ -41,19 +41,64 @@ along with Mod Organizer. If not, see .
using namespace MOBase;
-namespace {
- QString const nexusBaseUrl("https://api.nexusmods.com/v1");
+const QString NexusBaseUrl("https://api.nexusmods.com/v1");
+const std::chrono::seconds ValidationTimeout(10);
+
+
+ValidationProgressDialog::ValidationProgressDialog()
+ : m_dialogHolder(new QDialog), m_dialog(nullptr), m_bar(nullptr)
+{
+ m_dialog = m_dialogHolder.get();
+ m_bar = new QProgressBar;
+
+ auto* label = new QLabel(tr("Validating Nexus Connection"));
+ label->setAlignment(Qt::AlignHCenter);
+
+ auto* vbox = new QVBoxLayout(m_dialog);
+ vbox->addWidget(label);
+ vbox->addWidget(m_bar);
+
+ auto* buttons = new QDialogButtonBox(QDialogButtonBox::Cancel);
+ connect(buttons, &QDialogButtonBox::clicked, [&](auto* b){ onButton(b); });
+ vbox->addWidget(buttons);
+}
+
+void ValidationProgressDialog::setParentWidget(QWidget* w)
+{
+ // will be deleted by the parent
+ m_dialogHolder.release();
+
+ const auto wasVisible = m_dialog->isVisible();
+
+ m_dialog->hide();
+ m_dialog->setParent(w, m_dialog->windowFlags() | Qt::Dialog);
+ m_dialog->setModal(false);
+ m_dialog->setVisible(wasVisible);
+}
+
+void ValidationProgressDialog::show()
+{
+ m_dialog->show();
+}
+
+void ValidationProgressDialog::hide()
+{
+ m_dialog->hide();
+}
+
+void ValidationProgressDialog::onButton(QAbstractButton* b)
+{
}
+
NXMAccessManager::NXMAccessManager(QObject *parent, const QString &moVersion)
: QNetworkAccessManager(parent)
- , m_TopLevel(nullptr)
, m_ValidateReply(nullptr)
- , m_ProgressDialog(nullptr)
, m_MOVersion(moVersion)
{
m_ValidateTimeout.setSingleShot(true);
- m_ValidateTimeout.setInterval(30000);
+ m_ValidateTimeout.setInterval(ValidationTimeout);
+
connect(&m_ValidateTimeout, SIGNAL(timeout()), this, SLOT(validateTimeout()));
setCookieJar(new PersistentCookieJar(
QDir::fromNativeSeparators(Settings::instance().getCacheDirectory() + "/nexus_cookies.dat")));
@@ -74,16 +119,7 @@ NXMAccessManager::~NXMAccessManager()
void NXMAccessManager::setTopLevelWidget(QWidget* w)
{
- m_TopLevel = w;
-
- if (m_ProgressDialog) {
- const auto wasVisible = m_ProgressDialog->isVisible();
-
- m_ProgressDialog->hide();
- m_ProgressDialog->setParent(w, m_ProgressDialog->windowFlags() | Qt::Dialog);
- m_ProgressDialog->setModal(false);
- m_ProgressDialog->setVisible(wasVisible);
- }
+ m_ProgressDialog.setParentWidget(w);
}
QNetworkReply *NXMAccessManager::createRequest(
@@ -109,7 +145,7 @@ QNetworkReply *NXMAccessManager::createRequest(
void NXMAccessManager::showCookies() const
{
- QUrl url(nexusBaseUrl + "/");
+ QUrl url(NexusBaseUrl + "/");
for (const QNetworkCookie &cookie : cookieJar()->cookiesForUrl(url)) {
qDebug("%s - %s (expires: %s)",
cookie.name().constData(), cookie.value().constData(),
@@ -130,7 +166,7 @@ void NXMAccessManager::clearCookies()
void NXMAccessManager::startValidationCheck()
{
qDebug("Checking Nexus API Key...");
- QString requestString = nexusBaseUrl + "/users/validate";
+ QString requestString = NexusBaseUrl + "/users/validate";
QNetworkRequest request(requestString);
request.setRawHeader("APIKEY", m_ApiKey.toUtf8());
@@ -140,15 +176,8 @@ void NXMAccessManager::startValidationCheck()
request.setRawHeader("Application-Name", "MO2");
request.setRawHeader("Application-Version", m_MOVersion.toUtf8());
- if (!m_ProgressDialog) {
- m_ProgressDialog = new QProgressDialog(m_TopLevel);
- m_ProgressDialog->setModal(false);
- }
+ m_ProgressDialog.show();
- m_ProgressDialog->setLabelText(tr("Validating Nexus Connection"));
- QList buttons = m_ProgressDialog->findChildren();
- buttons.at(0)->setEnabled(false);
- m_ProgressDialog->show();
QCoreApplication::processEvents(); // for some reason the whole app hangs during the login. This way the user has at least a little feedback
m_ValidateReply = get(request);
@@ -162,23 +191,14 @@ void NXMAccessManager::startValidationCheck()
bool NXMAccessManager::validated() const
{
if (m_ValidateState == VALIDATE_CHECKING) {
- if (!m_ProgressDialog) {
- m_ProgressDialog = new QProgressDialog(m_TopLevel);
- m_ProgressDialog->setModal(false);
- }
+ m_ProgressDialog.show();
- m_ProgressDialog->setLabelText(tr("Validating Nexus Connection"));
- QList buttons = m_ProgressDialog->findChildren();
- buttons.at(0)->setEnabled(false);
- m_ProgressDialog->show();
while (m_ValidateState == VALIDATE_CHECKING) {
QCoreApplication::processEvents();
QThread::msleep(100);
}
- m_ProgressDialog->hide();
- m_ProgressDialog->deleteLater();
- m_ProgressDialog = nullptr;
+ m_ProgressDialog.hide();
}
return m_ValidateState == VALIDATE_VALID;
@@ -257,11 +277,8 @@ void NXMAccessManager::clearApiKey()
void NXMAccessManager::validateTimeout()
{
m_ValidateTimeout.stop();
- if (m_ProgressDialog != nullptr) {
- m_ProgressDialog->hide();
- m_ProgressDialog->deleteLater();
- m_ProgressDialog = nullptr;
- }
+ m_ProgressDialog.hide();
+
m_ApiKey.clear();
m_ValidateState = VALIDATE_NOT_VALID;
@@ -277,11 +294,8 @@ void NXMAccessManager::validateTimeout()
void NXMAccessManager::validateError(QNetworkReply::NetworkError)
{
m_ValidateTimeout.stop();
- if (m_ProgressDialog != nullptr) {
- m_ProgressDialog->hide();
- m_ProgressDialog->deleteLater();
- m_ProgressDialog = nullptr;
- }
+ m_ProgressDialog.hide();
+
m_ApiKey.clear();
m_ValidateState = VALIDATE_NOT_VALID;
@@ -300,10 +314,7 @@ void NXMAccessManager::validateError(QNetworkReply::NetworkError)
void NXMAccessManager::validateFinished()
{
m_ValidateTimeout.stop();
- if (m_ProgressDialog != nullptr) {
- m_ProgressDialog->deleteLater();
- m_ProgressDialog = nullptr;
- }
+ m_ProgressDialog.hide();
if (m_ValidateReply != nullptr) {
QJsonDocument jdoc = QJsonDocument::fromJson(m_ValidateReply->readAll());
diff --git a/src/nxmaccessmanager.h b/src/nxmaccessmanager.h
index 16dde612..89438316 100644
--- a/src/nxmaccessmanager.h
+++ b/src/nxmaccessmanager.h
@@ -29,6 +29,26 @@ along with Mod Organizer. If not, see .
namespace MOBase { class IPluginGame; }
+class ValidationProgressDialog : QObject
+{
+ Q_OBJECT;
+
+public:
+ ValidationProgressDialog();
+
+ void setParentWidget(QWidget* w);
+ void show();
+ void hide();
+
+private:
+ std::unique_ptr m_dialogHolder;
+ QDialog* m_dialog;
+ QProgressBar* m_bar;
+
+ void onButton(QAbstractButton* b);
+};
+
+
/**
* @brief access manager extended to handle nxm links
**/
@@ -99,7 +119,7 @@ private:
QWidget* m_TopLevel;
QTimer m_ValidateTimeout;
QNetworkReply *m_ValidateReply;
- mutable QProgressDialog* m_ProgressDialog;
+ mutable ValidationProgressDialog m_ProgressDialog;
QString m_MOVersion;
--
cgit v1.3.1
From 89d0528a002a3cd7f0db47b2db53bdaf0e9c494d Mon Sep 17 00:00:00 2001
From: isanae <14251494+isanae@users.noreply.github.com>
Date: Sun, 7 Jul 2019 18:22:36 -0400
Subject: progress dialog now shows elapsed time in progress bar
---
src/nxmaccessmanager.cpp | 43 ++++++++++++++++++++++++++++++++-----------
src/nxmaccessmanager.h | 11 ++++++++---
src/pch.h | 1 +
3 files changed, 41 insertions(+), 14 deletions(-)
(limited to 'src/nxmaccessmanager.h')
diff --git a/src/nxmaccessmanager.cpp b/src/nxmaccessmanager.cpp
index 4d9b2a92..d6f6290e 100644
--- a/src/nxmaccessmanager.cpp
+++ b/src/nxmaccessmanager.cpp
@@ -40,16 +40,20 @@ along with Mod Organizer. If not, see .
#include
using namespace MOBase;
+using namespace std::chrono_literals;
const QString NexusBaseUrl("https://api.nexusmods.com/v1");
-const std::chrono::seconds ValidationTimeout(10);
+const auto ValidationTimeout = 10s;
-ValidationProgressDialog::ValidationProgressDialog()
- : m_dialogHolder(new QDialog), m_dialog(nullptr), m_bar(nullptr)
+ValidationProgressDialog::ValidationProgressDialog(std::chrono::seconds t)
+ : m_timeout(t), m_dialog(nullptr), m_bar(nullptr), m_timer(nullptr)
{
+ m_dialogHolder.reset(new QDialog);
m_dialog = m_dialogHolder.get();
+
m_bar = new QProgressBar;
+ m_bar->setTextVisible(false);
auto* label = new QLabel(tr("Validating Nexus Connection"));
label->setAlignment(Qt::AlignHCenter);
@@ -76,13 +80,24 @@ void ValidationProgressDialog::setParentWidget(QWidget* w)
m_dialog->setVisible(wasVisible);
}
-void ValidationProgressDialog::show()
+void ValidationProgressDialog::start()
{
+ if (!m_timer) {
+ m_timer = new QTimer(m_dialog);
+ connect(m_timer, &QTimer::timeout, [&]{ onTimer(); });
+ m_timer->setInterval(100ms);
+ }
+
+ m_bar->setRange(0, m_timeout.count());
+ m_elapsed.start();
+ m_timer->start();
+
m_dialog->show();
}
-void ValidationProgressDialog::hide()
+void ValidationProgressDialog::stop()
{
+ m_timer->stop();
m_dialog->hide();
}
@@ -90,10 +105,16 @@ void ValidationProgressDialog::onButton(QAbstractButton* b)
{
}
+void ValidationProgressDialog::onTimer()
+{
+ m_bar->setValue(m_elapsed.elapsed() / 1000);
+}
+
NXMAccessManager::NXMAccessManager(QObject *parent, const QString &moVersion)
: QNetworkAccessManager(parent)
, m_ValidateReply(nullptr)
+ , m_ProgressDialog(ValidationTimeout)
, m_MOVersion(moVersion)
{
m_ValidateTimeout.setSingleShot(true);
@@ -176,7 +197,7 @@ void NXMAccessManager::startValidationCheck()
request.setRawHeader("Application-Name", "MO2");
request.setRawHeader("Application-Version", m_MOVersion.toUtf8());
- m_ProgressDialog.show();
+ m_ProgressDialog.start();
QCoreApplication::processEvents(); // for some reason the whole app hangs during the login. This way the user has at least a little feedback
@@ -191,14 +212,14 @@ void NXMAccessManager::startValidationCheck()
bool NXMAccessManager::validated() const
{
if (m_ValidateState == VALIDATE_CHECKING) {
- m_ProgressDialog.show();
+ m_ProgressDialog.start();
while (m_ValidateState == VALIDATE_CHECKING) {
QCoreApplication::processEvents();
QThread::msleep(100);
}
- m_ProgressDialog.hide();
+ m_ProgressDialog.stop();
}
return m_ValidateState == VALIDATE_VALID;
@@ -277,7 +298,7 @@ void NXMAccessManager::clearApiKey()
void NXMAccessManager::validateTimeout()
{
m_ValidateTimeout.stop();
- m_ProgressDialog.hide();
+ m_ProgressDialog.stop();
m_ApiKey.clear();
m_ValidateState = VALIDATE_NOT_VALID;
@@ -294,7 +315,7 @@ void NXMAccessManager::validateTimeout()
void NXMAccessManager::validateError(QNetworkReply::NetworkError)
{
m_ValidateTimeout.stop();
- m_ProgressDialog.hide();
+ m_ProgressDialog.stop();
m_ApiKey.clear();
m_ValidateState = VALIDATE_NOT_VALID;
@@ -314,7 +335,7 @@ void NXMAccessManager::validateError(QNetworkReply::NetworkError)
void NXMAccessManager::validateFinished()
{
m_ValidateTimeout.stop();
- m_ProgressDialog.hide();
+ m_ProgressDialog.stop();
if (m_ValidateReply != nullptr) {
QJsonDocument jdoc = QJsonDocument::fromJson(m_ValidateReply->readAll());
diff --git a/src/nxmaccessmanager.h b/src/nxmaccessmanager.h
index 89438316..b20cb6e8 100644
--- a/src/nxmaccessmanager.h
+++ b/src/nxmaccessmanager.h
@@ -25,6 +25,7 @@ along with Mod Organizer. If not, see .
#include
#include
#include
+#include
#include
namespace MOBase { class IPluginGame; }
@@ -34,18 +35,22 @@ class ValidationProgressDialog : QObject
Q_OBJECT;
public:
- ValidationProgressDialog();
+ ValidationProgressDialog(std::chrono::seconds timeout);
void setParentWidget(QWidget* w);
- void show();
- void hide();
+ void start();
+ void stop();
private:
+ std::chrono::seconds m_timeout;
std::unique_ptr m_dialogHolder;
QDialog* m_dialog;
QProgressBar* m_bar;
+ QTimer* m_timer;
+ QElapsedTimer m_elapsed;
void onButton(QAbstractButton* b);
+ void onTimer();
};
diff --git a/src/pch.h b/src/pch.h
index 1d8df43a..955939ba 100644
--- a/src/pch.h
+++ b/src/pch.h
@@ -98,6 +98,7 @@
#include
#include
#include
+#include
#include
#include
#include
--
cgit v1.3.1
From d9003f9e5407396fdd552c5df3d0be76ab9a16a3 Mon Sep 17 00:00:00 2001
From: isanae <14251494+isanae@users.noreply.github.com>
Date: Sun, 7 Jul 2019 19:00:34 -0400
Subject: made ValidationProgressDialog a QDialog to handle close events allow
hiding dialog and make it appear again if needed don't use an event loop in
validated(), it causes all sorts of problems because it can be reentrant if
another logged in action is done while the dialog is visible
---
src/nxmaccessmanager.cpp | 58 +++++++++++++++++++++++++-----------------------
src/nxmaccessmanager.h | 12 +++++++---
2 files changed, 39 insertions(+), 31 deletions(-)
(limited to 'src/nxmaccessmanager.h')
diff --git a/src/nxmaccessmanager.cpp b/src/nxmaccessmanager.cpp
index d6f6290e..a68dea54 100644
--- a/src/nxmaccessmanager.cpp
+++ b/src/nxmaccessmanager.cpp
@@ -46,63 +46,72 @@ const QString NexusBaseUrl("https://api.nexusmods.com/v1");
const auto ValidationTimeout = 10s;
-ValidationProgressDialog::ValidationProgressDialog(std::chrono::seconds t)
- : m_timeout(t), m_dialog(nullptr), m_bar(nullptr), m_timer(nullptr)
+ValidationProgressDialog::ValidationProgressDialog(std::chrono::seconds t) :
+ m_timeout(t), m_bar(nullptr), m_buttons(nullptr),
+ m_timer(nullptr)
{
- m_dialogHolder.reset(new QDialog);
- m_dialog = m_dialogHolder.get();
-
m_bar = new QProgressBar;
m_bar->setTextVisible(false);
auto* label = new QLabel(tr("Validating Nexus Connection"));
label->setAlignment(Qt::AlignHCenter);
- auto* vbox = new QVBoxLayout(m_dialog);
+ auto* vbox = new QVBoxLayout(this);
vbox->addWidget(label);
vbox->addWidget(m_bar);
- auto* buttons = new QDialogButtonBox(QDialogButtonBox::Cancel);
- connect(buttons, &QDialogButtonBox::clicked, [&](auto* b){ onButton(b); });
- vbox->addWidget(buttons);
+ m_buttons = new QDialogButtonBox;
+ m_buttons->addButton(tr("Hide"), QDialogButtonBox::RejectRole);
+ connect(m_buttons, &QDialogButtonBox::clicked, [&](auto* b){ onButton(b); });
+ vbox->addWidget(m_buttons);
}
void ValidationProgressDialog::setParentWidget(QWidget* w)
{
- // will be deleted by the parent
- m_dialogHolder.release();
-
- const auto wasVisible = m_dialog->isVisible();
+ const auto wasVisible = isVisible();
- m_dialog->hide();
- m_dialog->setParent(w, m_dialog->windowFlags() | Qt::Dialog);
- m_dialog->setModal(false);
- m_dialog->setVisible(wasVisible);
+ hide();
+ setParent(w, windowFlags() | Qt::Dialog);
+ setModal(false);
+ setVisible(wasVisible);
}
void ValidationProgressDialog::start()
{
if (!m_timer) {
- m_timer = new QTimer(m_dialog);
+ m_timer = new QTimer(this);
connect(m_timer, &QTimer::timeout, [&]{ onTimer(); });
m_timer->setInterval(100ms);
}
m_bar->setRange(0, m_timeout.count());
+ m_bar->setValue(0);
+
m_elapsed.start();
m_timer->start();
- m_dialog->show();
+ show();
}
void ValidationProgressDialog::stop()
{
m_timer->stop();
- m_dialog->hide();
+ hide();
+}
+
+void ValidationProgressDialog::closeEvent(QCloseEvent* e)
+{
+ hide();
+ e->ignore();
}
void ValidationProgressDialog::onButton(QAbstractButton* b)
{
+ if (m_buttons->buttonRole(b) == QDialogButtonBox::RejectRole) {
+ hide();
+ } else {
+ qCritical() << "validation dialog: unknown button pressed";
+ }
}
void ValidationProgressDialog::onTimer()
@@ -212,14 +221,7 @@ void NXMAccessManager::startValidationCheck()
bool NXMAccessManager::validated() const
{
if (m_ValidateState == VALIDATE_CHECKING) {
- m_ProgressDialog.start();
-
- while (m_ValidateState == VALIDATE_CHECKING) {
- QCoreApplication::processEvents();
- QThread::msleep(100);
- }
-
- m_ProgressDialog.stop();
+ m_ProgressDialog.show();
}
return m_ValidateState == VALIDATE_VALID;
diff --git a/src/nxmaccessmanager.h b/src/nxmaccessmanager.h
index b20cb6e8..4467ea8d 100644
--- a/src/nxmaccessmanager.h
+++ b/src/nxmaccessmanager.h
@@ -26,11 +26,12 @@ along with Mod Organizer. If not, see .
#include
#include
#include
+#include
#include
namespace MOBase { class IPluginGame; }
-class ValidationProgressDialog : QObject
+class ValidationProgressDialog : private QDialog
{
Q_OBJECT;
@@ -38,14 +39,19 @@ public:
ValidationProgressDialog(std::chrono::seconds timeout);
void setParentWidget(QWidget* w);
+
void start();
void stop();
+ using QDialog::show;
+
+protected:
+ void closeEvent(QCloseEvent* e) override;
+
private:
std::chrono::seconds m_timeout;
- std::unique_ptr m_dialogHolder;
- QDialog* m_dialog;
QProgressBar* m_bar;
+ QDialogButtonBox* m_buttons;
QTimer* m_timer;
QElapsedTimer m_elapsed;
--
cgit v1.3.1
From fa6602816160f6ac959527ce843dee22b1272603 Mon Sep 17 00:00:00 2001
From: isanae <14251494+isanae@users.noreply.github.com>
Date: Tue, 9 Jul 2019 00:47:29 -0400
Subject: dialog should be on the heap, gets deleted by the main window
---
src/nxmaccessmanager.cpp | 19 +++++++++----------
src/nxmaccessmanager.h | 2 +-
2 files changed, 10 insertions(+), 11 deletions(-)
(limited to 'src/nxmaccessmanager.h')
diff --git a/src/nxmaccessmanager.cpp b/src/nxmaccessmanager.cpp
index a68dea54..cabe07a9 100644
--- a/src/nxmaccessmanager.cpp
+++ b/src/nxmaccessmanager.cpp
@@ -46,9 +46,8 @@ const QString NexusBaseUrl("https://api.nexusmods.com/v1");
const auto ValidationTimeout = 10s;
-ValidationProgressDialog::ValidationProgressDialog(std::chrono::seconds t) :
- m_timeout(t), m_bar(nullptr), m_buttons(nullptr),
- m_timer(nullptr)
+ValidationProgressDialog::ValidationProgressDialog(std::chrono::seconds t)
+ : m_timeout(t), m_bar(nullptr), m_buttons(nullptr), m_timer(nullptr)
{
m_bar = new QProgressBar;
m_bar->setTextVisible(false);
@@ -123,7 +122,7 @@ void ValidationProgressDialog::onTimer()
NXMAccessManager::NXMAccessManager(QObject *parent, const QString &moVersion)
: QNetworkAccessManager(parent)
, m_ValidateReply(nullptr)
- , m_ProgressDialog(ValidationTimeout)
+ , m_ProgressDialog(new ValidationProgressDialog(ValidationTimeout))
, m_MOVersion(moVersion)
{
m_ValidateTimeout.setSingleShot(true);
@@ -149,7 +148,7 @@ NXMAccessManager::~NXMAccessManager()
void NXMAccessManager::setTopLevelWidget(QWidget* w)
{
- m_ProgressDialog.setParentWidget(w);
+ m_ProgressDialog->setParentWidget(w);
}
QNetworkReply *NXMAccessManager::createRequest(
@@ -206,7 +205,7 @@ void NXMAccessManager::startValidationCheck()
request.setRawHeader("Application-Name", "MO2");
request.setRawHeader("Application-Version", m_MOVersion.toUtf8());
- m_ProgressDialog.start();
+ m_ProgressDialog->start();
QCoreApplication::processEvents(); // for some reason the whole app hangs during the login. This way the user has at least a little feedback
@@ -221,7 +220,7 @@ void NXMAccessManager::startValidationCheck()
bool NXMAccessManager::validated() const
{
if (m_ValidateState == VALIDATE_CHECKING) {
- m_ProgressDialog.show();
+ m_ProgressDialog->show();
}
return m_ValidateState == VALIDATE_VALID;
@@ -300,7 +299,7 @@ void NXMAccessManager::clearApiKey()
void NXMAccessManager::validateTimeout()
{
m_ValidateTimeout.stop();
- m_ProgressDialog.stop();
+ m_ProgressDialog->stop();
m_ApiKey.clear();
m_ValidateState = VALIDATE_NOT_VALID;
@@ -317,7 +316,7 @@ void NXMAccessManager::validateTimeout()
void NXMAccessManager::validateError(QNetworkReply::NetworkError)
{
m_ValidateTimeout.stop();
- m_ProgressDialog.stop();
+ m_ProgressDialog->stop();
m_ApiKey.clear();
m_ValidateState = VALIDATE_NOT_VALID;
@@ -337,7 +336,7 @@ void NXMAccessManager::validateError(QNetworkReply::NetworkError)
void NXMAccessManager::validateFinished()
{
m_ValidateTimeout.stop();
- m_ProgressDialog.stop();
+ m_ProgressDialog->stop();
if (m_ValidateReply != nullptr) {
QJsonDocument jdoc = QJsonDocument::fromJson(m_ValidateReply->readAll());
diff --git a/src/nxmaccessmanager.h b/src/nxmaccessmanager.h
index 4467ea8d..f53f6648 100644
--- a/src/nxmaccessmanager.h
+++ b/src/nxmaccessmanager.h
@@ -130,7 +130,7 @@ private:
QWidget* m_TopLevel;
QTimer m_ValidateTimeout;
QNetworkReply *m_ValidateReply;
- mutable ValidationProgressDialog m_ProgressDialog;
+ mutable ValidationProgressDialog* m_ProgressDialog;
QString m_MOVersion;
--
cgit v1.3.1
From 5e5681709ab878f3aa6cf1344af44e8ae9544987 Mon Sep 17 00:00:00 2001
From: isanae <14251494+isanae@users.noreply.github.com>
Date: Thu, 11 Jul 2019 01:55:31 -0400
Subject: reworked the nexus connection panel moved most of the stuff into a
new NexusSSOLogin class
---
src/nxmaccessmanager.cpp | 2 +-
src/nxmaccessmanager.h | 1 +
src/settingsdialog.cpp | 321 +++++++++++++++++++++++++++++++------------
src/settingsdialog.h | 62 +++++++--
src/settingsdialog.ui | 351 ++++++++++++++++++++++++++++++++---------------
5 files changed, 531 insertions(+), 206 deletions(-)
(limited to 'src/nxmaccessmanager.h')
diff --git a/src/nxmaccessmanager.cpp b/src/nxmaccessmanager.cpp
index cabe07a9..8bbfd536 100644
--- a/src/nxmaccessmanager.cpp
+++ b/src/nxmaccessmanager.cpp
@@ -43,7 +43,7 @@ using namespace MOBase;
using namespace std::chrono_literals;
const QString NexusBaseUrl("https://api.nexusmods.com/v1");
-const auto ValidationTimeout = 10s;
+const std::chrono::seconds NXMAccessManager::ValidationTimeout = 10s;
ValidationProgressDialog::ValidationProgressDialog(std::chrono::seconds t)
diff --git a/src/nxmaccessmanager.h b/src/nxmaccessmanager.h
index f53f6648..cbec0530 100644
--- a/src/nxmaccessmanager.h
+++ b/src/nxmaccessmanager.h
@@ -67,6 +67,7 @@ class NXMAccessManager : public QNetworkAccessManager
{
Q_OBJECT
public:
+ static const std::chrono::seconds ValidationTimeout;
explicit NXMAccessManager(QObject *parent, const QString &moVersion);
diff --git a/src/settingsdialog.cpp b/src/settingsdialog.cpp
index 95e4ceb0..d1ace6a5 100644
--- a/src/settingsdialog.cpp
+++ b/src/settingsdialog.cpp
@@ -49,6 +49,8 @@ along with Mod Organizer. If not, see .
using namespace MOBase;
+const QString NexusSSO("wss://sso.nexusmods.com");
+const QString NexusSSOPage("https://www.nexusmods.com/sso?id=%1&application=modorganizer2");
class NexusManualKeyDialog : public QDialog
{
@@ -98,35 +100,177 @@ private:
};
+
+NexusSSOLogin::NexusSSOLogin()
+ : m_keyReceived(false), m_active(false)
+{
+ QObject::connect(
+ &m_socket, &QWebSocket::connected,
+ [&]{ onConnected(); });
+
+ QObject::connect(
+ &m_socket, qOverload(&QWebSocket::error),
+ [&](auto&& e){ onError(e); });
+
+ QObject::connect(
+ &m_socket, &QWebSocket::textMessageReceived,
+ [&](auto&& s){ onMessage(s); });
+
+ QObject::connect(
+ &m_socket, &QWebSocket::disconnected,
+ [&]{ onDisconnected(); });
+
+ QObject::connect(&m_timeout, &QTimer::timeout, [&]{ onTimeout(); });
+}
+
+void NexusSSOLogin::start()
+{
+ m_active = true;
+ setState(ConnectingToSSO);
+ m_timeout.start(NXMAccessManager::ValidationTimeout);
+ m_socket.open(NexusSSO);
+}
+
+void NexusSSOLogin::cancel()
+{
+ abort();
+ setState(Cancelled);
+}
+
+void NexusSSOLogin::close()
+{
+ m_active = false;
+ m_timeout.stop();
+ m_socket.close();
+}
+
+void NexusSSOLogin::abort()
+{
+ m_active = false;
+ m_timeout.stop();
+ m_socket.abort();
+}
+
+bool NexusSSOLogin::isActive() const
+{
+ return m_active;
+}
+
+void NexusSSOLogin::setState(States s, const QString& error)
+{
+ if (stateChanged) {
+ stateChanged(s, error);
+ }
+}
+
+void NexusSSOLogin::onConnected()
+{
+ setState(WaitingForToken);
+
+ m_keyReceived = false;
+
+ //if (m_guid.isEmpty()) {
+ boost::uuids::random_generator generator;
+ boost::uuids::uuid sessionId = generator();
+ m_guid = boost::uuids::to_string(sessionId).c_str();
+ //}
+
+ QJsonObject data;
+ data.insert(QString("id"), QJsonValue(m_guid));
+ //data.insert(QString("token"), QJsonValue(m_token));
+ data.insert(QString("protocol"), 2);
+
+ const QString message = QJsonDocument(data).toJson();
+ m_socket.sendTextMessage(message);
+}
+
+void NexusSSOLogin::onMessage(const QString& s)
+{
+ const QJsonDocument doc = QJsonDocument::fromJson(s.toUtf8());
+ const QVariantMap root = doc.object().toVariantMap();
+
+ if (!root["success"].toBool()) {
+ close();
+
+ setState(Error, QString("There was a problem with SSO initialization: %1")
+ .arg(root["error"].toString()));
+
+ return;
+ }
+
+ const QVariantMap data = root["data"].toMap();
+
+ if (data.contains("connection_token")) {
+ // first answer
+ m_token = data["connection_token"].toString();
+
+ // open browser
+ const auto url = NexusSSOPage.arg(m_guid);
+ shell::OpenLink(url);
+
+ m_timeout.stop();
+ setState(WaitingForBrowser);
+ } else {
+ // second answer
+ const auto key = data["api_key"].toString();
+ close();
+
+ if (keyChanged) {
+ keyChanged(key);
+ }
+
+ setState(Finished);
+ }
+}
+
+void NexusSSOLogin::onDisconnected()
+{
+ if (m_active) {
+ m_active = false;
+
+ if (!m_keyReceived) {
+ setState(ClosedByRemote);
+ }
+ }
+}
+
+void NexusSSOLogin::onError(QAbstractSocket::SocketError e)
+{
+ if (m_active) {
+ setState(Error, m_socket.errorString());
+ }
+}
+
+void NexusSSOLogin::onTimeout()
+{
+ abort();
+ setState(Timeout);
+}
+
+
SettingsDialog::SettingsDialog(PluginContainer *pluginContainer, Settings* settings, QWidget *parent)
: TutorableDialog("SettingsDialog", parent)
, ui(new Ui::SettingsDialog)
, m_settings(settings)
, m_PluginContainer(pluginContainer)
- , m_nexusLogin(new QWebSocket)
- , m_KeyReceived(false)
- , m_KeyCleared(false)
+ , m_keyChanged(false)
, m_GeometriesReset(false)
{
+ m_nexusLogin.keyChanged = [&](auto&& s){ onKeyChanged(s); };
+ m_nexusLogin.stateChanged = [&](auto&& s, auto&& e){ onStateChanged(s, e); };
+
ui->setupUi(this);
ui->pluginSettingsList->setStyleSheet("QTreeWidget::item {padding-right: 10px;}");
QShortcut *delShortcut
= new QShortcut(QKeySequence(Qt::Key_Delete), ui->pluginBlacklist);
connect(delShortcut, SIGNAL(activated()), this, SLOT(deleteBlacklistItem()));
- connect(m_nexusLogin, SIGNAL(connected()), this, SLOT(dispatchLogin()));
- connect(m_nexusLogin, SIGNAL(error(QAbstractSocket::SocketError)), this, SLOT(authError(QAbstractSocket::SocketError)));
- connect(m_nexusLogin, SIGNAL(textMessageReceived(const QString &)), this, SLOT(receiveApiKey(const QString &)));
- connect(m_nexusLogin, SIGNAL(disconnected()), this, SLOT(completeApiConnection()));
- m_loginTimer.callOnTimeout(this, &SettingsDialog::loginPing);
updateNexusButtons();
}
SettingsDialog::~SettingsDialog()
{
- m_loginTimer.stop();
- m_nexusLogin->close();
disconnect(this);
delete ui;
}
@@ -188,7 +332,7 @@ bool SettingsDialog::getResetGeometries()
bool SettingsDialog::getApiKeyChanged()
{
- return m_KeyReceived || m_KeyCleared;
+ return m_keyChanged;
}
void SettingsDialog::on_categoriesBtn_clicked()
@@ -391,7 +535,11 @@ void SettingsDialog::on_resetDialogsButton_clicked()
void SettingsDialog::on_nexusConnect_clicked()
{
- fetchNexusApiKey();
+ if (m_nexusLogin.isActive()) {
+ m_nexusLogin.cancel();
+ } else {
+ fetchNexusApiKey();
+ }
}
void SettingsDialog::on_nexusManualKey_clicked()
@@ -415,92 +563,95 @@ void SettingsDialog::on_nexusManualKey_clicked()
void SettingsDialog::fetchNexusApiKey()
{
- QUrl url = QUrl("wss://sso.nexusmods.com");
- m_nexusLogin->open(url);
+ ui->nexusLog->clear();
+ m_nexusLogin.start();
updateNexusButtons();
}
-void SettingsDialog::dispatchLogin()
+void SettingsDialog::onKeyChanged(const QString& key)
{
- m_KeyReceived = false;
- QJsonObject login;
- if (m_UUID.isEmpty()) {
- boost::uuids::random_generator generator;
- boost::uuids::uuid sessionId = generator();
- m_UUID = boost::uuids::to_string(sessionId).c_str();
+ if (key.isEmpty()) {
+ clearKey();
+ } else {
+ setKey(key);
}
- login.insert(QString("id"), QJsonValue(m_UUID));
- login.insert(QString("token"), QJsonValue(m_AuthToken));
- login.insert(QString("protocol"), 2);
- QJsonDocument loginDoc(login);
- QString finalMessage(loginDoc.toJson());
- m_nexusLogin->sendTextMessage(finalMessage);
- QDesktopServices::openUrl(QUrl(QString("https://www.nexusmods.com/sso?id=%1&application=%2").arg(m_UUID).arg("modorganizer2")));
- m_loginTimer.start(30000);
}
-void SettingsDialog::loginPing()
+void SettingsDialog::onStateChanged(NexusSSOLogin::States s, const QString& e)
{
- if (m_nexusLogin->isValid()) {
- m_nexusLogin->ping();
- m_totalPings++;
- }
- if (m_totalPings >= 60) {
- m_loginTimer.stop();
- m_totalPings = 0;
- m_nexusLogin->close(QWebSocketProtocol::CloseCodeGoingAway, "Timeout: No response received after thirty minutes. Cancelling request.");
- }
-}
+ QString log;
-void SettingsDialog::authError(QAbstractSocket::SocketError error)
-{
- auto errorInfo = m_nexusLogin->errorString();
- qCritical() << "An error occurred: " << errorInfo;
-}
+ switch (s)
+ {
+ case NexusSSOLogin::Idle:
+ {
+ break;
+ }
-void SettingsDialog::receiveApiKey(const QString &response)
-{
- QJsonDocument responseDoc = QJsonDocument::fromJson(response.toUtf8());
- QVariantMap responseData = responseDoc.object().toVariantMap();
- if (responseData["success"].toBool()) {
- QVariantMap data = responseData["data"].toMap();
- if (data.contains("connection_token")) {
- m_AuthToken = data["connection_token"].toString();
- } else {
- const auto key = data["api_key"].toString();
+ case NexusSSOLogin::ConnectingToSSO:
+ {
+ log = tr("Connecting to Nexus...");
+ break;
+ }
+
+ case NexusSSOLogin::WaitingForToken:
+ {
+ log = tr("Waiting for Nexus...");
+ break;
+ }
- m_nexusLogin->close();
- m_loginTimer.stop();
- m_totalPings = 0;
+ case NexusSSOLogin::WaitingForBrowser:
+ {
+ log = tr("Opened browser, waiting for user...");
+ break;
+ }
- if (key.isEmpty()) {
- clearKey();
- } else {
- setKey(key);
- }
+ case NexusSSOLogin::Finished:
+ {
+ log = tr("Connected.");
+ break;
}
- } else {
- QString error("There was a problem with SSO initialization: %1");
- qCritical() << error.arg(responseData["error"].toString());
- m_nexusLogin->close();
- }
-}
-void SettingsDialog::completeApiConnection()
-{
- if (!m_KeyReceived && !m_loginTimer.isActive()) {
- QMessageBox::warning(qApp->activeWindow(), tr("Error"),
- tr("Failed to retrieve a Nexus API key! Please try again. "
- "A browser window should open asking you to authorize."));
+ case NexusSSOLogin::Timeout:
+ {
+ log = QObject::tr(
+ "No answer from Nexus.\n"
+ "A firewall might be blocking Mod Organizer.");
- // try again
- fetchNexusApiKey();
+ break;
+ }
+
+ case NexusSSOLogin::ClosedByRemote:
+ {
+ log = QObject::tr("Nexus closed the connection.");
+ break;
+ }
+
+ case NexusSSOLogin::Cancelled:
+ {
+ log = QObject::tr("Cancelled.");
+ break;
+ }
+
+ case NexusSSOLogin::Error:
+ {
+ log = tr("Error: %1.").arg(e);
+ break;
+ }
}
+
+ if (!log.isEmpty()) {
+ for (auto&& line : log.split("\n")) {
+ ui->nexusLog->addItem(line);
+ }
+ }
+
+ updateNexusButtons();
}
bool SettingsDialog::setKey(const QString& key)
{
- m_KeyReceived = true;
+ m_keyChanged = true;
const bool ret = m_settings->setNexusApiKey(key);
updateNexusButtons();
return ret;
@@ -508,7 +659,7 @@ bool SettingsDialog::setKey(const QString& key)
bool SettingsDialog::clearKey()
{
- m_KeyCleared = true;
+ m_keyChanged = true;
const auto ret = m_settings->clearNexusApiKey();
updateNexusButtons();
@@ -530,22 +681,22 @@ void SettingsDialog::testApiKey()
void SettingsDialog::updateNexusButtons()
{
- if (m_nexusLogin->state() != QAbstractSocket::UnconnectedState) {
+ if (m_nexusLogin.isActive()) {
// api key is in the process of being retrieved
- ui->nexusConnect->setText("Connecting the API. Please login within the browser and accept the request. This will time out after 30 minutes.");
- ui->nexusConnect->setEnabled(false);
+ ui->nexusConnect->setText(tr("Cancel"));
+ ui->nexusConnect->setEnabled(true);
ui->nexusDisconnect->setEnabled(false);
ui->nexusManualKey->setEnabled(false);
}
else if (m_settings->hasNexusApiKey()) {
// api key is present
- ui->nexusConnect->setText("Nexus API Key Stored");
+ ui->nexusConnect->setText(tr("Connect to Nexus"));
ui->nexusConnect->setEnabled(false);
ui->nexusDisconnect->setEnabled(true);
ui->nexusManualKey->setEnabled(false);
} else {
// api key not present
- ui->nexusConnect->setText("Connect to Nexus");
+ ui->nexusConnect->setText(tr("Connect to Nexus"));
ui->nexusConnect->setEnabled(true);
ui->nexusDisconnect->setEnabled(false);
ui->nexusManualKey->setEnabled(true);
@@ -622,6 +773,8 @@ void SettingsDialog::on_clearCacheButton_clicked()
void SettingsDialog::on_nexusDisconnect_clicked()
{
clearKey();
+ ui->nexusLog->clear();
+ ui->nexusLog->addItem(tr("Disconnected."));
}
void SettingsDialog::normalizePath(QLineEdit *lineEdit)
diff --git a/src/settingsdialog.h b/src/settingsdialog.h
index 858a36d4..aee447d7 100644
--- a/src/settingsdialog.h
+++ b/src/settingsdialog.h
@@ -35,6 +35,52 @@ namespace Ui {
class SettingsDialog;
}
+class NexusSSOLogin
+{
+public:
+ enum States
+ {
+ Idle,
+ ConnectingToSSO,
+ WaitingForToken,
+ WaitingForBrowser,
+ Finished,
+ Timeout,
+ ClosedByRemote,
+ Cancelled,
+ Error
+ };
+
+ std::function keyChanged;
+ std::function stateChanged;
+
+ NexusSSOLogin();
+
+ void start();
+ void cancel();
+
+ bool isActive() const;
+
+private:
+ QWebSocket m_socket;
+ QString m_guid;
+ bool m_keyReceived;
+ QString m_token;
+ bool m_active;
+ QTimer m_timeout;
+
+ void setState(States s, const QString& error={});
+
+ void close();
+ void abort();
+
+ void onConnected();
+ void onMessage(const QString& s);
+ void onDisconnected();
+ void onError(QAbstractSocket::SocketError e);
+ void onTimeout();
+};
+
/**
* dialog used to change settings for Mod Organizer. On top of the
* settings managed by the "Settings" class, this offers a button to open the
@@ -127,11 +173,6 @@ private slots:
void on_resetGeometryBtn_clicked();
void deleteBlacklistItem();
- void dispatchLogin();
- void loginPing();
- void authError(QAbstractSocket::SocketError error);
- void receiveApiKey(const QString &apiKey);
- void completeApiConnection();
private:
Ui::SettingsDialog *ui;
@@ -145,16 +186,11 @@ private:
QColor m_ContainsColor;
QColor m_ContainedColor;
- bool m_KeyReceived;
- bool m_KeyCleared;
bool m_GeometriesReset;
- QString m_UUID;
- QString m_AuthToken;
+ bool m_keyChanged;
QString m_ExecutableBlacklist;
- QWebSocket *m_nexusLogin;
- QTimer m_loginTimer;
- int m_totalPings = 0;
+ NexusSSOLogin m_nexusLogin;
bool setKey(const QString& key);
bool clearKey();
@@ -162,6 +198,8 @@ private:
void fetchNexusApiKey();
void testApiKey();
+ void onKeyChanged(const QString& key);
+ void onStateChanged(NexusSSOLogin::States s, const QString& e);
};
#endif // SETTINGSDIALOG_H
diff --git a/src/settingsdialog.ui b/src/settingsdialog.ui
index faaf1653..dfbde943 100644
--- a/src/settingsdialog.ui
+++ b/src/settingsdialog.ui
@@ -451,111 +451,244 @@ If you use pre-releases, never contact me directly by e-mail or via private mess
Nexus
-
+
-
-
-
- Allows Mod Organizer to connect to the Nexus for downloading mods, checking for updates, and other such things.
-
-
- <!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.0//EN" "http://www.w3.org/TR/REC-html40/strict.dtd">
-<html><head><meta name="qrichtext" content="1" /><style type="text/css">
-p, li { white-space: pre-wrap; }
-</style></head><body style=" font-family:'MS Shell Dlg 2'; font-size:8pt; font-weight:400; font-style:normal;">
-<p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;">Allows Mod Organizer to connect to the Nexus for downloading mods, checking for updates, and other such things. Clicking "Connect to Nexus" will open a Nexus webpage to authorise Mod Organizer. You will need to be logged into your Nexus account. The authorisation is stored in the Windows Credential Manager. Your Nexus username and password are not required or stored by Mod Organizer.</p></body></html>
-
+
- Nexus
+ Nexus Connection
-
+
-
-
-
-
-
-
- Connect to Nexus
-
-
-
-
+
+
+
+ 0
+
+
+ 0
+
+
+ 0
+
+
+ 0
+
+ -
+
+
+ Connect to Nexus
+
+
+
+ -
+
+
+ Manually enter the API key and try to login
+
+
+ Enter API Key Manually
+
+
+
+ -
+
+
+ Clear the stored Nexus API key and force reauthorization.
+
+
+ Disconnect from Nexus
+
+
+
+ :/MO/gui/edit_clear:/MO/gui/edit_clear
+
+
+
+ -
+
+
+ Qt::Vertical
+
+
+
+ 0
+ 0
+
+
+
+
+
+
-
-
-
-
-
-
- Qt::Horizontal
-
-
-
- 40
- 20
-
-
-
-
- -
-
-
-
- 0
- 0
-
-
-
- Manually enter the API key and try to login
-
-
- Enter API Key Manually
-
-
-
- -
-
-
- Clear the stored Nexus API key and force reauthorization.
-
-
- Disconnect from Nexus
-
-
-
- :/MO/gui/edit_clear:/MO/gui/edit_clear
-
-
-
- -
-
-
- Remove cache and cookies.
-
-
- Clear Cache
-
-
-
- :/MO/gui/edit_clear:/MO/gui/edit_clear
-
-
-
- -
-
-
- Qt::Horizontal
-
-
-
- 40
- 20
-
-
-
-
-
+
+
+
+ 0
+
+
+ 0
+
+
+ 0
+
+
+ 0
+
+ -
+
+
+ QAbstractScrollArea::AdjustToContents
+
+
+
+
+
+
+
+
+
+ -
+
+
+
+ 0
+
+
+ 0
+
+
+ 0
+
+
+ 0
+
+
-
+
+
+ Nexus Account
+
+
+
-
+
+
+ User ID
+
+
+ Qt::LinksAccessibleByMouse|Qt::TextSelectableByKeyboard|Qt::TextSelectableByMouse
+
+
+
+ -
+
+
+ id
+
+
+
+ -
+
+
+ Username
+
+
+
+ -
+
+
+ username
+
+
+
+ -
+
+
+ Account
+
+
+
+ -
+
+
+ account
+
+
+
+
+
+
+ -
+
+
+ Statistics
+
+
+
-
+
+
+ Daily requests
+
+
+
+ -
+
+
+ Hourly requests
+
+
+
+ -
+
+
+ hourly requests
+
+
+
+ -
+
+
+ Requests queued
+
+
+
+ -
+
+
+ queued
+
+
+
+ -
+
+
+ daily requests
+
+
+
+
+
+ -
+
+
+
+ 0
+
+
+ 0
+
+
+ 0
+
+
+ 0
+
+
+
+
-
-
@@ -618,6 +751,20 @@ p, li { white-space: pre-wrap; }
+ -
+
+
+ Remove cache and cookies.
+
+
+ Clear Cache
+
+
+
+ :/MO/gui/edit_clear:/MO/gui/edit_clear
+
+
+
-
@@ -682,19 +829,6 @@ p, li { white-space: pre-wrap; }
- -
-
-
- Qt::Vertical
-
-
-
- 20
- 40
-
-
-
-
@@ -1359,7 +1493,6 @@ programs you are intentionally running.
browseProfilesDirBtn
overwriteDirEdit
browseOverwriteDirBtn
- clearCacheButton
associateButton
knownServersList
preferredServersList
--
cgit v1.3.1
From ad29525e982f83343dbd70e17b914e0a30adb662 Mon Sep 17 00:00:00 2001
From: isanae <14251494+isanae@users.noreply.github.com>
Date: Thu, 11 Jul 2019 02:31:59 -0400
Subject: moved NexusSSOLogin to nxmaccessmanager added logs for manual key
validation, will need to rewrite a few things
---
src/nxmaccessmanager.cpp | 166 +++++++++++++++++++++++++++++++++++++--
src/nxmaccessmanager.h | 64 ++++++++++++++-
src/settingsdialog.cpp | 198 +++++++----------------------------------------
src/settingsdialog.h | 52 +------------
4 files changed, 250 insertions(+), 230 deletions(-)
(limited to 'src/nxmaccessmanager.h')
diff --git a/src/nxmaccessmanager.cpp b/src/nxmaccessmanager.cpp
index 8bbfd536..a274261d 100644
--- a/src/nxmaccessmanager.cpp
+++ b/src/nxmaccessmanager.cpp
@@ -44,6 +44,8 @@ using namespace std::chrono_literals;
const QString NexusBaseUrl("https://api.nexusmods.com/v1");
const std::chrono::seconds NXMAccessManager::ValidationTimeout = 10s;
+const QString NexusSSO("wss://sso.nexusmods.com");
+const QString NexusSSOPage("https://www.nexusmods.com/sso?id=%1&application=modorganizer2");
ValidationProgressDialog::ValidationProgressDialog(std::chrono::seconds t)
@@ -94,7 +96,10 @@ void ValidationProgressDialog::start()
void ValidationProgressDialog::stop()
{
- m_timer->stop();
+ if (m_timer) {
+ m_timer->stop();
+ }
+
hide();
}
@@ -119,6 +124,153 @@ void ValidationProgressDialog::onTimer()
}
+NexusSSOLogin::NexusSSOLogin()
+ : m_keyReceived(false), m_active(false)
+{
+ QObject::connect(
+ &m_socket, &QWebSocket::connected,
+ [&]{ onConnected(); });
+
+ QObject::connect(
+ &m_socket, qOverload(&QWebSocket::error),
+ [&](auto&& e){ onError(e); });
+
+ QObject::connect(
+ &m_socket, &QWebSocket::textMessageReceived,
+ [&](auto&& s){ onMessage(s); });
+
+ QObject::connect(
+ &m_socket, &QWebSocket::disconnected,
+ [&]{ onDisconnected(); });
+
+ QObject::connect(&m_timeout, &QTimer::timeout, [&]{ onTimeout(); });
+}
+
+void NexusSSOLogin::start()
+{
+ m_active = true;
+ setState(ConnectingToSSO);
+ m_timeout.start(NXMAccessManager::ValidationTimeout);
+ m_socket.open(NexusSSO);
+}
+
+void NexusSSOLogin::cancel()
+{
+ abort();
+ setState(Cancelled);
+}
+
+void NexusSSOLogin::close()
+{
+ m_active = false;
+ m_timeout.stop();
+ m_socket.close();
+}
+
+void NexusSSOLogin::abort()
+{
+ m_active = false;
+ m_timeout.stop();
+ m_socket.abort();
+}
+
+bool NexusSSOLogin::isActive() const
+{
+ return m_active;
+}
+
+void NexusSSOLogin::setState(States s, const QString& error)
+{
+ if (stateChanged) {
+ stateChanged(s, error);
+ }
+}
+
+void NexusSSOLogin::onConnected()
+{
+ setState(WaitingForToken);
+
+ m_keyReceived = false;
+
+ //if (m_guid.isEmpty()) {
+ boost::uuids::random_generator generator;
+ boost::uuids::uuid sessionId = generator();
+ m_guid = boost::uuids::to_string(sessionId).c_str();
+ //}
+
+ QJsonObject data;
+ data.insert(QString("id"), QJsonValue(m_guid));
+ //data.insert(QString("token"), QJsonValue(m_token));
+ data.insert(QString("protocol"), 2);
+
+ const QString message = QJsonDocument(data).toJson();
+ m_socket.sendTextMessage(message);
+}
+
+void NexusSSOLogin::onMessage(const QString& s)
+{
+ const QJsonDocument doc = QJsonDocument::fromJson(s.toUtf8());
+ const QVariantMap root = doc.object().toVariantMap();
+
+ if (!root["success"].toBool()) {
+ close();
+
+ setState(Error, QString("There was a problem with SSO initialization: %1")
+ .arg(root["error"].toString()));
+
+ return;
+ }
+
+ const QVariantMap data = root["data"].toMap();
+
+ if (data.contains("connection_token")) {
+ // first answer
+ m_token = data["connection_token"].toString();
+
+ // open browser
+ const auto url = NexusSSOPage.arg(m_guid);
+ shell::OpenLink(url);
+
+ m_timeout.stop();
+ setState(WaitingForBrowser);
+ } else {
+ // second answer
+ const auto key = data["api_key"].toString();
+ close();
+
+ if (keyChanged) {
+ keyChanged(key);
+ }
+
+ setState(Finished);
+ }
+}
+
+void NexusSSOLogin::onDisconnected()
+{
+ if (m_active) {
+ m_active = false;
+
+ if (!m_keyReceived) {
+ setState(ClosedByRemote);
+ }
+ }
+}
+
+void NexusSSOLogin::onError(QAbstractSocket::SocketError e)
+{
+ if (m_active) {
+ setState(Error, m_socket.errorString());
+ }
+}
+
+void NexusSSOLogin::onTimeout()
+{
+ abort();
+ setState(Timeout);
+}
+
+
NXMAccessManager::NXMAccessManager(QObject *parent, const QString &moVersion)
: QNetworkAccessManager(parent)
, m_ValidateReply(nullptr)
@@ -192,7 +344,7 @@ void NXMAccessManager::clearCookies()
}
}
-void NXMAccessManager::startValidationCheck()
+void NXMAccessManager::startValidationCheck(bool showProgress)
{
qDebug("Checking Nexus API Key...");
QString requestString = NexusBaseUrl + "/users/validate";
@@ -205,7 +357,9 @@ void NXMAccessManager::startValidationCheck()
request.setRawHeader("Application-Name", "MO2");
request.setRawHeader("Application-Version", m_MOVersion.toUtf8());
- m_ProgressDialog->start();
+ if (showProgress) {
+ m_ProgressDialog->start();
+ }
QCoreApplication::processEvents(); // for some reason the whole app hangs during the login. This way the user has at least a little feedback
@@ -245,13 +399,13 @@ bool NXMAccessManager::validateWaiting() const
}
-void NXMAccessManager::apiCheck(const QString &apiKey, bool force)
+void NXMAccessManager::apiCheck(const QString &apiKey, ApiCheckFlags flags)
{
if (m_ValidateReply != nullptr) {
return;
}
- if (force) {
+ if (flags & Force) {
m_ValidateState = VALIDATE_NOT_CHECKED;
}
@@ -261,7 +415,7 @@ void NXMAccessManager::apiCheck(const QString &apiKey, bool force)
}
m_ApiKey = apiKey;
- startValidationCheck();
+ startValidationCheck((flags & HideProgress) == 0);
}
diff --git a/src/nxmaccessmanager.h b/src/nxmaccessmanager.h
index cbec0530..08a799f9 100644
--- a/src/nxmaccessmanager.h
+++ b/src/nxmaccessmanager.h
@@ -27,6 +27,7 @@ along with Mod Organizer. If not, see .
#include
#include
#include
+#include
#include
namespace MOBase { class IPluginGame; }
@@ -60,6 +61,52 @@ private:
};
+class NexusSSOLogin
+{
+public:
+ enum States
+ {
+ ConnectingToSSO,
+ WaitingForToken,
+ WaitingForBrowser,
+ Finished,
+ Timeout,
+ ClosedByRemote,
+ Cancelled,
+ Error
+ };
+
+ std::function keyChanged;
+ std::function stateChanged;
+
+ NexusSSOLogin();
+
+ void start();
+ void cancel();
+
+ bool isActive() const;
+
+private:
+ QWebSocket m_socket;
+ QString m_guid;
+ bool m_keyReceived;
+ QString m_token;
+ bool m_active;
+ QTimer m_timeout;
+
+ void setState(States s, const QString& error={});
+
+ void close();
+ void abort();
+
+ void onConnected();
+ void onMessage(const QString& s);
+ void onDisconnected();
+ void onError(QAbstractSocket::SocketError e);
+ void onTimeout();
+};
+
+
/**
* @brief access manager extended to handle nxm links
**/
@@ -67,6 +114,15 @@ class NXMAccessManager : public QNetworkAccessManager
{
Q_OBJECT
public:
+ enum ApiCheckFlagsEnum
+ {
+ NoFlags = 0,
+ Force,
+ HideProgress
+ };
+
+ Q_DECLARE_FLAGS(ApiCheckFlags, ApiCheckFlagsEnum)
+
static const std::chrono::seconds ValidationTimeout;
explicit NXMAccessManager(QObject *parent, const QString &moVersion);
@@ -80,7 +136,7 @@ public:
bool validateAttempted() const;
bool validateWaiting() const;
- void apiCheck(const QString &apiKey, bool force=false);
+ void apiCheck(const QString &apiKey, ApiCheckFlags flags=NoFlags);
void showCookies() const;
@@ -91,8 +147,6 @@ public:
QString apiKey() const;
void clearApiKey();
- void startValidationCheck();
-
void refuseValidation();
signals:
@@ -145,6 +199,10 @@ private:
VALIDATE_REFUSED,
VALIDATE_VALID
} m_ValidateState = VALIDATE_NOT_CHECKED;
+
+ void startValidationCheck(bool showProgress);
};
+Q_DECLARE_OPERATORS_FOR_FLAGS(NXMAccessManager::ApiCheckFlags);
+
#endif // NXMACCESSMANAGER_H
diff --git a/src/settingsdialog.cpp b/src/settingsdialog.cpp
index d1ace6a5..0131d20b 100644
--- a/src/settingsdialog.cpp
+++ b/src/settingsdialog.cpp
@@ -28,7 +28,6 @@ along with Mod Organizer. If not, see .
#include "settings.h"
#include "instancemanager.h"
#include "nexusinterface.h"
-#include "nxmaccessmanager.h"
#include "plugincontainer.h"
#include
@@ -49,9 +48,6 @@ along with Mod Organizer. If not, see .
using namespace MOBase;
-const QString NexusSSO("wss://sso.nexusmods.com");
-const QString NexusSSOPage("https://www.nexusmods.com/sso?id=%1&application=modorganizer2");
-
class NexusManualKeyDialog : public QDialog
{
public:
@@ -100,154 +96,6 @@ private:
};
-
-NexusSSOLogin::NexusSSOLogin()
- : m_keyReceived(false), m_active(false)
-{
- QObject::connect(
- &m_socket, &QWebSocket::connected,
- [&]{ onConnected(); });
-
- QObject::connect(
- &m_socket, qOverload(&QWebSocket::error),
- [&](auto&& e){ onError(e); });
-
- QObject::connect(
- &m_socket, &QWebSocket::textMessageReceived,
- [&](auto&& s){ onMessage(s); });
-
- QObject::connect(
- &m_socket, &QWebSocket::disconnected,
- [&]{ onDisconnected(); });
-
- QObject::connect(&m_timeout, &QTimer::timeout, [&]{ onTimeout(); });
-}
-
-void NexusSSOLogin::start()
-{
- m_active = true;
- setState(ConnectingToSSO);
- m_timeout.start(NXMAccessManager::ValidationTimeout);
- m_socket.open(NexusSSO);
-}
-
-void NexusSSOLogin::cancel()
-{
- abort();
- setState(Cancelled);
-}
-
-void NexusSSOLogin::close()
-{
- m_active = false;
- m_timeout.stop();
- m_socket.close();
-}
-
-void NexusSSOLogin::abort()
-{
- m_active = false;
- m_timeout.stop();
- m_socket.abort();
-}
-
-bool NexusSSOLogin::isActive() const
-{
- return m_active;
-}
-
-void NexusSSOLogin::setState(States s, const QString& error)
-{
- if (stateChanged) {
- stateChanged(s, error);
- }
-}
-
-void NexusSSOLogin::onConnected()
-{
- setState(WaitingForToken);
-
- m_keyReceived = false;
-
- //if (m_guid.isEmpty()) {
- boost::uuids::random_generator generator;
- boost::uuids::uuid sessionId = generator();
- m_guid = boost::uuids::to_string(sessionId).c_str();
- //}
-
- QJsonObject data;
- data.insert(QString("id"), QJsonValue(m_guid));
- //data.insert(QString("token"), QJsonValue(m_token));
- data.insert(QString("protocol"), 2);
-
- const QString message = QJsonDocument(data).toJson();
- m_socket.sendTextMessage(message);
-}
-
-void NexusSSOLogin::onMessage(const QString& s)
-{
- const QJsonDocument doc = QJsonDocument::fromJson(s.toUtf8());
- const QVariantMap root = doc.object().toVariantMap();
-
- if (!root["success"].toBool()) {
- close();
-
- setState(Error, QString("There was a problem with SSO initialization: %1")
- .arg(root["error"].toString()));
-
- return;
- }
-
- const QVariantMap data = root["data"].toMap();
-
- if (data.contains("connection_token")) {
- // first answer
- m_token = data["connection_token"].toString();
-
- // open browser
- const auto url = NexusSSOPage.arg(m_guid);
- shell::OpenLink(url);
-
- m_timeout.stop();
- setState(WaitingForBrowser);
- } else {
- // second answer
- const auto key = data["api_key"].toString();
- close();
-
- if (keyChanged) {
- keyChanged(key);
- }
-
- setState(Finished);
- }
-}
-
-void NexusSSOLogin::onDisconnected()
-{
- if (m_active) {
- m_active = false;
-
- if (!m_keyReceived) {
- setState(ClosedByRemote);
- }
- }
-}
-
-void NexusSSOLogin::onError(QAbstractSocket::SocketError e)
-{
- if (m_active) {
- setState(Error, m_socket.errorString());
- }
-}
-
-void NexusSSOLogin::onTimeout()
-{
- abort();
- setState(Timeout);
-}
-
-
SettingsDialog::SettingsDialog(PluginContainer *pluginContainer, Settings* settings, QWidget *parent)
: TutorableDialog("SettingsDialog", parent)
, ui(new Ui::SettingsDialog)
@@ -259,11 +107,22 @@ SettingsDialog::SettingsDialog(PluginContainer *pluginContainer, Settings* setti
m_nexusLogin.keyChanged = [&](auto&& s){ onKeyChanged(s); };
m_nexusLogin.stateChanged = [&](auto&& s, auto&& e){ onStateChanged(s, e); };
+ connect(
+ NexusInterface::instance(m_PluginContainer)->getAccessManager(),
+ &NXMAccessManager::validateSuccessful,
+ [&]{ onManualKeyValidation(true, ""); });
+
+ connect(
+ NexusInterface::instance(m_PluginContainer)->getAccessManager(),
+ &NXMAccessManager::validateFailed,
+ [&](auto&& e){ onManualKeyValidation(false, e); });
+
+
ui->setupUi(this);
ui->pluginSettingsList->setStyleSheet("QTreeWidget::item {padding-right: 10px;}");
- QShortcut *delShortcut
- = new QShortcut(QKeySequence(Qt::Key_Delete), ui->pluginBlacklist);
+ QShortcut *delShortcut = new QShortcut(
+ QKeySequence(Qt::Key_Delete), ui->pluginBlacklist);
connect(delShortcut, SIGNAL(activated()), this, SLOT(deleteBlacklistItem()));
updateNexusButtons();
@@ -556,7 +415,11 @@ void SettingsDialog::on_nexusManualKey_clicked()
clearKey();
} else {
if (setKey(key)) {
- testApiKey();
+ ui->nexusLog->clear();
+ ui->nexusLog->addItem(tr("Checking API key..."));
+
+ NexusInterface::instance(m_PluginContainer)->getAccessManager()->apiCheck(
+ key, NXMAccessManager::Force | NXMAccessManager::HideProgress);
}
}
}
@@ -583,11 +446,6 @@ void SettingsDialog::onStateChanged(NexusSSOLogin::States s, const QString& e)
switch (s)
{
- case NexusSSOLogin::Idle:
- {
- break;
- }
-
case NexusSSOLogin::ConnectingToSSO:
{
log = tr("Connecting to Nexus...");
@@ -649,6 +507,15 @@ void SettingsDialog::onStateChanged(NexusSSOLogin::States s, const QString& e)
updateNexusButtons();
}
+void SettingsDialog::onManualKeyValidation(bool success, const QString& e)
+{
+ if (success) {
+ ui->nexusLog->addItem("Connected.");
+ } else {
+ ui->nexusLog->addItem("Error: " + e);
+ }
+}
+
bool SettingsDialog::setKey(const QString& key)
{
m_keyChanged = true;
@@ -668,17 +535,6 @@ bool SettingsDialog::clearKey()
return ret;
}
-void SettingsDialog::testApiKey()
-{
- QString key;
- if (!m_settings->getNexusApiKey(key)) {
- qWarning().nospace() << "can't test API key, nothing stored";
- return;
- }
-
- NexusInterface::instance(m_PluginContainer)->getAccessManager()->apiCheck(key, true);
-}
-
void SettingsDialog::updateNexusButtons()
{
if (m_nexusLogin.isActive()) {
diff --git a/src/settingsdialog.h b/src/settingsdialog.h
index aee447d7..507214dd 100644
--- a/src/settingsdialog.h
+++ b/src/settingsdialog.h
@@ -21,12 +21,9 @@ along with Mod Organizer. If not, see .
#define SETTINGSDIALOG_H
#include "tutorabledialog.h"
+#include "nxmaccessmanager.h"
#include
-#include
-#include
-#include
#include
-#include
class PluginContainer;
class Settings;
@@ -35,51 +32,6 @@ namespace Ui {
class SettingsDialog;
}
-class NexusSSOLogin
-{
-public:
- enum States
- {
- Idle,
- ConnectingToSSO,
- WaitingForToken,
- WaitingForBrowser,
- Finished,
- Timeout,
- ClosedByRemote,
- Cancelled,
- Error
- };
-
- std::function keyChanged;
- std::function stateChanged;
-
- NexusSSOLogin();
-
- void start();
- void cancel();
-
- bool isActive() const;
-
-private:
- QWebSocket m_socket;
- QString m_guid;
- bool m_keyReceived;
- QString m_token;
- bool m_active;
- QTimer m_timeout;
-
- void setState(States s, const QString& error={});
-
- void close();
- void abort();
-
- void onConnected();
- void onMessage(const QString& s);
- void onDisconnected();
- void onError(QAbstractSocket::SocketError e);
- void onTimeout();
-};
/**
* dialog used to change settings for Mod Organizer. On top of the
@@ -197,9 +149,9 @@ private:
void updateNexusButtons();
void fetchNexusApiKey();
- void testApiKey();
void onKeyChanged(const QString& key);
void onStateChanged(NexusSSOLogin::States s, const QString& e);
+ void onManualKeyValidation(bool success, const QString& e);
};
#endif // SETTINGSDIALOG_H
--
cgit v1.3.1
From c0a52bc1ca3bcde8107f7cd2b8924c1dda487b1c Mon Sep 17 00:00:00 2001
From: isanae <14251494+isanae@users.noreply.github.com>
Date: Thu, 11 Jul 2019 05:06:42 -0400
Subject: extracted api key validator from NXMAccessManager api key now part of
ApiUserAccount
---
src/apiuseraccount.cpp | 11 ++
src/apiuseraccount.h | 13 +-
src/nexusinterface.cpp | 25 ++-
src/nexusinterface.h | 1 +
src/nxmaccessmanager.cpp | 441 +++++++++++++++++++++++++++++++----------------
src/nxmaccessmanager.h | 86 ++++++---
src/organizercore.cpp | 3 +-
7 files changed, 403 insertions(+), 177 deletions(-)
(limited to 'src/nxmaccessmanager.h')
diff --git a/src/apiuseraccount.cpp b/src/apiuseraccount.cpp
index b901e41a..596f8aa7 100644
--- a/src/apiuseraccount.cpp
+++ b/src/apiuseraccount.cpp
@@ -5,6 +5,11 @@ APIUserAccount::APIUserAccount()
{
}
+const QString& APIUserAccount::apiKey() const
+{
+ return m_key;
+}
+
const QString& APIUserAccount::id() const
{
return m_id;
@@ -25,6 +30,12 @@ const APILimits& APIUserAccount::limits() const
return m_limits;
}
+APIUserAccount& APIUserAccount::apiKey(const QString& key)
+{
+ m_key = key;
+ return *this;
+}
+
APIUserAccount& APIUserAccount::id(const QString& id)
{
m_id = id;
diff --git a/src/apiuseraccount.h b/src/apiuseraccount.h
index 8a238d71..7dd16128 100644
--- a/src/apiuseraccount.h
+++ b/src/apiuseraccount.h
@@ -60,6 +60,12 @@ public:
APIUserAccount();
+
+ /**
+ * api key
+ */
+ const QString& apiKey() const;
+
/**
* user id
*/
@@ -81,6 +87,11 @@ public:
const APILimits& limits() const;
+ /**
+ * sets the api key
+ */
+ APIUserAccount& apiKey(const QString& key);
+
/**
* sets the user id
*/
@@ -120,7 +131,7 @@ public:
bool exhausted() const;
private:
- QString m_id, m_name;
+ QString m_key, m_id, m_name;
APIUserAccountTypes m_type;
APILimits m_limits;
APIStats m_stats;
diff --git a/src/nexusinterface.cpp b/src/nexusinterface.cpp
index ee9acf2c..2bcd72f3 100644
--- a/src/nexusinterface.cpp
+++ b/src/nexusinterface.cpp
@@ -207,13 +207,28 @@ APILimits NexusInterface::defaultAPILimits()
}
APILimits NexusInterface::parseLimits(const QNetworkReply* reply)
+{
+ return parseLimits(reply->rawHeaderPairs());
+}
+
+APILimits NexusInterface::parseLimits(
+ const QList& headers)
{
APILimits limits;
- limits.maxDailyRequests = reply->rawHeader("x-rl-daily-limit").toInt();
- limits.remainingDailyRequests = reply->rawHeader("x-rl-daily-remaining").toInt();
- limits.maxHourlyRequests = reply->rawHeader("x-rl-hourly-limit").toInt();
- limits.remainingHourlyRequests = reply->rawHeader("x-rl-hourly-remaining").toInt();
+ for (const auto& pair : headers) {
+ const auto name = QString(pair.first).toLower();
+
+ if (name == "x-rl-daily-limit") {
+ limits.maxDailyRequests = pair.second.toInt();
+ } else if (name == "x-rl-daily-remaining") {
+ limits.remainingDailyRequests = pair.second.toInt();
+ } else if (name == "x-rl-hourly-limit") {
+ limits.maxHourlyRequests = pair.second.toInt();
+ } else if (name == "x-rl-hourly-remaining") {
+ limits.remainingHourlyRequests = pair.second.toInt();
+ }
+ }
return limits;
}
@@ -765,7 +780,7 @@ void NexusInterface::nextRequest()
QNetworkRequest request(url);
request.setAttribute(QNetworkRequest::CacheSaveControlAttribute, false);
request.setAttribute(QNetworkRequest::CacheLoadControlAttribute, QNetworkRequest::AlwaysNetwork);
- request.setRawHeader("APIKEY", m_AccessManager->apiKey().toUtf8());
+ request.setRawHeader("APIKEY", m_User.apiKey().toUtf8());
request.setHeader(QNetworkRequest::KnownHeaders::UserAgentHeader, m_AccessManager->userAgent(info.m_SubModule));
request.setHeader(QNetworkRequest::KnownHeaders::ContentTypeHeader, "application/json");
request.setRawHeader("Protocol-Version", "1.0.0");
diff --git a/src/nexusinterface.h b/src/nexusinterface.h
index 6e768149..0b1763c4 100644
--- a/src/nexusinterface.h
+++ b/src/nexusinterface.h
@@ -151,6 +151,7 @@ public:
public:
static APILimits defaultAPILimits();
static APILimits parseLimits(const QNetworkReply* reply);
+ static APILimits parseLimits(const QList& headers);
~NexusInterface();
diff --git a/src/nxmaccessmanager.cpp b/src/nxmaccessmanager.cpp
index a274261d..c0a6c227 100644
--- a/src/nxmaccessmanager.cpp
+++ b/src/nxmaccessmanager.cpp
@@ -127,6 +127,9 @@ void ValidationProgressDialog::onTimer()
NexusSSOLogin::NexusSSOLogin()
: m_keyReceived(false), m_active(false)
{
+ m_timeout.setInterval(NXMAccessManager::ValidationTimeout);
+ m_timeout.setSingleShot(true);
+
QObject::connect(
&m_socket, &QWebSocket::connected,
[&]{ onConnected(); });
@@ -135,6 +138,10 @@ NexusSSOLogin::NexusSSOLogin()
&m_socket, qOverload(&QWebSocket::error),
[&](auto&& e){ onError(e); });
+ QObject::connect(
+ &m_socket, &QWebSocket::sslErrors,
+ [&](auto&& errors){ onSslErrors(errors); });
+
QObject::connect(
&m_socket, &QWebSocket::textMessageReceived,
[&](auto&& s){ onMessage(s); });
@@ -150,21 +157,25 @@ void NexusSSOLogin::start()
{
m_active = true;
setState(ConnectingToSSO);
- m_timeout.start(NXMAccessManager::ValidationTimeout);
+ m_timeout.start();
m_socket.open(NexusSSO);
}
void NexusSSOLogin::cancel()
{
- abort();
- setState(Cancelled);
+ if (m_active) {
+ abort();
+ setState(Cancelled);
+ }
}
void NexusSSOLogin::close()
{
- m_active = false;
- m_timeout.stop();
- m_socket.close();
+ if (m_active) {
+ m_active = false;
+ m_timeout.stop();
+ m_socket.close();
+ }
}
void NexusSSOLogin::abort()
@@ -261,6 +272,16 @@ void NexusSSOLogin::onError(QAbstractSocket::SocketError e)
{
if (m_active) {
setState(Error, m_socket.errorString());
+ close();
+ }
+}
+
+void NexusSSOLogin::onSslErrors(const QList& errors)
+{
+ if (m_active) {
+ for (const auto& e : errors) {
+ setState(Error, e.errorString());
+ }
}
}
@@ -271,18 +292,207 @@ void NexusSSOLogin::onTimeout()
}
+NexusKeyValidator::NexusKeyValidator(NXMAccessManager& am)
+ : m_manager(am), m_reply(nullptr), m_active(false)
+{
+ m_timeout.setInterval(NXMAccessManager::ValidationTimeout);
+ m_timeout.setSingleShot(true);
+
+ QObject::connect(&m_timeout, &QTimer::timeout, [&]{ onTimeout(); });
+}
+
+NexusKeyValidator::~NexusKeyValidator()
+{
+ abort();
+}
+
+void NexusKeyValidator::start(const QString& key)
+{
+ if (m_reply) {
+ abort();
+ return;
+ }
+
+ qDebug("Checking Nexus API Key...");
+ setState(Connecting);
+
+ const QString requestUrl(NexusBaseUrl + "/users/validate");
+ QNetworkRequest request(requestUrl);
+
+ request.setRawHeader("APIKEY", key.toUtf8());
+ request.setHeader(QNetworkRequest::KnownHeaders::UserAgentHeader, m_manager.userAgent().toUtf8());
+ request.setHeader(QNetworkRequest::KnownHeaders::ContentTypeHeader, "application/json");
+ request.setRawHeader("Protocol-Version", "1.0.0");
+ request.setRawHeader("Application-Name", "MO2");
+ request.setRawHeader("Application-Version", m_manager.MOVersion().toUtf8());
+
+ m_reply = m_manager.get(request);
+ if (!m_reply) {
+ setState(Error, QObject::tr("Failed to request %1").arg(requestUrl));
+ return;
+ }
+
+ m_active = true;
+ m_timeout.start(NXMAccessManager::ValidationTimeout);
+
+ QObject::connect(
+ m_reply, &QNetworkReply::finished,
+ [&]{ onFinished(); });
+
+ QObject::connect(
+ m_reply, &QNetworkReply::sslErrors,
+ [&](auto&& errors){ onSslErrors(errors); });
+}
+
+void NexusKeyValidator::cancel()
+{
+ if (m_active) {
+ abort();
+ setState(Cancelled);
+ }
+}
+
+bool NexusKeyValidator::isActive() const
+{
+ return m_active;
+}
+
+void NexusKeyValidator::close()
+{
+ m_active = false;
+ m_timeout.stop();
+
+ if (m_reply) {
+ m_reply->disconnect();
+ m_reply->deleteLater();
+ m_reply = nullptr;
+ }
+}
+
+void NexusKeyValidator::abort()
+{
+ m_active = false;
+ m_timeout.stop();
+
+ if (m_reply) {
+ m_reply->disconnect();
+ m_reply->abort();
+ m_reply->deleteLater();
+ m_reply = nullptr;
+ }
+}
+
+void NexusKeyValidator::setState(States s, const QString& error)
+{
+ if (stateChanged) {
+ stateChanged(s, error);
+ }
+}
+
+void NexusKeyValidator::onFinished()
+{
+ if (!m_reply) {
+ // shouldn't happen
+ return;
+ }
+
+ m_timeout.stop();
+
+ const auto code = m_reply->attribute(QNetworkRequest::HttpStatusCodeAttribute).toInt();
+ const auto doc = QJsonDocument::fromJson(m_reply->readAll());
+ const auto headers = m_reply->rawHeaderPairs();
+ const auto error = m_reply->errorString();
+
+ close();
+
+ const QJsonObject data = doc.object();
+
+ if (code != 200) {
+ handleError(code, data.value("message").toString(), error);
+ return;
+ }
+
+ if (doc.isNull()) {
+ setState(InvalidJson);
+ return;
+ }
+
+ if (!data.contains("user_id")) {
+ setState(BadResponse);
+ return;
+ }
+
+ const int id = data.value("user_id").toInt();
+ const QString key = data.value("key").toString();
+ const QString name = data.value("name").toString();
+ const bool premium = data.value("is_premium").toBool();
+
+ const auto user = APIUserAccount()
+ .apiKey(key)
+ .id(QString("%1").arg(id))
+ .name(name)
+ .type(premium ? APIUserAccountTypes::Premium : APIUserAccountTypes::Regular)
+ .limits(NexusInterface::parseLimits(headers));
+
+ if (finished) {
+ setState(Finished);
+ finished(user);
+ }
+}
+
+void NexusKeyValidator::onSslErrors(const QList& errors)
+{
+ if (m_active) {
+ for (const auto& e : errors) {
+ setState(Error, e.errorString());
+ }
+ }
+}
+
+void NexusKeyValidator::onTimeout()
+{
+ abort();
+ setState(Timeout);
+}
+
+void NexusKeyValidator::handleError(
+ int code, const QString& nexusMessage, const QString& httpError)
+{
+ QString s = httpError;
+
+ if (!nexusMessage.isEmpty()) {
+ if (!s.isEmpty()) {
+ s += ", ";
+ }
+
+ s += nexusMessage;
+ }
+
+ if (code != 0) {
+ if (s.isEmpty()) {
+ s = QString("HTTP code %1").arg(code);
+ } else {
+ s += QString(" (%1)").arg(code);
+ }
+ }
+
+ setState(Error, s);
+}
+
+
+
NXMAccessManager::NXMAccessManager(QObject *parent, const QString &moVersion)
: QNetworkAccessManager(parent)
- , m_ValidateReply(nullptr)
, m_ProgressDialog(new ValidationProgressDialog(ValidationTimeout))
, m_MOVersion(moVersion)
+ , m_validator(*this)
+ , m_validationState(NotChecked)
{
- m_ValidateTimeout.setSingleShot(true);
- m_ValidateTimeout.setInterval(ValidationTimeout);
+ m_validator.stateChanged = [&](auto&& s, auto&& e){ onValidatorState(s, e); };
+ m_validator.finished = [&](auto&& user){ onValidatorFinished(user); };
- connect(&m_ValidateTimeout, SIGNAL(timeout()), this, SLOT(validateTimeout()));
- setCookieJar(new PersistentCookieJar(
- QDir::fromNativeSeparators(Settings::instance().getCacheDirectory() + "/nexus_cookies.dat")));
+ setCookieJar(new PersistentCookieJar(QDir::fromNativeSeparators(
+ Settings::instance().getCacheDirectory() + "/nexus_cookies.dat")));
if (networkAccessible() == QNetworkAccessManager::UnknownAccessibility) {
// why is this necessary all of a sudden?
@@ -290,14 +500,6 @@ NXMAccessManager::NXMAccessManager(QObject *parent, const QString &moVersion)
}
}
-NXMAccessManager::~NXMAccessManager()
-{
- if (m_ValidateReply != nullptr) {
- m_ValidateReply->deleteLater();
- m_ValidateReply = nullptr;
- }
-}
-
void NXMAccessManager::setTopLevelWidget(QWidget* w)
{
m_ProgressDialog->setParentWidget(w);
@@ -323,7 +525,6 @@ QNetworkReply *NXMAccessManager::createRequest(
}
}
-
void NXMAccessManager::showCookies() const
{
QUrl url(NexusBaseUrl + "/");
@@ -344,80 +545,122 @@ void NXMAccessManager::clearCookies()
}
}
-void NXMAccessManager::startValidationCheck(bool showProgress)
+void NXMAccessManager::startValidationCheck(const QString& key, bool showProgress)
{
- qDebug("Checking Nexus API Key...");
- QString requestString = NexusBaseUrl + "/users/validate";
-
- QNetworkRequest request(requestString);
- request.setRawHeader("APIKEY", m_ApiKey.toUtf8());
- request.setHeader(QNetworkRequest::KnownHeaders::UserAgentHeader, userAgent().toUtf8());
- request.setHeader(QNetworkRequest::KnownHeaders::ContentTypeHeader, "application/json");
- request.setRawHeader("Protocol-Version", "1.0.0");
- request.setRawHeader("Application-Name", "MO2");
- request.setRawHeader("Application-Version", m_MOVersion.toUtf8());
+ m_validationState = NotChecked;
+ m_validator.start(key);
if (showProgress) {
m_ProgressDialog->start();
}
+}
+
+void NXMAccessManager::onValidatorState(
+ NexusKeyValidator::States s, const QString& e)
+{
+ switch (s)
+ {
+ case NexusKeyValidator::Connecting: // fall-through
+ case NexusKeyValidator::Finished:
+ {
+ // no-op, success is handled in onValidatorFinished()
+ break;
+ }
+
+ case NexusKeyValidator::InvalidJson:
+ {
+ onValidatorError(tr("Invalid JSON"));
+ break;
+ }
+
+ case NexusKeyValidator::BadResponse:
+ {
+ onValidatorError(tr("Bad response"));
+ break;
+ }
+
+ case NexusKeyValidator::Timeout:
+ {
+ onValidatorError(tr("There was a timeout during the request"));
+ break;
+ }
+
+ case NexusKeyValidator::Cancelled:
+ {
+ onValidatorError(tr("Cancelled"));
+ break;
+ }
+
+ case NexusKeyValidator::Error:
+ {
+ onValidatorError(e);
+ break;
+ }
+ }
+}
- QCoreApplication::processEvents(); // for some reason the whole app hangs during the login. This way the user has at least a little feedback
+void NXMAccessManager::onValidatorFinished(const APIUserAccount& user)
+{
+ m_ProgressDialog->stop();
- m_ValidateReply = get(request);
- m_ValidateTimeout.start();
- m_ValidateState = VALIDATE_CHECKING;
- connect(m_ValidateReply, SIGNAL(finished()), this, SLOT(validateFinished()));
- connect(m_ValidateReply, SIGNAL(error(QNetworkReply::NetworkError)), this, SLOT(validateError(QNetworkReply::NetworkError)));
+ m_validationState = Valid;
+ emit credentialsReceived(user);
+ emit validateSuccessful(true);
}
+void NXMAccessManager::onValidatorError(const QString& e)
+{
+ m_ProgressDialog->stop();
+ m_validationState = Invalid;
+ emit validateFailed(e);
+}
bool NXMAccessManager::validated() const
{
- if (m_ValidateState == VALIDATE_CHECKING) {
+ if (m_validator.isActive()) {
m_ProgressDialog->show();
}
- return m_ValidateState == VALIDATE_VALID;
+ return (m_validationState == Valid);
}
-
void NXMAccessManager::refuseValidation()
{
- m_ValidateState = VALIDATE_REFUSED;
+ m_validationState = Invalid;
}
-
bool NXMAccessManager::validateAttempted() const
{
- return m_ValidateState != VALIDATE_NOT_CHECKED;
+ return (m_validationState != NotChecked);
}
-
bool NXMAccessManager::validateWaiting() const
{
- return m_ValidateReply != nullptr;
+ return m_validator.isActive();
}
-
void NXMAccessManager::apiCheck(const QString &apiKey, ApiCheckFlags flags)
{
- if (m_ValidateReply != nullptr) {
+ if (m_validator.isActive()) {
return;
}
if (flags & Force) {
- m_ValidateState = VALIDATE_NOT_CHECKED;
+ m_validationState = NotChecked;
}
- if (m_ValidateState == VALIDATE_VALID) {
+ if (m_validationState == Valid) {
emit validateSuccessful(false);
return;
}
- m_ApiKey = apiKey;
- startValidationCheck((flags & HideProgress) == 0);
+ startValidationCheck(apiKey, (flags & HideProgress) == 0);
}
+const QString& NXMAccessManager::MOVersion() const
+{
+ return m_MOVersion;
+}
QString NXMAccessManager::userAgent(const QString &subModule) const
{
@@ -436,100 +679,8 @@ QString NXMAccessManager::userAgent(const QString &subModule) const
return QString("Mod Organizer/%1 (%2) Qt/%3").arg(m_MOVersion, comments.join("; "), qVersion());
}
-
-QString NXMAccessManager::apiKey() const
-{
- return m_ApiKey;
-}
-
void NXMAccessManager::clearApiKey()
{
- m_ApiKey = "";
- m_ValidateState = VALIDATE_NOT_VALID;
-
+ m_validator.cancel();
emit credentialsReceived(APIUserAccount());
}
-
-void NXMAccessManager::validateTimeout()
-{
- m_ValidateTimeout.stop();
- m_ProgressDialog->stop();
-
- m_ApiKey.clear();
- m_ValidateState = VALIDATE_NOT_VALID;
-
- if (m_ValidateReply != nullptr) {
- m_ValidateReply->deleteLater();
- m_ValidateReply = nullptr;
- }
-
- emit validateFailed(tr("There was a timeout during the request"));
-}
-
-
-void NXMAccessManager::validateError(QNetworkReply::NetworkError)
-{
- m_ValidateTimeout.stop();
- m_ProgressDialog->stop();
-
- m_ApiKey.clear();
- m_ValidateState = VALIDATE_NOT_VALID;
-
- if (m_ValidateReply != nullptr) {
- m_ValidateReply->disconnect();
- QString error = m_ValidateReply->errorString();
- m_ValidateReply->deleteLater();
- m_ValidateReply = nullptr;
- emit validateFailed(error);
- } else {
- emit validateFailed(tr("Unknown error"));
- }
-}
-
-
-void NXMAccessManager::validateFinished()
-{
- m_ValidateTimeout.stop();
- m_ProgressDialog->stop();
-
- if (m_ValidateReply != nullptr) {
- QJsonDocument jdoc = QJsonDocument::fromJson(m_ValidateReply->readAll());
- if (!jdoc.isNull()) {
- QJsonObject credentialsData = jdoc.object();
- if (credentialsData.contains("user_id")) {
- int id = credentialsData.value("user_id").toInt();
- QString name = credentialsData.value("name").toString();
- bool premium = credentialsData.value("is_premium").toBool();
-
- const auto user = APIUserAccount()
- .id(QString("%1").arg(id))
- .name(name)
- .type(premium ? APIUserAccountTypes::Premium : APIUserAccountTypes::Regular)
- .limits(NexusInterface::parseLimits(m_ValidateReply));
-
-
- emit credentialsReceived(user);
-
- m_ValidateReply->deleteLater();
- m_ValidateReply = nullptr;
-
- m_ValidateState = VALIDATE_VALID;
- emit validateSuccessful(true);
-
- } else {
- m_ApiKey.clear();
- m_ValidateState = VALIDATE_NOT_VALID;
- emit validateFailed(tr("Validation failed, please reauthenticate in the Settings -> Nexus tab: %1").arg(credentialsData.value("message").toString()));
- }
- } else {
- m_ApiKey.clear();
- m_ValidateState = VALIDATE_NOT_CHECKED;
- emit validateFailed(tr("Could not parse response. Invalid JSON."));
- }
- }
- else {
- m_ApiKey.clear();
- m_ValidateState = VALIDATE_NOT_CHECKED;
- emit validateFailed(tr("Unknown error."));
- }
-}
diff --git a/src/nxmaccessmanager.h b/src/nxmaccessmanager.h
index 08a799f9..11370d65 100644
--- a/src/nxmaccessmanager.h
+++ b/src/nxmaccessmanager.h
@@ -31,6 +31,7 @@ along with Mod Organizer. If not, see .
#include
namespace MOBase { class IPluginGame; }
+class NXMAccessManager;
class ValidationProgressDialog : private QDialog
{
@@ -103,10 +104,56 @@ private:
void onMessage(const QString& s);
void onDisconnected();
void onError(QAbstractSocket::SocketError e);
+ void onSslErrors(const QList& errors);
void onTimeout();
};
+class NexusKeyValidator
+{
+public:
+ enum States
+ {
+ Connecting,
+ Finished,
+ InvalidJson,
+ BadResponse,
+ Timeout,
+ Cancelled,
+ Error
+ };
+
+ std::function finished;
+ std::function stateChanged;
+
+ NexusKeyValidator(NXMAccessManager& am);
+ ~NexusKeyValidator();
+
+ void start(const QString& key);
+ void cancel();
+
+ bool isActive() const;
+
+private:
+ NXMAccessManager& m_manager;
+ QNetworkReply* m_reply;
+ QTimer m_timeout;
+ bool m_active;
+
+ void setState(States s, const QString& error={});
+
+ void close();
+ void abort();
+
+ void onFinished();
+ void onSslErrors(const QList& errors);
+ void onTimeout();
+
+ void handleError(
+ int code, const QString& nexusMessage, const QString& httpError);
+};
+
+
/**
* @brief access manager extended to handle nxm links
**/
@@ -127,7 +174,6 @@ public:
explicit NXMAccessManager(QObject *parent, const QString &moVersion);
- ~NXMAccessManager();
void setTopLevelWidget(QWidget* w);
@@ -143,8 +189,8 @@ public:
void clearCookies();
QString userAgent(const QString &subModule = QString()) const;
+ const QString& MOVersion() const;
- QString apiKey() const;
void clearApiKey();
void refuseValidation();
@@ -164,17 +210,9 @@ signals:
* @param necessary true if a login was necessary and succeeded, false if the user is still logged in
**/
void validateSuccessful(bool necessary);
-
void validateFailed(const QString &message);
-
void credentialsReceived(const APIUserAccount& user);
-private slots:
-
- void validateFinished();
- void validateError(QNetworkReply::NetworkError errorCode);
- void validateTimeout();
-
protected:
virtual QNetworkReply *createRequest(
@@ -182,25 +220,23 @@ protected:
QIODevice *device);
private:
+ enum States
+ {
+ NotChecked,
+ Valid,
+ Invalid
+ };
+
QWidget* m_TopLevel;
- QTimer m_ValidateTimeout;
- QNetworkReply *m_ValidateReply;
mutable ValidationProgressDialog* m_ProgressDialog;
-
QString m_MOVersion;
+ NexusKeyValidator m_validator;
+ States m_validationState;
- QString m_ApiKey;
-
- enum {
- VALIDATE_NOT_CHECKED,
- VALIDATE_CHECKING,
- VALIDATE_NOT_VALID,
- VALIDATE_ATTEMPT_FAILED,
- VALIDATE_REFUSED,
- VALIDATE_VALID
- } m_ValidateState = VALIDATE_NOT_CHECKED;
-
- void startValidationCheck(bool showProgress);
+ void startValidationCheck(const QString& key, bool showProgress);
+ void onValidatorState(NexusKeyValidator::States s, const QString& e);
+ void onValidatorFinished(const APIUserAccount& user);
+ void onValidatorError(const QString& e);
};
Q_DECLARE_OPERATORS_FOR_FLAGS(NXMAccessManager::ApiCheckFlags);
diff --git a/src/organizercore.cpp b/src/organizercore.cpp
index 65c8eb81..87668f4b 100644
--- a/src/organizercore.cpp
+++ b/src/organizercore.cpp
@@ -2484,7 +2484,8 @@ void OrganizerCore::loginSuccessfulUpdate(bool necessary)
void OrganizerCore::loginFailed(const QString &message)
{
- qDebug("Nexus API validation failed: %s", qUtf8Printable(message));
+ qDebug().nospace().noquote()
+ << "Nexus API validation failed: " << message;
if (QMessageBox::question(qApp->activeWindow(), tr("Login failed"),
tr("Login failed, try again?"))
--
cgit v1.3.1
From be1ee2a97c867a80c07c4b865c306977d96249dc Mon Sep 17 00:00:00 2001
From: isanae <14251494+isanae@users.noreply.github.com>
Date: Thu, 11 Jul 2019 05:49:12 -0400
Subject: refactored state messages
---
src/nxmaccessmanager.cpp | 125 ++++++++++++++++++++++++++++++-----------------
src/nxmaccessmanager.h | 5 +-
src/settingsdialog.cpp | 118 +++-----------------------------------------
3 files changed, 90 insertions(+), 158 deletions(-)
(limited to 'src/nxmaccessmanager.h')
diff --git a/src/nxmaccessmanager.cpp b/src/nxmaccessmanager.cpp
index 40ab19b9..a331b2e8 100644
--- a/src/nxmaccessmanager.cpp
+++ b/src/nxmaccessmanager.cpp
@@ -153,6 +153,45 @@ NexusSSOLogin::NexusSSOLogin()
QObject::connect(&m_timeout, &QTimer::timeout, [&]{ onTimeout(); });
}
+QString NexusSSOLogin::stateToString(States s, const QString& e)
+{
+ switch (s)
+ {
+ case ConnectingToSSO:
+ return QObject::tr("Connecting to Nexus...");
+
+ case WaitingForToken:
+ return QObject::tr("Waiting for Nexus...");
+
+ case WaitingForBrowser:
+ return QObject::tr("Opened browser, waiting for user...");
+
+ case Finished:
+ return QObject::tr("Connected.");
+
+ case Timeout:
+ return QObject::tr(
+ "No answer from Nexus.\n"
+ "A firewall might be blocking Mod Organizer.");
+
+ case ClosedByRemote:
+ return QObject::tr("Nexus closed the connection.");
+
+ case Cancelled:
+ return QObject::tr("Cancelled.");
+
+ case Error: // fall-through
+ default:
+ {
+ if (e.isEmpty()) {
+ return QString("%1").arg(s);
+ } else {
+ return e;
+ }
+ }
+ }
+}
+
void NexusSSOLogin::start()
{
m_active = true;
@@ -306,6 +345,40 @@ NexusKeyValidator::~NexusKeyValidator()
abort();
}
+QString NexusKeyValidator::stateToString(States s, const QString& e)
+{
+ switch (s)
+ {
+ case NexusKeyValidator::Connecting:
+ return QObject::tr("Connecting to Nexus...");
+
+ case NexusKeyValidator::Finished:
+ return QObject::tr("Finished.");
+
+ case NexusKeyValidator::InvalidJson:
+ return QObject::tr("Invalid JSON");
+
+ case NexusKeyValidator::BadResponse:
+ return QObject::tr("Bad response");
+
+ case NexusKeyValidator::Timeout:
+ return QObject::tr("There was a timeout during the request");
+
+ case NexusKeyValidator::Cancelled:
+ return QObject::tr("Cancelled");
+
+ case NexusKeyValidator::Error: // fall-through
+ default:
+ {
+ if (e.isEmpty()) {
+ return QString("%1").arg(s);
+ } else {
+ return e;
+ }
+ }
+ }
+}
+
void NexusKeyValidator::start(const QString& key)
{
if (m_reply) {
@@ -558,45 +631,14 @@ void NXMAccessManager::startValidationCheck(const QString& key, bool showProgres
void NXMAccessManager::onValidatorState(
NexusKeyValidator::States s, const QString& e)
{
- switch (s)
- {
- case NexusKeyValidator::Connecting: // fall-through
- case NexusKeyValidator::Finished:
- {
- // no-op, success is handled in onValidatorFinished()
- break;
- }
-
- case NexusKeyValidator::InvalidJson:
- {
- onValidatorError(tr("Invalid JSON"));
- break;
- }
-
- case NexusKeyValidator::BadResponse:
- {
- onValidatorError(tr("Bad response"));
- break;
- }
-
- case NexusKeyValidator::Timeout:
- {
- onValidatorError(tr("There was a timeout during the request"));
- break;
- }
-
- case NexusKeyValidator::Cancelled:
- {
- onValidatorError(tr("Cancelled"));
- break;
- }
-
- case NexusKeyValidator::Error:
- {
- onValidatorError(e);
- break;
- }
+ if (s == NexusKeyValidator::Connecting || s == NexusKeyValidator::Finished) {
+ // no-op, success is handled in onValidatorFinished()
+ return;
}
+
+ m_ProgressDialog->stop();
+ m_validationState = Invalid;
+ emit validateFailed(NexusKeyValidator::stateToString(s, e));
}
void NXMAccessManager::onValidatorFinished(const APIUserAccount& user)
@@ -608,13 +650,6 @@ void NXMAccessManager::onValidatorFinished(const APIUserAccount& user)
emit validateSuccessful(true);
}
-void NXMAccessManager::onValidatorError(const QString& e)
-{
- m_ProgressDialog->stop();
- m_validationState = Invalid;
- emit validateFailed(e);
-}
-
bool NXMAccessManager::validated() const
{
if (m_validator.isActive()) {
diff --git a/src/nxmaccessmanager.h b/src/nxmaccessmanager.h
index 11370d65..c633ae3b 100644
--- a/src/nxmaccessmanager.h
+++ b/src/nxmaccessmanager.h
@@ -80,6 +80,8 @@ public:
std::function keyChanged;
std::function stateChanged;
+ static QString stateToString(States s, const QString& e);
+
NexusSSOLogin();
void start();
@@ -126,6 +128,8 @@ public:
std::function finished;
std::function stateChanged;
+ static QString stateToString(States s, const QString& e);
+
NexusKeyValidator(NXMAccessManager& am);
~NexusKeyValidator();
@@ -236,7 +240,6 @@ private:
void startValidationCheck(const QString& key, bool showProgress);
void onValidatorState(NexusKeyValidator::States s, const QString& e);
void onValidatorFinished(const APIUserAccount& user);
- void onValidatorError(const QString& e);
};
Q_DECLARE_OPERATORS_FOR_FLAGS(NXMAccessManager::ApiCheckFlags);
diff --git a/src/settingsdialog.cpp b/src/settingsdialog.cpp
index 12dbc482..df957f87 100644
--- a/src/settingsdialog.cpp
+++ b/src/settingsdialog.cpp
@@ -450,66 +450,10 @@ void SettingsDialog::onSSOKeyChanged(const QString& key)
void SettingsDialog::onSSOStateChanged(NexusSSOLogin::States s, const QString& e)
{
- QString log;
+ const auto log = NexusSSOLogin::stateToString(s, e);
- switch (s)
- {
- case NexusSSOLogin::ConnectingToSSO:
- {
- log = tr("Connecting to Nexus...");
- break;
- }
-
- case NexusSSOLogin::WaitingForToken:
- {
- log = tr("Waiting for Nexus...");
- break;
- }
-
- case NexusSSOLogin::WaitingForBrowser:
- {
- log = tr("Opened browser, waiting for user...");
- break;
- }
-
- case NexusSSOLogin::Finished:
- {
- log = tr("Connected.");
- break;
- }
-
- case NexusSSOLogin::Timeout:
- {
- log = QObject::tr(
- "No answer from Nexus.\n"
- "A firewall might be blocking Mod Organizer.");
-
- break;
- }
-
- case NexusSSOLogin::ClosedByRemote:
- {
- log = QObject::tr("Nexus closed the connection.");
- break;
- }
-
- case NexusSSOLogin::Cancelled:
- {
- log = QObject::tr("Cancelled.");
- break;
- }
-
- case NexusSSOLogin::Error:
- {
- log = tr("Error: %1.").arg(e);
- break;
- }
- }
-
- if (!log.isEmpty()) {
- for (auto&& line : log.split("\n")) {
- ui->nexusLog->addItem(line);
- }
+ for (auto&& line : log.split("\n")) {
+ ui->nexusLog->addItem(line);
}
updateNexusButtons();
@@ -518,60 +462,10 @@ void SettingsDialog::onSSOStateChanged(NexusSSOLogin::States s, const QString& e
void SettingsDialog::onValidatorStateChanged(
NexusKeyValidator::States s, const QString& e)
{
- QString log;
-
- switch (s)
- {
- case NexusKeyValidator::Connecting:
- {
- log = tr("Connecting to Nexus...");
- break;
- }
-
- case NexusKeyValidator::Finished:
- {
- log = tr("Connected.");
- break;
- }
-
- case NexusKeyValidator::InvalidJson:
- {
- log = tr("Invalid JSON");
- break;
- }
-
- case NexusKeyValidator::BadResponse:
- {
- log = tr("Bad response");
- break;
- }
-
- case NexusKeyValidator::Timeout:
- {
- log = QObject::tr(
- "No answer from Nexus.\n"
- "A firewall might be blocking Mod Organizer.");
+ const auto log = NexusKeyValidator::stateToString(s, e);
- break;
- }
-
- case NexusKeyValidator::Cancelled:
- {
- log = QObject::tr("Cancelled.");
- break;
- }
-
- case NexusKeyValidator::Error:
- {
- log = tr("Error: %1.").arg(e);
- break;
- }
- }
-
- if (!log.isEmpty()) {
- for (auto&& line : log.split("\n")) {
- ui->nexusLog->addItem(line);
- }
+ for (auto&& line : log.split("\n")) {
+ ui->nexusLog->addItem(line);
}
updateNexusButtons();
--
cgit v1.3.1
From 45daaec7aada840692db4bbcb9fd4ebfdb9dae1b Mon Sep 17 00:00:00 2001
From: isanae <14251494+isanae@users.noreply.github.com>
Date: Fri, 12 Jul 2019 03:09:03 -0400
Subject: removed useless flags, they were only used by settings
---
src/nxmaccessmanager.cpp | 13 +++++--------
src/nxmaccessmanager.h | 15 ++-------------
2 files changed, 7 insertions(+), 21 deletions(-)
(limited to 'src/nxmaccessmanager.h')
diff --git a/src/nxmaccessmanager.cpp b/src/nxmaccessmanager.cpp
index 196368fd..ce33af43 100644
--- a/src/nxmaccessmanager.cpp
+++ b/src/nxmaccessmanager.cpp
@@ -618,14 +618,11 @@ void NXMAccessManager::clearCookies()
}
}
-void NXMAccessManager::startValidationCheck(const QString& key, bool showProgress)
+void NXMAccessManager::startValidationCheck(const QString& key)
{
m_validationState = NotChecked;
m_validator.start(key);
-
- if (showProgress) {
- m_ProgressDialog->start();
- }
+ m_ProgressDialog->start();
}
void NXMAccessManager::onValidatorState(
@@ -674,13 +671,13 @@ bool NXMAccessManager::validateWaiting() const
return m_validator.isActive();
}
-void NXMAccessManager::apiCheck(const QString &apiKey, ApiCheckFlags flags)
+void NXMAccessManager::apiCheck(const QString &apiKey, bool force)
{
if (m_validator.isActive()) {
return;
}
- if (flags & Force) {
+ if (force) {
m_validationState = NotChecked;
}
@@ -689,7 +686,7 @@ void NXMAccessManager::apiCheck(const QString &apiKey, ApiCheckFlags flags)
return;
}
- startValidationCheck(apiKey, (flags & HideProgress) == 0);
+ startValidationCheck(apiKey);
}
const QString& NXMAccessManager::MOVersion() const
diff --git a/src/nxmaccessmanager.h b/src/nxmaccessmanager.h
index c633ae3b..0cfaffb5 100644
--- a/src/nxmaccessmanager.h
+++ b/src/nxmaccessmanager.h
@@ -165,15 +165,6 @@ class NXMAccessManager : public QNetworkAccessManager
{
Q_OBJECT
public:
- enum ApiCheckFlagsEnum
- {
- NoFlags = 0,
- Force,
- HideProgress
- };
-
- Q_DECLARE_FLAGS(ApiCheckFlags, ApiCheckFlagsEnum)
-
static const std::chrono::seconds ValidationTimeout;
explicit NXMAccessManager(QObject *parent, const QString &moVersion);
@@ -186,7 +177,7 @@ public:
bool validateAttempted() const;
bool validateWaiting() const;
- void apiCheck(const QString &apiKey, ApiCheckFlags flags=NoFlags);
+ void apiCheck(const QString &apiKey, bool force=false);
void showCookies() const;
@@ -237,11 +228,9 @@ private:
NexusKeyValidator m_validator;
States m_validationState;
- void startValidationCheck(const QString& key, bool showProgress);
+ void startValidationCheck(const QString& key);
void onValidatorState(NexusKeyValidator::States s, const QString& e);
void onValidatorFinished(const APIUserAccount& user);
};
-Q_DECLARE_OPERATORS_FOR_FLAGS(NXMAccessManager::ApiCheckFlags);
-
#endif // NXMACCESSMANAGER_H
--
cgit v1.3.1
From b69b3e5e471dfd16f1861bd1e4bed10cf46709b9 Mon Sep 17 00:00:00 2001
From: isanae <14251494+isanae@users.noreply.github.com>
Date: Fri, 12 Jul 2019 03:24:05 -0400
Subject: removed already commented out code: don't resend the guid and token,
nexus never answers with the api key, just create a new request every time
---
src/nxmaccessmanager.cpp | 4 ----
src/nxmaccessmanager.h | 1 -
2 files changed, 5 deletions(-)
(limited to 'src/nxmaccessmanager.h')
diff --git a/src/nxmaccessmanager.cpp b/src/nxmaccessmanager.cpp
index ce33af43..8b70f09b 100644
--- a/src/nxmaccessmanager.cpp
+++ b/src/nxmaccessmanager.cpp
@@ -242,15 +242,12 @@ void NexusSSOLogin::onConnected()
m_keyReceived = false;
- //if (m_guid.isEmpty()) {
boost::uuids::random_generator generator;
boost::uuids::uuid sessionId = generator();
m_guid = boost::uuids::to_string(sessionId).c_str();
- //}
QJsonObject data;
data.insert(QString("id"), QJsonValue(m_guid));
- //data.insert(QString("token"), QJsonValue(m_token));
data.insert(QString("protocol"), 2);
const QString message = QJsonDocument(data).toJson();
@@ -275,7 +272,6 @@ void NexusSSOLogin::onMessage(const QString& s)
if (data.contains("connection_token")) {
// first answer
- m_token = data["connection_token"].toString();
// open browser
const auto url = NexusSSOPage.arg(m_guid);
diff --git a/src/nxmaccessmanager.h b/src/nxmaccessmanager.h
index 0cfaffb5..eed7c1c9 100644
--- a/src/nxmaccessmanager.h
+++ b/src/nxmaccessmanager.h
@@ -93,7 +93,6 @@ private:
QWebSocket m_socket;
QString m_guid;
bool m_keyReceived;
- QString m_token;
bool m_active;
QTimer m_timeout;
--
cgit v1.3.1
From 3f487a5a6c9c23824298fdde3d76dc82edf3ca46 Mon Sep 17 00:00:00 2001
From: isanae <14251494+isanae@users.noreply.github.com>
Date: Fri, 16 Aug 2019 07:03:52 -0400
Subject: merged toolbars into restoreToolbars() and saveToolbars() added
centerOnMainWindowMonitor(), now also used by validation dialog added
overloads for splitter, used by main splitter fixed saveState() for
QMainWindow calling the wrong function
---
src/main.cpp | 11 +------
src/mainwindow.cpp | 28 +++++-----------
src/nxmaccessmanager.cpp | 13 ++++++--
src/nxmaccessmanager.h | 2 ++
src/pch.h | 1 +
src/settings.cpp | 86 ++++++++++++++++++++++++++++++++++++++++++------
src/settings.h | 19 ++++++++---
7 files changed, 114 insertions(+), 46 deletions(-)
(limited to 'src/nxmaccessmanager.h')
diff --git a/src/main.cpp b/src/main.cpp
index 506c6270..8eee41e4 100644
--- a/src/main.cpp
+++ b/src/main.cpp
@@ -697,16 +697,7 @@ int runApplication(MOApplication &application, SingleInstance &instance,
QPixmap pixmap(splashPath);
QSplashScreen splash(pixmap);
- const auto monitor = settings.geometry().getMainWindowMonitor();
- if (monitor && QGuiApplication::screens().size() > *monitor) {
- QGuiApplication::screens().at(*monitor)->geometry().center();
- const QPoint center = QGuiApplication::screens().at(*monitor)->geometry().center();
- splash.move(center - splash.rect().center());
- } else {
- const QPoint center = QGuiApplication::primaryScreen()->geometry().center();
- splash.move(center - splash.rect().center());
- }
-
+ settings.geometry().centerOnMainWindowMonitor(&splash);
splash.show();
splash.activateWindow();
diff --git a/src/mainwindow.cpp b/src/mainwindow.cpp
index 85be8563..6e6e3d22 100644
--- a/src/mainwindow.cpp
+++ b/src/mainwindow.cpp
@@ -2261,14 +2261,8 @@ void MainWindow::readSettings(const Settings& settings)
{
settings.restoreGeometry(this);
settings.restoreState(this);
-
- if (auto v=settings.geometry().getToolbarSize()) {
- setToolbarSize(*v);
- }
-
- if (auto v=settings.geometry().getToolbarButtonStyle()) {
- setToolbarButtonStyle(*v);
- }
+ settings.geometry().restoreToolbars(this);
+ settings.restoreState(ui->splitter);
if (auto v=settings.geometry().getMenubarVisible()) {
showMenuBar(*v);
@@ -2278,10 +2272,6 @@ void MainWindow::readSettings(const Settings& settings)
showStatusBar(*v);
}
- if (auto v=settings.geometry().getMainSplitterState()) {
- ui->splitter->restoreState(*v);
- }
-
{
auto v = settings.geometry().getFiltersVisible().value_or(false);
setCategoryListVisible(v);
@@ -2366,14 +2356,12 @@ void MainWindow::storeSettings(Settings& s) {
s.saveState(this);
s.saveGeometry(this);
- settings.setValue("toolbar_size", ui->toolBar->iconSize());
- settings.setValue("toolbar_button_style", static_cast(ui->toolBar->toolButtonStyle()));
- settings.setValue("menubar_visible", m_menuBarVisible);
- settings.setValue("statusbar_visible", m_statusBarVisible);
- settings.setValue("window_split", ui->splitter->saveState());
- QScreen *screen = this->window()->windowHandle()->screen();
- int screenId = QGuiApplication::screens().indexOf(screen);
- settings.setValue("window_monitor", screenId);
+ s.geometry().setMenubarVisible(m_menuBarVisible);
+ s.geometry().saveToolbars(this);
+ s.geometry().setStatusbarVisible(m_statusBarVisible);
+ s.saveState(ui->splitter);
+ s.geometry().saveMainWindowMonitor(this);
+
settings.setValue("browser_geometry", m_IntegratedBrowser.saveGeometry());
settings.setValue("filters_visible", ui->displayCategoriesBtn->isChecked());
diff --git a/src/nxmaccessmanager.cpp b/src/nxmaccessmanager.cpp
index fd1dc0c1..16190ca4 100644
--- a/src/nxmaccessmanager.cpp
+++ b/src/nxmaccessmanager.cpp
@@ -48,8 +48,9 @@ const QString NexusSSO("wss://sso.nexusmods.com");
const QString NexusSSOPage("https://www.nexusmods.com/sso?id=%1&application=modorganizer2");
-ValidationProgressDialog::ValidationProgressDialog(std::chrono::seconds t)
- : m_timeout(t), m_bar(nullptr), m_buttons(nullptr), m_timer(nullptr)
+ValidationProgressDialog::ValidationProgressDialog(std::chrono::seconds t) :
+ m_timeout(t), m_bar(nullptr), m_buttons(nullptr), m_timer(nullptr),
+ m_first(true)
{
m_bar = new QProgressBar;
m_bar->setTextVisible(false);
@@ -103,6 +104,14 @@ void ValidationProgressDialog::stop()
hide();
}
+void ValidationProgressDialog::showEvent(QShowEvent* e)
+{
+ if (m_first) {
+ Settings::instance().geometry().centerOnMainWindowMonitor(this);
+ m_first = false;
+ }
+}
+
void ValidationProgressDialog::closeEvent(QCloseEvent* e)
{
hide();
diff --git a/src/nxmaccessmanager.h b/src/nxmaccessmanager.h
index eed7c1c9..0c85153b 100644
--- a/src/nxmaccessmanager.h
+++ b/src/nxmaccessmanager.h
@@ -48,6 +48,7 @@ public:
using QDialog::show;
protected:
+ void showEvent(QShowEvent* e) override;
void closeEvent(QCloseEvent* e) override;
private:
@@ -56,6 +57,7 @@ private:
QDialogButtonBox* m_buttons;
QTimer* m_timer;
QElapsedTimer m_elapsed;
+ bool m_first;
void onButton(QAbstractButton* b);
void onTimer();
diff --git a/src/pch.h b/src/pch.h
index 504ef8f1..dd65efbe 100644
--- a/src/pch.h
+++ b/src/pch.h
@@ -189,6 +189,7 @@
#include
#include
#include
+#include
#include
#include
#include
diff --git a/src/settings.cpp b/src/settings.cpp
index 91e667d5..a3d12070 100644
--- a/src/settings.cpp
+++ b/src/settings.cpp
@@ -958,7 +958,7 @@ bool Settings::restoreGeometry(QWidget* w) const
void Settings::saveState(const QMainWindow* w)
{
- m_Settings.setValue(stateSettingName(w), w->saveGeometry());
+ m_Settings.setValue(stateSettingName(w), w->saveState());
}
bool Settings::restoreState(QMainWindow* w) const
@@ -986,24 +986,61 @@ bool Settings::restoreState(QHeaderView* w) const
return false;
}
+void Settings::saveState(const QSplitter* w)
+{
+ m_Settings.setValue(stateSettingName(w), w->saveState());
+}
+
+bool Settings::restoreState(QSplitter* w) const
+{
+ if (auto v=getOptional(m_Settings, stateSettingName(w))) {
+ w->restoreState(*v);
+ return true;
+ }
+
+ return false;
+}
+
GeometrySettings::GeometrySettings(QSettings& s)
: m_Settings(s)
{
}
-std::optional GeometrySettings::getToolbarSize() const
+bool GeometrySettings::restoreToolbars(QMainWindow* w) const
{
- return getOptional(m_Settings, "toolbar_size");
+ const auto size = getOptional(m_Settings, "toolbar_size");
+ const auto style = getOptional(m_Settings, "toolbar_button_style");
+
+ if (!size && !style) {
+ return false;
+ }
+
+ for (auto* tb : w->findChildren()) {
+ if (size) {
+ tb->setIconSize(*size);
+ }
+
+ if (style) {
+ tb->setToolButtonStyle(static_cast(*style));
+ }
+ }
+
+ return true;
}
-std::optional GeometrySettings::getToolbarButtonStyle() const
+void GeometrySettings::saveToolbars(const QMainWindow* w)
{
- if (auto v=getOptional(m_Settings, "toolbar_button_style")) {
- return static_cast(*v);
+ // all toolbars are identical, just save the first one
+ const auto tbs = w->findChildren();
+ if (tbs.isEmpty()) {
+ return;
}
- return {};
+ const auto* tb = tbs[0];
+
+ m_Settings.setValue("toolbar_size", tb->iconSize());
+ m_Settings.setValue("toolbar_button_style", static_cast(tb->toolButtonStyle()));
}
std::optional GeometrySettings::getMenubarVisible() const
@@ -1011,14 +1048,19 @@ std::optional GeometrySettings::getMenubarVisible() const
return getOptional(m_Settings, "menubar_visible");
}
+void GeometrySettings::setMenubarVisible(bool b)
+{
+ m_Settings.setValue("menubar_visible", b);
+}
+
std::optional GeometrySettings::getStatusbarVisible() const
{
return getOptional(m_Settings, "statusbar_visible");
}
-std::optional GeometrySettings::getMainSplitterState() const
+void GeometrySettings::setStatusbarVisible(bool b)
{
- return getOptional(m_Settings, "window_split");
+ m_Settings.setValue("statusbar_visible", b);
}
std::optional GeometrySettings::getFiltersVisible() const
@@ -1064,7 +1106,31 @@ void GeometrySettings::setModInfoTabOrder(const QString& names)
std::optional GeometrySettings::getMainWindowMonitor() const
{
- return getOptional(m_Settings, "window_monitor");
+ return getOptional(m_Settings, "geometry/window_monitor");
+}
+
+void GeometrySettings::centerOnMainWindowMonitor(QWidget* w)
+{
+ const auto monitor = getMainWindowMonitor();
+ QPoint center;
+
+ if (monitor && QGuiApplication::screens().size() > *monitor) {
+ center = QGuiApplication::screens().at(*monitor)->geometry().center();
+ } else {
+ center = QGuiApplication::primaryScreen()->geometry().center();
+ }
+
+ w->move(center - w->rect().center());
+}
+
+void GeometrySettings::saveMainWindowMonitor(const QMainWindow* w)
+{
+ if (auto* handle=w->windowHandle()) {
+ if (auto* screen = handle->screen()) {
+ const int screenId = QGuiApplication::screens().indexOf(screen);
+ m_Settings.setValue("geometry/window_monitor", screenId);
+ }
+ }
}
void GeometrySettings::setDockSize(const QString& name, int size)
diff --git a/src/settings.h b/src/settings.h
index 1575b3cd..bbf008f0 100644
--- a/src/settings.h
+++ b/src/settings.h
@@ -28,6 +28,8 @@ namespace MOBase {
class IPluginGame;
}
+class QSplitter;
+
class PluginContainer;
struct ServerInfo;
class Settings;
@@ -49,18 +51,24 @@ class GeometrySettings
public:
GeometrySettings(QSettings& s);
- std::optional getToolbarSize() const;
- std::optional getToolbarButtonStyle() const;
-
std::optional getMenubarVisible() const;
+ void setMenubarVisible(bool b);
+
+ bool restoreToolbars(QMainWindow* w) const;
+ void saveToolbars(const QMainWindow* w);
+
std::optional getStatusbarVisible() const;
- std::optional getMainSplitterState() const;
+ void setStatusbarVisible(bool b);
+
std::optional getFiltersVisible() const;
QStringList getModInfoTabOrder() const;
void setModInfoTabOrder(const QString& names);
std::optional getMainWindowMonitor() const;
+ void centerOnMainWindowMonitor(QWidget* w);
+ void saveMainWindowMonitor(const QMainWindow* w);
+
void setDockSize(const QString& name, int size);
std::optional getDockSize(const QString& name) const;
@@ -215,6 +223,9 @@ public:
void saveState(const QToolBar* toolbar);
bool restoreState(QToolBar* toolbar) const;
+ void saveState(const QSplitter* splitter);
+ bool restoreState(QSplitter* splitter) const;
+
/**
* retrieve the directory where profiles stored (with native separators)
--
cgit v1.3.1
From 3fe54c8431b9c1e792a235b9b370267447c3210c Mon Sep 17 00:00:00 2001
From: isanae <14251494+isanae@users.noreply.github.com>
Date: Sat, 5 Oct 2019 10:11:55 -0400
Subject: now using ui file for validation progress dialog moved elapsed timer
to NexusKeyValidator, progress dialog now just shows what the validator is
doing, which allows for hiding and showing it at any time recreate the dialog
when the parent changes, avoids theme errors
---
src/nxmaccessmanager.cpp | 92 ++++++++++++++++++-------------
src/nxmaccessmanager.h | 65 +++++++++++-----------
src/validationprogressdialog.ui | 117 ++++++++++++++++++++++++++++++++++++++++
3 files changed, 204 insertions(+), 70 deletions(-)
create mode 100644 src/validationprogressdialog.ui
(limited to 'src/nxmaccessmanager.h')
diff --git a/src/nxmaccessmanager.cpp b/src/nxmaccessmanager.cpp
index 3cc1b7d9..731feafb 100644
--- a/src/nxmaccessmanager.cpp
+++ b/src/nxmaccessmanager.cpp
@@ -18,6 +18,7 @@ along with Mod Organizer. If not, see .
*/
#include "nxmaccessmanager.h"
+#include "ui_validationprogressdialog.h"
#include "iplugingame.h"
#include "nexusinterface.h"
#include "nxmurl.h"
@@ -48,24 +49,14 @@ const QString NexusSSO("wss://sso.nexusmods.com");
const QString NexusSSOPage("https://www.nexusmods.com/sso?id=%1&application=modorganizer2");
-ValidationProgressDialog::ValidationProgressDialog(std::chrono::seconds t) :
- m_timeout(t), m_bar(nullptr), m_buttons(nullptr), m_timer(nullptr),
- m_first(true)
+ValidationProgressDialog::ValidationProgressDialog(const NexusKeyValidator& v)
+ : m_validator(v), m_updateTimer(nullptr), m_first(true)
{
- m_bar = new QProgressBar;
- m_bar->setTextVisible(false);
+ ui.reset(new Ui::ValidationProgressDialog);
+ ui->setupUi(this);
- auto* label = new QLabel(tr("Validating Nexus Connection"));
- label->setAlignment(Qt::AlignHCenter);
-
- auto* vbox = new QVBoxLayout(this);
- vbox->addWidget(label);
- vbox->addWidget(m_bar);
-
- m_buttons = new QDialogButtonBox;
- m_buttons->addButton(tr("Hide"), QDialogButtonBox::RejectRole);
- connect(m_buttons, &QDialogButtonBox::clicked, [&](auto* b){ onButton(b); });
- vbox->addWidget(m_buttons);
+ connect(ui->hide, &QPushButton::clicked, [&]{ onHide(); });
+ connect(ui->cancel, &QPushButton::clicked, [&]{ onCancel(); });
}
void ValidationProgressDialog::setParentWidget(QWidget* w)
@@ -75,30 +66,32 @@ void ValidationProgressDialog::setParentWidget(QWidget* w)
hide();
setParent(w, windowFlags() | Qt::Dialog);
setModal(false);
- setVisible(wasVisible);
+
+ if (w && wasVisible) {
+ setVisible(true);
+ }
}
void ValidationProgressDialog::start()
{
- if (!m_timer) {
- m_timer = new QTimer(this);
- connect(m_timer, &QTimer::timeout, [&]{ onTimer(); });
- m_timer->setInterval(100ms);
+ if (!m_updateTimer) {
+ m_updateTimer = new QTimer(this);
+ connect(m_updateTimer, &QTimer::timeout, [&]{ onTimer(); });
+ m_updateTimer->setInterval(100ms);
}
- m_bar->setRange(0, m_timeout.count());
- m_bar->setValue(0);
+ ui->progress->setRange(0, m_validator.timeout().count());
+ ui->progress->setValue(0);
- m_elapsed.start();
- m_timer->start();
+ m_updateTimer->start();
show();
}
void ValidationProgressDialog::stop()
{
- if (m_timer) {
- m_timer->stop();
+ if (m_updateTimer) {
+ m_updateTimer->stop();
}
hide();
@@ -118,18 +111,18 @@ void ValidationProgressDialog::closeEvent(QCloseEvent* e)
e->ignore();
}
-void ValidationProgressDialog::onButton(QAbstractButton* b)
+void ValidationProgressDialog::onHide()
+{
+ hide();
+}
+
+void ValidationProgressDialog::onCancel()
{
- if (m_buttons->buttonRole(b) == QDialogButtonBox::RejectRole) {
- hide();
- } else {
- qCritical() << "validation dialog: unknown button pressed";
- }
}
void ValidationProgressDialog::onTimer()
{
- m_bar->setValue(m_elapsed.elapsed() / 1000);
+ ui->progress->setValue(m_validator.elapsed().elapsed() / 1000);
}
@@ -395,6 +388,7 @@ void NexusKeyValidator::start(const QString& key)
m_active = true;
setState(Connecting);
+ m_elapsed.start();
const QString requestUrl(NexusBaseUrl + "/users/validate");
QNetworkRequest request(requestUrl);
@@ -437,6 +431,16 @@ bool NexusKeyValidator::isActive() const
return m_active;
}
+QElapsedTimer NexusKeyValidator::elapsed() const
+{
+ return m_elapsed;
+}
+
+std::chrono::seconds NexusKeyValidator::timeout() const
+{
+ return NXMAccessManager::ValidationTimeout;
+}
+
void NexusKeyValidator::close()
{
m_active = false;
@@ -563,11 +567,12 @@ void NexusKeyValidator::handleError(
NXMAccessManager::NXMAccessManager(QObject *parent, const QString &moVersion)
: QNetworkAccessManager(parent)
- , m_ProgressDialog(new ValidationProgressDialog(ValidationTimeout))
, m_MOVersion(moVersion)
, m_validator(*this)
, m_validationState(NotChecked)
{
+ m_ProgressDialog.reset(new ValidationProgressDialog(m_validator));
+
m_validator.stateChanged = [&](auto&& s, auto&& e){ onValidatorState(s, e); };
m_validator.finished = [&](auto&& user){ onValidatorFinished(user); };
@@ -582,7 +587,13 @@ NXMAccessManager::NXMAccessManager(QObject *parent, const QString &moVersion)
void NXMAccessManager::setTopLevelWidget(QWidget* w)
{
- m_ProgressDialog->setParentWidget(w);
+ if (w) {
+ m_ProgressDialog->setParentWidget(w);
+ } else {
+ const auto v = m_ProgressDialog->isVisible();
+ m_ProgressDialog.reset(new ValidationProgressDialog(m_validator));
+ m_validator.cancel();
+ }
}
QNetworkReply *NXMAccessManager::createRequest(
@@ -641,8 +652,13 @@ void NXMAccessManager::onValidatorState(
}
m_ProgressDialog->stop();
- m_validationState = Invalid;
- emit validateFailed(NexusKeyValidator::stateToString(s, e));
+
+ if (s == NexusKeyValidator::Cancelled) {
+ m_validationState = NotChecked;
+ } else {
+ m_validationState = Invalid;
+ emit validateFailed(NexusKeyValidator::stateToString(s, e));
+ }
}
void NXMAccessManager::onValidatorFinished(const APIUserAccount& user)
diff --git a/src/nxmaccessmanager.h b/src/nxmaccessmanager.h
index 0c85153b..2a4c066c 100644
--- a/src/nxmaccessmanager.h
+++ b/src/nxmaccessmanager.h
@@ -31,39 +31,9 @@ along with Mod Organizer. If not, see .
#include
namespace MOBase { class IPluginGame; }
+namespace Ui { class ValidationProgressDialog; }
class NXMAccessManager;
-class ValidationProgressDialog : private QDialog
-{
- Q_OBJECT;
-
-public:
- ValidationProgressDialog(std::chrono::seconds timeout);
-
- void setParentWidget(QWidget* w);
-
- void start();
- void stop();
-
- using QDialog::show;
-
-protected:
- void showEvent(QShowEvent* e) override;
- void closeEvent(QCloseEvent* e) override;
-
-private:
- std::chrono::seconds m_timeout;
- QProgressBar* m_bar;
- QDialogButtonBox* m_buttons;
- QTimer* m_timer;
- QElapsedTimer m_elapsed;
- bool m_first;
-
- void onButton(QAbstractButton* b);
- void onTimer();
-};
-
-
class NexusSSOLogin
{
public:
@@ -138,12 +108,15 @@ public:
void cancel();
bool isActive() const;
+ QElapsedTimer elapsed() const;
+ std::chrono::seconds timeout() const;
private:
NXMAccessManager& m_manager;
QNetworkReply* m_reply;
QTimer m_timeout;
bool m_active;
+ QElapsedTimer m_elapsed;
void setState(States s, const QString& error={});
@@ -159,6 +132,34 @@ private:
};
+class ValidationProgressDialog : public QDialog
+{
+ Q_OBJECT;
+
+public:
+ ValidationProgressDialog(const NexusKeyValidator& v);
+
+ void setParentWidget(QWidget* w);
+
+ void start();
+ void stop();
+
+protected:
+ void showEvent(QShowEvent* e) override;
+ void closeEvent(QCloseEvent* e) override;
+
+private:
+ std::unique_ptr ui;
+ const NexusKeyValidator& m_validator;
+ QTimer* m_updateTimer;
+ bool m_first;
+
+ void onHide();
+ void onCancel();
+ void onTimer();
+};
+
+
/**
* @brief access manager extended to handle nxm links
**/
@@ -224,7 +225,7 @@ private:
};
QWidget* m_TopLevel;
- mutable ValidationProgressDialog* m_ProgressDialog;
+ mutable std::unique_ptr m_ProgressDialog;
QString m_MOVersion;
NexusKeyValidator m_validator;
States m_validationState;
diff --git a/src/validationprogressdialog.ui b/src/validationprogressdialog.ui
new file mode 100644
index 00000000..1c0cbcb8
--- /dev/null
+++ b/src/validationprogressdialog.ui
@@ -0,0 +1,117 @@
+
+
+ ValidationProgressDialog
+
+
+
+ 0
+ 0
+ 305
+ 93
+
+
+
+ Validating Nexus Connection
+
+
+ -
+
+
+
+ 0
+
+
+ 0
+
+
+ 0
+
+
+ 0
+
+
-
+
+
+ Connecting to Nexus...
+
+
+
+ -
+
+
+ 24
+
+
+ false
+
+
+
+ -
+
+
+ Qt::Vertical
+
+
+
+ 20
+ 40
+
+
+
+
+
+
+
+ -
+
+
+
+ 0
+
+
+ 0
+
+
+ 0
+
+
+ 0
+
+
-
+
+
+ Cancel
+
+
+
+ -
+
+
+ Qt::Horizontal
+
+
+
+ 122
+ 20
+
+
+
+
+ -
+
+
+ Hide
+
+
+ true
+
+
+
+
+
+
+
+
+
+
+
--
cgit v1.3.1
From fc909d4b2eaff02cb8b7f38ca5079dc9b12cef68 Mon Sep 17 00:00:00 2001
From: isanae <14251494+isanae@users.noreply.github.com>
Date: Sat, 5 Oct 2019 10:41:23 -0400
Subject: implemented cancel button on progress dialog fixed crash when exiting
MO because the dialog is destroyed in atexit(), way after Qt is gone
---
src/nxmaccessmanager.cpp | 32 +++++++++++++++++++++++---------
src/nxmaccessmanager.h | 10 ++++++----
2 files changed, 29 insertions(+), 13 deletions(-)
(limited to 'src/nxmaccessmanager.h')
diff --git a/src/nxmaccessmanager.cpp b/src/nxmaccessmanager.cpp
index 731feafb..036b22ff 100644
--- a/src/nxmaccessmanager.cpp
+++ b/src/nxmaccessmanager.cpp
@@ -49,7 +49,7 @@ const QString NexusSSO("wss://sso.nexusmods.com");
const QString NexusSSOPage("https://www.nexusmods.com/sso?id=%1&application=modorganizer2");
-ValidationProgressDialog::ValidationProgressDialog(const NexusKeyValidator& v)
+ValidationProgressDialog::ValidationProgressDialog(NexusKeyValidator& v)
: m_validator(v), m_updateTimer(nullptr), m_first(true)
{
ui.reset(new Ui::ValidationProgressDialog);
@@ -118,6 +118,7 @@ void ValidationProgressDialog::onHide()
void ValidationProgressDialog::onCancel()
{
+ m_validator.cancel();
}
void ValidationProgressDialog::onTimer()
@@ -571,8 +572,6 @@ NXMAccessManager::NXMAccessManager(QObject *parent, const QString &moVersion)
, m_validator(*this)
, m_validationState(NotChecked)
{
- m_ProgressDialog.reset(new ValidationProgressDialog(m_validator));
-
m_validator.stateChanged = [&](auto&& s, auto&& e){ onValidatorState(s, e); };
m_validator.finished = [&](auto&& user){ onValidatorFinished(user); };
@@ -590,8 +589,7 @@ void NXMAccessManager::setTopLevelWidget(QWidget* w)
if (w) {
m_ProgressDialog->setParentWidget(w);
} else {
- const auto v = m_ProgressDialog->isVisible();
- m_ProgressDialog.reset(new ValidationProgressDialog(m_validator));
+ m_ProgressDialog.reset();
m_validator.cancel();
}
}
@@ -640,7 +638,7 @@ void NXMAccessManager::startValidationCheck(const QString& key)
{
m_validationState = NotChecked;
m_validator.start(key);
- m_ProgressDialog->start();
+ startProgress();
}
void NXMAccessManager::onValidatorState(
@@ -651,7 +649,7 @@ void NXMAccessManager::onValidatorState(
return;
}
- m_ProgressDialog->stop();
+ stopProgress();
if (s == NexusKeyValidator::Cancelled) {
m_validationState = NotChecked;
@@ -663,7 +661,7 @@ void NXMAccessManager::onValidatorState(
void NXMAccessManager::onValidatorFinished(const APIUserAccount& user)
{
- m_ProgressDialog->stop();
+ stopProgress();
m_validationState = Valid;
emit credentialsReceived(user);
@@ -673,7 +671,7 @@ void NXMAccessManager::onValidatorFinished(const APIUserAccount& user)
bool NXMAccessManager::validated() const
{
if (m_validator.isActive()) {
- m_ProgressDialog->show();
+ const_cast(this)->startProgress();
}
return (m_validationState == Valid);
@@ -739,3 +737,19 @@ void NXMAccessManager::clearApiKey()
m_validator.cancel();
emit credentialsReceived(APIUserAccount());
}
+
+void NXMAccessManager::startProgress()
+{
+ if (!m_ProgressDialog) {
+ m_ProgressDialog.reset(new ValidationProgressDialog(m_validator));
+ }
+
+ m_ProgressDialog->start();
+}
+
+void NXMAccessManager::stopProgress()
+{
+ if (m_ProgressDialog) {
+ m_ProgressDialog->stop();
+ }
+}
diff --git a/src/nxmaccessmanager.h b/src/nxmaccessmanager.h
index 2a4c066c..f0bdd8a6 100644
--- a/src/nxmaccessmanager.h
+++ b/src/nxmaccessmanager.h
@@ -137,7 +137,7 @@ class ValidationProgressDialog : public QDialog
Q_OBJECT;
public:
- ValidationProgressDialog(const NexusKeyValidator& v);
+ ValidationProgressDialog(NexusKeyValidator& v);
void setParentWidget(QWidget* w);
@@ -150,7 +150,7 @@ protected:
private:
std::unique_ptr ui;
- const NexusKeyValidator& m_validator;
+ NexusKeyValidator& m_validator;
QTimer* m_updateTimer;
bool m_first;
@@ -169,8 +169,7 @@ class NXMAccessManager : public QNetworkAccessManager
public:
static const std::chrono::seconds ValidationTimeout;
- explicit NXMAccessManager(QObject *parent, const QString &moVersion);
-
+ NXMAccessManager(QObject *parent, const QString &moVersion);
void setTopLevelWidget(QWidget* w);
@@ -233,6 +232,9 @@ private:
void startValidationCheck(const QString& key);
void onValidatorState(NexusKeyValidator::States s, const QString& e);
void onValidatorFinished(const APIUserAccount& user);
+
+ void startProgress();
+ void stopProgress();
};
#endif // NXMACCESSMANAGER_H
--
cgit v1.3.1
From 8269ac1b489d30ca6065ec2b97542ddbb22298b3 Mon Sep 17 00:00:00 2001
From: isanae <14251494+isanae@users.noreply.github.com>
Date: Sat, 5 Oct 2019 13:36:27 -0400
Subject: rework of the nexus key validator to allow multiple attempts before
failing
---
src/nxmaccessmanager.cpp | 495 ++++++++++++++++++++++++++++++--------------
src/nxmaccessmanager.h | 100 ++++++---
src/settingsdialognexus.cpp | 45 ++--
src/settingsdialognexus.h | 5 +-
4 files changed, 428 insertions(+), 217 deletions(-)
(limited to 'src/nxmaccessmanager.h')
diff --git a/src/nxmaccessmanager.cpp b/src/nxmaccessmanager.cpp
index 036b22ff..99b93048 100644
--- a/src/nxmaccessmanager.cpp
+++ b/src/nxmaccessmanager.cpp
@@ -44,7 +44,6 @@ using namespace MOBase;
using namespace std::chrono_literals;
const QString NexusBaseUrl("https://api.nexusmods.com/v1");
-const std::chrono::seconds NXMAccessManager::ValidationTimeout = 10s;
const QString NexusSSO("wss://sso.nexusmods.com");
const QString NexusSSOPage("https://www.nexusmods.com/sso?id=%1&application=modorganizer2");
@@ -69,6 +68,7 @@ void ValidationProgressDialog::setParentWidget(QWidget* w)
if (w && wasVisible) {
setVisible(true);
+ raise();
}
}
@@ -80,9 +80,7 @@ void ValidationProgressDialog::start()
m_updateTimer->setInterval(100ms);
}
- ui->progress->setRange(0, m_validator.timeout().count());
- ui->progress->setValue(0);
-
+ updateProgress();
m_updateTimer->start();
show();
@@ -123,14 +121,35 @@ void ValidationProgressDialog::onCancel()
void ValidationProgressDialog::onTimer()
{
- ui->progress->setValue(m_validator.elapsed().elapsed() / 1000);
+ updateProgress();
+}
+
+void ValidationProgressDialog::updateProgress()
+{
+ const auto* current = m_validator.currentAttempt();
+
+ if (current) {
+ ui->progress->setRange(0, current->timeout().count());
+ ui->progress->setValue(current->elapsed().elapsed() / 1000);
+ } else {
+ // indeterminate
+ ui->progress->setRange(0, 0);
+ }
+
+ if (const auto* a=m_validator.lastAttempt()) {
+ ui->label->setText(a->message() + ". " + tr("Trying again..."));
+ } else if (current) {
+ ui->label->setText(tr("Connecting to Nexus..."));
+ } else {
+ ui->label->setText("?");
+ }
}
NexusSSOLogin::NexusSSOLogin()
: m_keyReceived(false), m_active(false)
{
- m_timeout.setInterval(NXMAccessManager::ValidationTimeout);
+ m_timeout.setInterval(10s);
m_timeout.setSingleShot(true);
QObject::connect(
@@ -167,20 +186,22 @@ QString NexusSSOLogin::stateToString(States s, const QString& e)
return QObject::tr("Waiting for Nexus...");
case WaitingForBrowser:
- return QObject::tr(
- "Opened Nexus in browser.\n"
- "Switch to your browser and accept the request.");
+ return
+ QObject::tr("Opened Nexus in browser.") + "\n" +
+ QObject::tr("Switch to your browser and accept the request.");
case Finished:
return QObject::tr("Finished.");
case Timeout:
- return QObject::tr(
- "No answer from Nexus.\n"
- "A firewall might be blocking Mod Organizer.");
+ return
+ QObject::tr("No answer from Nexus.") + "\n" +
+ QObject::tr("A firewall might be blocking Mod Organizer.");
case ClosedByRemote:
- return QObject::tr("Nexus closed the connection.");
+ return
+ QObject::tr("Nexus closed the connection.") + "\n" +
+ QObject::tr("A firewall might be blocking Mod Organizer.");
case Cancelled:
return QObject::tr("Cancelled.");
@@ -300,10 +321,11 @@ void NexusSSOLogin::onMessage(const QString& s)
void NexusSSOLogin::onDisconnected()
{
if (m_active) {
- m_active = false;
-
if (!m_keyReceived) {
+ close();
setState(ClosedByRemote);
+ } else {
+ m_active = false;
}
}
}
@@ -332,84 +354,48 @@ void NexusSSOLogin::onTimeout()
}
-NexusKeyValidator::NexusKeyValidator(NXMAccessManager& am)
- : m_manager(am), m_reply(nullptr), m_active(false)
+ValidationAttempt::ValidationAttempt(std::chrono::seconds timeout)
+ : m_reply(nullptr), m_result(None)
{
- m_timeout.setInterval(NXMAccessManager::ValidationTimeout);
m_timeout.setSingleShot(true);
+ m_timeout.setInterval(timeout);
QObject::connect(&m_timeout, &QTimer::timeout, [&]{ onTimeout(); });
}
-NexusKeyValidator::~NexusKeyValidator()
-{
- abort();
-}
-
-QString NexusKeyValidator::stateToString(States s, const QString& e)
-{
- switch (s)
- {
- case NexusKeyValidator::Connecting:
- return QObject::tr("Connecting to Nexus...");
-
- case NexusKeyValidator::Finished:
- return QObject::tr("Finished.");
-
- case NexusKeyValidator::InvalidJson:
- return QObject::tr("Invalid JSON");
-
- case NexusKeyValidator::BadResponse:
- return QObject::tr("Bad response");
-
- case NexusKeyValidator::Timeout:
- return QObject::tr("There was a timeout during the request");
-
- case NexusKeyValidator::Cancelled:
- return QObject::tr("Cancelled");
-
- case NexusKeyValidator::Error: // fall-through
- default:
- {
- if (e.isEmpty()) {
- return QString("%1").arg(s);
- } else {
- return e;
- }
- }
- }
-}
-
-void NexusKeyValidator::start(const QString& key)
+void ValidationAttempt::start(NXMAccessManager& m, const QString& key)
{
- if (m_reply) {
- abort();
+ if (!sendRequest(m, key)) {
return;
}
- m_active = true;
- setState(Connecting);
m_elapsed.start();
+ m_timeout.start();
+
+ log::debug(
+ "validator: attempt started with timeout of {} seconds", timeout().count());
+}
+bool ValidationAttempt::sendRequest(
+ NXMAccessManager& m, const QString& key)
+{
const QString requestUrl(NexusBaseUrl + "/users/validate");
QNetworkRequest request(requestUrl);
request.setRawHeader("APIKEY", key.toUtf8());
- request.setHeader(QNetworkRequest::KnownHeaders::UserAgentHeader, m_manager.userAgent().toUtf8());
+ request.setHeader(QNetworkRequest::KnownHeaders::UserAgentHeader, m.userAgent().toUtf8());
request.setHeader(QNetworkRequest::KnownHeaders::ContentTypeHeader, "application/json");
request.setRawHeader("Protocol-Version", "1.0.0");
request.setRawHeader("Application-Name", "MO2");
- request.setRawHeader("Application-Version", m_manager.MOVersion().toUtf8());
+ request.setRawHeader("Application-Version", m.MOVersion().toUtf8());
+
+ m_reply = m.get(request);
- m_reply = m_manager.get(request);
if (!m_reply) {
- close();
- setState(Error, QObject::tr("Failed to request %1").arg(requestUrl));
- return;
+ setFailure(SoftError, QObject::tr("Failed to request %1").arg(requestUrl));
+ return false;
}
- m_timeout.start(NXMAccessManager::ValidationTimeout);
-
QObject::connect(
m_reply, &QNetworkReply::finished,
[&]{ onFinished(); });
@@ -417,93 +403,114 @@ void NexusKeyValidator::start(const QString& key)
QObject::connect(
m_reply, &QNetworkReply::sslErrors,
[&](auto&& errors){ onSslErrors(errors); });
+
+ return true;
}
-void NexusKeyValidator::cancel()
+void ValidationAttempt::cancel()
{
- if (m_active) {
- abort();
- setState(Cancelled);
+ if (!m_reply || m_result != None) {
+ // not running
+ return;
}
+
+ setFailure(Cancelled, QObject::tr("Cancelled"));
+
+ if (m_reply) {
+ m_reply->abort();
+ }
+
+ cleanup();
}
-bool NexusKeyValidator::isActive() const
+bool ValidationAttempt::done() const
{
- return m_active;
+ return (m_result != None);
}
-QElapsedTimer NexusKeyValidator::elapsed() const
+ValidationAttempt::Result ValidationAttempt::result() const
{
- return m_elapsed;
+ return m_result;
}
-std::chrono::seconds NexusKeyValidator::timeout() const
+const QString& ValidationAttempt::message() const
{
- return NXMAccessManager::ValidationTimeout;
+ return m_message;
}
-void NexusKeyValidator::close()
+std::chrono::seconds ValidationAttempt::timeout() const
{
- m_active = false;
- m_timeout.stop();
-
- if (m_reply) {
- m_reply->disconnect();
- m_reply->deleteLater();
- m_reply = nullptr;
- }
+ return std::chrono::duration_cast(
+ m_timeout.intervalAsDuration());
}
-void NexusKeyValidator::abort()
+QElapsedTimer ValidationAttempt::elapsed() const
{
- m_active = false;
- m_timeout.stop();
-
- if (m_reply) {
- m_reply->disconnect();
- m_reply->abort();
- m_reply->deleteLater();
- m_reply = nullptr;
- }
+ return m_elapsed;
}
-void NexusKeyValidator::setState(States s, const QString& error)
+void ValidationAttempt::onFinished()
{
- if (stateChanged) {
- stateChanged(s, error);
+ if (m_result == Cancelled) {
+ return;
}
-}
-void NexusKeyValidator::onFinished()
-{
+ log::debug("validator attempt: request has finished");
+
if (!m_reply) {
// shouldn't happen
+ log::error("validator attempt: reply is null");
+ setFailure(HardError, QObject::tr("Internal error"));
return;
}
- m_timeout.stop();
+ const auto code = m_reply->attribute(
+ QNetworkRequest::HttpStatusCodeAttribute).toInt();
+
+ if (code == 0) {
+ // request wasn't even sent
+ log::error("validator attempt: code is 0");
+ setFailure(SoftError, m_reply->errorString());
+ return;
+ }
- const auto code = m_reply->attribute(QNetworkRequest::HttpStatusCodeAttribute).toInt();
const auto doc = QJsonDocument::fromJson(m_reply->readAll());
const auto headers = m_reply->rawHeaderPairs();
- const auto error = m_reply->errorString();
-
- close();
+ const auto httpError = m_reply->errorString();
const QJsonObject data = doc.object();
if (code != 200) {
- handleError(code, data.value("message").toString(), error);
+ // http request failed
+
+ QString s = m_reply->errorString();
+
+ const auto nexusMessage = data.value("message").toString();
+ if (!nexusMessage.isEmpty()) {
+ if (!s.isEmpty()) {
+ s += ", ";
+ }
+
+ s += nexusMessage;
+ }
+
+ if (s.isEmpty()) {
+ s = QObject::tr("HTTP code %1").arg(code);
+ } else {
+ s += QString(" (%1)").arg(code);
+ }
+
+ setFailure(SoftError, s);
return;
}
if (doc.isNull()) {
- setState(InvalidJson);
+ setFailure(HardError, QObject::tr("Invalid JSON"));
return;
}
if (!data.contains("user_id")) {
- setState(BadResponse);
+ setFailure(HardError, QObject::tr("Bad response"));
return;
}
@@ -512,6 +519,11 @@ void NexusKeyValidator::onFinished()
const QString name = data.value("name").toString();
const bool premium = data.value("is_premium").toBool();
+ if (key.isEmpty()) {
+ setFailure(HardError, QObject::tr("API key is empty"));
+ return;
+ }
+
const auto user = APIUserAccount()
.apiKey(key)
.id(QString("%1").arg(id))
@@ -519,51 +531,218 @@ void NexusKeyValidator::onFinished()
.type(premium ? APIUserAccountTypes::Premium : APIUserAccountTypes::Regular)
.limits(NexusInterface::parseLimits(headers));
- if (finished) {
- setState(Finished);
- finished(user);
+ setSuccess(user);
+}
+
+void ValidationAttempt::onSslErrors(const QList& errors)
+{
+ log::error("validator attempt: ssl errors");
+
+ for (auto& e : errors) {
+ log::error(" . {}", e.errorString());
}
+
+ setFailure(HardError, QObject::tr("SSL error"));
}
-void NexusKeyValidator::onSslErrors(const QList& errors)
+void ValidationAttempt::onTimeout()
{
- if (m_active) {
- for (const auto& e : errors) {
- setState(Error, e.errorString());
- }
+ setFailure(SoftError, QObject::tr("Timed out"));
+}
+
+void ValidationAttempt::setFailure(Result r, const QString& error)
+{
+ if (r != Cancelled) {
+ // don't spam the log
+ log::error("validator attempt: {}", error);
+ }
+
+ cleanup();
+
+ m_result = r;
+ m_message = error;
+
+ if (failure) {
+ failure();
}
}
-void NexusKeyValidator::onTimeout()
+void ValidationAttempt::setSuccess(const APIUserAccount& user)
+{
+ log::debug("validator attempt successful");
+ cleanup();
+
+ m_result = Success;
+ m_message = "";
+
+ if (success) {
+ success(user);
+ }
+}
+
+void ValidationAttempt::cleanup()
+{
+ m_timeout.stop();
+
+ if (m_reply) {
+ m_reply->disconnect();
+ m_reply->deleteLater();
+ m_reply = nullptr;
+ }
+}
+
+
+NexusKeyValidator::NexusKeyValidator(NXMAccessManager& am)
+ : m_manager(am)
{
- abort();
- setState(Timeout);
}
-void NexusKeyValidator::handleError(
- int code, const QString& nexusMessage, const QString& httpError)
+NexusKeyValidator::~NexusKeyValidator()
{
- QString s = httpError;
+ cancel();
+}
- if (!nexusMessage.isEmpty()) {
- if (!s.isEmpty()) {
- s += ", ";
+void NexusKeyValidator::start(const QString& key, Behaviour b)
+{
+ if (isActive()) {
+ log::debug("validator: trying to start while ongoing; ignoring");
+ return;
+ }
+
+ m_key = key;
+
+ switch (b)
+ {
+ case OneShot:
+ {
+ createAttempts({10s});
+ break;
}
- s += nexusMessage;
+ case Retry:
+ {
+ createAttempts({5s, 5s, 10s});
+ break;
+ }
}
- if (code != 0) {
- if (s.isEmpty()) {
- s = QString("HTTP code %1").arg(code);
+ nextTry();
+}
+
+void NexusKeyValidator::createAttempts(
+ const std::vector& timeouts)
+{
+ m_attempts.clear();
+
+ for (auto&& t : timeouts) {
+ m_attempts.push_back(std::make_unique(t));
+ }
+}
+
+void NexusKeyValidator::cancel()
+{
+ log::debug("validator: cancelled");
+
+ for (auto&& a : m_attempts) {
+ a->cancel();
+ }
+}
+
+bool NexusKeyValidator::isActive() const
+{
+ for (auto&& a : m_attempts) {
+ if (!a->done()) {
+ return true;
+ }
+ }
+
+ return false;
+}
+
+const ValidationAttempt* NexusKeyValidator::lastAttempt() const
+{
+ const ValidationAttempt* last = nullptr;
+
+ for (auto&& a : m_attempts) {
+ if (a->done()) {
+ last = a.get();
} else {
- s += QString(" (%1)").arg(code);
+ break;
}
}
- setState(Error, s);
+ return last;
}
+const ValidationAttempt* NexusKeyValidator::currentAttempt() const
+{
+ for (auto&& a : m_attempts) {
+ if (!a->done()) {
+ return a.get();
+ }
+ }
+
+ return nullptr;
+}
+
+bool NexusKeyValidator::nextTry()
+{
+ for (auto&& a : m_attempts) {
+ if (!a->done()) {
+ a->success = [&](auto&& user){ onAttemptSuccess(*a, user); };
+ a->failure = [&]{ onAttemptFailure(*a); };
+
+ a->start(m_manager, m_key);
+ return true;
+ }
+ }
+
+ // no more
+ return false;
+}
+
+void NexusKeyValidator::onAttemptSuccess(
+ const ValidationAttempt&, const APIUserAccount& u)
+{
+ setFinished(ValidationAttempt::Success, "", u);
+}
+
+void NexusKeyValidator::onAttemptFailure(const ValidationAttempt& a)
+{
+ switch (a.result())
+ {
+ case ValidationAttempt::SoftError:
+ {
+ if (!nextTry()) {
+ setFinished(a.result(), a.message(), {});
+ }
+
+ break;
+ }
+
+ case ValidationAttempt::HardError:
+ {
+ cancel();
+ setFinished(a.result(), a.message(), {});
+ break;
+ }
+
+ case ValidationAttempt::Cancelled:
+ {
+ setFinished(ValidationAttempt::Cancelled, QObject::tr("Cancelled"), {});
+ break;
+ }
+ }
+}
+
+void NexusKeyValidator::setFinished(
+ ValidationAttempt::Result r, const QString& message,
+ std::optional user)
+{
+ if (finished) {
+ finished(r, message, user);
+ }
+}
NXMAccessManager::NXMAccessManager(QObject *parent, const QString &moVersion)
@@ -572,8 +751,9 @@ NXMAccessManager::NXMAccessManager(QObject *parent, const QString &moVersion)
, m_validator(*this)
, m_validationState(NotChecked)
{
- m_validator.stateChanged = [&](auto&& s, auto&& e){ onValidatorState(s, e); };
- m_validator.finished = [&](auto&& user){ onValidatorFinished(user); };
+ m_validator.finished = [&](auto&& r, auto&& m, auto&& u) {
+ onValidatorFinished(r, m, u);
+ };
setCookieJar(new PersistentCookieJar(QDir::fromNativeSeparators(
Settings::instance().paths().cache() + "/nexus_cookies.dat")));
@@ -587,7 +767,9 @@ NXMAccessManager::NXMAccessManager(QObject *parent, const QString &moVersion)
void NXMAccessManager::setTopLevelWidget(QWidget* w)
{
if (w) {
- m_ProgressDialog->setParentWidget(w);
+ if (m_ProgressDialog) {
+ m_ProgressDialog->setParentWidget(w);
+ }
} else {
m_ProgressDialog.reset();
m_validator.cancel();
@@ -637,37 +819,30 @@ void NXMAccessManager::clearCookies()
void NXMAccessManager::startValidationCheck(const QString& key)
{
m_validationState = NotChecked;
- m_validator.start(key);
+ m_validator.start(key, NexusKeyValidator::Retry);
startProgress();
}
-void NXMAccessManager::onValidatorState(
- NexusKeyValidator::States s, const QString& e)
+void NXMAccessManager::onValidatorFinished(
+ ValidationAttempt::Result r, const QString& message,
+ std::optional user)
{
- if (s == NexusKeyValidator::Connecting || s == NexusKeyValidator::Finished) {
- // no-op, success is handled in onValidatorFinished()
- return;
- }
-
stopProgress();
- if (s == NexusKeyValidator::Cancelled) {
- m_validationState = NotChecked;
+ if (user) {
+ m_validationState = Valid;
+ emit credentialsReceived(*user);
+ emit validateSuccessful(true);
} else {
- m_validationState = Invalid;
- emit validateFailed(NexusKeyValidator::stateToString(s, e));
+ if (r == ValidationAttempt::Cancelled) {
+ m_validationState = NotChecked;
+ } else {
+ m_validationState = Invalid;
+ emit validateFailed(message);
+ }
}
}
-void NXMAccessManager::onValidatorFinished(const APIUserAccount& user)
-{
- stopProgress();
-
- m_validationState = Valid;
- emit credentialsReceived(user);
- emit validateSuccessful(true);
-}
-
bool NXMAccessManager::validated() const
{
if (m_validator.isActive()) {
diff --git a/src/nxmaccessmanager.h b/src/nxmaccessmanager.h
index f0bdd8a6..b0ea45e7 100644
--- a/src/nxmaccessmanager.h
+++ b/src/nxmaccessmanager.h
@@ -82,53 +82,93 @@ private:
};
-class NexusKeyValidator
+class ValidationAttempt
{
public:
- enum States
+ enum Result
{
- Connecting,
- Finished,
- InvalidJson,
- BadResponse,
- Timeout,
- Cancelled,
- Error
+ None,
+ Success,
+ SoftError,
+ HardError,
+ Cancelled
};
- std::function finished;
- std::function stateChanged;
-
- static QString stateToString(States s, const QString& e);
+ std::function success;
+ std::function failure;
- NexusKeyValidator(NXMAccessManager& am);
- ~NexusKeyValidator();
+ ValidationAttempt(std::chrono::seconds timeout);
+ ValidationAttempt(const ValidationAttempt&) = delete;
+ ValidationAttempt& operator=(const ValidationAttempt&) = delete;
- void start(const QString& key);
+ void start(NXMAccessManager& m, const QString& key);
void cancel();
- bool isActive() const;
- QElapsedTimer elapsed() const;
+ bool done() const;
+ Result result() const;
+ const QString& message() const;
std::chrono::seconds timeout() const;
+ QElapsedTimer elapsed() const;
private:
- NXMAccessManager& m_manager;
QNetworkReply* m_reply;
+ Result m_result;
+ QString m_message;
QTimer m_timeout;
- bool m_active;
QElapsedTimer m_elapsed;
- void setState(States s, const QString& error={});
-
- void close();
- void abort();
+ bool sendRequest(NXMAccessManager& m, const QString& key);
void onFinished();
void onSslErrors(const QList& errors);
void onTimeout();
- void handleError(
- int code, const QString& nexusMessage, const QString& httpError);
+ void setFailure(Result r, const QString& error);
+ void setSuccess(const APIUserAccount& user);
+
+ void cleanup();
+};
+
+
+class NexusKeyValidator
+{
+public:
+ enum Behaviour
+ {
+ OneShot = 0,
+ Retry
+ };
+
+ using FinishedCallback = void (
+ ValidationAttempt::Result, const QString&,
+ std::optional);
+
+ std::function finished;
+
+ NexusKeyValidator(NXMAccessManager& am);
+ ~NexusKeyValidator();
+
+ void start(const QString& key, Behaviour b);
+ void cancel();
+
+ bool isActive() const;
+ const ValidationAttempt* lastAttempt() const;
+ const ValidationAttempt* currentAttempt() const;
+
+private:
+ NXMAccessManager& m_manager;
+ QString m_key;
+ std::vector> m_attempts;
+
+ void createAttempts(const std::vector& timeouts);
+
+ bool nextTry();
+ void onAttemptSuccess(const ValidationAttempt& a, const APIUserAccount& u);
+ void onAttemptFailure(const ValidationAttempt& a);
+
+ void setFinished(
+ ValidationAttempt::Result r, const QString& message,
+ std::optional user);
};
@@ -157,6 +197,7 @@ private:
void onHide();
void onCancel();
void onTimer();
+ void updateProgress();
};
@@ -167,8 +208,6 @@ class NXMAccessManager : public QNetworkAccessManager
{
Q_OBJECT
public:
- static const std::chrono::seconds ValidationTimeout;
-
NXMAccessManager(QObject *parent, const QString &moVersion);
void setTopLevelWidget(QWidget* w);
@@ -230,8 +269,9 @@ private:
States m_validationState;
void startValidationCheck(const QString& key);
- void onValidatorState(NexusKeyValidator::States s, const QString& e);
- void onValidatorFinished(const APIUserAccount& user);
+ void onValidatorFinished(
+ ValidationAttempt::Result r, const QString& message,
+ std::optional);
void startProgress();
void stopProgress();
diff --git a/src/settingsdialognexus.cpp b/src/settingsdialognexus.cpp
index 2021bdc1..209ed661 100644
--- a/src/settingsdialognexus.cpp
+++ b/src/settingsdialognexus.cpp
@@ -240,17 +240,13 @@ void NexusSettingsTab::validateKey(const QString& key)
m_nexusValidator.reset(new NexusKeyValidator(
*NexusInterface::instance(dialog().pluginContainer())->getAccessManager()));
- m_nexusValidator->stateChanged = [&](auto&& s, auto&& e){
- onValidatorStateChanged(s, e);
- };
-
- m_nexusValidator->finished = [&](auto&& user) {
- onValidatorFinished(user);
+ m_nexusValidator->finished = [&](auto&& r, auto&& m, auto&& u) {
+ onValidatorFinished(r, m, u);
};
}
addNexusLog(QObject::tr("Checking API key..."));
- m_nexusValidator->start(key);
+ m_nexusValidator->start(key, NexusKeyValidator::OneShot);
}
void NexusSettingsTab::onSSOKeyChanged(const QString& key)
@@ -277,32 +273,31 @@ void NexusSettingsTab::onSSOStateChanged(NexusSSOLogin::States s, const QString&
updateNexusState();
}
-void NexusSettingsTab::onValidatorStateChanged(
- NexusKeyValidator::States s, const QString& e)
+void NexusSettingsTab::onValidatorFinished(
+ ValidationAttempt::Result r, const QString& message,
+ std::optional user)
{
- if (s != NexusKeyValidator::Finished) {
- // finished state is handled in onValidatorFinished()
- const auto log = NexusKeyValidator::stateToString(s, e);
+ if (user) {
+ NexusInterface::instance(dialog().pluginContainer())->setUserAccount(*user);
+ addNexusLog(QObject::tr("Received user acount information"));
- for (auto&& line : log.split("\n")) {
- addNexusLog(line);
+ if (setKey(user->apiKey())) {
+ addNexusLog(QObject::tr("Linked with Nexus successfully."));
+ } else {
+ addNexusLog(QObject::tr("Failed to set API key"));
+ }
+ } else {
+ if (message.isEmpty()) {
+ // shouldn't happen
+ addNexusLog("Unknown error");
+ } else {
+ addNexusLog(message);
}
}
updateNexusState();
}
-void NexusSettingsTab::onValidatorFinished(const APIUserAccount& user)
-{
- NexusInterface::instance(dialog().pluginContainer())->setUserAccount(user);
-
- if (!user.apiKey().isEmpty()) {
- if (setKey(user.apiKey())) {
- addNexusLog(QObject::tr("Linked with Nexus successfully."));
- }
- }
-}
-
void NexusSettingsTab::addNexusLog(const QString& s)
{
ui->nexusLog->addItem(s);
diff --git a/src/settingsdialognexus.h b/src/settingsdialognexus.h
index 89a6618f..2cb1cc1e 100644
--- a/src/settingsdialognexus.h
+++ b/src/settingsdialognexus.h
@@ -32,8 +32,9 @@ private:
void onSSOKeyChanged(const QString& key);
void onSSOStateChanged(NexusSSOLogin::States s, const QString& e);
- void onValidatorStateChanged(NexusKeyValidator::States s, const QString& e);
- void onValidatorFinished(const APIUserAccount& user);
+ void onValidatorFinished(
+ ValidationAttempt::Result r, const QString& message,
+ std::optional useR);
void addNexusLog(const QString& s);
};
--
cgit v1.3.1
From e7cc4774e1a7d03fb0710875f6a91ec703b0005e Mon Sep 17 00:00:00 2001
From: isanae <14251494+isanae@users.noreply.github.com>
Date: Sat, 5 Oct 2019 13:47:11 -0400
Subject: don't show the progress dialog on startup until after the first
failure
---
src/nxmaccessmanager.cpp | 45 +++++++++++++++++++++++++++++++++++++++++++--
src/nxmaccessmanager.h | 4 ++++
2 files changed, 47 insertions(+), 2 deletions(-)
(limited to 'src/nxmaccessmanager.h')
diff --git a/src/nxmaccessmanager.cpp b/src/nxmaccessmanager.cpp
index 99b93048..5d8b8b9e 100644
--- a/src/nxmaccessmanager.cpp
+++ b/src/nxmaccessmanager.cpp
@@ -702,13 +702,21 @@ bool NexusKeyValidator::nextTry()
}
void NexusKeyValidator::onAttemptSuccess(
- const ValidationAttempt&, const APIUserAccount& u)
+ const ValidationAttempt& a, const APIUserAccount& u)
{
+ if (attemptFinished) {
+ attemptFinished(a);
+ }
+
setFinished(ValidationAttempt::Success, "", u);
}
void NexusKeyValidator::onAttemptFailure(const ValidationAttempt& a)
{
+ if (attemptFinished) {
+ attemptFinished(a);
+ }
+
switch (a.result())
{
case ValidationAttempt::SoftError:
@@ -755,6 +763,10 @@ NXMAccessManager::NXMAccessManager(QObject *parent, const QString &moVersion)
onValidatorFinished(r, m, u);
};
+ m_validator.attemptFinished = [&](auto&& a) {
+ onValidatorAttemptFinished(a);
+ };
+
setCookieJar(new PersistentCookieJar(QDir::fromNativeSeparators(
Settings::instance().paths().cache() + "/nexus_cookies.dat")));
@@ -820,7 +832,12 @@ void NXMAccessManager::startValidationCheck(const QString& key)
{
m_validationState = NotChecked;
m_validator.start(key, NexusKeyValidator::Retry);
- startProgress();
+
+ if (m_ProgressDialog) {
+ // don't show the progress dialog on startup for the first attempt; the
+ // dialog will be shown in onValidatorAttemptFinished() if it failed
+ startProgress();
+ }
}
void NXMAccessManager::onValidatorFinished(
@@ -843,6 +860,30 @@ void NXMAccessManager::onValidatorFinished(
}
}
+void NXMAccessManager::onValidatorAttemptFinished(const ValidationAttempt& a)
+{
+ if (!m_ProgressDialog) {
+ switch (a.result())
+ {
+ case ValidationAttempt::SoftError:
+ case ValidationAttempt::HardError:
+ {
+ startProgress();
+ break;
+ }
+
+ case ValidationAttempt::None:
+ case ValidationAttempt::Success:
+ case ValidationAttempt::Cancelled:
+ default:
+ {
+ // don't show the dialog
+ break;
+ }
+ }
+ }
+}
+
bool NXMAccessManager::validated() const
{
if (m_validator.isActive()) {
diff --git a/src/nxmaccessmanager.h b/src/nxmaccessmanager.h
index b0ea45e7..6a45d880 100644
--- a/src/nxmaccessmanager.h
+++ b/src/nxmaccessmanager.h
@@ -144,6 +144,7 @@ public:
std::optional);
std::function finished;
+ std::function attemptFinished;
NexusKeyValidator(NXMAccessManager& am);
~NexusKeyValidator();
@@ -269,10 +270,13 @@ private:
States m_validationState;
void startValidationCheck(const QString& key);
+
void onValidatorFinished(
ValidationAttempt::Result r, const QString& message,
std::optional);
+ void onValidatorAttemptFinished(const ValidationAttempt& a);
+
void startProgress();
void stopProgress();
};
--
cgit v1.3.1