diff --git a/td/telegram/Photo.cpp b/td/telegram/Photo.cpp index 05b35947..8c0dd00d 100644 --- a/td/telegram/Photo.cpp +++ b/td/telegram/Photo.cpp @@ -331,7 +331,7 @@ Variant get_photo_size(FileManager *file_manager, PhotoSizeSo res.type = static_cast(type[0]); } if (source.type == PhotoSizeSource::Type::Thumbnail) { - source.thumbnail_type = res.type; + source.thumbnail().thumbnail_type = res.type; } res.file_id = register_photo(file_manager, source, id, access_hash, file_reference, std::move(location), diff --git a/td/telegram/Photo.h b/td/telegram/Photo.h index 3454e819..2fb24ed3 100644 --- a/td/telegram/Photo.h +++ b/td/telegram/Photo.h @@ -47,38 +47,146 @@ struct PhotoSize { FileId file_id; }; +struct OfflineInputStickerSet { + int64 sticker_set_id = 0; + int64 sticker_set_access_hash = 0; + OfflineInputStickerSet() = default; + OfflineInputStickerSet(int64 sticker_set_id, int64 sticker_set_access_hash) + : sticker_set_id(sticker_set_id), sticker_set_access_hash(sticker_set_access_hash) { + } + tl_object_ptr as_telegram_api() const { + return make_tl_object(sticker_set_id, sticker_set_access_hash); + } + template + void store(StorerT &storer) const; + template + void parse(ParserT &parser); + struct AsKey { + const OfflineInputStickerSet &key; + template + void store(StorerT &storer) const; + }; + AsKey as_key() const { + return AsKey{*this}; + } +}; + +struct OfflineInputPeer { + DialogId dialog_id; + int64 dialog_access_hash = 0; + OfflineInputPeer() = default; + OfflineInputPeer(DialogId dialog_id, int64 dialog_access_hash) + : dialog_id(dialog_id), dialog_access_hash(dialog_access_hash) { + } + tl_object_ptr as_telegram_api() const { + switch (dialog_id.get_type()) { + case DialogType::User: { + UserId user_id = dialog_id.get_user_id(); + return make_tl_object(user_id.get(), dialog_access_hash); + } + case DialogType::Chat: { + ChatId chat_id = dialog_id.get_chat_id(); + return make_tl_object(chat_id.get()); + } + case DialogType::Channel: { + ChannelId channel_id = dialog_id.get_channel_id(); + return make_tl_object(channel_id.get(), dialog_access_hash); + } + case DialogType::SecretChat: + return nullptr; + case DialogType::None: + return make_tl_object(); + default: + UNREACHABLE(); + return nullptr; + } // namespace td + } + + template + void store(StorerT &storer) const; + template + void parse(ParserT &parser); + struct AsKey { + const OfflineInputPeer &key; + template + void store(StorerT &storer) const; + }; + AsKey as_key() const { + return AsKey{*this}; + } +}; + struct PhotoSizeSource { - enum class Type : int32 { Thumbnail, DialogPhoto, StickerSetThumbnail }; + enum class Type : int32 { Empty, Thumbnail, DialogPhoto, StickerSetThumbnail }; Type type; FileType file_type; // for photos, document thumbnails, encrypted thumbnails - int32 thumbnail_type = 0; - + struct Thumbnail { + Thumbnail() = default; + Thumbnail(int32 thumbnail_type) : thumbnail_type(thumbnail_type) { + } + int32 thumbnail_type = 0; + }; // for dialog photos - DialogId dialog_id; - int64 dialog_access_hash = 0; - bool is_big = false; + struct DialogPhoto { + DialogPhoto() = default; + DialogPhoto(OfflineInputPeer input_peer, bool is_big) : input_peer(input_peer), is_big(is_big) { + } + OfflineInputPeer input_peer; + bool is_big = false; + }; // for sticker set thumbnails - int64 sticker_set_id = 0; - int64 sticker_set_access_hash = 0; + struct StickerSetThumbnail { + StickerSetThumbnail() = default; + explicit StickerSetThumbnail(OfflineInputStickerSet input_sticker_set) : input_sticker_set(input_sticker_set) { + } + OfflineInputStickerSet input_sticker_set; + }; + Variant variant; + + PhotoSizeSource() : type(Type::Empty), file_type(FileType::None) { + } PhotoSizeSource(FileType file_type, int32 thumbnail_type) - : type(Type::Thumbnail), file_type(file_type), thumbnail_type(thumbnail_type) { + : type(Type::Thumbnail), file_type(file_type), variant(Thumbnail(thumbnail_type)) { } PhotoSizeSource(DialogId dialog_id, int64 dialog_access_hash, bool is_big) : type(Type::DialogPhoto) , file_type(FileType::ProfilePhoto) - , dialog_id(dialog_id) - , dialog_access_hash(dialog_access_hash) - , is_big(is_big) { + , variant(DialogPhoto(OfflineInputPeer(dialog_id, dialog_access_hash), is_big)) { } PhotoSizeSource(int64 sticker_set_id, int64 sticker_set_access_hash) : type(Type::StickerSetThumbnail) , file_type(FileType::Thumbnail) - , sticker_set_id(sticker_set_id) - , sticker_set_access_hash(sticker_set_access_hash) { + , variant(StickerSetThumbnail(OfflineInputStickerSet(sticker_set_id, sticker_set_access_hash))) { + } + + Thumbnail &thumbnail() { + return variant.get(); + } + const Thumbnail &thumbnail() const { + return variant.get(); + } + const DialogPhoto &dialog_photo() const { + return variant.get(); + } + const StickerSetThumbnail &sticker_set_thumbnail() const { + return variant.get(); + } + + template + void store(StorerT &storer) const; + template + void parse(ParserT &parser); + struct AsKey { + const PhotoSizeSource &key; + template + void store(StorerT &storer) const; + }; + AsKey as_key() const { + return AsKey{*this}; } }; diff --git a/td/telegram/Photo.hpp b/td/telegram/Photo.hpp index 0c683c9c..96b5f0f1 100644 --- a/td/telegram/Photo.hpp +++ b/td/telegram/Photo.hpp @@ -14,6 +14,126 @@ #include "td/utils/tl_helpers.h" namespace td { +template +void OfflineInputStickerSet::store(StorerT &storer) const { + using td::store; + store(sticker_set_id, storer); + store(sticker_set_access_hash, storer); +} +template +void OfflineInputStickerSet::parse(ParserT &parser) { + using td::parse; + parse(sticker_set_id, parser); + parse(sticker_set_access_hash, parser); +} + +template +void OfflineInputStickerSet::AsKey::store(StorerT &storer) const { + using td::store; + store(key.sticker_set_id, storer); +} + +template +void OfflineInputPeer::store(StorerT &storer) const { + using td::store; + store(dialog_id, storer); + store(dialog_access_hash, storer); +} +template +void OfflineInputPeer::parse(ParserT &parser) { + using td::parse; + parse(dialog_id, parser); + parse(dialog_access_hash, parser); +} + +template +void OfflineInputPeer::AsKey::store(StorerT &storer) const { + using td::store; + store(key.dialog_id, storer); +} + +template +void PhotoSizeSource::store(StorerT &storer) const { + using td::store; + store(file_type, storer); + store(type, storer); + switch (type) { + case Type::DialogPhoto: { + auto &dialog_photo = this->dialog_photo(); + store(dialog_photo.input_peer, storer); + store(dialog_photo.is_big, storer); + break; + } + case Type::StickerSetThumbnail: { + auto &sticker_set_thumbnail = this->sticker_set_thumbnail(); + store(sticker_set_thumbnail.input_sticker_set, storer); + break; + } + case Type::Thumbnail: { + auto &thumbnail = this->thumbnail(); + store(thumbnail.thumbnail_type, storer); + break; + } + case Type::Empty: + break; + } +} +template +void PhotoSizeSource::parse(ParserT &parser) { + using td::parse; + parse(file_type, parser); + parse(type, parser); + switch (type) { + case Type::DialogPhoto: { + DialogPhoto dialog_photo; + parse(dialog_photo.input_peer, parser); + parse(dialog_photo.is_big, parser); + variant = dialog_photo; + break; + } + case Type::StickerSetThumbnail: { + StickerSetThumbnail sticker_set_thumbnail; + parse(sticker_set_thumbnail.input_sticker_set, parser); + variant = sticker_set_thumbnail; + break; + } + case Type::Thumbnail: { + Thumbnail thumbnail; + parse(thumbnail.thumbnail_type, parser); + variant = thumbnail; + break; + } + case Type::Empty: + break; + } +} + +template +void PhotoSizeSource::AsKey::store(StorerT &storer) const { + using td::store; + store(key.file_type, storer); + store(key.type, storer); + switch (key.type) { + case Type::DialogPhoto: { + auto &dialog_photo = this->key.dialog_photo(); + store(dialog_photo.input_peer.as_key(), storer); + store(dialog_photo.is_big, storer); + break; + } + case Type::StickerSetThumbnail: { + auto &sticker_set_thumbnail = this->key.sticker_set_thumbnail(); + store(sticker_set_thumbnail.input_sticker_set.as_key(), storer); + break; + } + case Type::Thumbnail: { + auto &thumbnail = this->key.thumbnail(); + store(thumbnail.thumbnail_type, storer); + break; + } + case Type::Empty: + break; + } +} template void store(Dimensions dimensions, StorerT &storer) { diff --git a/td/telegram/Version.h b/td/telegram/Version.h index 2599256f..5f639dc9 100644 --- a/td/telegram/Version.h +++ b/td/telegram/Version.h @@ -31,6 +31,7 @@ enum class Version : int32 { AddNotificationGroupInfoMaxRemovedMessageId, SupportMinithumbnails, AddVideoCallsSupport, + PhotoSizeSource, Next }; diff --git a/td/telegram/files/FileData.hpp b/td/telegram/files/FileData.hpp index e4b1912d..13af0d0e 100644 --- a/td/telegram/files/FileData.hpp +++ b/td/telegram/files/FileData.hpp @@ -29,13 +29,18 @@ void FileData::store(StorerT &storer) const { bool has_expected_size = size_ == 0 && expected_size_ != 0; bool encryption_key_is_secure = encryption_key_.is_secure(); bool has_sources = !file_source_ids_.empty(); + bool has_version = true; BEGIN_STORE_FLAGS(); STORE_FLAG(has_owner_dialog_id); STORE_FLAG(has_expected_size); STORE_FLAG(encryption_key_is_secure); STORE_FLAG(has_sources); + STORE_FLAG(has_version); END_STORE_FLAGS(); + if (has_version) { + store(static_cast(Version::Next) - 1, storer); + } if (has_owner_dialog_id) { store(owner_dialog_id_, storer); } @@ -67,13 +72,20 @@ void FileData::parse(ParserT &parser, bool register_file_sources) { bool has_expected_size; bool encryption_key_is_secure; bool has_sources; + bool has_version; BEGIN_PARSE_FLAGS(); PARSE_FLAG(has_owner_dialog_id); PARSE_FLAG(has_expected_size); PARSE_FLAG(encryption_key_is_secure); PARSE_FLAG(has_sources); + PARSE_FLAG(has_version); END_PARSE_FLAGS_GENERIC(); + int32 version = 0; + if (has_version) { + parse(version, parser); + } + parser.set_version(version); if (has_owner_dialog_id) { parse(owner_dialog_id_, parser); } diff --git a/td/telegram/files/FileDb.cpp b/td/telegram/files/FileDb.cpp index e01c2c91..62edc4b1 100644 --- a/td/telegram/files/FileDb.cpp +++ b/td/telegram/files/FileDb.cpp @@ -11,6 +11,7 @@ #include "td/telegram/files/FileLocation.h" #include "td/telegram/files/FileLocation.hpp" #include "td/telegram/Version.h" +#include "td/telegram/logevent/LogEvent.h" // WithVersion #include "td/actor/actor.h" @@ -276,7 +277,8 @@ class FileDb : public FileDbInterface { //LOG(DEBUG) << "By id " << id.get() << " found data " << format::as_hex_dump<4>(Slice(data_str)); //LOG(INFO) << attempt_count; - TlParser parser(data_str); + logevent::WithVersion parser(data_str); + parser.set_version(static_cast(Version::Initial)); FileData data; data.parse(parser, true); parser.fetch_end(); @@ -313,7 +315,12 @@ Status fix_file_remote_location_key_bug(SqliteDb &db) { CHECK(TlParser(key).fetch_int() == OLD_KEY_MAGIC); auto remote_str = PSTRING() << key.substr(4, 4) << Slice("\0\0\0\0") << key.substr(8); FullRemoteFileLocation remote; - if (unserialize(remote, remote_str).is_ok()) { + logevent::WithVersion parser(remote_str); + parser.set_version(static_cast(Version::Initial)); + parse(remote, parser); + parser.fetch_end(); + auto status = parser.get_status(); + if (status.is_ok()) { kv.set(FileDbInterface::as_key(remote), value); } LOG(DEBUG) << "ERASE " << format::as_hex_dump<4>(Slice(key)); diff --git a/td/telegram/files/FileLocation.h b/td/telegram/files/FileLocation.h index cbc2e73f..ad06dac7 100644 --- a/td/telegram/files/FileLocation.h +++ b/td/telegram/files/FileLocation.h @@ -170,6 +170,7 @@ struct PhotoRemoteFileLocation { int64 volume_id_; int64 secret_; int32 local_id_; + PhotoSizeSource source_; template void store(StorerT &storer) const; @@ -474,10 +475,43 @@ class FullRemoteFileLocation { tl_object_ptr as_input_file_location() const { switch (location_type()) { - case LocationType::Photo: - return make_tl_object( - photo().volume_id_, photo().local_id_, photo().secret_, - BufferSlice(FileReferenceView(file_reference_).download())); + case LocationType::Photo: { + switch (photo().source_.type) { + case PhotoSizeSource::Type::Empty: + return make_tl_object( + photo().volume_id_, photo().local_id_, photo().secret_, + BufferSlice(FileReferenceView(file_reference_).download())); + case PhotoSizeSource::Type::Thumbnail: { + auto &thumbnail = photo().source_.thumbnail(); + switch (file_type_) { + case FileType::Photo: + return make_tl_object( + photo().id_, photo().access_hash_, BufferSlice(FileReferenceView(file_reference_).download()), + std::string(1, thumbnail.thumbnail_type)); + case FileType::Thumbnail: + return make_tl_object( + photo().id_, photo().access_hash_, BufferSlice(FileReferenceView(file_reference_).download()), + std::string(1, thumbnail.thumbnail_type)); + default: + case FileType::EncryptedThumbnail: + UNREACHABLE(); + } + } + case PhotoSizeSource::Type::DialogPhoto: { + LOG(ERROR) << "DIALOG PHOTO"; + auto &dialog_photo = photo().source_.dialog_photo(); + return make_tl_object( + dialog_photo.is_big * telegram_api::inputPeerPhotoFileLocation::Flags::BIG_MASK, dialog_photo.is_big, + dialog_photo.input_peer.as_telegram_api(), photo().volume_id_, photo().local_id_); + } + case PhotoSizeSource::Type::StickerSetThumbnail: { + LOG(ERROR) << "StickerSetThumbnail"; + auto &sticker_set_thumbnail = photo().source_.sticker_set_thumbnail(); + return make_tl_object( + sticker_set_thumbnail.input_sticker_set.as_telegram_api(), photo().volume_id_, photo().local_id_); + } + } + } case LocationType::Common: if (is_encrypted_secret()) { return make_tl_object(common().id_, common().access_hash_); @@ -531,7 +565,7 @@ class FullRemoteFileLocation { : file_type_(source.file_type) , dc_id_(dc_id) , file_reference_(FileReferenceView::create_one(file_reference)) - , variant_(PhotoRemoteFileLocation{id, access_hash, volume_id, -1, local_id}) { // TODO(now) use source + , variant_(PhotoRemoteFileLocation{id, access_hash, volume_id, -1, local_id, source}) { CHECK(is_photo()); check_file_reference(); } diff --git a/td/telegram/files/FileLocation.hpp b/td/telegram/files/FileLocation.hpp index 1a222982..06d6d2a6 100644 --- a/td/telegram/files/FileLocation.hpp +++ b/td/telegram/files/FileLocation.hpp @@ -9,12 +9,14 @@ #include "td/telegram/files/FileLocation.h" #include "td/telegram/files/FileType.h" -#include "td/telegram/net/DcId.h" +#include "td/telegram/Version.h" #include "td/utils/common.h" #include "td/utils/tl_helpers.h" #include "td/utils/Variant.h" +#include "td/telegram/Photo.hpp" + namespace td { template @@ -45,6 +47,7 @@ void PhotoRemoteFileLocation::store(StorerT &storer) const { store(volume_id_, storer); store(secret_, storer); store(local_id_, storer); + store(source_, storer); } template @@ -55,6 +58,9 @@ void PhotoRemoteFileLocation::parse(ParserT &parser) { parse(volume_id_, parser); parse(secret_, parser); parse(local_id_, parser); + if (parser.version() >= static_cast(Version::PhotoSizeSource)) { + parse(source_, parser); + } } template @@ -63,6 +69,7 @@ void PhotoRemoteFileLocation::AsKey::store(StorerT &storer) const { store(key.id_, storer); store(key.volume_id_, storer); store(key.local_id_, storer); + store(key.source_.as_key(), storer); } template diff --git a/td/telegram/files/FileManager.cpp b/td/telegram/files/FileManager.cpp index 57296ab5..ea959039 100644 --- a/td/telegram/files/FileManager.cpp +++ b/td/telegram/files/FileManager.cpp @@ -19,6 +19,7 @@ #include "td/telegram/misc.h" #include "td/telegram/SecureStorage.h" #include "td/telegram/TdDb.h" +#include "td/telegram/logevent/LogEvent.h" #include "td/actor/SleepActor.h" @@ -2618,7 +2619,12 @@ Result FileManager::from_persistent_id_v2(Slice binary, FileType file_ty binary.remove_suffix(1); auto decoded_binary = zero_decode(binary); FullRemoteFileLocation remote_location; - auto status = unserialize(remote_location, decoded_binary); + logevent::WithVersion parser(decoded_binary); + //TODO(now): encode version? + parser.set_version(static_cast(Version::Initial)); + parse(remote_location, parser); + parser.fetch_end(); + auto status = parser.get_status(); if (status.is_error()) { return Status::Error(10, "Wrong remote file id specified: can't unserialize it"); } diff --git a/td/telegram/files/FileStatsWorker.cpp b/td/telegram/files/FileStatsWorker.cpp index 159514e5..1873dbb0 100644 --- a/td/telegram/files/FileStatsWorker.cpp +++ b/td/telegram/files/FileStatsWorker.cpp @@ -14,6 +14,7 @@ #include "td/telegram/files/FileType.h" #include "td/telegram/Global.h" #include "td/telegram/TdDb.h" +#include "td/telegram/logevent/LogEvent.h" // WithVersion #include "td/db/SqliteKeyValue.h" @@ -57,7 +58,7 @@ void scan_db(CancellationToken &token, CallbackT &&callback) { if (value.substr(0, 2) == "@@") { return true; } - TlParser parser(value); + logevent::WithVersion parser(value); FileData data; data.parse(parser, false); if (parser.get_status().is_error()) { @@ -107,35 +108,33 @@ void scan_fs(CancellationToken &token, CallbackT &&callback) { continue; } auto files_dir = get_files_dir(file_type); - td::walk_path(files_dir, - [&](CSlice path, WalkPath::Type type) { - if (token) { - return WalkPath::Action::Abort; - } - if (type != WalkPath::Type::NotDir) { - return WalkPath::Action::Continue; - } - auto r_stat = stat(path); - if (r_stat.is_error()) { - LOG(WARNING) << "Stat in files gc failed: " << r_stat.error(); - return WalkPath::Action::Continue; - } - auto stat = r_stat.move_as_ok(); - if (ends_with(path, "/.nomedia") && stat.size_ == 0) { - // skip .nomedia file - return WalkPath::Action::Continue; - } + td::walk_path(files_dir, [&](CSlice path, WalkPath::Type type) { + if (token) { + return WalkPath::Action::Abort; + } + if (type != WalkPath::Type::NotDir) { + return WalkPath::Action::Continue; + } + auto r_stat = stat(path); + if (r_stat.is_error()) { + LOG(WARNING) << "Stat in files gc failed: " << r_stat.error(); + return WalkPath::Action::Continue; + } + auto stat = r_stat.move_as_ok(); + if (ends_with(path, "/.nomedia") && stat.size_ == 0) { + // skip .nomedia file + return WalkPath::Action::Continue; + } - FsFileInfo info; - info.path = path.str(); - info.size = stat.size_; - info.file_type = file_type; - info.atime_nsec = stat.atime_nsec_; - info.mtime_nsec = stat.mtime_nsec_; - callback(info); - return WalkPath::Action::Continue; - }) - .ignore(); + FsFileInfo info; + info.path = path.str(); + info.size = stat.size_; + info.file_type = file_type; + info.atime_nsec = stat.atime_nsec_; + info.mtime_nsec = stat.mtime_nsec_; + callback(info); + return WalkPath::Action::Continue; + }).ignore(); } } } // namespace