diff options
Diffstat (limited to 'launcher/modplatform/flame/FlameCheckUpdate.cpp')
-rw-r--r-- | launcher/modplatform/flame/FlameCheckUpdate.cpp | 209 |
1 files changed, 82 insertions, 127 deletions
diff --git a/launcher/modplatform/flame/FlameCheckUpdate.cpp b/launcher/modplatform/flame/FlameCheckUpdate.cpp index 12d99029..3658bf8d 100644 --- a/launcher/modplatform/flame/FlameCheckUpdate.cpp +++ b/launcher/modplatform/flame/FlameCheckUpdate.cpp @@ -10,7 +10,6 @@ #include "ModDownloadTask.h" static FlameAPI api; -static ModPlatform::ProviderCapabilities ProviderCaps; bool FlameCheckUpdate::abort() { @@ -64,156 +63,112 @@ ModPlatform::IndexedPack getProjectInfo(ModPlatform::IndexedVersion& ver_info) return pack; } -/* Check for update: - * - Get latest version available - * - Compare hash of the latest version with the current hash - * - If equal, no updates, else, there's updates, so add to the list - * */ -void FlameCheckUpdate::executeTask() +ModPlatform::IndexedVersion getFileInfo(int addonId, int fileId) { - setStatus(tr("Preparing mods for CurseForge...")); - setProgress(0, 5); - - QHash<int, Mod> mappings; + ModPlatform::IndexedVersion ver; - // Create all hashes - std::list<uint> murmur_hashes; + QEventLoop loop; - auto best_hash_type = ProviderCaps.hashType(ModPlatform::Provider::FLAME).first(); - for (auto mod : m_mods) { - QByteArray jar_data; + auto get_file_info_job = new NetJob("Flame::GetFileInfoJob", APPLICATION->network()); - try { - jar_data = FS::read(mod.fileinfo().absoluteFilePath()); - } catch (FS::FileSystemException& e) { - qCritical() << QString("Failed to open / read JAR file of %1").arg(mod.name()); - qCritical() << QString("Reason: ") << e.cause(); + auto response = new QByteArray(); + auto url = QString("https://api.curseforge.com/v1/mods/%1/files/%2").arg(QString::number(addonId), QString::number(fileId)); + auto dl = Net::Download::makeByteArray(url, response); + get_file_info_job->addNetAction(dl); - failed(e.what()); + QObject::connect(get_file_info_job, &NetJob::succeeded, [response, &ver]() { + QJsonParseError parse_error{}; + QJsonDocument doc = QJsonDocument::fromJson(*response, &parse_error); + if (parse_error.error != QJsonParseError::NoError) { + qWarning() << "Error while parsing JSON response from FlameCheckUpdate at " << parse_error.offset + << " reason: " << parse_error.errorString(); + qWarning() << *response; return; } - QByteArray jar_data_treated; - for (char c : jar_data) { - // CF-specific - if (!(c == 9 || c == 10 || c == 13 || c == 32)) - jar_data_treated.push_back(c); + try { + auto doc_obj = Json::requireObject(doc); + auto data_obj = Json::requireObject(doc_obj, "data"); + ver = FlameMod::loadIndexedPackVersion(data_obj); + } catch (Json::JsonException& e) { + qWarning() << e.cause(); + qDebug() << doc; } + }); - auto murmur_hash = MurmurHash2(jar_data_treated, jar_data_treated.length()); - murmur_hashes.emplace_back(murmur_hash); + QObject::connect(get_file_info_job, &NetJob::finished, [&loop, get_file_info_job] { + get_file_info_job->deleteLater(); + loop.quit(); + }); - mappings.insert(mod.metadata()->mod_id().toInt(), mod); - } + get_file_info_job->start(); + loop.exec(); - auto* response = new QByteArray(); - auto job = api.matchFingerprints(murmur_hashes, response); + return ver; +} - QEventLoop lock; +/* Check for update: + * - Get latest version available + * - Compare hash of the latest version with the current hash + * - If equal, no updates, else, there's updates, so add to the list + * */ +void FlameCheckUpdate::executeTask() +{ + setStatus(tr("Preparing mods for CurseForge...")); - connect(job.get(), &Task::succeeded, this, [this, response, &mappings] { - QJsonParseError parse_error{}; - QJsonDocument doc = QJsonDocument::fromJson(*response, &parse_error); - if (parse_error.error != QJsonParseError::NoError) { - qWarning() << "Error while parsing JSON response from FlameCheckUpdate at " << parse_error.offset - << " reason: " << parse_error.errorString(); - qWarning() << *response; + int i = 0; + for (auto mod : m_mods) { + setStatus(tr("Getting API response from CurseForge for '%1'").arg(mod.name())); + setProgress(i++, m_mods.size()); + + auto latest_ver = api.getLatestVersion({ mod.metadata()->project_id.toString(), m_game_versions, m_loaders }); - failed(parse_error.errorString()); + // Check if we were aborted while getting the latest version + if (m_was_aborted) { + aborted(); return; } - setStatus(tr("Parsing the first API response from CurseForge...")); - setProgress(2, 5); - - try { - auto doc_obj = Json::requireObject(doc); - auto data_obj = Json::ensureObject(doc_obj, "data"); - auto match_arr = Json::ensureArray(data_obj, "exactMatches"); - for (auto match : match_arr) { - auto match_obj = Json::ensureObject(match); - - ModPlatform::IndexedVersion current_ver; - try { - auto file_obj = Json::requireObject(match_obj, "file"); - current_ver = FlameMod::loadIndexedPackVersion(file_obj); - } catch (Json::JsonException& e) { - qCritical() << "Error while parsing Flame indexed version"; - qCritical() << e.what(); - failed(tr("An error occured while parsing a CurseForge indexed version!")); - return; - } - - auto mod_iter = mappings.find(current_ver.addonId.toInt()); - if (mod_iter == mappings.end()) { - qCritical() << "Failed to remap mod from Flame!"; - qDebug() << match_obj; - continue; - } - - auto mod = mod_iter.value(); - - setStatus(tr("Waiting for the API response from CurseForge for '%1'...").arg(mod.name())); - setProgress(3, 5); - - auto latest_ver = api.getLatestVersion({ current_ver.addonId.toString(), m_game_versions, m_loaders }); - - // Check if we were aborted while getting the latest version - if (m_was_aborted) { - aborted(); - return; - } - - setStatus(tr("Parsing the API response from CurseForge for '%1'...").arg(mod.name())); - setProgress(4, 5); - - if (!latest_ver.addonId.isValid()) { - emit checkFailed( - mod, - tr("No valid version found for this mod. It's probably unavailable for the current game version / mod loader.")); - continue; - } - - if (latest_ver.downloadUrl.isEmpty() && latest_ver.fileId != current_ver.fileId) { - auto pack = getProjectInfo(latest_ver); - auto recover_url = QString("%1/download/%2").arg(pack.websiteUrl, latest_ver.fileId.toString()); - emit checkFailed(mod, tr("Mod has a new update available, but is opted-out on CurseForge"), recover_url); - - continue; - } - - if (!latest_ver.hash.isEmpty() && (current_ver.hash != latest_ver.hash || mod.status() == ModStatus::NotInstalled)) { - // Fake pack with the necessary info to pass to the download task :) - ModPlatform::IndexedPack pack; - pack.name = mod.name(); - pack.addonId = mod.metadata()->project_id; - pack.websiteUrl = mod.homeurl(); - for (auto& author : mod.authors()) - pack.authors.append({ author }); - pack.description = mod.description(); - pack.provider = ModPlatform::Provider::FLAME; - - auto download_task = new ModDownloadTask(pack, latest_ver, m_mods_folder); - m_updatable.emplace_back(mod.name(), current_ver.hash, current_ver.version, latest_ver.version, - api.getModFileChangelog(latest_ver.addonId.toInt(), latest_ver.fileId.toInt()), - ModPlatform::Provider::FLAME, download_task); - } - } + setStatus(tr("Parsing the API response from CurseForge for '%1'...").arg(mod.name())); - } catch (Json::JsonException& e) { - failed(e.cause() + " : " + e.what()); + if (!latest_ver.addonId.isValid()) { + emit checkFailed(mod, tr("No valid version found for this mod. It's probably unavailable for the current game " + "version / mod loader.")); + continue; } - }); - connect(job.get(), &Task::finished, &lock, &QEventLoop::quit); + if (latest_ver.downloadUrl.isEmpty() && latest_ver.fileId != mod.metadata()->file_id) { + auto pack = getProjectInfo(latest_ver); + auto recover_url = QString("%1/download/%2").arg(pack.websiteUrl, latest_ver.fileId.toString()); + emit checkFailed(mod, tr("Mod has a new update available, but is opted-out on CurseForge"), recover_url); - setStatus(tr("Waiting for the first API response from CurseForge...")); - setProgress(1, 5); + continue; + } - m_net_job = job.get(); - job->start(); + if (!latest_ver.hash.isEmpty() && (mod.metadata()->hash != latest_ver.hash || mod.status() == ModStatus::NotInstalled)) { + // Fake pack with the necessary info to pass to the download task :) + ModPlatform::IndexedPack pack; + pack.name = mod.name(); + pack.slug = mod.metadata()->slug; + pack.addonId = mod.metadata()->project_id; + pack.websiteUrl = mod.homeurl(); + for (auto& author : mod.authors()) + pack.authors.append({ author }); + pack.description = mod.description(); + pack.provider = ModPlatform::Provider::FLAME; + + auto old_version = mod.version(); + if (old_version.isEmpty() && mod.status() != ModStatus::NotInstalled) { + auto current_ver = getFileInfo(latest_ver.addonId.toInt(), mod.metadata()->file_id.toInt()); + old_version = current_ver.version; + } - lock.exec(); + auto download_task = new ModDownloadTask(pack, latest_ver, m_mods_folder); + m_updatable.emplace_back(mod.name(), mod.metadata()->hash, old_version, latest_ver.version, + api.getModFileChangelog(latest_ver.addonId.toInt(), latest_ver.fileId.toInt()), + ModPlatform::Provider::FLAME, download_task); + } + } emitSucceeded(); } |