From 95023ca770fceaff498df79556a85546de2dde0f Mon Sep 17 00:00:00 2001 From: John Preston Date: Mon, 25 Mar 2019 13:17:47 +0400 Subject: [PATCH] Use StorageFileLocation in streaming loader. --- Telegram/SourceFiles/apiwrap.cpp | 42 +++++------ Telegram/SourceFiles/data/data_document.cpp | 14 ++-- .../media_streaming_loader_mtproto.cpp | 74 +++++-------------- .../media_streaming_loader_mtproto.h | 11 +-- .../SourceFiles/ui/image/image_location.cpp | 33 +++++++++ .../SourceFiles/ui/image/image_location.h | 1 + 6 files changed, 86 insertions(+), 89 deletions(-) diff --git a/Telegram/SourceFiles/apiwrap.cpp b/Telegram/SourceFiles/apiwrap.cpp index 17770fc91..90a923d53 100644 --- a/Telegram/SourceFiles/apiwrap.cpp +++ b/Telegram/SourceFiles/apiwrap.cpp @@ -3125,8 +3125,9 @@ void ApiWrap::toggleFavedSticker( return; } - auto failHandler = std::make_shared>(); + auto failHandler = std::make_shared>(); auto performRequest = [=] { + const auto usedFileReference = document->fileReference(); request(MTPmessages_FaveSticker( document->mtpInput(), MTP_bool(!faved) @@ -3134,16 +3135,15 @@ void ApiWrap::toggleFavedSticker( if (mtpIsTrue(result)) { Stickers::SetFaved(document, faved); } - }).fail( - base::duplicate(*failHandler) - ).send(); + }).fail([=](const RPCError &error) { + (*failHandler)(error, usedFileReference); + }).send(); }; - *failHandler = [=](const RPCError &error) { + *failHandler = [=](const RPCError &error, QByteArray usedFileReference) { if (error.code() == 400 && error.type().startsWith(qstr("FILE_REFERENCE_"))) { - const auto current = document->fileReference(); auto refreshed = [=](const UpdatedFileReferences &data) { - if (document->fileReference() != current) { + if (document->fileReference() != usedFileReference) { performRequest(); } }; @@ -3161,8 +3161,9 @@ void ApiWrap::toggleSavedGif( return; } - auto failHandler = std::make_shared>(); + auto failHandler = std::make_shared>(); auto performRequest = [=] { + const auto usedFileReference = document->fileReference(); request(MTPmessages_SaveGif( document->mtpInput(), MTP_bool(!saved) @@ -3172,16 +3173,15 @@ void ApiWrap::toggleSavedGif( App::addSavedGif(document); } } - }).fail( - base::duplicate(*failHandler) - ).send(); + }).fail([=](const RPCError &error) { + (*failHandler)(error, usedFileReference); + }).send(); }; - *failHandler = [=](const RPCError &error) { + *failHandler = [=](const RPCError & error, QByteArray usedFileReference) { if (error.code() == 400 && error.type().startsWith(qstr("FILE_REFERENCE_"))) { - const auto current = document->fileReference(); auto refreshed = [=](const UpdatedFileReferences &data) { - if (document->fileReference() != current) { + if (document->fileReference() != usedFileReference) { performRequest(); } }; @@ -4902,8 +4902,9 @@ void ApiWrap::sendExistingDocument( caption, MTPReplyMarkup()); - auto failHandler = std::make_shared>(); + auto failHandler = std::make_shared>(); auto performRequest = [=] { + const auto usedFileReference = document->fileReference(); history->sendRequestId = request(MTPmessages_SendMedia( MTP_flags(sendFlags), peer->input, @@ -4918,17 +4919,16 @@ void ApiWrap::sendExistingDocument( sentEntities )).done([=](const MTPUpdates &result) { applyUpdates(result, randomId); - }).fail( - base::duplicate(*failHandler) - ).afterRequest(history->sendRequestId + }).fail([=](const RPCError &error) { + (*failHandler)(error, usedFileReference); + }).afterRequest(history->sendRequestId ).send(); }; - *failHandler = [=](const RPCError &error) { + *failHandler = [=](const RPCError &error, QByteArray usedFileReference) { if (error.code() == 400 && error.type().startsWith(qstr("FILE_REFERENCE_"))) { - const auto current = document->fileReference(); auto refreshed = [=](const UpdatedFileReferences &data) { - if (document->fileReference() != current) { + if (document->fileReference() != usedFileReference) { performRequest(); } else { sendMessageFail(error); diff --git a/Telegram/SourceFiles/data/data_document.cpp b/Telegram/SourceFiles/data/data_document.cpp index 812ace968..c28e48dba 100644 --- a/Telegram/SourceFiles/data/data_document.cpp +++ b/Telegram/SourceFiles/data/data_document.cpp @@ -1195,12 +1195,14 @@ auto DocumentData::createStreamingLoader(Data::FileOrigin origin) const return hasRemoteLocation() ? std::make_unique( &session().api(), - _dc, - MTP_inputDocumentFileLocation( - MTP_long(id), - MTP_long(_access), - MTP_bytes(_fileReference), - MTP_string(QString())), + StorageFileLocation( + _dc, + session().userId(), + MTP_inputDocumentFileLocation( + MTP_long(id), + MTP_long(_access), + MTP_bytes(_fileReference), + MTP_string(QString()))), size, origin) : nullptr; diff --git a/Telegram/SourceFiles/media/streaming/media_streaming_loader_mtproto.cpp b/Telegram/SourceFiles/media/streaming/media_streaming_loader_mtproto.cpp index 6e1a6d443..060217235 100644 --- a/Telegram/SourceFiles/media/streaming/media_streaming_loader_mtproto.cpp +++ b/Telegram/SourceFiles/media/streaming/media_streaming_loader_mtproto.cpp @@ -8,44 +8,30 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL #include "media/streaming/media_streaming_loader_mtproto.h" #include "apiwrap.h" +#include "auth_session.h" #include "storage/cache/storage_cache_types.h" namespace Media { namespace Streaming { namespace { -constexpr auto kMaxConcurrentRequests = 2; -constexpr auto kDocumentBaseCacheTag = 0x0000000000010000ULL; -constexpr auto kDocumentBaseCacheMask = 0x000000000000FF00ULL; +constexpr auto kMaxConcurrentRequests = 4; } // namespace LoaderMtproto::LoaderMtproto( not_null api, - MTP::DcId dcId, - const MTPInputFileLocation &location, + const StorageFileLocation &location, int size, Data::FileOrigin origin) : _api(api) -, _dcId(dcId) , _location(location) , _size(size) , _origin(origin) { } std::optional LoaderMtproto::baseCacheKey() const { - return _location.match([&](const MTPDinputDocumentFileLocation &data) { - const auto id = data.vid.v; - const auto high = kDocumentBaseCacheTag - | ((uint64(_dcId) << 16) & kDocumentBaseCacheMask) - | (id >> 48); - const auto low = (id << 16); - - Ensures((low & 0xFFULL) == 0); - return Storage::Cache::Key{ high, low }; - }, [](auto &&) -> Storage::Cache::Key { - Unexpected("Not implemented file location type."); - }); + return _location.bigFileBaseCacheKey(); } int LoaderMtproto::size() const { @@ -99,18 +85,19 @@ void LoaderMtproto::sendNext() { } static auto DcIndex = 0; - const auto reference = locationFileReference(); + const auto usedFileReference = _location.fileReference(); const auto id = _sender.request(MTPupload_GetFile( - _location, + _location.tl(Auth().userId()), MTP_int(offset), MTP_int(kPartSize) )).done([=](const MTPupload_File &result) { requestDone(offset, result); }).fail([=](const RPCError &error) { - requestFailed(offset, error, reference); - }).toDC( - MTP::downloadDcId(_dcId, (++DcIndex) % MTP::kDownloadSessionsCount) - ).send(); + requestFailed(offset, error, usedFileReference); + }).toDC(MTP::downloadDcId( + _location.dcId(), + (++DcIndex) % MTP::kDownloadSessionsCount + )).send(); _requests.emplace(offset, id); sendNext(); @@ -155,43 +142,20 @@ void LoaderMtproto::requestFailed( return fail(); } const auto callback = [=](const Data::UpdatedFileReferences &updated) { - _location.match([&](const MTPDinputDocumentFileLocation &location) { - const auto i = updated.data.find( - Data::DocumentFileLocationId{ location.vid.v }); - if (i == end(updated.data)) { - return fail(); - } - const auto reference = i->second; - if (reference == usedFileReference) { - return fail(); - } else if (reference != location.vfile_reference.v) { - _location = MTP_inputDocumentFileLocation( - MTP_long(location.vid.v), - MTP_long(location.vaccess_hash.v), - MTP_bytes(reference), - MTP_string(QString())); - } - if (!_requests.take(offset)) { - // Request with such offset was already cancelled. - return; - } + _location.refreshFileReference(updated); + if (_location.fileReference() == usedFileReference) { + fail(); + } else if (!_requests.take(offset)) { + // Request with such offset was already cancelled. + return; + } else { _requested.add(offset); sendNext(); - }, [](auto &&) { - Unexpected("Not implemented file location type."); - }); + } }; _api->refreshFileReference(_origin, crl::guard(this, callback)); } -QByteArray LoaderMtproto::locationFileReference() const { - return _location.match([&](const MTPDinputDocumentFileLocation &data) { - return data.vfile_reference.v; - }, [](auto &&) -> QByteArray { - Unexpected("Not implemented file location type."); - }); -} - rpl::producer LoaderMtproto::parts() const { return _parts.events(); } diff --git a/Telegram/SourceFiles/media/streaming/media_streaming_loader_mtproto.h b/Telegram/SourceFiles/media/streaming/media_streaming_loader_mtproto.h index c2a9058d6..83300f6c6 100644 --- a/Telegram/SourceFiles/media/streaming/media_streaming_loader_mtproto.h +++ b/Telegram/SourceFiles/media/streaming/media_streaming_loader_mtproto.h @@ -20,8 +20,7 @@ class LoaderMtproto : public Loader, public base::has_weak_ptr { public: LoaderMtproto( not_null api, - MTP::DcId dcId, - const MTPInputFileLocation &location, + const StorageFileLocation &location, int size, Data::FileOrigin origin); @@ -44,8 +43,8 @@ private: void requestDone(int offset, const MTPupload_File &result); void requestFailed( - int offset, - const RPCError &error, + int offset, + const RPCError &error, const QByteArray &usedFileReference); void changeCdnParams( int offset, @@ -55,13 +54,11 @@ private: const QByteArray &encryptionIV, const QVector &hashes); - [[nodiscard]] QByteArray locationFileReference() const; - const not_null _api; const MTP::DcId _dcId = 0; // _location can be changed with an updated file_reference. - MTPInputFileLocation _location; + StorageFileLocation _location; const int _size = 0; const Data::FileOrigin _origin; diff --git a/Telegram/SourceFiles/ui/image/image_location.cpp b/Telegram/SourceFiles/ui/image/image_location.cpp index 8b9a545d4..ece1038bb 100644 --- a/Telegram/SourceFiles/ui/image/image_location.cpp +++ b/Telegram/SourceFiles/ui/image/image_location.cpp @@ -16,6 +16,9 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL namespace { +constexpr auto kDocumentBaseCacheTag = 0x0000000000010000ULL; +constexpr auto kDocumentBaseCacheMask = 0x000000000000FF00ULL; + MTPInputPeer GenerateInputPeer(uint64 id, uint64 accessHash, int32 self) { const auto bareId = [&] { return peerToBareMTPInt(id); @@ -335,6 +338,36 @@ Storage::Cache::Key StorageFileLocation::cacheKey() const { return Key(); } +Storage::Cache::Key StorageFileLocation::bigFileBaseCacheKey() const { + using Key = Storage::Cache::Key; + + // Skip '1' and '2' for legacy document cache keys. + const auto shifted = ((uint64(_type) + 3) << 8); + const auto sliced = uint64(_dcId) & 0xFFULL; + switch (_type) { + case Type::Document: { + const auto high = kDocumentBaseCacheTag + | ((uint64(_dcId) << 16) & kDocumentBaseCacheMask) + | (_id >> 48); + const auto low = (_id << 16); + + Ensures((low & 0xFFULL) == 0); + return Storage::Cache::Key{ high, low }; + } + + case Type::Legacy: + case Type::PeerPhoto: + case Type::StickerSetThumb: + case Type::Encrypted: + case Type::Secure: + case Type::Photo: + case Type::Takeout: + Unexpected("Not implemented file location type."); + + }; + Unexpected("Invalid file location type."); +} + QByteArray StorageFileLocation::fileReference() const { return _fileReference; } diff --git a/Telegram/SourceFiles/ui/image/image_location.h b/Telegram/SourceFiles/ui/image/image_location.h index 3454e154b..e092e7fb1 100644 --- a/Telegram/SourceFiles/ui/image/image_location.h +++ b/Telegram/SourceFiles/ui/image/image_location.h @@ -83,6 +83,7 @@ public: [[nodiscard]] Type type() const; [[nodiscard]] bool valid() const; [[nodiscard]] Storage::Cache::Key cacheKey() const; + [[nodiscard]] Storage::Cache::Key bigFileBaseCacheKey() const; [[nodiscard]] QByteArray fileReference() const; bool refreshFileReference(const Data::UpdatedFileReferences &updates);