export_api_wrap.cpp 66 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896897898899900901902903904905906907908909910911912913914915916917918919920921922923924925926927928929930931932933934935936937938939940941942943944945946947948949950951952953954955956957958959960961962963964965966967968969970971972973974975976977978979980981982983984985986987988989990991992993994995996997998999100010011002100310041005100610071008100910101011101210131014101510161017101810191020102110221023102410251026102710281029103010311032103310341035103610371038103910401041104210431044104510461047104810491050105110521053105410551056105710581059106010611062106310641065106610671068106910701071107210731074107510761077107810791080108110821083108410851086108710881089109010911092109310941095109610971098109911001101110211031104110511061107110811091110111111121113111411151116111711181119112011211122112311241125112611271128112911301131113211331134113511361137113811391140114111421143114411451146114711481149115011511152115311541155115611571158115911601161116211631164116511661167116811691170117111721173117411751176117711781179118011811182118311841185118611871188118911901191119211931194119511961197119811991200120112021203120412051206120712081209121012111212121312141215121612171218121912201221122212231224122512261227122812291230123112321233123412351236123712381239124012411242124312441245124612471248124912501251125212531254125512561257125812591260126112621263126412651266126712681269127012711272127312741275127612771278127912801281128212831284128512861287128812891290129112921293129412951296129712981299130013011302130313041305130613071308130913101311131213131314131513161317131813191320132113221323132413251326132713281329133013311332133313341335133613371338133913401341134213431344134513461347134813491350135113521353135413551356135713581359136013611362136313641365136613671368136913701371137213731374137513761377137813791380138113821383138413851386138713881389139013911392139313941395139613971398139914001401140214031404140514061407140814091410141114121413141414151416141714181419142014211422142314241425142614271428142914301431143214331434143514361437143814391440144114421443144414451446144714481449145014511452145314541455145614571458145914601461146214631464146514661467146814691470147114721473147414751476147714781479148014811482148314841485148614871488148914901491149214931494149514961497149814991500150115021503150415051506150715081509151015111512151315141515151615171518151915201521152215231524152515261527152815291530153115321533153415351536153715381539154015411542154315441545154615471548154915501551155215531554155515561557155815591560156115621563156415651566156715681569157015711572157315741575157615771578157915801581158215831584158515861587158815891590159115921593159415951596159715981599160016011602160316041605160616071608160916101611161216131614161516161617161816191620162116221623162416251626162716281629163016311632163316341635163616371638163916401641164216431644164516461647164816491650165116521653165416551656165716581659166016611662166316641665166616671668166916701671167216731674167516761677167816791680168116821683168416851686168716881689169016911692169316941695169616971698169917001701170217031704170517061707170817091710171117121713171417151716171717181719172017211722172317241725172617271728172917301731173217331734173517361737173817391740174117421743174417451746174717481749175017511752175317541755175617571758175917601761176217631764176517661767176817691770177117721773177417751776177717781779178017811782178317841785178617871788178917901791179217931794179517961797179817991800180118021803180418051806180718081809181018111812181318141815181618171818181918201821182218231824182518261827182818291830183118321833183418351836183718381839184018411842184318441845184618471848184918501851185218531854185518561857185818591860186118621863186418651866186718681869187018711872187318741875187618771878187918801881188218831884188518861887188818891890189118921893189418951896189718981899190019011902190319041905190619071908190919101911191219131914191519161917191819191920192119221923192419251926192719281929193019311932193319341935193619371938193919401941194219431944194519461947194819491950195119521953195419551956195719581959196019611962196319641965196619671968196919701971197219731974197519761977197819791980198119821983198419851986198719881989199019911992199319941995199619971998199920002001200220032004200520062007200820092010201120122013201420152016201720182019202020212022202320242025202620272028202920302031203220332034203520362037203820392040204120422043204420452046204720482049205020512052205320542055205620572058205920602061206220632064206520662067206820692070207120722073207420752076207720782079208020812082208320842085208620872088208920902091209220932094209520962097209820992100210121022103210421052106210721082109211021112112211321142115211621172118211921202121212221232124212521262127212821292130213121322133213421352136213721382139214021412142214321442145214621472148214921502151215221532154215521562157215821592160216121622163216421652166216721682169217021712172217321742175217621772178217921802181218221832184218521862187218821892190219121922193219421952196219721982199220022012202220322042205220622072208220922102211221222132214221522162217221822192220222122222223222422252226222722282229223022312232223322342235223622372238223922402241224222432244224522462247224822492250225122522253225422552256225722582259226022612262226322642265226622672268226922702271227222732274227522762277227822792280228122822283228422852286228722882289229022912292229322942295229622972298229923002301230223032304230523062307230823092310231123122313231423152316231723182319232023212322232323242325232623272328232923302331233223332334233523362337233823392340234123422343234423452346234723482349235023512352235323542355235623572358235923602361236223632364236523662367236823692370237123722373237423752376237723782379238023812382238323842385238623872388238923902391239223932394239523962397239823992400240124022403
  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 "export/export_api_wrap.h"
  8. #include "export/export_settings.h"
  9. #include "export/data/export_data_types.h"
  10. #include "export/output/export_output_result.h"
  11. #include "export/output/export_output_file.h"
  12. #include "mtproto/mtproto_response.h"
  13. #include "base/bytes.h"
  14. #include "base/options.h"
  15. #include "base/random.h"
  16. #include <set>
  17. #include <deque>
  18. namespace Export {
  19. namespace {
  20. constexpr auto kUserpicsSliceLimit = 100;
  21. constexpr auto kFileChunkSize = 128 * 1024;
  22. constexpr auto kFileRequestsCount = 2;
  23. //constexpr auto kFileNextRequestDelay = crl::time(20);
  24. constexpr auto kChatsSliceLimit = 100;
  25. constexpr auto kMessagesSliceLimit = 100;
  26. constexpr auto kTopPeerSliceLimit = 100;
  27. constexpr auto kFileMaxSize = 4000 * int64(1024 * 1024);
  28. constexpr auto kLocationCacheSize = 100'000;
  29. constexpr auto kMaxEmojiPerRequest = 100;
  30. constexpr auto kStoriesSliceLimit = 100;
  31. struct LocationKey {
  32. uint64 type;
  33. uint64 id;
  34. inline bool operator<(const LocationKey &other) const {
  35. return std::tie(type, id) < std::tie(other.type, other.id);
  36. }
  37. };
  38. LocationKey ComputeLocationKey(const Data::FileLocation &value) {
  39. auto result = LocationKey();
  40. result.type = value.dcId;
  41. value.data.match([&](const MTPDinputDocumentFileLocation &data) {
  42. const auto letter = data.vthumb_size().v.isEmpty()
  43. ? char(0)
  44. : data.vthumb_size().v[0];
  45. result.type |= (2ULL << 24);
  46. result.type |= (uint64(uint32(letter)) << 16);
  47. result.id = data.vid().v;
  48. }, [&](const MTPDinputPhotoFileLocation &data) {
  49. const auto letter = data.vthumb_size().v.isEmpty()
  50. ? char(0)
  51. : data.vthumb_size().v[0];
  52. result.type |= (6ULL << 24);
  53. result.type |= (uint64(uint32(letter)) << 16);
  54. result.id = data.vid().v;
  55. }, [&](const MTPDinputTakeoutFileLocation &data) {
  56. result.type |= (5ULL << 24);
  57. }, [](const auto &data) {
  58. Unexpected("File location type in Export::ComputeLocationKey.");
  59. });
  60. return result;
  61. }
  62. Settings::Type SettingsFromDialogsType(Data::DialogInfo::Type type) {
  63. using DialogType = Data::DialogInfo::Type;
  64. switch (type) {
  65. case DialogType::Self:
  66. case DialogType::Personal:
  67. return Settings::Type::PersonalChats;
  68. case DialogType::Bot:
  69. return Settings::Type::BotChats;
  70. case DialogType::PrivateGroup:
  71. case DialogType::PrivateSupergroup:
  72. return Settings::Type::PrivateGroups;
  73. case DialogType::PublicSupergroup:
  74. return Settings::Type::PublicGroups;
  75. case DialogType::PrivateChannel:
  76. return Settings::Type::PrivateChannels;
  77. case DialogType::PublicChannel:
  78. return Settings::Type::PublicChannels;
  79. }
  80. return Settings::Type(0);
  81. }
  82. } // namespace
  83. class ApiWrap::LoadedFileCache {
  84. public:
  85. using Location = Data::FileLocation;
  86. LoadedFileCache(int limit);
  87. void save(const Location &location, const QString &relativePath);
  88. std::optional<QString> find(const Location &location) const;
  89. private:
  90. int _limit = 0;
  91. std::map<LocationKey, QString> _map;
  92. std::deque<LocationKey> _list;
  93. };
  94. struct ApiWrap::StartProcess {
  95. FnMut<void(StartInfo)> done;
  96. enum class Step {
  97. UserpicsCount,
  98. StoriesCount,
  99. SplitRanges,
  100. DialogsCount,
  101. LeftChannelsCount,
  102. };
  103. std::deque<Step> steps;
  104. int splitIndex = 0;
  105. StartInfo info;
  106. };
  107. struct ApiWrap::ContactsProcess {
  108. FnMut<void(Data::ContactsList&&)> done;
  109. Data::ContactsList result;
  110. int topPeersOffset = 0;
  111. };
  112. struct ApiWrap::UserpicsProcess {
  113. FnMut<bool(Data::UserpicsInfo&&)> start;
  114. Fn<bool(DownloadProgress)> fileProgress;
  115. Fn<bool(Data::UserpicsSlice&&)> handleSlice;
  116. FnMut<void()> finish;
  117. int processed = 0;
  118. std::optional<Data::UserpicsSlice> slice;
  119. uint64 maxId = 0;
  120. bool lastSlice = false;
  121. int fileIndex = 0;
  122. };
  123. struct ApiWrap::StoriesProcess {
  124. FnMut<bool(Data::StoriesInfo&&)> start;
  125. Fn<bool(DownloadProgress)> fileProgress;
  126. Fn<bool(Data::StoriesSlice&&)> handleSlice;
  127. FnMut<void()> finish;
  128. int processed = 0;
  129. std::optional<Data::StoriesSlice> slice;
  130. int offsetId = 0;
  131. bool lastSlice = false;
  132. int fileIndex = 0;
  133. };
  134. struct ApiWrap::OtherDataProcess {
  135. Data::File file;
  136. FnMut<void(Data::File&&)> done;
  137. };
  138. struct ApiWrap::FileProcess {
  139. FileProcess(const QString &path, Output::Stats *stats);
  140. Output::File file;
  141. QString relativePath;
  142. Fn<bool(FileProgress)> progress;
  143. FnMut<void(const QString &relativePath)> done;
  144. uint64 randomId = 0;
  145. Data::FileLocation location;
  146. Data::FileOrigin origin;
  147. int64 offset = 0;
  148. int64 size = 0;
  149. struct Request {
  150. int64 offset = 0;
  151. QByteArray bytes;
  152. };
  153. std::deque<Request> requests;
  154. mtpRequestId requestId = 0;
  155. };
  156. struct ApiWrap::FileProgress {
  157. int64 ready = 0;
  158. int64 total = 0;
  159. };
  160. struct ApiWrap::ChatsProcess {
  161. Fn<bool(int count)> progress;
  162. FnMut<void(Data::DialogsInfo&&)> done;
  163. Data::DialogsInfo info;
  164. int processedCount = 0;
  165. std::map<PeerId, int> indexByPeer;
  166. };
  167. struct ApiWrap::LeftChannelsProcess : ChatsProcess {
  168. int fullCount = 0;
  169. int offset = 0;
  170. bool finished = false;
  171. };
  172. struct ApiWrap::DialogsProcess : ChatsProcess {
  173. int splitIndexPlusOne = 0;
  174. TimeId offsetDate = 0;
  175. int32 offsetId = 0;
  176. MTPInputPeer offsetPeer = MTP_inputPeerEmpty();
  177. };
  178. struct ApiWrap::ChatProcess {
  179. Data::DialogInfo info;
  180. FnMut<bool(const Data::DialogInfo &)> start;
  181. Fn<bool(DownloadProgress)> fileProgress;
  182. Fn<bool(Data::MessagesSlice&&)> handleSlice;
  183. FnMut<void()> done;
  184. FnMut<void(MTPmessages_Messages&&)> requestDone;
  185. int localSplitIndex = 0;
  186. int32 largestIdPlusOne = 1;
  187. Data::ParseMediaContext context;
  188. std::optional<Data::MessagesSlice> slice;
  189. bool lastSlice = false;
  190. int fileIndex = 0;
  191. };
  192. template <typename Request>
  193. class ApiWrap::RequestBuilder {
  194. public:
  195. using Original = MTP::ConcurrentSender::SpecificRequestBuilder<Request>;
  196. using Response = typename Request::ResponseType;
  197. RequestBuilder(
  198. Original &&builder,
  199. Fn<void(const MTP::Error&)> commonFailHandler);
  200. [[nodiscard]] RequestBuilder &done(FnMut<void()> &&handler);
  201. [[nodiscard]] RequestBuilder &done(
  202. FnMut<void(Response &&)> &&handler);
  203. [[nodiscard]] RequestBuilder &fail(
  204. Fn<bool(const MTP::Error&)> &&handler);
  205. mtpRequestId send();
  206. private:
  207. Original _builder;
  208. Fn<void(const MTP::Error&)> _commonFailHandler;
  209. };
  210. template <typename Request>
  211. ApiWrap::RequestBuilder<Request>::RequestBuilder(
  212. Original &&builder,
  213. Fn<void(const MTP::Error&)> commonFailHandler)
  214. : _builder(std::move(builder))
  215. , _commonFailHandler(std::move(commonFailHandler)) {
  216. }
  217. template <typename Request>
  218. auto ApiWrap::RequestBuilder<Request>::done(
  219. FnMut<void()> &&handler
  220. ) -> RequestBuilder& {
  221. if (handler) {
  222. [[maybe_unused]] auto &silence_warning = _builder.done(std::move(handler));
  223. }
  224. return *this;
  225. }
  226. template <typename Request>
  227. auto ApiWrap::RequestBuilder<Request>::done(
  228. FnMut<void(Response &&)> &&handler
  229. ) -> RequestBuilder& {
  230. if (handler) {
  231. [[maybe_unused]] auto &silence_warning = _builder.done(std::move(handler));
  232. }
  233. return *this;
  234. }
  235. template <typename Request>
  236. auto ApiWrap::RequestBuilder<Request>::fail(
  237. Fn<bool(const MTP::Error &)> &&handler
  238. ) -> RequestBuilder& {
  239. if (handler) {
  240. [[maybe_unused]] auto &silence_warning = _builder.fail([
  241. common = base::take(_commonFailHandler),
  242. specific = std::move(handler)
  243. ](const MTP::Error &error) {
  244. if (!specific(error)) {
  245. common(error);
  246. }
  247. });
  248. }
  249. return *this;
  250. }
  251. template <typename Request>
  252. mtpRequestId ApiWrap::RequestBuilder<Request>::send() {
  253. return _commonFailHandler
  254. ? _builder.fail(base::take(_commonFailHandler)).send()
  255. : _builder.send();
  256. }
  257. ApiWrap::LoadedFileCache::LoadedFileCache(int limit) : _limit(limit) {
  258. Expects(limit >= 0);
  259. }
  260. void ApiWrap::LoadedFileCache::save(
  261. const Location &location,
  262. const QString &relativePath) {
  263. if (!location) {
  264. return;
  265. }
  266. const auto key = ComputeLocationKey(location);
  267. _map[key] = relativePath;
  268. _list.push_back(key);
  269. if (_list.size() > _limit) {
  270. const auto key = _list.front();
  271. _list.pop_front();
  272. _map.erase(key);
  273. }
  274. }
  275. std::optional<QString> ApiWrap::LoadedFileCache::find(
  276. const Location &location) const {
  277. if (!location) {
  278. return std::nullopt;
  279. }
  280. const auto key = ComputeLocationKey(location);
  281. if (const auto i = _map.find(key); i != end(_map)) {
  282. return i->second;
  283. }
  284. return std::nullopt;
  285. }
  286. ApiWrap::FileProcess::FileProcess(const QString &path, Output::Stats *stats)
  287. : file(path, stats) {
  288. }
  289. template <typename Request>
  290. auto ApiWrap::mainRequest(Request &&request) {
  291. Expects(_takeoutId.has_value());
  292. auto original = std::move(_mtp.request(MTPInvokeWithTakeout<Request>(
  293. MTP_long(*_takeoutId),
  294. std::forward<Request>(request)
  295. )).toDC(MTP::ShiftDcId(0, MTP::kExportDcShift)));
  296. return RequestBuilder<MTPInvokeWithTakeout<Request>>(
  297. std::move(original),
  298. [=](const MTP::Error &result) { error(result); });
  299. }
  300. template <typename Request>
  301. auto ApiWrap::splitRequest(int index, Request &&request) {
  302. Expects(index < _splits.size());
  303. //if (index == _splits.size() - 1) {
  304. // return mainRequest(std::forward<Request>(request));
  305. //}
  306. return mainRequest(MTPInvokeWithMessagesRange<Request>(
  307. _splits[index],
  308. std::forward<Request>(request)));
  309. }
  310. auto ApiWrap::fileRequest(const Data::FileLocation &location, int64 offset) {
  311. Expects(location.dcId != 0
  312. || location.data.type() == mtpc_inputTakeoutFileLocation);
  313. Expects(_takeoutId.has_value());
  314. Expects(_fileProcess->requestId == 0);
  315. return std::move(_mtp.request(MTPInvokeWithTakeout<MTPupload_GetFile>(
  316. MTP_long(*_takeoutId),
  317. MTPupload_GetFile(
  318. MTP_flags(0),
  319. location.data,
  320. MTP_long(offset),
  321. MTP_int(kFileChunkSize))
  322. )).fail([=](const MTP::Error &result) {
  323. _fileProcess->requestId = 0;
  324. if (result.type() == u"TAKEOUT_FILE_EMPTY"_q
  325. && _otherDataProcess != nullptr) {
  326. filePartDone(
  327. 0,
  328. MTP_upload_file(
  329. MTP_storage_filePartial(),
  330. MTP_int(0),
  331. MTP_bytes()));
  332. } else if (result.type() == u"LOCATION_INVALID"_q
  333. || result.type() == u"VERSION_INVALID"_q
  334. || result.type() == u"LOCATION_NOT_AVAILABLE"_q) {
  335. filePartUnavailable();
  336. } else if (result.code() == 400
  337. && result.type().startsWith(u"FILE_REFERENCE_"_q)) {
  338. filePartRefreshReference(offset);
  339. } else {
  340. error(std::move(result));
  341. }
  342. }).toDC(MTP::ShiftDcId(location.dcId, MTP::kExportMediaDcShift)));
  343. }
  344. ApiWrap::ApiWrap(QPointer<MTP::Instance> weak, Fn<void(FnMut<void()>)> runner)
  345. : _mtp(weak, std::move(runner))
  346. , _fileCache(std::make_unique<LoadedFileCache>(kLocationCacheSize)) {
  347. }
  348. rpl::producer<MTP::Error> ApiWrap::errors() const {
  349. return _errors.events();
  350. }
  351. rpl::producer<Output::Result> ApiWrap::ioErrors() const {
  352. return _ioErrors.events();
  353. }
  354. void ApiWrap::startExport(
  355. const Settings &settings,
  356. Output::Stats *stats,
  357. FnMut<void(StartInfo)> done) {
  358. Expects(_settings == nullptr);
  359. Expects(_startProcess == nullptr);
  360. _settings = std::make_unique<Settings>(settings);
  361. _stats = stats;
  362. _startProcess = std::make_unique<StartProcess>();
  363. _startProcess->done = std::move(done);
  364. using Step = StartProcess::Step;
  365. if (_settings->types & Settings::Type::Userpics) {
  366. _startProcess->steps.push_back(Step::UserpicsCount);
  367. }
  368. if (_settings->types & Settings::Type::Stories) {
  369. _startProcess->steps.push_back(Step::StoriesCount);
  370. }
  371. if (_settings->types & Settings::Type::AnyChatsMask) {
  372. _startProcess->steps.push_back(Step::SplitRanges);
  373. _startProcess->steps.push_back(Step::DialogsCount);
  374. }
  375. if (_settings->types & Settings::Type::GroupsChannelsMask) {
  376. if (!_settings->onlySinglePeer()) {
  377. _startProcess->steps.push_back(Step::LeftChannelsCount);
  378. }
  379. }
  380. startMainSession([=] {
  381. sendNextStartRequest();
  382. });
  383. }
  384. void ApiWrap::sendNextStartRequest() {
  385. Expects(_startProcess != nullptr);
  386. auto &steps = _startProcess->steps;
  387. if (steps.empty()) {
  388. finishStartProcess();
  389. return;
  390. }
  391. using Step = StartProcess::Step;
  392. const auto step = steps.front();
  393. steps.pop_front();
  394. switch (step) {
  395. case Step::UserpicsCount:
  396. return requestUserpicsCount();
  397. case Step::StoriesCount:
  398. return requestStoriesCount();
  399. case Step::SplitRanges:
  400. return requestSplitRanges();
  401. case Step::DialogsCount:
  402. return requestDialogsCount();
  403. case Step::LeftChannelsCount:
  404. return requestLeftChannelsCount();
  405. }
  406. Unexpected("Step in ApiWrap::sendNextStartRequest.");
  407. }
  408. void ApiWrap::requestUserpicsCount() {
  409. Expects(_startProcess != nullptr);
  410. mainRequest(MTPphotos_GetUserPhotos(
  411. _user,
  412. MTP_int(0), // offset
  413. MTP_long(0), // max_id
  414. MTP_int(0) // limit
  415. )).done([=](const MTPphotos_Photos &result) {
  416. Expects(_settings != nullptr);
  417. Expects(_startProcess != nullptr);
  418. _startProcess->info.userpicsCount = result.match(
  419. [](const MTPDphotos_photos &data) {
  420. return int(data.vphotos().v.size());
  421. }, [](const MTPDphotos_photosSlice &data) {
  422. return data.vcount().v;
  423. });
  424. sendNextStartRequest();
  425. }).send();
  426. }
  427. void ApiWrap::requestStoriesCount() {
  428. Expects(_startProcess != nullptr);
  429. mainRequest(MTPstories_GetStoriesArchive(
  430. MTP_inputPeerSelf(),
  431. MTP_int(0), // offset_id
  432. MTP_int(0) // limit
  433. )).done([=](const MTPstories_Stories &result) {
  434. Expects(_settings != nullptr);
  435. Expects(_startProcess != nullptr);
  436. _startProcess->info.storiesCount = result.data().vcount().v;
  437. sendNextStartRequest();
  438. }).send();
  439. }
  440. void ApiWrap::requestSplitRanges() {
  441. Expects(_startProcess != nullptr);
  442. mainRequest(MTPmessages_GetSplitRanges(
  443. )).done([=](const MTPVector<MTPMessageRange> &result) {
  444. _splits = result.v;
  445. if (_splits.empty()) {
  446. _splits.push_back(MTP_messageRange(
  447. MTP_int(1),
  448. MTP_int(std::numeric_limits<int>::max())));
  449. }
  450. _startProcess->splitIndex = useOnlyLastSplit()
  451. ? (_splits.size() - 1)
  452. : 0;
  453. sendNextStartRequest();
  454. }).send();
  455. }
  456. void ApiWrap::requestDialogsCount() {
  457. Expects(_startProcess != nullptr);
  458. if (_settings->onlySinglePeer()) {
  459. _startProcess->info.dialogsCount
  460. = (_settings->singlePeer.type() == mtpc_inputPeerChannel
  461. ? 1
  462. : _splits.size());
  463. sendNextStartRequest();
  464. return;
  465. }
  466. const auto offsetDate = 0;
  467. const auto offsetId = 0;
  468. const auto offsetPeer = MTP_inputPeerEmpty();
  469. const auto limit = 1;
  470. const auto hash = uint64(0);
  471. splitRequest(_startProcess->splitIndex, MTPmessages_GetDialogs(
  472. MTP_flags(0),
  473. MTPint(), // folder_id
  474. MTP_int(offsetDate),
  475. MTP_int(offsetId),
  476. offsetPeer,
  477. MTP_int(limit),
  478. MTP_long(hash)
  479. )).done([=](const MTPmessages_Dialogs &result) {
  480. Expects(_settings != nullptr);
  481. Expects(_startProcess != nullptr);
  482. const auto count = result.match(
  483. [](const MTPDmessages_dialogs &data) {
  484. return int(data.vdialogs().v.size());
  485. }, [](const MTPDmessages_dialogsSlice &data) {
  486. return data.vcount().v;
  487. }, [](const MTPDmessages_dialogsNotModified &data) {
  488. return -1;
  489. });
  490. if (count < 0) {
  491. error("Unexpected dialogsNotModified received.");
  492. return;
  493. }
  494. _startProcess->info.dialogsCount += count;
  495. if (++_startProcess->splitIndex >= _splits.size()) {
  496. sendNextStartRequest();
  497. } else {
  498. requestDialogsCount();
  499. }
  500. }).send();
  501. }
  502. void ApiWrap::requestLeftChannelsCount() {
  503. Expects(_startProcess != nullptr);
  504. Expects(_leftChannelsProcess == nullptr);
  505. _leftChannelsProcess = std::make_unique<LeftChannelsProcess>();
  506. requestLeftChannelsSliceGeneric([=] {
  507. Expects(_startProcess != nullptr);
  508. Expects(_leftChannelsProcess != nullptr);
  509. _startProcess->info.dialogsCount
  510. += _leftChannelsProcess->fullCount;
  511. sendNextStartRequest();
  512. });
  513. }
  514. void ApiWrap::finishStartProcess() {
  515. Expects(_startProcess != nullptr);
  516. const auto process = base::take(_startProcess);
  517. process->done(process->info);
  518. }
  519. bool ApiWrap::useOnlyLastSplit() const {
  520. return !(_settings->types & Settings::Type::NonChannelChatsMask);
  521. }
  522. void ApiWrap::requestLeftChannelsList(
  523. Fn<bool(int count)> progress,
  524. FnMut<void(Data::DialogsInfo&&)> done) {
  525. Expects(_leftChannelsProcess != nullptr);
  526. _leftChannelsProcess->progress = std::move(progress);
  527. _leftChannelsProcess->done = std::move(done);
  528. requestLeftChannelsSlice();
  529. }
  530. void ApiWrap::requestLeftChannelsSlice() {
  531. requestLeftChannelsSliceGeneric([=] {
  532. Expects(_leftChannelsProcess != nullptr);
  533. if (_leftChannelsProcess->finished) {
  534. const auto process = base::take(_leftChannelsProcess);
  535. process->done(std::move(process->info));
  536. } else {
  537. requestLeftChannelsSlice();
  538. }
  539. });
  540. }
  541. void ApiWrap::requestDialogsList(
  542. Fn<bool(int count)> progress,
  543. FnMut<void(Data::DialogsInfo&&)> done) {
  544. Expects(_dialogsProcess == nullptr);
  545. _dialogsProcess = std::make_unique<DialogsProcess>();
  546. _dialogsProcess->splitIndexPlusOne = _splits.size();
  547. _dialogsProcess->progress = std::move(progress);
  548. _dialogsProcess->done = std::move(done);
  549. requestDialogsSlice();
  550. }
  551. void ApiWrap::startMainSession(FnMut<void()> done) {
  552. using Type = Settings::Type;
  553. const auto sizeLimit = _settings->media.sizeLimit;
  554. const auto hasFiles = ((_settings->media.types != 0) && (sizeLimit > 0))
  555. || (_settings->types & Type::Userpics)
  556. || (_settings->types & Type::Stories);
  557. using Flag = MTPaccount_InitTakeoutSession::Flag;
  558. const auto flags = Flag(0)
  559. | (_settings->types & Type::Contacts ? Flag::f_contacts : Flag(0))
  560. | (hasFiles ? Flag::f_files : Flag(0))
  561. | ((hasFiles && sizeLimit < kFileMaxSize)
  562. ? Flag::f_file_max_size
  563. : Flag(0))
  564. | (_settings->types & (Type::PersonalChats | Type::BotChats)
  565. ? Flag::f_message_users
  566. : Flag(0))
  567. | (_settings->types & Type::PrivateGroups
  568. ? (Flag::f_message_chats | Flag::f_message_megagroups)
  569. : Flag(0))
  570. | (_settings->types & Type::PublicGroups
  571. ? Flag::f_message_megagroups
  572. : Flag(0))
  573. | (_settings->types & (Type::PrivateChannels | Type::PublicChannels)
  574. ? Flag::f_message_channels
  575. : Flag(0));
  576. _mtp.request(MTPusers_GetUsers(
  577. MTP_vector<MTPInputUser>(1, MTP_inputUserSelf())
  578. )).done([=, done = std::move(done)](
  579. const MTPVector<MTPUser> &result) mutable {
  580. for (const auto &user : result.v) {
  581. user.match([&](const MTPDuser &data) {
  582. if (data.is_self()) {
  583. _selfId.emplace(data.vid());
  584. }
  585. }, [&](const MTPDuserEmpty&) {
  586. });
  587. }
  588. if (!_selfId) {
  589. error("Could not retrieve selfId.");
  590. return;
  591. }
  592. _mtp.request(MTPaccount_InitTakeoutSession(
  593. MTP_flags(flags),
  594. MTP_long(sizeLimit)
  595. )).done([=, done = std::move(done)](
  596. const MTPaccount_Takeout &result) mutable {
  597. _takeoutId = result.match([](const MTPDaccount_takeout &data) {
  598. return data.vid().v;
  599. });
  600. done();
  601. }).fail([=](const MTP::Error &result) {
  602. error(result);
  603. }).toDC(MTP::ShiftDcId(0, MTP::kExportDcShift)).send();
  604. }).fail([=](const MTP::Error &result) {
  605. error(result);
  606. }).send();
  607. }
  608. void ApiWrap::requestPersonalInfo(FnMut<void(Data::PersonalInfo&&)> done) {
  609. mainRequest(MTPusers_GetFullUser(
  610. _user
  611. )).done([=, done = std::move(done)](const MTPusers_UserFull &result) mutable {
  612. result.match([&](const MTPDusers_userFull &data) {
  613. if (!data.vusers().v.empty()) {
  614. done(Data::ParsePersonalInfo(data));
  615. } else {
  616. error("Bad user type.");
  617. }
  618. });
  619. }).send();
  620. }
  621. void ApiWrap::requestOtherData(
  622. const QString &suggestedPath,
  623. FnMut<void(Data::File&&)> done) {
  624. Expects(_otherDataProcess == nullptr);
  625. _otherDataProcess = std::make_unique<OtherDataProcess>();
  626. _otherDataProcess->done = std::move(done);
  627. _otherDataProcess->file.location.data = MTP_inputTakeoutFileLocation();
  628. _otherDataProcess->file.suggestedPath = suggestedPath;
  629. loadFile(
  630. _otherDataProcess->file,
  631. Data::FileOrigin(),
  632. [](FileProgress progress) { return true; },
  633. [=](const QString &result) { otherDataDone(result); });
  634. }
  635. void ApiWrap::otherDataDone(const QString &relativePath) {
  636. Expects(_otherDataProcess != nullptr);
  637. const auto process = base::take(_otherDataProcess);
  638. process->file.relativePath = relativePath;
  639. if (relativePath.isEmpty()) {
  640. process->file.skipReason = Data::File::SkipReason::Unavailable;
  641. }
  642. process->done(std::move(process->file));
  643. }
  644. void ApiWrap::requestUserpics(
  645. FnMut<bool(Data::UserpicsInfo&&)> start,
  646. Fn<bool(DownloadProgress)> progress,
  647. Fn<bool(Data::UserpicsSlice&&)> slice,
  648. FnMut<void()> finish) {
  649. Expects(_userpicsProcess == nullptr);
  650. _userpicsProcess = std::make_unique<UserpicsProcess>();
  651. _userpicsProcess->start = std::move(start);
  652. _userpicsProcess->fileProgress = std::move(progress);
  653. _userpicsProcess->handleSlice = std::move(slice);
  654. _userpicsProcess->finish = std::move(finish);
  655. mainRequest(MTPphotos_GetUserPhotos(
  656. _user,
  657. MTP_int(0), // offset
  658. MTP_long(_userpicsProcess->maxId),
  659. MTP_int(kUserpicsSliceLimit)
  660. )).done([=](const MTPphotos_Photos &result) mutable {
  661. Expects(_userpicsProcess != nullptr);
  662. auto startInfo = result.match(
  663. [](const MTPDphotos_photos &data) {
  664. return Data::UserpicsInfo{ int(data.vphotos().v.size()) };
  665. }, [](const MTPDphotos_photosSlice &data) {
  666. return Data::UserpicsInfo{ data.vcount().v };
  667. });
  668. if (!_userpicsProcess->start(std::move(startInfo))) {
  669. return;
  670. }
  671. handleUserpicsSlice(result);
  672. }).send();
  673. }
  674. void ApiWrap::handleUserpicsSlice(const MTPphotos_Photos &result) {
  675. Expects(_userpicsProcess != nullptr);
  676. result.match([&](const auto &data) {
  677. if constexpr (MTPDphotos_photos::Is<decltype(data)>()) {
  678. _userpicsProcess->lastSlice = true;
  679. }
  680. loadUserpicsFiles(Data::ParseUserpicsSlice(
  681. data.vphotos(),
  682. _userpicsProcess->processed));
  683. });
  684. }
  685. void ApiWrap::loadUserpicsFiles(Data::UserpicsSlice &&slice) {
  686. Expects(_userpicsProcess != nullptr);
  687. Expects(!_userpicsProcess->slice.has_value());
  688. if (slice.list.empty()) {
  689. _userpicsProcess->lastSlice = true;
  690. }
  691. _userpicsProcess->slice = std::move(slice);
  692. _userpicsProcess->fileIndex = 0;
  693. loadNextUserpic();
  694. }
  695. void ApiWrap::loadNextUserpic() {
  696. Expects(_userpicsProcess != nullptr);
  697. Expects(_userpicsProcess->slice.has_value());
  698. for (auto &list = _userpicsProcess->slice->list
  699. ; _userpicsProcess->fileIndex < list.size()
  700. ; ++_userpicsProcess->fileIndex) {
  701. const auto ready = processFileLoad(
  702. list[_userpicsProcess->fileIndex].image.file,
  703. Data::FileOrigin(),
  704. [=](FileProgress value) { return loadUserpicProgress(value); },
  705. [=](const QString &path) { loadUserpicDone(path); });
  706. if (!ready) {
  707. return;
  708. }
  709. }
  710. finishUserpicsSlice();
  711. }
  712. void ApiWrap::finishUserpicsSlice() {
  713. Expects(_userpicsProcess != nullptr);
  714. Expects(_userpicsProcess->slice.has_value());
  715. auto slice = *base::take(_userpicsProcess->slice);
  716. if (!slice.list.empty()) {
  717. _userpicsProcess->processed += slice.list.size();
  718. _userpicsProcess->maxId = slice.list.back().id;
  719. if (!_userpicsProcess->handleSlice(std::move(slice))) {
  720. return;
  721. }
  722. }
  723. if (_userpicsProcess->lastSlice) {
  724. finishUserpics();
  725. return;
  726. }
  727. mainRequest(MTPphotos_GetUserPhotos(
  728. _user,
  729. MTP_int(0), // offset
  730. MTP_long(_userpicsProcess->maxId),
  731. MTP_int(kUserpicsSliceLimit)
  732. )).done([=](const MTPphotos_Photos &result) {
  733. handleUserpicsSlice(result);
  734. }).send();
  735. }
  736. bool ApiWrap::loadUserpicProgress(FileProgress progress) {
  737. Expects(_fileProcess != nullptr);
  738. Expects(_userpicsProcess != nullptr);
  739. Expects(_userpicsProcess->slice.has_value());
  740. Expects((_userpicsProcess->fileIndex >= 0)
  741. && (_userpicsProcess->fileIndex
  742. < _userpicsProcess->slice->list.size()));
  743. return _userpicsProcess->fileProgress(DownloadProgress{
  744. _fileProcess->randomId,
  745. _fileProcess->relativePath,
  746. _userpicsProcess->fileIndex,
  747. progress.ready,
  748. progress.total });
  749. }
  750. void ApiWrap::loadUserpicDone(const QString &relativePath) {
  751. Expects(_userpicsProcess != nullptr);
  752. Expects(_userpicsProcess->slice.has_value());
  753. Expects((_userpicsProcess->fileIndex >= 0)
  754. && (_userpicsProcess->fileIndex
  755. < _userpicsProcess->slice->list.size()));
  756. const auto index = _userpicsProcess->fileIndex;
  757. auto &file = _userpicsProcess->slice->list[index].image.file;
  758. file.relativePath = relativePath;
  759. if (relativePath.isEmpty()) {
  760. file.skipReason = Data::File::SkipReason::Unavailable;
  761. }
  762. loadNextUserpic();
  763. }
  764. void ApiWrap::finishUserpics() {
  765. Expects(_userpicsProcess != nullptr);
  766. base::take(_userpicsProcess)->finish();
  767. }
  768. void ApiWrap::requestStories(
  769. FnMut<bool(Data::StoriesInfo&&)> start,
  770. Fn<bool(DownloadProgress)> progress,
  771. Fn<bool(Data::StoriesSlice&&)> slice,
  772. FnMut<void()> finish) {
  773. Expects(_storiesProcess == nullptr);
  774. _storiesProcess = std::make_unique<StoriesProcess>();
  775. _storiesProcess->start = std::move(start);
  776. _storiesProcess->fileProgress = std::move(progress);
  777. _storiesProcess->handleSlice = std::move(slice);
  778. _storiesProcess->finish = std::move(finish);
  779. mainRequest(MTPstories_GetStoriesArchive(
  780. MTP_inputPeerSelf(),
  781. MTP_int(_storiesProcess->offsetId),
  782. MTP_int(kStoriesSliceLimit)
  783. )).done([=](const MTPstories_Stories &result) mutable {
  784. Expects(_storiesProcess != nullptr);
  785. auto startInfo = Data::StoriesInfo{ result.data().vcount().v };
  786. if (!_storiesProcess->start(std::move(startInfo))) {
  787. return;
  788. }
  789. handleStoriesSlice(result);
  790. }).send();
  791. }
  792. void ApiWrap::handleStoriesSlice(const MTPstories_Stories &result) {
  793. Expects(_storiesProcess != nullptr);
  794. loadStoriesFiles(Data::ParseStoriesSlice(
  795. result.data().vstories(),
  796. _storiesProcess->processed));
  797. }
  798. void ApiWrap::loadStoriesFiles(Data::StoriesSlice &&slice) {
  799. Expects(_storiesProcess != nullptr);
  800. Expects(!_storiesProcess->slice.has_value());
  801. if (!slice.lastId) {
  802. _storiesProcess->lastSlice = true;
  803. }
  804. _storiesProcess->slice = std::move(slice);
  805. _storiesProcess->fileIndex = 0;
  806. loadNextStory();
  807. }
  808. void ApiWrap::loadNextStory() {
  809. Expects(_storiesProcess != nullptr);
  810. Expects(_storiesProcess->slice.has_value());
  811. for (auto &list = _storiesProcess->slice->list
  812. ; _storiesProcess->fileIndex < list.size()
  813. ; ++_storiesProcess->fileIndex) {
  814. auto &story = list[_storiesProcess->fileIndex];
  815. const auto origin = Data::FileOrigin{ .storyId = story.id };
  816. const auto ready = processFileLoad(
  817. story.file(),
  818. origin,
  819. [=](FileProgress value) { return loadStoryProgress(value); },
  820. [=](const QString &path) { loadStoryDone(path); });
  821. if (!ready) {
  822. return;
  823. }
  824. const auto thumbProgress = [=](FileProgress value) {
  825. return loadStoryThumbProgress(value);
  826. };
  827. const auto thumbReady = processFileLoad(
  828. story.thumb().file,
  829. origin,
  830. thumbProgress,
  831. [=](const QString &path) { loadStoryThumbDone(path); },
  832. nullptr,
  833. &story);
  834. if (!thumbReady) {
  835. return;
  836. }
  837. }
  838. finishStoriesSlice();
  839. }
  840. void ApiWrap::finishStoriesSlice() {
  841. Expects(_storiesProcess != nullptr);
  842. Expects(_storiesProcess->slice.has_value());
  843. auto slice = *base::take(_storiesProcess->slice);
  844. if (slice.lastId) {
  845. _storiesProcess->processed += slice.list.size();
  846. _storiesProcess->offsetId = slice.lastId;
  847. if (!_storiesProcess->handleSlice(std::move(slice))) {
  848. return;
  849. }
  850. }
  851. if (_storiesProcess->lastSlice) {
  852. finishStories();
  853. return;
  854. }
  855. mainRequest(MTPstories_GetStoriesArchive(
  856. MTP_inputPeerSelf(),
  857. MTP_int(_storiesProcess->offsetId),
  858. MTP_int(kStoriesSliceLimit)
  859. )).done([=](const MTPstories_Stories &result) {
  860. handleStoriesSlice(result);
  861. }).send();
  862. }
  863. bool ApiWrap::loadStoryProgress(FileProgress progress) {
  864. Expects(_fileProcess != nullptr);
  865. Expects(_storiesProcess != nullptr);
  866. Expects(_storiesProcess->slice.has_value());
  867. Expects((_storiesProcess->fileIndex >= 0)
  868. && (_storiesProcess->fileIndex
  869. < _storiesProcess->slice->list.size()));
  870. return _storiesProcess->fileProgress(DownloadProgress{
  871. _fileProcess->randomId,
  872. _fileProcess->relativePath,
  873. _storiesProcess->fileIndex,
  874. progress.ready,
  875. progress.total });
  876. }
  877. void ApiWrap::loadStoryDone(const QString &relativePath) {
  878. Expects(_storiesProcess != nullptr);
  879. Expects(_storiesProcess->slice.has_value());
  880. Expects((_storiesProcess->fileIndex >= 0)
  881. && (_storiesProcess->fileIndex
  882. < _storiesProcess->slice->list.size()));
  883. const auto index = _storiesProcess->fileIndex;
  884. auto &file = _storiesProcess->slice->list[index].file();
  885. file.relativePath = relativePath;
  886. if (relativePath.isEmpty()) {
  887. file.skipReason = Data::File::SkipReason::Unavailable;
  888. }
  889. loadNextStory();
  890. }
  891. bool ApiWrap::loadStoryThumbProgress(FileProgress progress) {
  892. return loadStoryProgress(progress);
  893. }
  894. void ApiWrap::loadStoryThumbDone(const QString &relativePath) {
  895. Expects(_storiesProcess != nullptr);
  896. Expects(_storiesProcess->slice.has_value());
  897. Expects((_storiesProcess->fileIndex >= 0)
  898. && (_storiesProcess->fileIndex
  899. < _storiesProcess->slice->list.size()));
  900. const auto index = _storiesProcess->fileIndex;
  901. auto &file = _storiesProcess->slice->list[index].thumb().file;
  902. file.relativePath = relativePath;
  903. if (relativePath.isEmpty()) {
  904. file.skipReason = Data::File::SkipReason::Unavailable;
  905. }
  906. loadNextStory();
  907. }
  908. void ApiWrap::finishStories() {
  909. Expects(_storiesProcess != nullptr);
  910. base::take(_storiesProcess)->finish();
  911. }
  912. void ApiWrap::requestContacts(FnMut<void(Data::ContactsList&&)> done) {
  913. Expects(_contactsProcess == nullptr);
  914. _contactsProcess = std::make_unique<ContactsProcess>();
  915. _contactsProcess->done = std::move(done);
  916. mainRequest(MTPcontacts_GetSaved(
  917. )).done([=](const MTPVector<MTPSavedContact> &result) {
  918. _contactsProcess->result = Data::ParseContactsList(result);
  919. const auto resolve = [=](int index, const auto &resolveNext) -> void {
  920. if (index == _contactsProcess->result.list.size()) {
  921. return requestTopPeersSlice();
  922. }
  923. const auto &contact = _contactsProcess->result.list[index];
  924. mainRequest(MTPcontacts_ResolvePhone(
  925. MTP_string(qs(contact.phoneNumber))
  926. )).done([=](const MTPcontacts_ResolvedPeer &result) {
  927. auto &contact = _contactsProcess->result.list[index];
  928. contact.userId = result.data().vpeer().match([&](
  929. const MTPDpeerUser &user) {
  930. return UserId(user.vuser_id());
  931. }, [](const auto &) {
  932. return UserId();
  933. });
  934. resolveNext(index + 1, resolveNext);
  935. }).fail([=](const MTP::Error &) {
  936. resolveNext(index + 1, resolveNext);
  937. return true;
  938. }).send();
  939. };
  940. if (base::options::lookup<bool>("show-peer-id-below-about").value()) {
  941. resolve(0, resolve);
  942. } else {
  943. requestTopPeersSlice();
  944. }
  945. }).send();
  946. }
  947. void ApiWrap::requestTopPeersSlice() {
  948. Expects(_contactsProcess != nullptr);
  949. using Flag = MTPcontacts_GetTopPeers::Flag;
  950. mainRequest(MTPcontacts_GetTopPeers(
  951. MTP_flags(Flag::f_correspondents
  952. | Flag::f_bots_inline
  953. | Flag::f_phone_calls),
  954. MTP_int(_contactsProcess->topPeersOffset),
  955. MTP_int(kTopPeerSliceLimit),
  956. MTP_long(0) // hash
  957. )).done([=](const MTPcontacts_TopPeers &result) {
  958. Expects(_contactsProcess != nullptr);
  959. if (!Data::AppendTopPeers(_contactsProcess->result, result)) {
  960. error("Unexpected data in ApiWrap::requestTopPeersSlice.");
  961. return;
  962. }
  963. const auto offset = _contactsProcess->topPeersOffset;
  964. const auto loaded = result.match(
  965. [](const MTPDcontacts_topPeersNotModified &data) {
  966. return true;
  967. }, [](const MTPDcontacts_topPeersDisabled &data) {
  968. return true;
  969. }, [&](const MTPDcontacts_topPeers &data) {
  970. for (const auto &category : data.vcategories().v) {
  971. const auto loaded = category.match(
  972. [&](const MTPDtopPeerCategoryPeers &data) {
  973. return offset + data.vpeers().v.size() >= data.vcount().v;
  974. });
  975. if (!loaded) {
  976. return false;
  977. }
  978. }
  979. return true;
  980. });
  981. if (loaded) {
  982. auto process = base::take(_contactsProcess);
  983. process->done(std::move(process->result));
  984. } else {
  985. _contactsProcess->topPeersOffset = std::max(std::max(
  986. _contactsProcess->result.correspondents.size(),
  987. _contactsProcess->result.inlineBots.size()),
  988. _contactsProcess->result.phoneCalls.size());
  989. requestTopPeersSlice();
  990. }
  991. }).send();
  992. }
  993. void ApiWrap::requestSessions(FnMut<void(Data::SessionsList&&)> done) {
  994. mainRequest(MTPaccount_GetAuthorizations(
  995. )).done([=, done = std::move(done)](
  996. const MTPaccount_Authorizations &result) mutable {
  997. auto list = Data::ParseSessionsList(result);
  998. mainRequest(MTPaccount_GetWebAuthorizations(
  999. )).done([=, done = std::move(done), list = std::move(list)](
  1000. const MTPaccount_WebAuthorizations &result) mutable {
  1001. list.webList = Data::ParseWebSessionsList(result).webList;
  1002. done(std::move(list));
  1003. }).send();
  1004. }).send();
  1005. }
  1006. void ApiWrap::requestMessages(
  1007. const Data::DialogInfo &info,
  1008. FnMut<bool(const Data::DialogInfo &)> start,
  1009. Fn<bool(DownloadProgress)> progress,
  1010. Fn<bool(Data::MessagesSlice&&)> slice,
  1011. FnMut<void()> done) {
  1012. Expects(_chatProcess == nullptr);
  1013. Expects(_selfId.has_value());
  1014. _chatProcess = std::make_unique<ChatProcess>();
  1015. _chatProcess->context.selfPeerId = peerFromUser(*_selfId);
  1016. _chatProcess->info = info;
  1017. _chatProcess->start = std::move(start);
  1018. _chatProcess->fileProgress = std::move(progress);
  1019. _chatProcess->handleSlice = std::move(slice);
  1020. _chatProcess->done = std::move(done);
  1021. requestMessagesCount(0);
  1022. }
  1023. void ApiWrap::requestMessagesCount(int localSplitIndex) {
  1024. Expects(_chatProcess != nullptr);
  1025. Expects(localSplitIndex < _chatProcess->info.splits.size());
  1026. requestChatMessages(
  1027. _chatProcess->info.splits[localSplitIndex],
  1028. 0, // offset_id
  1029. 0, // add_offset
  1030. 1, // limit
  1031. [=](const MTPmessages_Messages &result) {
  1032. Expects(_chatProcess != nullptr);
  1033. const auto count = result.match(
  1034. [](const MTPDmessages_messages &data) {
  1035. return int(data.vmessages().v.size());
  1036. }, [](const MTPDmessages_messagesSlice &data) {
  1037. return data.vcount().v;
  1038. }, [](const MTPDmessages_channelMessages &data) {
  1039. return data.vcount().v;
  1040. }, [](const MTPDmessages_messagesNotModified &data) {
  1041. return -1;
  1042. });
  1043. if (count < 0) {
  1044. error("Unexpected messagesNotModified received.");
  1045. return;
  1046. }
  1047. const auto skipSplit = !Data::SingleMessageAfter(
  1048. result,
  1049. _settings->singlePeerFrom);
  1050. if (skipSplit) {
  1051. // No messages from the requested range, skip this split.
  1052. messagesCountLoaded(localSplitIndex, 0);
  1053. return;
  1054. }
  1055. checkFirstMessageDate(localSplitIndex, count);
  1056. });
  1057. }
  1058. void ApiWrap::checkFirstMessageDate(int localSplitIndex, int count) {
  1059. Expects(_chatProcess != nullptr);
  1060. Expects(localSplitIndex < _chatProcess->info.splits.size());
  1061. if (_settings->singlePeerTill <= 0) {
  1062. messagesCountLoaded(localSplitIndex, count);
  1063. return;
  1064. }
  1065. // Request first message in this split to check if its' date < till.
  1066. requestChatMessages(
  1067. _chatProcess->info.splits[localSplitIndex],
  1068. 1, // offset_id
  1069. -1, // add_offset
  1070. 1, // limit
  1071. [=](const MTPmessages_Messages &result) {
  1072. Expects(_chatProcess != nullptr);
  1073. const auto skipSplit = !Data::SingleMessageBefore(
  1074. result,
  1075. _settings->singlePeerTill);
  1076. messagesCountLoaded(localSplitIndex, skipSplit ? 0 : count);
  1077. });
  1078. }
  1079. void ApiWrap::messagesCountLoaded(int localSplitIndex, int count) {
  1080. Expects(_chatProcess != nullptr);
  1081. Expects(localSplitIndex < _chatProcess->info.splits.size());
  1082. _chatProcess->info.messagesCountPerSplit[localSplitIndex] = count;
  1083. if (localSplitIndex + 1 < _chatProcess->info.splits.size()) {
  1084. requestMessagesCount(localSplitIndex + 1);
  1085. } else if (_chatProcess->start(_chatProcess->info)) {
  1086. requestMessagesSlice();
  1087. }
  1088. }
  1089. void ApiWrap::finishExport(FnMut<void()> done) {
  1090. const auto guard = gsl::finally([&] { _takeoutId = std::nullopt; });
  1091. mainRequest(MTPaccount_FinishTakeoutSession(
  1092. MTP_flags(MTPaccount_FinishTakeoutSession::Flag::f_success)
  1093. )).done(std::move(done)).send();
  1094. }
  1095. void ApiWrap::skipFile(uint64 randomId) {
  1096. if (!_fileProcess || _fileProcess->randomId != randomId) {
  1097. return;
  1098. }
  1099. LOG(("Export Info: File skipped."));
  1100. Assert(!_fileProcess->requests.empty());
  1101. Assert(_fileProcess->requestId != 0);
  1102. _mtp.request(base::take(_fileProcess->requestId)).cancel();
  1103. base::take(_fileProcess)->done(QString());
  1104. }
  1105. void ApiWrap::cancelExportFast() {
  1106. if (_takeoutId.has_value()) {
  1107. const auto requestId = mainRequest(MTPaccount_FinishTakeoutSession(
  1108. MTP_flags(0)
  1109. )).send();
  1110. _mtp.request(requestId).detach();
  1111. }
  1112. }
  1113. void ApiWrap::requestSinglePeerDialog() {
  1114. auto doneSinglePeer = [=](const auto &result) {
  1115. appendSinglePeerDialogs(
  1116. Data::ParseDialogsInfo(_settings->singlePeer, result));
  1117. };
  1118. const auto requestUser = [&](const MTPInputUser &data) {
  1119. mainRequest(MTPusers_GetUsers(
  1120. MTP_vector<MTPInputUser>(1, data)
  1121. )).done(std::move(doneSinglePeer)).send();
  1122. };
  1123. _settings->singlePeer.match([&](const MTPDinputPeerUser &data) {
  1124. requestUser(MTP_inputUser(data.vuser_id(), data.vaccess_hash()));
  1125. }, [&](const MTPDinputPeerChat &data) {
  1126. mainRequest(MTPmessages_GetChats(
  1127. MTP_vector<MTPlong>(1, data.vchat_id())
  1128. )).done(std::move(doneSinglePeer)).send();
  1129. }, [&](const MTPDinputPeerChannel &data) {
  1130. mainRequest(MTPchannels_GetChannels(
  1131. MTP_vector<MTPInputChannel>(
  1132. 1,
  1133. MTP_inputChannel(data.vchannel_id(), data.vaccess_hash()))
  1134. )).done(std::move(doneSinglePeer)).send();
  1135. }, [&](const MTPDinputPeerSelf &data) {
  1136. requestUser(MTP_inputUserSelf());
  1137. }, [&](const MTPDinputPeerUserFromMessage &data) {
  1138. Unexpected("From message peer in ApiWrap::requestSinglePeerDialog.");
  1139. }, [&](const MTPDinputPeerChannelFromMessage &data) {
  1140. Unexpected("From message peer in ApiWrap::requestSinglePeerDialog.");
  1141. }, [](const MTPDinputPeerEmpty &data) {
  1142. Unexpected("Empty peer in ApiWrap::requestSinglePeerDialog.");
  1143. });
  1144. }
  1145. mtpRequestId ApiWrap::requestSinglePeerMigrated(
  1146. const Data::DialogInfo &info) {
  1147. const auto input = info.input.match([&](
  1148. const MTPDinputPeerChannel & data) {
  1149. return MTP_inputChannel(
  1150. data.vchannel_id(),
  1151. data.vaccess_hash());
  1152. }, [](auto&&) -> MTPinputChannel {
  1153. Unexpected("Peer type in a supergroup.");
  1154. });
  1155. return mainRequest(MTPchannels_GetFullChannel(
  1156. input
  1157. )).done([=](const MTPmessages_ChatFull &result) {
  1158. auto info = result.match([&](
  1159. const MTPDmessages_chatFull &data) {
  1160. const auto migratedChatId = data.vfull_chat().match([&](
  1161. const MTPDchannelFull &data) {
  1162. return data.vmigrated_from_chat_id().value_or_empty();
  1163. }, [](auto &&other) -> BareId {
  1164. return 0;
  1165. });
  1166. return migratedChatId
  1167. ? Data::ParseDialogsInfo(
  1168. MTP_inputPeerChat(MTP_long(migratedChatId)),
  1169. MTP_messages_chats(data.vchats()))
  1170. : Data::DialogsInfo();
  1171. });
  1172. appendSinglePeerDialogs(std::move(info));
  1173. }).send();
  1174. }
  1175. void ApiWrap::appendSinglePeerDialogs(Data::DialogsInfo &&info) {
  1176. const auto isSupergroupType = [](Data::DialogInfo::Type type) {
  1177. using Type = Data::DialogInfo::Type;
  1178. return (type == Type::PrivateSupergroup)
  1179. || (type == Type::PublicSupergroup);
  1180. };
  1181. const auto isChannelType = [](Data::DialogInfo::Type type) {
  1182. using Type = Data::DialogInfo::Type;
  1183. return (type == Type::PrivateChannel)
  1184. || (type == Type::PublicChannel);
  1185. };
  1186. auto migratedRequestId = mtpRequestId(0);
  1187. const auto last = _dialogsProcess->splitIndexPlusOne - 1;
  1188. for (auto &info : info.chats) {
  1189. if (isSupergroupType(info.type) && !migratedRequestId) {
  1190. migratedRequestId = requestSinglePeerMigrated(info);
  1191. continue;
  1192. } else if (isChannelType(info.type)) {
  1193. continue;
  1194. }
  1195. for (auto i = last; i != 0; --i) {
  1196. info.splits.push_back(i - 1);
  1197. info.messagesCountPerSplit.push_back(0);
  1198. }
  1199. }
  1200. if (!migratedRequestId) {
  1201. _dialogsProcess->processedCount += info.chats.size();
  1202. }
  1203. appendDialogsSlice(std::move(info));
  1204. if (migratedRequestId
  1205. || !_dialogsProcess->progress(_dialogsProcess->processedCount)) {
  1206. return;
  1207. }
  1208. finishDialogsList();
  1209. }
  1210. void ApiWrap::requestDialogsSlice() {
  1211. Expects(_dialogsProcess != nullptr);
  1212. if (_settings->onlySinglePeer()) {
  1213. requestSinglePeerDialog();
  1214. return;
  1215. }
  1216. const auto splitIndex = _dialogsProcess->splitIndexPlusOne - 1;
  1217. const auto hash = uint64(0);
  1218. splitRequest(splitIndex, MTPmessages_GetDialogs(
  1219. MTP_flags(0),
  1220. MTPint(), // folder_id
  1221. MTP_int(_dialogsProcess->offsetDate),
  1222. MTP_int(_dialogsProcess->offsetId),
  1223. _dialogsProcess->offsetPeer,
  1224. MTP_int(kChatsSliceLimit),
  1225. MTP_long(hash)
  1226. )).done([=](const MTPmessages_Dialogs &result) {
  1227. if (result.type() == mtpc_messages_dialogsNotModified) {
  1228. error("Unexpected dialogsNotModified received.");
  1229. return;
  1230. }
  1231. auto finished = result.match(
  1232. [](const MTPDmessages_dialogs &data) {
  1233. return true;
  1234. }, [](const MTPDmessages_dialogsSlice &data) {
  1235. return data.vdialogs().v.isEmpty();
  1236. }, [](const MTPDmessages_dialogsNotModified &data) {
  1237. return true;
  1238. });
  1239. auto info = Data::ParseDialogsInfo(result);
  1240. _dialogsProcess->processedCount += info.chats.size();
  1241. const auto last = info.chats.empty()
  1242. ? Data::DialogInfo()
  1243. : info.chats.back();
  1244. appendDialogsSlice(std::move(info));
  1245. if (!_dialogsProcess->progress(_dialogsProcess->processedCount)) {
  1246. return;
  1247. }
  1248. if (!finished && last.topMessageDate > 0) {
  1249. _dialogsProcess->offsetId = last.topMessageId;
  1250. _dialogsProcess->offsetDate = last.topMessageDate;
  1251. _dialogsProcess->offsetPeer = last.input;
  1252. } else if (!useOnlyLastSplit()
  1253. && --_dialogsProcess->splitIndexPlusOne > 0) {
  1254. _dialogsProcess->offsetId = 0;
  1255. _dialogsProcess->offsetDate = 0;
  1256. _dialogsProcess->offsetPeer = MTP_inputPeerEmpty();
  1257. } else {
  1258. requestLeftChannelsIfNeeded();
  1259. return;
  1260. }
  1261. requestDialogsSlice();
  1262. }).send();
  1263. }
  1264. void ApiWrap::appendDialogsSlice(Data::DialogsInfo &&info) {
  1265. Expects(_dialogsProcess != nullptr);
  1266. Expects(_dialogsProcess->splitIndexPlusOne <= _splits.size());
  1267. appendChatsSlice(
  1268. *_dialogsProcess,
  1269. _dialogsProcess->info.chats,
  1270. std::move(info.chats),
  1271. _dialogsProcess->splitIndexPlusOne - 1);
  1272. }
  1273. void ApiWrap::requestLeftChannelsIfNeeded() {
  1274. if (_settings->types & Settings::Type::GroupsChannelsMask) {
  1275. requestLeftChannelsList([=](int count) {
  1276. Expects(_dialogsProcess != nullptr);
  1277. return _dialogsProcess->progress(
  1278. _dialogsProcess->processedCount + count);
  1279. }, [=](Data::DialogsInfo &&result) {
  1280. Expects(_dialogsProcess != nullptr);
  1281. _dialogsProcess->info.left = std::move(result.left);
  1282. finishDialogsList();
  1283. });
  1284. } else {
  1285. finishDialogsList();
  1286. }
  1287. }
  1288. void ApiWrap::finishDialogsList() {
  1289. Expects(_dialogsProcess != nullptr);
  1290. const auto process = base::take(_dialogsProcess);
  1291. Data::FinalizeDialogsInfo(process->info, *_settings);
  1292. process->done(std::move(process->info));
  1293. }
  1294. void ApiWrap::requestLeftChannelsSliceGeneric(FnMut<void()> done) {
  1295. Expects(_leftChannelsProcess != nullptr);
  1296. mainRequest(MTPchannels_GetLeftChannels(
  1297. MTP_int(_leftChannelsProcess->offset)
  1298. )).done([=, done = std::move(done)](
  1299. const MTPmessages_Chats &result) mutable {
  1300. Expects(_leftChannelsProcess != nullptr);
  1301. appendLeftChannelsSlice(Data::ParseLeftChannelsInfo(result));
  1302. const auto process = _leftChannelsProcess.get();
  1303. process->offset += result.match(
  1304. [](const auto &data) {
  1305. return int(data.vchats().v.size());
  1306. });
  1307. process->fullCount = result.match(
  1308. [](const MTPDmessages_chats &data) {
  1309. return int(data.vchats().v.size());
  1310. }, [](const MTPDmessages_chatsSlice &data) {
  1311. return data.vcount().v;
  1312. });
  1313. process->finished = result.match(
  1314. [](const MTPDmessages_chats &data) {
  1315. return true;
  1316. }, [](const MTPDmessages_chatsSlice &data) {
  1317. return data.vchats().v.isEmpty();
  1318. });
  1319. if (process->progress) {
  1320. if (!process->progress(process->info.left.size())) {
  1321. return;
  1322. }
  1323. }
  1324. done();
  1325. }).send();
  1326. }
  1327. void ApiWrap::appendLeftChannelsSlice(Data::DialogsInfo &&info) {
  1328. Expects(_leftChannelsProcess != nullptr);
  1329. Expects(!_splits.empty());
  1330. appendChatsSlice(
  1331. *_leftChannelsProcess,
  1332. _leftChannelsProcess->info.left,
  1333. std::move(info.left),
  1334. _splits.size() - 1);
  1335. }
  1336. void ApiWrap::appendChatsSlice(
  1337. ChatsProcess &process,
  1338. std::vector<Data::DialogInfo> &to,
  1339. std::vector<Data::DialogInfo> &&from,
  1340. int splitIndex) {
  1341. Expects(_settings != nullptr);
  1342. const auto types = _settings->types;
  1343. const auto goodByTypes = [&](const Data::DialogInfo &info) {
  1344. return ((types & SettingsFromDialogsType(info.type)) != 0);
  1345. };
  1346. auto filtered = ranges::views::all(
  1347. from
  1348. ) | ranges::views::filter([&](const Data::DialogInfo &info) {
  1349. if (goodByTypes(info)) {
  1350. return true;
  1351. } else if (info.migratedToChannelId
  1352. && (((types & Settings::Type::PublicGroups) != 0)
  1353. || ((types & Settings::Type::PrivateGroups) != 0))) {
  1354. return true;
  1355. }
  1356. return false;
  1357. });
  1358. to.reserve(to.size() + from.size());
  1359. for (auto &info : filtered) {
  1360. const auto nextIndex = to.size();
  1361. if (info.migratedToChannelId) {
  1362. const auto toPeerId = PeerId(info.migratedToChannelId);
  1363. const auto i = process.indexByPeer.find(toPeerId);
  1364. if (i != process.indexByPeer.end()
  1365. && Data::AddMigrateFromSlice(
  1366. to[i->second],
  1367. info,
  1368. splitIndex,
  1369. int(_splits.size()))) {
  1370. continue;
  1371. } else if (!goodByTypes(info)) {
  1372. continue;
  1373. }
  1374. }
  1375. const auto &[i, ok] = process.indexByPeer.emplace(
  1376. info.peerId,
  1377. nextIndex);
  1378. if (ok) {
  1379. to.push_back(std::move(info));
  1380. }
  1381. to[i->second].splits.push_back(splitIndex);
  1382. to[i->second].messagesCountPerSplit.push_back(0);
  1383. }
  1384. }
  1385. void ApiWrap::requestMessagesSlice() {
  1386. Expects(_chatProcess != nullptr);
  1387. const auto count = _chatProcess->info.messagesCountPerSplit[
  1388. _chatProcess->localSplitIndex];
  1389. if (!count) {
  1390. loadMessagesFiles({});
  1391. return;
  1392. }
  1393. requestChatMessages(
  1394. _chatProcess->info.splits[_chatProcess->localSplitIndex],
  1395. _chatProcess->largestIdPlusOne,
  1396. -kMessagesSliceLimit,
  1397. kMessagesSliceLimit,
  1398. [=](const MTPmessages_Messages &result) {
  1399. Expects(_chatProcess != nullptr);
  1400. result.match([&](const MTPDmessages_messagesNotModified &data) {
  1401. error("Unexpected messagesNotModified received.");
  1402. }, [&](const auto &data) {
  1403. if constexpr (MTPDmessages_messages::Is<decltype(data)>()) {
  1404. _chatProcess->lastSlice = true;
  1405. }
  1406. loadMessagesFiles(Data::ParseMessagesSlice(
  1407. _chatProcess->context,
  1408. data.vmessages(),
  1409. data.vusers(),
  1410. data.vchats(),
  1411. _chatProcess->info.relativePath));
  1412. });
  1413. });
  1414. }
  1415. void ApiWrap::requestChatMessages(
  1416. int splitIndex,
  1417. int offsetId,
  1418. int addOffset,
  1419. int limit,
  1420. FnMut<void(MTPmessages_Messages&&)> done) {
  1421. Expects(_chatProcess != nullptr);
  1422. _chatProcess->requestDone = std::move(done);
  1423. const auto doneHandler = [=](MTPmessages_Messages &&result) {
  1424. Expects(_chatProcess != nullptr);
  1425. base::take(_chatProcess->requestDone)(std::move(result));
  1426. };
  1427. const auto splitsCount = int(_splits.size());
  1428. const auto realPeerInput = (splitIndex >= 0)
  1429. ? _chatProcess->info.input
  1430. : _chatProcess->info.migratedFromInput;
  1431. const auto realSplitIndex = (splitIndex >= 0)
  1432. ? splitIndex
  1433. : (splitsCount + splitIndex);
  1434. if (_chatProcess->info.onlyMyMessages) {
  1435. splitRequest(realSplitIndex, MTPmessages_Search(
  1436. MTP_flags(MTPmessages_Search::Flag::f_from_id),
  1437. realPeerInput,
  1438. MTP_string(), // query
  1439. MTP_inputPeerSelf(),
  1440. MTPInputPeer(), // saved_peer_id
  1441. MTPVector<MTPReaction>(), // saved_reaction
  1442. MTPint(), // top_msg_id
  1443. MTP_inputMessagesFilterEmpty(),
  1444. MTP_int(0), // min_date
  1445. MTP_int(0), // max_date
  1446. MTP_int(offsetId),
  1447. MTP_int(addOffset),
  1448. MTP_int(limit),
  1449. MTP_int(0), // max_id
  1450. MTP_int(0), // min_id
  1451. MTP_long(0) // hash
  1452. )).done(doneHandler).send();
  1453. } else {
  1454. splitRequest(realSplitIndex, MTPmessages_GetHistory(
  1455. realPeerInput,
  1456. MTP_int(offsetId),
  1457. MTP_int(0), // offset_date
  1458. MTP_int(addOffset),
  1459. MTP_int(limit),
  1460. MTP_int(0), // max_id
  1461. MTP_int(0), // min_id
  1462. MTP_long(0) // hash
  1463. )).fail([=](const MTP::Error &error) {
  1464. Expects(_chatProcess != nullptr);
  1465. if (error.type() == u"CHANNEL_PRIVATE"_q) {
  1466. if (realPeerInput.type() == mtpc_inputPeerChannel
  1467. && !_chatProcess->info.onlyMyMessages) {
  1468. // Perhaps we just left / were kicked from channel.
  1469. // Just switch to only my messages.
  1470. _chatProcess->info.onlyMyMessages = true;
  1471. requestChatMessages(
  1472. splitIndex,
  1473. offsetId,
  1474. addOffset,
  1475. limit,
  1476. base::take(_chatProcess->requestDone));
  1477. return true;
  1478. }
  1479. }
  1480. return false;
  1481. }).done(doneHandler).send();
  1482. }
  1483. }
  1484. void ApiWrap::loadMessagesFiles(Data::MessagesSlice &&slice) {
  1485. Expects(_chatProcess != nullptr);
  1486. Expects(!_chatProcess->slice.has_value());
  1487. collectMessagesCustomEmoji(slice);
  1488. if (slice.list.empty()) {
  1489. _chatProcess->lastSlice = true;
  1490. }
  1491. _chatProcess->slice = std::move(slice);
  1492. _chatProcess->fileIndex = 0;
  1493. resolveCustomEmoji();
  1494. }
  1495. void ApiWrap::collectMessagesCustomEmoji(const Data::MessagesSlice &slice) {
  1496. for (const auto &message : slice.list) {
  1497. for (const auto &part : message.text) {
  1498. if (part.type == Data::TextPart::Type::CustomEmoji) {
  1499. if (const auto id = part.additional.toULongLong()) {
  1500. if (!_resolvedCustomEmoji.contains(id)) {
  1501. _unresolvedCustomEmoji.emplace(id);
  1502. }
  1503. }
  1504. }
  1505. }
  1506. for (const auto &reaction : message.reactions) {
  1507. if (reaction.type == Data::Reaction::Type::CustomEmoji) {
  1508. if (const auto id = reaction.documentId.toULongLong()) {
  1509. if (!_resolvedCustomEmoji.contains(id)) {
  1510. _unresolvedCustomEmoji.emplace(id);
  1511. }
  1512. }
  1513. }
  1514. }
  1515. }
  1516. }
  1517. void ApiWrap::resolveCustomEmoji() {
  1518. if (_unresolvedCustomEmoji.empty()) {
  1519. loadNextMessageFile();
  1520. return;
  1521. }
  1522. const auto count = std::min(
  1523. int(_unresolvedCustomEmoji.size()),
  1524. kMaxEmojiPerRequest);
  1525. auto v = QVector<MTPlong>();
  1526. v.reserve(count);
  1527. const auto till = end(_unresolvedCustomEmoji);
  1528. const auto from = end(_unresolvedCustomEmoji) - count;
  1529. for (auto i = from; i != till; ++i) {
  1530. v.push_back(MTP_long(*i));
  1531. }
  1532. _unresolvedCustomEmoji.erase(from, till);
  1533. const auto finalize = [=] {
  1534. for (const auto &id : v) {
  1535. if (_resolvedCustomEmoji.contains(id.v)) {
  1536. continue;
  1537. }
  1538. _resolvedCustomEmoji.emplace(
  1539. id.v,
  1540. Data::Document{
  1541. .file = {
  1542. .skipReason = Data::File::SkipReason::Unavailable,
  1543. },
  1544. });
  1545. }
  1546. resolveCustomEmoji();
  1547. };
  1548. mainRequest(MTPmessages_GetCustomEmojiDocuments(
  1549. MTP_vector<MTPlong>(v)
  1550. )).fail([=](const MTP::Error &error) {
  1551. LOG(("Export Error: Failed to get documents for emoji."));
  1552. finalize();
  1553. return true;
  1554. }).done([=](const MTPVector<MTPDocument> &result) {
  1555. for (const auto &entry : result.v) {
  1556. auto document = Data::ParseDocument(
  1557. _chatProcess->context,
  1558. entry,
  1559. _chatProcess->info.relativePath,
  1560. TimeId());
  1561. _resolvedCustomEmoji.emplace(document.id, std::move(document));
  1562. }
  1563. finalize();
  1564. }).send();
  1565. }
  1566. Data::Message *ApiWrap::currentFileMessage() const {
  1567. Expects(_chatProcess != nullptr);
  1568. Expects(_chatProcess->slice.has_value());
  1569. return &_chatProcess->slice->list[_chatProcess->fileIndex];
  1570. }
  1571. Data::FileOrigin ApiWrap::currentFileMessageOrigin() const {
  1572. Expects(_chatProcess != nullptr);
  1573. Expects(_chatProcess->slice.has_value());
  1574. const auto splitIndex = _chatProcess->info.splits[
  1575. _chatProcess->localSplitIndex];
  1576. auto result = Data::FileOrigin();
  1577. result.messageId = currentFileMessage()->id;
  1578. result.split = (splitIndex >= 0)
  1579. ? splitIndex
  1580. : (int(_splits.size()) + splitIndex);
  1581. result.peer = (splitIndex >= 0)
  1582. ? _chatProcess->info.input
  1583. : _chatProcess->info.migratedFromInput;
  1584. return result;
  1585. }
  1586. std::optional<QByteArray> ApiWrap::getCustomEmoji(QByteArray &data) {
  1587. if (const auto id = data.toULongLong()) {
  1588. const auto i = _resolvedCustomEmoji.find(id);
  1589. if (i == end(_resolvedCustomEmoji)) {
  1590. return Data::TextPart::UnavailableEmoji();
  1591. }
  1592. auto &file = i->second.file;
  1593. const auto fileProgress = [=](FileProgress value) {
  1594. return loadMessageEmojiProgress(value);
  1595. };
  1596. const auto ready = processFileLoad(
  1597. file,
  1598. { .customEmojiId = id },
  1599. fileProgress,
  1600. [=](const QString &path) { loadMessageEmojiDone(id, path); });
  1601. if (!ready) {
  1602. return std::nullopt;
  1603. }
  1604. using SkipReason = Data::File::SkipReason;
  1605. if (file.skipReason == SkipReason::Unavailable) {
  1606. return Data::TextPart::UnavailableEmoji();
  1607. } else if (file.skipReason == SkipReason::FileType
  1608. || file.skipReason == SkipReason::FileSize) {
  1609. return QByteArray();
  1610. } else {
  1611. return file.relativePath.toUtf8();
  1612. }
  1613. }
  1614. return data;
  1615. }
  1616. bool ApiWrap::messageCustomEmojiReady(Data::Message &message) {
  1617. for (auto &part : message.text) {
  1618. if (part.type == Data::TextPart::Type::CustomEmoji) {
  1619. auto data = getCustomEmoji(part.additional);
  1620. if (data.has_value()) {
  1621. part.additional = base::take(*data);
  1622. } else {
  1623. return false;
  1624. }
  1625. }
  1626. }
  1627. for (auto &reaction : message.reactions) {
  1628. if (reaction.type == Data::Reaction::Type::CustomEmoji) {
  1629. auto data = getCustomEmoji(reaction.documentId);
  1630. if (data.has_value()) {
  1631. reaction.documentId = base::take(*data);
  1632. } else {
  1633. return false;
  1634. }
  1635. }
  1636. }
  1637. return true;
  1638. }
  1639. void ApiWrap::loadNextMessageFile() {
  1640. Expects(_chatProcess != nullptr);
  1641. Expects(_chatProcess->slice.has_value());
  1642. for (auto &list = _chatProcess->slice->list
  1643. ; _chatProcess->fileIndex < list.size()
  1644. ; ++_chatProcess->fileIndex) {
  1645. auto &message = list[_chatProcess->fileIndex];
  1646. if (Data::SkipMessageByDate(message, *_settings)) {
  1647. continue;
  1648. }
  1649. if (!messageCustomEmojiReady(message)) {
  1650. return;
  1651. }
  1652. const auto fileProgress = [=](FileProgress value) {
  1653. return loadMessageFileProgress(value);
  1654. };
  1655. const auto ready = processFileLoad(
  1656. list[_chatProcess->fileIndex].file(),
  1657. currentFileMessageOrigin(),
  1658. fileProgress,
  1659. [=](const QString &path) { loadMessageFileDone(path); },
  1660. currentFileMessage());
  1661. if (!ready) {
  1662. return;
  1663. }
  1664. const auto thumbProgress = [=](FileProgress value) {
  1665. return loadMessageThumbProgress(value);
  1666. };
  1667. const auto thumbReady = processFileLoad(
  1668. list[_chatProcess->fileIndex].thumb().file,
  1669. currentFileMessageOrigin(),
  1670. thumbProgress,
  1671. [=](const QString &path) { loadMessageThumbDone(path); },
  1672. currentFileMessage());
  1673. if (!thumbReady) {
  1674. return;
  1675. }
  1676. }
  1677. finishMessagesSlice();
  1678. }
  1679. void ApiWrap::finishMessagesSlice() {
  1680. Expects(_chatProcess != nullptr);
  1681. Expects(_chatProcess->slice.has_value());
  1682. auto slice = *base::take(_chatProcess->slice);
  1683. if (!slice.list.empty()) {
  1684. _chatProcess->largestIdPlusOne = slice.list.back().id + 1;
  1685. const auto splitIndex = _chatProcess->info.splits[
  1686. _chatProcess->localSplitIndex];
  1687. if (splitIndex < 0) {
  1688. slice = AdjustMigrateMessageIds(std::move(slice));
  1689. }
  1690. if (!_chatProcess->handleSlice(std::move(slice))) {
  1691. return;
  1692. }
  1693. }
  1694. if (_chatProcess->lastSlice
  1695. && (++_chatProcess->localSplitIndex
  1696. < _chatProcess->info.splits.size())) {
  1697. _chatProcess->lastSlice = false;
  1698. _chatProcess->largestIdPlusOne = 1;
  1699. }
  1700. if (!_chatProcess->lastSlice) {
  1701. requestMessagesSlice();
  1702. } else {
  1703. finishMessages();
  1704. }
  1705. }
  1706. bool ApiWrap::loadMessageFileProgress(FileProgress progress) {
  1707. Expects(_fileProcess != nullptr);
  1708. Expects(_chatProcess != nullptr);
  1709. Expects(_chatProcess->slice.has_value());
  1710. Expects((_chatProcess->fileIndex >= 0)
  1711. && (_chatProcess->fileIndex < _chatProcess->slice->list.size()));
  1712. return _chatProcess->fileProgress(DownloadProgress{
  1713. .randomId = _fileProcess->randomId,
  1714. .path = _fileProcess->relativePath,
  1715. .itemIndex = _chatProcess->fileIndex,
  1716. .ready = progress.ready,
  1717. .total = progress.total });
  1718. }
  1719. void ApiWrap::loadMessageFileDone(const QString &relativePath) {
  1720. Expects(_chatProcess != nullptr);
  1721. Expects(_chatProcess->slice.has_value());
  1722. Expects((_chatProcess->fileIndex >= 0)
  1723. && (_chatProcess->fileIndex < _chatProcess->slice->list.size()));
  1724. const auto index = _chatProcess->fileIndex;
  1725. auto &file = _chatProcess->slice->list[index].file();
  1726. file.relativePath = relativePath;
  1727. if (relativePath.isEmpty()) {
  1728. file.skipReason = Data::File::SkipReason::Unavailable;
  1729. }
  1730. loadNextMessageFile();
  1731. }
  1732. bool ApiWrap::loadMessageThumbProgress(FileProgress progress) {
  1733. return loadMessageFileProgress(progress);
  1734. }
  1735. void ApiWrap::loadMessageThumbDone(const QString &relativePath) {
  1736. Expects(_chatProcess != nullptr);
  1737. Expects(_chatProcess->slice.has_value());
  1738. Expects((_chatProcess->fileIndex >= 0)
  1739. && (_chatProcess->fileIndex < _chatProcess->slice->list.size()));
  1740. const auto index = _chatProcess->fileIndex;
  1741. auto &file = _chatProcess->slice->list[index].thumb().file;
  1742. file.relativePath = relativePath;
  1743. if (relativePath.isEmpty()) {
  1744. file.skipReason = Data::File::SkipReason::Unavailable;
  1745. }
  1746. loadNextMessageFile();
  1747. }
  1748. bool ApiWrap::loadMessageEmojiProgress(FileProgress progress) {
  1749. return loadMessageFileProgress(progress);
  1750. }
  1751. void ApiWrap::loadMessageEmojiDone(uint64 id, const QString &relativePath) {
  1752. const auto i = _resolvedCustomEmoji.find(id);
  1753. if (i != end(_resolvedCustomEmoji)) {
  1754. i->second.file.relativePath = relativePath;
  1755. if (relativePath.isEmpty()) {
  1756. i->second.file.skipReason = Data::File::SkipReason::Unavailable;
  1757. }
  1758. }
  1759. loadNextMessageFile();
  1760. }
  1761. void ApiWrap::finishMessages() {
  1762. Expects(_chatProcess != nullptr);
  1763. Expects(!_chatProcess->slice.has_value());
  1764. const auto process = base::take(_chatProcess);
  1765. process->done();
  1766. }
  1767. bool ApiWrap::processFileLoad(
  1768. Data::File &file,
  1769. const Data::FileOrigin &origin,
  1770. Fn<bool(FileProgress)> progress,
  1771. FnMut<void(QString)> done,
  1772. Data::Message *message,
  1773. Data::Story *story) {
  1774. using SkipReason = Data::File::SkipReason;
  1775. if (!file.relativePath.isEmpty()
  1776. || file.skipReason != SkipReason::None) {
  1777. return true;
  1778. } else if (!file.location && file.content.isEmpty()) {
  1779. file.skipReason = SkipReason::Unavailable;
  1780. return true;
  1781. } else if (writePreloadedFile(file, origin)) {
  1782. return !file.relativePath.isEmpty();
  1783. }
  1784. using Type = MediaSettings::Type;
  1785. const auto media = message
  1786. ? &message->media
  1787. : story
  1788. ? &story->media
  1789. : nullptr;
  1790. const auto type = media ? v::match(media->content, [&](
  1791. const Data::Document &data) {
  1792. if (data.isSticker) {
  1793. return Type::Sticker;
  1794. } else if (data.isVideoMessage) {
  1795. return Type::VideoMessage;
  1796. } else if (data.isVoiceMessage) {
  1797. return Type::VoiceMessage;
  1798. } else if (data.isAnimated) {
  1799. return Type::GIF;
  1800. } else if (data.isVideoFile) {
  1801. return Type::Video;
  1802. } else {
  1803. return Type::File;
  1804. }
  1805. }, [](const auto &data) {
  1806. return Type::Photo;
  1807. }) : Type(0);
  1808. const auto fullSize = message
  1809. ? message->file().size
  1810. : story
  1811. ? story->file().size
  1812. : file.size;
  1813. if (message && Data::SkipMessageByDate(*message, *_settings)) {
  1814. file.skipReason = SkipReason::DateLimits;
  1815. return true;
  1816. } else if (!story && (_settings->media.types & type) != type) {
  1817. file.skipReason = SkipReason::FileType;
  1818. return true;
  1819. } else if (!story && fullSize >= _settings->media.sizeLimit) {
  1820. // Don't load thumbs for large files that we skip.
  1821. file.skipReason = SkipReason::FileSize;
  1822. return true;
  1823. }
  1824. loadFile(file, origin, std::move(progress), std::move(done));
  1825. return false;
  1826. }
  1827. bool ApiWrap::writePreloadedFile(
  1828. Data::File &file,
  1829. const Data::FileOrigin &origin) {
  1830. Expects(_settings != nullptr);
  1831. using namespace Output;
  1832. if (const auto path = _fileCache->find(file.location)) {
  1833. file.relativePath = *path;
  1834. return true;
  1835. } else if (!file.content.isEmpty()) {
  1836. const auto process = prepareFileProcess(file, origin);
  1837. if (const auto result = process->file.writeBlock(file.content)) {
  1838. file.relativePath = process->relativePath;
  1839. _fileCache->save(file.location, file.relativePath);
  1840. } else {
  1841. ioError(result);
  1842. }
  1843. return true;
  1844. }
  1845. return false;
  1846. }
  1847. void ApiWrap::loadFile(
  1848. const Data::File &file,
  1849. const Data::FileOrigin &origin,
  1850. Fn<bool(FileProgress)> progress,
  1851. FnMut<void(QString)> done) {
  1852. Expects(_fileProcess == nullptr);
  1853. Expects(file.location.dcId != 0
  1854. || file.location.data.type() == mtpc_inputTakeoutFileLocation);
  1855. _fileProcess = prepareFileProcess(file, origin);
  1856. _fileProcess->progress = std::move(progress);
  1857. _fileProcess->done = std::move(done);
  1858. if (_fileProcess->progress) {
  1859. const auto progress = FileProgress{
  1860. _fileProcess->file.size(),
  1861. _fileProcess->size
  1862. };
  1863. if (!_fileProcess->progress(progress)) {
  1864. return;
  1865. }
  1866. }
  1867. loadFilePart();
  1868. Ensures(_fileProcess->requestId != 0);
  1869. }
  1870. auto ApiWrap::prepareFileProcess(
  1871. const Data::File &file,
  1872. const Data::FileOrigin &origin) const
  1873. -> std::unique_ptr<FileProcess> {
  1874. Expects(_settings != nullptr);
  1875. const auto relativePath = Output::File::PrepareRelativePath(
  1876. _settings->path,
  1877. file.suggestedPath);
  1878. auto result = std::make_unique<FileProcess>(
  1879. _settings->path + relativePath,
  1880. _stats);
  1881. result->relativePath = relativePath;
  1882. result->location = file.location;
  1883. result->size = file.size;
  1884. result->origin = origin;
  1885. result->randomId = base::RandomValue<uint64>();
  1886. return result;
  1887. }
  1888. void ApiWrap::loadFilePart() {
  1889. if (!_fileProcess
  1890. || _fileProcess->requestId
  1891. || _fileProcess->requests.size() >= kFileRequestsCount
  1892. || (_fileProcess->size > 0
  1893. && _fileProcess->offset >= _fileProcess->size)) {
  1894. return;
  1895. }
  1896. const auto offset = _fileProcess->offset;
  1897. _fileProcess->requests.push_back({ offset });
  1898. _fileProcess->requestId = fileRequest(
  1899. _fileProcess->location,
  1900. _fileProcess->offset
  1901. ).done([=](const MTPupload_File &result) {
  1902. _fileProcess->requestId = 0;
  1903. filePartDone(offset, result);
  1904. }).send();
  1905. _fileProcess->offset += kFileChunkSize;
  1906. if (_fileProcess->size > 0
  1907. && _fileProcess->requests.size() < kFileRequestsCount) {
  1908. // Only one request at a time supported right now.
  1909. //const auto runner = _runner;
  1910. //crl::on_main([=] {
  1911. // QTimer::singleShot(kFileNextRequestDelay, [=] {
  1912. // runner([=] {
  1913. // loadFilePart();
  1914. // });
  1915. // });
  1916. //});
  1917. }
  1918. }
  1919. void ApiWrap::filePartDone(int64 offset, const MTPupload_File &result) {
  1920. Expects(_fileProcess != nullptr);
  1921. Expects(!_fileProcess->requests.empty());
  1922. if (result.type() == mtpc_upload_fileCdnRedirect) {
  1923. error("Cdn redirect is not supported.");
  1924. return;
  1925. }
  1926. const auto &data = result.c_upload_file();
  1927. if (data.vbytes().v.isEmpty()) {
  1928. if (_fileProcess->size > 0) {
  1929. error("Empty bytes received in file part.");
  1930. return;
  1931. }
  1932. const auto result = _fileProcess->file.writeBlock({});
  1933. if (!result) {
  1934. ioError(result);
  1935. return;
  1936. }
  1937. } else {
  1938. using Request = FileProcess::Request;
  1939. auto &requests = _fileProcess->requests;
  1940. const auto i = ranges::find(
  1941. requests,
  1942. offset,
  1943. [](const Request &request) { return request.offset; });
  1944. Assert(i != end(requests));
  1945. i->bytes = data.vbytes().v;
  1946. auto &file = _fileProcess->file;
  1947. while (!requests.empty() && !requests.front().bytes.isEmpty()) {
  1948. const auto &bytes = requests.front().bytes;
  1949. if (const auto result = file.writeBlock(bytes); !result) {
  1950. ioError(result);
  1951. return;
  1952. }
  1953. requests.pop_front();
  1954. }
  1955. if (_fileProcess->progress) {
  1956. _fileProcess->progress(FileProgress{
  1957. file.size(),
  1958. _fileProcess->size });
  1959. }
  1960. if (!requests.empty()
  1961. || !_fileProcess->size
  1962. || _fileProcess->size > _fileProcess->offset) {
  1963. loadFilePart();
  1964. return;
  1965. }
  1966. }
  1967. auto process = base::take(_fileProcess);
  1968. const auto relativePath = process->relativePath;
  1969. _fileCache->save(process->location, relativePath);
  1970. process->done(process->relativePath);
  1971. }
  1972. void ApiWrap::filePartRefreshReference(int64 offset) {
  1973. Expects(_fileProcess != nullptr);
  1974. Expects(_fileProcess->requestId == 0);
  1975. const auto &origin = _fileProcess->origin;
  1976. if (origin.storyId) {
  1977. _fileProcess->requestId = mainRequest(MTPstories_GetStoriesByID(
  1978. MTP_inputPeerSelf(),
  1979. MTP_vector<MTPint>(1, MTP_int(origin.storyId))
  1980. )).fail([=](const MTP::Error &error) {
  1981. _fileProcess->requestId = 0;
  1982. filePartUnavailable();
  1983. return true;
  1984. }).done([=](const MTPstories_Stories &result) {
  1985. _fileProcess->requestId = 0;
  1986. filePartExtractReference(offset, result);
  1987. }).send();
  1988. return;
  1989. } else if (!origin.messageId) {
  1990. error("FILE_REFERENCE error for non-message file.");
  1991. return;
  1992. }
  1993. if (origin.peer.type() == mtpc_inputPeerChannel
  1994. || origin.peer.type() == mtpc_inputPeerChannelFromMessage) {
  1995. const auto channel = (origin.peer.type() == mtpc_inputPeerChannel)
  1996. ? MTP_inputChannel(
  1997. origin.peer.c_inputPeerChannel().vchannel_id(),
  1998. origin.peer.c_inputPeerChannel().vaccess_hash())
  1999. : MTP_inputChannelFromMessage(
  2000. origin.peer.c_inputPeerChannelFromMessage().vpeer(),
  2001. origin.peer.c_inputPeerChannelFromMessage().vmsg_id(),
  2002. origin.peer.c_inputPeerChannelFromMessage().vchannel_id());
  2003. _fileProcess->requestId = mainRequest(MTPchannels_GetMessages(
  2004. channel,
  2005. MTP_vector<MTPInputMessage>(
  2006. 1,
  2007. MTP_inputMessageID(MTP_int(origin.messageId)))
  2008. )).fail([=](const MTP::Error &error) {
  2009. _fileProcess->requestId = 0;
  2010. filePartUnavailable();
  2011. return true;
  2012. }).done([=](const MTPmessages_Messages &result) {
  2013. _fileProcess->requestId = 0;
  2014. filePartExtractReference(offset, result);
  2015. }).send();
  2016. } else {
  2017. _fileProcess->requestId = splitRequest(
  2018. origin.split,
  2019. MTPmessages_GetMessages(
  2020. MTP_vector<MTPInputMessage>(
  2021. 1,
  2022. MTP_inputMessageID(MTP_int(origin.messageId)))
  2023. )
  2024. ).fail([=](const MTP::Error &error) {
  2025. _fileProcess->requestId = 0;
  2026. filePartUnavailable();
  2027. return true;
  2028. }).done([=](const MTPmessages_Messages &result) {
  2029. _fileProcess->requestId = 0;
  2030. filePartExtractReference(offset, result);
  2031. }).send();
  2032. }
  2033. }
  2034. void ApiWrap::filePartExtractReference(
  2035. int64 offset,
  2036. const MTPmessages_Messages &result) {
  2037. Expects(_fileProcess != nullptr);
  2038. Expects(_fileProcess->requestId == 0);
  2039. result.match([&](const MTPDmessages_messagesNotModified &data) {
  2040. error("Unexpected messagesNotModified received.");
  2041. }, [&](const auto &data) {
  2042. Expects(_selfId.has_value());
  2043. auto context = Data::ParseMediaContext();
  2044. context.selfPeerId = peerFromUser(*_selfId);
  2045. const auto messages = Data::ParseMessagesSlice(
  2046. context,
  2047. data.vmessages(),
  2048. data.vusers(),
  2049. data.vchats(),
  2050. _chatProcess->info.relativePath);
  2051. for (const auto &message : messages.list) {
  2052. if (message.id == _fileProcess->origin.messageId) {
  2053. const auto refresh1 = Data::RefreshFileReference(
  2054. _fileProcess->location,
  2055. message.file().location);
  2056. const auto refresh2 = Data::RefreshFileReference(
  2057. _fileProcess->location,
  2058. message.thumb().file.location);
  2059. if (refresh1 || refresh2) {
  2060. _fileProcess->requestId = fileRequest(
  2061. _fileProcess->location,
  2062. offset
  2063. ).done([=](const MTPupload_File &result) {
  2064. _fileProcess->requestId = 0;
  2065. filePartDone(offset, result);
  2066. }).send();
  2067. return;
  2068. }
  2069. }
  2070. }
  2071. filePartUnavailable();
  2072. });
  2073. }
  2074. void ApiWrap::filePartExtractReference(
  2075. int64 offset,
  2076. const MTPstories_Stories &result) {
  2077. Expects(_fileProcess != nullptr);
  2078. Expects(_fileProcess->requestId == 0);
  2079. const auto stories = Data::ParseStoriesSlice(
  2080. result.data().vstories(),
  2081. 0);
  2082. for (const auto &story : stories.list) {
  2083. if (story.id == _fileProcess->origin.storyId) {
  2084. const auto refresh1 = Data::RefreshFileReference(
  2085. _fileProcess->location,
  2086. story.file().location);
  2087. const auto refresh2 = Data::RefreshFileReference(
  2088. _fileProcess->location,
  2089. story.thumb().file.location);
  2090. if (refresh1 || refresh2) {
  2091. _fileProcess->requestId = fileRequest(
  2092. _fileProcess->location,
  2093. offset
  2094. ).done([=](const MTPupload_File &result) {
  2095. _fileProcess->requestId = 0;
  2096. filePartDone(offset, result);
  2097. }).send();
  2098. return;
  2099. }
  2100. }
  2101. }
  2102. filePartUnavailable();
  2103. }
  2104. void ApiWrap::filePartUnavailable() {
  2105. Expects(_fileProcess != nullptr);
  2106. Expects(!_fileProcess->requests.empty());
  2107. LOG(("Export Error: File unavailable."));
  2108. base::take(_fileProcess)->done(QString());
  2109. }
  2110. void ApiWrap::error(const MTP::Error &error) {
  2111. _errors.fire_copy(error);
  2112. }
  2113. void ApiWrap::error(const QString &text) {
  2114. error(MTP::Error(
  2115. MTP_rpc_error(MTP_int(0), MTP_string("API_ERROR: " + text))));
  2116. }
  2117. void ApiWrap::ioError(const Output::Result &result) {
  2118. _ioErrors.fire_copy(result);
  2119. }
  2120. ApiWrap::~ApiWrap() = default;
  2121. } // namespace Export