mtproto_concurrent_sender.h 12 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432
  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 "base/bytes.h"
  9. #include "base/weak_ptr.h"
  10. #include "base/flat_map.h"
  11. #include "mtproto/core_types.h"
  12. #include "mtproto/details/mtproto_serialized_request.h"
  13. #include <QtCore/QPointer>
  14. #include <rpl/details/callable.h>
  15. #ifndef _DEBUG
  16. #define MTP_SENDER_USE_GENERIC_HANDLERS
  17. #endif // !_DEBUG
  18. namespace MTP {
  19. class Error;
  20. class Instance;
  21. class ConcurrentSender : public base::has_weak_ptr {
  22. template <typename ...Args>
  23. static constexpr bool is_callable_v
  24. = rpl::details::is_callable_v<Args...>;
  25. template <typename Method>
  26. auto with_instance(Method &&method)
  27. -> std::enable_if_t<is_callable_v<Method, not_null<Instance*>>>;
  28. struct Handlers {
  29. FnMut<bool(mtpRequestId requestId, bytes::const_span result)> done;
  30. FnMut<void(mtpRequestId requestId, const Error &error)> fail;
  31. };
  32. enum class FailSkipPolicy {
  33. Simple,
  34. HandleFlood,
  35. HandleAll,
  36. };
  37. class RequestBuilder {
  38. public:
  39. RequestBuilder(const RequestBuilder &other) = delete;
  40. RequestBuilder(RequestBuilder &&other) = default;
  41. RequestBuilder &operator=(const RequestBuilder &other) = delete;
  42. RequestBuilder &operator=(RequestBuilder &&other) = delete;
  43. mtpRequestId send();
  44. protected:
  45. RequestBuilder(
  46. not_null<ConcurrentSender*> sender,
  47. details::SerializedRequest &&serialized) noexcept;
  48. void setToDC(ShiftedDcId dcId) noexcept;
  49. void setCanWait(crl::time ms) noexcept;
  50. template <typename Response, typename InvokeFullDone>
  51. void setDoneHandler(InvokeFullDone &&invoke) noexcept;
  52. template <typename InvokeFullFail>
  53. void setFailHandler(InvokeFullFail &&invoke) noexcept;
  54. void setFailSkipPolicy(FailSkipPolicy policy) noexcept;
  55. void setAfter(mtpRequestId requestId) noexcept;
  56. private:
  57. not_null<ConcurrentSender*> _sender;
  58. details::SerializedRequest _serialized;
  59. ShiftedDcId _dcId = 0;
  60. crl::time _canWait = 0;
  61. Handlers _handlers;
  62. FailSkipPolicy _failSkipPolicy = FailSkipPolicy::Simple;
  63. mtpRequestId _afterRequestId = 0;
  64. };
  65. public:
  66. ConcurrentSender(
  67. QPointer<Instance> weak,
  68. Fn<void(FnMut<void()>)> runner);
  69. template <typename Request>
  70. class SpecificRequestBuilder : public RequestBuilder {
  71. public:
  72. using Result = typename Request::ResponseType;
  73. SpecificRequestBuilder(
  74. const SpecificRequestBuilder &other) = delete;
  75. SpecificRequestBuilder(
  76. SpecificRequestBuilder &&other) = default;
  77. SpecificRequestBuilder &operator=(
  78. const SpecificRequestBuilder &other) = delete;
  79. SpecificRequestBuilder &operator=(
  80. SpecificRequestBuilder &&other) = delete;
  81. [[nodiscard]] SpecificRequestBuilder &toDC(
  82. ShiftedDcId dcId) noexcept;
  83. [[nodiscard]] SpecificRequestBuilder &afterDelay(
  84. crl::time ms) noexcept;
  85. #ifndef MTP_SENDER_USE_GENERIC_HANDLERS
  86. // Allow code completion to show response type.
  87. [[nodiscard]] SpecificRequestBuilder &done(FnMut<void()> &&handler);
  88. [[nodiscard]] SpecificRequestBuilder &done(
  89. FnMut<void(mtpRequestId, Result &&)> &&handler);
  90. [[nodiscard]] SpecificRequestBuilder &done(
  91. FnMut<void(Result &&)> &&handler);
  92. [[nodiscard]] SpecificRequestBuilder &fail(Fn<void()> &&handler);
  93. [[nodiscard]] SpecificRequestBuilder &fail(
  94. Fn<void(mtpRequestId, const Error &)> &&handler);
  95. [[nodiscard]] SpecificRequestBuilder &fail(
  96. Fn<void(const Error &)> &&handler);
  97. #else // !MTP_SENDER_USE_GENERIC_HANDLERS
  98. template <typename Handler>
  99. [[nodiscard]] SpecificRequestBuilder &done(Handler &&handler);
  100. template <typename Handler>
  101. [[nodiscard]] SpecificRequestBuilder &fail(Handler &&handler);
  102. #endif // MTP_SENDER_USE_GENERIC_HANDLERS
  103. [[nodiscard]] SpecificRequestBuilder &handleFloodErrors() noexcept;
  104. [[nodiscard]] SpecificRequestBuilder &handleAllErrors() noexcept;
  105. [[nodiscard]] SpecificRequestBuilder &afterRequest(
  106. mtpRequestId requestId) noexcept;
  107. private:
  108. SpecificRequestBuilder(
  109. not_null<ConcurrentSender*> sender,
  110. Request &&request) noexcept;
  111. friend class ConcurrentSender;
  112. };
  113. class SentRequestWrap {
  114. public:
  115. void cancel();
  116. void detach();
  117. private:
  118. friend class ConcurrentSender;
  119. SentRequestWrap(
  120. not_null<ConcurrentSender*> sender,
  121. mtpRequestId requestId);
  122. not_null<ConcurrentSender*> _sender;
  123. mtpRequestId _requestId = 0;
  124. };
  125. template <
  126. typename Request,
  127. typename = std::enable_if_t<!std::is_reference_v<Request>>,
  128. typename = typename Request::Unboxed>
  129. [[nodiscard]] SpecificRequestBuilder<Request> request(
  130. Request &&request) noexcept;
  131. [[nodiscard]] SentRequestWrap request(mtpRequestId requestId) noexcept;
  132. [[nodiscard]] auto requestCanceller() noexcept;
  133. ~ConcurrentSender();
  134. private:
  135. class HandlerMaker;
  136. friend class HandlerMaker;
  137. friend class RequestBuilder;
  138. friend class SentRequestWrap;
  139. void senderRequestRegister(mtpRequestId requestId, Handlers &&handlers);
  140. void senderRequestDone(
  141. mtpRequestId requestId,
  142. bytes::const_span result);
  143. void senderRequestFail(
  144. mtpRequestId requestId,
  145. const Error &error);
  146. void senderRequestCancel(mtpRequestId requestId);
  147. void senderRequestCancelAll();
  148. void senderRequestDetach(mtpRequestId requestId);
  149. const QPointer<Instance> _weak;
  150. const Fn<void(FnMut<void()>)> _runner;
  151. base::flat_map<mtpRequestId, Handlers> _requests;
  152. };
  153. template <typename Result, typename InvokeFullDone>
  154. void ConcurrentSender::RequestBuilder::setDoneHandler(
  155. InvokeFullDone &&invoke
  156. ) noexcept {
  157. _handlers.done = [handler = std::move(invoke)](
  158. mtpRequestId requestId,
  159. bytes::const_span result) mutable {
  160. auto from = reinterpret_cast<const mtpPrime*>(result.data());
  161. const auto end = from + result.size() / sizeof(mtpPrime);
  162. Result data;
  163. if (!data.read(from, end)) {
  164. return false;
  165. }
  166. handler(requestId, std::move(data));
  167. return true;
  168. };
  169. }
  170. template <typename InvokeFullFail>
  171. void ConcurrentSender::RequestBuilder::setFailHandler(
  172. InvokeFullFail &&invoke
  173. ) noexcept {
  174. _handlers.fail = std::move(invoke);
  175. }
  176. template <typename Request>
  177. ConcurrentSender::SpecificRequestBuilder<Request>::SpecificRequestBuilder(
  178. not_null<ConcurrentSender*> sender,
  179. Request &&request) noexcept
  180. : RequestBuilder(sender, details::SerializedRequest::Serialize(request)) {
  181. }
  182. template <typename Request>
  183. auto ConcurrentSender::SpecificRequestBuilder<Request>::toDC(
  184. ShiftedDcId dcId
  185. ) noexcept -> SpecificRequestBuilder & {
  186. setToDC(dcId);
  187. return *this;
  188. }
  189. template <typename Request>
  190. auto ConcurrentSender::SpecificRequestBuilder<Request>::afterDelay(
  191. crl::time ms
  192. ) noexcept -> SpecificRequestBuilder & {
  193. setCanWait(ms);
  194. return *this;
  195. }
  196. #ifndef MTP_SENDER_USE_GENERIC_HANDLERS
  197. // Allow code completion to show response type.
  198. template <typename Request>
  199. auto ConcurrentSender::SpecificRequestBuilder<Request>::done(
  200. FnMut<void(Result &&)> &&handler
  201. ) -> SpecificRequestBuilder & {
  202. setDoneHandler<Result>([handler = std::move(handler)](
  203. mtpRequestId requestId,
  204. Result &&result) mutable {
  205. handler(std::move(result));
  206. });
  207. return *this;
  208. }
  209. template <typename Request>
  210. auto ConcurrentSender::SpecificRequestBuilder<Request>::done(
  211. FnMut<void(mtpRequestId, Result &&)> &&handler
  212. ) -> SpecificRequestBuilder & {
  213. setDoneHandler<Result>(std::move(handler));
  214. return *this;
  215. }
  216. template <typename Request>
  217. auto ConcurrentSender::SpecificRequestBuilder<Request>::done(
  218. FnMut<void()> &&handler
  219. ) -> SpecificRequestBuilder & {
  220. setDoneHandler<Result>([handler = std::move(handler)](
  221. mtpRequestId requestId,
  222. Result &&result) mutable {
  223. std::move(handler)();
  224. });
  225. return *this;
  226. }
  227. template <typename Request>
  228. auto ConcurrentSender::SpecificRequestBuilder<Request>::fail(
  229. Fn<void(const Error &)> &&handler
  230. ) -> SpecificRequestBuilder & {
  231. setFailHandler([handler = std::move(handler)](
  232. mtpRequestId requestId,
  233. const Error &error) {
  234. handler(error);
  235. });
  236. return *this;
  237. }
  238. template <typename Request>
  239. auto ConcurrentSender::SpecificRequestBuilder<Request>::fail(
  240. Fn<void(mtpRequestId, const Error &)> &&handler
  241. ) -> SpecificRequestBuilder & {
  242. setFailHandler(std::move(handler));
  243. return *this;
  244. }
  245. template <typename Request>
  246. auto ConcurrentSender::SpecificRequestBuilder<Request>::fail(
  247. Fn<void()> &&handler
  248. ) -> SpecificRequestBuilder & {
  249. setFailHandler([handler = std::move(handler)](
  250. mtpRequestId requestId,
  251. const Error &error) {
  252. handler();
  253. });
  254. return *this;
  255. }
  256. #else // !MTP_SENDER_USE_GENERIC_HANDLERS
  257. template <typename Request>
  258. template <typename Handler>
  259. auto ConcurrentSender::SpecificRequestBuilder<Request>::done(
  260. Handler &&handler
  261. ) -> SpecificRequestBuilder & {
  262. using Result = typename Request::ResponseType;
  263. constexpr auto takesFull = rpl::details::is_callable_plain_v<
  264. Handler,
  265. mtpRequestId,
  266. Result>;
  267. [[maybe_unused]] constexpr auto takesResponse = rpl::details::is_callable_plain_v<
  268. Handler,
  269. Result>;
  270. [[maybe_unused]] constexpr auto takesNone = rpl::details::is_callable_plain_v<Handler>;
  271. if constexpr (takesFull) {
  272. setDoneHandler<Result>(std::forward<Handler>(handler));
  273. } else if constexpr (takesResponse) {
  274. setDoneHandler<Result>([handler = std::forward<Handler>(handler)](
  275. mtpRequestId requestId,
  276. Result &&result) mutable {
  277. handler(std::move(result));
  278. });
  279. } else if constexpr (takesNone) {
  280. setDoneHandler<Result>([handler = std::forward<Handler>(handler)](
  281. mtpRequestId requestId,
  282. Result &&result) mutable {
  283. handler();
  284. });
  285. } else {
  286. static_assert(false_t(Handler{}), "Bad done handler.");
  287. }
  288. return *this;
  289. }
  290. template <typename Request>
  291. template <typename Handler>
  292. auto ConcurrentSender::SpecificRequestBuilder<Request>::fail(
  293. Handler &&handler
  294. ) -> SpecificRequestBuilder & {
  295. constexpr auto takesFull = rpl::details::is_callable_plain_v<
  296. Handler,
  297. mtpRequestId,
  298. Error>;
  299. [[maybe_unused]] constexpr auto takesError = rpl::details::is_callable_plain_v<
  300. Handler,
  301. Error>;
  302. [[maybe_unused]] constexpr auto takesNone = rpl::details::is_callable_plain_v<Handler>;
  303. if constexpr (takesFull) {
  304. setFailHandler(std::forward<Handler>(handler));
  305. } else if constexpr (takesError) {
  306. setFailHandler([handler = std::forward<Handler>(handler)](
  307. mtpRequestId requestId,
  308. const Error &error) {
  309. handler(error);
  310. });
  311. } else if constexpr (takesNone) {
  312. setFailHandler([handler = std::forward<Handler>(handler)](
  313. mtpRequestId requestId,
  314. const Error &error) {
  315. handler();
  316. });
  317. } else {
  318. static_assert(false_t(Handler{}), "Bad fail handler.");
  319. }
  320. return *this;
  321. }
  322. #endif // MTP_SENDER_USE_GENERIC_HANDLERS
  323. template <typename Request>
  324. auto ConcurrentSender::SpecificRequestBuilder<Request>::handleFloodErrors(
  325. ) noexcept -> SpecificRequestBuilder & {
  326. setFailSkipPolicy(FailSkipPolicy::HandleFlood);
  327. return *this;
  328. }
  329. template <typename Request>
  330. auto ConcurrentSender::SpecificRequestBuilder<Request>::handleAllErrors(
  331. ) noexcept -> SpecificRequestBuilder & {
  332. setFailSkipPolicy(FailSkipPolicy::HandleAll);
  333. return *this;
  334. }
  335. template <typename Request>
  336. auto ConcurrentSender::SpecificRequestBuilder<Request>::afterRequest(
  337. mtpRequestId requestId
  338. ) noexcept -> SpecificRequestBuilder & {
  339. setAfter(requestId);
  340. return *this;
  341. }
  342. inline void ConcurrentSender::SentRequestWrap::cancel() {
  343. _sender->senderRequestCancel(_requestId);
  344. }
  345. inline void ConcurrentSender::SentRequestWrap::detach() {
  346. _sender->senderRequestDetach(_requestId);
  347. }
  348. inline ConcurrentSender::SentRequestWrap::SentRequestWrap(
  349. not_null<ConcurrentSender*> sender,
  350. mtpRequestId requestId
  351. ) : _sender(sender)
  352. , _requestId(requestId) {
  353. }
  354. template <typename Request, typename, typename>
  355. inline auto ConcurrentSender::request(Request &&request) noexcept
  356. -> SpecificRequestBuilder<Request> {
  357. return SpecificRequestBuilder<Request>(this, std::move(request));
  358. }
  359. inline auto ConcurrentSender::requestCanceller() noexcept {
  360. return [=](mtpRequestId requestId) {
  361. request(requestId).cancel();
  362. };
  363. }
  364. inline auto ConcurrentSender::request(mtpRequestId requestId) noexcept
  365. -> SentRequestWrap {
  366. return SentRequestWrap(this, requestId);
  367. }
  368. } // namespace MTP