#include "models/patchdownloader.h" #include "models/settings.h" #include "models/filesystem.h" #include void PatchDownloader::init() { for (const QString& patch: patches_) { Downloader* patch_downloader = new Downloader(this); patch_downloaders_[patch] = patch_downloader; patch_downloaders_status_[patch_downloader] = Downloader::Status(); QObject::connect(patch_downloader, &Downloader::progressChanged, this, &PatchDownloader::onDownloaderProgressChanged); QObject::connect(patch_downloader, &Downloader::downloadFinished, this, &PatchDownloader::onDownloaderFinished); } } PatchDownloader::~PatchDownloader() { for (const QString& patch: patches_) { patch_downloaders_[patch]->deleteLater(); } } PatchDownloader::PatchDownloader() { // Does nothing } void PatchDownloader::startPatchDownloaderChain() { if (started_) { qCritical() << "PatchDwnlder: Tried to start patch downloader chain while other was already running!"; } started_ = true; emit started(); checkForUpdates(); beginDownload(); // Finished signal will be emitted when all downloads are completed. // Note, this function finishes immediately after downloads are STARTED! } void PatchDownloader::onDownloaderProgressChanged(Downloader* context, Downloader::Status progress) { patch_downloaders_status_[context] = progress; Downloader::Status cumulative_status; for (const Downloader::Status& status: patch_downloaders_status_.values()) { cumulative_status = cumulative_status + status; } emit progressChanged(cumulative_status); } void PatchDownloader::onDownloaderFinished(Downloader* context) { context->targetFile->close(); context->targetFile->deleteLater(); context->targetFile = nullptr; Settings::setValue("DatabaseNeedInstall/" + patch_downloaders_.key(context), true); patch_downloaders_status_[context] = context->getDownloadStatus(); Downloader::Status cumulative_status; for (const Downloader::Status& status: patch_downloaders_status_.values()) { cumulative_status = cumulative_status + status; } if (!cumulative_status.running) { started_ = false; emit finished(); } } void PatchDownloader::checkForUpdates() { qDebug() << __FUNCTION__ << "Started check for updates!"; QUrlQuery query; // query for building GET-request aka patch-version for (const QString& patch: patches_) { query.addQueryItem(patch, "100"); } QUrl target_url; target_url.setUrl(Settings::getValue("Network/patch_updates_url").toString()); target_url.setQuery(query); QByteArray target_array; Downloader downloader; downloader.setUrl(target_url); downloader.targetBytearray = &target_array; downloader.start(); downloader.waitForDownloaded(); if (target_array.isEmpty()) { qWarning() << __FUNCTION__ << "Cannot check for updates, target_array is empty!"; return; } qDebug() << __FUNCTION__ << "Check for updates result: " << target_array; QStringList patch_info = QString(target_array).split('|'); if (patch_info.size() != patches_.size()) { qCritical() << __FUNCTION__ << "Incorrect patches number! Data: " << patch_info; return; } for (int i = 0; i < patches_.size(); ++i) { const QString patch = patches_[i]; const QStringList patch_data = patch_info[i].split(":::"); if (patch_data.size() != 3) { qCritical() << __FUNCTION__ << "Incorrect patch entry size! Entry: " << patch_data; return; } QString patch_filename = Settings::getValue("General/PatchDownloadDir").toString() + "/" + patch + ".db"; Settings::setValue("PatchDatabases/" + patch + "/url", patch_data[0]); Settings::setValue("PatchDatabases/" + patch + "/hashsum", patch_data[1]); Settings::setValue("PatchDatabases/" + patch + "/datetime", patch_data[2]); Settings::setValue("PatchDatabases/" + patch + "/path", patch_filename); } } void PatchDownloader::beginDownload() { bool downloads_started = false; for (const QString& patch: patches_) { QString target_filename = Settings::getValue("PatchDatabases/" + patch + "/path").toString(); qDebug() << __FUNCTION__ << patch << ": Checking if there's need to download patch"; if (!needDownloadDatabase(patch)) { qInfo() << patch << ": file " << target_filename << " is up-to-date, no need to download"; continue; } FileSystem::createFilePath(target_filename); QFile* target_file = new QFile(target_filename); if (!target_file->open(QIODevice::ReadWrite | QIODevice::Truncate)) { qWarning() << __FUNCTION__ << patch << "Cannot open file " << target_filename; continue; } qInfo() << __FUNCTION__ << patch << ": beginning download of file " << target_filename; patch_downloaders_[patch]->setUrl(Settings::getValue("PatchDatabases/" + patch + "/url").toUrl()); patch_downloaders_[patch]->targetFile = target_file; patch_downloaders_[patch]->start(); downloads_started = true; } if (!downloads_started) { started_ = false; emit finished(); } } bool PatchDownloader::needDownloadDatabase(QString db_name) { QString patch_filename = Settings::getValue("PatchDatabases/" + db_name + "/path").toString(); QString current_file_hash = FileSystem::fileHash(patch_filename); QString required_file_hash = Settings::getValue("PatchDatabases/" + db_name + "/hashsum").toString(); return Settings::getValue("DatabaseDownload/" + db_name).toBool() && (current_file_hash != required_file_hash); }