streamed_file_downloader.cpp 3.7 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172
  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/streamed_file_downloader.h"
  8. #include "media/streaming/media_streaming_loader.h"
  9. #include "media/streaming/media_streaming_reader.h"
  10. namespace Storage {
  11. namespace {
  12. using namespace Media::Streaming;
  13. constexpr auto kPartSize = Loader::kPartSize;
  14. constexpr auto kRequestPartsCount = 32;
  15. } // namespace
  16. StreamedFileDownloader::StreamedFileDownloader(
  17. not_null<Main::Session*> session,
  18. uint64 objectId,
  19. MTP::DcId dcId,
  20. Data::FileOrigin origin,
  21. Cache::Key cacheKey,
  22. MediaKey fileLocationKey,
  23. std::shared_ptr<Reader> reader,
  24. // For FileLoader
  25. const QString &toFile,
  26. int64 size,
  27. LocationType locationType,
  28. LoadToCacheSetting toCache,
  29. LoadFromCloudSetting fromCloud,
  30. bool autoLoading,
  31. uint8 cacheTag)
  32. : FileLoader(
  33. session,
  34. toFile,
  35. size,
  36. size,
  37. locationType,
  38. toCache,
  39. fromCloud,
  40. autoLoading,
  41. cacheTag)
  42. , _objectId(objectId)
  43. , _origin(origin)
  44. , _cacheKey(cacheKey)
  45. , _fileLocationKey(fileLocationKey)
  46. , _reader(std::move(reader))
  47. , _partsCount((size + kPartSize - 1) / kPartSize) {
  48. _partIsSaved.resize(_partsCount, false);
  49. _reader->partsForDownloader(
  50. ) | rpl::start_with_next([=](const LoadedPart &part) {
  51. if (part.offset == LoadedPart::kFailedOffset) {
  52. cancel(FailureReason::OtherFailure);
  53. } else {
  54. savePart(std::move(part));
  55. }
  56. }, _lifetime);
  57. }
  58. StreamedFileDownloader::~StreamedFileDownloader() {
  59. if (!_finished) {
  60. cancel();
  61. } else {
  62. _reader->cancelForDownloader(this);
  63. }
  64. }
  65. uint64 StreamedFileDownloader::objId() const {
  66. return _objectId;
  67. }
  68. Data::FileOrigin StreamedFileDownloader::fileOrigin() const {
  69. return _origin;
  70. }
  71. void StreamedFileDownloader::requestParts() {
  72. while (!_finished
  73. && _nextPartIndex < _partsCount
  74. && _partsRequested < kRequestPartsCount) {
  75. requestPart();
  76. }
  77. _reader->continueDownloaderFromMainThread();
  78. }
  79. void StreamedFileDownloader::requestPart() {
  80. Expects(!_finished);
  81. const auto index = std::find(
  82. begin(_partIsSaved) + _nextPartIndex,
  83. end(_partIsSaved),
  84. false
  85. ) - begin(_partIsSaved);
  86. if (index == _partsCount) {
  87. _nextPartIndex = _partsCount;
  88. return;
  89. }
  90. _nextPartIndex = index + 1;
  91. _reader->loadForDownloader(this, index * kPartSize);
  92. ++_partsRequested;
  93. }
  94. QByteArray StreamedFileDownloader::readLoadedPart(int64 offset) {
  95. Expects(offset >= 0 && offset < _fullSize);
  96. Expects(!(offset % kPartSize));
  97. const auto index = (offset / kPartSize);
  98. return _partIsSaved[index]
  99. ? readLoadedPartBack(offset, kPartSize)
  100. : QByteArray();
  101. }
  102. Storage::Cache::Key StreamedFileDownloader::cacheKey() const {
  103. return _cacheKey;
  104. }
  105. std::optional<MediaKey> StreamedFileDownloader::fileLocationKey() const {
  106. return _fileLocationKey;
  107. }
  108. void StreamedFileDownloader::cancelHook() {
  109. _partsRequested = 0;
  110. _nextPartIndex = 0;
  111. _reader->cancelForDownloader(this);
  112. }
  113. void StreamedFileDownloader::startLoading() {
  114. requestParts();
  115. }
  116. void StreamedFileDownloader::savePart(const LoadedPart &part) {
  117. Expects(part.offset >= 0 && part.offset < _reader->size());
  118. Expects(part.offset % kPartSize == 0);
  119. if (_finished || _cancelled) {
  120. return;
  121. }
  122. const auto offset = part.offset;
  123. const auto index = offset / kPartSize;
  124. Assert(index >= 0 && index < _partsCount);
  125. if (_partIsSaved[index]) {
  126. return;
  127. }
  128. _partIsSaved[index] = true;
  129. ++_partsSaved;
  130. if (index < _nextPartIndex) {
  131. --_partsRequested;
  132. }
  133. if (!writeResultPart(offset, bytes::make_span(part.bytes))) {
  134. return;
  135. }
  136. _reader->doneForDownloader(offset);
  137. if (_partsSaved == _partsCount) {
  138. finalizeResult();
  139. } else {
  140. requestParts();
  141. notifyAboutProgress();
  142. }
  143. }
  144. } // namespace Storage