From 557d363d029a6760b17db2e3bfdc4bbc4d12420e Mon Sep 17 00:00:00 2001 From: John Preston <johnprestonmail@gmail.com> Date: Sun, 15 Jul 2018 19:36:19 +0300 Subject: [PATCH] Refresh file references when downloading files. --- Telegram/SourceFiles/apiwrap.cpp | 127 ++++++++++ Telegram/SourceFiles/apiwrap.h | 26 +- .../SourceFiles/data/data_file_origin.cpp | 237 ++++++++++++++++++ Telegram/SourceFiles/data/data_file_origin.h | 47 ++++ .../SourceFiles/storage/file_download.cpp | 40 ++- Telegram/SourceFiles/storage/file_download.h | 8 +- Telegram/SourceFiles/ui/images.cpp | 4 +- Telegram/SourceFiles/ui/images.h | 3 + Telegram/gyp/telegram_sources.txt | 1 + 9 files changed, 487 insertions(+), 6 deletions(-) create mode 100644 Telegram/SourceFiles/data/data_file_origin.cpp diff --git a/Telegram/SourceFiles/apiwrap.cpp b/Telegram/SourceFiles/apiwrap.cpp index 1bed0a207..90365476a 100644 --- a/Telegram/SourceFiles/apiwrap.cpp +++ b/Telegram/SourceFiles/apiwrap.cpp @@ -42,6 +42,7 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL #include "chat_helpers/stickers.h" #include "ui/text_options.h" #include "storage/localimageloader.h" +#include "storage/file_download.h" #include "storage/storage_facade.h" #include "storage/storage_shared_media.h" #include "storage/storage_user_photos.h" @@ -67,6 +68,11 @@ constexpr auto kFeedReadTimeout = TimeMs(1000); constexpr auto kStickersByEmojiInvalidateTimeout = TimeMs(60 * 60 * 1000); constexpr auto kNotifySettingSaveTimeout = TimeMs(1000); +using SimpleFileLocationId = Data::SimpleFileLocationId; +using DocumentFileLocationId = Data::DocumentFileLocationId; +using FileLocationId = Data::FileLocationId; +using UpdatedFileReferences = Data::UpdatedFileReferences; + bool IsSilentPost(not_null<HistoryItem*> item, bool silent) { const auto history = item->history(); return silent @@ -2368,6 +2374,127 @@ void ApiWrap::channelRangeDifferenceDone( } } +template <typename Request> +void ApiWrap::requestFileReference( + Data::FileOrigin origin, + not_null<mtpFileLoader*> loader, + int requestId, + const QByteArray ¤t, + Request &&data) { + auto handler = crl::guard(loader, [=]( + const Data::UpdatedFileReferences &data) { + loader->refreshFileReferenceFrom(data, requestId, current); + }); + const auto i = _fileReferenceHandlers.find(origin); + if (i != end(_fileReferenceHandlers)) { + i->second.push_back(std::move(handler)); + return; + } + auto handlers = std::vector<FileReferencesHandler>(); + handlers.push_back(std::move(handler)); + _fileReferenceHandlers.emplace(origin, std::move(handlers)); + + request(std::move(data)).done([=](const auto &result) { + const auto parsed = Data::GetFileReferences(result); + const auto i = _fileReferenceHandlers.find(origin); + Assert(i != end(_fileReferenceHandlers)); + auto handlers = std::move(i->second); + _fileReferenceHandlers.erase(i); + for (auto &handler : handlers) { + handler(parsed); + } + }).fail([=](const RPCError &error) { + const auto i = _fileReferenceHandlers.find(origin); + Assert(i != end(_fileReferenceHandlers)); + auto handlers = std::move(i->second); + _fileReferenceHandlers.erase(i); + for (auto &handler : handlers) { + handler(Data::UpdatedFileReferences()); + } + }).send(); +} + +void ApiWrap::refreshFileReference( + Data::FileOrigin origin, + not_null<mtpFileLoader*> loader, + int requestId, + const QByteArray ¤t) { + const auto request = [&](auto &&data) { + requestFileReference( + origin, + loader, + requestId, + current, + std::move(data)); + }; + const auto fail = [&] { + loader->refreshFileReferenceFrom({}, requestId, current); + }; + origin.match([&](Data::FileOriginMessage data) { + if (const auto item = App::histItemById(data)) { + if (const auto channel = item->history()->peer->asChannel()) { + request(MTPchannels_GetMessages( + channel->inputChannel, + MTP_vector<MTPInputMessage>( + 1, + MTP_inputMessageID(MTP_int(item->id))))); + } else { + request(MTPmessages_GetMessages( + MTP_vector<MTPInputMessage>( + 1, + MTP_inputMessageID(MTP_int(item->id))))); + } + } else { + fail(); + } + }, [&](Data::FileOriginUserPhoto data) { + if (const auto user = App::user(data.userId)) { + request(MTPphotos_GetUserPhotos( + user->inputUser, + MTP_int(-1), + MTP_long(data.photoId), + MTP_int(1))); + } else { + fail(); + } + }, [&](Data::FileOriginPeerPhoto data) { + if (const auto peer = App::peer(data.peerId)) { + if (const auto user = peer->asUser()) { + request(MTPusers_GetUsers( + MTP_vector<MTPInputUser>(1, user->inputUser))); + } else if (const auto chat = peer->asChat()) { + request(MTPmessages_GetChats( + MTP_vector<MTPint>(1, chat->inputChat))); + } else if (const auto channel = peer->asChannel()) { + request(MTPchannels_GetChannels( + MTP_vector<MTPInputChannel>(1, channel->inputChannel))); + } else { + fail(); + } + } else { + fail(); + } + }, [&](Data::FileOriginStickerSet data) { + if (data.setId == Stickers::CloudRecentSetId + || data.setId == Stickers::RecentSetId) { + request(MTPmessages_GetRecentStickers( + MTP_flags(0), + MTP_int(0))); + } else if (data.setId == Stickers::FavedSetId) { + request(MTPmessages_GetFavedStickers(MTP_int(0))); + } else { + request(MTPmessages_GetStickerSet( + MTP_inputStickerSetID( + MTP_long(data.setId), + MTP_long(data.accessHash)))); + } + }, [&](Data::FileOriginSavedGifs data) { + request(MTPmessages_GetSavedGifs(MTP_int(0))); + }, [&](base::none_type) { + fail(); + }); +} + void ApiWrap::gotWebPages(ChannelData *channel, const MTPmessages_Messages &msgs, mtpRequestId req) { const QVector<MTPMessage> *v = 0; switch (msgs.type()) { diff --git a/Telegram/SourceFiles/apiwrap.h b/Telegram/SourceFiles/apiwrap.h index 094162d12..973d81475 100644 --- a/Telegram/SourceFiles/apiwrap.h +++ b/Telegram/SourceFiles/apiwrap.h @@ -22,6 +22,7 @@ struct MessageGroupId; struct SendingAlbum; enum class SendMediaType; struct FileLoadTo; +class mtpFileLoader; namespace InlineBots { class Result; @@ -55,7 +56,6 @@ inline int32 CountHash(IntRange &&range) { return int32(acc & 0x7FFFFFFF); } - } // namespace Api class ApiWrap : private MTP::Sender, private base::Subscriber { @@ -97,6 +97,12 @@ public: void requestParticipantsCountDelayed(not_null<ChannelData*> channel); void requestChannelRangeDifference(not_null<History*> history); + void refreshFileReference( + Data::FileOrigin origin, + not_null<mtpFileLoader*> loader, + int requestId, + const QByteArray ¤t); + void requestChangelog( const QString &sinceVersion, Fn<void(const MTPUpdates &result)> callback); @@ -315,6 +321,12 @@ private: TimeMs received = 0; }; + using SimpleFileLocationId = Data::SimpleFileLocationId; + using DocumentFileLocationId = Data::DocumentFileLocationId; + using FileLocationId = Data::FileLocationId; + using UpdatedFileReferences = Data::UpdatedFileReferences; + using FileReferencesHandler = FnMut<void(const UpdatedFileReferences&)>; + void updatesReceived(const MTPUpdates &updates); void checkQuitPreventFinished(); @@ -469,6 +481,14 @@ private: void sendNotifySettingsUpdates(); + template <typename Request> + void requestFileReference( + Data::FileOrigin origin, + not_null<mtpFileLoader*> loader, + int requestId, + const QByteArray ¤t, + Request &&data); + not_null<AuthSession*> _session; MessageDataRequests _messageDataRequests; @@ -605,6 +625,10 @@ private: base::flat_set<not_null<const PeerData*>> _updateNotifySettingsPeers; base::Timer _updateNotifySettingsTimer; + std::map< + Data::FileOrigin, + std::vector<FileReferencesHandler>> _fileReferenceHandlers; + mtpRequestId _deepLinkInfoRequestId = 0; TimeMs _termsUpdateSendAt = 0; diff --git a/Telegram/SourceFiles/data/data_file_origin.cpp b/Telegram/SourceFiles/data/data_file_origin.cpp new file mode 100644 index 000000000..99f4c352f --- /dev/null +++ b/Telegram/SourceFiles/data/data_file_origin.cpp @@ -0,0 +1,237 @@ +/* +This file is part of Telegram Desktop, +the official desktop application for the Telegram messaging service. + +For license and copyright information please follow this link: +https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL +*/ +#include "data/data_file_origin.h" + +namespace Data { +namespace { + +struct FileReferenceAccumulator { + template <typename Type> + void push(const MTPVector<Type> &data) { + for (const auto &item : data.v) { + push(item); + } + } + void push(const MTPFileLocation &data) { + data.match([&](const MTPDfileLocation &data) { + result.emplace(SimpleFileLocationId( + data.vvolume_id.v, + data.vdc_id.v, + data.vlocal_id.v), data.vfile_reference.v); + }, [](const MTPDfileLocationUnavailable &data) { + }); + } + void push(const MTPPhotoSize &data) { + data.match([](const MTPDphotoSizeEmpty &data) { + }, [&](const auto &data) { + push(data.vlocation); + }); + } + void push(const MTPPhoto &data) { + data.match([&](const MTPDphoto &data) { + for (const auto &size : data.vsizes.v) { + push(size); + } + }, [](const MTPDphotoEmpty &data) { + }); + } + void push(const MTPDocument &data) { + data.match([&](const MTPDdocument &data) { + push(data.vthumb); + result.emplace( + DocumentFileLocationId(data.vid.v), + data.vfile_reference.v); + }, [](const MTPDdocumentEmpty &data) { + }); + } + void push(const MTPUserProfilePhoto &data) { + data.match([&](const MTPDuserProfilePhoto &data) { + push(data.vphoto_small); + push(data.vphoto_big); + }, [](const MTPDuserProfilePhotoEmpty &data) { + }); + } + void push(const MTPChatPhoto &data) { + data.match([&](const MTPDchatPhoto &data) { + push(data.vphoto_small); + push(data.vphoto_big); + }, [](const MTPDchatPhotoEmpty &data) { + }); + } + void push(const MTPUser &data) { + data.match([&](const MTPDuser &data) { + if (data.has_photo()) { + push(data.vphoto); + } + }, [](const MTPDuserEmpty &data) { + }); + } + void push(const MTPChat &data) { + data.match([](const MTPDchatEmpty &data) { + }, [](const MTPDchannelForbidden &data) { + }, [](const MTPDchatForbidden &data) { + }, [&](const auto &data) { + push(data.vphoto); + }); + } + void push(const MTPWebPage &data) { + data.match([&](const MTPDwebPage &data) { + if (data.has_document()) { + push(data.vdocument); + } + if (data.has_photo()) { + push(data.vphoto); + } + }, [](const auto &data) { + }); + } + void push(const MTPGame &data) { + data.match([&](const MTPDgame &data) { + if (data.has_document()) { + push(data.vdocument); + } + }, [](const auto &data) { + }); + } + void push(const MTPMessageMedia &data) { + data.match([&](const MTPDmessageMediaPhoto &data) { + if (data.has_photo()) { + push(data.vphoto); + } + }, [&](const MTPDmessageMediaDocument &data) { + if (data.has_document()) { + push(data.vdocument); + } + }, [&](const MTPDmessageMediaWebPage &data) { + push(data.vwebpage); + }, [&](const MTPDmessageMediaGame &data) { + push(data.vgame); + }, [](const auto &data) { + }); + } + void push(const MTPMessage &data) { + data.match([&](const MTPDmessage &data) { + if (data.has_media()) { + push(data.vmedia); + } + }, [&](const MTPDmessageService &data) { + data.vaction.match( + [&](const MTPDmessageActionChatEditPhoto &data) { + push(data.vphoto); + }, [](const auto &data) { + }); + }, [](const MTPDmessageEmpty &data) { + }); + } + void push(const MTPmessages_Messages &data) { + data.match([](const MTPDmessages_messagesNotModified &) { + }, [&](const auto &data) { + push(data.vusers); + push(data.vchats); + push(data.vmessages); + }); + } + void push(const MTPphotos_Photos &data) { + data.match([&](const auto &data) { + push(data.vusers); + push(data.vphotos); + }); + } + void push(const MTPmessages_Chats &data) { + data.match([&](const auto &data) { + push(data.vchats); + }); + } + void push(const MTPmessages_RecentStickers &data) { + data.match([&](const MTPDmessages_recentStickers &data) { + push(data.vstickers); + }, [](const MTPDmessages_recentStickersNotModified &data) { + }); + } + void push(const MTPmessages_FavedStickers &data) { + data.match([&](const MTPDmessages_favedStickers &data) { + push(data.vstickers); + }, [](const MTPDmessages_favedStickersNotModified &data) { + }); + } + void push(const MTPmessages_StickerSet &data) { + data.match([&](const MTPDmessages_stickerSet &data) { + push(data.vdocuments); + }); + } + void push(const MTPmessages_SavedGifs &data) { + data.match([&](const MTPDmessages_savedGifs &data) { + push(data.vgifs); + }, [](const MTPDmessages_savedGifsNotModified &data) { + }); + } + + UpdatedFileReferences result; +}; + +template <typename Type> +UpdatedFileReferences GetFileReferencesHelper(const Type &data) { + FileReferenceAccumulator result; + result.push(data); + return result.result; +} + +} // namespace + +SimpleFileLocationId::SimpleFileLocationId( + uint64 volumeId, + int32 dcId, + int32 localId) +: volumeId(volumeId) +, dcId(dcId) +, localId(localId) { +} + +bool operator<( + const SimpleFileLocationId &a, + const SimpleFileLocationId &b) { + return std::tie(a.volumeId, a.dcId, a.localId) + < std::tie(b.volumeId, b.dcId, b.localId); +} + +UpdatedFileReferences GetFileReferences(const MTPmessages_Messages &data) { + return GetFileReferencesHelper(data); +} + +UpdatedFileReferences GetFileReferences(const MTPphotos_Photos &data) { + return GetFileReferencesHelper(data); +} + +UpdatedFileReferences GetFileReferences(const MTPVector<MTPUser> &data) { + return GetFileReferencesHelper(data); +} + +UpdatedFileReferences GetFileReferences(const MTPmessages_Chats &data) { + return GetFileReferencesHelper(data); +} + +UpdatedFileReferences GetFileReferences( + const MTPmessages_RecentStickers &data) { + return GetFileReferencesHelper(data); +} + +UpdatedFileReferences GetFileReferences( + const MTPmessages_FavedStickers &data) { + return GetFileReferencesHelper(data); +} + +UpdatedFileReferences GetFileReferences( + const MTPmessages_StickerSet &data) { + return GetFileReferencesHelper(data); +} + +UpdatedFileReferences GetFileReferences(const MTPmessages_SavedGifs &data) { + return GetFileReferencesHelper(data); +} + +} // namespace Data diff --git a/Telegram/SourceFiles/data/data_file_origin.h b/Telegram/SourceFiles/data/data_file_origin.h index c6b421dad..27a214055 100644 --- a/Telegram/SourceFiles/data/data_file_origin.h +++ b/Telegram/SourceFiles/data/data_file_origin.h @@ -7,6 +7,7 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL */ #pragma once +#include "base/variant.h" #include "data/data_types.h" namespace Data { @@ -21,6 +22,11 @@ struct FileOriginUserPhoto { UserId userId = 0; PhotoId photoId = 0; + + inline bool operator<(const FileOriginUserPhoto &other) const { + return std::tie(userId, photoId) + < std::tie(other.userId, other.photoId); + } }; struct FileOriginPeerPhoto { @@ -28,6 +34,10 @@ struct FileOriginPeerPhoto { } PeerId peerId = 0; + + inline bool operator<(const FileOriginPeerPhoto &other) const { + return peerId < other.peerId; + } }; struct FileOriginStickerSet { @@ -38,9 +48,16 @@ struct FileOriginStickerSet { uint64 setId = 0; uint64 accessHash = 0; + + inline bool operator<(const FileOriginStickerSet &other) const { + return setId < other.setId; + } }; struct FileOriginSavedGifs { + inline bool operator<(const FileOriginSavedGifs &) const { + return false; + } }; using FileOrigin = base::optional_variant< @@ -50,4 +67,34 @@ using FileOrigin = base::optional_variant< FileOriginStickerSet, FileOriginSavedGifs>; +// Volume_id, dc_id, local_id. +struct SimpleFileLocationId { + SimpleFileLocationId(uint64 volumeId, int32 dcId, int32 localId); + + uint64 volumeId = 0; + int32 dcId = 0; + int32 localId = 0; +}; + +bool operator<( + const SimpleFileLocationId &a, + const SimpleFileLocationId &b); + +using DocumentFileLocationId = uint64; +using FileLocationId = base::variant< + SimpleFileLocationId, + DocumentFileLocationId>; +using UpdatedFileReferences = std::map<FileLocationId, QByteArray>; + +UpdatedFileReferences GetFileReferences(const MTPmessages_Messages &data); +UpdatedFileReferences GetFileReferences(const MTPphotos_Photos &data); +UpdatedFileReferences GetFileReferences(const MTPVector<MTPUser> &data); +UpdatedFileReferences GetFileReferences(const MTPmessages_Chats &data); +UpdatedFileReferences GetFileReferences( + const MTPmessages_RecentStickers &data); +UpdatedFileReferences GetFileReferences( + const MTPmessages_FavedStickers &data); +UpdatedFileReferences GetFileReferences(const MTPmessages_StickerSet &data); +UpdatedFileReferences GetFileReferences(const MTPmessages_SavedGifs &data); + } // namespace Data diff --git a/Telegram/SourceFiles/storage/file_download.cpp b/Telegram/SourceFiles/storage/file_download.cpp index 7b6769e12..099f51640 100644 --- a/Telegram/SourceFiles/storage/file_download.cpp +++ b/Telegram/SourceFiles/storage/file_download.cpp @@ -394,7 +394,7 @@ void FileLoader::startLoading(bool loadFirst, bool prior) { } mtpFileLoader::mtpFileLoader( - const StorageImageLocation *location, + not_null<StorageImageLocation*> location, Data::FileOrigin origin, int32 size, LoadFromCloudSetting fromCloud @@ -479,6 +479,34 @@ Data::FileOrigin mtpFileLoader::fileOrigin() const { return _origin; } +void mtpFileLoader::refreshFileReferenceFrom( + const Data::UpdatedFileReferences &data, + int requestId, + const QByteArray ¤t) { + const auto updated = [&] { + if (_location) { + const auto i = data.find(Data::SimpleFileLocationId( + _location->volume(), + _location->dc(), + _location->local())); + return (i == end(data)) ? QByteArray() : i->second; + } + const auto i = data.find(_id); + return (i == end(data)) ? QByteArray() : i->second; + }(); + if (updated.isEmpty() || updated == current) { + cancel(true); + return; + } + if (_location) { + _location->refreshFileReference(updated); + } else { + _fileReference = updated; + } + const auto offset = finishSentRequestGetOffset(requestId); + makeRequest(offset); +} + bool mtpFileLoader::loadPart() { if (_finished || _lastComplete || (!_sentRequests.empty() && !_size)) { return false; @@ -766,7 +794,7 @@ void mtpFileLoader::placeSentRequest(mtpRequestId requestId, const RequestData & int mtpFileLoader::finishSentRequestGetOffset(mtpRequestId requestId) { auto it = _sentRequests.find(requestId); - Expects(it != _sentRequests.cend()); + Assert(it != _sentRequests.cend()); auto requestData = it->second; _downloader->requestedAmountIncrement(requestData.dcId, requestData.dcIndex, -partSize()); @@ -889,6 +917,14 @@ bool mtpFileLoader::partFailed( if (MTP::isDefaultHandledError(error)) { return false; } + if (error.type().startsWith(qstr("FILE_REFERENCE_"))) { + Auth().api().refreshFileReference( + _origin, + this, + requestId, + _location ? _location->fileReference() : _fileReference); + return true; + } cancel(true); return true; } diff --git a/Telegram/SourceFiles/storage/file_download.h b/Telegram/SourceFiles/storage/file_download.h index 18036c1da..7ef00e4c5 100644 --- a/Telegram/SourceFiles/storage/file_download.h +++ b/Telegram/SourceFiles/storage/file_download.h @@ -186,7 +186,7 @@ class mtpFileLoader : public FileLoader, public RPCSender { public: mtpFileLoader( - const StorageImageLocation *location, + not_null<StorageImageLocation*> location, Data::FileOrigin origin, int32 size, LoadFromCloudSetting fromCloud, @@ -219,6 +219,10 @@ public: void stop() override { rpcInvalidate(); } + void refreshFileReferenceFrom( + const Data::UpdatedFileReferences &data, + int requestId, + const QByteArray ¤t); ~mtpFileLoader(); @@ -277,7 +281,7 @@ private: int32 _nextRequestOffset = 0; MTP::DcId _dcId = 0; // for photo locations - const StorageImageLocation *_location = nullptr; + StorageImageLocation *_location = nullptr; uint64 _id = 0; // for document locations uint64 _accessHash = 0; diff --git a/Telegram/SourceFiles/ui/images.cpp b/Telegram/SourceFiles/ui/images.cpp index b0c0eed62..0cd698b70 100644 --- a/Telegram/SourceFiles/ui/images.cpp +++ b/Telegram/SourceFiles/ui/images.cpp @@ -1143,7 +1143,9 @@ FileLoader *StorageImage::createLoader( Data::FileOrigin origin, LoadFromCloudSetting fromCloud, bool autoLoading) { - if (_location.isNull()) return 0; + if (_location.isNull()) { + return nullptr; + } return new mtpFileLoader( &_location, origin, diff --git a/Telegram/SourceFiles/ui/images.h b/Telegram/SourceFiles/ui/images.h index 858f8fe2b..cea3ffc56 100644 --- a/Telegram/SourceFiles/ui/images.h +++ b/Telegram/SourceFiles/ui/images.h @@ -152,6 +152,9 @@ public: QByteArray fileReference() const { return _fileReference; } + void refreshFileReference(const QByteArray &data) { + _fileReference = data; + } static StorageImageLocation FromMTP( int32 width, diff --git a/Telegram/gyp/telegram_sources.txt b/Telegram/gyp/telegram_sources.txt index bdf2d2bf8..61dda8609 100644 --- a/Telegram/gyp/telegram_sources.txt +++ b/Telegram/gyp/telegram_sources.txt @@ -179,6 +179,7 @@ <(src_loc)/data/data_feed.h <(src_loc)/data/data_feed_messages.cpp <(src_loc)/data/data_feed_messages.h +<(src_loc)/data/data_file_origin.cpp <(src_loc)/data/data_file_origin.h <(src_loc)/data/data_flags.h <(src_loc)/data/data_game.h