diff options
Diffstat (limited to 'logic')
-rw-r--r-- | logic/BaseInstance.h | 2 | ||||
-rw-r--r-- | logic/OneSixInstance.cpp | 13 | ||||
-rw-r--r-- | logic/OneSixUpdate.cpp | 10 | ||||
-rw-r--r-- | logic/auth/MojangAccount.cpp | 4 | ||||
-rw-r--r-- | logic/auth/MojangAccount.h | 5 | ||||
-rw-r--r-- | logic/auth/MojangAccountList.cpp | 64 | ||||
-rw-r--r-- | logic/auth/MojangAccountList.h | 7 | ||||
-rw-r--r-- | logic/auth/flows/AuthenticateTask.cpp | 6 | ||||
-rw-r--r-- | logic/auth/flows/RefreshTask.cpp | 9 | ||||
-rw-r--r-- | logic/lists/InstanceList.cpp | 21 | ||||
-rw-r--r-- | logic/lists/InstanceList.h | 8 | ||||
-rw-r--r-- | logic/net/ByteArrayDownload.cpp | 8 | ||||
-rw-r--r-- | logic/net/CacheDownload.cpp | 14 | ||||
-rw-r--r-- | logic/net/ForgeMirrors.cpp | 8 | ||||
-rw-r--r-- | logic/net/ForgeXzDownload.cpp | 18 | ||||
-rw-r--r-- | logic/net/MD5EtagDownload.cpp | 16 | ||||
-rw-r--r-- | logic/net/NetAction.h | 23 | ||||
-rw-r--r-- | logic/net/NetJob.h | 12 | ||||
-rw-r--r-- | logic/net/PasteUpload.cpp | 2 | ||||
-rw-r--r-- | logic/net/S3ListBucket.cpp | 175 | ||||
-rw-r--r-- | logic/net/S3ListBucket.h | 57 |
21 files changed, 195 insertions, 287 deletions
diff --git a/logic/BaseInstance.h b/logic/BaseInstance.h index 93e57414..5f426676 100644 --- a/logic/BaseInstance.h +++ b/logic/BaseInstance.h @@ -149,7 +149,7 @@ public: */ virtual SettingsObject &settings() const; - /// returns a valid update task if update is needed, NULL otherwise + /// returns a valid update task virtual std::shared_ptr<Task> doUpdate(bool only_prepare) = 0; /// returns a valid minecraft process, ready for launch with the given account. diff --git a/logic/OneSixInstance.cpp b/logic/OneSixInstance.cpp index 337830a2..fd41b9e5 100644 --- a/logic/OneSixInstance.cpp +++ b/logic/OneSixInstance.cpp @@ -152,8 +152,17 @@ QStringList OneSixInstance::processMinecraftArgs(MojangAccountPtr account) token_mapping["game_directory"] = absRootDir; QString absAssetsDir = QDir("assets/").absolutePath(); token_mapping["game_assets"] = reconstructAssets(d->version).absolutePath(); - //TODO: this is something new and not even fully implemented in the vanilla launcher. - token_mapping["user_properties"] = "{ }"; + + auto user = account->user(); + QJsonObject userAttrs; + for(auto key: user.properties.keys()) + { + auto array = QJsonArray::fromStringList(user.properties.values(key)); + userAttrs.insert(key, array); + } + QJsonDocument value(userAttrs); + + token_mapping["user_properties"] = value.toJson(QJsonDocument::Compact); token_mapping["user_type"] = account->currentProfile()->legacy ? "legacy" : "mojang"; // 1.7.3+ assets tokens token_mapping["assets_root"] = absAssetsDir; diff --git a/logic/OneSixUpdate.cpp b/logic/OneSixUpdate.cpp index 4228fc44..696eeff0 100644 --- a/logic/OneSixUpdate.cpp +++ b/logic/OneSixUpdate.cpp @@ -54,11 +54,9 @@ void OneSixUpdate::executeTask() if (m_only_prepare) { - if (m_inst->shouldUpdate()) - { - emitFailed("Unable to update instance in offline mode."); - return; - } + /* + * FIXME: in offline mode, do not proceed! + */ setStatus("Testing the Java installation."); QString java_path = m_inst->settings().get("JavaPath").toString(); @@ -243,11 +241,13 @@ void OneSixUpdate::assetIndexFinished() auto objectDL = MD5EtagDownload::make( QUrl("http://" + URLConstants::RESOURCE_BASE + objectName), objectFile.filePath()); + objectDL->m_total_progress = object.size; dls.append(objectDL); } } if(dls.size()) { + setStatus("Getting the assets files from Mojang..."); auto job = new NetJob("Assets for " + inst->name()); for(auto dl: dls) job->addNetAction(dl); diff --git a/logic/auth/MojangAccount.cpp b/logic/auth/MojangAccount.cpp index 185c735c..bc6af98f 100644 --- a/logic/auth/MojangAccount.cpp +++ b/logic/auth/MojangAccount.cpp @@ -68,6 +68,7 @@ MojangAccountPtr MojangAccount::loadFromJson(const QJsonObject &object) User u; QJsonObject userStructure = object.value("user").toObject(); u.id = userStructure.value("id").toString(); + /* QJsonObject propMap = userStructure.value("properties").toObject(); for(auto key: propMap.keys()) { @@ -75,6 +76,7 @@ MojangAccountPtr MojangAccount::loadFromJson(const QJsonObject &object) for(auto value: values) u.properties.insert(key, value.toString()); } + */ account->m_user = u; } account->m_username = username; @@ -119,6 +121,7 @@ QJsonObject MojangAccount::saveToJson() const QJsonObject userStructure; { userStructure.insert("id", m_user.id); + /* QJsonObject userAttrs; for(auto key: m_user.properties.keys()) { @@ -126,6 +129,7 @@ QJsonObject MojangAccount::saveToJson() const userAttrs.insert(key, array); } userStructure.insert("properties", userAttrs); + */ } json.insert("user", userStructure); diff --git a/logic/auth/MojangAccount.h b/logic/auth/MojangAccount.h index 9eecbc4f..325aa826 100644 --- a/logic/auth/MojangAccount.h +++ b/logic/auth/MojangAccount.h @@ -122,6 +122,11 @@ public: /* queries */ return m_profiles; } + const User & user() + { + return m_user; + } + //! Get the session ID required for legacy Minecraft versions QString sessionId() const { diff --git a/logic/auth/MojangAccountList.cpp b/logic/auth/MojangAccountList.cpp index 0d13cd34..70bc0cf2 100644 --- a/logic/auth/MojangAccountList.cpp +++ b/logic/auth/MojangAccountList.cpp @@ -22,10 +22,12 @@ #include <QJsonArray> #include <QJsonObject> #include <QJsonParseError> +#include <QDir> #include "logger/QsLog.h" #include "logic/auth/MojangAccount.h" +#include <pathutils.h> #define ACCOUNT_LIST_FORMAT_VERSION 2 @@ -148,9 +150,6 @@ QVariant MojangAccountList::data(const QModelIndex &index, int role) const case Qt::DisplayRole: switch (index.column()) { - case ActiveColumn: - return account == m_activeAccount; - case NameColumn: return account->username(); @@ -164,6 +163,13 @@ QVariant MojangAccountList::data(const QModelIndex &index, int role) const case PointerRole: return qVariantFromValue(account); + case Qt::CheckStateRole: + switch (index.column()) + { + case ActiveColumn: + return account == m_activeAccount; + } + default: return QVariant(); } @@ -212,6 +218,36 @@ int MojangAccountList::columnCount(const QModelIndex &parent) const return 2; } +Qt::ItemFlags MojangAccountList::flags(const QModelIndex &index) const +{ + if (index.row() < 0 || index.row() >= rowCount(index) || !index.isValid()) + { + return Qt::NoItemFlags; + } + + return Qt::ItemIsUserCheckable | Qt::ItemIsEnabled | Qt::ItemIsSelectable; +} + +bool MojangAccountList::setData(const QModelIndex &index, const QVariant &value, int role) +{ + if (index.row() < 0 || index.row() >= rowCount(index) || !index.isValid()) + { + return false; + } + + if(role == Qt::CheckStateRole) + { + if(value == Qt::Checked) + { + MojangAccountPtr account = this->at(index.row()); + this->setActiveAccount(account->username()); + } + } + + emit dataChanged(index, index); + return true; +} + void MojangAccountList::updateListData(QList<MojangAccountPtr> versions) { beginResetModel(); @@ -311,6 +347,18 @@ bool MojangAccountList::saveList(const QString &filePath) return false; } + // make sure the parent folder exists + if(!ensureFilePathExists(path)) + return false; + + // make sure the file wasn't overwritten with a folder before (fixes a bug) + QFileInfo finfo(path); + if(finfo.isDir()) + { + QDir badDir(path); + badDir.removeRecursively(); + } + QLOG_INFO() << "Writing account list to" << path; QLOG_DEBUG() << "Building JSON data structure."; @@ -366,3 +414,13 @@ void MojangAccountList::setListFilePath(QString path, bool autosave) m_listFilePath = path; m_autosave = autosave; } + +bool MojangAccountList::anyAccountIsValid() +{ + for(auto account:m_accounts) + { + if(account->accountStatus() != NotVerified) + return true; + } + return false; +} diff --git a/logic/auth/MojangAccountList.h b/logic/auth/MojangAccountList.h index b3301bf6..6f4fbb17 100644 --- a/logic/auth/MojangAccountList.h +++ b/logic/auth/MojangAccountList.h @@ -64,6 +64,8 @@ public: virtual QVariant headerData(int section, Qt::Orientation orientation, int role) const; virtual int rowCount(const QModelIndex &parent) const; virtual int columnCount(const QModelIndex &parent) const; + virtual Qt::ItemFlags flags(const QModelIndex &index) const; + virtual bool setData(const QModelIndex &index, const QVariant &value, int role); /*! * Adds a the given Mojang account to the account list. @@ -124,6 +126,11 @@ public: * If the username given is an empty string, sets the active account to nothing. */ virtual void setActiveAccount(const QString &username); + + /*! + * Returns true if any of the account is at least Validated + */ + bool anyAccountIsValid(); signals: /*! diff --git a/logic/auth/flows/AuthenticateTask.cpp b/logic/auth/flows/AuthenticateTask.cpp index cc26cd1b..f60be35d 100644 --- a/logic/auth/flows/AuthenticateTask.cpp +++ b/logic/auth/flows/AuthenticateTask.cpp @@ -162,23 +162,17 @@ bool AuthenticateTask::processResponse(QJsonObject responseData) } // this is what the vanilla launcher passes to the userProperties launch param - // doesn't seem to be used for anything so far? I don't get any of this data on my account - // (peterixxx) - // is it a good idea to log this? if (responseData.contains("user")) { User u; auto obj = responseData.value("user").toObject(); u.id = obj.value("id").toString(); - QLOG_DEBUG() << "User ID: " << u.id ; auto propArray = obj.value("properties").toArray(); - QLOG_DEBUG() << "User Properties: "; for (auto prop : propArray) { auto propTuple = prop.toObject(); auto name = propTuple.value("name").toString(); auto value = propTuple.value("value").toString(); - QLOG_DEBUG() << name << " : " << value; u.properties.insert(name, value); } m_account->m_user = u; diff --git a/logic/auth/flows/RefreshTask.cpp b/logic/auth/flows/RefreshTask.cpp index 16feac6e..5f68ccc7 100644 --- a/logic/auth/flows/RefreshTask.cpp +++ b/logic/auth/flows/RefreshTask.cpp @@ -112,20 +112,21 @@ bool RefreshTask::processResponse(QJsonObject responseData) // this is what the vanilla launcher passes to the userProperties launch param if (responseData.contains("user")) { + User u; auto obj = responseData.value("user").toObject(); - auto userId = obj.value("id").toString(); + u.id = obj.value("id").toString(); auto propArray = obj.value("properties").toArray(); - QLOG_DEBUG() << "User ID: " << userId; - QLOG_DEBUG() << "User Properties: "; for (auto prop : propArray) { auto propTuple = prop.toObject(); auto name = propTuple.value("name").toString(); auto value = propTuple.value("value").toString(); - QLOG_DEBUG() << name << " : " << value; + u.properties.insert(name, value); } + m_account->m_user = u; } + // We've made it through the minefield of possible errors. Return true to indicate that // we've succeeded. QLOG_DEBUG() << "Finished reading refresh response."; diff --git a/logic/lists/InstanceList.cpp b/logic/lists/InstanceList.cpp index b9595578..15fd10ba 100644 --- a/logic/lists/InstanceList.cpp +++ b/logic/lists/InstanceList.cpp @@ -36,11 +36,16 @@ const static int GROUP_FILE_FORMAT_VERSION = 1; InstanceList::InstanceList(const QString &instDir, QObject *parent) : QAbstractListModel(parent), m_instDir(instDir) { + connect(MMC, &MultiMC::aboutToQuit, this, &InstanceList::saveGroupList); + + if (!QDir::current().exists(m_instDir)) + { + QDir::current().mkpath(m_instDir); + } } InstanceList::~InstanceList() { - saveGroupList(); } int InstanceList::rowCount(const QModelIndex &parent) const @@ -112,6 +117,11 @@ void InstanceList::groupChanged() saveGroupList(); } +QStringList InstanceList::getGroups() +{ + return m_groups.toList(); +} + void InstanceList::saveGroupList() { QString groupFileName = m_instDir + "/instgroups.json"; @@ -121,7 +131,7 @@ void InstanceList::saveGroupList() if (!groupFile.open(QIODevice::WriteOnly | QIODevice::Truncate)) { // An error occurred. Ignore it. - QLOG_ERROR() << "Failed to read instance group file."; + QLOG_ERROR() << "Failed to save instance group file."; return; } QTextStream out(&groupFile); @@ -132,6 +142,10 @@ void InstanceList::saveGroupList() QString group = instance->group(); if (group.isEmpty()) continue; + + // keep a list/set of groups for choosing + m_groups.insert(group); + if (!groupMap.count(group)) { QSet<QString> set; @@ -248,6 +262,9 @@ void InstanceList::loadGroupList(QMap<QString, QString> &groupMap) continue; } + // keep a list/set of groups for choosing + m_groups.insert(groupName); + // Iterate through the list of instances in the group. QJsonArray instancesArray = groupObj.value("instances").toArray(); diff --git a/logic/lists/InstanceList.h b/logic/lists/InstanceList.h index 8cd39746..f23b7763 100644 --- a/logic/lists/InstanceList.h +++ b/logic/lists/InstanceList.h @@ -17,6 +17,7 @@ #include <QObject> #include <QAbstractListModel> +#include <QSet> #include "categorizedsortfilterproxymodel.h" #include <QIcon> @@ -29,6 +30,9 @@ class InstanceList : public QAbstractListModel Q_OBJECT private: void loadGroupList(QMap<QString, QString> &groupList); + +private +slots: void saveGroupList(); public: @@ -94,6 +98,9 @@ public: InstancePtr getInstanceById(QString id) const; QModelIndex getInstanceIndexById(const QString &id) const; + + // FIXME: instead of iterating through all instances and forming a set, keep the set around + QStringList getGroups(); signals: void dataIsInvalid(); @@ -113,6 +120,7 @@ private: protected: QString m_instDir; QList<InstancePtr> m_instances; + QSet<QString> m_groups; }; class InstanceProxyModel : public KCategorizedSortFilterProxyModel diff --git a/logic/net/ByteArrayDownload.cpp b/logic/net/ByteArrayDownload.cpp index af5af8e9..27d2a250 100644 --- a/logic/net/ByteArrayDownload.cpp +++ b/logic/net/ByteArrayDownload.cpp @@ -42,7 +42,9 @@ void ByteArrayDownload::start() void ByteArrayDownload::downloadProgress(qint64 bytesReceived, qint64 bytesTotal) { - emit progress(index_within_job, bytesReceived, bytesTotal); + m_total_progress = bytesTotal; + m_progress = bytesReceived; + emit progress(m_index_within_job, bytesReceived, bytesTotal); } void ByteArrayDownload::downloadError(QNetworkReply::NetworkError error) @@ -62,14 +64,14 @@ void ByteArrayDownload::downloadFinished() m_status = Job_Finished; m_data = m_reply->readAll(); m_reply.reset(); - emit succeeded(index_within_job); + emit succeeded(m_index_within_job); return; } // else the download failed else { m_reply.reset(); - emit failed(index_within_job); + emit failed(m_index_within_job); return; } } diff --git a/logic/net/CacheDownload.cpp b/logic/net/CacheDownload.cpp index 873d3a2e..6eadae39 100644 --- a/logic/net/CacheDownload.cpp +++ b/logic/net/CacheDownload.cpp @@ -35,14 +35,14 @@ void CacheDownload::start() { if (!m_entry->stale) { - emit succeeded(index_within_job); + emit succeeded(m_index_within_job); return; } m_output_file.setFileName(m_target_path); // if there already is a file and md5 checking is in effect and it can be opened if (!ensureFilePathExists(m_target_path)) { - emit failed(index_within_job); + emit failed(m_index_within_job); return; } QLOG_INFO() << "Downloading " << m_url.toString(); @@ -69,7 +69,9 @@ void CacheDownload::start() void CacheDownload::downloadProgress(qint64 bytesReceived, qint64 bytesTotal) { - emit progress(index_within_job, bytesReceived, bytesTotal); + m_total_progress = bytesTotal; + m_progress = bytesReceived; + emit progress(m_index_within_job, bytesReceived, bytesTotal); } void CacheDownload::downloadError(QNetworkReply::NetworkError error) @@ -116,7 +118,7 @@ void CacheDownload::downloadFinished() MMC->metacache()->updateEntry(m_entry); m_reply.reset(); - emit succeeded(index_within_job); + emit succeeded(m_index_within_job); return; } // else the download failed @@ -125,7 +127,7 @@ void CacheDownload::downloadFinished() m_output_file.close(); m_output_file.remove(); m_reply.reset(); - emit failed(index_within_job); + emit failed(m_index_within_job); return; } } @@ -140,7 +142,7 @@ void CacheDownload::downloadReadyRead() * Can't open the file... the job failed */ m_reply->abort(); - emit failed(index_within_job); + emit failed(m_index_within_job); return; } } diff --git a/logic/net/ForgeMirrors.cpp b/logic/net/ForgeMirrors.cpp index fd7eccca..b224306f 100644 --- a/logic/net/ForgeMirrors.cpp +++ b/logic/net/ForgeMirrors.cpp @@ -68,7 +68,7 @@ void ForgeMirrors::deferToFixedList() "https://www.creeperhost.net/link.php?id=1", "http://new.creeperrepo.net/forge/maven/"}); injectDownloads(); - emit succeeded(index_within_job); + emit succeeded(m_index_within_job); } void ForgeMirrors::parseMirrorList() @@ -88,7 +88,7 @@ void ForgeMirrors::parseMirrorList() if(!m_mirrors.size()) deferToFixedList(); injectDownloads(); - emit succeeded(index_within_job); + emit succeeded(m_index_within_job); } void ForgeMirrors::injectDownloads() @@ -108,7 +108,9 @@ void ForgeMirrors::injectDownloads() void ForgeMirrors::downloadProgress(qint64 bytesReceived, qint64 bytesTotal) { - emit progress(index_within_job, bytesReceived, bytesTotal); + m_total_progress = bytesTotal; + m_progress = bytesReceived; + emit progress(m_index_within_job, bytesReceived, bytesTotal); } void ForgeMirrors::downloadReadyRead() diff --git a/logic/net/ForgeXzDownload.cpp b/logic/net/ForgeXzDownload.cpp index f119878a..1771d304 100644 --- a/logic/net/ForgeXzDownload.cpp +++ b/logic/net/ForgeXzDownload.cpp @@ -44,20 +44,20 @@ void ForgeXzDownload::start() if (!m_entry->stale) { m_status = Job_Finished; - emit succeeded(index_within_job); + emit succeeded(m_index_within_job); return; } // can we actually create the real, final file? if (!ensureFilePathExists(m_target_path)) { m_status = Job_Failed; - emit failed(index_within_job); + emit failed(m_index_within_job); return; } if (m_mirrors.empty()) { m_status = Job_Failed; - emit failed(index_within_job); + emit failed(m_index_within_job); return; } @@ -80,7 +80,9 @@ void ForgeXzDownload::start() void ForgeXzDownload::downloadProgress(qint64 bytesReceived, qint64 bytesTotal) { - emit progress(index_within_job, bytesReceived, bytesTotal); + m_total_progress = bytesTotal; + m_progress = bytesReceived; + emit progress(m_index_within_job, bytesReceived, bytesTotal); } void ForgeXzDownload::downloadError(QNetworkReply::NetworkError error) @@ -100,7 +102,7 @@ void ForgeXzDownload::failAndTryNextMirror() m_mirror_index = next; updateUrl(); - emit failed(index_within_job); + emit failed(m_index_within_job); } void ForgeXzDownload::updateUrl() @@ -148,7 +150,7 @@ void ForgeXzDownload::downloadFinished() m_status = Job_Failed; m_pack200_xz_file.remove(); m_reply.reset(); - emit failed(index_within_job); + emit failed(m_index_within_job); return; } } @@ -175,7 +177,7 @@ void ForgeXzDownload::downloadReadyRead() * Can't open the file... the job failed */ m_reply->abort(); - emit failed(index_within_job); + emit failed(m_index_within_job); return; } } @@ -347,5 +349,5 @@ void ForgeXzDownload::decompressAndInstall() MMC->metacache()->updateEntry(m_entry); m_reply.reset(); - emit succeeded(index_within_job); + emit succeeded(m_index_within_job); } diff --git a/logic/net/MD5EtagDownload.cpp b/logic/net/MD5EtagDownload.cpp index 4b9f52af..435e854e 100644 --- a/logic/net/MD5EtagDownload.cpp +++ b/logic/net/MD5EtagDownload.cpp @@ -44,7 +44,7 @@ void MD5EtagDownload::start() if (m_check_md5 && hash == m_expected_md5) { QLOG_INFO() << "Skipping " << m_url.toString() << ": md5 match."; - emit succeeded(index_within_job); + emit succeeded(m_index_within_job); return; } else @@ -54,7 +54,7 @@ void MD5EtagDownload::start() } if (!ensureFilePathExists(filename)) { - emit failed(index_within_job); + emit failed(m_index_within_job); return; } @@ -68,7 +68,7 @@ void MD5EtagDownload::start() // Plus, this way, we don't end up starting a download for a file we can't open. if (!m_output_file.open(QIODevice::WriteOnly)) { - emit failed(index_within_job); + emit failed(m_index_within_job); return; } @@ -86,7 +86,9 @@ void MD5EtagDownload::start() void MD5EtagDownload::downloadProgress(qint64 bytesReceived, qint64 bytesTotal) { - emit progress(index_within_job, bytesReceived, bytesTotal); + m_total_progress = bytesTotal; + m_progress = bytesReceived; + emit progress(m_index_within_job, bytesReceived, bytesTotal); } void MD5EtagDownload::downloadError(QNetworkReply::NetworkError error) @@ -107,7 +109,7 @@ void MD5EtagDownload::downloadFinished() QLOG_INFO() << "Finished " << m_url.toString() << " got " << m_reply->rawHeader("ETag").constData(); m_reply.reset(); - emit succeeded(index_within_job); + emit succeeded(m_index_within_job); return; } // else the download failed @@ -115,7 +117,7 @@ void MD5EtagDownload::downloadFinished() { m_output_file.close(); m_reply.reset(); - emit failed(index_within_job); + emit failed(m_index_within_job); return; } } @@ -130,7 +132,7 @@ void MD5EtagDownload::downloadReadyRead() * Can't open the file... the job failed */ m_reply->abort(); - emit failed(index_within_job); + emit failed(m_index_within_job); return; } } diff --git a/logic/net/NetAction.h b/logic/net/NetAction.h index c96d8f8f..97c96e5d 100644 --- a/logic/net/NetAction.h +++ b/logic/net/NetAction.h @@ -39,6 +39,19 @@ public: virtual ~NetAction() {}; public: + virtual qint64 totalProgress() const + { + return m_total_progress; + } + virtual qint64 currentProgress() const + { + return m_progress; + } + virtual qint64 numberOfFailures() const + { + return m_failures; + } +public: /// the network reply std::shared_ptr<QNetworkReply> m_reply; @@ -46,10 +59,16 @@ public: QUrl m_url; /// The file's status - JobStatus m_status; + JobStatus m_status = Job_NotStarted; /// index within the parent job - int index_within_job = 0; + int m_index_within_job = 0; + + qint64 m_progress = 0; + qint64 m_total_progress = 1; + + /// number of failures up to this point + int m_failures = 0; signals: void started(int index); diff --git a/logic/net/NetJob.h b/logic/net/NetJob.h index 6e2e7607..68c4c408 100644 --- a/logic/net/NetJob.h +++ b/logic/net/NetJob.h @@ -36,10 +36,16 @@ public: template <typename T> bool addNetAction(T action) { NetActionPtr base = std::static_pointer_cast<NetAction>(action); - base->index_within_job = downloads.size(); + base->m_index_within_job = downloads.size(); downloads.append(action); - parts_progress.append(part_info()); - total_progress++; + part_info pi; + { + pi.current_progress = base->currentProgress(); + pi.total_progress = base->totalProgress(); + pi.failures = base->numberOfFailures(); + } + parts_progress.append(pi); + total_progress += pi.total_progress; // if this is already running, the action needs to be started right away! if (isRunning()) { diff --git a/logic/net/PasteUpload.cpp b/logic/net/PasteUpload.cpp index acf09291..fa54d084 100644 --- a/logic/net/PasteUpload.cpp +++ b/logic/net/PasteUpload.cpp @@ -78,7 +78,9 @@ bool PasteUpload::parseResult(QJsonDocument doc, QString *parseError) parseError = new QString(object.value("error").toString()); return false; } + // FIXME: not the place for GUI things. QString pasteUrl = object.value("paste").toObject().value("link").toString(); QDesktopServices::openUrl(pasteUrl); return true; } + diff --git a/logic/net/S3ListBucket.cpp b/logic/net/S3ListBucket.cpp deleted file mode 100644 index 439b7086..00000000 --- a/logic/net/S3ListBucket.cpp +++ /dev/null @@ -1,175 +0,0 @@ -/* Copyright 2013 MultiMC Contributors - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -#include "S3ListBucket.h" -#include "MultiMC.h" -#include "logger/QsLog.h" -#include <QUrlQuery> -#include <qxmlstream.h> -#include <QDomDocument> - -inline QDomElement getDomElementByTagName(QDomElement parent, QString tagname) -{ - QDomNodeList elementList = parent.elementsByTagName(tagname); - if (elementList.count()) - return elementList.at(0).toElement(); - else - return QDomElement(); -} - -S3ListBucket::S3ListBucket(QUrl url) : NetAction() -{ - m_url = url; - m_status = Job_NotStarted; -} - -void S3ListBucket::start() -{ - QUrl finalUrl = m_url; - if (current_marker.size()) - { - QUrlQuery query; - query.addQueryItem("marker", current_marker); - finalUrl.setQuery(query); - } - QNetworkRequest request(finalUrl); - request.setHeader(QNetworkRequest::UserAgentHeader, "MultiMC/5.0 (Uncached)"); - auto worker = MMC->qnam(); - QNetworkReply *rep = worker->get(request); - - m_reply = std::shared_ptr<QNetworkReply>(rep); - connect(rep, SIGNAL(downloadProgress(qint64, qint64)), - SLOT(downloadProgress(qint64, qint64))); - connect(rep, SIGNAL(finished()), SLOT(downloadFinished())); - connect(rep, SIGNAL(error(QNetworkReply::NetworkError)), - SLOT(downloadError(QNetworkReply::NetworkError))); - connect(rep, SIGNAL(readyRead()), SLOT(downloadReadyRead())); -} - -void S3ListBucket::downloadProgress(qint64 bytesReceived, qint64 bytesTotal) -{ - emit progress(index_within_job, bytesSoFar + bytesReceived, bytesSoFar + bytesTotal); -} - -void S3ListBucket::downloadError(QNetworkReply::NetworkError error) -{ - // error happened during download. - QLOG_ERROR() << "Error getting URL:" << m_url.toString().toLocal8Bit() - << "Network error: " << error; - m_status = Job_Failed; -} - -void S3ListBucket::processValidReply() -{ - QLOG_TRACE() << "GOT: " << m_url.toString() << " marker:" << current_marker; - auto readContents = [&](QXmlStreamReader & xml) - { - QString Key, ETag, Size; - while (!(xml.tokenType() == QXmlStreamReader::EndElement && xml.name() == "Contents")) - { - if (xml.tokenType() == QXmlStreamReader::StartElement) - { - if (xml.name() == "Key") - { - Key = xml.readElementText(); - } - if (xml.name() == "ETag") - { - ETag = xml.readElementText(); - } - if (xml.name() == "Size") - { - Size = xml.readElementText(); - } - } - xml.readNext(); - } - if (xml.error() != QXmlStreamReader::NoError) - return; - objects.append({Key, ETag, Size.toLongLong()}); - }; - - // nothing went wrong... - QByteArray ba = m_reply->readAll(); - - QString xmlErrorMsg; - - bool is_truncated = false; - QXmlStreamReader xml(ba); - while (!xml.atEnd() && !xml.hasError()) - { - /* Read next element.*/ - QXmlStreamReader::TokenType token = xml.readNext(); - /* If token is just StartDocument, we'll go to next.*/ - if (token == QXmlStreamReader::StartDocument) - { - continue; - } - if (token == QXmlStreamReader::StartElement) - { - /* If it's named person, we'll dig the information from there.*/ - if (xml.name() == "Contents") - { - readContents(xml); - } - else if (xml.name() == "IsTruncated") - { - is_truncated = (xml.readElementText() == "true"); - } - } - } - if (xml.hasError()) - { - QLOG_ERROR() << "Failed to process s3.amazonaws.com/Minecraft.Resources. XML error:" - << xml.errorString() << ba; - emit failed(index_within_job); - return; - } - if (is_truncated) - { - current_marker = objects.last().Key; - bytesSoFar += m_reply->size(); - m_reply.reset(); - start(); - } - else - { - m_status = Job_Finished; - m_reply.reset(); - emit succeeded(index_within_job); - } - return; -} - -void S3ListBucket::downloadFinished() -{ - // if the download succeeded - if (m_status != Job_Failed) - { - processValidReply(); - } - // else the download failed - else - { - m_reply.reset(); - emit failed(index_within_job); - return; - } -} - -void S3ListBucket::downloadReadyRead() -{ - // ~_~ -} diff --git a/logic/net/S3ListBucket.h b/logic/net/S3ListBucket.h deleted file mode 100644 index e7c5e05c..00000000 --- a/logic/net/S3ListBucket.h +++ /dev/null @@ -1,57 +0,0 @@ -/* Copyright 2013 MultiMC Contributors - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -#pragma once -#include "NetAction.h" - -struct S3Object -{ - QString Key; - QString ETag; - qlonglong size; -}; - -typedef std::shared_ptr<class S3ListBucket> S3ListBucketPtr; -class S3ListBucket : public NetAction -{ - Q_OBJECT -public: - S3ListBucket(QUrl url); - static S3ListBucketPtr make(QUrl url) - { - return S3ListBucketPtr(new S3ListBucket(url)); - } - -public: - QList<S3Object> objects; - -public -slots: - virtual void start() override; - -protected -slots: - virtual void downloadProgress(qint64 bytesReceived, qint64 bytesTotal) override; - virtual void downloadError(QNetworkReply::NetworkError error) override; - virtual void downloadFinished() override; - virtual void downloadReadyRead() override; - -private: - void processValidReply(); - -private: - qint64 bytesSoFar = 0; - QString current_marker; -}; |