Refresh file references when downloading files.

This commit is contained in:
John Preston 2018-07-15 19:36:19 +03:00
parent 839885910c
commit 557d363d02
9 changed files with 487 additions and 6 deletions

View File

@ -42,6 +42,7 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL
#include "chat_helpers/stickers.h" #include "chat_helpers/stickers.h"
#include "ui/text_options.h" #include "ui/text_options.h"
#include "storage/localimageloader.h" #include "storage/localimageloader.h"
#include "storage/file_download.h"
#include "storage/storage_facade.h" #include "storage/storage_facade.h"
#include "storage/storage_shared_media.h" #include "storage/storage_shared_media.h"
#include "storage/storage_user_photos.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 kStickersByEmojiInvalidateTimeout = TimeMs(60 * 60 * 1000);
constexpr auto kNotifySettingSaveTimeout = TimeMs(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) { bool IsSilentPost(not_null<HistoryItem*> item, bool silent) {
const auto history = item->history(); const auto history = item->history();
return silent 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 &current,
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 &current) {
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) { void ApiWrap::gotWebPages(ChannelData *channel, const MTPmessages_Messages &msgs, mtpRequestId req) {
const QVector<MTPMessage> *v = 0; const QVector<MTPMessage> *v = 0;
switch (msgs.type()) { switch (msgs.type()) {

View File

@ -22,6 +22,7 @@ struct MessageGroupId;
struct SendingAlbum; struct SendingAlbum;
enum class SendMediaType; enum class SendMediaType;
struct FileLoadTo; struct FileLoadTo;
class mtpFileLoader;
namespace InlineBots { namespace InlineBots {
class Result; class Result;
@ -55,7 +56,6 @@ inline int32 CountHash(IntRange &&range) {
return int32(acc & 0x7FFFFFFF); return int32(acc & 0x7FFFFFFF);
} }
} // namespace Api } // namespace Api
class ApiWrap : private MTP::Sender, private base::Subscriber { class ApiWrap : private MTP::Sender, private base::Subscriber {
@ -97,6 +97,12 @@ public:
void requestParticipantsCountDelayed(not_null<ChannelData*> channel); void requestParticipantsCountDelayed(not_null<ChannelData*> channel);
void requestChannelRangeDifference(not_null<History*> history); void requestChannelRangeDifference(not_null<History*> history);
void refreshFileReference(
Data::FileOrigin origin,
not_null<mtpFileLoader*> loader,
int requestId,
const QByteArray &current);
void requestChangelog( void requestChangelog(
const QString &sinceVersion, const QString &sinceVersion,
Fn<void(const MTPUpdates &result)> callback); Fn<void(const MTPUpdates &result)> callback);
@ -315,6 +321,12 @@ private:
TimeMs received = 0; 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 updatesReceived(const MTPUpdates &updates);
void checkQuitPreventFinished(); void checkQuitPreventFinished();
@ -469,6 +481,14 @@ private:
void sendNotifySettingsUpdates(); void sendNotifySettingsUpdates();
template <typename Request>
void requestFileReference(
Data::FileOrigin origin,
not_null<mtpFileLoader*> loader,
int requestId,
const QByteArray &current,
Request &&data);
not_null<AuthSession*> _session; not_null<AuthSession*> _session;
MessageDataRequests _messageDataRequests; MessageDataRequests _messageDataRequests;
@ -605,6 +625,10 @@ private:
base::flat_set<not_null<const PeerData*>> _updateNotifySettingsPeers; base::flat_set<not_null<const PeerData*>> _updateNotifySettingsPeers;
base::Timer _updateNotifySettingsTimer; base::Timer _updateNotifySettingsTimer;
std::map<
Data::FileOrigin,
std::vector<FileReferencesHandler>> _fileReferenceHandlers;
mtpRequestId _deepLinkInfoRequestId = 0; mtpRequestId _deepLinkInfoRequestId = 0;
TimeMs _termsUpdateSendAt = 0; TimeMs _termsUpdateSendAt = 0;

View File

@ -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

View File

@ -7,6 +7,7 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL
*/ */
#pragma once #pragma once
#include "base/variant.h"
#include "data/data_types.h" #include "data/data_types.h"
namespace Data { namespace Data {
@ -21,6 +22,11 @@ struct FileOriginUserPhoto {
UserId userId = 0; UserId userId = 0;
PhotoId photoId = 0; PhotoId photoId = 0;
inline bool operator<(const FileOriginUserPhoto &other) const {
return std::tie(userId, photoId)
< std::tie(other.userId, other.photoId);
}
}; };
struct FileOriginPeerPhoto { struct FileOriginPeerPhoto {
@ -28,6 +34,10 @@ struct FileOriginPeerPhoto {
} }
PeerId peerId = 0; PeerId peerId = 0;
inline bool operator<(const FileOriginPeerPhoto &other) const {
return peerId < other.peerId;
}
}; };
struct FileOriginStickerSet { struct FileOriginStickerSet {
@ -38,9 +48,16 @@ struct FileOriginStickerSet {
uint64 setId = 0; uint64 setId = 0;
uint64 accessHash = 0; uint64 accessHash = 0;
inline bool operator<(const FileOriginStickerSet &other) const {
return setId < other.setId;
}
}; };
struct FileOriginSavedGifs { struct FileOriginSavedGifs {
inline bool operator<(const FileOriginSavedGifs &) const {
return false;
}
}; };
using FileOrigin = base::optional_variant< using FileOrigin = base::optional_variant<
@ -50,4 +67,34 @@ using FileOrigin = base::optional_variant<
FileOriginStickerSet, FileOriginStickerSet,
FileOriginSavedGifs>; 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 } // namespace Data

View File

@ -394,7 +394,7 @@ void FileLoader::startLoading(bool loadFirst, bool prior) {
} }
mtpFileLoader::mtpFileLoader( mtpFileLoader::mtpFileLoader(
const StorageImageLocation *location, not_null<StorageImageLocation*> location,
Data::FileOrigin origin, Data::FileOrigin origin,
int32 size, int32 size,
LoadFromCloudSetting fromCloud LoadFromCloudSetting fromCloud
@ -479,6 +479,34 @@ Data::FileOrigin mtpFileLoader::fileOrigin() const {
return _origin; return _origin;
} }
void mtpFileLoader::refreshFileReferenceFrom(
const Data::UpdatedFileReferences &data,
int requestId,
const QByteArray &current) {
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() { bool mtpFileLoader::loadPart() {
if (_finished || _lastComplete || (!_sentRequests.empty() && !_size)) { if (_finished || _lastComplete || (!_sentRequests.empty() && !_size)) {
return false; return false;
@ -766,7 +794,7 @@ void mtpFileLoader::placeSentRequest(mtpRequestId requestId, const RequestData &
int mtpFileLoader::finishSentRequestGetOffset(mtpRequestId requestId) { int mtpFileLoader::finishSentRequestGetOffset(mtpRequestId requestId) {
auto it = _sentRequests.find(requestId); auto it = _sentRequests.find(requestId);
Expects(it != _sentRequests.cend()); Assert(it != _sentRequests.cend());
auto requestData = it->second; auto requestData = it->second;
_downloader->requestedAmountIncrement(requestData.dcId, requestData.dcIndex, -partSize()); _downloader->requestedAmountIncrement(requestData.dcId, requestData.dcIndex, -partSize());
@ -889,6 +917,14 @@ bool mtpFileLoader::partFailed(
if (MTP::isDefaultHandledError(error)) { if (MTP::isDefaultHandledError(error)) {
return false; return false;
} }
if (error.type().startsWith(qstr("FILE_REFERENCE_"))) {
Auth().api().refreshFileReference(
_origin,
this,
requestId,
_location ? _location->fileReference() : _fileReference);
return true;
}
cancel(true); cancel(true);
return true; return true;
} }

View File

@ -186,7 +186,7 @@ class mtpFileLoader : public FileLoader, public RPCSender {
public: public:
mtpFileLoader( mtpFileLoader(
const StorageImageLocation *location, not_null<StorageImageLocation*> location,
Data::FileOrigin origin, Data::FileOrigin origin,
int32 size, int32 size,
LoadFromCloudSetting fromCloud, LoadFromCloudSetting fromCloud,
@ -219,6 +219,10 @@ public:
void stop() override { void stop() override {
rpcInvalidate(); rpcInvalidate();
} }
void refreshFileReferenceFrom(
const Data::UpdatedFileReferences &data,
int requestId,
const QByteArray &current);
~mtpFileLoader(); ~mtpFileLoader();
@ -277,7 +281,7 @@ private:
int32 _nextRequestOffset = 0; int32 _nextRequestOffset = 0;
MTP::DcId _dcId = 0; // for photo locations MTP::DcId _dcId = 0; // for photo locations
const StorageImageLocation *_location = nullptr; StorageImageLocation *_location = nullptr;
uint64 _id = 0; // for document locations uint64 _id = 0; // for document locations
uint64 _accessHash = 0; uint64 _accessHash = 0;

View File

@ -1143,7 +1143,9 @@ FileLoader *StorageImage::createLoader(
Data::FileOrigin origin, Data::FileOrigin origin,
LoadFromCloudSetting fromCloud, LoadFromCloudSetting fromCloud,
bool autoLoading) { bool autoLoading) {
if (_location.isNull()) return 0; if (_location.isNull()) {
return nullptr;
}
return new mtpFileLoader( return new mtpFileLoader(
&_location, &_location,
origin, origin,

View File

@ -152,6 +152,9 @@ public:
QByteArray fileReference() const { QByteArray fileReference() const {
return _fileReference; return _fileReference;
} }
void refreshFileReference(const QByteArray &data) {
_fileReference = data;
}
static StorageImageLocation FromMTP( static StorageImageLocation FromMTP(
int32 width, int32 width,

View File

@ -179,6 +179,7 @@
<(src_loc)/data/data_feed.h <(src_loc)/data/data_feed.h
<(src_loc)/data/data_feed_messages.cpp <(src_loc)/data/data_feed_messages.cpp
<(src_loc)/data/data_feed_messages.h <(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_file_origin.h
<(src_loc)/data/data_flags.h <(src_loc)/data/data_flags.h
<(src_loc)/data/data_game.h <(src_loc)/data/data_game.h