summaryrefslogtreecommitdiff
path: root/src/downloadmanager.cpp
diff options
context:
space:
mode:
authorTannin <devnull@localhost>2014-04-05 15:36:42 +0200
committerTannin <devnull@localhost>2014-04-05 15:36:42 +0200
commitcabed9b268c9f095d5e3b98a6797b0bcdcd38b1f (patch)
tree454b03b0c5664e90fe586e7b39603e34a526d35b /src/downloadmanager.cpp
parent98e5e57a845541acddf519a81957261f58008cb9 (diff)
parentc017f4a0d50b67a44e276bd5ae8929ed3990c62c (diff)
Merge with branch1.1
Diffstat (limited to 'src/downloadmanager.cpp')
-rw-r--r--src/downloadmanager.cpp199
1 files changed, 165 insertions, 34 deletions
diff --git a/src/downloadmanager.cpp b/src/downloadmanager.cpp
index 676cd7ef..8c127511 100644
--- a/src/downloadmanager.cpp
+++ b/src/downloadmanager.cpp
@@ -22,21 +22,22 @@ along with Mod Organizer. If not, see <http://www.gnu.org/licenses/>.
#include "nxmurl.h"
#include <gameinfo.h>
#include <nxmurl.h>
+#include <taskprogressmanager.h>
#include "utility.h"
#include "json.h"
#include "selectiondialog.h"
+#include <utility.h>
#include <QTimer>
#include <QFileInfo>
#include <QRegExp>
#include <QDirIterator>
#include <QInputDialog>
-#include <boost/bind.hpp>
-#include <regex>
#include <QMessageBox>
#include <QCoreApplication>
+#include <boost/bind.hpp>
+#include <regex>
-using QtJson::Json;
using namespace MOBase;
@@ -61,18 +62,21 @@ DownloadManager::DownloadInfo *DownloadManager::DownloadInfo::createNew(const Mo
info->m_CurrentUrl = 0;
info->m_Tries = AUTOMATIC_RETRIES;
info->m_State = STATE_STARTED;
+ info->m_TaskProgressId = TaskProgressManager::instance().getId();
return info;
}
-DownloadManager::DownloadInfo *DownloadManager::DownloadInfo::createFromMeta(const QString &filePath)
+DownloadManager::DownloadInfo *DownloadManager::DownloadInfo::createFromMeta(const QString &filePath, bool showHidden)
{
DownloadInfo *info = new DownloadInfo;
QString metaFileName = filePath + ".meta";
QSettings metaFile(metaFileName, QSettings::IniFormat);
- if (metaFile.value("removed", false).toBool()) {
+ if (!showHidden && metaFile.value("removed", false).toBool()) {
return NULL;
+ } else {
+ info->m_Hidden = metaFile.value("removed", false).toBool();
}
QString fileName = QFileInfo(filePath).fileName();
@@ -101,7 +105,7 @@ DownloadManager::DownloadInfo *DownloadManager::DownloadInfo::createFromMeta(con
info->m_CurrentUrl = 0;
info->m_Urls = metaFile.value("url", "").toString().split(";");
info->m_Tries = 0;
- info->m_FileInfo = new ModRepositoryFileInfo();
+ info->m_TaskProgressId = TaskProgressManager::instance().getId();
info->m_FileInfo->name = metaFile.value("name", "").toString();
info->m_FileInfo->modName = metaFile.value("modName", "").toString();
info->m_FileInfo->modID = metaFile.value("modID", 0).toInt();
@@ -151,7 +155,8 @@ QString DownloadManager::DownloadInfo::currentURL()
DownloadManager::DownloadManager(NexusInterface *nexusInterface, QObject *parent)
- : IDownloadManager(parent), m_NexusInterface(nexusInterface), m_DirWatcher()
+ : IDownloadManager(parent), m_NexusInterface(nexusInterface), m_DirWatcher(), m_ShowHidden(false),
+ m_DateExpression("/Date\\((\\d+)\\)/")
{
connect(&m_DirWatcher, SIGNAL(directoryChanged(QString)), this, SLOT(directoryChanged(QString)));
}
@@ -162,6 +167,7 @@ DownloadManager::~DownloadManager()
for (QVector<DownloadInfo*>::iterator iter = m_ActiveDownloads.begin(); iter != m_ActiveDownloads.end(); ++iter) {
delete *iter;
}
+ m_ActiveDownloads.clear();
}
@@ -187,23 +193,21 @@ void DownloadManager::pauseAll()
::Sleep(100);
bool done = false;
-
- int tries = 20;
-
+ QTime startTime = QTime::currentTime();
// further loops: busy waiting for all downloads to complete. This could be neater...
- while (!done && (tries > 0)) {
+ while (!done && (startTime.secsTo(QTime::currentTime()) < 5)) {
QCoreApplication::processEvents();
done = true;
foreach (DownloadInfo *info, m_ActiveDownloads) {
if ((info->m_State < STATE_CANCELED) ||
- (info->m_State != STATE_FETCHINGFILEINFO) || (info->m_State != STATE_FETCHINGMODINFO)) {
+ (info->m_State == STATE_FETCHINGFILEINFO) ||
+ (info->m_State == STATE_FETCHINGMODINFO)) {
done = false;
break;
}
}
if (!done) {
::Sleep(100);
- --tries;
}
}
}
@@ -216,8 +220,8 @@ void DownloadManager::setOutputDirectory(const QString &outputDirectory)
m_DirWatcher.removePaths(directories);
}
m_OutputDirectory = QDir::fromNativeSeparators(outputDirectory);
- m_DirWatcher.addPath(m_OutputDirectory);
refreshList();
+ m_DirWatcher.addPath(m_OutputDirectory);
}
@@ -233,11 +237,19 @@ void DownloadManager::setSupportedExtensions(const QStringList &extensions)
refreshList();
}
+void DownloadManager::setShowHidden(bool showHidden)
+{
+ m_ShowHidden = showHidden;
+ refreshList();
+}
+
void DownloadManager::refreshList()
{
+ int downloadsBefore = m_ActiveDownloads.size();
+
// remove finished downloads
for (QVector<DownloadInfo*>::iterator Iter = m_ActiveDownloads.begin(); Iter != m_ActiveDownloads.end();) {
- if (((*Iter)->m_State == STATE_READY) || ((*Iter)->m_State == STATE_INSTALLED)) {
+ if (((*Iter)->m_State == STATE_READY) || ((*Iter)->m_State == STATE_INSTALLED) || ((*Iter)->m_State == STATE_UNINSTALLED)) {
delete *Iter;
Iter = m_ActiveDownloads.erase(Iter);
} else {
@@ -251,9 +263,22 @@ void DownloadManager::refreshList()
}
nameFilters.append(QString("*").append(UNFINISHED));
-
QDir dir(QDir::fromNativeSeparators(m_OutputDirectory));
+ // find orphaned meta files and delete them (sounds cruel but it's better for everyone)
+ QStringList orphans;
+ QStringList metaFiles = dir.entryList(QStringList() << "*.meta");
+ foreach (const QString &metaFile, metaFiles) {
+ QString baseFile = metaFile.left(metaFile.length() - 5);
+ if (!QFile::exists(dir.absoluteFilePath(baseFile))) {
+ orphans.append(dir.absoluteFilePath(metaFile));
+ }
+ }
+ if (orphans.size() > 0) {
+ qDebug("%d orphaned meta files will be deleted", orphans.size());
+ shellDelete(orphans, true);
+ }
+
// add existing downloads to list
foreach (QString file, dir.entryList(nameFilters, QDir::Files, QDir::Time)) {
bool Exists = false;
@@ -265,17 +290,21 @@ void DownloadManager::refreshList()
}
}
if (Exists) {
+ qDebug("%s exists", qPrintable(file));
continue;
}
QString fileName = QDir::fromNativeSeparators(m_OutputDirectory) + "/" + file;
- DownloadInfo *info = DownloadInfo::createFromMeta(fileName);
+ DownloadInfo *info = DownloadInfo::createFromMeta(fileName, m_ShowHidden);
if (info != NULL) {
m_ActiveDownloads.push_front(info);
}
}
- qDebug("downloads after refresh: %d", m_ActiveDownloads.size());
+
+ if (m_ActiveDownloads.size() != downloadsBefore) {
+ qDebug("downloads after refresh: %d", m_ActiveDownloads.size());
+ }
emit update(-1);
}
@@ -324,6 +353,7 @@ bool DownloadManager::addDownload(QNetworkReply *reply, const QStringList &URLs,
(QMessageBox::question(NULL, tr("Download again?"), tr("A file with the same name has already been downloaded. "
"Do you want to download it again? The new file will receive a different name."),
QMessageBox::Yes | QMessageBox::No) == QMessageBox::No)) {
+ removePending(modID, fileID);
delete newDownload;
return false;
}
@@ -332,11 +362,24 @@ bool DownloadManager::addDownload(QNetworkReply *reply, const QStringList &URLs,
startDownload(reply, newDownload, false);
- emit update(-1);
+// emit update(-1);
return true;
}
+void DownloadManager::removePending(int modID, int fileID)
+{
+ emit aboutToUpdate();
+ for (auto iter = m_PendingDownloads.begin(); iter != m_PendingDownloads.end(); ++iter) {
+ if ((iter->first == modID) && (iter->second == fileID)) {
+ m_PendingDownloads.erase(iter);
+ break;
+ }
+ }
+ emit update(-1);
+}
+
+
void DownloadManager::startDownload(QNetworkReply *reply, DownloadInfo *newDownload, bool resume)
{
newDownload->m_Reply = reply;
@@ -366,11 +409,14 @@ void DownloadManager::startDownload(QNetworkReply *reply, DownloadInfo *newDownl
if (!resume) {
newDownload->m_PreResumeSize = newDownload->m_Output.size();
+ removePending(newDownload->m_ModID, newDownload->m_FileID);
+
emit aboutToUpdate();
m_ActiveDownloads.append(newDownload);
emit update(-1);
+ emit downloadAdded();
}
}
@@ -378,7 +424,23 @@ void DownloadManager::startDownload(QNetworkReply *reply, DownloadInfo *newDownl
void DownloadManager::addNXMDownload(const QString &url)
{
NXMUrl nxmInfo(url);
- m_RequestIDs.insert(m_NexusInterface->requestFileInfo(nxmInfo.getModId(), nxmInfo.getFileId(), this, QVariant()));
+
+ QString managedGame = ToQString(MOShared::GameInfo::instance().getGameShortName());
+ qDebug("add nxm download: %s", qPrintable(url));
+ if (nxmInfo.game().compare(managedGame, Qt::CaseInsensitive) != 0) {
+ qDebug("download requested for wrong game (game: %s, url: %s)", qPrintable(managedGame), qPrintable(nxmInfo.game()));
+ QMessageBox::information(NULL, 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(managedGame), QMessageBox::Ok);
+ return;
+ }
+
+ emit aboutToUpdate();
+
+ m_PendingDownloads.append(std::make_pair(nxmInfo.modId(), nxmInfo.fileId()));
+
+ emit update(-1);
+ emit downloadAdded();
+ m_RequestIDs.insert(m_NexusInterface->requestFileInfo(nxmInfo.modId(), nxmInfo.fileId(), this, nxmInfo.fileId()));
}
@@ -449,6 +511,22 @@ void DownloadManager::refreshAlphabeticalTranslation()
}
+void DownloadManager::restoreDownload(int index)
+{
+ if ((index < 0) || (index >= m_ActiveDownloads.size())) {
+ throw MyException(tr("invalid index"));
+ }
+
+ DownloadInfo *download = m_ActiveDownloads.at(index);
+ download->m_Hidden = false;
+
+ QString filePath = m_OutputDirectory + "/" + download->m_FileName;
+
+ QSettings metaSettings(filePath.append(".meta"), QSettings::IniFormat);
+ metaSettings.setValue("removed", false);
+}
+
+
void DownloadManager::removeDownload(int index, bool deleteFile)
{
try {
@@ -504,9 +582,13 @@ void DownloadManager::pauseDownload(int index)
return;
}
- if (m_ActiveDownloads.at(index)->m_State == STATE_DOWNLOADING) {
- setState(m_ActiveDownloads.at(index), STATE_PAUSING);
- qDebug("pausing %d - %s", index, m_ActiveDownloads[index]->m_FileName.toUtf8().constData());
+ DownloadInfo *info = m_ActiveDownloads.at(index);
+
+ if (info->m_State == STATE_DOWNLOADING) {
+ setState(info, STATE_PAUSING);
+ qDebug("pausing %d - %s", index, info->m_FileName.toUtf8().constData());
+ } else if ((info->m_State == STATE_FETCHINGMODINFO) || (info->m_State == STATE_FETCHINGFILEINFO)) {
+ setState(info, STATE_READY);
}
}
@@ -605,6 +687,19 @@ int DownloadManager::numTotalDownloads() const
return m_ActiveDownloads.size();
}
+int DownloadManager::numPendingDownloads() const
+{
+ return m_PendingDownloads.size();
+}
+
+std::pair<int, int> DownloadManager::getPendingDownload(int index)
+{
+ if ((index < 0) || (index >= m_PendingDownloads.size())) {
+ throw MyException(tr("invalid index"));
+ }
+
+ return m_PendingDownloads.at(index);
+}
QString DownloadManager::getFilePath(int index) const
{
@@ -692,6 +787,14 @@ int DownloadManager::getModID(int index) const
return m_ActiveDownloads.at(index)->m_FileInfo->modID;
}
+bool DownloadManager::isHidden(int index) const
+{
+ if ((index < 0) || (index >= m_ActiveDownloads.size())) {
+ throw MyException(tr("invalid index"));
+ }
+ return m_ActiveDownloads.at(index)->m_Hidden;
+}
+
const ModRepositoryFileInfo *DownloadManager::getFileInfo(int index) const
{
@@ -825,11 +928,11 @@ void DownloadManager::downloadProgress(qint64 bytesReceived, qint64 bytesTotal)
setState(info, STATE_PAUSED);
} else {
if (bytesTotal > info->m_TotalSize) {
- qDebug("file size %s: %lld", qPrintable(info->m_FileName), bytesTotal);
info->m_TotalSize = bytesTotal;
}
int oldProgress = info->m_Progress;
info->m_Progress = ((info->m_ResumePos + bytesReceived) * 100) / (info->m_ResumePos + bytesTotal);
+ TaskProgressManager::instance().updateProgress(info->m_TaskProgressId, bytesReceived, bytesTotal);
if (oldProgress != info->m_Progress) {
emit update(index);
}
@@ -858,6 +961,7 @@ void DownloadManager::createMetaFile(DownloadInfo *info)
metaFile.setValue("modName", info->m_FileInfo->modName);
metaFile.setValue("version", info->m_FileInfo->version.canonicalString());
metaFile.setValue("newestVersion", info->m_FileInfo->newestVersion.canonicalString());
+ metaFile.setValue("fileTime", info->m_FileInfo->m_FileTime);
metaFile.setValue("fileCategory", info->m_FileInfo->fileCategory);
metaFile.setValue("category", info->m_FileInfo->categoryID);
metaFile.setValue("repository", info->m_FileInfo->repository);
@@ -866,6 +970,7 @@ void DownloadManager::createMetaFile(DownloadInfo *info)
metaFile.setValue("uninstalled", info->m_State == DownloadManager::STATE_UNINSTALLED);
metaFile.setValue("paused", (info->m_State == DownloadManager::STATE_PAUSED) ||
(info->m_State == DownloadManager::STATE_ERROR));
+ metaFile.setValue("removed", info->m_Hidden);
// slightly hackish...
for (int i = 0; i < m_ActiveDownloads.size(); ++i) {
@@ -889,11 +994,9 @@ void DownloadManager::nxmDescriptionAvailable(int, QVariant userData, QVariant r
DownloadInfo *info = downloadInfoByID(userData.toInt());
if (info == NULL) return;
-
info->m_FileInfo->categoryID = result["category_id"].toInt();
info->m_FileInfo->modName = result["name"].toString().trimmed();
info->m_FileInfo->newestVersion.parse(result["version"].toString());
-
if (info->m_FileInfo->fileID != 0) {
setState(info, STATE_READY);
} else {
@@ -902,6 +1005,17 @@ void DownloadManager::nxmDescriptionAvailable(int, QVariant userData, QVariant r
}
+QDateTime DownloadManager::matchDate(const QString &timeString)
+{
+ if (m_DateExpression.exactMatch(timeString)) {
+ return QDateTime::fromMSecsSinceEpoch(m_DateExpression.cap(1).toLongLong());
+ } else {
+ qWarning("date not matched: %s", qPrintable(timeString));
+ return QDateTime::currentDateTime();
+ }
+}
+
+
EFileCategory convertFileCategory(int id)
{
// TODO: need to handle file categories in the mod page plugin
@@ -947,7 +1061,11 @@ void DownloadManager::nxmFilesAvailable(int, QVariant userData, QVariant resultD
(fileNameVariant == info->m_FileName) || (fileNameVariant == alternativeLocalName)) {
info->m_FileInfo->name = fileInfo["name"].toString();
info->m_FileInfo->version.parse(fileInfo["version"].toString());
+ if (info->m_FileInfo->version.isEmpty()) {
+ info->m_FileInfo->version = info->m_NexusInfo.m_NewestVersion;
+ }
info->m_FileInfo->fileCategory = convertFileCategory(fileInfo["category_id"].toInt());
+ info->m_FileInfo->fileTime = matchDate(fileInfo["date"].toString());
info->m_FileInfo->fileID = fileInfo["id"].toInt();
found = true;
break;
@@ -986,7 +1104,7 @@ void DownloadManager::nxmFilesAvailable(int, QVariant userData, QVariant resultD
}
-void DownloadManager::nxmFileInfoAvailable(int modID, int fileID, QVariant, QVariant resultData, int requestID)
+void DownloadManager::nxmFileInfoAvailable(int modID, int fileID, QVariant userData, QVariant resultData, int requestID)
{
std::set<int>::iterator idIter = m_RequestIDs.find(requestID);
if (idIter == m_RequestIDs.end()) {
@@ -998,11 +1116,15 @@ void DownloadManager::nxmFileInfoAvailable(int modID, int fileID, QVariant, QVar
ModRepositoryFileInfo *info = new ModRepositoryFileInfo();
QVariantMap result = resultData.toMap();
-
info->name = result["name"].toString();
+ qDebug("file info received for %s", qPrintable(info.m_Name));
info->version.parse(result["version"].toString());
+ if (info.m_Version.isEmpty()) {
+ info.m_Version = info.m_NewestVersion;
+ }
info->fileName = result["uri"].toString();
info->fileCategory = result["category_id"].toInt();
+ info->fileTime = matchDate(result["date"].toString());
info->description = result["description"].toString();
info->repository = "Nexus";
@@ -1010,7 +1132,7 @@ void DownloadManager::nxmFileInfoAvailable(int modID, int fileID, QVariant, QVar
info->fileID = fileID;
QObject *test = info;
- m_RequestIDs.insert(m_NexusInterface->requestDownloadURL(modID, fileID, this, qVariantFromValue(test)));
+ m_RequestIDs.insert(m_NexusInterface->requestDownloadURL(modID, fileID, this, qVariantFromValue(info)));
}
@@ -1096,6 +1218,7 @@ void DownloadManager::nxmDownloadURLsAvailable(int modID, int fileID, QVariant u
ModRepositoryFileInfo *info = qobject_cast<ModRepositoryFileInfo*>(qvariant_cast<QObject*>(userData));
QVariantList resultList = resultData.toList();
if (resultList.length() == 0) {
+ removePending(modID, fileID);
emit showMessage(tr("No download server available. Please try again later."));
return;
}
@@ -1114,7 +1237,7 @@ void DownloadManager::nxmDownloadURLsAvailable(int modID, int fileID, QVariant u
}
-void DownloadManager::nxmRequestFailed(int modID, QVariant, int requestID, const QString &errorString)
+void DownloadManager::nxmRequestFailed(int modID, int fileID, QVariant userData, int requestID, const QString &errorString)
{
std::set<int>::iterator idIter = m_RequestIDs.find(requestID);
if (idIter == m_RequestIDs.end()) {
@@ -1138,6 +1261,8 @@ void DownloadManager::nxmRequestFailed(int modID, QVariant, int requestID, const
break;
}
}
+
+ removePending(modID, fileID);
emit showMessage(tr("Failed to request file info from nexus: %1").arg(errorString));
}
@@ -1152,16 +1277,21 @@ void DownloadManager::downloadFinished()
QByteArray data = info->m_Reply->readAll();
info->m_Output.write(data);
info->m_Output.close();
+ TaskProgressManager::instance().forgetMe(info->m_TaskProgressId);
bool error = false;
-
if ((info->m_State != STATE_CANCELING) &&
(info->m_State != STATE_PAUSING)) {
+ bool textData = reply->header(QNetworkRequest::ContentTypeHeader).toString().startsWith("text", Qt::CaseInsensitive);
if ((info->m_Output.size() == 0) ||
((reply->error() != QNetworkReply::NoError) && (reply->error() != QNetworkReply::OperationCanceledError)) ||
- reply->header(QNetworkRequest::ContentTypeHeader).toString().startsWith("text", Qt::CaseInsensitive)) {
+ textData) {
if (info->m_Tries == 0) {
- emit showMessage(tr("Download failed: %1 (%2)").arg(reply->errorString()).arg(reply->error()));
+ if (textData && (reply->error() == QNetworkReply::NoError)) {
+ emit showMessage(tr("Download failed. Server reported: %1").arg(QString(data)));
+ } else {
+ emit showMessage(tr("Download failed: %1 (%2)").arg(reply->errorString()).arg(reply->error()));
+ }
}
error = true;
setState(info, STATE_PAUSING);
@@ -1233,7 +1363,7 @@ void DownloadManager::downloadFinished()
if ((info->m_Tries > 0) && error) {
--info->m_Tries;
- resumeDownload(index);
+ resumeDownloadInt(index);
}
} else {
qWarning("no download index %d", index);
@@ -1265,3 +1395,4 @@ void DownloadManager::directoryChanged(const QString&)
{
refreshList();
}
+