textspatch.cpp 8.6 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244
  1. #include "textspatch.h"
  2. #include "LotroDat/LotroDat.h"
  3. #include "LotroDat/Database.h"
  4. #include "models/lotrodatmanagerobserver.h"
  5. #include <QUrlQuery>
  6. #include <QSet>
  7. #include <QThread>
  8. TextsPatch::TextsPatch(LotroDatManager *mgr, QObject *parent) : Patch("TextsPatch", mgr, parent)
  9. {
  10. connect(lotro_mgr_, &LotroDatManager::operationStarted, this, &TextsPatch::onLotroDatManagerOperationStarted);
  11. connect(lotro_mgr_, &LotroDatManager::operationFinished, this, &TextsPatch::onLotroDatManagerOperationFinished);
  12. connect(lotro_mgr_->getObserver(), &LotroDatManagerObserver::statusChanged, this, &TextsPatch::onLotroDatManagerStatusChanged);
  13. }
  14. void TextsPatch::checkForUpdates()
  15. {
  16. emit operationStarted("checkForUpdates", this);
  17. QUrlQuery query; // query for building GET-request aka patch-version
  18. foreach (QString db_name, databases_names) {
  19. query.addQueryItem(db_name, "100");
  20. }
  21. QUrl target_url;
  22. target_url.setUrl(Settings::getValue("Network/patch_updates_url").toString());
  23. target_url.setQuery(query);
  24. QByteArray target_array;
  25. Downloader downloader;
  26. downloader.setUrl(target_url);
  27. downloader.targetBytearray = &target_array;
  28. downloader.start();
  29. downloader.waitForDownloaded();
  30. if (target_array.isEmpty()) {
  31. qDebug() << __FUNCTION__ << "Cannot download, target_array is empty!";
  32. emit errorOccured("checkForUpdates", this, "QueryDownloadFailed");
  33. emit operationFinished("checkForUpdates", this, false);
  34. return;
  35. }
  36. QStringList patch_info = QString(target_array).split("|");
  37. if (patch_info.size() != databases_names.size()) {
  38. qDebug() << __FUNCTION__ << "Incorrect patches number! Data: " << patch_info;
  39. emit errorOccured("checkForUpdates", this, "IncorrectQueryResult");
  40. emit operationFinished("checkForUpdates", this, false);
  41. return;
  42. }
  43. for (int i = 0; i < databases_names.size(); ++i) {
  44. QStringList patch_data = patch_info[i].split(":::");
  45. if (patch_data.size() != 3) {
  46. qDebug() << __FUNCTION__ << "Incorrect patch entry size! Entry: " << patch_data;
  47. emit errorOccured("checkForUpdates", this, "IncorrectDbInfo");
  48. emit operationFinished("checkForUpdates", this, false);
  49. return;
  50. }
  51. QString patch_filename = Settings::getValue("General/PatchDownloadDir").toString() + "/" + QUrl(patch_data[0]).fileName();
  52. Settings::setValue("PatchDatabases/" + databases_names[i] + "/url", patch_data[0]);
  53. Settings::setValue("PatchDatabases/" + databases_names[i] + "/hashsum", patch_data[1]);
  54. Settings::setValue("PatchDatabases/" + databases_names[i] + "/datetime", patch_data[2]);
  55. Settings::setValue("PatchDatabases/" + databases_names[i] + "/path", patch_filename);
  56. }
  57. emit operationFinished("checkForUpdates", this, true);
  58. }
  59. void TextsPatch::download()
  60. {
  61. if (elapsed_patches_to_download_ != 0) {
  62. qDebug() << "Trying to start download of patch set " << patch_name_ << " while download is still active!";
  63. return;
  64. }
  65. emit operationStarted("download", this);
  66. bool download_started = false;
  67. foreach (QString db_name, databases_names) {
  68. QString settings_prefix = "PatchDatabases/" + db_name;
  69. QString target_filename = QApplication::applicationDirPath() + "/" + Settings::getValue(settings_prefix + "/path").toString();
  70. qDebug() << "TextsPatch: Checking if there's no need to download file " << target_filename;
  71. if (FileSystem::fileHash(target_filename) == Settings::getValue(settings_prefix + "/hashsum").toString()) {
  72. qDebug() << "TextsPatch: file " << target_filename << " is fresh, no need to download";
  73. continue;
  74. }
  75. FileSystem::createFilePath(target_filename);
  76. QFile* target_file = new QFile(target_filename);
  77. if (!target_file->open(QIODevice::ReadWrite | QIODevice::Truncate)) {
  78. emit errorOccured("download", this, "CantOpenDbFile");
  79. continue;
  80. }
  81. qDebug() << "TextsPatch: beginning download of file " << target_filename;
  82. download_started = true;
  83. ++elapsed_patches_to_download_;
  84. Downloader* downloader = new Downloader();
  85. downloader->setUrl(Settings::getValue(settings_prefix + "/url").toUrl());
  86. downloader->targetFile = target_file;
  87. connect(downloader, &Downloader::progressChanged, this, &TextsPatch::onDownloaderProgressChanged);
  88. connect(downloader, &Downloader::downloadFinished, this, &TextsPatch::onDownloaderFinished);
  89. downloaders_.insert(downloader);
  90. downloader->start();
  91. }
  92. if (!download_started) {
  93. emit operationFinished("download", this, true);
  94. } // otherwise will be emitted on the last onDownloaderFinished signal
  95. }
  96. void TextsPatch::install()
  97. {
  98. emit operationStarted("install", this);
  99. QThread::sleep(5);
  100. emit operationFinished("install", this, true);
  101. }
  102. void TextsPatch::activate()
  103. {
  104. emit operationStarted("activate", this);
  105. QThread::sleep(5);
  106. emit operationFinished("activate", this, true);
  107. }
  108. void TextsPatch::onDownloaderProgressChanged(Downloader *, Downloader::Status)
  109. {
  110. Downloader::Status all_downloads_status;
  111. foreach (Downloader* downloader, downloaders_) {
  112. all_downloads_status = all_downloads_status + downloader->getDownloadStatus();
  113. }
  114. emit downloadStatusChanged(this, all_downloads_status);
  115. }
  116. void TextsPatch::onDownloaderFinished(Downloader *ptr)
  117. {
  118. Downloader::Status all_downloads_status;
  119. foreach (Downloader* downloader, downloaders_) {
  120. all_downloads_status = all_downloads_status + downloader->getDownloadStatus();
  121. }
  122. ptr->targetFile->close();
  123. ptr->targetFile->deleteLater();
  124. if (elapsed_patches_to_download_ == 1) {
  125. foreach (Downloader* downloader, downloaders_) {
  126. downloader->deleteLater();
  127. }
  128. downloaders_.clear();
  129. emit downloadStatusChanged(this, all_downloads_status);
  130. emit operationFinished("download", this, true);
  131. }
  132. --elapsed_patches_to_download_;
  133. }
  134. void TextsPatch::onLotroDatManagerOperationFinished(QString operation_name, QVector<QVariant> args, bool successful)
  135. {
  136. if (operation_name == "installPatch") {
  137. if (!args[0].toString().contains("SoundsPatch_")) {
  138. return;
  139. }
  140. status_.process = CurrentProcess::E_AWAITING_INSTALL;
  141. status_.percent = 100;
  142. emit installStatusChanged(this, status_);
  143. --elapsed_databases_to_install_;
  144. if (!successful) {
  145. emit errorOccured("install", this, "Database " + args[0].toString() + " (" + args[1].toString() + ") was not installed due to Legacy core error.");
  146. }
  147. if (elapsed_databases_to_install_ == 0) {
  148. status_.process = CurrentProcess::E_FINISHED;
  149. emit operationFinished("install", this, true);
  150. }
  151. }
  152. if (operation_name == "enableCategory" || operation_name == "disableCategory") {
  153. if (!args[0].toString().contains("SoundsPatch_")) {
  154. return;
  155. }
  156. status_.process = CurrentProcess::E_AWAITING_APPLY;
  157. status_.percent = 100;
  158. emit installStatusChanged(this, status_);
  159. --elapsed_categories_to_activate_;
  160. if (!successful) {
  161. emit errorOccured("activate", this, "Error in patch " + args[0].toString() + ": activating category " + QString::number(args[1].toInt()) + " failed.");
  162. }
  163. if (elapsed_categories_to_activate_ == 0) {
  164. status_.process = CurrentProcess::E_FINISHED;
  165. emit operationFinished("activate", this, true);
  166. }
  167. }
  168. }
  169. void TextsPatch::onLotroDatManagerOperationStarted(QString operation_name, QVector<QVariant> args)
  170. {
  171. if (operation_name == "installPatch") {
  172. if (!args[0].toString().contains("SoundsPatch_")) {
  173. return;
  174. }
  175. status_.process = CurrentProcess::E_INSTALL;
  176. status_.current_part++;
  177. status_.percent = 0;
  178. emit installStatusChanged(this, status_);
  179. }
  180. if (operation_name == "enableCategory" || operation_name == "disableCategory") {
  181. if (!args[0].toString().contains("SoundsPatch_")) {
  182. return;
  183. }
  184. status_.process = CurrentProcess::E_APPLY;
  185. status_.current_part++;
  186. status_.percent = 0;
  187. emit installStatusChanged(this, status_);
  188. }
  189. }
  190. void TextsPatch::onLotroDatManagerStatusChanged(LotroDatManager::Status status)
  191. {
  192. if (status_.process != CurrentProcess::E_INSTALL || status_.process != CurrentProcess::E_APPLY) {
  193. return;
  194. }
  195. status_.percent = status.percent;
  196. emit installStatusChanged(this, status_);
  197. }