Use StorageFileLocation in streaming loader.

This commit is contained in:
John Preston 2019-03-25 13:17:47 +04:00
parent 3f49796c43
commit 95023ca770
6 changed files with 86 additions and 89 deletions

View File

@ -3125,8 +3125,9 @@ void ApiWrap::toggleFavedSticker(
return; return;
} }
auto failHandler = std::make_shared<Fn<void(const RPCError&)>>(); auto failHandler = std::make_shared<Fn<void(const RPCError&, QByteArray)>>();
auto performRequest = [=] { auto performRequest = [=] {
const auto usedFileReference = document->fileReference();
request(MTPmessages_FaveSticker( request(MTPmessages_FaveSticker(
document->mtpInput(), document->mtpInput(),
MTP_bool(!faved) MTP_bool(!faved)
@ -3134,16 +3135,15 @@ void ApiWrap::toggleFavedSticker(
if (mtpIsTrue(result)) { if (mtpIsTrue(result)) {
Stickers::SetFaved(document, faved); Stickers::SetFaved(document, faved);
} }
}).fail( }).fail([=](const RPCError &error) {
base::duplicate(*failHandler) (*failHandler)(error, usedFileReference);
).send(); }).send();
}; };
*failHandler = [=](const RPCError &error) { *failHandler = [=](const RPCError &error, QByteArray usedFileReference) {
if (error.code() == 400 if (error.code() == 400
&& error.type().startsWith(qstr("FILE_REFERENCE_"))) { && error.type().startsWith(qstr("FILE_REFERENCE_"))) {
const auto current = document->fileReference();
auto refreshed = [=](const UpdatedFileReferences &data) { auto refreshed = [=](const UpdatedFileReferences &data) {
if (document->fileReference() != current) { if (document->fileReference() != usedFileReference) {
performRequest(); performRequest();
} }
}; };
@ -3161,8 +3161,9 @@ void ApiWrap::toggleSavedGif(
return; return;
} }
auto failHandler = std::make_shared<Fn<void(const RPCError&)>>(); auto failHandler = std::make_shared<Fn<void(const RPCError&, QByteArray)>>();
auto performRequest = [=] { auto performRequest = [=] {
const auto usedFileReference = document->fileReference();
request(MTPmessages_SaveGif( request(MTPmessages_SaveGif(
document->mtpInput(), document->mtpInput(),
MTP_bool(!saved) MTP_bool(!saved)
@ -3172,16 +3173,15 @@ void ApiWrap::toggleSavedGif(
App::addSavedGif(document); App::addSavedGif(document);
} }
} }
}).fail( }).fail([=](const RPCError &error) {
base::duplicate(*failHandler) (*failHandler)(error, usedFileReference);
).send(); }).send();
}; };
*failHandler = [=](const RPCError &error) { *failHandler = [=](const RPCError & error, QByteArray usedFileReference) {
if (error.code() == 400 if (error.code() == 400
&& error.type().startsWith(qstr("FILE_REFERENCE_"))) { && error.type().startsWith(qstr("FILE_REFERENCE_"))) {
const auto current = document->fileReference();
auto refreshed = [=](const UpdatedFileReferences &data) { auto refreshed = [=](const UpdatedFileReferences &data) {
if (document->fileReference() != current) { if (document->fileReference() != usedFileReference) {
performRequest(); performRequest();
} }
}; };
@ -4902,8 +4902,9 @@ void ApiWrap::sendExistingDocument(
caption, caption,
MTPReplyMarkup()); MTPReplyMarkup());
auto failHandler = std::make_shared<Fn<void(const RPCError&)>>(); auto failHandler = std::make_shared<Fn<void(const RPCError&, QByteArray)>>();
auto performRequest = [=] { auto performRequest = [=] {
const auto usedFileReference = document->fileReference();
history->sendRequestId = request(MTPmessages_SendMedia( history->sendRequestId = request(MTPmessages_SendMedia(
MTP_flags(sendFlags), MTP_flags(sendFlags),
peer->input, peer->input,
@ -4918,17 +4919,16 @@ void ApiWrap::sendExistingDocument(
sentEntities sentEntities
)).done([=](const MTPUpdates &result) { )).done([=](const MTPUpdates &result) {
applyUpdates(result, randomId); applyUpdates(result, randomId);
}).fail( }).fail([=](const RPCError &error) {
base::duplicate(*failHandler) (*failHandler)(error, usedFileReference);
).afterRequest(history->sendRequestId }).afterRequest(history->sendRequestId
).send(); ).send();
}; };
*failHandler = [=](const RPCError &error) { *failHandler = [=](const RPCError &error, QByteArray usedFileReference) {
if (error.code() == 400 if (error.code() == 400
&& error.type().startsWith(qstr("FILE_REFERENCE_"))) { && error.type().startsWith(qstr("FILE_REFERENCE_"))) {
const auto current = document->fileReference();
auto refreshed = [=](const UpdatedFileReferences &data) { auto refreshed = [=](const UpdatedFileReferences &data) {
if (document->fileReference() != current) { if (document->fileReference() != usedFileReference) {
performRequest(); performRequest();
} else { } else {
sendMessageFail(error); sendMessageFail(error);

View File

@ -1195,12 +1195,14 @@ auto DocumentData::createStreamingLoader(Data::FileOrigin origin) const
return hasRemoteLocation() return hasRemoteLocation()
? std::make_unique<Media::Streaming::LoaderMtproto>( ? std::make_unique<Media::Streaming::LoaderMtproto>(
&session().api(), &session().api(),
_dc, StorageFileLocation(
MTP_inputDocumentFileLocation( _dc,
MTP_long(id), session().userId(),
MTP_long(_access), MTP_inputDocumentFileLocation(
MTP_bytes(_fileReference), MTP_long(id),
MTP_string(QString())), MTP_long(_access),
MTP_bytes(_fileReference),
MTP_string(QString()))),
size, size,
origin) origin)
: nullptr; : nullptr;

View File

@ -8,44 +8,30 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL
#include "media/streaming/media_streaming_loader_mtproto.h" #include "media/streaming/media_streaming_loader_mtproto.h"
#include "apiwrap.h" #include "apiwrap.h"
#include "auth_session.h"
#include "storage/cache/storage_cache_types.h" #include "storage/cache/storage_cache_types.h"
namespace Media { namespace Media {
namespace Streaming { namespace Streaming {
namespace { namespace {
constexpr auto kMaxConcurrentRequests = 2; constexpr auto kMaxConcurrentRequests = 4;
constexpr auto kDocumentBaseCacheTag = 0x0000000000010000ULL;
constexpr auto kDocumentBaseCacheMask = 0x000000000000FF00ULL;
} // namespace } // namespace
LoaderMtproto::LoaderMtproto( LoaderMtproto::LoaderMtproto(
not_null<ApiWrap*> api, not_null<ApiWrap*> api,
MTP::DcId dcId, const StorageFileLocation &location,
const MTPInputFileLocation &location,
int size, int size,
Data::FileOrigin origin) Data::FileOrigin origin)
: _api(api) : _api(api)
, _dcId(dcId)
, _location(location) , _location(location)
, _size(size) , _size(size)
, _origin(origin) { , _origin(origin) {
} }
std::optional<Storage::Cache::Key> LoaderMtproto::baseCacheKey() const { std::optional<Storage::Cache::Key> LoaderMtproto::baseCacheKey() const {
return _location.match([&](const MTPDinputDocumentFileLocation &data) { return _location.bigFileBaseCacheKey();
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.");
});
} }
int LoaderMtproto::size() const { int LoaderMtproto::size() const {
@ -99,18 +85,19 @@ void LoaderMtproto::sendNext() {
} }
static auto DcIndex = 0; static auto DcIndex = 0;
const auto reference = locationFileReference(); const auto usedFileReference = _location.fileReference();
const auto id = _sender.request(MTPupload_GetFile( const auto id = _sender.request(MTPupload_GetFile(
_location, _location.tl(Auth().userId()),
MTP_int(offset), MTP_int(offset),
MTP_int(kPartSize) MTP_int(kPartSize)
)).done([=](const MTPupload_File &result) { )).done([=](const MTPupload_File &result) {
requestDone(offset, result); requestDone(offset, result);
}).fail([=](const RPCError &error) { }).fail([=](const RPCError &error) {
requestFailed(offset, error, reference); requestFailed(offset, error, usedFileReference);
}).toDC( }).toDC(MTP::downloadDcId(
MTP::downloadDcId(_dcId, (++DcIndex) % MTP::kDownloadSessionsCount) _location.dcId(),
).send(); (++DcIndex) % MTP::kDownloadSessionsCount
)).send();
_requests.emplace(offset, id); _requests.emplace(offset, id);
sendNext(); sendNext();
@ -155,43 +142,20 @@ void LoaderMtproto::requestFailed(
return fail(); return fail();
} }
const auto callback = [=](const Data::UpdatedFileReferences &updated) { const auto callback = [=](const Data::UpdatedFileReferences &updated) {
_location.match([&](const MTPDinputDocumentFileLocation &location) { _location.refreshFileReference(updated);
const auto i = updated.data.find( if (_location.fileReference() == usedFileReference) {
Data::DocumentFileLocationId{ location.vid.v }); fail();
if (i == end(updated.data)) { } else if (!_requests.take(offset)) {
return fail(); // Request with such offset was already cancelled.
} return;
const auto reference = i->second; } else {
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;
}
_requested.add(offset); _requested.add(offset);
sendNext(); sendNext();
}, [](auto &&) { }
Unexpected("Not implemented file location type.");
});
}; };
_api->refreshFileReference(_origin, crl::guard(this, callback)); _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<LoadedPart> LoaderMtproto::parts() const { rpl::producer<LoadedPart> LoaderMtproto::parts() const {
return _parts.events(); return _parts.events();
} }

View File

@ -20,8 +20,7 @@ class LoaderMtproto : public Loader, public base::has_weak_ptr {
public: public:
LoaderMtproto( LoaderMtproto(
not_null<ApiWrap*> api, not_null<ApiWrap*> api,
MTP::DcId dcId, const StorageFileLocation &location,
const MTPInputFileLocation &location,
int size, int size,
Data::FileOrigin origin); Data::FileOrigin origin);
@ -44,8 +43,8 @@ private:
void requestDone(int offset, const MTPupload_File &result); void requestDone(int offset, const MTPupload_File &result);
void requestFailed( void requestFailed(
int offset, int offset,
const RPCError &error, const RPCError &error,
const QByteArray &usedFileReference); const QByteArray &usedFileReference);
void changeCdnParams( void changeCdnParams(
int offset, int offset,
@ -55,13 +54,11 @@ private:
const QByteArray &encryptionIV, const QByteArray &encryptionIV,
const QVector<MTPFileHash> &hashes); const QVector<MTPFileHash> &hashes);
[[nodiscard]] QByteArray locationFileReference() const;
const not_null<ApiWrap*> _api; const not_null<ApiWrap*> _api;
const MTP::DcId _dcId = 0; const MTP::DcId _dcId = 0;
// _location can be changed with an updated file_reference. // _location can be changed with an updated file_reference.
MTPInputFileLocation _location; StorageFileLocation _location;
const int _size = 0; const int _size = 0;
const Data::FileOrigin _origin; const Data::FileOrigin _origin;

View File

@ -16,6 +16,9 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL
namespace { namespace {
constexpr auto kDocumentBaseCacheTag = 0x0000000000010000ULL;
constexpr auto kDocumentBaseCacheMask = 0x000000000000FF00ULL;
MTPInputPeer GenerateInputPeer(uint64 id, uint64 accessHash, int32 self) { MTPInputPeer GenerateInputPeer(uint64 id, uint64 accessHash, int32 self) {
const auto bareId = [&] { const auto bareId = [&] {
return peerToBareMTPInt(id); return peerToBareMTPInt(id);
@ -335,6 +338,36 @@ Storage::Cache::Key StorageFileLocation::cacheKey() const {
return Key(); 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 { QByteArray StorageFileLocation::fileReference() const {
return _fileReference; return _fileReference;
} }

View File

@ -83,6 +83,7 @@ public:
[[nodiscard]] Type type() const; [[nodiscard]] Type type() const;
[[nodiscard]] bool valid() const; [[nodiscard]] bool valid() const;
[[nodiscard]] Storage::Cache::Key cacheKey() const; [[nodiscard]] Storage::Cache::Key cacheKey() const;
[[nodiscard]] Storage::Cache::Key bigFileBaseCacheKey() const;
[[nodiscard]] QByteArray fileReference() const; [[nodiscard]] QByteArray fileReference() const;
bool refreshFileReference(const Data::UpdatedFileReferences &updates); bool refreshFileReference(const Data::UpdatedFileReferences &updates);