Finish assets update for 1.7.3

This commit is contained in:
Petr Mrázek 2013-12-10 07:12:52 +01:00
parent 8db2e5db81
commit 3f5c46a1c4
20 changed files with 203 additions and 381 deletions

View File

@ -284,8 +284,8 @@ logic/InstanceLauncher.cpp
# network stuffs
logic/net/NetAction.h
logic/net/FileDownload.h
logic/net/FileDownload.cpp
logic/net/MD5EtagDownload.h
logic/net/MD5EtagDownload.cpp
logic/net/ByteArrayDownload.h
logic/net/ByteArrayDownload.cpp
logic/net/CacheDownload.h
@ -325,8 +325,6 @@ logic/LegacyForge.h
logic/LegacyForge.cpp
# 1.6 instances
logic/OneSixAssets.h
logic/OneSixAssets.cpp
logic/OneSixInstance.h
logic/OneSixInstance.cpp
logic/OneSixInstance_p.h
@ -385,13 +383,8 @@ logic/SkinUtils.h
logic/SkinUtils.cpp
# Assets
logic/assets/AssetsIndex.h
logic/assets/AssetsIndex.cpp
logic/assets/AssetsUtils.h
logic/assets/AssetsUtils.cpp
logic/assets/Assets.h
logic/assets/Assets.cpp
)

View File

@ -351,7 +351,8 @@ void MultiMC::initGlobalSettings()
void MultiMC::initHttpMetaCache()
{
m_metacache.reset(new HttpMetaCache("metacache"));
m_metacache->addBase("assets", QDir("assets").absolutePath());
m_metacache->addBase("asset_indexes", QDir("assets/indexes").absolutePath());
m_metacache->addBase("asset_objects", QDir("assets/objects").absolutePath());
m_metacache->addBase("versions", QDir("versions").absolutePath());
m_metacache->addBase("libraries", QDir("libraries").absolutePath());
m_metacache->addBase("minecraftforge", QDir("mods/minecraftforge").absolutePath());

View File

@ -72,7 +72,6 @@
#include "logic/BaseInstance.h"
#include "logic/InstanceFactory.h"
#include "logic/MinecraftProcess.h"
#include "logic/OneSixAssets.h"
#include "logic/OneSixUpdate.h"
#include "logic/JavaUtils.h"
#include "logic/NagUtils.h"
@ -233,15 +232,6 @@ MainWindow::MainWindow(QWidget *parent) : QMainWindow(parent), ui(new Ui::MainWi
{
MMC->lwjgllist()->loadList();
}
assets_downloader = new OneSixAssets();
connect(assets_downloader, SIGNAL(indexStarted()), SLOT(assetsIndexStarted()));
connect(assets_downloader, SIGNAL(filesStarted()), SLOT(assetsFilesStarted()));
connect(assets_downloader, SIGNAL(filesProgress(int, int, int)),
SLOT(assetsFilesProgress(int, int, int)));
connect(assets_downloader, SIGNAL(failed()), SLOT(assetsFailed()));
connect(assets_downloader, SIGNAL(finished()), SLOT(assetsFinished()));
//assets_downloader->start();
}
const QString currentInstanceId = MMC->settings()->get("SelectedInstance").toString();
@ -274,7 +264,6 @@ MainWindow::~MainWindow()
delete ui;
delete proxymodel;
delete drawer;
delete assets_downloader;
}
void MainWindow::repopulateAccountsMenu()

View File

