summaryrefslogtreecommitdiff
path: root/src/downloadmanager.cpp
diff options
context:
space:
mode:
authorChris Bessent <lost.dragonist@gmail.com>2020-01-06 05:17:01 -0700
committerGitHub <noreply@github.com>2020-01-06 05:17:01 -0700
commitdfa600996c49c1b23dca884c963dc917bd9cfc0a (patch)
treec6def4277cc962822d0dcde71fa9148e050f693f /src/downloadmanager.cpp
parente69078e2399a88bda7bb9ffae7a3d57db9a4e9cf (diff)
parentd1a788dfad341b32235abc25c2ba1645f8be1ace (diff)
Merge pull request #954 from ModOrganizer2/Develop
Stage for release 2.2.2
Diffstat (limited to 'src/downloadmanager.cpp')
-rw-r--r--src/downloadmanager.cpp220
1 files changed, 142 insertions, 78 deletions
diff --git a/src/downloadmanager.cpp b/src/downloadmanager.cpp
index 648b102a..adfbc84d 100644
--- a/src/downloadmanager.cpp
+++ b/src/downloadmanager.cpp
@@ -200,8 +200,9 @@ QString DownloadManager::DownloadInfo::currentURL()
}
-DownloadManager::DownloadManager(NexusInterface *nexusInterface, QObject *parent)
- : IDownloadManager(parent), m_NexusInterface(nexusInterface), m_DirWatcher(), m_ShowHidden(false)
+DownloadManager::DownloadManager(NexusInterface *nexusInterface, QObject *parent) :
+ IDownloadManager(parent), m_NexusInterface(nexusInterface), m_DirWatcher(), m_ShowHidden(false),
+ m_ParentWidget(nullptr)
{
m_OrganizerCore = dynamic_cast<OrganizerCore*>(parent);
connect(&m_DirWatcher, SIGNAL(directoryChanged(QString)), this, SLOT(directoryChanged(QString)));
@@ -219,6 +220,10 @@ DownloadManager::~DownloadManager()
m_ActiveDownloads.clear();
}
+void DownloadManager::setParentWidget(QWidget* w)
+{
+ m_ParentWidget = w;
+}
bool DownloadManager::downloadsInProgress()
{
@@ -288,12 +293,6 @@ void DownloadManager::setOutputDirectory(const QString &outputDirectory)
}
-void DownloadManager::setPreferredServers(const std::map<QString, int> &preferredServers)
-{
- m_PreferredServers = preferredServers;
-}
-
-
void DownloadManager::setSupportedExtensions(const QStringList &extensions)
{
m_SupportedExtensions = extensions;
@@ -352,7 +351,7 @@ void DownloadManager::refreshList()
}
}
if (orphans.size() > 0) {
- qDebug("%d orphaned meta files will be deleted", orphans.size());
+ log::debug("{} orphaned meta files will be deleted", orphans.size());
shellDelete(orphans, true);
}
@@ -378,9 +377,6 @@ void DownloadManager::refreshList()
}
}
- //if (m_ActiveDownloads.size() != downloadsBefore) {
- qDebug("Downloads after refresh: %d", m_ActiveDownloads.size());
- //}
emit update(-1);
//let watcher trigger refreshes again
@@ -401,7 +397,7 @@ bool DownloadManager::addDownload(const QStringList &URLs, QString gameName,
}
QUrl preferredUrl = QUrl::fromEncoded(URLs.first().toLocal8Bit());
- qDebug("selected download url: %s", qUtf8Printable(preferredUrl.toString()));
+ log::debug("selected download url: {}", preferredUrl.toString());
QNetworkRequest request(preferredUrl);
request.setHeader(QNetworkRequest::UserAgentHeader, m_NexusInterface->getAccessManager()->userAgent());
return addDownload(m_NexusInterface->getAccessManager()->get(request), URLs, fileName, gameName, modID, fileID, fileInfo);
@@ -510,7 +506,7 @@ void DownloadManager::startDownload(QNetworkReply *reply, DownloadInfo *newDownl
if (QFile::exists(m_OutputDirectory + "/" + newDownload->m_FileName)) {
setState(newDownload, STATE_PAUSING);
QCoreApplication::processEvents();
- if (QMessageBox::question(nullptr, tr("Download again?"), tr("A file with the same name \"%1\" has already been downloaded. "
+ if (QMessageBox::question(m_ParentWidget, tr("Download again?"), tr("A file with the same name \"%1\" has already been downloaded. "
"Do you want to download it again? The new file will receive a different name.").arg(newDownload->m_FileName),
QMessageBox::Yes | QMessageBox::No) == QMessageBox::No) {
if (reply->isFinished())
@@ -522,7 +518,7 @@ void DownloadManager::startDownload(QNetworkReply *reply, DownloadInfo *newDownl
newDownload->setName(getDownloadFileName(newDownload->m_FileName, true), true);
endDisableDirWatcher();
if (newDownload->m_State == STATE_PAUSED)
- resumeDownload(indexByName(newDownload->m_FileName));
+ resumeDownload(indexByInfo(newDownload));
else
setState(newDownload, STATE_DOWNLOADING);
}
@@ -536,7 +532,7 @@ void DownloadManager::startDownload(QNetworkReply *reply, DownloadInfo *newDownl
newDownload->m_State != STATE_READY &&
newDownload->m_State != STATE_FETCHINGMODINFO &&
reply->isFinished()) {
- downloadFinished(indexByName(newDownload->m_FileName));
+ downloadFinished(indexByInfo(newDownload));
return;
}
} else
@@ -562,24 +558,25 @@ void DownloadManager::addNXMDownload(const QString &url)
break;
}
}
- qDebug("add nxm download: %s", qUtf8Printable(url));
+ log::debug("add nxm download: {}", url);
if (foundGame == nullptr) {
- qDebug("download requested for wrong game (game: %s, url: %s)", qUtf8Printable(m_ManagedGame->gameShortName()), qUtf8Printable(nxmInfo.game()));
- QMessageBox::information(nullptr, tr("Wrong Game"), tr("The download link is for a mod for \"%1\" but this instance of MO "
+ log::debug("download requested for wrong game (game: {}, url: {})", m_ManagedGame->gameShortName(), nxmInfo.game());
+ QMessageBox::information(m_ParentWidget, tr("Wrong Game"), tr("The download link is for a mod for \"%1\" but this instance of MO "
"has been set up for \"%2\".").arg(nxmInfo.game()).arg(m_ManagedGame->gameShortName()), QMessageBox::Ok);
return;
}
for (auto tuple : m_PendingDownloads) {
if (std::get<0>(tuple).compare(foundGame->gameShortName(), Qt::CaseInsensitive) == 0, std::get<1>(tuple) == nxmInfo.modId() && std::get<2>(tuple) == nxmInfo.fileId()) {
- QString debugStr("download requested is already queued (mod: %1, file: %2)");
- QString infoStr(tr("There is already a download queued for this file.\n\nMod %1\nFile %2"));
+ const auto infoStr =
+ tr("There is already a download queued for this file.\n\nMod %1\nFile %2")
+ .arg(nxmInfo.modId()).arg(nxmInfo.fileId());
- debugStr = debugStr.arg(nxmInfo.modId()).arg(nxmInfo.fileId());
- infoStr = infoStr.arg(nxmInfo.modId()).arg(nxmInfo.fileId());
+ log::debug(
+ "download requested is already queued (mod: {}, file: {})",
+ nxmInfo.modId(), nxmInfo.fileId());
- qDebug(qUtf8Printable(debugStr));
- QMessageBox::information(nullptr, tr("Already Queued"), infoStr, QMessageBox::Ok);
+ QMessageBox::information(m_ParentWidget, tr("Already Queued"), infoStr, QMessageBox::Ok);
return;
}
}
@@ -622,8 +619,8 @@ void DownloadManager::addNXMDownload(const QString &url)
infoStr = infoStr.arg(QStringLiteral("<blank>"));
}
- qDebug(qUtf8Printable(debugStr));
- QMessageBox::information(nullptr, tr("Already Started"), infoStr, QMessageBox::Ok);
+ log::debug("{}", debugStr);
+ QMessageBox::information(m_ParentWidget, tr("Already Started"), infoStr, QMessageBox::Ok);
return;
}
}
@@ -660,7 +657,7 @@ void DownloadManager::removeFile(int index, bool deleteFile)
if ((download->m_State == STATE_STARTED) ||
(download->m_State == STATE_DOWNLOADING)) {
// shouldn't have been possible
- qCritical("tried to remove active download");
+ log::error("tried to remove active download");
endDisableDirWatcher();
return;
}
@@ -717,7 +714,7 @@ void DownloadManager::refreshAlphabeticalTranslation()
m_AlphabeticalTranslation.push_back(pos);
}
- qSort(m_AlphabeticalTranslation.begin(), m_AlphabeticalTranslation.end(), LessThanWrapper(this));
+ std::sort(m_AlphabeticalTranslation.begin(), m_AlphabeticalTranslation.end(), LessThanWrapper(this));
}
@@ -798,7 +795,7 @@ void DownloadManager::removeDownload(int index, bool deleteFile)
emit update(-1);
endDisableDirWatcher();
} catch (const std::exception &e) {
- qCritical("failed to remove download: %s", e.what());
+ log::error("failed to remove download: {}", e.what());
}
refreshList();
}
@@ -883,7 +880,7 @@ void DownloadManager::resumeDownloadInt(int index)
if (info->m_State == STATE_ERROR) {
info->m_CurrentUrl = (info->m_CurrentUrl + 1) % info->m_Urls.count();
}
- qDebug("request resume from url %s", qUtf8Printable(info->currentURL()));
+ log::debug("request resume from url {}", info->currentURL());
QNetworkRequest request(QUrl::fromEncoded(info->currentURL().toLocal8Bit()));
request.setHeader(QNetworkRequest::UserAgentHeader, m_NexusInterface->getAccessManager()->userAgent());
if (info->m_State != STATE_ERROR) {
@@ -896,7 +893,7 @@ void DownloadManager::resumeDownloadInt(int index)
std::get<2>(info->m_SpeedDiff) = 0;
std::get<3>(info->m_SpeedDiff) = 0;
std::get<4>(info->m_SpeedDiff) = 0;
- qDebug("resume at %lld bytes", info->m_ResumePos);
+ log::debug("resume at {} bytes", info->m_ResumePos);
startDownload(m_NexusInterface->getAccessManager()->get(request), info, true);
}
emit update(index);
@@ -924,7 +921,7 @@ void DownloadManager::queryInfo(int index)
DownloadInfo *info = m_ActiveDownloads[index];
if (info->m_FileInfo->repository != "Nexus") {
- qWarning("re-querying file info is currently only possible with Nexus");
+ log::warn("re-querying file info is currently only possible with Nexus");
return;
}
@@ -976,7 +973,7 @@ void DownloadManager::queryInfoMd5(int index)
DownloadInfo *info = m_ActiveDownloads[index];
if (info->m_FileInfo->repository != "Nexus") {
- qWarning("re-querying file info is currently only possible with Nexus");
+ log::warn("re-querying file info is currently only possible with Nexus");
return;
}
@@ -993,16 +990,39 @@ void DownloadManager::queryInfoMd5(int index)
downloadFile.setFileName(m_OrganizerCore->downloadsPath() + "\\" + info->m_FileName);
}
if (!downloadFile.exists()) {
- qDebug("Can't find download file %s", info->m_FileName);
+ log::error("Can't find download file '{}'", info->m_FileName);
return;
}
if (!downloadFile.open(QIODevice::ReadOnly)) {
- qDebug("Can't open download file %s", info->m_FileName);
+ log::error("Can't open download file '{}'", info->m_FileName);
return;
}
- info->m_Hash = QCryptographicHash::hash(downloadFile.readAll(), QCryptographicHash::Md5);
+
+ QCryptographicHash hash(QCryptographicHash::Md5);
+ const qint64 progressStep = 10 * 1024 * 1024;
+ QProgressDialog progress(tr("Hashing download file '%1'").arg(info->m_FileName),
+ tr("Cancel"),
+ 0,
+ downloadFile.size() / progressStep);
+ progress.setWindowModality(Qt::WindowModal);
+ progress.setMinimumDuration(1000);
+
+ for (qint64 i = 0; i < downloadFile.size(); i += progressStep) {
+ progress.setValue(progress.value()+1);
+ if (progress.wasCanceled()) {
+ break;
+ }
+ hash.addData(downloadFile.read(progressStep));
+ }
+ if (progress.wasCanceled()) {
+ downloadFile.close();
+ return;
+ }
+
+ progress.close();
downloadFile.close();
+ info->m_Hash = hash.result();
info->m_ReQueried = true;
setState(info, STATE_FETCHINGMODINFO_MD5);
}
@@ -1016,7 +1036,7 @@ void DownloadManager::visitOnNexus(int index)
DownloadInfo *info = m_ActiveDownloads[index];
if (info->m_FileInfo->repository != "Nexus") {
- qWarning("Visiting mod page is currently only possible with Nexus");
+ log::warn("Visiting mod page is currently only possible with Nexus");
return;
}
@@ -1044,11 +1064,11 @@ void DownloadManager::openFile(int index)
QDir path = QDir(m_OutputDirectory);
if (path.exists(getFileName(index))) {
- shell::OpenFile(getFilePath(index));
+ shell::Open(getFilePath(index));
return;
}
- shell::ExploreFile(m_OutputDirectory);
+ shell::Explore(m_OutputDirectory);
return;
}
@@ -1062,18 +1082,18 @@ void DownloadManager::openInDownloadsFolder(int index)
const auto path = getFilePath(index);
if (QFile::exists(path)) {
- shell::ExploreFile(path);
+ shell::Explore(path);
return;
}
else {
const auto unfinished = path + ".unfinished";
if (QFile::exists(unfinished)) {
- shell::ExploreFile(unfinished);
+ shell::Explore(unfinished);
return;
}
}
- shell::ExploreFile(m_OutputDirectory);
+ shell::Explore(m_OutputDirectory);
}
@@ -1155,7 +1175,12 @@ QDateTime DownloadManager::getFileTime(int index) const
DownloadInfo *info = m_ActiveDownloads.at(index);
if (!info->m_Created.isValid()) {
- info->m_Created = QFileInfo(info->m_Output).created();
+ QFileInfo fileInfo(info->m_Output);
+ info->m_Created = fileInfo.birthTime();
+ if (!info->m_Created.isValid())
+ info->m_Created = fileInfo.metadataChangeTime();
+ if (!info->m_Created.isValid())
+ info->m_Created = fileInfo.lastModified();
}
return info->m_Created;
@@ -1214,6 +1239,19 @@ int DownloadManager::getModID(int index) const
return m_ActiveDownloads.at(index)->m_FileInfo->modID;
}
+QString DownloadManager::getDisplayGameName(int index) const
+{
+ if ((index < 0) || (index >= m_ActiveDownloads.size())) {
+ throw MyException(tr("mod id: invalid download index %1").arg(index));
+ }
+ QString gameName = m_ActiveDownloads.at(index)->m_FileInfo->gameName;
+ IPluginGame* gamePlugin = m_OrganizerCore->getGame(gameName);
+ if (gamePlugin) {
+ gameName = gamePlugin->gameName();
+ }
+ return gameName;
+}
+
QString DownloadManager::getGameName(int index) const
{
if ((index < 0) || (index >= m_ActiveDownloads.size())) {
@@ -1384,7 +1422,7 @@ void DownloadManager::setState(DownloadManager::DownloadInfo *info, DownloadMana
m_RequestIDs.insert(m_NexusInterface->requestFiles(info->m_FileInfo->gameName, info->m_FileInfo->modID, this, info->m_DownloadID, QString()));
} break;
case STATE_FETCHINGMODINFO_MD5: {
- qDebug(qUtf8Printable(QString("Searching %1 for MD5 of %2").arg(info->m_GamesToQuery[0]).arg(QString(info->m_Hash.toHex()))));
+ log::debug("Searching {} for MD5 of {}", info->m_GamesToQuery[0], QString(info->m_Hash.toHex()));
m_RequestIDs.insert(m_NexusInterface->requestInfoFromMd5(info->m_GamesToQuery[0], info->m_Hash, this, info->m_DownloadID, QString()));
} break;
case STATE_READY: {
@@ -1444,22 +1482,11 @@ void DownloadManager::downloadProgress(qint64 bytesReceived, qint64 bytesTotal)
std::get<4>(info->m_SpeedDiff) = ((calc*0.5) + (std::get<4>(info->m_SpeedDiff)*1.5)) / 2;
// calculate the download speed
- double speed = (std::get<4>(info->m_SpeedDiff) * 1000.0) / (5 * 1000);
+ const double speed = (std::get<4>(info->m_SpeedDiff) * 1000.0) / (5 * 1000);
- QString unit;
- if (speed < 1000) {
- unit = "B/s";
- }
- else if (speed < 1000*1024) {
- speed /= 1024;
- unit = "KB/s";
- }
- else {
- speed /= 1024 * 1024;
- unit = "MB/s";
- }
-
- info->m_Progress.second = QString::fromLatin1("%1% - %2 %3").arg(info->m_Progress.first).arg(QString::number(speed, 'f', 1)).arg(unit);
+ info->m_Progress.second = QString::fromLatin1("%1% - %2")
+ .arg(info->m_Progress.first)
+ .arg(MOBase::localizedByteSpeed(speed));
TaskProgressManager::instance().updateProgress(info->m_TaskProgressId, bytesReceived, bytesTotal);
emit update(index);
@@ -1597,6 +1624,8 @@ void DownloadManager::nxmFilesAvailable(QString, int, QVariant userData, QVarian
emit showMessage(tr("No matching file found on Nexus! Maybe this file is no longer available or it was renamed?"));
} else {
SelectionDialog selection(tr("No file on Nexus matches the selected file by name. Please manually choose the correct one."));
+ std::sort(files.begin(), files.end(), [](const QVariant& lhs, const QVariant& rhs)
+ {return lhs.toMap()["uploaded_timestamp"].toInt() > rhs.toMap()["uploaded_timestamp"].toInt();});
for (QVariant file : files) {
QVariantMap fileInfo = file.toMap();
if (fileInfo["category_id"].toInt() != 6)
@@ -1614,8 +1643,9 @@ void DownloadManager::nxmFilesAvailable(QString, int, QVariant userData, QVarian
}
} else {
if (info->m_FileInfo->fileID == 0) {
- qWarning("could not determine file id for %s (state %d)",
- qUtf8Printable(info->m_FileName), info->m_State);
+ log::warn(
+ "could not determine file id for {} (state {})",
+ info->m_FileName, info->m_State);
}
}
@@ -1663,23 +1693,38 @@ void DownloadManager::nxmFileInfoAvailable(QString gameName, int modID, int file
m_RequestIDs.insert(m_NexusInterface->requestDownloadURL(info->gameName, info->modID, info->fileID, this, qVariantFromValue(test), QString()));
}
-static int evaluateFileInfoMap(const QVariantMap &map, const std::map<QString, int> &preferredServers)
+static int evaluateFileInfoMap(
+ const QVariantMap &map,
+ const ServerList::container& preferredServers)
{
- int result = 0;
+ int preference = 0;
+ bool found = false;
+ const auto name = map["short_name"].toString();
- auto preference = preferredServers.find(map["short_name"].toString());
+ for (const auto& server : preferredServers) {
+ if (server.name() == name) {
+ preference = server.preferred();
+ found = true;
+ break;
+ }
+ }
- if (preference != preferredServers.end()) {
- result += 100 + preference->second * 20;
+ if (!found) {
+ return 0;
}
- return result;
+ return 100 + preference * 20;
}
// sort function to sort by best download server
-bool DownloadManager::ServerByPreference(const std::map<QString, int> &preferredServers, const QVariant &LHS, const QVariant &RHS)
+//
+bool ServerByPreference(
+ const ServerList::container& preferredServers,
+ const QVariant &LHS, const QVariant &RHS)
{
- return evaluateFileInfoMap(LHS.toMap(), preferredServers) > evaluateFileInfoMap(RHS.toMap(), preferredServers);
+ const auto a = evaluateFileInfoMap(LHS.toMap(), preferredServers);
+ const auto b = evaluateFileInfoMap(RHS.toMap(), preferredServers);
+ return (a > b);
}
int DownloadManager::startDownloadURLs(const QStringList &urls)
@@ -1711,6 +1756,16 @@ int DownloadManager::indexByName(const QString &fileName) const
return -1;
}
+int DownloadManager::indexByInfo(const DownloadInfo* info) const
+{
+ for (int i = 0; i < m_ActiveDownloads.size(); ++i) {
+ if (m_ActiveDownloads[i] == info) {
+ return i;
+ }
+ }
+ return -1;
+}
+
void DownloadManager::nxmDownloadURLsAvailable(QString gameName, int modID, int fileID, QVariant userData, QVariant resultData, int requestID)
{
std::set<int>::iterator idIter = m_RequestIDs.find(requestID);
@@ -1728,7 +1783,12 @@ void DownloadManager::nxmDownloadURLsAvailable(QString gameName, int modID, int
return;
}
- std::sort(resultList.begin(), resultList.end(), boost::bind(&DownloadManager::ServerByPreference, m_PreferredServers, _1, _2));
+ const auto servers = m_OrganizerCore->settings().network().servers();
+
+ std::sort(
+ resultList.begin(),
+ resultList.end(),
+ boost::bind(&ServerByPreference, servers.getPreferred(), _1, _2));
info->userData["downloadMap"] = resultList;
@@ -1779,7 +1839,7 @@ void DownloadManager::nxmFileInfoFromMd5Available(QString gameName, QVariant use
if (chosenIdx < 0) {
chosenIdx = i; //intentional to not break in order to check other results
} else {
- qDebug("Multiple active files found during MD5 search. Defaulting to time stamps...");
+ log::debug("Multiple active files found during MD5 search. Defaulting to time stamps...");
chosenIdx = -1;
break;
}
@@ -1999,7 +2059,7 @@ void DownloadManager::downloadFinished(int index)
resumeDownloadInt(index);
}
} else {
- qWarning("no download index %d", index);
+ log::warn("no download index {}", index);
}
}
@@ -2008,9 +2068,9 @@ void DownloadManager::downloadError(QNetworkReply::NetworkError error)
{
if (error != QNetworkReply::OperationCanceledError) {
QNetworkReply *reply = qobject_cast<QNetworkReply*>(sender());
- qWarning("%s (%d)", reply != nullptr ? qUtf8Printable(reply->errorString())
- : "Download error occured",
- error);
+ log::warn("{} ({})",
+ reply != nullptr ? reply->errorString() : "Download error occured",
+ error);
}
}
@@ -2033,7 +2093,7 @@ void DownloadManager::metaDataChanged()
}
}
} else {
- qWarning("meta data event for unknown download");
+ log::warn("meta data event for unknown download");
}
}
@@ -2068,7 +2128,11 @@ void DownloadManager::writeData(DownloadInfo *info)
if (ret < info->m_Reply->size()) {
QString fileName = info->m_FileName; // m_FileName may be destroyed after setState
setState(info, DownloadState::STATE_CANCELED);
- qCritical(QString("Unable to write download \"%2\" to drive (return %1)").arg(ret).arg(info->m_FileName).toLocal8Bit());
+
+ log::error(
+ "Unable to write download \"{}\" to drive (return {})",
+ info->m_FileName, ret);
+
reportError(tr("Unable to write download to drive (return %1).\n"
"Check the drive's available storage.\n\n"
"Canceling download \"%2\"...").arg(ret).arg(fileName));