diff --git a/CMake/GetGitRevisionDescription.cmake b/CMake/GetGitRevisionDescription.cmake index a99610c43..b56558209 100644 --- a/CMake/GetGitRevisionDescription.cmake +++ b/CMake/GetGitRevisionDescription.cmake @@ -58,10 +58,12 @@ endfunction() function(get_git_head_revision _refspecvar _hashvar) _git_find_closest_git_dir("${CMAKE_CURRENT_SOURCE_DIR}" GIT_DIR) - file(RELATIVE_PATH _relative_to_source_dir "${CMAKE_CURRENT_SOURCE_DIR}" "${GIT_DIR}") - if (_relative_to_source_dir MATCHES "^[.][.]") - # We've gone above the CMake root dir. - set(GIT_DIR "") + if (NOT GIT_DIR STREQUAL "") + file(RELATIVE_PATH _relative_to_source_dir "${CMAKE_CURRENT_SOURCE_DIR}" "${GIT_DIR}") + if (_relative_to_source_dir MATCHES "^[.][.]") + # We've gone above the CMake root dir. + set(GIT_DIR "") + endif() endif() if (GIT_DIR STREQUAL "") set(${_refspecvar} "GITDIR-NOTFOUND" PARENT_SCOPE) diff --git a/CMakeLists.txt b/CMakeLists.txt index 090d8771b..ec99c1405 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -307,7 +307,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 @@ -442,6 +441,7 @@ set(TDLIB_SOURCE td/telegram/StorageManager.cpp td/telegram/MemoryManager.cpp td/telegram/SuggestedAction.cpp + td/telegram/Support.cpp td/telegram/Td.cpp td/telegram/TdDb.cpp td/telegram/TermsOfService.cpp @@ -512,7 +512,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 @@ -691,6 +690,7 @@ set(TDLIB_SOURCE td/telegram/StorageManager.h td/telegram/MemoryManager.h td/telegram/SuggestedAction.h + td/telegram/Support.h td/telegram/Td.h td/telegram/TdCallback.h td/telegram/TdDb.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/example/android/AddIntDef.php b/example/android/AddIntDef.php index e6b2bdfc9..d4ae4a65b 100644 --- a/example/android/AddIntDef.php +++ b/example/android/AddIntDef.php @@ -12,7 +12,7 @@ 'import androidx.annotation.Nullable;'.PHP_EOL. PHP_EOL. 'import java.lang.annotation.Retention;'.PHP_EOL. - 'import java.lang.annotation.RetentionPolicy;', $file); + 'import java.lang.annotation.RetentionPolicy;'.PHP_EOL, $file); preg_match_all('/public static class ([A-Za-z0-9]+) extends ([A-Za-z0-9]+)/', $file, $matches, PREG_SET_ORDER); $children = []; @@ -21,13 +21,20 @@ continue; } - $children[$val[2]][] = PHP_EOL.' '.$val[1].'.CONSTRUCTOR'; + $children[$val[2]][] = ' '.$val[1].'.CONSTRUCTOR'; } $file = preg_replace_callback('/public abstract static class ([A-Za-z0-9]+)()? extends Object [{]/', function ($val) use ($children) { - return $val[0].PHP_EOL.' @Retention(RetentionPolicy.SOURCE)'.PHP_EOL.' @IntDef({'.implode(',', $children[$val[1]]).<<<'EOL' + $values = implode(','.PHP_EOL, $children[$val[1]]); + return $val[0].<</dev/null; pwd -P)/$(basename -- "$ANDROID_SDK_ROOT")" OPENSSL_INSTALL_DIR="$(cd "$(dirname -- "$OPENSSL_INSTALL_DIR")" >/dev/null; pwd -P)/$(basename -- "$OPENSSL_INSTALL_DIR")" +cd $(dirname $0) + echo "Downloading OpenSSL sources..." rm -f $OPENSSL_VERSION.tar.gz || exit 1 $WGET https://github.com/openssl/openssl/archive/refs/tags/$OPENSSL_VERSION.tar.gz || exit 1 @@ -43,15 +44,21 @@ if ! clang --help >/dev/null 2>&1 ; then exit 1 fi +ANDROID_API32=16 +ANDROID_API64=21 +if [[ ${ANDROID_NDK_VERSION%%.*} -ge 24 ]] ; then + ANDROID_API32=19 +fi + for ABI in arm64-v8a armeabi-v7a x86_64 x86 ; do - if [[ $ABI == "x86" ]]; then - ./Configure android-x86 no-shared -U__ANDROID_API__ -D__ANDROID_API__=16 || exit 1 - elif [[ $ABI == "x86_64" ]]; then - ./Configure android-x86_64 no-shared -U__ANDROID_API__ -D__ANDROID_API__=21 || exit 1 - elif [[ $ABI == "armeabi-v7a" ]]; then - ./Configure android-arm no-shared -U__ANDROID_API__ -D__ANDROID_API__=16 -D__ARM_MAX_ARCH__=8 || exit 1 - elif [[ $ABI == "arm64-v8a" ]]; then - ./Configure android-arm64 no-shared -U__ANDROID_API__ -D__ANDROID_API__=21 || exit 1 + if [[ $ABI == "x86" ]] ; then + ./Configure android-x86 no-shared -U__ANDROID_API__ -D__ANDROID_API__=$ANDROID_API32 || exit 1 + elif [[ $ABI == "x86_64" ]] ; then + ./Configure android-x86_64 no-shared -U__ANDROID_API__ -D__ANDROID_API__=$ANDROID_API64 || exit 1 + elif [[ $ABI == "armeabi-v7a" ]] ; then + ./Configure android-arm no-shared -U__ANDROID_API__ -D__ANDROID_API__=$ANDROID_API32 -D__ARM_MAX_ARCH__=8 || exit 1 + elif [[ $ABI == "arm64-v8a" ]] ; then + ./Configure android-arm64 no-shared -U__ANDROID_API__ -D__ANDROID_API__=$ANDROID_API64 || exit 1 fi sed -i.bak 's/-O3/-O3 -ffunction-sections -fdata-sections/g' Makefile || exit 1 diff --git a/example/android/build-tdlib.sh b/example/android/build-tdlib.sh index 4a4d80275..1ff9ae7af 100755 --- a/example/android/build-tdlib.sh +++ b/example/android/build-tdlib.sh @@ -1,5 +1,4 @@ #!/usr/bin/env bash -cd $(dirname $0) ANDROID_SDK_ROOT=${1:-SDK} ANDROID_NDK_VERSION=${2:-23.2.8568313} @@ -28,6 +27,8 @@ ANDROID_NDK_ROOT="$ANDROID_SDK_ROOT/ndk/$ANDROID_NDK_VERSION" OPENSSL_INSTALL_DIR="$(cd "$(dirname -- "$OPENSSL_INSTALL_DIR")" >/dev/null; pwd -P)/$(basename -- "$OPENSSL_INSTALL_DIR")" PATH=$ANDROID_SDK_ROOT/cmake/3.22.1/bin:$PATH +cd $(dirname $0) + echo "Downloading annotation Java package..." rm -f android.jar annotation-1.4.0.jar || exit 1 $WGET https://maven.google.com/androidx/annotation/annotation/1.4.0/annotation-1.4.0.jar || exit 1 @@ -65,12 +66,15 @@ for ABI in arm64-v8a armeabi-v7a x86_64 x86 ; do mkdir -p tdlib/libs/$ABI/ || exit 1 cp -p build-$ABI/libtd*.so* tdlib/libs/$ABI/ || exit 1 if [[ "$ANDROID_STL" == "c++_shared" ]] ; then - FULL_ABI=$(case $ABI in - "arm64-v8a") echo "aarch64-linux-android" ;; - "armeabi-v7a") echo "arm-linux-androideabi" ;; - "x86_64") echo "x86_64-linux-android" ;; - "x86") echo "i686-linux-android" ;; - esac) + if [[ "$ABI" == "arm64-v8a" ]] ; then + FULL_ABI="aarch64-linux-android" + elif [[ "$ABI" == "armeabi-v7a" ]] ; then + FULL_ABI="arm-linux-androideabi" + elif [[ "$ABI" == "x86_64" ]] ; then + FULL_ABI="x86_64-linux-android" + elif [[ "$ABI" == "x86" ]] ; then + FULL_ABI="i686-linux-android" + fi cp "$ANDROID_NDK_ROOT/toolchains/llvm/prebuilt/$HOST_ARCH/sysroot/usr/lib/$FULL_ABI/libc++_shared.so" tdlib/libs/$ABI/ || exit 1 "$ANDROID_NDK_ROOT/toolchains/llvm/prebuilt/$HOST_ARCH/bin/llvm-strip" tdlib/libs/$ABI/libc++_shared.so || exit 1 fi diff --git a/example/android/check-environment.sh b/example/android/check-environment.sh index f3bdf960d..1308647b6 100755 --- a/example/android/check-environment.sh +++ b/example/android/check-environment.sh @@ -25,7 +25,7 @@ else exit 1 fi -for TOOL_NAME in gperf jar javadoc make perl php sed tar yes unzip ; do +for TOOL_NAME in gperf jar java javadoc make perl php sed tar yes unzip ; do if ! which "$TOOL_NAME" >/dev/null 2>&1 ; then echo "Error: this script requires $TOOL_NAME tool installed." exit 1 @@ -43,3 +43,8 @@ if ! perl -MExtUtils::MakeMaker -MLocale::Maketext::Simple -MPod::Usage -e '' >/ fi exit 1 fi + +if ! java --help >/dev/null 2>&1 ; then + echo "Error: Java installation is broken. Install JDK from https://www.oracle.com/java/technologies/downloads/." + exit 1 +fi diff --git a/example/android/fetch-sdk.sh b/example/android/fetch-sdk.sh index f814ede99..61d93170a 100755 --- a/example/android/fetch-sdk.sh +++ b/example/android/fetch-sdk.sh @@ -1,5 +1,4 @@ #!/usr/bin/env bash -cd $(dirname $0) ANDROID_SDK_ROOT=${1:-SDK} ANDROID_NDK_VERSION=${2:-23.2.8568313} diff --git a/example/uwp/build.ps1 b/example/uwp/build.ps1 index 755b090ef..587945a4b 100644 --- a/example/uwp/build.ps1 +++ b/example/uwp/build.ps1 @@ -41,7 +41,7 @@ function prepare { cd build-native - cmake "$td_root" -DCMAKE_TOOLCHAIN_FILE="$vcpkg_cmake" -DTD_ENABLE_DOTNET=ON + cmake -A Win32 -DCMAKE_TOOLCHAIN_FILE="$vcpkg_cmake" -DTD_ENABLE_DOTNET=ON "$td_root" CheckLastExitCode cmake --build . --target prepare_cross_compiling CheckLastExitCode @@ -62,7 +62,7 @@ function config { if ($arch -eq "x86") { $fixed_arch = "win32" } - cmake "$td_root" -A $fixed_arch -DCMAKE_SYSTEM_VERSION="10.0" -DCMAKE_SYSTEM_NAME="WindowsStore" -DCMAKE_TOOLCHAIN_FILE="$vcpkg_cmake" -DTD_ENABLE_DOTNET=ON + cmake -A $fixed_arch -DCMAKE_SYSTEM_VERSION="10.0" -DCMAKE_SYSTEM_NAME="WindowsStore" -DCMAKE_TOOLCHAIN_FILE="$vcpkg_cmake" -DTD_ENABLE_DOTNET=ON "$td_root" CheckLastExitCode cd .. } diff --git a/td/generate/scheme/td_api.tl b/td/generate/scheme/td_api.tl index a5b819d96..32a3bdd21 100644 --- a/td/generate/scheme/td_api.tl +++ b/td/generate/scheme/td_api.tl @@ -4571,6 +4571,10 @@ logVerbosityLevel verbosity_level:int32 = LogVerbosityLevel; logTags tags:vector = LogTags; +//@description Contains custom information about the user @message Information message @author Information author @date Information change date +userSupportInfo message:formattedText author:string date:int32 = UserSupportInfo; + + //@description A simple object containing a number; for testing only @value Number testInt value:int32 = TestInt; //@description A simple object containing a string; for testing only @value String @@ -6609,6 +6613,13 @@ getLogTagVerbosityLevel tag:string = LogVerbosityLevel; addLogMessage verbosity_level:int32 text:string = Ok; +//@description Returns support information for the given user; for Telegram support only @user_id User identifier +getUserSupportInfo user_id:int53 = UserSupportInfo; + +//@description Sets support information for the given user; for Telegram support only @user_id User identifier @message New information message +setUserSupportInfo user_id:int53 message:formattedText = UserSupportInfo; + + //@description Does nothing; for testing only. This is an offline method. Can be called before authorization testCallEmpty = Ok; //@description Returns the received string; for testing only. This is an offline method. Can be called before authorization @x String to return diff --git a/td/telegram/AnimationsManager.cpp b/td/telegram/AnimationsManager.cpp index a22923c1a..e48089d8e 100644 --- a/td/telegram/AnimationsManager.cpp +++ b/td/telegram/AnimationsManager.cpp @@ -7,7 +7,6 @@ #include "td/telegram/AnimationsManager.h" #include "td/telegram/AuthManager.h" -#include "td/telegram/ConfigShared.h" #include "td/telegram/DialogId.h" #include "td/telegram/Document.h" #include "td/telegram/DocumentsManager.h" @@ -18,6 +17,7 @@ #include "td/telegram/Global.h" #include "td/telegram/logevent/LogEvent.h" #include "td/telegram/misc.h" +#include "td/telegram/OptionManager.h" #include "td/telegram/PhotoFormat.h" #include "td/telegram/secret_api.h" #include "td/telegram/Td.h" @@ -127,17 +127,13 @@ class SaveGifQuery final : public Td::ResultHandler { }; AnimationsManager::AnimationsManager(Td *td, ActorShared<> parent) : td_(td), parent_(std::move(parent)) { - auto limit_string = G()->td_db()->get_binlog_pmc()->get("saved_animations_limit"); - if (!limit_string.empty()) { - auto new_limit = to_integer(limit_string); - if (new_limit > 0) { - LOG(DEBUG) << "Load saved animations limit = " << new_limit; - saved_animations_limit_ = new_limit; - } else { - LOG(ERROR) << "Wrong saved animations limit = \"" << limit_string << "\" stored in database"; - } - } + on_update_animation_search_emojis(); + on_update_animation_search_provider(); + on_update_saved_animations_limit(); + next_saved_animations_load_time_ = Time::now(); + + G()->td_db()->get_binlog_pmc()->erase("saved_animations_limit"); // legacy } AnimationsManager::~AnimationsManager() { @@ -412,15 +408,16 @@ SecretInputMedia AnimationsManager::get_secret_input_media(FileId animation_file layer}; } -void AnimationsManager::on_update_animation_search_emojis(string animation_search_emojis) { +void AnimationsManager::on_update_animation_search_emojis() { if (G()->close_flag()) { return; } if (td_->auth_manager_->is_bot()) { - G()->shared_config().set_option_empty("animation_search_emojis"); + td_->option_manager_->set_option_empty("animation_search_emojis"); return; } + auto animation_search_emojis = td_->option_manager_->get_option_string("animation_search_emojis"); is_animation_search_emojis_inited_ = true; if (animation_search_emojis_ == animation_search_emojis) { return; @@ -430,15 +427,16 @@ void AnimationsManager::on_update_animation_search_emojis(string animation_searc try_send_update_animation_search_parameters(); } -void AnimationsManager::on_update_animation_search_provider(string animation_search_provider) { +void AnimationsManager::on_update_animation_search_provider() { if (G()->close_flag()) { return; } if (td_->auth_manager_->is_bot()) { - G()->shared_config().set_option_empty("animation_search_provider"); + td_->option_manager_->set_option_empty("animation_search_provider"); return; } + string animation_search_provider = td_->option_manager_->get_option_string("animation_search_provider"); is_animation_search_provider_inited_ = true; if (animation_search_provider_ == animation_search_provider) { return; @@ -448,11 +446,15 @@ void AnimationsManager::on_update_animation_search_provider(string animation_sea try_send_update_animation_search_parameters(); } -void AnimationsManager::on_update_saved_animations_limit(int32 saved_animations_limit) { +void AnimationsManager::on_update_saved_animations_limit() { + if (G()->close_flag()) { + return; + } + auto saved_animations_limit = + narrow_cast(td_->option_manager_->get_option_integer("saved_animations_limit", 200)); if (saved_animations_limit != saved_animations_limit_) { if (saved_animations_limit > 0) { LOG(INFO) << "Update saved animations limit to " << saved_animations_limit; - G()->td_db()->get_binlog_pmc()->set("saved_animations_limit", to_string(saved_animations_limit)); saved_animations_limit_ = saved_animations_limit; if (static_cast(saved_animation_ids_.size()) > saved_animations_limit_) { saved_animation_ids_.resize(saved_animations_limit_); diff --git a/td/telegram/AnimationsManager.h b/td/telegram/AnimationsManager.h index f8d69f994..bb8f28230 100644 --- a/td/telegram/AnimationsManager.h +++ b/td/telegram/AnimationsManager.h @@ -63,11 +63,11 @@ class AnimationsManager final : public Actor { void merge_animations(FileId new_id, FileId old_id); - void on_update_animation_search_emojis(string animation_search_emojis); + void on_update_animation_search_emojis(); - void on_update_animation_search_provider(string animation_search_provider); + void on_update_animation_search_provider(); - void on_update_saved_animations_limit(int32 saved_animations_limit); + void on_update_saved_animations_limit(); void reload_saved_animations(bool force); diff --git a/td/telegram/AttachMenuManager.cpp b/td/telegram/AttachMenuManager.cpp index 3aec01c4a..224bd23da 100644 --- a/td/telegram/AttachMenuManager.cpp +++ b/td/telegram/AttachMenuManager.cpp @@ -805,22 +805,25 @@ void AttachMenuManager::reload_attach_menu_bots(Promise &&promise) { if (!is_active()) { return; } - auto query_promise = - PromiseCreator::lambda([actor_id = actor_id(this), promise = std::move(promise)]( - Result> &&result) mutable { - send_closure(actor_id, &AttachMenuManager::on_reload_attach_menu_bots, std::move(result), std::move(promise)); - }); - td_->create_handler(std::move(query_promise))->send(hash_); + + reload_attach_menu_bots_queries_.push_back(std::move(promise)); + if (reload_attach_menu_bots_queries_.size() == 1) { + auto query_promise = PromiseCreator::lambda( + [actor_id = actor_id(this)](Result> &&result) { + send_closure(actor_id, &AttachMenuManager::on_reload_attach_menu_bots, std::move(result)); + }); + td_->create_handler(std::move(query_promise))->send(hash_); + } } void AttachMenuManager::on_reload_attach_menu_bots( - Result> &&result, Promise &&promise) { + Result> &&result) { if (!is_active()) { - return promise.set_value(Unit()); + return set_promises(reload_attach_menu_bots_queries_); } if (result.is_error()) { set_timeout_in(Random::fast(60, 120)); - return promise.set_value(Unit()); + return set_promises(reload_attach_menu_bots_queries_); } is_inited_ = true; @@ -830,7 +833,7 @@ void AttachMenuManager::on_reload_attach_menu_bots( auto attach_menu_bots_ptr = result.move_as_ok(); auto constructor_id = attach_menu_bots_ptr->get_id(); if (constructor_id == telegram_api::attachMenuBotsNotModified::ID) { - return promise.set_value(Unit()); + return set_promises(reload_attach_menu_bots_queries_); } CHECK(constructor_id == telegram_api::attachMenuBots::ID); auto attach_menu_bots = move_tl_object_as(attach_menu_bots_ptr); @@ -867,7 +870,7 @@ void AttachMenuManager::on_reload_attach_menu_bots( save_attach_menu_bots(); } - promise.set_value(Unit()); + set_promises(reload_attach_menu_bots_queries_); } void AttachMenuManager::remove_bot_from_attach_menu(UserId user_id) { diff --git a/td/telegram/AttachMenuManager.h b/td/telegram/AttachMenuManager.h index 6efceb8b0..18e0822af 100644 --- a/td/telegram/AttachMenuManager.h +++ b/td/telegram/AttachMenuManager.h @@ -136,8 +136,7 @@ class AttachMenuManager final : public Actor { void save_attach_menu_bots(); - void on_reload_attach_menu_bots(Result> &&result, - Promise &&promise); + void on_reload_attach_menu_bots(Result> &&result); void on_get_attach_menu_bot(UserId user_id, Result> &&result, @@ -150,6 +149,7 @@ class AttachMenuManager final : public Actor { int64 hash_ = 0; vector attach_menu_bots_; FlatHashMap attach_menu_bot_file_source_ids_; + vector> reload_attach_menu_bots_queries_; struct OpenedWebView { DialogId dialog_id_; diff --git a/td/telegram/AudiosManager.cpp b/td/telegram/AudiosManager.cpp index 7a28b00d2..fbc89ce22 100644 --- a/td/telegram/AudiosManager.cpp +++ b/td/telegram/AudiosManager.cpp @@ -7,12 +7,16 @@ #include "td/telegram/AudiosManager.h" #include "td/telegram/AuthManager.h" +#include "td/telegram/DialogId.h" #include "td/telegram/files/FileManager.h" #include "td/telegram/files/FileType.h" +#include "td/telegram/Global.h" #include "td/telegram/PhotoFormat.h" #include "td/telegram/secret_api.h" #include "td/telegram/Td.h" +#include "td/actor/actor.h" + #include "td/utils/logging.h" #include "td/utils/misc.h" #include "td/utils/PathView.h" diff --git a/td/telegram/AuthManager.cpp b/td/telegram/AuthManager.cpp index d5f37e452..010a68583 100644 --- a/td/telegram/AuthManager.cpp +++ b/td/telegram/AuthManager.cpp @@ -9,7 +9,6 @@ #include "td/telegram/AttachMenuManager.h" #include "td/telegram/AuthManager.hpp" #include "td/telegram/ConfigManager.h" -#include "td/telegram/ConfigShared.h" #include "td/telegram/ContactsManager.h" #include "td/telegram/Global.h" #include "td/telegram/logevent/LogEvent.h" @@ -19,6 +18,7 @@ #include "td/telegram/net/NetQueryDispatcher.h" #include "td/telegram/NewPasswordState.h" #include "td/telegram/NotificationManager.h" +#include "td/telegram/OptionManager.h" #include "td/telegram/PasswordManager.h" #include "td/telegram/StateManager.h" #include "td/telegram/StickersManager.h" @@ -51,7 +51,7 @@ AuthManager::AuthManager(int32 api_id, const string &api_hash, ActorShared<> par if (my_id.is_valid()) { // just in case LOG(INFO) << "Logged in as " << my_id; - G()->shared_config().set_option_integer("my_id", my_id.get()); + td_->option_manager_->set_option_integer("my_id", my_id.get()); update_state(State::Ok); } else { LOG(ERROR) << "Restore unknown my_id"; @@ -701,8 +701,8 @@ void AuthManager::on_log_out_result(NetQueryPtr &result) { if (r_log_out.is_ok()) { auto logged_out = r_log_out.move_as_ok(); if (!logged_out->future_auth_token_.empty()) { - G()->shared_config().set_option_string("authentication_token", - base64url_encode(logged_out->future_auth_token_.as_slice())); + td_->option_manager_->set_option_string("authentication_token", + base64url_encode(logged_out->future_auth_token_.as_slice())); } } else { status = r_log_out.move_as_error(); @@ -722,6 +722,10 @@ void AuthManager::on_authorization_lost(string source) { LOG(INFO) << "Ignore authorization loss because of " << source << ", while logging out"; return; } + if (state_ == State::Closing || state_ == State::DestroyingKeys) { + LOG(INFO) << "Ignore duplicate authorization loss because of " << source; + return; + } LOG(WARNING) << "Lost authorization because of " << source; destroy_auth_keys(); } @@ -792,7 +796,7 @@ void AuthManager::on_get_authorization(tl_object_ptr(auth_ptr); - G()->shared_config().set_option_integer("authorization_date", G()->unix_time()); + td_->option_manager_->set_option_integer("authorization_date", G()->unix_time()); if (was_check_bot_token_) { is_bot_ = true; G()->td_db()->get_binlog_pmc()->set("auth_is_bot", "true"); @@ -815,10 +819,10 @@ void AuthManager::on_get_authorization(tl_object_ptrflags_ & telegram_api::auth_authorization::TMP_SESSIONS_MASK) != 0) { - G()->shared_config().set_option_integer("session_count", auth->tmp_sessions_); + td_->option_manager_->set_option_integer("session_count", auth->tmp_sessions_); } if (auth->setup_password_required_ && auth->otherwise_relogin_days_ > 0) { - G()->shared_config().set_option_integer("otherwise_relogin_days", auth->otherwise_relogin_days_); + td_->option_manager_->set_option_integer("otherwise_relogin_days", auth->otherwise_relogin_days_); } td_->attach_menu_manager_->init(); td_->messages_manager_->on_authorization_success(); diff --git a/td/telegram/BackgroundManager.cpp b/td/telegram/BackgroundManager.cpp index 5a2df2c54..7cd8abcd4 100644 --- a/td/telegram/BackgroundManager.cpp +++ b/td/telegram/BackgroundManager.cpp @@ -8,7 +8,6 @@ #include "td/telegram/AuthManager.h" #include "td/telegram/BackgroundType.hpp" -#include "td/telegram/ConfigShared.h" #include "td/telegram/DialogId.h" #include "td/telegram/Document.h" #include "td/telegram/DocumentsManager.h" @@ -453,7 +452,7 @@ void BackgroundManager::get_backgrounds(bool for_dark_theme, Result BackgroundManager::get_background_url(const string &name, td_api::object_ptr background_type) { TRY_RESULT(type, BackgroundType::get_background_type(background_type.get())); - auto url = PSTRING() << G()->shared_config().get_option_string("t_me_url", "https://t.me/") << "bg/"; + auto url = PSTRING() << G()->get_option_string("t_me_url", "https://t.me/") << "bg/"; auto link = type.get_link(); if (type.has_file()) { url += name; diff --git a/td/telegram/CallActor.cpp b/td/telegram/CallActor.cpp index 64def5a85..3f4f8e894 100644 --- a/td/telegram/CallActor.cpp +++ b/td/telegram/CallActor.cpp @@ -6,7 +6,6 @@ // #include "td/telegram/CallActor.h" -#include "td/telegram/ConfigShared.h" #include "td/telegram/ContactsManager.h" #include "td/telegram/DhCache.h" #include "td/telegram/DialogId.h" @@ -511,7 +510,7 @@ Status CallActor::do_update_call(telegram_api::phoneCallWaiting &call) { if ((call.flags_ & telegram_api::phoneCallWaiting::RECEIVE_DATE_MASK) != 0) { call_state_.is_received = true; call_state_need_flush_ = true; - int64 call_ring_timeout_ms = G()->shared_config().get_option_integer("call_ring_timeout_ms", 90000); + int64 call_ring_timeout_ms = G()->get_option_integer("call_ring_timeout_ms", 90000); set_timeout_in(static_cast(call_ring_timeout_ms) * 0.001); } } @@ -594,7 +593,7 @@ Status CallActor::do_update_call(telegram_api::phoneCallAccepted &call) { void CallActor::on_begin_exchanging_key() { call_state_.type = CallState::Type::ExchangingKey; call_state_need_flush_ = true; - int64 call_receive_timeout_ms = G()->shared_config().get_option_integer("call_receive_timeout_ms", 20000); + int64 call_receive_timeout_ms = G()->get_option_integer("call_receive_timeout_ms", 20000); auto timeout = static_cast(call_receive_timeout_ms) * 0.001; LOG(INFO) << "Set call timeout to " << timeout; set_timeout_in(timeout); @@ -773,7 +772,7 @@ void CallActor::try_send_request_query() { call_state_.protocol.get_input_phone_call_protocol()); auto query = G()->net_query_creator().create(tl_query); state_ = State::WaitRequestResult; - int64 call_receive_timeout_ms = G()->shared_config().get_option_integer("call_receive_timeout_ms", 20000); + int64 call_receive_timeout_ms = G()->get_option_integer("call_receive_timeout_ms", 20000); auto timeout = static_cast(call_receive_timeout_ms) * 0.001; LOG(INFO) << "Set call timeout to " << timeout; set_timeout_in(timeout); diff --git a/td/telegram/ConfigManager.cpp b/td/telegram/ConfigManager.cpp index cb6f095b3..d64d088ac 100644 --- a/td/telegram/ConfigManager.cpp +++ b/td/telegram/ConfigManager.cpp @@ -7,7 +7,6 @@ #include "td/telegram/ConfigManager.h" #include "td/telegram/AuthManager.h" -#include "td/telegram/ConfigShared.h" #include "td/telegram/ConnectionState.h" #include "td/telegram/Global.h" #include "td/telegram/JsonValue.h" @@ -244,22 +243,19 @@ static ActorOwn<> get_simple_config_impl(Promise promise, in #endif } -ActorOwn<> get_simple_config_azure(Promise promise, const ConfigShared *shared_config, bool is_test, - int32 scheduler_id) { +ActorOwn<> get_simple_config_azure(Promise promise, bool prefer_ipv6, Slice domain_name, + bool is_test, int32 scheduler_id) { string url = PSTRING() << "https://software-download.microsoft.com/" << (is_test ? "test" : "prod") << "v2/config.txt"; - const bool prefer_ipv6 = shared_config == nullptr ? false : shared_config->get_option_boolean("prefer_ipv6"); return get_simple_config_impl(std::move(promise), scheduler_id, std::move(url), "tcdnb.azureedge.net", {}, prefer_ipv6, [](HttpQuery &http_query) -> Result { return http_query.content_.str(); }); } static ActorOwn<> get_simple_config_dns(Slice address, Slice host, Promise promise, - const ConfigShared *shared_config, bool is_test, int32 scheduler_id) { - string name = shared_config == nullptr ? string() : shared_config->get_option_string("dc_txt_domain_name"); - const bool prefer_ipv6 = shared_config == nullptr ? false : shared_config->get_option_boolean("prefer_ipv6"); - if (name.empty()) { - name = is_test ? "tapv3.stel.com" : "apv3.stel.com"; + bool prefer_ipv6, Slice domain_name, bool is_test, int32 scheduler_id) { + if (domain_name.empty()) { + domain_name = is_test ? Slice("tapv3.stel.com") : Slice("apv3.stel.com"); } auto get_config = [](HttpQuery &http_query) -> Result { auto get_data = [](JsonValue &answer) -> Result { @@ -302,21 +298,22 @@ static ActorOwn<> get_simple_config_dns(Slice address, Slice host, Promise get_simple_config_google_dns(Promise promise, const ConfigShared *shared_config, +ActorOwn<> get_simple_config_google_dns(Promise promise, bool prefer_ipv6, Slice domain_name, bool is_test, int32 scheduler_id) { - return get_simple_config_dns("dns.google/resolve", "dns.google", std::move(promise), shared_config, is_test, - scheduler_id); + return get_simple_config_dns("dns.google/resolve", "dns.google", std::move(promise), prefer_ipv6, domain_name, + is_test, scheduler_id); } -ActorOwn<> get_simple_config_mozilla_dns(Promise promise, const ConfigShared *shared_config, +ActorOwn<> get_simple_config_mozilla_dns(Promise promise, bool prefer_ipv6, Slice domain_name, bool is_test, int32 scheduler_id) { return get_simple_config_dns("mozilla.cloudflare-dns.com/dns-query", "mozilla.cloudflare-dns.com", std::move(promise), - shared_config, is_test, scheduler_id); + prefer_ipv6, domain_name, is_test, scheduler_id); } static string generate_firebase_remote_config_payload() { @@ -329,9 +326,8 @@ static string generate_firebase_remote_config_payload() { << app_instance_id << "\"}"; } -ActorOwn<> get_simple_config_firebase_remote_config(Promise promise, - const ConfigShared *shared_config, bool is_test, - int32 scheduler_id) { +ActorOwn<> get_simple_config_firebase_remote_config(Promise promise, bool prefer_ipv6, + Slice domain_name, bool is_test, int32 scheduler_id) { if (is_test) { promise.set_error(Status::Error(400, "Test config is not supported")); return ActorOwn<>(); @@ -341,7 +337,6 @@ ActorOwn<> get_simple_config_firebase_remote_config(Promise string url = "https://firebaseremoteconfig.googleapis.com/v1/projects/peak-vista-421/namespaces/" "firebase:fetch?key=AIzaSyC2-kAkpDsroixRXw-sTw-Wfqo4NxjMwwM"; - const bool prefer_ipv6 = shared_config == nullptr ? false : shared_config->get_option_boolean("prefer_ipv6"); auto get_config = [](HttpQuery &http_query) -> Result { TRY_RESULT(json, json_decode(http_query.get_arg("entries"))); if (json.type() != JsonValue::Type::Object) { @@ -355,7 +350,7 @@ ActorOwn<> get_simple_config_firebase_remote_config(Promise {}, prefer_ipv6, std::move(get_config), payload, "application/json"); } -ActorOwn<> get_simple_config_firebase_realtime(Promise promise, const ConfigShared *shared_config, +ActorOwn<> get_simple_config_firebase_realtime(Promise promise, bool prefer_ipv6, Slice domain_name, bool is_test, int32 scheduler_id) { if (is_test) { promise.set_error(Status::Error(400, "Test config is not supported")); @@ -363,7 +358,6 @@ ActorOwn<> get_simple_config_firebase_realtime(Promise promi } string url = "https://reserve-5a846.firebaseio.com/ipconfigv3.json"; - const bool prefer_ipv6 = shared_config == nullptr ? false : shared_config->get_option_boolean("prefer_ipv6"); auto get_config = [](HttpQuery &http_query) -> Result { return http_query.get_arg("content").str(); }; @@ -371,15 +365,14 @@ ActorOwn<> get_simple_config_firebase_realtime(Promise promi prefer_ipv6, std::move(get_config)); } -ActorOwn<> get_simple_config_firebase_firestore(Promise promise, const ConfigShared *shared_config, - bool is_test, int32 scheduler_id) { +ActorOwn<> get_simple_config_firebase_firestore(Promise promise, bool prefer_ipv6, + Slice domain_name, bool is_test, int32 scheduler_id) { if (is_test) { promise.set_error(Status::Error(400, "Test config is not supported")); return ActorOwn<>(); } string url = "https://www.google.com/v1/projects/reserve-5a846/databases/(default)/documents/ipconfig/v3"; - const bool prefer_ipv6 = shared_config == nullptr ? false : shared_config->get_option_boolean("prefer_ipv6"); auto get_config = [](HttpQuery &http_query) -> Result { TRY_RESULT(json, json_decode(http_query.get_arg("fields"))); if (json.type() != JsonValue::Type::Object) { @@ -661,7 +654,7 @@ class ConfigRecoverer final : public Actor { auto config = r_simple_config.move_as_ok(); VLOG(config_recoverer) << "Receive raw " << to_string(config); if (config->expires_ >= G()->unix_time()) { - string phone_number = G()->shared_config().get_option_string("my_phone_number"); + string phone_number = G()->get_option_string("my_phone_number"); simple_config_.dc_options.clear(); for (auto &rule : config->rules_) { @@ -708,7 +701,7 @@ class ConfigRecoverer final : public Actor { } static bool expect_blocking() { - return G()->shared_config().get_option_boolean("expect_blocking", true); + return G()->get_option_boolean("expect_blocking", true); } double get_config_expire_time() const { @@ -842,8 +835,9 @@ class ConfigRecoverer final : public Actor { return get_simple_config_mozilla_dns; } }(); - simple_config_query_ = - get_simple_config(std::move(promise), &G()->shared_config(), G()->is_test_dc(), G()->get_gc_scheduler_id()); + simple_config_query_ = get_simple_config(std::move(promise), G()->get_option_boolean("prefer_ipv6"), + G()->get_option_string("dc_txt_domain_name"), G()->is_test_dc(), + G()->get_gc_scheduler_id()); simple_config_turn_++; } @@ -1101,9 +1095,8 @@ void ConfigManager::request_config_from_dc_impl(DcId dc_id, bool reopen_sessions } void ConfigManager::do_set_ignore_sensitive_content_restrictions(bool ignore_sensitive_content_restrictions) { - G()->shared_config().set_option_boolean("ignore_sensitive_content_restrictions", - ignore_sensitive_content_restrictions); - bool have_ignored_restriction_reasons = G()->shared_config().have_option("ignored_restriction_reasons"); + G()->set_option_boolean("ignore_sensitive_content_restrictions", ignore_sensitive_content_restrictions); + bool have_ignored_restriction_reasons = G()->have_option("ignored_restriction_reasons"); if (have_ignored_restriction_reasons != ignore_sensitive_content_restrictions) { reget_app_config(Auto()); } @@ -1113,7 +1106,7 @@ void ConfigManager::do_set_archive_and_mute(bool archive_and_mute) { if (archive_and_mute) { remove_suggested_action(suggested_actions_, SuggestedAction{SuggestedAction::Type::EnableArchiveAndMuteNewChats}); } - G()->shared_config().set_option_boolean("archive_and_mute_new_chats_from_unknown_users", archive_and_mute); + G()->set_option_boolean("archive_and_mute_new_chats_from_unknown_users", archive_and_mute); } void ConfigManager::hide_suggested_action(SuggestedAction suggested_action) { @@ -1211,7 +1204,7 @@ void ConfigManager::on_result(NetQueryPtr res) { if (result_ptr.is_error()) { fail_promises(set_content_settings_queries_[ignore_sensitive_content_restrictions], result_ptr.move_as_error()); } else { - if (G()->shared_config().get_option_boolean("can_ignore_sensitive_content_restrictions") && + if (G()->get_option_boolean("can_ignore_sensitive_content_restrictions") && last_set_content_settings_ == ignore_sensitive_content_restrictions) { do_set_ignore_sensitive_content_restrictions(ignore_sensitive_content_restrictions); } @@ -1237,7 +1230,7 @@ void ConfigManager::on_result(NetQueryPtr res) { auto result = result_ptr.move_as_ok(); do_set_ignore_sensitive_content_restrictions(result->sensitive_enabled_); - G()->shared_config().set_option_boolean("can_ignore_sensitive_content_restrictions", result->sensitive_can_change_); + G()->set_option_boolean("can_ignore_sensitive_content_restrictions", result->sensitive_can_change_); set_promises(get_content_settings_queries_); return; @@ -1328,130 +1321,130 @@ void ConfigManager::process_config(tl_object_ptr config) { set_timeout_at(expire_time_.at()); LOG_IF(ERROR, config->test_mode_ != G()->is_test_dc()) << "Wrong parameter is_test"; - ConfigShared &shared_config = G()->shared_config(); + Global &options = *G(); // Do not save dc_options in config, because it will be interpreted and saved by ConnectionCreator. send_closure(G()->connection_creator(), &ConnectionCreator::on_dc_options, DcOptions(config->dc_options_)); - shared_config.set_option_integer("recent_stickers_limit", config->stickers_recent_limit_); - shared_config.set_option_integer("favorite_stickers_limit", config->stickers_faved_limit_); - shared_config.set_option_integer("saved_animations_limit", config->saved_gifs_limit_); - shared_config.set_option_integer("channels_read_media_period", config->channels_read_media_period_); + options.set_option_integer("recent_stickers_limit", config->stickers_recent_limit_); + options.set_option_integer("favorite_stickers_limit", config->stickers_faved_limit_); + options.set_option_integer("saved_animations_limit", config->saved_gifs_limit_); + options.set_option_integer("channels_read_media_period", config->channels_read_media_period_); - shared_config.set_option_boolean("test_mode", config->test_mode_); - shared_config.set_option_integer("forwarded_message_count_max", config->forwarded_count_max_); - shared_config.set_option_integer("basic_group_size_max", config->chat_size_max_); - shared_config.set_option_integer("supergroup_size_max", config->megagroup_size_max_); - shared_config.set_option_integer("pinned_chat_count_max", config->pinned_dialogs_count_max_); - shared_config.set_option_integer("pinned_archived_chat_count_max", config->pinned_infolder_count_max_); - if (is_from_main_dc || !shared_config.have_option("expect_blocking")) { - shared_config.set_option_boolean("expect_blocking", config->blocked_mode_); + options.set_option_boolean("test_mode", config->test_mode_); + options.set_option_integer("forwarded_message_count_max", config->forwarded_count_max_); + options.set_option_integer("basic_group_size_max", config->chat_size_max_); + options.set_option_integer("supergroup_size_max", config->megagroup_size_max_); + options.set_option_integer("pinned_chat_count_max", config->pinned_dialogs_count_max_); + options.set_option_integer("pinned_archived_chat_count_max", config->pinned_infolder_count_max_); + if (is_from_main_dc || !options.have_option("expect_blocking")) { + options.set_option_boolean("expect_blocking", config->blocked_mode_); } - if (is_from_main_dc || !shared_config.have_option("dc_txt_domain_name")) { - shared_config.set_option_string("dc_txt_domain_name", config->dc_txt_domain_name_); + if (is_from_main_dc || !options.have_option("dc_txt_domain_name")) { + options.set_option_string("dc_txt_domain_name", config->dc_txt_domain_name_); } - if (is_from_main_dc || !shared_config.have_option("t_me_url")) { + if (is_from_main_dc || !options.have_option("t_me_url")) { auto url = config->me_url_prefix_; if (!url.empty()) { if (url.back() != '/') { url.push_back('/'); } - shared_config.set_option_string("t_me_url", url); + options.set_option_string("t_me_url", url); } } if (is_from_main_dc) { - shared_config.set_option_integer("webfile_dc_id", config->webfile_dc_id_); + options.set_option_integer("webfile_dc_id", config->webfile_dc_id_); if ((config->flags_ & telegram_api::config::TMP_SESSIONS_MASK) != 0) { - shared_config.set_option_integer("session_count", config->tmp_sessions_); + options.set_option_integer("session_count", config->tmp_sessions_); } else { - shared_config.set_option_empty("session_count"); + options.set_option_empty("session_count"); } if ((config->flags_ & telegram_api::config::SUGGESTED_LANG_CODE_MASK) != 0) { - shared_config.set_option_string("suggested_language_pack_id", config->suggested_lang_code_); - shared_config.set_option_integer("language_pack_version", config->lang_pack_version_); - shared_config.set_option_integer("base_language_pack_version", config->base_lang_pack_version_); + options.set_option_string("suggested_language_pack_id", config->suggested_lang_code_); + options.set_option_integer("language_pack_version", config->lang_pack_version_); + options.set_option_integer("base_language_pack_version", config->base_lang_pack_version_); } else { - shared_config.set_option_empty("suggested_language_pack_id"); - shared_config.set_option_empty("language_pack_version"); - shared_config.set_option_empty("base_language_pack_version"); + options.set_option_empty("suggested_language_pack_id"); + options.set_option_empty("language_pack_version"); + options.set_option_empty("base_language_pack_version"); } } if (is_from_main_dc) { - shared_config.set_option_integer("edit_time_limit", config->edit_time_limit_); - shared_config.set_option_boolean("revoke_pm_inbox", config->revoke_pm_inbox_); - shared_config.set_option_integer("revoke_time_limit", config->revoke_time_limit_); - shared_config.set_option_integer("revoke_pm_time_limit", config->revoke_pm_time_limit_); + options.set_option_integer("edit_time_limit", config->edit_time_limit_); + options.set_option_boolean("revoke_pm_inbox", config->revoke_pm_inbox_); + options.set_option_integer("revoke_time_limit", config->revoke_time_limit_); + options.set_option_integer("revoke_pm_time_limit", config->revoke_pm_time_limit_); - shared_config.set_option_integer("rating_e_decay", config->rating_e_decay_); + options.set_option_integer("rating_e_decay", config->rating_e_decay_); - shared_config.set_option_boolean("calls_enabled", config->phonecalls_enabled_); + options.set_option_boolean("calls_enabled", config->phonecalls_enabled_); } - shared_config.set_option_integer("call_ring_timeout_ms", config->call_ring_timeout_ms_); - shared_config.set_option_integer("call_connect_timeout_ms", config->call_connect_timeout_ms_); - shared_config.set_option_integer("call_packet_timeout_ms", config->call_packet_timeout_ms_); - shared_config.set_option_integer("call_receive_timeout_ms", config->call_receive_timeout_ms_); + options.set_option_integer("call_ring_timeout_ms", config->call_ring_timeout_ms_); + options.set_option_integer("call_connect_timeout_ms", config->call_connect_timeout_ms_); + options.set_option_integer("call_packet_timeout_ms", config->call_packet_timeout_ms_); + options.set_option_integer("call_receive_timeout_ms", config->call_receive_timeout_ms_); - shared_config.set_option_integer("message_text_length_max", clamp(config->message_length_max_, 4096, 1000000)); - shared_config.set_option_integer("message_caption_length_max", clamp(config->caption_length_max_, 1024, 1000000)); + options.set_option_integer("message_text_length_max", clamp(config->message_length_max_, 4096, 1000000)); + options.set_option_integer("message_caption_length_max", clamp(config->caption_length_max_, 1024, 1000000)); if (config->gif_search_username_.empty()) { - shared_config.set_option_empty("animation_search_bot_username"); + options.set_option_empty("animation_search_bot_username"); } else { - shared_config.set_option_string("animation_search_bot_username", config->gif_search_username_); + options.set_option_string("animation_search_bot_username", config->gif_search_username_); } if (config->venue_search_username_.empty()) { - shared_config.set_option_empty("venue_search_bot_username"); + options.set_option_empty("venue_search_bot_username"); } else { - shared_config.set_option_string("venue_search_bot_username", config->venue_search_username_); + options.set_option_string("venue_search_bot_username", config->venue_search_username_); } if (config->img_search_username_.empty()) { - shared_config.set_option_empty("photo_search_bot_username"); + options.set_option_empty("photo_search_bot_username"); } else { - shared_config.set_option_string("photo_search_bot_username", config->img_search_username_); + options.set_option_string("photo_search_bot_username", config->img_search_username_); } auto fix_timeout_ms = [](int32 timeout_ms) { return clamp(timeout_ms, 1000, 86400 * 1000); }; - shared_config.set_option_integer("online_update_period_ms", fix_timeout_ms(config->online_update_period_ms_)); + options.set_option_integer("online_update_period_ms", fix_timeout_ms(config->online_update_period_ms_)); - shared_config.set_option_integer("online_cloud_timeout_ms", fix_timeout_ms(config->online_cloud_timeout_ms_)); - shared_config.set_option_integer("notification_cloud_delay_ms", fix_timeout_ms(config->notify_cloud_delay_ms_)); - shared_config.set_option_integer("notification_default_delay_ms", fix_timeout_ms(config->notify_default_delay_ms_)); + options.set_option_integer("online_cloud_timeout_ms", fix_timeout_ms(config->online_cloud_timeout_ms_)); + options.set_option_integer("notification_cloud_delay_ms", fix_timeout_ms(config->notify_cloud_delay_ms_)); + options.set_option_integer("notification_default_delay_ms", fix_timeout_ms(config->notify_default_delay_ms_)); // delete outdated options - shared_config.set_option_empty("suggested_language_code"); - shared_config.set_option_empty("chat_big_size"); - shared_config.set_option_empty("group_size_max"); - shared_config.set_option_empty("saved_gifs_limit"); - shared_config.set_option_empty("sessions_count"); - shared_config.set_option_empty("forwarded_messages_count_max"); - shared_config.set_option_empty("broadcast_size_max"); - shared_config.set_option_empty("group_chat_size_max"); - shared_config.set_option_empty("chat_size_max"); - shared_config.set_option_empty("megagroup_size_max"); - shared_config.set_option_empty("offline_blur_timeout_ms"); - shared_config.set_option_empty("offline_idle_timeout_ms"); - shared_config.set_option_empty("notify_cloud_delay_ms"); - shared_config.set_option_empty("notify_default_delay_ms"); - shared_config.set_option_empty("large_chat_size"); + options.set_option_empty("suggested_language_code"); + options.set_option_empty("chat_big_size"); + options.set_option_empty("group_size_max"); + options.set_option_empty("saved_gifs_limit"); + options.set_option_empty("sessions_count"); + options.set_option_empty("forwarded_messages_count_max"); + options.set_option_empty("broadcast_size_max"); + options.set_option_empty("group_chat_size_max"); + options.set_option_empty("chat_size_max"); + options.set_option_empty("megagroup_size_max"); + options.set_option_empty("offline_blur_timeout_ms"); + options.set_option_empty("offline_idle_timeout_ms"); + options.set_option_empty("notify_cloud_delay_ms"); + options.set_option_empty("notify_default_delay_ms"); + options.set_option_empty("large_chat_size"); // TODO implement online status updates - // shared_config.set_option_integer("offline_blur_timeout_ms", config->offline_blur_timeout_ms_); - // shared_config.set_option_integer("offline_idle_timeout_ms", config->offline_idle_timeout_ms_); + // options.set_option_integer("offline_blur_timeout_ms", config->offline_blur_timeout_ms_); + // options.set_option_integer("offline_idle_timeout_ms", config->offline_idle_timeout_ms_); - // shared_config.set_option_integer("push_chat_period_ms", config->push_chat_period_ms_); - // shared_config.set_option_integer("push_chat_limit", config->push_chat_limit_); + // options.set_option_integer("push_chat_period_ms", config->push_chat_period_ms_); + // options.set_option_integer("push_chat_limit", config->push_chat_limit_); if (is_from_main_dc) { reget_app_config(Auto()); - if (!shared_config.have_option("can_ignore_sensitive_content_restrictions") || - !shared_config.have_option("ignore_sensitive_content_restrictions")) { + if (!options.have_option("can_ignore_sensitive_content_restrictions") || + !options.have_option("ignore_sensitive_content_restrictions")) { get_content_settings(Auto()); } - if (!shared_config.have_option("archive_and_mute_new_chats_from_unknown_users")) { + if (!options.have_option("archive_and_mute_new_chats_from_unknown_users")) { get_global_privacy_settings(Auto()); } } @@ -1461,8 +1454,7 @@ void ConfigManager::process_app_config(tl_object_ptr &c CHECK(config != nullptr); LOG(INFO) << "Receive app config " << to_string(config); - const bool archive_and_mute = - G()->shared_config().get_option_boolean("archive_and_mute_new_chats_from_unknown_users"); + const bool archive_and_mute = G()->get_option_boolean("archive_and_mute_new_chats_from_unknown_users"); string autologin_token; vector autologin_domains; @@ -1701,16 +1693,16 @@ void ConfigManager::process_app_config(tl_object_ptr &c auto setting_value = get_json_value_int(std::move(video_note_setting->value_), Slice()); if (setting_value > 0) { if (video_note_setting->key_ == "diameter") { - G()->shared_config().set_option_integer("suggested_video_note_length", setting_value); + G()->set_option_integer("suggested_video_note_length", setting_value); } if (video_note_setting->key_ == "video_bitrate") { - G()->shared_config().set_option_integer("suggested_video_note_video_bitrate", setting_value); + G()->set_option_integer("suggested_video_note_video_bitrate", setting_value); } if (video_note_setting->key_ == "audio_bitrate") { - G()->shared_config().set_option_integer("suggested_video_note_audio_bitrate", setting_value); + G()->set_option_integer("suggested_video_note_audio_bitrate", setting_value); } if (video_note_setting->key_ == "max_size") { - G()->shared_config().set_option_integer("video_note_size_max", setting_value); + G()->set_option_integer("video_note_size_max", setting_value); } } } else { @@ -1740,17 +1732,17 @@ void ConfigManager::process_app_config(tl_object_ptr &c } if (key == "ringtone_duration_max") { auto setting_value = get_json_value_int(std::move(key_value->value_), key); - G()->shared_config().set_option_integer("notification_sound_duration_max", setting_value); + G()->set_option_integer("notification_sound_duration_max", setting_value); continue; } if (key == "ringtone_size_max") { auto setting_value = get_json_value_int(std::move(key_value->value_), key); - G()->shared_config().set_option_integer("notification_sound_size_max", setting_value); + G()->set_option_integer("notification_sound_size_max", setting_value); continue; } if (key == "ringtone_saved_count_max") { auto setting_value = get_json_value_int(std::move(key_value->value_), key); - G()->shared_config().set_option_integer("notification_sound_count_max", setting_value); + G()->set_option_integer("notification_sound_count_max", setting_value); continue; } if (key == "premium_promo_order") { @@ -1774,7 +1766,7 @@ void ConfigManager::process_app_config(tl_object_ptr &c if (suffix == "_limit_default" || suffix == "_limit_premium") { auto setting_value = get_json_value_int(std::move(key_value->value_), key); if (setting_value > 0) { - G()->shared_config().set_option_integer(key, setting_value); + G()->set_option_integer(key, setting_value); } else { LOG(ERROR) << "Receive invalid value " << setting_value << " for " << key; } @@ -1817,18 +1809,18 @@ void ConfigManager::process_app_config(tl_object_ptr &c send_closure(G()->link_manager(), &LinkManager::update_autologin_domains, std::move(autologin_token), std::move(autologin_domains), std::move(url_auth_domains)); - ConfigShared &shared_config = G()->shared_config(); + Global &options = *G(); if (ignored_restriction_reasons.empty()) { - shared_config.set_option_empty("ignored_restriction_reasons"); + options.set_option_empty("ignored_restriction_reasons"); - if (shared_config.get_option_boolean("ignore_sensitive_content_restrictions", true)) { + if (options.get_option_boolean("ignore_sensitive_content_restrictions", true)) { get_content_settings(Auto()); } } else { - shared_config.set_option_string("ignored_restriction_reasons", ignored_restriction_reasons); + options.set_option_string("ignored_restriction_reasons", ignored_restriction_reasons); - if (!shared_config.get_option_boolean("can_ignore_sensitive_content_restrictions")) { + if (!options.get_option_boolean("can_ignore_sensitive_content_restrictions")) { get_content_settings(Auto()); } } @@ -1843,94 +1835,93 @@ void ConfigManager::process_app_config(tl_object_ptr &c } dice_success_values[dice_emoji_it->second] = it.second; } - shared_config.set_option_string("dice_success_values", implode(dice_success_values, ',')); - shared_config.set_option_string("dice_emojis", implode(dice_emojis, '\x01')); + options.set_option_string("dice_success_values", implode(dice_success_values, ',')); + options.set_option_string("dice_emojis", implode(dice_emojis, '\x01')); } - shared_config.set_option_string("emoji_sounds", implode(emoji_sounds, ',')); + options.set_option_string("emoji_sounds", implode(emoji_sounds, ',')); if (animated_emoji_zoom <= 0 || animated_emoji_zoom > 2.0) { - shared_config.set_option_empty("animated_emoji_zoom"); + options.set_option_empty("animated_emoji_zoom"); } else { - shared_config.set_option_integer("animated_emoji_zoom", static_cast(animated_emoji_zoom * 1e9)); + options.set_option_integer("animated_emoji_zoom", static_cast(animated_emoji_zoom * 1e9)); } if (animation_search_provider.empty()) { - shared_config.set_option_empty("animation_search_provider"); + options.set_option_empty("animation_search_provider"); } else { - shared_config.set_option_string("animation_search_provider", animation_search_provider); + options.set_option_string("animation_search_provider", animation_search_provider); } if (animation_search_emojis.empty()) { - shared_config.set_option_empty("animation_search_emojis"); + options.set_option_empty("animation_search_emojis"); } else { - shared_config.set_option_string("animation_search_emojis", animation_search_emojis); + options.set_option_string("animation_search_emojis", animation_search_emojis); } if (!can_archive_and_mute_new_chats_from_unknown_users) { - shared_config.set_option_empty("can_archive_and_mute_new_chats_from_unknown_users"); + options.set_option_empty("can_archive_and_mute_new_chats_from_unknown_users"); } else { - shared_config.set_option_boolean("can_archive_and_mute_new_chats_from_unknown_users", - can_archive_and_mute_new_chats_from_unknown_users); + options.set_option_boolean("can_archive_and_mute_new_chats_from_unknown_users", + can_archive_and_mute_new_chats_from_unknown_users); } if (chat_read_mark_expire_period <= 0) { - shared_config.set_option_empty("chat_read_mark_expire_period"); + options.set_option_empty("chat_read_mark_expire_period"); } else { - shared_config.set_option_integer("chat_read_mark_expire_period", chat_read_mark_expire_period); + options.set_option_integer("chat_read_mark_expire_period", chat_read_mark_expire_period); } if (chat_read_mark_size_threshold <= 0) { - shared_config.set_option_empty("chat_read_mark_size_threshold"); + options.set_option_empty("chat_read_mark_size_threshold"); } else { - shared_config.set_option_integer("chat_read_mark_size_threshold", chat_read_mark_size_threshold); + options.set_option_integer("chat_read_mark_size_threshold", chat_read_mark_size_threshold); } - if (!shared_config.have_option("default_reaction_need_sync")) { - shared_config.set_option_string("default_reaction", default_reaction); + if (!options.have_option("default_reaction_need_sync")) { + options.set_option_string("default_reaction", default_reaction); } if (reactions_uniq_max <= 0 || reactions_uniq_max == 11) { - shared_config.set_option_empty("reactions_uniq_max"); + options.set_option_empty("reactions_uniq_max"); } else { - shared_config.set_option_integer("reactions_uniq_max", reactions_uniq_max); + options.set_option_integer("reactions_uniq_max", reactions_uniq_max); } - bool is_premium = shared_config.get_option_boolean("is_premium"); + bool is_premium = options.get_option_boolean("is_premium"); - auto chat_filter_count_max = shared_config.get_option_integer( + auto chat_filter_count_max = options.get_option_integer( is_premium ? Slice("dialog_filters_limit_premium") : Slice("dialog_filters_limit_default"), is_premium ? 20 : 10); - shared_config.set_option_integer("chat_filter_count_max", static_cast(chat_filter_count_max)); + options.set_option_integer("chat_filter_count_max", static_cast(chat_filter_count_max)); - auto chat_filter_chosen_chat_count_max = shared_config.get_option_integer( + auto chat_filter_chosen_chat_count_max = options.get_option_integer( is_premium ? Slice("dialog_filters_chats_limit_premium") : Slice("dialog_filters_chats_limit_default"), is_premium ? 200 : 100); - shared_config.set_option_integer("chat_filter_chosen_chat_count_max", - static_cast(chat_filter_chosen_chat_count_max)); + options.set_option_integer("chat_filter_chosen_chat_count_max", + static_cast(chat_filter_chosen_chat_count_max)); - auto bio_length_max = shared_config.get_option_integer( + auto bio_length_max = options.get_option_integer( is_premium ? Slice("about_length_limit_premium") : Slice("about_length_limit_default"), is_premium ? 140 : 70); - shared_config.set_option_integer("bio_length_max", bio_length_max); + options.set_option_integer("bio_length_max", bio_length_max); if (!is_premium_available) { premium_bot_username.clear(); // just in case premium_invoice_slug.clear(); // just in case premium_features.clear(); // just in case - shared_config.set_option_empty("is_premium_available"); + options.set_option_empty("is_premium_available"); } else { - shared_config.set_option_boolean("is_premium_available", is_premium_available); + options.set_option_boolean("is_premium_available", is_premium_available); } - shared_config.set_option_string("premium_features", implode(premium_features, ',')); + options.set_option_string("premium_features", implode(premium_features, ',')); if (premium_bot_username.empty()) { - shared_config.set_option_empty("premium_bot_username"); + options.set_option_empty("premium_bot_username"); } else { - shared_config.set_option_string("premium_bot_username", premium_bot_username); + options.set_option_string("premium_bot_username", premium_bot_username); } if (premium_invoice_slug.empty()) { - shared_config.set_option_empty("premium_invoice_slug"); + options.set_option_empty("premium_invoice_slug"); } else { - shared_config.set_option_string("premium_invoice_slug", premium_invoice_slug); + options.set_option_string("premium_invoice_slug", premium_invoice_slug); } - shared_config.set_option_integer("stickers_premium_by_emoji_num", stickers_premium_by_emoji_num); - shared_config.set_option_integer("stickers_normal_by_emoji_per_premium_num", - stickers_normal_by_emoji_per_premium_num); + options.set_option_integer("stickers_premium_by_emoji_num", stickers_premium_by_emoji_num); + options.set_option_integer("stickers_normal_by_emoji_per_premium_num", stickers_normal_by_emoji_per_premium_num); - shared_config.set_option_empty("default_ton_blockchain_config"); - shared_config.set_option_empty("default_ton_blockchain_name"); + options.set_option_empty("default_ton_blockchain_config"); + options.set_option_empty("default_ton_blockchain_name"); // do not update suggested actions while changing content settings or dismissing an action if (!is_set_content_settings_request_sent_ && dismiss_suggested_action_request_count_ == 0) { diff --git a/td/telegram/ConfigManager.h b/td/telegram/ConfigManager.h index 272058c5f..4805fc8e6 100644 --- a/td/telegram/ConfigManager.h +++ b/td/telegram/ConfigManager.h @@ -30,8 +30,6 @@ namespace td { extern int VERBOSITY_NAME(config_recoverer); -class ConfigShared; - using SimpleConfig = tl_object_ptr; struct SimpleConfigResult { Result r_config; @@ -40,24 +38,23 @@ struct SimpleConfigResult { Result decode_config(Slice input); -ActorOwn<> get_simple_config_azure(Promise promise, const ConfigShared *shared_config, bool is_test, - int32 scheduler_id); +ActorOwn<> get_simple_config_azure(Promise promise, bool prefer_ipv6, Slice domain_name, + bool is_test, int32 scheduler_id); -ActorOwn<> get_simple_config_google_dns(Promise promise, const ConfigShared *shared_config, +ActorOwn<> get_simple_config_google_dns(Promise promise, bool prefer_ipv6, Slice domain_name, bool is_test, int32 scheduler_id); -ActorOwn<> get_simple_config_mozilla_dns(Promise promise, const ConfigShared *shared_config, +ActorOwn<> get_simple_config_mozilla_dns(Promise promise, bool prefer_ipv6, Slice domain_name, bool is_test, int32 scheduler_id); -ActorOwn<> get_simple_config_firebase_remote_config(Promise promise, - const ConfigShared *shared_config, bool is_test, - int32 scheduler_id); +ActorOwn<> get_simple_config_firebase_remote_config(Promise promise, bool prefer_ipv6, + Slice domain_name, bool is_test, int32 scheduler_id); -ActorOwn<> get_simple_config_firebase_realtime(Promise promise, const ConfigShared *shared_config, +ActorOwn<> get_simple_config_firebase_realtime(Promise promise, bool prefer_ipv6, Slice domain_name, bool is_test, int32 scheduler_id); -ActorOwn<> get_simple_config_firebase_firestore(Promise promise, const ConfigShared *shared_config, - bool is_test, int32 scheduler_id); +ActorOwn<> get_simple_config_firebase_firestore(Promise promise, bool prefer_ipv6, + Slice domain_name, bool is_test, int32 scheduler_id); class HttpDate { static bool is_leap(int32 year) { 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/ContactsManager.cpp b/td/telegram/ContactsManager.cpp index cd8734331..c061c2557 100644 --- a/td/telegram/ContactsManager.cpp +++ b/td/telegram/ContactsManager.cpp @@ -11,7 +11,6 @@ #include "td/telegram/BotMenuButton.h" #include "td/telegram/ChannelParticipantFilter.h" #include "td/telegram/ConfigManager.h" -#include "td/telegram/ConfigShared.h" #include "td/telegram/Dependencies.h" #include "td/telegram/DialogInviteLink.h" #include "td/telegram/DialogLocation.h" @@ -36,6 +35,7 @@ #include "td/telegram/misc.h" #include "td/telegram/net/NetQuery.h" #include "td/telegram/NotificationManager.h" +#include "td/telegram/OptionManager.h" #include "td/telegram/PasswordManager.h" #include "td/telegram/Photo.h" #include "td/telegram/Photo.hpp" @@ -3334,11 +3334,11 @@ ContactsManager::ContactsManager(Td *td, ActorShared<> parent) : td_(td), parent my_id_ = load_my_id(); - G()->shared_config().set_option_integer("telegram_service_notifications_chat_id", - DialogId(get_service_notifications_user_id()).get()); - G()->shared_config().set_option_integer("replies_bot_chat_id", DialogId(get_replies_bot_user_id()).get()); - G()->shared_config().set_option_integer("group_anonymous_bot_user_id", get_anonymous_bot_user_id().get()); - G()->shared_config().set_option_integer("channel_bot_user_id", get_channel_bot_user_id().get()); + td_->option_manager_->set_option_integer("telegram_service_notifications_chat_id", + DialogId(get_service_notifications_user_id()).get()); + td_->option_manager_->set_option_integer("replies_bot_chat_id", DialogId(get_replies_bot_user_id()).get()); + td_->option_manager_->set_option_integer("group_anonymous_bot_user_id", get_anonymous_bot_user_id().get()); + td_->option_manager_->set_option_integer("channel_bot_user_id", get_channel_bot_user_id().get()); if (G()->parameters().use_chat_info_db) { auto next_contacts_sync_date_string = G()->td_db()->get_binlog_pmc()->get("next_contacts_sync_date"); @@ -3374,7 +3374,6 @@ ContactsManager::ContactsManager(Td *td, ActorShared<> parent) : td_(td), parent G()->td_db()->get_binlog_pmc()->get("pending_location_visibility_expire_date"); if (!pending_location_visibility_expire_date_string.empty()) { pending_location_visibility_expire_date_ = to_integer(pending_location_visibility_expire_date_string); - try_send_set_location_visibility_query(); } update_is_location_visible(); LOG(INFO) << "Loaded location_visibility_expire_date = " << location_visibility_expire_date_ @@ -3412,6 +3411,12 @@ ContactsManager::~ContactsManager() { linked_channel_ids_, restricted_user_ids_, restricted_channel_ids_); } +void ContactsManager::start_up() { + if (!pending_location_visibility_expire_date_) { + try_send_set_location_visibility_query(); + } +} + void ContactsManager::tear_down() { parent_.reset(); @@ -5100,7 +5105,7 @@ void ContactsManager::set_my_id(UserId my_id) { if (my_old_id != my_id) { my_id_ = my_id; G()->td_db()->get_binlog_pmc()->set("my_id", to_string(my_id.get())); - G()->shared_config().set_option_integer("my_id", my_id_.get()); + td_->option_manager_->set_option_integer("my_id", my_id_.get()); G()->td_db()->get_binlog_pmc()->force_sync(Promise()); } } @@ -6037,20 +6042,24 @@ void ContactsManager::set_location(const Location &location, Promise &&pro td_->create_handler(std::move(query_promise))->send(location, true, -1); } -void ContactsManager::set_location_visibility() { - bool is_location_visible = G()->shared_config().get_option_boolean("is_location_visible"); +void ContactsManager::set_location_visibility(Td *td) { + bool is_location_visible = td->option_manager_->get_option_boolean("is_location_visible"); auto pending_location_visibility_expire_date = is_location_visible ? std::numeric_limits::max() : 0; - if (pending_location_visibility_expire_date_ == -1 && - pending_location_visibility_expire_date == location_visibility_expire_date_) { - return; - } - if (pending_location_visibility_expire_date_ != pending_location_visibility_expire_date) { - pending_location_visibility_expire_date_ = pending_location_visibility_expire_date; + if (td->contacts_manager_ == nullptr) { G()->td_db()->get_binlog_pmc()->set("pending_location_visibility_expire_date", to_string(pending_location_visibility_expire_date)); - update_is_location_visible(); + return; } - try_send_set_location_visibility_query(); + if (td->contacts_manager_->pending_location_visibility_expire_date_ == -1 && + pending_location_visibility_expire_date == td->contacts_manager_->location_visibility_expire_date_) { + return; + } + if (td->contacts_manager_->pending_location_visibility_expire_date_ != pending_location_visibility_expire_date) { + td->contacts_manager_->pending_location_visibility_expire_date_ = pending_location_visibility_expire_date; + G()->td_db()->get_binlog_pmc()->set("pending_location_visibility_expire_date", + to_string(pending_location_visibility_expire_date)); + } + td->contacts_manager_->try_send_set_location_visibility_query(); } void ContactsManager::try_send_set_location_visibility_query() { @@ -6061,6 +6070,7 @@ void ContactsManager::try_send_set_location_visibility_query() { return; } + LOG(INFO) << "Trying to send set location visibility query"; if (is_set_location_visibility_request_sent_) { return; } @@ -6261,7 +6271,7 @@ void ContactsManager::set_location_visibility_expire_date(int32 expire_date) { void ContactsManager::update_is_location_visible() { auto expire_date = pending_location_visibility_expire_date_ != -1 ? pending_location_visibility_expire_date_ : location_visibility_expire_date_; - G()->shared_config().set_option_boolean("is_location_visible", expire_date != 0); + td_->option_manager_->set_option_boolean("is_location_visible", expire_date != 0); } void ContactsManager::on_update_bot_commands(DialogId dialog_id, UserId bot_user_id, @@ -6491,7 +6501,7 @@ void ContactsManager::set_name(const string &first_name, const string &last_name } void ContactsManager::set_bio(const string &bio, Promise &&promise) { - auto max_bio_length = static_cast(G()->shared_config().get_option_integer("bio_length_max")); + auto max_bio_length = static_cast(td_->option_manager_->get_option_integer("bio_length_max")); auto new_bio = strip_empty_characters(bio, max_bio_length); for (auto &c : new_bio) { if (c == '\n') { @@ -8613,7 +8623,7 @@ void ContactsManager::on_get_user(tl_object_ptr &&user_ptr, if (flags & USER_FLAG_IS_ME) { set_my_id(user_id); if (!is_bot) { - G()->shared_config().set_option_string("my_phone_number", user->phone_); + td_->option_manager_->set_option_string("my_phone_number", user->phone_); } } @@ -10208,8 +10218,8 @@ void ContactsManager::for_each_secret_chat_with_user(UserId user_id, const std:: void ContactsManager::update_user(User *u, UserId user_id, bool from_binlog, bool from_database) { CHECK(u != nullptr); if (user_id == get_my_id()) { - if (G()->shared_config().get_option_boolean("is_premium") != u->is_premium) { - G()->shared_config().set_option_boolean("is_premium", u->is_premium); + if (td_->option_manager_->get_option_boolean("is_premium") != u->is_premium) { + td_->option_manager_->set_option_boolean("is_premium", u->is_premium); send_closure(td_->config_manager_, &ConfigManager::request_config, true); } } @@ -11940,15 +11950,15 @@ void ContactsManager::on_update_user_full_need_phone_number_privacy_exception( } void ContactsManager::on_ignored_restriction_reasons_changed() { - for (auto user_id : restricted_user_ids_) { + restricted_user_ids_.foreach([&](const UserId &user_id) { send_closure(G()->td(), &Td::send_update, td_api::make_object(get_user_object(user_id, get_user(user_id)))); - } - for (auto channel_id : restricted_channel_ids_) { + }); + restricted_channel_ids_.foreach([&](const ChannelId &channel_id) { send_closure( G()->td(), &Td::send_update, td_api::make_object(get_supergroup_object(channel_id, get_channel(channel_id)))); - } + }); } void ContactsManager::on_set_profile_photo(tl_object_ptr &&photo, int64 old_photo_id) { diff --git a/td/telegram/ContactsManager.h b/td/telegram/ContactsManager.h index 3d6a08441..ee28afdd3 100644 --- a/td/telegram/ContactsManager.h +++ b/td/telegram/ContactsManager.h @@ -51,6 +51,7 @@ #include "td/utils/StringBuilder.h" #include "td/utils/Time.h" #include "td/utils/WaitFreeHashMap.h" +#include "td/utils/WaitFreeHashSet.h" #include #include @@ -326,7 +327,7 @@ class ContactsManager final : public Actor { void set_location(const Location &location, Promise &&promise); - void set_location_visibility(); + static void set_location_visibility(Td *td); void get_is_location_visible(Promise &&promise); @@ -1693,6 +1694,8 @@ class ContactsManager final : public Actor { void on_channel_participant_cache_timeout(ChannelId channel_id); + void start_up() final; + void tear_down() final; Td *td_; @@ -1724,7 +1727,7 @@ class ContactsManager final : public Actor { WaitFreeHashMap, ChannelIdHash> channels_; WaitFreeHashMap, ChannelIdHash> channels_full_; mutable FlatHashSet unknown_channels_; - FlatHashSet invalidated_channels_full_; + WaitFreeHashSet invalidated_channels_full_; WaitFreeHashMap channel_full_file_source_ids_; WaitFreeHashMap, SecretChatIdHash> secret_chats_; @@ -1843,8 +1846,8 @@ class ContactsManager final : public Actor { WaitFreeHashMap linked_channel_ids_; - FlatHashSet restricted_user_ids_; - FlatHashSet restricted_channel_ids_; + WaitFreeHashSet restricted_user_ids_; + WaitFreeHashSet restricted_channel_ids_; vector next_all_imported_contacts_; vector imported_contacts_unique_id_; diff --git a/td/telegram/DeviceTokenManager.cpp b/td/telegram/DeviceTokenManager.cpp index 727e0bc23..472435ea6 100644 --- a/td/telegram/DeviceTokenManager.cpp +++ b/td/telegram/DeviceTokenManager.cpp @@ -256,7 +256,7 @@ void DeviceTokenManager::register_device(tl_object_ptr devi } else { if ((info.state == TokenInfo::State::Reregister || info.state == TokenInfo::State::Sync) && info.token == token && info.other_user_ids == input_user_ids && info.is_app_sandbox == is_app_sandbox && encrypt == info.encrypt) { - int64 push_token_id = encrypt ? info.encryption_key_id : G()->get_my_id(); + int64 push_token_id = encrypt ? info.encryption_key_id : G()->get_option_integer("my_id"); return promise.set_value(td_api::make_object(push_token_id)); } @@ -308,7 +308,7 @@ vector> DeviceTokenManager::get_encryption_keys() const if (info.encrypt) { result.emplace_back(info.encryption_key_id, info.encryption_key); } else { - result.emplace_back(G()->get_my_id(), Slice()); + result.emplace_back(G()->get_option_integer("my_id"), Slice()); } } } @@ -424,7 +424,7 @@ void DeviceTokenManager::on_result(NetQueryPtr net_query) { if (info.encrypt) { push_token_id = info.encryption_key_id; } else { - push_token_id = G()->get_my_id(); + push_token_id = G()->get_option_integer("my_id"); } } info.promise.set_value(td_api::make_object(push_token_id)); diff --git a/td/telegram/DialogFilter.cpp b/td/telegram/DialogFilter.cpp index 87716feee..518e53022 100644 --- a/td/telegram/DialogFilter.cpp +++ b/td/telegram/DialogFilter.cpp @@ -6,7 +6,6 @@ // #include "td/telegram/DialogFilter.h" -#include "td/telegram/ConfigShared.h" #include "td/telegram/DialogId.h" #include "td/telegram/Global.h" @@ -20,7 +19,7 @@ namespace td { int32 DialogFilter::get_max_filter_dialogs() { - return narrow_cast(G()->shared_config().get_option_integer("chat_filter_chosen_chat_count_max", 100)); + return narrow_cast(G()->get_option_integer("chat_filter_chosen_chat_count_max", 100)); } unique_ptr DialogFilter::get_dialog_filter( diff --git a/td/telegram/DocumentsManager.cpp b/td/telegram/DocumentsManager.cpp index 4e42f687d..36cdf39d3 100644 --- a/td/telegram/DocumentsManager.cpp +++ b/td/telegram/DocumentsManager.cpp @@ -15,6 +15,7 @@ #include "td/telegram/files/FileLocation.h" #include "td/telegram/files/FileManager.h" #include "td/telegram/files/FileType.h" +#include "td/telegram/Global.h" #include "td/telegram/misc.h" #include "td/telegram/net/DcId.h" #include "td/telegram/PhotoSizeSource.h" @@ -29,6 +30,8 @@ #include "td/telegram/VideosManager.h" #include "td/telegram/VoiceNotesManager.h" +#include "td/actor/actor.h" + #include "td/utils/common.h" #include "td/utils/HttpUrl.h" #include "td/utils/logging.h" diff --git a/td/telegram/DocumentsManager.hpp b/td/telegram/DocumentsManager.hpp index 3df6820da..63b8bdb5a 100644 --- a/td/telegram/DocumentsManager.hpp +++ b/td/telegram/DocumentsManager.hpp @@ -12,7 +12,6 @@ #include "td/telegram/PhotoSize.hpp" #include "td/telegram/Version.h" -#include "td/utils/logging.h" #include "td/utils/tl_helpers.h" #include "td/telegram/ConfigShared.h" diff --git a/td/telegram/DownloadManager.h b/td/telegram/DownloadManager.h index de2133944..51068e190 100644 --- a/td/telegram/DownloadManager.h +++ b/td/telegram/DownloadManager.h @@ -15,7 +15,6 @@ #include "td/utils/common.h" #include "td/utils/Promise.h" -#include "td/utils/Status.h" namespace td { diff --git a/td/telegram/DownloadManagerCallback.h b/td/telegram/DownloadManagerCallback.h index 19da9c842..3bf087733 100644 --- a/td/telegram/DownloadManagerCallback.h +++ b/td/telegram/DownloadManagerCallback.h @@ -15,6 +15,7 @@ #include "td/actor/actor.h" #include "td/utils/common.h" +#include "td/utils/Promise.h" #include diff --git a/td/telegram/Global.cpp b/td/telegram/Global.cpp index e8df3c801..79bf898a4 100644 --- a/td/telegram/Global.cpp +++ b/td/telegram/Global.cpp @@ -6,7 +6,7 @@ // #include "td/telegram/Global.h" -#include "td/telegram/ConfigShared.h" +#include "td/telegram/AuthManager.h" #include "td/telegram/net/ConnectionCreator.h" #include "td/telegram/net/NetQueryDispatcher.h" #include "td/telegram/net/TempAuthKeyWatchdog.h" @@ -29,10 +29,7 @@ Global::Global() = default; Global::~Global() = default; void Global::log_out(Slice reason) { - CHECK(shared_config_ != nullptr); - if (!shared_config_->have_option("auth")) { - shared_config_->set_option_string("auth", reason); - } + send_closure(auth_manager_, &AuthManager::on_authorization_lost, reason.str()); } void Global::close_all(Promise<> on_finished) { @@ -170,8 +167,7 @@ void Global::update_server_time_difference(double diff) { server_time_difference_was_updated_ = true; do_save_server_time_difference(); - CHECK(Scheduler::instance()); - send_closure(option_manager(), &OptionManager::on_update_server_time_difference); + get_option_manager()->on_update_server_time_difference(); } } @@ -184,7 +180,7 @@ void Global::save_server_time() { } void Global::do_save_server_time_difference() { - if (shared_config_ != nullptr && shared_config_->get_option_boolean("disable_time_adjustment_protection")) { + if (get_option_boolean("disable_time_adjustment_protection")) { td_db()->get_binlog_pmc()->erase("server_time_difference"); return; } @@ -223,8 +219,7 @@ double Global::get_dns_time_difference() const { } DcId Global::get_webfile_dc_id() const { - CHECK(shared_config_ != nullptr); - auto dc_id = narrow_cast(shared_config_->get_option_integer("webfile_dc_id")); + auto dc_id = narrow_cast(get_option_integer("webfile_dc_id")); if (!DcId::is_valid(dc_id)) { if (is_test_dc()) { dc_id = 2; @@ -239,8 +234,7 @@ DcId Global::get_webfile_dc_id() const { } bool Global::ignore_background_updates() const { - return !parameters_.use_file_db && !parameters_.use_secret_chats && - shared_config_->get_option_boolean("ignore_background_updates"); + return !parameters_.use_file_db && !parameters_.use_secret_chats && get_option_boolean("ignore_background_updates"); } void Global::set_net_query_stats(std::shared_ptr net_query_stats) { @@ -252,8 +246,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_ != nullptr); + return option_manager_; +} + +OptionManager *Global::get_option_manager() { + CHECK(option_manager_ != nullptr); + return option_manager_; +} + +void Global::set_option_empty(Slice name) { + get_option_manager()->set_option_empty(name); +} + +void Global::set_option_boolean(Slice name, bool value) { + get_option_manager()->set_option_boolean(name, value); +} + +void Global::set_option_integer(Slice name, int64 value) { + get_option_manager()->set_option_integer(name, value); +} + +void Global::set_option_string(Slice name, Slice value) { + get_option_manager()->set_option_string(name, value); +} + +bool Global::have_option(Slice name) const { + return get_option_manager()->have_option(name); +} + +bool Global::get_option_boolean(Slice name, bool default_value) const { + return get_option_manager()->get_option_boolean(name, default_value); +} + +int64 Global::get_option_integer(Slice name, int64 default_value) const { + return get_option_manager()->get_option_integer(name, default_value); +} + +string Global::get_option_string(Slice name, string default_value) const { + 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 c5cf59bf2..949a62da0 100644 --- a/td/telegram/Global.h +++ b/td/telegram/Global.h @@ -33,10 +33,10 @@ namespace td { class AnimationsManager; class AttachMenuManager; +class AuthManager; class BackgroundManager; class CallManager; class ConfigManager; -class ConfigShared; class ConnectionCreator; class ContactsManager; class DownloadManager; @@ -178,12 +178,21 @@ 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); - ConfigShared &shared_config() { - CHECK(shared_config_.get() != nullptr); - return *shared_config_; - } + void set_option_boolean(Slice name, bool value); + + 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; bool is_server_time_reliable() const { return server_time_difference_was_updated_; @@ -241,6 +250,10 @@ class Global final : public ActorContext { attach_menu_manager_ = attach_menu_manager; } + void set_auth_manager(ActorId auth_manager) { + auth_manager_ = auth_manager; + } + ActorId background_manager() const { return background_manager_; } @@ -339,10 +352,7 @@ class Global final : public ActorContext { notification_settings_manager_ = notification_settings_manager; } - ActorId option_manager() const { - return option_manager_; - } - void set_option_manager(ActorId option_manager) { + void set_option_manager(OptionManager *option_manager) { option_manager_ = option_manager; } @@ -432,13 +442,6 @@ class Global final : public ActorContext { return parameters_; } - int64 get_my_id() const { - return my_id_; - } - void set_my_id(int64 my_id) { - my_id_ = my_id; - } - int32 get_gc_scheduler_id() const { return gc_scheduler_id_; } @@ -521,6 +524,7 @@ class Global final : public ActorContext { ActorId td_; ActorId animations_manager_; ActorId attach_menu_manager_; + ActorId auth_manager_; ActorId background_manager_; ActorId call_manager_; ActorId config_manager_; @@ -535,7 +539,6 @@ class Global final : public ActorContext { ActorId messages_manager_; ActorId notification_manager_; ActorId notification_settings_manager_; - ActorId option_manager_; ActorId password_manager_; ActorId secret_chats_manager_; ActorId sponsored_message_manager_; @@ -551,6 +554,8 @@ class Global final : public ActorContext { unique_ptr mtproto_header_; + OptionManager *option_manager_ = nullptr; + TdParameters parameters_; int32 gc_scheduler_id_ = 0; int32 slow_net_scheduler_id_ = 0; @@ -577,16 +582,16 @@ 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); FlatHashMap location_access_hashes_; 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/InlineQueriesManager.cpp b/td/telegram/InlineQueriesManager.cpp index f2de3067f..523d1965b 100644 --- a/td/telegram/InlineQueriesManager.cpp +++ b/td/telegram/InlineQueriesManager.cpp @@ -354,7 +354,8 @@ Result> InlineQueriesManager: auto constructor_id = input_message_content->get_id(); if (constructor_id == td_api::inputMessageText::ID) { - TRY_RESULT(input_message_text, process_input_message_text(td_, DialogId(), std::move(input_message_content), true)); + TRY_RESULT(input_message_text, process_input_message_text(td_, DialogId(td_->contacts_manager_->get_my_id()), + std::move(input_message_content), true)); int32 flags = 0; if (input_reply_markup != nullptr) { flags |= telegram_api::inputBotInlineMessageText::REPLY_MARKUP_MASK; @@ -401,8 +402,8 @@ Result> InlineQueriesManager: return venue.get_input_bot_inline_message_media_venue(std::move(input_reply_markup)); } if (constructor_id == allowed_media_content_id) { - TRY_RESULT(caption, process_input_caption(td_->contacts_manager_.get(), DialogId(), - extract_input_caption(input_message_content), true)); + TRY_RESULT(caption, get_formatted_text(td_, DialogId(td_->contacts_manager_->get_my_id()), + extract_input_caption(input_message_content), true, true, true, false)); int32 flags = 0; if (input_reply_markup != nullptr) { flags |= telegram_api::inputBotInlineMessageMediaAuto::REPLY_MARKUP_MASK; diff --git a/td/telegram/InputMessageText.cpp b/td/telegram/InputMessageText.cpp index 2afda69ee..843a3a3e8 100644 --- a/td/telegram/InputMessageText.cpp +++ b/td/telegram/InputMessageText.cpp @@ -6,10 +6,7 @@ // #include "td/telegram/InputMessageText.h" -#include "td/telegram/ConfigShared.h" -#include "td/telegram/Global.h" #include "td/telegram/MessageEntity.h" -#include "td/telegram/Td.h" #include "td/utils/common.h" @@ -30,31 +27,10 @@ Result process_input_message_text(const Td *td, DialogId dialo CHECK(input_message_content != nullptr); CHECK(input_message_content->get_id() == td_api::inputMessageText::ID); auto input_message_text = static_cast(input_message_content.get()); - if (input_message_text->text_ == nullptr) { - if (for_draft) { - return InputMessageText{FormattedText(), input_message_text->disable_web_page_preview_, - input_message_text->clear_draft_}; - } - - return Status::Error(400, "Message text can't be empty"); - } - - TRY_RESULT(entities, - get_message_entities(td->contacts_manager_.get(), std::move(input_message_text->text_->entities_))); - auto need_skip_bot_commands = need_always_skip_bot_commands(td->contacts_manager_.get(), dialog_id, is_bot); - bool parse_markdown = G()->shared_config().get_option_boolean("always_parse_markdown"); - TRY_STATUS(fix_formatted_text(input_message_text->text_->text_, entities, for_draft, parse_markdown, - need_skip_bot_commands, is_bot || for_draft || parse_markdown, for_draft)); - InputMessageText result{FormattedText{std::move(input_message_text->text_->text_), std::move(entities)}, - input_message_text->disable_web_page_preview_, input_message_text->clear_draft_}; - if (parse_markdown) { - result.text = parse_markdown_v3(std::move(result.text)); - fix_formatted_text(result.text.text, result.text.entities, for_draft, false, need_skip_bot_commands, - is_bot || for_draft, for_draft) - .ensure(); - } - remove_unallowed_entities(td, result.text, dialog_id); - return std::move(result); + TRY_RESULT(text, get_formatted_text(td, dialog_id, std::move(input_message_text->text_), is_bot, for_draft, for_draft, + for_draft)); + return InputMessageText{std::move(text), input_message_text->disable_web_page_preview_, + input_message_text->clear_draft_}; } // used only for draft diff --git a/td/telegram/LanguagePackManager.cpp b/td/telegram/LanguagePackManager.cpp index a1268dca2..19122457d 100644 --- a/td/telegram/LanguagePackManager.cpp +++ b/td/telegram/LanguagePackManager.cpp @@ -6,7 +6,6 @@ // #include "td/telegram/LanguagePackManager.h" -#include "td/telegram/ConfigShared.h" #include "td/telegram/Global.h" #include "td/telegram/logevent/LogEvent.h" #include "td/telegram/misc.h" @@ -64,7 +63,7 @@ struct LanguagePackManager::Language { FlatHashMap ordinary_strings_; FlatHashMap> pluralized_strings_; FlatHashSet deleted_strings_; - SqliteKeyValue kv_; // usages should be guarded by database_->mutex_ + SqliteKeyValue kv_; // usages must be guarded by database_->mutex_ }; struct LanguagePackManager::LanguageInfo { @@ -91,7 +90,7 @@ struct LanguagePackManager::LanguageInfo { struct LanguagePackManager::LanguagePack { std::mutex mutex_; - SqliteKeyValue pack_kv_; // usages should be guarded by database_->mutex_ + SqliteKeyValue pack_kv_; // usages must be guarded by database_->mutex_ std::map custom_language_pack_infos_; // sorted by language_code vector> server_language_pack_infos_; // sorted by server FlatHashMap> all_server_language_pack_infos_; @@ -199,21 +198,17 @@ LanguagePackManager::LanguageDatabase *LanguagePackManager::add_language_databas return it->second.get(); } -void LanguagePackManager::start_up() { +LanguagePackManager::LanguagePackManager(ActorShared<> parent) : parent_(std::move(parent)) { std::lock_guard database_lock(language_database_mutex_); manager_count_++; - language_pack_ = G()->shared_config().get_option_string("localization_target"); - language_code_ = G()->shared_config().get_option_string("language_pack_id"); + language_pack_ = G()->get_option_string("localization_target"); + language_code_ = G()->get_option_string("language_pack_id"); CHECK(check_language_pack_name(language_pack_)); CHECK(check_language_code_name(language_code_)); - database_ = add_language_database(G()->shared_config().get_option_string("language_pack_database_path")); + database_ = add_language_database(G()->get_option_string("language_pack_database_path")); if (!language_pack_.empty() && !language_code_.empty()) { auto language = add_language(database_, language_pack_, language_code_); - if (language->version_ == -1) { - load_empty_language_pack(language_code_); - } - repair_chosen_language_info(); std::lock_guard language_lock(language->mutex_); base_language_code_ = language->base_language_code_; @@ -222,10 +217,7 @@ void LanguagePackManager::start_up() { base_language_code_.clear(); } if (!base_language_code_.empty()) { - auto base_language = add_language(database_, language_pack_, base_language_code_); - if (base_language->version_ == -1) { - load_empty_language_pack(base_language_code_); - } + add_language(database_, language_pack_, base_language_code_); } LOG(INFO) << "Use localization target \"" << language_pack_ << "\" with language pack \"" << language_code_ @@ -234,6 +226,30 @@ void LanguagePackManager::start_up() { } } +void LanguagePackManager::start_up() { + if (language_pack_.empty() || language_code_.empty()) { + return; + } + + auto language = get_language(database_, language_pack_, language_code_); + CHECK(language != nullptr); + if (language->version_ == -1) { + load_empty_language_pack(language_code_); + } + repair_chosen_language_info(); + + if (!base_language_code_.empty()) { + auto base_language = get_language(database_, language_pack_, base_language_code_); + CHECK(base_language != nullptr); + if (base_language->version_ == -1) { + load_empty_language_pack(base_language_code_); + } + } + + on_language_pack_version_changed(false, -1); + on_language_pack_version_changed(true, -1); +} + void LanguagePackManager::tear_down() { if (ExitGuard::is_exited()) { return; @@ -241,7 +257,7 @@ void LanguagePackManager::tear_down() { std::lock_guard lock(language_database_mutex_); manager_count_--; if (manager_count_ == 0) { - // can't clear language packs, because they may be accessed later using synchronous requests + // can't clear language packs, because they can be accessed later using synchronous requests // LOG(INFO) << "Clear language packs"; // language_databases_.clear(); } @@ -339,7 +355,7 @@ vector LanguagePackManager::get_used_language_codes() { } void LanguagePackManager::on_language_pack_changed() { - auto new_language_pack = G()->shared_config().get_option_string("localization_target"); + auto new_language_pack = G()->get_option_string("localization_target"); if (new_language_pack == language_pack_) { return; } @@ -350,7 +366,7 @@ void LanguagePackManager::on_language_pack_changed() { } void LanguagePackManager::on_language_code_changed() { - auto new_language_code = G()->shared_config().get_option_string("language_pack_id"); + auto new_language_code = G()->get_option_string("language_pack_id"); if (new_language_code == language_code_) { return; } @@ -365,16 +381,17 @@ void LanguagePackManager::on_language_pack_version_changed(bool is_base, int32 n return; } - LOG(INFO) << (is_base ? "Base" : "Main") << " language pack vesrion has changed to " << new_version; Language *language = get_language(database_, language_pack_, language_code_); int32 version = language == nullptr ? static_cast(-1) : language->version_.load(); + LOG(INFO) << (is_base ? "Base" : "Main") << " language pack vesrion has changed from main " << version << " to " + << new_version; if (version == -1) { return load_empty_language_pack(language_code_); } if (new_version < 0) { Slice version_key = is_base ? Slice("base_language_pack_version") : Slice("language_pack_version"); - new_version = narrow_cast(G()->shared_config().get_option_integer(version_key, -1)); + new_version = narrow_cast(G()->get_option_integer(version_key, -1)); } if (new_version <= 0) { return; @@ -495,8 +512,8 @@ void LanguagePackManager::on_update_language_pack(tl_object_ptrshared_config().set_option_empty("language_pack_version"); - G()->shared_config().set_option_empty("base_language_pack_version"); + G()->set_option_empty("language_pack_version"); + G()->set_option_empty("base_language_pack_version"); if (!language_pack_.empty() && !language_code_.empty()) { LOG(INFO) << "Add main language " << language_code_; @@ -946,7 +963,7 @@ void LanguagePackManager::on_get_language_info(const string &language_pack, } } if (was_updated_base_language_code) { - G()->shared_config().set_option_empty("base_language_pack_version"); + G()->set_option_empty("base_language_pack_version"); if (!base_language_code_.empty()) { add_language(database_, language_pack_, base_language_code_); on_language_pack_version_changed(true, std::numeric_limits::max()); diff --git a/td/telegram/LanguagePackManager.h b/td/telegram/LanguagePackManager.h index 973d8d3b1..fa2e22752 100644 --- a/td/telegram/LanguagePackManager.h +++ b/td/telegram/LanguagePackManager.h @@ -29,8 +29,7 @@ class SqliteKeyValue; class LanguagePackManager final : public NetQueryCallback { public: - explicit LanguagePackManager(ActorShared<> parent) : parent_(std::move(parent)) { - } + explicit LanguagePackManager(ActorShared<> parent); LanguagePackManager(const LanguagePackManager &) = delete; LanguagePackManager &operator=(const LanguagePackManager &) = delete; LanguagePackManager(LanguagePackManager &&) = delete; diff --git a/td/telegram/LinkManager.cpp b/td/telegram/LinkManager.cpp index 25e777381..6886df6ec 100644 --- a/td/telegram/LinkManager.cpp +++ b/td/telegram/LinkManager.cpp @@ -10,7 +10,6 @@ #include "td/telegram/ChannelId.h" #include "td/telegram/ChannelType.h" #include "td/telegram/ConfigManager.h" -#include "td/telegram/ConfigShared.h" #include "td/telegram/ContactsManager.h" #include "td/telegram/DialogId.h" #include "td/telegram/DialogParticipant.h" @@ -254,8 +253,7 @@ class LinkManager::InternalLinkBotStart final : public InternalLink { td_api::object_ptr get_internal_link_type_object() const final { bool autostart = autostart_; - if (Scheduler::context() != nullptr && - bot_username_ == G()->shared_config().get_option_string("premium_bot_username")) { + if (Scheduler::context() != nullptr && bot_username_ == G()->get_option_string("premium_bot_username")) { autostart = true; } return td_api::make_object(bot_username_, start_parameter_, autostart); @@ -889,7 +887,7 @@ LinkManager::LinkInfo LinkManager::get_link_info(Slice link) { vector t_me_urls{Slice("t.me"), Slice("telegram.me"), Slice("telegram.dog")}; if (Scheduler::context() != nullptr) { // for tests only - string cur_t_me_url = G()->shared_config().get_option_string("t_me_url"); + string cur_t_me_url = G()->get_option_string("t_me_url"); if (tolower_begins_with(cur_t_me_url, "http://") || tolower_begins_with(cur_t_me_url, "https://")) { Slice t_me_url = cur_t_me_url; t_me_url = t_me_url.substr(t_me_url[4] == 's' ? 8 : 7); @@ -1570,7 +1568,7 @@ string LinkManager::get_dialog_invite_link(Slice hash, bool is_internal) { if (is_internal) { return PSTRING() << "tg:join?invite=" << hash; } else { - return PSTRING() << G()->shared_config().get_option_string("t_me_url", "https://t.me/") << '+' << hash; + return PSTRING() << G()->get_option_string("t_me_url", "https://t.me/") << '+' << hash; } } diff --git a/td/telegram/MessageContent.cpp b/td/telegram/MessageContent.cpp index 5fdd0c896..d7a4d6047 100644 --- a/td/telegram/MessageContent.cpp +++ b/td/telegram/MessageContent.cpp @@ -14,7 +14,6 @@ #include "td/telegram/CallDiscardReason.h" #include "td/telegram/ChannelId.h" #include "td/telegram/ChatId.h" -#include "td/telegram/ConfigShared.h" #include "td/telegram/Contact.h" #include "td/telegram/ContactsManager.h" #include "td/telegram/Dependencies.h" @@ -44,6 +43,7 @@ #include "td/telegram/MessageSender.h" #include "td/telegram/misc.h" #include "td/telegram/net/DcId.h" +#include "td/telegram/OptionManager.h" #include "td/telegram/Payments.h" #include "td/telegram/Payments.hpp" #include "td/telegram/Photo.h" @@ -1630,12 +1630,12 @@ InlineMessageContent create_inline_message_content(Td *td, FileId file_id, } result.disable_web_page_preview = inline_message->no_webpage_; + FormattedText text{std::move(inline_message->message_), std::move(entities)}; WebPageId web_page_id; if (!result.disable_web_page_preview) { - web_page_id = td->web_pages_manager_->get_web_page_by_url(get_first_url(inline_message->message_, entities)); + web_page_id = td->web_pages_manager_->get_web_page_by_url(get_first_url(text)); } - result.message_content = make_unique( - FormattedText{std::move(inline_message->message_), std::move(entities)}, web_page_id); + result.message_content = make_unique(std::move(text), web_page_id); reply_markup = std::move(inline_message->reply_markup_); break; } @@ -1772,8 +1772,7 @@ static Result create_input_message_content( dialog_id.get_type() != DialogType::Channel || td->contacts_manager_->get_channel_permissions(dialog_id.get_channel_id()).can_add_web_page_previews(); if (!is_bot && !disable_web_page_preview && can_add_web_page_previews) { - web_page_id = td->web_pages_manager_->get_web_page_by_url( - get_first_url(input_message_text.text.text, input_message_text.text.entities)); + web_page_id = td->web_pages_manager_->get_web_page_by_url(get_first_url(input_message_text.text)); } content = make_unique(std::move(input_message_text.text), web_page_id); break; @@ -2018,7 +2017,7 @@ static Result create_input_message_content( return Status::Error(400, "Wrong correct option ID specified"); } auto r_explanation = - process_input_caption(td->contacts_manager_.get(), dialog_id, std::move(type->explanation_), is_bot); + get_formatted_text(td, dialog_id, std::move(type->explanation_), is_bot, true, true, false); if (r_explanation.is_error()) { return r_explanation.move_as_error(); } @@ -2159,8 +2158,8 @@ Result get_input_message_content( } } - TRY_RESULT(caption, process_input_caption(td->contacts_manager_.get(), dialog_id, - extract_input_caption(input_message_content), td->auth_manager_->is_bot())); + TRY_RESULT(caption, get_formatted_text(td, dialog_id, extract_input_caption(input_message_content), + td->auth_manager_->is_bot(), true, false, false)); return create_input_message_content(dialog_id, std::move(input_message_content), td, std::move(caption), file_id, std::move(thumbnail), std::move(sticker_file_ids), is_premium); } @@ -4674,7 +4673,7 @@ unique_ptr dup_message_content(Td *td, DialogId dialog_id, const } case MessageContentType::Sticker: { auto result = make_unique(*static_cast(content)); - result->is_premium = G()->shared_config().get_option_boolean("is_premium"); + result->is_premium = td->option_manager_->get_option_boolean("is_premium"); if (td->stickers_manager_->has_input_media(result->file_id, to_secret)) { return std::move(result); } @@ -5973,20 +5972,21 @@ void update_used_hashtags(Td *td, const MessageContent *content) { const unsigned char *ptr = Slice(text->text).ubegin(); const unsigned char *end = Slice(text->text).uend(); int32 utf16_pos = 0; + uint32 skipped_code = 0; for (auto &entity : text->entities) { if (entity.type != MessageEntity::Type::Hashtag) { continue; } while (utf16_pos < entity.offset && ptr < end) { utf16_pos += 1 + (ptr[0] >= 0xf0); - ptr = next_utf8_unsafe(ptr, nullptr, "update_used_hashtags"); + ptr = next_utf8_unsafe(ptr, &skipped_code); } CHECK(utf16_pos == entity.offset); auto from = ptr; while (utf16_pos < entity.offset + entity.length && ptr < end) { utf16_pos += 1 + (ptr[0] >= 0xf0); - ptr = next_utf8_unsafe(ptr, nullptr, "update_used_hashtags 2"); + ptr = next_utf8_unsafe(ptr, &skipped_code); } CHECK(utf16_pos == entity.offset + entity.length); auto to = ptr; diff --git a/td/telegram/MessageEntity.cpp b/td/telegram/MessageEntity.cpp index 3741b908f..efbde7ecd 100644 --- a/td/telegram/MessageEntity.cpp +++ b/td/telegram/MessageEntity.cpp @@ -6,11 +6,11 @@ // #include "td/telegram/MessageEntity.h" -#include "td/telegram/ConfigShared.h" #include "td/telegram/ContactsManager.h" #include "td/telegram/Dependencies.h" #include "td/telegram/LinkManager.h" #include "td/telegram/misc.h" +#include "td/telegram/OptionManager.h" #include "td/telegram/SecretChatLayer.h" #include "td/telegram/StickersManager.h" #include "td/telegram/Td.h" @@ -21,6 +21,7 @@ #include "td/utils/format.h" #include "td/utils/logging.h" #include "td/utils/misc.h" +#include "td/utils/Promise.h" #include "td/utils/SliceBuilder.h" #include "td/utils/unicode.h" #include "td/utils/utf8.h" @@ -261,7 +262,7 @@ static vector match_mentions(Slice str) { if (ptr != begin) { uint32 prev; - next_utf8_unsafe(prev_utf8_unsafe(ptr), &prev, "match_mentions"); + next_utf8_unsafe(prev_utf8_unsafe(ptr), &prev); if (is_word_character(prev)) { ptr++; @@ -279,7 +280,7 @@ static vector match_mentions(Slice str) { } uint32 next = 0; if (ptr != end) { - next_utf8_unsafe(ptr, &next, "match_mentions 2"); + next_utf8_unsafe(ptr, &next); } if (is_word_character(next)) { continue; @@ -305,7 +306,7 @@ static vector match_bot_commands(Slice str) { if (ptr != begin) { uint32 prev; - next_utf8_unsafe(prev_utf8_unsafe(ptr), &prev, "match_bot_commands"); + next_utf8_unsafe(prev_utf8_unsafe(ptr), &prev); if (is_word_character(prev) || prev == '/' || prev == '<' || prev == '>') { ptr++; @@ -338,7 +339,7 @@ static vector match_bot_commands(Slice str) { uint32 next = 0; if (ptr != end) { - next_utf8_unsafe(ptr, &next, "match_bot_commands 2"); + next_utf8_unsafe(ptr, &next); } if (is_word_character(next) || next == '/' || next == '<' || next == '>') { continue; @@ -381,7 +382,7 @@ static vector match_hashtags(Slice str) { if (ptr != begin) { uint32 prev; - next_utf8_unsafe(prev_utf8_unsafe(ptr), &prev, "match_hashtags"); + next_utf8_unsafe(prev_utf8_unsafe(ptr), &prev); if (is_hashtag_letter(prev, category)) { ptr++; @@ -394,7 +395,7 @@ static vector match_hashtags(Slice str) { bool was_letter = false; while (ptr != end) { uint32 code; - auto next_ptr = next_utf8_unsafe(ptr, &code, "match_hashtags 2"); + auto next_ptr = next_utf8_unsafe(ptr, &code); if (!is_hashtag_letter(code, category)) { break; } @@ -442,7 +443,7 @@ static vector match_cashtags(Slice str) { if (ptr != begin) { uint32 prev; - next_utf8_unsafe(prev_utf8_unsafe(ptr), &prev, "match_cashtags"); + next_utf8_unsafe(prev_utf8_unsafe(ptr), &prev); if (is_hashtag_letter(prev, category) || prev == '$') { ptr++; @@ -466,7 +467,7 @@ static vector match_cashtags(Slice str) { if (cashtag_end != end) { uint32 code; - next_utf8_unsafe(ptr, &code, "match_cashtags 2"); + next_utf8_unsafe(ptr, &code); if (is_hashtag_letter(code, category) || code == '$') { continue; } @@ -505,7 +506,7 @@ static vector match_media_timestamps(Slice str) { if (media_timestamp_begin != begin) { uint32 prev; - next_utf8_unsafe(prev_utf8_unsafe(media_timestamp_begin), &prev, "match_media_timestamps 1"); + next_utf8_unsafe(prev_utf8_unsafe(media_timestamp_begin), &prev); if (is_word_character(prev)) { continue; @@ -513,7 +514,7 @@ static vector match_media_timestamps(Slice str) { } if (media_timestamp_end != end) { uint32 next; - next_utf8_unsafe(media_timestamp_end, &next, "match_media_timestamps 2"); + next_utf8_unsafe(media_timestamp_end, &next); if (is_word_character(next)) { continue; @@ -545,7 +546,7 @@ static vector match_bank_card_numbers(Slice str) { } if (ptr != begin) { uint32 prev; - next_utf8_unsafe(prev_utf8_unsafe(ptr), &prev, "match_bank_card_numbers"); + next_utf8_unsafe(prev_utf8_unsafe(ptr), &prev); if (prev == '.' || prev == ',' || prev == '+' || prev == '-' || prev == '_' || get_unicode_simple_category(prev) == UnicodeSimpleCategory::Letter) { @@ -581,7 +582,7 @@ static vector match_bank_card_numbers(Slice str) { } if (card_number_end != end) { uint32 next; - next_utf8_unsafe(card_number_end, &next, "match_bank_card_numbers 2"); + next_utf8_unsafe(card_number_end, &next); if (next == '-' || next == '_' || get_unicode_simple_category(next) == UnicodeSimpleCategory::Letter) { continue; } @@ -656,7 +657,7 @@ static vector match_tg_urls(Slice str) { auto path_end_ptr = ptr + 1; while (path_end_ptr != end) { uint32 code = 0; - auto next_ptr = next_utf8_unsafe(path_end_ptr, &code, "match_tg_urls"); + auto next_ptr = next_utf8_unsafe(path_end_ptr, &code); if (!is_url_path_symbol(code)) { break; } @@ -738,7 +739,7 @@ static vector match_urls(Slice str) { while (domain_begin_ptr != begin) { domain_begin_ptr = prev_utf8_unsafe(domain_begin_ptr); uint32 code = 0; - auto next_ptr = next_utf8_unsafe(domain_begin_ptr, &code, "match_urls 0"); + auto next_ptr = next_utf8_unsafe(domain_begin_ptr, &code); if (!is_domain_symbol(code)) { domain_begin_ptr = next_ptr; break; @@ -747,25 +748,12 @@ static vector match_urls(Slice str) { const unsigned char *last_at_ptr = nullptr; const unsigned char *domain_end_ptr = begin + dot_pos; - if (domain_begin_ptr == begin || domain_begin_ptr[-1] != '@') { - // try to find '@' to the right if there is no '@' to the left - while (domain_end_ptr != end) { - uint32 code = 0; - auto next_ptr = next_utf8_unsafe(domain_end_ptr, &code, "match_urls"); - if (code == '@') { - last_at_ptr = domain_end_ptr; - } - if (!is_user_data_symbol(code)) { - break; - } - domain_end_ptr = next_ptr; - } - domain_end_ptr = last_at_ptr == nullptr ? begin + dot_pos : last_at_ptr + 1; - } while (domain_end_ptr != end) { uint32 code = 0; - auto next_ptr = next_utf8_unsafe(domain_end_ptr, &code, "match_urls 2"); - if (!is_domain_symbol(code)) { + auto next_ptr = next_utf8_unsafe(domain_end_ptr, &code); + if (code == '@') { + last_at_ptr = domain_end_ptr; + } else if (!is_domain_symbol(code)) { break; } domain_end_ptr = next_ptr; @@ -775,7 +763,7 @@ static vector match_urls(Slice str) { while (domain_begin_ptr != begin) { domain_begin_ptr = prev_utf8_unsafe(domain_begin_ptr); uint32 code = 0; - auto next_ptr = next_utf8_unsafe(domain_begin_ptr, &code, "match_urls 3"); + auto next_ptr = next_utf8_unsafe(domain_begin_ptr, &code); if (!is_user_data_symbol(code)) { domain_begin_ptr = next_ptr; break; @@ -807,7 +795,7 @@ static vector match_urls(Slice str) { auto path_end_ptr = url_end_ptr + 1; while (path_end_ptr != end) { uint32 code = 0; - auto next_ptr = next_utf8_unsafe(path_end_ptr, &code, "match_urls 4"); + auto next_ptr = next_utf8_unsafe(path_end_ptr, &code); if (!is_url_path_symbol(code)) { break; } @@ -835,7 +823,7 @@ static vector match_urls(Slice str) { while (user_data_begin_ptr != begin) { user_data_begin_ptr = prev_utf8_unsafe(user_data_begin_ptr); uint32 code = 0; - auto next_ptr = next_utf8_unsafe(user_data_begin_ptr, &code, "match_urls 5"); + auto next_ptr = next_utf8_unsafe(user_data_begin_ptr, &code); if (!is_user_data_symbol(code)) { user_data_begin_ptr = next_ptr; break; @@ -855,7 +843,7 @@ static vector match_urls(Slice str) { while (protocol_begin_ptr != begin) { protocol_begin_ptr = prev_utf8_unsafe(protocol_begin_ptr); uint32 code = 0; - auto next_ptr = next_utf8_unsafe(protocol_begin_ptr, &code, "match_urls 6"); + auto next_ptr = next_utf8_unsafe(protocol_begin_ptr, &code); if (!is_protocol_symbol(code)) { protocol_begin_ptr = next_ptr; break; @@ -875,7 +863,7 @@ static vector match_urls(Slice str) { auto prefix_end = prefix.uend(); auto prefix_back = prev_utf8_unsafe(prefix_end); uint32 code = 0; - next_utf8_unsafe(prefix_back, &code, "match_urls 7"); + next_utf8_unsafe(prefix_back, &code); if (is_word_character(code) || code == '/' || code == '#' || code == '@') { is_bad = true; } @@ -965,34 +953,31 @@ bool is_email_address(Slice str) { Slice userdata; Slice domain; std::tie(userdata, domain) = split(str, '@'); - vector userdata_parts; + if (domain.empty()) { + return false; + } + size_t prev = 0; + size_t userdata_part_count = 0; for (size_t i = 0; i < userdata.size(); i++) { if (userdata[i] == '.' || userdata[i] == '+') { - userdata_parts.push_back(userdata.substr(prev, i - prev)); - prev = i + 1; - } - } - userdata_parts.push_back(userdata.substr(prev)); - if (userdata_parts.size() >= 12) { - return false; - } - for (auto &part : userdata_parts) { - for (auto c : part) { - if (!is_alpha_digit_or_underscore_or_minus(c)) { + if (i - prev >= 27) { return false; } - } - } - if (userdata_parts.back().empty() || userdata_parts.back().size() >= 36) { - return false; - } - userdata_parts.pop_back(); - for (auto &part : userdata_parts) { - if (part.size() >= 27) { + userdata_part_count++; + prev = i + 1; + } else if (!is_alpha_digit_or_underscore_or_minus(userdata[i])) { return false; } } + userdata_part_count++; + if (userdata_part_count >= 12) { + return false; + } + auto last_part_length = userdata.size() - prev; + if (last_part_length == 0 || last_part_length >= 36) { + return false; + } vector domain_parts = full_split(domain, '.'); if (domain_parts.size() <= 1 || domain_parts.size() > 7) { @@ -1158,6 +1143,17 @@ static bool is_common_tld(Slice str) { "zippo", "zm", "zone", "zuerich", // comment for clang-format to prevent it from placing all strings on separate lines "zw"}); + bool is_lower = true; + for (auto c : str) { + if (static_cast(c - 'a') > 'z' - 'a') { + is_lower = false; + break; + } + } + if (is_lower) { + // fast path + return tlds.count(str) > 0; + } string str_lower = utf8_to_lower(str); if (str_lower != str && utf8_substr(Slice(str_lower), 1) == utf8_substr(str, 1)) { return false; @@ -1185,10 +1181,12 @@ static Slice fix_url(Slice str) { } domain.truncate(domain.rfind(':')); - string domain_lower = domain.str(); - to_lower_inplace(domain_lower); - if (domain_lower == "teiegram.org") { - return Slice(); + if (domain.size() == 12 && (domain[0] == 't' || domain[0] == 'T')) { + string domain_lower = domain.str(); + to_lower_inplace(domain_lower); + if (domain_lower == "teiegram.org") { + return Slice(); + } } int32 balance[3] = {0, 0, 0}; @@ -1224,42 +1222,44 @@ static Slice fix_url(Slice str) { } full_url.remove_suffix(path.size() - path_pos); - vector domain_parts = full_split(domain, '.'); - if (domain_parts.size() <= 1) { + size_t prev = 0; + size_t domain_part_count = 0; + bool has_non_digit = false; + bool is_ipv4 = true; + for (size_t i = 0; i <= domain.size(); i++) { + if (i == domain.size() || domain[i] == '.') { + auto part_size = i - prev; + if (part_size == 0 || part_size >= 64 || domain[i - 1] == '-') { + return Slice(); + } + if (is_ipv4) { + if (part_size > 3) { + is_ipv4 = false; + } + if (part_size == 3 && + (domain[prev] >= '3' || (domain[prev] == '2' && (domain[prev + 1] >= '6' || + (domain[prev + 1] == '5' && domain[prev + 2] >= '6'))))) { + is_ipv4 = false; + } + if (domain[prev] == '0' && part_size >= 2) { + is_ipv4 = false; + } + } + + domain_part_count++; + if (i != domain.size()) { + prev = i + 1; + } + } else if (!is_digit(domain[i])) { + is_ipv4 = false; + has_non_digit = true; + } + } + if (domain_part_count == 1) { return Slice(); } - bool is_ipv4 = domain_parts.size() == 4; - bool has_non_digit = false; - for (auto &part : domain_parts) { - if (part.empty() || part.size() >= 64) { - return Slice(); - } - if (part.back() == '-') { - return Slice(); - } - - if (!has_non_digit) { - if (part.size() > 3) { - is_ipv4 = false; - } - for (auto c : part) { - if (!is_digit(c)) { - is_ipv4 = false; - has_non_digit = true; - } - } - if (part.size() == 3 && - (part[0] >= '3' || (part[0] == '2' && (part[1] >= '6' || (part[1] == '5' && part[2] >= '6'))))) { - is_ipv4 = false; - } - if (part[0] == '0' && part.size() >= 2) { - is_ipv4 = false; - } - } - } - - if (is_ipv4) { + if (is_ipv4 && domain_part_count == 4) { return full_url; } @@ -1267,7 +1267,7 @@ static Slice fix_url(Slice str) { return Slice(); } - auto tld = domain_parts.back(); + auto tld = domain.substr(prev); if (utf8_length(tld) <= 1) { return Slice(); } @@ -1294,9 +1294,14 @@ static Slice fix_url(Slice str) { } } - domain_parts.pop_back(); - if (domain_parts.back().find('_') < domain_parts.back().size()) { - return Slice(); + CHECK(prev > 0); + prev--; + while (prev-- > 0) { + if (domain[prev] == '_') { + return Slice(); + } else if (domain[prev] == '.') { + break; + } } return full_url; @@ -1664,10 +1669,11 @@ static void fix_entity_offsets(Slice text, vector &entities) { entity.offset = utf16_pos; } + uint32 skipped_code = 0; while (ptr != end && cnt > 0) { unsigned char c = ptr[0]; utf16_pos += 1 + (c >= 0xf0); - ptr = next_utf8_unsafe(ptr, nullptr, "fix_entity_offsets"); + ptr = next_utf8_unsafe(ptr, &skipped_code); pos = static_cast(ptr - begin); if (entity_begin == pos) { @@ -1774,8 +1780,8 @@ static bool is_plain_domain(Slice url) { return url.find('/') >= url.size() && url.find('?') >= url.size() && url.find('#') >= url.size(); } -string get_first_url(Slice text, const vector &entities) { - for (auto &entity : entities) { +string get_first_url(const FormattedText &text) { + for (auto &entity : text.entities) { switch (entity.type) { case MessageEntity::Type::Mention: break; @@ -1784,7 +1790,10 @@ string get_first_url(Slice text, const vector &entities) { case MessageEntity::Type::BotCommand: break; case MessageEntity::Type::Url: { - Slice url = utf8_utf16_substr(text, entity.offset, entity.length); + if (entity.length <= 4) { + continue; + } + Slice url = utf8_utf16_substr(text.text, entity.offset, entity.length); string scheme = to_lower(url.substr(0, 4)); if (scheme == "ton:" || begins_with(scheme, "tg:") || scheme == "ftp:" || is_plain_domain(url)) { continue; @@ -4287,15 +4296,32 @@ td_api::object_ptr extract_input_caption( } } -Result process_input_caption(const ContactsManager *contacts_manager, DialogId dialog_id, - tl_object_ptr &&caption, bool is_bot) { - if (caption == nullptr) { - return FormattedText(); +Result get_formatted_text(const Td *td, DialogId dialog_id, + td_api::object_ptr &&text, bool is_bot, + bool allow_empty, bool skip_media_timestamps, bool for_draft) { + if (text == nullptr) { + if (allow_empty) { + return FormattedText(); + } + + return Status::Error(400, "Text must be non-empty"); } - TRY_RESULT(entities, get_message_entities(contacts_manager, std::move(caption->entities_))); - TRY_STATUS(fix_formatted_text(caption->text_, entities, true, false, - need_always_skip_bot_commands(contacts_manager, dialog_id, is_bot), is_bot, false)); - return FormattedText{std::move(caption->text_), std::move(entities)}; + + TRY_RESULT(entities, get_message_entities(td->contacts_manager_.get(), std::move(text->entities_))); + auto need_skip_bot_commands = need_always_skip_bot_commands(td->contacts_manager_.get(), dialog_id, is_bot); + bool parse_markdown = td->option_manager_->get_option_boolean("always_parse_markdown"); + TRY_STATUS(fix_formatted_text(text->text_, entities, allow_empty, parse_markdown, need_skip_bot_commands, + is_bot || skip_media_timestamps || parse_markdown, for_draft)); + + FormattedText result{std::move(text->text_), std::move(entities)}; + if (parse_markdown) { + result = parse_markdown_v3(std::move(result)); + fix_formatted_text(result.text, result.entities, allow_empty, false, need_skip_bot_commands, + is_bot || skip_media_timestamps, for_draft) + .ensure(); + } + remove_unallowed_entities(td, result, dialog_id); + return std::move(result); } void add_formatted_text_dependencies(Dependencies &dependencies, const FormattedText *text) { @@ -4473,7 +4499,7 @@ void remove_unallowed_entities(const Td *td, FormattedText &text, DialogId dialo remove_intersecting_entities(text.entities); } } - if (!G()->shared_config().get_option_boolean("is_premium") && + if (!td->option_manager_->get_option_boolean("is_premium") && dialog_id != DialogId(td->contacts_manager_->get_my_id())) { remove_premium_custom_emoji_entities(td, text.entities, false); } diff --git a/td/telegram/MessageEntity.h b/td/telegram/MessageEntity.h index 8e85fa6c2..9fa0c59c4 100644 --- a/td/telegram/MessageEntity.h +++ b/td/telegram/MessageEntity.h @@ -170,7 +170,7 @@ vector> find_media_timestamps(Slice str); // slice + me void remove_empty_entities(vector &entities); -string get_first_url(Slice text, const vector &entities); +string get_first_url(const FormattedText &text); Result> parse_markdown(string &text); @@ -212,8 +212,9 @@ FormattedText get_message_text(const ContactsManager *contacts_manager, string m td_api::object_ptr extract_input_caption( tl_object_ptr &input_message_content); -Result process_input_caption(const ContactsManager *contacts_manager, DialogId dialog_id, - tl_object_ptr &&caption, bool is_bot); +Result get_formatted_text(const Td *td, DialogId dialog_id, + td_api::object_ptr &&text, bool is_bot, + bool allow_empty, bool skip_media_timestamps, bool for_draft); void add_formatted_text_dependencies(Dependencies &dependencies, const FormattedText *text); diff --git a/td/telegram/MessageReaction.cpp b/td/telegram/MessageReaction.cpp index 56692ca90..ca6a429c4 100644 --- a/td/telegram/MessageReaction.cpp +++ b/td/telegram/MessageReaction.cpp @@ -7,14 +7,19 @@ #include "td/telegram/MessageReaction.h" #include "td/telegram/AccessRights.h" +#include "td/telegram/ConfigManager.h" #include "td/telegram/ContactsManager.h" #include "td/telegram/Global.h" #include "td/telegram/MessageSender.h" #include "td/telegram/MessagesManager.h" +#include "td/telegram/OptionManager.h" #include "td/telegram/ServerMessageId.h" +#include "td/telegram/StickersManager.h" #include "td/telegram/Td.h" #include "td/telegram/UpdatesManager.h" +#include "td/actor/actor.h" + #include "td/utils/algorithm.h" #include "td/utils/buffer.h" #include "td/utils/FlatHashSet.h" @@ -217,6 +222,46 @@ class GetMessageReactionsListQuery final : public Td::ResultHandler { } }; +class SetDefaultReactionQuery final : public Td::ResultHandler { + string reaction_; + + public: + void send(const string &reaction) { + reaction_ = reaction; + send_query(G()->net_query_creator().create(telegram_api::messages_setDefaultReaction(reaction))); + } + + void on_result(BufferSlice packet) final { + auto result_ptr = fetch_result(packet); + if (result_ptr.is_error()) { + return on_error(result_ptr.move_as_error()); + } + + if (!result_ptr.ok()) { + return on_error(Status::Error(400, "Receive false")); + } + + auto default_reaction = td_->option_manager_->get_option_string("default_reaction", "-"); + LOG(INFO) << "Successfully set reaction " << reaction_ << " as default, current default is " << default_reaction; + + if (default_reaction != reaction_) { + send_set_default_reaction_query(td_); + } else { + td_->option_manager_->set_option_empty("default_reaction_needs_sync"); + } + } + + void on_error(Status status) final { + if (G()->close_flag()) { + return; + } + + LOG(INFO) << "Failed to set default reaction: " << status; + td_->option_manager_->set_option_empty("default_reaction_needs_sync"); + send_closure(G()->config_manager(), &ConfigManager::reget_app_config, Promise()); + } +}; + void MessageReaction::add_recent_chooser_dialog_id(DialogId dialog_id) { recent_chooser_dialog_ids_.insert(recent_chooser_dialog_ids_.begin(), dialog_id); if (recent_chooser_dialog_ids_.size() > MAX_RECENT_CHOOSERS + 1) { @@ -545,4 +590,22 @@ void get_message_added_reactions(Td *td, FullMessageId full_message_id, string r ->send(full_message_id, std::move(reaction), std::move(offset), limit); } +void set_default_reaction(Td *td, string reaction, Promise &&promise) { + if (!td->stickers_manager_->is_active_reaction(reaction)) { + return promise.set_error(Status::Error(400, "Can't set incative reaction as default")); + } + + if (td->option_manager_->get_option_string("default_reaction", "-") != reaction) { + td->option_manager_->set_option_string("default_reaction", reaction); + if (!td->option_manager_->get_option_boolean("default_reaction_needs_sync")) { + td->option_manager_->set_option_boolean("default_reaction_needs_sync", true); + } + } + promise.set_value(Unit()); +} + +void send_set_default_reaction_query(Td *td) { + td->create_handler()->send(td->option_manager_->get_option_string("default_reaction")); +} + } // namespace td diff --git a/td/telegram/MessageReaction.h b/td/telegram/MessageReaction.h index a1380e2db..e46593921 100644 --- a/td/telegram/MessageReaction.h +++ b/td/telegram/MessageReaction.h @@ -180,4 +180,8 @@ void set_message_reaction(Td *td, FullMessageId full_message_id, string reaction void get_message_added_reactions(Td *td, FullMessageId full_message_id, string reaction, string offset, int32 limit, Promise> &&promise); +void set_default_reaction(Td *td, string reaction, Promise &&promise); + +void send_set_default_reaction_query(Td *td); + } // namespace td diff --git a/td/telegram/MessagesDb.cpp b/td/telegram/MessagesDb.cpp index 87a819201..e079426b3 100644 --- a/td/telegram/MessagesDb.cpp +++ b/td/telegram/MessagesDb.cpp @@ -736,7 +736,7 @@ class MessagesDbImpl final : public MessagesDbSyncInterface { for (auto ptr = query.ubegin(), end = query.uend(); ptr < end;) { uint32 code; auto code_ptr = ptr; - ptr = next_utf8_unsafe(ptr, &code, "prepare_query"); + ptr = next_utf8_unsafe(ptr, &code); if (is_word_character(code)) { if (!in_word) { in_word = true; diff --git a/td/telegram/MessagesManager.cpp b/td/telegram/MessagesManager.cpp index d047aa42c..9e094ed03 100644 --- a/td/telegram/MessagesManager.cpp +++ b/td/telegram/MessagesManager.cpp @@ -10,7 +10,6 @@ #include "td/telegram/ChainId.h" #include "td/telegram/ChannelType.h" #include "td/telegram/ChatId.h" -#include "td/telegram/ConfigShared.h" #include "td/telegram/ContactsManager.h" #include "td/telegram/Dependencies.h" #include "td/telegram/DialogActionBar.h" @@ -51,6 +50,7 @@ #include "td/telegram/NotificationSettingsManager.h" #include "td/telegram/NotificationSound.h" #include "td/telegram/NotificationType.h" +#include "td/telegram/OptionManager.h" #include "td/telegram/PollId.h" #include "td/telegram/PublicDialogType.h" #include "td/telegram/ReplyMarkup.h" @@ -3213,7 +3213,7 @@ class SendMessageQuery final : public Td::ResultHandler { std::move(reply_markup), std::move(entities), schedule_date, std::move(as_input_peer)), {{dialog_id, MessageContentType::Text}, {dialog_id, is_copy ? MessageContentType::Photo : MessageContentType::Text}}); - if (G()->shared_config().get_option_boolean("use_quick_ack")) { + if (td_->option_manager_->get_option_boolean("use_quick_ack")) { query->quick_ack_promise_ = PromiseCreator::lambda([random_id](Result result) { if (result.is_ok()) { send_closure(G()->messages_manager(), &MessagesManager::on_send_message_get_quick_ack, random_id); @@ -3284,7 +3284,7 @@ class StartBotQuery final : public Td::ResultHandler { auto query = G()->net_query_creator().create( telegram_api::messages_startBot(std::move(bot_input_user), std::move(input_peer), random_id, parameter), {{dialog_id, MessageContentType::Text}, {dialog_id, MessageContentType::Photo}}); - if (G()->shared_config().get_option_boolean("use_quick_ack")) { + if (td_->option_manager_->get_option_boolean("use_quick_ack")) { query->quick_ack_promise_ = PromiseCreator::lambda([random_id](Result result) { if (result.is_ok()) { send_closure(G()->messages_manager(), &MessagesManager::on_send_message_get_quick_ack, random_id); @@ -3526,7 +3526,7 @@ class SendMediaQuery final : public Td::ResultHandler { reply_to_message_id.get_server_message_id().get(), std::move(input_media), text, random_id, std::move(reply_markup), std::move(entities), schedule_date, std::move(as_input_peer)), {{dialog_id, content_type}, {dialog_id, is_copy ? MessageContentType::Text : content_type}}); - if (G()->shared_config().get_option_boolean("use_quick_ack") && was_uploaded_) { + if (td_->option_manager_->get_option_boolean("use_quick_ack") && was_uploaded_) { query->quick_ack_promise_ = PromiseCreator::lambda([random_id](Result result) { if (result.is_ok()) { send_closure(G()->messages_manager(), &MessagesManager::on_send_message_get_quick_ack, random_id); @@ -3890,7 +3890,7 @@ class ForwardMessagesQuery final : public Td::ResultHandler { false /*ignored*/, std::move(from_input_peer), MessagesManager::get_server_message_ids(message_ids), std::move(random_ids), std::move(to_input_peer), schedule_date, std::move(as_input_peer)), {{to_dialog_id, MessageContentType::Text}, {to_dialog_id, MessageContentType::Photo}}); - if (G()->shared_config().get_option_boolean("use_quick_ack")) { + if (td_->option_manager_->get_option_boolean("use_quick_ack")) { query->quick_ack_promise_ = PromiseCreator::lambda([random_ids = random_ids_](Result result) { if (result.is_ok()) { for (auto random_id : random_ids) { @@ -9453,6 +9453,7 @@ void MessagesManager::after_get_difference() { auto full_message_id = it.first; auto dialog_id = full_message_id.get_dialog_id(); auto message_id = full_message_id.get_message_id(); + auto old_message_id = it.second; CHECK(message_id.is_valid()); CHECK(message_id.is_server()); switch (dialog_id.get_type()) { @@ -9464,7 +9465,7 @@ void MessagesManager::after_get_difference() { // fallthrough case DialogType::User: case DialogType::Chat: { - if (!have_message_force({dialog_id, it.second}, "after get difference")) { + if (!have_message_force({dialog_id, old_message_id}, "after get difference")) { // The sent message has already been deleted by the user or sent to inaccessible channel. // The sent message may never be received, but we will need updateMessageId in case the message is received // to delete it from the server and not add to the chat. @@ -9475,7 +9476,7 @@ void MessagesManager::after_get_difference() { if (!have_input_peer(dialog_id, AccessRights::Read) || (d != nullptr && message_id <= td::max(d->last_clear_history_message_id, d->max_unavailable_message_id))) { - update_message_ids_to_delete.push_back(it.first); + update_message_ids_to_delete.push_back(full_message_id); } break; } @@ -9483,22 +9484,20 @@ void MessagesManager::after_get_difference() { const Dialog *d = get_dialog(dialog_id); CHECK(d != nullptr); if (dialog_id.get_type() == DialogType::Channel || message_id <= d->last_new_message_id) { - LOG(ERROR) << "Receive updateMessageId from " << it.second << " to " << full_message_id + LOG(ERROR) << "Receive updateMessageId from " << old_message_id << " to " << full_message_id << " but not receive corresponding message, last_new_message_id = " << d->last_new_message_id; } if (dialog_id.get_type() != DialogType::Channel && message_id <= d->last_new_message_id) { dump_debug_message_op(get_dialog(dialog_id)); } if (message_id <= d->last_new_message_id) { - get_message_from_server(it.first, PromiseCreator::lambda([full_message_id](Result result) { - if (result.is_error()) { - LOG(WARNING) - << "Failed to get missing " << full_message_id << ": " << result.error(); - } else { - LOG(WARNING) << "Successfully get missing " << full_message_id; - } - }), - "get missing"); + get_message_from_server( + full_message_id, + PromiseCreator::lambda([actor_id = actor_id(this), full_message_id, old_message_id](Result result) { + send_closure(actor_id, &MessagesManager::on_restore_missing_message_after_get_difference, + full_message_id, old_message_id, std::move(result)); + }), + "get missing"); } else if (dialog_id.get_type() == DialogType::Channel) { LOG(INFO) << "Schedule getDifference in " << dialog_id.get_channel_id(); channel_get_difference_retry_timeout_.add_timeout_in(dialog_id.get(), 0.001); @@ -9534,6 +9533,41 @@ void MessagesManager::after_get_difference() { } } +void MessagesManager::on_restore_missing_message_after_get_difference(FullMessageId full_message_id, + MessageId old_message_id, Result result) { + if (result.is_error()) { + LOG(WARNING) << "Failed to get missing " << full_message_id << " for " << old_message_id << ": " << result.error(); + } else { + LOG(WARNING) << "Successfully get missing " << full_message_id << " for " << old_message_id; + + bool have_message = have_message_force(full_message_id, "on_restore_missing_message_after_get_difference"); + if (!have_message && update_message_ids_.count(full_message_id)) { + LOG(ERROR) << "Receive messageEmpty instead of missing " << full_message_id << " for " << old_message_id; + + auto dialog_id = full_message_id.get_dialog_id(); + Dialog *d = get_dialog(dialog_id); + CHECK(d != nullptr); + + bool need_update_dialog_pos = false; + vector deleted_message_ids; + auto m = delete_message(d, old_message_id, true, &need_update_dialog_pos, + "on_restore_missing_message_after_get_difference"); + if (m == nullptr) { + LOG(INFO) << "Can't delete " << old_message_id << " because it is not found"; + } else { + deleted_message_ids.push_back(m->message_id.get()); + } + + if (need_update_dialog_pos) { + send_update_chat_last_message(d, "on_restore_missing_message_after_get_difference"); + } + send_update_delete_messages(dialog_id, std::move(deleted_message_ids), true, false); + + update_message_ids_.erase(full_message_id); + } + } +} + void MessagesManager::on_get_empty_messages(DialogId dialog_id, const vector &empty_message_ids) { if (!empty_message_ids.empty()) { delete_dialog_messages(dialog_id, empty_message_ids, true, true, "on_get_empty_messages"); @@ -10781,9 +10815,9 @@ bool MessagesManager::can_revoke_message(DialogId dialog_id, const Message *m) c auto content_type = m->content->get_type(); switch (dialog_id.get_type()) { case DialogType::User: { - bool can_revoke_incoming = G()->shared_config().get_option_boolean("revoke_pm_inbox", true); + bool can_revoke_incoming = td_->option_manager_->get_option_boolean("revoke_pm_inbox", true); int64 revoke_time_limit = - G()->shared_config().get_option_integer("revoke_pm_time_limit", DEFAULT_REVOKE_TIME_LIMIT); + td_->option_manager_->get_option_integer("revoke_pm_time_limit", DEFAULT_REVOKE_TIME_LIMIT); if (G()->unix_time_cached() - m->date < 86400 && content_type == MessageContentType::Dice) { return false; @@ -10795,7 +10829,8 @@ bool MessagesManager::can_revoke_message(DialogId dialog_id, const Message *m) c case DialogType::Chat: { bool is_appointed_administrator = td_->contacts_manager_->is_appointed_chat_administrator(dialog_id.get_chat_id()); - int64 revoke_time_limit = G()->shared_config().get_option_integer("revoke_time_limit", DEFAULT_REVOKE_TIME_LIMIT); + int64 revoke_time_limit = + td_->option_manager_->get_option_integer("revoke_time_limit", DEFAULT_REVOKE_TIME_LIMIT); return ((m->is_outgoing && !is_service_message_content(content_type)) || is_appointed_administrator) && G()->unix_time_cached() - m->date <= revoke_time_limit; @@ -11133,7 +11168,7 @@ MessagesManager::CanDeleteDialog MessagesManager::can_delete_dialog(const Dialog td_->contacts_manager_->is_user_bot(d->dialog_id.get_user_id())) { return {true, false}; } - return {true, G()->shared_config().get_option_boolean("revoke_pm_inbox", true)}; + return {true, td_->option_manager_->get_option_boolean("revoke_pm_inbox", true)}; case DialogType::Chat: // chats can be deleted only for self and can be deleted for everyone by their creator return {true, td_->contacts_manager_->get_chat_status(d->dialog_id.get_chat_id()).is_creator()}; @@ -11671,7 +11706,7 @@ int32 MessagesManager::get_unload_dialog_delay() const { CHECK(is_message_unload_enabled()); auto default_unload_delay = td_->auth_manager_->is_bot() ? DIALOG_UNLOAD_BOT_DELAY : DIALOG_UNLOAD_DELAY; - return narrow_cast(G()->shared_config().get_option_integer("message_unload_delay", default_unload_delay)); + return narrow_cast(td_->option_manager_->get_option_integer("message_unload_delay", default_unload_delay)); } int32 MessagesManager::get_next_unload_dialog_delay() const { @@ -13270,7 +13305,7 @@ void MessagesManager::init() { if (is_authorized && td_->auth_manager_->is_bot()) { disable_get_dialog_filter_ = true; } - authorization_date_ = G()->shared_config().get_option_integer("authorization_date"); + authorization_date_ = td_->option_manager_->get_option_integer("authorization_date"); if (was_authorized_user) { auto dialog_filters = G()->td_db()->get_binlog_pmc()->get("dialog_filters"); @@ -13279,7 +13314,7 @@ void MessagesManager::init() { if (log_event_parse(log_event, dialog_filters).is_ok()) { server_main_dialog_list_position_ = log_event.server_main_dialog_list_position; main_dialog_list_position_ = log_event.main_dialog_list_position; - if (!G()->shared_config().get_option_boolean("is_premium") && + if (!td_->option_manager_->get_option_boolean("is_premium") && (server_main_dialog_list_position_ != 0 || main_dialog_list_position_ != 0)) { LOG(INFO) << "Ignore main chat list position " << server_main_dialog_list_position_ << '/' << main_dialog_list_position_; @@ -13671,7 +13706,7 @@ void MessagesManager::init() { void MessagesManager::on_authorization_success() { CHECK(td_->auth_manager_->is_authorized()); - authorization_date_ = G()->shared_config().get_option_integer("authorization_date"); + authorization_date_ = td_->option_manager_->get_option_integer("authorization_date"); if (td_->auth_manager_->is_bot()) { disable_get_dialog_filter_ = true; @@ -17350,7 +17385,7 @@ void MessagesManager::on_get_dialog_filters(Resultshared_config().get_option_boolean("is_premium")) { + if (server_main_dialog_list_position != 0 && !td_->option_manager_->get_option_boolean("is_premium")) { LOG(INFO) << "Ignore server main chat list position " << server_main_dialog_list_position; server_main_dialog_list_position = 0; } @@ -18385,7 +18420,8 @@ Status MessagesManager::can_get_message_viewers(DialogId dialog_id, const Messag if (!m->is_outgoing) { return Status::Error(400, "Can't get viewers of incoming messages"); } - if (G()->unix_time() - m->date > G()->shared_config().get_option_integer("chat_read_mark_expire_period", 7 * 86400)) { + if (G()->unix_time() - m->date > + td_->option_manager_->get_option_integer("chat_read_mark_expire_period", 7 * 86400)) { return Status::Error(400, "Message is too old"); } @@ -18418,7 +18454,7 @@ Status MessagesManager::can_get_message_viewers(DialogId dialog_id, const Messag if (participant_count == 0) { return Status::Error(400, "Chat is empty or have unknown number of members"); } - if (participant_count > G()->shared_config().get_option_integer("chat_read_mark_size_threshold", 100)) { + if (participant_count > td_->option_manager_->get_option_integer("chat_read_mark_size_threshold", 100)) { return Status::Error(400, "Chat is too big"); } @@ -18836,7 +18872,7 @@ Result> MessagesManager::get_message_link(FullMessageId } SliceBuilder sb; - sb << G()->shared_config().get_option_string("t_me_url", "https://t.me/"); + sb << td_->option_manager_->get_option_string("t_me_url", "https://t.me/"); if (for_comment) { auto *top_m = get_message_force(d, m->top_thread_message_id, "get_public_message_link"); @@ -19217,7 +19253,7 @@ Result> MessagesManager::create_dialog_filter(DialogFil void MessagesManager::create_dialog_filter(td_api::object_ptr filter, Promise> &&promise) { CHECK(!td_->auth_manager_->is_bot()); - auto max_dialog_filters = clamp(G()->shared_config().get_option_integer("chat_filter_count_max"), + auto max_dialog_filters = clamp(td_->option_manager_->get_option_integer("chat_filter_count_max"), static_cast(0), static_cast(100)); if (dialog_filters_.size() >= narrow_cast(max_dialog_filters)) { return promise.set_error(Status::Error(400, "The maximum number of chat folders exceeded")); @@ -19389,7 +19425,7 @@ void MessagesManager::reorder_dialog_filters(vector dialog_filte if (main_dialog_list_position < 0 || main_dialog_list_position > static_cast(dialog_filters_.size())) { return promise.set_error(Status::Error(400, "Invalid main chat list position specified")); } - if (!G()->shared_config().get_option_boolean("is_premium")) { + if (!td_->option_manager_->get_option_boolean("is_premium")) { main_dialog_list_position = 0; } @@ -19960,7 +19996,7 @@ void MessagesManager::clear_all_draft_messages(bool exclude_secret_chats, Promis td_->create_handler(std::move(promise))->send(); } -int32 MessagesManager::get_pinned_dialogs_limit(DialogListId dialog_list_id) { +int32 MessagesManager::get_pinned_dialogs_limit(DialogListId dialog_list_id) const { if (dialog_list_id.is_filter()) { return DialogFilter::get_max_filter_dialogs(); } @@ -19971,9 +20007,9 @@ int32 MessagesManager::get_pinned_dialogs_limit(DialogListId dialog_list_id) { key = Slice("pinned_archived_chat_count_max"); default_limit = 100; } - int32 limit = clamp(narrow_cast(G()->shared_config().get_option_integer(key)), 0, 1000); + int32 limit = clamp(narrow_cast(td_->option_manager_->get_option_integer(key)), 0, 1000); if (limit <= 0) { - if (G()->shared_config().get_option_boolean("is_premium")) { + if (td_->option_manager_->get_option_boolean("is_premium")) { default_limit *= 2; } return default_limit; @@ -22322,7 +22358,7 @@ td_api::object_ptr MessagesManager::get_dialog_message_ db_query.dialog_id = dialog_id; db_query.filter = filter; db_query.from_message_id = fixed_from_message_id; - db_query.tz_offset = static_cast(G()->shared_config().get_option_integer("utc_time_offset")); + db_query.tz_offset = static_cast(td_->option_manager_->get_option_integer("utc_time_offset")); G()->td_db()->get_messages_db_async()->get_dialog_message_calendar(db_query, std::move(new_promise)); return {}; } @@ -24424,8 +24460,8 @@ vector MessagesManager::get_message_available_reactions(const vector result; if (can_use_reactions) { - bool is_premium = G()->shared_config().get_option_boolean("is_premium"); - int64 reactions_uniq_max = G()->shared_config().get_option_integer("reactions_uniq_max", 11); + bool is_premium = td_->option_manager_->get_option_boolean("is_premium"); + int64 reactions_uniq_max = td_->option_manager_->get_option_integer("reactions_uniq_max", 11); bool can_add_new_reactions = m->reactions == nullptr || static_cast(m->reactions->reactions_.size()) < reactions_uniq_max; // can add only active available reactions or remove previously set reaction @@ -24978,7 +25014,7 @@ unique_ptr MessagesManager::create_message_to_send( m->is_copy = is_copy || m->forward_info != nullptr; if (td_->auth_manager_->is_bot() || options.disable_notification || - G()->shared_config().get_option_boolean("ignore_default_disable_notification")) { + td_->option_manager_->get_option_boolean("ignore_default_disable_notification")) { m->disable_notification = options.disable_notification; } else { m->disable_notification = d->notification_settings.silent_send_message; @@ -25123,7 +25159,8 @@ MessageId MessagesManager::get_reply_to_message_id(Dialog *d, MessageId top_thre } void MessagesManager::fix_server_reply_to_message_id(DialogId dialog_id, MessageId message_id, - DialogId reply_in_dialog_id, MessageId &reply_to_message_id) { + DialogId reply_in_dialog_id, + MessageId &reply_to_message_id) const { if (!reply_to_message_id.is_valid()) { if (reply_to_message_id.is_valid_scheduled()) { CHECK(message_id.is_scheduled()); @@ -25588,7 +25625,7 @@ Result MessagesManager::process_input_message_content( UserId(), copied_message->send_emoji); } - bool is_premium = G()->shared_config().get_option_boolean("is_premium"); + bool is_premium = td_->option_manager_->get_option_boolean("is_premium"); TRY_RESULT(content, get_input_message_content(dialog_id, std::move(input_message_content), td_, is_premium)); if (content.ttl < 0 || content.ttl > MAX_PRIVATE_MESSAGE_TTL) { @@ -25614,9 +25651,8 @@ Result MessagesManager::process_message_copy_options( result.send_copy = true; result.replace_caption = options->replace_caption_; if (result.replace_caption) { - TRY_RESULT_ASSIGN(result.new_caption, - process_input_caption(td_->contacts_manager_.get(), dialog_id, std::move(options->new_caption_), - td_->auth_manager_->is_bot())); + TRY_RESULT_ASSIGN(result.new_caption, get_formatted_text(td_, dialog_id, std::move(options->new_caption_), + td_->auth_manager_->is_bot(), true, false, false)); } return std::move(result); } @@ -26748,11 +26784,11 @@ void MessagesManager::do_send_inline_query_result_message(DialogId dialog_id, Me random_id, query_id, result_id); } -bool MessagesManager::has_qts_messages(DialogId dialog_id) { +bool MessagesManager::has_qts_messages(DialogId dialog_id) const { switch (dialog_id.get_type()) { case DialogType::User: case DialogType::Chat: - return G()->shared_config().get_option_integer("session_count") > 1; + return td_->option_manager_->get_option_integer("session_count") > 1; case DialogType::Channel: case DialogType::SecretChat: return false; @@ -26851,7 +26887,7 @@ bool MessagesManager::can_edit_message(DialogId dialog_id, const Message *m, boo if (has_edit_time_limit) { const int32 DEFAULT_EDIT_TIME_LIMIT = 2 * 86400; - int64 edit_time_limit = G()->shared_config().get_option_integer("edit_time_limit", DEFAULT_EDIT_TIME_LIMIT); + int64 edit_time_limit = td_->option_manager_->get_option_integer("edit_time_limit", DEFAULT_EDIT_TIME_LIMIT); if (G()->unix_time_cached() - m->date - (is_editing ? 300 : 0) >= edit_time_limit) { return false; } @@ -27366,8 +27402,8 @@ void MessagesManager::edit_message_caption(FullMessageId full_message_id, return promise.set_error(Status::Error(400, "There is no caption in the message to edit")); } - auto r_caption = process_input_caption(td_->contacts_manager_.get(), dialog_id, std::move(input_caption), - td_->auth_manager_->is_bot()); + auto r_caption = + get_formatted_text(td_, dialog_id, std::move(input_caption), td_->auth_manager_->is_bot(), true, false, false); if (r_caption.is_error()) { return promise.set_error(r_caption.move_as_error()); } @@ -27566,8 +27602,8 @@ void MessagesManager::edit_inline_message_caption(const string &inline_message_i return promise.set_error(Status::Error(400, "Method is available only for bots")); } - auto r_caption = process_input_caption(td_->contacts_manager_.get(), DialogId(), std::move(input_caption), - td_->auth_manager_->is_bot()); + auto r_caption = + get_formatted_text(td_, DialogId(), std::move(input_caption), td_->auth_manager_->is_bot(), true, false, false); if (r_caption.is_error()) { return promise.set_error(r_caption.move_as_error()); } @@ -29356,7 +29392,7 @@ Result MessagesManager::get_messag } if (is_from_scheduled && dialog_id != get_my_dialog_id() && - G()->shared_config().get_option_boolean("disable_sent_scheduled_message_notifications")) { + td_->option_manager_->get_option_boolean("disable_sent_scheduled_message_notifications")) { return Status::Error("Ignore notification about sent scheduled message"); } @@ -30219,7 +30255,7 @@ bool MessagesManager::is_message_notification_disabled(const Dialog *d, const Me return true; } if (m->is_from_scheduled && d->dialog_id != get_my_dialog_id() && - G()->shared_config().get_option_boolean("disable_sent_scheduled_message_notifications")) { + td_->option_manager_->get_option_boolean("disable_sent_scheduled_message_notifications")) { return true; } if (m->forward_info != nullptr && m->forward_info->is_imported) { @@ -30682,6 +30718,10 @@ void MessagesManager::send_update_delete_messages(DialogId dialog_id, vectormessages == nullptr); + if ((d->dialog_id.get_type() == DialogType::User || d->dialog_id.get_type() == DialogType::SecretChat) && + td_->auth_manager_->is_bot()) { + (void)get_dialog_photo(d->dialog_id); // to apply pending user photo + } d->is_update_new_chat_being_sent = true; auto chat_object = get_chat_object(d); bool has_action_bar = chat_object->action_bar_ != nullptr; @@ -32707,7 +32747,12 @@ void MessagesManager::on_dialog_photo_updated(DialogId dialog_id) { make_tl_object( dialog_id.get(), get_chat_photo_info_object(td_->file_manager_.get(), get_dialog_photo(dialog_id)))); } else if (d != nullptr && d->is_update_new_chat_being_sent) { - LOG(ERROR) << "Changed photo of " << dialog_id << " while the chat is being added: " << get_dialog_photo(dialog_id); + const auto *photo = get_dialog_photo(dialog_id); + if (photo == nullptr) { + LOG(ERROR) << "Removed photo of " << dialog_id << " while the chat is being added"; + } else { + LOG(ERROR) << "Changed photo of " << dialog_id << " while the chat is being added to " << *photo; + } } } @@ -34796,7 +34841,7 @@ MessagesManager::Message *MessagesManager::add_message_to_dialog(Dialog *d, uniq if (dialog_type == DialogType::Channel && !message->contains_unread_mention) { auto channel_read_media_period = - G()->shared_config().get_option_integer("channels_read_media_period", (G()->is_test_dc() ? 300 : 7 * 86400)); + td_->option_manager_->get_option_integer("channels_read_media_period", (G()->is_test_dc() ? 300 : 7 * 86400)); if (message->date < G()->unix_time_cached() - channel_read_media_period) { update_opened_message_content(message->content.get()); } @@ -36960,7 +37005,8 @@ void MessagesManager::fix_new_dialog(Dialog *d, unique_ptr &&last_datab update_dialog_pos(d, "fix_new_dialog 7", true, is_loaded_from_database); } if (is_loaded_from_database && d->order != order && order < MAX_ORDINARY_DIALOG_ORDER && - !td_->contacts_manager_->is_dialog_info_received_from_server(dialog_id) && !d->had_last_yet_unsent_message) { + !td_->contacts_manager_->is_dialog_info_received_from_server(dialog_id) && !d->had_last_yet_unsent_message && + !td_->auth_manager_->is_bot()) { LOG(ERROR) << dialog_id << " has order " << d->order << " instead of saved to database order " << order; } @@ -36984,18 +37030,21 @@ void MessagesManager::fix_new_dialog(Dialog *d, unique_ptr &&last_datab << ", max_notification_message_id = " << d->max_notification_message_id; if (d->messages != nullptr) { - LOG_CHECK(d->messages->message_id == last_message_id) - << d->messages->message_id << ' ' << last_message_id << ' ' << d->last_message_id << ' ' - << d->last_database_message_id << ' ' << d->debug_set_dialog_last_database_message_id << ' ' - << d->messages->debug_source; - LOG_CHECK(d->messages->left == nullptr) - << d->messages->left->message_id << ' ' << d->messages->message_id << ' ' << d->messages->left->message_id - << ' ' << last_message_id << ' ' << d->last_message_id << ' ' << d->last_database_message_id << ' ' - << d->debug_set_dialog_last_database_message_id << ' ' << d->messages->debug_source; - LOG_CHECK(d->messages->right == nullptr) - << d->messages->right->message_id << ' ' << d->messages->message_id << ' ' << d->messages->right->message_id - << ' ' << last_message_id << ' ' << d->last_message_id << ' ' << d->last_database_message_id << ' ' - << d->debug_set_dialog_last_database_message_id << ' ' << d->messages->debug_source; + if (d->messages->message_id != last_message_id || d->messages->left != nullptr || d->messages->right != nullptr) { + auto common_data = + PSTRING() << ' ' << last_message_id << ' ' << d->last_message_id << ' ' << d->last_database_message_id << ' ' + << d->debug_set_dialog_last_database_message_id << ' ' << d->messages->debug_source << ' ' + << is_loaded_from_database << ' ' << being_added_dialog_id_ << ' ' << being_added_new_dialog_id_ + << ' ' << dialog_id << ' ' << d->is_channel_difference_finished << ' ' + << debug_last_get_channel_difference_dialog_id_ << ' ' << debug_last_get_channel_difference_source_; + LOG_CHECK(d->messages->message_id == last_message_id) << d->messages->message_id << common_data; + LOG_CHECK(d->messages->left == nullptr) + << d->messages->left->message_id << ' ' << d->messages->message_id << ' ' << d->messages->left->message_id + << ' ' << d->messages->left->debug_source << common_data; + LOG_CHECK(d->messages->right == nullptr) + << d->messages->right->message_id << ' ' << d->messages->message_id << ' ' << d->messages->right->message_id + << ' ' << d->messages->right->debug_source << common_data; + } } // must be after update_dialog_pos, because uses d->order @@ -38237,6 +38286,10 @@ void MessagesManager::get_channel_difference(DialogId dialog_id, int32 pts, bool << " because it has already been run"; return; } + + debug_last_get_channel_difference_dialog_id_ = dialog_id; + debug_last_get_channel_difference_source_ = source; + auto input_channel = td_->contacts_manager_->get_input_channel(dialog_id.get_channel_id()); if (input_channel == nullptr) { LOG(ERROR) << "Skip running channels.getDifference for " << dialog_id << " from " << source diff --git a/td/telegram/MessagesManager.h b/td/telegram/MessagesManager.h index b4f49d1fe..dce02bd81 100644 --- a/td/telegram/MessagesManager.h +++ b/td/telegram/MessagesManager.h @@ -78,6 +78,7 @@ #include "td/utils/Status.h" #include "td/utils/StringBuilder.h" #include "td/utils/WaitFreeHashMap.h" +#include "td/utils/WaitFreeHashSet.h" #include #include @@ -1373,7 +1374,7 @@ class MessagesManager final : public Actor { FlatHashMap last_assigned_scheduled_message_id; // date -> message_id - FlatHashSet deleted_message_ids; + WaitFreeHashSet deleted_message_ids; FlatHashSet deleted_scheduled_server_message_ids; vector> pending_new_message_notifications; @@ -1894,7 +1895,7 @@ class MessagesManager final : public Actor { bool can_edit_message(DialogId dialog_id, const Message *m, bool is_editing, bool only_reply_markup = false) const; - static bool has_qts_messages(DialogId dialog_id); + bool has_qts_messages(DialogId dialog_id) const; bool can_report_dialog(DialogId dialog_id) const; @@ -1918,8 +1919,8 @@ class MessagesManager final : public Actor { MessageId get_reply_to_message_id(Dialog *d, MessageId top_thread_message_id, MessageId message_id, bool for_draft); - static void fix_server_reply_to_message_id(DialogId dialog_id, MessageId message_id, DialogId reply_in_dialog_id, - MessageId &reply_to_message_id); + void fix_server_reply_to_message_id(DialogId dialog_id, MessageId message_id, DialogId reply_in_dialog_id, + MessageId &reply_to_message_id) const; bool can_set_game_score(DialogId dialog_id, const Message *m) const; @@ -2588,7 +2589,7 @@ class MessagesManager final : public Actor { void remove_dialog_newer_messages(Dialog *d, MessageId from_message_id, const char *source); - static int32 get_pinned_dialogs_limit(DialogListId dialog_list_id); + int32 get_pinned_dialogs_limit(DialogListId dialog_list_id) const; static vector remove_secret_chat_dialog_ids(vector dialog_ids); @@ -2951,6 +2952,9 @@ class MessagesManager final : public Actor { void ttl_db_loop(double server_now); void ttl_db_on_result(Result, int32>> r_result, bool dummy); + void on_restore_missing_message_after_get_difference(FullMessageId full_message_id, MessageId old_message_id, + Result result); + void on_get_message_link_dialog(MessageLinkInfo &&info, Promise &&promise); void on_get_message_link_message(MessageLinkInfo &&info, DialogId dialog_id, Promise &&promise); @@ -3715,6 +3719,8 @@ class MessagesManager final : public Actor { DialogId being_added_new_dialog_id_; DialogId debug_channel_difference_dialog_; + DialogId debug_last_get_channel_difference_dialog_id_; + const char *debug_last_get_channel_difference_source_ = "unknown"; double start_time_ = 0; bool is_inited_ = false; diff --git a/td/telegram/NotificationManager.cpp b/td/telegram/NotificationManager.cpp index acf3e701c..ab9826703 100644 --- a/td/telegram/NotificationManager.cpp +++ b/td/telegram/NotificationManager.cpp @@ -9,7 +9,6 @@ #include "td/telegram/AuthManager.h" #include "td/telegram/ChannelId.h" #include "td/telegram/ChatId.h" -#include "td/telegram/ConfigShared.h" #include "td/telegram/ContactsManager.h" #include "td/telegram/DeviceTokenManager.h" #include "td/telegram/Document.h" @@ -22,6 +21,7 @@ #include "td/telegram/misc.h" #include "td/telegram/net/ConnectionCreator.h" #include "td/telegram/net/DcId.h" +#include "td/telegram/OptionManager.h" #include "td/telegram/Photo.h" #include "td/telegram/Photo.hpp" #include "td/telegram/SecretChatId.h" @@ -95,10 +95,10 @@ class SetContactSignUpNotificationQuery final : public Td::ResultHandler { }; class GetContactSignUpNotificationQuery final : public Td::ResultHandler { - Promise promise_; + Promise promise_; public: - explicit GetContactSignUpNotificationQuery(Promise &&promise) : promise_(std::move(promise)) { + explicit GetContactSignUpNotificationQuery(Promise &&promise) : promise_(std::move(promise)) { } void send() { @@ -111,8 +111,7 @@ class GetContactSignUpNotificationQuery final : public Td::ResultHandler { return on_error(result_ptr.move_as_error()); } - td_->notification_manager_->on_get_disable_contact_registered_notifications(result_ptr.ok()); - promise_.set_value(Unit()); + promise_.set_value(result_ptr.move_as_ok()); } void on_error(Status status) final { @@ -209,7 +208,7 @@ void NotificationManager::init() { } disable_contact_registered_notifications_ = - G()->shared_config().get_option_boolean("disable_contact_registered_notifications"); + td_->option_manager_->get_option_boolean("disable_contact_registered_notifications"); auto sync_state = G()->td_db()->get_binlog_pmc()->get(get_is_contact_registered_notifications_synchronized_key()); if (sync_state.empty()) { sync_state = "00"; @@ -2394,7 +2393,7 @@ void NotificationManager::on_notification_group_count_max_changed(bool send_upda } auto new_max_notification_group_count = narrow_cast( - G()->shared_config().get_option_integer("notification_group_count_max", DEFAULT_GROUP_COUNT_MAX)); + td_->option_manager_->get_option_integer("notification_group_count_max", DEFAULT_GROUP_COUNT_MAX)); CHECK(MIN_NOTIFICATION_GROUP_COUNT_MAX <= new_max_notification_group_count && new_max_notification_group_count <= MAX_NOTIFICATION_GROUP_COUNT_MAX); @@ -2458,7 +2457,7 @@ void NotificationManager::on_notification_group_size_max_changed() { } auto new_max_notification_group_size = narrow_cast( - G()->shared_config().get_option_integer("notification_group_size_max", DEFAULT_GROUP_SIZE_MAX)); + td_->option_manager_->get_option_integer("notification_group_size_max", DEFAULT_GROUP_SIZE_MAX)); CHECK(MIN_NOTIFICATION_GROUP_SIZE_MAX <= new_max_notification_group_size && new_max_notification_group_size <= MAX_NOTIFICATION_GROUP_SIZE_MAX); @@ -2541,7 +2540,7 @@ void NotificationManager::on_online_cloud_timeout_changed() { } online_cloud_timeout_ms_ = narrow_cast( - G()->shared_config().get_option_integer("online_cloud_timeout_ms", DEFAULT_ONLINE_CLOUD_TIMEOUT_MS)); + td_->option_manager_->get_option_integer("online_cloud_timeout_ms", DEFAULT_ONLINE_CLOUD_TIMEOUT_MS)); VLOG(notifications) << "Set online_cloud_timeout_ms to " << online_cloud_timeout_ms_; } @@ -2551,7 +2550,7 @@ void NotificationManager::on_notification_cloud_delay_changed() { } notification_cloud_delay_ms_ = narrow_cast( - G()->shared_config().get_option_integer("notification_cloud_delay_ms", DEFAULT_ONLINE_CLOUD_DELAY_MS)); + td_->option_manager_->get_option_integer("notification_cloud_delay_ms", DEFAULT_ONLINE_CLOUD_DELAY_MS)); VLOG(notifications) << "Set notification_cloud_delay_ms to " << notification_cloud_delay_ms_; } @@ -2561,7 +2560,7 @@ void NotificationManager::on_notification_default_delay_changed() { } notification_default_delay_ms_ = narrow_cast( - G()->shared_config().get_option_integer("notification_default_delay_ms", DEFAULT_DEFAULT_DELAY_MS)); + td_->option_manager_->get_option_integer("notification_default_delay_ms", DEFAULT_DEFAULT_DELAY_MS)); VLOG(notifications) << "Set notification_default_delay_ms to " << notification_default_delay_ms_; } @@ -2570,8 +2569,7 @@ void NotificationManager::on_disable_contact_registered_notifications_changed() return; } - auto is_disabled = G()->shared_config().get_option_boolean("disable_contact_registered_notifications"); - + auto is_disabled = td_->option_manager_->get_option_boolean("disable_contact_registered_notifications"); if (is_disabled == disable_contact_registered_notifications_) { return; } @@ -2582,17 +2580,18 @@ void NotificationManager::on_disable_contact_registered_notifications_changed() } } -void NotificationManager::on_get_disable_contact_registered_notifications(bool is_disabled) { - if (disable_contact_registered_notifications_ == is_disabled) { - return; +void NotificationManager::on_get_disable_contact_registered_notifications(bool is_disabled, Promise &&promise) { + if (G()->close_flag() || disable_contact_registered_notifications_ == is_disabled) { + return promise.set_value(Unit()); } disable_contact_registered_notifications_ = is_disabled; if (is_disabled) { - G()->shared_config().set_option_boolean("disable_contact_registered_notifications", is_disabled); + td_->option_manager_->set_option_boolean("disable_contact_registered_notifications", is_disabled); } else { - G()->shared_config().set_option_empty("disable_contact_registered_notifications"); + td_->option_manager_->set_option_empty("disable_contact_registered_notifications"); } + promise.set_value(Unit()); } void NotificationManager::set_contact_registered_notifications_sync_state(SyncState new_state) { @@ -2649,7 +2648,16 @@ void NotificationManager::get_disable_contact_registered_notifications(Promisecreate_handler(std::move(promise))->send(); + auto query_promise = + PromiseCreator::lambda([actor_id = actor_id(this), promise = std::move(promise)](Result &&result) mutable { + if (result.is_error()) { + promise.set_error(result.move_as_error()); + } else { + send_closure(actor_id, &NotificationManager::on_get_disable_contact_registered_notifications, result.ok(), + std::move(promise)); + } + }); + td_->create_handler(std::move(query_promise))->send(); } void NotificationManager::process_push_notification(string payload, Promise &&user_promise) { @@ -2705,7 +2713,7 @@ void NotificationManager::process_push_notification(string payload, Promisestate_manager(), &StateManager::on_online, false); } - if (receiver_id == 0 || receiver_id == G()->get_my_id()) { + if (receiver_id == 0 || receiver_id == td_->option_manager_->get_option_integer("my_id")) { auto status = process_push_notification_payload(payload, was_encrypted, promise); if (status.is_error()) { if (status.code() == 406 || status.code() == 200) { diff --git a/td/telegram/NotificationManager.h b/td/telegram/NotificationManager.h index 3ece92dae..ff307928e 100644 --- a/td/telegram/NotificationManager.h +++ b/td/telegram/NotificationManager.h @@ -108,8 +108,6 @@ class NotificationManager final : public Actor { void on_disable_contact_registered_notifications_changed(); - void on_get_disable_contact_registered_notifications(bool is_disabled); - void process_push_notification(string payload, Promise &&user_promise); static Result get_push_receiver_id(string payload); @@ -337,6 +335,8 @@ class NotificationManager final : public Actor { void on_contact_registered_notifications_sync(bool is_disabled, Result result); + void on_get_disable_contact_registered_notifications(bool is_disabled, Promise &&promise); + void save_announcement_ids(); static ActiveNotificationsUpdate as_active_notifications_update(const td_api::updateActiveNotifications *update); diff --git a/td/telegram/NotificationSettingsManager.cpp b/td/telegram/NotificationSettingsManager.cpp index 3d49ad02d..e39528bb0 100644 --- a/td/telegram/NotificationSettingsManager.cpp +++ b/td/telegram/NotificationSettingsManager.cpp @@ -10,7 +10,6 @@ #include "td/telegram/AudiosManager.h" #include "td/telegram/AudiosManager.hpp" #include "td/telegram/AuthManager.h" -#include "td/telegram/ConfigShared.h" #include "td/telegram/ContactsManager.h" #include "td/telegram/Document.h" #include "td/telegram/DocumentsManager.h" @@ -25,6 +24,7 @@ #include "td/telegram/NotificationManager.h" #include "td/telegram/NotificationSettings.hpp" #include "td/telegram/NotificationSound.h" +#include "td/telegram/OptionManager.h" #include "td/telegram/Td.h" #include "td/telegram/TdDb.h" #include "td/telegram/telegram_api.h" @@ -874,7 +874,7 @@ void NotificationSettingsManager::add_saved_ringtone(td_api::object_ptrfile_manager_->get_file_view(file_id); CHECK(!file_view.empty()); - if (file_view.size() > G()->shared_config().get_option_integer("notification_sound_size_max")) { + if (file_view.size() > td_->option_manager_->get_option_integer("notification_sound_size_max")) { return promise.set_error(Status::Error(400, "Notification sound file is too big")); } auto file_type = file_view.get_type(); @@ -889,7 +889,7 @@ void NotificationSettingsManager::add_saved_ringtone(td_api::object_ptr G()->shared_config().get_option_integer("notification_sound_duration_max")) { + if (duration > td_->option_manager_->get_option_integer("notification_sound_duration_max")) { return promise.set_error(Status::Error(400, "Notification sound is too long")); } if (file_view.has_remote_location() && !file_view.is_encrypted()) { @@ -1114,7 +1114,7 @@ void NotificationSettingsManager::on_remove_saved_ringtone(int64 ringtone_id, Pr CHECK(are_saved_ringtones_loaded_); - auto max_count = G()->shared_config().get_option_integer("notification_sound_count_max"); + auto max_count = td_->option_manager_->get_option_integer("notification_sound_count_max"); if (saved_ringtone_file_ids_.size() >= static_cast(max_count)) { // reload all saved ringtones to get ringtones besides the limit return reload_saved_ringtones(PromiseCreator::lambda([promise = std::move(promise)](Result &&result) mutable { diff --git a/td/telegram/OptionManager.cpp b/td/telegram/OptionManager.cpp index 8dd2b28db..3394bff67 100644 --- a/td/telegram/OptionManager.cpp +++ b/td/telegram/OptionManager.cpp @@ -10,13 +10,13 @@ #include "td/telegram/AttachMenuManager.h" #include "td/telegram/AuthManager.h" #include "td/telegram/ConfigManager.h" -#include "td/telegram/ConfigShared.h" #include "td/telegram/ContactsManager.h" #include "td/telegram/DialogId.h" #include "td/telegram/GitCommitHash.h" #include "td/telegram/Global.h" #include "td/telegram/JsonValue.h" #include "td/telegram/LanguagePackManager.h" +#include "td/telegram/MessageReaction.h" #include "td/telegram/net/MtprotoHeader.h" #include "td/telegram/net/NetQueryDispatcher.h" #include "td/telegram/NotificationManager.h" @@ -26,11 +26,14 @@ #include "td/telegram/SuggestedAction.h" #include "td/telegram/Td.h" #include "td/telegram/TdDb.h" -#include "td/telegram/telegram_api.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/buffer.h" #include "td/utils/logging.h" #include "td/utils/misc.h" #include "td/utils/port/Clocks.h" @@ -43,95 +46,162 @@ namespace td { -class SetDefaultReactionQuery final : public Td::ResultHandler { - Promise promise_; - - public: - explicit SetDefaultReactionQuery(Promise &&promise) : promise_(std::move(promise)) { - } - - void send(const string &reaction) { - send_query(G()->net_query_creator().create(telegram_api::messages_setDefaultReaction(reaction))); - } - - void on_result(BufferSlice packet) final { - auto result_ptr = fetch_result(packet); - if (result_ptr.is_error()) { - return on_error(result_ptr.move_as_error()); - } - - if (result_ptr.ok()) { - promise_.set_value(Unit()); - } else { - on_error(Status::Error(400, "Receive false")); - } - } - - void on_error(Status status) final { - LOG(INFO) << "Failed to set default reaction: " << status; - promise_.set_error(std::move(status)); - } -}; - -OptionManager::OptionManager(Td *td, ActorShared<> parent) : td_(td), parent_(std::move(parent)) { +OptionManager::OptionManager(Td *td) + : td_(td), options_(td::make_unique()), option_pmc_(G()->td_db()->get_config_pmc_shared()) { send_unix_time_update(); - if (G()->shared_config().have_option("language_database_path")) { - G()->shared_config().set_option_string("language_pack_database_path", - G()->shared_config().get_option_string("language_database_path")); - G()->shared_config().set_option_empty("language_database_path"); + auto all_options = option_pmc_->get_all(); + all_options["utc_time_offset"] = PSTRING() << 'I' << Clocks::tz_offset(); + for (const auto &name_value : all_options) { + const string &name = name_value.first; + const string &value = name_value.second; + options_->set(name, value); + if (!is_internal_option(name)) { + 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()->shared_config().have_option("language_pack")) { - G()->shared_config().set_option_string("localization_target", - G()->shared_config().get_option_string("language_pack")); - G()->shared_config().set_option_empty("language_pack"); - } - if (G()->shared_config().have_option("language_code")) { - G()->shared_config().set_option_string("language_pack_id", G()->shared_config().get_option_string("language_code")); - G()->shared_config().set_option_empty("language_code"); - } - if (!G()->shared_config().have_option("message_text_length_max")) { - G()->shared_config().set_option_integer("message_text_length_max", 4096); - } - if (!G()->shared_config().have_option("message_caption_length_max")) { - G()->shared_config().set_option_integer("message_caption_length_max", 1024); - } - if (!G()->shared_config().have_option("bio_length_max")) { - G()->shared_config().set_option_integer("bio_length_max", 70); - } - if (!G()->shared_config().have_option("suggested_video_note_length")) { - G()->shared_config().set_option_integer("suggested_video_note_length", 384); - } - if (!G()->shared_config().have_option("suggested_video_note_video_bitrate")) { - G()->shared_config().set_option_integer("suggested_video_note_video_bitrate", 1000); - } - if (!G()->shared_config().have_option("suggested_video_note_audio_bitrate")) { - G()->shared_config().set_option_integer("suggested_video_note_audio_bitrate", 64); - } - if (!G()->shared_config().have_option("notification_sound_duration_max")) { - G()->shared_config().set_option_integer("notification_sound_duration_max", 5); - } - if (!G()->shared_config().have_option("notification_sound_size_max")) { - G()->shared_config().set_option_integer("notification_sound_size_max", 307200); - } - if (!G()->shared_config().have_option("notification_sound_count_max")) { - G()->shared_config().set_option_integer("notification_sound_count_max", G()->is_test_dc() ? 5 : 100); - } - if (!G()->shared_config().have_option("chat_filter_count_max")) { - G()->shared_config().set_option_integer("chat_filter_count_max", G()->is_test_dc() ? 3 : 10); - } - if (!G()->shared_config().have_option("chat_filter_chosen_chat_count_max")) { - G()->shared_config().set_option_integer("chat_filter_chosen_chat_count_max", G()->is_test_dc() ? 5 : 100); - } - G()->shared_config().set_option_integer("utc_time_offset", Clocks::tz_offset()); -} -void OptionManager::tear_down() { - parent_.reset(); + if (!have_option("message_text_length_max")) { + set_option_integer("message_text_length_max", 4096); + } + if (!have_option("message_caption_length_max")) { + set_option_integer("message_caption_length_max", 1024); + } + if (!have_option("bio_length_max")) { + set_option_integer("bio_length_max", 70); + } + if (!have_option("suggested_video_note_length")) { + set_option_integer("suggested_video_note_length", 384); + } + if (!have_option("suggested_video_note_video_bitrate")) { + set_option_integer("suggested_video_note_video_bitrate", 1000); + } + if (!have_option("suggested_video_note_audio_bitrate")) { + set_option_integer("suggested_video_note_audio_bitrate", 64); + } + if (!have_option("notification_sound_duration_max")) { + set_option_integer("notification_sound_duration_max", 5); + } + if (!have_option("notification_sound_size_max")) { + set_option_integer("notification_sound_size_max", 307200); + } + if (!have_option("notification_sound_count_max")) { + set_option_integer("notification_sound_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); + } + if (!have_option("chat_filter_chosen_chat_count_max")) { + set_option_integer("chat_filter_chosen_chat_count_max", G()->is_test_dc() ? 5 : 100); + } } OptionManager::~OptionManager() = default; +void OptionManager::on_td_inited() { + is_td_inited_ = true; + + for (auto &request : pending_get_options_) { + get_option(request.first, std::move(request.second)); + } + reset_to_empty(pending_get_options_); +} + +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()); + } + + if (!G()->close_flag() && is_td_inited_) { + on_option_updated(name); + } + + if (!is_internal_option(name)) { + send_closure(G()->td(), &Td::send_update, + td_api::make_object(name.str(), get_option_value_object(get_option(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()); } @@ -142,6 +212,7 @@ void OptionManager::send_unix_time_update() { } void OptionManager::on_update_server_time_difference() { + // can be called from any thread if (std::abs(G()->get_server_time_difference() - last_sent_server_time_difference_) < 0.5) { return; } @@ -150,7 +221,7 @@ void OptionManager::on_update_server_time_difference() { } void OptionManager::clear_options() { - for (const auto &option : G()->shared_config().get_options()) { + for (const auto &option : options_->get_all()) { if (!is_internal_option(option.first)) { send_closure( G()->td(), &Td::send_update, @@ -163,8 +234,7 @@ bool OptionManager::is_internal_option(Slice name) { switch (name[0]) { case 'a': return name == "about_length_limit_default" || name == "about_length_limit_premium" || - name == "animated_emoji_zoom" || name == "animation_search_emojis" || - name == "animation_search_provider" || name == "auth"; + name == "animated_emoji_zoom" || name == "animation_search_emojis" || name == "animation_search_provider"; case 'b': return name == "base_language_pack_version"; case 'c': @@ -221,24 +291,17 @@ bool OptionManager::is_synchronous_option(Slice name) { return td::contains(get_synchronous_options(), name); } -void OptionManager::on_option_updated(const string &name) { - if (G()->close_flag()) { - return; - } +void OptionManager::on_option_updated(Slice name) { switch (name[0]) { case 'a': if (name == "animated_emoji_zoom") { // nothing to do: animated emoji zoom is updated only at launch } if (name == "animation_search_emojis") { - td_->animations_manager_->on_update_animation_search_emojis(G()->shared_config().get_option_string(name)); + td_->animations_manager_->on_update_animation_search_emojis(); } if (name == "animation_search_provider") { - td_->animations_manager_->on_update_animation_search_provider(G()->shared_config().get_option_string(name)); - } - if (name == "auth") { - send_closure(td_->auth_manager_actor_, &AuthManager::on_authorization_lost, - G()->shared_config().get_option_string(name)); + td_->animations_manager_->on_update_animation_search_provider(); } break; case 'b': @@ -248,14 +311,14 @@ void OptionManager::on_option_updated(const string &name) { break; case 'c': if (name == "connection_parameters") { - if (G()->mtproto_header().set_parameters(G()->shared_config().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()->shared_config().get_option_boolean(name)) { - set_default_reaction(); + if (name == "default_reaction_needs_sync" && get_option_boolean(name)) { + send_set_default_reaction_query(td_); } if (name == "dice_emojis") { send_closure(td_->stickers_manager_actor_, &StickersManager::on_update_dice_emojis); @@ -271,8 +334,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()->shared_config().get_option_boolean(name)); + send_closure(td_->top_dialog_manager_actor_, &TopDialogManager::update_is_enabled, !get_option_boolean(name)); } break; case 'e': @@ -282,8 +344,7 @@ void OptionManager::on_option_updated(const string &name) { break; case 'f': if (name == "favorite_stickers_limit") { - td_->stickers_manager_->on_update_favorite_stickers_limit( - narrow_cast(G()->shared_config().get_option_integer(name))); + td_->stickers_manager_->on_update_favorite_stickers_limit(); } break; case 'i': @@ -291,7 +352,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()->shared_config().get_option_boolean(name))) { + if (G()->mtproto_header().set_is_emulator(get_option_boolean(name))) { G()->net_query_dispatcher().update_mtproto_header(); } } @@ -299,7 +360,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()->shared_config().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()); @@ -309,16 +370,11 @@ 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()->shared_config().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()->shared_config().get_option_integer(name)); - } - break; case 'n': if (name == "notification_cloud_delay_ms") { send_closure(td_->notification_manager_actor_, &NotificationManager::on_notification_cloud_delay_changed); @@ -339,7 +395,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()->shared_config().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, {})); @@ -351,14 +407,12 @@ void OptionManager::on_option_updated(const string &name) { send_closure(td_->top_dialog_manager_actor_, &TopDialogManager::update_rating_e_decay); } if (name == "recent_stickers_limit") { - td_->stickers_manager_->on_update_recent_stickers_limit( - narrow_cast(G()->shared_config().get_option_integer(name))); + td_->stickers_manager_->on_update_recent_stickers_limit(); } break; case 's': if (name == "saved_animations_limit") { - td_->animations_manager_->on_update_saved_animations_limit( - narrow_cast(G()->shared_config().get_option_integer(name))); + td_->animations_manager_->on_update_saved_animations_limit(); } if (name == "session_count") { G()->net_query_dispatcher().update_session_count(); @@ -372,7 +426,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()->shared_config().get_option_integer(name)))) { + if (G()->mtproto_header().set_tz_offset(static_cast(get_option_integer(name)))) { G()->net_query_dispatcher().update_mtproto_header(); } } @@ -380,22 +434,14 @@ void OptionManager::on_option_updated(const string &name) { default: break; } - - if (is_internal_option(name)) { - return; - } - - // send_closure was already used in the callback - td_->send_update( - td_api::make_object(name, get_option_value_object(G()->shared_config().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()->shared_config().get_option(name))); + promise.set_value(get_option_value_object(get_option(name))); }); }; switch (name[0]) { @@ -412,8 +458,13 @@ void OptionManager::get_option(const string &name, Promisenotification_manager_actor_, - &NotificationManager::get_disable_contact_registered_notifications, wrap_promise()); + if (is_td_inited_) { + send_closure_later(td_->notification_manager_actor_, + &NotificationManager::get_disable_contact_registered_notifications, wrap_promise()); + } else { + pending_get_options_.emplace_back(name, std::move(promise)); + } + return; } break; case 'i': @@ -421,8 +472,12 @@ void OptionManager::get_option(const string &name, Promiseconfig_manager_, &ConfigManager::get_content_settings, wrap_promise()); } if (!is_bot && name == "is_location_visible") { - return send_closure_later(td_->contacts_manager_actor_, &ContactsManager::get_is_location_visible, - wrap_promise()); + if (is_td_inited_) { + send_closure_later(td_->contacts_manager_actor_, &ContactsManager::get_is_location_visible, wrap_promise()); + } else { + pending_get_options_.emplace_back(name, std::move(promise)); + } + return; } break; case 'o': @@ -466,7 +521,7 @@ void OptionManager::set_option(const string &name, td_api::object_ptrshared_config().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")); @@ -480,7 +535,7 @@ void OptionManager::set_option(const string &name, td_api::object_ptrshared_config().set_option_integer(name, int_value); + set_option_integer(name, int_value); } promise.set_value(Unit()); return true; @@ -491,7 +546,7 @@ void OptionManager::set_option(const string &name, td_api::object_ptrshared_config().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")); @@ -499,7 +554,7 @@ void OptionManager::set_option(const string &name, td_api::object_ptr(value.get())->value_; - G()->shared_config().set_option_boolean(name, bool_value); + set_option_boolean(name, bool_value); } promise.set_value(Unit()); return true; @@ -510,7 +565,7 @@ void OptionManager::set_option(const string &name, td_api::object_ptrshared_config().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")); @@ -519,10 +574,10 @@ void OptionManager::set_option(const string &name, td_api::object_ptr(value.get())->value_; if (str_value.empty()) { - G()->shared_config().set_option_empty(name); + set_option_empty(name); } else { if (check_value(str_value)) { - G()->shared_config().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; @@ -566,10 +621,12 @@ void OptionManager::set_option(const string &name, td_api::object_ptrstickers_manager_->is_active_reaction(value.str()); - })) { - G()->shared_config().set_option_boolean("default_reaction_needs_sync", true); + if (!is_bot && name == "default_reaction") { + string reaction; + if (value_constructor_id == td_api::optionValueString::ID) { + reaction = static_cast(value.get())->value_; + } + set_default_reaction(td_, std::move(reaction), std::move(promise)); return; } if (!is_bot && set_boolean_option("disable_animated_emoji")) { @@ -641,7 +698,7 @@ void OptionManager::set_option(const string &name, td_api::object_ptrshared_config().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")); } @@ -659,7 +716,7 @@ void OptionManager::set_option(const string &name, td_api::object_ptrcontacts_manager_->set_location_visibility(); + ContactsManager::set_location_visibility(td_); return; } break; @@ -766,19 +823,16 @@ void OptionManager::set_option(const string &name, td_api::object_ptrshared_config().set_option_boolean(name, - static_cast(value.get())->value_); + set_option_boolean(name, static_cast(value.get())->value_); break; case td_api::optionValueEmpty::ID: - G()->shared_config().set_option_empty(name); + set_option_empty(name); break; case td_api::optionValueInteger::ID: - G()->shared_config().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()->shared_config().set_option_string(name, - static_cast(value.get())->value_); + set_option_string(name, static_cast(value.get())->value_); break; default: UNREACHABLE(); @@ -830,7 +884,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()->shared_config().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))); @@ -838,23 +892,4 @@ void OptionManager::get_current_state(vector> } } -void OptionManager::set_default_reaction() { - auto promise = PromiseCreator::lambda([actor_id = actor_id(this)](Result &&result) { - send_closure(actor_id, &OptionManager::on_set_default_reaction, result.is_ok()); - }); - td_->create_handler(std::move(promise)) - ->send(G()->shared_config().get_option_string("default_reaction")); -} - -void OptionManager::on_set_default_reaction(bool success) { - if (G()->close_flag() && !success) { - return; - } - - G()->shared_config().set_option_empty("default_reaction_needs_sync"); - if (!success) { - send_closure(G()->config_manager(), &ConfigManager::reget_app_config, Promise()); - } -} - } // namespace td diff --git a/td/telegram/OptionManager.h b/td/telegram/OptionManager.h index 5b21739d0..dd79d4b80 100644 --- a/td/telegram/OptionManager.h +++ b/td/telegram/OptionManager.h @@ -8,35 +8,54 @@ #include "td/telegram/td_api.h" -#include "td/actor/actor.h" - #include "td/utils/common.h" #include "td/utils/Promise.h" #include "td/utils/Slice.h" +#include +#include +#include + namespace td { +class KeyValueSyncInterface; class Td; +class TsSeqKeyValue; -class OptionManager final : public Actor { +class OptionManager { public: - OptionManager(Td *td, ActorShared<> parent); - + explicit OptionManager(Td *td); OptionManager(const OptionManager &) = delete; OptionManager &operator=(const OptionManager &) = delete; OptionManager(OptionManager &&) = delete; OptionManager &operator=(OptionManager &&) = delete; - ~OptionManager() final; + ~OptionManager(); + + void on_td_inited(); + + 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; + + 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 on_option_updated(const string &name); - 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); @@ -47,7 +66,11 @@ class OptionManager final : public Actor { void get_current_state(vector> &updates) const; 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); @@ -59,14 +82,14 @@ class OptionManager final : public Actor { void send_unix_time_update(); - void set_default_reaction(); - - void on_set_default_reaction(bool success); - Td *td_; - ActorShared<> parent_; + bool is_td_inited_ = false; + vector>>> pending_get_options_; - double last_sent_server_time_difference_ = 1e100; + unique_ptr options_; + std::shared_ptr option_pmc_; + + std::atomic last_sent_server_time_difference_{1e100}; }; } // namespace td diff --git a/td/telegram/PasswordManager.cpp b/td/telegram/PasswordManager.cpp index 5ebb0c8b1..e95900e03 100644 --- a/td/telegram/PasswordManager.cpp +++ b/td/telegram/PasswordManager.cpp @@ -7,7 +7,6 @@ #include "td/telegram/PasswordManager.h" #include "td/telegram/ConfigManager.h" -#include "td/telegram/ConfigShared.h" #include "td/telegram/DhCache.h" #include "td/telegram/DialogId.h" #include "td/telegram/Global.h" @@ -785,7 +784,7 @@ void PasswordManager::do_get_state(Promise promise) { state.has_recovery_email_address = password->has_recovery_; state.has_secure_values = password->has_secure_values_; - auto days = narrow_cast(G()->shared_config().get_option_integer("otherwise_relogin_days")); + auto days = narrow_cast(G()->get_option_integer("otherwise_relogin_days")); if (days > 0) { dismiss_suggested_action(SuggestedAction{SuggestedAction::Type::SetPassword, DialogId(), days}, Promise()); diff --git a/td/telegram/Premium.cpp b/td/telegram/Premium.cpp index d90c9ba2b..b43df2ccf 100644 --- a/td/telegram/Premium.cpp +++ b/td/telegram/Premium.cpp @@ -8,13 +8,11 @@ #include "td/telegram/AnimationsManager.h" #include "td/telegram/Application.h" -#include "td/telegram/ConfigShared.h" #include "td/telegram/ContactsManager.h" #include "td/telegram/DialogId.h" #include "td/telegram/Document.h" #include "td/telegram/DocumentsManager.h" #include "td/telegram/Global.h" -#include "td/telegram/JsonValue.h" #include "td/telegram/MessageEntity.h" #include "td/telegram/Payments.h" #include "td/telegram/Td.h" @@ -399,10 +397,8 @@ static string get_premium_source(const td_api::object_ptr } static td_api::object_ptr get_premium_limit_object(Slice key) { - int32 default_limit = - static_cast(G()->shared_config().get_option_integer(PSLICE() << key << "_limit_default")); - int32 premium_limit = - static_cast(G()->shared_config().get_option_integer(PSLICE() << key << "_limit_premium")); + auto default_limit = static_cast(G()->get_option_integer(PSLICE() << key << "_limit_default")); + auto premium_limit = static_cast(G()->get_option_integer(PSLICE() << key << "_limit_premium")); if (default_limit <= 0 || premium_limit <= default_limit) { return nullptr; } @@ -455,7 +451,7 @@ void get_premium_limit(const td_api::object_ptr &limit void get_premium_features(Td *td, const td_api::object_ptr &source, Promise> &&promise) { auto premium_features = - full_split(G()->shared_config().get_option_string( + full_split(G()->get_option_string( "premium_features", "double_limits,more_upload,faster_download,voice_to_text,no_ads,unique_reactions,premium_stickers," "animated_emoji,advanced_chat_management,profile_badge,animated_userpics,app_icons"), @@ -487,11 +483,11 @@ void get_premium_features(Td *td, const td_api::object_ptr payment_link; - auto premium_bot_username = G()->shared_config().get_option_string("premium_bot_username"); + auto premium_bot_username = G()->get_option_string("premium_bot_username"); if (!premium_bot_username.empty()) { payment_link = td_api::make_object(premium_bot_username, source_str, true); } else { - auto premium_invoice_slug = G()->shared_config().get_option_string("premium_invoice_slug"); + auto premium_invoice_slug = G()->get_option_string("premium_invoice_slug"); if (!premium_invoice_slug.empty()) { payment_link = td_api::make_object(premium_invoice_slug); } diff --git a/td/telegram/PremiumGiftOption.cpp b/td/telegram/PremiumGiftOption.cpp index 133608191..733ca57b9 100644 --- a/td/telegram/PremiumGiftOption.cpp +++ b/td/telegram/PremiumGiftOption.cpp @@ -10,8 +10,8 @@ #include "td/telegram/Payments.h" #include "td/utils/common.h" +#include "td/utils/logging.h" -#include #include namespace td { diff --git a/td/telegram/RestrictionReason.cpp b/td/telegram/RestrictionReason.cpp index 0ed1af374..c23d895fb 100644 --- a/td/telegram/RestrictionReason.cpp +++ b/td/telegram/RestrictionReason.cpp @@ -6,7 +6,6 @@ // #include "td/telegram/RestrictionReason.h" -#include "td/telegram/ConfigShared.h" #include "td/telegram/Global.h" #include "td/utils/algorithm.h" @@ -22,10 +21,9 @@ string get_restriction_reason_description(const vector &restr return string(); } - auto ignored_restriction_reasons = - full_split(G()->shared_config().get_option_string("ignored_restriction_reasons"), ','); + auto ignored_restriction_reasons = full_split(G()->get_option_string("ignored_restriction_reasons"), ','); auto platform = [] { - if (G()->shared_config().get_option_boolean("ignore_platform_restrictions")) { + if (G()->get_option_boolean("ignore_platform_restrictions")) { return Slice(); } diff --git a/td/telegram/SecretChatsManager.cpp b/td/telegram/SecretChatsManager.cpp index 696e4bd68..4883c09f4 100644 --- a/td/telegram/SecretChatsManager.cpp +++ b/td/telegram/SecretChatsManager.cpp @@ -6,7 +6,6 @@ // #include "td/telegram/SecretChatsManager.h" -#include "td/telegram/ConfigShared.h" #include "td/telegram/ContactsManager.h" #include "td/telegram/DhCache.h" #include "td/telegram/EncryptedFile.h" @@ -321,7 +320,7 @@ unique_ptr SecretChatsManager::make_secret_chat_contex } bool get_config_option_boolean(const string &name) const final { - return G()->shared_config().get_option_boolean(name); + return G()->get_option_boolean(name); } int32 unix_time() final { diff --git a/td/telegram/SponsoredMessageManager.cpp b/td/telegram/SponsoredMessageManager.cpp index 6ce90206e..3a1caa343 100644 --- a/td/telegram/SponsoredMessageManager.cpp +++ b/td/telegram/SponsoredMessageManager.cpp @@ -7,7 +7,6 @@ #include "td/telegram/SponsoredMessageManager.h" #include "td/telegram/ChannelId.h" -#include "td/telegram/ConfigShared.h" #include "td/telegram/ContactsManager.h" #include "td/telegram/Global.h" #include "td/telegram/LinkManager.h" @@ -15,6 +14,7 @@ #include "td/telegram/MessageEntity.h" #include "td/telegram/MessagesManager.h" #include "td/telegram/net/NetQueryCreator.h" +#include "td/telegram/OptionManager.h" #include "td/telegram/ServerMessageId.h" #include "td/telegram/Td.h" #include "td/telegram/telegram_api.h" @@ -169,7 +169,7 @@ td_api::object_ptr SponsoredMessageManager::get_sponso case DialogType::Channel: if (sponsored_message.server_message_id.is_valid()) { auto channel_id = sponsored_message.sponsor_dialog_id.get_channel_id(); - auto t_me = G()->shared_config().get_option_string("t_me_url", "https://t.me/"); + auto t_me = td_->option_manager_->get_option_string("t_me_url", "https://t.me/"); link = td_api::make_object( PSTRING() << t_me << "c/" << channel_id.get() << '/' << sponsored_message.server_message_id.get()); } diff --git a/td/telegram/StickerFormat.cpp b/td/telegram/StickerFormat.cpp index bf074aba7..9ec9b60ae 100644 --- a/td/telegram/StickerFormat.cpp +++ b/td/telegram/StickerFormat.cpp @@ -147,15 +147,15 @@ bool is_sticker_format_vector(StickerFormat sticker_format) { } int64 get_max_sticker_file_size(StickerFormat sticker_format, StickerType sticker_type, bool for_thumbnail) { - bool is_emoji = sticker_type == StickerType::CustomEmoji; + bool is_custom_emoji = sticker_type == StickerType::CustomEmoji; switch (sticker_format) { case StickerFormat::Unknown: case StickerFormat::Webp: - return for_thumbnail ? (1 << 17) : (is_emoji ? (1 << 17) : (1 << 19)); + return for_thumbnail ? (1 << 17) : (is_custom_emoji ? (1 << 17) : (1 << 19)); case StickerFormat::Tgs: return for_thumbnail ? (1 << 15) : (1 << 16); case StickerFormat::Webm: - return for_thumbnail ? (1 << 15) : (is_emoji ? (1 << 16) : (1 << 18)); + return for_thumbnail ? (1 << 15) : (is_custom_emoji ? (1 << 16) : (1 << 18)); default: UNREACHABLE(); return 0; diff --git a/td/telegram/StickersManager.cpp b/td/telegram/StickersManager.cpp index 3e8825ded..750459bc8 100644 --- a/td/telegram/StickersManager.cpp +++ b/td/telegram/StickersManager.cpp @@ -10,7 +10,6 @@ #include "td/telegram/AuthManager.h" #include "td/telegram/AvailableReaction.h" #include "td/telegram/ConfigManager.h" -#include "td/telegram/ConfigShared.h" #include "td/telegram/ContactsManager.h" #include "td/telegram/DialogId.h" #include "td/telegram/Document.h" @@ -28,6 +27,7 @@ #include "td/telegram/net/DcId.h" #include "td/telegram/net/MtprotoHeader.h" #include "td/telegram/net/NetQueryDispatcher.h" +#include "td/telegram/OptionManager.h" #include "td/telegram/PhotoSizeSource.h" #include "td/telegram/secret_api.h" #include "td/telegram/SecretChatLayer.h" @@ -1390,11 +1390,8 @@ StickersManager::StickersManager(Td *td, ActorShared<> parent) : td_(td), parent upload_sticker_file_callback_ = std::make_shared(); on_update_animated_emoji_zoom(); - - on_update_recent_stickers_limit( - narrow_cast(G()->shared_config().get_option_integer("recent_stickers_limit", 200))); - on_update_favorite_stickers_limit( - narrow_cast(G()->shared_config().get_option_integer("favorite_stickers_limit", 5))); + on_update_recent_stickers_limit(); + on_update_favorite_stickers_limit(); next_click_animated_emoji_message_time_ = Time::now(); next_update_animated_emoji_clicked_time_ = Time::now(); @@ -1439,7 +1436,7 @@ void StickersManager::init() { load_special_sticker_set_info_from_binlog(sticker_set); dice_emojis_str_ = - G()->shared_config().get_option_string("dice_emojis", "🎲\x01🎯\x01🏀\x01⚽\x01⚽️\x01🎰\x01🎳"); + td_->option_manager_->get_option_string("dice_emojis", "🎲\x01🎯\x01🏀\x01⚽\x01⚽️\x01🎰\x01🎳"); dice_emojis_ = full_split(dice_emojis_str_, '\x01'); for (auto &dice_emoji : dice_emojis_) { auto &animated_dice_sticker_set = add_special_sticker_set(SpecialStickerSetType::animated_dice(dice_emoji)); @@ -1450,6 +1447,7 @@ void StickersManager::init() { send_closure_later(actor_id(this), &StickersManager::load_reactions); on_update_dice_success_values(); + on_update_dice_emojis(); on_update_emoji_sounds(); @@ -1473,9 +1471,9 @@ void StickersManager::init() { G()->td_db()->get_binlog_pmc()->erase("invalidate_old_featured_sticker_sets"); } - G()->td_db()->get_binlog_pmc()->erase("animated_dice_sticker_set"); // legacy - G()->shared_config().set_option_empty("animated_dice_sticker_set_name"); // legacy - G()->shared_config().set_option_empty("animated_emoji_sticker_set_name"); // legacy + G()->td_db()->get_binlog_pmc()->erase("animated_dice_sticker_set"); // legacy + td_->option_manager_->set_option_empty("animated_dice_sticker_set_name"); // legacy + td_->option_manager_->set_option_empty("animated_emoji_sticker_set_name"); // legacy } void StickersManager::reload_reactions() { @@ -1690,9 +1688,7 @@ void StickersManager::on_load_special_sticker_set(const SpecialStickerSetType &t } vector full_message_ids; - for (const auto &full_message_id : it->second) { - full_message_ids.push_back(full_message_id); - } + it->second.foreach([&](const FullMessageId &full_message_id) { full_message_ids.push_back(full_message_id); }); CHECK(!full_message_ids.empty()); for (const auto &full_message_id : full_message_ids) { td_->messages_manager_->on_external_update_message_content(full_message_id); @@ -2234,7 +2230,7 @@ tl_object_ptr StickersManager::get_sticker_set_info_obje vector regular_sticker_ids; vector premium_sticker_ids; std::tie(regular_sticker_ids, premium_sticker_ids) = split_stickers_by_premium(sticker_set); - auto is_premium = G()->shared_config().get_option_boolean("is_premium"); + auto is_premium = td_->option_manager_->get_option_boolean("is_premium"); size_t max_premium_stickers = is_premium ? covers_limit : 1; if (premium_sticker_ids.size() > max_premium_stickers) { premium_sticker_ids.resize(max_premium_stickers); @@ -2428,7 +2424,7 @@ FileId StickersManager::get_custom_animated_emoji_sticker_id(int64 custom_emoji_ td_api::object_ptr StickersManager::get_animated_emoji_object(const string &emoji, int64 custom_emoji_id) { - if (disable_animated_emojis_) { + if (td_->auth_manager_->is_bot() || disable_animated_emojis_) { return nullptr; } @@ -4114,8 +4110,8 @@ vector StickersManager::get_stickers(StickerType sticker_type, string em vector regular_sticker_ids; vector premium_sticker_ids; std::tie(regular_sticker_ids, premium_sticker_ids) = split_stickers_by_premium(result); - if (G()->shared_config().get_option_boolean("is_premium") || allow_premium) { - auto normal_count = G()->shared_config().get_option_integer("stickers_normal_by_emoji_per_premium_num", 2); + if (td_->option_manager_->get_option_boolean("is_premium") || allow_premium) { + auto normal_count = td_->option_manager_->get_option_integer("stickers_normal_by_emoji_per_premium_num", 2); if (normal_count < 0) { normal_count = 2; } @@ -4150,7 +4146,7 @@ vector StickersManager::get_stickers(StickerType sticker_type, string em } } if (sorted.size() < limit_size_t) { - auto premium_count = G()->shared_config().get_option_integer("stickers_premium_by_emoji_num", 0); + auto premium_count = td_->option_manager_->get_option_integer("stickers_premium_by_emoji_num", 0); if (premium_count > 0) { for (const auto &sticker_id : premium_sticker_ids) { LOG(INFO) << "Add premium sticker " << sticker_id << " from installed sticker set"; @@ -5014,7 +5010,7 @@ void StickersManager::on_update_dice_emojis() { return; } if (td_->auth_manager_->is_bot()) { - G()->shared_config().set_option_empty("dice_emojis"); + td_->option_manager_->set_option_empty("dice_emojis"); return; } if (!is_inited_) { @@ -5022,7 +5018,7 @@ void StickersManager::on_update_dice_emojis() { } auto dice_emojis_str = - G()->shared_config().get_option_string("dice_emojis", "🎲\x01🎯\x01🏀\x01⚽\x01⚽️\x01🎰\x01🎳"); + td_->option_manager_->get_option_string("dice_emojis", "🎲\x01🎯\x01🏀\x01⚽\x01⚽️\x01🎰\x01🎳"); if (dice_emojis_str == dice_emojis_str_) { return; } @@ -5054,7 +5050,7 @@ void StickersManager::on_update_dice_success_values() { return; } if (td_->auth_manager_->is_bot()) { - G()->shared_config().set_option_empty("dice_success_values"); + td_->option_manager_->set_option_empty("dice_success_values"); return; } if (!is_inited_) { @@ -5062,7 +5058,7 @@ void StickersManager::on_update_dice_success_values() { } auto dice_success_values_str = - G()->shared_config().get_option_string("dice_success_values", "0,6:62,5:110,5:110,5:110,64:110,6:110"); + td_->option_manager_->get_option_string("dice_success_values", "0,6:62,5:110,5:110,5:110,64:110,6:110"); if (dice_success_values_str == dice_success_values_str_) { return; } @@ -5080,7 +5076,7 @@ void StickersManager::on_update_emoji_sounds() { return; } - auto emoji_sounds_str = G()->shared_config().get_option_string("emoji_sounds"); + auto emoji_sounds_str = td_->option_manager_->get_option_string("emoji_sounds"); if (emoji_sounds_str == emoji_sounds_str_) { return; } @@ -5127,7 +5123,7 @@ void StickersManager::on_update_disable_animated_emojis() { return; } - auto disable_animated_emojis = G()->shared_config().get_option_boolean("disable_animated_emoji"); + auto disable_animated_emojis = td_->option_manager_->get_option_boolean("disable_animated_emoji"); if (disable_animated_emojis == disable_animated_emojis_) { return; } @@ -5174,9 +5170,8 @@ void StickersManager::try_update_animated_emoji_messages() { (new_animated_sticker.first.is_valid() && new_sound_file_id != it.second->sound_file_id_)) { it.second->animated_emoji_sticker_ = new_animated_sticker; it.second->sound_file_id_ = new_sound_file_id; - for (const auto &full_message_id : it.second->full_message_ids_) { - full_message_ids.push_back(full_message_id); - } + it.second->full_message_ids_.foreach( + [&](const FullMessageId &full_message_id) { full_message_ids.push_back(full_message_id); }); } } for (const auto &full_message_id : full_message_ids) { @@ -5194,9 +5189,8 @@ void StickersManager::try_update_custom_emoji_messages(int64 custom_emoji_id) { auto new_sticker_id = get_custom_animated_emoji_sticker_id(custom_emoji_id); if (new_sticker_id != it->second->sticker_id_) { it->second->sticker_id_ = new_sticker_id; - for (const auto &full_message_id : it->second->full_message_ids_) { - full_message_ids.push_back(full_message_id); - } + it->second->full_message_ids_.foreach( + [&](const FullMessageId &full_message_id) { full_message_ids.push_back(full_message_id); }); } for (const auto &full_message_id : full_message_ids) { td_->messages_manager_->on_external_update_message_content(full_message_id); @@ -5266,8 +5260,7 @@ void StickersManager::register_dice(const string &emoji, int32 value, FullMessag LOG(INFO) << "Register dice " << emoji << " with value " << value << " from " << full_message_id << " from " << source; - bool is_inserted = dice_messages_[emoji].insert(full_message_id).second; - LOG_CHECK(is_inserted) << source << " " << emoji << " " << value << " " << full_message_id; + dice_messages_[emoji].insert(full_message_id); if (!td::contains(dice_emojis_, emoji)) { if (full_message_id.get_message_id().is_any_server() && @@ -5336,8 +5329,7 @@ void StickersManager::register_emoji(const string &emoji, int64 custom_emoji_id, get_custom_emoji_stickers({custom_emoji_id}, true, Promise>()); } } - bool is_inserted = emoji_messages.full_message_ids_.insert(full_message_id).second; - LOG_CHECK(is_inserted) << source << ' ' << custom_emoji_id << ' ' << full_message_id; + emoji_messages.full_message_ids_.insert(full_message_id); return; } @@ -5350,8 +5342,7 @@ void StickersManager::register_emoji(const string &emoji, int64 custom_emoji_id, emoji_messages.animated_emoji_sticker_ = get_animated_emoji_sticker(emoji); emoji_messages.sound_file_id_ = get_animated_emoji_sound_file_id(emoji); } - bool is_inserted = emoji_messages.full_message_ids_.insert(full_message_id).second; - LOG_CHECK(is_inserted) << source << ' ' << emoji << ' ' << full_message_id; + emoji_messages.full_message_ids_.insert(full_message_id); } void StickersManager::unregister_emoji(const string &emoji, int64 custom_emoji_id, FullMessageId full_message_id, @@ -7909,10 +7900,12 @@ void StickersManager::save_recent_stickers_to_database(bool is_attached) { void StickersManager::on_update_animated_emoji_zoom() { animated_emoji_zoom_ = - static_cast(G()->shared_config().get_option_integer("animated_emoji_zoom", 625000000)) * 1e-9; + static_cast(td_->option_manager_->get_option_integer("animated_emoji_zoom", 625000000)) * 1e-9; } -void StickersManager::on_update_recent_stickers_limit(int32 recent_stickers_limit) { +void StickersManager::on_update_recent_stickers_limit() { + auto recent_stickers_limit = + narrow_cast(td_->option_manager_->get_option_integer("recent_stickers_limit", 200)); if (recent_stickers_limit != recent_stickers_limit_) { if (recent_stickers_limit > 0) { LOG(INFO) << "Update recent stickers limit to " << recent_stickers_limit; @@ -7929,7 +7922,9 @@ void StickersManager::on_update_recent_stickers_limit(int32 recent_stickers_limi } } -void StickersManager::on_update_favorite_stickers_limit(int32 favorite_stickers_limit) { +void StickersManager::on_update_favorite_stickers_limit() { + auto favorite_stickers_limit = + narrow_cast(td_->option_manager_->get_option_integer("favorite_stickers_limit", 5)); if (favorite_stickers_limit != favorite_stickers_limit_) { if (favorite_stickers_limit > 0) { LOG(INFO) << "Update favorite stickers limit to " << favorite_stickers_limit; @@ -8458,7 +8453,7 @@ vector StickersManager::get_emoji_language_codes(const vector &i } if (!text.empty()) { uint32 code = 0; - next_utf8_unsafe(text.ubegin(), &code, "get_emoji_language_codes"); + next_utf8_unsafe(text.ubegin(), &code); if ((0x410 <= code && code <= 0x44F) || code == 0x401 || code == 0x451) { // the first letter is cyrillic if (!td::contains(language_codes, "ru") && !td::contains(language_codes, "uk") && diff --git a/td/telegram/StickersManager.h b/td/telegram/StickersManager.h index 943b6a5f8..977e78a56 100644 --- a/td/telegram/StickersManager.h +++ b/td/telegram/StickersManager.h @@ -34,6 +34,7 @@ #include "td/utils/Slice.h" #include "td/utils/Status.h" #include "td/utils/WaitFreeHashMap.h" +#include "td/utils/WaitFreeHashSet.h" #include #include @@ -281,9 +282,9 @@ class StickersManager final : public Actor { void clear_recent_stickers(bool is_attached, Promise &&promise); - void on_update_recent_stickers_limit(int32 recent_stickers_limit); + void on_update_recent_stickers_limit(); - void on_update_favorite_stickers_limit(int32 favorite_stickers_limit); + void on_update_favorite_stickers_limit(); void reload_favorite_stickers(bool force); @@ -1004,17 +1005,17 @@ class StickersManager final : public Actor { }; FlatHashMap> premium_gift_messages_; - FlatHashMap> dice_messages_; + FlatHashMap> dice_messages_; struct EmojiMessages { - FlatHashSet full_message_ids_; + WaitFreeHashSet full_message_ids_; std::pair animated_emoji_sticker_; FileId sound_file_id_; }; FlatHashMap> emoji_messages_; struct CustomEmojiMessages { - FlatHashSet full_message_ids_; + WaitFreeHashSet full_message_ids_; FileId sticker_id_; }; FlatHashMap> custom_emoji_messages_; diff --git a/td/telegram/StorageManager.cpp b/td/telegram/StorageManager.cpp index c0272e45c..946e24435 100644 --- a/td/telegram/StorageManager.cpp +++ b/td/telegram/StorageManager.cpp @@ -6,7 +6,6 @@ // #include "td/telegram/StorageManager.h" -#include "td/telegram/ConfigShared.h" #include "td/telegram/DialogId.h" #include "td/telegram/files/FileGcWorker.h" #include "td/telegram/files/FileStatsWorker.h" @@ -188,7 +187,7 @@ int64 StorageManager::get_database_size() { int64 StorageManager::get_language_pack_database_size() { int64 size = 0; - auto path = G()->shared_config().get_option_string("language_pack_database_path"); + auto path = G()->get_option_string("language_pack_database_path"); if (!path.empty()) { SqliteDb::with_db_path(path, [&size](CSlice path) { size += get_file_size(path); }); } @@ -317,8 +316,7 @@ void StorageManager::save_last_gc_timestamp() { } void StorageManager::schedule_next_gc() { - if (!G()->shared_config().get_option_boolean("use_storage_optimizer") && - !G()->parameters().enable_storage_optimizer) { + if (!G()->get_option_boolean("use_storage_optimizer") && !G()->parameters().enable_storage_optimizer) { next_gc_at_ = 0; cancel_timeout(); LOG(INFO) << "No next file clean up is scheduled"; diff --git a/td/telegram/SuggestedAction.cpp b/td/telegram/SuggestedAction.cpp index 212ccabd5..fb4b4e3b0 100644 --- a/td/telegram/SuggestedAction.cpp +++ b/td/telegram/SuggestedAction.cpp @@ -8,7 +8,6 @@ #include "td/telegram/ChannelId.h" #include "td/telegram/ConfigManager.h" -#include "td/telegram/ConfigShared.h" #include "td/telegram/ContactsManager.h" #include "td/telegram/Global.h" #include "td/telegram/Td.h" @@ -181,11 +180,11 @@ void dismiss_suggested_action(SuggestedAction action, Promise &&promise) { if (action.otherwise_relogin_days_ <= 0) { return promise.set_error(Status::Error(400, "Invalid authorization_delay specified")); } - auto days = narrow_cast(G()->shared_config().get_option_integer("otherwise_relogin_days")); + auto days = narrow_cast(G()->get_option_integer("otherwise_relogin_days")); if (days == action.otherwise_relogin_days_) { vector removed_actions{SuggestedAction{SuggestedAction::Type::SetPassword, DialogId(), days}}; send_closure(G()->td(), &Td::send_update, get_update_suggested_actions_object({}, removed_actions)); - G()->shared_config().set_option_empty("otherwise_relogin_days"); + G()->set_option_empty("otherwise_relogin_days"); } return promise.set_value(Unit()); } diff --git a/td/telegram/Support.cpp b/td/telegram/Support.cpp new file mode 100644 index 000000000..190848b0b --- /dev/null +++ b/td/telegram/Support.cpp @@ -0,0 +1,111 @@ +// +// 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/Support.h" + +#include "td/telegram/ContactsManager.h" +#include "td/telegram/Global.h" +#include "td/telegram/MessageEntity.h" +#include "td/telegram/Td.h" + +#include "td/utils/buffer.h" +#include "td/utils/Status.h" + +namespace td { + +static td_api::object_ptr get_user_support_info_object( + Td *td, telegram_api::object_ptr user_info) { + CHECK(user_info != nullptr); + auto result = td_api::make_object(); + FormattedText message; + if (user_info->get_id() == telegram_api::help_userInfo::ID) { + auto info = telegram_api::move_object_as(user_info); + message = get_message_text(td->contacts_manager_.get(), std::move(info->message_), std::move(info->entities_), true, + true, info->date_, false, "get_user_support_info_object"); + result->author_ = std::move(info->author_); + result->date_ = info->date_; + } + result->message_ = get_formatted_text_object(message, true, 0); + return result; +} + +class GetUserInfoQuery final : public Td::ResultHandler { + Promise> promise_; + + public: + explicit GetUserInfoQuery(Promise> &&promise) + : promise_(std::move(promise)) { + } + + void send(UserId user_id) { + auto r_input_user = td_->contacts_manager_->get_input_user(user_id); + if (r_input_user.is_error()) { + return on_error(r_input_user.move_as_error()); + } + + send_query(G()->net_query_creator().create(telegram_api::help_getUserInfo(r_input_user.move_as_ok()))); + } + + void on_result(BufferSlice packet) final { + auto result_ptr = fetch_result(packet); + if (result_ptr.is_error()) { + return on_error(result_ptr.move_as_error()); + } + + promise_.set_value(get_user_support_info_object(td_, result_ptr.move_as_ok())); + } + + void on_error(Status status) final { + promise_.set_error(std::move(status)); + } +}; + +class EditUserInfoQuery final : public Td::ResultHandler { + Promise> promise_; + + public: + explicit EditUserInfoQuery(Promise> &&promise) + : promise_(std::move(promise)) { + } + + void send(UserId user_id, FormattedText &&formatted_text) { + auto r_input_user = td_->contacts_manager_->get_input_user(user_id); + if (r_input_user.is_error()) { + return on_error(r_input_user.move_as_error()); + } + + send_query(G()->net_query_creator().create(telegram_api::help_editUserInfo( + r_input_user.move_as_ok(), formatted_text.text, + get_input_message_entities(td_->contacts_manager_.get(), &formatted_text, "EditUserInfoQuery")))); + } + + void on_result(BufferSlice packet) final { + auto result_ptr = fetch_result(packet); + if (result_ptr.is_error()) { + return on_error(result_ptr.move_as_error()); + } + + promise_.set_value(get_user_support_info_object(td_, result_ptr.move_as_ok())); + } + + void on_error(Status status) final { + promise_.set_error(std::move(status)); + } +}; + +void get_user_info(Td *td, UserId user_id, Promise> &&promise) { + td->create_handler(std::move(promise))->send(user_id); +} + +void set_user_info(Td *td, UserId user_id, td_api::object_ptr &&message, + Promise> &&promise) { + TRY_RESULT_PROMISE( + promise, formatted_text, + get_formatted_text(td, DialogId(td->contacts_manager_->get_my_id()), std::move(message), false, true, true, false)); + td->create_handler(std::move(promise))->send(user_id, std::move(formatted_text)); +} + +} // namespace td diff --git a/td/telegram/Support.h b/td/telegram/Support.h new file mode 100644 index 000000000..3c0cb3d9e --- /dev/null +++ b/td/telegram/Support.h @@ -0,0 +1,24 @@ +// +// 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/telegram/td_api.h" +#include "td/telegram/UserId.h" + +#include "td/utils/common.h" +#include "td/utils/Promise.h" + +namespace td { + +class Td; + +void get_user_info(Td *td, UserId user_id, Promise> &&promise); + +void set_user_info(Td *td, UserId user_id, td_api::object_ptr &&message, + Promise> &&promise); + +} // namespace td diff --git a/td/telegram/Td.cpp b/td/telegram/Td.cpp index 7ed2a4ebd..06e32ceb5 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" @@ -112,6 +111,7 @@ #include "td/telegram/StorageManager.h" #include "td/telegram/MemoryManager.h" #include "td/telegram/SuggestedAction.h" +#include "td/telegram/Support.h" #include "td/telegram/td_api.hpp" #include "td/telegram/TdDb.h" #include "td/telegram/telegram_api.hpp" @@ -2646,8 +2646,7 @@ void Td::on_online_updated(bool force, bool send_update) { } if (is_online_) { alarm_timeout_.set_timeout_in( - ONLINE_ALARM_ID, - static_cast(G()->shared_config().get_option_integer("online_update_period_ms", 210000)) * 1e-3); + ONLINE_ALARM_ID, static_cast(G()->get_option_integer("online_update_period_ms", 210000)) * 1e-3); } else { alarm_timeout_.cancel_timeout(ONLINE_ALARM_ID); } @@ -2762,7 +2761,7 @@ void Td::set_is_online(bool is_online) { } void Td::set_is_bot_online(bool is_bot_online) { - if (G()->shared_config().get_option_integer("session_count") > 1) { + if (G()->get_option_integer("session_count") > 1) { is_bot_online = false; } @@ -2946,12 +2945,12 @@ void Td::request(uint64 id, tl_object_ptr function) { return; } - request_set_.insert(id); if (function == nullptr) { - return send_error_impl(id, make_error(400, "Request is empty")); + return callback_->on_error(id, make_error(400, "Request is empty")); } VLOG(td_requests) << "Receive request " << id << ": " << to_string(function); + request_set_.emplace(id, function->get_id()); if (is_synchronous_request(function.get())) { // send response synchronously return send_result(id, static_request(std::move(function))); @@ -3279,8 +3278,6 @@ void Td::dec_actor_refcnt() { LOG(DEBUG) << "NotificationManager was cleared" << timer; notification_settings_manager_.reset(); LOG(DEBUG) << "NotificationSettingsManager was cleared" << timer; - option_manager_.reset(); - LOG(DEBUG) << "OptionManager was cleared" << timer; poll_manager_.reset(); LOG(DEBUG) << "PollManager was cleared" << timer; sponsored_message_manager_.reset(); @@ -3303,9 +3300,12 @@ void Td::dec_actor_refcnt() { LOG(DEBUG) << "VoiceNotesManager was cleared" << timer; web_pages_manager_.reset(); LOG(DEBUG) << "WebPagesManager was cleared" << timer; - Promise<> promise = PromiseCreator::lambda([actor_id = create_reference()](Unit) mutable { actor_id.reset(); }); - G()->set_shared_config(nullptr); + G()->set_option_manager(nullptr); + option_manager_.reset(); + LOG(DEBUG) << "OptionManager was cleared" << timer; + + Promise<> promise = PromiseCreator::lambda([actor_id = create_reference()](Unit) mutable { actor_id.reset(); }); if (destroy_flag_) { G()->close_and_destroy_all(std::move(promise)); } else { @@ -3370,7 +3370,7 @@ void Td::clear_requests() { alarm_timeout_.cancel_timeout(alarm_id); } while (!request_set_.empty()) { - uint64 id = *request_set_.begin(); + uint64 id = request_set_.begin()->first; if (destroy_flag_) { send_error_impl(id, make_error(401, "Unauthorized")); } else { @@ -3389,7 +3389,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(); } @@ -3484,8 +3484,6 @@ void Td::clear() { LOG(DEBUG) << "NotificationManager actor was cleared" << timer; notification_settings_manager_actor_.reset(); LOG(DEBUG) << "NotificationSettingsManager actor was cleared" << timer; - option_manager_actor_.reset(); - LOG(DEBUG) << "OptionManager actor was cleared" << timer; poll_manager_actor_.reset(); LOG(DEBUG) << "PollManager actor was cleared" << timer; sponsored_message_manager_actor_.reset(); @@ -3664,6 +3662,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: @@ -3674,15 +3675,14 @@ void Td::init(Result r_opened_database) { } }); - options_.language_pack = G()->shared_config().get_option_string("localization_target"); - options_.language_code = G()->shared_config().get_option_string("language_pack_id"); - options_.parameters = G()->shared_config().get_option_string("connection_parameters"); - options_.tz_offset = static_cast(G()->shared_config().get_option_integer("utc_time_offset")); - options_.is_emulator = G()->shared_config().get_option_boolean("is_emulator"); + options_.language_pack = G()->get_option_string("localization_target"); + options_.language_code = G()->get_option_string("language_pack_id"); + options_.parameters = G()->get_option_string("connection_parameters"); + options_.tz_offset = static_cast(G()->get_option_integer("utc_time_offset")); + options_.is_emulator = G()->get_option_boolean("is_emulator"); // options_.proxy = Proxy(); G()->set_mtproto_header(make_unique(options_)); - G()->set_store_all_files_in_files_directory( - G()->shared_config().get_option_boolean("store_all_files_in_files_directory")); + G()->set_store_all_files_in_files_directory(G()->get_option_boolean("store_all_files_in_files_directory")); VLOG(td_init) << "Create NetQueryDispatcher"; auto net_query_dispatcher = make_unique([&] { return create_reference(); }); @@ -3696,16 +3696,17 @@ void Td::init(Result r_opened_database) { VLOG(td_init) << "Create AuthManager"; auth_manager_ = td::make_unique(parameters_.api_id, parameters_.api_hash, create_reference()); auth_manager_actor_ = register_actor("AuthManager", auth_manager_.get()); + G()->set_auth_manager(auth_manager_actor_.get()); init_file_manager(); init_managers(); - G()->set_my_id(G()->shared_config().get_option_integer("my_id")); - storage_manager_ = create_actor("StorageManager", create_reference(), G()->get_gc_scheduler_id()); G()->set_storage_manager(storage_manager_.get()); + option_manager_->on_td_inited(); + VLOG(td_init) << "Send binlog events"; for (auto &event : events.user_events) { contacts_manager_->on_binlog_user_event(std::move(event)); @@ -3732,6 +3733,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); } @@ -3826,8 +3831,9 @@ 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"; - G()->set_shared_config(td::make_unique(G()->td_db()->get_config_pmc_shared())); + VLOG(td_init) << "Create OptionManager"; + option_manager_ = make_unique(this); + G()->set_option_manager(option_manager_.get()); init_connection_creator(); @@ -3838,30 +3844,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 - G()->shared_config().set_callback(make_unique()); } void Td::init_connection_creator() { @@ -4112,11 +4094,11 @@ void Td::send_result(uint64 id, tl_object_ptr object) { auto it = request_set_.find(id); if (it != request_set_.end()) { - request_set_.erase(it); - VLOG(td_requests) << "Sending result for request " << id << ": " << to_string(object); if (object == nullptr) { object = make_tl_object(404, "Not Found"); } + VLOG(td_requests) << "Sending result for request " << id << ": " << to_string(object); + request_set_.erase(it); callback_->on_result(id, std::move(object)); } } @@ -4126,11 +4108,11 @@ void Td::send_error_impl(uint64 id, tl_object_ptr error) { CHECK(error != nullptr); auto it = request_set_.find(id); if (it != request_set_.end()) { - request_set_.erase(it); - VLOG(td_requests) << "Sending error for request " << id << ": " << oneline(to_string(error)); if (error->code_ == 0 && error->message_ == "Lost promise") { - LOG(FATAL) << "Lost promise for query " << id; + LOG(FATAL) << "Lost promise for query " << id << " of type " << it->second; } + VLOG(td_requests) << "Sending error for request " << id << ": " << oneline(to_string(error)); + request_set_.erase(it); callback_->on_error(id, std::move(error)); } } @@ -4884,7 +4866,7 @@ void Td::on_request(uint64 id, td_api::optimizeStorage &request) { } void Td::on_request(uint64 id, td_api::getNetworkStatistics &request) { - if (!request.only_current_ && G()->shared_config().get_option_boolean("disable_persistent_network_statistics")) { + if (!request.only_current_ && G()->get_option_boolean("disable_persistent_network_statistics")) { return send_error_raw(id, 400, "Persistent network statistics is disabled"); } CREATE_REQUEST_PROMISE(); @@ -4988,15 +4970,15 @@ void Td::on_request(uint64 id, const td_api::getTopChats &request) { promise.set_value(MessagesManager::get_chats_object(-1, result.ok())); } }); - top_dialog_manager_->get_top_dialogs(get_top_dialog_category(request.category_), request.limit_, - std::move(query_promise)); + send_closure(top_dialog_manager_actor_, &TopDialogManager::get_top_dialogs, + get_top_dialog_category(request.category_), request.limit_, std::move(query_promise)); } void Td::on_request(uint64 id, const td_api::removeTopChat &request) { CHECK_IS_USER(); CREATE_OK_REQUEST_PROMISE(); - top_dialog_manager_->remove_dialog(get_top_dialog_category(request.category_), DialogId(request.chat_id_), - std::move(promise)); + send_closure(top_dialog_manager_actor_, &TopDialogManager::remove_dialog, get_top_dialog_category(request.category_), + DialogId(request.chat_id_), std::move(promise)); } void Td::on_request(uint64 id, const td_api::loadChats &request) { @@ -5333,17 +5315,17 @@ void Td::on_request(uint64 id, td_api::getMessagePublicForwards &request) { void Td::on_request(uint64 id, const td_api::removeNotification &request) { CHECK_IS_USER(); CREATE_OK_REQUEST_PROMISE(); - notification_manager_->remove_notification(NotificationGroupId(request.notification_group_id_), - NotificationId(request.notification_id_), false, true, std::move(promise), - "td_api::removeNotification"); + send_closure(notification_manager_actor_, &NotificationManager::remove_notification, + NotificationGroupId(request.notification_group_id_), NotificationId(request.notification_id_), false, + true, std::move(promise), "td_api::removeNotification"); } void Td::on_request(uint64 id, const td_api::removeNotificationGroup &request) { CHECK_IS_USER(); CREATE_OK_REQUEST_PROMISE(); - notification_manager_->remove_notification_group(NotificationGroupId(request.notification_group_id_), - NotificationId(request.max_notification_id_), MessageId(), -1, true, - std::move(promise)); + send_closure(notification_manager_actor_, &NotificationManager::remove_notification_group, + NotificationGroupId(request.notification_group_id_), NotificationId(request.max_notification_id_), + MessageId(), -1, true, std::move(promise)); } void Td::on_request(uint64 id, const td_api::deleteMessages &request) { @@ -5670,7 +5652,7 @@ void Td::on_request(uint64 id, const td_api::createCall &request) { return send_error_raw(id, r_input_user.error().code(), r_input_user.error().message()); } - if (!G()->shared_config().get_option_boolean("calls_enabled")) { + if (!G()->get_option_boolean("calls_enabled")) { return send_error_raw(id, 400, "Calls are not enabled for the current user"); } @@ -8031,6 +8013,18 @@ void Td::on_request(uint64 id, const td_api::pingProxy &request) { send_closure(G()->connection_creator(), &ConnectionCreator::ping_proxy, request.proxy_id_, std::move(query_promise)); } +void Td::on_request(uint64 id, const td_api::getUserSupportInfo &request) { + CHECK_IS_USER(); + CREATE_REQUEST_PROMISE(); + get_user_info(this, UserId(request.user_id_), std::move(promise)); +} + +void Td::on_request(uint64 id, td_api::setUserSupportInfo &request) { + CHECK_IS_USER(); + CREATE_REQUEST_PROMISE(); + set_user_info(this, UserId(request.user_id_), std::move(request.message_), std::move(promise)); +} + void Td::on_request(uint64 id, const td_api::getTextEntities &request) { UNREACHABLE(); } diff --git a/td/telegram/Td.h b/td/telegram/Td.h index 6a1b63bf5..8dcb5cb37 100644 --- a/td/telegram/Td.h +++ b/td/telegram/Td.h @@ -39,7 +39,7 @@ #include #endif #include -#include +#include #include namespace td { @@ -140,6 +140,7 @@ class Td final : public Actor { unique_ptr audios_manager_; unique_ptr callback_queries_manager_; unique_ptr documents_manager_; + unique_ptr option_manager_; unique_ptr video_notes_manager_; unique_ptr videos_manager_; @@ -175,8 +176,6 @@ class Td final : public Actor { ActorOwn notification_manager_actor_; unique_ptr notification_settings_manager_; ActorOwn notification_settings_manager_actor_; - unique_ptr option_manager_; - ActorOwn option_manager_actor_; unique_ptr poll_manager_; ActorOwn poll_manager_actor_; unique_ptr sponsored_message_manager_; @@ -294,7 +293,7 @@ class Td final : public Actor { ConnectionState connection_state_ = ConnectionState::Empty; - std::unordered_multiset request_set_; + std::unordered_multimap request_set_; int actor_refcnt_ = 0; int request_actor_refcnt_ = 0; int stop_cnt_ = 2; @@ -1358,6 +1357,10 @@ class Td final : public Actor { void on_request(uint64 id, const td_api::pingProxy &request); + void on_request(uint64 id, const td_api::getUserSupportInfo &request); + + void on_request(uint64 id, td_api::setUserSupportInfo &request); + void on_request(uint64 id, const td_api::getTextEntities &request); void on_request(uint64 id, const td_api::parseTextEntities &request); diff --git a/td/telegram/TopDialogManager.cpp b/td/telegram/TopDialogManager.cpp index 679b54ede..e57752cd0 100644 --- a/td/telegram/TopDialogManager.cpp +++ b/td/telegram/TopDialogManager.cpp @@ -8,7 +8,6 @@ #include "td/telegram/AccessRights.h" #include "td/telegram/AuthManager.h" -#include "td/telegram/ConfigShared.h" #include "td/telegram/ContactsManager.h" #include "td/telegram/DialogId.h" #include "td/telegram/Global.h" @@ -296,7 +295,7 @@ void TopDialogManager::update_rating_e_decay() { if (!is_active_) { return; } - rating_e_decay_ = narrow_cast(G()->shared_config().get_option_integer("rating_e_decay", rating_e_decay_)); + rating_e_decay_ = narrow_cast(G()->get_option_integer("rating_e_decay", rating_e_decay_)); } template @@ -463,11 +462,11 @@ void TopDialogManager::on_get_top_peers(Resultshared_config().set_option_boolean("disable_top_chats", true); + G()->set_option_boolean("disable_top_chats", true); set_is_enabled(false); // apply immediately break; case telegram_api::contacts_topPeers::ID: { - G()->shared_config().set_option_empty("disable_top_chats"); + G()->set_option_empty("disable_top_chats"); set_is_enabled(true); // apply immediately auto top_peers = move_tl_object_as(std::move(top_peers_parent)); @@ -531,7 +530,7 @@ void TopDialogManager::init() { } is_active_ = G()->parameters().use_chat_info_db && !td_->auth_manager_->is_bot(); - is_enabled_ = !G()->shared_config().get_option_boolean("disable_top_chats"); + is_enabled_ = !G()->get_option_boolean("disable_top_chats"); update_rating_e_decay(); string need_update_top_peers = G()->td_db()->get_binlog_pmc()->get("top_peers_enabled"); diff --git a/td/telegram/UpdatesManager.cpp b/td/telegram/UpdatesManager.cpp index 47b40d599..ffde03cc9 100644 --- a/td/telegram/UpdatesManager.cpp +++ b/td/telegram/UpdatesManager.cpp @@ -14,7 +14,6 @@ #include "td/telegram/ChannelId.h" #include "td/telegram/ChatId.h" #include "td/telegram/ConfigManager.h" -#include "td/telegram/ConfigShared.h" #include "td/telegram/ContactsManager.h" #include "td/telegram/DialogAction.h" #include "td/telegram/DialogId.h" @@ -35,6 +34,7 @@ #include "td/telegram/NotificationManager.h" #include "td/telegram/NotificationSettings.h" #include "td/telegram/NotificationSettingsManager.h" +#include "td/telegram/OptionManager.h" #include "td/telegram/Payments.h" #include "td/telegram/PollId.h" #include "td/telegram/PollManager.h" @@ -1062,6 +1062,8 @@ void UpdatesManager::on_get_updates_state(tl_object_ptr::max()) { LOG(WARNING) << "Restore pts to " << state->pts_; // restoring right pts + CHECK(pending_pts_updates_.empty()); + process_postponed_pts_updates(); // drop all updates with old pts pts_manager_.init(state->pts_); last_get_difference_pts_ = get_pts(); last_pts_save_time_ = Time::now() - 2 * MAX_PTS_SAVE_DELAY; @@ -1553,7 +1555,7 @@ void UpdatesManager::on_get_difference(tl_object_ptrshared_config().get_option_integer("session_count") <= 1) { + if (td_->option_manager_->get_option_integer("session_count") <= 1) { LOG(ERROR) << "Receive differenceTooLong"; } // TODO @@ -2261,8 +2263,8 @@ void UpdatesManager::add_pending_pts_update(tl_object_ptr if (old_pts > new_pts - pts_count) { LOG(WARNING) << "Have old_pts (= " << old_pts << ") + pts_count (= " << pts_count << ") > new_pts (= " << new_pts - << "). Logged in " << G()->shared_config().get_option_integer("authorization_date") << ". Update from " - << source << " = " << oneline(to_string(update)); + << "). Logged in " << td_->option_manager_->get_option_integer("authorization_date") + << ". Update from " << source << " = " << oneline(to_string(update)); postpone_pts_update(std::move(update), new_pts, pts_count, receive_time, std::move(promise)); set_pts_gap_timeout(0.001); return; @@ -2277,8 +2279,8 @@ void UpdatesManager::add_pending_pts_update(tl_object_ptr LOG(WARNING) << "Have old_pts (= " << old_pts << ") + accumulated_pts_count (= " << accumulated_pts_count_ << ") > accumulated_pts (= " << accumulated_pts_ << "). new_pts = " << new_pts << ", pts_count = " << pts_count << ". Logged in " - << G()->shared_config().get_option_integer("authorization_date") << ". Update from " << source << " = " - << oneline(to_string(update)); + << td_->option_manager_->get_option_integer("authorization_date") << ". Update from " << source + << " = " << oneline(to_string(update)); postpone_pts_update(std::move(update), new_pts, pts_count, receive_time, std::move(promise)); set_pts_gap_timeout(0.001); return; @@ -2441,6 +2443,7 @@ void UpdatesManager::process_postponed_pts_updates() { return; } + auto begin_time = Time::now(); auto initial_pts = get_pts(); auto old_pts = initial_pts; int32 skipped_update_count = 0; @@ -2505,6 +2508,14 @@ void UpdatesManager::process_postponed_pts_updates() { << skipped_update_count << ", applying " << applied_update_count << " and keeping " << postponed_pts_updates_.size() << " postponed updates"; } + + auto passed_time = Time::now() - begin_time; + if (passed_time >= 1.0) { + LOG(WARNING) << "Pts has changed from " << initial_pts << " to " << old_pts << " after skipping " + << skipped_update_count << ", applying " << applied_update_count << " and keeping " + << postponed_pts_updates_.size() << " postponed for " << (Time::now() - get_difference_start_time_) + << " updates in " << passed_time; + } } void UpdatesManager::process_pending_pts_updates() { diff --git a/td/telegram/VideoNotesManager.cpp b/td/telegram/VideoNotesManager.cpp index fdedc949a..b810b4f5d 100644 --- a/td/telegram/VideoNotesManager.cpp +++ b/td/telegram/VideoNotesManager.cpp @@ -8,12 +8,15 @@ #include "td/telegram/AuthManager.h" #include "td/telegram/files/FileManager.h" +#include "td/telegram/Global.h" #include "td/telegram/PhotoFormat.h" #include "td/telegram/secret_api.h" #include "td/telegram/Td.h" #include "td/telegram/td_api.h" #include "td/telegram/telegram_api.h" +#include "td/actor/actor.h" + #include "td/telegram/ConfigShared.h" #include "td/utils/logging.h" #include "td/utils/Status.h" diff --git a/td/telegram/VideosManager.cpp b/td/telegram/VideosManager.cpp index 686fa72c5..41ea776be 100644 --- a/td/telegram/VideosManager.cpp +++ b/td/telegram/VideosManager.cpp @@ -8,6 +8,7 @@ #include "td/telegram/AuthManager.h" #include "td/telegram/files/FileManager.h" +#include "td/telegram/Global.h" #include "td/telegram/PhotoFormat.h" #include "td/telegram/secret_api.h" #include "td/telegram/Td.h" @@ -15,6 +16,8 @@ #include "td/telegram/telegram_api.h" #include "td/telegram/ConfigShared.h" +#include "td/actor/actor.h" + #include "td/utils/logging.h" #include "td/utils/misc.h" #include "td/utils/Status.h" diff --git a/td/telegram/WebPagesManager.cpp b/td/telegram/WebPagesManager.cpp index 2e6c85c29..bc2abcd05 100644 --- a/td/telegram/WebPagesManager.cpp +++ b/td/telegram/WebPagesManager.cpp @@ -796,31 +796,20 @@ void WebPagesManager::on_get_web_page_preview_fail(int64 request_id, const strin } int64 WebPagesManager::get_web_page_preview(td_api::object_ptr &&text, Promise &&promise) { - if (text == nullptr) { - promise.set_value(Unit()); + auto r_formatted_text = get_formatted_text(td_, DialogId(), std::move(text), false, true, true, true); + if (r_formatted_text.is_error()) { + promise.set_error(r_formatted_text.move_as_error()); return 0; } + auto formatted_text = r_formatted_text.move_as_ok(); - auto r_entities = get_message_entities(td_->contacts_manager_.get(), std::move(text->entities_)); - if (r_entities.is_error()) { - promise.set_error(r_entities.move_as_error()); - return 0; - } - auto entities = r_entities.move_as_ok(); - - auto result = fix_formatted_text(text->text_, entities, true, false, true, true, false); - if (result.is_error() || text->text_.empty()) { - promise.set_value(Unit()); - return 0; - } - - auto url = get_first_url(text->text_, entities); + auto url = get_first_url(formatted_text); if (url.empty()) { promise.set_value(Unit()); return 0; } - LOG(INFO) << "Trying to get web page preview for message \"" << text->text_ << '"'; + LOG(INFO) << "Trying to get web page preview for message \"" << formatted_text.text << '"'; int64 request_id = get_web_page_preview_request_id_++; auto web_page_id = get_web_page_by_url(url); @@ -829,8 +818,10 @@ int64 WebPagesManager::get_web_page_preview(td_api::object_ptrcreate_handler(std::move(promise)) - ->send(text->text_, get_input_message_entities(td_->contacts_manager_.get(), entities, "get_web_page_preview"), - request_id, std::move(url)); + ->send( + formatted_text.text, + get_input_message_entities(td_->contacts_manager_.get(), formatted_text.entities, "get_web_page_preview"), + request_id, std::move(url)); } return request_id; } diff --git a/td/telegram/cli.cpp b/td/telegram/cli.cpp index 44f275d53..97ef04e2a 100644 --- a/td/telegram/cli.cpp +++ b/td/telegram/cli.cpp @@ -1127,6 +1127,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))); @@ -4823,6 +4829,15 @@ class CliClient final : public Actor { send_request(td_api::make_object(as_proxy_id(args))); } else if (op == "pproxy") { send_request(td_api::make_object(as_proxy_id(args))); + } else if (op == "gusi") { + UserId user_id; + get_args(args, user_id); + send_request(td_api::make_object(user_id)); + } else if (op == "susi") { + UserId user_id; + string text; + get_args(args, user_id, text); + send_request(td_api::make_object(user_id, as_formatted_text(text))); } else if (op == "touch") { auto r_fd = FileFd::open(args, FileFd::Read | FileFd::Write); if (r_fd.is_error()) { diff --git a/td/telegram/files/FileGcParameters.cpp b/td/telegram/files/FileGcParameters.cpp index 1fb8cef5f..b541fe59e 100644 --- a/td/telegram/files/FileGcParameters.cpp +++ b/td/telegram/files/FileGcParameters.cpp @@ -6,7 +6,6 @@ // #include "td/telegram/files/FileGcParameters.h" -#include "td/telegram/ConfigShared.h" #include "td/telegram/Global.h" #include "td/utils/format.h" @@ -21,17 +20,16 @@ FileGcParameters::FileGcParameters(int64 size, int32 ttl, int32 count, int32 imm , owner_dialog_ids_(std::move(owner_dialog_ids)) , exclude_owner_dialog_ids_(std::move(exclude_owner_dialog_ids)) , dialog_limit_(dialog_limit) { - auto &config = G()->shared_config(); - max_files_size_ = size >= 0 ? size : config.get_option_integer("storage_max_files_size", 100 << 10) << 10; + max_files_size_ = size >= 0 ? size : G()->get_option_integer("storage_max_files_size", 100 << 10) << 10; max_time_from_last_access_ = - ttl >= 0 ? ttl : narrow_cast(config.get_option_integer("storage_max_time_from_last_access", 60 * 60 * 23)); + ttl >= 0 ? ttl : narrow_cast(G()->get_option_integer("storage_max_time_from_last_access", 60 * 60 * 23)); - max_file_count_ = count >= 0 ? count : narrow_cast(config.get_option_integer("storage_max_file_count", 40000)); + max_file_count_ = count >= 0 ? count : narrow_cast(G()->get_option_integer("storage_max_file_count", 40000)); immunity_delay_ = immunity_delay >= 0 ? immunity_delay - : narrow_cast(config.get_option_integer("storage_immunity_delay", 60 * 60)); + : narrow_cast(G()->get_option_integer("storage_immunity_delay", 60 * 60)); } StringBuilder &operator<<(StringBuilder &string_builder, const FileGcParameters ¶meters) { diff --git a/td/telegram/files/FileLoadManager.cpp b/td/telegram/files/FileLoadManager.cpp index ff291a1d9..e7656d2d1 100644 --- a/td/telegram/files/FileLoadManager.cpp +++ b/td/telegram/files/FileLoadManager.cpp @@ -6,7 +6,6 @@ // #include "td/telegram/files/FileLoadManager.h" -#include "td/telegram/ConfigShared.h" #include "td/telegram/Global.h" #include "td/telegram/net/DcId.h" #include "td/telegram/TdParameters.h" @@ -29,7 +28,7 @@ void FileLoadManager::start_up() { !G()->parameters().use_file_db /*tdlib_engine*/ ? ResourceManager::Mode::Greedy : ResourceManager::Mode::Baseline); - if (G()->shared_config().get_option_boolean("is_premium")) { + if (G()->get_option_boolean("is_premium")) { max_download_resource_limit_ *= 8; } } diff --git a/td/telegram/files/FileManager.cpp b/td/telegram/files/FileManager.cpp index 64e284e04..cff4be731 100644 --- a/td/telegram/files/FileManager.cpp +++ b/td/telegram/files/FileManager.cpp @@ -6,7 +6,6 @@ // #include "td/telegram/files/FileManager.h" -#include "td/telegram/ConfigShared.h" #include "td/telegram/DownloadManager.h" #include "td/telegram/FileReferenceManager.h" #include "td/telegram/files/FileData.h" @@ -999,7 +998,7 @@ Status FileManager::check_local_location(FullLocalFileLocation &location, int64 return get_file_size_error(" for a photo"); } if (location.file_type_ == FileType::VideoNote && - size > G()->shared_config().get_option_integer("video_note_size_max", DEFAULT_VIDEO_NOTE_SIZE_MAX)) { + size > G()->get_option_integer("video_note_size_max", DEFAULT_VIDEO_NOTE_SIZE_MAX)) { return get_file_size_error(" for a video note"); } return Status::OK(); @@ -2027,7 +2026,7 @@ bool FileManager::set_encryption_key(FileId file_id, FileEncryptionKey key) { } bool FileManager::set_content(FileId file_id, BufferSlice bytes) { - if (G()->shared_config().get_option_boolean("ignore_inline_thumbnails")) { + if (G()->get_option_boolean("ignore_inline_thumbnails")) { return false; } @@ -2577,7 +2576,7 @@ void FileManager::resume_upload(FileId file_id, vector bad_parts, std::shar return; } - if (file_view.has_local_location()) { + if (file_view.has_local_location() && new_priority != 0) { auto status = check_local_location(node); if (status.is_error()) { LOG(INFO) << "Full local location of file " << file_id << " for upload is invalid: " << status; @@ -3169,7 +3168,7 @@ Result FileManager::get_input_file_id(FileType type, const tl_object_ptr return FileId(); } string hash; - if (G()->shared_config().get_option_boolean("reuse_uploaded_photos_by_hash") && new_type == FileType::Photo) { + if (G()->get_option_boolean("reuse_uploaded_photos_by_hash") && new_type == FileType::Photo) { auto r_stat = stat(path); if (r_stat.is_ok() && r_stat.ok().size_ > 0 && r_stat.ok().size_ < 11000000) { auto r_file_content = read_file_str(path, r_stat.ok().size_); diff --git a/td/telegram/files/FileManager.h b/td/telegram/files/FileManager.h index 6edfe601d..c3b2d4455 100644 --- a/td/telegram/files/FileManager.h +++ b/td/telegram/files/FileManager.h @@ -26,7 +26,6 @@ #include "td/utils/common.h" #include "td/utils/Container.h" #include "td/utils/Enumerator.h" -#include "td/utils/FlatHashMap.h" #include "td/utils/FlatHashSet.h" #include "td/utils/logging.h" #include "td/utils/optional.h" diff --git a/td/telegram/net/ConnectionCreator.cpp b/td/telegram/net/ConnectionCreator.cpp index 9ca56b401..e24984cfa 100644 --- a/td/telegram/net/ConnectionCreator.cpp +++ b/td/telegram/net/ConnectionCreator.cpp @@ -7,7 +7,6 @@ #include "td/telegram/net/ConnectionCreator.h" #include "td/telegram/ConfigManager.h" -#include "td/telegram/ConfigShared.h" #include "td/telegram/Global.h" #include "td/telegram/logevent/LogEvent.h" #include "td/telegram/MessagesManager.h" @@ -234,7 +233,7 @@ void ConnectionCreator::get_proxy_link(int32 proxy_id, Promise promise) } auto &proxy = it->second; - string url = G()->shared_config().get_option_string("t_me_url", "https://t.me/"); + string url = G()->get_option_string("t_me_url", "https://t.me/"); bool is_socks = false; switch (proxy.type()) { case Proxy::Type::Socks5: @@ -269,7 +268,7 @@ void ConnectionCreator::get_proxy_link(int32 proxy_id, Promise promise) } ActorId ConnectionCreator::get_dns_resolver() { - if (G()->shared_config().get_option_boolean("expect_blocking", true)) { + if (G()->get_option_boolean("expect_blocking", true)) { if (block_get_host_by_name_actor_.empty()) { VLOG(connections) << "Init block bypass DNS resolver"; GetHostByNameActor::Options options; @@ -297,7 +296,7 @@ void ConnectionCreator::ping_proxy(int32 proxy_id, Promise promise) { CHECK(!close_flag_); if (proxy_id == 0) { auto main_dc_id = G()->net_query_dispatcher().get_main_dc_id(); - bool prefer_ipv6 = G()->shared_config().get_option_boolean("prefer_ipv6"); + bool prefer_ipv6 = G()->get_option_boolean("prefer_ipv6"); auto infos = dc_options_set_.find_all_connections(main_dc_id, false, false, prefer_ipv6, false); if (infos.empty()) { return promise.set_error(Status::Error(400, "Can't find valid DC address")); @@ -344,7 +343,7 @@ void ConnectionCreator::ping_proxy(int32 proxy_id, Promise promise) { return promise.set_error(Status::Error(400, "Unknown proxy identifier")); } const Proxy &proxy = it->second; - bool prefer_ipv6 = G()->shared_config().get_option_boolean("prefer_ipv6"); + bool prefer_ipv6 = G()->get_option_boolean("prefer_ipv6"); send_closure(get_dns_resolver(), &GetHostByNameActor::run, proxy.server().str(), proxy.port(), prefer_ipv6, PromiseCreator::lambda([actor_id = actor_id(this), promise = std::move(promise), proxy_id](Result result) mutable { @@ -413,9 +412,9 @@ void ConnectionCreator::ping_proxy_buffered_socket_fd(IPAddress ip_address, Buff void ConnectionCreator::set_active_proxy_id(int32 proxy_id, bool from_binlog) { active_proxy_id_ = proxy_id; if (proxy_id == 0) { - G()->shared_config().set_option_empty("enabled_proxy_id"); + G()->set_option_empty("enabled_proxy_id"); } else { - G()->shared_config().set_option_integer("enabled_proxy_id", proxy_id); + G()->set_option_integer("enabled_proxy_id", proxy_id); } if (!from_binlog) { if (proxy_id == 0) { @@ -701,8 +700,7 @@ Result ConnectionCreator::get_transport_type(const Proxy Result ConnectionCreator::find_connection(const Proxy &proxy, const IPAddress &proxy_ip_address, DcId dc_id, bool allow_media_only, FindConnectionExtra &extra) { extra.debug_str = PSTRING() << "Failed to find valid IP address for " << dc_id; - bool prefer_ipv6 = - G()->shared_config().get_option_boolean("prefer_ipv6") || (proxy.use_proxy() && proxy_ip_address.is_ipv6()); + bool prefer_ipv6 = G()->get_option_boolean("prefer_ipv6") || (proxy.use_proxy() && proxy_ip_address.is_ipv6()); bool only_http = proxy.use_http_caching_proxy(); #if TD_DARWIN_WATCH_OS only_http = true; @@ -1281,7 +1279,7 @@ void ConnectionCreator::loop() { if (resolve_proxy_query_token_ == 0) { resolve_proxy_query_token_ = next_token(); const Proxy &proxy = proxies_[active_proxy_id_]; - bool prefer_ipv6 = G()->shared_config().get_option_boolean("prefer_ipv6"); + bool prefer_ipv6 = G()->get_option_boolean("prefer_ipv6"); VLOG(connections) << "Resolve IP address " << resolve_proxy_query_token_ << " of " << proxy.server(); send_closure( get_dns_resolver(), &GetHostByNameActor::run, proxy.server().str(), proxy.port(), prefer_ipv6, diff --git a/td/telegram/net/NetQuery.cpp b/td/telegram/net/NetQuery.cpp index 7250fcd1f..016116287 100644 --- a/td/telegram/net/NetQuery.cpp +++ b/td/telegram/net/NetQuery.cpp @@ -22,10 +22,6 @@ namespace td { int VERBOSITY_NAME(net_query) = VERBOSITY_NAME(INFO); -int64 NetQuery::get_my_id() { - return G()->get_my_id(); -} - void NetQuery::debug(string state, bool may_be_lost) { may_be_lost_ = may_be_lost; VLOG(net_query) << *this << " " << tag("state", state); @@ -57,7 +53,7 @@ NetQuery::NetQuery(State state, uint64 id, BufferSlice &&query, BufferSlice &&an td::unique(chain_ids_); auto &data = get_data_unsafe(); - data.my_id_ = get_my_id(); + data.my_id_ = G()->get_option_integer("my_id"); data.start_timestamp_ = data.state_timestamp_ = Time::now(); LOG(INFO) << *this; if (stats) { diff --git a/td/telegram/net/NetQuery.h b/td/telegram/net/NetQuery.h index d885bd784..aede39251 100644 --- a/td/telegram/net/NetQuery.h +++ b/td/telegram/net/NetQuery.h @@ -329,8 +329,6 @@ class NetQuery final : public TsListNode { source_ = std::move(source); } - static int64 get_my_id(); - static int32 tl_magic(const BufferSlice &buffer_slice); public: diff --git a/td/telegram/net/NetQueryDispatcher.cpp b/td/telegram/net/NetQueryDispatcher.cpp index e94845e72..41492d555 100644 --- a/td/telegram/net/NetQueryDispatcher.cpp +++ b/td/telegram/net/NetQueryDispatcher.cpp @@ -6,7 +6,6 @@ // #include "td/telegram/net/NetQueryDispatcher.h" -#include "td/telegram/ConfigShared.h" #include "td/telegram/Global.h" #include "td/telegram/net/AuthDataShared.h" #include "td/telegram/net/DcAuthManager.h" @@ -47,7 +46,7 @@ void NetQueryDispatcher::dispatch(NetQueryPtr net_query) { net_query->set_error(Global::request_aborted_error()); return complete_net_query(std::move(net_query)); } - if (G()->shared_config().get_option_boolean("test_flood_wait")) { + if (G()->get_option_boolean("test_flood_wait")) { net_query->set_error(Status::Error(429, "Too Many Requests: retry after 10")); return complete_net_query(std::move(net_query)); // if (net_query->is_ok() && net_query->tl_constructor() == 0x0d9d75a4) { @@ -168,7 +167,7 @@ Status NetQueryDispatcher::wait_dc_init(DcId dc_id, bool force) { int32 slow_net_scheduler_id = G()->get_slow_net_scheduler_id(); auto raw_dc_id = dc_id.get_raw_id(); - bool is_premium = G()->shared_config().get_option_boolean("is_premium"); + bool is_premium = G()->get_option_boolean("is_premium"); int32 upload_session_count = (raw_dc_id != 2 && raw_dc_id != 4) || is_premium ? 8 : 4; int32 download_session_count = is_premium ? 8 : 2; int32 download_small_session_count = is_premium ? 8 : 2; @@ -278,11 +277,11 @@ bool NetQueryDispatcher::is_dc_inited(int32 raw_dc_id) { } int32 NetQueryDispatcher::get_session_count() { - return max(narrow_cast(G()->shared_config().get_option_integer("session_count")), 1); + return max(narrow_cast(G()->get_option_integer("session_count")), 1); } bool NetQueryDispatcher::get_use_pfs() { - return G()->shared_config().get_option_boolean("use_pfs") || get_session_count() > 1; + return G()->get_option_boolean("use_pfs") || get_session_count() > 1; } NetQueryDispatcher::NetQueryDispatcher(const std::function()> &create_reference) { diff --git a/td/telegram/net/NetStatsManager.cpp b/td/telegram/net/NetStatsManager.cpp index daa9515c9..7fbb93149 100644 --- a/td/telegram/net/NetStatsManager.cpp +++ b/td/telegram/net/NetStatsManager.cpp @@ -6,7 +6,6 @@ // #include "td/telegram/net/NetStatsManager.h" -#include "td/telegram/ConfigShared.h" #include "td/telegram/Global.h" #include "td/telegram/logevent/LogEvent.h" #include "td/telegram/StateManager.h" @@ -213,7 +212,7 @@ void NetStatsManager::start_up() { auto since_str = G()->td_db()->get_binlog_pmc()->get("net_stats_since"); if (!since_str.empty()) { auto since = to_integer(since_str); - auto authorization_date = G()->shared_config().get_option_integer("authorization_date"); + auto authorization_date = G()->get_option_integer("authorization_date"); if (unix_time < since) { since_total_ = unix_time; G()->td_db()->get_binlog_pmc()->set("net_stats_since", to_string(since_total_)); @@ -290,7 +289,7 @@ void NetStatsManager::update(NetStatsInfo &info, bool force_save) { } void NetStatsManager::save_stats(NetStatsInfo &info, NetType net_type) { - if (G()->shared_config().get_option_boolean("disable_persistent_network_statistics")) { + if (G()->get_option_boolean("disable_persistent_network_statistics")) { return; } diff --git a/td/telegram/net/SessionMultiProxy.cpp b/td/telegram/net/SessionMultiProxy.cpp index 462a0765b..3051cccf0 100644 --- a/td/telegram/net/SessionMultiProxy.cpp +++ b/td/telegram/net/SessionMultiProxy.cpp @@ -65,9 +65,11 @@ void SessionMultiProxy::update_destroy_auth_key(bool need_destroy_auth_key) { need_destroy_auth_key_ = need_destroy_auth_key; send_closure(sessions_[0].proxy, &SessionProxy::update_destroy, need_destroy_auth_key_); } + void SessionMultiProxy::update_session_count(int32 session_count) { update_options(session_count, use_pfs_); } + void SessionMultiProxy::update_use_pfs(bool use_pfs) { update_options(session_count_, use_pfs); } diff --git a/tdactor/td/actor/impl/Scheduler.h b/tdactor/td/actor/impl/Scheduler.h index 74910ff53..b9022c75a 100644 --- a/tdactor/td/actor/impl/Scheduler.h +++ b/tdactor/td/actor/impl/Scheduler.h @@ -15,6 +15,7 @@ #include "td/utils/ObjectPool.h" #include "td/utils/port/detail/PollableFd.h" #include "td/utils/port/PollFlags.h" +#include "td/utils/Promise.h" #include "td/utils/Slice.h" #include "td/utils/Time.h" diff --git a/tddb/td/db/SeqKeyValue.h b/tddb/td/db/SeqKeyValue.h index 6cf5627c2..e785f2140 100644 --- a/tddb/td/db/SeqKeyValue.h +++ b/tddb/td/db/SeqKeyValue.h @@ -32,6 +32,7 @@ class SeqKeyValue { } return next_seq_no(); } + SeqNo erase(const string &key) { auto it = map_.find(key); if (it == map_.end()) { @@ -40,9 +41,11 @@ class SeqKeyValue { map_.erase(it); return next_seq_no(); } + SeqNo seq_no() const { return current_id_ + 1; } + string get(const string &key) const { auto it = map_.find(key); if (it == map_.end()) { @@ -51,11 +54,12 @@ class SeqKeyValue { return it->second; } - template - void foreach(const F &f) { - for (auto &it : map_) { - f(it.first, it.second); + bool isset(const string &key) const { + auto it = map_.find(key); + if (it == map_.end()) { + return false; } + return true; } size_t size() const { diff --git a/tddb/td/db/SqliteConnectionSafe.cpp b/tddb/td/db/SqliteConnectionSafe.cpp index fd11d941e..a3c13d712 100644 --- a/tddb/td/db/SqliteConnectionSafe.cpp +++ b/tddb/td/db/SqliteConnectionSafe.cpp @@ -18,7 +18,7 @@ SqliteConnectionSafe::SqliteConnectionSafe(string path, DbKey key, optionalload() << ": " << r_db.error().message(); } auto db = r_db.move_as_ok(); db.exec("PRAGMA journal_mode=WAL").ensure(); diff --git a/tddb/td/db/SqliteConnectionSafe.h b/tddb/td/db/SqliteConnectionSafe.h index 8e98b54c7..a8bae2b3c 100644 --- a/tddb/td/db/SqliteConnectionSafe.h +++ b/tddb/td/db/SqliteConnectionSafe.h @@ -14,6 +14,8 @@ #include "td/utils/common.h" #include "td/utils/optional.h" +#include + namespace td { class SqliteConnectionSafe { @@ -30,7 +32,7 @@ class SqliteConnectionSafe { private: string path_; - uint32 close_state_ = 0; + std::atomic close_state_{0}; LazySchedulerLocalStorage lsls_connection_; }; diff --git a/tddb/td/db/TsSeqKeyValue.h b/tddb/td/db/TsSeqKeyValue.h index e26810831..dca0b03b4 100644 --- a/tddb/td/db/TsSeqKeyValue.h +++ b/tddb/td/db/TsSeqKeyValue.h @@ -33,29 +33,41 @@ class TsSeqKeyValue { auto lock = rw_mutex_.lock_write().move_as_ok(); return kv_.set(key, value); } + std::pair set_and_lock(Slice key, Slice value) { auto lock = rw_mutex_.lock_write().move_as_ok(); return std::make_pair(kv_.set(key, value), std::move(lock)); } + SeqNo erase(const string &key) { auto lock = rw_mutex_.lock_write().move_as_ok(); return kv_.erase(key); } + std::pair erase_and_lock(const string &key) { auto lock = rw_mutex_.lock_write().move_as_ok(); return std::make_pair(kv_.erase(key), std::move(lock)); } - string get(const string &key) { + + string get(const string &key) const { auto lock = rw_mutex_.lock_read().move_as_ok(); return kv_.get(key); } + + bool isset(const string &key) const { + auto lock = rw_mutex_.lock_read().move_as_ok(); + return kv_.isset(key); + } + size_t size() const { return kv_.size(); } - std::unordered_map get_all() { + + std::unordered_map get_all() const { auto lock = rw_mutex_.lock_write().move_as_ok(); return kv_.get_all(); } + // not thread safe method SeqKeyValue &inner() { return kv_; @@ -66,7 +78,7 @@ class TsSeqKeyValue { } private: - RwMutex rw_mutex_; + mutable RwMutex rw_mutex_; SeqKeyValue kv_; }; diff --git a/tdnet/td/net/HttpChunkedByteFlow.cpp b/tdnet/td/net/HttpChunkedByteFlow.cpp index 40c213180..95fb850b9 100644 --- a/tdnet/td/net/HttpChunkedByteFlow.cpp +++ b/tdnet/td/net/HttpChunkedByteFlow.cpp @@ -46,12 +46,12 @@ bool HttpChunkedByteFlow::loop() { set_need_size(need_size); break; } - total_size_ += ready; - uncommited_size_ += ready; - if (total_size_ > MAX_SIZE) { + if (total_size_ > MAX_SIZE - ready) { finish(Status::Error(PSLICE() << "Too big query " << tag("size", input_->size()))); return false; } + total_size_ += ready; + uncommited_size_ += ready; output_.append(input_->cut_head(ready)); result = true; diff --git a/tdnet/td/net/HttpChunkedByteFlow.h b/tdnet/td/net/HttpChunkedByteFlow.h index 5b9532769..4e00fb80c 100644 --- a/tdnet/td/net/HttpChunkedByteFlow.h +++ b/tdnet/td/net/HttpChunkedByteFlow.h @@ -17,8 +17,8 @@ class HttpChunkedByteFlow final : public ByteFlowBase { bool loop() final; private: - static constexpr int MAX_CHUNK_SIZE = 15 << 20; // some reasonable limit - static constexpr int MAX_SIZE = std::numeric_limits::max(); // some reasonable limit + static constexpr size_t MAX_CHUNK_SIZE = 15 << 20; // some reasonable limit + static constexpr size_t MAX_SIZE = std::numeric_limits::max(); // some reasonable limit static constexpr size_t MIN_UPDATE_SIZE = 1 << 14; enum class State { ReadChunkLength, ReadChunkContent, OK }; State state_ = State::ReadChunkLength; diff --git a/tdnet/td/net/HttpReader.cpp b/tdnet/td/net/HttpReader.cpp index 7a914374a..416356cde 100644 --- a/tdnet/td/net/HttpReader.cpp +++ b/tdnet/td/net/HttpReader.cpp @@ -103,7 +103,7 @@ Result HttpReader::read_next(HttpQuery *query, bool can_be_slow) { *source >> flow_sink_; content_ = flow_sink_.get_output(); - if (content_length_ > MAX_CONTENT_SIZE) { + if (content_length_ >= MAX_CONTENT_SIZE) { return Status::Error(413, PSLICE() << "Request Entity Too Large: content length is " << content_length_); } @@ -320,7 +320,7 @@ Result HttpReader::parse_multipart_form_data(bool can_be_slow) { header_value.remove_prefix(10); while (true) { header_value = trim(header_value); - const char *key_end = + const auto *key_end = static_cast(std::memchr(header_value.data(), '=', header_value.size())); if (key_end == nullptr) { break; @@ -558,7 +558,11 @@ void HttpReader::process_header(MutableSlice header_name, MutableSlice header_va // TODO: check if protocol is HTTP/1.1 query_->keep_alive_ = true; if (header_name == "content-length") { - content_length_ = to_integer(header_value); + auto content_length = to_integer(header_value); + if (content_length > MAX_CONTENT_SIZE) { + content_length = MAX_CONTENT_SIZE; + } + content_length_ = static_cast(content_length); } else if (header_name == "connection") { to_lower_inplace(header_value); if (header_value == "close") { diff --git a/tdnet/td/net/HttpReader.h b/tdnet/td/net/HttpReader.h index 4e86795a3..3851e7467 100644 --- a/tdnet/td/net/HttpReader.h +++ b/tdnet/td/net/HttpReader.h @@ -101,11 +101,11 @@ class HttpReader { void close_temp_file(); void clean_temporary_file(); - static constexpr size_t MAX_CONTENT_SIZE = std::numeric_limits::max(); // Some reasonable limit - static constexpr size_t MAX_TOTAL_PARAMETERS_LENGTH = 1 << 20; // Some reasonable limit - static constexpr size_t MAX_TOTAL_HEADERS_LENGTH = 1 << 18; // Some reasonable limit - static constexpr size_t MAX_BOUNDARY_LENGTH = 70; // As defined by RFC1341 - static constexpr int64 MAX_FILE_SIZE = static_cast(4000) << 20; // Telegram server file size limit + static constexpr size_t MAX_CONTENT_SIZE = std::numeric_limits::max(); // Some reasonable limit + static constexpr size_t MAX_TOTAL_PARAMETERS_LENGTH = 1 << 20; // Some reasonable limit + static constexpr size_t MAX_TOTAL_HEADERS_LENGTH = 1 << 18; // Some reasonable limit + static constexpr size_t MAX_BOUNDARY_LENGTH = 70; // As defined by RFC1341 + static constexpr int64 MAX_FILE_SIZE = static_cast(4000) << 20; // Telegram server file size limit static constexpr const char TEMP_DIRECTORY_PREFIX[] = "tdlib-server-tmp"; }; diff --git a/tdtl/td/tl/tl_config.cpp b/tdtl/td/tl/tl_config.cpp index 0ec4ec4fb..871b7e22b 100644 --- a/tdtl/td/tl/tl_config.cpp +++ b/tdtl/td/tl/tl_config.cpp @@ -344,6 +344,7 @@ tl_config tl_config_parser::parse_config() { std::int32_t constructors_n = try_parse_int(); assert(static_cast(constructors_n) == constructors_total); + (void)constructors_total; for (std::int32_t i = 0; i < constructors_n; i++) { tl_combinator *constructor = read_combinator(); config.get_type(constructor->type_id)->add_constructor(constructor); diff --git a/tdutils/CMakeLists.txt b/tdutils/CMakeLists.txt index 7eed9eb24..b273157e0 100644 --- a/tdutils/CMakeLists.txt +++ b/tdutils/CMakeLists.txt @@ -294,6 +294,7 @@ set(TDUTILS_SOURCE td/utils/Variant.h td/utils/VectorQueue.h td/utils/WaitFreeHashMap.h + td/utils/WaitFreeHashSet.h td/utils/WaitFreeVector.h ) @@ -336,6 +337,7 @@ set(TDUTILS_TEST_SOURCE ${CMAKE_CURRENT_SOURCE_DIR}/test/StealingQueue.cpp ${CMAKE_CURRENT_SOURCE_DIR}/test/variant.cpp ${CMAKE_CURRENT_SOURCE_DIR}/test/WaitFreeHashMap.cpp + ${CMAKE_CURRENT_SOURCE_DIR}/test/WaitFreeHashSet.cpp ${CMAKE_CURRENT_SOURCE_DIR}/test/WaitFreeVector.cpp PARENT_SCOPE ) diff --git a/tdutils/td/utils/Hints.cpp b/tdutils/td/utils/Hints.cpp index dfe584fc5..762281315 100644 --- a/tdutils/td/utils/Hints.cpp +++ b/tdutils/td/utils/Hints.cpp @@ -34,7 +34,7 @@ vector Hints::fix_words(vector words) { return words; } -vector Hints::get_words(Slice name, bool is_search) { +vector Hints::get_words(Slice name) { bool in_word = false; string word; vector words; @@ -42,7 +42,7 @@ vector Hints::get_words(Slice name, bool is_search) { auto end = name.uend(); while (pos != end) { uint32 code; - pos = next_utf8_unsafe(pos, &code, is_search ? "get_words_search" : "get_words_add"); + pos = next_utf8_unsafe(pos, &code); code = prepare_search_character(code); if (code == 0) { @@ -94,7 +94,7 @@ void Hints::add(KeyT key, Slice name) { return; } vector old_transliterations; - for (auto &old_word : get_words(it->second, false)) { + for (auto &old_word : get_words(it->second)) { delete_word(old_word, key, word_to_keys_); for (auto &w : get_word_transliterations(old_word, false)) { @@ -116,7 +116,7 @@ void Hints::add(KeyT key, Slice name) { } vector transliterations; - for (auto &word : get_words(name, false)) { + for (auto &word : get_words(name)) { add_word(word, key, word_to_keys_); for (auto &w : get_word_transliterations(word, false)) { @@ -166,7 +166,7 @@ std::pair> Hints::search(Slice query, int32 limit, b return {key_to_name_.size(), std::move(results)}; } - auto words = get_words(query, true); + auto words = get_words(query); if (return_all_for_empty_query && words.empty()) { results.reserve(key_to_name_.size()); for (auto &it : key_to_name_) { diff --git a/tdutils/td/utils/Hints.h b/tdutils/td/utils/Hints.h index d9f4115c7..f59e45f50 100644 --- a/tdutils/td/utils/Hints.h +++ b/tdutils/td/utils/Hints.h @@ -52,7 +52,7 @@ class Hints { static vector fix_words(vector words); - static vector get_words(Slice name, bool is_search); + static vector get_words(Slice name); static void add_search_results(vector &results, const string &word, const std::map> &word_to_keys); diff --git a/tdutils/td/utils/WaitFreeHashMap.h b/tdutils/td/utils/WaitFreeHashMap.h index 8fe04b24b..6d55e9150 100644 --- a/tdutils/td/utils/WaitFreeHashMap.h +++ b/tdutils/td/utils/WaitFreeHashMap.h @@ -43,7 +43,7 @@ class WaitFreeHashMap { return const_cast(this)->get_storage(key); } - void split() { + void split_storage() { CHECK(wait_free_storage_ == nullptr); wait_free_storage_ = make_unique(); for (auto &it : default_map_) { @@ -57,7 +57,7 @@ class WaitFreeHashMap { auto &storage = get_storage(key); storage[key] = std::move(value); if (default_map_.size() == MAX_STORAGE_SIZE) { - split(); + split_storage(); } } @@ -103,7 +103,7 @@ class WaitFreeHashMap { return result; } - split(); + split_storage(); } return get_wait_free_storage(key)[key]; diff --git a/tdutils/td/utils/WaitFreeHashSet.h b/tdutils/td/utils/WaitFreeHashSet.h new file mode 100644 index 000000000..e2cec3777 --- /dev/null +++ b/tdutils/td/utils/WaitFreeHashSet.h @@ -0,0 +1,114 @@ +// +// 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/utils/common.h" +#include "td/utils/FlatHashSet.h" +#include "td/utils/HashTableUtils.h" + +#include + +namespace td { + +template , class EqT = std::equal_to> +class WaitFreeHashSet { + using Storage = FlatHashSet; + static constexpr size_t MAX_STORAGE_COUNT = 256; + static_assert((MAX_STORAGE_COUNT & (MAX_STORAGE_COUNT - 1)) == 0, ""); + static constexpr size_t MAX_STORAGE_SIZE = MAX_STORAGE_COUNT * MAX_STORAGE_COUNT / 2; + + Storage default_set_; + struct WaitFreeStorage { + Storage sets_[MAX_STORAGE_COUNT]; + }; + unique_ptr wait_free_storage_; + + Storage &get_wait_free_storage(const KeyT &key) { + return wait_free_storage_->sets_[randomize_hash(HashT()(key)) & (MAX_STORAGE_COUNT - 1)]; + } + + Storage &get_storage(const KeyT &key) { + if (wait_free_storage_ == nullptr) { + return default_set_; + } + + return get_wait_free_storage(key); + } + + const Storage &get_storage(const KeyT &key) const { + return const_cast(this)->get_storage(key); + } + + void split_storage() { + CHECK(wait_free_storage_ == nullptr); + wait_free_storage_ = make_unique(); + for (auto &it : default_set_) { + get_wait_free_storage(it).insert(it); + } + default_set_.clear(); + } + + public: + void insert(const KeyT &key) { + auto &storage = get_storage(key); + storage.insert(key); + if (default_set_.size() == MAX_STORAGE_SIZE) { + split_storage(); + } + } + + size_t count(const KeyT &key) const { + const auto &storage = get_storage(key); + return storage.count(key); + } + + size_t erase(const KeyT &key) { + return get_storage(key).erase(key); + } + + void foreach(std::function callback) const { + if (wait_free_storage_ == nullptr) { + for (auto &it : default_set_) { + callback(it); + } + return; + } + + for (size_t i = 0; i < MAX_STORAGE_COUNT; i++) { + for (auto &it : wait_free_storage_->sets_[i]) { + callback(it); + } + } + } + + size_t size() const { + if (wait_free_storage_ == nullptr) { + return default_set_.size(); + } + + size_t result = 0; + for (size_t i = 0; i < MAX_STORAGE_COUNT; i++) { + result += wait_free_storage_->sets_[i].size(); + } + return result; + } + + bool empty() const { + if (wait_free_storage_ == nullptr) { + return default_set_.empty(); + } + + for (size_t i = 0; i < MAX_STORAGE_COUNT; i++) { + if (!wait_free_storage_->sets_[i].empty()) { + return false; + } + } + return true; + } +}; + +} // namespace td diff --git a/tdutils/td/utils/WaitFreeVector.h b/tdutils/td/utils/WaitFreeVector.h index dc57fb1e2..40ffd41c6 100644 --- a/tdutils/td/utils/WaitFreeVector.h +++ b/tdutils/td/utils/WaitFreeVector.h @@ -8,6 +8,8 @@ #include "td/utils/common.h" +#include + namespace td { template diff --git a/tdutils/td/utils/filesystem.cpp b/tdutils/td/utils/filesystem.cpp index ae7483cf4..edb5df867 100644 --- a/tdutils/td/utils/filesystem.cpp +++ b/tdutils/td/utils/filesystem.cpp @@ -133,7 +133,7 @@ static string clean_filename_part(Slice name, int max_length) { int size = 0; for (auto *it = name.ubegin(); it != name.uend() && size < max_length;) { uint32 code; - it = next_utf8_unsafe(it, &code, "clean_filename_part"); + it = next_utf8_unsafe(it, &code); if (!is_ok(code)) { if (prepare_search_character(code) == 0) { continue; diff --git a/tdutils/td/utils/port/IPAddress.cpp b/tdutils/td/utils/port/IPAddress.cpp index 7e1e72532..32c26403d 100644 --- a/tdutils/td/utils/port/IPAddress.cpp +++ b/tdutils/td/utils/port/IPAddress.cpp @@ -53,7 +53,7 @@ static void punycode(string &result, Slice part) { auto end = part.uend(); while (begin != end) { uint32 code; - begin = next_utf8_unsafe(begin, &code, "punycode"); + begin = next_utf8_unsafe(begin, &code); if (code <= 127u) { result += to_lower(static_cast(code)); processed++; diff --git a/tdutils/td/utils/port/detail/ThreadPthread.cpp b/tdutils/td/utils/port/detail/ThreadPthread.cpp index 30234d0aa..64ea20dc0 100644 --- a/tdutils/td/utils/port/detail/ThreadPthread.cpp +++ b/tdutils/td/utils/port/detail/ThreadPthread.cpp @@ -14,6 +14,7 @@ char disable_linker_warning_about_empty_file_thread_pthread_cpp TD_UNUSED; #include #include +#include #if TD_FREEBSD || TD_OPENBSD || TD_NETBSD #include #endif @@ -82,6 +83,12 @@ void ThreadPthread::detach() { } } +void ThreadPthread::send_real_time_signal(id thread_id, int real_time_signal_number) { +#ifdef SIGRTMIN + pthread_kill(thread_id, SIGRTMIN + real_time_signal_number); +#endif +} + int ThreadPthread::do_pthread_create(pthread_t *thread, const pthread_attr_t *attr, void *(*start_routine)(void *), void *arg) { return pthread_create(thread, attr, start_routine, arg); diff --git a/tdutils/td/utils/port/detail/ThreadPthread.h b/tdutils/td/utils/port/detail/ThreadPthread.h index c50546c14..ff54633c6 100644 --- a/tdutils/td/utils/port/detail/ThreadPthread.h +++ b/tdutils/td/utils/port/detail/ThreadPthread.h @@ -26,6 +26,7 @@ namespace td { namespace detail { + class ThreadPthread { public: ThreadPthread() = default; @@ -63,6 +64,8 @@ class ThreadPthread { using id = pthread_t; + static void send_real_time_signal(id thread_id, int real_time_signal_number); + private: MovableValue is_inited_; pthread_t thread_; @@ -85,6 +88,7 @@ class ThreadPthread { namespace this_thread_pthread { ThreadPthread::id get_id(); } // namespace this_thread_pthread + } // namespace detail } // namespace td diff --git a/tdutils/td/utils/port/detail/ThreadStl.h b/tdutils/td/utils/port/detail/ThreadStl.h index 0d9f8f2ff..474ef6ecc 100644 --- a/tdutils/td/utils/port/detail/ThreadStl.h +++ b/tdutils/td/utils/port/detail/ThreadStl.h @@ -23,6 +23,7 @@ namespace td { namespace detail { + class ThreadStl { public: ThreadStl() = default; @@ -33,6 +34,7 @@ class ThreadStl { ~ThreadStl() { join(); } + template explicit ThreadStl(Function &&f, Args &&...args) { thread_ = std::thread([args = std::make_tuple(decay_copy(std::forward(f)), @@ -48,12 +50,15 @@ class ThreadStl { thread_.join(); } } + void detach() { if (thread_.joinable()) { thread_.detach(); } } + void set_name(CSlice name) { + // not supported } static unsigned hardware_concurrency() { @@ -62,6 +67,10 @@ class ThreadStl { using id = std::thread::id; + static void send_real_time_signal(id thread_id, int real_time_signal_number) { + // not supported + } + private: std::thread thread_; @@ -70,9 +79,11 @@ class ThreadStl { return std::forward(v); } }; + namespace this_thread_stl { using std::this_thread::get_id; } // namespace this_thread_stl + } // namespace detail } // namespace td diff --git a/tdutils/td/utils/port/signals.cpp b/tdutils/td/utils/port/signals.cpp index e597f334b..d61cf69d9 100644 --- a/tdutils/td/utils/port/signals.cpp +++ b/tdutils/td/utils/port/signals.cpp @@ -191,10 +191,10 @@ Status set_extended_signal_handler(SignalType type, extended_signal_handler func return set_signal_handler_impl(std::move(signals), siginfo_handler); } -Status set_runtime_signal_handler(int runtime_signal_number, void (*func)(int)) { +Status set_real_time_signal_handler(int real_time_signal_number, void (*func)(int)) { #ifdef SIGRTMIN - CHECK(SIGRTMIN + runtime_signal_number <= SIGRTMAX); - return set_signal_handler_impl({SIGRTMIN + runtime_signal_number}, func == nullptr ? SIG_DFL : func); + CHECK(SIGRTMIN + real_time_signal_number <= SIGRTMAX); + return set_signal_handler_impl({SIGRTMIN + real_time_signal_number}, func == nullptr ? SIG_DFL : func); #else return Status::OK(); #endif diff --git a/tdutils/td/utils/port/signals.h b/tdutils/td/utils/port/signals.h index dd15e09b6..fa5fbae97 100644 --- a/tdutils/td/utils/port/signals.h +++ b/tdutils/td/utils/port/signals.h @@ -20,7 +20,7 @@ Status set_signal_handler(SignalType type, void (*func)(int sig)) TD_WARN_UNUSED Status set_extended_signal_handler(SignalType type, void (*func)(int sig, void *addr)) TD_WARN_UNUSED_RESULT; -Status set_runtime_signal_handler(int runtime_signal_number, void (*func)(int sig)) TD_WARN_UNUSED_RESULT; +Status set_real_time_signal_handler(int real_time_signal_number, void (*func)(int sig)) TD_WARN_UNUSED_RESULT; Status ignore_signal(SignalType type) TD_WARN_UNUSED_RESULT; diff --git a/tdutils/td/utils/translit.cpp b/tdutils/td/utils/translit.cpp index 3b1fbfd62..65cfcf007 100644 --- a/tdutils/td/utils/translit.cpp +++ b/tdutils/td/utils/translit.cpp @@ -56,7 +56,7 @@ static void add_word_transliterations(vector &result, Slice word, bool a auto end = word.uend(); while (pos != end) { uint32 code; - pos = next_utf8_unsafe(pos, &code, "add_word_transliterations"); + pos = next_utf8_unsafe(pos, &code); auto it = simple_rules.find(code); if (it != simple_rules.end()) { s += it->second; @@ -89,7 +89,7 @@ static void add_word_transliterations(vector &result, Slice word, bool a } uint32 code; - pos = next_utf8_unsafe(pos, &code, "add_word_transliterations 2"); + pos = next_utf8_unsafe(pos, &code); auto it = simple_rules.find(code); if (it != simple_rules.end()) { s += it->second; diff --git a/tdutils/td/utils/unicode.cpp b/tdutils/td/utils/unicode.cpp index 0b9a6ee42..7d2093519 100644 --- a/tdutils/td/utils/unicode.cpp +++ b/tdutils/td/utils/unicode.cpp @@ -8,9 +8,6 @@ #include "td/utils/logging.h" -#include -#include - namespace td { // list of [(range_begin << 5) + range_type] @@ -145,6 +142,70 @@ static const uint32 unicode_simple_category_ranges[] = { 4194305, 5561344, 5562369, 5695264, 5695489, 5702592, 5702657, 5887040, 5887489, 6126624, 6225921, 6243264, 6291457, 6449504, 4294967295}; +static const uint16 unicode_simple_category_jump_pos[] = { + 1, 9, 27, 27, 27, 27, 36, 44, 55, 55, 57, 63, 68, 75, 86, 91, 102, 114, 119, + 130, 158, 180, 202, 225, 250, 271, 292, 312, 324, 332, 357, 365, 368, 383, 397, 397, 397, 407, + 423, 431, 436, 437, 437, 437, 437, 440, 448, 458, 467, 472, 480, 487, 494, 498, 503, 509, 516, + 524, 538, 538, 540, 540, 540, 558, 578, 592, 595, 622, 625, 625, 625, 625, 625, 626, 629, 629, + 629, 629, 629, 630, 631, 631, 631, 631, 631, 631, 631, 631, 632, 632, 640, 650, 667, 669, 669, + 669, 670, 682, 689, 692, 699, 706, 709, 709, 710, 710, 710, 710, 710, 710, 710, 710, 710, 710, + 710, 710, 710, 710, 710, 710, 710, 710, 710, 710, 710, 710, 710, 710, 710, 710, 710, 710, 710, + 710, 710, 710, 710, 710, 710, 710, 710, 710, 710, 710, 710, 710, 710, 710, 710, 710, 710, 710, + 710, 710, 710, 710, 712, 712, 712, 712, 712, 712, 712, 712, 712, 712, 712, 712, 712, 712, 712, + 712, 712, 712, 712, 712, 712, 712, 712, 712, 712, 712, 712, 712, 712, 712, 712, 712, 712, 712, + 712, 712, 712, 712, 712, 712, 712, 712, 712, 712, 712, 712, 712, 712, 712, 712, 712, 712, 712, + 712, 712, 712, 712, 712, 712, 712, 712, 712, 712, 712, 712, 712, 712, 712, 712, 712, 712, 712, + 712, 712, 712, 712, 712, 712, 712, 712, 712, 712, 712, 712, 712, 712, 712, 712, 712, 712, 712, + 712, 712, 712, 712, 712, 712, 712, 712, 712, 712, 712, 712, 712, 712, 712, 712, 712, 712, 712, + 712, 712, 712, 712, 712, 712, 712, 712, 712, 712, 712, 712, 712, 712, 712, 712, 712, 712, 712, + 712, 712, 712, 712, 712, 712, 712, 712, 712, 712, 712, 712, 712, 712, 712, 712, 712, 712, 712, + 712, 712, 712, 712, 712, 712, 712, 712, 712, 712, 712, 712, 712, 712, 712, 712, 712, 712, 712, + 712, 712, 712, 712, 712, 712, 712, 716, 716, 716, 724, 728, 731, 741, 752, 763, 769, 781, 793, + 810, 825, 829, 829, 829, 829, 829, 829, 829, 829, 829, 829, 829, 829, 829, 829, 829, 829, 829, + 829, 829, 829, 829, 829, 829, 829, 829, 829, 829, 829, 829, 829, 829, 829, 829, 829, 829, 829, + 829, 829, 829, 829, 829, 829, 829, 829, 829, 829, 829, 829, 829, 829, 829, 829, 829, 829, 829, + 829, 829, 829, 829, 829, 829, 829, 829, 829, 829, 829, 829, 829, 829, 829, 829, 829, 829, 829, + 829, 829, 829, 829, 829, 829, 829, 829, 829, 829, 829, 829, 829, 829, 834, 834, 834, 834, 834, + 834, 834, 834, 834, 834, 834, 834, 834, 834, 834, 834, 834, 834, 834, 834, 834, 834, 834, 834, + 834, 834, 834, 834, 834, 834, 834, 834, 834, 834, 834, 834, 834, 834, 834, 834, 834, 834, 834, + 834, 834, 834, 834, 834, 834, 834, 834, 834, 834, 834, 834, 834, 834, 834, 834, 834, 834, 834, + 834, 834, 834, 834, 835, 835, 835, 837, 839, 857, 859, 859, 859, 861, 866, 869, 870, 877, 887, + 899, 900, 904, 906, 907, 913, 923, 931, 931, 939, 945, 959, 959, 959, 965, 971, 987, 996, 1001, + 1008, 1021, 1030, 1038, 1042, 1044, 1049, 1052, 1052, 1055, 1059, 1067, 1073, 1082, 1088, 1100, 1112, 1116, 1129, + 1147, 1148, 1156, 1163, 1164, 1168, 1174, 1180, 1186, 1187, 1188, 1193, 1208, 1217, 1225, 1230, 1230, 1231, 1240, + 1242, 1256, 1261, 1261, 1263, 1263, 1268, 1268, 1268, 1268, 1268, 1268, 1268, 1268, 1270, 1272, 1272, 1273, 1273, + 1273, 1273, 1273, 1273, 1273, 1273, 1273, 1273, 1273, 1273, 1273, 1273, 1273, 1273, 1273, 1273, 1273, 1273, 1273, + 1276, 1276, 1276, 1276, 1276, 1276, 1276, 1276, 1276, 1277, 1277, 1277, 1277, 1277, 1277, 1277, 1277, 1277, 1277, + 1277, 1277, 1277, 1277, 1277, 1277, 1277, 1277, 1277, 1277, 1277, 1277, 1277, 1277, 1277, 1277, 1277, 1277, 1277, + 1277, 1277, 1278, 1278, 1278, 1278, 1278, 1279, 1279, 1279, 1279, 1279, 1279, 1279, 1279, 1279, 1279, 1279, 1279, + 1279, 1279, 1279, 1279, 1279, 1279, 1279, 1279, 1279, 1279, 1279, 1279, 1279, 1279, 1279, 1279, 1279, 1279, 1279, + 1279, 1279, 1279, 1279, 1279, 1279, 1279, 1279, 1279, 1279, 1279, 1279, 1279, 1279, 1279, 1279, 1279, 1279, 1279, + 1279, 1279, 1279, 1279, 1279, 1279, 1279, 1279, 1279, 1279, 1279, 1279, 1279, 1279, 1279, 1279, 1279, 1280, 1280, + 1280, 1280, 1280, 1286, 1292, 1302, 1303, 1303, 1303, 1303, 1303, 1305, 1307, 1310, 1317, 1317, 1317, 1317, 1317, + 1317, 1317, 1317, 1317, 1317, 1317, 1317, 1317, 1317, 1317, 1317, 1317, 1317, 1317, 1317, 1317, 1317, 1317, 1317, + 1317, 1317, 1317, 1317, 1317, 1317, 1317, 1317, 1317, 1317, 1317, 1317, 1317, 1317, 1317, 1317, 1317, 1317, 1317, + 1317, 1317, 1317, 1317, 1317, 1319, 1319, 1319, 1319, 1319, 1319, 1319, 1319, 1319, 1319, 1321, 1322, 1322, 1322, + 1322, 1322, 1322, 1322, 1322, 1322, 1322, 1322, 1322, 1322, 1322, 1322, 1322, 1322, 1322, 1322, 1322, 1322, 1322, + 1322, 1322, 1322, 1322, 1322, 1322, 1322, 1322, 1322, 1322, 1322, 1322, 1322, 1322, 1322, 1322, 1322, 1322, 1322, + 1322, 1322, 1322, 1322, 1322, 1322, 1322, 1322, 1322, 1322, 1322, 1322, 1322, 1322, 1322, 1322, 1322, 1322, 1322, + 1322, 1322, 1322, 1322, 1322, 1322, 1322, 1322, 1322, 1329, 1329, 1329, 1335, 1335, 1335, 1336, 1336, 1336, 1336, + 1336, 1336, 1336, 1336, 1336, 1336, 1336, 1336, 1336, 1336, 1336, 1336, 1336, 1336, 1337, 1341, 1344, 1344, 1344, + 1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344, + 1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344, + 1344, 1344, 1344, 1346, 1348, 1349, 1351, 1367, 1385, 1385, 1385, 1393, 1401, 1410, 1410, 1410, 1410, 1410, 1410, + 1410, 1410, 1410, 1410, 1410, 1410, 1410, 1410, 1411, 1412, 1412, 1412, 1413, 1420, 1420, 1420, 1426, 1426, 1426, + 1426, 1426, 1426, 1426, 1426, 1426, 1426, 1435, 1435, 1439, 1444, 1444, 1444, 1444, 1444, 1444, 1445, 1450, 1454, + 1455, 1511, 1520, 1520, 1520, 1520, 1521, 1522, 1522, 1522, 1522, 1522, 1522, 1522, 1522, 1522, 1522, 1522, 1522, + 1522, 1522, 1522, 1522, 1522, 1522, 1522, 1522, 1522, 1524, 1524, 1524, 1524, 1524, 1524, 1524, 1524, 1525, 1537, + 1538, 1538, 1538, 1538, 1538, 1538, 1538, 1538, 1538, 1538, 1538, 1538, 1538, 1538}; + +static const char *unicode_simple_category_table = + "\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00" + "\x00\x00\x00\x00\x04\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x02\x02\x02\x02\x02\x02\x02\x02" + "\x02\x02\x00\x00\x00\x00\x00\x00\x00\x01\x01\x01\x01\x01\x01\x01\x01\x01\x01\x01\x01\x01\x01\x01\x01\x01\x01\x01" + "\x01\x01\x01\x01\x01\x01\x01\x00\x00\x00\x00\x00\x00\x01\x01\x01\x01\x01\x01\x01\x01\x01\x01\x01\x01\x01\x01\x01" + "\x01\x01\x01\x01\x01\x01\x01\x01\x01\x01\x01\x00\x00\x00\x00\x00"; + static constexpr uint32 TABLE_SIZE = 1280; static const int16 prepare_search_character_table[TABLE_SIZE] = { @@ -1186,8 +1247,17 @@ static const int32 without_diacritics_ranges[] = { 918000, -918001, 2147483647, 0}; UnicodeSimpleCategory get_unicode_simple_category(uint32 code) { - auto it = std::upper_bound(std::begin(unicode_simple_category_ranges), std::end(unicode_simple_category_ranges), - (code << 5) + 30); + if (code < 128) { + return static_cast(unicode_simple_category_table[code]); + } + auto jump_pos_index = code <= 0x20000 ? code >> 7 : (0x20000 >> 7) - (0x20000 >> 16) + (code >> 16); + // CHECK(jump_pos_index < sizeof(unicode_simple_category_ranges) / sizeof(unicode_simple_category_ranges[0])); + auto it = unicode_simple_category_ranges + unicode_simple_category_jump_pos[jump_pos_index]; + code = (code << 5) + 30; + // CHECK(unicode_simple_category_ranges[unicode_simple_category_jump_pos[jump_pos_index + 1]] > code); + while (*it <= code) { + ++it; + } return static_cast(*(it - 1) & 31); } diff --git a/tdutils/td/utils/utf8.cpp b/tdutils/td/utils/utf8.cpp index ff9a21fd3..e4e62cf06 100644 --- a/tdutils/td/utils/utf8.cpp +++ b/tdutils/td/utils/utf8.cpp @@ -6,7 +6,6 @@ // #include "td/utils/utf8.h" -#include "td/utils/logging.h" #include "td/utils/misc.h" #include "td/utils/SliceBuilder.h" #include "td/utils/unicode.h" @@ -81,33 +80,23 @@ void append_utf8_character(string &str, uint32 ch) { } } -const unsigned char *next_utf8_unsafe(const unsigned char *ptr, uint32 *code, const char *source) { +const unsigned char *next_utf8_unsafe(const unsigned char *ptr, uint32 *code) { uint32 a = ptr[0]; if ((a & 0x80) == 0) { - if (code) { - *code = a; - } + *code = a; return ptr + 1; } else if ((a & 0x20) == 0) { - if (code) { - *code = ((a & 0x1f) << 6) | (ptr[1] & 0x3f); - } + *code = ((a & 0x1f) << 6) | (ptr[1] & 0x3f); return ptr + 2; } else if ((a & 0x10) == 0) { - if (code) { - *code = ((a & 0x0f) << 12) | ((ptr[1] & 0x3f) << 6) | (ptr[2] & 0x3f); - } + *code = ((a & 0x0f) << 12) | ((ptr[1] & 0x3f) << 6) | (ptr[2] & 0x3f); return ptr + 3; } else if ((a & 0x08) == 0) { - if (code) { - *code = ((a & 0x07) << 18) | ((ptr[1] & 0x3f) << 12) | ((ptr[2] & 0x3f) << 6) | (ptr[3] & 0x3f); - } + *code = ((a & 0x07) << 18) | ((ptr[1] & 0x3f) << 12) | ((ptr[2] & 0x3f) << 6) | (ptr[3] & 0x3f); return ptr + 4; } - LOG(FATAL) << a << " " << source; - if (code) { - *code = 0; - } + UNREACHABLE(); + *code = 0; return ptr; } @@ -117,7 +106,7 @@ string utf8_to_lower(Slice str) { auto end = str.uend(); while (pos != end) { uint32 code; - pos = next_utf8_unsafe(pos, &code, "utf8_to_lower"); + pos = next_utf8_unsafe(pos, &code); append_utf8_character(result, unicode_to_lower(code)); } return result; diff --git a/tdutils/td/utils/utf8.h b/tdutils/td/utils/utf8.h index e16eef4d1..236cc87c0 100644 --- a/tdutils/td/utils/utf8.h +++ b/tdutils/td/utils/utf8.h @@ -49,7 +49,7 @@ inline const unsigned char *prev_utf8_unsafe(const unsigned char *ptr) { } /// moves pointer one UTF-8 character forward and saves code of the skipped character in *code -const unsigned char *next_utf8_unsafe(const unsigned char *ptr, uint32 *code, const char *source); +const unsigned char *next_utf8_unsafe(const unsigned char *ptr, uint32 *code); /// truncates UTF-8 string to the given length in Unicode characters template diff --git a/tdutils/test/WaitFreeHashSet.cpp b/tdutils/test/WaitFreeHashSet.cpp new file mode 100644 index 000000000..d6adab2bc --- /dev/null +++ b/tdutils/test/WaitFreeHashSet.cpp @@ -0,0 +1,71 @@ +// +// 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/utils/common.h" +#include "td/utils/FlatHashSet.h" +#include "td/utils/Random.h" +#include "td/utils/tests.h" +#include "td/utils/WaitFreeHashSet.h" + +TEST(WaitFreeHashSet, stress_test) { + td::Random::Xorshift128plus rnd(123); + td::FlatHashSet reference; + td::WaitFreeHashSet set; + + td::vector steps; + auto add_step = [&](td::uint32 weight, auto f) { + steps.emplace_back(td::RandomSteps::Step{std::move(f), weight}); + }; + + auto gen_key = [&] { + return rnd() % 100000 + 1; + }; + + auto check = [&] { + ASSERT_EQ(reference.size(), set.size()); + ASSERT_EQ(reference.empty(), set.empty()); + + if (reference.size() < 100) { + td::uint64 result = 0; + for (auto &it : reference) { + result += it * 101; + } + set.foreach([&](const td::uint64 &key) { result -= key * 101; }); + ASSERT_EQ(0u, result); + } + }; + + add_step(2000, [&] { + auto key = gen_key(); + ASSERT_EQ(reference.count(key), set.count(key)); + reference.insert(key); + set.insert(key); + ASSERT_EQ(reference.count(key), set.count(key)); + check(); + }); + + add_step(500, [&] { + auto key = gen_key(); + size_t reference_erased_count = reference.erase(key); + size_t set_erased_count = set.erase(key); + ASSERT_EQ(reference_erased_count, set_erased_count); + check(); + }); + + td::RandomSteps runner(std::move(steps)); + for (size_t i = 0; i < 1000000; i++) { + runner.step(rnd); + } + + for (size_t test = 0; test < 1000; test++) { + reference = {}; + set = {}; + + for (size_t i = 0; i < 100; i++) { + runner.step(rnd); + } + } +} diff --git a/tdutils/test/bitmask.cpp b/tdutils/test/bitmask.cpp index 63b4c27bd..e81c406bb 100644 --- a/tdutils/test/bitmask.cpp +++ b/tdutils/test/bitmask.cpp @@ -50,7 +50,7 @@ class RangeSet { RangeSet res; for (auto begin = data.ubegin(); begin != data.uend();) { uint32 size; - begin = next_utf8_unsafe(begin, &size, "RangeSet"); + begin = next_utf8_unsafe(begin, &size); if (!is_empty && size != 0) { res.ranges_.push_back({curr * BIT_SIZE, (curr + size) * BIT_SIZE}); diff --git a/tdutils/test/misc.cpp b/tdutils/test/misc.cpp index 34a541e5a..6c5ae17d9 100644 --- a/tdutils/test/misc.cpp +++ b/tdutils/test/misc.cpp @@ -623,6 +623,26 @@ TEST(Misc, unicode) { test_unicode(td::remove_diacritics); } +TEST(Misc, get_unicode_simple_category) { + td::uint32 result = 0; + for (size_t t = 0; t < 100; t++) { + for (td::uint32 i = 0; i <= 0x10ffff; i++) { + result = result * 123 + static_cast(static_cast(td::get_unicode_simple_category(i))); + } + } + LOG(INFO) << result; +} + +TEST(Misc, get_unicode_simple_category_small) { + td::uint32 result = 0; + for (size_t t = 0; t < 1000; t++) { + for (td::uint32 i = 0; i <= 0xffff; i++) { + result = result * 123 + static_cast(static_cast(td::get_unicode_simple_category(i))); + } + } + LOG(INFO) << result; +} + TEST(BigNum, from_decimal) { ASSERT_TRUE(td::BigNum::from_decimal("").is_error()); ASSERT_TRUE(td::BigNum::from_decimal("a").is_error()); diff --git a/test/message_entities.cpp b/test/message_entities.cpp index 3ceaa0a17..cab24ddbf 100644 --- a/test/message_entities.cpp +++ b/test/message_entities.cpp @@ -6,6 +6,8 @@ // #include "td/telegram/MessageEntity.h" +#include "td/telegram/UserId.h" + #include "td/utils/algorithm.h" #include "td/utils/common.h" #include "td/utils/format.h" @@ -560,7 +562,8 @@ TEST(MessageEntities, url) { check_url("http://ÀТеСт.МоСкВач", {"http://ÀТеСт.МоСкВач"}); check_url("ÀÁ.com. ÀÁ.com.", {"ÀÁ.com", "ÀÁ.com"}); check_url("ÀÁ.com,ÀÁ.com.", {"ÀÁ.com", "ÀÁ.com"}); - check_url("teiegram.org", {}); + check_url("teiegram.org/test", {}); + check_url("TeiegraM.org/test", {}); check_url("http://test.google.com/?q=abc()}[]def", {"http://test.google.com/?q=abc()"}); check_url("http://test.google.com/?q=abc([{)]}def", {"http://test.google.com/?q=abc([{)]}def"}); check_url("http://test.google.com/?q=abc(){}]def", {"http://test.google.com/?q=abc(){}"}); @@ -653,11 +656,11 @@ TEST(MessageEntities, url) { check_url("https://a.de}bc@c.com", {"https://a.de"}, {"bc@c.com"}); check_url("https://a.de(bc@c.com", {"https://a.de"}, {"bc@c.com"}); check_url("https://a.de)bc@c.com", {"https://a.de"}, {"bc@c.com"}); - check_url("https://a.de\\bc@c.com", {"https://a.de\\bc@c.com"}); + check_url("https://a.debc@c.com", {"https://a.debc@c.com"}); check_url("https://a.de'bc@c.com", {"https://a.de"}, {"bc@c.com"}); check_url("https://a.de`bc@c.com", {"https://a.de"}, {"bc@c.com"}); - check_url("https://a.bc:de.fg@c.com", {"https://a.bc:de.fg@c.com"}); - check_url("https://a:h.bc:de.fg@c.com", {"https://a:h.bc:de.fg@c.com"}); + check_url("https://a.bcde.fg@c.com", {"https://a.bcde.fg@c.com"}); + check_url("https://a:h.bcde.fg@c.com", {"https://a:h.bcde.fg@c.com"}); check_url("https://abc@c.com", {"https://abc@c.com"}); check_url("https://de[bc@c.com", {}, {"bc@c.com"}); check_url("https://de/bc@c.com", {}); @@ -702,6 +705,7 @@ TEST(MessageEntities, url) { check_url("http://test―‑@―google―.―com―/―–―‐―/―/―/―?―‑―#―――", {"http://test―‑@―google―.―com―/―–―‐―/―/―/―?―‑―#―――"}); check_url("http://google.com/‖", {"http://google.com/"}); check_url("a@b@c.com", {}, {}); + check_url("abc@c.com@d.com", {}); check_url("a@b.com:c@1", {}, {"a@b.com"}); check_url("test@test.software", {}, {"test@test.software"}); check_url("a:b?@gmail.com", {}); @@ -710,6 +714,10 @@ TEST(MessageEntities, url) { check_url("a:b#@gmail.com", {}); check_url("a!:b@gmail.com", {"a!:b@gmail.com"}); check_url("a:b!@gmail.com", {"a:b!@gmail.com"}); + check_url("http://test_.com", {}); + check_url("test_.com", {}); + check_url("_test.com", {}); + check_url("_.test.com", {"_.test.com"}); } static void check_fix_formatted_text(td::string str, td::vector entities, @@ -832,6 +840,7 @@ TEST(MessageEntities, fix_formatted_text) { } str = "aba \r\n caba "; + td::UserId user_id(static_cast(1)); for (td::int32 length = 1; length <= 3; length++) { for (td::int32 offset = 0; static_cast(offset + length) <= str.size(); offset++) { for (auto type : {td::MessageEntity::Type::Bold, td::MessageEntity::Type::Url, td::MessageEntity::Type::TextUrl, @@ -855,12 +864,22 @@ TEST(MessageEntities, fix_formatted_text) { td::vector entities; entities.emplace_back(type, offset, length); + if (type == td::MessageEntity::Type::TextUrl) { + entities.back().argument = "t.me"; + } else if (type == td::MessageEntity::Type::MentionName) { + entities.back().user_id = user_id; + } td::vector fixed_entities; if (fixed_length > 0) { for (auto i = 0; i < length; i++) { if (!td::is_space(str[offset + i]) || type == td::MessageEntity::Type::TextUrl || type == td::MessageEntity::Type::MentionName) { fixed_entities.emplace_back(type, fixed_offset, fixed_length); + if (type == td::MessageEntity::Type::TextUrl) { + fixed_entities.back().argument = "t.me"; + } else if (type == td::MessageEntity::Type::MentionName) { + fixed_entities.back().user_id = user_id; + } break; } } @@ -905,9 +924,11 @@ TEST(MessageEntities, fix_formatted_text) { for (td::int32 offset2 = 0; offset2 <= 8 - length2; offset2++) { if (offset != offset2) { td::vector entities; - entities.emplace_back(td::MessageEntity::Type::TextUrl, offset, length); - entities.emplace_back(td::MessageEntity::Type::TextUrl, offset2, length2); + entities.emplace_back(td::MessageEntity::Type::TextUrl, offset, length, "t.me"); + entities.emplace_back(td::MessageEntity::Type::TextUrl, offset2, length2, "t.me"); + entities.emplace_back(td::MessageEntity::Type::TextUrl, offset2 + length2, 1); td::vector fixed_entities = entities; + fixed_entities.pop_back(); std::sort(fixed_entities.begin(), fixed_entities.end()); if (fixed_entities[0].offset + fixed_entities[0].length > fixed_entities[1].offset) { fixed_entities.pop_back(); diff --git a/test/mtproto.cpp b/test/mtproto.cpp index 4f7e5c3f1..f15c5ca10 100644 --- a/test/mtproto.cpp +++ b/test/mtproto.cpp @@ -167,7 +167,7 @@ TEST(Mtproto, config) { } }); cnt++; - func(std::move(promise), nullptr, is_test, -1).release(); + func(std::move(promise), false, td::Slice(), is_test, -1).release(); }; run(td::get_simple_config_azure, false);