diff --git a/CMakeLists.txt b/CMakeLists.txt index 5e270a71e..24c365497 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -303,7 +303,6 @@ set(TDLIB_SOURCE td/telegram/ChannelParticipantFilter.cpp td/telegram/ClientActor.cpp td/telegram/ConfigManager.cpp - td/telegram/ConfigShared.cpp td/telegram/ConnectionState.cpp td/telegram/Contact.cpp td/telegram/ContactsManager.cpp @@ -508,7 +507,6 @@ set(TDLIB_SOURCE td/telegram/ChatId.h td/telegram/ClientActor.h td/telegram/ConfigManager.h - td/telegram/ConfigShared.h td/telegram/ConnectionState.h td/telegram/Contact.h td/telegram/ContactsManager.h diff --git a/SplitSource.php b/SplitSource.php index bb9099503..1932b31c0 100644 --- a/SplitSource.php +++ b/SplitSource.php @@ -281,7 +281,6 @@ function split_file($file, $chunks, $undo) { 'audios_manager[_(-][^.]|AudiosManager' => "AudiosManager", 'auth_manager[_(-][^.]|AuthManager' => 'AuthManager', 'background_manager[_(-][^.]|BackgroundManager' => "BackgroundManager", - 'ConfigShared|shared_config[(]' => 'ConfigShared', 'contacts_manager[_(-][^.]|ContactsManager([^ ;.]| [^*])' => 'ContactsManager', 'country_info_manager[_(-][^.]|CountryInfoManager' => 'CountryInfoManager', 'documents_manager[_(-][^.]|DocumentsManager' => "DocumentsManager", diff --git a/td/telegram/ConfigShared.cpp b/td/telegram/ConfigShared.cpp deleted file mode 100644 index 3e6c0adc8..000000000 --- a/td/telegram/ConfigShared.cpp +++ /dev/null @@ -1,118 +0,0 @@ -// -// Copyright Aliaksei Levin (levlam@telegram.org), Arseny Smirnov (arseny30@gmail.com) 2014-2022 -// -// Distributed under the Boost Software License, Version 1.0. (See accompanying -// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) -// -#include "td/telegram/ConfigShared.h" - -#include "td/utils/logging.h" -#include "td/utils/misc.h" -#include "td/utils/SliceBuilder.h" - -namespace td { - -ConfigShared::ConfigShared(std::shared_ptr config_pmc) : config_pmc_(std::move(config_pmc)) { -} - -void ConfigShared::set_callback(unique_ptr callback) { - callback_ = std::move(callback); - if (callback_ == nullptr) { - return; - } - - for (const auto &key_value : config_pmc_->get_all()) { - on_option_updated(key_value.first); - } -} - -void ConfigShared::set_option_boolean(Slice name, bool value) { - if (set_option(name, value ? Slice("Btrue") : Slice("Bfalse"))) { - on_option_updated(name); - } -} - -void ConfigShared::set_option_empty(Slice name) { - if (set_option(name, Slice())) { - on_option_updated(name); - } -} - -void ConfigShared::set_option_integer(Slice name, int64 value) { - if (set_option(name, PSLICE() << 'I' << value)) { - on_option_updated(name); - } -} - -void ConfigShared::set_option_string(Slice name, Slice value) { - if (set_option(name, PSLICE() << 'S' << value)) { - on_option_updated(name); - } -} - -bool ConfigShared::have_option(Slice name) const { - return config_pmc_->isset(name.str()); -} - -string ConfigShared::get_option(Slice name) const { - return config_pmc_->get(name.str()); -} - -std::unordered_map ConfigShared::get_options() const { - return config_pmc_->get_all(); -} - -bool ConfigShared::get_option_boolean(Slice name, bool default_value) const { - auto value = get_option(name); - if (value.empty()) { - return default_value; - } - if (value == "Btrue") { - return true; - } - if (value == "Bfalse") { - return false; - } - LOG(ERROR) << "Found \"" << value << "\" instead of boolean option " << name; - return default_value; -} - -int64 ConfigShared::get_option_integer(Slice name, int64 default_value) const { - auto value = get_option(name); - if (value.empty()) { - return default_value; - } - if (value[0] != 'I') { - LOG(ERROR) << "Found \"" << value << "\" instead of integer option " << name; - return default_value; - } - return to_integer(value.substr(1)); -} - -string ConfigShared::get_option_string(Slice name, string default_value) const { - auto value = get_option(name); - if (value.empty()) { - return default_value; - } - if (value[0] != 'S') { - LOG(ERROR) << "Found \"" << value << "\" instead of string option " << name; - return default_value; - } - return value.substr(1); -} - -bool ConfigShared::set_option(Slice name, Slice value) { - if (value.empty()) { - return config_pmc_->erase(name.str()) != 0; - } else { - return config_pmc_->set(name.str(), value.str()) != 0; - } -} - -void ConfigShared::on_option_updated(Slice name) const { - if (callback_ != nullptr) { - callback_->on_option_updated(name.str(), get_option(name)); - } -} - -} // namespace td diff --git a/td/telegram/ConfigShared.h b/td/telegram/ConfigShared.h deleted file mode 100644 index 33e4a66b3..000000000 --- a/td/telegram/ConfigShared.h +++ /dev/null @@ -1,60 +0,0 @@ -// -// Copyright Aliaksei Levin (levlam@telegram.org), Arseny Smirnov (arseny30@gmail.com) 2014-2022 -// -// Distributed under the Boost Software License, Version 1.0. (See accompanying -// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) -// -#pragma once - -#include "td/db/KeyValueSyncInterface.h" - -#include "td/utils/common.h" -#include "td/utils/Slice.h" - -#include -#include - -namespace td { - -class ConfigShared { - public: - class Callback { - public: - Callback() = default; - Callback(const Callback &) = delete; - Callback &operator=(const Callback &) = delete; - Callback(Callback &&) = delete; - Callback &operator=(Callback &&) = delete; - virtual ~Callback() = default; - virtual void on_option_updated(const string &name, const string &value) const = 0; - }; - - explicit ConfigShared(std::shared_ptr config_pmc); - - void set_callback(unique_ptr callback); - - void set_option_boolean(Slice name, bool value); - void set_option_empty(Slice name); - void set_option_integer(Slice name, int64 value); - void set_option_string(Slice name, Slice value); - - bool have_option(Slice name) const; - - string get_option(Slice name) const; - - std::unordered_map get_options() const; - - bool get_option_boolean(Slice name, bool default_value = false) const; - int64 get_option_integer(Slice name, int64 default_value = 0) const; - string get_option_string(Slice name, string default_value = "") const; - - private: - std::shared_ptr config_pmc_; - unique_ptr callback_; - - bool set_option(Slice name, Slice value); - - void on_option_updated(Slice name) const; -}; - -} // namespace td diff --git a/td/telegram/Global.cpp b/td/telegram/Global.cpp index 2121469a0..a231df11f 100644 --- a/td/telegram/Global.cpp +++ b/td/telegram/Global.cpp @@ -7,7 +7,6 @@ #include "td/telegram/Global.h" #include "td/telegram/AuthManager.h" -#include "td/telegram/ConfigShared.h" #include "td/telegram/net/ConnectionCreator.h" #include "td/telegram/net/NetQueryDispatcher.h" #include "td/telegram/net/TempAuthKeyWatchdog.h" @@ -248,48 +247,46 @@ void Global::set_net_query_dispatcher(unique_ptr net_query_d net_query_dispatcher_ = std::move(net_query_dispatcher); } -void Global::set_shared_config(unique_ptr shared_config) { - shared_config_ = std::move(shared_config); +const OptionManager *Global::get_option_manager() const { + CHECK(!option_manager_.empty()) + return option_manager_.get_actor_unsafe(); +} + +OptionManager *Global::get_option_manager() { + CHECK(!option_manager_.empty()) + return option_manager_.get_actor_unsafe(); } void Global::set_option_empty(Slice name) { - shared_config_->set_option_empty(name); + get_option_manager()->set_option_empty(name); } void Global::set_option_boolean(Slice name, bool value) { - shared_config_->set_option_boolean(name, value); + get_option_manager()->set_option_boolean(name, value); } void Global::set_option_integer(Slice name, int64 value) { - shared_config_->set_option_integer(name, value); + get_option_manager()->set_option_integer(name, value); } void Global::set_option_string(Slice name, Slice value) { - shared_config_->set_option_string(name, value); + get_option_manager()->set_option_string(name, value); } bool Global::have_option(Slice name) const { - return shared_config_->have_option(name); -} - -string Global::get_option(Slice name) const { - return shared_config_->get_option(name); -} - -std::unordered_map Global::get_options() const { - return shared_config_->get_options(); + return get_option_manager()->have_option(name); } bool Global::get_option_boolean(Slice name, bool default_value) const { - return shared_config_->get_option_boolean(name, default_value); + return get_option_manager()->get_option_boolean(name, default_value); } int64 Global::get_option_integer(Slice name, int64 default_value) const { - return shared_config_->get_option_integer(name, default_value); + return get_option_manager()->get_option_integer(name, default_value); } string Global::get_option_string(Slice name, string default_value) const { - return shared_config_->get_option_string(name, std::move(default_value)); + return get_option_manager()->get_option_string(name, std::move(default_value)); } int64 Global::get_location_key(double latitude, double longitude) { diff --git a/td/telegram/Global.h b/td/telegram/Global.h index eedb0a82b..d546b2f9d 100644 --- a/td/telegram/Global.h +++ b/td/telegram/Global.h @@ -28,7 +28,6 @@ #include #include #include -#include namespace td { @@ -38,7 +37,6 @@ class AuthManager; class BackgroundManager; class CallManager; class ConfigManager; -class ConfigShared; class ConnectionCreator; class ContactsManager; class DownloadManager; @@ -129,8 +127,6 @@ class Global final : public ActorContext { return net_query_dispatcher_.get() != nullptr; } - void set_shared_config(unique_ptr shared_config); - void set_option_empty(Slice name); void set_option_boolean(Slice name, bool value); @@ -141,10 +137,6 @@ class Global final : public ActorContext { bool have_option(Slice name) const; - string get_option(Slice name) const; - - std::unordered_map get_options() const; - bool get_option_boolean(Slice name, bool default_value = false) const; int64 get_option_integer(Slice name, int64 default_value = 0) const; @@ -540,8 +532,6 @@ class Global final : public ActorContext { LazySchedulerLocalStorage> net_query_creator_; unique_ptr net_query_dispatcher_; - unique_ptr shared_config_; - int64 my_id_ = 0; // hack static int64 get_location_key(double latitude, double longitude); @@ -550,6 +540,10 @@ class Global final : public ActorContext { int32 to_unix_time(double server_time) const; + const OptionManager *get_option_manager() const; + + OptionManager *get_option_manager(); + void do_save_server_time_difference(); void do_close(Promise<> on_finish, bool destroy_flag); diff --git a/td/telegram/OptionManager.cpp b/td/telegram/OptionManager.cpp index 6ef59552f..c9e325537 100644 --- a/td/telegram/OptionManager.cpp +++ b/td/telegram/OptionManager.cpp @@ -28,7 +28,13 @@ #include "td/telegram/TdDb.h" #include "td/telegram/TopDialogManager.h" +#include "td/db/KeyValueSyncInterface.h" +#include "td/db/TsSeqKeyValue.h" + +#include "td/actor/actor.h" + #include "td/utils/algorithm.h" +#include "td/utils/logging.h" #include "td/utils/misc.h" #include "td/utils/port/Clocks.h" #include "td/utils/SliceBuilder.h" @@ -40,55 +46,77 @@ namespace td { -OptionManager::OptionManager(Td *td, ActorShared<> parent) : td_(td), parent_(std::move(parent)) { +OptionManager::OptionManager(Td *td, ActorShared<> parent) + : td_(td) + , parent_(std::move(parent)) + , options_(td::make_unique()) + , option_pmc_(G()->td_db()->get_config_pmc_shared()) { send_unix_time_update(); - if (G()->have_option("language_database_path")) { - G()->set_option_string("language_pack_database_path", G()->get_option_string("language_database_path")); - G()->set_option_empty("language_database_path"); + for (const auto &name_value : option_pmc_->get_all()) { + const string &name = name_value.first; + const string &value = name_value.second; + options_->set(name, value); + if (!is_internal_option(name)) { + if (name != "utc_time_offset") { + send_closure(G()->td(), &Td::send_update, + td_api::make_object(name, get_option_value_object(value))); + } + } else if (name == "otherwise_relogin_days") { + auto days = narrow_cast(get_option_integer(name)); + if (days > 0) { + vector added_actions{SuggestedAction{SuggestedAction::Type::SetPassword, DialogId(), days}}; + send_closure(G()->td(), &Td::send_update, get_update_suggested_actions_object(added_actions, {})); + } + } } - if (G()->have_option("language_pack")) { - G()->set_option_string("localization_target", G()->get_option_string("language_pack")); - G()->set_option_empty("language_pack"); + + if (have_option("language_database_path")) { + set_option_string("language_pack_database_path", get_option_string("language_database_path")); + set_option_empty("language_database_path"); } - if (G()->have_option("language_code")) { - G()->set_option_string("language_pack_id", G()->get_option_string("language_code")); - G()->set_option_empty("language_code"); + if (have_option("language_pack")) { + set_option_string("localization_target", get_option_string("language_pack")); + set_option_empty("language_pack"); } - if (!G()->have_option("message_text_length_max")) { - G()->set_option_integer("message_text_length_max", 4096); + if (have_option("language_code")) { + set_option_string("language_pack_id", get_option_string("language_code")); + set_option_empty("language_code"); } - if (!G()->have_option("message_caption_length_max")) { - G()->set_option_integer("message_caption_length_max", 1024); + if (!have_option("message_text_length_max")) { + set_option_integer("message_text_length_max", 4096); } - if (!G()->have_option("bio_length_max")) { - G()->set_option_integer("bio_length_max", 70); + if (!have_option("message_caption_length_max")) { + set_option_integer("message_caption_length_max", 1024); } - if (!G()->have_option("suggested_video_note_length")) { - G()->set_option_integer("suggested_video_note_length", 384); + if (!have_option("bio_length_max")) { + set_option_integer("bio_length_max", 70); } - if (!G()->have_option("suggested_video_note_video_bitrate")) { - G()->set_option_integer("suggested_video_note_video_bitrate", 1000); + if (!have_option("suggested_video_note_length")) { + set_option_integer("suggested_video_note_length", 384); } - if (!G()->have_option("suggested_video_note_audio_bitrate")) { - G()->set_option_integer("suggested_video_note_audio_bitrate", 64); + if (!have_option("suggested_video_note_video_bitrate")) { + set_option_integer("suggested_video_note_video_bitrate", 1000); } - if (!G()->have_option("notification_sound_duration_max")) { - G()->set_option_integer("notification_sound_duration_max", 5); + if (!have_option("suggested_video_note_audio_bitrate")) { + set_option_integer("suggested_video_note_audio_bitrate", 64); } - if (!G()->have_option("notification_sound_size_max")) { - G()->set_option_integer("notification_sound_size_max", 307200); + if (!have_option("notification_sound_duration_max")) { + set_option_integer("notification_sound_duration_max", 5); } - if (!G()->have_option("notification_sound_count_max")) { - G()->set_option_integer("notification_sound_count_max", G()->is_test_dc() ? 5 : 100); + if (!have_option("notification_sound_size_max")) { + set_option_integer("notification_sound_size_max", 307200); } - if (!G()->have_option("chat_filter_count_max")) { - G()->set_option_integer("chat_filter_count_max", G()->is_test_dc() ? 3 : 10); + if (!have_option("notification_sound_count_max")) { + set_option_integer("notification_sound_count_max", G()->is_test_dc() ? 5 : 100); } - if (!G()->have_option("chat_filter_chosen_chat_count_max")) { - G()->set_option_integer("chat_filter_chosen_chat_count_max", G()->is_test_dc() ? 5 : 100); + if (!have_option("chat_filter_count_max")) { + set_option_integer("chat_filter_count_max", G()->is_test_dc() ? 3 : 10); } - G()->set_option_integer("utc_time_offset", Clocks::tz_offset()); + if (!have_option("chat_filter_chosen_chat_count_max")) { + set_option_integer("chat_filter_chosen_chat_count_max", G()->is_test_dc() ? 5 : 100); + } + set_option_integer("utc_time_offset", Clocks::tz_offset()); } void OptionManager::tear_down() { @@ -97,6 +125,86 @@ void OptionManager::tear_down() { OptionManager::~OptionManager() = default; +void OptionManager::set_option_boolean(Slice name, bool value) { + set_option(name, value ? Slice("Btrue") : Slice("Bfalse")); +} + +void OptionManager::set_option_empty(Slice name) { + set_option(name, Slice()); +} + +void OptionManager::set_option_integer(Slice name, int64 value) { + set_option(name, PSLICE() << 'I' << value); +} + +void OptionManager::set_option_string(Slice name, Slice value) { + set_option(name, PSLICE() << 'S' << value); +} + +bool OptionManager::have_option(Slice name) const { + return options_->isset(name.str()); +} + +bool OptionManager::get_option_boolean(Slice name, bool default_value) const { + auto value = get_option(name); + if (value.empty()) { + return default_value; + } + if (value == "Btrue") { + return true; + } + if (value == "Bfalse") { + return false; + } + LOG(ERROR) << "Found \"" << value << "\" instead of boolean option " << name; + return default_value; +} + +int64 OptionManager::get_option_integer(Slice name, int64 default_value) const { + auto value = get_option(name); + if (value.empty()) { + return default_value; + } + if (value[0] != 'I') { + LOG(ERROR) << "Found \"" << value << "\" instead of integer option " << name; + return default_value; + } + return to_integer(value.substr(1)); +} + +string OptionManager::get_option_string(Slice name, string default_value) const { + auto value = get_option(name); + if (value.empty()) { + return default_value; + } + if (value[0] != 'S') { + LOG(ERROR) << "Found \"" << value << "\" instead of string option " << name; + return default_value; + } + return value.substr(1); +} + +void OptionManager::set_option(Slice name, Slice value) { + CHECK(!name.empty()); + CHECK(Scheduler::instance()->sched_id() == 0); + if (value.empty()) { + if (option_pmc_->erase(name.str()) == 0) { + return; + } + option_pmc_->erase(name.str()); + } else { + if (options_->set(name, value) == 0) { + return; + } + option_pmc_->set(name.str(), value.str()); + } + on_option_updated(name); +} + +string OptionManager::get_option(Slice name) const { + return options_->get(name.str()); +} + td_api::object_ptr OptionManager::get_unix_time_option_value_object() { return td_api::make_object(G()->unix_time()); } @@ -115,7 +223,7 @@ void OptionManager::on_update_server_time_difference() { } void OptionManager::clear_options() { - for (const auto &option : G()->get_options()) { + for (const auto &option : options_->get_all()) { if (!is_internal_option(option.first)) { send_closure( G()->td(), &Td::send_update, @@ -185,7 +293,7 @@ bool OptionManager::is_synchronous_option(Slice name) { return td::contains(get_synchronous_options(), name); } -void OptionManager::on_option_updated(const string &name) { +void OptionManager::on_option_updated(Slice name) { if (G()->close_flag()) { return; } @@ -208,13 +316,13 @@ void OptionManager::on_option_updated(const string &name) { break; case 'c': if (name == "connection_parameters") { - if (G()->mtproto_header().set_parameters(G()->get_option_string(name))) { + if (G()->mtproto_header().set_parameters(get_option_string(name))) { G()->net_query_dispatcher().update_mtproto_header(); } } break; case 'd': - if (name == "default_reaction_needs_sync" && G()->get_option_boolean(name)) { + if (name == "default_reaction_needs_sync" && get_option_boolean(name)) { send_set_default_reaction_query(td_); } if (name == "dice_emojis") { @@ -231,8 +339,7 @@ void OptionManager::on_option_updated(const string &name) { &NotificationManager::on_disable_contact_registered_notifications_changed); } if (name == "disable_top_chats") { - send_closure(td_->top_dialog_manager_actor_, &TopDialogManager::update_is_enabled, - !G()->get_option_boolean(name)); + send_closure(td_->top_dialog_manager_actor_, &TopDialogManager::update_is_enabled, !get_option_boolean(name)); } break; case 'e': @@ -250,7 +357,7 @@ void OptionManager::on_option_updated(const string &name) { send_closure(td_->contacts_manager_actor_, &ContactsManager::on_ignored_restriction_reasons_changed); } if (name == "is_emulator") { - if (G()->mtproto_header().set_is_emulator(G()->get_option_boolean(name))) { + if (G()->mtproto_header().set_is_emulator(get_option_boolean(name))) { G()->net_query_dispatcher().update_mtproto_header(); } } @@ -258,7 +365,7 @@ void OptionManager::on_option_updated(const string &name) { case 'l': if (name == "language_pack_id") { send_closure(td_->language_pack_manager_, &LanguagePackManager::on_language_code_changed); - if (G()->mtproto_header().set_language_code(G()->get_option_string(name))) { + if (G()->mtproto_header().set_language_code(get_option_string(name))) { G()->net_query_dispatcher().update_mtproto_header(); } send_closure(td_->attach_menu_manager_actor_, &AttachMenuManager::reload_attach_menu_bots, Promise()); @@ -268,14 +375,14 @@ void OptionManager::on_option_updated(const string &name) { } if (name == "localization_target") { send_closure(td_->language_pack_manager_, &LanguagePackManager::on_language_pack_changed); - if (G()->mtproto_header().set_language_pack(G()->get_option_string(name))) { + if (G()->mtproto_header().set_language_pack(get_option_string(name))) { G()->net_query_dispatcher().update_mtproto_header(); } } break; case 'm': if (name == "my_id") { - G()->set_my_id(G()->get_option_integer(name)); + G()->set_my_id(get_option_integer(name)); } break; case 'n': @@ -298,7 +405,7 @@ void OptionManager::on_option_updated(const string &name) { send_closure(td_->notification_manager_actor_, &NotificationManager::on_online_cloud_timeout_changed); } if (name == "otherwise_relogin_days") { - auto days = narrow_cast(G()->get_option_integer(name)); + auto days = narrow_cast(get_option_integer(name)); if (days > 0) { vector added_actions{SuggestedAction{SuggestedAction::Type::SetPassword, DialogId(), days}}; send_closure(G()->td(), &Td::send_update, get_update_suggested_actions_object(added_actions, {})); @@ -329,7 +436,7 @@ void OptionManager::on_option_updated(const string &name) { send_closure(td_->storage_manager_, &StorageManager::update_use_storage_optimizer); } if (name == "utc_time_offset") { - if (G()->mtproto_header().set_tz_offset(static_cast(G()->get_option_integer(name)))) { + if (G()->mtproto_header().set_tz_offset(static_cast(get_option_integer(name)))) { G()->net_query_dispatcher().update_mtproto_header(); } } @@ -342,16 +449,16 @@ void OptionManager::on_option_updated(const string &name) { return; } - // send_closure was already used in the callback - td_->send_update(td_api::make_object(name, get_option_value_object(G()->get_option(name)))); + send_closure(G()->td(), &Td::send_update, + td_api::make_object(name.str(), get_option_value_object(get_option(name)))); } void OptionManager::get_option(const string &name, Promise> &&promise) { bool is_bot = td_->auth_manager_ != nullptr && td_->auth_manager_->is_authorized() && td_->auth_manager_->is_bot(); - auto wrap_promise = [&] { - return PromiseCreator::lambda([promise = std::move(promise), name](Unit result) mutable { + auto wrap_promise = [this, &promise, &name] { + return PromiseCreator::lambda([this, promise = std::move(promise), name](Unit result) mutable { // the option is already updated on success, ignore errors - promise.set_value(get_option_value_object(G()->get_option(name))); + promise.set_value(get_option_value_object(get_option(name))); }); }; switch (name[0]) { @@ -422,7 +529,7 @@ void OptionManager::set_option(const string &name, td_api::object_ptrset_option_empty(option_name); + set_option_empty(option_name); } else { if (value_constructor_id != td_api::optionValueInteger::ID) { promise.set_error(Status::Error(400, PSLICE() << "Option \"" << name << "\" must have integer value")); @@ -436,7 +543,7 @@ void OptionManager::set_option(const string &name, td_api::object_ptrset_option_integer(name, int_value); + set_option_integer(name, int_value); } promise.set_value(Unit()); return true; @@ -447,7 +554,7 @@ void OptionManager::set_option(const string &name, td_api::object_ptrset_option_empty(name); + set_option_empty(name); } else { if (value_constructor_id != td_api::optionValueBoolean::ID) { promise.set_error(Status::Error(400, PSLICE() << "Option \"" << name << "\" must have boolean value")); @@ -455,7 +562,7 @@ void OptionManager::set_option(const string &name, td_api::object_ptr(value.get())->value_; - G()->set_option_boolean(name, bool_value); + set_option_boolean(name, bool_value); } promise.set_value(Unit()); return true; @@ -466,7 +573,7 @@ void OptionManager::set_option(const string &name, td_api::object_ptrset_option_empty(name); + set_option_empty(name); } else { if (value_constructor_id != td_api::optionValueString::ID) { promise.set_error(Status::Error(400, PSLICE() << "Option \"" << name << "\" must have string value")); @@ -475,10 +582,10 @@ void OptionManager::set_option(const string &name, td_api::object_ptr(value.get())->value_; if (str_value.empty()) { - G()->set_option_empty(name); + set_option_empty(name); } else { if (check_value(str_value)) { - G()->set_option_string(name, str_value); + set_option_string(name, str_value); } else { promise.set_error(Status::Error(400, PSLICE() << "Option \"" << name << "\" can't have specified value")); return false; @@ -571,7 +678,7 @@ void OptionManager::set_option(const string &name, td_api::object_ptrget_option_boolean("can_ignore_sensitive_content_restrictions")) { + if (!get_option_boolean("can_ignore_sensitive_content_restrictions")) { return promise.set_error( Status::Error(400, "Option \"ignore_sensitive_content_restrictions\" can't be changed by the user")); } @@ -691,16 +798,16 @@ void OptionManager::set_option(const string &name, td_api::object_ptrset_option_boolean(name, static_cast(value.get())->value_); + set_option_boolean(name, static_cast(value.get())->value_); break; case td_api::optionValueEmpty::ID: - G()->set_option_empty(name); + set_option_empty(name); break; case td_api::optionValueInteger::ID: - G()->set_option_integer(name, static_cast(value.get())->value_); + set_option_integer(name, static_cast(value.get())->value_); break; case td_api::optionValueString::ID: - G()->set_option_string(name, static_cast(value.get())->value_); + set_option_string(name, static_cast(value.get())->value_); break; default: UNREACHABLE(); @@ -752,7 +859,7 @@ void OptionManager::get_current_state(vector> updates.push_back(td_api::make_object("unix_time", get_unix_time_option_value_object())); - for (const auto &option : G()->get_options()) { + for (const auto &option : options_->get_all()) { if (!is_internal_option(option.first)) { updates.push_back( td_api::make_object(option.first, get_option_value_object(option.second))); diff --git a/td/telegram/OptionManager.h b/td/telegram/OptionManager.h index 26775ff2a..464074b36 100644 --- a/td/telegram/OptionManager.h +++ b/td/telegram/OptionManager.h @@ -14,9 +14,13 @@ #include "td/utils/Promise.h" #include "td/utils/Slice.h" +#include + namespace td { +class KeyValueSyncInterface; class Td; +class TsSeqKeyValue; class OptionManager final : public Actor { public: @@ -28,15 +32,29 @@ class OptionManager final : public Actor { OptionManager &operator=(OptionManager &&) = delete; ~OptionManager() final; - void on_update_server_time_difference(); + void set_option_boolean(Slice name, bool value); - void on_option_updated(const string &name); + void set_option_empty(Slice name); + + void set_option_integer(Slice name, int64 value); + + void set_option_string(Slice name, Slice value); + + bool have_option(Slice name) const; + + bool get_option_boolean(Slice name, bool default_value = false) const; + + int64 get_option_integer(Slice name, int64 default_value = 0) const; + + string get_option_string(Slice name, string default_value = "") const; + + void on_update_server_time_difference(); void get_option(const string &name, Promise> &&promise); void set_option(const string &name, td_api::object_ptr &&value, Promise &&promise); - static void clear_options(); + void clear_options(); static bool is_synchronous_option(Slice name); @@ -49,6 +67,12 @@ class OptionManager final : public Actor { private: void tear_down() final; + void set_option(Slice name, Slice value); + + void on_option_updated(Slice name); + + string get_option(Slice name) const; + static bool is_internal_option(Slice name); static const vector &get_synchronous_options(); @@ -62,6 +86,9 @@ class OptionManager final : public Actor { Td *td_; ActorShared<> parent_; + unique_ptr options_; + std::shared_ptr option_pmc_; + double last_sent_server_time_difference_ = 1e100; }; diff --git a/td/telegram/Td.cpp b/td/telegram/Td.cpp index 874e7e26a..134a4999a 100644 --- a/td/telegram/Td.cpp +++ b/td/telegram/Td.cpp @@ -25,7 +25,6 @@ #include "td/telegram/ChannelType.h" #include "td/telegram/ChatId.h" #include "td/telegram/ConfigManager.h" -#include "td/telegram/ConfigShared.h" #include "td/telegram/ContactsManager.h" #include "td/telegram/CountryInfoManager.h" #include "td/telegram/DeviceTokenManager.h" @@ -3298,7 +3297,6 @@ void Td::dec_actor_refcnt() { LOG(DEBUG) << "WebPagesManager was cleared" << timer; Promise<> promise = PromiseCreator::lambda([actor_id = create_reference()](Unit) mutable { actor_id.reset(); }); - G()->set_shared_config(nullptr); if (destroy_flag_) { G()->close_and_destroy_all(std::move(promise)); } else { @@ -3371,7 +3369,7 @@ void Td::clear() { Timer timer; if (destroy_flag_) { - OptionManager::clear_options(); + option_manager_->clear_options(); if (!auth_manager_->is_bot()) { notification_manager_->destroy_all_notifications(); } @@ -3643,6 +3641,9 @@ void Td::init(Result r_opened_database) { init_options_and_network(); + // we need to process td_api::getOption along with td_api::setOption for consistency + // we need to process td_api::setOption before managers and MTProto header are created, + // because their initialiation may be affected by the options complete_pending_preauthentication_requests([](int32 id) { switch (id) { case td_api::getOption::ID: @@ -3711,6 +3712,10 @@ void Td::init(Result r_opened_database) { on_save_app_log_binlog_event(this, std::move(event)); } + if (option_manager_->get_option_boolean("default_reaction_needs_sync")) { + send_set_default_reaction_query(this); + } + if (is_online_) { on_online_updated(true, true); } @@ -3805,10 +3810,10 @@ void Td::init_options_and_network() { send_closure(state_manager_, &StateManager::add_callback, make_unique(create_reference())); G()->set_state_manager(state_manager_.get()); - VLOG(td_init) << "Create ConfigShared"; - auto config_shared = td::make_unique(G()->td_db()->get_config_pmc_shared()); - auto config_shared_ptr = config_shared.get(); - G()->set_shared_config(std::move(config_shared)); + VLOG(td_init) << "Create OptionManager"; + option_manager_ = make_unique(this, create_reference()); + option_manager_actor_ = register_actor("OptionManager", option_manager_.get()); + G()->set_option_manager(option_manager_actor_.get()); init_connection_creator(); @@ -3819,30 +3824,6 @@ void Td::init_options_and_network() { VLOG(td_init) << "Create ConfigManager"; config_manager_ = create_actor("ConfigManager", create_reference()); G()->set_config_manager(config_manager_.get()); - - VLOG(td_init) << "Create OptionManager"; - option_manager_ = make_unique(this, create_reference()); - option_manager_actor_ = register_actor("OptionManager", option_manager_.get()); - G()->set_option_manager(option_manager_actor_.get()); - - VLOG(td_init) << "Set ConfigShared callback"; - class ConfigSharedCallback final : public ConfigShared::Callback { - public: - void on_option_updated(const string &name, const string &value) const final { - send_closure_later(G()->option_manager(), &OptionManager::on_option_updated, name); - } - ~ConfigSharedCallback() final { - LOG(INFO) << "Destroy ConfigSharedCallback"; - } - }; - // we need to set ConfigShared callback before td_api::getOption requests are processed for consistency - // TODO currently they will be inconsistent anyway, because td_api::getOption returns current value, - // but in td_api::updateOption there will be a newer value, obtained at the time of update creation - // so, there can be even two succesive updateOption with the same value - // we need to process td_api::getOption along with td_api::setOption for consistency - // we need to process td_api::setOption before managers and MTProto header are created, - // because their initialiation may be affected by the options - config_shared_ptr->set_callback(make_unique()); } void Td::init_connection_creator() { diff --git a/td/telegram/cli.cpp b/td/telegram/cli.cpp index b9eaf86d8..114fd27e0 100644 --- a/td/telegram/cli.cpp +++ b/td/telegram/cli.cpp @@ -1126,6 +1126,12 @@ class CliClient final : public Actor { send_request(td_api::make_object( "@telegram /test_command https://telegram.org telegram.me @gif @test")); + send_request( + td_api::make_object("xxx", td_api::make_object(true))); + send_request(td_api::make_object("xxx", td_api::make_object(1))); + send_request(td_api::make_object("xxx", td_api::make_object("2"))); + send_request(td_api::make_object("xxx", td_api::make_object())); + send_request(td_api::make_object("use_pfs")); send_request(td_api::make_object( "use_pfs", td_api::make_object(std::time(nullptr) / 86400 % 2 == 0)));