diff --git a/td/generate/tl_writer_td.cpp b/td/generate/tl_writer_td.cpp index f56622ddf..30c232541 100644 --- a/td/generate/tl_writer_td.cpp +++ b/td/generate/tl_writer_td.cpp @@ -49,8 +49,9 @@ bool TD_TL_writer::is_combinator_supported(const tl::tl_combinator *constructor) return true; } -bool TD_TL_writer::is_default_constructor_generated(const tl::tl_combinator *t, bool is_function) const { - return tl_name == "td_api" || tl_name == "TdApi" || (t->var_count > 0 && !is_function); +bool TD_TL_writer::is_default_constructor_generated(const tl::tl_combinator *t, bool can_be_parsed, + bool can_be_stored) const { + return tl_name == "td_api" || tl_name == "TdApi" || (t->var_count > 0 && can_be_parsed); } int TD_TL_writer::get_storer_type(const tl::tl_combinator *t, const std::string &storer_name) const { diff --git a/td/generate/tl_writer_td.h b/td/generate/tl_writer_td.h index cef02ca0d..b958df605 100644 --- a/td/generate/tl_writer_td.h +++ b/td/generate/tl_writer_td.h @@ -35,7 +35,8 @@ class TD_TL_writer : public tl::TL_writer { bool is_built_in_complex_type(const std::string &name) const override; bool is_type_bare(const tl::tl_type *t) const override; bool is_combinator_supported(const tl::tl_combinator *constructor) const override; - bool is_default_constructor_generated(const tl::tl_combinator *t, bool is_function) const override; + bool is_default_constructor_generated(const tl::tl_combinator *t, bool can_be_parsed, + bool can_be_stored) const override; int get_storer_type(const tl::tl_combinator *t, const std::string &storer_name) const override; Mode get_parser_mode(int type) const override; diff --git a/td/telegram/MessagesManager.cpp b/td/telegram/MessagesManager.cpp index b7dd46518..8711f701a 100644 --- a/td/telegram/MessagesManager.cpp +++ b/td/telegram/MessagesManager.cpp @@ -9506,7 +9506,7 @@ void MessagesManager::on_get_history(DialogId dialog_id, MessageId from_message_ return; } - { + if (messages.size() > 1) { // check that messages are received in decreasing message_id order MessageId cur_message_id = MessageId::max(); for (const auto &message : messages) { @@ -35917,19 +35917,110 @@ void MessagesManager::do_get_channel_difference(DialogId dialog_id, int32 pts, b } void MessagesManager::process_get_channel_difference_updates( - DialogId dialog_id, vector> &&new_messages, + DialogId dialog_id, int32 new_pts, vector> &&new_messages, vector> &&other_updates) { LOG(INFO) << "In get channel difference for " << dialog_id << " receive " << new_messages.size() << " messages and " << other_updates.size() << " other updates"; CHECK(!debug_channel_difference_dialog_.is_valid()); debug_channel_difference_dialog_ = dialog_id; - for (auto &update : other_updates) { - if (update->get_id() == telegram_api::updateMessageID::ID) { - // in channels.getDifference updateMessageID can't be received for scheduled messages - auto sent_message_update = move_tl_object_as(update); - on_update_message_id(sent_message_update->random_id_, MessageId(ServerMessageId(sent_message_update->id_)), - "get_channel_difference"); - update = nullptr; + + // identifiers of edited and deleted messages + std::unordered_set changed_message_ids; + for (auto &update_ptr : other_updates) { + bool is_good_update = true; + switch (update_ptr->get_id()) { + case telegram_api::updateMessageID::ID: { + // in channels.getDifference updateMessageID can't be received for scheduled messages + auto sent_message_update = move_tl_object_as(update_ptr); + on_update_message_id(sent_message_update->random_id_, MessageId(ServerMessageId(sent_message_update->id_)), + "get_channel_difference"); + update_ptr = nullptr; + break; + } + case telegram_api::updateDeleteChannelMessages::ID: { + auto *update = static_cast(update_ptr.get()); + if (DialogId(ChannelId(update->channel_id_)) != dialog_id) { + is_good_update = false; + } else { + for (auto &message : update->messages_) { + changed_message_ids.insert(MessageId(ServerMessageId(message))); + } + } + break; + } + case telegram_api::updateEditChannelMessage::ID: { + auto *update = static_cast(update_ptr.get()); + auto full_message_id = get_full_message_id(update->message_, false); + if (full_message_id.get_dialog_id() != dialog_id) { + is_good_update = false; + } else { + changed_message_ids.insert(full_message_id.get_message_id()); + } + break; + } + case telegram_api::updatePinnedChannelMessages::ID: { + auto *update = static_cast(update_ptr.get()); + if (DialogId(ChannelId(update->channel_id_)) != dialog_id) { + is_good_update = false; + } + break; + } + default: + is_good_update = false; + break; + } + if (!is_good_update) { + LOG(ERROR) << "Receive wrong update in channelDifference of " << dialog_id << ": " << to_string(update_ptr); + update_ptr = nullptr; + } + } + + auto is_edited_message = [](const tl_object_ptr &message) { + if (message->get_id() != telegram_api::message::ID) { + return false; + } + return static_cast(message.get())->edit_date_ > 0; + }; + + for (auto &message : new_messages) { + if (is_edited_message(message)) { + changed_message_ids.insert(get_message_id(message, false)); + } + } + + // extract awaited sent messages, which were edited or deleted after that + auto postponed_updates_it = postponed_channel_updates_.find(dialog_id); + std::map> awaited_messages; + if (postponed_updates_it != postponed_channel_updates_.end()) { + auto &updates = postponed_updates_it->second; + while (!updates.empty()) { + auto it = updates.begin(); + auto update_pts = it->second.pts; + if (update_pts > new_pts) { + break; + } + + auto update = std::move(it->second.update); + auto promise = std::move(it->second.promise); + updates.erase(it); + + if (!promise && update->get_id() == telegram_api::updateNewChannelMessage::ID) { + auto update_new_channel_message = static_cast(update.get()); + auto message_id = get_message_id(update_new_channel_message->message_, false); + FullMessageId full_message_id(dialog_id, message_id); + if (update_message_ids_.find(full_message_id) != update_message_ids_.end() && + changed_message_ids.find(message_id) != changed_message_ids.end()) { + changed_message_ids.erase(message_id); + awaited_messages.emplace(message_id, std::move(update_new_channel_message->message_)); + continue; + } + } + + LOG(INFO) << "Skip to be applied from getChannelDifference " << to_string(update); + promise.set_value(Unit()); + } + if (updates.empty()) { + postponed_channel_updates_.erase(postponed_updates_it); } } @@ -35937,22 +36028,31 @@ void MessagesManager::process_get_channel_difference_updates( bool need_repair_unread_count = !new_messages.empty() && get_message_date(new_messages[0]) < G()->unix_time() - 2 * 86400; + auto it = awaited_messages.begin(); for (auto &message : new_messages) { + auto message_id = get_message_id(message, false); + while (it != awaited_messages.end() && it->first < message_id) { + on_get_message(std::move(it->second), true, true, false, true, true, "postponed channel update"); + ++it; + } + if (it != awaited_messages.end() && it->first == message_id) { + if (is_edited_message(message)) { + // the new message is edited, apply postponed one and move this to updateEditChannelMessage + other_updates.push_back(make_tl_object(std::move(message), new_pts, 0)); + message = std::move(it->second); + } + ++it; + } on_get_message(std::move(message), true, true, false, true, true, "get channel difference"); } + while (it != awaited_messages.end()) { + on_get_message(std::move(it->second), true, true, false, true, true, "postponed channel update 2"); + ++it; + } for (auto &update : other_updates) { if (update != nullptr) { - switch (update->get_id()) { - case telegram_api::updateDeleteChannelMessages::ID: - case telegram_api::updateEditChannelMessage::ID: - case telegram_api::updatePinnedChannelMessages::ID: - process_channel_update(std::move(update)); - break; - default: - LOG(ERROR) << "Unsupported update received in getChannelDifference: " << oneline(to_string(update)); - break; - } + process_channel_update(std::move(update)); } } LOG_CHECK(!running_get_channel_difference(dialog_id)) << '"' << active_get_channel_differencies_[dialog_id] << '"'; @@ -36184,7 +36284,24 @@ void MessagesManager::on_get_channel_difference( new_pts = request_pts + 1; } - process_get_channel_difference_updates(dialog_id, std::move(difference->new_messages_), + if (difference->new_messages_.size() > 1) { + // check that new messages are received in increasing message_id order + MessageId cur_message_id; + for (const auto &message : difference->new_messages_) { + auto message_id = get_message_id(message, false); + if (message_id <= cur_message_id) { + // TODO move to ERROR + LOG(FATAL) << "Receive " << cur_message_id << " after " << message_id << " in channelDifference of " + << dialog_id << " with pts " << request_pts << " and limit " << request_limit << ": " + << to_string(difference); + after_get_channel_difference(dialog_id, false); + return; + } + cur_message_id = message_id; + } + } + + process_get_channel_difference_updates(dialog_id, new_pts, std::move(difference->new_messages_), std::move(difference->other_updates_)); set_channel_pts(d, new_pts, "channel difference"); @@ -36296,9 +36413,9 @@ void MessagesManager::after_get_channel_difference(DialogId dialog_id, bool succ auto d = get_dialog(dialog_id); bool have_access = have_input_peer(dialog_id, AccessRights::Read); auto pts = d != nullptr ? d->pts : load_channel_pts(dialog_id); - auto updates_it = postponed_channel_updates_.find(dialog_id); - if (updates_it != postponed_channel_updates_.end()) { - auto &updates = updates_it->second; + auto postponed_updates_it = postponed_channel_updates_.find(dialog_id); + if (postponed_updates_it != postponed_channel_updates_.end()) { + auto &updates = postponed_updates_it->second; LOG(INFO) << "Begin to apply " << updates.size() << " postponed channel updates"; while (!updates.empty()) { auto it = updates.begin(); @@ -36339,7 +36456,7 @@ void MessagesManager::after_get_channel_difference(DialogId dialog_id, bool succ } } if (updates.empty()) { - postponed_channel_updates_.erase(updates_it); + postponed_channel_updates_.erase(postponed_updates_it); } LOG(INFO) << "Finish to apply postponed channel updates"; } diff --git a/td/telegram/MessagesManager.h b/td/telegram/MessagesManager.h index 3c71fb4c9..2f04cc1ac 100644 --- a/td/telegram/MessagesManager.h +++ b/td/telegram/MessagesManager.h @@ -2793,7 +2793,7 @@ class MessagesManager final : public Actor { void do_get_channel_difference(DialogId dialog_id, int32 pts, bool force, tl_object_ptr &&input_channel, const char *source); - void process_get_channel_difference_updates(DialogId dialog_id, + void process_get_channel_difference_updates(DialogId dialog_id, int32 new_pts, vector> &&new_messages, vector> &&other_updates); diff --git a/td/telegram/PasswordManager.cpp b/td/telegram/PasswordManager.cpp index 0bf057bc7..09a4c5312 100644 --- a/td/telegram/PasswordManager.cpp +++ b/td/telegram/PasswordManager.cpp @@ -635,13 +635,16 @@ Result PasswordManager::get_password_inp Result PasswordManager::get_password_input_settings( const UpdateSettings &update_settings, bool has_password, const NewPasswordState &state, const PasswordPrivateState *private_state) { - auto settings = make_tl_object(); bool have_secret = private_state != nullptr && private_state->secret; auto update_secure_secret = update_settings.update_secure_secret; + int32 flags = 0; + BufferSlice new_password_hash; + tl_object_ptr new_algo; + string new_hint; if (update_settings.update_password) { - settings->flags_ |= telegram_api::account_passwordInputSettings::NEW_PASSWORD_HASH_MASK; - settings->flags_ |= telegram_api::account_passwordInputSettings::NEW_ALGO_MASK; - settings->flags_ |= telegram_api::account_passwordInputSettings::HINT_MASK; + flags |= telegram_api::account_passwordInputSettings::NEW_PASSWORD_HASH_MASK; + flags |= telegram_api::account_passwordInputSettings::NEW_ALGO_MASK; + flags |= telegram_api::account_passwordInputSettings::HINT_MASK; if (!update_settings.new_password.empty()) { auto new_client_salt = create_salt(state.client_salt); @@ -650,16 +653,15 @@ Result PasswordManager::get_password_inp if (new_hash.is_error()) { return Status::Error(400, "Unable to change password, because it may be unsafe"); } - settings->new_password_hash_ = new_hash.move_as_ok(); - settings->new_algo_ = - make_tl_object( - std::move(new_client_salt), BufferSlice(state.server_salt), state.srp_g, BufferSlice(state.srp_p)); - settings->hint_ = std::move(update_settings.new_hint); + new_password_hash = new_hash.move_as_ok(); + new_algo = make_tl_object( + std::move(new_client_salt), BufferSlice(state.server_salt), state.srp_g, BufferSlice(state.srp_p)); + new_hint = std::move(update_settings.new_hint); if (have_secret) { update_secure_secret = true; } } else { - settings->new_algo_ = make_tl_object(); + new_algo = make_tl_object(); } } @@ -673,6 +675,7 @@ Result PasswordManager::get_password_inp update_secure_secret = false; } + tl_object_ptr new_secure_settings; if (update_secure_secret) { auto secret = have_secret ? std::move(private_state->secret.value()) : secure_storage::Secret::create_new(); auto algorithm = @@ -681,15 +684,16 @@ Result PasswordManager::get_password_inp update_settings.update_password ? update_settings.new_password : update_settings.current_password, algorithm->salt_.as_slice(), secure_storage::EnryptionAlgorithm::Pbkdf2); - settings->flags_ |= telegram_api::account_passwordInputSettings::NEW_SECURE_SETTINGS_MASK; - settings->new_secure_settings_ = make_tl_object( + flags |= telegram_api::account_passwordInputSettings::NEW_SECURE_SETTINGS_MASK; + new_secure_settings = make_tl_object( std::move(algorithm), BufferSlice(encrypted_secret.as_slice()), secret.get_hash()); } if (update_settings.update_recovery_email_address) { - settings->flags_ |= telegram_api::account_passwordInputSettings::EMAIL_MASK; - settings->email_ = std::move(update_settings.recovery_email_address); + flags |= telegram_api::account_passwordInputSettings::EMAIL_MASK; } - return std::move(settings); + return make_tl_object( + flags, std::move(new_algo), std::move(new_password_hash), new_hint, update_settings.recovery_email_address, + std::move(new_secure_settings)); } void PasswordManager::do_update_password_settings_impl(UpdateSettings update_settings, PasswordState state, diff --git a/tdtl/td/tl/tl_generate.cpp b/tdtl/td/tl/tl_generate.cpp index 84478aae3..95e87947e 100644 --- a/tdtl/td/tl/tl_generate.cpp +++ b/tdtl/td/tl/tl_generate.cpp @@ -253,7 +253,7 @@ static void write_function(tl_outputer &out, const tl_combinator *t, const std:: std::vector vars(t->var_count); out.append(w.gen_function_vars(t, vars)); - if (w.is_default_constructor_generated(t, true)) { + if (w.is_default_constructor_generated(t, false, true)) { write_class_constructor(out, t, class_name, true, w); } if (required_args) { @@ -306,7 +306,35 @@ static void write_constructor(tl_outputer &out, const tl_combinator *t, const st int required_args = gen_field_definitions(out, t, class_name, w); out.append(w.gen_flags_definitions(t)); - if (w.is_default_constructor_generated(t, false)) { + bool can_be_parsed = false; + bool is_can_be_parsed_inited = false; + std::vector parsers = w.get_parsers(); + for (std::size_t i = 0; i < parsers.size(); i++) { + int parser_type = w.get_parser_type(t, parsers[i]); + if (w.get_parser_mode(parser_type) != TL_writer::All) { + can_be_parsed |= is_reachable_for_parser(parser_type, t->name, request_types, result_types, w); + is_can_be_parsed_inited = true; + } + } + if (!is_can_be_parsed_inited) { + can_be_parsed = true; + } + + bool can_be_stored = false; + bool is_can_be_stored_inited = false; + std::vector storers = w.get_storers(); + for (std::size_t i = 0; i < storers.size(); i++) { + int storer_type = w.get_storer_type(t, storers[i]); + if (w.get_storer_mode(storer_type) != TL_writer::All) { + can_be_stored |= is_reachable_for_storer(storer_type, t->name, request_types, result_types, w); + is_can_be_stored_inited = true; + } + } + if (!is_can_be_stored_inited) { + can_be_stored = true; + } + + if (w.is_default_constructor_generated(t, can_be_parsed, can_be_stored)) { write_class_constructor(out, t, class_name, true, w); } if (required_args) { @@ -319,7 +347,6 @@ static void write_constructor(tl_outputer &out, const tl_combinator *t, const st assert(t->result->get_type() == NODE_TYPE_TYPE); const tl_tree_type *result_type = static_cast(t->result); - std::vector parsers = w.get_parsers(); for (std::size_t i = 0; i < parsers.size(); i++) { write_constructor_fetch(out, parsers[i], t, class_name, parent_class, result_type, required_args == 1 && result_type->type->simple_constructors == 1, request_types, @@ -327,7 +354,6 @@ static void write_constructor(tl_outputer &out, const tl_combinator *t, const st } // STORER - std::vector storers = w.get_storers(); for (std::size_t i = 0; i < storers.size(); i++) { write_constructor_store(out, storers[i], t, class_name, result_type, required_args == 1 && result_type->type->simple_constructors == 1, request_types, diff --git a/tdtl/td/tl/tl_writer.cpp b/tdtl/td/tl/tl_writer.cpp index f965a4b04..965dfdef1 100644 --- a/tdtl/td/tl/tl_writer.cpp +++ b/tdtl/td/tl/tl_writer.cpp @@ -135,7 +135,7 @@ bool TL_writer::is_documentation_generated() const { return false; } -bool TL_writer::is_default_constructor_generated(const tl_combinator *t, bool is_function) const { +bool TL_writer::is_default_constructor_generated(const tl_combinator *t, bool can_be_parsed, bool can_be_stored) const { return true; } diff --git a/tdtl/td/tl/tl_writer.h b/tdtl/td/tl/tl_writer.h index f8e6e71ba..b2ccf55af 100644 --- a/tdtl/td/tl/tl_writer.h +++ b/tdtl/td/tl/tl_writer.h @@ -56,7 +56,7 @@ class TL_writer { virtual bool is_type_bare(const tl_type *t) const = 0; virtual bool is_combinator_supported(const tl_combinator *constructor) const; virtual bool is_documentation_generated() const; - virtual bool is_default_constructor_generated(const tl_combinator *t, bool is_function) const; + virtual bool is_default_constructor_generated(const tl_combinator *t, bool can_be_parsed, bool can_be_stored) const; virtual int get_parser_type(const tl_combinator *t, const std::string &parser_name) const; virtual int get_storer_type(const tl_combinator *t, const std::string &storer_name) const;