patchdownloader.cpp 6.9 KB

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