storage_cloud_blob.cpp 3.7 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151
  1. /*
  2. This file is part of Telegram Desktop,
  3. the official desktop application for the Telegram messaging service.
  4. For license and copyright information please follow this link:
  5. https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL
  6. */
  7. #include "storage/storage_cloud_blob.h"
  8. #include "base/zlib_help.h"
  9. #include "lang/lang_keys.h"
  10. #include "ui/text/format_values.h"
  11. #include "main/main_account.h"
  12. #include "main/main_session.h"
  13. namespace Storage::CloudBlob {
  14. namespace {
  15. QByteArray ReadFinalFile(const QString &path) {
  16. constexpr auto kMaxZipSize = 10 * 1024 * 1024;
  17. auto file = QFile(path);
  18. if (file.size() > kMaxZipSize || !file.open(QIODevice::ReadOnly)) {
  19. return QByteArray();
  20. }
  21. return file.readAll();
  22. }
  23. bool ExtractZipFile(zlib::FileToRead &zip, const QString path) {
  24. constexpr auto kMaxSize = 25 * 1024 * 1024;
  25. const auto content = zip.readCurrentFileContent(kMaxSize);
  26. if (content.isEmpty() || zip.error() != UNZ_OK) {
  27. return false;
  28. }
  29. auto file = QFile(path);
  30. return file.open(QIODevice::WriteOnly)
  31. && (file.write(content) == content.size());
  32. }
  33. } // namespace
  34. bool UnpackBlob(
  35. const QString &path,
  36. const QString &folder,
  37. Fn<bool(const QString &)> checkNameCallback) {
  38. const auto bytes = ReadFinalFile(path);
  39. if (bytes.isEmpty()) {
  40. return false;
  41. }
  42. auto zip = zlib::FileToRead(bytes);
  43. if (zip.goToFirstFile() != UNZ_OK) {
  44. return false;
  45. }
  46. do {
  47. const auto name = zip.getCurrentFileName();
  48. const auto path = folder + '/' + name;
  49. if (checkNameCallback(name) && !ExtractZipFile(zip, path)) {
  50. return false;
  51. }
  52. const auto jump = zip.goToNextFile();
  53. if (jump == UNZ_END_OF_LIST_OF_FILE) {
  54. break;
  55. } else if (jump != UNZ_OK) {
  56. return false;
  57. }
  58. } while (true);
  59. return true;
  60. }
  61. QString StateDescription(const BlobState &state, tr::phrase<> activeText) {
  62. return v::match(state, [](const Available &data) {
  63. return tr::lng_emoji_set_download(
  64. tr::now,
  65. lt_size,
  66. Ui::FormatSizeText(data.size));
  67. }, [](const Ready &data) -> QString {
  68. return tr::lng_emoji_set_ready(tr::now);
  69. }, [&](const Active &data) -> QString {
  70. return activeText(tr::now);
  71. }, [](const Loading &data) {
  72. const auto percent = (data.size > 0)
  73. ? std::clamp((data.already * 100) / float64(data.size), 0., 100.)
  74. : 0.;
  75. return tr::lng_emoji_set_loading(
  76. tr::now,
  77. lt_percent,
  78. QString::number(int(base::SafeRound(percent))) + '%',
  79. lt_progress,
  80. Ui::FormatDownloadText(data.already, data.size));
  81. }, [](const Failed &data) {
  82. return tr::lng_attach_failed(tr::now);
  83. });
  84. }
  85. BlobLoader::BlobLoader(
  86. QObject *parent,
  87. not_null<Main::Session*> session,
  88. int id,
  89. MTP::DedicatedLoader::Location location,
  90. const QString &folder,
  91. int64 size)
  92. : QObject(parent)
  93. , _folder(folder)
  94. , _id(id)
  95. , _state(Loading{ 0, size })
  96. , _mtproto(session.get()) {
  97. const auto ready = [=](std::unique_ptr<MTP::DedicatedLoader> loader) {
  98. if (loader) {
  99. setImplementation(std::move(loader));
  100. } else {
  101. fail();
  102. }
  103. };
  104. MTP::StartDedicatedLoader(&_mtproto, location, _folder, ready);
  105. }
  106. int BlobLoader::id() const {
  107. return _id;
  108. }
  109. rpl::producer<BlobState> BlobLoader::state() const {
  110. return _state.value();
  111. }
  112. void BlobLoader::setImplementation(
  113. std::unique_ptr<MTP::DedicatedLoader> loader) {
  114. _implementation = std::move(loader);
  115. _state = _implementation->progress(
  116. ) | rpl::map([](const Loading &state) {
  117. return BlobState(state);
  118. });
  119. _implementation->failed(
  120. ) | rpl::start_with_next([=] {
  121. fail();
  122. }, _implementation->lifetime());
  123. _implementation->ready(
  124. ) | rpl::start_with_next([=](const QString &filepath) {
  125. unpack(filepath);
  126. }, _implementation->lifetime());
  127. QDir(_folder).removeRecursively();
  128. _implementation->start();
  129. }
  130. void BlobLoader::fail() {
  131. _state = Failed();
  132. }
  133. } // namespace Storage::CloudBlob