Move option-related functions to OptionManager.

This commit is contained in:
levlam 2022-08-18 14:54:57 +03:00
parent 6f7e775dee
commit 149d505781
10 changed files with 238 additions and 307 deletions

View File

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

View File

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

View File

@ -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<KeyValueSyncInterface> config_pmc) : config_pmc_(std::move(config_pmc)) {
}
void ConfigShared::set_callback(unique_ptr<Callback> 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<string, string> 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<int64>(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

View File

@ -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 <memory>
#include <unordered_map>
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<KeyValueSyncInterface> config_pmc);
void set_callback(unique_ptr<Callback> 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<string, string> 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<KeyValueSyncInterface> config_pmc_;
unique_ptr<Callback> callback_;
bool set_option(Slice name, Slice value);
void on_option_updated(Slice name) const;
};
} // namespace td

View File

@ -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<NetQueryDispatcher> net_query_d
net_query_dispatcher_ = std::move(net_query_dispatcher);
}
void Global::set_shared_config(unique_ptr<ConfigShared> 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<string, string> 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) {

View File

@ -28,7 +28,6 @@
#include <atomic>
#include <memory>
#include <mutex>
#include <unordered_map>
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<ConfigShared> 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<string, string> 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<unique_ptr<NetQueryCreator>> net_query_creator_;
unique_ptr<NetQueryDispatcher> net_query_dispatcher_;
unique_ptr<ConfigShared> 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);

View File

@ -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<TsSeqKeyValue>())
, 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<td_api::updateOption>(name, get_option_value_object(value)));
}
} else if (name == "otherwise_relogin_days") {
auto days = narrow_cast<int32>(get_option_integer(name));
if (days > 0) {
vector<SuggestedAction> 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<int64>(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<td_api::OptionValue> OptionManager::get_unix_time_option_value_object() {
return td_api::make_object<td_api::optionValueInteger>(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<Unit>());
@ -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<int32>(G()->get_option_integer(name));
auto days = narrow_cast<int32>(get_option_integer(name));
if (days > 0) {
vector<SuggestedAction> 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<int32>(G()->get_option_integer(name)))) {
if (G()->mtproto_header().set_tz_offset(static_cast<int32>(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<td_api::updateOption>(name, get_option_value_object(G()->get_option(name))));
send_closure(G()->td(), &Td::send_update,
td_api::make_object<td_api::updateOption>(name.str(), get_option_value_object(get_option(name))));
}
void OptionManager::get_option(const string &name, Promise<td_api::object_ptr<td_api::OptionValue>> &&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_ptr<td_api::Op
return false;
}
if (value_constructor_id == td_api::optionValueEmpty::ID) {
G()->set_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_ptr<td_api::Op
<< max_value << "]"));
return false;
}
G()->set_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_ptr<td_api::Op
return false;
}
if (value_constructor_id == td_api::optionValueEmpty::ID) {
G()->set_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<td_api::Op
}
bool bool_value = static_cast<td_api::optionValueBoolean *>(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_ptr<td_api::Op
return false;
}
if (value_constructor_id == td_api::optionValueEmpty::ID) {
G()->set_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<td_api::Op
const string &str_value = static_cast<td_api::optionValueString *>(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_ptr<td_api::Op
return;
}
if (!is_bot && name == "ignore_sensitive_content_restrictions") {
if (!G()->get_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_ptr<td_api::Op
}
switch (value_constructor_id) {
case td_api::optionValueBoolean::ID:
G()->set_option_boolean(name, static_cast<const td_api::optionValueBoolean *>(value.get())->value_);
set_option_boolean(name, static_cast<const td_api::optionValueBoolean *>(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<const td_api::optionValueInteger *>(value.get())->value_);
set_option_integer(name, static_cast<const td_api::optionValueInteger *>(value.get())->value_);
break;
case td_api::optionValueString::ID:
G()->set_option_string(name, static_cast<const td_api::optionValueString *>(value.get())->value_);
set_option_string(name, static_cast<const td_api::optionValueString *>(value.get())->value_);
break;
default:
UNREACHABLE();
@ -752,7 +859,7 @@ void OptionManager::get_current_state(vector<td_api::object_ptr<td_api::Update>>
updates.push_back(td_api::make_object<td_api::updateOption>("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<td_api::updateOption>(option.first, get_option_value_object(option.second)));

View File

@ -14,9 +14,13 @@
#include "td/utils/Promise.h"
#include "td/utils/Slice.h"
#include <memory>
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<td_api::object_ptr<td_api::OptionValue>> &&promise);
void set_option(const string &name, td_api::object_ptr<td_api::OptionValue> &&value, Promise<Unit> &&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<Slice> &get_synchronous_options();
@ -62,6 +86,9 @@ class OptionManager final : public Actor {
Td *td_;
ActorShared<> parent_;
unique_ptr<TsSeqKeyValue> options_;
std::shared_ptr<KeyValueSyncInterface> option_pmc_;
double last_sent_server_time_difference_ = 1e100;
};

View File

@ -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<TdDb::OpenedDatabase> 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<TdDb::OpenedDatabase> 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<StateManagerCallback>(create_reference()));
G()->set_state_manager(state_manager_.get());
VLOG(td_init) << "Create ConfigShared";
auto config_shared = td::make_unique<ConfigShared>(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<OptionManager>(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>("ConfigManager", create_reference());
G()->set_config_manager(config_manager_.get());
VLOG(td_init) << "Create OptionManager";
option_manager_ = make_unique<OptionManager>(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<ConfigSharedCallback>());
}
void Td::init_connection_creator() {

View File

@ -1126,6 +1126,12 @@ class CliClient final : public Actor {
send_request(td_api::make_object<td_api::getTextEntities>(
"@telegram /test_command https://telegram.org telegram.me @gif @test"));
send_request(
td_api::make_object<td_api::setOption>("xxx", td_api::make_object<td_api::optionValueBoolean>(true)));
send_request(td_api::make_object<td_api::setOption>("xxx", td_api::make_object<td_api::optionValueInteger>(1)));
send_request(td_api::make_object<td_api::setOption>("xxx", td_api::make_object<td_api::optionValueString>("2")));
send_request(td_api::make_object<td_api::setOption>("xxx", td_api::make_object<td_api::optionValueEmpty>()));
send_request(td_api::make_object<td_api::getOption>("use_pfs"));
send_request(td_api::make_object<td_api::setOption>(
"use_pfs", td_api::make_object<td_api::optionValueBoolean>(std::time(nullptr) / 86400 % 2 == 0)));