Merge remote-tracking branch 'td/master'

# Conflicts:
#	td/telegram/PollManager.cpp
#	td/telegram/VideoNotesManager.cpp
This commit is contained in:
Andrea Cavalli 2022-08-29 00:41:56 +02:00
commit 6bddb57999
114 changed files with 1840 additions and 1263 deletions

View File

@ -58,11 +58,13 @@ endfunction()
function(get_git_head_revision _refspecvar _hashvar) function(get_git_head_revision _refspecvar _hashvar)
_git_find_closest_git_dir("${CMAKE_CURRENT_SOURCE_DIR}" GIT_DIR) _git_find_closest_git_dir("${CMAKE_CURRENT_SOURCE_DIR}" GIT_DIR)
if (NOT GIT_DIR STREQUAL "")
file(RELATIVE_PATH _relative_to_source_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 "^[.][.]") if (_relative_to_source_dir MATCHES "^[.][.]")
# We've gone above the CMake root dir. # We've gone above the CMake root dir.
set(GIT_DIR "") set(GIT_DIR "")
endif() endif()
endif()
if (GIT_DIR STREQUAL "") if (GIT_DIR STREQUAL "")
set(${_refspecvar} "GITDIR-NOTFOUND" PARENT_SCOPE) set(${_refspecvar} "GITDIR-NOTFOUND" PARENT_SCOPE)
set(${_hashvar} "GITDIR-NOTFOUND" PARENT_SCOPE) set(${_hashvar} "GITDIR-NOTFOUND" PARENT_SCOPE)

View File

@ -307,7 +307,6 @@ set(TDLIB_SOURCE
td/telegram/ChannelParticipantFilter.cpp td/telegram/ChannelParticipantFilter.cpp
td/telegram/ClientActor.cpp td/telegram/ClientActor.cpp
td/telegram/ConfigManager.cpp td/telegram/ConfigManager.cpp
td/telegram/ConfigShared.cpp
td/telegram/ConnectionState.cpp td/telegram/ConnectionState.cpp
td/telegram/Contact.cpp td/telegram/Contact.cpp
td/telegram/ContactsManager.cpp td/telegram/ContactsManager.cpp
@ -442,6 +441,7 @@ set(TDLIB_SOURCE
td/telegram/StorageManager.cpp td/telegram/StorageManager.cpp
td/telegram/MemoryManager.cpp td/telegram/MemoryManager.cpp
td/telegram/SuggestedAction.cpp td/telegram/SuggestedAction.cpp
td/telegram/Support.cpp
td/telegram/Td.cpp td/telegram/Td.cpp
td/telegram/TdDb.cpp td/telegram/TdDb.cpp
td/telegram/TermsOfService.cpp td/telegram/TermsOfService.cpp
@ -512,7 +512,6 @@ set(TDLIB_SOURCE
td/telegram/ChatId.h td/telegram/ChatId.h
td/telegram/ClientActor.h td/telegram/ClientActor.h
td/telegram/ConfigManager.h td/telegram/ConfigManager.h
td/telegram/ConfigShared.h
td/telegram/ConnectionState.h td/telegram/ConnectionState.h
td/telegram/Contact.h td/telegram/Contact.h
td/telegram/ContactsManager.h td/telegram/ContactsManager.h
@ -691,6 +690,7 @@ set(TDLIB_SOURCE
td/telegram/StorageManager.h td/telegram/StorageManager.h
td/telegram/MemoryManager.h td/telegram/MemoryManager.h
td/telegram/SuggestedAction.h td/telegram/SuggestedAction.h
td/telegram/Support.h
td/telegram/Td.h td/telegram/Td.h
td/telegram/TdCallback.h td/telegram/TdCallback.h
td/telegram/TdDb.h td/telegram/TdDb.h

View File

@ -281,7 +281,6 @@ function split_file($file, $chunks, $undo) {
'audios_manager[_(-][^.]|AudiosManager' => "AudiosManager", 'audios_manager[_(-][^.]|AudiosManager' => "AudiosManager",
'auth_manager[_(-][^.]|AuthManager' => 'AuthManager', 'auth_manager[_(-][^.]|AuthManager' => 'AuthManager',
'background_manager[_(-][^.]|BackgroundManager' => "BackgroundManager", 'background_manager[_(-][^.]|BackgroundManager' => "BackgroundManager",
'ConfigShared|shared_config[(]' => 'ConfigShared',
'contacts_manager[_(-][^.]|ContactsManager([^ ;.]| [^*])' => 'ContactsManager', 'contacts_manager[_(-][^.]|ContactsManager([^ ;.]| [^*])' => 'ContactsManager',
'country_info_manager[_(-][^.]|CountryInfoManager' => 'CountryInfoManager', 'country_info_manager[_(-][^.]|CountryInfoManager' => 'CountryInfoManager',
'documents_manager[_(-][^.]|DocumentsManager' => "DocumentsManager", 'documents_manager[_(-][^.]|DocumentsManager' => "DocumentsManager",

View File

@ -12,7 +12,7 @@
'import androidx.annotation.Nullable;'.PHP_EOL. 'import androidx.annotation.Nullable;'.PHP_EOL.
PHP_EOL. PHP_EOL.
'import java.lang.annotation.Retention;'.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); preg_match_all('/public static class ([A-Za-z0-9]+) extends ([A-Za-z0-9]+)/', $file, $matches, PREG_SET_ORDER);
$children = []; $children = [];
@ -21,13 +21,20 @@
continue; 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]+)(<R extends Object>)? extends Object [{]/', $file = preg_replace_callback('/public abstract static class ([A-Za-z0-9]+)(<R extends Object>)? extends Object [{]/',
function ($val) use ($children) { 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].<<<EOL
/**
* Describes possible values returned by getConstructor().
*/
@Retention(RetentionPolicy.SOURCE)
@IntDef({
$values
}) })
public @interface Constructors {} public @interface Constructors {}

View File

@ -1,7 +1,7 @@
# TDLib Android example # TDLib Android example
This is an example of building `TDLib` for Android. This is an example of building `TDLib` for Android.
You need a Bash shell on Linux, macOS, or Windows with some common tools, a C++ compiler, cmake, JDK, PHP, and gperf pre-installed. You need a Bash shell on Linux, macOS, or Windows with some common tools, a C++ compiler, JDK, PHP, perl, and gperf pre-installed.
## Building TDLib for Android ## Building TDLib for Android

View File

@ -1,5 +1,4 @@
#!/usr/bin/env bash #!/usr/bin/env bash
cd $(dirname $0)
ANDROID_SDK_ROOT=${1:-SDK} ANDROID_SDK_ROOT=${1:-SDK}
ANDROID_NDK_VERSION=${2:-23.2.8568313} ANDROID_NDK_VERSION=${2:-23.2.8568313}
@ -23,6 +22,8 @@ mkdir -p $OPENSSL_INSTALL_DIR || exit 1
ANDROID_SDK_ROOT="$(cd "$(dirname -- "$ANDROID_SDK_ROOT")" >/dev/null; pwd -P)/$(basename -- "$ANDROID_SDK_ROOT")" ANDROID_SDK_ROOT="$(cd "$(dirname -- "$ANDROID_SDK_ROOT")" >/dev/null; pwd -P)/$(basename -- "$ANDROID_SDK_ROOT")"
OPENSSL_INSTALL_DIR="$(cd "$(dirname -- "$OPENSSL_INSTALL_DIR")" >/dev/null; pwd -P)/$(basename -- "$OPENSSL_INSTALL_DIR")" OPENSSL_INSTALL_DIR="$(cd "$(dirname -- "$OPENSSL_INSTALL_DIR")" >/dev/null; pwd -P)/$(basename -- "$OPENSSL_INSTALL_DIR")"
cd $(dirname $0)
echo "Downloading OpenSSL sources..." echo "Downloading OpenSSL sources..."
rm -f $OPENSSL_VERSION.tar.gz || exit 1 rm -f $OPENSSL_VERSION.tar.gz || exit 1
$WGET https://github.com/openssl/openssl/archive/refs/tags/$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 exit 1
fi 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 for ABI in arm64-v8a armeabi-v7a x86_64 x86 ; do
if [[ $ABI == "x86" ]] ; then if [[ $ABI == "x86" ]] ; then
./Configure android-x86 no-shared -U__ANDROID_API__ -D__ANDROID_API__=16 || exit 1 ./Configure android-x86 no-shared -U__ANDROID_API__ -D__ANDROID_API__=$ANDROID_API32 || exit 1
elif [[ $ABI == "x86_64" ]] ; then elif [[ $ABI == "x86_64" ]] ; then
./Configure android-x86_64 no-shared -U__ANDROID_API__ -D__ANDROID_API__=21 || exit 1 ./Configure android-x86_64 no-shared -U__ANDROID_API__ -D__ANDROID_API__=$ANDROID_API64 || exit 1
elif [[ $ABI == "armeabi-v7a" ]] ; then elif [[ $ABI == "armeabi-v7a" ]] ; then
./Configure android-arm no-shared -U__ANDROID_API__ -D__ANDROID_API__=16 -D__ARM_MAX_ARCH__=8 || exit 1 ./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 elif [[ $ABI == "arm64-v8a" ]] ; then
./Configure android-arm64 no-shared -U__ANDROID_API__ -D__ANDROID_API__=21 || exit 1 ./Configure android-arm64 no-shared -U__ANDROID_API__ -D__ANDROID_API__=$ANDROID_API64 || exit 1
fi fi
sed -i.bak 's/-O3/-O3 -ffunction-sections -fdata-sections/g' Makefile || exit 1 sed -i.bak 's/-O3/-O3 -ffunction-sections -fdata-sections/g' Makefile || exit 1

View File

@ -1,5 +1,4 @@
#!/usr/bin/env bash #!/usr/bin/env bash
cd $(dirname $0)
ANDROID_SDK_ROOT=${1:-SDK} ANDROID_SDK_ROOT=${1:-SDK}
ANDROID_NDK_VERSION=${2:-23.2.8568313} 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")" 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 PATH=$ANDROID_SDK_ROOT/cmake/3.22.1/bin:$PATH
cd $(dirname $0)
echo "Downloading annotation Java package..." echo "Downloading annotation Java package..."
rm -f android.jar annotation-1.4.0.jar || exit 1 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 $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 mkdir -p tdlib/libs/$ABI/ || exit 1
cp -p build-$ABI/libtd*.so* tdlib/libs/$ABI/ || exit 1 cp -p build-$ABI/libtd*.so* tdlib/libs/$ABI/ || exit 1
if [[ "$ANDROID_STL" == "c++_shared" ]] ; then if [[ "$ANDROID_STL" == "c++_shared" ]] ; then
FULL_ABI=$(case $ABI in if [[ "$ABI" == "arm64-v8a" ]] ; then
"arm64-v8a") echo "aarch64-linux-android" ;; FULL_ABI="aarch64-linux-android"
"armeabi-v7a") echo "arm-linux-androideabi" ;; elif [[ "$ABI" == "armeabi-v7a" ]] ; then
"x86_64") echo "x86_64-linux-android" ;; FULL_ABI="arm-linux-androideabi"
"x86") echo "i686-linux-android" ;; elif [[ "$ABI" == "x86_64" ]] ; then
esac) 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 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 "$ANDROID_NDK_ROOT/toolchains/llvm/prebuilt/$HOST_ARCH/bin/llvm-strip" tdlib/libs/$ABI/libc++_shared.so || exit 1
fi fi

View File

@ -25,7 +25,7 @@ else
exit 1 exit 1
fi 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 if ! which "$TOOL_NAME" >/dev/null 2>&1 ; then
echo "Error: this script requires $TOOL_NAME tool installed." echo "Error: this script requires $TOOL_NAME tool installed."
exit 1 exit 1
@ -43,3 +43,8 @@ if ! perl -MExtUtils::MakeMaker -MLocale::Maketext::Simple -MPod::Usage -e '' >/
fi fi
exit 1 exit 1
fi 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

View File

@ -1,5 +1,4 @@
#!/usr/bin/env bash #!/usr/bin/env bash
cd $(dirname $0)
ANDROID_SDK_ROOT=${1:-SDK} ANDROID_SDK_ROOT=${1:-SDK}
ANDROID_NDK_VERSION=${2:-23.2.8568313} ANDROID_NDK_VERSION=${2:-23.2.8568313}

View File

