patchdownloader.cpp 5.8 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157
  1. #include "models/patchdownloader.h"
  2. #include "models/settings.h"
  3. #include "models/filesystem.h"
  4. #include <QUrlQuery>
  5. void PatchDownloader::init() {
  6. for (const QString& patch: patches_) {
  7. Downloader* patch_downloader = new Downloader(this);
  8. patch_downloaders_[patch] = patch_downloader;
  9. patch_downloaders_status_[patch_downloader] = Downloader::Status();
  10. QObject::connect(patch_downloader, &Downloader::progressChanged, this, &PatchDownloader::onDownloaderProgressChanged);
  11. QObject::connect(patch_downloader, &Downloader::downloadFinished, this, &PatchDownloader::onDownloaderFinished);
  12. }
  13. }
  14. PatchDownloader::~PatchDownloader()
  15. {
  16. for (const QString& patch: patches_) {
  17. patch_downloaders_[patch]->deleteLater();
  18. }
  19. }
  20. PatchDownloader::PatchDownloader() {
  21. // Does nothing
  22. }
  23. void PatchDownloader::startPatchDownloaderChain() {
  24. if (started_) {
  25. qCritical() << "PatchDwnlder: Tried to start patch downloader chain while other was already running!";
  26. }
  27. started_ = true;
  28. emit started();
  29. checkForUpdates();
  30. beginDownload();
  31. // Finished signal will be emitted when all downloads are completed.
  32. // Note, this function finishes immediately after downloads are STARTED!
  33. }
  34. void PatchDownloader::onDownloaderProgressChanged(Downloader* context, Downloader::Status progress) {
  35. patch_downloaders_status_[context] = progress;
  36. Downloader::Status cumulative_status;
  37. for (const Downloader::Status& status: patch_downloaders_status_.values()) {
  38. cumulative_status = cumulative_status + status;
  39. }
  40. emit progressChanged(cumulative_status);
  41. }
  42. void PatchDownloader::onDownloaderFinished(Downloader* context) {
  43. context->targetFile->close();
  44. context->targetFile->deleteLater();
  45. context->targetFile = nullptr;
  46. Settings::setValue("DatabaseNeedInstall/" + patch_downloaders_.key(context), true);
  47. patch_downloaders_status_[context] = context->getDownloadStatus();
  48. Downloader::Status cumulative_status;
  49. for (const Downloader::Status& status: patch_downloaders_status_.values()) {
  50. cumulative_status = cumulative_status + status;
  51. }
  52. if (!cumulative_status.running) {
  53. started_ = false;
  54. emit finished();
  55. }
  56. }
  57. void PatchDownloader::checkForUpdates() {
  58. qDebug() << __FUNCTION__ << "Started check for updates!";
  59. QUrlQuery query; // query for building GET-request aka patch-version
  60. for (const QString& patch: patches_) {
  61. query.addQueryItem(patch, "100");
  62. }
  63. QUrl target_url;
  64. target_url.setUrl(Settings::getValue("Network/patch_updates_url").toString());
  65. target_url.setQuery(query);
  66. QByteArray target_array;
  67. Downloader downloader;
  68. downloader.setUrl(target_url);
  69. downloader.targetBytearray = &target_array;
  70. downloader.start();
  71. downloader.waitForDownloaded();
  72. if (target_array.isEmpty()) {
  73. qWarning() << __FUNCTION__ << "Cannot check for updates, target_array is empty!";
  74. return;
  75. }
  76. qDebug() << __FUNCTION__ << "Check for updates result: " << target_array;
  77. QStringList patch_info = QString(target_array).split('|');
  78. if (patch_info.size() != patches_.size()) {
  79. qCritical() << __FUNCTION__ << "Incorrect patches number! Data: " << patch_info;
  80. return;
  81. }
  82. for (int i = 0; i < patches_.size(); ++i) {
  83. const QString patch = patches_[i];
  84. const QStringList patch_data = patch_info[i].split(":::");
  85. if (patch_data.size() != 3) {
  86. qCritical() << __FUNCTION__ << "Incorrect patch entry size! Entry: " << patch_data;
  87. return;
  88. }
  89. QString patch_filename = Settings::getValue("General/PatchDownloadDir").toString() + "/" + patch + ".db";
  90. Settings::setValue("PatchDatabases/" + patch + "/url", patch_data[0]);
  91. Settings::setValue("PatchDatabases/" + patch + "/hashsum", patch_data[1]);
  92. Settings::setValue("PatchDatabases/" + patch + "/datetime", patch_data[2]);
  93. Settings::setValue("PatchDatabases/" + patch + "/path", patch_filename);
  94. }
  95. }
  96. void PatchDownloader::beginDownload() {
  97. bool downloads_started = false;
  98. for (const QString& patch: patches_) {
  99. QString target_filename = Settings::getValue("PatchDatabases/" + patch + "/path").toString();
  100. qDebug() << __FUNCTION__ << patch << ": Checking if there's need to download patch";
  101. if (!needDownloadDatabase(patch)) {
  102. qInfo() << patch << ": file " << target_filename << " is up-to-date, no need to download";
  103. continue;
  104. }
  105. FileSystem::createFilePath(target_filename);
  106. QFile* target_file = new QFile(target_filename);
  107. if (!target_file->open(QIODevice::ReadWrite | QIODevice::Truncate)) {
  108. qWarning() << __FUNCTION__ << patch << "Cannot open file " << target_filename;
  109. continue;
  110. }
  111. qInfo() << __FUNCTION__ << patch << ": beginning download of file " << target_filename;
  112. patch_downloaders_[patch]->setUrl(Settings::getValue("PatchDatabases/" + patch + "/url").toUrl());
  113. patch_downloaders_[patch]->targetFile = target_file;
  114. patch_downloaders_[patch]->start();
  115. downloads_started = true;
  116. }
  117. if (!downloads_started) {
  118. started_ = false;
  119. emit finished();
  120. }
  121. }
  122. bool PatchDownloader::needDownloadDatabase(QString db_name)
  123. {
  124. QString patch_filename = Settings::getValue("PatchDatabases/" + db_name + "/path").toString();
  125. QString current_file_hash = FileSystem::fileHash(patch_filename);
  126. QString required_file_hash = Settings::getValue("PatchDatabases/" + db_name + "/hashsum").toString();
  127. return Settings::getValue("DatabaseDownload/" + db_name).toBool() && (current_file_hash != required_file_hash);
  128. }