summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorSilarn <jrim@rimpo.org>2019-02-09 04:52:44 -0600
committerSilarn <jrim@rimpo.org>2019-02-18 21:31:20 -0600
commit5a7d0243c69d5194ee1a4d0be05d2bcaec18aeac (patch)
tree649ac46d7eb4f53cae61ec28f8c5adf67ec4035a
parentb59c44aaa16fc286159059a2b940c144a577e01a (diff)
Implement bulk update check layer
-rw-r--r--src/mainwindow.cpp33
-rw-r--r--src/mainwindow.h1
-rw-r--r--src/modinfo.cpp73
-rw-r--r--src/modinfo.h2
-rw-r--r--src/modinforegular.cpp4
-rw-r--r--src/nexusinterface.cpp64
-rw-r--r--src/nexusinterface.h24
7 files changed, 188 insertions, 13 deletions
diff --git a/src/mainwindow.cpp b/src/mainwindow.cpp
index a17b51d5..5e97a959 100644
--- a/src/mainwindow.cpp
+++ b/src/mainwindow.cpp
@@ -5468,10 +5468,39 @@ void MainWindow::modUpdateCheck(std::multimap<QString, int> IDs)
if (m_OrganizerCore.settings().getNexusApiKey(apiKey)) {
m_OrganizerCore.doAfterLogin([=]() { this->modUpdateCheck(IDs); });
NexusInterface::instance(&m_PluginContainer)->getAccessManager()->apiCheck(apiKey);
- } else {
+ } else
qWarning("You are not currently authenticated with Nexus. Please do so under Settings -> Nexus.");
+ }
+}
+
+void MainWindow::nxmUpdateInfoAvailable(QString gameName, QVariant userData, QVariant resultData, int)
+{
+ QString gameNameReal;
+ for (IPluginGame *game : m_PluginContainer.plugins<IPluginGame>()) {
+ if (game->gameNexusName() == gameName) {
+ gameNameReal = game->gameShortName();
+ break;
+ }
+ }
+ QVariantList resultList = resultData.toList();
+ std::set<QSharedPointer<ModInfo>> finalMods = ModInfo::filteredMods(gameNameReal, resultList, userData.toBool(), true);
+
+ if (finalMods.empty()) {
+ qInfo("None of your mods appear to have had recent file updates.");
+ }
+
+ std::set<std::pair<QString, int>> organizedGames;
+ for (auto mod : finalMods) {
+ if (mod->canBeUpdated()) {
+ organizedGames.insert(std::make_pair<QString, int>(mod->getGameName().toLower(), mod->getNexusID()));
}
}
+
+ if (!finalMods.empty() && organizedGames.empty())
+ qWarning("All of your mods have been checked recently. We restrict update checks to help preserve your available API requests.");
+
+ for (auto game : organizedGames)
+ NexusInterface::instance(&m_PluginContainer)->requestUpdates(game.second, this, QVariant(), game.first, QString());
}
void MainWindow::nxmUpdatesAvailable(QString gameName, int modID, QVariant userData, QVariant resultData, int requestID)
@@ -5594,7 +5623,7 @@ void MainWindow::nxmModInfoAvailable(QString gameName, int modID, QVariant userD
mod->setIsEndorsed(false);
}
mod->setLastNexusQuery(QDateTime::currentDateTimeUtc());
- mod->setNexusLastModified(QDateTime::fromSecsSinceEpoch(result["updated_timestamp"].toInt()));
+ mod->setNexusLastModified(QDateTime::fromSecsSinceEpoch(result["updated_timestamp"].toInt(), Qt::UTC));
mod->saveMeta();
}
}
diff --git a/src/mainwindow.h b/src/mainwindow.h
index 59be9800..d2704b72 100644
--- a/src/mainwindow.h
+++ b/src/mainwindow.h
@@ -510,6 +510,7 @@ private slots:
void modUpdateCheck(std::multimap<QString, int> IDs);
+ void nxmUpdateInfoAvailable(QString gameName, QVariant userData, QVariant resultData, int requestID);
void nxmUpdatesAvailable(QString gameName, int modID, QVariant userData, QVariant resultData, int requestID);
void nxmModInfoAvailable(QString gameName, int modID, QVariant userData, QVariant resultData, int requestID);
void nxmEndorsementToggled(QString, int, QVariant, QVariant resultData, int);
diff --git a/src/modinfo.cpp b/src/modinfo.cpp
index a1059e24..3e694baf 100644
--- a/src/modinfo.cpp
+++ b/src/modinfo.cpp
@@ -294,25 +294,82 @@ int ModInfo::checkAllForUpdate(PluginContainer *pluginContainer, QObject *receiv
// NexusInterface::instance(pluginContainer)->requestUpdates(game->nexusModOrganizerID(), receiver, QVariant(), game->gameShortName(), QString());
//}
- std::set<std::pair<QString, int>> organizedGames;
+ QDateTime earliest = QDateTime::currentDateTimeUtc();
+ QDateTime latest;
+ std::set<QString> games;
for (auto mod : s_Collection) {
if (mod->canBeUpdated()) {
- organizedGames.insert(std::make_pair<QString, int>(mod->getGameName().toLower(), mod->getNexusID()));
+ if (mod->getLastNexusUpdate() < earliest)
+ earliest = mod->getLastNexusUpdate();
+ if (mod->getLastNexusUpdate() > latest)
+ latest = mod->getLastNexusUpdate();
+ games.insert(mod->getGameName().toLower());
}
}
- result = organizedGames.size();
-
- if (organizedGames.empty())
- qWarning("All of your mods have been checked recently. We restrict update checks to help preserve your available API requests.");
+ if (latest < QDateTime::currentDateTimeUtc().addDays(-30)) {
+ std::set<std::pair<QString, int>> organizedGames;
+ for (auto mod : s_Collection) {
+ if (mod->canBeUpdated()) {
+ organizedGames.insert(std::make_pair<QString, int>(mod->getGameName().toLower(), mod->getNexusID()));
+ }
+ }
+
+ result = organizedGames.size();
- for (auto game : organizedGames) {
- NexusInterface::instance(pluginContainer)->requestUpdates(game.second, receiver, QVariant(), game.first, QString());
+ if (organizedGames.empty())
+ qWarning("All of your mods have been checked recently. We restrict update checks to help preserve your available API requests.");
+
+ for (auto game : organizedGames) {
+ NexusInterface::instance(pluginContainer)->requestUpdates(game.second, receiver, QVariant(), game.first, QString());
+ }
+ } else if (earliest < QDateTime::currentDateTimeUtc().addDays(-30)) {
+ for (auto gameName : games)
+ NexusInterface::instance(pluginContainer)->requestUpdateInfo(gameName, NexusInterface::UpdatePeriod::MONTH, receiver, QVariant(true), QString());
+ } else if (earliest < QDateTime::currentDateTimeUtc().addDays(-7)) {
+ for (auto gameName : games)
+ NexusInterface::instance(pluginContainer)->requestUpdateInfo(gameName, NexusInterface::UpdatePeriod::MONTH, receiver, QVariant(false), QString());
+ } else if (earliest < QDateTime::currentDateTimeUtc().addDays(-1)) {
+ for (auto gameName : games)
+ NexusInterface::instance(pluginContainer)->requestUpdateInfo(gameName, NexusInterface::UpdatePeriod::WEEK, receiver, QVariant(false), QString());
+ } else {
+ for (auto gameName : games)
+ NexusInterface::instance(pluginContainer)->requestUpdateInfo(gameName, NexusInterface::UpdatePeriod::DAY, receiver, QVariant(false), QString());
}
return result;
}
+std::set<QSharedPointer<ModInfo>> ModInfo::filteredMods(QString gameName, QVariantList updateData, bool addOldMods, bool markUpdated)
+{
+ std::set<QSharedPointer<ModInfo>> finalMods;
+ for (QVariant result : updateData) {
+ QVariantMap update = result.toMap();
+ for (auto mod : s_Collection)
+ if (mod->getNexusID() == update["mod_id"].toInt() && mod->getGameName().compare(gameName, Qt::CaseInsensitive) == 0)
+ if (mod->getLastNexusUpdate() > QDateTime::fromSecsSinceEpoch(update["latest_file_update"].toInt(), Qt::UTC))
+ finalMods.insert(mod);
+ }
+
+ if (addOldMods)
+ for (auto mod : s_Collection)
+ if (mod->getLastNexusUpdate() < QDateTime::currentDateTimeUtc().addDays(-30) && mod->getGameName().compare(gameName, Qt::CaseInsensitive) == 0)
+ finalMods.insert(mod);
+
+ if (markUpdated) {
+ std::set<QSharedPointer<ModInfo>> updates;
+ for (auto mod : s_Collection)
+ if (mod->getGameName().compare(gameName, Qt::CaseInsensitive) == 0 && mod->canBeUpdated())
+ updates.insert(mod);
+ std::set<QSharedPointer<ModInfo>> diff;
+ std::set_difference(updates.begin(), updates.end(), finalMods.begin(), finalMods.end(), std::inserter(diff, diff.end()));
+ for (auto skipped : diff) {
+ skipped->setLastNexusUpdate(QDateTime::currentDateTimeUtc());
+ skipped->updateNXMInfo();
+ }
+ }
+ return finalMods;
+}
int ModInfo::manualUpdateCheck(PluginContainer *pluginContainer, QObject *receiver, std::multimap<QString, int> IDs)
{
diff --git a/src/modinfo.h b/src/modinfo.h
index 348583d2..8c234225 100644
--- a/src/modinfo.h
+++ b/src/modinfo.h
@@ -195,6 +195,8 @@ public:
**/
static int checkAllForUpdate(PluginContainer *pluginContainer, QObject *receiver);
+ static std::set<QSharedPointer<ModInfo>> filteredMods(QString gameName, QVariantList updateData, bool addOldMods = false, bool markUpdated = false);
+
/**
* @brief create a new mod from the specified directory and add it to the collection
* @param dir directory to create from
diff --git a/src/modinforegular.cpp b/src/modinforegular.cpp
index 10a1317c..9532bf6d 100644
--- a/src/modinforegular.cpp
+++ b/src/modinforegular.cpp
@@ -235,10 +235,10 @@ void ModInfoRegular::nxmDescriptionAvailable(QString, int, QVariant, QVariant re
setEndorsedState(ENDORSED_FALSE);
}
m_LastNexusQuery = QDateTime::currentDateTimeUtc();
- m_NexusLastModified = QDateTime::fromSecsSinceEpoch(result["updated_timestamp"].toInt());
+ m_NexusLastModified = QDateTime::fromSecsSinceEpoch(result["updated_timestamp"].toInt(), Qt::UTC);
m_MetaInfoChanged = true;
saveMeta();
- disconnect(sender(), SIGNAL(nxmDescriptionAvailable(QString, int, QVariant, QVariant)));
+ disconnect(sender(), SIGNAL(descriptionAvailable(QString, int, QVariant, QVariant)));
emit modDetailsUpdated(true);
}
diff --git a/src/nexusinterface.cpp b/src/nexusinterface.cpp
index f1fa252a..abddbd3e 100644
--- a/src/nexusinterface.cpp
+++ b/src/nexusinterface.cpp
@@ -343,6 +343,26 @@ int NexusInterface::requestModInfo(QString gameName, int modID, QObject *receive
return -1;
}
+int NexusInterface::requestUpdateInfo(QString gameName, NexusInterface::UpdatePeriod period, QObject *receiver, QVariant userData,
+ const QString &subModule, const MOBase::IPluginGame const *game)
+{
+ if (std::max(m_RemainingDailyRequests, m_RemainingHourlyRequests) >= 200) {
+ NXMRequestInfo requestInfo(period, NXMRequestInfo::TYPE_CHECKUPDATES, userData, subModule, game);
+ m_RequestQueue.enqueue(requestInfo);
+
+ connect(this, SIGNAL(nxmUpdateInfoAvailable(QString, QVariant, QVariant, int)),
+ receiver, SLOT(nxmUpdateInfoAvailable(QString, QVariant, QVariant, int)), Qt::UniqueConnection);
+
+ connect(this, SIGNAL(nxmRequestFailed(QString, int, int, QVariant, int, QNetworkReply::NetworkError, QString)),
+ receiver, SLOT(nxmRequestFailed(QString, int, int, QVariant, int, QNetworkReply::NetworkError, QString)), Qt::UniqueConnection);
+
+ nextRequest();
+ return requestInfo.m_ID;
+ }
+ qCritical() << QString("You have fewer than 200 requests remaining (%1). Only downloads and login validation are being allowed.")
+ .arg(std::max(m_RemainingDailyRequests, m_RemainingHourlyRequests));
+ return -1;
+}
int NexusInterface::requestUpdates(const int &modID, QObject *receiver, QVariant userData,
QString gameName, const QString &subModule)
@@ -531,6 +551,21 @@ void NexusInterface::nextRequest()
case NXMRequestInfo::TYPE_MODINFO: {
url = QString("%1/games/%2/mods/%3").arg(info.m_URL).arg(info.m_GameName).arg(info.m_ModID);
} break;
+ case NXMRequestInfo::TYPE_CHECKUPDATES: {
+ QString period;
+ switch (info.m_UpdatePeriod) {
+ case UpdatePeriod::DAY:
+ period = "1d";
+ break;
+ case UpdatePeriod::WEEK:
+ period = "1w";
+ break;
+ case UpdatePeriod::MONTH:
+ period = "1m";
+ break;
+ }
+ url = QString("%1/games/%2/mods/updated?period=%3").arg(info.m_URL).arg(info.m_GameName).arg(period);
+ } break;
case NXMRequestInfo::TYPE_FILES:
case NXMRequestInfo::TYPE_GETUPDATES: {
url = QString("%1/games/%2/mods/%3/files").arg(info.m_URL).arg(info.m_GameName).arg(info.m_ModID);
@@ -624,6 +659,9 @@ void NexusInterface::requestFinished(std::list<NXMRequestInfo>::iterator iter)
case NXMRequestInfo::TYPE_MODINFO: {
emit nxmModInfoAvailable(iter->m_GameName, iter->m_ModID, iter->m_UserData, result, iter->m_ID);
} break;
+ case NXMRequestInfo::TYPE_CHECKUPDATES: {
+ emit nxmUpdateInfoAvailable(iter->m_GameName, iter->m_UserData, result, iter->m_ID);
+ } break;
case NXMRequestInfo::TYPE_FILES: {
emit nxmFilesAvailable(iter->m_GameName, iter->m_ModID, iter->m_UserData, result, iter->m_ID);
} break;
@@ -726,6 +764,7 @@ NexusInterface::NXMRequestInfo::NXMRequestInfo(int modID
, m_FileID(0)
, m_Reply(nullptr)
, m_Type(type)
+ , m_UpdatePeriod(UpdatePeriod::NONE)
, m_UserData(userData)
, m_Timeout(nullptr)
, m_Reroute(false)
@@ -750,6 +789,7 @@ NexusInterface::NXMRequestInfo::NXMRequestInfo(int modID
, m_FileID(0)
, m_Reply(nullptr)
, m_Type(type)
+ , m_UpdatePeriod(UpdatePeriod::NONE)
, m_UserData(userData)
, m_Timeout(nullptr)
, m_Reroute(false)
@@ -773,6 +813,30 @@ NexusInterface::NXMRequestInfo::NXMRequestInfo(int modID
, m_FileID(fileID)
, m_Reply(nullptr)
, m_Type(type)
+ , m_UpdatePeriod(UpdatePeriod::NONE)
+ , m_UserData(userData)
+ , m_Timeout(nullptr)
+ , m_Reroute(false)
+ , m_ID(s_NextID.fetchAndAddAcquire(1))
+ , m_URL(get_management_url(game))
+ , m_SubModule(subModule)
+ , m_NexusGameID(game->nexusGameID())
+ , m_GameName(game->gameNexusName())
+ , m_Endorse(false)
+{}
+
+NexusInterface::NXMRequestInfo::NXMRequestInfo(UpdatePeriod period
+ , NexusInterface::NXMRequestInfo::Type type
+ , QVariant userData
+ , const QString &subModule
+ , MOBase::IPluginGame const *game
+)
+ : m_ModID(0)
+ , m_ModVersion("0")
+ , m_FileID(0)
+ , m_Reply(nullptr)
+ , m_Type(type)
+ , m_UpdatePeriod(period)
, m_UserData(userData)
, m_Timeout(nullptr)
, m_Reroute(false)
diff --git a/src/nexusinterface.h b/src/nexusinterface.h
index 1c283335..06b19947 100644
--- a/src/nexusinterface.h
+++ b/src/nexusinterface.h
@@ -129,6 +129,15 @@ class NexusInterface : public QObject
public:
+ enum UpdatePeriod {
+ NONE,
+ DAY,
+ WEEK,
+ MONTH
+ };
+
+public:
+
~NexusInterface();
static NexusInterface *instance(PluginContainer *pluginContainer);
@@ -202,6 +211,15 @@ public:
int requestModInfo(QString gameName, int modID, QObject *receiver, QVariant userData, const QString &subModule,
MOBase::IPluginGame const *game);
+ int requestUpdateInfo(QString gameName, NexusInterface::UpdatePeriod period, QObject *receiver, QVariant userData,
+ const QString &subModule)
+ {
+ return requestUpdateInfo(gameName, period, receiver, userData, subModule, getGame(gameName));
+ }
+
+ int requestUpdateInfo(QString gameName, NexusInterface::UpdatePeriod period, QObject *receiver, QVariant userData,
+ const QString &subModule, MOBase::IPluginGame const *game);
+
/**
* @brief request nexus descriptions for multiple mods at once
* @param modID id of the mod the caller is interested in
@@ -378,6 +396,7 @@ signals:
void nxmDescriptionAvailable(QString gameName, int modID, QVariant userData, QVariant resultData, int requestID);
void nxmModInfoAvailable(QString gameName, int modID, QVariant userData, QVariant resultData, int requestID);
+ void nxmUpdateInfoAvailable(QString gameName, QVariant userData, QVariant resultData, int requestID);
void nxmUpdatesAvailable(QString gameName, int modID, QVariant userData, QVariant resultData, int requestID);
void nxmFilesAvailable(QString gameName, int modID, QVariant userData, QVariant resultData, int requestID);
void nxmFileInfoAvailable(QString gameName, int modID, int fileID, QVariant userData, QVariant resultData, int requestID);
@@ -415,8 +434,10 @@ private:
TYPE_FILEINFO,
TYPE_DOWNLOADURL,
TYPE_TOGGLEENDORSEMENT,
- TYPE_GETUPDATES
+ TYPE_GETUPDATES,
+ TYPE_CHECKUPDATES
} m_Type;
+ UpdatePeriod m_UpdatePeriod;
QVariant m_UserData;
QTimer *m_Timeout;
QString m_URL;
@@ -430,6 +451,7 @@ private:
NXMRequestInfo(int modID, Type type, QVariant userData, const QString &subModule, MOBase::IPluginGame const *game);
NXMRequestInfo(int modID, QString modVersion, Type type, QVariant userData, const QString &subModule, MOBase::IPluginGame const *game);
NXMRequestInfo(int modID, int fileID, Type type, QVariant userData, const QString &subModule, MOBase::IPluginGame const *game);
+ NXMRequestInfo(UpdatePeriod period, Type type, QVariant userData, const QString &subModule, MOBase::IPluginGame const *game);
private:
static QAtomicInt s_NextID;