dedicated_file_loader.h 4.7 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207
  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. #pragma once
  8. #include "mtproto/mtp_instance.h"
  9. namespace Main {
  10. class Session;
  11. } // namespace Main
  12. namespace MTP {
  13. class WeakInstance final : private QObject {
  14. public:
  15. explicit WeakInstance(base::weak_ptr<Main::Session> session);
  16. template <typename Request>
  17. void send(
  18. const Request &request,
  19. Fn<void(const typename Request::ResponseType &result)> done,
  20. Fn<void(const Error &error)> fail,
  21. ShiftedDcId dcId = 0);
  22. [[nodiscard]] base::weak_ptr<Main::Session> session() const;
  23. [[nodiscard]] bool valid() const;
  24. [[nodiscard]] Instance *instance() const;
  25. ~WeakInstance();
  26. private:
  27. void die();
  28. bool removeRequest(mtpRequestId requestId);
  29. void reportUnavailable(Fn<void(const Error &error)> callback);
  30. base::weak_ptr<Main::Session> _session;
  31. Instance *_instance = nullptr;
  32. std::map<mtpRequestId, Fn<void(const Error &)>> _requests;
  33. rpl::lifetime _lifetime;
  34. };
  35. class AbstractDedicatedLoader : public base::has_weak_ptr {
  36. public:
  37. AbstractDedicatedLoader(const QString &filepath, int chunkSize);
  38. static constexpr auto kChunkSize = 128 * 1024;
  39. static constexpr auto kMaxFileSize = 256 * 1024 * 1024;
  40. struct Progress {
  41. int64 already = 0;
  42. int64 size = 0;
  43. inline bool operator<(const Progress &other) const {
  44. return (already < other.already)
  45. || (already == other.already && size < other.size);
  46. }
  47. inline bool operator==(const Progress &other) const {
  48. return (already == other.already) && (size == other.size);
  49. }
  50. };
  51. void start();
  52. void wipeFolder();
  53. void wipeOutput();
  54. int64 alreadySize() const;
  55. int64 totalSize() const;
  56. rpl::producer<Progress> progress() const;
  57. rpl::producer<QString> ready() const;
  58. rpl::producer<> failed() const;
  59. rpl::lifetime &lifetime();
  60. virtual ~AbstractDedicatedLoader() = default;
  61. protected:
  62. void threadSafeFailed();
  63. // Single threaded.
  64. void writeChunk(bytes::const_span data, int totalSize);
  65. private:
  66. virtual void startLoading() = 0;
  67. bool validateOutput();
  68. void threadSafeProgress(Progress progress);
  69. void threadSafeReady();
  70. QString _filepath;
  71. int _chunkSize = 0;
  72. QFile _output;
  73. int64 _alreadySize = 0;
  74. int64 _totalSize = 0;
  75. mutable QMutex _sizesMutex;
  76. rpl::event_stream<Progress> _progress;
  77. rpl::event_stream<QString> _ready;
  78. rpl::event_stream<> _failed;
  79. rpl::lifetime _lifetime;
  80. };
  81. class DedicatedLoader : public AbstractDedicatedLoader {
  82. public:
  83. struct Location {
  84. QString username;
  85. int32 postId = 0;
  86. };
  87. struct File {
  88. QString name;
  89. int64 size = 0;
  90. DcId dcId = 0;
  91. MTPInputFileLocation location;
  92. };
  93. DedicatedLoader(
  94. base::weak_ptr<Main::Session> session,
  95. const QString &folder,
  96. const File &file);
  97. private:
  98. struct Request {
  99. int64 offset = 0;
  100. QByteArray bytes;
  101. };
  102. void startLoading() override;
  103. void sendRequest();
  104. void gotPart(int offset, const MTPupload_File &result);
  105. Fn<void(const Error &)> failHandler();
  106. static constexpr auto kRequestsCount = 2;
  107. static constexpr auto kNextRequestDelay = crl::time(20);
  108. std::deque<Request> _requests;
  109. int64 _size = 0;
  110. int64 _offset = 0;
  111. DcId _dcId = 0;
  112. MTPInputFileLocation _location;
  113. WeakInstance _mtp;
  114. };
  115. void ResolveChannel(
  116. not_null<MTP::WeakInstance*> mtp,
  117. const QString &username,
  118. Fn<void(const MTPInputChannel &channel)> done,
  119. Fn<void()> fail);
  120. std::optional<MTPMessage> GetMessagesElement(
  121. const MTPmessages_Messages &list);
  122. void StartDedicatedLoader(
  123. not_null<MTP::WeakInstance*> mtp,
  124. const DedicatedLoader::Location &location,
  125. const QString &folder,
  126. Fn<void(std::unique_ptr<DedicatedLoader>)> ready);
  127. template <typename Request>
  128. void WeakInstance::send(
  129. const Request &request,
  130. Fn<void(const typename Request::ResponseType &result)> done,
  131. Fn<void(const Error &error)> fail,
  132. MTP::ShiftedDcId dcId) {
  133. using Result = typename Request::ResponseType;
  134. if (!valid()) {
  135. reportUnavailable(fail);
  136. return;
  137. }
  138. const auto onDone = crl::guard((QObject*)this, [=](
  139. const Response &response) {
  140. auto result = Result();
  141. auto from = response.reply.constData();
  142. if (!result.read(from, from + response.reply.size())) {
  143. return false;
  144. }
  145. if (removeRequest(response.requestId)) {
  146. done(result);
  147. }
  148. return true;
  149. });
  150. const auto onFail = crl::guard((QObject*)this, [=](
  151. const Error &error,
  152. const Response &response) {
  153. if (MTP::IsDefaultHandledError(error)) {
  154. return false;
  155. }
  156. if (removeRequest(response.requestId)) {
  157. fail(error);
  158. }
  159. return true;
  160. });
  161. const auto requestId = _instance->send(
  162. request,
  163. std::move(onDone),
  164. std::move(onFail),
  165. dcId);
  166. _requests.emplace(requestId, fail);
  167. }
  168. } // namespace MTP