@ -41,7 +41,7 @@ function prepare {
cd build-native 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 CheckLastExitCode
cmake --build . --target prepare_cross_compiling cmake --build . --target prepare_cross_compiling
CheckLastExitCode CheckLastExitCode
@ -62,7 +62,7 @@ function config {
if ($arch -eq "x86") { if ($arch -eq "x86") {
$fixed_arch = "win32" $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 CheckLastExitCode
cd .. cd ..
} }

View File

@ -4571,6 +4571,10 @@ logVerbosityLevel verbosity_level:int32 = LogVerbosityLevel;
logTags tags:vector<string> = LogTags; logTags tags:vector<string> = 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 //@description A simple object containing a number; for testing only @value Number
testInt value:int32 = TestInt; testInt value:int32 = TestInt;
//@description A simple object containing a string; for testing only @value String //@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; 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 //@description Does nothing; for testing only. This is an offline method. Can be called before authorization
testCallEmpty = Ok; testCallEmpty = Ok;
//@description Returns the received string; for testing only. This is an offline method. Can be called before authorization @x String to return //@description Returns the received string; for testing only. This is an offline method. Can be called before authorization @x String to return

View File

@ -7,7 +7,6 @@
#include "td/telegram/AnimationsManager.h" #include "td/telegram/AnimationsManager.h"
#include "td/telegram/AuthManager.h" #include "td/telegram/AuthManager.h"
#include "td/telegram/ConfigShared.h"
#include "td/telegram/DialogId.h" #include "td/telegram/DialogId.h"
#include "td/telegram/Document.h" #include "td/telegram/Document.h"
#include "td/telegram/DocumentsManager.h" #include "td/telegram/DocumentsManager.h"
@ -18,6 +17,7 @@
#include "td/telegram/Global.h" #include "td/telegram/Global.h"
#include "td/telegram/logevent/LogEvent.h" #include "td/telegram/logevent/LogEvent.h"
#include "td/telegram/misc.h" #include "td/telegram/misc.h"
#include "td/telegram/OptionManager.h"
#include "td/telegram/PhotoFormat.h" #include "td/telegram/PhotoFormat.h"
#include "td/telegram/secret_api.h" #include "td/telegram/secret_api.h"
#include "td/telegram/Td.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)) { 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"); on_update_animation_search_emojis();
if (!limit_string.empty()) { on_update_animation_search_provider();
auto new_limit = to_integer<int32>(limit_string); on_update_saved_animations_limit();
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";
}
}
next_saved_animations_load_time_ = Time::now(); next_saved_animations_load_time_ = Time::now();
G()->td_db()->get_binlog_pmc()->erase("saved_animations_limit"); // legacy
} }
AnimationsManager::~AnimationsManager() { AnimationsManager::~AnimationsManager() {
@ -412,15 +408,16 @@ SecretInputMedia AnimationsManager::get_secret_input_media(FileId animation_file
layer}; layer};
} }
void AnimationsManager::on_update_animation_search_emojis(string animation_search_emojis) { void AnimationsManager::on_update_animation_search_emojis() {
if (G()->close_flag()) { if (G()->close_flag()) {
return; return;
} }
if (td_->auth_manager_->is_bot()) { 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; return;
} }
auto animation_search_emojis = td_->option_manager_->get_option_string("animation_search_emojis");
is_animation_search_emojis_inited_ = true; is_animation_search_emojis_inited_ = true;
if (animation_search_emojis_ == animation_search_emojis) { if (animation_search_emojis_ == animation_search_emojis) {
return; return;
@ -430,15 +427,16 @@ void AnimationsManager::on_update_animation_search_emojis(string animation_searc
try_send_update_animation_search_parameters(); 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()) { if (G()->close_flag()) {
return; return;
} }
if (td_->auth_manager_->is_bot()) { 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; return;
} }
string animation_search_provider = td_->option_manager_->get_option_string("animation_search_provider");
is_animation_search_provider_inited_ = true; is_animation_search_provider_inited_ = true;
if (animation_search_provider_ == animation_search_provider) { if (animation_search_provider_ == animation_search_provider) {
return; return;
@ -448,11 +446,15 @@ void AnimationsManager::on_update_animation_search_provider(string animation_sea
try_send_update_animation_search_parameters(); 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<int32>(td_->option_manager_->get_option_integer("saved_animations_limit", 200));
if (saved_animations_limit != saved_animations_limit_) { if (saved_animations_limit != saved_animations_limit_) {
if (saved_animations_limit > 0) { if (saved_animations_limit > 0) {
LOG(INFO) << "Update saved animations limit to " << saved_animations_limit; 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; saved_animations_limit_ = saved_animations_limit;
if (static_cast<int32>(saved_animation_ids_.size()) > saved_animations_limit_) { if (static_cast<int32>(saved_animation_ids_.size()) > saved_animations_limit_) {
saved_animation_ids_.resize(saved_animations_limit_); saved_animation_ids_.resize(saved_animations_limit_);

View File

@ -63,11 +63,11 @@ class AnimationsManager final : public Actor {
void merge_animations(FileId new_id, FileId old_id); 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); void reload_saved_animations(bool force);

View File

@ -805,22 +805,25 @@ void AttachMenuManager::reload_attach_menu_bots(Promise<Unit> &&promise) {
if (!is_active()) { if (!is_active()) {
return; return;
} }
auto query_promise =
PromiseCreator::lambda([actor_id = actor_id(this), promise = std::move(promise)]( reload_attach_menu_bots_queries_.push_back(std::move(promise));
Result<telegram_api::object_ptr<telegram_api::AttachMenuBots>> &&result) mutable { if (reload_attach_menu_bots_queries_.size() == 1) {
send_closure(actor_id, &AttachMenuManager::on_reload_attach_menu_bots, std::move(result), std::move(promise)); auto query_promise = PromiseCreator::lambda(
[actor_id = actor_id(this)](Result<telegram_api::object_ptr<telegram_api::AttachMenuBots>> &&result) {
send_closure(actor_id, &AttachMenuManager::on_reload_attach_menu_bots, std::move(result));
}); });
td_->create_handler<GetAttachMenuBotsQuery>(std::move(query_promise))->send(hash_); td_->create_handler<GetAttachMenuBotsQuery>(std::move(query_promise))->send(hash_);
} }
}
void AttachMenuManager::on_reload_attach_menu_bots( void AttachMenuManager::on_reload_attach_menu_bots(
Result<telegram_api::object_ptr<telegram_api::AttachMenuBots>> &&result, Promise<Unit> &&promise) { Result<telegram_api::object_ptr<telegram_api::AttachMenuBots>> &&result) {
if (!is_active()) { if (!is_active()) {
return promise.set_value(Unit()); return set_promises(reload_attach_menu_bots_queries_);
} }
if (result.is_error()) { if (result.is_error()) {
set_timeout_in(Random::fast(60, 120)); set_timeout_in(Random::fast(60, 120));
return promise.set_value(Unit()); return set_promises(reload_attach_menu_bots_queries_);
} }
is_inited_ = true; is_inited_ = true;
@ -830,7 +833,7 @@ void AttachMenuManager::on_reload_attach_menu_bots(
auto attach_menu_bots_ptr = result.move_as_ok(); auto attach_menu_bots_ptr = result.move_as_ok();
auto constructor_id = attach_menu_bots_ptr->get_id(); auto constructor_id = attach_menu_bots_ptr->get_id();
if (constructor_id == telegram_api::attachMenuBotsNotModified::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); CHECK(constructor_id == telegram_api::attachMenuBots::ID);
auto attach_menu_bots = move_tl_object_as<telegram_api::attachMenuBots>(attach_menu_bots_ptr); auto attach_menu_bots = move_tl_object_as<telegram_api::attachMenuBots>(attach_menu_bots_ptr);
@ -867,7 +870,7 @@ void AttachMenuManager::on_reload_attach_menu_bots(
save_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) { void AttachMenuManager::remove_bot_from_attach_menu(UserId user_id) {

View File

@ -136,8 +136,7 @@ class AttachMenuManager final : public Actor {
void save_attach_menu_bots(); void save_attach_menu_bots();
void on_reload_attach_menu_bots(Result<telegram_api::object_ptr<telegram_api::AttachMenuBots>> &&result, void on_reload_attach_menu_bots(Result<telegram_api::object_ptr<telegram_api::AttachMenuBots>> &&result);
Promise<Unit> &&promise);
void on_get_attach_menu_bot(UserId user_id, void on_get_attach_menu_bot(UserId user_id,
Result<telegram_api::object_ptr<telegram_api::attachMenuBotsBot>> &&result, Result<telegram_api::object_ptr<telegram_api::attachMenuBotsBot>> &&result,
@ -150,6 +149,7 @@ class AttachMenuManager final : public Actor {
int64 hash_ = 0; int64 hash_ = 0;
vector<AttachMenuBot> attach_menu_bots_; vector<AttachMenuBot> attach_menu_bots_;
FlatHashMap<UserId, FileSourceId, UserIdHash> attach_menu_bot_file_source_ids_; FlatHashMap<UserId, FileSourceId, UserIdHash> attach_menu_bot_file_source_ids_;
vector<Promise<Unit>> reload_attach_menu_bots_queries_;
struct OpenedWebView { struct OpenedWebView {
DialogId dialog_id_; DialogId dialog_id_;

View File

@ -7,12 +7,16 @@
#include "td/telegram/AudiosManager.h" #include "td/telegram/AudiosManager.h"
#include "td/telegram/AuthManager.h" #include "td/telegram/AuthManager.h"
#include "td/telegram/DialogId.h"
#include "td/telegram/files/FileManager.h" #include "td/telegram/files/FileManager.h"
#include "td/telegram/files/FileType.h" #include "td/telegram/files/FileType.h"
#include "td/telegram/Global.h"
#include "td/telegram/PhotoFormat.h" #include "td/telegram/PhotoFormat.h"
#include "td/telegram/secret_api.h" #include "td/telegram/secret_api.h"
#include "td/telegram/Td.h" #include "td/telegram/Td.h"
#include "td/actor/actor.h"
#include "td/utils/logging.h" #include "td/utils/logging.h"
#include "td/utils/misc.h" #include "td/utils/misc.h"
#include "td/utils/PathView.h" #include "td/utils/PathView.h"

View File

@ -9,7 +9,6 @@
#include "td/telegram/AttachMenuManager.h" #include "td/telegram/AttachMenuManager.h"
#include "td/telegram/AuthManager.hpp" #include "td/telegram/AuthManager.hpp"
#include "td/telegram/ConfigManager.h" #include "td/telegram/ConfigManager.h"
#include "td/telegram/ConfigShared.h"
#include "td/telegram/ContactsManager.h" #include "td/telegram/ContactsManager.h"
#include "td/telegram/Global.h" #include "td/telegram/Global.h"
#include "td/telegram/logevent/LogEvent.h" #include "td/telegram/logevent/LogEvent.h"
@ -19,6 +18,7 @@
#include "td/telegram/net/NetQueryDispatcher.h" #include "td/telegram/net/NetQueryDispatcher.h"
#include "td/telegram/NewPasswordState.h" #include "td/telegram/NewPasswordState.h"
#include "td/telegram/NotificationManager.h" #include "td/telegram/NotificationManager.h"
#include "td/telegram/OptionManager.h"
#include "td/telegram/PasswordManager.h" #include "td/telegram/PasswordManager.h"
#include "td/telegram/StateManager.h" #include "td/telegram/StateManager.h"
#include "td/telegram/StickersManager.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()) { if (my_id.is_valid()) {
// just in case // just in case
LOG(INFO) << "Logged in as " << my_id; 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); update_state(State::Ok);
} else { } else {
LOG(ERROR) << "Restore unknown my_id"; LOG(ERROR) << "Restore unknown my_id";
@ -701,7 +701,7 @@ void AuthManager::on_log_out_result(NetQueryPtr &result) {
if (r_log_out.is_ok()) { if (r_log_out.is_ok()) {
auto logged_out = r_log_out.move_as_ok(); auto logged_out = r_log_out.move_as_ok();
if (!logged_out->future_auth_token_.empty()) { if (!logged_out->future_auth_token_.empty()) {
G()->shared_config().set_option_string("authentication_token", td_->option_manager_->set_option_string("authentication_token",
base64url_encode(logged_out->future_auth_token_.as_slice())); base64url_encode(logged_out->future_auth_token_.as_slice()));
} }
} else { } else {
@ -722,6 +722,10 @@ void AuthManager::on_authorization_lost(string source) {
LOG(INFO) << "Ignore authorization loss because of " << source << ", while logging out"; LOG(INFO) << "Ignore authorization loss because of " << source << ", while logging out";
return; 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; LOG(WARNING) << "Lost authorization because of " << source;
destroy_auth_keys(); destroy_auth_keys();
} }
@ -792,7 +796,7 @@ void AuthManager::on_get_authorization(tl_object_ptr<telegram_api::auth_Authoriz
} }
auto auth = telegram_api::move_object_as<telegram_api::auth_authorization>(auth_ptr); auto auth = telegram_api::move_object_as<telegram_api::auth_authorization>(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_) { if (was_check_bot_token_) {
is_bot_ = true; is_bot_ = true;
G()->td_db()->get_binlog_pmc()->set("auth_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_ptr<telegram_api::auth_Authoriz
return; return;
} }
if ((auth->flags_ & telegram_api::auth_authorization::TMP_SESSIONS_MASK) != 0) { if ((auth->flags_ & 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) { 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_->attach_menu_manager_->init();
td_->messages_manager_->on_authorization_success(); td_->messages_manager_->on_authorization_success();

View File

@ -8,7 +8,6 @@
#include "td/telegram/AuthManager.h" #include "td/telegram/AuthManager.h"
#include "td/telegram/BackgroundType.hpp" #include "td/telegram/BackgroundType.hpp"
#include "td/telegram/ConfigShared.h"
#include "td/telegram/DialogId.h" #include "td/telegram/DialogId.h"
#include "td/telegram/Document.h" #include "td/telegram/Document.h"
#include "td/telegram/DocumentsManager.h" #include "td/telegram/DocumentsManager.h"
@ -453,7 +452,7 @@ void BackgroundManager::get_backgrounds(bool for_dark_theme,
Result<string> BackgroundManager::get_background_url(const string &name, Result<string> BackgroundManager::get_background_url(const string &name,
td_api::object_ptr<td_api::BackgroundType> background_type) { td_api::object_ptr<td_api::BackgroundType> background_type) {
TRY_RESULT(type, BackgroundType::get_background_type(background_type.get())); 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(); auto link = type.get_link();
if (type.has_file()) { if (type.has_file()) {
url += name; url += name;

View File

@ -6,7 +6,6 @@
// //
#include "td/telegram/CallActor.h" #include "td/telegram/CallActor.h"
#include "td/telegram/ConfigShared.h"
#include "td/telegram/ContactsManager.h" #include "td/telegram/ContactsManager.h"
#include "td/telegram/DhCache.h" #include "td/telegram/DhCache.h"
#include "td/telegram/DialogId.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) { if ((call.flags_ & telegram_api::phoneCallWaiting::RECEIVE_DATE_MASK) != 0) {
call_state_.is_received = true; call_state_.is_received = true;
call_state_need_flush_ = 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<double>(call_ring_timeout_ms) * 0.001); set_timeout_in(static_cast<double>(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() { void CallActor::on_begin_exchanging_key() {
call_state_.type = CallState::Type::ExchangingKey; call_state_.type = CallState::Type::ExchangingKey;
call_state_need_flush_ = true; 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<double>(call_receive_timeout_ms) * 0.001; auto timeout = static_cast<double>(call_receive_timeout_ms) * 0.001;
LOG(INFO) << "Set call timeout to " << timeout; LOG(INFO) << "Set call timeout to " << timeout;
set_timeout_in(timeout); set_timeout_in(timeout);
@ -773,7 +772,7 @@ void CallActor::try_send_request_query() {
call_state_.protocol.get_input_phone_call_protocol()); call_state_.protocol.get_input_phone_call_protocol());
auto query = G()->net_query_creator().create(tl_query); auto query = G()->net_query_creator().create(tl_query);
state_ = State::WaitRequestResult; 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<double>(call_receive_timeout_ms) * 0.001; auto timeout = static_cast<double>(call_receive_timeout_ms) * 0.001;
LOG(INFO) << "Set call timeout to " << timeout; LOG(INFO) << "Set call timeout to " << timeout;
set_timeout_in(timeout); set_timeout_in(timeout);

View File

@ -7,7 +7,6 @@
#include "td/telegram/ConfigManager.h" #include "td/telegram/ConfigManager.h"
#include "td/telegram/AuthManager.h" #include "td/telegram/AuthManager.h"
#include "td/telegram/ConfigShared.h"
#include "td/telegram/ConnectionState.h" #include "td/telegram/ConnectionState.h"
#include "td/telegram/Global.h" #include "td/telegram/Global.h"
#include "td/telegram/JsonValue.h" #include "td/telegram/JsonValue.h"
@ -244,22 +243,19 @@ static ActorOwn<> get_simple_config_impl(Promise<SimpleConfigResult> promise, in
#endif #endif
} }
ActorOwn<> get_simple_config_azure(Promise<SimpleConfigResult> promise, const ConfigShared *shared_config, bool is_test, ActorOwn<> get_simple_config_azure(Promise<SimpleConfigResult> promise, bool prefer_ipv6, Slice domain_name,
int32 scheduler_id) { bool is_test, int32 scheduler_id) {
string url = PSTRING() << "https://software-download.microsoft.com/" << (is_test ? "test" : "prod") string url = PSTRING() << "https://software-download.microsoft.com/" << (is_test ? "test" : "prod")
<< "v2/config.txt"; << "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", {}, return get_simple_config_impl(std::move(promise), scheduler_id, std::move(url), "tcdnb.azureedge.net", {},
prefer_ipv6, prefer_ipv6,
[](HttpQuery &http_query) -> Result<string> { return http_query.content_.str(); }); [](HttpQuery &http_query) -> Result<string> { return http_query.content_.str(); });
} }
static ActorOwn<> get_simple_config_dns(Slice address, Slice host, Promise<SimpleConfigResult> promise, static ActorOwn<> get_simple_config_dns(Slice address, Slice host, Promise<SimpleConfigResult> promise,
const ConfigShared *shared_config, bool is_test, int32 scheduler_id) { bool prefer_ipv6, Slice domain_name, bool is_test, int32 scheduler_id) {
string name = shared_config == nullptr ? string() : shared_config->get_option_string("dc_txt_domain_name"); if (domain_name.empty()) {
const bool prefer_ipv6 = shared_config == nullptr ? false : shared_config->get_option_boolean("prefer_ipv6"); domain_name = is_test ? Slice("tapv3.stel.com") : Slice("apv3.stel.com");
if (name.empty()) {
name = is_test ? "tapv3.stel.com" : "apv3.stel.com";
} }
auto get_config = [](HttpQuery &http_query) -> Result<string> { auto get_config = [](HttpQuery &http_query) -> Result<string> {
auto get_data = [](JsonValue &answer) -> Result<string> { auto get_data = [](JsonValue &answer) -> Result<string> {
@ -302,21 +298,22 @@ static ActorOwn<> get_simple_config_dns(Slice address, Slice host, Promise<Simpl
return get_data(answer); return get_data(answer);
} }
}; };
return get_simple_config_impl(std::move(promise), scheduler_id, return get_simple_config_impl(
PSTRING() << "https://" << address << "?name=" << url_encode(name) << "&type=TXT", std::move(promise), scheduler_id,
host.str(), {{"Accept", "application/dns-json"}}, prefer_ipv6, std::move(get_config)); PSTRING() << "https://" << address << "?name=" << url_encode(domain_name) << "&type=TXT", host.str(),
{{"Accept", "application/dns-json"}}, prefer_ipv6, std::move(get_config));
} }
ActorOwn<> get_simple_config_google_dns(Promise<SimpleConfigResult> promise, const ConfigShared *shared_config, ActorOwn<> get_simple_config_google_dns(Promise<SimpleConfigResult> promise, bool prefer_ipv6, Slice domain_name,
bool is_test, int32 scheduler_id) { bool is_test, int32 scheduler_id) {
return get_simple_config_dns("dns.google/resolve", "dns.google", std::move(promise), shared_config, is_test, return get_simple_config_dns("dns.google/resolve", "dns.google", std::move(promise), prefer_ipv6, domain_name,
scheduler_id); is_test, scheduler_id);
} }
ActorOwn<> get_simple_config_mozilla_dns(Promise<SimpleConfigResult> promise, const ConfigShared *shared_config, ActorOwn<> get_simple_config_mozilla_dns(Promise<SimpleConfigResult> promise, bool prefer_ipv6, Slice domain_name,
bool is_test, int32 scheduler_id) { bool is_test, int32 scheduler_id) {
return get_simple_config_dns("mozilla.cloudflare-dns.com/dns-query", "mozilla.cloudflare-dns.com", std::move(promise), 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() { static string generate_firebase_remote_config_payload() {
@ -329,9 +326,8 @@ static string generate_firebase_remote_config_payload() {
<< app_instance_id << "\"}"; << app_instance_id << "\"}";
} }
ActorOwn<> get_simple_config_firebase_remote_config(Promise<SimpleConfigResult> promise, ActorOwn<> get_simple_config_firebase_remote_config(Promise<SimpleConfigResult> promise, bool prefer_ipv6,
const ConfigShared *shared_config, bool is_test, Slice domain_name, bool is_test, int32 scheduler_id) {
int32 scheduler_id) {
if (is_test) { if (is_test) {
promise.set_error(Status::Error(400, "Test config is not supported")); promise.set_error(Status::Error(400, "Test config is not supported"));
return ActorOwn<>(); return ActorOwn<>();
@ -341,7 +337,6 @@ ActorOwn<> get_simple_config_firebase_remote_config(Promise<SimpleConfigResult>
string url = string url =
"https://firebaseremoteconfig.googleapis.com/v1/projects/peak-vista-421/namespaces/" "https://firebaseremoteconfig.googleapis.com/v1/projects/peak-vista-421/namespaces/"
"firebase:fetch?key=AIzaSyC2-kAkpDsroixRXw-sTw-Wfqo4NxjMwwM"; "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<string> { auto get_config = [](HttpQuery &http_query) -> Result<string> {
TRY_RESULT(json, json_decode(http_query.get_arg("entries"))); TRY_RESULT(json, json_decode(http_query.get_arg("entries")));
if (json.type() != JsonValue::Type::Object) { if (json.type() != JsonValue::Type::Object) {
@ -355,7 +350,7 @@ ActorOwn<> get_simple_config_firebase_remote_config(Promise<SimpleConfigResult>
{}, prefer_ipv6, std::move(get_config), payload, "application/json"); {}, prefer_ipv6, std::move(get_config), payload, "application/json");
} }
ActorOwn<> get_simple_config_firebase_realtime(Promise<SimpleConfigResult> promise, const ConfigShared *shared_config, ActorOwn<> get_simple_config_firebase_realtime(Promise<SimpleConfigResult> promise, bool prefer_ipv6, Slice domain_name,
bool is_test, int32 scheduler_id) { bool is_test, int32 scheduler_id) {
if (is_test) { if (is_test) {
promise.set_error(Status::Error(400, "Test config is not supported")); promise.set_error(Status::Error(400, "Test config is not supported"));
@ -363,7 +358,6 @@ ActorOwn<> get_simple_config_firebase_realtime(Promise<SimpleConfigResult> promi
} }
string url = "https://reserve-5a846.firebaseio.com/ipconfigv3.json"; 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<string> { auto get_config = [](HttpQuery &http_query) -> Result<string> {
return http_query.get_arg("content").str(); return http_query.get_arg("content").str();
}; };
@ -371,15 +365,14 @@ ActorOwn<> get_simple_config_firebase_realtime(Promise<SimpleConfigResult> promi
prefer_ipv6, std::move(get_config)); prefer_ipv6, std::move(get_config));
} }
ActorOwn<> get_simple_config_firebase_firestore(Promise<SimpleConfigResult> promise, const ConfigShared *shared_config, ActorOwn<> get_simple_config_firebase_firestore(Promise<SimpleConfigResult> promise, bool prefer_ipv6,
bool is_test, int32 scheduler_id) { Slice domain_name, bool is_test, int32 scheduler_id) {
if (is_test) { if (is_test) {
promise.set_error(Status::Error(400, "Test config is not supported")); promise.set_error(Status::Error(400, "Test config is not supported"));
return ActorOwn<>(); return ActorOwn<>();
} }
string url = "https://www.google.com/v1/projects/reserve-5a846/databases/(default)/documents/ipconfig/v3"; 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<string> { auto get_config = [](HttpQuery &http_query) -> Result<string> {
TRY_RESULT(json, json_decode(http_query.get_arg("fields"))); TRY_RESULT(json, json_decode(http_query.get_arg("fields")));
if (json.type() != JsonValue::Type::Object) { if (json.type() != JsonValue::Type::Object) {
@ -661,7 +654,7 @@ class ConfigRecoverer final : public Actor {
auto config = r_simple_config.move_as_ok(); auto config = r_simple_config.move_as_ok();
VLOG(config_recoverer) << "Receive raw " << to_string(config); VLOG(config_recoverer) << "Receive raw " << to_string(config);
if (config->expires_ >= G()->unix_time()) { 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(); simple_config_.dc_options.clear();
for (auto &rule : config->rules_) { for (auto &rule : config->rules_) {
@ -708,7 +701,7 @@ class ConfigRecoverer final : public Actor {
} }
static bool expect_blocking() { 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 { double get_config_expire_time() const {
@ -842,8 +835,9 @@ class ConfigRecoverer final : public Actor {
return get_simple_config_mozilla_dns; return get_simple_config_mozilla_dns;
} }
}(); }();
simple_config_query_ = simple_config_query_ = get_simple_config(std::move(promise), G()->get_option_boolean("prefer_ipv6"),
get_simple_config(std::move(promise), &G()->shared_config(), G()->is_test_dc(), G()->get_gc_scheduler_id()); G()->get_option_string("dc_txt_domain_name"), G()->is_test_dc(),
G()->get_gc_scheduler_id());
simple_config_turn_++; 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) { void ConfigManager::do_set_ignore_sensitive_content_restrictions(bool ignore_sensitive_content_restrictions) {
G()->shared_config().set_option_boolean("ignore_sensitive_content_restrictions", G()->set_option_boolean("ignore_sensitive_content_restrictions", ignore_sensitive_content_restrictions);
ignore_sensitive_content_restrictions); bool have_ignored_restriction_reasons = G()->have_option("ignored_restriction_reasons");
bool have_ignored_restriction_reasons = G()->shared_config().have_option("ignored_restriction_reasons");
if (have_ignored_restriction_reasons != ignore_sensitive_content_restrictions) { if (have_ignored_restriction_reasons != ignore_sensitive_content_restrictions) {
reget_app_config(Auto()); reget_app_config(Auto());
} }
@ -1113,7 +1106,7 @@ void ConfigManager::do_set_archive_and_mute(bool archive_and_mute) {
if (archive_and_mute) { if (archive_and_mute) {
remove_suggested_action(suggested_actions_, SuggestedAction{SuggestedAction::Type::EnableArchiveAndMuteNewChats}); 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) { void ConfigManager::hide_suggested_action(SuggestedAction suggested_action) {
@ -1211,7 +1204,7 @@ void ConfigManager::on_result(NetQueryPtr res) {
if (result_ptr.is_error()) { if (result_ptr.is_error()) {
fail_promises(set_content_settings_queries_[ignore_sensitive_content_restrictions], result_ptr.move_as_error()); fail_promises(set_content_settings_queries_[ignore_sensitive_content_restrictions], result_ptr.move_as_error());
} else { } 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) { last_set_content_settings_ == ignore_sensitive_content_restrictions) {
do_set_ignore_sensitive_content_restrictions(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(); auto result = result_ptr.move_as_ok();
do_set_ignore_sensitive_content_restrictions(result->sensitive_enabled_); 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_); set_promises(get_content_settings_queries_);
return; return;
@ -1328,130 +1321,130 @@ void ConfigManager::process_config(tl_object_ptr<telegram_api::config> config) {
set_timeout_at(expire_time_.at()); set_timeout_at(expire_time_.at());
LOG_IF(ERROR, config->test_mode_ != G()->is_test_dc()) << "Wrong parameter is_test"; 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. // 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_)); 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_); options.set_option_integer("recent_stickers_limit", config->stickers_recent_limit_);
shared_config.set_option_integer("favorite_stickers_limit", config->stickers_faved_limit_); options.set_option_integer("favorite_stickers_limit", config->stickers_faved_limit_);
shared_config.set_option_integer("saved_animations_limit", config->saved_gifs_limit_); options.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("channels_read_media_period", config->channels_read_media_period_);
shared_config.set_option_boolean("test_mode", config->test_mode_); options.set_option_boolean("test_mode", config->test_mode_);
shared_config.set_option_integer("forwarded_message_count_max", config->forwarded_count_max_); options.set_option_integer("forwarded_message_count_max", config->forwarded_count_max_);
shared_config.set_option_integer("basic_group_size_max", config->chat_size_max_); options.set_option_integer("basic_group_size_max", config->chat_size_max_);
shared_config.set_option_integer("supergroup_size_max", config->megagroup_size_max_); options.set_option_integer("supergroup_size_max", config->megagroup_size_max_);
shared_config.set_option_integer("pinned_chat_count_max", config->pinned_dialogs_count_max_); options.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_); options.set_option_integer("pinned_archived_chat_count_max", config->pinned_infolder_count_max_);
if (is_from_main_dc || !shared_config.have_option("expect_blocking")) { if (is_from_main_dc || !options.have_option("expect_blocking")) {
shared_config.set_option_boolean("expect_blocking", config->blocked_mode_); options.set_option_boolean("expect_blocking", config->blocked_mode_);
} }
if (is_from_main_dc || !shared_config.have_option("dc_txt_domain_name")) { if (is_from_main_dc || !options.have_option("dc_txt_domain_name")) {
shared_config.set_option_string("dc_txt_domain_name", config->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_; auto url = config->me_url_prefix_;
if (!url.empty()) { if (!url.empty()) {
if (url.back() != '/') { if (url.back() != '/') {
url.push_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) { 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) { 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 { } 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) { if ((config->flags_ & telegram_api::config::SUGGESTED_LANG_CODE_MASK) != 0) {
shared_config.set_option_string("suggested_language_pack_id", config->suggested_lang_code_); options.set_option_string("suggested_language_pack_id", config->suggested_lang_code_);
shared_config.set_option_integer("language_pack_version", config->lang_pack_version_); options.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_integer("base_language_pack_version", config->base_lang_pack_version_);
} else { } else {
shared_config.set_option_empty("suggested_language_pack_id"); options.set_option_empty("suggested_language_pack_id");
shared_config.set_option_empty("language_pack_version"); options.set_option_empty("language_pack_version");
shared_config.set_option_empty("base_language_pack_version"); options.set_option_empty("base_language_pack_version");
} }
} }
if (is_from_main_dc) { if (is_from_main_dc) {
shared_config.set_option_integer("edit_time_limit", config->edit_time_limit_); options.set_option_integer("edit_time_limit", config->edit_time_limit_);
shared_config.set_option_boolean("revoke_pm_inbox", config->revoke_pm_inbox_); options.set_option_boolean("revoke_pm_inbox", config->revoke_pm_inbox_);
shared_config.set_option_integer("revoke_time_limit", config->revoke_time_limit_); options.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("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_); options.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_); options.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_); options.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_receive_timeout_ms", config->call_receive_timeout_ms_);
shared_config.set_option_integer("message_text_length_max", clamp(config->message_length_max_, 4096, 1000000)); options.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_caption_length_max", clamp(config->caption_length_max_, 1024, 1000000));
if (config->gif_search_username_.empty()) { if (config->gif_search_username_.empty()) {
shared_config.set_option_empty("animation_search_bot_username"); options.set_option_empty("animation_search_bot_username");
} else { } 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()) { if (config->venue_search_username_.empty()) {
shared_config.set_option_empty("venue_search_bot_username"); options.set_option_empty("venue_search_bot_username");
} else { } 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()) { if (config->img_search_username_.empty()) {
shared_config.set_option_empty("photo_search_bot_username"); options.set_option_empty("photo_search_bot_username");
} else { } 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) { auto fix_timeout_ms = [](int32 timeout_ms) {
return clamp(timeout_ms, 1000, 86400 * 1000); 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_)); options.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_)); options.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("notification_default_delay_ms", fix_timeout_ms(config->notify_default_delay_ms_));
// delete outdated options // delete outdated options
shared_config.set_option_empty("suggested_language_code"); options.set_option_empty("suggested_language_code");
shared_config.set_option_empty("chat_big_size"); options.set_option_empty("chat_big_size");
shared_config.set_option_empty("group_size_max"); options.set_option_empty("group_size_max");
shared_config.set_option_empty("saved_gifs_limit"); options.set_option_empty("saved_gifs_limit");
shared_config.set_option_empty("sessions_count"); options.set_option_empty("sessions_count");
shared_config.set_option_empty("forwarded_messages_count_max"); options.set_option_empty("forwarded_messages_count_max");
shared_config.set_option_empty("broadcast_size_max"); options.set_option_empty("broadcast_size_max");
shared_config.set_option_empty("group_chat_size_max"); options.set_option_empty("group_chat_size_max");
shared_config.set_option_empty("chat_size_max"); options.set_option_empty("chat_size_max");
shared_config.set_option_empty("megagroup_size_max"); options.set_option_empty("megagroup_size_max");
shared_config.set_option_empty("offline_blur_timeout_ms"); options.set_option_empty("offline_blur_timeout_ms");
shared_config.set_option_empty("offline_idle_timeout_ms"); options.set_option_empty("offline_idle_timeout_ms");
shared_config.set_option_empty("notify_cloud_delay_ms"); options.set_option_empty("notify_cloud_delay_ms");
shared_config.set_option_empty("notify_default_delay_ms"); options.set_option_empty("notify_default_delay_ms");
shared_config.set_option_empty("large_chat_size"); options.set_option_empty("large_chat_size");
// TODO implement online status updates // TODO implement online status updates
// shared_config.set_option_integer("offline_blur_timeout_ms", config->offline_blur_timeout_ms_); // options.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_idle_timeout_ms", config->offline_idle_timeout_ms_);
// shared_config.set_option_integer("push_chat_period_ms", config->push_chat_period_ms_); // options.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_limit", config->push_chat_limit_);
if (is_from_main_dc) { if (is_from_main_dc) {
reget_app_config(Auto()); reget_app_config(Auto());
if (!shared_config.have_option("can_ignore_sensitive_content_restrictions") || if (!options.have_option("can_ignore_sensitive_content_restrictions") ||
!shared_config.have_option("ignore_sensitive_content_restrictions")) { !options.have_option("ignore_sensitive_content_restrictions")) {
get_content_settings(Auto()); 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()); get_global_privacy_settings(Auto());
} }
} }
@ -1461,8 +1454,7 @@ void ConfigManager::process_app_config(tl_object_ptr<telegram_api::JSONValue> &c
CHECK(config != nullptr); CHECK(config != nullptr);
LOG(INFO) << "Receive app config " << to_string(config); LOG(INFO) << "Receive app config " << to_string(config);
const bool archive_and_mute = const bool archive_and_mute = G()->get_option_boolean("archive_and_mute_new_chats_from_unknown_users");
G()->shared_config().get_option_boolean("archive_and_mute_new_chats_from_unknown_users");
string autologin_token; string autologin_token;
vector<string> autologin_domains; vector<string> autologin_domains;
@ -1701,16 +1693,16 @@ void ConfigManager::process_app_config(tl_object_ptr<telegram_api::JSONValue> &c
auto setting_value = get_json_value_int(std::move(video_note_setting->value_), Slice()); auto setting_value = get_json_value_int(std::move(video_note_setting->value_), Slice());
if (setting_value > 0) { if (setting_value > 0) {
if (video_note_setting->key_ == "diameter") { 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") { 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") { 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") { 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 { } else {
@ -1740,17 +1732,17 @@ void ConfigManager::process_app_config(tl_object_ptr<telegram_api::JSONValue> &c
} }
if (key == "ringtone_duration_max") { if (key == "ringtone_duration_max") {
auto setting_value = get_json_value_int(std::move(key_value->value_), key); 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; continue;
} }
if (key == "ringtone_size_max") { if (key == "ringtone_size_max") {
auto setting_value = get_json_value_int(std::move(key_value->value_), key); 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; continue;
} }
if (key == "ringtone_saved_count_max") { if (key == "ringtone_saved_count_max") {
auto setting_value = get_json_value_int(std::move(key_value->value_), key); 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; continue;
} }
if (key == "premium_promo_order") { if (key == "premium_promo_order") {
@ -1774,7 +1766,7 @@ void ConfigManager::process_app_config(tl_object_ptr<telegram_api::JSONValue> &c
if (suffix == "_limit_default" || suffix == "_limit_premium") { if (suffix == "_limit_default" || suffix == "_limit_premium") {
auto setting_value = get_json_value_int(std::move(key_value->value_), key); auto setting_value = get_json_value_int(std::move(key_value->value_), key);
if (setting_value > 0) { if (setting_value > 0) {
G()->shared_config().set_option_integer(key, setting_value); G()->set_option_integer(key, setting_value);
} else { } else {
LOG(ERROR) << "Receive invalid value " << setting_value << " for " << key; LOG(ERROR) << "Receive invalid value " << setting_value << " for " << key;
} }
@ -1817,18 +1809,18 @@ void ConfigManager::process_app_config(tl_object_ptr<telegram_api::JSONValue> &c
send_closure(G()->link_manager(), &LinkManager::update_autologin_domains, std::move(autologin_token), send_closure(G()->link_manager(), &LinkManager::update_autologin_domains, std::move(autologin_token),
std::move(autologin_domains), std::move(url_auth_domains)); std::move(autologin_domains), std::move(url_auth_domains));
ConfigShared &shared_config = G()->shared_config(); Global &options = *G();
if (ignored_restriction_reasons.empty()) { 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()); get_content_settings(Auto());
} }
} else { } 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()); get_content_settings(Auto());
} }
} }
@ -1843,94 +1835,93 @@ void ConfigManager::process_app_config(tl_object_ptr<telegram_api::JSONValue> &c
} }
dice_success_values[dice_emoji_it->second] = it.second; dice_success_values[dice_emoji_it->second] = it.second;
} }
shared_config.set_option_string("dice_success_values", implode(dice_success_values, ',')); options.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_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) { 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 { } else {
shared_config.set_option_integer("animated_emoji_zoom", static_cast<int64>(animated_emoji_zoom * 1e9)); options.set_option_integer("animated_emoji_zoom", static_cast<int64>(animated_emoji_zoom * 1e9));
} }
if (animation_search_provider.empty()) { if (animation_search_provider.empty()) {
shared_config.set_option_empty("animation_search_provider"); options.set_option_empty("animation_search_provider");
} else { } 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()) { if (animation_search_emojis.empty()) {
shared_config.set_option_empty("animation_search_emojis"); options.set_option_empty("animation_search_emojis");
} else { } 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) { 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 { } else {
shared_config.set_option_boolean("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); can_archive_and_mute_new_chats_from_unknown_users);
} }
if (chat_read_mark_expire_period <= 0) { 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 { } 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) { 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 { } 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")) { if (!options.have_option("default_reaction_need_sync")) {
shared_config.set_option_string("default_reaction", default_reaction); options.set_option_string("default_reaction", default_reaction);
} }
if (reactions_uniq_max <= 0 || reactions_uniq_max == 11) { 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 { } 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); 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<int32>(chat_filter_count_max)); options.set_option_integer("chat_filter_count_max", static_cast<int32>(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 ? Slice("dialog_filters_chats_limit_premium") : Slice("dialog_filters_chats_limit_default"),
is_premium ? 200 : 100); is_premium ? 200 : 100);
shared_config.set_option_integer("chat_filter_chosen_chat_count_max", options.set_option_integer("chat_filter_chosen_chat_count_max",
static_cast<int32>(chat_filter_chosen_chat_count_max)); static_cast<int32>(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); 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) { if (!is_premium_available) {
premium_bot_username.clear(); // just in case premium_bot_username.clear(); // just in case
premium_invoice_slug.clear(); // just in case premium_invoice_slug.clear(); // just in case
premium_features.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 { } 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()) { if (premium_bot_username.empty()) {
shared_config.set_option_empty("premium_bot_username"); options.set_option_empty("premium_bot_username");
} else { } 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()) { if (premium_invoice_slug.empty()) {
shared_config.set_option_empty("premium_invoice_slug"); options.set_option_empty("premium_invoice_slug");
} else { } 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); options.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", options.set_option_integer("stickers_normal_by_emoji_per_premium_num", stickers_normal_by_emoji_per_premium_num);
stickers_normal_by_emoji_per_premium_num);
shared_config.set_option_empty("default_ton_blockchain_config"); options.set_option_empty("default_ton_blockchain_config");
shared_config.set_option_empty("default_ton_blockchain_name"); options.set_option_empty("default_ton_blockchain_name");
// do not update suggested actions while changing content settings or dismissing an action // 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) { if (!is_set_content_settings_request_sent_ && dismiss_suggested_action_request_count_ == 0) {

View File

@ -30,8 +30,6 @@ namespace td {
extern int VERBOSITY_NAME(config_recoverer); extern int VERBOSITY_NAME(config_recoverer);
class ConfigShared;
using SimpleConfig = tl_object_ptr<telegram_api::help_configSimple>; using SimpleConfig = tl_object_ptr<telegram_api::help_configSimple>;
struct SimpleConfigResult { struct SimpleConfigResult {
Result<SimpleConfig> r_config; Result<SimpleConfig> r_config;
@ -40,25 +38,24 @@ struct SimpleConfigResult {
Result<SimpleConfig> decode_config(Slice input); Result<SimpleConfig> decode_config(Slice input);
ActorOwn<> get_simple_config_azure(Promise<SimpleConfigResult> promise, const ConfigShared *shared_config, bool is_test, ActorOwn<> get_simple_config_azure(Promise<SimpleConfigResult> promise, bool prefer_ipv6, Slice domain_name,
int32 scheduler_id);
ActorOwn<> get_simple_config_google_dns(Promise<SimpleConfigResult> promise, const ConfigShared *shared_config,
bool is_test, int32 scheduler_id); bool is_test, int32 scheduler_id);
ActorOwn<> get_simple_config_mozilla_dns(Promise<SimpleConfigResult> promise, const ConfigShared *shared_config, ActorOwn<> get_simple_config_google_dns(Promise<SimpleConfigResult> promise, bool prefer_ipv6, Slice domain_name,
bool is_test, int32 scheduler_id); bool is_test, int32 scheduler_id);
ActorOwn<> get_simple_config_firebase_remote_config(Promise<SimpleConfigResult> promise, ActorOwn<> get_simple_config_mozilla_dns(Promise<SimpleConfigResult> promise, bool prefer_ipv6, Slice domain_name,
const ConfigShared *shared_config, bool is_test,
int32 scheduler_id);
ActorOwn<> get_simple_config_firebase_realtime(Promise<SimpleConfigResult> promise, const ConfigShared *shared_config,
bool is_test, int32 scheduler_id); bool is_test, int32 scheduler_id);
ActorOwn<> get_simple_config_firebase_firestore(Promise<SimpleConfigResult> promise, const ConfigShared *shared_config, ActorOwn<> get_simple_config_firebase_remote_config(Promise<SimpleConfigResult> promise, bool prefer_ipv6,
Slice domain_name, bool is_test, int32 scheduler_id);
ActorOwn<> get_simple_config_firebase_realtime(Promise<SimpleConfigResult> promise, bool prefer_ipv6, Slice domain_name,
bool is_test, int32 scheduler_id); bool is_test, int32 scheduler_id);
ActorOwn<> get_simple_config_firebase_firestore(Promise<SimpleConfigResult> promise, bool prefer_ipv6,
Slice domain_name, bool is_test, int32 scheduler_id);
class HttpDate { class HttpDate {
static bool is_leap(int32 year) { static bool is_leap(int32 year) {
return year % 4 == 0 && (year % 100 != 0 || year % 400 == 0); return year % 4 == 0 && (year % 100 != 0 || year % 400 == 0);

View File

@ -1,118 +0,0 @@
//
// Copyright Aliaksei Levin (levlam@telegram.org), Arseny Smirnov (arseny30@gmail.com) 2014-2022
//
// Distributed under the Boost Software License, Version 1.0. (See accompanying
// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
//
#include "td/telegram/ConfigShared.h"
#include "td/utils/logging.h"
#include "td/utils/misc.h"
#include "td/utils/SliceBuilder.h"
namespace td {
ConfigShared::ConfigShared(std::shared_ptr<KeyValueSyncInterface> config_pmc) : config_pmc_(std::move(config_pmc)) {
}
void ConfigShared::set_callback(unique_ptr<Callback> callback) {
callback_ = std::move(callback);
if (callback_ == nullptr) {
return;
}
for (const auto &key_value : config_pmc_->get_all()) {
on_option_updated(key_value.first);
}
}
void ConfigShared::set_option_boolean(Slice name, bool value) {
if (set_option(name, value ? Slice("Btrue") : Slice("Bfalse"))) {
on_option_updated(name);
}
}
void ConfigShared::set_option_empty(Slice name) {
if (set_option(name, Slice())) {
on_option_updated(name);
}
}
void ConfigShared::set_option_integer(Slice name, int64 value) {
if (set_option(name, PSLICE() << 'I' << value)) {
on_option_updated(name);
}
}
void ConfigShared::set_option_string(Slice name, Slice value) {
if (set_option(name, PSLICE() << 'S' << value)) {
on_option_updated(name);
}
}
bool ConfigShared::have_option(Slice name) const {
return config_pmc_->isset(name.str());
}
string ConfigShared::get_option(Slice name) const {
return config_pmc_->get(name.str());
}
std::unordered_map<string, string> ConfigShared::get_options() const {
return config_pmc_->get_all();
}
bool ConfigShared::get_option_boolean(Slice name, bool default_value) const {
auto value = get_option(name);
if (value.empty()) {
return default_value;
}
if (value == "Btrue") {
return true;
}
if (value == "Bfalse") {
return false;
}
LOG(ERROR) << "Found \"" << value << "\" instead of boolean option " << name;
return default_value;
}
int64 ConfigShared::get_option_integer(Slice name, int64 default_value) const {
auto value = get_option(name);
if (value.empty()) {
return default_value;
}
if (value[0] != 'I') {
LOG(ERROR) << "Found \"" << value << "\" instead of integer option " << name;
return default_value;
}
return to_integer<int64>(value.substr(1));
}
string ConfigShared::get_option_string(Slice name, string default_value) const {
auto value = get_option(name);
if (value.empty()) {
return default_value;
}
if (value[0] != 'S') {
LOG(ERROR) << "Found \"" << value << "\" instead of string option " << name;
return default_value;
}
return value.substr(1);
}
bool ConfigShared::set_option(Slice name, Slice value) {
if (value.empty()) {
return config_pmc_->erase(name.str()) != 0;
} else {
return config_pmc_->set(name.str(), value.str()) != 0;
}
}
void ConfigShared::on_option_updated(Slice name) const {
if (callback_ != nullptr) {
callback_->on_option_updated(name.str(), get_option(name));
}
}
} // namespace td

View File

@ -1,60 +0,0 @@
//
// Copyright Aliaksei Levin (levlam@telegram.org), Arseny Smirnov (arseny30@gmail.com) 2014-2022
//
// Distributed under the Boost Software License, Version 1.0. (See accompanying
// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
//
#pragma once
#include "td/db/KeyValueSyncInterface.h"
#include "td/utils/common.h"
#include "td/utils/Slice.h"
#include <memory>
#include <unordered_map>
namespace td {
class ConfigShared {
public:
class Callback {
public:
Callback() = default;
Callback(const Callback &) = delete;
Callback &operator=(const Callback &) = delete;
Callback(Callback &&) = delete;
Callback &operator=(Callback &&) = delete;
virtual ~Callback() = default;
virtual void on_option_updated(const string &name, const string &value) const = 0;
};
explicit ConfigShared(std::shared_ptr<KeyValueSyncInterface> config_pmc);
void set_callback(unique_ptr<Callback> callback);
void set_option_boolean(Slice name, bool value);
void set_option_empty(Slice name);
void set_option_integer(Slice name, int64 value);
void set_option_string(Slice name, Slice value);
bool have_option(Slice name) const;
string get_option(Slice name) const;
std::unordered_map<string, string> get_options() const;
bool get_option_boolean(Slice name, bool default_value = false) const;
int64 get_option_integer(Slice name, int64 default_value = 0) const;
string get_option_string(Slice name, string default_value = "") const;
private:
std::shared_ptr<KeyValueSyncInterface> config_pmc_;
unique_ptr<Callback> callback_;
bool set_option(Slice name, Slice value);
void on_option_updated(Slice name) const;
};
} // namespace td

View File

@ -11,7 +11,6 @@
#include "td/telegram/BotMenuButton.h" #include "td/telegram/BotMenuButton.h"
#include "td/telegram/ChannelParticipantFilter.h" #include "td/telegram/ChannelParticipantFilter.h"
#include "td/telegram/ConfigManager.h" #include "td/telegram/ConfigManager.h"
#include "td/telegram/ConfigShared.h"
#include "td/telegram/Dependencies.h" #include "td/telegram/Dependencies.h"
#include "td/telegram/DialogInviteLink.h" #include "td/telegram/DialogInviteLink.h"
#include "td/telegram/DialogLocation.h" #include "td/telegram/DialogLocation.h"
@ -36,6 +35,7 @@
#include "td/telegram/misc.h" #include "td/telegram/misc.h"
#include "td/telegram/net/NetQuery.h" #include "td/telegram/net/NetQuery.h"
#include "td/telegram/NotificationManager.h" #include "td/telegram/NotificationManager.h"
#include "td/telegram/OptionManager.h"
#include "td/telegram/PasswordManager.h" #include "td/telegram/PasswordManager.h"
#include "td/telegram/Photo.h" #include "td/telegram/Photo.h"
#include "td/telegram/Photo.hpp" #include "td/telegram/Photo.hpp"
@ -3334,11 +3334,11 @@ ContactsManager::ContactsManager(Td *td, ActorShared<> parent) : td_(td), parent
my_id_ = load_my_id(); my_id_ = load_my_id();
G()->shared_config().set_option_integer("telegram_service_notifications_chat_id", td_->option_manager_->set_option_integer("telegram_service_notifications_chat_id",
DialogId(get_service_notifications_user_id()).get()); DialogId(get_service_notifications_user_id()).get());
G()->shared_config().set_option_integer("replies_bot_chat_id", DialogId(get_replies_bot_user_id()).get()); td_->option_manager_->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()); td_->option_manager_->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("channel_bot_user_id", get_channel_bot_user_id().get());
if (G()->parameters().use_chat_info_db) { if (G()->parameters().use_chat_info_db) {
auto next_contacts_sync_date_string = G()->td_db()->get_binlog_pmc()->get("next_contacts_sync_date"); 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"); G()->td_db()->get_binlog_pmc()->get("pending_location_visibility_expire_date");
if (!pending_location_visibility_expire_date_string.empty()) { if (!pending_location_visibility_expire_date_string.empty()) {
pending_location_visibility_expire_date_ = to_integer<int32>(pending_location_visibility_expire_date_string); pending_location_visibility_expire_date_ = to_integer<int32>(pending_location_visibility_expire_date_string);
try_send_set_location_visibility_query();
} }
update_is_location_visible(); update_is_location_visible();
LOG(INFO) << "Loaded location_visibility_expire_date = " << location_visibility_expire_date_ 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_); 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() { void ContactsManager::tear_down() {
parent_.reset(); parent_.reset();
@ -5100,7 +5105,7 @@ void ContactsManager::set_my_id(UserId my_id) {
if (my_old_id != my_id) { if (my_old_id != my_id) {
my_id_ = my_id; my_id_ = my_id;
G()->td_db()->get_binlog_pmc()->set("my_id", to_string(my_id.get())); 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<Unit>()); G()->td_db()->get_binlog_pmc()->force_sync(Promise<Unit>());
} }
} }
@ -6037,20 +6042,24 @@ void ContactsManager::set_location(const Location &location, Promise<Unit> &&pro
td_->create_handler<SearchDialogsNearbyQuery>(std::move(query_promise))->send(location, true, -1); td_->create_handler<SearchDialogsNearbyQuery>(std::move(query_promise))->send(location, true, -1);
} }
void ContactsManager::set_location_visibility() { void ContactsManager::set_location_visibility(Td *td) {
bool is_location_visible = G()->shared_config().get_option_boolean("is_location_visible"); 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<int32>::max() : 0; auto pending_location_visibility_expire_date = is_location_visible ? std::numeric_limits<int32>::max() : 0;
if (pending_location_visibility_expire_date_ == -1 && if (td->contacts_manager_ == nullptr) {
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;
G()->td_db()->get_binlog_pmc()->set("pending_location_visibility_expire_date", G()->td_db()->get_binlog_pmc()->set("pending_location_visibility_expire_date",
to_string(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() { void ContactsManager::try_send_set_location_visibility_query() {
@ -6061,6 +6070,7 @@ void ContactsManager::try_send_set_location_visibility_query() {
return; return;
} }
LOG(INFO) << "Trying to send set location visibility query";
if (is_set_location_visibility_request_sent_) { if (is_set_location_visibility_request_sent_) {
return; return;
} }
@ -6261,7 +6271,7 @@ void ContactsManager::set_location_visibility_expire_date(int32 expire_date) {
void ContactsManager::update_is_location_visible() { void ContactsManager::update_is_location_visible() {
auto expire_date = pending_location_visibility_expire_date_ != -1 ? pending_location_visibility_expire_date_ auto expire_date = pending_location_visibility_expire_date_ != -1 ? pending_location_visibility_expire_date_
: 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, 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<Unit> &&promise) { void ContactsManager::set_bio(const string &bio, Promise<Unit> &&promise) {
auto max_bio_length = static_cast<size_t>(G()->shared_config().get_option_integer("bio_length_max")); auto max_bio_length = static_cast<size_t>(td_->option_manager_->get_option_integer("bio_length_max"));
auto new_bio = strip_empty_characters(bio, max_bio_length); auto new_bio = strip_empty_characters(bio, max_bio_length);
for (auto &c : new_bio) { for (auto &c : new_bio) {
if (c == '\n') { if (c == '\n') {
@ -8613,7 +8623,7 @@ void ContactsManager::on_get_user(tl_object_ptr<telegram_api::User> &&user_ptr,
if (flags & USER_FLAG_IS_ME) { if (flags & USER_FLAG_IS_ME) {
set_my_id(user_id); set_my_id(user_id);
if (!is_bot) { 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) { void ContactsManager::update_user(User *u, UserId user_id, bool from_binlog, bool from_database) {
CHECK(u != nullptr); CHECK(u != nullptr);
if (user_id == get_my_id()) { if (user_id == get_my_id()) {
if (G()->shared_config().get_option_boolean("is_premium") != u->is_premium) { if (td_->option_manager_->get_option_boolean("is_premium") != u->is_premium) {
G()->shared_config().set_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); 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() { 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, send_closure(G()->td(), &Td::send_update,
td_api::make_object<td_api::updateUser>(get_user_object(user_id, get_user(user_id)))); td_api::make_object<td_api::updateUser>(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( send_closure(
G()->td(), &Td::send_update, G()->td(), &Td::send_update,
td_api::make_object<td_api::updateSupergroup>(get_supergroup_object(channel_id, get_channel(channel_id)))); td_api::make_object<td_api::updateSupergroup>(get_supergroup_object(channel_id, get_channel(channel_id))));
} });
} }
void ContactsManager::on_set_profile_photo(tl_object_ptr<telegram_api::photos_photo> &&photo, int64 old_photo_id) { void ContactsManager::on_set_profile_photo(tl_object_ptr<telegram_api::photos_photo> &&photo, int64 old_photo_id) {

View File

@ -51,6 +51,7 @@
#include "td/utils/StringBuilder.h" #include "td/utils/StringBuilder.h"
#include "td/utils/Time.h" #include "td/utils/Time.h"
#include "td/utils/WaitFreeHashMap.h" #include "td/utils/WaitFreeHashMap.h"
#include "td/utils/WaitFreeHashSet.h"
#include <functional> #include <functional>
#include <memory> #include <memory>
@ -326,7 +327,7 @@ class ContactsManager final : public Actor {
void set_location(const Location &location, Promise<Unit> &&promise); void set_location(const Location &location, Promise<Unit> &&promise);
void set_location_visibility(); static void set_location_visibility(Td *td);
void get_is_location_visible(Promise<Unit> &&promise); void get_is_location_visible(Promise<Unit> &&promise);
@ -1693,6 +1694,8 @@ class ContactsManager final : public Actor {
void on_channel_participant_cache_timeout(ChannelId channel_id); void on_channel_participant_cache_timeout(ChannelId channel_id);
void start_up() final;
void tear_down() final; void tear_down() final;
Td *td_; Td *td_;
@ -1724,7 +1727,7 @@ class ContactsManager final : public Actor {
WaitFreeHashMap<ChannelId, unique_ptr<Channel>, ChannelIdHash> channels_; WaitFreeHashMap<ChannelId, unique_ptr<Channel>, ChannelIdHash> channels_;
WaitFreeHashMap<ChannelId, unique_ptr<ChannelFull>, ChannelIdHash> channels_full_; WaitFreeHashMap<ChannelId, unique_ptr<ChannelFull>, ChannelIdHash> channels_full_;
mutable FlatHashSet<ChannelId, ChannelIdHash> unknown_channels_; mutable FlatHashSet<ChannelId, ChannelIdHash> unknown_channels_;
FlatHashSet<ChannelId, ChannelIdHash> invalidated_channels_full_; WaitFreeHashSet<ChannelId, ChannelIdHash> invalidated_channels_full_;
WaitFreeHashMap<ChannelId, FileSourceId, ChannelIdHash> channel_full_file_source_ids_; WaitFreeHashMap<ChannelId, FileSourceId, ChannelIdHash> channel_full_file_source_ids_;
WaitFreeHashMap<SecretChatId, unique_ptr<SecretChat>, SecretChatIdHash> secret_chats_; WaitFreeHashMap<SecretChatId, unique_ptr<SecretChat>, SecretChatIdHash> secret_chats_;
@ -1843,8 +1846,8 @@ class ContactsManager final : public Actor {
WaitFreeHashMap<ChannelId, ChannelId, ChannelIdHash> linked_channel_ids_; WaitFreeHashMap<ChannelId, ChannelId, ChannelIdHash> linked_channel_ids_;
FlatHashSet<UserId, UserIdHash> restricted_user_ids_; WaitFreeHashSet<UserId, UserIdHash> restricted_user_ids_;
FlatHashSet<ChannelId, ChannelIdHash> restricted_channel_ids_; WaitFreeHashSet<ChannelId, ChannelIdHash> restricted_channel_ids_;
vector<Contact> next_all_imported_contacts_; vector<Contact> next_all_imported_contacts_;
vector<size_t> imported_contacts_unique_id_; vector<size_t> imported_contacts_unique_id_;

View File

@ -256,7 +256,7 @@ void DeviceTokenManager::register_device(tl_object_ptr<td_api::DeviceToken> devi
} else { } else {
if ((info.state == TokenInfo::State::Reregister || info.state == TokenInfo::State::Sync) && info.token == token && 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) { 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<td_api::pushReceiverId>(push_token_id)); return promise.set_value(td_api::make_object<td_api::pushReceiverId>(push_token_id));
} }
@ -308,7 +308,7 @@ vector<std::pair<int64, Slice>> DeviceTokenManager::get_encryption_keys() const
if (info.encrypt) { if (info.encrypt) {
result.emplace_back(info.encryption_key_id, info.encryption_key); result.emplace_back(info.encryption_key_id, info.encryption_key);
} else { } 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) { if (info.encrypt) {
push_token_id = info.encryption_key_id; push_token_id = info.encryption_key_id;
} else { } 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<td_api::pushReceiverId>(push_token_id)); info.promise.set_value(td_api::make_object<td_api::pushReceiverId>(push_token_id));

View File

@ -6,7 +6,6 @@
// //
#include "td/telegram/DialogFilter.h" #include "td/telegram/DialogFilter.h"
#include "td/telegram/ConfigShared.h"
#include "td/telegram/DialogId.h" #include "td/telegram/DialogId.h"
#include "td/telegram/Global.h" #include "td/telegram/Global.h"
@ -20,7 +19,7 @@
namespace td { namespace td {
int32 DialogFilter::get_max_filter_dialogs() { int32 DialogFilter::get_max_filter_dialogs() {
return narrow_cast<int32>(G()->shared_config().get_option_integer("chat_filter_chosen_chat_count_max", 100)); return narrow_cast<int32>(G()->get_option_integer("chat_filter_chosen_chat_count_max", 100));
} }
unique_ptr<DialogFilter> DialogFilter::get_dialog_filter( unique_ptr<DialogFilter> DialogFilter::get_dialog_filter(

View File

@ -15,6 +15,7 @@
#include "td/telegram/files/FileLocation.h" #include "td/telegram/files/FileLocation.h"
#include "td/telegram/files/FileManager.h" #include "td/telegram/files/FileManager.h"
#include "td/telegram/files/FileType.h" #include "td/telegram/files/FileType.h"
#include "td/telegram/Global.h"
#include "td/telegram/misc.h" #include "td/telegram/misc.h"
#include "td/telegram/net/DcId.h" #include "td/telegram/net/DcId.h"
#include "td/telegram/PhotoSizeSource.h" #include "td/telegram/PhotoSizeSource.h"
@ -29,6 +30,8 @@
#include "td/telegram/VideosManager.h" #include "td/telegram/VideosManager.h"
#include "td/telegram/VoiceNotesManager.h" #include "td/telegram/VoiceNotesManager.h"
#include "td/actor/actor.h"
#include "td/utils/common.h" #include "td/utils/common.h"
#include "td/utils/HttpUrl.h" #include "td/utils/HttpUrl.h"
#include "td/utils/logging.h" #include "td/utils/logging.h"

View File

@ -12,7 +12,6 @@
#include "td/telegram/PhotoSize.hpp" #include "td/telegram/PhotoSize.hpp"
#include "td/telegram/Version.h" #include "td/telegram/Version.h"
#include "td/utils/logging.h"
#include "td/utils/tl_helpers.h" #include "td/utils/tl_helpers.h"
#include "td/telegram/ConfigShared.h" #include "td/telegram/ConfigShared.h"

View File

@ -15,7 +15,6 @@
#include "td/utils/common.h" #include "td/utils/common.h"
#include "td/utils/Promise.h" #include "td/utils/Promise.h"
#include "td/utils/Status.h"
namespace td { namespace td {

View File

@ -15,6 +15,7 @@
#include "td/actor/actor.h" #include "td/actor/actor.h"
#include "td/utils/common.h" #include "td/utils/common.h"
#include "td/utils/Promise.h"
#include <memory> #include <memory>

View File

@ -6,7 +6,7 @@
// //
#include "td/telegram/Global.h" #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/ConnectionCreator.h"
#include "td/telegram/net/NetQueryDispatcher.h" #include "td/telegram/net/NetQueryDispatcher.h"
#include "td/telegram/net/TempAuthKeyWatchdog.h" #include "td/telegram/net/TempAuthKeyWatchdog.h"
@ -29,10 +29,7 @@ Global::Global() = default;
Global::~Global() = default; Global::~Global() = default;
void Global::log_out(Slice reason) { void Global::log_out(Slice reason) {
CHECK(shared_config_ != nullptr); send_closure(auth_manager_, &AuthManager::on_authorization_lost, reason.str());
if (!shared_config_->have_option("auth")) {
shared_config_->set_option_string("auth", reason);
}
} }
void Global::close_all(Promise<> on_finished) { 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; server_time_difference_was_updated_ = true;
do_save_server_time_difference(); do_save_server_time_difference();
CHECK(Scheduler::instance()); get_option_manager()->on_update_server_time_difference();
send_closure(option_manager(), &OptionManager::on_update_server_time_difference);
} }
} }
@ -184,7 +180,7 @@ void Global::save_server_time() {
} }
void Global::do_save_server_time_difference() { 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"); td_db()->get_binlog_pmc()->erase("server_time_difference");
return; return;
} }
@ -223,8 +219,7 @@ double Global::get_dns_time_difference() const {
} }
DcId Global::get_webfile_dc_id() const { DcId Global::get_webfile_dc_id() const {
CHECK(shared_config_ != nullptr); auto dc_id = narrow_cast<int32>(get_option_integer("webfile_dc_id"));
auto dc_id = narrow_cast<int32>(shared_config_->get_option_integer("webfile_dc_id"));
if (!DcId::is_valid(dc_id)) { if (!DcId::is_valid(dc_id)) {
if (is_test_dc()) { if (is_test_dc()) {
dc_id = 2; dc_id = 2;
@ -239,8 +234,7 @@ DcId Global::get_webfile_dc_id() const {
} }
bool Global::ignore_background_updates() const { bool Global::ignore_background_updates() const {
return !parameters_.use_file_db && !parameters_.use_secret_chats && return !parameters_.use_file_db && !parameters_.use_secret_chats && get_option_boolean("ignore_background_updates");
shared_config_->get_option_boolean("ignore_background_updates");
} }
void Global::set_net_query_stats(std::shared_ptr<NetQueryStats> net_query_stats) { void Global::set_net_query_stats(std::shared_ptr<NetQueryStats> net_query_stats) {
@ -252,8 +246,46 @@ void Global::set_net_query_dispatcher(unique_ptr<NetQueryDispatcher> net_query_d
net_query_dispatcher_ = std::move(net_query_dispatcher); net_query_dispatcher_ = std::move(net_query_dispatcher);
} }
void Global::set_shared_config(unique_ptr<ConfigShared> shared_config) { const OptionManager *Global::get_option_manager() const {
shared_config_ = std::move(shared_config); 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) { int64 Global::get_location_key(double latitude, double longitude) {

View File

@ -33,10 +33,10 @@ namespace td {
class AnimationsManager; class AnimationsManager;
class AttachMenuManager; class AttachMenuManager;
class AuthManager;
class BackgroundManager; class BackgroundManager;
class CallManager; class CallManager;
class ConfigManager; class ConfigManager;
class ConfigShared;
class ConnectionCreator; class ConnectionCreator;
class ContactsManager; class ContactsManager;
class DownloadManager; class DownloadManager;
@ -178,12 +178,21 @@ class Global final : public ActorContext {
return net_query_dispatcher_.get() != nullptr; return net_query_dispatcher_.get() != nullptr;
} }
void set_shared_config(unique_ptr<ConfigShared> shared_config); void set_option_empty(Slice name);
ConfigShared &shared_config() { void set_option_boolean(Slice name, bool value);
CHECK(shared_config_.get() != nullptr);
return *shared_config_; 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 { bool is_server_time_reliable() const {
return server_time_difference_was_updated_; return server_time_difference_was_updated_;
@ -241,6 +250,10 @@ class Global final : public ActorContext {
attach_menu_manager_ = attach_menu_manager; attach_menu_manager_ = attach_menu_manager;
} }
void set_auth_manager(ActorId<AuthManager> auth_manager) {
auth_manager_ = auth_manager;
}
ActorId<BackgroundManager> background_manager() const { ActorId<BackgroundManager> background_manager() const {
return background_manager_; return background_manager_;
} }
@ -339,10 +352,7 @@ class Global final : public ActorContext {
notification_settings_manager_ = notification_settings_manager; notification_settings_manager_ = notification_settings_manager;
} }
ActorId<OptionManager> option_manager() const { void set_option_manager(OptionManager *option_manager) {
return option_manager_;
}
void set_option_manager(ActorId<OptionManager> option_manager) {
option_manager_ = option_manager; option_manager_ = option_manager;
} }
@ -432,13 +442,6 @@ class Global final : public ActorContext {
return parameters_; 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 { int32 get_gc_scheduler_id() const {
return gc_scheduler_id_; return gc_scheduler_id_;
} }
@ -521,6 +524,7 @@ class Global final : public ActorContext {
ActorId<Td> td_; ActorId<Td> td_;
ActorId<AnimationsManager> animations_manager_; ActorId<AnimationsManager> animations_manager_;
ActorId<AttachMenuManager> attach_menu_manager_; ActorId<AttachMenuManager> attach_menu_manager_;
ActorId<AuthManager> auth_manager_;
ActorId<BackgroundManager> background_manager_; ActorId<BackgroundManager> background_manager_;
ActorId<CallManager> call_manager_; ActorId<CallManager> call_manager_;
ActorId<ConfigManager> config_manager_; ActorId<ConfigManager> config_manager_;
@ -535,7 +539,6 @@ class Global final : public ActorContext {
ActorId<MessagesManager> messages_manager_; ActorId<MessagesManager> messages_manager_;
ActorId<NotificationManager> notification_manager_; ActorId<NotificationManager> notification_manager_;
ActorId<NotificationSettingsManager> notification_settings_manager_; ActorId<NotificationSettingsManager> notification_settings_manager_;
ActorId<OptionManager> option_manager_;
ActorId<PasswordManager> password_manager_; ActorId<PasswordManager> password_manager_;
ActorId<SecretChatsManager> secret_chats_manager_; ActorId<SecretChatsManager> secret_chats_manager_;
ActorId<SponsoredMessageManager> sponsored_message_manager_; ActorId<SponsoredMessageManager> sponsored_message_manager_;
@ -551,6 +554,8 @@ class Global final : public ActorContext {
unique_ptr<MtprotoHeader> mtproto_header_; unique_ptr<MtprotoHeader> mtproto_header_;
OptionManager *option_manager_ = nullptr;
TdParameters parameters_; TdParameters parameters_;
int32 gc_scheduler_id_ = 0; int32 gc_scheduler_id_ = 0;
int32 slow_net_scheduler_id_ = 0; int32 slow_net_scheduler_id_ = 0;
@ -577,16 +582,16 @@ class Global final : public ActorContext {
LazySchedulerLocalStorage<unique_ptr<NetQueryCreator>> net_query_creator_; LazySchedulerLocalStorage<unique_ptr<NetQueryCreator>> net_query_creator_;
unique_ptr<NetQueryDispatcher> net_query_dispatcher_; unique_ptr<NetQueryDispatcher> net_query_dispatcher_;
unique_ptr<ConfigShared> shared_config_;
int64 my_id_ = 0; // hack
static int64 get_location_key(double latitude, double longitude); static int64 get_location_key(double latitude, double longitude);
FlatHashMap<int64, int64> location_access_hashes_; FlatHashMap<int64, int64> location_access_hashes_;
int32 to_unix_time(double server_time) const; 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_save_server_time_difference();
void do_close(Promise<> on_finish, bool destroy_flag); void do_close(Promise<> on_finish, bool destroy_flag);

View File

@ -354,7 +354,8 @@ Result<tl_object_ptr<telegram_api::InputBotInlineMessage>> InlineQueriesManager:
auto constructor_id = input_message_content->get_id(); auto constructor_id = input_message_content->get_id();
if (constructor_id == td_api::inputMessageText::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; int32 flags = 0;
if (input_reply_markup != nullptr) { if (input_reply_markup != nullptr) {
flags |= telegram_api::inputBotInlineMessageText::REPLY_MARKUP_MASK; flags |= telegram_api::inputBotInlineMessageText::REPLY_MARKUP_MASK;
@ -401,8 +402,8 @@ Result<tl_object_ptr<telegram_api::InputBotInlineMessage>> InlineQueriesManager:
return venue.get_input_bot_inline_message_media_venue(std::move(input_reply_markup)); return venue.get_input_bot_inline_message_media_venue(std::move(input_reply_markup));
} }
if (constructor_id == allowed_media_content_id) { if (constructor_id == allowed_media_content_id) {
TRY_RESULT(caption, process_input_caption(td_->contacts_manager_.get(), DialogId(), TRY_RESULT(caption, get_formatted_text(td_, DialogId(td_->contacts_manager_->get_my_id()),
extract_input_caption(input_message_content), true)); extract_input_caption(input_message_content), true, true, true, false));
int32 flags = 0; int32 flags = 0;
if (input_reply_markup != nullptr) { if (input_reply_markup != nullptr) {
flags |= telegram_api::inputBotInlineMessageMediaAuto::REPLY_MARKUP_MASK; flags |= telegram_api::inputBotInlineMessageMediaAuto::REPLY_MARKUP_MASK;

View File

@ -6,10 +6,7 @@
// //
#include "td/telegram/InputMessageText.h" #include "td/telegram/InputMessageText.h"
#include "td/telegram/ConfigShared.h"
#include "td/telegram/Global.h"
#include "td/telegram/MessageEntity.h" #include "td/telegram/MessageEntity.h"
#include "td/telegram/Td.h"
#include "td/utils/common.h" #include "td/utils/common.h"
@ -30,33 +27,12 @@ Result<InputMessageText> process_input_message_text(const Td *td, DialogId dialo
CHECK(input_message_content != nullptr); CHECK(input_message_content != nullptr);
CHECK(input_message_content->get_id() == td_api::inputMessageText::ID); CHECK(input_message_content->get_id() == td_api::inputMessageText::ID);
auto input_message_text = static_cast<td_api::inputMessageText *>(input_message_content.get()); auto input_message_text = static_cast<td_api::inputMessageText *>(input_message_content.get());
if (input_message_text->text_ == nullptr) { TRY_RESULT(text, get_formatted_text(td, dialog_id, std::move(input_message_text->text_), is_bot, for_draft, for_draft,
if (for_draft) { for_draft));
return InputMessageText{FormattedText(), input_message_text->disable_web_page_preview_, return InputMessageText{std::move(text), input_message_text->disable_web_page_preview_,
input_message_text->clear_draft_}; 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);
}
// used only for draft // used only for draft
td_api::object_ptr<td_api::inputMessageText> get_input_message_text_object(const InputMessageText &input_message_text) { td_api::object_ptr<td_api::inputMessageText> get_input_message_text_object(const InputMessageText &input_message_text) {
return td_api::make_object<td_api::inputMessageText>(get_formatted_text_object(input_message_text.text, false, -1), return td_api::make_object<td_api::inputMessageText>(get_formatted_text_object(input_message_text.text, false, -1),

View File

@ -6,7 +6,6 @@
// //
#include "td/telegram/LanguagePackManager.h" #include "td/telegram/LanguagePackManager.h"
#include "td/telegram/ConfigShared.h"
#include "td/telegram/Global.h" #include "td/telegram/Global.h"
#include "td/telegram/logevent/LogEvent.h" #include "td/telegram/logevent/LogEvent.h"
#include "td/telegram/misc.h" #include "td/telegram/misc.h"
@ -64,7 +63,7 @@ struct LanguagePackManager::Language {
FlatHashMap<string, string> ordinary_strings_; FlatHashMap<string, string> ordinary_strings_;
FlatHashMap<string, unique_ptr<PluralizedString>> pluralized_strings_; FlatHashMap<string, unique_ptr<PluralizedString>> pluralized_strings_;
FlatHashSet<string> deleted_strings_; FlatHashSet<string> deleted_strings_;
SqliteKeyValue kv_; // usages should be guarded by database_->mutex_ SqliteKeyValue kv_; // usages must be guarded by database_->mutex_
}; };
struct LanguagePackManager::LanguageInfo { struct LanguagePackManager::LanguageInfo {
@ -91,7 +90,7 @@ struct LanguagePackManager::LanguageInfo {
struct LanguagePackManager::LanguagePack { struct LanguagePackManager::LanguagePack {
std::mutex mutex_; 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<string, LanguageInfo> custom_language_pack_infos_; // sorted by language_code std::map<string, LanguageInfo> custom_language_pack_infos_; // sorted by language_code
vector<std::pair<string, LanguageInfo>> server_language_pack_infos_; // sorted by server vector<std::pair<string, LanguageInfo>> server_language_pack_infos_; // sorted by server
FlatHashMap<string, unique_ptr<LanguageInfo>> all_server_language_pack_infos_; FlatHashMap<string, unique_ptr<LanguageInfo>> all_server_language_pack_infos_;
@ -199,21 +198,17 @@ LanguagePackManager::LanguageDatabase *LanguagePackManager::add_language_databas
return it->second.get(); return it->second.get();
} }
void LanguagePackManager::start_up() { LanguagePackManager::LanguagePackManager(ActorShared<> parent) : parent_(std::move(parent)) {
std::lock_guard<std::mutex> database_lock(language_database_mutex_); std::lock_guard<std::mutex> database_lock(language_database_mutex_);
manager_count_++; manager_count_++;
language_pack_ = G()->shared_config().get_option_string("localization_target"); language_pack_ = G()->get_option_string("localization_target");
language_code_ = G()->shared_config().get_option_string("language_pack_id"); language_code_ = G()->get_option_string("language_pack_id");
CHECK(check_language_pack_name(language_pack_)); CHECK(check_language_pack_name(language_pack_));
CHECK(check_language_code_name(language_code_)); 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()) { if (!language_pack_.empty() && !language_code_.empty()) {
auto language = add_language(database_, language_pack_, language_code_); 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<std::mutex> language_lock(language->mutex_); std::lock_guard<std::mutex> language_lock(language->mutex_);
base_language_code_ = language->base_language_code_; base_language_code_ = language->base_language_code_;
@ -222,10 +217,7 @@ void LanguagePackManager::start_up() {
base_language_code_.clear(); base_language_code_.clear();
} }
if (!base_language_code_.empty()) { if (!base_language_code_.empty()) {
auto base_language = add_language(database_, language_pack_, base_language_code_); add_language(database_, language_pack_, base_language_code_);
if (base_language->version_ == -1) {
load_empty_language_pack(base_language_code_);
}
} }
LOG(INFO) << "Use localization target \"" << language_pack_ << "\" with language pack \"" << 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() { void LanguagePackManager::tear_down() {
if (ExitGuard::is_exited()) { if (ExitGuard::is_exited()) {
return; return;
@ -241,7 +257,7 @@ void LanguagePackManager::tear_down() {
std::lock_guard<std::mutex> lock(language_database_mutex_); std::lock_guard<std::mutex> lock(language_database_mutex_);
manager_count_--; manager_count_--;
if (manager_count_ == 0) { 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"; // LOG(INFO) << "Clear language packs";
// language_databases_.clear(); // language_databases_.clear();
} }
@ -339,7 +355,7 @@ vector<string> LanguagePackManager::get_used_language_codes() {
} }
void LanguagePackManager::on_language_pack_changed() { 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_) { if (new_language_pack == language_pack_) {
return; return;
} }
@ -350,7 +366,7 @@ void LanguagePackManager::on_language_pack_changed() {
} }
void LanguagePackManager::on_language_code_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_) { if (new_language_code == language_code_) {
return; return;
} }
@ -365,16 +381,17 @@ void LanguagePackManager::on_language_pack_version_changed(bool is_base, int32 n
return; return;
} }
LOG(INFO) << (is_base ? "Base" : "Main") << " language pack vesrion has changed to " << new_version;
Language *language = get_language(database_, language_pack_, language_code_); Language *language = get_language(database_, language_pack_, language_code_);
int32 version = language == nullptr ? static_cast<int32>(-1) : language->version_.load(); int32 version = language == nullptr ? static_cast<int32>(-1) : language->version_.load();
LOG(INFO) << (is_base ? "Base" : "Main") << " language pack vesrion has changed from main " << version << " to "
<< new_version;
if (version == -1) { if (version == -1) {
return load_empty_language_pack(language_code_); return load_empty_language_pack(language_code_);
} }
if (new_version < 0) { if (new_version < 0) {
Slice version_key = is_base ? Slice("base_language_pack_version") : Slice("language_pack_version"); Slice version_key = is_base ? Slice("base_language_pack_version") : Slice("language_pack_version");
new_version = narrow_cast<int32>(G()->shared_config().get_option_integer(version_key, -1)); new_version = narrow_cast<int32>(G()->get_option_integer(version_key, -1));
} }
if (new_version <= 0) { if (new_version <= 0) {
return; return;
@ -495,8 +512,8 @@ void LanguagePackManager::on_update_language_pack(tl_object_ptr<telegram_api::la
} }
void LanguagePackManager::inc_generation() { void LanguagePackManager::inc_generation() {
G()->shared_config().set_option_empty("language_pack_version"); G()->set_option_empty("language_pack_version");
G()->shared_config().set_option_empty("base_language_pack_version"); G()->set_option_empty("base_language_pack_version");
if (!language_pack_.empty() && !language_code_.empty()) { if (!language_pack_.empty() && !language_code_.empty()) {
LOG(INFO) << "Add main language " << language_code_; 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) { 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()) { if (!base_language_code_.empty()) {
add_language(database_, language_pack_, base_language_code_); add_language(database_, language_pack_, base_language_code_);
on_language_pack_version_changed(true, std::numeric_limits<int32>::max()); on_language_pack_version_changed(true, std::numeric_limits<int32>::max());

View File

@ -29,8 +29,7 @@ class SqliteKeyValue;
class LanguagePackManager final : public NetQueryCallback { class LanguagePackManager final : public NetQueryCallback {
public: public:
explicit LanguagePackManager(ActorShared<> parent) : parent_(std::move(parent)) { explicit LanguagePackManager(ActorShared<> parent);
}
LanguagePackManager(const LanguagePackManager &) = delete; LanguagePackManager(const LanguagePackManager &) = delete;
LanguagePackManager &operator=(const LanguagePackManager &) = delete; LanguagePackManager &operator=(const LanguagePackManager &) = delete;
LanguagePackManager(LanguagePackManager &&) = delete; LanguagePackManager(LanguagePackManager &&) = delete;

View File

@ -10,7 +10,6 @@
#include "td/telegram/ChannelId.h" #include "td/telegram/ChannelId.h"
#include "td/telegram/ChannelType.h" #include "td/telegram/ChannelType.h"
#include "td/telegram/ConfigManager.h" #include "td/telegram/ConfigManager.h"
#include "td/telegram/ConfigShared.h"
#include "td/telegram/ContactsManager.h" #include "td/telegram/ContactsManager.h"
#include "td/telegram/DialogId.h" #include "td/telegram/DialogId.h"
#include "td/telegram/DialogParticipant.h" #include "td/telegram/DialogParticipant.h"
@ -254,8 +253,7 @@ class LinkManager::InternalLinkBotStart final : public InternalLink {
td_api::object_ptr<td_api::InternalLinkType> get_internal_link_type_object() const final { td_api::object_ptr<td_api::InternalLinkType> get_internal_link_type_object() const final {
bool autostart = autostart_; bool autostart = autostart_;
if (Scheduler::context() != nullptr && if (Scheduler::context() != nullptr && bot_username_ == G()->get_option_string("premium_bot_username")) {
bot_username_ == G()->shared_config().get_option_string("premium_bot_username")) {
autostart = true; autostart = true;
} }
return td_api::make_object<td_api::internalLinkTypeBotStart>(bot_username_, start_parameter_, autostart); return td_api::make_object<td_api::internalLinkTypeBotStart>(bot_username_, start_parameter_, autostart);
@ -889,7 +887,7 @@ LinkManager::LinkInfo LinkManager::get_link_info(Slice link) {
vector<Slice> t_me_urls{Slice("t.me"), Slice("telegram.me"), Slice("telegram.dog")}; vector<Slice> t_me_urls{Slice("t.me"), Slice("telegram.me"), Slice("telegram.dog")};
if (Scheduler::context() != nullptr) { // for tests only 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://")) { 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; Slice t_me_url = cur_t_me_url;
t_me_url = t_me_url.substr(t_me_url[4] == 's' ? 8 : 7); 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) { if (is_internal) {
return PSTRING() << "tg:join?invite=" << hash; return PSTRING() << "tg:join?invite=" << hash;
} else { } 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;
} }
} }

View File

@ -14,7 +14,6 @@
#include "td/telegram/CallDiscardReason.h" #include "td/telegram/CallDiscardReason.h"
#include "td/telegram/ChannelId.h" #include "td/telegram/ChannelId.h"
#include "td/telegram/ChatId.h" #include "td/telegram/ChatId.h"
#include "td/telegram/ConfigShared.h"
#include "td/telegram/Contact.h" #include "td/telegram/Contact.h"
#include "td/telegram/ContactsManager.h" #include "td/telegram/ContactsManager.h"
#include "td/telegram/Dependencies.h" #include "td/telegram/Dependencies.h"
@ -44,6 +43,7 @@
#include "td/telegram/MessageSender.h" #include "td/telegram/MessageSender.h"
#include "td/telegram/misc.h" #include "td/telegram/misc.h"
#include "td/telegram/net/DcId.h" #include "td/telegram/net/DcId.h"
#include "td/telegram/OptionManager.h"
#include "td/telegram/Payments.h" #include "td/telegram/Payments.h"
#include "td/telegram/Payments.hpp" #include "td/telegram/Payments.hpp"
#include "td/telegram/Photo.h" #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_; result.disable_web_page_preview = inline_message->no_webpage_;
FormattedText text{std::move(inline_message->message_), std::move(entities)};
WebPageId web_page_id; WebPageId web_page_id;
if (!result.disable_web_page_preview) { 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<MessageText>( result.message_content = make_unique<MessageText>(std::move(text), web_page_id);
FormattedText{std::move(inline_message->message_), std::move(entities)}, web_page_id);
reply_markup = std::move(inline_message->reply_markup_); reply_markup = std::move(inline_message->reply_markup_);
break; break;
} }
@ -1772,8 +1772,7 @@ static Result<InputMessageContent> create_input_message_content(
dialog_id.get_type() != DialogType::Channel || dialog_id.get_type() != DialogType::Channel ||
td->contacts_manager_->get_channel_permissions(dialog_id.get_channel_id()).can_add_web_page_previews(); 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) { if (!is_bot && !disable_web_page_preview && can_add_web_page_previews) {
web_page_id = td->web_pages_manager_->get_web_page_by_url( web_page_id = td->web_pages_manager_->get_web_page_by_url(get_first_url(input_message_text.text));
get_first_url(input_message_text.text.text, input_message_text.text.entities));
} }
content = make_unique<MessageText>(std::move(input_message_text.text), web_page_id); content = make_unique<MessageText>(std::move(input_message_text.text), web_page_id);
break; break;
@ -2018,7 +2017,7 @@ static Result<InputMessageContent> create_input_message_content(
return Status::Error(400, "Wrong correct option ID specified"); return Status::Error(400, "Wrong correct option ID specified");
} }
auto r_explanation = 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()) { if (r_explanation.is_error()) {
return r_explanation.move_as_error(); return r_explanation.move_as_error();
} }
@ -2159,8 +2158,8 @@ Result<InputMessageContent> get_input_message_content(
} }
} }
TRY_RESULT(caption, process_input_caption(td->contacts_manager_.get(), dialog_id, TRY_RESULT(caption, get_formatted_text(td, dialog_id, extract_input_caption(input_message_content),
extract_input_caption(input_message_content), td->auth_manager_->is_bot())); 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, 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); std::move(thumbnail), std::move(sticker_file_ids), is_premium);
} }
@ -4674,7 +4673,7 @@ unique_ptr<MessageContent> dup_message_content(Td *td, DialogId dialog_id, const
} }
case MessageContentType::Sticker: { case MessageContentType::Sticker: {
auto result = make_unique<MessageSticker>(*static_cast<const MessageSticker *>(content)); auto result = make_unique<MessageSticker>(*static_cast<const MessageSticker *>(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)) { if (td->stickers_manager_->has_input_media(result->file_id, to_secret)) {
return std::move(result); 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 *ptr = Slice(text->text).ubegin();
const unsigned char *end = Slice(text->text).uend(); const unsigned char *end = Slice(text->text).uend();
int32 utf16_pos = 0; int32 utf16_pos = 0;
uint32 skipped_code = 0;
for (auto &entity : text->entities) { for (auto &entity : text->entities) {
if (entity.type != MessageEntity::Type::Hashtag) { if (entity.type != MessageEntity::Type::Hashtag) {
continue; continue;
} }
while (utf16_pos < entity.offset && ptr < end) { while (utf16_pos < entity.offset && ptr < end) {
utf16_pos += 1 + (ptr[0] >= 0xf0); 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); CHECK(utf16_pos == entity.offset);
auto from = ptr; auto from = ptr;
while (utf16_pos < entity.offset + entity.length && ptr < end) { while (utf16_pos < entity.offset + entity.length && ptr < end) {
utf16_pos += 1 + (ptr[0] >= 0xf0); 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); CHECK(utf16_pos == entity.offset + entity.length);
auto to = ptr; auto to = ptr;

View File

@ -6,11 +6,11 @@
// //
#include "td/telegram/MessageEntity.h" #include "td/telegram/MessageEntity.h"
#include "td/telegram/ConfigShared.h"
#include "td/telegram/ContactsManager.h" #include "td/telegram/ContactsManager.h"
#include "td/telegram/Dependencies.h" #include "td/telegram/Dependencies.h"
#include "td/telegram/LinkManager.h" #include "td/telegram/LinkManager.h"
#include "td/telegram/misc.h" #include "td/telegram/misc.h"
#include "td/telegram/OptionManager.h"
#include "td/telegram/SecretChatLayer.h" #include "td/telegram/SecretChatLayer.h"
#include "td/telegram/StickersManager.h" #include "td/telegram/StickersManager.h"
#include "td/telegram/Td.h" #include "td/telegram/Td.h"
@ -21,6 +21,7 @@
#include "td/utils/format.h" #include "td/utils/format.h"
#include "td/utils/logging.h" #include "td/utils/logging.h"
#include "td/utils/misc.h" #include "td/utils/misc.h"
#include "td/utils/Promise.h"
#include "td/utils/SliceBuilder.h" #include "td/utils/SliceBuilder.h"
#include "td/utils/unicode.h" #include "td/utils/unicode.h"
#include "td/utils/utf8.h" #include "td/utils/utf8.h"
@ -261,7 +262,7 @@ static vector<Slice> match_mentions(Slice str) {
if (ptr != begin) { if (ptr != begin) {
uint32 prev; 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)) { if (is_word_character(prev)) {
ptr++; ptr++;
@ -279,7 +280,7 @@ static vector<Slice> match_mentions(Slice str) {
} }
uint32 next = 0; uint32 next = 0;
if (ptr != end) { if (ptr != end) {
next_utf8_unsafe(ptr, &next, "match_mentions 2"); next_utf8_unsafe(ptr, &next);
} }
if (is_word_character(next)) { if (is_word_character(next)) {
continue; continue;
@ -305,7 +306,7 @@ static vector<Slice> match_bot_commands(Slice str) {
if (ptr != begin) { if (ptr != begin) {
uint32 prev; 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 == '>') { if (is_word_character(prev) || prev == '/' || prev == '<' || prev == '>') {
ptr++; ptr++;
@ -338,7 +339,7 @@ static vector<Slice> match_bot_commands(Slice str) {
uint32 next = 0; uint32 next = 0;
if (ptr != end) { 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 == '>') { if (is_word_character(next) || next == '/' || next == '<' || next == '>') {
continue; continue;
@ -381,7 +382,7 @@ static vector<Slice> match_hashtags(Slice str) {
if (ptr != begin) { if (ptr != begin) {
uint32 prev; 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)) { if (is_hashtag_letter(prev, category)) {
ptr++; ptr++;
@ -394,7 +395,7 @@ static vector<Slice> match_hashtags(Slice str) {
bool was_letter = false; bool was_letter = false;
while (ptr != end) { while (ptr != end) {
uint32 code; 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)) { if (!is_hashtag_letter(code, category)) {
break; break;
} }
@ -442,7 +443,7 @@ static vector<Slice> match_cashtags(Slice str) {
if (ptr != begin) { if (ptr != begin) {
uint32 prev; 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 == '$') { if (is_hashtag_letter(prev, category) || prev == '$') {
ptr++; ptr++;
@ -466,7 +467,7 @@ static vector<Slice> match_cashtags(Slice str) {
if (cashtag_end != end) { if (cashtag_end != end) {
uint32 code; uint32 code;
next_utf8_unsafe(ptr, &code, "match_cashtags 2"); next_utf8_unsafe(ptr, &code);
if (is_hashtag_letter(code, category) || code == '$') { if (is_hashtag_letter(code, category) || code == '$') {
continue; continue;
} }
@ -505,7 +506,7 @@ static vector<Slice> match_media_timestamps(Slice str) {
if (media_timestamp_begin != begin) { if (media_timestamp_begin != begin) {
uint32 prev; 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)) { if (is_word_character(prev)) {
continue; continue;
@ -513,7 +514,7 @@ static vector<Slice> match_media_timestamps(Slice str) {
} }
if (media_timestamp_end != end) { if (media_timestamp_end != end) {
uint32 next; 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)) { if (is_word_character(next)) {
continue; continue;
@ -545,7 +546,7 @@ static vector<Slice> match_bank_card_numbers(Slice str) {
} }
if (ptr != begin) { if (ptr != begin) {
uint32 prev; 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 == '_' || if (prev == '.' || prev == ',' || prev == '+' || prev == '-' || prev == '_' ||
get_unicode_simple_category(prev) == UnicodeSimpleCategory::Letter) { get_unicode_simple_category(prev) == UnicodeSimpleCategory::Letter) {
@ -581,7 +582,7 @@ static vector<Slice> match_bank_card_numbers(Slice str) {
} }
if (card_number_end != end) { if (card_number_end != end) {
uint32 next; 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) { if (next == '-' || next == '_' || get_unicode_simple_category(next) == UnicodeSimpleCategory::Letter) {
continue; continue;
} }
@ -656,7 +657,7 @@ static vector<Slice> match_tg_urls(Slice str) {
auto path_end_ptr = ptr + 1; auto path_end_ptr = ptr + 1;
while (path_end_ptr != end) { while (path_end_ptr != end) {
uint32 code = 0; 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)) { if (!is_url_path_symbol(code)) {
break; break;
} }
@ -738,7 +739,7 @@ static vector<Slice> match_urls(Slice str) {
while (domain_begin_ptr != begin) { while (domain_begin_ptr != begin) {
domain_begin_ptr = prev_utf8_unsafe(domain_begin_ptr); domain_begin_ptr = prev_utf8_unsafe(domain_begin_ptr);
uint32 code = 0; 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)) { if (!is_domain_symbol(code)) {
domain_begin_ptr = next_ptr; domain_begin_ptr = next_ptr;
break; break;
@ -747,25 +748,12 @@ static vector<Slice> match_urls(Slice str) {
const unsigned char *last_at_ptr = nullptr; const unsigned char *last_at_ptr = nullptr;
const unsigned char *domain_end_ptr = begin + dot_pos; 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) { while (domain_end_ptr != end) {
uint32 code = 0; uint32 code = 0;
auto next_ptr = next_utf8_unsafe(domain_end_ptr, &code, "match_urls"); auto next_ptr = next_utf8_unsafe(domain_end_ptr, &code);
if (code == '@') { if (code == '@') {
last_at_ptr = domain_end_ptr; last_at_ptr = domain_end_ptr;
} } else if (!is_domain_symbol(code)) {
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)) {
break; break;
} }
domain_end_ptr = next_ptr; domain_end_ptr = next_ptr;
@ -775,7 +763,7 @@ static vector<Slice> match_urls(Slice str) {
while (domain_begin_ptr != begin) { while (domain_begin_ptr != begin) {
domain_begin_ptr = prev_utf8_unsafe(domain_begin_ptr); domain_begin_ptr = prev_utf8_unsafe(domain_begin_ptr);
uint32 code = 0; 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)) { if (!is_user_data_symbol(code)) {
domain_begin_ptr = next_ptr; domain_begin_ptr = next_ptr;
break; break;
@ -807,7 +795,7 @@ static vector<Slice> match_urls(Slice str) {
auto path_end_ptr = url_end_ptr + 1; auto path_end_ptr = url_end_ptr + 1;
while (path_end_ptr != end) { while (path_end_ptr != end) {
uint32 code = 0; 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)) { if (!is_url_path_symbol(code)) {
break; break;
} }
@ -835,7 +823,7 @@ static vector<Slice> match_urls(Slice str) {
while (user_data_begin_ptr != begin) { while (user_data_begin_ptr != begin) {
user_data_begin_ptr = prev_utf8_unsafe(user_data_begin_ptr); user_data_begin_ptr = prev_utf8_unsafe(user_data_begin_ptr);
uint32 code = 0; 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)) { if (!is_user_data_symbol(code)) {
user_data_begin_ptr = next_ptr; user_data_begin_ptr = next_ptr;
break; break;
@ -855,7 +843,7 @@ static vector<Slice> match_urls(Slice str) {
while (protocol_begin_ptr != begin) { while (protocol_begin_ptr != begin) {
protocol_begin_ptr = prev_utf8_unsafe(protocol_begin_ptr); protocol_begin_ptr = prev_utf8_unsafe(protocol_begin_ptr);
uint32 code = 0; 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)) { if (!is_protocol_symbol(code)) {
protocol_begin_ptr = next_ptr; protocol_begin_ptr = next_ptr;
break; break;
@ -875,7 +863,7 @@ static vector<Slice> match_urls(Slice str) {
auto prefix_end = prefix.uend(); auto prefix_end = prefix.uend();
auto prefix_back = prev_utf8_unsafe(prefix_end); auto prefix_back = prev_utf8_unsafe(prefix_end);
uint32 code = 0; 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 == '@') { if (is_word_character(code) || code == '/' || code == '#' || code == '@') {
is_bad = true; is_bad = true;
} }
@ -965,34 +953,31 @@ bool is_email_address(Slice str) {
Slice userdata; Slice userdata;
Slice domain; Slice domain;
std::tie(userdata, domain) = split(str, '@'); std::tie(userdata, domain) = split(str, '@');
vector<Slice> userdata_parts; if (domain.empty()) {
return false;
}
size_t prev = 0; size_t prev = 0;
size_t userdata_part_count = 0;
for (size_t i = 0; i < userdata.size(); i++) { for (size_t i = 0; i < userdata.size(); i++) {
if (userdata[i] == '.' || userdata[i] == '+') { if (userdata[i] == '.' || userdata[i] == '+') {
userdata_parts.push_back(userdata.substr(prev, i - prev)); if (i - prev >= 27) {
return false;
}
userdata_part_count++;
prev = i + 1; prev = i + 1;
} } else if (!is_alpha_digit_or_underscore_or_minus(userdata[i])) {
}
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)) {
return false; return false;
} }
} }
} userdata_part_count++;
if (userdata_parts.back().empty() || userdata_parts.back().size() >= 36) { if (userdata_part_count >= 12) {
return false; return false;
} }
userdata_parts.pop_back(); auto last_part_length = userdata.size() - prev;
for (auto &part : userdata_parts) { if (last_part_length == 0 || last_part_length >= 36) {
if (part.size() >= 27) {
return false; return false;
} }
}
vector<Slice> domain_parts = full_split(domain, '.'); vector<Slice> domain_parts = full_split(domain, '.');
if (domain_parts.size() <= 1 || domain_parts.size() > 7) { if (domain_parts.size() <= 1 || domain_parts.size() > 7) {
@ -1158,6 +1143,17 @@ static bool is_common_tld(Slice str) {
"zippo", "zm", "zone", "zuerich", "zippo", "zm", "zone", "zuerich",
// comment for clang-format to prevent it from placing all strings on separate lines // comment for clang-format to prevent it from placing all strings on separate lines
"zw"}); "zw"});
bool is_lower = true;
for (auto c : str) {
if (static_cast<uint32>(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); string str_lower = utf8_to_lower(str);
if (str_lower != str && utf8_substr(Slice(str_lower), 1) == utf8_substr(str, 1)) { if (str_lower != str && utf8_substr(Slice(str_lower), 1) == utf8_substr(str, 1)) {
return false; return false;
@ -1185,11 +1181,13 @@ static Slice fix_url(Slice str) {
} }
domain.truncate(domain.rfind(':')); domain.truncate(domain.rfind(':'));
if (domain.size() == 12 && (domain[0] == 't' || domain[0] == 'T')) {
string domain_lower = domain.str(); string domain_lower = domain.str();
to_lower_inplace(domain_lower); to_lower_inplace(domain_lower);
if (domain_lower == "teiegram.org") { if (domain_lower == "teiegram.org") {
return Slice(); return Slice();
} }
}
int32 balance[3] = {0, 0, 0}; int32 balance[3] = {0, 0, 0};
size_t path_pos; size_t path_pos;
@ -1224,42 +1222,44 @@ static Slice fix_url(Slice str) {
} }
full_url.remove_suffix(path.size() - path_pos); full_url.remove_suffix(path.size() - path_pos);
vector<Slice> domain_parts = full_split(domain, '.'); size_t prev = 0;
if (domain_parts.size() <= 1) { size_t domain_part_count = 0;
return Slice();
}
bool is_ipv4 = domain_parts.size() == 4;
bool has_non_digit = false; bool has_non_digit = false;
for (auto &part : domain_parts) { bool is_ipv4 = true;
if (part.empty() || part.size() >= 64) { 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(); return Slice();
} }
if (part.back() == '-') { if (is_ipv4) {
return Slice(); if (part_size > 3) {
}
if (!has_non_digit) {
if (part.size() > 3) {
is_ipv4 = false; is_ipv4 = false;
} }
for (auto c : part) { if (part_size == 3 &&
if (!is_digit(c)) { (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; is_ipv4 = false;
has_non_digit = true; has_non_digit = true;
} }
} }
if (part.size() == 3 && if (domain_part_count == 1) {
(part[0] >= '3' || (part[0] == '2' && (part[1] >= '6' || (part[1] == '5' && part[2] >= '6'))))) { return Slice();
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; return full_url;
} }
@ -1267,7 +1267,7 @@ static Slice fix_url(Slice str) {
return Slice(); return Slice();
} }
auto tld = domain_parts.back(); auto tld = domain.substr(prev);
if (utf8_length(tld) <= 1) { if (utf8_length(tld) <= 1) {
return Slice(); return Slice();
} }
@ -1294,9 +1294,14 @@ static Slice fix_url(Slice str) {
} }
} }
domain_parts.pop_back(); CHECK(prev > 0);
if (domain_parts.back().find('_') < domain_parts.back().size()) { prev--;
while (prev-- > 0) {
if (domain[prev] == '_') {
return Slice(); return Slice();
} else if (domain[prev] == '.') {
break;
}
} }
return full_url; return full_url;
@ -1664,10 +1669,11 @@ static void fix_entity_offsets(Slice text, vector<MessageEntity> &entities) {
entity.offset = utf16_pos; entity.offset = utf16_pos;
} }
uint32 skipped_code = 0;
while (ptr != end && cnt > 0) { while (ptr != end && cnt > 0) {
unsigned char c = ptr[0]; unsigned char c = ptr[0];
utf16_pos += 1 + (c >= 0xf0); utf16_pos += 1 + (c >= 0xf0);
ptr = next_utf8_unsafe(ptr, nullptr, "fix_entity_offsets"); ptr = next_utf8_unsafe(ptr, &skipped_code);
pos = static_cast<int32>(ptr - begin); pos = static_cast<int32>(ptr - begin);
if (entity_begin == pos) { 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(); return url.find('/') >= url.size() && url.find('?') >= url.size() && url.find('#') >= url.size();
} }
string get_first_url(Slice text, const vector<MessageEntity> &entities) { string get_first_url(const FormattedText &text) {
for (auto &entity : entities) { for (auto &entity : text.entities) {
switch (entity.type) { switch (entity.type) {
case MessageEntity::Type::Mention: case MessageEntity::Type::Mention:
break; break;
@ -1784,7 +1790,10 @@ string get_first_url(Slice text, const vector<MessageEntity> &entities) {
case MessageEntity::Type::BotCommand: case MessageEntity::Type::BotCommand:
break; break;
case MessageEntity::Type::Url: { 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)); string scheme = to_lower(url.substr(0, 4));
if (scheme == "ton:" || begins_with(scheme, "tg:") || scheme == "ftp:" || is_plain_domain(url)) { if (scheme == "ton:" || begins_with(scheme, "tg:") || scheme == "ftp:" || is_plain_domain(url)) {
continue; continue;
@ -4287,15 +4296,32 @@ td_api::object_ptr<td_api::formattedText> extract_input_caption(
} }
} }
Result<FormattedText> process_input_caption(const ContactsManager *contacts_manager, DialogId dialog_id, Result<FormattedText> get_formatted_text(const Td *td, DialogId dialog_id,
tl_object_ptr<td_api::formattedText> &&caption, bool is_bot) { td_api::object_ptr<td_api::formattedText> &&text, bool is_bot,
if (caption == nullptr) { bool allow_empty, bool skip_media_timestamps, bool for_draft) {
if (text == nullptr) {
if (allow_empty) {
return FormattedText(); return FormattedText();
} }
TRY_RESULT(entities, get_message_entities(contacts_manager, std::move(caption->entities_)));
TRY_STATUS(fix_formatted_text(caption->text_, entities, true, false, return Status::Error(400, "Text must be non-empty");
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) { 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); 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())) { dialog_id != DialogId(td->contacts_manager_->get_my_id())) {
remove_premium_custom_emoji_entities(td, text.entities, false); remove_premium_custom_emoji_entities(td, text.entities, false);
} }

View File

@ -170,7 +170,7 @@ vector<std::pair<Slice, int32>> find_media_timestamps(Slice str); // slice + me
void remove_empty_entities(vector<MessageEntity> &entities); void remove_empty_entities(vector<MessageEntity> &entities);
string get_first_url(Slice text, const vector<MessageEntity> &entities); string get_first_url(const FormattedText &text);
Result<vector<MessageEntity>> parse_markdown(string &text); Result<vector<MessageEntity>> parse_markdown(string &text);
@ -212,8 +212,9 @@ FormattedText get_message_text(const ContactsManager *contacts_manager, string m
td_api::object_ptr<td_api::formattedText> extract_input_caption( td_api::object_ptr<td_api::formattedText> extract_input_caption(
tl_object_ptr<td_api::InputMessageContent> &input_message_content); tl_object_ptr<td_api::InputMessageContent> &input_message_content);
Result<FormattedText> process_input_caption(const ContactsManager *contacts_manager, DialogId dialog_id, Result<FormattedText> get_formatted_text(const Td *td, DialogId dialog_id,
tl_object_ptr<td_api::formattedText> &&caption, bool is_bot); td_api::object_ptr<td_api::formattedText> &&text, bool is_bot,
bool allow_empty, bool skip_media_timestamps, bool for_draft);
void add_formatted_text_dependencies(Dependencies &dependencies, const FormattedText *text); void add_formatted_text_dependencies(Dependencies &dependencies, const FormattedText *text);

View File

@ -7,14 +7,19 @@
#include "td/telegram/MessageReaction.h" #include "td/telegram/MessageReaction.h"
#include "td/telegram/AccessRights.h" #include "td/telegram/AccessRights.h"
#include "td/telegram/ConfigManager.h"
#include "td/telegram/ContactsManager.h" #include "td/telegram/ContactsManager.h"
#include "td/telegram/Global.h" #include "td/telegram/Global.h"
#include "td/telegram/MessageSender.h" #include "td/telegram/MessageSender.h"
#include "td/telegram/MessagesManager.h" #include "td/telegram/MessagesManager.h"
#include "td/telegram/OptionManager.h"
#include "td/telegram/ServerMessageId.h" #include "td/telegram/ServerMessageId.h"
#include "td/telegram/StickersManager.h"
#include "td/telegram/Td.h" #include "td/telegram/Td.h"
#include "td/telegram/UpdatesManager.h" #include "td/telegram/UpdatesManager.h"
#include "td/actor/actor.h"
#include "td/utils/algorithm.h" #include "td/utils/algorithm.h"
#include "td/utils/buffer.h" #include "td/utils/buffer.h"
#include "td/utils/FlatHashSet.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<telegram_api::messages_setDefaultReaction>(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<Unit>());
}
};
void MessageReaction::add_recent_chooser_dialog_id(DialogId dialog_id) { void MessageReaction::add_recent_chooser_dialog_id(DialogId dialog_id) {
recent_chooser_dialog_ids_.insert(recent_chooser_dialog_ids_.begin(), dialog_id); recent_chooser_dialog_ids_.insert(recent_chooser_dialog_ids_.begin(), dialog_id);
if (recent_chooser_dialog_ids_.size() > MAX_RECENT_CHOOSERS + 1) { 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); ->send(full_message_id, std::move(reaction), std::move(offset), limit);
} }
void set_default_reaction(Td *td, string reaction, Promise<Unit> &&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<SetDefaultReactionQuery>()->send(td->option_manager_->get_option_string("default_reaction"));
}
} // namespace td } // namespace td

View File

@ -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, void get_message_added_reactions(Td *td, FullMessageId full_message_id, string reaction, string offset, int32 limit,
Promise<td_api::object_ptr<td_api::addedReactions>> &&promise); Promise<td_api::object_ptr<td_api::addedReactions>> &&promise);
void set_default_reaction(Td *td, string reaction, Promise<Unit> &&promise);
void send_set_default_reaction_query(Td *td);
} // namespace td } // namespace td

View File

@ -736,7 +736,7 @@ class MessagesDbImpl final : public MessagesDbSyncInterface {
for (auto ptr = query.ubegin(), end = query.uend(); ptr < end;) { for (auto ptr = query.ubegin(), end = query.uend(); ptr < end;) {
uint32 code; uint32 code;
auto code_ptr = ptr; auto code_ptr = ptr;
ptr = next_utf8_unsafe(ptr, &code, "prepare_query"); ptr = next_utf8_unsafe(ptr, &code);
if (is_word_character(code)) { if (is_word_character(code)) {
if (!in_word) { if (!in_word) {
in_word = true; in_word = true;

View File

@ -10,7 +10,6 @@
#include "td/telegram/ChainId.h" #include "td/telegram/ChainId.h"
#include "td/telegram/ChannelType.h" #include "td/telegram/ChannelType.h"
#include "td/telegram/ChatId.h" #include "td/telegram/ChatId.h"
#include "td/telegram/ConfigShared.h"
#include "td/telegram/ContactsManager.h" #include "td/telegram/ContactsManager.h"
#include "td/telegram/Dependencies.h" #include "td/telegram/Dependencies.h"
#include "td/telegram/DialogActionBar.h" #include "td/telegram/DialogActionBar.h"
@ -51,6 +50,7 @@
#include "td/telegram/NotificationSettingsManager.h" #include "td/telegram/NotificationSettingsManager.h"
#include "td/telegram/NotificationSound.h" #include "td/telegram/NotificationSound.h"
#include "td/telegram/NotificationType.h" #include "td/telegram/NotificationType.h"
#include "td/telegram/OptionManager.h"
#include "td/telegram/PollId.h" #include "td/telegram/PollId.h"
#include "td/telegram/PublicDialogType.h" #include "td/telegram/PublicDialogType.h"
#include "td/telegram/ReplyMarkup.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)), std::move(reply_markup), std::move(entities), schedule_date, std::move(as_input_peer)),
{{dialog_id, MessageContentType::Text}, {{dialog_id, MessageContentType::Text},
{dialog_id, is_copy ? MessageContentType::Photo : 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<Unit> result) { query->quick_ack_promise_ = PromiseCreator::lambda([random_id](Result<Unit> result) {
if (result.is_ok()) { if (result.is_ok()) {
send_closure(G()->messages_manager(), &MessagesManager::on_send_message_get_quick_ack, random_id); 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( auto query = G()->net_query_creator().create(
telegram_api::messages_startBot(std::move(bot_input_user), std::move(input_peer), random_id, parameter), telegram_api::messages_startBot(std::move(bot_input_user), std::move(input_peer), random_id, parameter),
{{dialog_id, MessageContentType::Text}, {dialog_id, MessageContentType::Photo}}); {{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<Unit> result) { query->quick_ack_promise_ = PromiseCreator::lambda([random_id](Result<Unit> result) {
if (result.is_ok()) { if (result.is_ok()) {
send_closure(G()->messages_manager(), &MessagesManager::on_send_message_get_quick_ack, random_id); 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, 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)), 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}}); {{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<Unit> result) { query->quick_ack_promise_ = PromiseCreator::lambda([random_id](Result<Unit> result) {
if (result.is_ok()) { if (result.is_ok()) {
send_closure(G()->messages_manager(), &MessagesManager::on_send_message_get_quick_ack, random_id); 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), 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)), 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}}); {{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<Unit> result) { query->quick_ack_promise_ = PromiseCreator::lambda([random_ids = random_ids_](Result<Unit> result) {
if (result.is_ok()) { if (result.is_ok()) {
for (auto random_id : random_ids) { for (auto random_id : random_ids) {
@ -9453,6 +9453,7 @@ void MessagesManager::after_get_difference() {
auto full_message_id = it.first; auto full_message_id = it.first;
auto dialog_id = full_message_id.get_dialog_id(); auto dialog_id = full_message_id.get_dialog_id();
auto message_id = full_message_id.get_message_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_valid());
CHECK(message_id.is_server()); CHECK(message_id.is_server());
switch (dialog_id.get_type()) { switch (dialog_id.get_type()) {
@ -9464,7 +9465,7 @@ void MessagesManager::after_get_difference() {
// fallthrough // fallthrough
case DialogType::User: case DialogType::User:
case DialogType::Chat: { 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 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 // 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. // 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) || if (!have_input_peer(dialog_id, AccessRights::Read) ||
(d != nullptr && (d != nullptr &&
message_id <= td::max(d->last_clear_history_message_id, d->max_unavailable_message_id))) { 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; break;
} }
@ -9483,20 +9484,18 @@ void MessagesManager::after_get_difference() {
const Dialog *d = get_dialog(dialog_id); const Dialog *d = get_dialog(dialog_id);
CHECK(d != nullptr); CHECK(d != nullptr);
if (dialog_id.get_type() == DialogType::Channel || message_id <= d->last_new_message_id) { 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; << " 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) { if (dialog_id.get_type() != DialogType::Channel && message_id <= d->last_new_message_id) {
dump_debug_message_op(get_dialog(dialog_id)); dump_debug_message_op(get_dialog(dialog_id));
} }
if (message_id <= d->last_new_message_id) { if (message_id <= d->last_new_message_id) {
get_message_from_server(it.first, PromiseCreator::lambda([full_message_id](Result<Unit> result) { get_message_from_server(
if (result.is_error()) { full_message_id,
LOG(WARNING) PromiseCreator::lambda([actor_id = actor_id(this), full_message_id, old_message_id](Result<Unit> result) {
<< "Failed to get missing " << full_message_id << ": " << result.error(); send_closure(actor_id, &MessagesManager::on_restore_missing_message_after_get_difference,
} else { full_message_id, old_message_id, std::move(result));
LOG(WARNING) << "Successfully get missing " << full_message_id;
}
}), }),
"get missing"); "get missing");
} else if (dialog_id.get_type() == DialogType::Channel) { } else if (dialog_id.get_type() == DialogType::Channel) {
@ -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<Unit> 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<int64> 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<MessageId> &empty_message_ids) { void MessagesManager::on_get_empty_messages(DialogId dialog_id, const vector<MessageId> &empty_message_ids) {
if (!empty_message_ids.empty()) { if (!empty_message_ids.empty()) {
delete_dialog_messages(dialog_id, empty_message_ids, true, true, "on_get_empty_messages"); 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(); auto content_type = m->content->get_type();
switch (dialog_id.get_type()) { switch (dialog_id.get_type()) {
case DialogType::User: { 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 = 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) { if (G()->unix_time_cached() - m->date < 86400 && content_type == MessageContentType::Dice) {
return false; return false;
@ -10795,7 +10829,8 @@ bool MessagesManager::can_revoke_message(DialogId dialog_id, const Message *m) c
case DialogType::Chat: { case DialogType::Chat: {
bool is_appointed_administrator = bool is_appointed_administrator =
td_->contacts_manager_->is_appointed_chat_administrator(dialog_id.get_chat_id()); 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) && return ((m->is_outgoing && !is_service_message_content(content_type)) || is_appointed_administrator) &&
G()->unix_time_cached() - m->date <= revoke_time_limit; 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())) { td_->contacts_manager_->is_user_bot(d->dialog_id.get_user_id())) {
return {true, false}; 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: case DialogType::Chat:
// chats can be deleted only for self and can be deleted for everyone by their creator // 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()}; 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()); CHECK(is_message_unload_enabled());
auto default_unload_delay = td_->auth_manager_->is_bot() ? DIALOG_UNLOAD_BOT_DELAY : DIALOG_UNLOAD_DELAY; auto default_unload_delay = td_->auth_manager_->is_bot() ? DIALOG_UNLOAD_BOT_DELAY : DIALOG_UNLOAD_DELAY;
return narrow_cast<int32>(G()->shared_config().get_option_integer("message_unload_delay", default_unload_delay)); return narrow_cast<int32>(td_->option_manager_->get_option_integer("message_unload_delay", default_unload_delay));
} }
int32 MessagesManager::get_next_unload_dialog_delay() const { int32 MessagesManager::get_next_unload_dialog_delay() const {
@ -13270,7 +13305,7 @@ void MessagesManager::init() {
if (is_authorized && td_->auth_manager_->is_bot()) { if (is_authorized && td_->auth_manager_->is_bot()) {
disable_get_dialog_filter_ = true; 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) { if (was_authorized_user) {
auto dialog_filters = G()->td_db()->get_binlog_pmc()->get("dialog_filters"); 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()) { if (log_event_parse(log_event, dialog_filters).is_ok()) {
server_main_dialog_list_position_ = log_event.server_main_dialog_list_position; server_main_dialog_list_position_ = log_event.server_main_dialog_list_position;
main_dialog_list_position_ = log_event.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)) { (server_main_dialog_list_position_ != 0 || main_dialog_list_position_ != 0)) {
LOG(INFO) << "Ignore main chat list position " << server_main_dialog_list_position_ << '/' LOG(INFO) << "Ignore main chat list position " << server_main_dialog_list_position_ << '/'
<< main_dialog_list_position_; << main_dialog_list_position_;
@ -13671,7 +13706,7 @@ void MessagesManager::init() {
void MessagesManager::on_authorization_success() { void MessagesManager::on_authorization_success() {
CHECK(td_->auth_manager_->is_authorized()); 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()) { if (td_->auth_manager_->is_bot()) {
disable_get_dialog_filter_ = true; disable_get_dialog_filter_ = true;
@ -17350,7 +17385,7 @@ void MessagesManager::on_get_dialog_filters(Result<vector<tl_object_ptr<telegram
LOG(ERROR) << "Receive no dialogFilterDefault"; LOG(ERROR) << "Receive no dialogFilterDefault";
server_main_dialog_list_position = 0; server_main_dialog_list_position = 0;
} }
if (server_main_dialog_list_position != 0 && !G()->shared_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; LOG(INFO) << "Ignore server main chat list position " << server_main_dialog_list_position;
server_main_dialog_list_position = 0; 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) { if (!m->is_outgoing) {
return Status::Error(400, "Can't get viewers of incoming messages"); 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"); 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) { if (participant_count == 0) {
return Status::Error(400, "Chat is empty or have unknown number of members"); 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"); return Status::Error(400, "Chat is too big");
} }
@ -18836,7 +18872,7 @@ Result<std::pair<string, bool>> MessagesManager::get_message_link(FullMessageId
} }
SliceBuilder sb; 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) { if (for_comment) {
auto *top_m = get_message_force(d, m->top_thread_message_id, "get_public_message_link"); auto *top_m = get_message_force(d, m->top_thread_message_id, "get_public_message_link");
@ -19217,7 +19253,7 @@ Result<unique_ptr<DialogFilter>> MessagesManager::create_dialog_filter(DialogFil
void MessagesManager::create_dialog_filter(td_api::object_ptr<td_api::chatFilter> filter, void MessagesManager::create_dialog_filter(td_api::object_ptr<td_api::chatFilter> filter,
Promise<td_api::object_ptr<td_api::chatFilterInfo>> &&promise) { Promise<td_api::object_ptr<td_api::chatFilterInfo>> &&promise) {
CHECK(!td_->auth_manager_->is_bot()); 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<int64>(0), static_cast<int64>(100)); static_cast<int64>(0), static_cast<int64>(100));
if (dialog_filters_.size() >= narrow_cast<size_t>(max_dialog_filters)) { if (dialog_filters_.size() >= narrow_cast<size_t>(max_dialog_filters)) {
return promise.set_error(Status::Error(400, "The maximum number of chat folders exceeded")); return promise.set_error(Status::Error(400, "The maximum number of chat folders exceeded"));
@ -19389,7 +19425,7 @@ void MessagesManager::reorder_dialog_filters(vector<DialogFilterId> dialog_filte
if (main_dialog_list_position < 0 || main_dialog_list_position > static_cast<int32>(dialog_filters_.size())) { if (main_dialog_list_position < 0 || main_dialog_list_position > static_cast<int32>(dialog_filters_.size())) {
return promise.set_error(Status::Error(400, "Invalid main chat list position specified")); 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; main_dialog_list_position = 0;
} }
@ -19960,7 +19996,7 @@ void MessagesManager::clear_all_draft_messages(bool exclude_secret_chats, Promis
td_->create_handler<ClearAllDraftsQuery>(std::move(promise))->send(); td_->create_handler<ClearAllDraftsQuery>(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()) { if (dialog_list_id.is_filter()) {
return DialogFilter::get_max_filter_dialogs(); 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"); key = Slice("pinned_archived_chat_count_max");
default_limit = 100; default_limit = 100;
} }
int32 limit = clamp(narrow_cast<int32>(G()->shared_config().get_option_integer(key)), 0, 1000); int32 limit = clamp(narrow_cast<int32>(td_->option_manager_->get_option_integer(key)), 0, 1000);
if (limit <= 0) { if (limit <= 0) {
if (G()->shared_config().get_option_boolean("is_premium")) { if (td_->option_manager_->get_option_boolean("is_premium")) {
default_limit *= 2; default_limit *= 2;
} }
return default_limit; return default_limit;
@ -22322,7 +22358,7 @@ td_api::object_ptr<td_api::messageCalendar> MessagesManager::get_dialog_message_
db_query.dialog_id = dialog_id; db_query.dialog_id = dialog_id;
db_query.filter = filter; db_query.filter = filter;
db_query.from_message_id = fixed_from_message_id; db_query.from_message_id = fixed_from_message_id;
db_query.tz_offset = static_cast<int32>(G()->shared_config().get_option_integer("utc_time_offset")); db_query.tz_offset = static_cast<int32>(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)); G()->td_db()->get_messages_db_async()->get_dialog_message_calendar(db_query, std::move(new_promise));
return {}; return {};
} }
@ -24424,8 +24460,8 @@ vector<AvailableReaction> MessagesManager::get_message_available_reactions(const
vector<AvailableReaction> result; vector<AvailableReaction> result;
if (can_use_reactions) { if (can_use_reactions) {
bool is_premium = G()->shared_config().get_option_boolean("is_premium"); bool is_premium = td_->option_manager_->get_option_boolean("is_premium");
int64 reactions_uniq_max = G()->shared_config().get_option_integer("reactions_uniq_max", 11); int64 reactions_uniq_max = td_->option_manager_->get_option_integer("reactions_uniq_max", 11);
bool can_add_new_reactions = bool can_add_new_reactions =
m->reactions == nullptr || static_cast<int64>(m->reactions->reactions_.size()) < reactions_uniq_max; m->reactions == nullptr || static_cast<int64>(m->reactions->reactions_.size()) < reactions_uniq_max;
// can add only active available reactions or remove previously set reaction // can add only active available reactions or remove previously set reaction
@ -24978,7 +25014,7 @@ unique_ptr<MessagesManager::Message> MessagesManager::create_message_to_send(
m->is_copy = is_copy || m->forward_info != nullptr; m->is_copy = is_copy || m->forward_info != nullptr;
if (td_->auth_manager_->is_bot() || options.disable_notification || 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; m->disable_notification = options.disable_notification;
} else { } else {
m->disable_notification = d->notification_settings.silent_send_message; 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, 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()) {
if (reply_to_message_id.is_valid_scheduled()) { if (reply_to_message_id.is_valid_scheduled()) {
CHECK(message_id.is_scheduled()); CHECK(message_id.is_scheduled());
@ -25588,7 +25625,7 @@ Result<InputMessageContent> MessagesManager::process_input_message_content(
UserId(), copied_message->send_emoji); 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)); 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) { if (content.ttl < 0 || content.ttl > MAX_PRIVATE_MESSAGE_TTL) {
@ -25614,9 +25651,8 @@ Result<MessageCopyOptions> MessagesManager::process_message_copy_options(
result.send_copy = true; result.send_copy = true;
result.replace_caption = options->replace_caption_; result.replace_caption = options->replace_caption_;
if (result.replace_caption) { if (result.replace_caption) {
TRY_RESULT_ASSIGN(result.new_caption, TRY_RESULT_ASSIGN(result.new_caption, get_formatted_text(td_, dialog_id, std::move(options->new_caption_),
process_input_caption(td_->contacts_manager_.get(), dialog_id, std::move(options->new_caption_), td_->auth_manager_->is_bot(), true, false, false));
td_->auth_manager_->is_bot()));
} }
return std::move(result); 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); 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()) { switch (dialog_id.get_type()) {
case DialogType::User: case DialogType::User:
case DialogType::Chat: 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::Channel:
case DialogType::SecretChat: case DialogType::SecretChat:
return false; return false;
@ -26851,7 +26887,7 @@ bool MessagesManager::can_edit_message(DialogId dialog_id, const Message *m, boo
if (has_edit_time_limit) { if (has_edit_time_limit) {
const int32 DEFAULT_EDIT_TIME_LIMIT = 2 * 86400; 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) { if (G()->unix_time_cached() - m->date - (is_editing ? 300 : 0) >= edit_time_limit) {
return false; 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")); 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), auto r_caption =
td_->auth_manager_->is_bot()); get_formatted_text(td_, dialog_id, std::move(input_caption), td_->auth_manager_->is_bot(), true, false, false);
if (r_caption.is_error()) { if (r_caption.is_error()) {
return promise.set_error(r_caption.move_as_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")); 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), auto r_caption =
td_->auth_manager_->is_bot()); get_formatted_text(td_, DialogId(), std::move(input_caption), td_->auth_manager_->is_bot(), true, false, false);
if (r_caption.is_error()) { if (r_caption.is_error()) {
return promise.set_error(r_caption.move_as_error()); return promise.set_error(r_caption.move_as_error());
} }
@ -29356,7 +29392,7 @@ Result<MessagesManager::MessagePushNotificationInfo> MessagesManager::get_messag
} }
if (is_from_scheduled && dialog_id != get_my_dialog_id() && 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"); 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; return true;
} }
if (m->is_from_scheduled && d->dialog_id != get_my_dialog_id() && 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; return true;
} }
if (m->forward_info != nullptr && m->forward_info->is_imported) { if (m->forward_info != nullptr && m->forward_info->is_imported) {
@ -30682,6 +30718,10 @@ void MessagesManager::send_update_delete_messages(DialogId dialog_id, vector<int
void MessagesManager::send_update_new_chat(Dialog *d) { void MessagesManager::send_update_new_chat(Dialog *d) {
CHECK(d != nullptr); CHECK(d != nullptr);
CHECK(d->messages == nullptr); CHECK(d->messages == 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; d->is_update_new_chat_being_sent = true;
auto chat_object = get_chat_object(d); auto chat_object = get_chat_object(d);
bool has_action_bar = chat_object->action_bar_ != nullptr; 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<td_api::updateChatPhoto>( make_tl_object<td_api::updateChatPhoto>(
dialog_id.get(), get_chat_photo_info_object(td_->file_manager_.get(), get_dialog_photo(dialog_id)))); 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) { } 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) { if (dialog_type == DialogType::Channel && !message->contains_unread_mention) {
auto channel_read_media_period = 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) { if (message->date < G()->unix_time_cached() - channel_read_media_period) {
update_opened_message_content(message->content.get()); update_opened_message_content(message->content.get());
} }
@ -36960,7 +37005,8 @@ void MessagesManager::fix_new_dialog(Dialog *d, unique_ptr<Message> &&last_datab
update_dialog_pos(d, "fix_new_dialog 7", true, is_loaded_from_database); 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 && 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; 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<Message> &&last_datab
<< ", max_notification_message_id = " << d->max_notification_message_id; << ", max_notification_message_id = " << d->max_notification_message_id;
if (d->messages != nullptr) { if (d->messages != nullptr) {
LOG_CHECK(d->messages->message_id == last_message_id) if (d->messages->message_id != last_message_id || d->messages->left != nullptr || d->messages->right != nullptr) {
<< d->messages->message_id << ' ' << last_message_id << ' ' << d->last_message_id << ' ' auto common_data =
<< d->last_database_message_id << ' ' << d->debug_set_dialog_last_database_message_id << ' ' PSTRING() << ' ' << last_message_id << ' ' << d->last_message_id << ' ' << d->last_database_message_id << ' '
<< d->messages->debug_source; << 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) LOG_CHECK(d->messages->left == nullptr)
<< d->messages->left->message_id << ' ' << d->messages->message_id << ' ' << d->messages->left->message_id << 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->messages->left->debug_source << common_data;
<< d->debug_set_dialog_last_database_message_id << ' ' << d->messages->debug_source;
LOG_CHECK(d->messages->right == nullptr) LOG_CHECK(d->messages->right == nullptr)
<< d->messages->right->message_id << ' ' << d->messages->message_id << ' ' << d->messages->right->message_id << 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->messages->right->debug_source << common_data;
<< d->debug_set_dialog_last_database_message_id << ' ' << d->messages->debug_source; }
} }
// must be after update_dialog_pos, because uses d->order // 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"; << " because it has already been run";
return; 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()); auto input_channel = td_->contacts_manager_->get_input_channel(dialog_id.get_channel_id());
if (input_channel == nullptr) { if (input_channel == nullptr) {
LOG(ERROR) << "Skip running channels.getDifference for " << dialog_id << " from " << source LOG(ERROR) << "Skip running channels.getDifference for " << dialog_id << " from " << source

View File

@ -78,6 +78,7 @@
#include "td/utils/Status.h" #include "td/utils/Status.h"
#include "td/utils/StringBuilder.h" #include "td/utils/StringBuilder.h"
#include "td/utils/WaitFreeHashMap.h" #include "td/utils/WaitFreeHashMap.h"
#include "td/utils/WaitFreeHashSet.h"
#include <array> #include <array>
#include <functional> #include <functional>
@ -1373,7 +1374,7 @@ class MessagesManager final : public Actor {
FlatHashMap<int32, MessageId> last_assigned_scheduled_message_id; // date -> message_id FlatHashMap<int32, MessageId> last_assigned_scheduled_message_id; // date -> message_id
FlatHashSet<MessageId, MessageIdHash> deleted_message_ids; WaitFreeHashSet<MessageId, MessageIdHash> deleted_message_ids;
FlatHashSet<ScheduledServerMessageId, ScheduledServerMessageIdHash> deleted_scheduled_server_message_ids; FlatHashSet<ScheduledServerMessageId, ScheduledServerMessageIdHash> deleted_scheduled_server_message_ids;
vector<std::pair<DialogId, MessageId>> pending_new_message_notifications; vector<std::pair<DialogId, MessageId>> 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; 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; 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); 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, void fix_server_reply_to_message_id(DialogId dialog_id, MessageId message_id, DialogId reply_in_dialog_id,
MessageId &reply_to_message_id); MessageId &reply_to_message_id) const;
bool can_set_game_score(DialogId dialog_id, const Message *m) 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); 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<DialogId> remove_secret_chat_dialog_ids(vector<DialogId> dialog_ids); static vector<DialogId> remove_secret_chat_dialog_ids(vector<DialogId> dialog_ids);
@ -2951,6 +2952,9 @@ class MessagesManager final : public Actor {
void ttl_db_loop(double server_now); void ttl_db_loop(double server_now);
void ttl_db_on_result(Result<std::pair<std::vector<MessagesDbMessage>, int32>> r_result, bool dummy); void ttl_db_on_result(Result<std::pair<std::vector<MessagesDbMessage>, int32>> r_result, bool dummy);
void on_restore_missing_message_after_get_difference(FullMessageId full_message_id, MessageId old_message_id,
Result<Unit> result);
void on_get_message_link_dialog(MessageLinkInfo &&info, Promise<MessageLinkInfo> &&promise); void on_get_message_link_dialog(MessageLinkInfo &&info, Promise<MessageLinkInfo> &&promise);
void on_get_message_link_message(MessageLinkInfo &&info, DialogId dialog_id, Promise<MessageLinkInfo> &&promise); void on_get_message_link_message(MessageLinkInfo &&info, DialogId dialog_id, Promise<MessageLinkInfo> &&promise);
@ -3715,6 +3719,8 @@ class MessagesManager final : public Actor {
DialogId being_added_new_dialog_id_; DialogId being_added_new_dialog_id_;
DialogId debug_channel_difference_dialog_; 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; double start_time_ = 0;
bool is_inited_ = false; bool is_inited_ = false;

View File

@ -9,7 +9,6 @@
#include "td/telegram/AuthManager.h" #include "td/telegram/AuthManager.h"
#include "td/telegram/ChannelId.h" #include "td/telegram/ChannelId.h"
#include "td/telegram/ChatId.h" #include "td/telegram/ChatId.h"
#include "td/telegram/ConfigShared.h"
#include "td/telegram/ContactsManager.h" #include "td/telegram/ContactsManager.h"
#include "td/telegram/DeviceTokenManager.h" #include "td/telegram/DeviceTokenManager.h"
#include "td/telegram/Document.h" #include "td/telegram/Document.h"
@ -22,6 +21,7 @@
#include "td/telegram/misc.h" #include "td/telegram/misc.h"
#include "td/telegram/net/ConnectionCreator.h" #include "td/telegram/net/ConnectionCreator.h"
#include "td/telegram/net/DcId.h" #include "td/telegram/net/DcId.h"
#include "td/telegram/OptionManager.h"
#include "td/telegram/Photo.h" #include "td/telegram/Photo.h"
#include "td/telegram/Photo.hpp" #include "td/telegram/Photo.hpp"
#include "td/telegram/SecretChatId.h" #include "td/telegram/SecretChatId.h"
@ -95,10 +95,10 @@ class SetContactSignUpNotificationQuery final : public Td::ResultHandler {
}; };
class GetContactSignUpNotificationQuery final : public Td::ResultHandler { class GetContactSignUpNotificationQuery final : public Td::ResultHandler {
Promise<Unit> promise_; Promise<bool> promise_;
public: public:
explicit GetContactSignUpNotificationQuery(Promise<Unit> &&promise) : promise_(std::move(promise)) { explicit GetContactSignUpNotificationQuery(Promise<bool> &&promise) : promise_(std::move(promise)) {
} }
void send() { void send() {
@ -111,8 +111,7 @@ class GetContactSignUpNotificationQuery final : public Td::ResultHandler {
return on_error(result_ptr.move_as_error()); return on_error(result_ptr.move_as_error());
} }
td_->notification_manager_->on_get_disable_contact_registered_notifications(result_ptr.ok()); promise_.set_value(result_ptr.move_as_ok());
promise_.set_value(Unit());
} }
void on_error(Status status) final { void on_error(Status status) final {
@ -209,7 +208,7 @@ void NotificationManager::init() {
} }
disable_contact_registered_notifications_ = 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()); auto sync_state = G()->td_db()->get_binlog_pmc()->get(get_is_contact_registered_notifications_synchronized_key());
if (sync_state.empty()) { if (sync_state.empty()) {
sync_state = "00"; 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<int32>( auto new_max_notification_group_count = narrow_cast<int32>(
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 && CHECK(MIN_NOTIFICATION_GROUP_COUNT_MAX <= new_max_notification_group_count &&
new_max_notification_group_count <= MAX_NOTIFICATION_GROUP_COUNT_MAX); 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<int32>( auto new_max_notification_group_size = narrow_cast<int32>(
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 && CHECK(MIN_NOTIFICATION_GROUP_SIZE_MAX <= new_max_notification_group_size &&
new_max_notification_group_size <= MAX_NOTIFICATION_GROUP_SIZE_MAX); 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<int32>( online_cloud_timeout_ms_ = narrow_cast<int32>(
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_; 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<int32>( notification_cloud_delay_ms_ = narrow_cast<int32>(
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_; 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<int32>( notification_default_delay_ms_ = narrow_cast<int32>(
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_; 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; 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_) { if (is_disabled == disable_contact_registered_notifications_) {
return; return;
} }
@ -2582,17 +2580,18 @@ void NotificationManager::on_disable_contact_registered_notifications_changed()
} }
} }
void NotificationManager::on_get_disable_contact_registered_notifications(bool is_disabled) { void NotificationManager::on_get_disable_contact_registered_notifications(bool is_disabled, Promise<Unit> &&promise) {
if (disable_contact_registered_notifications_ == is_disabled) { if (G()->close_flag() || disable_contact_registered_notifications_ == is_disabled) {
return; return promise.set_value(Unit());
} }
disable_contact_registered_notifications_ = is_disabled; disable_contact_registered_notifications_ = is_disabled;
if (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 { } 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) { void NotificationManager::set_contact_registered_notifications_sync_state(SyncState new_state) {
@ -2649,7 +2648,16 @@ void NotificationManager::get_disable_contact_registered_notifications(Promise<U
return; return;
} }
td_->create_handler<GetContactSignUpNotificationQuery>(std::move(promise))->send(); auto query_promise =
PromiseCreator::lambda([actor_id = actor_id(this), promise = std::move(promise)](Result<bool> &&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<GetContactSignUpNotificationQuery>(std::move(query_promise))->send();
} }
void NotificationManager::process_push_notification(string payload, Promise<Unit> &&user_promise) { void NotificationManager::process_push_notification(string payload, Promise<Unit> &&user_promise) {
@ -2705,7 +2713,7 @@ void NotificationManager::process_push_notification(string payload, Promise<Unit
send_closure(G()->state_manager(), &StateManager::on_online, false); send_closure(G()->state_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); auto status = process_push_notification_payload(payload, was_encrypted, promise);
if (status.is_error()) { if (status.is_error()) {
if (status.code() == 406 || status.code() == 200) { if (status.code() == 406 || status.code() == 200) {

View File

@ -108,8 +108,6 @@ class NotificationManager final : public Actor {
void on_disable_contact_registered_notifications_changed(); void on_disable_contact_registered_notifications_changed();
void on_get_disable_contact_registered_notifications(bool is_disabled);
void process_push_notification(string payload, Promise<Unit> &&user_promise); void process_push_notification(string payload, Promise<Unit> &&user_promise);
static Result<int64> get_push_receiver_id(string payload); static Result<int64> 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<Unit> result); void on_contact_registered_notifications_sync(bool is_disabled, Result<Unit> result);
void on_get_disable_contact_registered_notifications(bool is_disabled, Promise<Unit> &&promise);
void save_announcement_ids(); void save_announcement_ids();
static ActiveNotificationsUpdate as_active_notifications_update(const td_api::updateActiveNotifications *update); static ActiveNotificationsUpdate as_active_notifications_update(const td_api::updateActiveNotifications *update);

View File

@ -10,7 +10,6 @@
#include "td/telegram/AudiosManager.h" #include "td/telegram/AudiosManager.h"
#include "td/telegram/AudiosManager.hpp" #include "td/telegram/AudiosManager.hpp"
#include "td/telegram/AuthManager.h" #include "td/telegram/AuthManager.h"
#include "td/telegram/ConfigShared.h"
#include "td/telegram/ContactsManager.h" #include "td/telegram/ContactsManager.h"
#include "td/telegram/Document.h" #include "td/telegram/Document.h"
#include "td/telegram/DocumentsManager.h" #include "td/telegram/DocumentsManager.h"
@ -25,6 +24,7 @@
#include "td/telegram/NotificationManager.h" #include "td/telegram/NotificationManager.h"
#include "td/telegram/NotificationSettings.hpp" #include "td/telegram/NotificationSettings.hpp"
#include "td/telegram/NotificationSound.h" #include "td/telegram/NotificationSound.h"
#include "td/telegram/OptionManager.h"
#include "td/telegram/Td.h" #include "td/telegram/Td.h"
#include "td/telegram/TdDb.h" #include "td/telegram/TdDb.h"
#include "td/telegram/telegram_api.h" #include "td/telegram/telegram_api.h"
@ -874,7 +874,7 @@ void NotificationSettingsManager::add_saved_ringtone(td_api::object_ptr<td_api::
FileId file_id = r_file_id.ok(); FileId file_id = r_file_id.ok();
auto file_view = td_->file_manager_->get_file_view(file_id); auto file_view = td_->file_manager_->get_file_view(file_id);
CHECK(!file_view.empty()); 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")); return promise.set_error(Status::Error(400, "Notification sound file is too big"));
} }
auto file_type = file_view.get_type(); auto file_type = file_view.get_type();
@ -889,7 +889,7 @@ void NotificationSettingsManager::add_saved_ringtone(td_api::object_ptr<td_api::
default: default:
break; break;
} }
if (duration > 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")); return promise.set_error(Status::Error(400, "Notification sound is too long"));
} }
if (file_view.has_remote_location() && !file_view.is_encrypted()) { 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_); 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<uint64>(max_count)) { if (saved_ringtone_file_ids_.size() >= static_cast<uint64>(max_count)) {
// reload all saved ringtones to get ringtones besides the limit // reload all saved ringtones to get ringtones besides the limit
return reload_saved_ringtones(PromiseCreator::lambda([promise = std::move(promise)](Result<Unit> &&result) mutable { return reload_saved_ringtones(PromiseCreator::lambda([promise = std::move(promise)](Result<Unit> &&result) mutable {

View File

@ -10,13 +10,13 @@
#include "td/telegram/AttachMenuManager.h" #include "td/telegram/AttachMenuManager.h"
#include "td/telegram/AuthManager.h" #include "td/telegram/AuthManager.h"
#include "td/telegram/ConfigManager.h" #include "td/telegram/ConfigManager.h"
#include "td/telegram/ConfigShared.h"
#include "td/telegram/ContactsManager.h" #include "td/telegram/ContactsManager.h"
#include "td/telegram/DialogId.h" #include "td/telegram/DialogId.h"
#include "td/telegram/GitCommitHash.h" #include "td/telegram/GitCommitHash.h"
#include "td/telegram/Global.h" #include "td/telegram/Global.h"
#include "td/telegram/JsonValue.h" #include "td/telegram/JsonValue.h"
#include "td/telegram/LanguagePackManager.h" #include "td/telegram/LanguagePackManager.h"
#include "td/telegram/MessageReaction.h"
#include "td/telegram/net/MtprotoHeader.h" #include "td/telegram/net/MtprotoHeader.h"
#include "td/telegram/net/NetQueryDispatcher.h" #include "td/telegram/net/NetQueryDispatcher.h"
#include "td/telegram/NotificationManager.h" #include "td/telegram/NotificationManager.h"
@ -26,11 +26,14 @@
#include "td/telegram/SuggestedAction.h" #include "td/telegram/SuggestedAction.h"
#include "td/telegram/Td.h" #include "td/telegram/Td.h"
#include "td/telegram/TdDb.h" #include "td/telegram/TdDb.h"
#include "td/telegram/telegram_api.h"
#include "td/telegram/TopDialogManager.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/algorithm.h"
#include "td/utils/buffer.h"
#include "td/utils/logging.h" #include "td/utils/logging.h"
#include "td/utils/misc.h" #include "td/utils/misc.h"
#include "td/utils/port/Clocks.h" #include "td/utils/port/Clocks.h"
@ -43,95 +46,162 @@
namespace td { namespace td {
class SetDefaultReactionQuery final : public Td::ResultHandler { OptionManager::OptionManager(Td *td)
Promise<Unit> promise_; : td_(td), options_(td::make_unique<TsSeqKeyValue>()), option_pmc_(G()->td_db()->get_config_pmc_shared()) {
public:
explicit SetDefaultReactionQuery(Promise<Unit> &&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<telegram_api::messages_setDefaultReaction>(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)) {
send_unix_time_update(); send_unix_time_update();
if (G()->shared_config().have_option("language_database_path")) { auto all_options = option_pmc_->get_all();
G()->shared_config().set_option_string("language_pack_database_path", all_options["utc_time_offset"] = PSTRING() << 'I' << Clocks::tz_offset();
G()->shared_config().get_option_string("language_database_path")); for (const auto &name_value : all_options) {
G()->shared_config().set_option_empty("language_database_path"); 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<td_api::updateOption>(name, get_option_value_object(value)));
} else if (name == "otherwise_relogin_days") {
auto days = narrow_cast<int32>(get_option_integer(name));
if (days > 0) {
vector<SuggestedAction> added_actions{SuggestedAction{SuggestedAction::Type::SetPassword, DialogId(), days}};
send_closure(G()->td(), &Td::send_update, get_update_suggested_actions_object(added_actions, {}));
} }
if (G()->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() { if (!have_option("message_text_length_max")) {
parent_.reset(); 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; 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<int64>(value.substr(1));
}
string OptionManager::get_option_string(Slice name, string default_value) const {
auto value = get_option(name);
if (value.empty()) {
return default_value;
}
if (value[0] != 'S') {
LOG(ERROR) << "Found \"" << value << "\" instead of string option " << name;
return default_value;
}
return value.substr(1);
}
void OptionManager::set_option(Slice name, Slice value) {
CHECK(!name.empty());
CHECK(Scheduler::instance()->sched_id() == 0);
if (value.empty()) {
if (option_pmc_->erase(name.str()) == 0) {
return;
}
option_pmc_->erase(name.str());
} else {
if (options_->set(name, value) == 0) {
return;
}
option_pmc_->set(name.str(), value.str());
}
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<td_api::updateOption>(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<td_api::OptionValue> OptionManager::get_unix_time_option_value_object() { td_api::object_ptr<td_api::OptionValue> OptionManager::get_unix_time_option_value_object() {
return td_api::make_object<td_api::optionValueInteger>(G()->unix_time()); return td_api::make_object<td_api::optionValueInteger>(G()->unix_time());
} }
@ -142,6 +212,7 @@ void OptionManager::send_unix_time_update() {
} }
void OptionManager::on_update_server_time_difference() { 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) { if (std::abs(G()->get_server_time_difference() - last_sent_server_time_difference_) < 0.5) {
return; return;
} }
@ -150,7 +221,7 @@ void OptionManager::on_update_server_time_difference() {
} }
void OptionManager::clear_options() { 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)) { if (!is_internal_option(option.first)) {
send_closure( send_closure(
G()->td(), &Td::send_update, G()->td(), &Td::send_update,
@ -163,8 +234,7 @@ bool OptionManager::is_internal_option(Slice name) {
switch (name[0]) { switch (name[0]) {
case 'a': case 'a':
return name == "about_length_limit_default" || name == "about_length_limit_premium" || return name == "about_length_limit_default" || name == "about_length_limit_premium" ||
name == "animated_emoji_zoom" || name == "animation_search_emojis" || name == "animated_emoji_zoom" || name == "animation_search_emojis" || name == "animation_search_provider";
name == "animation_search_provider" || name == "auth";
case 'b': case 'b':
return name == "base_language_pack_version"; return name == "base_language_pack_version";
case 'c': case 'c':
@ -221,24 +291,17 @@ bool OptionManager::is_synchronous_option(Slice name) {
return td::contains(get_synchronous_options(), name); return td::contains(get_synchronous_options(), name);
} }
void OptionManager::on_option_updated(const string &name) { void OptionManager::on_option_updated(Slice name) {
if (G()->close_flag()) {
return;
}
switch (name[0]) { switch (name[0]) {
case 'a': case 'a':
if (name == "animated_emoji_zoom") { if (name == "animated_emoji_zoom") {
// nothing to do: animated emoji zoom is updated only at launch // nothing to do: animated emoji zoom is updated only at launch
} }
if (name == "animation_search_emojis") { 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") { if (name == "animation_search_provider") {
td_->animations_manager_->on_update_animation_search_provider(G()->shared_config().get_option_string(name)); td_->animations_manager_->on_update_animation_search_provider();
}
if (name == "auth") {
send_closure(td_->auth_manager_actor_, &AuthManager::on_authorization_lost,
G()->shared_config().get_option_string(name));
} }
break; break;
case 'b': case 'b':
@ -248,14 +311,14 @@ void OptionManager::on_option_updated(const string &name) {
break; break;
case 'c': case 'c':
if (name == "connection_parameters") { 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(); G()->net_query_dispatcher().update_mtproto_header();
} }
} }
break; break;
case 'd': case 'd':
if (name == "default_reaction_needs_sync" && G()->shared_config().get_option_boolean(name)) { if (name == "default_reaction_needs_sync" && get_option_boolean(name)) {
set_default_reaction(); send_set_default_reaction_query(td_);
} }
if (name == "dice_emojis") { if (name == "dice_emojis") {
send_closure(td_->stickers_manager_actor_, &StickersManager::on_update_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); &NotificationManager::on_disable_contact_registered_notifications_changed);
} }
if (name == "disable_top_chats") { if (name == "disable_top_chats") {
send_closure(td_->top_dialog_manager_actor_, &TopDialogManager::update_is_enabled, send_closure(td_->top_dialog_manager_actor_, &TopDialogManager::update_is_enabled, !get_option_boolean(name));
!G()->shared_config().get_option_boolean(name));
} }
break; break;
case 'e': case 'e':
@ -282,8 +344,7 @@ void OptionManager::on_option_updated(const string &name) {
break; break;
case 'f': case 'f':
if (name == "favorite_stickers_limit") { if (name == "favorite_stickers_limit") {
td_->stickers_manager_->on_update_favorite_stickers_limit( td_->stickers_manager_->on_update_favorite_stickers_limit();
narrow_cast<int32>(G()->shared_config().get_option_integer(name)));
} }
break; break;
case 'i': 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); send_closure(td_->contacts_manager_actor_, &ContactsManager::on_ignored_restriction_reasons_changed);
} }
if (name == "is_emulator") { 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(); G()->net_query_dispatcher().update_mtproto_header();
} }
} }
@ -299,7 +360,7 @@ void OptionManager::on_option_updated(const string &name) {
case 'l': case 'l':
if (name == "language_pack_id") { if (name == "language_pack_id") {
send_closure(td_->language_pack_manager_, &LanguagePackManager::on_language_code_changed); 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(); G()->net_query_dispatcher().update_mtproto_header();
} }
send_closure(td_->attach_menu_manager_actor_, &AttachMenuManager::reload_attach_menu_bots, Promise<Unit>()); send_closure(td_->attach_menu_manager_actor_, &AttachMenuManager::reload_attach_menu_bots, Promise<Unit>());
@ -309,16 +370,11 @@ void OptionManager::on_option_updated(const string &name) {
} }
if (name == "localization_target") { if (name == "localization_target") {
send_closure(td_->language_pack_manager_, &LanguagePackManager::on_language_pack_changed); 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(); G()->net_query_dispatcher().update_mtproto_header();
} }
} }
break; break;
case 'm':
if (name == "my_id") {
G()->set_my_id(G()->shared_config().get_option_integer(name));
}
break;
case 'n': case 'n':
if (name == "notification_cloud_delay_ms") { if (name == "notification_cloud_delay_ms") {
send_closure(td_->notification_manager_actor_, &NotificationManager::on_notification_cloud_delay_changed); 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); send_closure(td_->notification_manager_actor_, &NotificationManager::on_online_cloud_timeout_changed);
} }
if (name == "otherwise_relogin_days") { if (name == "otherwise_relogin_days") {
auto days = narrow_cast<int32>(G()->shared_config().get_option_integer(name)); auto days = narrow_cast<int32>(get_option_integer(name));
if (days > 0) { if (days > 0) {
vector<SuggestedAction> added_actions{SuggestedAction{SuggestedAction::Type::SetPassword, DialogId(), days}}; vector<SuggestedAction> added_actions{SuggestedAction{SuggestedAction::Type::SetPassword, DialogId(), days}};
send_closure(G()->td(), &Td::send_update, get_update_suggested_actions_object(added_actions, {})); 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); send_closure(td_->top_dialog_manager_actor_, &TopDialogManager::update_rating_e_decay);
} }
if (name == "recent_stickers_limit") { if (name == "recent_stickers_limit") {
td_->stickers_manager_->on_update_recent_stickers_limit( td_->stickers_manager_->on_update_recent_stickers_limit();
narrow_cast<int32>(G()->shared_config().get_option_integer(name)));
} }
break; break;
case 's': case 's':
if (name == "saved_animations_limit") { if (name == "saved_animations_limit") {
td_->animations_manager_->on_update_saved_animations_limit( td_->animations_manager_->on_update_saved_animations_limit();
narrow_cast<int32>(G()->shared_config().get_option_integer(name)));
} }
if (name == "session_count") { if (name == "session_count") {
G()->net_query_dispatcher().update_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); send_closure(td_->storage_manager_, &StorageManager::update_use_storage_optimizer);
} }
if (name == "utc_time_offset") { if (name == "utc_time_offset") {
if (G()->mtproto_header().set_tz_offset(static_cast<int32>(G()->shared_config().get_option_integer(name)))) { if (G()->mtproto_header().set_tz_offset(static_cast<int32>(get_option_integer(name)))) {
G()->net_query_dispatcher().update_mtproto_header(); G()->net_query_dispatcher().update_mtproto_header();
} }
} }
@ -380,22 +434,14 @@ void OptionManager::on_option_updated(const string &name) {
default: default:
break; break;
} }
if (is_internal_option(name)) {
return;
}
// send_closure was already used in the callback
td_->send_update(
td_api::make_object<td_api::updateOption>(name, get_option_value_object(G()->shared_config().get_option(name))));
} }
void OptionManager::get_option(const string &name, Promise<td_api::object_ptr<td_api::OptionValue>> &&promise) { void OptionManager::get_option(const string &name, Promise<td_api::object_ptr<td_api::OptionValue>> &&promise) {
bool is_bot = td_->auth_manager_ != nullptr && td_->auth_manager_->is_authorized() && td_->auth_manager_->is_bot(); bool is_bot = td_->auth_manager_ != nullptr && td_->auth_manager_->is_authorized() && td_->auth_manager_->is_bot();
auto wrap_promise = [&] { auto wrap_promise = [this, &promise, &name] {
return PromiseCreator::lambda([promise = std::move(promise), name](Unit result) mutable { return PromiseCreator::lambda([this, promise = std::move(promise), name](Unit result) mutable {
// the option is already updated on success, ignore errors // 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]) { switch (name[0]) {
@ -412,8 +458,13 @@ void OptionManager::get_option(const string &name, Promise<td_api::object_ptr<td
break; break;
case 'd': case 'd':
if (!is_bot && name == "disable_contact_registered_notifications") { if (!is_bot && name == "disable_contact_registered_notifications") {
return send_closure_later(td_->notification_manager_actor_, if (is_td_inited_) {
send_closure_later(td_->notification_manager_actor_,
&NotificationManager::get_disable_contact_registered_notifications, wrap_promise()); &NotificationManager::get_disable_contact_registered_notifications, wrap_promise());
} else {
pending_get_options_.emplace_back(name, std::move(promise));
}
return;
} }
break; break;
case 'i': case 'i':
@ -421,8 +472,12 @@ void OptionManager::get_option(const string &name, Promise<td_api::object_ptr<td
return send_closure_later(td_->config_manager_, &ConfigManager::get_content_settings, wrap_promise()); return send_closure_later(td_->config_manager_, &ConfigManager::get_content_settings, wrap_promise());
} }
if (!is_bot && name == "is_location_visible") { if (!is_bot && name == "is_location_visible") {
return send_closure_later(td_->contacts_manager_actor_, &ContactsManager::get_is_location_visible, if (is_td_inited_) {
wrap_promise()); 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; break;
case 'o': case 'o':
@ -466,7 +521,7 @@ void OptionManager::set_option(const string &name, td_api::object_ptr<td_api::Op
return false; return false;
} }
if (value_constructor_id == td_api::optionValueEmpty::ID) { if (value_constructor_id == td_api::optionValueEmpty::ID) {
G()->shared_config().set_option_empty(option_name); set_option_empty(option_name);
} else { } else {
if (value_constructor_id != td_api::optionValueInteger::ID) { if (value_constructor_id != td_api::optionValueInteger::ID) {
promise.set_error(Status::Error(400, PSLICE() << "Option \"" << name << "\" must have integer value")); 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_ptr<td_api::Op
<< max_value << "]")); << max_value << "]"));
return false; return false;
} }
G()->shared_config().set_option_integer(name, int_value); set_option_integer(name, int_value);
} }
promise.set_value(Unit()); promise.set_value(Unit());
return true; return true;
@ -491,7 +546,7 @@ void OptionManager::set_option(const string &name, td_api::object_ptr<td_api::Op
return false; return false;
} }
if (value_constructor_id == td_api::optionValueEmpty::ID) { if (value_constructor_id == td_api::optionValueEmpty::ID) {
G()->shared_config().set_option_empty(name); set_option_empty(name);
} else { } else {
if (value_constructor_id != td_api::optionValueBoolean::ID) { if (value_constructor_id != td_api::optionValueBoolean::ID) {
promise.set_error(Status::Error(400, PSLICE() << "Option \"" << name << "\" must have boolean value")); 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<td_api::Op
} }
bool bool_value = static_cast<td_api::optionValueBoolean *>(value.get())->value_; bool bool_value = static_cast<td_api::optionValueBoolean *>(value.get())->value_;
G()->shared_config().set_option_boolean(name, bool_value); set_option_boolean(name, bool_value);
} }
promise.set_value(Unit()); promise.set_value(Unit());
return true; return true;
@ -510,7 +565,7 @@ void OptionManager::set_option(const string &name, td_api::object_ptr<td_api::Op
return false; return false;
} }
if (value_constructor_id == td_api::optionValueEmpty::ID) { if (value_constructor_id == td_api::optionValueEmpty::ID) {
G()->shared_config().set_option_empty(name); set_option_empty(name);
} else { } else {
if (value_constructor_id != td_api::optionValueString::ID) { if (value_constructor_id != td_api::optionValueString::ID) {
promise.set_error(Status::Error(400, PSLICE() << "Option \"" << name << "\" must have string value")); 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<td_api::Op
const string &str_value = static_cast<td_api::optionValueString *>(value.get())->value_; const string &str_value = static_cast<td_api::optionValueString *>(value.get())->value_;
if (str_value.empty()) { if (str_value.empty()) {
G()->shared_config().set_option_empty(name); set_option_empty(name);
} else { } else {
if (check_value(str_value)) { if (check_value(str_value)) {
G()->shared_config().set_option_string(name, str_value); set_option_string(name, str_value);
} else { } else {
promise.set_error(Status::Error(400, PSLICE() << "Option \"" << name << "\" can't have specified value")); promise.set_error(Status::Error(400, PSLICE() << "Option \"" << name << "\" can't have specified value"));
return false; return false;
@ -566,10 +621,12 @@ void OptionManager::set_option(const string &name, td_api::object_ptr<td_api::Op
} }
break; break;
case 'd': case 'd':
if (!is_bot && set_string_option("default_reaction", [td = td_](Slice value) { if (!is_bot && name == "default_reaction") {
return td->stickers_manager_->is_active_reaction(value.str()); string reaction;
})) { if (value_constructor_id == td_api::optionValueString::ID) {
G()->shared_config().set_option_boolean("default_reaction_needs_sync", true); reaction = static_cast<td_api::optionValueString *>(value.get())->value_;
}
set_default_reaction(td_, std::move(reaction), std::move(promise));
return; return;
} }
if (!is_bot && set_boolean_option("disable_animated_emoji")) { if (!is_bot && set_boolean_option("disable_animated_emoji")) {
@ -641,7 +698,7 @@ void OptionManager::set_option(const string &name, td_api::object_ptr<td_api::Op
return; return;
} }
if (!is_bot && name == "ignore_sensitive_content_restrictions") { if (!is_bot && name == "ignore_sensitive_content_restrictions") {
if (!G()->shared_config().get_option_boolean("can_ignore_sensitive_content_restrictions")) { if (!get_option_boolean("can_ignore_sensitive_content_restrictions")) {
return promise.set_error( return promise.set_error(
Status::Error(400, "Option \"ignore_sensitive_content_restrictions\" can't be changed by the user")); 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_ptr<td_api::Op
return; return;
} }
if (!is_bot && set_boolean_option("is_location_visible")) { if (!is_bot && set_boolean_option("is_location_visible")) {
td_->contacts_manager_->set_location_visibility(); ContactsManager::set_location_visibility(td_);
return; return;
} }
break; break;
@ -766,19 +823,16 @@ void OptionManager::set_option(const string &name, td_api::object_ptr<td_api::Op
} }
switch (value_constructor_id) { switch (value_constructor_id) {
case td_api::optionValueBoolean::ID: case td_api::optionValueBoolean::ID:
G()->shared_config().set_option_boolean(name, set_option_boolean(name, static_cast<const td_api::optionValueBoolean *>(value.get())->value_);
static_cast<const td_api::optionValueBoolean *>(value.get())->value_);
break; break;
case td_api::optionValueEmpty::ID: case td_api::optionValueEmpty::ID:
G()->shared_config().set_option_empty(name); set_option_empty(name);
break; break;
case td_api::optionValueInteger::ID: case td_api::optionValueInteger::ID:
G()->shared_config().set_option_integer(name, set_option_integer(name, static_cast<const td_api::optionValueInteger *>(value.get())->value_);
static_cast<const td_api::optionValueInteger *>(value.get())->value_);
break; break;
case td_api::optionValueString::ID: case td_api::optionValueString::ID:
G()->shared_config().set_option_string(name, set_option_string(name, static_cast<const td_api::optionValueString *>(value.get())->value_);
static_cast<const td_api::optionValueString *>(value.get())->value_);
break; break;
default: default:
UNREACHABLE(); UNREACHABLE();
@ -830,7 +884,7 @@ void OptionManager::get_current_state(vector<td_api::object_ptr<td_api::Update>>
updates.push_back(td_api::make_object<td_api::updateOption>("unix_time", get_unix_time_option_value_object())); updates.push_back(td_api::make_object<td_api::updateOption>("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)) { if (!is_internal_option(option.first)) {
updates.push_back( updates.push_back(
td_api::make_object<td_api::updateOption>(option.first, get_option_value_object(option.second))); td_api::make_object<td_api::updateOption>(option.first, get_option_value_object(option.second)));
@ -838,23 +892,4 @@ void OptionManager::get_current_state(vector<td_api::object_ptr<td_api::Update>>
} }
} }
void OptionManager::set_default_reaction() {
auto promise = PromiseCreator::lambda([actor_id = actor_id(this)](Result<Unit> &&result) {
send_closure(actor_id, &OptionManager::on_set_default_reaction, result.is_ok());
});
td_->create_handler<SetDefaultReactionQuery>(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<Unit>());
}
}
} // namespace td } // namespace td

View File

@ -8,35 +8,54 @@
#include "td/telegram/td_api.h" #include "td/telegram/td_api.h"
#include "td/actor/actor.h"
#include "td/utils/common.h" #include "td/utils/common.h"
#include "td/utils/Promise.h" #include "td/utils/Promise.h"
#include "td/utils/Slice.h" #include "td/utils/Slice.h"
#include <atomic>
#include <memory>
#include <utility>
namespace td { namespace td {
class KeyValueSyncInterface;
class Td; class Td;
class TsSeqKeyValue;
class OptionManager final : public Actor { class OptionManager {
public: public:
OptionManager(Td *td, ActorShared<> parent); explicit OptionManager(Td *td);
OptionManager(const OptionManager &) = delete; OptionManager(const OptionManager &) = delete;
OptionManager &operator=(const OptionManager &) = delete; OptionManager &operator=(const OptionManager &) = delete;
OptionManager(OptionManager &&) = delete; OptionManager(OptionManager &&) = delete;
OptionManager &operator=(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_update_server_time_difference();
void on_option_updated(const string &name);
void get_option(const string &name, Promise<td_api::object_ptr<td_api::OptionValue>> &&promise); void get_option(const string &name, Promise<td_api::object_ptr<td_api::OptionValue>> &&promise);
void set_option(const string &name, td_api::object_ptr<td_api::OptionValue> &&value, Promise<Unit> &&promise); void set_option(const string &name, td_api::object_ptr<td_api::OptionValue> &&value, Promise<Unit> &&promise);
static void clear_options(); void clear_options();
static bool is_synchronous_option(Slice name); static bool is_synchronous_option(Slice name);
@ -47,7 +66,11 @@ class OptionManager final : public Actor {
void get_current_state(vector<td_api::object_ptr<td_api::Update>> &updates) const; void get_current_state(vector<td_api::object_ptr<td_api::Update>> &updates) const;
private: private:
void tear_down() final; void set_option(Slice name, Slice value);
void on_option_updated(Slice name);
string get_option(Slice name) const;
static bool is_internal_option(Slice name); static bool is_internal_option(Slice name);
@ -59,14 +82,14 @@ class OptionManager final : public Actor {
void send_unix_time_update(); void send_unix_time_update();
void set_default_reaction();
void on_set_default_reaction(bool success);
Td *td_; Td *td_;
ActorShared<> parent_; bool is_td_inited_ = false;
vector<std::pair<string, Promise<td_api::object_ptr<td_api::OptionValue>>>> pending_get_options_;
double last_sent_server_time_difference_ = 1e100; unique_ptr<TsSeqKeyValue> options_;
std::shared_ptr<KeyValueSyncInterface> option_pmc_;
std::atomic<double> last_sent_server_time_difference_{1e100};
}; };
} // namespace td } // namespace td

View File

@ -7,7 +7,6 @@
#include "td/telegram/PasswordManager.h" #include "td/telegram/PasswordManager.h"
#include "td/telegram/ConfigManager.h" #include "td/telegram/ConfigManager.h"
#include "td/telegram/ConfigShared.h"
#include "td/telegram/DhCache.h" #include "td/telegram/DhCache.h"
#include "td/telegram/DialogId.h" #include "td/telegram/DialogId.h"
#include "td/telegram/Global.h" #include "td/telegram/Global.h"
@ -785,7 +784,7 @@ void PasswordManager::do_get_state(Promise<PasswordState> promise) {
state.has_recovery_email_address = password->has_recovery_; state.has_recovery_email_address = password->has_recovery_;
state.has_secure_values = password->has_secure_values_; state.has_secure_values = password->has_secure_values_;
auto days = narrow_cast<int32>(G()->shared_config().get_option_integer("otherwise_relogin_days")); auto days = narrow_cast<int32>(G()->get_option_integer("otherwise_relogin_days"));
if (days > 0) { if (days > 0) {
dismiss_suggested_action(SuggestedAction{SuggestedAction::Type::SetPassword, DialogId(), days}, dismiss_suggested_action(SuggestedAction{SuggestedAction::Type::SetPassword, DialogId(), days},
Promise<Unit>()); Promise<Unit>());

View File

@ -8,13 +8,11 @@
#include "td/telegram/AnimationsManager.h" #include "td/telegram/AnimationsManager.h"
#include "td/telegram/Application.h" #include "td/telegram/Application.h"
#include "td/telegram/ConfigShared.h"
#include "td/telegram/ContactsManager.h" #include "td/telegram/ContactsManager.h"
#include "td/telegram/DialogId.h" #include "td/telegram/DialogId.h"
#include "td/telegram/Document.h" #include "td/telegram/Document.h"
#include "td/telegram/DocumentsManager.h" #include "td/telegram/DocumentsManager.h"
#include "td/telegram/Global.h" #include "td/telegram/Global.h"
#include "td/telegram/JsonValue.h"
#include "td/telegram/MessageEntity.h" #include "td/telegram/MessageEntity.h"
#include "td/telegram/Payments.h" #include "td/telegram/Payments.h"
#include "td/telegram/Td.h" #include "td/telegram/Td.h"
@ -399,10 +397,8 @@ static string get_premium_source(const td_api::object_ptr<td_api::PremiumSource>
} }
static td_api::object_ptr<td_api::premiumLimit> get_premium_limit_object(Slice key) { static td_api::object_ptr<td_api::premiumLimit> get_premium_limit_object(Slice key) {
int32 default_limit = auto default_limit = static_cast<int32>(G()->get_option_integer(PSLICE() << key << "_limit_default"));
static_cast<int32>(G()->shared_config().get_option_integer(PSLICE() << key << "_limit_default")); auto premium_limit = static_cast<int32>(G()->get_option_integer(PSLICE() << key << "_limit_premium"));
int32 premium_limit =
static_cast<int32>(G()->shared_config().get_option_integer(PSLICE() << key << "_limit_premium"));
if (default_limit <= 0 || premium_limit <= default_limit) { if (default_limit <= 0 || premium_limit <= default_limit) {
return nullptr; return nullptr;
} }
@ -455,7 +451,7 @@ void get_premium_limit(const td_api::object_ptr<td_api::PremiumLimitType> &limit
void get_premium_features(Td *td, const td_api::object_ptr<td_api::PremiumSource> &source, void get_premium_features(Td *td, const td_api::object_ptr<td_api::PremiumSource> &source,
Promise<td_api::object_ptr<td_api::premiumFeatures>> &&promise) { Promise<td_api::object_ptr<td_api::premiumFeatures>> &&promise) {
auto premium_features = auto premium_features =
full_split(G()->shared_config().get_option_string( full_split(G()->get_option_string(
"premium_features", "premium_features",
"double_limits,more_upload,faster_download,voice_to_text,no_ads,unique_reactions,premium_stickers," "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"), "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<td_api::PremiumSource
} }
td_api::object_ptr<td_api::InternalLinkType> payment_link; td_api::object_ptr<td_api::InternalLinkType> 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()) { if (!premium_bot_username.empty()) {
payment_link = td_api::make_object<td_api::internalLinkTypeBotStart>(premium_bot_username, source_str, true); payment_link = td_api::make_object<td_api::internalLinkTypeBotStart>(premium_bot_username, source_str, true);
} else { } 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()) { if (!premium_invoice_slug.empty()) {
payment_link = td_api::make_object<td_api::internalLinkTypeInvoice>(premium_invoice_slug); payment_link = td_api::make_object<td_api::internalLinkTypeInvoice>(premium_invoice_slug);
} }

View File

@ -10,8 +10,8 @@
#include "td/telegram/Payments.h" #include "td/telegram/Payments.h"
#include "td/utils/common.h" #include "td/utils/common.h"
#include "td/utils/logging.h"
#include <limits>
#include <tuple> #include <tuple>
namespace td { namespace td {

View File

@ -6,7 +6,6 @@
// //
#include "td/telegram/RestrictionReason.h" #include "td/telegram/RestrictionReason.h"
#include "td/telegram/ConfigShared.h"
#include "td/telegram/Global.h" #include "td/telegram/Global.h"
#include "td/utils/algorithm.h" #include "td/utils/algorithm.h"
@ -22,10 +21,9 @@ string get_restriction_reason_description(const vector<RestrictionReason> &restr
return string(); return string();
} }
auto ignored_restriction_reasons = auto ignored_restriction_reasons = full_split(G()->get_option_string("ignored_restriction_reasons"), ',');
full_split(G()->shared_config().get_option_string("ignored_restriction_reasons"), ',');
auto platform = [] { auto platform = [] {
if (G()->shared_config().get_option_boolean("ignore_platform_restrictions")) { if (G()->get_option_boolean("ignore_platform_restrictions")) {
return Slice(); return Slice();
} }

View File

@ -6,7 +6,6 @@
// //
#include "td/telegram/SecretChatsManager.h" #include "td/telegram/SecretChatsManager.h"
#include "td/telegram/ConfigShared.h"
#include "td/telegram/ContactsManager.h" #include "td/telegram/ContactsManager.h"
#include "td/telegram/DhCache.h" #include "td/telegram/DhCache.h"
#include "td/telegram/EncryptedFile.h" #include "td/telegram/EncryptedFile.h"
@ -321,7 +320,7 @@ unique_ptr<SecretChatActor::Context> SecretChatsManager::make_secret_chat_contex
} }
bool get_config_option_boolean(const string &name) const final { 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 { int32 unix_time() final {

View File

@ -7,7 +7,6 @@
#include "td/telegram/SponsoredMessageManager.h" #include "td/telegram/SponsoredMessageManager.h"
#include "td/telegram/ChannelId.h" #include "td/telegram/ChannelId.h"
#include "td/telegram/ConfigShared.h"
#include "td/telegram/ContactsManager.h" #include "td/telegram/ContactsManager.h"
#include "td/telegram/Global.h" #include "td/telegram/Global.h"
#include "td/telegram/LinkManager.h" #include "td/telegram/LinkManager.h"
@ -15,6 +14,7 @@
#include "td/telegram/MessageEntity.h" #include "td/telegram/MessageEntity.h"
#include "td/telegram/MessagesManager.h" #include "td/telegram/MessagesManager.h"
#include "td/telegram/net/NetQueryCreator.h" #include "td/telegram/net/NetQueryCreator.h"
#include "td/telegram/OptionManager.h"
#include "td/telegram/ServerMessageId.h" #include "td/telegram/ServerMessageId.h"
#include "td/telegram/Td.h" #include "td/telegram/Td.h"
#include "td/telegram/telegram_api.h" #include "td/telegram/telegram_api.h"
@ -169,7 +169,7 @@ td_api::object_ptr<td_api::sponsoredMessage> SponsoredMessageManager::get_sponso
case DialogType::Channel: case DialogType::Channel:
if (sponsored_message.server_message_id.is_valid()) { if (sponsored_message.server_message_id.is_valid()) {
auto channel_id = sponsored_message.sponsor_dialog_id.get_channel_id(); 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<td_api::internalLinkTypeMessage>( link = td_api::make_object<td_api::internalLinkTypeMessage>(
PSTRING() << t_me << "c/" << channel_id.get() << '/' << sponsored_message.server_message_id.get()); PSTRING() << t_me << "c/" << channel_id.get() << '/' << sponsored_message.server_message_id.get());
} }

View File

@ -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) { 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) { switch (sticker_format) {
case StickerFormat::Unknown: case StickerFormat::Unknown:
case StickerFormat::Webp: 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: case StickerFormat::Tgs:
return for_thumbnail ? (1 << 15) : (1 << 16); return for_thumbnail ? (1 << 15) : (1 << 16);
case StickerFormat::Webm: 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: default:
UNREACHABLE(); UNREACHABLE();
return 0; return 0;

View File

@ -10,7 +10,6 @@
#include "td/telegram/AuthManager.h" #include "td/telegram/AuthManager.h"
#include "td/telegram/AvailableReaction.h" #include "td/telegram/AvailableReaction.h"
#include "td/telegram/ConfigManager.h" #include "td/telegram/ConfigManager.h"
#include "td/telegram/ConfigShared.h"
#include "td/telegram/ContactsManager.h" #include "td/telegram/ContactsManager.h"
#include "td/telegram/DialogId.h" #include "td/telegram/DialogId.h"
#include "td/telegram/Document.h" #include "td/telegram/Document.h"
@ -28,6 +27,7 @@
#include "td/telegram/net/DcId.h" #include "td/telegram/net/DcId.h"
#include "td/telegram/net/MtprotoHeader.h" #include "td/telegram/net/MtprotoHeader.h"
#include "td/telegram/net/NetQueryDispatcher.h" #include "td/telegram/net/NetQueryDispatcher.h"
#include "td/telegram/OptionManager.h"
#include "td/telegram/PhotoSizeSource.h" #include "td/telegram/PhotoSizeSource.h"
#include "td/telegram/secret_api.h" #include "td/telegram/secret_api.h"
#include "td/telegram/SecretChatLayer.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<UploadStickerFileCallback>(); upload_sticker_file_callback_ = std::make_shared<UploadStickerFileCallback>();
on_update_animated_emoji_zoom(); on_update_animated_emoji_zoom();
on_update_recent_stickers_limit();
on_update_recent_stickers_limit( on_update_favorite_stickers_limit();
narrow_cast<int32>(G()->shared_config().get_option_integer("recent_stickers_limit", 200)));
on_update_favorite_stickers_limit(
narrow_cast<int32>(G()->shared_config().get_option_integer("favorite_stickers_limit", 5)));
next_click_animated_emoji_message_time_ = Time::now(); next_click_animated_emoji_message_time_ = Time::now();
next_update_animated_emoji_clicked_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); load_special_sticker_set_info_from_binlog(sticker_set);
dice_emojis_str_ = 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'); dice_emojis_ = full_split(dice_emojis_str_, '\x01');
for (auto &dice_emoji : dice_emojis_) { for (auto &dice_emoji : dice_emojis_) {
auto &animated_dice_sticker_set = add_special_sticker_set(SpecialStickerSetType::animated_dice(dice_emoji)); 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); send_closure_later(actor_id(this), &StickersManager::load_reactions);
on_update_dice_success_values(); on_update_dice_success_values();
on_update_dice_emojis();
on_update_emoji_sounds(); on_update_emoji_sounds();
@ -1474,8 +1472,8 @@ void StickersManager::init() {
} }
G()->td_db()->get_binlog_pmc()->erase("animated_dice_sticker_set"); // legacy G()->td_db()->get_binlog_pmc()->erase("animated_dice_sticker_set"); // legacy
G()->shared_config().set_option_empty("animated_dice_sticker_set_name"); // legacy td_->option_manager_->set_option_empty("animated_dice_sticker_set_name"); // legacy
G()->shared_config().set_option_empty("animated_emoji_sticker_set_name"); // legacy td_->option_manager_->set_option_empty("animated_emoji_sticker_set_name"); // legacy
} }
void StickersManager::reload_reactions() { void StickersManager::reload_reactions() {
@ -1690,9 +1688,7 @@ void StickersManager::on_load_special_sticker_set(const SpecialStickerSetType &t
} }
vector<FullMessageId> full_message_ids; vector<FullMessageId> full_message_ids;
for (const auto &full_message_id : it->second) { it->second.foreach([&](const FullMessageId &full_message_id) { full_message_ids.push_back(full_message_id); });
full_message_ids.push_back(full_message_id);
}
CHECK(!full_message_ids.empty()); CHECK(!full_message_ids.empty());
for (const auto &full_message_id : full_message_ids) { for (const auto &full_message_id : full_message_ids) {
td_->messages_manager_->on_external_update_message_content(full_message_id); td_->messages_manager_->on_external_update_message_content(full_message_id);
@ -2234,7 +2230,7 @@ tl_object_ptr<td_api::stickerSetInfo> StickersManager::get_sticker_set_info_obje
vector<FileId> regular_sticker_ids; vector<FileId> regular_sticker_ids;
vector<FileId> premium_sticker_ids; vector<FileId> premium_sticker_ids;
std::tie(regular_sticker_ids, premium_sticker_ids) = split_stickers_by_premium(sticker_set); 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; size_t max_premium_stickers = is_premium ? covers_limit : 1;
if (premium_sticker_ids.size() > max_premium_stickers) { if (premium_sticker_ids.size() > max_premium_stickers) {
premium_sticker_ids.resize(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<td_api::animatedEmoji> StickersManager::get_animated_emoji_object(const string &emoji, td_api::object_ptr<td_api::animatedEmoji> StickersManager::get_animated_emoji_object(const string &emoji,
int64 custom_emoji_id) { int64 custom_emoji_id) {
if (disable_animated_emojis_) { if (td_->auth_manager_->is_bot() || disable_animated_emojis_) {
return nullptr; return nullptr;
} }
@ -4114,8 +4110,8 @@ vector<FileId> StickersManager::get_stickers(StickerType sticker_type, string em
vector<FileId> regular_sticker_ids; vector<FileId> regular_sticker_ids;
vector<FileId> premium_sticker_ids; vector<FileId> premium_sticker_ids;
std::tie(regular_sticker_ids, premium_sticker_ids) = split_stickers_by_premium(result); std::tie(regular_sticker_ids, premium_sticker_ids) = split_stickers_by_premium(result);
if (G()->shared_config().get_option_boolean("is_premium") || allow_premium) { if (td_->option_manager_->get_option_boolean("is_premium") || allow_premium) {
auto normal_count = G()->shared_config().get_option_integer("stickers_normal_by_emoji_per_premium_num", 2); auto normal_count = td_->option_manager_->get_option_integer("stickers_normal_by_emoji_per_premium_num", 2);
if (normal_count < 0) { if (normal_count < 0) {
normal_count = 2; normal_count = 2;
} }
@ -4150,7 +4146,7 @@ vector<FileId> StickersManager::get_stickers(StickerType sticker_type, string em
} }
} }
if (sorted.size() < limit_size_t) { 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) { if (premium_count > 0) {
for (const auto &sticker_id : premium_sticker_ids) { for (const auto &sticker_id : premium_sticker_ids) {
LOG(INFO) << "Add premium sticker " << sticker_id << " from installed sticker set"; LOG(INFO) << "Add premium sticker " << sticker_id << " from installed sticker set";
@ -5014,7 +5010,7 @@ void StickersManager::on_update_dice_emojis() {
return; return;
} }
if (td_->auth_manager_->is_bot()) { if (td_->auth_manager_->is_bot()) {
G()->shared_config().set_option_empty("dice_emojis"); td_->option_manager_->set_option_empty("dice_emojis");
return; return;
} }
if (!is_inited_) { if (!is_inited_) {
@ -5022,7 +5018,7 @@ void StickersManager::on_update_dice_emojis() {
} }
auto dice_emojis_str = 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_) { if (dice_emojis_str == dice_emojis_str_) {
return; return;
} }
@ -5054,7 +5050,7 @@ void StickersManager::on_update_dice_success_values() {
return; return;
} }
if (td_->auth_manager_->is_bot()) { 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; return;
} }
if (!is_inited_) { if (!is_inited_) {
@ -5062,7 +5058,7 @@ void StickersManager::on_update_dice_success_values() {
} }
auto dice_success_values_str = 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_) { if (dice_success_values_str == dice_success_values_str_) {
return; return;
} }
@ -5080,7 +5076,7 @@ void StickersManager::on_update_emoji_sounds() {
return; 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_) { if (emoji_sounds_str == emoji_sounds_str_) {
return; return;
} }
@ -5127,7 +5123,7 @@ void StickersManager::on_update_disable_animated_emojis() {
return; 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_) { if (disable_animated_emojis == disable_animated_emojis_) {
return; 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_)) { (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->animated_emoji_sticker_ = new_animated_sticker;
it.second->sound_file_id_ = new_sound_file_id; it.second->sound_file_id_ = new_sound_file_id;
for (const auto &full_message_id : it.second->full_message_ids_) { it.second->full_message_ids_.foreach(
full_message_ids.push_back(full_message_id); [&](const FullMessageId &full_message_id) { full_message_ids.push_back(full_message_id); });
}
} }
} }
for (const auto &full_message_id : full_message_ids) { 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); auto new_sticker_id = get_custom_animated_emoji_sticker_id(custom_emoji_id);
if (new_sticker_id != it->second->sticker_id_) { if (new_sticker_id != it->second->sticker_id_) {
it->second->sticker_id_ = new_sticker_id; it->second->sticker_id_ = new_sticker_id;
for (const auto &full_message_id : it->second->full_message_ids_) { it->second->full_message_ids_.foreach(
full_message_ids.push_back(full_message_id); [&](const FullMessageId &full_message_id) { full_message_ids.push_back(full_message_id); });
}
} }
for (const auto &full_message_id : full_message_ids) { for (const auto &full_message_id : full_message_ids) {
td_->messages_manager_->on_external_update_message_content(full_message_id); 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 " LOG(INFO) << "Register dice " << emoji << " with value " << value << " from " << full_message_id << " from "
<< source; << source;
bool is_inserted = dice_messages_[emoji].insert(full_message_id).second; dice_messages_[emoji].insert(full_message_id);
LOG_CHECK(is_inserted) << source << " " << emoji << " " << value << " " << full_message_id;
if (!td::contains(dice_emojis_, emoji)) { if (!td::contains(dice_emojis_, emoji)) {
if (full_message_id.get_message_id().is_any_server() && 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<td_api::object_ptr<td_api::stickers>>()); get_custom_emoji_stickers({custom_emoji_id}, true, Promise<td_api::object_ptr<td_api::stickers>>());
} }
} }
bool is_inserted = emoji_messages.full_message_ids_.insert(full_message_id).second; emoji_messages.full_message_ids_.insert(full_message_id);
LOG_CHECK(is_inserted) << source << ' ' << custom_emoji_id << ' ' << full_message_id;
return; 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.animated_emoji_sticker_ = get_animated_emoji_sticker(emoji);
emoji_messages.sound_file_id_ = get_animated_emoji_sound_file_id(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; emoji_messages.full_message_ids_.insert(full_message_id);
LOG_CHECK(is_inserted) << source << ' ' << emoji << ' ' << full_message_id;
} }
void StickersManager::unregister_emoji(const string &emoji, int64 custom_emoji_id, FullMessageId 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() { void StickersManager::on_update_animated_emoji_zoom() {
animated_emoji_zoom_ = animated_emoji_zoom_ =
static_cast<double>(G()->shared_config().get_option_integer("animated_emoji_zoom", 625000000)) * 1e-9; static_cast<double>(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<int32>(td_->option_manager_->get_option_integer("recent_stickers_limit", 200));
if (recent_stickers_limit != recent_stickers_limit_) { if (recent_stickers_limit != recent_stickers_limit_) {
if (recent_stickers_limit > 0) { if (recent_stickers_limit > 0) {
LOG(INFO) << "Update recent stickers limit to " << recent_stickers_limit; 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<int32>(td_->option_manager_->get_option_integer("favorite_stickers_limit", 5));
if (favorite_stickers_limit != favorite_stickers_limit_) { if (favorite_stickers_limit != favorite_stickers_limit_) {
if (favorite_stickers_limit > 0) { if (favorite_stickers_limit > 0) {
LOG(INFO) << "Update favorite stickers limit to " << favorite_stickers_limit; LOG(INFO) << "Update favorite stickers limit to " << favorite_stickers_limit;
@ -8458,7 +8453,7 @@ vector<string> StickersManager::get_emoji_language_codes(const vector<string> &i
} }
if (!text.empty()) { if (!text.empty()) {
uint32 code = 0; 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) { if ((0x410 <= code && code <= 0x44F) || code == 0x401 || code == 0x451) {
// the first letter is cyrillic // the first letter is cyrillic
if (!td::contains(language_codes, "ru") && !td::contains(language_codes, "uk") && if (!td::contains(language_codes, "ru") && !td::contains(language_codes, "uk") &&

View File

@ -34,6 +34,7 @@
#include "td/utils/Slice.h" #include "td/utils/Slice.h"
#include "td/utils/Status.h" #include "td/utils/Status.h"
#include "td/utils/WaitFreeHashMap.h" #include "td/utils/WaitFreeHashMap.h"
#include "td/utils/WaitFreeHashSet.h"
#include <memory> #include <memory>
#include <tuple> #include <tuple>
@ -281,9 +282,9 @@ class StickersManager final : public Actor {
void clear_recent_stickers(bool is_attached, Promise<Unit> &&promise); void clear_recent_stickers(bool is_attached, Promise<Unit> &&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); void reload_favorite_stickers(bool force);
@ -1004,17 +1005,17 @@ class StickersManager final : public Actor {
}; };
FlatHashMap<int32, unique_ptr<GiftPremiumMessages>> premium_gift_messages_; FlatHashMap<int32, unique_ptr<GiftPremiumMessages>> premium_gift_messages_;
FlatHashMap<string, FlatHashSet<FullMessageId, FullMessageIdHash>> dice_messages_; FlatHashMap<string, WaitFreeHashSet<FullMessageId, FullMessageIdHash>> dice_messages_;
struct EmojiMessages { struct EmojiMessages {
FlatHashSet<FullMessageId, FullMessageIdHash> full_message_ids_; WaitFreeHashSet<FullMessageId, FullMessageIdHash> full_message_ids_;
std::pair<FileId, int> animated_emoji_sticker_; std::pair<FileId, int> animated_emoji_sticker_;
FileId sound_file_id_; FileId sound_file_id_;
}; };
FlatHashMap<string, unique_ptr<EmojiMessages>> emoji_messages_; FlatHashMap<string, unique_ptr<EmojiMessages>> emoji_messages_;
struct CustomEmojiMessages { struct CustomEmojiMessages {
FlatHashSet<FullMessageId, FullMessageIdHash> full_message_ids_; WaitFreeHashSet<FullMessageId, FullMessageIdHash> full_message_ids_;
FileId sticker_id_; FileId sticker_id_;
}; };
FlatHashMap<int64, unique_ptr<CustomEmojiMessages>> custom_emoji_messages_; FlatHashMap<int64, unique_ptr<CustomEmojiMessages>> custom_emoji_messages_;

View File

@ -6,7 +6,6 @@
// //
#include "td/telegram/StorageManager.h" #include "td/telegram/StorageManager.h"
#include "td/telegram/ConfigShared.h"
#include "td/telegram/DialogId.h" #include "td/telegram/DialogId.h"
#include "td/telegram/files/FileGcWorker.h" #include "td/telegram/files/FileGcWorker.h"
#include "td/telegram/files/FileStatsWorker.h" #include "td/telegram/files/FileStatsWorker.h"
@ -188,7 +187,7 @@ int64 StorageManager::get_database_size() {
int64 StorageManager::get_language_pack_database_size() { int64 StorageManager::get_language_pack_database_size() {
int64 size = 0; 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()) { if (!path.empty()) {
SqliteDb::with_db_path(path, [&size](CSlice path) { size += get_file_size(path); }); 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() { void StorageManager::schedule_next_gc() {
if (!G()->shared_config().get_option_boolean("use_storage_optimizer") && if (!G()->get_option_boolean("use_storage_optimizer") && !G()->parameters().enable_storage_optimizer) {
!G()->parameters().enable_storage_optimizer) {
next_gc_at_ = 0; next_gc_at_ = 0;
cancel_timeout(); cancel_timeout();
LOG(INFO) << "No next file clean up is scheduled"; LOG(INFO) << "No next file clean up is scheduled";

View File

@ -8,7 +8,6 @@
#include "td/telegram/ChannelId.h" #include "td/telegram/ChannelId.h"
#include "td/telegram/ConfigManager.h" #include "td/telegram/ConfigManager.h"
#include "td/telegram/ConfigShared.h"
#include "td/telegram/ContactsManager.h" #include "td/telegram/ContactsManager.h"
#include "td/telegram/Global.h" #include "td/telegram/Global.h"
#include "td/telegram/Td.h" #include "td/telegram/Td.h"
@ -181,11 +180,11 @@ void dismiss_suggested_action(SuggestedAction action, Promise<Unit> &&promise) {
if (action.otherwise_relogin_days_ <= 0) { if (action.otherwise_relogin_days_ <= 0) {
return promise.set_error(Status::Error(400, "Invalid authorization_delay specified")); return promise.set_error(Status::Error(400, "Invalid authorization_delay specified"));
} }
auto days = narrow_cast<int32>(G()->shared_config().get_option_integer("otherwise_relogin_days")); auto days = narrow_cast<int32>(G()->get_option_integer("otherwise_relogin_days"));
if (days == action.otherwise_relogin_days_) { if (days == action.otherwise_relogin_days_) {
vector<SuggestedAction> removed_actions{SuggestedAction{SuggestedAction::Type::SetPassword, DialogId(), days}}; vector<SuggestedAction> removed_actions{SuggestedAction{SuggestedAction::Type::SetPassword, DialogId(), days}};
send_closure(G()->td(), &Td::send_update, get_update_suggested_actions_object({}, removed_actions)); 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()); return promise.set_value(Unit());
} }

111
td/telegram/Support.cpp Normal file
View File

@ -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<td_api::userSupportInfo> get_user_support_info_object(
Td *td, telegram_api::object_ptr<telegram_api::help_UserInfo> user_info) {
CHECK(user_info != nullptr);
auto result = td_api::make_object<td_api::userSupportInfo>();
FormattedText message;
if (user_info->get_id() == telegram_api::help_userInfo::ID) {
auto info = telegram_api::move_object_as<telegram_api::help_userInfo>(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<td_api::object_ptr<td_api::userSupportInfo>> promise_;
public:
explicit GetUserInfoQuery(Promise<td_api::object_ptr<td_api::userSupportInfo>> &&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<telegram_api::help_getUserInfo>(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<td_api::object_ptr<td_api::userSupportInfo>> promise_;
public:
explicit EditUserInfoQuery(Promise<td_api::object_ptr<td_api::userSupportInfo>> &&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<telegram_api::help_editUserInfo>(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<td_api::object_ptr<td_api::userSupportInfo>> &&promise) {
td->create_handler<GetUserInfoQuery>(std::move(promise))->send(user_id);
}
void set_user_info(Td *td, UserId user_id, td_api::object_ptr<td_api::formattedText> &&message,
Promise<td_api::object_ptr<td_api::userSupportInfo>> &&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<EditUserInfoQuery>(std::move(promise))->send(user_id, std::move(formatted_text));
}
} // namespace td

24
td/telegram/Support.h Normal file
View File

@ -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<td_api::object_ptr<td_api::userSupportInfo>> &&promise);
void set_user_info(Td *td, UserId user_id, td_api::object_ptr<td_api::formattedText> &&message,
Promise<td_api::object_ptr<td_api::userSupportInfo>> &&promise);
} // namespace td

View File

@ -25,7 +25,6 @@
#include "td/telegram/ChannelType.h" #include "td/telegram/ChannelType.h"
#include "td/telegram/ChatId.h" #include "td/telegram/ChatId.h"
#include "td/telegram/ConfigManager.h" #include "td/telegram/ConfigManager.h"
#include "td/telegram/ConfigShared.h"
#include "td/telegram/ContactsManager.h" #include "td/telegram/ContactsManager.h"
#include "td/telegram/CountryInfoManager.h" #include "td/telegram/CountryInfoManager.h"
#include "td/telegram/DeviceTokenManager.h" #include "td/telegram/DeviceTokenManager.h"
@ -112,6 +111,7 @@
#include "td/telegram/StorageManager.h" #include "td/telegram/StorageManager.h"
#include "td/telegram/MemoryManager.h" #include "td/telegram/MemoryManager.h"
#include "td/telegram/SuggestedAction.h" #include "td/telegram/SuggestedAction.h"
#include "td/telegram/Support.h"
#include "td/telegram/td_api.hpp" #include "td/telegram/td_api.hpp"
#include "td/telegram/TdDb.h" #include "td/telegram/TdDb.h"
#include "td/telegram/telegram_api.hpp" #include "td/telegram/telegram_api.hpp"
@ -2646,8 +2646,7 @@ void Td::on_online_updated(bool force, bool send_update) {
} }
if (is_online_) { if (is_online_) {
alarm_timeout_.set_timeout_in( alarm_timeout_.set_timeout_in(
ONLINE_ALARM_ID, ONLINE_ALARM_ID, static_cast<double>(G()->get_option_integer("online_update_period_ms", 210000)) * 1e-3);
static_cast<double>(G()->shared_config().get_option_integer("online_update_period_ms", 210000)) * 1e-3);
} else { } else {
alarm_timeout_.cancel_timeout(ONLINE_ALARM_ID); 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) { 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; is_bot_online = false;
} }
@ -2946,12 +2945,12 @@ void Td::request(uint64 id, tl_object_ptr<td_api::Function> function) {
return; return;
} }
request_set_.insert(id);
if (function == nullptr) { 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); VLOG(td_requests) << "Receive request " << id << ": " << to_string(function);
request_set_.emplace(id, function->get_id());
if (is_synchronous_request(function.get())) { if (is_synchronous_request(function.get())) {
// send response synchronously // send response synchronously
return send_result(id, static_request(std::move(function))); return send_result(id, static_request(std::move(function)));
@ -3279,8 +3278,6 @@ void Td::dec_actor_refcnt() {
LOG(DEBUG) << "NotificationManager was cleared" << timer; LOG(DEBUG) << "NotificationManager was cleared" << timer;
notification_settings_manager_.reset(); notification_settings_manager_.reset();
LOG(DEBUG) << "NotificationSettingsManager was cleared" << timer; LOG(DEBUG) << "NotificationSettingsManager was cleared" << timer;
option_manager_.reset();
LOG(DEBUG) << "OptionManager was cleared" << timer;
poll_manager_.reset(); poll_manager_.reset();
LOG(DEBUG) << "PollManager was cleared" << timer; LOG(DEBUG) << "PollManager was cleared" << timer;
sponsored_message_manager_.reset(); sponsored_message_manager_.reset();
@ -3303,9 +3300,12 @@ void Td::dec_actor_refcnt() {
LOG(DEBUG) << "VoiceNotesManager was cleared" << timer; LOG(DEBUG) << "VoiceNotesManager was cleared" << timer;
web_pages_manager_.reset(); web_pages_manager_.reset();
LOG(DEBUG) << "WebPagesManager was cleared" << timer; 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_) { if (destroy_flag_) {
G()->close_and_destroy_all(std::move(promise)); G()->close_and_destroy_all(std::move(promise));
} else { } else {
@ -3370,7 +3370,7 @@ void Td::clear_requests() {
alarm_timeout_.cancel_timeout(alarm_id); alarm_timeout_.cancel_timeout(alarm_id);
} }
while (!request_set_.empty()) { while (!request_set_.empty()) {
uint64 id = *request_set_.begin(); uint64 id = request_set_.begin()->first;
if (destroy_flag_) { if (destroy_flag_) {
send_error_impl(id, make_error(401, "Unauthorized")); send_error_impl(id, make_error(401, "Unauthorized"));
} else { } else {
@ -3389,7 +3389,7 @@ void Td::clear() {
Timer timer; Timer timer;
if (destroy_flag_) { if (destroy_flag_) {
OptionManager::clear_options(); option_manager_->clear_options();
if (!auth_manager_->is_bot()) { if (!auth_manager_->is_bot()) {
notification_manager_->destroy_all_notifications(); notification_manager_->destroy_all_notifications();
} }
@ -3484,8 +3484,6 @@ void Td::clear() {
LOG(DEBUG) << "NotificationManager actor was cleared" << timer; LOG(DEBUG) << "NotificationManager actor was cleared" << timer;
notification_settings_manager_actor_.reset(); notification_settings_manager_actor_.reset();
LOG(DEBUG) << "NotificationSettingsManager actor was cleared" << timer; LOG(DEBUG) << "NotificationSettingsManager actor was cleared" << timer;
option_manager_actor_.reset();
LOG(DEBUG) << "OptionManager actor was cleared" << timer;
poll_manager_actor_.reset(); poll_manager_actor_.reset();
LOG(DEBUG) << "PollManager actor was cleared" << timer; LOG(DEBUG) << "PollManager actor was cleared" << timer;
sponsored_message_manager_actor_.reset(); sponsored_message_manager_actor_.reset();
@ -3664,6 +3662,9 @@ void Td::init(Result<TdDb::OpenedDatabase> r_opened_database) {
init_options_and_network(); 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) { complete_pending_preauthentication_requests([](int32 id) {
switch (id) { switch (id) {
case td_api::getOption::ID: case td_api::getOption::ID:
@ -3674,15 +3675,14 @@ void Td::init(Result<TdDb::OpenedDatabase> r_opened_database) {
} }
}); });
options_.language_pack = G()->shared_config().get_option_string("localization_target"); options_.language_pack = G()->get_option_string("localization_target");
options_.language_code = G()->shared_config().get_option_string("language_pack_id"); options_.language_code = G()->get_option_string("language_pack_id");
options_.parameters = G()->shared_config().get_option_string("connection_parameters"); options_.parameters = G()->get_option_string("connection_parameters");
options_.tz_offset = static_cast<int32>(G()->shared_config().get_option_integer("utc_time_offset")); options_.tz_offset = static_cast<int32>(G()->get_option_integer("utc_time_offset"));
options_.is_emulator = G()->shared_config().get_option_boolean("is_emulator"); options_.is_emulator = G()->get_option_boolean("is_emulator");
// options_.proxy = Proxy(); // options_.proxy = Proxy();
G()->set_mtproto_header(make_unique<MtprotoHeader>(options_)); G()->set_mtproto_header(make_unique<MtprotoHeader>(options_));
G()->set_store_all_files_in_files_directory( G()->set_store_all_files_in_files_directory(G()->get_option_boolean("store_all_files_in_files_directory"));
G()->shared_config().get_option_boolean("store_all_files_in_files_directory"));
VLOG(td_init) << "Create NetQueryDispatcher"; VLOG(td_init) << "Create NetQueryDispatcher";
auto net_query_dispatcher = make_unique<NetQueryDispatcher>([&] { return create_reference(); }); auto net_query_dispatcher = make_unique<NetQueryDispatcher>([&] { return create_reference(); });
@ -3696,16 +3696,17 @@ void Td::init(Result<TdDb::OpenedDatabase> r_opened_database) {
VLOG(td_init) << "Create AuthManager"; VLOG(td_init) << "Create AuthManager";
auth_manager_ = td::make_unique<AuthManager>(parameters_.api_id, parameters_.api_hash, create_reference()); auth_manager_ = td::make_unique<AuthManager>(parameters_.api_id, parameters_.api_hash, create_reference());
auth_manager_actor_ = register_actor("AuthManager", auth_manager_.get()); auth_manager_actor_ = register_actor("AuthManager", auth_manager_.get());
G()->set_auth_manager(auth_manager_actor_.get());
init_file_manager(); init_file_manager();
init_managers(); init_managers();
G()->set_my_id(G()->shared_config().get_option_integer("my_id"));
storage_manager_ = create_actor<StorageManager>("StorageManager", create_reference(), G()->get_gc_scheduler_id()); storage_manager_ = create_actor<StorageManager>("StorageManager", create_reference(), G()->get_gc_scheduler_id());
G()->set_storage_manager(storage_manager_.get()); G()->set_storage_manager(storage_manager_.get());
option_manager_->on_td_inited();
VLOG(td_init) << "Send binlog events"; VLOG(td_init) << "Send binlog events";
for (auto &event : events.user_events) { for (auto &event : events.user_events) {
contacts_manager_->on_binlog_user_event(std::move(event)); contacts_manager_->on_binlog_user_event(std::move(event));
@ -3732,6 +3733,10 @@ void Td::init(Result<TdDb::OpenedDatabase> r_opened_database) {
on_save_app_log_binlog_event(this, std::move(event)); 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_) { if (is_online_) {
on_online_updated(true, true); on_online_updated(true, true);
} }
@ -3826,8 +3831,9 @@ void Td::init_options_and_network() {
send_closure(state_manager_, &StateManager::add_callback, make_unique<StateManagerCallback>(create_reference())); send_closure(state_manager_, &StateManager::add_callback, make_unique<StateManagerCallback>(create_reference()));
G()->set_state_manager(state_manager_.get()); G()->set_state_manager(state_manager_.get());
VLOG(td_init) << "Create ConfigShared"; VLOG(td_init) << "Create OptionManager";
G()->set_shared_config(td::make_unique<ConfigShared>(G()->td_db()->get_config_pmc_shared())); option_manager_ = make_unique<OptionManager>(this);
G()->set_option_manager(option_manager_.get());
init_connection_creator(); init_connection_creator();
@ -3838,30 +3844,6 @@ void Td::init_options_and_network() {
VLOG(td_init) << "Create ConfigManager"; VLOG(td_init) << "Create ConfigManager";
config_manager_ = create_actor<ConfigManager>("ConfigManager", create_reference()); config_manager_ = create_actor<ConfigManager>("ConfigManager", create_reference());
G()->set_config_manager(config_manager_.get()); G()->set_config_manager(config_manager_.get());
VLOG(td_init) << "Create OptionManager";
option_manager_ = make_unique<OptionManager>(this, create_reference());
option_manager_actor_ = register_actor("OptionManager", option_manager_.get());
G()->set_option_manager(option_manager_actor_.get());
VLOG(td_init) << "Set ConfigShared callback";
class ConfigSharedCallback final : public ConfigShared::Callback {
public:
void on_option_updated(const string &name, const string &value) const final {
send_closure_later(G()->option_manager(), &OptionManager::on_option_updated, name);
}
~ConfigSharedCallback() final {
LOG(INFO) << "Destroy ConfigSharedCallback";
}
};
// we need to set ConfigShared callback before td_api::getOption requests are processed for consistency
// TODO currently they will be inconsistent anyway, because td_api::getOption returns current value,
// but in td_api::updateOption there will be a newer value, obtained at the time of update creation
// so, there can be even two succesive updateOption with the same value
// we need to process td_api::getOption along with td_api::setOption for consistency
// we need to process td_api::setOption before managers and MTProto header are created,
// because their initialiation may be affected by the options
G()->shared_config().set_callback(make_unique<ConfigSharedCallback>());
} }
void Td::init_connection_creator() { void Td::init_connection_creator() {
@ -4112,11 +4094,11 @@ void Td::send_result(uint64 id, tl_object_ptr<td_api::Object> object) {
auto it = request_set_.find(id); auto it = request_set_.find(id);
if (it != request_set_.end()) { if (it != request_set_.end()) {
request_set_.erase(it);
VLOG(td_requests) << "Sending result for request " << id << ": " << to_string(object);
if (object == nullptr) { if (object == nullptr) {
object = make_tl_object<td_api::error>(404, "Not Found"); object = make_tl_object<td_api::error>(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)); callback_->on_result(id, std::move(object));
} }
} }
@ -4126,11 +4108,11 @@ void Td::send_error_impl(uint64 id, tl_object_ptr<td_api::error> error) {
CHECK(error != nullptr); CHECK(error != nullptr);
auto it = request_set_.find(id); auto it = request_set_.find(id);
if (it != request_set_.end()) { 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") { 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)); 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) { 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"); return send_error_raw(id, 400, "Persistent network statistics is disabled");
} }
CREATE_REQUEST_PROMISE(); 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())); promise.set_value(MessagesManager::get_chats_object(-1, result.ok()));
} }
}); });
top_dialog_manager_->get_top_dialogs(get_top_dialog_category(request.category_), request.limit_, send_closure(top_dialog_manager_actor_, &TopDialogManager::get_top_dialogs,
std::move(query_promise)); get_top_dialog_category(request.category_), request.limit_, std::move(query_promise));
} }
void Td::on_request(uint64 id, const td_api::removeTopChat &request) { void Td::on_request(uint64 id, const td_api::removeTopChat &request) {
CHECK_IS_USER(); CHECK_IS_USER();
CREATE_OK_REQUEST_PROMISE(); CREATE_OK_REQUEST_PROMISE();
top_dialog_manager_->remove_dialog(get_top_dialog_category(request.category_), DialogId(request.chat_id_), send_closure(top_dialog_manager_actor_, &TopDialogManager::remove_dialog, get_top_dialog_category(request.category_),
std::move(promise)); DialogId(request.chat_id_), std::move(promise));
} }
void Td::on_request(uint64 id, const td_api::loadChats &request) { 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) { void Td::on_request(uint64 id, const td_api::removeNotification &request) {
CHECK_IS_USER(); CHECK_IS_USER();
CREATE_OK_REQUEST_PROMISE(); CREATE_OK_REQUEST_PROMISE();
notification_manager_->remove_notification(NotificationGroupId(request.notification_group_id_), send_closure(notification_manager_actor_, &NotificationManager::remove_notification,
NotificationId(request.notification_id_), false, true, std::move(promise), NotificationGroupId(request.notification_group_id_), NotificationId(request.notification_id_), false,
"td_api::removeNotification"); true, std::move(promise), "td_api::removeNotification");
} }
void Td::on_request(uint64 id, const td_api::removeNotificationGroup &request) { void Td::on_request(uint64 id, const td_api::removeNotificationGroup &request) {
CHECK_IS_USER(); CHECK_IS_USER();
CREATE_OK_REQUEST_PROMISE(); CREATE_OK_REQUEST_PROMISE();
notification_manager_->remove_notification_group(NotificationGroupId(request.notification_group_id_), send_closure(notification_manager_actor_, &NotificationManager::remove_notification_group,
NotificationId(request.max_notification_id_), MessageId(), -1, true, NotificationGroupId(request.notification_group_id_), NotificationId(request.max_notification_id_),
std::move(promise)); MessageId(), -1, true, std::move(promise));
} }
void Td::on_request(uint64 id, const td_api::deleteMessages &request) { 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()); 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"); 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)); 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) { void Td::on_request(uint64 id, const td_api::getTextEntities &request) {
UNREACHABLE(); UNREACHABLE();
} }

View File

@ -39,7 +39,7 @@
#include <malloc.h> #include <malloc.h>
#endif #endif
#include <memory> #include <memory>
#include <unordered_set> #include <unordered_map>
#include <utility> #include <utility>
namespace td { namespace td {
@ -140,6 +140,7 @@ class Td final : public Actor {
unique_ptr<AudiosManager> audios_manager_; unique_ptr<AudiosManager> audios_manager_;
unique_ptr<CallbackQueriesManager> callback_queries_manager_; unique_ptr<CallbackQueriesManager> callback_queries_manager_;
unique_ptr<DocumentsManager> documents_manager_; unique_ptr<DocumentsManager> documents_manager_;
unique_ptr<OptionManager> option_manager_;
unique_ptr<VideoNotesManager> video_notes_manager_; unique_ptr<VideoNotesManager> video_notes_manager_;
unique_ptr<VideosManager> videos_manager_; unique_ptr<VideosManager> videos_manager_;
@ -175,8 +176,6 @@ class Td final : public Actor {
ActorOwn<NotificationManager> notification_manager_actor_; ActorOwn<NotificationManager> notification_manager_actor_;
unique_ptr<NotificationSettingsManager> notification_settings_manager_; unique_ptr<NotificationSettingsManager> notification_settings_manager_;
ActorOwn<NotificationSettingsManager> notification_settings_manager_actor_; ActorOwn<NotificationSettingsManager> notification_settings_manager_actor_;
unique_ptr<OptionManager> option_manager_;
ActorOwn<OptionManager> option_manager_actor_;
unique_ptr<PollManager> poll_manager_; unique_ptr<PollManager> poll_manager_;
ActorOwn<PollManager> poll_manager_actor_; ActorOwn<PollManager> poll_manager_actor_;
unique_ptr<SponsoredMessageManager> sponsored_message_manager_; unique_ptr<SponsoredMessageManager> sponsored_message_manager_;
@ -294,7 +293,7 @@ class Td final : public Actor {
ConnectionState connection_state_ = ConnectionState::Empty; ConnectionState connection_state_ = ConnectionState::Empty;
std::unordered_multiset<uint64> request_set_; std::unordered_multimap<uint64, int32> request_set_;
int actor_refcnt_ = 0; int actor_refcnt_ = 0;
int request_actor_refcnt_ = 0; int request_actor_refcnt_ = 0;
int stop_cnt_ = 2; 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::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::getTextEntities &request);
void on_request(uint64 id, const td_api::parseTextEntities &request); void on_request(uint64 id, const td_api::parseTextEntities &request);

View File

@ -8,7 +8,6 @@
#include "td/telegram/AccessRights.h" #include "td/telegram/AccessRights.h"
#include "td/telegram/AuthManager.h" #include "td/telegram/AuthManager.h"
#include "td/telegram/ConfigShared.h"
#include "td/telegram/ContactsManager.h" #include "td/telegram/ContactsManager.h"
#include "td/telegram/DialogId.h" #include "td/telegram/DialogId.h"
#include "td/telegram/Global.h" #include "td/telegram/Global.h"
@ -296,7 +295,7 @@ void TopDialogManager::update_rating_e_decay() {
if (!is_active_) { if (!is_active_) {
return; return;
} }
rating_e_decay_ = narrow_cast<int32>(G()->shared_config().get_option_integer("rating_e_decay", rating_e_decay_)); rating_e_decay_ = narrow_cast<int32>(G()->get_option_integer("rating_e_decay", rating_e_decay_));
} }
template <class StorerT> template <class StorerT>
@ -463,11 +462,11 @@ void TopDialogManager::on_get_top_peers(Result<telegram_api::object_ptr<telegram
// nothing to do // nothing to do
break; break;
case telegram_api::contacts_topPeersDisabled::ID: case telegram_api::contacts_topPeersDisabled::ID:
G()->shared_config().set_option_boolean("disable_top_chats", true); G()->set_option_boolean("disable_top_chats", true);
set_is_enabled(false); // apply immediately set_is_enabled(false); // apply immediately
break; break;
case telegram_api::contacts_topPeers::ID: { 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 set_is_enabled(true); // apply immediately
auto top_peers = move_tl_object_as<telegram_api::contacts_topPeers>(std::move(top_peers_parent)); auto top_peers = move_tl_object_as<telegram_api::contacts_topPeers>(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_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(); update_rating_e_decay();
string need_update_top_peers = G()->td_db()->get_binlog_pmc()->get("top_peers_enabled"); string need_update_top_peers = G()->td_db()->get_binlog_pmc()->get("top_peers_enabled");

View File

@ -14,7 +14,6 @@
#include "td/telegram/ChannelId.h" #include "td/telegram/ChannelId.h"
#include "td/telegram/ChatId.h" #include "td/telegram/ChatId.h"
#include "td/telegram/ConfigManager.h" #include "td/telegram/ConfigManager.h"
#include "td/telegram/ConfigShared.h"
#include "td/telegram/ContactsManager.h" #include "td/telegram/ContactsManager.h"
#include "td/telegram/DialogAction.h" #include "td/telegram/DialogAction.h"
#include "td/telegram/DialogId.h" #include "td/telegram/DialogId.h"
@ -35,6 +34,7 @@
#include "td/telegram/NotificationManager.h" #include "td/telegram/NotificationManager.h"
#include "td/telegram/NotificationSettings.h" #include "td/telegram/NotificationSettings.h"
#include "td/telegram/NotificationSettingsManager.h" #include "td/telegram/NotificationSettingsManager.h"
#include "td/telegram/OptionManager.h"
#include "td/telegram/Payments.h" #include "td/telegram/Payments.h"
#include "td/telegram/PollId.h" #include "td/telegram/PollId.h"
#include "td/telegram/PollManager.h" #include "td/telegram/PollManager.h"
@ -1062,6 +1062,8 @@ void UpdatesManager::on_get_updates_state(tl_object_ptr<telegram_api::updates_st
if (get_pts() == std::numeric_limits<int32>::max()) { if (get_pts() == std::numeric_limits<int32>::max()) {
LOG(WARNING) << "Restore pts to " << state->pts_; LOG(WARNING) << "Restore pts to " << state->pts_;
// restoring right pts // restoring right pts
CHECK(pending_pts_updates_.empty());
process_postponed_pts_updates(); // drop all updates with old pts
pts_manager_.init(state->pts_); pts_manager_.init(state->pts_);
last_get_difference_pts_ = get_pts(); last_get_difference_pts_ = get_pts();
last_pts_save_time_ = Time::now() - 2 * MAX_PTS_SAVE_DELAY; last_pts_save_time_ = Time::now() - 2 * MAX_PTS_SAVE_DELAY;
@ -1553,7 +1555,7 @@ void UpdatesManager::on_get_difference(tl_object_ptr<telegram_api::updates_Diffe
break; break;
} }
case telegram_api::updates_differenceTooLong::ID: { case telegram_api::updates_differenceTooLong::ID: {
if (G()->shared_config().get_option_integer("session_count") <= 1) { if (td_->option_manager_->get_option_integer("session_count") <= 1) {
LOG(ERROR) << "Receive differenceTooLong"; LOG(ERROR) << "Receive differenceTooLong";
} }
// TODO // TODO
@ -2261,8 +2263,8 @@ void UpdatesManager::add_pending_pts_update(tl_object_ptr<telegram_api::Update>
if (old_pts > new_pts - pts_count) { if (old_pts > new_pts - pts_count) {
LOG(WARNING) << "Have old_pts (= " << old_pts << ") + pts_count (= " << pts_count << ") > new_pts (= " << new_pts 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 " << "). Logged in " << td_->option_manager_->get_option_integer("authorization_date")
<< source << " = " << oneline(to_string(update)); << ". Update from " << source << " = " << oneline(to_string(update));
postpone_pts_update(std::move(update), new_pts, pts_count, receive_time, std::move(promise)); postpone_pts_update(std::move(update), new_pts, pts_count, receive_time, std::move(promise));
set_pts_gap_timeout(0.001); set_pts_gap_timeout(0.001);
return; return;
@ -2277,8 +2279,8 @@ void UpdatesManager::add_pending_pts_update(tl_object_ptr<telegram_api::Update>
LOG(WARNING) << "Have old_pts (= " << old_pts << ") + accumulated_pts_count (= " << accumulated_pts_count_ LOG(WARNING) << "Have old_pts (= " << old_pts << ") + accumulated_pts_count (= " << accumulated_pts_count_
<< ") > accumulated_pts (= " << accumulated_pts_ << "). new_pts = " << new_pts << ") > accumulated_pts (= " << accumulated_pts_ << "). new_pts = " << new_pts
<< ", pts_count = " << pts_count << ". Logged in " << ", pts_count = " << pts_count << ". Logged in "
<< G()->shared_config().get_option_integer("authorization_date") << ". Update from " << source << " = " << td_->option_manager_->get_option_integer("authorization_date") << ". Update from " << source
<< oneline(to_string(update)); << " = " << oneline(to_string(update));
postpone_pts_update(std::move(update), new_pts, pts_count, receive_time, std::move(promise)); postpone_pts_update(std::move(update), new_pts, pts_count, receive_time, std::move(promise));
set_pts_gap_timeout(0.001); set_pts_gap_timeout(0.001);
return; return;
@ -2441,6 +2443,7 @@ void UpdatesManager::process_postponed_pts_updates() {
return; return;
} }
auto begin_time = Time::now();
auto initial_pts = get_pts(); auto initial_pts = get_pts();
auto old_pts = initial_pts; auto old_pts = initial_pts;
int32 skipped_update_count = 0; int32 skipped_update_count = 0;
@ -2505,6 +2508,14 @@ void UpdatesManager::process_postponed_pts_updates() {
<< skipped_update_count << ", applying " << applied_update_count << " and keeping " << skipped_update_count << ", applying " << applied_update_count << " and keeping "
<< postponed_pts_updates_.size() << " postponed updates"; << 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() { void UpdatesManager::process_pending_pts_updates() {

View File

@ -8,12 +8,15 @@
#include "td/telegram/AuthManager.h" #include "td/telegram/AuthManager.h"
#include "td/telegram/files/FileManager.h" #include "td/telegram/files/FileManager.h"
#include "td/telegram/Global.h"
#include "td/telegram/PhotoFormat.h" #include "td/telegram/PhotoFormat.h"
#include "td/telegram/secret_api.h" #include "td/telegram/secret_api.h"
#include "td/telegram/Td.h" #include "td/telegram/Td.h"
#include "td/telegram/td_api.h" #include "td/telegram/td_api.h"
#include "td/telegram/telegram_api.h" #include "td/telegram/telegram_api.h"
#include "td/actor/actor.h"
#include "td/telegram/ConfigShared.h" #include "td/telegram/ConfigShared.h"
#include "td/utils/logging.h" #include "td/utils/logging.h"
#include "td/utils/Status.h" #include "td/utils/Status.h"

View File

@ -8,6 +8,7 @@
#include "td/telegram/AuthManager.h" #include "td/telegram/AuthManager.h"
#include "td/telegram/files/FileManager.h" #include "td/telegram/files/FileManager.h"
#include "td/telegram/Global.h"
#include "td/telegram/PhotoFormat.h" #include "td/telegram/PhotoFormat.h"
#include "td/telegram/secret_api.h" #include "td/telegram/secret_api.h"
#include "td/telegram/Td.h" #include "td/telegram/Td.h"
@ -15,6 +16,8 @@
#include "td/telegram/telegram_api.h" #include "td/telegram/telegram_api.h"
#include "td/telegram/ConfigShared.h" #include "td/telegram/ConfigShared.h"
#include "td/actor/actor.h"
#include "td/utils/logging.h" #include "td/utils/logging.h"
#include "td/utils/misc.h" #include "td/utils/misc.h"
#include "td/utils/Status.h" #include "td/utils/Status.h"

View File

@ -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<td_api::formattedText> &&text, Promise<Unit> &&promise) { int64 WebPagesManager::get_web_page_preview(td_api::object_ptr<td_api::formattedText> &&text, Promise<Unit> &&promise) {
if (text == nullptr) { auto r_formatted_text = get_formatted_text(td_, DialogId(), std::move(text), false, true, true, true);
promise.set_value(Unit()); if (r_formatted_text.is_error()) {
promise.set_error(r_formatted_text.move_as_error());
return 0; 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_)); auto url = get_first_url(formatted_text);
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);
if (url.empty()) { if (url.empty()) {
promise.set_value(Unit()); promise.set_value(Unit());
return 0; 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_++; int64 request_id = get_web_page_preview_request_id_++;
auto web_page_id = get_web_page_by_url(url); auto web_page_id = get_web_page_by_url(url);
@ -829,7 +818,9 @@ int64 WebPagesManager::get_web_page_preview(td_api::object_ptr<td_api::formatted
promise.set_value(Unit()); promise.set_value(Unit());
} else { } else {
td_->create_handler<GetWebPagePreviewQuery>(std::move(promise)) td_->create_handler<GetWebPagePreviewQuery>(std::move(promise))
->send(text->text_, get_input_message_entities(td_->contacts_manager_.get(), entities, "get_web_page_preview"), ->send(
formatted_text.text,
get_input_message_entities(td_->contacts_manager_.get(), formatted_text.entities, "get_web_page_preview"),
request_id, std::move(url)); request_id, std::move(url));
} }
return request_id; return request_id;

View File

@ -1127,6 +1127,12 @@ class CliClient final : public Actor {
send_request(td_api::make_object<td_api::getTextEntities>( send_request(td_api::make_object<td_api::getTextEntities>(
"@telegram /test_command https://telegram.org telegram.me @gif @test")); "@telegram /test_command https://telegram.org telegram.me @gif @test"));
send_request(
td_api::make_object<td_api::setOption>("xxx", td_api::make_object<td_api::optionValueBoolean>(true)));
send_request(td_api::make_object<td_api::setOption>("xxx", td_api::make_object<td_api::optionValueInteger>(1)));
send_request(td_api::make_object<td_api::setOption>("xxx", td_api::make_object<td_api::optionValueString>("2")));
send_request(td_api::make_object<td_api::setOption>("xxx", td_api::make_object<td_api::optionValueEmpty>()));
send_request(td_api::make_object<td_api::getOption>("use_pfs")); send_request(td_api::make_object<td_api::getOption>("use_pfs"));
send_request(td_api::make_object<td_api::setOption>( send_request(td_api::make_object<td_api::setOption>(
"use_pfs", td_api::make_object<td_api::optionValueBoolean>(std::time(nullptr) / 86400 % 2 == 0))); "use_pfs", td_api::make_object<td_api::optionValueBoolean>(std::time(nullptr) / 86400 % 2 == 0)));
@ -4823,6 +4829,15 @@ class CliClient final : public Actor {
send_request(td_api::make_object<td_api::getProxyLink>(as_proxy_id(args))); send_request(td_api::make_object<td_api::getProxyLink>(as_proxy_id(args)));
} else if (op == "pproxy") { } else if (op == "pproxy") {
send_request(td_api::make_object<td_api::pingProxy>(as_proxy_id(args))); send_request(td_api::make_object<td_api::pingProxy>(as_proxy_id(args)));
} else if (op == "gusi") {
UserId user_id;
get_args(args, user_id);
send_request(td_api::make_object<td_api::getUserSupportInfo>(user_id));
} else if (op == "susi") {
UserId user_id;
string text;
get_args(args, user_id, text);
send_request(td_api::make_object<td_api::setUserSupportInfo>(user_id, as_formatted_text(text)));
} else if (op == "touch") { } else if (op == "touch") {
auto r_fd = FileFd::open(args, FileFd::Read | FileFd::Write); auto r_fd = FileFd::open(args, FileFd::Read | FileFd::Write);
if (r_fd.is_error()) { if (r_fd.is_error()) {

View File

@ -6,7 +6,6 @@
// //
#include "td/telegram/files/FileGcParameters.h" #include "td/telegram/files/FileGcParameters.h"
#include "td/telegram/ConfigShared.h"
#include "td/telegram/Global.h" #include "td/telegram/Global.h"
#include "td/utils/format.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)) , owner_dialog_ids_(std::move(owner_dialog_ids))
, exclude_owner_dialog_ids_(std::move(exclude_owner_dialog_ids)) , exclude_owner_dialog_ids_(std::move(exclude_owner_dialog_ids))
, dialog_limit_(dialog_limit) { , dialog_limit_(dialog_limit) {
auto &config = G()->shared_config(); max_files_size_ = size >= 0 ? size : G()->get_option_integer("storage_max_files_size", 100 << 10) << 10;
max_files_size_ = size >= 0 ? size : config.get_option_integer("storage_max_files_size", 100 << 10) << 10;
max_time_from_last_access_ = max_time_from_last_access_ =
ttl >= 0 ? ttl : narrow_cast<int32>(config.get_option_integer("storage_max_time_from_last_access", 60 * 60 * 23)); ttl >= 0 ? ttl : narrow_cast<int32>(G()->get_option_integer("storage_max_time_from_last_access", 60 * 60 * 23));
max_file_count_ = count >= 0 ? count : narrow_cast<int32>(config.get_option_integer("storage_max_file_count", 40000)); max_file_count_ = count >= 0 ? count : narrow_cast<int32>(G()->get_option_integer("storage_max_file_count", 40000));
immunity_delay_ = immunity_delay >= 0 immunity_delay_ = immunity_delay >= 0
? immunity_delay ? immunity_delay
: narrow_cast<int32>(config.get_option_integer("storage_immunity_delay", 60 * 60)); : narrow_cast<int32>(G()->get_option_integer("storage_immunity_delay", 60 * 60));
} }
StringBuilder &operator<<(StringBuilder &string_builder, const FileGcParameters &parameters) { StringBuilder &operator<<(StringBuilder &string_builder, const FileGcParameters &parameters) {

View File

@ -6,7 +6,6 @@
// //
#include "td/telegram/files/FileLoadManager.h" #include "td/telegram/files/FileLoadManager.h"
#include "td/telegram/ConfigShared.h"
#include "td/telegram/Global.h" #include "td/telegram/Global.h"
#include "td/telegram/net/DcId.h" #include "td/telegram/net/DcId.h"
#include "td/telegram/TdParameters.h" #include "td/telegram/TdParameters.h"
@ -29,7 +28,7 @@ void FileLoadManager::start_up() {
!G()->parameters().use_file_db /*tdlib_engine*/ !G()->parameters().use_file_db /*tdlib_engine*/
? ResourceManager::Mode::Greedy ? ResourceManager::Mode::Greedy
: ResourceManager::Mode::Baseline); : ResourceManager::Mode::Baseline);
if (G()->shared_config().get_option_boolean("is_premium")) { if (G()->get_option_boolean("is_premium")) {
max_download_resource_limit_ *= 8; max_download_resource_limit_ *= 8;
} }
} }

View File

@ -6,7 +6,6 @@
// //
#include "td/telegram/files/FileManager.h" #include "td/telegram/files/FileManager.h"
#include "td/telegram/ConfigShared.h"
#include "td/telegram/DownloadManager.h" #include "td/telegram/DownloadManager.h"
#include "td/telegram/FileReferenceManager.h" #include "td/telegram/FileReferenceManager.h"
#include "td/telegram/files/FileData.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"); return get_file_size_error(" for a photo");
} }
if (location.file_type_ == FileType::VideoNote && 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 get_file_size_error(" for a video note");
} }
return Status::OK(); 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) { 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; return false;
} }
@ -2577,7 +2576,7 @@ void FileManager::resume_upload(FileId file_id, vector<int> bad_parts, std::shar
return; return;
} }
if (file_view.has_local_location()) { if (file_view.has_local_location() && new_priority != 0) {
auto status = check_local_location(node); auto status = check_local_location(node);
if (status.is_error()) { if (status.is_error()) {
LOG(INFO) << "Full local location of file " << file_id << " for upload is invalid: " << status; LOG(INFO) << "Full local location of file " << file_id << " for upload is invalid: " << status;
@ -3169,7 +3168,7 @@ Result<FileId> FileManager::get_input_file_id(FileType type, const tl_object_ptr
return FileId(); return FileId();
} }
string hash; 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); auto r_stat = stat(path);
if (r_stat.is_ok() && r_stat.ok().size_ > 0 && r_stat.ok().size_ < 11000000) { 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_); auto r_file_content = read_file_str(path, r_stat.ok().size_);

View File

@ -26,7 +26,6 @@
#include "td/utils/common.h" #include "td/utils/common.h"
#include "td/utils/Container.h" #include "td/utils/Container.h"
#include "td/utils/Enumerator.h" #include "td/utils/Enumerator.h"
#include "td/utils/FlatHashMap.h"
#include "td/utils/FlatHashSet.h" #include "td/utils/FlatHashSet.h"
#include "td/utils/logging.h" #include "td/utils/logging.h"
#include "td/utils/optional.h" #include "td/utils/optional.h"

View File

@ -7,7 +7,6 @@
#include "td/telegram/net/ConnectionCreator.h" #include "td/telegram/net/ConnectionCreator.h"
#include "td/telegram/ConfigManager.h" #include "td/telegram/ConfigManager.h"
#include "td/telegram/ConfigShared.h"
#include "td/telegram/Global.h" #include "td/telegram/Global.h"
#include "td/telegram/logevent/LogEvent.h" #include "td/telegram/logevent/LogEvent.h"
#include "td/telegram/MessagesManager.h" #include "td/telegram/MessagesManager.h"
@ -234,7 +233,7 @@ void ConnectionCreator::get_proxy_link(int32 proxy_id, Promise<string> promise)
} }
auto &proxy = it->second; 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; bool is_socks = false;
switch (proxy.type()) { switch (proxy.type()) {
case Proxy::Type::Socks5: case Proxy::Type::Socks5:
@ -269,7 +268,7 @@ void ConnectionCreator::get_proxy_link(int32 proxy_id, Promise<string> promise)
} }
ActorId<GetHostByNameActor> ConnectionCreator::get_dns_resolver() { ActorId<GetHostByNameActor> 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()) { if (block_get_host_by_name_actor_.empty()) {
VLOG(connections) << "Init block bypass DNS resolver"; VLOG(connections) << "Init block bypass DNS resolver";
GetHostByNameActor::Options options; GetHostByNameActor::Options options;
@ -297,7 +296,7 @@ void ConnectionCreator::ping_proxy(int32 proxy_id, Promise<double> promise) {
CHECK(!close_flag_); CHECK(!close_flag_);
if (proxy_id == 0) { if (proxy_id == 0) {
auto main_dc_id = G()->net_query_dispatcher().get_main_dc_id(); 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); auto infos = dc_options_set_.find_all_connections(main_dc_id, false, false, prefer_ipv6, false);
if (infos.empty()) { if (infos.empty()) {
return promise.set_error(Status::Error(400, "Can't find valid DC address")); 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<double> promise) {
return promise.set_error(Status::Error(400, "Unknown proxy identifier")); return promise.set_error(Status::Error(400, "Unknown proxy identifier"));
} }
const Proxy &proxy = it->second; 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, 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), PromiseCreator::lambda([actor_id = actor_id(this), promise = std::move(promise),
proxy_id](Result<IPAddress> result) mutable { proxy_id](Result<IPAddress> 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) { void ConnectionCreator::set_active_proxy_id(int32 proxy_id, bool from_binlog) {
active_proxy_id_ = proxy_id; active_proxy_id_ = proxy_id;
if (proxy_id == 0) { if (proxy_id == 0) {
G()->shared_config().set_option_empty("enabled_proxy_id"); G()->set_option_empty("enabled_proxy_id");
} else { } 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 (!from_binlog) {
if (proxy_id == 0) { if (proxy_id == 0) {
@ -701,8 +700,7 @@ Result<mtproto::TransportType> ConnectionCreator::get_transport_type(const Proxy
Result<SocketFd> ConnectionCreator::find_connection(const Proxy &proxy, const IPAddress &proxy_ip_address, DcId dc_id, Result<SocketFd> ConnectionCreator::find_connection(const Proxy &proxy, const IPAddress &proxy_ip_address, DcId dc_id,
bool allow_media_only, FindConnectionExtra &extra) { bool allow_media_only, FindConnectionExtra &extra) {
extra.debug_str = PSTRING() << "Failed to find valid IP address for " << dc_id; extra.debug_str = PSTRING() << "Failed to find valid IP address for " << dc_id;
bool prefer_ipv6 = bool prefer_ipv6 = G()->get_option_boolean("prefer_ipv6") || (proxy.use_proxy() && proxy_ip_address.is_ipv6());
G()->shared_config().get_option_boolean("prefer_ipv6") || (proxy.use_proxy() && proxy_ip_address.is_ipv6());
bool only_http = proxy.use_http_caching_proxy(); bool only_http = proxy.use_http_caching_proxy();
#if TD_DARWIN_WATCH_OS #if TD_DARWIN_WATCH_OS
only_http = true; only_http = true;
@ -1281,7 +1279,7 @@ void ConnectionCreator::loop() {
if (resolve_proxy_query_token_ == 0) { if (resolve_proxy_query_token_ == 0) {
resolve_proxy_query_token_ = next_token(); resolve_proxy_query_token_ = next_token();
const Proxy &proxy = proxies_[active_proxy_id_]; 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(); VLOG(connections) << "Resolve IP address " << resolve_proxy_query_token_ << " of " << proxy.server();
send_closure( send_closure(
get_dns_resolver(), &GetHostByNameActor::run, proxy.server().str(), proxy.port(), prefer_ipv6, get_dns_resolver(), &GetHostByNameActor::run, proxy.server().str(), proxy.port(), prefer_ipv6,

View File

@ -22,10 +22,6 @@ namespace td {
int VERBOSITY_NAME(net_query) = VERBOSITY_NAME(INFO); 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) { void NetQuery::debug(string state, bool may_be_lost) {
may_be_lost_ = may_be_lost; may_be_lost_ = may_be_lost;
VLOG(net_query) << *this << " " << tag("state", state); 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_); td::unique(chain_ids_);
auto &data = get_data_unsafe(); 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(); data.start_timestamp_ = data.state_timestamp_ = Time::now();
LOG(INFO) << *this; LOG(INFO) << *this;
if (stats) { if (stats) {

View File

@ -329,8 +329,6 @@ class NetQuery final : public TsListNode<NetQueryDebug> {
source_ = std::move(source); source_ = std::move(source);
} }
static int64 get_my_id();
static int32 tl_magic(const BufferSlice &buffer_slice); static int32 tl_magic(const BufferSlice &buffer_slice);
public: public:

View File

@ -6,7 +6,6 @@
// //
#include "td/telegram/net/NetQueryDispatcher.h" #include "td/telegram/net/NetQueryDispatcher.h"
#include "td/telegram/ConfigShared.h"
#include "td/telegram/Global.h" #include "td/telegram/Global.h"
#include "td/telegram/net/AuthDataShared.h" #include "td/telegram/net/AuthDataShared.h"
#include "td/telegram/net/DcAuthManager.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()); net_query->set_error(Global::request_aborted_error());
return complete_net_query(std::move(net_query)); 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")); net_query->set_error(Status::Error(429, "Too Many Requests: retry after 10"));
return complete_net_query(std::move(net_query)); return complete_net_query(std::move(net_query));
// if (net_query->is_ok() && net_query->tl_constructor() == 0x0d9d75a4) { // 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(); int32 slow_net_scheduler_id = G()->get_slow_net_scheduler_id();
auto raw_dc_id = dc_id.get_raw_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 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_session_count = is_premium ? 8 : 2;
int32 download_small_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() { int32 NetQueryDispatcher::get_session_count() {
return max(narrow_cast<int32>(G()->shared_config().get_option_integer("session_count")), 1); return max(narrow_cast<int32>(G()->get_option_integer("session_count")), 1);
} }
bool NetQueryDispatcher::get_use_pfs() { 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<ActorShared<>()> &create_reference) { NetQueryDispatcher::NetQueryDispatcher(const std::function<ActorShared<>()> &create_reference) {

View File

@ -6,7 +6,6 @@
// //
#include "td/telegram/net/NetStatsManager.h" #include "td/telegram/net/NetStatsManager.h"
#include "td/telegram/ConfigShared.h"
#include "td/telegram/Global.h" #include "td/telegram/Global.h"
#include "td/telegram/logevent/LogEvent.h" #include "td/telegram/logevent/LogEvent.h"
#include "td/telegram/StateManager.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"); auto since_str = G()->td_db()->get_binlog_pmc()->get("net_stats_since");
if (!since_str.empty()) { if (!since_str.empty()) {
auto since = to_integer<int32>(since_str); auto since = to_integer<int32>(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) { if (unix_time < since) {
since_total_ = unix_time; since_total_ = unix_time;
G()->td_db()->get_binlog_pmc()->set("net_stats_since", to_string(since_total_)); 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) { 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; return;
} }

View File

@ -65,9 +65,11 @@ void SessionMultiProxy::update_destroy_auth_key(bool need_destroy_auth_key) {
need_destroy_auth_key_ = need_destroy_auth_key; need_destroy_auth_key_ = need_destroy_auth_key;
send_closure(sessions_[0].proxy, &SessionProxy::update_destroy, need_destroy_auth_key_); send_closure(sessions_[0].proxy, &SessionProxy::update_destroy, need_destroy_auth_key_);
} }
void SessionMultiProxy::update_session_count(int32 session_count) { void SessionMultiProxy::update_session_count(int32 session_count) {
update_options(session_count, use_pfs_); update_options(session_count, use_pfs_);
} }
void SessionMultiProxy::update_use_pfs(bool use_pfs) { void SessionMultiProxy::update_use_pfs(bool use_pfs) {
update_options(session_count_, use_pfs); update_options(session_count_, use_pfs);
} }

View File

@ -15,6 +15,7 @@
#include "td/utils/ObjectPool.h" #include "td/utils/ObjectPool.h"
#include "td/utils/port/detail/PollableFd.h" #include "td/utils/port/detail/PollableFd.h"
#include "td/utils/port/PollFlags.h" #include "td/utils/port/PollFlags.h"
#include "td/utils/Promise.h"
#include "td/utils/Slice.h" #include "td/utils/Slice.h"
#include "td/utils/Time.h" #include "td/utils/Time.h"

View File

@ -32,6 +32,7 @@ class SeqKeyValue {
} }
return next_seq_no(); return next_seq_no();
} }
SeqNo erase(const string &key) { SeqNo erase(const string &key) {
auto it = map_.find(key); auto it = map_.find(key);
if (it == map_.end()) { if (it == map_.end()) {
@ -40,9 +41,11 @@ class SeqKeyValue {
map_.erase(it); map_.erase(it);
return next_seq_no(); return next_seq_no();
} }
SeqNo seq_no() const { SeqNo seq_no() const {
return current_id_ + 1; return current_id_ + 1;
} }
string get(const string &key) const { string get(const string &key) const {
auto it = map_.find(key); auto it = map_.find(key);
if (it == map_.end()) { if (it == map_.end()) {
@ -51,11 +54,12 @@ class SeqKeyValue {
return it->second; return it->second;
} }
template <class F> bool isset(const string &key) const {
void foreach(const F &f) { auto it = map_.find(key);
for (auto &it : map_) { if (it == map_.end()) {
f(it.first, it.second); return false;
} }
return true;
} }
size_t size() const { size_t size() const {

View File

@ -18,7 +18,7 @@ SqliteConnectionSafe::SqliteConnectionSafe(string path, DbKey key, optional<int3
cipher_version = std::move(cipher_version)] { cipher_version = std::move(cipher_version)] {
auto r_db = SqliteDb::open_with_key(path, false, key, cipher_version.copy()); auto r_db = SqliteDb::open_with_key(path, false, key, cipher_version.copy());
if (r_db.is_error()) { if (r_db.is_error()) {
LOG(FATAL) << "Can't open database in state " << *close_state_ptr << ": " << r_db.error().message(); LOG(FATAL) << "Can't open database in state " << close_state_ptr->load() << ": " << r_db.error().message();
} }
auto db = r_db.move_as_ok(); auto db = r_db.move_as_ok();
db.exec("PRAGMA journal_mode=WAL").ensure(); db.exec("PRAGMA journal_mode=WAL").ensure();

View File

@ -14,6 +14,8 @@
#include "td/utils/common.h" #include "td/utils/common.h"
#include "td/utils/optional.h" #include "td/utils/optional.h"
#include <atomic>
namespace td { namespace td {
class SqliteConnectionSafe { class SqliteConnectionSafe {
@ -30,7 +32,7 @@ class SqliteConnectionSafe {
private: private:
string path_; string path_;
uint32 close_state_ = 0; std::atomic<uint32> close_state_{0};
LazySchedulerLocalStorage<SqliteDb> lsls_connection_; LazySchedulerLocalStorage<SqliteDb> lsls_connection_;
}; };

View File

@ -33,29 +33,41 @@ class TsSeqKeyValue {
auto lock = rw_mutex_.lock_write().move_as_ok(); auto lock = rw_mutex_.lock_write().move_as_ok();
return kv_.set(key, value); return kv_.set(key, value);
} }
std::pair<SeqNo, RwMutex::WriteLock> set_and_lock(Slice key, Slice value) { std::pair<SeqNo, RwMutex::WriteLock> set_and_lock(Slice key, Slice value) {
auto lock = rw_mutex_.lock_write().move_as_ok(); auto lock = rw_mutex_.lock_write().move_as_ok();
return std::make_pair(kv_.set(key, value), std::move(lock)); return std::make_pair(kv_.set(key, value), std::move(lock));
} }
SeqNo erase(const string &key) { SeqNo erase(const string &key) {
auto lock = rw_mutex_.lock_write().move_as_ok(); auto lock = rw_mutex_.lock_write().move_as_ok();
return kv_.erase(key); return kv_.erase(key);
} }
std::pair<SeqNo, RwMutex::WriteLock> erase_and_lock(const string &key) { std::pair<SeqNo, RwMutex::WriteLock> erase_and_lock(const string &key) {
auto lock = rw_mutex_.lock_write().move_as_ok(); auto lock = rw_mutex_.lock_write().move_as_ok();
return std::make_pair(kv_.erase(key), std::move(lock)); 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(); auto lock = rw_mutex_.lock_read().move_as_ok();
return kv_.get(key); 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 { size_t size() const {
return kv_.size(); return kv_.size();
} }
std::unordered_map<string, string> get_all() {
std::unordered_map<string, string> get_all() const {
auto lock = rw_mutex_.lock_write().move_as_ok(); auto lock = rw_mutex_.lock_write().move_as_ok();
return kv_.get_all(); return kv_.get_all();
} }
// not thread safe method // not thread safe method
SeqKeyValue &inner() { SeqKeyValue &inner() {
return kv_; return kv_;
@ -66,7 +78,7 @@ class TsSeqKeyValue {
} }
private: private:
RwMutex rw_mutex_; mutable RwMutex rw_mutex_;
SeqKeyValue kv_; SeqKeyValue kv_;
}; };

View File

@ -46,12 +46,12 @@ bool HttpChunkedByteFlow::loop() {
set_need_size(need_size); set_need_size(need_size);
break; break;
} }
total_size_ += ready; if (total_size_ > MAX_SIZE - ready) {
uncommited_size_ += ready;
if (total_size_ > MAX_SIZE) {
finish(Status::Error(PSLICE() << "Too big query " << tag("size", input_->size()))); finish(Status::Error(PSLICE() << "Too big query " << tag("size", input_->size())));
return false; return false;
} }
total_size_ += ready;
uncommited_size_ += ready;
output_.append(input_->cut_head(ready)); output_.append(input_->cut_head(ready));
result = true; result = true;

View File

@ -17,8 +17,8 @@ class HttpChunkedByteFlow final : public ByteFlowBase {
bool loop() final; bool loop() final;
private: private:
static constexpr int MAX_CHUNK_SIZE = 15 << 20; // some reasonable limit static constexpr size_t MAX_CHUNK_SIZE = 15 << 20; // some reasonable limit
static constexpr int MAX_SIZE = std::numeric_limits<int32>::max(); // some reasonable limit static constexpr size_t MAX_SIZE = std::numeric_limits<uint32>::max(); // some reasonable limit
static constexpr size_t MIN_UPDATE_SIZE = 1 << 14; static constexpr size_t MIN_UPDATE_SIZE = 1 << 14;
enum class State { ReadChunkLength, ReadChunkContent, OK }; enum class State { ReadChunkLength, ReadChunkContent, OK };
State state_ = State::ReadChunkLength; State state_ = State::ReadChunkLength;

View File

@ -103,7 +103,7 @@ Result<size_t> HttpReader::read_next(HttpQuery *query, bool can_be_slow) {
*source >> flow_sink_; *source >> flow_sink_;
content_ = flow_sink_.get_output(); 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_); return Status::Error(413, PSLICE() << "Request Entity Too Large: content length is " << content_length_);
} }
@ -320,7 +320,7 @@ Result<bool> HttpReader::parse_multipart_form_data(bool can_be_slow) {
header_value.remove_prefix(10); header_value.remove_prefix(10);
while (true) { while (true) {
header_value = trim(header_value); header_value = trim(header_value);
const char *key_end = const auto *key_end =
static_cast<const char *>(std::memchr(header_value.data(), '=', header_value.size())); static_cast<const char *>(std::memchr(header_value.data(), '=', header_value.size()));
if (key_end == nullptr) { if (key_end == nullptr) {
break; break;
@ -558,7 +558,11 @@ void HttpReader::process_header(MutableSlice header_name, MutableSlice header_va
// TODO: check if protocol is HTTP/1.1 // TODO: check if protocol is HTTP/1.1
query_->keep_alive_ = true; query_->keep_alive_ = true;
if (header_name == "content-length") { if (header_name == "content-length") {
content_length_ = to_integer<size_t>(header_value); auto content_length = to_integer<uint64>(header_value);
if (content_length > MAX_CONTENT_SIZE) {
content_length = MAX_CONTENT_SIZE;
}
content_length_ = static_cast<size_t>(content_length);
} else if (header_name == "connection") { } else if (header_name == "connection") {
to_lower_inplace(header_value); to_lower_inplace(header_value);
if (header_value == "close") { if (header_value == "close") {

View File

@ -101,7 +101,7 @@ class HttpReader {
void close_temp_file(); void close_temp_file();
void clean_temporary_file(); void clean_temporary_file();
static constexpr size_t MAX_CONTENT_SIZE = std::numeric_limits<int32>::max(); // Some reasonable limit static constexpr size_t MAX_CONTENT_SIZE = std::numeric_limits<uint32>::max(); // Some reasonable limit
static constexpr size_t MAX_TOTAL_PARAMETERS_LENGTH = 1 << 20; // 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_TOTAL_HEADERS_LENGTH = 1 << 18; // Some reasonable limit
static constexpr size_t MAX_BOUNDARY_LENGTH = 70; // As defined by RFC1341 static constexpr size_t MAX_BOUNDARY_LENGTH = 70; // As defined by RFC1341

View File

@ -344,6 +344,7 @@ tl_config tl_config_parser::parse_config() {
std::int32_t constructors_n = try_parse_int(); std::int32_t constructors_n = try_parse_int();
assert(static_cast<std::size_t>(constructors_n) == constructors_total); assert(static_cast<std::size_t>(constructors_n) == constructors_total);
(void)constructors_total;
for (std::int32_t i = 0; i < constructors_n; i++) { for (std::int32_t i = 0; i < constructors_n; i++) {
tl_combinator *constructor = read_combinator(); tl_combinator *constructor = read_combinator();
config.get_type(constructor->type_id)->add_constructor(constructor); config.get_type(constructor->type_id)->add_constructor(constructor);

View File

@ -294,6 +294,7 @@ set(TDUTILS_SOURCE
td/utils/Variant.h td/utils/Variant.h
td/utils/VectorQueue.h td/utils/VectorQueue.h
td/utils/WaitFreeHashMap.h td/utils/WaitFreeHashMap.h
td/utils/WaitFreeHashSet.h
td/utils/WaitFreeVector.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/StealingQueue.cpp
${CMAKE_CURRENT_SOURCE_DIR}/test/variant.cpp ${CMAKE_CURRENT_SOURCE_DIR}/test/variant.cpp
${CMAKE_CURRENT_SOURCE_DIR}/test/WaitFreeHashMap.cpp ${CMAKE_CURRENT_SOURCE_DIR}/test/WaitFreeHashMap.cpp
${CMAKE_CURRENT_SOURCE_DIR}/test/WaitFreeHashSet.cpp
${CMAKE_CURRENT_SOURCE_DIR}/test/WaitFreeVector.cpp ${CMAKE_CURRENT_SOURCE_DIR}/test/WaitFreeVector.cpp
PARENT_SCOPE PARENT_SCOPE
) )

View File

@ -34,7 +34,7 @@ vector<string> Hints::fix_words(vector<string> words) {
return words; return words;
} }
vector<string> Hints::get_words(Slice name, bool is_search) { vector<string> Hints::get_words(Slice name) {
bool in_word = false; bool in_word = false;
string word; string word;
vector<string> words; vector<string> words;
@ -42,7 +42,7 @@ vector<string> Hints::get_words(Slice name, bool is_search) {
auto end = name.uend(); auto end = name.uend();
while (pos != end) { while (pos != end) {
uint32 code; 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); code = prepare_search_character(code);
if (code == 0) { if (code == 0) {
@ -94,7 +94,7 @@ void Hints::add(KeyT key, Slice name) {
return; return;
} }
vector<string> old_transliterations; vector<string> 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_); delete_word(old_word, key, word_to_keys_);
for (auto &w : get_word_transliterations(old_word, false)) { for (auto &w : get_word_transliterations(old_word, false)) {
@ -116,7 +116,7 @@ void Hints::add(KeyT key, Slice name) {
} }
vector<string> transliterations; vector<string> transliterations;
for (auto &word : get_words(name, false)) { for (auto &word : get_words(name)) {
add_word(word, key, word_to_keys_); add_word(word, key, word_to_keys_);
for (auto &w : get_word_transliterations(word, false)) { for (auto &w : get_word_transliterations(word, false)) {
@ -166,7 +166,7 @@ std::pair<size_t, vector<Hints::KeyT>> Hints::search(Slice query, int32 limit, b
return {key_to_name_.size(), std::move(results)}; 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()) { if (return_all_for_empty_query && words.empty()) {
results.reserve(key_to_name_.size()); results.reserve(key_to_name_.size());
for (auto &it : key_to_name_) { for (auto &it : key_to_name_) {

View File

@ -52,7 +52,7 @@ class Hints {
static vector<string> fix_words(vector<string> words); static vector<string> fix_words(vector<string> words);
static vector<string> get_words(Slice name, bool is_search); static vector<string> get_words(Slice name);
static void add_search_results(vector<KeyT> &results, const string &word, static void add_search_results(vector<KeyT> &results, const string &word,
const std::map<string, vector<KeyT>> &word_to_keys); const std::map<string, vector<KeyT>> &word_to_keys);

View File

@ -43,7 +43,7 @@ class WaitFreeHashMap {
return const_cast<WaitFreeHashMap *>(this)->get_storage(key); return const_cast<WaitFreeHashMap *>(this)->get_storage(key);
} }
void split() { void split_storage() {
CHECK(wait_free_storage_ == nullptr); CHECK(wait_free_storage_ == nullptr);
wait_free_storage_ = make_unique<WaitFreeStorage>(); wait_free_storage_ = make_unique<WaitFreeStorage>();
for (auto &it : default_map_) { for (auto &it : default_map_) {
@ -57,7 +57,7 @@ class WaitFreeHashMap {
auto &storage = get_storage(key); auto &storage = get_storage(key);
storage[key] = std::move(value); storage[key] = std::move(value);
if (default_map_.size() == MAX_STORAGE_SIZE) { if (default_map_.size() == MAX_STORAGE_SIZE) {
split(); split_storage();
} }
} }
@ -103,7 +103,7 @@ class WaitFreeHashMap {
return result; return result;
} }
split(); split_storage();
} }
return get_wait_free_storage(key)[key]; return get_wait_free_storage(key)[key];

View File

@ -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 <functional>
namespace td {
template <class KeyT, class HashT = std::hash<KeyT>, class EqT = std::equal_to<KeyT>>
class WaitFreeHashSet {
using Storage = FlatHashSet<KeyT, HashT, EqT>;
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<WaitFreeStorage> 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<WaitFreeHashSet *>(this)->get_storage(key);
}
void split_storage() {
CHECK(wait_free_storage_ == nullptr);
wait_free_storage_ = make_unique<WaitFreeStorage>();
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<void(const KeyT &key)> 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

View File

@ -8,6 +8,8 @@
#include "td/utils/common.h" #include "td/utils/common.h"
#include <utility>
namespace td { namespace td {
template <class T> template <class T>

View File

@ -133,7 +133,7 @@ static string clean_filename_part(Slice name, int max_length) {
int size = 0; int size = 0;
for (auto *it = name.ubegin(); it != name.uend() && size < max_length;) { for (auto *it = name.ubegin(); it != name.uend() && size < max_length;) {
uint32 code; uint32 code;
it = next_utf8_unsafe(it, &code, "clean_filename_part"); it = next_utf8_unsafe(it, &code);
if (!is_ok(code)) { if (!is_ok(code)) {
if (prepare_search_character(code) == 0) { if (prepare_search_character(code) == 0) {
continue; continue;

View File

@ -53,7 +53,7 @@ static void punycode(string &result, Slice part) {
auto end = part.uend(); auto end = part.uend();
while (begin != end) { while (begin != end) {
uint32 code; uint32 code;
begin = next_utf8_unsafe(begin, &code, "punycode"); begin = next_utf8_unsafe(begin, &code);
if (code <= 127u) { if (code <= 127u) {
result += to_lower(static_cast<char>(code)); result += to_lower(static_cast<char>(code));
processed++; processed++;

Some files were not shown because too many files have changed in this diff Show More