summaryrefslogtreecommitdiff
path: root/src
diff options
context:
space:
mode:
authorSilarn <jrim@rimpo.org>2019-01-29 15:12:59 -0600
committerSilarn <jrim@rimpo.org>2019-02-18 21:28:27 -0600
commitef286a938d79f74947a392d049068e4818ccf7fd (patch)
treeea00a2230be258ee3e54b8f5124fc9483c91865c /src
parenta305ea2270c02172973f365986f194652ad344ec (diff)
Multiple fixes:
* Uses current daily/hourly rate limits * Fixed issue with translating API game string to mod game string ** Corrects issues with update checks and downloads
Diffstat (limited to 'src')
-rw-r--r--src/downloadmanager.cpp29
-rw-r--r--src/downloadmanager.h3
-rw-r--r--src/mainwindow.cpp20
-rw-r--r--src/mainwindow.h3
-rw-r--r--src/nexusinterface.cpp56
-rw-r--r--src/nexusinterface.h11
-rw-r--r--src/nxmaccessmanager.cpp10
-rw-r--r--src/nxmaccessmanager.h240
8 files changed, 201 insertions, 171 deletions
diff --git a/src/downloadmanager.cpp b/src/downloadmanager.cpp
index 2ba46d74..f5e4d688 100644
--- a/src/downloadmanager.cpp
+++ b/src/downloadmanager.cpp
@@ -19,11 +19,11 @@ along with Mod Organizer. If not, see <http://www.gnu.org/licenses/>.
#include "downloadmanager.h"
+#include "organizercore.h"
#include "nxmurl.h"
#include "nexusinterface.h"
#include "nxmaccessmanager.h"
#include "iplugingame.h"
-#include "downloadmanager.h"
#include <nxmurl.h>
#include <taskprogressmanager.h>
#include "utility.h"
@@ -203,6 +203,7 @@ QString DownloadManager::DownloadInfo::currentURL()
DownloadManager::DownloadManager(NexusInterface *nexusInterface, QObject *parent)
: IDownloadManager(parent), m_NexusInterface(nexusInterface), m_DirWatcher(), m_ShowHidden(false)
{
+ m_OrganizerCore = dynamic_cast<OrganizerCore*>(parent);
connect(&m_DirWatcher, SIGNAL(directoryChanged(QString)), this, SLOT(directoryChanged(QString)));
m_TimeoutTimer.setSingleShot(false);
//connect(&m_TimeoutTimer, SIGNAL(timeout()), this, SLOT(checkDownloadTimeout()));
@@ -1532,7 +1533,16 @@ void DownloadManager::nxmFileInfoAvailable(QString gameName, int modID, int file
info->description = BBCode::convertToHTML(result["changelog_html"].toString());
info->repository = "Nexus";
- info->gameName = gameName;
+
+ QStringList games(m_ManagedGame->validShortNames());
+ games += m_ManagedGame->gameShortName();
+ for (auto game : games) {
+ MOBase::IPluginGame *gamePlugin = m_OrganizerCore->getGame(game);
+ if (gamePlugin->gameNexusName().compare(gameName, Qt::CaseInsensitive) == 0) {
+ info->gameName = gamePlugin->gameShortName();
+ }
+ }
+
info->modID = modID;
info->fileID = fileID;
@@ -1597,10 +1607,21 @@ void DownloadManager::nxmDownloadURLsAvailable(QString gameName, int modID, int
m_RequestIDs.erase(idIter);
}
+ QString gameShortName;
+ QStringList games(m_ManagedGame->validShortNames());
+ games += m_ManagedGame->gameShortName();
+ for (auto game : games) {
+ MOBase::IPluginGame *gamePlugin = m_OrganizerCore->getGame(game);
+ if (gamePlugin->gameNexusName() == gameName) {
+ gameShortName = gamePlugin->gameShortName();
+ break;
+ }
+ }
+
ModRepositoryFileInfo *info = qobject_cast<ModRepositoryFileInfo*>(qvariant_cast<QObject*>(userData));
QVariantList resultList = resultData.toList();
if (resultList.length() == 0) {
- removePending(gameName, modID, fileID);
+ removePending(gameShortName, modID, fileID);
emit showMessage(tr("No download server available. Please try again later."));
return;
}
@@ -1614,7 +1635,7 @@ void DownloadManager::nxmDownloadURLsAvailable(QString gameName, int modID, int
foreach (const QVariant &server, resultList) {
URLs.append(server.toMap()["URI"].toString());
}
- addDownload(URLs, gameName, modID, fileID, info);
+ addDownload(URLs, gameShortName, modID, fileID, info);
}
diff --git a/src/downloadmanager.h b/src/downloadmanager.h
index 3c36143e..841a9fbc 100644
--- a/src/downloadmanager.h
+++ b/src/downloadmanager.h
@@ -40,6 +40,7 @@ namespace MOBase { class IPluginGame; }
class NexusInterface;
class PluginContainer;
+class OrganizerCore;
/*!
* \brief manages downloading of files and provides progress information for gui elements
@@ -532,6 +533,8 @@ private:
NexusInterface *m_NexusInterface;
+ OrganizerCore *m_OrganizerCore;
+
QVector<std::tuple<QString, int, int>> m_PendingDownloads;
QVector<DownloadInfo*> m_ActiveDownloads;
diff --git a/src/mainwindow.cpp b/src/mainwindow.cpp
index 02720d44..094a44af 100644
--- a/src/mainwindow.cpp
+++ b/src/mainwindow.cpp
@@ -402,9 +402,9 @@ MainWindow::MainWindow(QSettings &initSettings
connect(NexusInterface::instance(&pluginContainer)->getAccessManager(), SIGNAL(validateFailed(QString)), this, SLOT(validationFailed(QString)));
connect(NexusInterface::instance(&pluginContainer)->getAccessManager(), SIGNAL(credentialsReceived(const QString&, bool)),
this, SLOT(updateWindowTitle(const QString&, bool)));
- connect(NexusInterface::instance(&pluginContainer)->getAccessManager(), SIGNAL(credentialsReceived(const QString&, bool)),
- NexusInterface::instance(&m_PluginContainer), SLOT(setRateMax(const QString&, bool)));
- connect(NexusInterface::instance(&pluginContainer), SIGNAL(requestsChanged(int, int)), this, SLOT(updateAPICounter(int, int)));
+ connect(NexusInterface::instance(&pluginContainer)->getAccessManager(), SIGNAL(credentialsReceived(const QString&, bool, std::tuple<int, int, int, int>)),
+ NexusInterface::instance(&m_PluginContainer), SLOT(setRateMax(const QString&, bool, std::tuple<int, int, int, int>)));
+ connect(NexusInterface::instance(&pluginContainer), SIGNAL(requestsChanged(int, std::tuple<int, int, int, int>)), this, SLOT(updateAPICounter(int, std::tuple<int, int, int, int>)));
connect(&TutorialManager::instance(), SIGNAL(windowTutorialFinished(QString)), this, SLOT(windowTutorialFinished(QString)));
connect(ui->tabWidget, SIGNAL(currentChanged(int)), &TutorialManager::instance(), SIGNAL(tabChanged(int)));
@@ -439,11 +439,6 @@ MainWindow::MainWindow(QSettings &initSettings
connect(&m_SaveMetaTimer, SIGNAL(timeout()), this, SLOT(saveModMetas()));
m_SaveMetaTimer.start(5000);
- m_NexusLimitTimer.setTimerType(Qt::TimerType::PreciseTimer);
- m_NexusLimitTimer.setSingleShot(false);
- connect(&m_NexusLimitTimer, SIGNAL(timeout()), NexusInterface::instance(&m_PluginContainer), SLOT(calculateRequests()));
- m_NexusLimitTimer.start(1000);
-
setCategoryListVisible(initSettings.value("categorylist_visible", true).toBool());
FileDialogMemory::restore(initSettings);
@@ -5640,14 +5635,15 @@ void MainWindow::nxmRequestFailed(QString gameName, int modID, int, QVariant, in
}
-void MainWindow::updateAPICounter(int queueCount, int requestsRemaining)
+void MainWindow::updateAPICounter(int queueCount, std::tuple<int, int, int, int> limits)
{
- ui->apiRequests->setText(QString("API: Q: %1 | T: %2").arg(queueCount).arg(requestsRemaining));
- if (requestsRemaining > 150) {
+ ui->apiRequests->setText(QString("API: Q: %1 | D: %2 | H: %3").arg(queueCount).arg(std::get<0>(limits)).arg(std::get<2>(limits)));
+ int requestsRemaining = std::get<0>(limits) + std::get<2>(limits);
+ if (requestsRemaining > 300) {
QPalette palette = ui->apiRequests->palette();
palette.setColor(ui->apiRequests->backgroundRole(), Qt::darkGreen);
ui->apiRequests->setPalette(palette);
- } else if (requestsRemaining < 50) {
+ } else if (requestsRemaining < 150) {
QPalette palette = ui->apiRequests->palette();
palette.setColor(ui->apiRequests->backgroundRole(), Qt::darkRed);
ui->apiRequests->setPalette(palette);
diff --git a/src/mainwindow.h b/src/mainwindow.h
index 900f7cba..b3490d07 100644
--- a/src/mainwindow.h
+++ b/src/mainwindow.h
@@ -348,7 +348,6 @@ private:
QTimer m_CheckBSATimer;
QTimer m_SaveMetaTimer;
QTimer m_UpdateProblemsTimer;
- QTimer m_NexusLimitTimer;
QFuture<void> m_MetaSave;
@@ -515,7 +514,7 @@ private slots:
void nxmDownloadURLs(QString, int modID, int fileID, QVariant userData, QVariant resultData, int requestID);
void nxmRequestFailed(QString gameName, int modID, int fileID, QVariant userData, int requestID, QNetworkReply::NetworkError error, const QString &errorString);
- void updateAPICounter(int queueCount, int requestsRemaining);
+ void updateAPICounter(int queueCount, std::tuple<int, int, int, int> limits);
void editCategories();
void deselectFilters();
diff --git a/src/nexusinterface.cpp b/src/nexusinterface.cpp
index 1e50f0b2..7481cf96 100644
--- a/src/nexusinterface.cpp
+++ b/src/nexusinterface.cpp
@@ -148,7 +148,7 @@ QAtomicInt NexusInterface::NXMRequestInfo::s_NextID(0);
NexusInterface::NexusInterface(PluginContainer *pluginContainer)
- : m_NMMVersion(), m_PluginContainer(pluginContainer), m_RemainingRequests(300), m_MaxRequests(300)
+ : m_NMMVersion(), m_PluginContainer(pluginContainer), m_RemainingDailyRequests(0), m_RemainingHourlyRequests(0), m_MaxDailyRequests(0), m_MaxHourlyRequests(0)
{
m_MOVersion = createVersionInfo();
@@ -194,16 +194,13 @@ void NexusInterface::loginCompleted()
nextRequest();
}
-void NexusInterface::setRateMax(const QString &userName, bool isPremium)
+void NexusInterface::setRateMax(const QString&, bool, std::tuple<int, int, int, int> limits)
{
- if (isPremium) {
- m_MaxRequests = 600;
- m_RemainingRequests = 600;
- } else {
- m_MaxRequests = 300;
- m_RemainingRequests = 300;
- }
- emit requestsChanged(m_RequestQueue.size(), m_RemainingRequests);
+ m_RemainingDailyRequests = std::get<0>(limits);
+ m_MaxDailyRequests = std::get<1>(limits);
+ m_RemainingHourlyRequests = std::get<2>(limits);
+ m_MaxHourlyRequests = std::get<3>(limits);
+ emit requestsChanged(m_RequestQueue.size(), limits);
}
void NexusInterface::interpretNexusFileName(const QString &fileName, QString &modName, int &modID, bool query)
@@ -474,10 +471,16 @@ void NexusInterface::nextRequest()
return;
}
- if (m_RemainingRequests <= 0) {
- qWarning() << tr("You've exceeded the Nexus API rate limit and requests are now being throttled.");
- if (!m_RetryTimer.isActive())
- m_RetryTimer.start();
+ if (m_RemainingDailyRequests + m_RemainingHourlyRequests <= 0) {
+ if (!m_RetryTimer.isActive()) {
+ QTime time = QTime::currentTime();
+ QTime targetTime;
+ targetTime.setHMS((time.hour() + 1) % 23, 0, 5);
+ m_RetryTimer.start(time.msecsTo(targetTime));
+ QString warning("You've exceeded the Nexus API rate limit and requests are now being throttled. "
+ "Your next batch of requests will be available in approximately %1 minutes and %2 seconds.");
+ qWarning() << warning.arg(time.secsTo(targetTime) / 60).arg(time.secsTo(targetTime) % 60);
+ }
return;
}
@@ -490,8 +493,6 @@ void NexusInterface::nextRequest()
}
}
- m_RemainingRequests--;
-
NXMRequestInfo info = m_RequestQueue.dequeue();
info.m_Timeout = new QTimer(this);
info.m_Timeout->setInterval(60000);
@@ -545,7 +546,6 @@ void NexusInterface::nextRequest()
connect(info.m_Timeout, SIGNAL(timeout()), this, SLOT(requestTimeout()));
info.m_Timeout->start();
m_ActiveRequest.push_back(info);
- emit requestsChanged(m_RequestQueue.size(), m_RemainingRequests);
}
@@ -561,8 +561,6 @@ void NexusInterface::requestFinished(std::list<NXMRequestInfo>::iterator iter)
if (reply->error() != QNetworkReply::NoError) {
int statusCode = reply->attribute(QNetworkRequest::HttpStatusCodeAttribute).toInt();
if (statusCode == 429) {
- m_RemainingRequests = 0;
- emit requestsChanged(m_RequestQueue.size(), m_RemainingRequests);
qWarning("Requests have hit the rate limit threshold and are now being throttled. This request will be retried.");
qWarning("Error: %s", reply->errorString().toUtf8().constData());
m_RequestQueue.enqueue(*iter);
@@ -617,6 +615,18 @@ void NexusInterface::requestFinished(std::list<NXMRequestInfo>::iterator iter)
}
}
}
+
+ m_RemainingDailyRequests = reply->rawHeader("x-rl-daily-remaining").toInt();
+ m_MaxDailyRequests = reply->rawHeader("x-rl-daily-limit").toInt();
+ m_RemainingHourlyRequests = reply->rawHeader("x-rl-hourly-remaining").toInt();
+ m_MaxHourlyRequests = reply->rawHeader("x-rl-hourly-limit").toInt();
+
+ emit requestsChanged(m_RequestQueue.size(), std::tuple<int, int, int, int>(std::make_tuple(
+ m_RemainingDailyRequests,
+ m_MaxDailyRequests,
+ m_RemainingHourlyRequests,
+ m_MaxHourlyRequests
+ )));
}
@@ -668,14 +678,6 @@ void NexusInterface::requestTimeout()
}
}
-void NexusInterface::calculateRequests()
-{
- if (m_RemainingRequests < m_MaxRequests) {
- m_RemainingRequests++;
- emit requestsChanged(m_RequestQueue.size(), m_RemainingRequests);
- }
-}
-
namespace {
QString get_management_url(MOBase::IPluginGame const *game)
{
diff --git a/src/nexusinterface.h b/src/nexusinterface.h
index a68948e6..e60ebf3f 100644
--- a/src/nexusinterface.h
+++ b/src/nexusinterface.h
@@ -348,12 +348,11 @@ signals:
void nxmDownloadURLsAvailable(QString gameName, int modID, int fileID, QVariant userData, QVariant resultData, int requestID);
void nxmEndorsementToggled(QString gameName, int modID, QVariant userData, QVariant resultData, int requestID);
void nxmRequestFailed(QString gameName, int modID, int fileID, QVariant userData, int requestID, QNetworkReply::NetworkError error, const QString &errorString);
- void requestsChanged(int queueCount, int requestsRemaining);
+ void requestsChanged(int queueCount, std::tuple<int,int,int,int> requestsRemaining);
public slots:
- void setRateMax(const QString &userName, bool isPremium);
- void calculateRequests();
+ void setRateMax(const QString&, bool, std::tuple<int,int,int,int> limits);
private slots:
@@ -426,8 +425,10 @@ private:
QTimer m_RetryTimer;
- int m_RemainingRequests;
- int m_MaxRequests;
+ int m_RemainingDailyRequests;
+ int m_RemainingHourlyRequests;
+ int m_MaxDailyRequests;
+ int m_MaxHourlyRequests;
};
diff --git a/src/nxmaccessmanager.cpp b/src/nxmaccessmanager.cpp
index 6847ba25..d9bb2905 100644
--- a/src/nxmaccessmanager.cpp
+++ b/src/nxmaccessmanager.cpp
@@ -252,7 +252,15 @@ void NXMAccessManager::validateFinished()
QString test = jdoc.toJson();
QString name = credentialsData.value("name").toString();
bool premium = credentialsData.value("is_premium?").toBool();
- emit credentialsReceived(name, premium);
+
+ std::tuple<int, int, int, int> limits(std::make_tuple(
+ m_ValidateReply->rawHeader("x-rl-daily-remaining").toInt(),
+ m_ValidateReply->rawHeader("x-rl-daily-limit").toInt(),
+ m_ValidateReply->rawHeader("x-rl-hourly-remaining").toInt(),
+ m_ValidateReply->rawHeader("x-rl-hourly-limit").toInt()
+ ));
+
+ emit credentialsReceived(name, premium, limits);
m_ValidateReply->deleteLater();
m_ValidateReply = nullptr;
diff --git a/src/nxmaccessmanager.h b/src/nxmaccessmanager.h
index b316ef77..7fdb508f 100644
--- a/src/nxmaccessmanager.h
+++ b/src/nxmaccessmanager.h
@@ -1,120 +1,120 @@
-/*
-Copyright (C) 2012 Sebastian Herbord. All rights reserved.
-
-This file is part of Mod Organizer.
-
-Mod Organizer is free software: you can redistribute it and/or modify
-it under the terms of the GNU General Public License as published by
-the Free Software Foundation, either version 3 of the License, or
-(at your option) any later version.
-
-Mod Organizer is distributed in the hope that it will be useful,
-but WITHOUT ANY WARRANTY; without even the implied warranty of
-MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
-GNU General Public License for more details.
-
-You should have received a copy of the GNU General Public License
-along with Mod Organizer. If not, see <http://www.gnu.org/licenses/>.
-*/
-
-#ifndef NXMACCESSMANAGER_H
-#define NXMACCESSMANAGER_H
-
-
-#include <QNetworkAccessManager>
-#include <QTimer>
-#include <QNetworkReply>
-#include <QProgressDialog>
-#include <set>
-
-namespace MOBase { class IPluginGame; }
-
-/**
- * @brief access manager extended to handle nxm links
- **/
-class NXMAccessManager : public QNetworkAccessManager
-{
- Q_OBJECT
-public:
-
- explicit NXMAccessManager(QObject *parent, const QString &moVersion);
-
- ~NXMAccessManager();
-
- void setNMMVersion(const QString &nmmVersion);
-
- bool validated() const;
-
- bool validateAttempted() const;
- bool validateWaiting() const;
-
- void apiCheck(const QString &apiKey);
-
- void showCookies() const;
-
- void clearCookies();
-
- QString userAgent(const QString &subModule = QString()) const;
-
- QString apiKey() const;
-
- void startValidationCheck();
-
- void refuseValidation();
-
-signals:
-
- /**
- * @brief emitted when a nxm:// link is opened
- *
- * @param url the nxm-link
- **/
- void requestNXMDownload(const QString &url);
-
- /**
- * @brief emitted after a successful login or if login was not necessary
- *
- * @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 QString &userName, bool premium);
-
-private slots:
-
- void validateFinished();
- void validateError(QNetworkReply::NetworkError errorCode);
- void validateTimeout();
-
-protected:
-
- virtual QNetworkReply *createRequest(
- QNetworkAccessManager::Operation operation, const QNetworkRequest &request,
- QIODevice *device);
-
-private:
-
- QTimer m_ValidateTimeout;
- QNetworkReply *m_ValidateReply;
- QProgressDialog *m_ProgressDialog { nullptr };
-
- QString m_MOVersion;
- QString m_NMMVersion;
-
- QString m_ApiKey;
-
- bool m_ValidateAttempted;
- enum {
- VALIDATE_NOT_CHECKED,
- VALIDATE_CHECKING,
- VALIDATE_NOT_VALID,
- VALIDATE_ATTEMPT_FAILED,
- VALIDATE_REFUSED,
- VALIDATE_VALID
- } m_ValidateState = VALIDATE_NOT_CHECKED;
-
-};
-
-#endif // NXMACCESSMANAGER_H
+/*
+Copyright (C) 2012 Sebastian Herbord. All rights reserved.
+
+This file is part of Mod Organizer.
+
+Mod Organizer is free software: you can redistribute it and/or modify
+it under the terms of the GNU General Public License as published by
+the Free Software Foundation, either version 3 of the License, or
+(at your option) any later version.
+
+Mod Organizer is distributed in the hope that it will be useful,
+but WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+GNU General Public License for more details.
+
+You should have received a copy of the GNU General Public License
+along with Mod Organizer. If not, see <http://www.gnu.org/licenses/>.
+*/
+
+#ifndef NXMACCESSMANAGER_H
+#define NXMACCESSMANAGER_H
+
+
+#include <QNetworkAccessManager>
+#include <QTimer>
+#include <QNetworkReply>
+#include <QProgressDialog>
+#include <set>
+
+namespace MOBase { class IPluginGame; }
+
+/**
+ * @brief access manager extended to handle nxm links
+ **/
+class NXMAccessManager : public QNetworkAccessManager
+{
+ Q_OBJECT
+public:
+
+ explicit NXMAccessManager(QObject *parent, const QString &moVersion);
+
+ ~NXMAccessManager();
+
+ void setNMMVersion(const QString &nmmVersion);
+
+ bool validated() const;
+
+ bool validateAttempted() const;
+ bool validateWaiting() const;
+
+ void apiCheck(const QString &apiKey);
+
+ void showCookies() const;
+
+ void clearCookies();
+
+ QString userAgent(const QString &subModule = QString()) const;
+
+ QString apiKey() const;
+
+ void startValidationCheck();
+
+ void refuseValidation();
+
+signals:
+
+ /**
+ * @brief emitted when a nxm:// link is opened
+ *
+ * @param url the nxm-link
+ **/
+ void requestNXMDownload(const QString &url);
+
+ /**
+ * @brief emitted after a successful login or if login was not necessary
+ *
+ * @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 QString &userName, bool premium, std::tuple<int, int, int, int> limits);
+
+private slots:
+
+ void validateFinished();
+ void validateError(QNetworkReply::NetworkError errorCode);
+ void validateTimeout();
+
+protected:
+
+ virtual QNetworkReply *createRequest(
+ QNetworkAccessManager::Operation operation, const QNetworkRequest &request,
+ QIODevice *device);
+
+private:
+
+ QTimer m_ValidateTimeout;
+ QNetworkReply *m_ValidateReply;
+ QProgressDialog *m_ProgressDialog { nullptr };
+
+ QString m_MOVersion;
+ QString m_NMMVersion;
+
+ QString m_ApiKey;
+
+ bool m_ValidateAttempted;
+ enum {
+ VALIDATE_NOT_CHECKED,
+ VALIDATE_CHECKING,
+ VALIDATE_NOT_VALID,
+ VALIDATE_ATTEMPT_FAILED,
+ VALIDATE_REFUSED,
+ VALIDATE_VALID
+ } m_ValidateState = VALIDATE_NOT_CHECKED;
+
+};
+
+#endif // NXMACCESSMANAGER_H