patchdownloader.cpp 7.0 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210
  1. #include "patchdownloader.h"
  2. #include "models/filesystem.h"
  3. #include <QApplication>
  4. #include <QDir>
  5. #include <QStringList>
  6. #include <QUrlQuery>
  7. #include <QVariant>
  8. #include <QDebug>
  9. PatchDownloader::PatchDownloader(QSettings *settings, QObject *parent) : QObject(parent), patch_download_dir(QApplication::applicationDirPath() + "/data")
  10. {
  11. app_settings = settings;
  12. active_downloads_number = 0;
  13. connect(&update_check_timer, &QTimer::timeout, this, &PatchDownloader::checkForUpdates);
  14. update_check_timer.setInterval(1000 * 60 * 5); // 5 minutes
  15. update_check_timer.start();
  16. }
  17. PatchDownloader::~PatchDownloader()
  18. {
  19. foreach (Downloader* downloader, downloads_list) {
  20. downloader->waitForDownloaded();
  21. downloader->deleteLater();
  22. }
  23. }
  24. void PatchDownloader::checkForUpdates()
  25. {
  26. foreach (QString patch_name, all_patch_names) {
  27. if (downloads_list.contains(patch_name))
  28. continue;
  29. downloads_list[patch_name] = new Downloader();
  30. connect(downloads_list[patch_name], &Downloader::progressChanged, this, &PatchDownloader::onDownloaderProgressChanged);
  31. connect(downloads_list[patch_name], &Downloader::downloadFinished, this, &PatchDownloader::onDownloaderCompleted);
  32. }
  33. if (active_downloads_number > 0) {
  34. qDebug() << "PatchDownloader: downloads are not ready yet, passing checkForUpdates";
  35. return;
  36. }
  37. emit checkForUpdatesStarted();
  38. if (!updatePatchList()) {
  39. emit checkForUpdatesFinished();
  40. return;
  41. }
  42. removeOldPatchesFromDirecrory();
  43. addMissingPatchesToDownloadList();
  44. emit checkForUpdatesFinished();
  45. }
  46. void PatchDownloader::onDownloaderCompleted(Downloader *downloader_ptr)
  47. {
  48. if (downloader_ptr->targetFile) {
  49. downloader_ptr->targetFile->close();
  50. downloader_ptr->targetFile->deleteLater();
  51. }
  52. active_downloads_number--;
  53. if (active_downloads_number == 0) {
  54. emit downloadCompleted();
  55. }
  56. }
  57. void PatchDownloader::onDownloaderProgressChanged(Downloader*)
  58. {
  59. quint64 totalSize = 0;
  60. quint64 downloadedSize = 0;
  61. quint64 summary_speed = 0;
  62. quint64 time_elapsed = 0;
  63. foreach (Downloader* downloader, downloads_list) {
  64. totalSize += downloader->getBytesTotal();
  65. downloadedSize += downloader->getBytesDownloaded();
  66. if (downloader->getBytesTotal() != downloader->getBytesDownloaded()) {
  67. summary_speed += downloader->getSpeed();
  68. }
  69. }
  70. time_elapsed = (totalSize - downloadedSize) / qMax(quint64(1), summary_speed);
  71. emit progressChanged(downloadedSize, totalSize,
  72. Downloader::getSpeedFormatted(summary_speed),
  73. Downloader::getElapsedTimeFormatted(time_elapsed));
  74. }
  75. int PatchDownloader::versionFromPatchFilename(QString filename)
  76. {
  77. int version = 0;
  78. for (int i = filename.indexOf("_v") + 2; i < filename.indexOf("_v") + 7; i += 2) {
  79. version = version * 10 + (filename.at(i).toLatin1() - '0');
  80. }
  81. return version;
  82. }
  83. bool PatchDownloader::updatePatchList()
  84. {
  85. QUrlQuery query; // query for building GET-request aka patch-version
  86. foreach (QString patch_name, all_patch_names) {
  87. query.addQueryItem(patch_name, "100");
  88. }
  89. QUrl target_url;
  90. target_url.setUrl("http://translate.lotros.ru/groupware/check_updates");
  91. target_url.setQuery(query);
  92. QByteArray target_array;
  93. Downloader downloader;
  94. downloader.setUrl(target_url);
  95. downloader.targetBytearray = &target_array;
  96. downloader.start();
  97. downloader.waitForDownloaded();
  98. if (target_array.isEmpty()) {
  99. qDebug() << __FUNCTION__ << "Cannot download, target_array is empty!";
  100. emit getPatchListError();
  101. return false;
  102. }
  103. QStringList entry_list = QString(target_array).split('|');
  104. if (entry_list.size() != all_patch_names.size()) {
  105. qDebug() << __FUNCTION__ << "Entry list size is not equal to patch names size!" << QString(target_array);
  106. emit getPatchListError();
  107. return false;
  108. }
  109. for (int i = 0; i < entry_list.size(); ++i) {
  110. QStringList current_patch_data = entry_list[i].split(":::");
  111. if (current_patch_data.size() != 3) {
  112. qDebug() << __FUNCTION__ << "Incorrect patch entry size! Entry: " << entry_list[i];
  113. emit getPatchListError();
  114. return false;
  115. }
  116. patch_data[all_patch_names[i]] = {current_patch_data[0], current_patch_data[1], current_patch_data[2], all_patch_names[i]};
  117. }
  118. return true;
  119. }
  120. bool PatchDownloader::removeOldPatchesFromDirecrory()
  121. {
  122. QStringList actual_hash_list;
  123. foreach (Patch patch, patch_data) {
  124. actual_hash_list.append(patch.md5_hash);
  125. }
  126. qDebug() << "Removing old patches. Current hash list " << actual_hash_list;
  127. QStringList paths = patch_download_dir.entryList(QDir::Files);
  128. foreach (QString filename, paths) {
  129. QString hash = FileSystem::fileHash(patch_download_dir.absolutePath() + "/" + filename, QCryptographicHash::Md5);
  130. if (!actual_hash_list.contains(hash)) {
  131. qDebug() << "File " << filename << " with hash " << hash << "seems outdated, deleting!";
  132. if (!QFile::remove(patch_download_dir.absolutePath() + "/" +filename)) {
  133. qDebug() << __FUNCTION__ << "Unable to remove file " << filename;
  134. emit removeFileError(patch_download_dir.absolutePath() + "/" + filename);
  135. }
  136. }
  137. }
  138. return true;
  139. }
  140. bool PatchDownloader::addMissingPatchesToDownloadList()
  141. {
  142. QDir dir(patch_download_dir);
  143. if (!dir.exists())
  144. QDir().mkdir(patch_download_dir.absolutePath());
  145. bool download_started = false;
  146. foreach (Patch patch, patch_data) {
  147. QString patch_filepath = patch_download_dir.absolutePath() + "/" + patch.url.fileName();
  148. qDebug() << "Patch" << patch.name << "is marked as" << app_settings->value("patches/" + patch.name, "Disabled");
  149. if (app_settings->value("patches/" + patch.name, "Disabled").toString() != "Enabled")
  150. continue;
  151. if (FileSystem::fileExists(patch_filepath)) {
  152. if (FileSystem::fileHash(patch_filepath, QCryptographicHash::Md5) == patch.md5_hash)
  153. continue;
  154. if (!QFile::remove(patch_filepath)) {
  155. qDebug() << __FUNCTION__ << "Unable to remove file " << patch_filepath;
  156. emit removeFileError(patch_filepath);
  157. continue;
  158. }
  159. }
  160. if (!download_started) {
  161. download_started = true;
  162. qDebug() << "Started downloads of PatchDownloader!";
  163. emit downloadStarted();
  164. }
  165. qDebug() << "Starting download of file " << patch_filepath << " from url " << patch.url;
  166. downloads_list[patch.name]->setUrl(patch.url);
  167. downloads_list[patch.name]->targetFile = new QFile(patch_filepath, downloads_list[patch.name]);
  168. downloads_list[patch.name]->targetFile->open(QIODevice::ReadWrite);
  169. downloads_list[patch.name]->start();
  170. active_downloads_number++;
  171. }
  172. return true;
  173. }