@ -31,7 +31,6 @@ class KCategorizedView;
class KCategoryDrawer;
class MinecraftProcess;
class ConsoleWindow;
class OneSixAssets;
namespace Ui
{
@ -173,7 +172,6 @@ private:
InstanceProxyModel *proxymodel;
MinecraftProcess *proc;
ConsoleWindow *console;
OneSixAssets *assets_downloader;
LabeledToolButton *renameButton;
QToolButton *changeIconButton;

View File

@ -266,7 +266,7 @@ void LegacyUpdate::jarStart()
urlstr += intended_version_id + "/" + intended_version_id + ".jar";
auto dljob = new NetJob("Minecraft.jar for version " + intended_version_id);
dljob->addNetAction(FileDownload::make(QUrl(urlstr), inst->defaultBaseJar()));
dljob->addNetAction(MD5EtagDownload::make(QUrl(urlstr), inst->defaultBaseJar()));
legacyDownloadJob.reset(dljob);
connect(dljob, SIGNAL(succeeded()), SLOT(jarFinished()));
connect(dljob, SIGNAL(failed()), SLOT(jarFailed()));

View File

@ -1,127 +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 <QString>
#include "logger/QsLog.h"
#include <QtXml/QtXml>
#include "OneSixAssets.h"
#include "net/NetJob.h"
#include "net/HttpMetaCache.h"
#include "net/S3ListBucket.h"
#include "MultiMC.h"
#define ASSETS_URL "http://resources.download.minecraft.net/"
class ThreadedDeleter : public QThread
{
Q_OBJECT
public:
void run()
{
QLOG_INFO() << "Cleaning up assets folder...";
QDirIterator iter(m_base, QDirIterator::Subdirectories);
int base_length = m_base.length();
while (iter.hasNext())
{
QString filename = iter.next();
QFileInfo current(filename);
// we keep the dirs... whatever
if (current.isDir())
continue;
QString trimmedf = filename;
trimmedf.remove(0, base_length + 1);
if (m_whitelist.contains(trimmedf))
{
QLOG_TRACE() << trimmedf << " gets to live";
}
else
{
// DO NOT TOLERATE JUNK
QLOG_TRACE() << trimmedf << " dies";
QFile f(filename);
f.remove();
}
}
}
QString m_base;
QStringList m_whitelist;
};
void OneSixAssets::downloadFinished()
{
deleter = new ThreadedDeleter();
QDir dir("assets");
deleter->m_base = dir.absolutePath();
deleter->m_whitelist = nuke_whitelist;
connect(deleter, SIGNAL(finished()), SIGNAL(finished()));
deleter->start();
}
void OneSixAssets::S3BucketFinished()
{
QString prefix(ASSETS_URL);
nuke_whitelist.clear();
emit filesStarted();
auto firstJob = index_job->first();
auto objectList = std::dynamic_pointer_cast<S3ListBucket>(firstJob)->objects;
NetJob *job = new NetJob("Assets");
connect(job, SIGNAL(succeeded()), SLOT(downloadFinished()));
connect(job, SIGNAL(failed()), SIGNAL(failed()));
connect(job, SIGNAL(filesProgress(int, int, int)), SIGNAL(filesProgress(int, int, int)));
auto metacache = MMC->metacache();
for (auto object : objectList)
{
// Filter folder keys (zero size)
if (object.size == 0)
continue;
nuke_whitelist.append(object.Key);
auto entry = metacache->resolveEntry("assets", object.Key, object.ETag);
if (entry->stale)
{
job->addNetAction(CacheDownload::make(QUrl(prefix + object.Key), entry));
}
}
if (job->size())
{
files_job.reset(job);
files_job->start();
}
else
{
delete job;
emit finished();
}
}
void OneSixAssets::start()
{
auto job = new NetJob("Assets index");
job->addNetAction(S3ListBucket::make(QUrl(ASSETS_URL)));
connect(job, SIGNAL(succeeded()), SLOT(S3BucketFinished()));
connect(job, SIGNAL(failed()), SIGNAL(failed()));
emit indexStarted();
index_job.reset(job);
job->start();
}
#include "OneSixAssets.moc"

View File

@ -1,45 +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 "net/NetJob.h"
class Private;
class ThreadedDeleter;
class OneSixAssets : public QObject
{
Q_OBJECT
signals:
void failed();
void finished();
void indexStarted();
void filesStarted();
void filesProgress(int, int, int);
public
slots:
void S3BucketFinished();
void downloadFinished();
public:
void start();
private:
ThreadedDeleter *deleter;
QStringList nuke_whitelist;
NetJobPtr index_job;
NetJobPtr files_job;
};

View File

@ -26,7 +26,6 @@
#include <JlCompress.h>
#include "gui/dialogs/OneSixModEditDialog.h"
#include "logger/QsLog.h"
#include "logic/assets/AssetsIndex.h"
#include "logic/assets/AssetsUtils.h"
OneSixInstance::OneSixInstance(const QString &rootDir, SettingsObject *setting_obj,
@ -96,9 +95,9 @@ QDir OneSixInstance::reconstructAssets(std::shared_ptr<OneSixVersion> version)
{
QLOG_INFO() << "Reconstructing virtual assets folder at" << virtualRoot.path();
for(QString map : index.objects->keys())
for(QString map : index.objects.keys())
{
AssetObject asset_object = index.objects->value(map);
AssetObject asset_object = index.objects.value(map);
QString target_path = PathCombine(virtualRoot.path(), map);
QFile target(target_path);

View File

@ -29,6 +29,7 @@
#include "OneSixLibrary.h"
#include "OneSixInstance.h"
#include "net/ForgeMirrors.h"
#include "assets/AssetsUtils.h"
#include "pathutils.h"
#include <JlCompress.h>
@ -50,7 +51,7 @@ void OneSixUpdate::executeTask()
return;
}
if(m_only_prepare)
if (m_only_prepare)
{
if (m_inst->shouldUpdate())
{
@ -93,7 +94,7 @@ void OneSixUpdate::checkJavaOnline()
checker.reset(new JavaChecker());
connect(checker.get(), SIGNAL(checkFinished(JavaCheckResult)), this,
SLOT(checkFinishedOnline(JavaCheckResult)));
SLOT(checkFinishedOnline(JavaCheckResult)));
checker->performCheck(java_path);
}
@ -193,6 +194,96 @@ void OneSixUpdate::versionFileFailed()
emitFailed("Failed to download the version description. Try again.");
}
void OneSixUpdate::assetIndexStart()
{
setStatus("Updating asset index.");
OneSixInstance *inst = (OneSixInstance *)m_inst;
std::shared_ptr<OneSixVersion> version = inst->getFullVersion();
QString assetName = version->assets;
QUrl indexUrl("https://s3.amazonaws.com/Minecraft.Download/indexes/" + assetName + ".json");
QString localPath = assetName + ".json";
auto job = new NetJob("Asset index for " + inst->name());
auto metacache = MMC->metacache();
auto entry = metacache->resolveEntry("asset_indexes", localPath);
job->addNetAction(CacheDownload::make(indexUrl, entry));
jarlibDownloadJob.reset(job);
connect(jarlibDownloadJob.get(), SIGNAL(succeeded()), SLOT(assetIndexFinished()));
connect(jarlibDownloadJob.get(), SIGNAL(failed()), SLOT(assetIndexFailed()));
connect(jarlibDownloadJob.get(), SIGNAL(progress(qint64, qint64)),
SIGNAL(progress(qint64, qint64)));
jarlibDownloadJob->start();
}
void OneSixUpdate::assetIndexFinished()
{
AssetsIndex index;
OneSixInstance *inst = (OneSixInstance *)m_inst;
std::shared_ptr<OneSixVersion> version = inst->getFullVersion();
QString assetName = version->assets;
QString asset_fname = "assets/indexes/" + assetName + ".json";
if (!AssetsUtils::loadAssetsIndexJson(asset_fname, &index))
{
emitFailed("Failed to read the assets index!");
}
QList<Md5EtagDownloadPtr> dls;
for (auto object : index.objects.values())
{
QString objectName = object.hash.left(2) + "/" + object.hash;
QFileInfo objectFile("assets/objects/" + objectName);
if ((!objectFile.isFile()) || (objectFile.size() != object.size))
{
auto objectDL = MD5EtagDownload::make(
QUrl("http://resources.download.minecraft.net/" + objectName),
objectFile.filePath());
dls.append(objectDL);
/*
Downloadable downloadable = new AssetDownloadable(
proxy, new URL("http://resources.download.minecraft.net/" + filename), file,
false, object.getHash(), object.getSize());
downloadable.setExpectedSize(object.getSize());
result.add(downloadable);
*/
}
}
if(dls.size())
{
auto job = new NetJob("Assets for " + inst->name());
for(auto dl: dls)
job->addNetAction(dl);
jarlibDownloadJob.reset(job);
connect(jarlibDownloadJob.get(), SIGNAL(succeeded()), SLOT(assetsFinished()));
connect(jarlibDownloadJob.get(), SIGNAL(failed()), SLOT(assetsFailed()));
connect(jarlibDownloadJob.get(), SIGNAL(progress(qint64, qint64)),
SIGNAL(progress(qint64, qint64)));
jarlibDownloadJob->start();
return;
}
assetsFinished();
}
void OneSixUpdate::assetIndexFailed()
{
emitFailed("Failed to download the assets index!");
}
void OneSixUpdate::assetsFinished()
{
prepareForLaunch();
}
void OneSixUpdate::assetsFailed()
{
emitFailed("Failed to download assets!");
}
void OneSixUpdate::jarlibStart()
{
setStatus("Getting the library files from Mojang.");
@ -215,7 +306,7 @@ void OneSixUpdate::jarlibStart()
targetstr += version->id + "/" + version->id + ".jar";
auto job = new NetJob("Libraries for instance " + inst->name());
job->addNetAction(FileDownload::make(QUrl(urlstr), targetstr));
job->addNetAction(MD5EtagDownload::make(QUrl(urlstr), targetstr));
jarlibDownloadJob.reset(job);
auto libs = version->getActiveNativeLibs();
@ -265,7 +356,7 @@ void OneSixUpdate::jarlibStart()
void OneSixUpdate::jarlibFinished()
{
prepareForLaunch();
assetIndexStart();
}
void OneSixUpdate::jarlibFailed()

View File

@ -43,6 +43,13 @@ slots:
void jarlibFinished();
void jarlibFailed();
void assetIndexStart();
void assetIndexFinished();
void assetIndexFailed();
void assetsFinished();
void assetsFailed();
void checkJavaOnline();
void checkFinishedOnline(JavaCheckResult result);
void checkFinishedOffline(JavaCheckResult result);

View File

@ -1,14 +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.
*/

View File

@ -1,16 +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

View File

@ -1,31 +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 "AssetsIndex.h"
AssetsIndex::AssetsIndex()
{
// TODO: leak?
this->objects = new QMap<QString, AssetObject>();
this->isVirtual = false;
}
AssetObject::AssetObject(QString hash, qint64 size) : hash(hash), size(size)
{
}
AssetObject::AssetObject()
{
}

View File

@ -1,42 +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 <QString>
#include <QMap>
class AssetObject;
class AssetsIndex
{
public:
QMap<QString, AssetObject> *objects;
bool isVirtual;
AssetsIndex();
};
class AssetObject
{
public:
AssetObject(QString hash, qint64 size);
AssetObject();
bool equals(AssetObject* other);
QString getHashCode();
QString hash;
qint64 size;
};

View File

@ -28,54 +28,64 @@ namespace AssetsUtils
void migrateOldAssets()
{
QDir assets_dir("assets");
if(!assets_dir.exists()) return;
if (!assets_dir.exists())
return;
assets_dir.setFilter(QDir::AllEntries | QDir::NoDotAndDotDot);
int base_length = assets_dir.path().length();
QList<QString> blacklist = {"indexes", "objects", "virtual"};
if(!assets_dir.exists("objects")) assets_dir.mkdir("objects");
if (!assets_dir.exists("objects"))
assets_dir.mkdir("objects");
QDir objects_dir("assets/objects");
QDirIterator iterator(assets_dir, QDirIterator::Subdirectories);
int successes = 0;
int failures = 0;
while (iterator.hasNext()) {
while (iterator.hasNext())
{
QString currentDir = iterator.next();
currentDir = currentDir.remove(0, base_length+1);
currentDir = currentDir.remove(0, base_length + 1);
bool ignore = false;
for(QString blacklisted : blacklist)
for (QString blacklisted : blacklist)
{
if(currentDir.startsWith(blacklisted)) ignore = true;
if (currentDir.startsWith(blacklisted))
ignore = true;
}
if (!iterator.fileInfo().isDir() && !ignore) {
if (!iterator.fileInfo().isDir() && !ignore)
{
QString filename = iterator.filePath();
QFile input(filename);
input.open(QIODevice::ReadOnly | QIODevice::WriteOnly);
QString sha1sum = QCryptographicHash::hash(input.readAll(), QCryptographicHash::Sha1)
.toHex()
.constData();
QString sha1sum =
QCryptographicHash::hash(input.readAll(), QCryptographicHash::Sha1)
.toHex()
.constData();
QString object_name = filename.remove(0, base_length+1);
QString object_name = filename.remove(0, base_length + 1);
QLOG_DEBUG() << "Processing" << object_name << ":" << sha1sum << input.size();
QString object_tlk = sha1sum.left(2);
QString object_tlk_dir = objects_dir.path() + "/" + object_tlk;
QDir tlk_dir(object_tlk_dir);
if(!tlk_dir.exists()) objects_dir.mkdir(object_tlk);
if (!tlk_dir.exists())
objects_dir.mkdir(object_tlk);
QString new_filename = tlk_dir.path() + "/" + sha1sum;
QFile new_object(new_filename);
if(!new_object.exists())
if (!new_object.exists())
{
bool rename_success = input.rename(new_filename);
QLOG_DEBUG() << " Doesn't exist, copying to" << new_filename << ":" << QString::number(rename_success);
if(rename_success) successes++;
else failures++;
QLOG_DEBUG() << " Doesn't exist, copying to" << new_filename << ":"
<< QString::number(rename_success);
if (rename_success)
successes++;
else
failures++;
}
else
{
@ -85,26 +95,31 @@ void migrateOldAssets()
}
}
if(successes + failures == 0) {
if (successes + failures == 0)
{
QLOG_DEBUG() << "No legacy assets needed importing.";
}
else
{
QLOG_DEBUG() << "Finished copying legacy assets:" << successes << "successes and" << failures << "failures.";
QLOG_DEBUG() << "Finished copying legacy assets:" << successes << "successes and"
<< failures << "failures.";
QDirIterator cleanup_iterator(assets_dir);
while (cleanup_iterator.hasNext()) {
while (cleanup_iterator.hasNext())
{
QString currentDir = cleanup_iterator.next();
currentDir = currentDir.remove(0, base_length+1);
currentDir = currentDir.remove(0, base_length + 1);
bool ignore = false;
for(QString blacklisted : blacklist)
for (QString blacklisted : blacklist)
{
if(currentDir.startsWith(blacklisted)) ignore = true;
if (currentDir.startsWith(blacklisted))
ignore = true;
}
if (cleanup_iterator.fileInfo().isDir() && !ignore) {
if (cleanup_iterator.fileInfo().isDir() && !ignore)
{
QString path = cleanup_iterator.filePath();
QDir folder(path);
@ -122,18 +137,18 @@ void migrateOldAssets()
*/
bool loadAssetsIndexJson(QString path, AssetsIndex *index)
{
/*
{
"objects": {
"icons/icon_16x16.png": {
"hash": "bdf48ef6b5d0d23bbb02e17d04865216179f510a",
"size": 3665
},
...
/*
{
"objects": {
"icons/icon_16x16.png": {
"hash": "bdf48ef6b5d0d23bbb02e17d04865216179f510a",
"size": 3665
},
...
}
}
}
}
}
*/
*/
QFile file(path);
@ -155,7 +170,8 @@ bool loadAssetsIndexJson(QString path, AssetsIndex *index)
// Fail if the JSON is invalid.
if (parseError.error != QJsonParseError::NoError)
{
QLOG_ERROR() << "Failed to parse assets index file:" << parseError.errorString() << "at offset " << QString::number(parseError.offset);
QLOG_ERROR() << "Failed to parse assets index file:" << parseError.errorString()
<< "at offset " << QString::number(parseError.offset);
return false;
}
@ -169,7 +185,7 @@ bool loadAssetsIndexJson(QString path, AssetsIndex *index)
QJsonObject root = jsonDoc.object();
QJsonValue isVirtual = root.value("virtual");
if(!isVirtual.isUndefined())
if (!isVirtual.isUndefined())
{
index->isVirtual = isVirtual.toBool(false);
}
@ -177,48 +193,35 @@ bool loadAssetsIndexJson(QString path, AssetsIndex *index)
QJsonValue objects = root.value("objects");
QVariantMap map = objects.toVariant().toMap();
for(QVariantMap::const_iterator iter = map.begin(); iter != map.end(); ++iter) {
//QLOG_DEBUG() << iter.key();
for (QVariantMap::const_iterator iter = map.begin(); iter != map.end(); ++iter)
{
// QLOG_DEBUG() << iter.key();
QVariant variant = iter.value();
QVariantMap nested_objects = variant.toMap();
AssetObject object;
for(QVariantMap::const_iterator nested_iter = nested_objects.begin(); nested_iter != nested_objects.end(); ++nested_iter) {
//QLOG_DEBUG() << nested_iter.key() << nested_iter.value().toString();
for (QVariantMap::const_iterator nested_iter = nested_objects.begin();
nested_iter != nested_objects.end(); ++nested_iter)
{
// QLOG_DEBUG() << nested_iter.key() << nested_iter.value().toString();
QString key = nested_iter.key();
QVariant value = nested_iter.value();
if(key == "hash")
if (key == "hash")
{
object.hash = value.toString();
}
else if(key == "size")
else if (key == "size")
{
object.size = value.toDouble();
}
}
index->objects->insert(iter.key(), object);
index->objects.insert(iter.key(), object);
}
return true;
/*for (QJsonValue accountVal : objects)
{
QJsonObject accountObj = accountVal.toObject();
MojangAccountPtr account = MojangAccount::loadFromJson(accountObj);
if (account.get() != nullptr)
{
connect(account.get(), SIGNAL(changed()), SLOT(accountChanged()));
m_accounts.append(account);
}
else
{
QLOG_WARN() << "Failed to load an account.";
}
}*/
//return false;
}
}

View File

@ -15,7 +15,22 @@
#pragma once
#include "AssetsIndex.h"
#include <QString>
#include <QMap>
class AssetObject;
struct AssetObject
{
QString hash;
qint64 size;
};
struct AssetsIndex
{
QMap<QString, AssetObject> objects;
bool isVirtual = false;
};
namespace AssetsUtils
{

View File

@ -14,12 +14,12 @@
*/
#include "MultiMC.h"
#include "FileDownload.h"
#include "MD5EtagDownload.h"
#include <pathutils.h>
#include <QCryptographicHash>
#include "logger/QsLog.h"
FileDownload::FileDownload(QUrl url, QString target_path) : NetAction()
MD5EtagDownload::MD5EtagDownload(QUrl url, QString target_path) : NetAction()
{
m_url = url;
m_target_path = target_path;
@ -27,7 +27,7 @@ FileDownload::FileDownload(QUrl url, QString target_path) : NetAction()
m_status = Job_NotStarted;
}
void FileDownload::start()
void MD5EtagDownload::start()
{
QString filename = m_target_path;
m_output_file.setFileName(filename);
@ -58,7 +58,7 @@ void FileDownload::start()
return;
}
QLOG_INFO() << "Downloading " << m_url.toString();
QLOG_INFO() << "Downloading " << m_url.toString() << " expecting " << m_expected_md5;
QNetworkRequest request(m_url);
request.setRawHeader(QString("If-None-Match").toLatin1(), m_expected_md5.toLatin1());
request.setHeader(QNetworkRequest::UserAgentHeader, "MultiMC/5.0 (Uncached)");
@ -75,19 +75,19 @@ void FileDownload::start()
connect(rep, SIGNAL(readyRead()), SLOT(downloadReadyRead()));
}
void FileDownload::downloadProgress(qint64 bytesReceived, qint64 bytesTotal)
void MD5EtagDownload::downloadProgress(qint64 bytesReceived, qint64 bytesTotal)
{
emit progress(index_within_job, bytesReceived, bytesTotal);
}
void FileDownload::downloadError(QNetworkReply::NetworkError error)
void MD5EtagDownload::downloadError(QNetworkReply::NetworkError error)
{
// error happened during download.
// TODO: log the reason why
m_status = Job_Failed;
}
void FileDownload::downloadFinished()
void MD5EtagDownload::downloadFinished()
{
// if the download succeeded
if (m_status != Job_Failed)
@ -96,6 +96,7 @@ void FileDownload::downloadFinished()
m_status = Job_Finished;
m_output_file.close();
QLOG_INFO() << "Finished " << m_url.toString() << " got " << m_reply->rawHeader("ETag").constData();
m_reply.reset();
emit succeeded(index_within_job);
return;
@ -110,7 +111,7 @@ void FileDownload::downloadFinished()
}
}
void FileDownload::downloadReadyRead()
void MD5EtagDownload::downloadReadyRead()
{
if (!m_output_file.isOpen())
{

View File

@ -18,8 +18,8 @@
#include "NetAction.h"
#include <QFile>
typedef std::shared_ptr<class FileDownload> FileDownloadPtr;
class FileDownload : public NetAction
typedef std::shared_ptr<class MD5EtagDownload> Md5EtagDownloadPtr;
class MD5EtagDownload : public NetAction
{
Q_OBJECT
public:
@ -35,10 +35,10 @@ public:
QFile m_output_file;
public:
explicit FileDownload(QUrl url, QString target_path);
static FileDownloadPtr make(QUrl url, QString target_path)
explicit MD5EtagDownload(QUrl url, QString target_path);
static Md5EtagDownloadPtr make(QUrl url, QString target_path)
{
return FileDownloadPtr(new FileDownload(url, target_path));
return Md5EtagDownloadPtr(new MD5EtagDownload(url, target_path));
}
protected
slots:

View File

@ -16,7 +16,7 @@
#include "NetJob.h"
#include "pathutils.h"
#include "MultiMC.h"
#include "FileDownload.h"
#include "MD5EtagDownload.h"
#include "ByteArrayDownload.h"
#include "CacheDownload.h"

View File

@ -18,7 +18,7 @@
#include <QLabel>
#include "NetAction.h"
#include "ByteArrayDownload.h"
#include "FileDownload.h"
#include "MD5EtagDownload.h"
#include "CacheDownload.h"
#include "HttpMetaCache.h"
#include "ForgeXzDownload.h"