diff --git a/lib/common/src/version.h b/lib/common/src/version.h index 890b5622..4d43f0ef 100644 --- a/lib/common/src/version.h +++ b/lib/common/src/version.h @@ -7,4 +7,4 @@ #pragma once -#define NCHAT_VERSION "5.2.8" +#define NCHAT_VERSION "5.2.9" diff --git a/lib/tgchat/ext/td/CMakeLists.txt b/lib/tgchat/ext/td/CMakeLists.txt index d3918fac..cdcf3405 100644 --- a/lib/tgchat/ext/td/CMakeLists.txt +++ b/lib/tgchat/ext/td/CMakeLists.txt @@ -6,7 +6,7 @@ if (POLICY CMP0065) cmake_policy(SET CMP0065 NEW) endif() -project(TDLib VERSION 1.8.35 LANGUAGES CXX C) +project(TDLib VERSION 1.8.36 LANGUAGES CXX C) if (NOT DEFINED CMAKE_MODULE_PATH) set(CMAKE_MODULE_PATH "") @@ -41,6 +41,9 @@ prevent_in_source_build() option(TD_ENABLE_JNI "Use \"ON\" to enable JNI-compatible TDLib API.") option(TD_ENABLE_DOTNET "Use \"ON\" to enable generation of C++/CLI or C++/CX TDLib API bindings.") +if (NOT CMAKE_CROSSCOMPILING) + option(TD_GENERATE_SOURCE_FILES "Use \"ON\" to just generate TDLib source files.") +endif() if (TD_ENABLE_DOTNET AND (CMAKE_VERSION VERSION_LESS "3.1.0")) message(FATAL_ERROR "CMake 3.1.0 or higher is required. You are running version ${CMAKE_VERSION}.") @@ -114,11 +117,13 @@ if (EMSCRIPTEN) set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} --post-js ${CMAKE_CURRENT_SOURCE_DIR}/post.js") endif() -if (NOT OPENSSL_FOUND) - find_package(OpenSSL) -endif() -if (OPENSSL_FOUND) - message(STATUS "Found OpenSSL: ${OPENSSL_INCLUDE_DIR} ${OPENSSL_LIBRARIES}") +if (NOT TD_GENERATE_SOURCE_FILES) + if (NOT OPENSSL_FOUND) + find_package(OpenSSL) + endif() + if (OPENSSL_FOUND) + message(STATUS "Found OpenSSL: ${OPENSSL_INCLUDE_DIR} ${OPENSSL_LIBRARIES}") + endif() endif() set(CMAKE_THREAD_PREFER_PTHREAD ON) @@ -138,6 +143,11 @@ if (MSVC) if (TD_ENABLE_MULTI_PROCESSOR_COMPILATION) set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} /MP") endif() + + if (TD_ENABLE_JNI) + # https://github.com/tdlib/td/issues/2912 + add_definitions(-D_DISABLE_CONSTEXPR_MUTEX_CONSTRUCTOR) + endif() endif() if (CLANG OR GCC) @@ -163,12 +173,20 @@ configure_file("${CMAKE_CURRENT_SOURCE_DIR}/td/telegram/GitCommitHash.cpp.in" "$ add_subdirectory(tdtl) +if (TD_GENERATE_SOURCE_FILES) + set(TDUTILS_MIME_TYPE ON CACHE BOOL "") + set(TDUTILS_USE_EXTERNAL_DEPENDENCIES OFF CACHE BOOL "") +endif() add_subdirectory(tdutils) add_subdirectory(td/generate) if (NOT CMAKE_CROSSCOMPILING) - add_custom_target(prepare_cross_compiling DEPENDS tl_generate_mtproto tl_generate_common tdmime_auto tl_generate_json) + set(TD_ALWAYS_GENERATE_SOURCE "") + if (TD_GENERATE_SOURCE_FILES) + set(TD_ALWAYS_GENERATE_SOURCE "ALL") + endif() + add_custom_target(prepare_cross_compiling ${TD_ALWAYS_GENERATE_SOURCE} DEPENDS tl_generate_mtproto tl_generate_common tdmime_auto tl_generate_json) if (TD_ENABLE_DOTNET) add_custom_target(remove_cpp_documentation WORKING_DIRECTORY "${CMAKE_CURRENT_SOURCE_DIR}" @@ -182,7 +200,9 @@ if (NOT CMAKE_CROSSCOMPILING) endif() if (NOT OPENSSL_FOUND) - message(WARNING "Can't find OpenSSL: stop TDLib building") + if (NOT TD_GENERATE_SOURCE_FILES) + message(WARNING "Can't find OpenSSL: stop TDLib building") + endif() return() endif() @@ -194,8 +214,8 @@ if (NOT ZLIB_FOUND) return() endif() -if (NOT TDUTILS_MIME_TYPE) - message(WARNING "Option TDUTILS_MIME_TYPE must not be disabled: stop TDLib building") +if (NOT TDUTILS_MIME_TYPE OR NOT TDUTILS_USE_EXTERNAL_DEPENDENCIES) + message(WARNING "Option TDUTILS_MIME_TYPE and TDUTILS_USE_EXTERNAL_DEPENDENCIES must not be disabled: stop TDLib building") return() endif() @@ -320,6 +340,7 @@ set(TD_MTPROTO_SOURCE set(TDLIB_SOURCE_PART1 td/telegram/AccountManager.cpp + td/telegram/AlarmManager.cpp td/telegram/AnimationsManager.cpp td/telegram/Application.cpp td/telegram/AttachMenuManager.cpp @@ -337,6 +358,7 @@ set(TDLIB_SOURCE_PART1 td/telegram/BotCommandScope.cpp td/telegram/BotInfoManager.cpp td/telegram/BotMenuButton.cpp + td/telegram/BotQueries.cpp td/telegram/BusinessAwayMessage.cpp td/telegram/BusinessAwayMessageSchedule.cpp td/telegram/BusinessBotManageBar.cpp @@ -536,6 +558,7 @@ set(TDLIB_SOURCE_PART2 td/telegram/ReplyMarkup.cpp td/telegram/ReportReason.cpp td/telegram/RequestedDialogType.cpp + td/telegram/Requests.cpp td/telegram/RestrictionReason.cpp td/telegram/SavedMessagesManager.cpp td/telegram/SavedMessagesTopicId.cpp @@ -606,6 +629,7 @@ set(TDLIB_SOURCE_PART2 td/telegram/AccessRights.h td/telegram/AccountManager.h td/telegram/AffectedHistory.h + td/telegram/AlarmManager.h td/telegram/AnimationsManager.h td/telegram/Application.h td/telegram/AttachMenuManager.h @@ -625,6 +649,7 @@ set(TDLIB_SOURCE_PART2 td/telegram/BotCommandScope.h td/telegram/BotInfoManager.h td/telegram/BotMenuButton.h + td/telegram/BotQueries.h td/telegram/BusinessAwayMessage.h td/telegram/BusinessAwayMessageSchedule.h td/telegram/BusinessBotManageBar.h @@ -877,6 +902,7 @@ set(TDLIB_SOURCE_PART2 td/telegram/ReportReason.h td/telegram/RequestActor.h td/telegram/RequestedDialogType.h + td/telegram/Requests.h td/telegram/RestrictionReason.h td/telegram/SavedMessagesManager.h td/telegram/SavedMessagesTopicId.h diff --git a/lib/tgchat/ext/td/README.md b/lib/tgchat/ext/td/README.md index ae6e1922..10fc6b89 100644 --- a/lib/tgchat/ext/td/README.md +++ b/lib/tgchat/ext/td/README.md @@ -21,7 +21,7 @@ TDLib (Telegram Database library) is a cross-platform library for building [Tele * **Cross-platform**: `TDLib` can be used on Android, iOS, Windows, macOS, Linux, FreeBSD, OpenBSD, NetBSD, illumos, Windows Phone, WebAssembly, watchOS, tvOS, visionOS, Tizen, Cygwin. It should also work on other *nix systems with or without minimal effort. * **Multilanguage**: `TDLib` can be easily used with any programming language that is able to execute C functions. Additionally, it already has native Java (using `JNI`) bindings and .NET (using `C++/CLI` and `C++/CX`) bindings. * **Easy to use**: `TDLib` takes care of all network implementation details, encryption and local data storage. -* **High-performance**: in the [Telegram Bot API](https://core.telegram.org/bots/api), each `TDLib` instance handles more than 24000 active bots simultaneously. +* **High-performance**: in the [Telegram Bot API](https://core.telegram.org/bots/api), each `TDLib` instance handles more than 25000 active bots simultaneously. * **Well-documented**: all `TDLib` API methods and public interfaces are fully documented. * **Consistent**: `TDLib` guarantees that all updates are delivered in the right order. * **Reliable**: `TDLib` remains stable on slow and unreliable Internet connections. @@ -103,7 +103,7 @@ target_link_libraries(YourTarget PRIVATE Td::TdStatic) Or you could install `TDLib` and then reference it in your CMakeLists.txt like this: ``` -find_package(Td 1.8.35 REQUIRED) +find_package(Td 1.8.36 REQUIRED) target_link_libraries(YourTarget PRIVATE Td::TdStatic) ``` See [example/cpp/CMakeLists.txt](https://github.com/tdlib/td/blob/master/example/cpp/CMakeLists.txt). diff --git a/lib/tgchat/ext/td/SplitSource.php b/lib/tgchat/ext/td/SplitSource.php index f3ac19b1..d335df42 100644 --- a/lib/tgchat/ext/td/SplitSource.php +++ b/lib/tgchat/ext/td/SplitSource.php @@ -203,7 +203,7 @@ function split_file($file, $chunks, $undo) { $set_sizes[$parent] = 0; } $sets[$parent] .= $f; - $set_sizes[$parent] += preg_match('/Td::~?Td/', $f) ? 1000000 : strlen($f); + $set_sizes[$parent] += strlen($f); } arsort($set_sizes); @@ -293,179 +293,168 @@ function ($matches) use ($needed_std_headers) { ); } - if (!preg_match('/Td::~?Td/', $new_content)) { // destructor Td::~Td needs to see definitions of all forward-declared classes - $td_methods = array( - 'AccentColorId' => 'AccentColorId', - 'account_manager[_(-](?![.]get[(][)])|AccountManager[^;>]' => 'AccountManager', - 'animations_manager[_(-](?![.]get[(][)])|AnimationsManager[^;>]' => 'AnimationsManager', - 'attach_menu_manager[_(-](?![.]get[(][)])|AttachMenuManager[^;>]' => 'AttachMenuManager', - 'audios_manager[_(-](?![.]get[(][)])|AudiosManager' => 'AudiosManager', - 'auth_manager[_(-](?![.]get[(][)])|AuthManager' => 'AuthManager', - 'AutoDownloadSettings|[a-z_]*auto_download_settings' => 'AutoDownloadSettings', - 'autosave_manager[_(-](?![.]get[(][)])|AutosaveManager' => 'AutosaveManager', - 'BackgroundId' => 'BackgroundId', - 'background_manager[_(-](?![.]get[(][)])|BackgroundManager' => 'BackgroundManager', - 'BackgroundType' => 'BackgroundType', - 'Birthdate' => 'Birthdate', - 'BotMenuButton|[a-z_]*_menu_button' => 'BotMenuButton', - 'boost_manager[_(-](?![.]get[(][)])|BoostManager' => 'BoostManager', - 'bot_info_manager[_(-](?![.]get[(][)])|BotInfoManager' => 'BotInfoManager', - 'BusinessAwayMessage' => 'BusinessAwayMessage', - 'BusinessChatLink' => 'BusinessChatLink', - 'BusinessConnectedBot' => 'BusinessConnectedBot', - 'BusinessConnectionId' => 'BusinessConnectionId', - 'business_connection_manager[_(-](?![.]get[(][)])|BusinessConnectionManager' => 'BusinessConnectionManager', - 'BusinessGreetingMessage' => 'BusinessGreetingMessage', - 'BusinessInfo|business_info' => 'BusinessInfo', - 'BusinessIntro' => 'BusinessIntro', - 'business_manager[_(-](?![.]get[(][)])|BusinessManager' => 'BusinessManager', - 'BusinessRecipients' => 'BusinessRecipients', - 'BusinessWorkHours' => 'BusinessWorkHours', - 'callback_queries_manager[_(-](?![.]get[(][)])|CallbackQueriesManager' => 'CallbackQueriesManager', - 'CallId' => 'CallId', - 'call_manager[_(-](?![.]get[(][)])|CallManager' => 'CallManager', - 'ChannelId' => 'ChannelId', - 'channel_recommendation_manager[_(-](?![.]get[(][)])|ChannelRecommendationManager' => 'ChannelRecommendationManager', - 'ChatId' => 'ChatId', - 'chat_manager[_(-](?![.]get[(][)])|ChatManager([^ ;.]| [^*])' => 'ChatManager', - 'common_dialog_manager[_(-](?![.]get[(][)])|CommonDialogManager' => 'CommonDialogManager', - 'connection_state_manager[_(-](?![.]get[(][)])|ConnectionStateManager' => 'ConnectionStateManager', - 'country_info_manager[_(-](?![.]get[(][)])|CountryInfoManager' => 'CountryInfoManager', - 'CustomEmojiId' => 'CustomEmojiId', - 'device_token_manager[_(-](?![.]get[(][)])|DeviceTokenManager' => 'DeviceTokenManager', - 'DialogAction[^M]' => 'DialogAction', - 'dialog_action_manager[_(-](?![.]get[(][)])|DialogActionManager' => 'DialogActionManager', - 'DialogFilter[^A-Z]' => 'DialogFilter', - 'DialogFilterId' => 'DialogFilterId', - 'dialog_filter_manager[_(-](?![.]get[(][)])|DialogFilterManager' => 'DialogFilterManager', - 'DialogId' => 'DialogId', - 'dialog_invite_link_manager[_(-](?![.]get[(][)])|DialogInviteLinkManager' => 'DialogInviteLinkManager', - 'DialogListId' => 'DialogListId', - 'DialogLocation' => 'DialogLocation', - 'dialog_manager[_(-](?![.]get[(][)])|DialogManager' => 'DialogManager', - 'DialogParticipantFilter' => 'DialogParticipantFilter', - 'dialog_participant_manager[_(-](?![.]get[(][)])|DialogParticipantManager' => 'DialogParticipantManager', - 'DialogSource' => 'DialogSource', - 'documents_manager[_(-](?![.]get[(][)])|DocumentsManager' => 'DocumentsManager', - 'download_manager[_(-](?![.]get[(][)])|DownloadManager[^C]' => 'DownloadManager', - 'DownloadManagerCallback' => 'DownloadManagerCallback', - 'EmailVerification' => 'EmailVerification', - 'EmojiGroup' => 'EmojiGroup', - 'EmojiStatus|[a-z_]*_emoji_status' => 'EmojiStatus', - 'FactCheck' => 'FactCheck', - 'file_reference_manager[_(-](?![.]get[(][)])|FileReferenceManager|file_references[)]' => 'FileReferenceManager', - 'file_manager[_(-](?![.]get[(][)])|FileManager([^ ;.]| [^*])|update_file[)]' => 'files/FileManager', - 'FolderId' => 'FolderId', - 'forum_topic_manager[_(-](?![.]get[(][)])|ForumTopicManager' => 'ForumTopicManager', - 'game_manager[_(-](?![.]get[(][)])|GameManager' => 'GameManager', - 'G[(][)]|Global[^A-Za-z]' => 'Global', - 'GlobalPrivacySettings' => 'GlobalPrivacySettings', - 'GroupCallId' => 'GroupCallId', - 'group_call_manager[_(-](?![.]get[(][)])|GroupCallManager' => 'GroupCallManager', - 'hashtag_hints[_(-](?![.]get[(][)])|HashtagHints' => 'HashtagHints', - 'inline_message_manager[_(-](?![.]get[(][)])|InlineMessageManager' => 'InlineMessageManager', - 'inline_queries_manager[_(-](?![.]get[(][)])|InlineQueriesManager' => 'InlineQueriesManager', - 'InputBusinessChatLink' => 'InputBusinessChatLink', - 'language_pack_manager[_(-]|LanguagePackManager' => 'LanguagePackManager', - 'link_manager[_(-](?![.]get[(][)])|LinkManager' => 'LinkManager', - 'LogeventIdWithGeneration|add_log_event|delete_log_event|get_erase_log_event_promise|parse_time|store_time' => 'logevent/LogEventHelper', - 'MessageCopyOptions' => 'MessageCopyOptions', - 'MessageEffectId' => 'MessageEffectId', - 'MessageForwardInfo|LastForwardedMessageInfo|forward_info' => 'MessageForwardInfo', - 'MessageFullId' => 'MessageFullId', - 'MessageId' => 'MessageId', - 'message_import_manager[_(-](?![.]get[(][)])|MessageImportManager' => 'MessageImportManager', - 'MessageLinkInfo' => 'MessageLinkInfo', - 'MessageQuote' => 'MessageQuote', - 'MessageReaction|UnreadMessageReaction|[a-z_]*message[a-z_]*reaction' => 'MessageReaction', - 'MessageReactor' => 'MessageReactor', - 'MessageSearchOffset' => 'MessageSearchOffset', - '[a-z_]*_message_sender' => 'MessageSender', - 'messages_manager[_(-](?![.]get[(][)])|MessagesManager' => 'MessagesManager', - 'MessageThreadInfo' => 'MessageThreadInfo', - 'MessageTtl' => 'MessageTtl', - 'MissingInvitee' => 'MissingInvitee', - 'notification_manager[_(-](?![.]get[(][)])|NotificationManager|notifications[)]' => 'NotificationManager', - 'notification_settings_manager[_(-](?![.]get[(][)])|NotificationSettingsManager' => 'NotificationSettingsManager', - 'online_manager[_(-](?![.]get[(][)])|OnlineManager' => 'OnlineManager', - 'option_manager[_(-](?![.]get[(][)])|OptionManager' => 'OptionManager', - 'password_manager[_(-](?![.]get[(][)])|PasswordManager' => 'PasswordManager', - 'people_nearby_manager[_(-](?![.]get[(][)])|PeopleNearbyManager' => 'PeopleNearbyManager', - 'phone_number_manager[_(-](?![.]get[(][)])|PhoneNumberManager' => 'PhoneNumberManager', - 'PhotoSizeSource' => 'PhotoSizeSource', - 'poll_manager[_(-](?![.]get[(][)])|PollManager' => 'PollManager', - 'privacy_manager[_(-](?![.]get[(][)])|PrivacyManager' => 'PrivacyManager', - 'promo_data_manager[_(-](?![.]get[(][)])|PromoDataManager' => 'PromoDataManager', - 'PublicDialogType|get_public_dialog_type' => 'PublicDialogType', - 'quick_reply_manager[_(-](?![.]get[(][)])|QuickReplyManager' => 'QuickReplyManager', - 'ReactionListType|[a-z_]*_reaction_list_type' => 'ReactionListType', - 'reaction_manager[_(-](?![.]get[(][)])|ReactionManager' => 'ReactionManager', - 'ReactionNotificationSettings' => 'ReactionNotificationSettings', - 'ReactionNotificationsFrom' => 'ReactionNotificationsFrom', - 'ReactionType|[a-z_]*_reaction_type' => 'ReactionType', - 'RequestActor|RequestOnceActor' => 'RequestActor', - 'saved_messages_manager[_(-](?![.]get[(][)])|SavedMessagesManager' => 'SavedMessagesManager', - 'ScopeNotificationSettings|[a-z_]*_scope_notification_settings' => 'ScopeNotificationSettings', - 'SecretChatActor' => 'SecretChatActor', - 'secret_chats_manager[_(-]|SecretChatsManager' => 'SecretChatsManager', - 'secure_manager[_(-](?![.]get[(][)])|SecureManager' => 'SecureManager', - 'SentEmailCode' => 'SentEmailCode', - 'SharedDialog' => 'SharedDialog', - 'sponsored_message_manager[_(-](?![.]get[(][)])|SponsoredMessageManager' => 'SponsoredMessageManager', - 'star_manager[_(-](?![.]get[(][)])|StarManager' => 'StarManager', - 'StarSubscription[^P]' => 'StarSubscription', - 'StarSubscriptionPricing' => 'StarSubscriptionPricing', - 'state_manager[_(-](?![.]get[(][)])|StateManager' => 'StateManager', - 'statistics_manager[_(-](?![.]get[(][)])|StatisticsManager' => 'StatisticsManager', - 'StickerSetId' => 'StickerSetId', - 'stickers_manager[_(-](?![.]get[(][)])|StickersManager' => 'StickersManager', - 'storage_manager[_(-](?![.]get[(][)])|StorageManager' => 'StorageManager', - 'StoryId' => 'StoryId', - 'StoryListId' => 'StoryListId', - 'story_manager[_(-](?![.]get[(][)])|StoryManager' => 'StoryManager', - 'SuggestedAction|[a-z_]*_suggested_action' => 'SuggestedAction', - 'SynchronousRequests' => 'SynchronousRequests', - 'td_api' => 'td_api', - 'td_db[(][)]|TdDb[^A-Za-z]' => 'TdDb', - 'telegram_api' => 'telegram_api', - 'terms_of_service_manager[_(-](?![.]get[(][)])|TermsOfServiceManager' => 'TermsOfServiceManager', - 'theme_manager[_(-](?![.]get[(][)])|ThemeManager' => 'ThemeManager', - 'ThemeSettings' => 'ThemeSettings', - 'time_zone_manager[_(-](?![.]get[(][)])|TimeZoneManager' => 'TimeZoneManager', - 'TopDialogCategory|get_top_dialog_category' => 'TopDialogCategory', - 'top_dialog_manager[_(-](?![.]get[(][)])|TopDialogManager' => 'TopDialogManager', - 'translation_manager[_(-](?![.]get[(][)])|TranslationManager' => 'TranslationManager', - 'transcription_manager[_(-](?![.]get[(][)])|TranscriptionManager' => 'TranscriptionManager', - 'updates_manager[_(-](?![.]get[(][)])|UpdatesManager|get_difference[)]|updateSentMessage|dummyUpdate' => 'UpdatesManager', - 'UserId' => 'UserId', - 'user_manager[_(-](?![.]get[(][)])|UserManager([^ ;.]| [^*])' => 'UserManager', - 'video_notes_manager[_(-](?![.]get[(][)])|VideoNotesManager' => 'VideoNotesManager', - 'videos_manager[_(-](?![.]get[(][)])|VideosManager' => 'VideosManager', - 'voice_notes_manager[_(-](?![.]get[(][)])|VoiceNotesManager' => 'VoiceNotesManager', - 'WebPageId(Hash)?' => 'WebPageId', - 'web_pages_manager[_(-](?![.]get[(][)])|WebPagesManager' => 'WebPagesManager'); - - foreach ($td_methods as $pattern => $header) { - if (strpos($cpp_name, $header) !== false) { - continue; - } + $td_methods = array( + 'AccentColorId' => 'AccentColorId', + 'account_manager[_(-](?![.]get[(][)])|AccountManager[^;>]' => 'AccountManager', + 'alarm_manager[_(-](?![.]get[(][)])|AlarmManager' => 'AlarmManager', + 'animations_manager[_(-](?![.]get[(][)])|AnimationsManager[^;>]' => 'AnimationsManager', + 'attach_menu_manager[_(-](?![.]get[(][)])|AttachMenuManager[^;>]' => 'AttachMenuManager', + 'audios_manager[_(-](?![.]get[(][)])|AudiosManager' => 'AudiosManager', + 'auth_manager[_(-](?![.]get[(][)])|AuthManager' => 'AuthManager', + 'AutoDownloadSettings|[a-z_]*auto_download_settings' => 'AutoDownloadSettings', + 'autosave_manager[_(-](?![.]get[(][)])|AutosaveManager' => 'AutosaveManager', + 'BackgroundId' => 'BackgroundId', + 'background_manager[_(-](?![.]get[(][)])|BackgroundManager' => 'BackgroundManager', + 'BackgroundType' => 'BackgroundType', + 'Birthdate' => 'Birthdate', + 'BotMenuButton|[a-z_]*_menu_button' => 'BotMenuButton', + 'send_bot_custom_query|answer_bot_custom_query|set_bot_updates_status' => 'BotQueries', + 'boost_manager[_(-](?![.]get[(][)])|BoostManager' => 'BoostManager', + 'bot_info_manager[_(-](?![.]get[(][)])|BotInfoManager' => 'BotInfoManager', + 'BusinessAwayMessage' => 'BusinessAwayMessage', + 'BusinessChatLink' => 'BusinessChatLink', + 'BusinessConnectedBot' => 'BusinessConnectedBot', + 'BusinessConnectionId' => 'BusinessConnectionId', + 'business_connection_manager[_(-](?![.]get[(][)])|BusinessConnectionManager' => 'BusinessConnectionManager', + 'BusinessGreetingMessage' => 'BusinessGreetingMessage', + 'BusinessInfo|business_info' => 'BusinessInfo', + 'BusinessIntro' => 'BusinessIntro', + 'business_manager[_(-](?![.]get[(][)])|BusinessManager' => 'BusinessManager', + 'BusinessRecipients' => 'BusinessRecipients', + 'BusinessWorkHours' => 'BusinessWorkHours', + 'callback_queries_manager[_(-](?![.]get[(][)])|CallbackQueriesManager' => 'CallbackQueriesManager', + 'CallId' => 'CallId', + 'call_manager[_(-](?![.]get[(][)])|CallManager' => 'CallManager', + 'ChannelId' => 'ChannelId', + 'channel_recommendation_manager[_(-](?![.]get[(][)])|ChannelRecommendationManager' => 'ChannelRecommendationManager', + 'ChatId' => 'ChatId', + 'chat_manager[_(-](?![.]get[(][)])|ChatManager([^ ;.]| [^*])' => 'ChatManager', + 'common_dialog_manager[_(-](?![.]get[(][)])|CommonDialogManager' => 'CommonDialogManager', + 'connection_state_manager[_(-](?![.]get[(][)])|ConnectionStateManager' => 'ConnectionStateManager', + 'country_info_manager[_(-](?![.]get[(][)])|CountryInfoManager' => 'CountryInfoManager', + 'CustomEmojiId' => 'CustomEmojiId', + 'device_token_manager[_(-](?![.]get[(][)])|DeviceTokenManager' => 'DeviceTokenManager', + 'DialogAction[^M]' => 'DialogAction', + 'dialog_action_manager[_(-](?![.]get[(][)])|DialogActionManager' => 'DialogActionManager', + 'DialogFilter[^A-Z]' => 'DialogFilter', + 'DialogFilterId' => 'DialogFilterId', + 'dialog_filter_manager[_(-](?![.]get[(][)])|DialogFilterManager' => 'DialogFilterManager', + 'DialogId' => 'DialogId', + 'dialog_invite_link_manager[_(-](?![.]get[(][)])|DialogInviteLinkManager' => 'DialogInviteLinkManager', + 'DialogListId' => 'DialogListId', + 'DialogLocation' => 'DialogLocation', + 'dialog_manager[_(-](?![.]get[(][)])|DialogManager' => 'DialogManager', + 'DialogParticipantFilter' => 'DialogParticipantFilter', + 'dialog_participant_manager[_(-](?![.]get[(][)])|DialogParticipantManager' => 'DialogParticipantManager', + 'DialogSource' => 'DialogSource', + 'documents_manager[_(-](?![.]get[(][)])|DocumentsManager' => 'DocumentsManager', + 'download_manager[_(-](?![.]get[(][)])|DownloadManager[^C]' => 'DownloadManager', + 'DownloadManagerCallback' => 'DownloadManagerCallback', + 'EmailVerification' => 'EmailVerification', + 'EmojiGroup' => 'EmojiGroup', + 'EmojiStatus|[a-z_]*_emoji_status' => 'EmojiStatus', + 'FactCheck' => 'FactCheck', + 'file_reference_manager[_(-](?![.]get[(][)])|FileReferenceManager|file_references[)]' => 'FileReferenceManager', + 'file_manager[_(-](?![.]get[(][)])|FileManager([^ ;.]| [^*])|update_file[)]' => 'files/FileManager', + 'FolderId' => 'FolderId', + 'forum_topic_manager[_(-](?![.]get[(][)])|ForumTopicManager' => 'ForumTopicManager', + 'game_manager[_(-](?![.]get[(][)])|GameManager' => 'GameManager', + 'G[(][)]|Global[^A-Za-z]' => 'Global', + 'GlobalPrivacySettings' => 'GlobalPrivacySettings', + 'GroupCallId' => 'GroupCallId', + 'group_call_manager[_(-](?![.]get[(][)])|GroupCallManager' => 'GroupCallManager', + 'hashtag_hints[_(-](?![.]get[(][)])|HashtagHints' => 'HashtagHints', + 'inline_message_manager[_(-](?![.]get[(][)])|InlineMessageManager' => 'InlineMessageManager', + 'inline_queries_manager[_(-](?![.]get[(][)])|InlineQueriesManager' => 'InlineQueriesManager', + 'InputBusinessChatLink' => 'InputBusinessChatLink', + 'language_pack_manager[_(-]|LanguagePackManager' => 'LanguagePackManager', + 'link_manager[_(-](?![.]get[(][)])|LinkManager' => 'LinkManager', + 'LogeventIdWithGeneration|add_log_event|delete_log_event|get_erase_log_event_promise|parse_time|store_time' => 'logevent/LogEventHelper', + 'MessageCopyOptions' => 'MessageCopyOptions', + 'MessageEffectId' => 'MessageEffectId', + 'MessageForwardInfo|LastForwardedMessageInfo|forward_info' => 'MessageForwardInfo', + 'MessageFullId' => 'MessageFullId', + 'MessageId' => 'MessageId', + 'message_import_manager[_(-](?![.]get[(][)])|MessageImportManager' => 'MessageImportManager', + 'MessageLinkInfo' => 'MessageLinkInfo', + 'MessageQuote' => 'MessageQuote', + 'MessageReaction|UnreadMessageReaction|[a-z_]*message[a-z_]*reaction' => 'MessageReaction', + 'MessageReactor' => 'MessageReactor', + 'MessageSearchOffset' => 'MessageSearchOffset', + '[a-z_]*_message_sender' => 'MessageSender', + 'messages_manager[_(-](?![.]get[(][)])|MessagesManager' => 'MessagesManager', + 'MessageThreadInfo' => 'MessageThreadInfo', + 'MessageTtl' => 'MessageTtl', + 'MissingInvitee' => 'MissingInvitee', + 'notification_manager[_(-](?![.]get[(][)])|NotificationManager|notifications[)]' => 'NotificationManager', + 'notification_settings_manager[_(-](?![.]get[(][)])|NotificationSettingsManager' => 'NotificationSettingsManager', + 'online_manager[_(-](?![.]get[(][)])|OnlineManager' => 'OnlineManager', + 'option_manager[_(-](?![.]get[(][)])|OptionManager' => 'OptionManager', + 'password_manager[_(-](?![.]get[(][)])|PasswordManager' => 'PasswordManager', + 'people_nearby_manager[_(-](?![.]get[(][)])|PeopleNearbyManager' => 'PeopleNearbyManager', + 'phone_number_manager[_(-](?![.]get[(][)])|PhoneNumberManager' => 'PhoneNumberManager', + 'PhotoSizeSource' => 'PhotoSizeSource', + 'poll_manager[_(-](?![.]get[(][)])|PollManager' => 'PollManager', + 'privacy_manager[_(-](?![.]get[(][)])|PrivacyManager' => 'PrivacyManager', + 'promo_data_manager[_(-](?![.]get[(][)])|PromoDataManager' => 'PromoDataManager', + 'PublicDialogType|get_public_dialog_type' => 'PublicDialogType', + 'quick_reply_manager[_(-](?![.]get[(][)])|QuickReplyManager' => 'QuickReplyManager', + 'ReactionListType|[a-z_]*_reaction_list_type' => 'ReactionListType', + 'reaction_manager[_(-](?![.]get[(][)])|ReactionManager' => 'ReactionManager', + 'ReactionNotificationSettings' => 'ReactionNotificationSettings', + 'ReactionNotificationsFrom' => 'ReactionNotificationsFrom', + 'ReactionType|[a-z_]*_reaction_type' => 'ReactionType', + 'RequestActor|RequestOnceActor' => 'RequestActor', + 'saved_messages_manager[_(-](?![.]get[(][)])|SavedMessagesManager' => 'SavedMessagesManager', + 'ScopeNotificationSettings|[a-z_]*_scope_notification_settings' => 'ScopeNotificationSettings', + 'SecretChatActor' => 'SecretChatActor', + 'secret_chats_manager[_(-]|SecretChatsManager' => 'SecretChatsManager', + 'secure_manager[_(-](?![.]get[(][)])|SecureManager' => 'SecureManager', + 'SentEmailCode' => 'SentEmailCode', + 'SharedDialog' => 'SharedDialog', + 'sponsored_message_manager[_(-](?![.]get[(][)])|SponsoredMessageManager' => 'SponsoredMessageManager', + 'star_manager[_(-](?![.]get[(][)])|StarManager' => 'StarManager', + 'StarSubscription[^P]' => 'StarSubscription', + 'StarSubscriptionPricing' => 'StarSubscriptionPricing', + 'state_manager[_(-](?![.]get[(][)])|StateManager' => 'StateManager', + 'statistics_manager[_(-](?![.]get[(][)])|StatisticsManager' => 'StatisticsManager', + 'StickerSetId' => 'StickerSetId', + 'stickers_manager[_(-](?![.]get[(][)])|StickersManager' => 'StickersManager', + 'storage_manager[_(-](?![.]get[(][)])|StorageManager' => 'StorageManager', + 'StoryId' => 'StoryId', + 'StoryListId' => 'StoryListId', + 'story_manager[_(-](?![.]get[(][)])|StoryManager' => 'StoryManager', + 'SuggestedAction|[a-z_]*_suggested_action' => 'SuggestedAction', + 'SynchronousRequests' => 'SynchronousRequests', + 'td_api' => 'td_api', + 'td_db[(][)]|TdDb[^A-Za-z]' => 'TdDb', + 'telegram_api' => 'telegram_api', + 'terms_of_service_manager[_(-](?![.]get[(][)])|TermsOfServiceManager' => 'TermsOfServiceManager', + 'theme_manager[_(-](?![.]get[(][)])|ThemeManager' => 'ThemeManager', + 'ThemeSettings' => 'ThemeSettings', + 'time_zone_manager[_(-](?![.]get[(][)])|TimeZoneManager' => 'TimeZoneManager', + 'TopDialogCategory|get_top_dialog_category' => 'TopDialogCategory', + 'top_dialog_manager[_(-](?![.]get[(][)])|TopDialogManager' => 'TopDialogManager', + 'translation_manager[_(-](?![.]get[(][)])|TranslationManager' => 'TranslationManager', + 'transcription_manager[_(-](?![.]get[(][)])|TranscriptionManager' => 'TranscriptionManager', + 'updates_manager[_(-](?![.]get[(][)])|UpdatesManager|get_difference[)]|updateSentMessage|dummyUpdate' => 'UpdatesManager', + 'UserId' => 'UserId', + 'user_manager[_(-](?![.]get[(][)])|UserManager([^ ;.]| [^*])' => 'UserManager', + 'video_notes_manager[_(-](?![.]get[(][)])|VideoNotesManager' => 'VideoNotesManager', + 'videos_manager[_(-](?![.]get[(][)])|VideosManager' => 'VideosManager', + 'voice_notes_manager[_(-](?![.]get[(][)])|VoiceNotesManager' => 'VoiceNotesManager', + 'WebPageId(Hash)?' => 'WebPageId', + 'web_pages_manager[_(-](?![.]get[(][)])|WebPagesManager' => 'WebPagesManager'); + + foreach ($td_methods as $pattern => $header) { + if (strpos($cpp_name, $header) !== false) { + continue; + } - $include_name = '#include "td/telegram/'.$header.'.h"'; - if (strpos($new_content, $include_name) !== false && preg_match('/[^a-zA-Z0-9_]('.$pattern.')/', str_replace($include_name, '', $new_content)) === 0) { - $new_content = str_replace($include_name, '', $new_content); - } + $include_name = '#include "td/telegram/'.$header.'.h"'; + if (strpos($new_content, $include_name) !== false && preg_match('/[^a-zA-Z0-9_]('.$pattern.')/', str_replace($include_name, '', $new_content)) === 0) { + $new_content = str_replace($include_name, '', $new_content); } - } else { - $new_content = preg_replace_callback( - '|#include "[a-z_A-Z/0-9.]*"|', - function ($matches) { - if (strpos($matches[0], "Manager") !== false || strpos($matches[0], "HashtagHints") !== false || strpos($matches[0], "Td.h") !== false) { - return $matches[0]; - } - return ''; - }, - $new_content - ); } if (!file_exists($new_files[$n]) || file_get_contents($new_files[$n]) !== $new_content) { @@ -487,8 +476,10 @@ function ($matches) { $files = array('td/telegram/ChatManager' => 10, 'td/telegram/MessagesManager' => 50, 'td/telegram/NotificationManager' => 10, + 'td/telegram/Requests' => 50, 'td/telegram/StickersManager' => 10, - 'td/telegram/Td' => 50, + 'td/telegram/StoryManager' => 10, + 'td/telegram/UpdatesManager' => 10, 'td/telegram/UserManager' => 10, 'td/generate/auto/td/telegram/td_api' => 10, 'td/generate/auto/td/telegram/td_api_json' => 10, diff --git a/lib/tgchat/ext/td/example/android/build-tdlib.sh b/lib/tgchat/ext/td/example/android/build-tdlib.sh index c670a922..f62ba1ac 100755 --- a/lib/tgchat/ext/td/example/android/build-tdlib.sh +++ b/lib/tgchat/ext/td/example/android/build-tdlib.sh @@ -39,8 +39,8 @@ cd $(dirname $0) echo "Generating TDLib source files..." mkdir -p build-native-$TDLIB_INTERFACE || exit 1 cd build-native-$TDLIB_INTERFACE -cmake $TDLIB_INTERFACE_OPTION .. || exit 1 -cmake --build . --target prepare_cross_compiling || exit 1 +cmake $TDLIB_INTERFACE_OPTION -DTD_GENERATE_SOURCE_FILES=ON .. || exit 1 +cmake --build . || exit 1 cd .. rm -rf tdlib || exit 1 diff --git a/lib/tgchat/ext/td/example/cpp/CMakeLists.txt b/lib/tgchat/ext/td/example/cpp/CMakeLists.txt index 62648d80..28343436 100644 --- a/lib/tgchat/ext/td/example/cpp/CMakeLists.txt +++ b/lib/tgchat/ext/td/example/cpp/CMakeLists.txt @@ -2,7 +2,7 @@ cmake_minimum_required(VERSION 3.4 FATAL_ERROR) project(TdExample VERSION 1.0 LANGUAGES CXX) -find_package(Td 1.8.35 REQUIRED) +find_package(Td 1.8.36 REQUIRED) add_executable(tdjson_example tdjson_example.cpp) target_link_libraries(tdjson_example PRIVATE Td::TdJson) diff --git a/lib/tgchat/ext/td/example/ios/README.md b/lib/tgchat/ext/td/example/ios/README.md index e1bd1ede..9f91042a 100644 --- a/lib/tgchat/ext/td/example/ios/README.md +++ b/lib/tgchat/ext/td/example/ios/README.md @@ -13,13 +13,13 @@ To compile `TDLib` you will need to: ``` brew install gperf cmake coreutils ``` -* If you don't want to build `TDLib` for macOS first, you **must** pregenerate required source code files using `CMake` prepare_cross_compiling target: +* If you don't want to build `TDLib` for macOS first, you **must** pregenerate required source code files in the following way: ``` cd mkdir native-build cd native-build -cmake .. -cmake --build . --target prepare_cross_compiling +cmake -DTD_GENERATE_SOURCE_FILES=ON .. +cmake --build . ``` * Build OpenSSL for iOS, watchOS, tvOS, visionOS, and macOS: ``` diff --git a/lib/tgchat/ext/td/example/uwp/Telegram.Td.UWP.nuspec b/lib/tgchat/ext/td/example/uwp/Telegram.Td.UWP.nuspec index 84e08b4a..44cd8964 100644 --- a/lib/tgchat/ext/td/example/uwp/Telegram.Td.UWP.nuspec +++ b/lib/tgchat/ext/td/example/uwp/Telegram.Td.UWP.nuspec @@ -2,7 +2,7 @@ Telegram.Td.UWP - 1.8.35 + 1.8.36 TDLib for Universal Windows Platform Telegram Telegram diff --git a/lib/tgchat/ext/td/example/uwp/build.ps1 b/lib/tgchat/ext/td/example/uwp/build.ps1 index 463592fa..dd569b63 100644 --- a/lib/tgchat/ext/td/example/uwp/build.ps1 +++ b/lib/tgchat/ext/td/example/uwp/build.ps1 @@ -42,9 +42,9 @@ function prepare { cd build-native - cmake -A Win32 -DCMAKE_TOOLCHAIN_FILE="$vcpkg_cmake" -DTD_ENABLE_DOTNET=ON "$td_root" + cmake -A Win32 -DTD_GENERATE_SOURCE_FILES=ON -DTD_ENABLE_DOTNET=ON "$td_root" CheckLastExitCode - cmake --build . --target prepare_cross_compiling + cmake --build . CheckLastExitCode cd .. diff --git a/lib/tgchat/ext/td/example/uwp/extension.vsixmanifest b/lib/tgchat/ext/td/example/uwp/extension.vsixmanifest index 094406a1..7cb33103 100644 --- a/lib/tgchat/ext/td/example/uwp/extension.vsixmanifest +++ b/lib/tgchat/ext/td/example/uwp/extension.vsixmanifest @@ -1,6 +1,6 @@ - + TDLib for Universal Windows Platform TDLib is a library for building Telegram clients https://core.telegram.org/tdlib diff --git a/lib/tgchat/ext/td/td/generate/CMakeLists.txt b/lib/tgchat/ext/td/td/generate/CMakeLists.txt index 07f46c3b..1ff2d3d8 100644 --- a/lib/tgchat/ext/td/td/generate/CMakeLists.txt +++ b/lib/tgchat/ext/td/td/generate/CMakeLists.txt @@ -143,7 +143,7 @@ if (NOT CMAKE_CROSSCOMPILING) target_link_libraries(tl_writer_cpp PRIVATE tdtl) target_include_directories(tl_writer_cpp PUBLIC $) if (TD_ENABLE_JNI) - target_compile_definitions(tl_writer_cpp PRIVATE TD_ENABLE_JNI=1) + target_compile_definitions(tl_writer_cpp PRIVATE TD_ENABLE_JNI=1 GIT_COMMIT_HASH=${TD_GIT_COMMIT_HASH}) endif() if (TD_ENABLE_DOTNET) target_compile_definitions(tl_writer_cpp PRIVATE DISABLE_HPP_DOCUMENTATION=1) @@ -181,6 +181,7 @@ if (NOT CMAKE_CROSSCOMPILING) add_executable(td_generate_java_api ${TL_GENERATE_JAVA_SOURCE}) target_link_libraries(td_generate_java_api PRIVATE tdtl) + target_compile_definitions(td_generate_java_api PRIVATE GIT_COMMIT_HASH=${TD_GIT_COMMIT_HASH}) add_executable(generate_json ${TL_GENERATE_JSON_SOURCE}) target_link_libraries(generate_json PRIVATE tdtl tdutils) diff --git a/lib/tgchat/ext/td/td/generate/DoxygenTlDocumentationGenerator.php b/lib/tgchat/ext/td/td/generate/DoxygenTlDocumentationGenerator.php index aee94a03..5fa507ba 100644 --- a/lib/tgchat/ext/td/td/generate/DoxygenTlDocumentationGenerator.php +++ b/lib/tgchat/ext/td/td/generate/DoxygenTlDocumentationGenerator.php @@ -130,7 +130,7 @@ protected function needSkipLine($line) strpos($tline, 'result += ') === 0 || strpos($tline, 'result = ') || strpos($tline, ' : values') || strpos($line, 'JNIEnv') || strpos($line, 'jfieldID') || $tline === 'virtual ~Object() {' || $tline === 'virtual void store(TlStorerToString &s, const char *field_name) const = 0;' || - $tline === 'const char *&get_package_name_ref();'; + $tline === 'const char *&get_package_name_ref();' || $tline === 'const char *get_git_commit_hash();'; } protected function isHeaderLine($line) diff --git a/lib/tgchat/ext/td/td/generate/scheme/td_api.tl b/lib/tgchat/ext/td/td/generate/scheme/td_api.tl index cb798a2d..a267cc53 100644 --- a/lib/tgchat/ext/td/td/generate/scheme/td_api.tl +++ b/lib/tgchat/ext/td/td/generate/scheme/td_api.tl @@ -845,16 +845,16 @@ premiumPaymentOption currency:string amount:int53 discount_percentage:int32 mont //@last_transaction_id Identifier of the last in-store transaction for the currently used option premiumStatePaymentOption payment_option:premiumPaymentOption is_current:Bool is_upgrade:Bool last_transaction_id:string = PremiumStatePaymentOption; -//@description Describes an option for creating Telegram Premium gift codes. Use telegramPaymentPurposePremiumGiftCodes for out-of-store payments +//@description Describes an option for creating Telegram Premium gift codes or Telegram Premium giveaway. Use telegramPaymentPurposePremiumGiftCodes or telegramPaymentPurposePremiumGiveaway for out-of-store payments //@currency ISO 4217 currency code for Telegram Premium gift code payment //@amount The amount to pay, in the smallest units of the currency -//@user_count Number of users which will be able to activate the gift codes +//@winner_count Number of users which will be able to activate the gift codes //@month_count Number of months the Telegram Premium subscription will be active //@store_product_id Identifier of the store product associated with the option; may be empty if none //@store_product_quantity Number of times the store product must be paid -premiumGiftCodePaymentOption currency:string amount:int53 user_count:int32 month_count:int32 store_product_id:string store_product_quantity:int32 = PremiumGiftCodePaymentOption; +premiumGiftCodePaymentOption currency:string amount:int53 winner_count:int32 month_count:int32 store_product_id:string store_product_quantity:int32 = PremiumGiftCodePaymentOption; -//@description Contains a list of options for creating Telegram Premium gift codes @options The list of options +//@description Contains a list of options for creating Telegram Premium gift codes or Telegram Premium giveaway @options The list of options premiumGiftCodePaymentOptions options:vector = PremiumGiftCodePaymentOptions; //@description Contains information about a Telegram Premium gift code @@ -878,6 +878,26 @@ starPaymentOption currency:string amount:int53 star_count:int53 store_product_id //@description Contains a list of options for buying Telegram Stars @options The list of options starPaymentOptions options:vector = StarPaymentOptions; +//@description Describes an option for the number of winners of a Telegram Star giveaway +//@winner_count The number of users that will be chosen as winners +//@won_star_count The number of Telegram Stars that will be won by the winners of the giveaway +//@is_default True, if the option must be chosen by default +starGiveawayWinnerOption winner_count:int32 won_star_count:int53 is_default:Bool = StarGiveawayWinnerOption; + +//@description Describes an option for creating Telegram Star giveaway. Use telegramPaymentPurposeStarGiveaway for out-of-store payments +//@currency ISO 4217 currency code for the payment +//@amount The amount to pay, in the smallest units of the currency +//@star_count Number of Telegram Stars that will be distributed among winners +//@store_product_id Identifier of the store product associated with the option; may be empty if none +//@yearly_boost_count Number of times the chat will be boosted for one year if the option is chosen +//@winner_options Allowed options for the number of giveaway winners +//@is_default True, if the option must be chosen by default +//@is_additional True, if the option must be shown only in the full list of payment options +starGiveawayPaymentOption currency:string amount:int53 star_count:int53 store_product_id:string yearly_boost_count:int32 winner_options:vector is_default:Bool is_additional:Bool = StarGiveawayPaymentOption; + +//@description Contains a list of options for creating Telegram Star giveaway @options The list of options +starGiveawayPaymentOptions options:vector = StarGiveawayPaymentOptions; + //@class StarTransactionDirection @description Describes direction of a transaction with Telegram Stars @@ -890,8 +910,8 @@ starTransactionDirectionOutgoing = StarTransactionDirection; //@class BotTransactionPurpose @description Describes purpose of a transaction with a bot -//@description Paid media were bought @media The bought media if the trancastion wasn't refunded -botTransactionPurposePaidMedia media:vector = BotTransactionPurpose; +//@description Paid media were bought @media The bought media if the trancastion wasn't refunded @payload Bot-provided payload; for bots only +botTransactionPurposePaidMedia media:vector payload:string = BotTransactionPurpose; //@description User bought a product from the bot //@product_info Information about the bought product; may be null if not applicable @@ -899,20 +919,23 @@ botTransactionPurposePaidMedia media:vector = BotTransactionPurpose; botTransactionPurposeInvoicePayment product_info:productInfo invoice_payload:bytes = BotTransactionPurpose; -//@class ChannelTransactionPurpose @description Describes purpose of a transaction with a channel +//@class ChatTransactionPurpose @description Describes purpose of a transaction with a supergroup or a channel //@description Paid media were bought -//@message_id Identifier of the corresponding message with paid media; can be an identifier of a deleted message +//@message_id Identifier of the corresponding message with paid media; can be 0 or an identifier of a deleted message //@media The bought media if the trancastion wasn't refunded -channelTransactionPurposePaidMedia message_id:int53 media:vector = ChannelTransactionPurpose; +chatTransactionPurposePaidMedia message_id:int53 media:vector = ChatTransactionPurpose; //@description User joined the channel and subscribed to regular payments in Telegram Stars //@period The number of seconds between consecutive Telegram Star debiting -channelTransactionPurposeJoin period:int32 = ChannelTransactionPurpose; +chatTransactionPurposeJoin period:int32 = ChatTransactionPurpose; //@description User paid for a reaction -//@message_id Identifier of the reacted message; can be an identifier of a deleted message -channelTransactionPurposeReaction message_id:int53 = ChannelTransactionPurpose; +//@message_id Identifier of the reacted message; can be 0 or an identifier of a deleted message +chatTransactionPurposeReaction message_id:int53 = ChatTransactionPurpose; + +//@description User received Telegram Stars from a giveaway @giveaway_message_id Identifier of the message with giveaway; can be 0 or an identifier of a deleted message +chatTransactionPurposeGiveaway giveaway_message_id:int53 = ChatTransactionPurpose; //@class StarTransactionPartner @description Describes source or recipient of a transaction with Telegram Stars @@ -938,8 +961,8 @@ starTransactionPartnerBot user_id:int53 purpose:BotTransactionPurpose = StarTran //@description The transaction is a transaction with a business account @user_id Identifier of the business account user @media The bought media if the trancastion wasn't refunded starTransactionPartnerBusiness user_id:int53 media:vector = StarTransactionPartner; -//@description The transaction is a transaction with a channel chat @chat_id Identifier of the chat @purpose Purpose of the transaction -starTransactionPartnerChannel chat_id:int53 purpose:ChannelTransactionPurpose = StarTransactionPartner; +//@description The transaction is a transaction with a supergroup or a channel chat @chat_id Identifier of the chat @purpose Purpose of the transaction +starTransactionPartnerChat chat_id:int53 purpose:ChatTransactionPurpose = StarTransactionPartner; //@description The transaction is a gift of Telegram Stars from another user //@user_id Identifier of the user; 0 if the gift was anonymous @@ -965,41 +988,52 @@ starTransaction id:string star_count:int53 is_refund:Bool date:int32 partner:Sta starTransactions star_count:int53 transactions:vector next_offset:string = StarTransactions; -//@class PremiumGiveawayParticipantStatus @description Contains information about status of a user in a Telegram Premium giveaway +//@class GiveawayParticipantStatus @description Contains information about status of a user in a giveaway //@description The user is eligible for the giveaway -premiumGiveawayParticipantStatusEligible = PremiumGiveawayParticipantStatus; +giveawayParticipantStatusEligible = GiveawayParticipantStatus; //@description The user participates in the giveaway -premiumGiveawayParticipantStatusParticipating = PremiumGiveawayParticipantStatus; +giveawayParticipantStatusParticipating = GiveawayParticipantStatus; //@description The user can't participate in the giveaway, because they have already been member of the chat //@joined_chat_date Point in time (Unix timestamp) when the user joined the chat -premiumGiveawayParticipantStatusAlreadyWasMember joined_chat_date:int32 = PremiumGiveawayParticipantStatus; +giveawayParticipantStatusAlreadyWasMember joined_chat_date:int32 = GiveawayParticipantStatus; //@description The user can't participate in the giveaway, because they are an administrator in one of the chats that created the giveaway @chat_id Identifier of the chat administered by the user -premiumGiveawayParticipantStatusAdministrator chat_id:int53 = PremiumGiveawayParticipantStatus; +giveawayParticipantStatusAdministrator chat_id:int53 = GiveawayParticipantStatus; //@description The user can't participate in the giveaway, because they phone number is from a disallowed country @user_country_code A two-letter ISO 3166-1 alpha-2 country code of the user's country -premiumGiveawayParticipantStatusDisallowedCountry user_country_code:string = PremiumGiveawayParticipantStatus; +giveawayParticipantStatusDisallowedCountry user_country_code:string = GiveawayParticipantStatus; -//@class PremiumGiveawayInfo @description Contains information about Telegram Premium giveaway +//@class GiveawayInfo @description Contains information about a giveaway //@description Describes an ongoing giveaway //@creation_date Point in time (Unix timestamp) when the giveaway was created //@status Status of the current user in the giveaway //@is_ended True, if the giveaway has ended and results are being prepared -premiumGiveawayInfoOngoing creation_date:int32 status:PremiumGiveawayParticipantStatus is_ended:Bool = PremiumGiveawayInfo; +giveawayInfoOngoing creation_date:int32 status:GiveawayParticipantStatus is_ended:Bool = GiveawayInfo; //@description Describes a completed giveaway //@creation_date Point in time (Unix timestamp) when the giveaway was created //@actual_winners_selection_date Point in time (Unix timestamp) when the winners were selected. May be bigger than winners selection date specified in parameters of the giveaway //@was_refunded True, if the giveaway was canceled and was fully refunded +//@is_winner True, if the cuurent user is a winner of the giveaway //@winner_count Number of winners in the giveaway -//@activation_count Number of winners, which activated their gift codes -//@gift_code Telegram Premium gift code that was received by the current user; empty if the user isn't a winner in the giveaway -premiumGiveawayInfoCompleted creation_date:int32 actual_winners_selection_date:int32 was_refunded:Bool winner_count:int32 activation_count:int32 gift_code:string = PremiumGiveawayInfo; +//@activation_count Number of winners, which activated their gift codes; for Telegram Premium giveaways only +//@gift_code Telegram Premium gift code that was received by the current user; empty if the user isn't a winner in the giveaway or the giveaway isn't a Telegram Premium giveaway +//@won_star_count The amount of Telegram Stars won by the current user; 0 if the user isn't a winner in the giveaway or the giveaway isn't a Telegram Star giveaway +giveawayInfoCompleted creation_date:int32 actual_winners_selection_date:int32 was_refunded:Bool is_winner:Bool winner_count:int32 activation_count:int32 gift_code:string won_star_count:int53 = GiveawayInfo; + + +//@class GiveawayPrize @description Contains information about a giveaway prize + +//@description The giveaway sends Telegram Premium subscriptions to the winners @month_count Number of months the Telegram Premium subscription will be active after code activation +giveawayPrizePremium month_count:int32 = GiveawayPrize; + +//@description The giveaway sends Telegram Stars to the winners @star_count Number of Telegram Stars that will be shared by all winners +giveawayPrizeStars star_count:int53 = GiveawayPrize; //@description Contains information about supported accent color for user/chat name, background of empty chat photo, replies to messages and link previews @@ -1622,9 +1656,9 @@ inputTextQuote text:formattedText position:int32 = InputTextQuote; //@origin Information about origin of the message if the message was from another chat or topic; may be null for messages from the same chat //@origin_send_date Point in time (Unix timestamp) when the message was sent if the message was from another chat or topic; 0 for messages from the same chat //@content Media content of the message if the message was from another chat or topic; may be null for messages from the same chat and messages without media. -//-Can be only one of the following types: messageAnimation, messageAudio, messageContact, messageDice, messageDocument, messageGame, messageInvoice, messageLocation, -//-messagePaidMedia, messagePhoto, messagePoll, messagePremiumGiveaway, messagePremiumGiveawayWinners, messageSticker, messageStory, messageText (for link preview), -//-messageVenue, messageVideo, messageVideoNote, or messageVoiceNote +//-Can be only one of the following types: messageAnimation, messageAudio, messageContact, messageDice, messageDocument, messageGame, messageGiveaway, messageGiveawayWinners, +//-messageInvoice, messageLocation, messagePaidMedia, messagePhoto, messagePoll, messageSticker, messageStory, messageText (for link preview), messageVenue, messageVideo, +//-messageVideoNote, or messageVoiceNote messageReplyToMessage chat_id:int53 message_id:int53 quote:textQuote origin:MessageOrigin origin_send_date:int32 content:MessageContent = MessageReplyTo; //@description Describes a story replied by a given message @story_sender_chat_id The identifier of the sender of the story @story_id The identifier of the story @@ -2656,22 +2690,17 @@ linkPreviewAlbumMediaVideo video:video = LinkPreviewAlbumMedia; //@description The link is a link to a media album consisting of photos and videos @media The list of album media @caption Album caption linkPreviewTypeAlbum media:vector caption:string = LinkPreviewType; -//@description The link is a link to an animation @animation The animation @author Author of the animation -linkPreviewTypeAnimation animation:animation author:string = LinkPreviewType; +//@description The link is a link to an animation @animation The animation +linkPreviewTypeAnimation animation:animation = LinkPreviewType; -//@description The link is a link to an app at App Store or Google Play @photo Photo for the app @author Author of the app -linkPreviewTypeApp photo:photo author:string = LinkPreviewType; +//@description The link is a link to an app at App Store or Google Play @photo Photo for the app +linkPreviewTypeApp photo:photo = LinkPreviewType; -//@description The link is a link to a web site @photo Article's main photo; may be null @author Author of the article -linkPreviewTypeArticle photo:photo author:string = LinkPreviewType; +//@description The link is a link to a web site @photo Article's main photo; may be null +linkPreviewTypeArticle photo:photo = LinkPreviewType; -//@description The link is a link to an audio -//@url URL of the audio; may be empty if none -//@mime_type MIME type of the audio file -//@audio The audio description; may be null if unknown -//@duration Duration of the audio, in seconds; 0 if unknown -//@author Author of the audio -linkPreviewTypeAudio url:string mime_type:string audio:audio duration:int32 author:string = LinkPreviewType; +//@description The link is a link to an audio @audio The audio description +linkPreviewTypeAudio audio:audio = LinkPreviewType; //@description The link is a link to a background. Link preview title and description are available only for filled backgrounds //@document Document with the background; may be null for filled backgrounds @@ -2687,35 +2716,46 @@ linkPreviewTypeChannelBoost photo:chatPhoto = LinkPreviewType; //@creates_join_request True, if the link only creates join request linkPreviewTypeChat type:InviteLinkChatType photo:chatPhoto creates_join_request:Bool = LinkPreviewType; -//@description The link is a link to a general file @document The document description @author Author of the document -linkPreviewTypeDocument document:document author:string = LinkPreviewType; +//@description The link is a link to a general file @document The document description +linkPreviewTypeDocument document:document = LinkPreviewType; //@description The link is a link to an animation player //@url URL of the external animation player //@thumbnail Thumbnail of the animation; may be null if unknown //@duration Duration of the animation, in seconds -//@author Author of the animation //@width Expected width of the embedded player //@height Expected height of the embedded player -linkPreviewTypeEmbeddedAnimationPlayer url:string thumbnail:photo duration:int32 author:string width:int32 height:int32 = LinkPreviewType; +linkPreviewTypeEmbeddedAnimationPlayer url:string thumbnail:photo duration:int32 width:int32 height:int32 = LinkPreviewType; //@description The link is a link to an audio player //@url URL of the external audio player //@thumbnail Thumbnail of the audio; may be null if unknown //@duration Duration of the audio, in seconds -//@author Author of the audio //@width Expected width of the embedded player //@height Expected height of the embedded player -linkPreviewTypeEmbeddedAudioPlayer url:string thumbnail:photo duration:int32 author:string width:int32 height:int32 = LinkPreviewType; +linkPreviewTypeEmbeddedAudioPlayer url:string thumbnail:photo duration:int32 width:int32 height:int32 = LinkPreviewType; //@description The link is a link to a video player //@url URL of the external video player //@thumbnail Thumbnail of the video; may be null if unknown //@duration Duration of the video, in seconds -//@author Author of the video //@width Expected width of the embedded player //@height Expected height of the embedded player -linkPreviewTypeEmbeddedVideoPlayer url:string thumbnail:photo duration:int32 author:string width:int32 height:int32 = LinkPreviewType; +linkPreviewTypeEmbeddedVideoPlayer url:string thumbnail:photo duration:int32 width:int32 height:int32 = LinkPreviewType; + +//@description The link is a link to an audio file +//@url URL of the audio file +//@mime_type MIME type of the audio file +//@duration Duration of the audio, in seconds; 0 if unknown +linkPreviewTypeExternalAudio url:string mime_type:string duration:int32 = LinkPreviewType; + +//@description The link is a link to a video file +//@url URL of the video file +//@mime_type MIME type of the video file +//@width Expected width of the video preview; 0 if unknown +//@height Expected height of the video preview; 0 if unknown +//@duration Duration of the video, in seconds; 0 if unknown +linkPreviewTypeExternalVideo url:string mime_type:string width:int32 height:int32 duration:int32 = LinkPreviewType; //@description The link is a link to an invoice linkPreviewTypeInvoice = LinkPreviewType; @@ -2723,8 +2763,8 @@ linkPreviewTypeInvoice = LinkPreviewType; //@description The link is a link to a text or a poll Telegram message linkPreviewTypeMessage = LinkPreviewType; -//@description The link is a link to a photo @photo The photo @author Author of the photo -linkPreviewTypePhoto photo:photo author:string = LinkPreviewType; +//@description The link is a link to a photo @photo The photo +linkPreviewTypePhoto photo:photo = LinkPreviewType; //@description The link is a link to a Telegram Premium gift code linkPreviewTypePremiumGiftCode = LinkPreviewType; @@ -2753,15 +2793,8 @@ linkPreviewTypeUnsupported = LinkPreviewType; //@description The link is a link to a user @photo Photo of the user; may be null if none @is_bot True, if the user is a bot linkPreviewTypeUser photo:chatPhoto is_bot:Bool = LinkPreviewType; -//@description The link is a link to a video -//@url URL of the video; may be empty if none -//@mime_type MIME type of the video file -//@video The video description; may be null if unknown -//@width Expected width of the preview -//@height Expected height of the preview -//@duration Duration of the video, in seconds; 0 if unknown -//@author Author of the video -linkPreviewTypeVideo url:string mime_type:string video:video width:int32 height:int32 duration:int32 author:string = LinkPreviewType; +//@description The link is a link to a video @video The video description +linkPreviewTypeVideo video:video = LinkPreviewType; //@description The link is a link to a video chat //@photo Photo of the chat with the video chat; may be null if none @@ -2784,6 +2817,7 @@ linkPreviewTypeWebApp photo:photo = LinkPreviewType; //@site_name Short name of the site (e.g., Google Docs, App Store) //@title Title of the content //@param_description Description of the content +//@author Author of the content //@type Type of the link preview //@has_large_media True, if size of media in the preview can be changed //@show_large_media True, if large media preview must be shown; otherwise, the media preview must be shown small and only the first frame must be shown for videos @@ -2791,7 +2825,7 @@ linkPreviewTypeWebApp photo:photo = LinkPreviewType; //@skip_confirmation True, if there is no need to show an ordinary open URL confirmation, when opening the URL from the preview, because the URL is shown in the message text in clear //@show_above_text True, if the link preview must be shown above message text; otherwise, the link preview must be shown below the message text //@instant_view_version Version of instant view (currently, can be 1 or 2) for the web page; 0 if none -linkPreview url:string display_url:string site_name:string title:string description:formattedText type:LinkPreviewType has_large_media:Bool show_large_media:Bool show_media_above_description:Bool skip_confirmation:Bool show_above_text:Bool instant_view_version:int32 = LinkPreview; +linkPreview url:string display_url:string site_name:string title:string description:formattedText author:string type:LinkPreviewType has_large_media:Bool show_large_media:Bool show_media_above_description:Bool skip_confirmation:Bool show_above_text:Bool instant_view_version:int32 = LinkPreview; //@description Contains information about a country @@ -2860,6 +2894,7 @@ locationAddress country_code:string state:string city:string street:string = Loc //@background_color A color of the background in the RGB24 format //@secondary_background_color A secondary color for the background in the RGB24 format //@header_background_color A color of the header background in the RGB24 format +//@bottom_bar_background_color A color of the bottom bar background in the RGB24 format //@section_background_color A color of the section background in the RGB24 format //@section_separator_color A color of the section separator in the RGB24 format //@text_color A color of text in the RGB24 format @@ -2871,7 +2906,7 @@ locationAddress country_code:string state:string city:string street:string = Loc //@link_color A color of links in the RGB24 format //@button_color A color of the buttons in the RGB24 format //@button_text_color A color of text on the buttons in the RGB24 format -themeParameters background_color:int32 secondary_background_color:int32 header_background_color:int32 section_background_color:int32 section_separator_color:int32 text_color:int32 accent_text_color:int32 section_header_text_color:int32 subtitle_text_color:int32 destructive_text_color:int32 hint_color:int32 link_color:int32 button_color:int32 button_text_color:int32 = ThemeParameters; +themeParameters background_color:int32 secondary_background_color:int32 header_background_color:int32 bottom_bar_background_color:int32 section_background_color:int32 section_separator_color:int32 text_color:int32 accent_text_color:int32 section_header_text_color:int32 subtitle_text_color:int32 destructive_text_color:int32 hint_color:int32 link_color:int32 button_color:int32 button_text_color:int32 = ThemeParameters; //@description Portion of the price of a product (e.g., "delivery cost", "tax amount") @label Label for this portion of the product price @amount Currency amount in the smallest units of the currency @@ -3035,9 +3070,9 @@ paidMediaVideo video:video = PaidMedia; paidMediaUnsupported = PaidMedia; -//@description Describes parameters of a Telegram Premium giveaway -//@boosted_chat_id Identifier of the supergroup or channel chat, which will be automatically boosted by the winners of the giveaway for duration of the Premium subscription. -//-If the chat is a channel, then can_post_messages right is required in the channel, otherwise, the user must be an administrator in the supergroup +//@description Describes parameters of a giveaway +//@boosted_chat_id Identifier of the supergroup or channel chat, which will be automatically boosted by the winners of the giveaway for duration of the Telegram Premium subscription, +//-or for the specified time. If the chat is a channel, then can_post_messages right is required in the channel, otherwise, the user must be an administrator in the supergroup //@additional_chat_ids Identifiers of other supergroup or channel chats that must be subscribed by the users to be eligible for the giveaway. There can be up to getOption("giveaway_additional_chat_count_max") additional chats //@winners_selection_date Point in time (Unix timestamp) when the giveaway is expected to be performed; must be 60-getOption("giveaway_duration_max") seconds in the future in scheduled giveaways //@only_new_members True, if only new members of the chats will be eligible for the giveaway @@ -3045,7 +3080,7 @@ paidMediaUnsupported = PaidMedia; //@country_codes The list of two-letter ISO 3166-1 alpha-2 codes of countries, users from which will be eligible for the giveaway. If empty, then all users can participate in the giveaway. //-There can be up to getOption("giveaway_country_count_max") chosen countries. Users with phone number that was bought at https://fragment.com can participate in any giveaway and the country code "FT" must not be specified in the list //@prize_description Additional description of the giveaway prize; 0-128 characters -premiumGiveawayParameters boosted_chat_id:int53 additional_chat_ids:vector winners_selection_date:int32 only_new_members:Bool has_public_winners:Bool country_codes:vector prize_description:string = PremiumGiveawayParameters; +giveawayParameters boosted_chat_id:int53 additional_chat_ids:vector winners_selection_date:int32 only_new_members:Bool has_public_winners:Bool country_codes:vector prize_description:string = GiveawayParameters; //@description File with the date it was uploaded @file The file @date Point in time (Unix timestamp) when the file was uploaded @@ -3591,35 +3626,37 @@ messageGiftedPremium gifter_user_id:int53 receiver_user_id:int53 currency:string //@code The gift code messagePremiumGiftCode creator_id:MessageSender is_from_giveaway:Bool is_unclaimed:Bool currency:string amount:int53 cryptocurrency:string cryptocurrency_amount:int64 month_count:int32 sticker:sticker code:string = MessageContent; -//@description A Telegram Premium giveaway was created for the chat. Use telegramPaymentPurposePremiumGiveaway or storePaymentPurposePremiumGiveaway to create a giveaway -messagePremiumGiveawayCreated = MessageContent; +//@description A giveaway was created for the chat. Use telegramPaymentPurposePremiumGiveaway, storePaymentPurposePremiumGiveaway, telegramPaymentPurposeStarGiveaway, or storePaymentPurposeStarGiveaway to create a giveaway +//@star_count Number of Telegram Stars that will be shared by winners of the giveaway; 0 for Telegram Premium giveaways +messageGiveawayCreated star_count:int53 = MessageContent; -//@description A Telegram Premium giveaway +//@description A giveaway //@parameters Giveaway parameters //@winner_count Number of users which will receive Telegram Premium subscription gift codes -//@month_count Number of months the Telegram Premium subscription will be active after code activation +//@prize Prize of the giveaway //@sticker A sticker to be shown in the message; may be null if unknown -messagePremiumGiveaway parameters:premiumGiveawayParameters winner_count:int32 month_count:int32 sticker:sticker = MessageContent; +messageGiveaway parameters:giveawayParameters winner_count:int32 prize:GiveawayPrize sticker:sticker = MessageContent; -//@description A Telegram Premium giveaway without public winners has been completed for the chat +//@description A giveaway without public winners has been completed for the chat //@giveaway_message_id Identifier of the message with the giveaway; can be 0 if the message was deleted //@winner_count Number of winners in the giveaway -//@unclaimed_prize_count Number of undistributed prizes -messagePremiumGiveawayCompleted giveaway_message_id:int53 winner_count:int32 unclaimed_prize_count:int32 = MessageContent; +//@is_star_giveaway True, if the giveaway is a Telegram Star giveaway +//@unclaimed_prize_count Number of undistributed prizes; for Telegram Premium giveaways only +messageGiveawayCompleted giveaway_message_id:int53 winner_count:int32 is_star_giveaway:Bool unclaimed_prize_count:int32 = MessageContent; -//@description A Telegram Premium giveaway with public winners has been completed for the chat -//@boosted_chat_id Identifier of the channel chat, which was automatically boosted by the winners of the giveaway for duration of the Premium subscription +//@description A giveaway with public winners has been completed for the chat +//@boosted_chat_id Identifier of the supergroup or channel chat, which was automatically boosted by the winners of the giveaway //@giveaway_message_id Identifier of the message with the giveaway in the boosted chat //@additional_chat_count Number of other chats that participated in the giveaway //@actual_winners_selection_date Point in time (Unix timestamp) when the winners were selected. May be bigger than winners selection date specified in parameters of the giveaway //@only_new_members True, if only new members of the chats were eligible for the giveaway //@was_refunded True, if the giveaway was canceled and was fully refunded -//@month_count Number of months the Telegram Premium subscription will be active after code activation +//@prize Prize of the giveaway //@prize_description Additional description of the giveaway prize //@winner_count Total number of winners in the giveaway //@winner_user_ids Up to 100 user identifiers of the winners of the giveaway -//@unclaimed_prize_count Number of undistributed prizes -messagePremiumGiveawayWinners boosted_chat_id:int53 giveaway_message_id:int53 additional_chat_count:int32 actual_winners_selection_date:int32 only_new_members:Bool was_refunded:Bool month_count:int32 prize_description:string winner_count:int32 winner_user_ids:vector unclaimed_prize_count:int32 = MessageContent; +//@unclaimed_prize_count Number of undistributed prizes; for Telegram Premium giveaways only +messageGiveawayWinners boosted_chat_id:int53 giveaway_message_id:int53 additional_chat_count:int32 actual_winners_selection_date:int32 only_new_members:Bool was_refunded:Bool prize:GiveawayPrize prize_description:string winner_count:int32 winner_user_ids:vector unclaimed_prize_count:int32 = MessageContent; //@description Telegram Stars were gifted to a user //@gifter_user_id The identifier of a user that gifted Telegram Stars; 0 if the gift was anonymous or is outgoing @@ -3633,6 +3670,15 @@ messagePremiumGiveawayWinners boosted_chat_id:int53 giveaway_message_id:int53 ad //@sticker A sticker to be shown in the message; may be null if unknown messageGiftedStars gifter_user_id:int53 receiver_user_id:int53 currency:string amount:int53 cryptocurrency:string cryptocurrency_amount:int64 star_count:int53 transaction_id:string sticker:sticker = MessageContent; +//@description A Telegram Stars were received by the cuurent user from a giveaway +//@star_count Number of Telegram Stars that were received +//@transaction_id Identifier of the transaction for Telegram Stars credit +//@boosted_chat_id Identifier of the supergroup or channel chat, which was automatically boosted by the winners of the giveaway +//@giveaway_message_id Identifier of the message with the giveaway in the boosted chat; can be 0 if the message was deleted +//@is_unclaimed True, if the corresponding winner wasn't chosen and the Telegram Stars were received by the owner of the boosted chat +//@sticker A sticker to be shown in the message; may be null if unknown +messageGiveawayPrizeStars star_count:int53 transaction_id:string boosted_chat_id:int53 giveaway_message_id:int53 is_unclaimed:Bool sticker:sticker = MessageContent; + //@description A contact has registered with Telegram messageContactRegistered = MessageContent; @@ -3790,7 +3836,7 @@ messageSelfDestructTypeImmediately = MessageSelfDestructType; //@only_preview Pass true to get a fake message instead of actually sending them messageSendOptions disable_notification:Bool from_background:Bool protect_content:Bool update_order_of_installed_sticker_sets:Bool scheduling_state:MessageSchedulingState effect_id:int64 sending_id:int32 only_preview:Bool = MessageSendOptions; -//@description Options to be used when a message content is copied without reference to the original sender. Service messages, messages with messageInvoice, messagePaidMedia, messagePremiumGiveaway, or messagePremiumGiveawayWinners content can't be copied +//@description Options to be used when a message content is copied without reference to the original sender. Service messages, messages with messageInvoice, messagePaidMedia, messageGiveaway, or messageGiveawayWinners content can't be copied //@send_copy True, if content of the message needs to be copied without reference to the original sender. Always true if the message is forwarded to a secret chat or is local //@replace_caption True, if media caption of the message copy needs to be replaced. Ignored if send_copy is false //@new_caption New message caption; pass null to copy message without caption. Ignored if replace_caption is false @@ -3840,7 +3886,8 @@ inputMessageDocument document:InputFile thumbnail:inputThumbnail disable_content //@paid_media The content of the paid media //@caption Message caption; pass null to use an empty caption; 0-getOption("message_caption_length_max") characters //@show_caption_above_media True, if the caption must be shown above the video; otherwise, the caption must be shown below the video; not supported in secret chats -inputMessagePaidMedia star_count:int53 paid_media:vector caption:formattedText show_caption_above_media:Bool = InputMessageContent; +//@payload Bot-provided data for the paid media; bots only +inputMessagePaidMedia star_count:int53 paid_media:vector caption:formattedText show_caption_above_media:Bool payload:string = InputMessageContent; //@description A photo message //@photo Photo to send. The photo must be at most 10 MB in size. The photo's width and height must not exceed 10000 in total. Width and height ratio must be at most 20 @@ -3951,6 +3998,7 @@ inputMessageForwarded from_chat_id:int53 message_id:int53 in_game_share:Bool cop //@description Contains properties of a message and describes actions that can be done with the message right now +//@can_be_copied_to_secret_chat True, if content of the message can be copied to a secret chat using inputMessageForwarded or forwardMessages with copy options //@can_be_deleted_only_for_self True, if the message can be deleted only for the current user while other users will continue to see it using the method deleteMessages with revoke == false //@can_be_deleted_for_all_users True, if the message can be deleted for all users using the method deleteMessages with revoke == true //@can_be_edited True, if the message can be edited using the methods editMessageText, editMessageMedia, editMessageCaption, or editMessageReplyMarkup. @@ -3976,7 +4024,7 @@ inputMessageForwarded from_chat_id:int53 message_id:int53 in_game_share:Bool cop //@can_report_supergroup_spam True, if the message can be reported using reportSupergroupSpam //@can_set_fact_check True, if fact check for the message can be changed through setMessageFactCheck //@need_show_statistics True, if message statistics must be available from context menu of the message -messageProperties can_be_deleted_only_for_self:Bool can_be_deleted_for_all_users:Bool can_be_edited:Bool can_be_forwarded:Bool can_be_paid:Bool can_be_pinned:Bool can_be_replied:Bool can_be_replied_in_another_chat:Bool can_be_saved:Bool can_be_shared_in_story:Bool can_edit_scheduling_state:Bool can_get_embedding_code:Bool can_get_link:Bool can_get_media_timestamp_links:Bool can_get_message_thread:Bool can_get_read_date:Bool can_get_statistics:Bool can_get_viewers:Bool can_recognize_speech:Bool can_report_chat:Bool can_report_reactions:Bool can_report_supergroup_spam:Bool can_set_fact_check:Bool need_show_statistics:Bool = MessageProperties; +messageProperties can_be_copied_to_secret_chat:Bool can_be_deleted_only_for_self:Bool can_be_deleted_for_all_users:Bool can_be_edited:Bool can_be_forwarded:Bool can_be_paid:Bool can_be_pinned:Bool can_be_replied:Bool can_be_replied_in_another_chat:Bool can_be_saved:Bool can_be_shared_in_story:Bool can_edit_scheduling_state:Bool can_get_embedding_code:Bool can_get_link:Bool can_get_media_timestamp_links:Bool can_get_message_thread:Bool can_get_read_date:Bool can_get_statistics:Bool can_get_viewers:Bool can_recognize_speech:Bool can_report_chat:Bool can_report_reactions:Bool can_report_supergroup_spam:Bool can_set_fact_check:Bool need_show_statistics:Bool = MessageProperties; //@class SearchMessagesFilter @description Represents a filter for message search results @@ -4536,24 +4584,26 @@ chatBoostFeatures features:vector min_profile_background //@gift_code The created Telegram Premium gift code, which is known only if this is a gift code for the current user, or it has already been claimed chatBoostSourceGiftCode user_id:int53 gift_code:string = ChatBoostSource; -//@description The chat created a Telegram Premium giveaway +//@description The chat created a giveaway //@user_id Identifier of a user that won in the giveaway; 0 if none -//@gift_code The created Telegram Premium gift code if it was used by the user or can be claimed by the current user; an empty string otherwise +//@gift_code The created Telegram Premium gift code if it was used by the user or can be claimed by the current user; an empty string otherwise; for Telegram Premium giveways only +//@star_count Number of Telegram Stars distributed among winners of the giveaway //@giveaway_message_id Identifier of the corresponding giveaway message; can be an identifier of a deleted message -//@is_unclaimed True, if the winner for the corresponding Telegram Premium subscription wasn't chosen, because there were not enough participants -chatBoostSourceGiveaway user_id:int53 gift_code:string giveaway_message_id:int53 is_unclaimed:Bool = ChatBoostSource; +//@is_unclaimed True, if the winner for the corresponding giveaway prize wasn't chosen, because there were not enough participants +chatBoostSourceGiveaway user_id:int53 gift_code:string star_count:int53 giveaway_message_id:int53 is_unclaimed:Bool = ChatBoostSource; //@description A user with Telegram Premium subscription or gifted Telegram Premium boosted the chat //@user_id Identifier of the user chatBoostSourcePremium user_id:int53 = ChatBoostSource; -//@description Describes a prepaid Telegram Premium giveaway +//@description Describes a prepaid giveaway //@id Unique identifier of the prepaid giveaway -//@winner_count Number of users which will receive Telegram Premium subscription gift codes -//@month_count Number of months the Telegram Premium subscription will be active after code activation +//@winner_count Number of users which will receive giveaway prize +//@prize Prize of the giveaway +//@boost_count The number of boosts received by the chat from the giveaway; for Telegram Star giveaways only //@payment_date Point in time (Unix timestamp) when the giveaway was paid -prepaidPremiumGiveaway id:int64 winner_count:int32 month_count:int32 payment_date:int32 = PrepaidPremiumGiveaway; +prepaidGiveaway id:int64 winner_count:int32 prize:GiveawayPrize boost_count:int32 payment_date:int32 = PrepaidGiveaway; //@description Describes current boost status of a chat //@boost_url An HTTP URL, which can be used to boost the chat @@ -4566,7 +4616,7 @@ prepaidPremiumGiveaway id:int64 winner_count:int32 month_count:int32 payment_dat //@premium_member_count Approximate number of Telegram Premium subscribers joined the chat; always 0 if the current user isn't an administrator in the chat //@premium_member_percentage A percentage of Telegram Premium subscribers joined the chat; always 0 if the current user isn't an administrator in the chat //@prepaid_giveaways The list of prepaid giveaways available for the chat; only for chat administrators -chatBoostStatus boost_url:string applied_slot_ids:vector level:int32 gift_code_boost_count:int32 boost_count:int32 current_level_boost_count:int32 next_level_boost_count:int32 premium_member_count:int32 premium_member_percentage:double prepaid_giveaways:vector = ChatBoostStatus; +chatBoostStatus boost_url:string applied_slot_ids:vector level:int32 gift_code_boost_count:int32 boost_count:int32 current_level_boost_count:int32 next_level_boost_count:int32 premium_member_count:int32 premium_member_percentage:double prepaid_giveaways:vector = ChatBoostStatus; //@description Describes a boost applied to a chat //@id Unique identifier of the boost @@ -5282,6 +5332,9 @@ chatEventMemberPromoted user_id:int53 old_status:ChatMemberStatus new_status:Cha //@description A chat member was restricted/unrestricted or banned/unbanned, or the list of their restrictions has changed @member_id Affected chat member identifier @old_status Previous status of the chat member @new_status New status of the chat member chatEventMemberRestricted member_id:MessageSender old_status:ChatMemberStatus new_status:ChatMemberStatus = ChatEventAction; +//@description A chat member extended their subscription to the chat @user_id Affected chat member user identifier @old_status Previous status of the chat member @new_status New status of the chat member +chatEventMemberSubscriptionExtended user_id:int53 old_status:ChatMemberStatus new_status:ChatMemberStatus = ChatEventAction; + //@description The chat available reactions were changed @old_available_reactions Previous chat available reactions @new_available_reactions New chat available reactions chatEventAvailableReactionsChanged old_available_reactions:ChatAvailableReactions new_available_reactions:ChatAvailableReactions = ChatEventAction; @@ -5428,7 +5481,8 @@ chatEvents events:vector = ChatEvents; //@invite_link_changes True, if changes to invite links need to be returned //@video_chat_changes True, if video chat actions need to be returned //@forum_changes True, if forum-related actions need to be returned -chatEventLogFilters message_edits:Bool message_deletions:Bool message_pins:Bool member_joins:Bool member_leaves:Bool member_invites:Bool member_promotions:Bool member_restrictions:Bool info_changes:Bool setting_changes:Bool invite_link_changes:Bool video_chat_changes:Bool forum_changes:Bool = ChatEventLogFilters; +//@subscription_extensions True, if subscription extensions need to be returned +chatEventLogFilters message_edits:Bool message_deletions:Bool message_pins:Bool member_joins:Bool member_leaves:Bool member_invites:Bool member_promotions:Bool member_restrictions:Bool info_changes:Bool setting_changes:Bool invite_link_changes:Bool video_chat_changes:Bool forum_changes:Bool subscription_extensions:Bool = ChatEventLogFilters; //@class LanguagePackStringValue @description Represents the value of a string in a language pack @@ -5741,7 +5795,15 @@ storePaymentPurposePremiumGiftCodes boosted_chat_id:int53 currency:string amount //@parameters Giveaway parameters //@currency ISO 4217 currency code of the payment currency //@amount Paid amount, in the smallest units of the currency -storePaymentPurposePremiumGiveaway parameters:premiumGiveawayParameters currency:string amount:int53 = StorePaymentPurpose; +storePaymentPurposePremiumGiveaway parameters:giveawayParameters currency:string amount:int53 = StorePaymentPurpose; + +//@description The user creating a Telegram Star giveaway +//@parameters Giveaway parameters +//@currency ISO 4217 currency code of the payment currency +//@amount Paid amount, in the smallest units of the currency +//@winner_count The number of users to receive Telegram Stars +//@star_count The number of Telegram Stars to be distributed through the giveaway +storePaymentPurposeStarGiveaway parameters:giveawayParameters currency:string amount:int53 winner_count:int32 star_count:int53 = StorePaymentPurpose; //@description The user buying Telegram Stars //@currency ISO 4217 currency code of the payment currency @@ -5773,7 +5835,7 @@ telegramPaymentPurposePremiumGiftCodes boosted_chat_id:int53 currency:string amo //@amount Paid amount, in the smallest units of the currency //@winner_count Number of users which will be able to activate the gift codes //@month_count Number of months the Telegram Premium subscription will be active for the users -telegramPaymentPurposePremiumGiveaway parameters:premiumGiveawayParameters currency:string amount:int53 winner_count:int32 month_count:int32 = TelegramPaymentPurpose; +telegramPaymentPurposePremiumGiveaway parameters:giveawayParameters currency:string amount:int53 winner_count:int32 month_count:int32 = TelegramPaymentPurpose; //@description The user buying Telegram Stars //@currency ISO 4217 currency code of the payment currency @@ -5788,6 +5850,14 @@ telegramPaymentPurposeStars currency:string amount:int53 star_count:int53 = Tele //@star_count Number of bought Telegram Stars telegramPaymentPurposeGiftedStars user_id:int53 currency:string amount:int53 star_count:int53 = TelegramPaymentPurpose; +//@description The user creating a Telegram Star giveaway +//@parameters Giveaway parameters +//@currency ISO 4217 currency code of the payment currency +//@amount Paid amount, in the smallest units of the currency +//@winner_count The number of users to receive Telegram Stars +//@star_count The number of Telegram Stars to be distributed through the giveaway +telegramPaymentPurposeStarGiveaway parameters:giveawayParameters currency:string amount:int53 winner_count:int32 star_count:int53 = TelegramPaymentPurpose; + //@description The user joins a chat and subscribes to regular payments in Telegram Stars @invite_link Invite link to use telegramPaymentPurposeJoinChat invite_link:string = TelegramPaymentPurpose; @@ -6055,11 +6125,11 @@ pushMessageContentPoll question:string is_regular:Bool is_pinned:Bool = PushMess //@description A message with a Telegram Premium gift code created for the user @month_count Number of months the Telegram Premium subscription will be active after code activation pushMessageContentPremiumGiftCode month_count:int32 = PushMessageContent; -//@description A message with a Telegram Premium giveaway -//@winner_count Number of users which will receive Telegram Premium subscription gift codes; 0 for pinned message -//@month_count Number of months the Telegram Premium subscription will be active after code activation; 0 for pinned message +//@description A message with a giveaway +//@winner_count Number of users which will receive giveaway prizes; 0 for pinned message +//@prize Prize of the giveaway; may be null for pinned message //@is_pinned True, if the message is a pinned message with the specified content -pushMessageContentPremiumGiveaway winner_count:int32 month_count:int32 is_pinned:Bool = PushMessageContent; +pushMessageContentGiveaway winner_count:int32 prize:GiveawayPrize is_pinned:Bool = PushMessageContent; //@description A screenshot of a message in the chat has been taken pushMessageContentScreenshotTaken = PushMessageContent; @@ -6348,7 +6418,7 @@ canSendMessageToUserResultUserIsDeleted = CanSendMessageToUserResult; canSendMessageToUserResultUserRestrictsNewChats = CanSendMessageToUserResult; -//@description Contains information about the period of inactivity after which the current user's account will automatically be deleted @days Number of days of inactivity before the account will be flagged for deletion; 30-366 days +//@description Contains information about the period of inactivity after which the current user's account will automatically be deleted @days Number of days of inactivity before the account will be flagged for deletion; 30-730 days accountTtl days:int32 = AccountTtl; @@ -7246,7 +7316,8 @@ chatStatisticsChannel period:dateRange member_count:statisticalValue mean_messag //@total_amount Total amount of the cryptocurrency earned, in the smallest units of the cryptocurrency //@balance_amount Amount of the cryptocurrency that isn't withdrawn yet, in the smallest units of the cryptocurrency //@available_amount Amount of the cryptocurrency available for withdrawal, in the smallest units of the cryptocurrency -chatRevenueAmount cryptocurrency:string total_amount:int64 balance_amount:int64 available_amount:int64 = ChatRevenueAmount; +//@withdrawal_enabled True, if Telegram Stars can be withdrawn now or later +chatRevenueAmount cryptocurrency:string total_amount:int64 balance_amount:int64 available_amount:int64 withdrawal_enabled:Bool = ChatRevenueAmount; //@description A detailed statistics about revenue earned from sponsored messages in a chat //@revenue_by_hour_graph A graph containing amount of revenue in a given hour @@ -8016,6 +8087,11 @@ updateMessageReaction chat_id:int53 message_id:int53 actor_id:MessageSender date //@reactions The list of reactions added to the message updateMessageReactions chat_id:int53 message_id:int53 date:int32 reactions:vector = Update; +//@description Paid media were purchased by a user; for bots only +//@user_id User identifier +//@payload Bot-specified payload for the paid media +updatePaidMediaPurchased user_id:int53 payload:string = Update; + //@description Contains a list of updates @updates List of updates updates updates:vector = Updates; @@ -8268,7 +8344,7 @@ getMessageLocally chat_id:int53 message_id:int53 = Message; //@description Returns information about a non-bundled message that is replied by a given message. Also, returns the pinned message, the game message, the invoice message, //-the message with a previously set same background, the giveaway message, and the topic creation message for messages of the types -//-messagePinMessage, messageGameScore, messagePaymentSuccessful, messageChatSetBackground, messagePremiumGiveawayCompleted and topic messages without non-bundled replied message respectively +//-messagePinMessage, messageGameScore, messagePaymentSuccessful, messageChatSetBackground, messageGiveawayCompleted and topic messages without non-bundled replied message respectively //@chat_id Identifier of the chat the message belongs to //@message_id Identifier of the reply message getRepliedMessage chat_id:int53 message_id:int53 = Message; @@ -8935,7 +9011,7 @@ setBusinessMessageIsPinned business_connection_id:string chat_id:int53 message_i //@description Checks validness of a name for a quick reply shortcut. Can be called synchronously @name The name of the shortcut; 1-32 characters checkQuickReplyShortcutName name:string = Ok; -//@description Loads quick reply shortcuts created by the current user. The loaded topics will be sent through updateQuickReplyShortcuts +//@description Loads quick reply shortcuts created by the current user. The loaded data will be sent through updateQuickReplyShortcut and updateQuickReplyShortcuts loadQuickReplyShortcuts = Ok; //@description Changes name of a quick reply shortcut @shortcut_id Unique identifier of the quick reply shortcut @name New name for the shortcut. Use checkQuickReplyShortcutName to check its validness @@ -9075,7 +9151,7 @@ clearRecentReactions = Ok; //@description Adds a reaction or a tag to a message. Use getMessageAvailableReactions to receive the list of available reactions for the message //@chat_id Identifier of the chat to which the message belongs //@message_id Identifier of the message -//@reaction_type Type of the reaction to add. Use addPaidMessageReaction instead to add the paid reaction +//@reaction_type Type of the reaction to add. Use addPendingPaidMessageReaction instead to add the paid reaction //@is_big Pass true if the reaction is added with a big animation //@update_recent_reactions Pass true if the reaction needs to be added to recent reactions; tags are never added to the list of recent reactions addMessageReaction chat_id:int53 message_id:int53 reaction_type:ReactionType is_big:Bool update_recent_reactions:Bool = Ok; @@ -9086,16 +9162,18 @@ addMessageReaction chat_id:int53 message_id:int53 reaction_type:ReactionType is_ //@reaction_type Type of the reaction to remove. The paid reaction can't be removed removeMessageReaction chat_id:int53 message_id:int53 reaction_type:ReactionType = Ok; -//@description Adds the paid message reaction to a message. Use getMessageAvailableReactions to receive the list of available reactions for the message +//@description Adds the paid message reaction to a message. Use getMessageAvailableReactions to check whether the reaction is available for the message //@chat_id Identifier of the chat to which the message belongs //@message_id Identifier of the message -//@star_count Number of Telegram Stars to be used for the reaction; 1-getOption("paid_reaction_star_count_max") -//@is_anonymous Pass true to make paid reaction of the user on the message anonymous; pass false to make the user's profile visible among top reactors -addPaidMessageReaction chat_id:int53 message_id:int53 star_count:int53 is_anonymous:Bool = Ok; +//@star_count Number of Telegram Stars to be used for the reaction. The total number of pending paid reactions must not exceed getOption("paid_reaction_star_count_max") +//@use_default_is_anonymous Pass true if the user didn't choose anonymity explicitly, for example, the reaction is set from the message bubble +//@is_anonymous Pass true to make paid reaction of the user on the message anonymous; pass false to make the user's profile visible among top reactors. Ignored if use_default_is_anonymous == true +addPendingPaidMessageReaction chat_id:int53 message_id:int53 star_count:int53 use_default_is_anonymous:Bool is_anonymous:Bool = Ok; -//@description Removes all pending paid reactions on a message. Can be called within 5 seconds after the last addPaidMessageReaction call -//@chat_id Identifier of the chat to which the message belongs -//@message_id Identifier of the message +//@description Applies all pending paid reactions on a message @chat_id Identifier of the chat to which the message belongs @message_id Identifier of the message +commitPendingPaidMessageReactions chat_id:int53 message_id:int53 = Ok; + +//@description Removes all pending paid reactions on a message @chat_id Identifier of the chat to which the message belongs @message_id Identifier of the message removePendingPaidMessageReactions chat_id:int53 message_id:int53 = Ok; //@description Changes whether the paid message reaction of the user to a message is anonymous. The message must have paid reaction added by the user @@ -9268,10 +9346,10 @@ getInlineQueryResults bot_user_id:int53 chat_id:int53 user_location:location que answerInlineQuery inline_query_id:int64 is_personal:Bool button:inlineQueryResultsButton results:vector cache_time:int32 next_offset:string = Ok; -//@description Returns popular Web App bots +//@description Returns the most grossing Web App bots //@offset Offset of the first entry to return as received from the previous request; use empty string to get the first chunk of results //@limit The maximum number of bots to be returned; up to 100 -getPopularWebAppBots offset:string limit:int32 = FoundUsers; +getGrossingWebAppBots offset:string limit:int32 = FoundUsers; //@description Returns information about a Web App by its short name. Returns a 404 error if the Web App is not found //@bot_user_id Identifier of the target bot @@ -10509,6 +10587,9 @@ getAttachedStickerSets file_id:int32 = StickerSets; //@description Returns information about a sticker set by its identifier @set_id Identifier of the sticker set getStickerSet set_id:int64 = StickerSet; +//@description Returns name of a sticker set by its identifier @set_id Identifier of the sticker set +getStickerSetName set_id:int64 = Text; + //@description Searches for a sticker set by its name @name Name of the sticker set searchStickerSet name:string = StickerSet; @@ -11497,7 +11578,7 @@ clickPremiumSubscriptionButton = Ok; //@description Returns state of Telegram Premium subscription and promotion videos for Premium features getPremiumState = PremiumState; -//@description Returns available options for Telegram Premium gift code or giveaway creation +//@description Returns available options for Telegram Premium gift code or Telegram Premium giveaway creation //@boosted_chat_id Identifier of the supergroup or channel chat, which will be automatically boosted by receivers of the gift codes and which is administered by the user; 0 if none getPremiumGiftCodePaymentOptions boosted_chat_id:int53 = PremiumGiftCodePaymentOptions; @@ -11507,15 +11588,17 @@ checkPremiumGiftCode code:string = PremiumGiftCodeInfo; //@description Applies a Telegram Premium gift code @code The code to apply applyPremiumGiftCode code:string = Ok; -//@description Launches a prepaid Telegram Premium giveaway +//@description Launches a prepaid giveaway //@giveaway_id Unique identifier of the prepaid giveaway //@parameters Giveaway parameters -launchPrepaidPremiumGiveaway giveaway_id:int64 parameters:premiumGiveawayParameters = Ok; +//@winner_count The number of users to receive giveaway prize +//@star_count The number of Telegram Stars to be distributed through the giveaway; pass 0 for Telegram Premium giveaways +launchPrepaidGiveaway giveaway_id:int64 parameters:giveawayParameters winner_count:int32 star_count:int53 = Ok; -//@description Returns information about a Telegram Premium giveaway +//@description Returns information about a giveaway //@chat_id Identifier of the channel chat which started the giveaway //@message_id Identifier of the giveaway or a giveaway winners message in the chat -getPremiumGiveawayInfo chat_id:int53 message_id:int53 = PremiumGiveawayInfo; +getGiveawayInfo chat_id:int53 message_id:int53 = GiveawayInfo; //@description Returns available options for Telegram Stars purchase getStarPaymentOptions = StarPaymentOptions; @@ -11523,6 +11606,9 @@ getStarPaymentOptions = StarPaymentOptions; //@description Returns available options for Telegram Stars gifting @user_id Identifier of the user that will receive Telegram Stars; pass 0 to get options for an unspecified user getStarGiftPaymentOptions user_id:int53 = StarPaymentOptions; +//@description Returns available options for Telegram Star giveaway creation +getStarGiveawayPaymentOptions = StarGiveawayPaymentOptions; + //@description Returns the list of Telegram Star transactions for the specified owner //@owner_id Identifier of the owner of the Telegram Stars; can be the identifier of the current user, identifier of an owned bot, //-or identifier of a channel chat with supergroupFullInfo.can_get_star_revenue_statistics == true diff --git a/lib/tgchat/ext/td/td/generate/scheme/telegram_api.tl b/lib/tgchat/ext/td/td/generate/scheme/telegram_api.tl index 8efa13df..1a02c77f 100644 --- a/lib/tgchat/ext/td/td/generate/scheme/telegram_api.tl +++ b/lib/tgchat/ext/td/td/generate/scheme/telegram_api.tl @@ -69,7 +69,7 @@ inputMediaPoll#f94e5f1 flags:# poll:Poll correct_answers:flags.0?Vector s inputMediaDice#e66fbf7b emoticon:string = InputMedia; inputMediaStory#89fdd778 peer:InputPeer id:int = InputMedia; inputMediaWebPage#c21b8849 flags:# force_large_media:flags.0?true force_small_media:flags.1?true optional:flags.2?true url:string = InputMedia; -inputMediaPaidMedia#aa661fc3 stars_amount:long extended_media:Vector = InputMedia; +inputMediaPaidMedia#c4103386 flags:# stars_amount:long extended_media:Vector payload:flags.0?string = InputMedia; inputChatPhotoEmpty#1ca48f57 = InputChatPhoto; inputChatUploadedPhoto#bdcdaec0 flags:# file:flags.0?InputFile video:flags.1?InputFile video_start_ts:flags.2?double video_emoji_markup:flags.3?VideoSize = InputChatPhoto; @@ -157,8 +157,8 @@ messageMediaGeoLive#b940c666 flags:# geo:GeoPoint heading:flags.0?int period:int messageMediaPoll#4bd6e798 poll:Poll results:PollResults = MessageMedia; messageMediaDice#3f7ee58b value:int emoticon:string = MessageMedia; messageMediaStory#68cb6283 flags:# via_mention:flags.1?true peer:Peer id:int story:flags.0?StoryItem = MessageMedia; -messageMediaGiveaway#daad85b0 flags:# only_new_subscribers:flags.0?true winners_are_visible:flags.2?true channels:Vector countries_iso2:flags.1?Vector prize_description:flags.3?string quantity:int months:int until_date:int = MessageMedia; -messageMediaGiveawayResults#c6991068 flags:# only_new_subscribers:flags.0?true refunded:flags.2?true channel_id:long additional_peers_count:flags.3?int launch_msg_id:int winners_count:int unclaimed_count:int winners:Vector months:int prize_description:flags.1?string until_date:int = MessageMedia; +messageMediaGiveaway#aa073beb flags:# only_new_subscribers:flags.0?true winners_are_visible:flags.2?true channels:Vector countries_iso2:flags.1?Vector prize_description:flags.3?string quantity:int months:flags.4?int stars:flags.5?long until_date:int = MessageMedia; +messageMediaGiveawayResults#ceaa3ea1 flags:# only_new_subscribers:flags.0?true refunded:flags.2?true channel_id:long additional_peers_count:flags.3?int launch_msg_id:int winners_count:int unclaimed_count:int winners:Vector months:flags.4?int stars:flags.5?long prize_description:flags.1?string until_date:int = MessageMedia; messageMediaPaidMedia#a8852491 stars_amount:long extended_media:Vector = MessageMedia; messageActionEmpty#b6aef7b0 = MessageAction; @@ -200,12 +200,13 @@ messageActionSuggestProfilePhoto#57de635e photo:Photo = MessageAction; messageActionRequestedPeer#31518e9b button_id:int peers:Vector = MessageAction; messageActionSetChatWallPaper#5060a3f4 flags:# same:flags.0?true for_both:flags.1?true wallpaper:WallPaper = MessageAction; messageActionGiftCode#678c2e09 flags:# via_giveaway:flags.0?true unclaimed:flags.2?true boost_peer:flags.1?Peer months:int slug:string currency:flags.2?string amount:flags.2?long crypto_currency:flags.3?string crypto_amount:flags.3?long = MessageAction; -messageActionGiveawayLaunch#332ba9ed = MessageAction; -messageActionGiveawayResults#2a9fadc5 winners_count:int unclaimed_count:int = MessageAction; +messageActionGiveawayLaunch#a80f51e4 flags:# stars:flags.0?long = MessageAction; +messageActionGiveawayResults#87e2f155 flags:# stars:flags.0?true winners_count:int unclaimed_count:int = MessageAction; messageActionBoostApply#cc02aa6d boosts:int = MessageAction; messageActionRequestedPeerSentMe#93b31848 button_id:int peers:Vector = MessageAction; messageActionPaymentRefunded#41b3e202 flags:# peer:Peer currency:string total_amount:long payload:flags.0?bytes charge:PaymentCharge = MessageAction; messageActionGiftStars#45d5b021 flags:# currency:string amount:long stars:long crypto_currency:flags.0?string crypto_amount:flags.0?long transaction_id:flags.1?string = MessageAction; +messageActionPrizeStars#b00c47a2 flags:# unclaimed:flags.0?true stars:long transaction_id:string boost_peer:Peer giveaway_msg_id:int = MessageAction; dialog#d58a08c6 flags:# pinned:flags.2?true unread_mark:flags.3?true view_forum_as_messages:flags.6?true peer:Peer top_message:int read_inbox_max_id:int read_outbox_max_id:int unread_count:int unread_mentions_count:int unread_reactions_count:int notify_settings:PeerNotifySettings pts:flags.0?int draft:flags.1?DraftMessage folder_id:flags.4?int ttl_period:flags.5?int = Dialog; dialogFolder#71bd134c flags:# pinned:flags.2?true folder:Folder peer:Peer top_message:int unread_muted_peers_count:int unread_unmuted_peers_count:int unread_muted_messages_count:int unread_unmuted_messages_count:int = Dialog; @@ -446,6 +447,8 @@ updateBroadcastRevenueTransactions#dfd961f5 peer:Peer balances:BroadcastRevenueB updateStarsBalance#fb85198 balance:long = Update; updateBusinessBotCallbackQuery#1ea2fda7 flags:# query_id:long user_id:long connection_id:string message:Message reply_to_message:flags.2?Message chat_instance:long data:flags.0?bytes = Update; updateStarsRevenueStatus#a584b019 peer:Peer status:StarsRevenueStatus = Update; +updateBotPurchasedPaidMedia#283bd312 user_id:long payload:string qts:int = Update; +updatePaidReactionPrivacy#51ca7aec private:Bool = Update; updates.state#a56c2a3e pts:int qts:int date:int seq:int unread_count:int = updates.State; @@ -1037,12 +1040,13 @@ channelAdminLogEventActionChangeWallpaper#31bb5d52 prev_value:WallPaper new_valu channelAdminLogEventActionChangeEmojiStatus#3ea9feb1 prev_value:EmojiStatus new_value:EmojiStatus = ChannelAdminLogEventAction; channelAdminLogEventActionChangeEmojiStickerSet#46d840ab prev_stickerset:InputStickerSet new_stickerset:InputStickerSet = ChannelAdminLogEventAction; channelAdminLogEventActionToggleSignatureProfiles#60a79c79 new_value:Bool = ChannelAdminLogEventAction; +channelAdminLogEventActionParticipantSubExtend#64642db3 prev_participant:ChannelParticipant new_participant:ChannelParticipant = ChannelAdminLogEventAction; channelAdminLogEvent#1fad68cd id:long date:int user_id:long action:ChannelAdminLogEventAction = ChannelAdminLogEvent; channels.adminLogResults#ed8af74d events:Vector chats:Vector users:Vector = channels.AdminLogResults; -channelAdminLogEventsFilter#ea107ae4 flags:# join:flags.0?true leave:flags.1?true invite:flags.2?true ban:flags.3?true unban:flags.4?true kick:flags.5?true unkick:flags.6?true promote:flags.7?true demote:flags.8?true info:flags.9?true settings:flags.10?true pinned:flags.11?true edit:flags.12?true delete:flags.13?true group_call:flags.14?true invites:flags.15?true send:flags.16?true forums:flags.17?true = ChannelAdminLogEventsFilter; +channelAdminLogEventsFilter#ea107ae4 flags:# join:flags.0?true leave:flags.1?true invite:flags.2?true ban:flags.3?true unban:flags.4?true kick:flags.5?true unkick:flags.6?true promote:flags.7?true demote:flags.8?true info:flags.9?true settings:flags.10?true pinned:flags.11?true edit:flags.12?true delete:flags.13?true group_call:flags.14?true invites:flags.15?true send:flags.16?true forums:flags.17?true sub_extend:flags.18?true = ChannelAdminLogEventsFilter; popularContact#5ce14175 client_id:long importers:int = PopularContact; @@ -1496,6 +1500,7 @@ inputStorePaymentPremiumGiftCode#a3805f3f flags:# users:Vector boost_ inputStorePaymentPremiumGiveaway#160544ca flags:# only_new_subscribers:flags.0?true winners_are_visible:flags.3?true boost_peer:InputPeer additional_peers:flags.1?Vector countries_iso2:flags.2?Vector prize_description:flags.4?string random_id:long until_date:int currency:string amount:long = InputStorePaymentPurpose; inputStorePaymentStarsTopup#dddd0f56 stars:long currency:string amount:long = InputStorePaymentPurpose; inputStorePaymentStarsGift#1d741ef7 user_id:InputUser stars:long currency:string amount:long = InputStorePaymentPurpose; +inputStorePaymentStarsGiveaway#751f08fa flags:# only_new_subscribers:flags.0?true winners_are_visible:flags.3?true stars:long boost_peer:InputPeer additional_peers:flags.1?Vector countries_iso2:flags.2?Vector prize_description:flags.4?string random_id:long until_date:int currency:string amount:long users:int = InputStorePaymentPurpose; premiumGiftOption#74c34319 flags:# months:int currency:string amount:long bot_url:string store_product:flags.0?string = PremiumGiftOption; @@ -1657,11 +1662,12 @@ premiumGiftCodeOption#257e962b flags:# users:int months:int store_product:flags. payments.checkedGiftCode#284a1096 flags:# via_giveaway:flags.2?true from_id:flags.4?Peer giveaway_msg_id:flags.3?int to_id:flags.0?long date:int months:int used_date:flags.1?int chats:Vector users:Vector = payments.CheckedGiftCode; payments.giveawayInfo#4367daa0 flags:# participating:flags.0?true preparing_results:flags.3?true start_date:int joined_too_early_date:flags.1?int admin_disallowed_chat_id:flags.2?long disallowed_country:flags.4?string = payments.GiveawayInfo; -payments.giveawayInfoResults#cd5570 flags:# winner:flags.0?true refunded:flags.1?true start_date:int gift_code_slug:flags.0?string finish_date:int winners_count:int activated_count:int = payments.GiveawayInfo; +payments.giveawayInfoResults#e175e66f flags:# winner:flags.0?true refunded:flags.1?true start_date:int gift_code_slug:flags.3?string stars_prize:flags.4?long finish_date:int winners_count:int activated_count:flags.2?int = payments.GiveawayInfo; prepaidGiveaway#b2539d54 id:long months:int quantity:int date:int = PrepaidGiveaway; +prepaidStarsGiveaway#9a9d77e0 id:long stars:long quantity:int boosts:int date:int = PrepaidGiveaway; -boost#2a1c8c71 flags:# gift:flags.1?true giveaway:flags.2?true unclaimed:flags.3?true id:string user_id:flags.0?long giveaway_msg_id:flags.2?int date:int expires:int used_gift_slug:flags.4?string multiplier:flags.5?int = Boost; +boost#4b3e14d6 flags:# gift:flags.1?true giveaway:flags.2?true unclaimed:flags.3?true id:string user_id:flags.0?long giveaway_msg_id:flags.2?int date:int expires:int used_gift_slug:flags.4?string multiplier:flags.5?int stars:flags.6?long = Boost; premium.boostsList#86f8613c flags:# count:int boosts:Vector next_offset:flags.0?string users:Vector = premium.BoostsList; @@ -1819,7 +1825,7 @@ reactionNotificationsFromAll#4b9e22a0 = ReactionNotificationsFrom; reactionsNotifySettings#56e34970 flags:# messages_notify_from:flags.0?ReactionNotificationsFrom stories_notify_from:flags.1?ReactionNotificationsFrom sound:NotificationSound show_previews:Bool = ReactionsNotifySettings; -broadcastRevenueBalances#8438f1c6 current_balance:long available_balance:long overall_revenue:long = BroadcastRevenueBalances; +broadcastRevenueBalances#c3ff71e7 flags:# withdrawal_enabled:flags.0?true current_balance:long available_balance:long overall_revenue:long = BroadcastRevenueBalances; availableEffect#93c3e27e flags:# premium_required:flags.2?true id:long emoticon:string static_icon_id:flags.0?long effect_sticker_id:long effect_animation_id:flags.1?long = AvailableEffect; @@ -1838,7 +1844,7 @@ starsTransactionPeerAds#60682812 = StarsTransactionPeer; starsTopupOption#bd915c0 flags:# extended:flags.1?true stars:long store_product:flags.0?string currency:string amount:long = StarsTopupOption; -starsTransaction#433aeb2b flags:# refund:flags.3?true pending:flags.4?true failed:flags.6?true gift:flags.10?true reaction:flags.11?true id:string stars:long date:int peer:StarsTransactionPeer title:flags.0?string description:flags.1?string photo:flags.2?WebDocument transaction_date:flags.5?int transaction_url:flags.5?string bot_payload:flags.7?bytes msg_id:flags.8?int extended_media:flags.9?Vector subscription_period:flags.12?int = StarsTransaction; +starsTransaction#ee7522d5 flags:# refund:flags.3?true pending:flags.4?true failed:flags.6?true gift:flags.10?true reaction:flags.11?true id:string stars:long date:int peer:StarsTransactionPeer title:flags.0?string description:flags.1?string photo:flags.2?WebDocument transaction_date:flags.5?int transaction_url:flags.5?string bot_payload:flags.7?bytes msg_id:flags.8?int extended_media:flags.9?Vector subscription_period:flags.12?int giveaway_post_id:flags.13?int = StarsTransaction; payments.starsStatus#bbfa316c flags:# balance:long subscriptions:flags.1?Vector subscriptions_next_offset:flags.2?string subscriptions_missing_balance:flags.4?long history:flags.3?Vector next_offset:flags.0?string chats:Vector users:Vector = payments.StarsStatus; @@ -1872,6 +1878,10 @@ starsSubscription#538ecf18 flags:# canceled:flags.0?true can_refulfill:flags.1?t messageReactor#4ba3a95a flags:# top:flags.0?true my:flags.1?true anonymous:flags.2?true peer_id:flags.3?Peer count:int = MessageReactor; +starsGiveawayOption#94ce852a flags:# extended:flags.0?true default:flags.1?true stars:long yearly_boosts:int store_product:flags.2?string currency:string amount:long winners:Vector = StarsGiveawayOption; + +starsGiveawayWinnersOption#54236209 flags:# default:flags.0?true users:int per_user_stars:long = StarsGiveawayWinnersOption; + ---functions--- invokeAfterMsg#cb9f372d {X:Type} msg_id:long query:!X = X; @@ -2268,8 +2278,9 @@ messages.editFactCheck#589ee75 peer:InputPeer msg_id:int text:TextWithEntities = messages.deleteFactCheck#d1da940c peer:InputPeer msg_id:int = Updates; messages.getFactCheck#b9cdc5ee peer:InputPeer msg_id:Vector = Vector; messages.requestMainWebView#c9e01e7b flags:# compact:flags.7?true peer:InputPeer bot:InputUser start_param:flags.1?string theme_params:flags.0?DataJSON platform:string = WebViewResult; -messages.sendPaidReaction#25c8fe3e flags:# private:flags.0?true peer:InputPeer msg_id:int count:int random_id:long = Updates; +messages.sendPaidReaction#9dd6a67b flags:# peer:InputPeer msg_id:int count:int random_id:long private:flags.0?Bool = Updates; messages.togglePaidReactionPrivacy#849ad397 peer:InputPeer msg_id:int private:Bool = Bool; +messages.getPaidReactionPrivacy#472455aa = Updates; updates.getState#edd4882a = updates.State; updates.getDifference#19c2f763 flags:# pts:int pts_limit:flags.1?int pts_total_limit:flags.0?int date:int qts:int qts_limit:flags.2?int = updates.Difference; @@ -2435,6 +2446,7 @@ payments.getStarsGiftOptions#d3c96bc8 flags:# user_id:flags.0?InputUser = Vector payments.getStarsSubscriptions#32512c5 flags:# missing_balance:flags.0?true peer:InputPeer offset:string = payments.StarsStatus; payments.changeStarsSubscription#c7770878 flags:# peer:InputPeer subscription_id:string canceled:flags.0?Bool = Bool; payments.fulfillStarsSubscription#cc5bebb3 peer:InputPeer subscription_id:string = Bool; +payments.getStarsGiveawayOptions#bd1efd3e = Vector; stickers.createStickerSet#9021ab67 flags:# masks:flags.0?true emojis:flags.5?true text_color:flags.6?true user_id:InputUser title:string short_name:string thumb:flags.2?InputDocument stickers:Vector software:flags.3?string = messages.StickerSet; stickers.removeStickerFromSet#f7760f51 sticker:InputDocument = messages.StickerSet; diff --git a/lib/tgchat/ext/td/td/generate/tl_writer_java.cpp b/lib/tgchat/ext/td/td/generate/tl_writer_java.cpp index d6ef8693..504c8894 100644 --- a/lib/tgchat/ext/td/td/generate/tl_writer_java.cpp +++ b/lib/tgchat/ext/td/td/generate/tl_writer_java.cpp @@ -198,6 +198,8 @@ std::string TD_TL_writer_java::gen_output_begin(const std::string &additional_im } std::string TD_TL_writer_java::gen_output_begin_once() const { +#define DEFINE_STR_VALUE_IMPL(x) #x +#define DEFINE_STR_VALUE(x) DEFINE_STR_VALUE_IMPL(x) return " static {\n" " try {\n" " System.loadLibrary(\"tdjni\");\n" @@ -205,10 +207,14 @@ std::string TD_TL_writer_java::gen_output_begin_once() const { " e.printStackTrace();\n" " }\n" " }\n\n" + " private static final String GIT_COMMIT_HASH = \"" DEFINE_STR_VALUE(GIT_COMMIT_HASH) + "\";\n\n" " private " + tl_name + "() {\n" " }\n\n"; +#undef DEFINE_STR_VALUE +#undef DEFINE_STR_VALUE_IMPL } std::string TD_TL_writer_java::gen_output_end() const { diff --git a/lib/tgchat/ext/td/td/generate/tl_writer_jni_cpp.cpp b/lib/tgchat/ext/td/td/generate/tl_writer_jni_cpp.cpp index 159b3563..d7aaefaa 100644 --- a/lib/tgchat/ext/td/td/generate/tl_writer_jni_cpp.cpp +++ b/lib/tgchat/ext/td/td/generate/tl_writer_jni_cpp.cpp @@ -12,11 +12,18 @@ namespace td { std::string TD_TL_writer_jni_cpp::gen_output_begin_once() const { +#define DEFINE_STR_VALUE_IMPL(x) #x +#define DEFINE_STR_VALUE(x) DEFINE_STR_VALUE_IMPL(x) return TD_TL_writer_cpp::gen_output_begin_once() + "\nconst char *&get_package_name_ref() {\n" " static const char *package_name = \"Package name must be initialized first\";\n" " return package_name;\n" + "}\n" + "\nconst char *get_git_commit_hash() {\n" + " return \"" DEFINE_STR_VALUE(GIT_COMMIT_HASH) "\";\n" "}\n"; +#undef DEFINE_STR_VALUE +#undef DEFINE_STR_VALUE_IMPL } bool TD_TL_writer_jni_cpp::is_built_in_simple_type(const std::string &name) const { @@ -483,7 +490,8 @@ std::string TD_TL_writer_jni_cpp::gen_store_function_begin(const std::string &st std::string TD_TL_writer_jni_cpp::gen_fetch_switch_begin() const { return " if (p == nullptr) { return nullptr; }\n" - " switch (env->CallIntMethod(p, jni::GetConstructorID)) {\n"; + " jint constructor = env->CallIntMethod(p, jni::GetConstructorID);" + " switch (constructor) {\n"; } std::string TD_TL_writer_jni_cpp::gen_fetch_switch_case(const tl::tl_combinator *t, int arity) const { @@ -496,7 +504,7 @@ std::string TD_TL_writer_jni_cpp::gen_fetch_switch_case(const tl::tl_combinator std::string TD_TL_writer_jni_cpp::gen_fetch_switch_end() const { return " default:\n" - " LOG(WARNING) << \"Unknown constructor found\";\n" + " LOG(WARNING) << \"Unknown Java API constructor found \" << format::as_hex(constructor);\n" " return nullptr;\n" " }\n"; } diff --git a/lib/tgchat/ext/td/td/generate/tl_writer_jni_h.cpp b/lib/tgchat/ext/td/td/generate/tl_writer_jni_h.cpp index 094dd6c3..40edd529 100644 --- a/lib/tgchat/ext/td/td/generate/tl_writer_jni_h.cpp +++ b/lib/tgchat/ext/td/td/generate/tl_writer_jni_h.cpp @@ -87,7 +87,7 @@ std::string TD_TL_writer_jni_h::gen_output_begin_once() const { ";\n" "using BaseObject = " + gen_base_tl_class_name()); - return result + "const char *&get_package_name_ref();\n\n"; + return result + "const char *&get_package_name_ref();\nconst char *get_git_commit_hash();\n\n"; } std::string TD_TL_writer_jni_h::gen_class_begin(const std::string &class_name, const std::string &base_class_name, diff --git a/lib/tgchat/ext/td/td/mtproto/Handshake.cpp b/lib/tgchat/ext/td/td/mtproto/Handshake.cpp index b8d5d70a..1478e3c5 100644 --- a/lib/tgchat/ext/td/td/mtproto/Handshake.cpp +++ b/lib/tgchat/ext/td/td/mtproto/Handshake.cpp @@ -60,13 +60,13 @@ void AuthKeyHandshake::set_timeout_in(double timeout_in) { void AuthKeyHandshake::clear() { last_query_ = string(); - state_ = Start; + state_ = State::Start; start_time_ = Time::now(); timeout_in_ = 1e9; } bool AuthKeyHandshake::is_ready_for_finish() const { - return state_ == Finish; + return state_ == State::Finish; } void AuthKeyHandshake::on_finish() { @@ -156,7 +156,7 @@ Status AuthKeyHandshake::on_res_pq(Slice message, Callback *connection, PublicRs mtproto_api::req_DH_params req_dh_params(nonce_, server_nonce_, p, q, rsa_key.fingerprint, encrypted_data); send(connection, create_function_storer(req_dh_params)); - state_ = ServerDHParams; + state_ = State::ServerDHParams; return Status::OK(); } @@ -250,7 +250,7 @@ Status AuthKeyHandshake::on_server_dh_params(Slice message, Callback *connection server_salt_ = as(new_nonce_.raw) ^ as(server_nonce_.raw); - state_ = DHGenResponse; + state_ = State::DHGenResponse; return Status::OK(); } @@ -272,7 +272,7 @@ Status AuthKeyHandshake::on_dh_gen_response(Slice message, Callback *connection) if (dh_gen_ok->new_nonce_hash1_.as_slice() != Slice(new_nonce_hash).substr(4)) { return Status::Error("New nonce hash mismatch"); } - state_ = Finish; + state_ = State::Finish; return Status::OK(); } case mtproto_api::dh_gen_fail::ID: @@ -298,10 +298,10 @@ void AuthKeyHandshake::do_send(Callback *connection, const Storer &storer) { } void AuthKeyHandshake::resume(Callback *connection) { - if (state_ == Start) { + if (state_ == State::Start) { return on_start(connection).ignore(); } - if (state_ == Finish) { + if (state_ == State::Finish) { LOG(ERROR) << "State is Finish during resume. UNREACHABLE"; return clear(); } @@ -314,13 +314,13 @@ void AuthKeyHandshake::resume(Callback *connection) { } Status AuthKeyHandshake::on_start(Callback *connection) { - if (state_ != Start) { + if (state_ != State::Start) { clear(); return Status::Error(PSLICE() << "on_start called after start " << tag("state", state_)); } Random::secure_bytes(nonce_.raw, sizeof(nonce_)); send(connection, create_function_storer(mtproto_api::req_pq_multi(nonce_))); - state_ = ResPQ; + state_ = State::ResPQ; return Status::OK(); } @@ -328,21 +328,39 @@ Status AuthKeyHandshake::on_start(Callback *connection) { Status AuthKeyHandshake::on_message(Slice message, Callback *connection, AuthKeyHandshakeContext *context) { Status status = [&] { switch (state_) { - case ResPQ: + case State::ResPQ: return on_res_pq(message, connection, context->get_public_rsa_key_interface()); - case ServerDHParams: + case State::ServerDHParams: return on_server_dh_params(message, connection, context->get_dh_callback()); - case DHGenResponse: + case State::DHGenResponse: return on_dh_gen_response(message, connection); default: UNREACHABLE(); } }(); if (status.is_error()) { + LOG(WARNING) << "Failed to process hasdshake response in state " << state_ << ": " << status.message(); clear(); } return status; } +StringBuilder &operator<<(StringBuilder &string_builder, const AuthKeyHandshake::State &state) { + switch (state) { + case AuthKeyHandshake::State::Start: + return string_builder << "Start"; + case AuthKeyHandshake::State::ResPQ: + return string_builder << "ResPQ"; + case AuthKeyHandshake::State::ServerDHParams: + return string_builder << "ServerDHParams"; + case AuthKeyHandshake::State::DHGenResponse: + return string_builder << "DHGenResponse"; + case AuthKeyHandshake::State::Finish: + return string_builder << "Finish"; + default: + UNREACHABLE(); + } +} + } // namespace mtproto } // namespace td diff --git a/lib/tgchat/ext/td/td/mtproto/Handshake.h b/lib/tgchat/ext/td/td/mtproto/Handshake.h index 0c810e44..39df4b50 100644 --- a/lib/tgchat/ext/td/td/mtproto/Handshake.h +++ b/lib/tgchat/ext/td/td/mtproto/Handshake.h @@ -13,6 +13,7 @@ #include "td/utils/Slice.h" #include "td/utils/Status.h" #include "td/utils/StorerBase.h" +#include "td/utils/StringBuilder.h" #include "td/utils/UInt.h" namespace td { @@ -69,8 +70,8 @@ class AuthKeyHandshake { } private: - enum State : int32 { Start, ResPQ, ServerDHParams, DHGenResponse, Finish }; - State state_ = Start; + enum class State : int32 { Start, ResPQ, ServerDHParams, DHGenResponse, Finish }; + State state_ = State::Start; enum class Mode : int32 { Main, Temp }; Mode mode_ = Mode::Main; int32 dc_id_ = 0; @@ -100,6 +101,8 @@ class AuthKeyHandshake { Status on_res_pq(Slice message, Callback *connection, PublicRsaKeyInterface *public_rsa_key) TD_WARN_UNUSED_RESULT; Status on_server_dh_params(Slice message, Callback *connection, DhCallback *dh_callback) TD_WARN_UNUSED_RESULT; Status on_dh_gen_response(Slice message, Callback *connection) TD_WARN_UNUSED_RESULT; + + friend StringBuilder &operator<<(StringBuilder &string_builder, const State &state); }; } // namespace mtproto diff --git a/lib/tgchat/ext/td/td/telegram/AlarmManager.cpp b/lib/tgchat/ext/td/td/telegram/AlarmManager.cpp new file mode 100644 index 00000000..df50fe12 --- /dev/null +++ b/lib/tgchat/ext/td/td/telegram/AlarmManager.cpp @@ -0,0 +1,58 @@ +// +// Copyright Aliaksei Levin (levlam@telegram.org), Arseny Smirnov (arseny30@gmail.com) 2014-2024 +// +// 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/AlarmManager.h" + +#include "td/telegram/Global.h" + +#include "td/utils/Status.h" + +namespace td { + +AlarmManager::AlarmManager(ActorShared<> parent) : parent_(std::move(parent)) { + alarm_timeout_.set_callback(on_alarm_timeout_callback); + alarm_timeout_.set_callback_data(static_cast(this)); +} + +void AlarmManager::tear_down() { + while (!pending_alarms_.empty()) { + auto it = pending_alarms_.begin(); + auto alarm_id = it->first; + auto promise = std::move(it->second); + pending_alarms_.erase(it); + promise.set_error(G()->request_aborted_error()); + alarm_timeout_.cancel_timeout(alarm_id); + } + parent_.reset(); +} + +void AlarmManager::on_alarm_timeout_callback(void *alarm_manager_ptr, int64 alarm_id) { + auto alarm_manager = static_cast(alarm_manager_ptr); + auto alarm_manager_id = alarm_manager->actor_id(alarm_manager); + send_closure_later(alarm_manager_id, &AlarmManager::on_alarm_timeout, alarm_id); +} + +void AlarmManager::on_alarm_timeout(int64 alarm_id) { + auto it = pending_alarms_.find(alarm_id); + if (it == pending_alarms_.end()) { + return; + } + auto promise = std::move(it->second); + pending_alarms_.erase(alarm_id); + promise.set_value(Unit()); +} + +void AlarmManager::set_alarm(double seconds, Promise &&promise) { + if (seconds < 0 || seconds > 3e9) { + return promise.set_error(Status::Error(400, "Wrong parameter seconds specified")); + } + + auto alarm_id = alarm_id_++; + pending_alarms_.emplace(alarm_id, std::move(promise)); + alarm_timeout_.set_timeout_in(alarm_id, seconds); +} + +} // namespace td diff --git a/lib/tgchat/ext/td/td/telegram/AlarmManager.h b/lib/tgchat/ext/td/td/telegram/AlarmManager.h new file mode 100644 index 00000000..22908886 --- /dev/null +++ b/lib/tgchat/ext/td/td/telegram/AlarmManager.h @@ -0,0 +1,38 @@ +// +// Copyright Aliaksei Levin (levlam@telegram.org), Arseny Smirnov (arseny30@gmail.com) 2014-2024 +// +// 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/actor/actor.h" +#include "td/actor/MultiTimeout.h" + +#include "td/utils/common.h" +#include "td/utils/FlatHashMap.h" +#include "td/utils/Promise.h" + +namespace td { + +class AlarmManager final : public Actor { + public: + explicit AlarmManager(ActorShared<> parent); + + void set_alarm(double seconds, Promise &&promise); + + private: + void tear_down() final; + + static void on_alarm_timeout_callback(void *alarm_manager_ptr, int64 alarm_id); + + void on_alarm_timeout(int64 alarm_id); + + ActorShared<> parent_; + + int64 alarm_id_ = 1; + FlatHashMap> pending_alarms_; + MultiTimeout alarm_timeout_{"AlarmTimeout"}; +}; + +} // namespace td diff --git a/lib/tgchat/ext/td/td/telegram/AnimationsManager.cpp b/lib/tgchat/ext/td/td/telegram/AnimationsManager.cpp index e972fde6..36ae136b 100644 --- a/lib/tgchat/ext/td/td/telegram/AnimationsManager.cpp +++ b/lib/tgchat/ext/td/td/telegram/AnimationsManager.cpp @@ -312,20 +312,22 @@ tl_object_ptr AnimationsManager::get_input_media( if (file_view.is_encrypted()) { return nullptr; } - if (file_view.has_remote_location() && !file_view.main_remote_location().is_web() && input_file == nullptr) { + const auto *main_remote_location = file_view.get_main_remote_location(); + if (main_remote_location != nullptr && !main_remote_location->is_web() && input_file == nullptr) { int32 flags = 0; if (has_spoiler) { flags |= telegram_api::inputMediaDocument::SPOILER_MASK; } - return make_tl_object( - flags, false /*ignored*/, file_view.main_remote_location().as_input_document(), 0, string()); + return make_tl_object(flags, false /*ignored*/, + main_remote_location->as_input_document(), 0, string()); } - if (file_view.has_url()) { + const auto *url = file_view.get_url(); + if (url != nullptr) { int32 flags = 0; if (has_spoiler) { flags |= telegram_api::inputMediaDocumentExternal::SPOILER_MASK; } - return make_tl_object(flags, false /*ignored*/, file_view.url(), 0); + return make_tl_object(flags, false /*ignored*/, *url, 0); } if (input_file != nullptr) { @@ -364,7 +366,7 @@ tl_object_ptr AnimationsManager::get_input_media( flags, false /*ignored*/, false /*ignored*/, false /*ignored*/, std::move(input_file), std::move(input_thumbnail), mime_type, std::move(attributes), std::move(added_stickers), 0); } else { - CHECK(!file_view.has_remote_location()); + CHECK(main_remote_location == nullptr); } return nullptr; @@ -380,8 +382,9 @@ SecretInputMedia AnimationsManager::get_secret_input_media(FileId animation_file if (!file_view.is_encrypted_secret() || file_view.encryption_key().empty()) { return SecretInputMedia{}; } - if (file_view.has_remote_location()) { - input_file = file_view.main_remote_location().as_input_encrypted_file(); + const auto *main_remote_location = file_view.get_main_remote_location(); + if (main_remote_location != nullptr) { + input_file = main_remote_location->as_input_encrypted_file(); } if (!input_file) { return SecretInputMedia{}; @@ -656,12 +659,13 @@ int64 AnimationsManager::get_saved_animations_hash(const char *source) const { auto animation = get_animation(animation_id); CHECK(animation != nullptr); auto file_view = td_->file_manager_->get_file_view(animation_id); - CHECK(file_view.has_remote_location()); - if (!file_view.remote_location().is_document()) { - LOG(ERROR) << "Saved animation remote location is not document: " << source << " " << file_view.remote_location(); + const auto *full_remote_location = file_view.get_full_remote_location(); + CHECK(full_remote_location != nullptr); + if (!full_remote_location->is_document()) { + LOG(ERROR) << "Saved animation remote location is not a document: " << source << ' ' << *full_remote_location; continue; } - numbers.push_back(file_view.remote_location().get_id()); + numbers.push_back(full_remote_location->get_id()); } return get_vector_hash(numbers); } @@ -684,11 +688,12 @@ void AnimationsManager::send_save_gif_query(FileId animation_id, bool unsave, Pr // TODO invokeAfter and log event auto file_view = td_->file_manager_->get_file_view(animation_id); - CHECK(file_view.has_remote_location()); - LOG_CHECK(file_view.remote_location().is_document()) << file_view.remote_location(); - CHECK(!file_view.remote_location().is_web()); + const auto *full_remote_location = file_view.get_full_remote_location(); + CHECK(full_remote_location != nullptr); + CHECK(full_remote_location->is_document()); + CHECK(!full_remote_location->is_web()); td_->create_handler(std::move(promise)) - ->send(animation_id, file_view.remote_location().as_input_document(), unsave); + ->send(animation_id, full_remote_location->as_input_document(), unsave); } void AnimationsManager::add_saved_animation_by_id(FileId animation_id) { @@ -747,13 +752,14 @@ void AnimationsManager::add_saved_animation_impl(FileId animation_id, bool add_o return promise.set_error(Status::Error(400, "Only MPEG4 animations can be saved")); } - if (!file_view.has_remote_location()) { + const auto *full_remote_location = file_view.get_full_remote_location(); + if (full_remote_location == nullptr) { return promise.set_error(Status::Error(400, "Can save only sent animations")); } - if (file_view.remote_location().is_web()) { + if (full_remote_location->is_web()) { return promise.set_error(Status::Error(400, "Can't save web animations")); } - if (!file_view.remote_location().is_document()) { + if (!full_remote_location->is_document()) { return promise.set_error(Status::Error(400, "Can't save encrypted animations")); } diff --git a/lib/tgchat/ext/td/td/telegram/AudiosManager.cpp b/lib/tgchat/ext/td/td/telegram/AudiosManager.cpp index 1225da6a..12ecd846 100644 --- a/lib/tgchat/ext/td/td/telegram/AudiosManager.cpp +++ b/lib/tgchat/ext/td/td/telegram/AudiosManager.cpp @@ -81,8 +81,9 @@ td_api::object_ptr AudiosManager::get_notification_so auto file_view = td_->file_manager_->get_file_view(file_id); CHECK(!file_view.empty()); CHECK(file_view.get_type() == FileType::Ringtone); - CHECK(file_view.has_remote_location()); - auto document_id = file_view.remote_location().get_id(); + auto full_remote_location = file_view.get_full_remote_location(); + CHECK(full_remote_location != nullptr); + auto document_id = full_remote_location->get_id(); auto title = audio->title; if (title.empty() && !audio->file_name.empty()) { title = PathView(audio->file_name).file_name_without_extension().str(); @@ -237,8 +238,9 @@ SecretInputMedia AudiosManager::get_secret_input_media(FileId audio_file_id, if (!file_view.is_encrypted_secret() || file_view.encryption_key().empty()) { return SecretInputMedia{}; } - if (file_view.has_remote_location()) { - input_file = file_view.main_remote_location().as_input_encrypted_file(); + const auto *main_remote_location = file_view.get_main_remote_location(); + if (main_remote_location != nullptr) { + input_file = main_remote_location->as_input_encrypted_file(); } if (!input_file) { return SecretInputMedia{}; @@ -271,12 +273,14 @@ tl_object_ptr AudiosManager::get_input_media( if (file_view.is_encrypted()) { return nullptr; } - if (file_view.has_remote_location() && !file_view.main_remote_location().is_web() && input_file == nullptr) { - return make_tl_object( - 0, false /*ignored*/, file_view.main_remote_location().as_input_document(), 0, string()); + const auto *main_remote_location = file_view.get_main_remote_location(); + if (main_remote_location != nullptr && !main_remote_location->is_web() && input_file == nullptr) { + return make_tl_object(0, false /*ignored*/, + main_remote_location->as_input_document(), 0, string()); } - if (file_view.has_url()) { - return make_tl_object(0, false /*ignored*/, file_view.url(), 0); + const auto *url = file_view.get_url(); + if (url != nullptr) { + return make_tl_object(0, false /*ignored*/, *url, 0); } if (input_file != nullptr) { @@ -303,7 +307,7 @@ tl_object_ptr AudiosManager::get_input_media( std::move(input_thumbnail), mime_type, std::move(attributes), vector>(), 0); } else { - CHECK(!file_view.has_remote_location()); + CHECK(main_remote_location == nullptr); } return nullptr; diff --git a/lib/tgchat/ext/td/td/telegram/BackgroundManager.cpp b/lib/tgchat/ext/td/td/telegram/BackgroundManager.cpp index e30d5e8a..958a2b67 100644 --- a/lib/tgchat/ext/td/td/telegram/BackgroundManager.cpp +++ b/lib/tgchat/ext/td/td/telegram/BackgroundManager.cpp @@ -654,7 +654,7 @@ Result BackgroundManager::prepare_input_file(const tl_object_ptr get_chat_boost_object( } return td_api::make_object( td->user_manager_->get_user_id_object(user_id, "chatBoostSourceGiveaway"), boost->used_gift_slug_, - giveaway_message_id.get(), boost->unclaimed_); + boost->stars_, giveaway_message_id.get(), boost->unclaimed_); } if (boost->gift_) { UserId user_id(boost->user_id_); @@ -187,11 +188,29 @@ class GetBoostsStatusQuery final : public Td::ResultHandler { premium_member_percentage = 100.0 * premium_member_count / participant_count; } } - auto giveaways = transform(std::move(result->prepaid_giveaways_), - [](telegram_api::object_ptr giveaway) { - return td_api::make_object( - giveaway->id_, giveaway->quantity_, giveaway->months_, giveaway->date_); - }); + auto giveaways = transform( + std::move(result->prepaid_giveaways_), + [](telegram_api::object_ptr giveaway_ptr) + -> td_api::object_ptr { + switch (giveaway_ptr->get_id()) { + case telegram_api::prepaidGiveaway::ID: { + auto giveaway = telegram_api::move_object_as(giveaway_ptr); + return td_api::make_object( + giveaway->id_, giveaway->quantity_, + td_api::make_object(giveaway->months_), 0, giveaway->date_); + } + case telegram_api::prepaidStarsGiveaway::ID: { + auto giveaway = telegram_api::move_object_as(giveaway_ptr); + return td_api::make_object( + giveaway->id_, giveaway->quantity_, + td_api::make_object(StarManager::get_star_count(giveaway->stars_)), + giveaway->boosts_, giveaway->date_); + } + default: + UNREACHABLE(); + return nullptr; + } + }); auto boost_count = max(0, result->boosts_); auto gift_code_boost_count = clamp(result->gift_boosts_, 0, boost_count); promise_.set_value(td_api::make_object( diff --git a/lib/tgchat/ext/td/td/telegram/BotInfoManager.cpp b/lib/tgchat/ext/td/td/telegram/BotInfoManager.cpp index ab3b0021..73ab204e 100644 --- a/lib/tgchat/ext/td/td/telegram/BotInfoManager.cpp +++ b/lib/tgchat/ext/td/td/telegram/BotInfoManager.cpp @@ -848,8 +848,9 @@ void BotInfoManager::on_upload_bot_media_preview(FileId file_id, FileView file_view = td_->file_manager_->get_file_view(file_id); CHECK(!file_view.is_encrypted()); - if (input_file == nullptr && file_view.has_remote_location()) { - if (file_view.main_remote_location().is_web()) { + const auto *main_remote_location = file_view.get_main_remote_location(); + if (input_file == nullptr && main_remote_location != nullptr) { + if (main_remote_location->is_web()) { return pending_preview->promise_.set_error(Status::Error(400, "Can't use web photo as a preview")); } if (pending_preview->was_reuploaded_) { @@ -858,7 +859,7 @@ void BotInfoManager::on_upload_bot_media_preview(FileId file_id, pending_preview->was_reuploaded_ = true; // delete file reference and forcely reupload the file - td_->file_manager_->delete_file_reference(file_id, file_view.main_remote_location().get_file_reference()); + td_->file_manager_->delete_file_reference(file_id, main_remote_location->get_file_reference()); return do_add_bot_media_preview(std::move(pending_preview), {-1}); } CHECK(input_file != nullptr); @@ -891,16 +892,21 @@ void BotInfoManager::on_upload_bot_media_preview_error(FileId file_id, Status st telegram_api::object_ptr BotInfoManager::get_fake_input_media(FileId file_id) const { FileView file_view = td_->file_manager_->get_file_view(file_id); - if (file_view.empty() || !file_view.has_remote_location() || file_view.remote_location().is_web()) { + if (file_view.empty()) { return nullptr; } + auto full_remote_location = file_view.get_full_remote_location(); + if (full_remote_location == nullptr || full_remote_location->is_web()) { + return nullptr; + } + switch (file_view.get_type()) { case FileType::VideoStory: return telegram_api::make_object( - 0, false /*ignored*/, file_view.remote_location().as_input_document(), 0, string()); + 0, false /*ignored*/, full_remote_location->as_input_document(), 0, string()); case FileType::PhotoStory: return telegram_api::make_object(0, false /*ignored*/, - file_view.remote_location().as_input_photo(), 0); + full_remote_location->as_input_photo(), 0); default: return nullptr; } diff --git a/lib/tgchat/ext/td/td/telegram/BotQueries.cpp b/lib/tgchat/ext/td/td/telegram/BotQueries.cpp new file mode 100644 index 00000000..aa87839c --- /dev/null +++ b/lib/tgchat/ext/td/td/telegram/BotQueries.cpp @@ -0,0 +1,116 @@ +// +// Copyright Aliaksei Levin (levlam@telegram.org), Arseny Smirnov (arseny30@gmail.com) 2014-2024 +// +// 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/BotQueries.h" + +#include "td/telegram/Global.h" +#include "td/telegram/Td.h" +#include "td/telegram/telegram_api.h" + +#include "td/utils/buffer.h" +#include "td/utils/logging.h" +#include "td/utils/Status.h" + +namespace td { + +class SendCustomRequestQuery final : public Td::ResultHandler { + Promise> promise_; + + public: + explicit SendCustomRequestQuery(Promise> &&promise) + : promise_(std::move(promise)) { + } + + void send(const string &method, const string ¶meters) { + send_query(G()->net_query_creator().create( + telegram_api::bots_sendCustomRequest(method, telegram_api::make_object(parameters)))); + } + + void on_result(BufferSlice packet) final { + auto result_ptr = fetch_result(packet); + if (result_ptr.is_error()) { + return on_error(result_ptr.move_as_error()); + } + + auto result = result_ptr.move_as_ok(); + promise_.set_value(td_api::make_object(result->data_)); + } + + void on_error(Status status) final { + promise_.set_error(std::move(status)); + } +}; + +class AnswerCustomQueryQuery final : public Td::ResultHandler { + Promise promise_; + + public: + explicit AnswerCustomQueryQuery(Promise &&promise) : promise_(std::move(promise)) { + } + + void send(int64 custom_query_id, const string &data) { + send_query(G()->net_query_creator().create(telegram_api::bots_answerWebhookJSONQuery( + custom_query_id, telegram_api::make_object(data)))); + } + + void on_result(BufferSlice packet) final { + auto result_ptr = fetch_result(packet); + if (result_ptr.is_error()) { + return on_error(result_ptr.move_as_error()); + } + + bool result = result_ptr.ok(); + if (!result) { + LOG(INFO) << "Sending answer to a custom query has failed"; + } + promise_.set_value(Unit()); + } + + void on_error(Status status) final { + promise_.set_error(std::move(status)); + } +}; + +class SetBotUpdatesStatusQuery final : public Td::ResultHandler { + public: + void send(int32 pending_update_count, const string &error_message) { + send_query( + G()->net_query_creator().create(telegram_api::help_setBotUpdatesStatus(pending_update_count, error_message))); + } + + void on_result(BufferSlice packet) final { + auto result_ptr = fetch_result(packet); + if (result_ptr.is_error()) { + return on_error(result_ptr.move_as_error()); + } + + bool result = result_ptr.ok(); + LOG_IF(WARNING, !result) << "Set bot updates status has failed"; + } + + void on_error(Status status) final { + if (!G()->is_expected_error(status)) { + LOG(WARNING) << "Receive error for SetBotUpdatesStatusQuery: " << status; + } + status.ignore(); + } +}; + +void send_bot_custom_query(Td *td, const string &method, const string ¶meters, + Promise> &&promise) { + td->create_handler(std::move(promise))->send(method, parameters); +} + +void answer_bot_custom_query(Td *td, int64 custom_query_id, const string &data, Promise &&promise) { + td->create_handler(std::move(promise))->send(custom_query_id, data); +} + +void set_bot_updates_status(Td *td, int32 pending_update_count, const string &error_message, Promise &&promise) { + td->create_handler()->send(pending_update_count, error_message); + promise.set_value(Unit()); +} + +} // namespace td diff --git a/lib/tgchat/ext/td/td/telegram/BotQueries.h b/lib/tgchat/ext/td/td/telegram/BotQueries.h new file mode 100644 index 00000000..5364520b --- /dev/null +++ b/lib/tgchat/ext/td/td/telegram/BotQueries.h @@ -0,0 +1,25 @@ +// +// Copyright Aliaksei Levin (levlam@telegram.org), Arseny Smirnov (arseny30@gmail.com) 2014-2024 +// +// 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/utils/common.h" +#include "td/utils/Promise.h" + +namespace td { + +class Td; + +void send_bot_custom_query(Td *td, const string &method, const string ¶meters, + Promise> &&promise); + +void answer_bot_custom_query(Td *td, int64 custom_query_id, const string &data, Promise &&promise); + +void set_bot_updates_status(Td *td, int32 pending_update_count, const string &error_message, Promise &&promise); + +} // namespace td diff --git a/lib/tgchat/ext/td/td/telegram/BusinessChatLink.h b/lib/tgchat/ext/td/td/telegram/BusinessChatLink.h index 06fbe091..ee53be06 100644 --- a/lib/tgchat/ext/td/td/telegram/BusinessChatLink.h +++ b/lib/tgchat/ext/td/td/telegram/BusinessChatLink.h @@ -43,8 +43,8 @@ class BusinessChatLinks { friend StringBuilder &operator<<(StringBuilder &string_builder, const BusinessChatLinks &links); public: - explicit BusinessChatLinks(const UserManager *user_manager, - vector> &&links); + BusinessChatLinks(const UserManager *user_manager, + vector> &&links); td_api::object_ptr get_business_chat_links_object(const UserManager *user_manager) const; }; diff --git a/lib/tgchat/ext/td/td/telegram/BusinessConnectionManager.cpp b/lib/tgchat/ext/td/td/telegram/BusinessConnectionManager.cpp index 3534f1e9..3f399586 100644 --- a/lib/tgchat/ext/td/td/telegram/BusinessConnectionManager.cpp +++ b/lib/tgchat/ext/td/td/telegram/BusinessConnectionManager.cpp @@ -865,7 +865,7 @@ void BusinessConnectionManager::do_send_message(unique_ptr &&mes auto file_id = get_message_file_id(fake_message); CHECK(file_id.is_valid()); FileView file_view = td_->file_manager_->get_file_view(file_id); - if (file_view.has_remote_location()) { + if (file_view.has_full_remote_location()) { UploadMediaResult result; result.message_ = std::move(fake_message); result.input_media_ = std::move(input_media); @@ -950,7 +950,8 @@ void BusinessConnectionManager::upload_media(unique_ptr &&messag if (file_view.is_encrypted()) { return promise.set_error(Status::Error(400, "Can't use encrypted file")); } - if (file_view.has_remote_location() && file_view.main_remote_location().is_web()) { + const auto *main_remote_location = file_view.get_main_remote_location(); + if (main_remote_location != nullptr && main_remote_location->is_web()) { return promise.set_error(Status::Error(400, "Can't use a web file")); } @@ -958,7 +959,7 @@ void BusinessConnectionManager::upload_media(unique_ptr &&messag media.message_ = std::move(message); media.promise_ = std::move(promise); - if (!file_view.has_remote_location() && file_view.has_url()) { + if (!file_view.has_full_remote_location() && file_view.has_url()) { return do_upload_media(std::move(media), nullptr); } @@ -1130,7 +1131,7 @@ void BusinessConnectionManager::send_message_album( auto file_id = get_message_file_id(message); CHECK(file_id.is_valid()); FileView file_view = td_->file_manager_->get_file_view(file_id); - if (file_view.has_remote_location()) { + if (file_view.has_full_remote_location()) { UploadMediaResult result; result.message_ = std::move(message); result.input_media_ = std::move(input_media); @@ -1249,8 +1250,13 @@ void BusinessConnectionManager::on_upload_message_paid_media(int64 request_id, s auto upload_result = r_upload_result.move_as_ok(); input_media.push_back(std::move(upload_result.input_media_)); } + auto payload = get_message_content_payload(message->content_.get()); + int32 flags = 0; + if (!payload.empty()) { + flags |= telegram_api::inputMediaPaidMedia::PAYLOAD_MASK; + } auto input_media_paid_media = telegram_api::make_object( - get_message_content_star_count(message->content_.get()), std::move(input_media)); + flags, get_message_content_star_count(message->content_.get()), std::move(input_media), payload); td_->create_handler(std::move(promise)) ->send(std::move(message), std::move(input_media_paid_media)); } @@ -1362,7 +1368,7 @@ void BusinessConnectionManager::edit_business_message_media( auto file_id = get_message_content_any_file_id(content.content.get()); CHECK(file_id.is_valid()); FileView file_view = td_->file_manager_->get_file_view(file_id); - if (file_view.has_remote_location()) { + if (file_view.has_full_remote_location()) { const FormattedText *caption = get_message_content_caption(content.content.get()); td_->create_handler(std::move(promise)) ->send(1 << 11, business_connection_id, dialog_id, message_id, caption == nullptr ? "" : caption->text, diff --git a/lib/tgchat/ext/td/td/telegram/BusinessIntro.cpp b/lib/tgchat/ext/td/td/telegram/BusinessIntro.cpp index ed40da65..93de62e5 100644 --- a/lib/tgchat/ext/td/td/telegram/BusinessIntro.cpp +++ b/lib/tgchat/ext/td/td/telegram/BusinessIntro.cpp @@ -45,8 +45,8 @@ BusinessIntro::BusinessIntro(Td *td, td_api::object_ptrfile_manager_->get_file_view(file_id); - if (!file_view.has_remote_location() || !file_view.main_remote_location().is_document() || - file_view.main_remote_location().is_web() || + const auto *main_remote_location = file_view.get_main_remote_location(); + if (main_remote_location == nullptr || !main_remote_location->is_document() || main_remote_location->is_web() || td->stickers_manager_->get_sticker_type(file_id) == StickerType::CustomEmoji) { file_id = FileId(); } @@ -67,7 +67,9 @@ telegram_api::object_ptr BusinessIntro::get_in telegram_api::object_ptr input_document; if (sticker_file_id_.is_valid()) { auto file_view = td->file_manager_->get_file_view(sticker_file_id_); - input_document = file_view.main_remote_location().as_input_document(); + const auto *main_remote_location = file_view.get_main_remote_location(); + CHECK(main_remote_location != nullptr); + input_document = main_remote_location->as_input_document(); flags |= telegram_api::inputBusinessIntro::STICKER_MASK; } diff --git a/lib/tgchat/ext/td/td/telegram/CallActor.cpp b/lib/tgchat/ext/td/td/telegram/CallActor.cpp index e0a247aa..5137814f 100644 --- a/lib/tgchat/ext/td/td/telegram/CallActor.cpp +++ b/lib/tgchat/ext/td/td/telegram/CallActor.cpp @@ -366,7 +366,7 @@ void CallActor::send_call_log(td_api::object_ptr log_file, Pr if (file_view.is_encrypted()) { return promise.set_error(Status::Error(400, "Can't use encrypted file")); } - if (!file_view.has_local_location() && !file_view.has_generate_location()) { + if (!file_view.has_full_local_location() && !file_view.has_generate_location()) { return promise.set_error(Status::Error(400, "Need local or generate location to upload call log")); } diff --git a/lib/tgchat/ext/td/td/telegram/CallbackQueriesManager.cpp b/lib/tgchat/ext/td/td/telegram/CallbackQueriesManager.cpp index 0aa4eb21..4afaa112 100644 --- a/lib/tgchat/ext/td/td/telegram/CallbackQueriesManager.cpp +++ b/lib/tgchat/ext/td/td/telegram/CallbackQueriesManager.cpp @@ -12,6 +12,7 @@ #include "td/telegram/Global.h" #include "td/telegram/InlineQueriesManager.h" #include "td/telegram/MessagesManager.h" +#include "td/telegram/net/NetQuery.h" #include "td/telegram/PasswordManager.h" #include "td/telegram/Td.h" #include "td/telegram/td_api.h" diff --git a/lib/tgchat/ext/td/td/telegram/ChatManager.cpp b/lib/tgchat/ext/td/td/telegram/ChatManager.cpp index 8f48822e..da5b6cd7 100644 --- a/lib/tgchat/ext/td/td/telegram/ChatManager.cpp +++ b/lib/tgchat/ext/td/td/telegram/ChatManager.cpp @@ -28,7 +28,6 @@ #include "td/telegram/MinChannel.h" #include "td/telegram/misc.h" #include "td/telegram/MissingInvitee.h" -#include "td/telegram/net/NetQuery.h" #include "td/telegram/OptionManager.h" #include "td/telegram/PeerColor.h" #include "td/telegram/Photo.h" diff --git a/lib/tgchat/ext/td/td/telegram/ChatReactions.cpp b/lib/tgchat/ext/td/td/telegram/ChatReactions.cpp index a379a45e..91779e73 100644 --- a/lib/tgchat/ext/td/td/telegram/ChatReactions.cpp +++ b/lib/tgchat/ext/td/td/telegram/ChatReactions.cpp @@ -86,6 +86,14 @@ ChatReactions ChatReactions::get_active_reactions( return result; } +void ChatReactions::fix_broadcast_reactions(const vector &active_reaction_types) { + if (allow_all_regular_) { + reaction_types_ = active_reaction_types; + allow_all_regular_ = false; + allow_all_custom_ = false; + } +} + bool ChatReactions::is_allowed_reaction_type(const ReactionType &reaction_type) const { CHECK(!allow_all_regular_); if (allow_all_custom_ && reaction_type.is_custom_reaction()) { diff --git a/lib/tgchat/ext/td/td/telegram/ChatReactions.h b/lib/tgchat/ext/td/td/telegram/ChatReactions.h index f1ed0aea..8b7c9053 100644 --- a/lib/tgchat/ext/td/td/telegram/ChatReactions.h +++ b/lib/tgchat/ext/td/td/telegram/ChatReactions.h @@ -45,6 +45,8 @@ struct ChatReactions { ChatReactions get_active_reactions( const FlatHashMap &active_reaction_pos) const; + void fix_broadcast_reactions(const vector &active_reaction_types); + bool is_allowed_reaction_type(const ReactionType &reaction) const; telegram_api::object_ptr get_input_chat_reactions() const; diff --git a/lib/tgchat/ext/td/td/telegram/Client.cpp b/lib/tgchat/ext/td/td/telegram/Client.cpp index 39340e67..45322cee 100644 --- a/lib/tgchat/ext/td/td/telegram/Client.cpp +++ b/lib/tgchat/ext/td/td/telegram/Client.cpp @@ -298,7 +298,7 @@ class TdReceiver { unique_ptr create_callback(ClientManager::ClientId client_id) { class Callback final : public TdCallback { public: - explicit Callback(ClientManager::ClientId client_id, std::shared_ptr output_queue) + Callback(ClientManager::ClientId client_id, std::shared_ptr output_queue) : client_id_(client_id), output_queue_(std::move(output_queue)) { } void on_result(uint64 id, td_api::object_ptr result) final { diff --git a/lib/tgchat/ext/td/td/telegram/ClientActor.cpp b/lib/tgchat/ext/td/td/telegram/ClientActor.cpp index e70df1dc..915ba7f1 100644 --- a/lib/tgchat/ext/td/td/telegram/ClientActor.cpp +++ b/lib/tgchat/ext/td/td/telegram/ClientActor.cpp @@ -6,7 +6,6 @@ // #include "td/telegram/ClientActor.h" -#include "td/telegram/net/NetQueryCounter.h" #include "td/telegram/net/NetQueryStats.h" #include "td/telegram/Td.h" diff --git a/lib/tgchat/ext/td/td/telegram/ConfigManager.cpp b/lib/tgchat/ext/td/td/telegram/ConfigManager.cpp index a6b6dc65..5abd7754 100644 --- a/lib/tgchat/ext/td/td/telegram/ConfigManager.cpp +++ b/lib/tgchat/ext/td/td/telegram/ConfigManager.cpp @@ -2064,11 +2064,11 @@ void ConfigManager::process_app_config(tl_object_ptr &c continue; } if (key == "stars_usd_sell_rate_x1000") { - G()->set_option_integer("usd_to_1000_star_rate", get_json_value_int(std::move(key_value->value_), key)); + G()->set_option_integer("usd_to_thousand_star_rate", get_json_value_int(std::move(key_value->value_), key)); continue; } if (key == "stars_usd_withdraw_rate_x1000") { - G()->set_option_integer("1000_star_to_usd_rate", get_json_value_int(std::move(key_value->value_), key)); + G()->set_option_integer("thousand_star_to_usd_rate", get_json_value_int(std::move(key_value->value_), key)); continue; } diff --git a/lib/tgchat/ext/td/td/telegram/DialogAction.cpp b/lib/tgchat/ext/td/td/telegram/DialogAction.cpp index 3baccbf6..a8267a0b 100644 --- a/lib/tgchat/ext/td/td/telegram/DialogAction.cpp +++ b/lib/tgchat/ext/td/td/telegram/DialogAction.cpp @@ -425,6 +425,7 @@ bool DialogAction::is_canceled_by_message_of_type(MessageContentType message_con case MessageContentType::DialogShared: case MessageContentType::PaymentRefunded: case MessageContentType::GiftStars: + case MessageContentType::PrizeStars: return false; default: UNREACHABLE(); diff --git a/lib/tgchat/ext/td/td/telegram/DialogEventLog.cpp b/lib/tgchat/ext/td/td/telegram/DialogEventLog.cpp index 4b5f69a1..ff3ef6f2 100644 --- a/lib/tgchat/ext/td/td/telegram/DialogEventLog.cpp +++ b/lib/tgchat/ext/td/td/telegram/DialogEventLog.cpp @@ -476,6 +476,27 @@ static td_api::object_ptr get_chat_event_action_object( return td_api::make_object(old_emoji_status.get_emoji_status_object(), new_emoji_status.get_emoji_status_object()); } + case telegram_api::channelAdminLogEventActionParticipantSubExtend::ID: { + auto action = move_tl_object_as(action_ptr); + auto channel_type = td->chat_manager_->get_channel_type(channel_id); + DialogParticipant old_dialog_participant(std::move(action->prev_participant_), channel_type); + DialogParticipant new_dialog_participant(std::move(action->new_participant_), channel_type); + if (old_dialog_participant.dialog_id_ != new_dialog_participant.dialog_id_) { + LOG(ERROR) << old_dialog_participant.dialog_id_ << " VS " << new_dialog_participant.dialog_id_; + return nullptr; + } + if (!old_dialog_participant.is_valid() || !new_dialog_participant.is_valid() || + old_dialog_participant.dialog_id_.get_type() != DialogType::User || + !old_dialog_participant.status_.is_member() || !new_dialog_participant.status_.is_member()) { + LOG(ERROR) << "Wrong subscription: " << old_dialog_participant << " -> " << new_dialog_participant; + return nullptr; + } + return td_api::make_object( + td->user_manager_->get_user_id_object(old_dialog_participant.dialog_id_.get_user_id(), + "chatEventMemberSubscriptionExtended"), + old_dialog_participant.status_.get_chat_member_status_object(), + new_dialog_participant.status_.get_chat_member_status_object()); + } default: UNREACHABLE(); return nullptr; @@ -617,12 +638,15 @@ static telegram_api::object_ptr get_i if (filters->forum_changes_) { flags |= telegram_api::channelAdminLogEventsFilter::FORUMS_MASK; } + if (filters->subscription_extensions_) { + flags |= telegram_api::channelAdminLogEventsFilter::SUB_EXTEND_MASK; + } return telegram_api::make_object( flags, false /*ignored*/, false /*ignored*/, false /*ignored*/, false /*ignored*/, false /*ignored*/, false /*ignored*/, false /*ignored*/, false /*ignored*/, false /*ignored*/, false /*ignored*/, false /*ignored*/, false /*ignored*/, false /*ignored*/, false /*ignored*/, false /*ignored*/, false /*ignored*/, false /*ignored*/, - false /*ignored*/); + false /*ignored*/, false /*ignored*/); } void get_dialog_event_log(Td *td, DialogId dialog_id, const string &query, int64 from_event_id, int32 limit, diff --git a/lib/tgchat/ext/td/td/telegram/DialogInviteLinkManager.cpp b/lib/tgchat/ext/td/td/telegram/DialogInviteLinkManager.cpp index 155dad3e..3b8413e0 100644 --- a/lib/tgchat/ext/td/td/telegram/DialogInviteLinkManager.cpp +++ b/lib/tgchat/ext/td/td/telegram/DialogInviteLinkManager.cpp @@ -986,12 +986,19 @@ void DialogInviteLinkManager::export_dialog_invite_link(DialogId dialog_id, stri if (subscription_pricing.is_empty()) { return promise.set_error(Status::Error(400, "Invalid subscription pricing specified")); } + CHECK(expire_date == 0 && usage_limit == 0 && !creates_join_request); } else { CHECK(subscription_pricing.is_empty()); } + if (creates_join_request && usage_limit > 0) { + return promise.set_error( + Status::Error(400, "Member limit can't be specified for links requiring administrator approval")); + } + td_->user_manager_->get_me(PromiseCreator::lambda( - [actor_id = actor_id(this), dialog_id, title = std::move(title), expire_date, usage_limit, creates_join_request, - subscription_pricing, is_permanent, promise = std::move(promise)](Result &&result) mutable { + [actor_id = actor_id(this), dialog_id, title = clean_name(std::move(title), MAX_INVITE_LINK_TITLE_LENGTH), + expire_date, usage_limit, creates_join_request, subscription_pricing, is_permanent, + promise = std::move(promise)](Result &&result) mutable { if (result.is_error()) { promise.set_error(result.move_as_error()); } else { @@ -1008,18 +1015,9 @@ void DialogInviteLinkManager::export_dialog_invite_link_impl( Promise> &&promise) { TRY_STATUS_PROMISE(promise, G()->close_status()); TRY_STATUS_PROMISE(promise, can_manage_dialog_invite_links(dialog_id)); - if (creates_join_request && usage_limit > 0) { - return promise.set_error( - Status::Error(400, "Member limit can't be specified for links requiring administrator approval")); - } - if ((expire_date || usage_limit || creates_join_request) && !subscription_pricing.is_empty()) { - return promise.set_error( - Status::Error(400, "Subscription plan can't be specified for links with additional restrictions")); - } - auto new_title = clean_name(std::move(title), MAX_INVITE_LINK_TITLE_LENGTH); td_->create_handler(std::move(promise)) - ->send(dialog_id, new_title, expire_date, usage_limit, creates_join_request, subscription_pricing, is_permanent); + ->send(dialog_id, title, expire_date, usage_limit, creates_join_request, subscription_pricing, is_permanent); } void DialogInviteLinkManager::edit_dialog_invite_link(DialogId dialog_id, const string &invite_link, string title, diff --git a/lib/tgchat/ext/td/td/telegram/DialogManager.cpp b/lib/tgchat/ext/td/td/telegram/DialogManager.cpp index bb3b692a..3bd8b416 100644 --- a/lib/tgchat/ext/td/td/telegram/DialogManager.cpp +++ b/lib/tgchat/ext/td/td/telegram/DialogManager.cpp @@ -1403,8 +1403,10 @@ void DialogManager::set_dialog_photo(DialogId dialog_id, const td_api::object_pt } auto file_view = td_->file_manager_->get_file_view(file_id); + const auto *main_remote_location = file_view.get_main_remote_location(); + CHECK(main_remote_location != nullptr); auto input_chat_photo = - telegram_api::make_object(file_view.main_remote_location().as_input_photo()); + telegram_api::make_object(main_remote_location->as_input_photo()); return send_edit_dialog_photo_query(dialog_id, file_id, std::move(input_chat_photo), std::move(promise)); } case td_api::inputChatPhotoStatic::ID: { @@ -1498,8 +1500,9 @@ void DialogManager::on_upload_dialog_photo(FileId file_id, FileView file_view = td_->file_manager_->get_file_view(file_id); CHECK(!file_view.is_encrypted()); - if (input_file == nullptr && file_view.has_remote_location()) { - if (file_view.main_remote_location().is_web()) { + const auto *main_remote_location = file_view.get_main_remote_location(); + if (input_file == nullptr && main_remote_location != nullptr) { + if (main_remote_location->is_web()) { return promise.set_error(Status::Error(400, "Can't use web photo as profile photo")); } if (is_reupload) { @@ -1509,12 +1512,12 @@ void DialogManager::on_upload_dialog_photo(FileId file_id, if (is_animation) { CHECK(file_view.get_type() == FileType::Animation); // delete file reference and forcely reupload the file - auto file_reference = FileManager::extract_file_reference(file_view.main_remote_location().as_input_document()); + auto file_reference = FileManager::extract_file_reference(main_remote_location->as_input_document()); td_->file_manager_->delete_file_reference(file_id, file_reference); upload_dialog_photo(dialog_id, file_id, is_animation, main_frame_timestamp, true, std::move(promise), {-1}); } else { CHECK(file_view.get_type() == FileType::Photo); - auto input_photo = file_view.main_remote_location().as_input_photo(); + auto input_photo = main_remote_location->as_input_photo(); auto input_chat_photo = telegram_api::make_object(std::move(input_photo)); send_edit_dialog_photo_query(dialog_id, file_id, std::move(input_chat_photo), std::move(promise)); } @@ -1830,13 +1833,16 @@ void DialogManager::report_dialog_photo(DialogId dialog_id, FileId file_id, Repo if (file_view.empty()) { return promise.set_error(Status::Error(400, "Unknown file identifier")); } - if (get_main_file_type(file_view.get_type()) != FileType::Photo || !file_view.has_remote_location() || - !file_view.remote_location().is_photo()) { + if (get_main_file_type(file_view.get_type()) != FileType::Photo) { return promise.set_error(Status::Error(400, "Only full chat photos can be reported")); } + const auto *full_remote_location = file_view.get_full_remote_location(); + if (full_remote_location == nullptr || !full_remote_location->is_photo()) { + return promise.set_error(Status::Error(400, "Invalid photo identifier specified")); + } td_->create_handler(std::move(promise)) - ->send(dialog_id, file_id, file_view.remote_location().as_input_photo(), std::move(reason)); + ->send(dialog_id, file_id, full_remote_location->as_input_photo(), std::move(reason)); } Status DialogManager::can_pin_messages(DialogId dialog_id) const { diff --git a/lib/tgchat/ext/td/td/telegram/DocumentsManager.cpp b/lib/tgchat/ext/td/td/telegram/DocumentsManager.cpp index 7a4174de..07baf540 100644 --- a/lib/tgchat/ext/td/td/telegram/DocumentsManager.cpp +++ b/lib/tgchat/ext/td/td/telegram/DocumentsManager.cpp @@ -623,7 +623,8 @@ const DocumentsManager::GeneralDocument *DocumentsManager::get_document(FileId f bool DocumentsManager::has_input_media(FileId file_id, FileId thumbnail_file_id, bool is_secret) const { auto file_view = td_->file_manager_->get_file_view(file_id); if (is_secret) { - if (!file_view.is_encrypted_secret() || file_view.encryption_key().empty() || !file_view.has_remote_location()) { + if (!file_view.is_encrypted_secret() || file_view.encryption_key().empty() || + !file_view.has_full_remote_location()) { return false; } @@ -632,13 +633,13 @@ bool DocumentsManager::has_input_media(FileId file_id, FileId thumbnail_file_id, if (file_view.is_encrypted()) { return false; } - if (td_->auth_manager_->is_bot() && file_view.has_remote_location()) { + if (td_->auth_manager_->is_bot() && file_view.has_full_remote_location()) { return true; } // having remote location is not enough to have InputMedia, because the file may not have valid file_reference // also file_id needs to be duped, because upload can be called to repair the file_reference and every upload // request must have unique file_id - return /* file_view.has_remote_location() || */ file_view.has_url(); + return /* file_view.has_full_remote_location() || */ file_view.has_url(); } } @@ -652,8 +653,9 @@ SecretInputMedia DocumentsManager::get_secret_input_media(FileId document_file_i if (!file_view.is_encrypted_secret() || file_view.encryption_key().empty()) { return SecretInputMedia{}; } - if (file_view.has_remote_location()) { - input_file = file_view.main_remote_location().as_input_encrypted_file(); + const auto *main_remote_location = file_view.get_main_remote_location(); + if (main_remote_location != nullptr) { + input_file = main_remote_location->as_input_encrypted_file(); } if (!input_file) { return SecretInputMedia{}; @@ -682,12 +684,14 @@ tl_object_ptr DocumentsManager::get_input_media( if (file_view.is_encrypted()) { return nullptr; } - if (file_view.has_remote_location() && !file_view.main_remote_location().is_web() && input_file == nullptr) { - return make_tl_object( - 0, false /*ignored*/, file_view.main_remote_location().as_input_document(), 0, string()); + const auto *main_remote_location = file_view.get_main_remote_location(); + if (main_remote_location != nullptr && !main_remote_location->is_web() && input_file == nullptr) { + return make_tl_object(0, false /*ignored*/, + main_remote_location->as_input_document(), 0, string()); } - if (file_view.has_url()) { - return make_tl_object(0, false /*ignored*/, file_view.url(), 0); + const auto *url = file_view.get_url(); + if (url != nullptr) { + return make_tl_object(0, false /*ignored*/, *url, 0); } if (input_file != nullptr) { @@ -711,7 +715,7 @@ tl_object_ptr DocumentsManager::get_input_media( std::move(input_thumbnail), document->mime_type, std::move(attributes), vector>(), 0); } else { - CHECK(!file_view.has_remote_location()); + CHECK(main_remote_location == nullptr); } return nullptr; diff --git a/lib/tgchat/ext/td/td/telegram/Game.cpp b/lib/tgchat/ext/td/td/telegram/Game.cpp index 85aa9bef..d89dd221 100644 --- a/lib/tgchat/ext/td/td/telegram/Game.cpp +++ b/lib/tgchat/ext/td/td/telegram/Game.cpp @@ -80,11 +80,12 @@ const FormattedText &Game::get_text() const { return text_; } -tl_object_ptr Game::get_game_object(Td *td, bool skip_bot_commands) const { - return make_tl_object(id_, short_name_, title_, - get_formatted_text_object(td->user_manager_.get(), text_, skip_bot_commands, -1), - description_, get_photo_object(td->file_manager_.get(), photo_), - td->animations_manager_->get_animation_object(animation_file_id_)); +tl_object_ptr Game::get_game_object(Td *td, bool is_server, bool skip_bot_commands) const { + return make_tl_object( + id_, short_name_, title_, + get_formatted_text_object(is_server ? td->user_manager_.get() : nullptr, text_, skip_bot_commands, -1), + description_, get_photo_object(td->file_manager_.get(), photo_), + td->animations_manager_->get_animation_object(animation_file_id_)); } bool Game::has_input_media() const { diff --git a/lib/tgchat/ext/td/td/telegram/Game.h b/lib/tgchat/ext/td/td/telegram/Game.h index 4178981e..3d224ad9 100644 --- a/lib/tgchat/ext/td/td/telegram/Game.h +++ b/lib/tgchat/ext/td/td/telegram/Game.h @@ -61,7 +61,7 @@ class Game { const FormattedText &get_text() const; - tl_object_ptr get_game_object(Td *td, bool skip_bot_commands) const; + tl_object_ptr get_game_object(Td *td, bool is_server, bool skip_bot_commands) const; bool has_input_media() const; diff --git a/lib/tgchat/ext/td/td/telegram/GiveawayParameters.cpp b/lib/tgchat/ext/td/td/telegram/GiveawayParameters.cpp index 480bd055..068d6ed8 100644 --- a/lib/tgchat/ext/td/td/telegram/GiveawayParameters.cpp +++ b/lib/tgchat/ext/td/td/telegram/GiveawayParameters.cpp @@ -36,8 +36,8 @@ Result GiveawayParameters::get_boosted_channel_id(Td *td, DialogId di return channel_id; } -Result GiveawayParameters::get_giveaway_parameters( - Td *td, const td_api::premiumGiveawayParameters *parameters) { +Result GiveawayParameters::get_giveaway_parameters(Td *td, + const td_api::giveawayParameters *parameters) { if (parameters == nullptr) { return Status::Error(400, "Giveaway parameters must be non-empty"); } @@ -123,19 +123,58 @@ GiveawayParameters::get_input_store_payment_premium_giveaway(Td *td, const strin vector(country_codes_), prize_description_, random_id, date_, currency, amount); } -td_api::object_ptr GiveawayParameters::get_premium_giveaway_parameters_object( - Td *td) const { +telegram_api::object_ptr +GiveawayParameters::get_input_store_payment_stars_giveaway(Td *td, const string ¤cy, int64 amount, + int32 user_count, int64 star_count) const { + int64 random_id; + do { + random_id = Random::secure_int64(); + } while (random_id == 0); + + auto boost_input_peer = td->dialog_manager_->get_input_peer(DialogId(boosted_channel_id_), AccessRights::Write); + CHECK(boost_input_peer != nullptr); + + vector> additional_input_peers; + for (auto additional_channel_id : additional_channel_ids_) { + auto input_peer = td->dialog_manager_->get_input_peer(DialogId(additional_channel_id), AccessRights::Write); + CHECK(input_peer != nullptr); + additional_input_peers.push_back(std::move(input_peer)); + } + + int32 flags = 0; + if (only_new_subscribers_) { + flags |= telegram_api::inputStorePaymentStarsGiveaway::ONLY_NEW_SUBSCRIBERS_MASK; + } + if (winners_are_visible_) { + flags |= telegram_api::inputStorePaymentStarsGiveaway::WINNERS_ARE_VISIBLE_MASK; + } + if (!additional_input_peers.empty()) { + flags |= telegram_api::inputStorePaymentStarsGiveaway::ADDITIONAL_PEERS_MASK; + } + if (!country_codes_.empty()) { + flags |= telegram_api::inputStorePaymentStarsGiveaway::COUNTRIES_ISO2_MASK; + } + if (!prize_description_.empty()) { + flags |= telegram_api::inputStorePaymentStarsGiveaway::PRIZE_DESCRIPTION_MASK; + } + return telegram_api::make_object( + flags, false /*ignored*/, false /*ignored*/, star_count, std::move(boost_input_peer), + std::move(additional_input_peers), vector(country_codes_), prize_description_, random_id, date_, currency, + amount, user_count); +} + +td_api::object_ptr GiveawayParameters::get_giveaway_parameters_object(Td *td) const { CHECK(is_valid()); vector chat_ids; for (auto channel_id : additional_channel_ids_) { DialogId dialog_id(channel_id); - td->dialog_manager_->force_create_dialog(dialog_id, "premiumGiveawayParameters", true); - chat_ids.push_back(td->dialog_manager_->get_chat_id_object(dialog_id, "premiumGiveawayParameters")); + td->dialog_manager_->force_create_dialog(dialog_id, "giveawayParameters", true); + chat_ids.push_back(td->dialog_manager_->get_chat_id_object(dialog_id, "giveawayParameters")); } DialogId dialog_id(boosted_channel_id_); - td->dialog_manager_->force_create_dialog(dialog_id, "premiumGiveawayParameters", true); - return td_api::make_object( - td->dialog_manager_->get_chat_id_object(dialog_id, "premiumGiveawayParameters"), std::move(chat_ids), date_, + td->dialog_manager_->force_create_dialog(dialog_id, "giveawayParameters", true); + return td_api::make_object( + td->dialog_manager_->get_chat_id_object(dialog_id, "giveawayParameters"), std::move(chat_ids), date_, only_new_subscribers_, winners_are_visible_, vector(country_codes_), prize_description_); } diff --git a/lib/tgchat/ext/td/td/telegram/GiveawayParameters.h b/lib/tgchat/ext/td/td/telegram/GiveawayParameters.h index 53aa41a3..2080df1e 100644 --- a/lib/tgchat/ext/td/td/telegram/GiveawayParameters.h +++ b/lib/tgchat/ext/td/td/telegram/GiveawayParameters.h @@ -52,8 +52,7 @@ class GiveawayParameters { , prize_description_(std::move(prize_description)) { } - static Result get_giveaway_parameters(Td *td, - const td_api::premiumGiveawayParameters *parameters); + static Result get_giveaway_parameters(Td *td, const td_api::giveawayParameters *parameters); bool is_valid() const { for (auto channel_id : additional_channel_ids_) { @@ -75,7 +74,10 @@ class GiveawayParameters { telegram_api::object_ptr get_input_store_payment_premium_giveaway( Td *td, const string ¤cy, int64 amount) const; - td_api::object_ptr get_premium_giveaway_parameters_object(Td *td) const; + telegram_api::object_ptr get_input_store_payment_stars_giveaway( + Td *td, const string ¤cy, int64 amount, int32 user_count, int64 star_count) const; + + td_api::object_ptr get_giveaway_parameters_object(Td *td) const; template void store(StorerT &storer) const; diff --git a/lib/tgchat/ext/td/td/telegram/Global.cpp b/lib/tgchat/ext/td/td/telegram/Global.cpp index 269f633f..4714ffba 100644 --- a/lib/tgchat/ext/td/td/telegram/Global.cpp +++ b/lib/tgchat/ext/td/td/telegram/Global.cpp @@ -9,6 +9,7 @@ #include "td/telegram/AuthManager.h" #include "td/telegram/net/ConnectionCreator.h" #include "td/telegram/net/NetQueryDispatcher.h" +#include "td/telegram/net/NetQueryStats.h" #include "td/telegram/net/TempAuthKeyWatchdog.h" #include "td/telegram/OptionManager.h" #include "td/telegram/StateManager.h" diff --git a/lib/tgchat/ext/td/td/telegram/Global.h b/lib/tgchat/ext/td/td/telegram/Global.h index a9ba54a4..4a2ea40c 100644 --- a/lib/tgchat/ext/td/td/telegram/Global.h +++ b/lib/tgchat/ext/td/td/telegram/Global.h @@ -61,6 +61,7 @@ class LinkManager; class MessageImportManager; class MessagesManager; class NetQueryDispatcher; +class NetQueryStats; class NotificationManager; class NotificationSettingsManager; class OnlineManager; diff --git a/lib/tgchat/ext/td/td/telegram/InlineQueriesManager.cpp b/lib/tgchat/ext/td/td/telegram/InlineQueriesManager.cpp index f3a7bd87..6e4d5787 100644 --- a/lib/tgchat/ext/td/td/telegram/InlineQueriesManager.cpp +++ b/lib/tgchat/ext/td/td/telegram/InlineQueriesManager.cpp @@ -442,7 +442,7 @@ Result> InlineQueriesManager: bool InlineQueriesManager::register_inline_message_content( int64 query_id, const string &result_id, FileId file_id, - tl_object_ptr &&inline_message, int32 allowed_media_content_id, bool allow_invoice, + tl_object_ptr &&inline_message, int32 allowed_media_content_id, bool is_secret_chat, Photo *photo, Game *game) { CHECK(query_id != 0); if (result_id.empty()) { @@ -452,7 +452,7 @@ bool InlineQueriesManager::register_inline_message_content( InlineMessageContent content = create_inline_message_content(td_, file_id, std::move(inline_message), allowed_media_content_id, photo, game); if (content.message_content != nullptr) { - if (!allow_invoice && content.message_content->get_type() == MessageContentType::Invoice) { + if (is_secret_chat && !can_send_message_content_to_secret_chat(content.message_content->get_type())) { return false; } @@ -917,22 +917,22 @@ Result> InlineQueriesManager:: TRY_RESULT(file_id, td_->file_manager_->get_input_file_id( file_type, make_tl_object(content_url), DialogId(), false, false)); FileView file_view = td_->file_manager_->get_file_view(file_id); - CHECK(file_view.has_remote_location()); if (file_view.is_encrypted()) { return Status::Error(400, "Can't send encrypted file"); } - if (file_view.main_remote_location().is_web()) { + const auto *main_remote_location = file_view.get_main_remote_location(); + CHECK(main_remote_location != nullptr); + if (main_remote_location->is_web()) { return Status::Error(400, "Can't send web file"); } if (file_type == FileType::Photo) { - return make_tl_object( - id, type, file_view.main_remote_location().as_input_photo(), std::move(inline_message)); + return make_tl_object(id, type, main_remote_location->as_input_photo(), + std::move(inline_message)); } return make_tl_object( - flags, id, type, title, description, file_view.main_remote_location().as_input_document(), - std::move(inline_message)); + flags, id, type, title, description, main_remote_location->as_input_document(), std::move(inline_message)); } if (!url.empty()) { @@ -1609,7 +1609,7 @@ void InlineQueriesManager::on_get_inline_query_results( td_->user_manager_->on_get_users(std::move(results->users_), "on_get_inline_query_results"); auto dialog_type = dialog_id.get_type(); - bool allow_invoice = dialog_type != DialogType::SecretChat; + bool is_secret_chat = dialog_type == DialogType::SecretChat; vector> output_results; for (auto &result_ptr : results->results_) { tl_object_ptr output_result; @@ -1638,11 +1638,11 @@ void InlineQueriesManager::on_get_inline_query_results( std::move(result->document_), DialogId()); game->id_ = std::move(result->id_); - game->game_ = inline_game.get_game_object(td_, true); + game->game_ = inline_game.get_game_object(td_, true, true); if (!register_inline_message_content(results->query_id_, game->id_, FileId(), std::move(result->send_message_), td_api::inputMessageGame::ID, - allow_invoice, nullptr, &inline_game)) { + is_secret_chat, nullptr, &inline_game)) { continue; } output_result = std::move(game); @@ -1668,7 +1668,7 @@ void InlineQueriesManager::on_get_inline_query_results( if (!register_inline_message_content(results->query_id_, animation->id_, parsed_document.file_id, std::move(result->send_message_), td_api::inputMessageAnimation::ID, - allow_invoice)) { + is_secret_chat)) { continue; } output_result = std::move(animation); @@ -1683,7 +1683,7 @@ void InlineQueriesManager::on_get_inline_query_results( if (!register_inline_message_content(results->query_id_, audio->id_, parsed_document.file_id, std::move(result->send_message_), td_api::inputMessageAudio::ID, - allow_invoice)) { + is_secret_chat)) { continue; } output_result = std::move(audio); @@ -1701,7 +1701,7 @@ void InlineQueriesManager::on_get_inline_query_results( if (!register_inline_message_content(results->query_id_, document->id_, parsed_document.file_id, std::move(result->send_message_), td_api::inputMessageDocument::ID, - allow_invoice)) { + is_secret_chat)) { continue; } output_result = std::move(document); @@ -1716,7 +1716,7 @@ void InlineQueriesManager::on_get_inline_query_results( if (!register_inline_message_content(results->query_id_, sticker->id_, parsed_document.file_id, std::move(result->send_message_), td_api::inputMessageSticker::ID, - allow_invoice)) { + is_secret_chat)) { continue; } output_result = std::move(sticker); @@ -1733,7 +1733,7 @@ void InlineQueriesManager::on_get_inline_query_results( if (!register_inline_message_content(results->query_id_, video->id_, parsed_document.file_id, std::move(result->send_message_), td_api::inputMessageVideo::ID, - allow_invoice)) { + is_secret_chat)) { continue; } output_result = std::move(video); @@ -1752,7 +1752,7 @@ void InlineQueriesManager::on_get_inline_query_results( if (!register_inline_message_content(results->query_id_, voice_note->id_, parsed_document.file_id, std::move(result->send_message_), td_api::inputMessageVoiceNote::ID, - allow_invoice)) { + is_secret_chat)) { continue; } output_result = std::move(voice_note); @@ -1780,7 +1780,7 @@ void InlineQueriesManager::on_get_inline_query_results( if (!register_inline_message_content(results->query_id_, photo->id_, FileId(), std::move(result->send_message_), td_api::inputMessagePhoto::ID, - allow_invoice, &p)) { + is_secret_chat, &p)) { continue; } output_result = std::move(photo); @@ -1808,7 +1808,7 @@ void InlineQueriesManager::on_get_inline_query_results( article->thumbnail_ = register_thumbnail(std::move(result->thumb_)); if (!register_inline_message_content(results->query_id_, article->id_, FileId(), - std::move(result->send_message_), -1, allow_invoice)) { + std::move(result->send_message_), -1, is_secret_chat)) { continue; } output_result = std::move(article); @@ -1828,7 +1828,7 @@ void InlineQueriesManager::on_get_inline_query_results( contact->thumbnail_ = register_thumbnail(std::move(result->thumb_)); if (!register_inline_message_content(results->query_id_, contact->id_, FileId(), - std::move(result->send_message_), -1, allow_invoice)) { + std::move(result->send_message_), -1, is_secret_chat)) { continue; } output_result = std::move(contact); @@ -1849,7 +1849,7 @@ void InlineQueriesManager::on_get_inline_query_results( location->thumbnail_ = register_thumbnail(std::move(result->thumb_)); if (!register_inline_message_content(results->query_id_, location->id_, FileId(), - std::move(result->send_message_), -1, allow_invoice)) { + std::move(result->send_message_), -1, is_secret_chat)) { continue; } output_result = std::move(location); @@ -1877,7 +1877,7 @@ void InlineQueriesManager::on_get_inline_query_results( venue->thumbnail_ = register_thumbnail(std::move(result->thumb_)); if (!register_inline_message_content(results->query_id_, venue->id_, FileId(), - std::move(result->send_message_), -1, allow_invoice)) { + std::move(result->send_message_), -1, is_secret_chat)) { continue; } output_result = std::move(venue); @@ -1907,7 +1907,7 @@ void InlineQueriesManager::on_get_inline_query_results( if (!register_inline_message_content(results->query_id_, photo->id_, FileId(), std::move(result->send_message_), td_api::inputMessagePhoto::ID, - allow_invoice, &new_photo)) { + is_secret_chat, &new_photo)) { continue; } output_result = std::move(photo); @@ -1968,7 +1968,7 @@ void InlineQueriesManager::on_get_inline_query_results( audio->audio_ = td_->audios_manager_->get_audio_object(file_id); if (!register_inline_message_content(results->query_id_, audio->id_, file_id, std::move(result->send_message_), td_api::inputMessageAudio::ID, - allow_invoice)) { + is_secret_chat)) { continue; } output_result = std::move(audio); @@ -1980,7 +1980,7 @@ void InlineQueriesManager::on_get_inline_query_results( document->description_ = std::move(result->description_); if (!register_inline_message_content(results->query_id_, document->id_, file_id, std::move(result->send_message_), td_api::inputMessageDocument::ID, - allow_invoice)) { + is_secret_chat)) { continue; } output_result = std::move(document); @@ -1991,7 +1991,7 @@ void InlineQueriesManager::on_get_inline_query_results( animation->title_ = std::move(result->title_); if (!register_inline_message_content(results->query_id_, animation->id_, file_id, std::move(result->send_message_), td_api::inputMessageAnimation::ID, - allow_invoice)) { + is_secret_chat)) { continue; } output_result = std::move(animation); @@ -2001,7 +2001,7 @@ void InlineQueriesManager::on_get_inline_query_results( sticker->sticker_ = td_->stickers_manager_->get_sticker_object(file_id); if (!register_inline_message_content(results->query_id_, sticker->id_, file_id, std::move(result->send_message_), td_api::inputMessageSticker::ID, - allow_invoice)) { + is_secret_chat)) { continue; } output_result = std::move(sticker); @@ -2013,7 +2013,7 @@ void InlineQueriesManager::on_get_inline_query_results( video->description_ = std::move(result->description_); if (!register_inline_message_content(results->query_id_, video->id_, file_id, std::move(result->send_message_), td_api::inputMessageVideo::ID, - allow_invoice)) { + is_secret_chat)) { continue; } output_result = std::move(video); @@ -2024,7 +2024,7 @@ void InlineQueriesManager::on_get_inline_query_results( voice_note->title_ = std::move(result->title_); if (!register_inline_message_content(results->query_id_, voice_note->id_, file_id, std::move(result->send_message_), td_api::inputMessageVoiceNote::ID, - allow_invoice)) { + is_secret_chat)) { continue; } output_result = std::move(voice_note); diff --git a/lib/tgchat/ext/td/td/telegram/InlineQueriesManager.h b/lib/tgchat/ext/td/td/telegram/InlineQueriesManager.h index 232d008f..5327c821 100644 --- a/lib/tgchat/ext/td/td/telegram/InlineQueriesManager.h +++ b/lib/tgchat/ext/td/td/telegram/InlineQueriesManager.h @@ -101,7 +101,7 @@ class InlineQueriesManager final : public Actor { bool register_inline_message_content(int64 query_id, const string &result_id, FileId file_id, tl_object_ptr &&inline_message, - int32 allowed_media_content_id, bool allow_invoice, Photo *photo = nullptr, + int32 allowed_media_content_id, bool is_secret_chat, Photo *photo = nullptr, Game *game = nullptr); tl_object_ptr register_thumbnail( diff --git a/lib/tgchat/ext/td/td/telegram/InputInvoice.cpp b/lib/tgchat/ext/td/td/telegram/InputInvoice.cpp index 92e5531c..071402c3 100644 --- a/lib/tgchat/ext/td/td/telegram/InputInvoice.cpp +++ b/lib/tgchat/ext/td/td/telegram/InputInvoice.cpp @@ -248,13 +248,15 @@ Result InputInvoice::process_input_message_invoice( return result; } -td_api::object_ptr InputInvoice::get_message_invoice_object(Td *td, bool skip_bot_commands, +td_api::object_ptr InputInvoice::get_message_invoice_object(Td *td, bool is_server, + bool skip_bot_commands, int32 max_media_timestamp) const { - auto extended_media_object = extended_media_.get_message_extended_media_object(td); - auto extended_media_caption_object = extended_media_object == nullptr - ? nullptr - : get_formatted_text_object(td->user_manager_.get(), extended_media_caption_, - skip_bot_commands, max_media_timestamp); + auto extended_media_object = extended_media_.get_paid_media_object(td); + auto extended_media_caption_object = + extended_media_object == nullptr + ? nullptr + : get_formatted_text_object(is_server ? td->user_manager_.get() : nullptr, extended_media_caption_, + skip_bot_commands, max_media_timestamp); return td_api::make_object( get_product_info_object(td, title_, description_, photo_), invoice_.currency_, total_amount_, start_parameter_, invoice_.is_test_, invoice_.need_shipping_address_, receipt_message_id_.get(), std::move(extended_media_object), @@ -309,8 +311,8 @@ tl_object_ptr InputInvoice::Invoice::get_input_invoice() max_tip_amount_, vector(suggested_tip_amounts_), terms_of_service_url); } -static tl_object_ptr get_input_web_document(const FileManager *file_manager, - const Photo &photo) { +static telegram_api::object_ptr get_input_web_document(const FileManager *file_manager, + const Photo &photo) { if (photo.is_empty()) { return nullptr; } @@ -326,12 +328,12 @@ static tl_object_ptr get_input_web_document(cons } auto file_view = file_manager->get_file_view(size.file_id); - CHECK(file_view.has_url()); + const auto *url = file_view.get_url(); + CHECK(url != nullptr); - auto file_name = get_url_file_name(file_view.url()); - return make_tl_object( - file_view.url(), size.size, MimeType::from_extension(PathView(file_name).extension(), "image/jpeg"), - std::move(attributes)); + auto file_name = get_url_file_name(*url); + return telegram_api::make_object( + *url, size.size, MimeType::from_extension(PathView(file_name).extension(), "image/jpeg"), std::move(attributes)); } tl_object_ptr InputInvoice::get_input_media_invoice( diff --git a/lib/tgchat/ext/td/td/telegram/InputInvoice.h b/lib/tgchat/ext/td/td/telegram/InputInvoice.h index 809dd4de..9fcb3466 100644 --- a/lib/tgchat/ext/td/td/telegram/InputInvoice.h +++ b/lib/tgchat/ext/td/td/telegram/InputInvoice.h @@ -83,7 +83,7 @@ class InputInvoice { static Result process_input_message_invoice( td_api::object_ptr &&input_message_content, Td *td, DialogId owner_dialog_id); - td_api::object_ptr get_message_invoice_object(Td *td, bool skip_bot_commands, + td_api::object_ptr get_message_invoice_object(Td *td, bool is_server, bool skip_bot_commands, int32 max_media_timestamp) const; tl_object_ptr get_input_media_invoice( diff --git a/lib/tgchat/ext/td/td/telegram/LinkManager.cpp b/lib/tgchat/ext/td/td/telegram/LinkManager.cpp index 6feead16..75ee1165 100644 --- a/lib/tgchat/ext/td/td/telegram/LinkManager.cpp +++ b/lib/tgchat/ext/td/td/telegram/LinkManager.cpp @@ -10,8 +10,10 @@ #include "td/telegram/BackgroundType.h" #include "td/telegram/ChannelId.h" #include "td/telegram/ChannelType.h" +#include "td/telegram/ChatManager.h" #include "td/telegram/ConfigManager.h" #include "td/telegram/DialogId.h" +#include "td/telegram/DialogInviteLinkManager.h" #include "td/telegram/DialogManager.h" #include "td/telegram/DialogParticipant.h" #include "td/telegram/Global.h" @@ -22,6 +24,7 @@ #include "td/telegram/net/Proxy.h" #include "td/telegram/OptionManager.h" #include "td/telegram/ServerMessageId.h" +#include "td/telegram/StickersManager.h" #include "td/telegram/StoryId.h" #include "td/telegram/Td.h" #include "td/telegram/TdDb.h" @@ -406,7 +409,7 @@ class LinkManager::InternalLinkBuyStars final : public InternalLink { } public: - explicit InternalLinkBuyStars(int64 star_count, const string &purpose) + InternalLinkBuyStars(int64 star_count, const string &purpose) : star_count_(clamp(star_count, static_cast(1), static_cast(1000000000000))), purpose_(purpose) { } }; @@ -845,6 +848,105 @@ class LinkManager::InternalLinkWebApp final : public InternalLink { } }; +class GetRecentMeUrlsQuery final : public Td::ResultHandler { + Promise> promise_; + + public: + explicit GetRecentMeUrlsQuery(Promise> &&promise) : promise_(std::move(promise)) { + } + + void send(const string &referrer) { + send_query(G()->net_query_creator().create(telegram_api::help_getRecentMeUrls(referrer))); + } + + void on_result(BufferSlice packet) final { + auto result_ptr = fetch_result(packet); + if (result_ptr.is_error()) { + return on_error(result_ptr.move_as_error()); + } + + auto urls_full = result_ptr.move_as_ok(); + td_->user_manager_->on_get_users(std::move(urls_full->users_), "GetRecentMeUrlsQuery"); + td_->chat_manager_->on_get_chats(std::move(urls_full->chats_), "GetRecentMeUrlsQuery"); + + auto urls = std::move(urls_full->urls_); + auto results = td_api::make_object(); + results->urls_.reserve(urls.size()); + for (auto &url_ptr : urls) { + CHECK(url_ptr != nullptr); + td_api::object_ptr result = td_api::make_object(); + switch (url_ptr->get_id()) { + case telegram_api::recentMeUrlUser::ID: { + auto url = telegram_api::move_object_as(url_ptr); + result->url_ = std::move(url->url_); + UserId user_id(url->user_id_); + if (!user_id.is_valid()) { + LOG(ERROR) << "Receive invalid " << user_id; + result = nullptr; + break; + } + result->type_ = td_api::make_object( + td_->user_manager_->get_user_id_object(user_id, "tMeUrlTypeUser")); + break; + } + case telegram_api::recentMeUrlChat::ID: { + auto url = telegram_api::move_object_as(url_ptr); + result->url_ = std::move(url->url_); + ChannelId channel_id(url->chat_id_); + if (!channel_id.is_valid()) { + LOG(ERROR) << "Receive invalid " << channel_id; + result = nullptr; + break; + } + result->type_ = td_api::make_object( + td_->chat_manager_->get_supergroup_id_object(channel_id, "tMeUrlTypeSupergroup")); + break; + } + case telegram_api::recentMeUrlChatInvite::ID: { + auto url = telegram_api::move_object_as(url_ptr); + result->url_ = std::move(url->url_); + td_->dialog_invite_link_manager_->on_get_dialog_invite_link_info(result->url_, std::move(url->chat_invite_), + Promise()); + auto info_object = td_->dialog_invite_link_manager_->get_chat_invite_link_info_object(result->url_); + if (info_object == nullptr) { + result = nullptr; + break; + } + result->type_ = td_api::make_object(std::move(info_object)); + break; + } + case telegram_api::recentMeUrlStickerSet::ID: { + auto url = telegram_api::move_object_as(url_ptr); + result->url_ = std::move(url->url_); + auto sticker_set_id = + td_->stickers_manager_->on_get_sticker_set_covered(std::move(url->set_), false, "recentMeUrlStickerSet"); + if (!sticker_set_id.is_valid()) { + LOG(ERROR) << "Receive invalid sticker set"; + result = nullptr; + break; + } + result->type_ = td_api::make_object(sticker_set_id.get()); + break; + } + case telegram_api::recentMeUrlUnknown::ID: + // skip + result = nullptr; + break; + default: + UNREACHABLE(); + } + if (result != nullptr) { + results->urls_.push_back(std::move(result)); + } + } + promise_.set_value(std::move(results)); + } + + void on_error(Status status) final { + promise_.set_error(std::move(status)); + } +}; + class GetDeepLinkInfoQuery final : public Td::ResultHandler { Promise> promise_; @@ -1101,7 +1203,7 @@ Result LinkManager::check_link_impl(Slice link, bool http_only, bool htt query.remove_prefix(1); } for (auto c : http_url.host_) { - if (!is_alnum(c) && c != '-' && c != '_') { + if (!is_alnum(c) && c != '-' && c != '_' && !(is_tonsite && c == '.')) { return Status::Error("Unallowed characters in URL host"); } } @@ -2536,6 +2638,10 @@ void LinkManager::update_autologin_domains(vector autologin_domains, vec } } +void LinkManager::get_recent_me_urls(const string &referrer, Promise> &&promise) { + td_->create_handler(std::move(promise))->send(referrer); +} + void LinkManager::get_deep_link_info(Slice link, Promise> &&promise) { Slice link_scheme("tg:"); if (begins_with(link, link_scheme)) { diff --git a/lib/tgchat/ext/td/td/telegram/LinkManager.h b/lib/tgchat/ext/td/td/telegram/LinkManager.h index 1f72d5ec..ee477dd2 100644 --- a/lib/tgchat/ext/td/td/telegram/LinkManager.h +++ b/lib/tgchat/ext/td/td/telegram/LinkManager.h @@ -68,6 +68,8 @@ class LinkManager final : public Actor { void update_autologin_domains(vector autologin_domains, vector url_auth_domains, vector whitelisted_domains); + void get_recent_me_urls(const string &referrer, Promise> &&promise); + void get_deep_link_info(Slice link, Promise> &&promise); void get_external_link_info(string &&link, Promise> &&promise); diff --git a/lib/tgchat/ext/td/td/telegram/MessageContent.cpp b/lib/tgchat/ext/td/td/telegram/MessageContent.cpp index 8695b825..0577de8e 100644 --- a/lib/tgchat/ext/td/td/telegram/MessageContent.cpp +++ b/lib/tgchat/ext/td/td/telegram/MessageContent.cpp @@ -504,7 +504,7 @@ class MessageChatSetTtl final : public MessageContent { class MessageUnsupported final : public MessageContent { public: - static constexpr int32 CURRENT_VERSION = 33; + static constexpr int32 CURRENT_VERSION = 36; int32 version = CURRENT_VERSION; MessageUnsupported() = default; @@ -1003,10 +1003,14 @@ class MessageGiveaway final : public MessageContent { GiveawayParameters giveaway_parameters; int32 quantity = 0; int32 months = 0; + int64 star_count = 0; MessageGiveaway() = default; - MessageGiveaway(GiveawayParameters giveaway_parameters, int32 quantity, int32 months) - : giveaway_parameters(std::move(giveaway_parameters)), quantity(quantity), months(months) { + MessageGiveaway(GiveawayParameters giveaway_parameters, int32 quantity, int32 months, int64 star_count) + : giveaway_parameters(std::move(giveaway_parameters)) + , quantity(quantity) + , months(months) + , star_count(star_count) { } MessageContentType get_type() const final { @@ -1016,7 +1020,11 @@ class MessageGiveaway final : public MessageContent { class MessageGiveawayLaunch final : public MessageContent { public: + int64 star_count = 0; + MessageGiveawayLaunch() = default; + explicit MessageGiveawayLaunch(int64 star_count) : star_count(star_count) { + } MessageContentType get_type() const final { return MessageContentType::GiveawayLaunch; @@ -1028,10 +1036,15 @@ class MessageGiveawayResults final : public MessageContent { MessageId giveaway_message_id; int32 winner_count = 0; int32 unclaimed_count = 0; + bool is_star_giveaway = false; MessageGiveawayResults() = default; - MessageGiveawayResults(MessageId giveaway_message_id, int32 winner_count, int32 unclaimed_count) - : giveaway_message_id(giveaway_message_id), winner_count(winner_count), unclaimed_count(unclaimed_count) { + MessageGiveawayResults(MessageId giveaway_message_id, int32 winner_count, int32 unclaimed_count, + bool is_star_giveaway) + : giveaway_message_id(giveaway_message_id) + , winner_count(winner_count) + , unclaimed_count(unclaimed_count) + , is_star_giveaway(is_star_giveaway) { } MessageContentType get_type() const final { @@ -1045,6 +1058,7 @@ class MessageGiveawayWinners final : public MessageContent { ChannelId boosted_channel_id; int32 additional_dialog_count = 0; int32 month_count = 0; + int64 star_count = 0; string prize_description; int32 winners_selection_date = 0; bool only_new_subscribers = false; @@ -1055,13 +1069,14 @@ class MessageGiveawayWinners final : public MessageContent { MessageGiveawayWinners() = default; MessageGiveawayWinners(MessageId giveaway_message_id, ChannelId boosted_channel_id, int32 additional_dialog_count, - int32 month_count, string &&prize_description, int32 winners_selection_date, + int32 month_count, int64 star_count, string &&prize_description, int32 winners_selection_date, bool only_new_subscribers, bool was_refunded, int32 winner_count, int32 unclaimed_count, vector &&winner_user_ids) : giveaway_message_id(giveaway_message_id) , boosted_channel_id(boosted_channel_id) , additional_dialog_count(additional_dialog_count) , month_count(month_count) + , star_count(star_count) , prize_description(std::move(prize_description)) , winners_selection_date(winners_selection_date) , only_new_subscribers(only_new_subscribers) @@ -1127,10 +1142,11 @@ class MessagePaidMedia final : public MessageContent { vector media; FormattedText caption; int64 star_count = 0; + string payload; MessagePaidMedia() = default; - MessagePaidMedia(vector &&media, FormattedText &&caption, int64 star_count) - : media(std::move(media)), caption(std::move(caption)), star_count(star_count) { + MessagePaidMedia(vector &&media, FormattedText &&caption, int64 star_count, string payload) + : media(std::move(media)), caption(std::move(caption)), star_count(star_count), payload(std::move(payload)) { } MessageContentType get_type() const final { @@ -1188,6 +1204,29 @@ class MessageGiftStars final : public MessageContent { } }; +class MessagePrizeStars final : public MessageContent { + public: + int64 star_count = 0; + string transaction_id; + DialogId boosted_dialog_id; + MessageId giveaway_message_id; + bool is_unclaimed = false; + + MessagePrizeStars() = default; + MessagePrizeStars(int64 star_count, string &&transaction_id, DialogId boosted_dialog_id, + MessageId giveaway_message_id, bool is_unclaimed) + : star_count(star_count) + , transaction_id(std::move(transaction_id)) + , boosted_dialog_id(boosted_dialog_id) + , giveaway_message_id(giveaway_message_id) + , is_unclaimed(is_unclaimed) { + } + + MessageContentType get_type() const final { + return MessageContentType::PrizeStars; + } +}; + template static void store(const MessageContent *content, StorerT &storer) { CHECK(content != nullptr); @@ -1650,15 +1689,29 @@ static void store(const MessageContent *content, StorerT &storer) { } case MessageContentType::Giveaway: { const auto *m = static_cast(content); + bool has_star_count = m->star_count != 0; BEGIN_STORE_FLAGS(); + STORE_FLAG(has_star_count); END_STORE_FLAGS(); store(m->giveaway_parameters, storer); store(m->quantity, storer); store(m->months, storer); + if (has_star_count) { + store(m->star_count, storer); + } break; } - case MessageContentType::GiveawayLaunch: + case MessageContentType::GiveawayLaunch: { + const auto *m = static_cast(content); + bool has_star_count = m->star_count != 0; + BEGIN_STORE_FLAGS(); + STORE_FLAG(has_star_count); + END_STORE_FLAGS(); + if (has_star_count) { + store(m->star_count, storer); + } break; + } case MessageContentType::GiveawayResults: { const auto *m = static_cast(content); bool has_winner_count = m->winner_count != 0; @@ -1668,6 +1721,7 @@ static void store(const MessageContent *content, StorerT &storer) { STORE_FLAG(has_winner_count); STORE_FLAG(has_unclaimed_count); STORE_FLAG(has_giveaway_message_id); + STORE_FLAG(m->is_star_giveaway); END_STORE_FLAGS(); if (has_winner_count) { store(m->winner_count, storer); @@ -1691,6 +1745,7 @@ static void store(const MessageContent *content, StorerT &storer) { bool has_winner_count = m->winner_count != 0; bool has_unclaimed_count = m->unclaimed_count != 0; bool has_winner_user_ids = !m->winner_user_ids.empty(); + bool has_star_count = m->star_count != 0; BEGIN_STORE_FLAGS(); STORE_FLAG(m->only_new_subscribers); STORE_FLAG(m->was_refunded); @@ -1703,6 +1758,7 @@ static void store(const MessageContent *content, StorerT &storer) { STORE_FLAG(has_winner_count); STORE_FLAG(has_unclaimed_count); STORE_FLAG(has_winner_user_ids); + STORE_FLAG(has_star_count); END_STORE_FLAGS(); if (has_giveaway_message_id) { store(m->giveaway_message_id, storer); @@ -1731,6 +1787,9 @@ static void store(const MessageContent *content, StorerT &storer) { if (has_winner_user_ids) { store(m->winner_user_ids, storer); } + if (has_star_count) { + store(m->star_count, storer); + } break; } case MessageContentType::ExpiredVideoNote: @@ -1755,14 +1814,19 @@ static void store(const MessageContent *content, StorerT &storer) { case MessageContentType::PaidMedia: { const auto *m = static_cast(content); bool has_caption = !m->caption.text.empty(); + bool has_payload = !m->payload.empty(); BEGIN_STORE_FLAGS(); STORE_FLAG(has_caption); + STORE_FLAG(has_payload); END_STORE_FLAGS(); store(m->media, storer); if (has_caption) { store(m->caption, storer); } store(m->star_count, storer); + if (has_payload) { + store(m->payload, storer); + } break; } case MessageContentType::PaymentRefunded: { @@ -1801,6 +1865,17 @@ static void store(const MessageContent *content, StorerT &storer) { } break; } + case MessageContentType::PrizeStars: { + const auto *m = static_cast(content); + BEGIN_STORE_FLAGS(); + STORE_FLAG(m->is_unclaimed); + END_STORE_FLAGS(); + store(m->star_count, storer); + store(m->transaction_id, storer); + store(m->boosted_dialog_id, storer); + store(m->giveaway_message_id, storer); + break; + } default: UNREACHABLE(); } @@ -2424,20 +2499,36 @@ static void parse(unique_ptr &content, ParserT &parser) { } case MessageContentType::Giveaway: { auto m = make_unique(); + bool has_star_count; BEGIN_PARSE_FLAGS(); + PARSE_FLAG(has_star_count); END_PARSE_FLAGS(); parse(m->giveaway_parameters, parser); parse(m->quantity, parser); parse(m->months, parser); + if (has_star_count) { + parse(m->star_count, parser); + } if (!m->giveaway_parameters.is_valid()) { is_bad = true; } content = std::move(m); break; } - case MessageContentType::GiveawayLaunch: - content = make_unique(); + case MessageContentType::GiveawayLaunch: { + auto m = make_unique(); + bool has_star_count = false; + if (parser.version() >= static_cast(Version::SupportStarGiveaways)) { + BEGIN_PARSE_FLAGS(); + PARSE_FLAG(has_star_count); + END_PARSE_FLAGS(); + } + if (has_star_count) { + parse(m->star_count, parser); + } + content = std::move(m); break; + } case MessageContentType::GiveawayResults: { auto m = make_unique(); bool has_winner_count; @@ -2447,6 +2538,7 @@ static void parse(unique_ptr &content, ParserT &parser) { PARSE_FLAG(has_winner_count); PARSE_FLAG(has_unclaimed_count); PARSE_FLAG(has_giveaway_message_id); + PARSE_FLAG(m->is_star_giveaway); END_PARSE_FLAGS(); if (has_winner_count) { parse(m->winner_count, parser); @@ -2474,6 +2566,7 @@ static void parse(unique_ptr &content, ParserT &parser) { bool has_winner_count; bool has_unclaimed_count; bool has_winner_user_ids; + bool has_star_count; BEGIN_PARSE_FLAGS(); PARSE_FLAG(m->only_new_subscribers); PARSE_FLAG(m->was_refunded); @@ -2486,6 +2579,7 @@ static void parse(unique_ptr &content, ParserT &parser) { PARSE_FLAG(has_winner_count); PARSE_FLAG(has_unclaimed_count); PARSE_FLAG(has_winner_user_ids); + PARSE_FLAG(has_star_count); END_PARSE_FLAGS(); if (has_giveaway_message_id) { parse(m->giveaway_message_id, parser); @@ -2514,6 +2608,9 @@ static void parse(unique_ptr &content, ParserT &parser) { if (has_winner_user_ids) { parse(m->winner_user_ids, parser); } + if (has_star_count) { + parse(m->star_count, parser); + } if (m->winner_count < 0 || m->unclaimed_count < 0) { is_bad = true; } @@ -2553,14 +2650,19 @@ static void parse(unique_ptr &content, ParserT &parser) { case MessageContentType::PaidMedia: { auto m = make_unique(); bool has_caption; + bool has_payload; BEGIN_PARSE_FLAGS(); PARSE_FLAG(has_caption); + PARSE_FLAG(has_payload); END_PARSE_FLAGS(); parse(m->media, parser); if (has_caption) { parse(m->caption, parser); } parse(m->star_count, parser); + if (has_payload) { + parse(m->payload, parser); + } for (auto &media : m->media) { if (media.is_empty()) { @@ -2608,6 +2710,18 @@ static void parse(unique_ptr &content, ParserT &parser) { content = std::move(m); break; } + case MessageContentType::PrizeStars: { + auto m = make_unique(); + BEGIN_PARSE_FLAGS(); + PARSE_FLAG(m->is_unclaimed); + END_PARSE_FLAGS(); + parse(m->star_count, parser); + parse(m->transaction_id, parser); + parse(m->boosted_dialog_id, parser); + parse(m->giveaway_message_id, parser); + content = std::move(m); + break; + } default: is_bad = true; @@ -2961,7 +3075,7 @@ static Result create_input_message_content( } content = td::make_unique(std::move(extended_media), std::move(caption), - input_paid_media->star_count_); + input_paid_media->star_count_, std::move(input_paid_media->payload_)); break; } case td_api::inputMessagePhoto::ID: { @@ -3372,6 +3486,7 @@ bool can_message_content_have_input_media(const Td *td, const MessageContent *co case MessageContentType::DialogShared: case MessageContentType::PaymentRefunded: case MessageContentType::GiftStars: + case MessageContentType::PrizeStars: return false; case MessageContentType::Animation: case MessageContentType::Audio: @@ -3517,6 +3632,7 @@ SecretInputMedia get_message_content_secret_input_media( case MessageContentType::PaidMedia: case MessageContentType::PaymentRefunded: case MessageContentType::GiftStars: + case MessageContentType::PrizeStars: break; default: UNREACHABLE(); @@ -3595,7 +3711,12 @@ static telegram_api::object_ptr get_message_content_in } input_media.push_back(std::move(media)); } - return telegram_api::make_object(m->star_count, std::move(input_media)); + int32 flags = 0; + if (!m->payload.empty()) { + flags |= telegram_api::inputMediaPaidMedia::PAYLOAD_MASK; + } + return telegram_api::make_object(flags, m->star_count, std::move(input_media), + m->payload); } case MessageContentType::Photo: { const auto *m = static_cast(content); @@ -3685,6 +3806,7 @@ static telegram_api::object_ptr get_message_content_in case MessageContentType::DialogShared: case MessageContentType::PaymentRefunded: case MessageContentType::GiftStars: + case MessageContentType::PrizeStars: break; default: UNREACHABLE(); @@ -3938,6 +4060,7 @@ void delete_message_content_thumbnail(MessageContent *content, Td *td, int32 med case MessageContentType::DialogShared: case MessageContentType::PaymentRefunded: case MessageContentType::GiftStars: + case MessageContentType::PrizeStars: break; default: UNREACHABLE(); @@ -3969,6 +4092,9 @@ Status can_send_message_content(DialogId dialog_id, const MessageContent *conten }(); auto content_type = content->get_type(); + if (dialog_type == DialogType::SecretChat && !can_send_message_content_to_secret_chat(content_type)) { + return Status::Error(400, "Message can't be sent to a secret chat"); + } switch (content_type) { case MessageContentType::Animation: if (!permissions.can_send_animations()) { @@ -3989,9 +4115,6 @@ Status can_send_message_content(DialogId dialog_id, const MessageContent *conten if (!permissions.can_send_stickers()) { return Status::Error(400, "Not enough rights to send dice to the chat"); } - if (dialog_type == DialogType::SecretChat) { - return Status::Error(400, "Dice can't be sent to secret chats"); - } break; case MessageContentType::Document: if (!permissions.can_send_documents()) { @@ -4002,9 +4125,6 @@ Status can_send_message_content(DialogId dialog_id, const MessageContent *conten if (dialog_type == DialogType::Channel && td->chat_manager_->is_broadcast_channel(dialog_id.get_channel_id())) { // return Status::Error(400, "Games can't be sent to channel chats"); } - if (dialog_type == DialogType::SecretChat) { - return Status::Error(400, "Games can't be sent to secret chats"); - } if (!permissions.can_send_games()) { return Status::Error(400, "Not enough rights to send games to the chat"); } @@ -4013,25 +4133,16 @@ Status can_send_message_content(DialogId dialog_id, const MessageContent *conten if (!permissions.can_send_messages()) { return Status::Error(400, "Not enough rights to send giveaways to the chat"); } - if (dialog_type == DialogType::SecretChat) { - return Status::Error(400, "Giveaways can't be sent to secret chats"); - } break; case MessageContentType::GiveawayWinners: if (!permissions.can_send_messages()) { return Status::Error(400, "Not enough rights to send giveaway winners to the chat"); } - if (dialog_type == DialogType::SecretChat) { - return Status::Error(400, "Giveaway winners can't be sent to secret chats"); - } break; case MessageContentType::Invoice: if (!permissions.can_send_messages()) { return Status::Error(400, "Not enough rights to send invoice messages to the chat"); } - if (dialog_type == DialogType::SecretChat) { - return Status::Error(400, "Invoice messages can't be sent to secret chats"); - } break; case MessageContentType::LiveLocation: if (!permissions.can_send_messages()) { @@ -4048,9 +4159,6 @@ Status can_send_message_content(DialogId dialog_id, const MessageContent *conten if (!permissions.can_send_photos() || !permissions.can_send_videos()) { return Status::Error(400, "Not enough rights to send paid media to the chat"); } - if (dialog_type == DialogType::SecretChat) { - return Status::Error(400, "Paid media can't be sent to secret chats"); - } } else { if (!td->auth_manager_->is_bot() && (dialog_type != DialogType::Channel || !td->chat_manager_->is_broadcast_channel(dialog_id.get_channel_id()))) { @@ -4075,9 +4183,6 @@ Status can_send_message_content(DialogId dialog_id, const MessageContent *conten !td->user_manager_->is_user_bot(dialog_id.get_user_id())) { return Status::Error(400, "Polls can't be sent to the private chat"); } - if (dialog_type == DialogType::SecretChat) { - return Status::Error(400, "Polls can't be sent to secret chats"); - } break; case MessageContentType::Sticker: if (!permissions.can_send_stickers()) { @@ -4091,9 +4196,6 @@ Status can_send_message_content(DialogId dialog_id, const MessageContent *conten if (!permissions.can_send_photos() || !permissions.can_send_videos()) { return Status::Error(400, "Not enough rights to send stories to the chat"); } - if (dialog_type == DialogType::SecretChat) { - return Status::Error(400, "Story messages can't be sent to secret chats"); - } break; case MessageContentType::Text: if (!permissions.can_send_messages()) { @@ -4178,6 +4280,7 @@ Status can_send_message_content(DialogId dialog_id, const MessageContent *conten case MessageContentType::DialogShared: case MessageContentType::PaymentRefunded: case MessageContentType::GiftStars: + case MessageContentType::PrizeStars: UNREACHABLE(); } return Status::OK(); @@ -4329,6 +4432,7 @@ static int32 get_message_content_media_index_mask(const MessageContent *content, case MessageContentType::PaidMedia: case MessageContentType::PaymentRefunded: case MessageContentType::GiftStars: + case MessageContentType::PrizeStars: return 0; default: UNREACHABLE(); @@ -4627,6 +4731,8 @@ vector get_message_content_min_user_ids(const Td *td, const MessageConte break; case MessageContentType::GiftStars: break; + case MessageContentType::PrizeStars: + break; default: UNREACHABLE(); break; @@ -4870,7 +4976,7 @@ void merge_message_contents(Td *td, const MessageContent *old_content, MessageCo const auto *old_ = static_cast(old_content); const auto *new_ = static_cast(new_content); auto get_content_object = [td, dialog_id](const MessageContent *content) { - return to_string(get_message_content_object(content, td, dialog_id, false, -1, false, false, + return to_string(get_message_content_object(content, td, dialog_id, false, false, -1, false, false, std::numeric_limits::max(), false, false)); }; if (old_->text.text != new_->text.text) { @@ -4979,18 +5085,24 @@ void merge_message_contents(Td *td, const MessageContent *old_content, MessageCo } case MessageContentType::VideoNote: { const auto *old_ = static_cast(old_content); - const auto *new_ = static_cast(new_content); + auto *new_ = static_cast(new_content); if (old_->file_id != new_->file_id && need_merge_files) { td->video_notes_manager_->merge_video_notes(new_->file_id, old_->file_id); } + if (old_->is_viewed) { + new_->is_viewed = true; + } break; } case MessageContentType::VoiceNote: { const auto *old_ = static_cast(old_content); - const auto *new_ = static_cast(new_content); + auto *new_ = static_cast(new_content); if (old_->file_id != new_->file_id && need_merge_files) { td->voice_notes_manager_->merge_voice_notes(new_->file_id, old_->file_id); } + if (old_->is_listened) { + new_->is_listened = true; + } break; } case MessageContentType::Contact: @@ -5049,6 +5161,7 @@ void merge_message_contents(Td *td, const MessageContent *old_content, MessageCo case MessageContentType::DialogShared: case MessageContentType::PaymentRefunded: case MessageContentType::GiftStars: + case MessageContentType::PrizeStars: break; default: UNREACHABLE(); @@ -5203,6 +5316,7 @@ bool merge_message_content_file_id(Td *td, MessageContent *message_content, File case MessageContentType::DialogShared: case MessageContentType::PaymentRefunded: case MessageContentType::GiftStars: + case MessageContentType::PrizeStars: LOG(ERROR) << "Receive new file " << new_file_id << " in a sent message of the type " << content_type; break; default: @@ -5695,18 +5809,24 @@ void compare_message_contents(Td *td, const MessageContent *old_content, const M const auto *lhs = static_cast(old_content); const auto *rhs = static_cast(new_content); if (lhs->giveaway_parameters != rhs->giveaway_parameters || lhs->quantity != rhs->quantity || - lhs->months != rhs->months) { + lhs->months != rhs->months || lhs->star_count != rhs->star_count) { need_update = true; } break; } - case MessageContentType::GiveawayLaunch: + case MessageContentType::GiveawayLaunch: { + const auto *lhs = static_cast(old_content); + const auto *rhs = static_cast(new_content); + if (lhs->star_count != rhs->star_count) { + need_update = true; + } break; + } case MessageContentType::GiveawayResults: { const auto *lhs = static_cast(old_content); const auto *rhs = static_cast(new_content); if (lhs->giveaway_message_id != rhs->giveaway_message_id || lhs->winner_count != rhs->winner_count || - lhs->unclaimed_count != rhs->unclaimed_count) { + lhs->unclaimed_count != rhs->unclaimed_count || lhs->is_star_giveaway != rhs->is_star_giveaway) { need_update = true; } break; @@ -5716,7 +5836,7 @@ void compare_message_contents(Td *td, const MessageContent *old_content, const M const auto *rhs = static_cast(new_content); if (lhs->giveaway_message_id != rhs->giveaway_message_id || lhs->boosted_channel_id != rhs->boosted_channel_id || lhs->additional_dialog_count != rhs->additional_dialog_count || lhs->month_count != rhs->month_count || - lhs->prize_description != rhs->prize_description || + lhs->star_count != rhs->star_count || lhs->prize_description != rhs->prize_description || lhs->winners_selection_date != rhs->winners_selection_date || lhs->only_new_subscribers != rhs->only_new_subscribers || lhs->was_refunded != rhs->was_refunded || lhs->winner_count != rhs->winner_count || lhs->unclaimed_count != rhs->unclaimed_count || @@ -5759,6 +5879,9 @@ void compare_message_contents(Td *td, const MessageContent *old_content, const M is_content_changed = true; } } + if (lhs->payload != rhs->payload) { + is_content_changed = true; + } } break; } @@ -5783,6 +5906,16 @@ void compare_message_contents(Td *td, const MessageContent *old_content, const M } break; } + case MessageContentType::PrizeStars: { + const auto *lhs = static_cast(old_content); + const auto *rhs = static_cast(new_content); + if (lhs->star_count != rhs->star_count || lhs->transaction_id != rhs->transaction_id || + lhs->boosted_dialog_id != rhs->boosted_dialog_id || lhs->giveaway_message_id != rhs->giveaway_message_id || + lhs->is_unclaimed != rhs->is_unclaimed) { + need_update = true; + } + break; + } default: UNREACHABLE(); break; @@ -5843,14 +5976,16 @@ void register_message_content(Td *td, const MessageContent *content, MessageFull return td->stickers_manager_->register_dice(dice->emoji, dice->dice_value, message_full_id, {}, source); } case MessageContentType::GiftPremium: - return td->stickers_manager_->register_premium_gift(static_cast(content)->months, + return td->stickers_manager_->register_premium_gift(static_cast(content)->months, 0, message_full_id, source); case MessageContentType::GiftCode: - return td->stickers_manager_->register_premium_gift(static_cast(content)->months, - message_full_id, source); - case MessageContentType::Giveaway: - return td->stickers_manager_->register_premium_gift(static_cast(content)->months, + return td->stickers_manager_->register_premium_gift(static_cast(content)->months, 0, message_full_id, source); + case MessageContentType::Giveaway: { + auto giveaway = static_cast(content); + return td->stickers_manager_->register_premium_gift(giveaway->months, giveaway->star_count, message_full_id, + source); + } case MessageContentType::SuggestProfilePhoto: return td->user_manager_->register_suggested_profile_photo( static_cast(content)->photo); @@ -5859,8 +5994,11 @@ void register_message_content(Td *td, const MessageContent *content, MessageFull message_full_id, {}, source); case MessageContentType::GiftStars: { auto star_count = static_cast(content)->star_count; - return td->stickers_manager_->register_premium_gift(StarManager::get_months_by_star_count(star_count), - message_full_id, source); + return td->stickers_manager_->register_premium_gift(0, star_count, message_full_id, source); + } + case MessageContentType::PrizeStars: { + auto star_count = static_cast(content)->star_count; + return td->stickers_manager_->register_premium_gift(0, star_count, message_full_id, source); } default: return; @@ -5926,7 +6064,9 @@ void reregister_message_content(Td *td, const MessageContent *old_content, const break; case MessageContentType::Giveaway: if (static_cast(old_content)->months == - static_cast(new_content)->months) { + static_cast(new_content)->months && + static_cast(old_content)->star_count == + static_cast(new_content)->star_count) { return; } break; @@ -5942,6 +6082,12 @@ void reregister_message_content(Td *td, const MessageContent *old_content, const return; } break; + case MessageContentType::PrizeStars: + if (static_cast(old_content)->star_count == + static_cast(new_content)->star_count) { + return; + } + break; default: return; } @@ -5981,21 +6127,26 @@ void unregister_message_content(Td *td, const MessageContent *content, MessageFu return td->stickers_manager_->unregister_dice(dice->emoji, dice->dice_value, message_full_id, {}, source); } case MessageContentType::GiftPremium: - return td->stickers_manager_->unregister_premium_gift(static_cast(content)->months, + return td->stickers_manager_->unregister_premium_gift(static_cast(content)->months, 0, message_full_id, source); case MessageContentType::GiftCode: - return td->stickers_manager_->unregister_premium_gift(static_cast(content)->months, - message_full_id, source); - case MessageContentType::Giveaway: - return td->stickers_manager_->unregister_premium_gift(static_cast(content)->months, + return td->stickers_manager_->unregister_premium_gift(static_cast(content)->months, 0, message_full_id, source); + case MessageContentType::Giveaway: { + auto giveaway = static_cast(content); + return td->stickers_manager_->unregister_premium_gift(giveaway->months, giveaway->star_count, message_full_id, + source); + } case MessageContentType::Story: return td->story_manager_->unregister_story(static_cast(content)->story_full_id, message_full_id, {}, source); case MessageContentType::GiftStars: { auto star_count = static_cast(content)->star_count; - return td->stickers_manager_->unregister_premium_gift(StarManager::get_months_by_star_count(star_count), - message_full_id, source); + return td->stickers_manager_->unregister_premium_gift(0, star_count, message_full_id, source); + } + case MessageContentType::PrizeStars: { + auto star_count = static_cast(content)->star_count; + return td->stickers_manager_->unregister_premium_gift(0, star_count, message_full_id, source); } default: return; @@ -6682,7 +6833,8 @@ unique_ptr get_message_content(Td *td, FormattedText message, td->dialog_manager_->force_create_dialog(DialogId(channel_id), "messageMediaGiveaway", true); } } - if (channel_ids.empty() || media->quantity_ <= 0 || media->months_ <= 0 || media->until_date_ < 0) { + if (channel_ids.empty() || media->quantity_ <= 0 || (media->months_ <= 0 && media->stars_ <= 0) || + media->until_date_ < 0) { if (message_date >= 1700000000) { // approximate release date LOG(ERROR) << "Receive " << to_string(media); } @@ -6694,14 +6846,15 @@ unique_ptr get_message_content(Td *td, FormattedText message, GiveawayParameters{boosted_channel_id, std::move(channel_ids), media->only_new_subscribers_, media->winners_are_visible_, media->until_date_, std::move(media->countries_iso2_), std::move(media->prize_description_)}, - media->quantity_, media->months_); + media->quantity_, media->months_, StarManager::get_star_count(media->stars_)); } case telegram_api::messageMediaGiveawayResults::ID: { auto media = move_tl_object_as(media_ptr); auto giveaway_message_id = MessageId(ServerMessageId(media->launch_msg_id_)); auto boosted_channel_id = ChannelId(media->channel_id_); if (!giveaway_message_id.is_valid() || !boosted_channel_id.is_valid() || media->additional_peers_count_ < 0 || - media->months_ <= 0 || media->until_date_ <= 0 || media->winners_count_ < 0 || media->unclaimed_count_ < 0) { + (media->months_ <= 0 && media->stars_ <= 0) || media->until_date_ <= 0 || media->winners_count_ < 0 || + media->unclaimed_count_ < 0) { LOG(ERROR) << "Receive " << to_string(media); break; } @@ -6718,8 +6871,9 @@ unique_ptr get_message_content(Td *td, FormattedText message, } return td::make_unique( giveaway_message_id, boosted_channel_id, media->additional_peers_count_, media->months_, - std::move(media->prize_description_), media->until_date_, media->only_new_subscribers_, media->refunded_, - media->winners_count_, media->unclaimed_count_, std::move(winner_user_ids)); + StarManager::get_star_count(media->stars_), std::move(media->prize_description_), media->until_date_, + media->only_new_subscribers_, media->refunded_, media->winners_count_, media->unclaimed_count_, + std::move(winner_user_ids)); } case telegram_api::messageMediaPaidMedia::ID: { auto media = telegram_api::move_object_as(media_ptr); @@ -6727,7 +6881,7 @@ unique_ptr get_message_content(Td *td, FormattedText message, return MessageExtendedMedia(td, std::move(extended_media), owner_dialog_id); }); return td::make_unique(std::move(extended_media), std::move(message), - StarManager::get_star_count(media->stars_amount_)); + StarManager::get_star_count(media->stars_amount_), string()); } case telegram_api::messageMediaUnsupported::ID: return make_unique(); @@ -7002,6 +7156,7 @@ unique_ptr dup_message_content(Td *td, DialogId dialog_id, const case MessageContentType::DialogShared: case MessageContentType::PaymentRefunded: case MessageContentType::GiftStars: + case MessageContentType::PrizeStars: return nullptr; default: UNREACHABLE(); @@ -7064,6 +7219,7 @@ unique_ptr get_action_message_content(Td *td, tl_object_ptr get_action_message_content(Td *td, tl_object_ptr(reply_to_message_id, std::move(background_info), action->for_both_); } - case telegram_api::messageActionGiveawayLaunch::ID: - return make_unique(); + case telegram_api::messageActionGiveawayLaunch::ID: { + auto action = move_tl_object_as(action_ptr); + return td::make_unique(StarManager::get_star_count(action->stars_)); + } case telegram_api::messageActionGiftCode::ID: { auto action = move_tl_object_as(action_ptr); DialogId dialog_id; @@ -7451,7 +7609,7 @@ unique_ptr get_action_message_content(Td *td, tl_object_ptr(reply_to_message_id, action->winners_count_, - action->unclaimed_count_); + action->unclaimed_count_, action->stars_); } case telegram_api::messageActionBoostApply::ID: { auto action = move_tl_object_as(action_ptr); @@ -7495,22 +7653,34 @@ unique_ptr get_action_message_content(Td *td, tl_object_ptr(action_ptr); if (action->amount_ <= 0 || !check_currency_amount(action->amount_)) { - LOG(ERROR) << "Receive invalid gifted stars price " << action->amount_; + LOG(ERROR) << "Receive invalid gifted star price " << action->amount_; action->amount_ = 0; } if (action->crypto_currency_.empty()) { if (action->crypto_amount_ != 0) { - LOG(ERROR) << "Receive gifted stars crypto price " << action->crypto_amount_ << " without currency"; + LOG(ERROR) << "Receive gifted star crypto price " << action->crypto_amount_ << " without currency"; action->crypto_amount_ = 0; } } else if (action->crypto_amount_ <= 0) { - LOG(ERROR) << "Receive invalid gifted stars crypto amount " << action->crypto_amount_; + LOG(ERROR) << "Receive invalid gifted star crypto amount " << action->crypto_amount_; action->crypto_amount_ = 0; } return td::make_unique( std::move(action->currency_), action->amount_, std::move(action->crypto_currency_), action->crypto_amount_, StarManager::get_star_count(action->stars_), std::move(action->transaction_id_)); } + case telegram_api::messageActionPrizeStars::ID: { + auto action = move_tl_object_as(action_ptr); + DialogId boosted_dialog_id = DialogId(action->boost_peer_); + if (!boosted_dialog_id.is_valid()) { + LOG(ERROR) << "Receive invalid " << oneline(to_string(action)); + break; + } + td->dialog_manager_->force_create_dialog(boosted_dialog_id, "messageActionPrizeStars", true); + return td::make_unique( + StarManager::get_star_count(action->stars_), std::move(action->transaction_id_), boosted_dialog_id, + MessageId(ServerMessageId(action->giveaway_msg_id_)), action->unclaimed_); + } default: UNREACHABLE(); } @@ -7518,25 +7688,28 @@ unique_ptr get_action_message_content(Td *td, tl_object_ptr(FormattedText(), WebPageId(), false, false, false, string()); } -tl_object_ptr get_message_content_object(const MessageContent *content, Td *td, - DialogId dialog_id, bool is_outgoing, - int32 message_date, bool is_content_secret, - bool skip_bot_commands, int32 max_media_timestamp, - bool invert_media, bool disable_web_page_preview) { +td_api::object_ptr get_message_content_object(const MessageContent *content, Td *td, + DialogId dialog_id, bool is_server, + bool is_outgoing, int32 message_date, + bool is_content_secret, bool skip_bot_commands, + int32 max_media_timestamp, bool invert_media, + bool disable_web_page_preview) { CHECK(content != nullptr); + auto get_text_object = [&](const FormattedText &text) { + return get_formatted_text_object(is_server ? td->user_manager_.get() : nullptr, text, skip_bot_commands, + max_media_timestamp); + }; switch (content->get_type()) { case MessageContentType::Animation: { const auto *m = static_cast(content); - return make_tl_object( - td->animations_manager_->get_animation_object(m->file_id), - get_formatted_text_object(td->user_manager_.get(), m->caption, skip_bot_commands, max_media_timestamp), - invert_media, m->has_spoiler, is_content_secret); + return make_tl_object(td->animations_manager_->get_animation_object(m->file_id), + get_text_object(m->caption), invert_media, m->has_spoiler, + is_content_secret); } case MessageContentType::Audio: { const auto *m = static_cast(content); - return make_tl_object( - td->audios_manager_->get_audio_object(m->file_id), - get_formatted_text_object(td->user_manager_.get(), m->caption, skip_bot_commands, max_media_timestamp)); + return make_tl_object(td->audios_manager_->get_audio_object(m->file_id), + get_text_object(m->caption)); } case MessageContentType::Contact: { const auto *m = static_cast(content); @@ -7545,16 +7718,15 @@ tl_object_ptr get_message_content_object(const MessageCo case MessageContentType::Document: { const auto *m = static_cast(content); return make_tl_object( - td->documents_manager_->get_document_object(m->file_id, PhotoFormat::Jpeg), - get_formatted_text_object(td->user_manager_.get(), m->caption, skip_bot_commands, max_media_timestamp)); + td->documents_manager_->get_document_object(m->file_id, PhotoFormat::Jpeg), get_text_object(m->caption)); } case MessageContentType::Game: { const auto *m = static_cast(content); - return make_tl_object(m->game.get_game_object(td, skip_bot_commands)); + return make_tl_object(m->game.get_game_object(td, is_server, skip_bot_commands)); } case MessageContentType::Invoice: { const auto *m = static_cast(content); - return m->input_invoice.get_message_invoice_object(td, skip_bot_commands, max_media_timestamp); + return m->input_invoice.get_message_invoice_object(td, is_server, skip_bot_commands, max_media_timestamp); } case MessageContentType::LiveLocation: { const auto *m = static_cast(content); @@ -7576,10 +7748,8 @@ tl_object_ptr get_message_content_object(const MessageCo LOG(ERROR) << "Have empty " << m->photo; return make_tl_object(); } - auto caption = - get_formatted_text_object(td->user_manager_.get(), m->caption, skip_bot_commands, max_media_timestamp); - return make_tl_object(std::move(photo), std::move(caption), invert_media, m->has_spoiler, - is_content_secret); + return make_tl_object(std::move(photo), get_text_object(m->caption), invert_media, + m->has_spoiler, is_content_secret); } case MessageContentType::Sticker: { const auto *m = static_cast(content); @@ -7616,9 +7786,8 @@ tl_object_ptr get_message_content_object(const MessageCo link_preview_options = td_api::make_object( disable_web_page_preview, m->web_page_url, m->force_small_media, m->force_large_media, invert_media); } - return make_tl_object( - get_formatted_text_object(td->user_manager_.get(), m->text, skip_bot_commands, max_media_timestamp), - std::move(web_page), std::move(link_preview_options)); + return make_tl_object(get_text_object(m->text), std::move(web_page), + std::move(link_preview_options)); } case MessageContentType::Unsupported: return make_tl_object(); @@ -7628,10 +7797,9 @@ tl_object_ptr get_message_content_object(const MessageCo } case MessageContentType::Video: { const auto *m = static_cast(content); - return make_tl_object( - td->videos_manager_->get_video_object(m->file_id), - get_formatted_text_object(td->user_manager_.get(), m->caption, skip_bot_commands, max_media_timestamp), - invert_media, m->has_spoiler, is_content_secret); + return make_tl_object(td->videos_manager_->get_video_object(m->file_id), + get_text_object(m->caption), invert_media, m->has_spoiler, + is_content_secret); } case MessageContentType::VideoNote: { const auto *m = static_cast(content); @@ -7640,10 +7808,8 @@ tl_object_ptr get_message_content_object(const MessageCo } case MessageContentType::VoiceNote: { const auto *m = static_cast(content); - return make_tl_object( - td->voice_notes_manager_->get_voice_note_object(m->file_id), - get_formatted_text_object(td->user_manager_.get(), m->caption, skip_bot_commands, max_media_timestamp), - m->is_listened); + return make_tl_object(td->voice_notes_manager_->get_voice_note_object(m->file_id), + get_text_object(m->caption), m->is_listened); } case MessageContentType::ChatCreate: { const auto *m = static_cast(content); @@ -7828,7 +7994,7 @@ tl_object_ptr get_message_content_object(const MessageCo } return td_api::make_object( gifter_user_id, receiver_user_id, m->currency, m->amount, m->crypto_currency, m->crypto_amount, m->months, - td->stickers_manager_->get_premium_gift_sticker_object(m->months)); + td->stickers_manager_->get_premium_gift_sticker_object(m->months, 0)); } case MessageContentType::TopicCreate: { const auto *m = static_cast(content); @@ -7890,29 +8056,42 @@ tl_object_ptr get_message_content_object(const MessageCo ? get_message_sender_object(td, m->creator_dialog_id, "messagePremiumGiftCode") : nullptr, m->via_giveaway, m->is_unclaimed, m->currency, m->amount, m->crypto_currency, m->crypto_amount, m->months, - td->stickers_manager_->get_premium_gift_sticker_object(m->months), m->code); + td->stickers_manager_->get_premium_gift_sticker_object(m->months, 0), m->code); } case MessageContentType::Giveaway: { const auto *m = static_cast(content); - return td_api::make_object( - m->giveaway_parameters.get_premium_giveaway_parameters_object(td), m->quantity, m->months, - td->stickers_manager_->get_premium_gift_sticker_object(m->months)); + td_api::object_ptr prize; + if (m->months != 0) { + prize = td_api::make_object(m->months); + } else { + prize = td_api::make_object(m->star_count); + } + return td_api::make_object( + m->giveaway_parameters.get_giveaway_parameters_object(td), m->quantity, std::move(prize), + td->stickers_manager_->get_premium_gift_sticker_object(m->months, m->star_count)); + } + case MessageContentType::GiveawayLaunch: { + const auto *m = static_cast(content); + return td_api::make_object(m->star_count); } - case MessageContentType::GiveawayLaunch: - return td_api::make_object(); case MessageContentType::GiveawayResults: { const auto *m = static_cast(content); - return td_api::make_object(m->giveaway_message_id.get(), m->winner_count, - m->unclaimed_count); + return td_api::make_object(m->giveaway_message_id.get(), m->winner_count, + m->is_star_giveaway, m->unclaimed_count); } case MessageContentType::GiveawayWinners: { const auto *m = static_cast(content); - return td_api::make_object( - td->dialog_manager_->get_chat_id_object(DialogId(m->boosted_channel_id), "messagePremiumGiveawayWinners"), + td_api::object_ptr prize; + if (m->month_count != 0) { + prize = td_api::make_object(m->month_count); + } else { + prize = td_api::make_object(m->star_count); + } + return td_api::make_object( + td->dialog_manager_->get_chat_id_object(DialogId(m->boosted_channel_id), "messageGiveawayWinners"), m->giveaway_message_id.get(), m->additional_dialog_count, m->winners_selection_date, m->only_new_subscribers, - m->was_refunded, m->month_count, m->prize_description, m->winner_count, - td->user_manager_->get_user_ids_object(m->winner_user_ids, "messagePremiumGiveawayWinners"), - m->unclaimed_count); + m->was_refunded, std::move(prize), m->prize_description, m->winner_count, + td->user_manager_->get_user_ids_object(m->winner_user_ids, "messageGiveawayWinners"), m->unclaimed_count); } case MessageContentType::ExpiredVideoNote: return make_tl_object(); @@ -7939,10 +8118,8 @@ tl_object_ptr get_message_content_object(const MessageCo case MessageContentType::PaidMedia: { const auto *m = static_cast(content); return td_api::make_object( - m->star_count, - transform(m->media, [&](const auto &media) { return media.get_message_extended_media_object(td); }), - get_formatted_text_object(td->user_manager_.get(), m->caption, skip_bot_commands, max_media_timestamp), - invert_media); + m->star_count, transform(m->media, [&](const auto &media) { return media.get_paid_media_object(td); }), + get_text_object(m->caption), invert_media); } case MessageContentType::PaymentRefunded: { const auto *m = static_cast(content); @@ -7969,8 +8146,15 @@ tl_object_ptr get_message_content_object(const MessageCo } return td_api::make_object( gifter_user_id, receiver_user_id, m->currency, m->amount, m->crypto_currency, m->crypto_amount, m->star_count, - m->transaction_id, - td->stickers_manager_->get_premium_gift_sticker_object(StarManager::get_months_by_star_count(m->star_count))); + m->transaction_id, td->stickers_manager_->get_premium_gift_sticker_object(0, m->star_count)); + } + case MessageContentType::PrizeStars: { + const auto *m = static_cast(content); + return td_api::make_object( + m->star_count, m->transaction_id, + td->dialog_manager_->get_chat_id_object(m->boosted_dialog_id, "messageGiveawayPrizeStars"), + m->giveaway_message_id.get(), m->is_unclaimed, + td->stickers_manager_->get_premium_gift_sticker_object(0, m->star_count)); } default: UNREACHABLE(); @@ -8079,6 +8263,11 @@ int64 get_message_content_star_count(const MessageContent *content) { return static_cast(content)->star_count; } +string get_message_content_payload(const MessageContent *content) { + CHECK(content->get_type() == MessageContentType::PaidMedia); + return static_cast(content)->payload; +} + int32 get_message_content_duration(const MessageContent *content, const Td *td) { CHECK(content != nullptr); switch (content->get_type()) { @@ -8531,6 +8720,7 @@ string get_message_content_search_text(const Td *td, const MessageContent *conte case MessageContentType::DialogShared: case MessageContentType::PaymentRefunded: case MessageContentType::GiftStars: + case MessageContentType::PrizeStars: return string(); default: UNREACHABLE(); @@ -8933,6 +9123,11 @@ void add_message_content_dependencies(Dependencies &dependencies, const MessageC } case MessageContentType::GiftStars: break; + case MessageContentType::PrizeStars: { + const auto *content = static_cast(message_content); + dependencies.add_dialog_and_dependencies(DialogId(content->boosted_dialog_id)); + break; + } default: UNREACHABLE(); break; diff --git a/lib/tgchat/ext/td/td/telegram/MessageContent.h b/lib/tgchat/ext/td/td/telegram/MessageContent.h index edf734d8..4d9a861e 100644 --- a/lib/tgchat/ext/td/td/telegram/MessageContent.h +++ b/lib/tgchat/ext/td/td/telegram/MessageContent.h @@ -268,10 +268,11 @@ unique_ptr get_action_message_content(Td *td, tl_object_ptr get_message_content_object(const MessageContent *content, Td *td, - DialogId dialog_id, bool is_outgoing, - int32 message_date, bool is_content_secret, - bool skip_bot_commands, int32 max_media_timestamp, - bool invert_media, bool disable_web_page_preview); + DialogId dialog_id, bool is_server, + bool is_outgoing, int32 message_date, + bool is_content_secret, bool skip_bot_commands, + int32 max_media_timestamp, bool invert_media, + bool disable_web_page_preview); FormattedText *get_message_content_text_mutable(MessageContent *content); @@ -281,6 +282,8 @@ const FormattedText *get_message_content_caption(const MessageContent *content); int64 get_message_content_star_count(const MessageContent *content); +string get_message_content_payload(const MessageContent *content); + int32 get_message_content_duration(const MessageContent *content, const Td *td); int32 get_message_content_media_duration(const MessageContent *content, const Td *td); diff --git a/lib/tgchat/ext/td/td/telegram/MessageContentType.cpp b/lib/tgchat/ext/td/td/telegram/MessageContentType.cpp index 554b4d86..e8c4c287 100644 --- a/lib/tgchat/ext/td/td/telegram/MessageContentType.cpp +++ b/lib/tgchat/ext/td/td/telegram/MessageContentType.cpp @@ -152,6 +152,8 @@ StringBuilder &operator<<(StringBuilder &string_builder, MessageContentType cont return string_builder << "PaymentRefunded"; case MessageContentType::GiftStars: return string_builder << "GiftStars"; + case MessageContentType::PrizeStars: + return string_builder << "PrizeStars"; default: return string_builder << "Invalid type " << static_cast(content_type); } @@ -242,6 +244,7 @@ bool is_allowed_media_group_content(MessageContentType content_type) { case MessageContentType::PaidMedia: case MessageContentType::PaymentRefunded: case MessageContentType::GiftStars: + case MessageContentType::PrizeStars: return false; default: UNREACHABLE(); @@ -326,6 +329,7 @@ bool can_be_secret_message_content(MessageContentType content_type) { case MessageContentType::PaidMedia: case MessageContentType::PaymentRefunded: case MessageContentType::GiftStars: + case MessageContentType::PrizeStars: return false; default: UNREACHABLE(); @@ -406,6 +410,7 @@ bool can_be_local_message_content(MessageContentType content_type) { case MessageContentType::PaidMedia: case MessageContentType::PaymentRefunded: case MessageContentType::GiftStars: + case MessageContentType::PrizeStars: return false; default: UNREACHABLE(); @@ -486,6 +491,7 @@ bool is_service_message_content(MessageContentType content_type) { case MessageContentType::DialogShared: case MessageContentType::PaymentRefunded: case MessageContentType::GiftStars: + case MessageContentType::PrizeStars: return true; default: UNREACHABLE(); @@ -566,6 +572,7 @@ bool is_editable_message_content(MessageContentType content_type) { case MessageContentType::DialogShared: case MessageContentType::PaymentRefunded: case MessageContentType::GiftStars: + case MessageContentType::PrizeStars: return false; default: UNREACHABLE(); @@ -710,6 +717,7 @@ bool can_have_message_content_caption(MessageContentType content_type) { case MessageContentType::DialogShared: case MessageContentType::PaymentRefunded: case MessageContentType::GiftStars: + case MessageContentType::PrizeStars: return false; default: UNREACHABLE(); @@ -717,6 +725,88 @@ bool can_have_message_content_caption(MessageContentType content_type) { } } +bool can_send_message_content_to_secret_chat(MessageContentType content_type) { + switch (content_type) { + case MessageContentType::Animation: + case MessageContentType::Audio: + case MessageContentType::Contact: + case MessageContentType::Document: + case MessageContentType::LiveLocation: + case MessageContentType::Location: + case MessageContentType::Photo: + case MessageContentType::Sticker: + case MessageContentType::Text: + case MessageContentType::Venue: + case MessageContentType::Video: + case MessageContentType::VideoNote: + case MessageContentType::VoiceNote: + return true; + case MessageContentType::Dice: + case MessageContentType::Game: + case MessageContentType::Giveaway: + case MessageContentType::GiveawayWinners: + case MessageContentType::Invoice: + case MessageContentType::PaidMedia: + case MessageContentType::Poll: + case MessageContentType::Story: + return false; + case MessageContentType::None: + case MessageContentType::ChatCreate: + case MessageContentType::ChatChangeTitle: + case MessageContentType::ChatChangePhoto: + case MessageContentType::ChatDeletePhoto: + case MessageContentType::ChatDeleteHistory: + case MessageContentType::ChatAddUsers: + case MessageContentType::ChatJoinedByLink: + case MessageContentType::ChatDeleteUser: + case MessageContentType::ChatMigrateTo: + case MessageContentType::ChannelCreate: + case MessageContentType::ChannelMigrateFrom: + case MessageContentType::PinMessage: + case MessageContentType::GameScore: + case MessageContentType::ScreenshotTaken: + case MessageContentType::ChatSetTtl: + case MessageContentType::Unsupported: + case MessageContentType::Call: + case MessageContentType::PaymentSuccessful: + case MessageContentType::ContactRegistered: + case MessageContentType::ExpiredPhoto: + case MessageContentType::ExpiredVideo: + case MessageContentType::CustomServiceAction: + case MessageContentType::WebsiteConnected: + case MessageContentType::PassportDataSent: + case MessageContentType::PassportDataReceived: + case MessageContentType::ProximityAlertTriggered: + case MessageContentType::GroupCall: + case MessageContentType::InviteToGroupCall: + case MessageContentType::ChatSetTheme: + case MessageContentType::WebViewDataSent: + case MessageContentType::WebViewDataReceived: + case MessageContentType::GiftPremium: + case MessageContentType::TopicCreate: + case MessageContentType::TopicEdit: + case MessageContentType::SuggestProfilePhoto: + case MessageContentType::WriteAccessAllowed: + case MessageContentType::RequestedDialog: + case MessageContentType::WebViewWriteAccessAllowed: + case MessageContentType::SetBackground: + case MessageContentType::WriteAccessAllowedByRequest: + case MessageContentType::GiftCode: + case MessageContentType::GiveawayLaunch: + case MessageContentType::GiveawayResults: + case MessageContentType::ExpiredVideoNote: + case MessageContentType::ExpiredVoiceNote: + case MessageContentType::BoostApply: + case MessageContentType::DialogShared: + case MessageContentType::PaymentRefunded: + case MessageContentType::GiftStars: + case MessageContentType::PrizeStars: + default: + UNREACHABLE(); + return false; + } +} + uint64 get_message_content_chain_id(MessageContentType content_type) { switch (content_type) { case MessageContentType::Animation: diff --git a/lib/tgchat/ext/td/td/telegram/MessageContentType.h b/lib/tgchat/ext/td/td/telegram/MessageContentType.h index f2465f1d..ef5d3603 100644 --- a/lib/tgchat/ext/td/td/telegram/MessageContentType.h +++ b/lib/tgchat/ext/td/td/telegram/MessageContentType.h @@ -83,7 +83,8 @@ enum class MessageContentType : int32 { DialogShared, PaidMedia, PaymentRefunded, - GiftStars + GiftStars, + PrizeStars }; // increase MessageUnsupported::CURRENT_VERSION each time a new message content type is added @@ -111,6 +112,8 @@ MessageContentType get_expired_message_content_type(MessageContentType content_t bool can_have_message_content_caption(MessageContentType content_type); +bool can_send_message_content_to_secret_chat(MessageContentType content_type); + uint64 get_message_content_chain_id(MessageContentType content_type); struct MessageContentTypeHash { diff --git a/lib/tgchat/ext/td/td/telegram/MessageEntity.cpp b/lib/tgchat/ext/td/td/telegram/MessageEntity.cpp index 7bfcffd8..1cb9e0d7 100644 --- a/lib/tgchat/ext/td/td/telegram/MessageEntity.cpp +++ b/lib/tgchat/ext/td/td/telegram/MessageEntity.cpp @@ -649,8 +649,8 @@ static vector match_tg_urls(Slice str) { } else if (ptr - begin >= 3 && to_lower(ptr[-3]) == 't' && to_lower(ptr[-2]) == 'o' && to_lower(ptr[-1]) == 'n') { url_begin = ptr - 3; } else if (ptr - begin >= 7 && to_lower(ptr[-7]) == 't' && to_lower(ptr[-6]) == 'o' && to_lower(ptr[-5]) == 'n' && - to_lower(ptr[-5]) == 's' && to_lower(ptr[-5]) == 'i' && to_lower(ptr[-5]) == 't' && - to_lower(ptr[-5]) == 'e') { + to_lower(ptr[-4]) == 's' && to_lower(ptr[-3]) == 'i' && to_lower(ptr[-2]) == 't' && + to_lower(ptr[-1]) == 'e') { url_begin = ptr - 3; } } diff --git a/lib/tgchat/ext/td/td/telegram/MessageExtendedMedia.cpp b/lib/tgchat/ext/td/td/telegram/MessageExtendedMedia.cpp index eb740d57..649342bf 100644 --- a/lib/tgchat/ext/td/td/telegram/MessageExtendedMedia.cpp +++ b/lib/tgchat/ext/td/td/telegram/MessageExtendedMedia.cpp @@ -199,7 +199,7 @@ bool MessageExtendedMedia::update_to(Td *td, return false; } -td_api::object_ptr MessageExtendedMedia::get_message_extended_media_object(Td *td) const { +td_api::object_ptr MessageExtendedMedia::get_paid_media_object(Td *td) const { if (type_ == Type::Empty) { return nullptr; } diff --git a/lib/tgchat/ext/td/td/telegram/MessageExtendedMedia.h b/lib/tgchat/ext/td/td/telegram/MessageExtendedMedia.h index 613cb1be..eced72fd 100644 --- a/lib/tgchat/ext/td/td/telegram/MessageExtendedMedia.h +++ b/lib/tgchat/ext/td/td/telegram/MessageExtendedMedia.h @@ -74,7 +74,7 @@ class MessageExtendedMedia { bool update_to(Td *td, telegram_api::object_ptr extended_media_ptr, DialogId owner_dialog_id); - td_api::object_ptr get_message_extended_media_object(Td *td) const; + td_api::object_ptr get_paid_media_object(Td *td) const; void append_file_ids(const Td *td, vector &file_ids) const; diff --git a/lib/tgchat/ext/td/td/telegram/MessageImportManager.cpp b/lib/tgchat/ext/td/td/telegram/MessageImportManager.cpp index 56f41779..c8f18f12 100644 --- a/lib/tgchat/ext/td/td/telegram/MessageImportManager.cpp +++ b/lib/tgchat/ext/td/td/telegram/MessageImportManager.cpp @@ -385,8 +385,9 @@ void MessageImportManager::on_upload_imported_messages(FileId file_id, FileView file_view = td_->file_manager_->get_file_view(file_id); CHECK(!file_view.is_encrypted()); - if (input_file == nullptr && file_view.has_remote_location()) { - if (file_view.main_remote_location().is_web()) { + const auto *main_remote_location = file_view.get_main_remote_location(); + if (input_file == nullptr && main_remote_location != nullptr) { + if (main_remote_location->is_web()) { return promise.set_error(Status::Error(400, "Can't use web file")); } if (is_reupload) { @@ -395,7 +396,7 @@ void MessageImportManager::on_upload_imported_messages(FileId file_id, CHECK(file_view.get_type() == FileType::Document); // delete file reference and forcely reupload the file - auto file_reference = FileManager::extract_file_reference(file_view.main_remote_location().as_input_document()); + auto file_reference = FileManager::extract_file_reference(main_remote_location->as_input_document()); td_->file_manager_->delete_file_reference(file_id, file_reference); upload_imported_messages(dialog_id, file_id, std::move(attached_file_ids), true, std::move(promise), {-1}); return; @@ -496,8 +497,9 @@ void MessageImportManager::on_upload_imported_message_attachment(FileId file_id, FileView file_view = td_->file_manager_->get_file_view(file_id); CHECK(!file_view.is_encrypted()); - if (input_file == nullptr && file_view.has_remote_location()) { - if (file_view.main_remote_location().is_web()) { + const auto *main_remote_location = file_view.get_main_remote_location(); + if (input_file == nullptr && main_remote_location != nullptr) { + if (main_remote_location->is_web()) { return promise.set_error(Status::Error(400, "Can't use web file")); } if (is_reupload) { @@ -505,10 +507,9 @@ void MessageImportManager::on_upload_imported_message_attachment(FileId file_id, } // delete file reference and forcely reupload the file - auto file_reference = - file_view.get_type() == FileType::Photo - ? FileManager::extract_file_reference(file_view.main_remote_location().as_input_photo()) - : FileManager::extract_file_reference(file_view.main_remote_location().as_input_document()); + auto file_reference = file_view.get_type() == FileType::Photo + ? FileManager::extract_file_reference(main_remote_location->as_input_photo()) + : FileManager::extract_file_reference(main_remote_location->as_input_document()); td_->file_manager_->delete_file_reference(file_id, file_reference); upload_imported_message_attachment(dialog_id, import_id, file_id, true, std::move(promise), {-1}); return; diff --git a/lib/tgchat/ext/td/td/telegram/MessageReaction.cpp b/lib/tgchat/ext/td/td/telegram/MessageReaction.cpp index f5c10fe1..6f834e0c 100644 --- a/lib/tgchat/ext/td/td/telegram/MessageReaction.cpp +++ b/lib/tgchat/ext/td/td/telegram/MessageReaction.cpp @@ -13,6 +13,7 @@ #include "td/telegram/Global.h" #include "td/telegram/MessageSender.h" #include "td/telegram/MessagesManager.h" +#include "td/telegram/OptionManager.h" #include "td/telegram/ServerMessageId.h" #include "td/telegram/StarManager.h" #include "td/telegram/Td.h" @@ -157,13 +158,16 @@ class SendReactionQuery final : public Td::ResultHandler { class SendPaidReactionQuery final : public Td::ResultHandler { Promise promise_; DialogId dialog_id_; + int64 star_count_; public: explicit SendPaidReactionQuery(Promise &&promise) : promise_(std::move(promise)) { } - void send(MessageFullId message_full_id, int32 star_count, bool is_anonymous, int64 random_id) { + void send(MessageFullId message_full_id, int32 star_count, bool use_default_is_anonymous, bool is_anonymous, + int64 random_id) { dialog_id_ = message_full_id.get_dialog_id(); + star_count_ = star_count; auto input_peer = td_->dialog_manager_->get_input_peer(dialog_id_, AccessRights::Read); if (input_peer == nullptr) { @@ -171,13 +175,13 @@ class SendPaidReactionQuery final : public Td::ResultHandler { } int32 flags = 0; - if (is_anonymous) { + if (!use_default_is_anonymous) { flags |= telegram_api::messages_sendPaidReaction::PRIVATE_MASK; } send_query(G()->net_query_creator().create( - telegram_api::messages_sendPaidReaction(flags, false /*ignored*/, std::move(input_peer), + telegram_api::messages_sendPaidReaction(flags, std::move(input_peer), message_full_id.get_message_id().get_server_message_id().get(), - star_count, random_id), + star_count, random_id, is_anonymous), {{dialog_id_}, {message_full_id}})); } @@ -189,13 +193,16 @@ class SendPaidReactionQuery final : public Td::ResultHandler { auto ptr = result_ptr.move_as_ok(); LOG(INFO) << "Receive result for SendPaidReactionQuery: " << to_string(ptr); + td_->star_manager_->add_pending_owned_star_count(star_count_, true); td_->updates_manager_->on_get_updates(std::move(ptr), std::move(promise_)); } void on_error(Status status) final { if (status.message() == "MESSAGE_NOT_MODIFIED") { + td_->star_manager_->add_pending_owned_star_count(star_count_, true); return promise_.set_value(Unit()); } + td_->star_manager_->add_pending_owned_star_count(star_count_, false); td_->dialog_manager_->on_get_dialog_error(dialog_id_, status, "SendPaidReactionQuery"); promise_.set_error(std::move(status)); } @@ -238,6 +245,30 @@ class TogglePaidReactionPrivacyQuery final : public Td::ResultHandler { } }; +class GetPaidReactionPrivacyQuery final : public Td::ResultHandler { + public: + void send() { + send_query(G()->net_query_creator().create(telegram_api::messages_getPaidReactionPrivacy())); + } + + void on_result(BufferSlice packet) final { + auto result_ptr = fetch_result(packet); + if (result_ptr.is_error()) { + return on_error(result_ptr.move_as_error()); + } + + auto ptr = result_ptr.move_as_ok(); + LOG(INFO) << "Receive result for GetPaidReactionPrivacyQuery: " << to_string(ptr); + td_->updates_manager_->on_get_updates(std::move(ptr), Promise()); + } + + void on_error(Status status) final { + if (!G()->is_expected_error(status)) { + LOG(ERROR) << "Receive " << status; + } + } +}; + class GetMessageReactionsListQuery final : public Td::ResultHandler { Promise> promise_; DialogId dialog_id_; @@ -747,6 +778,7 @@ void MessageReactions::update_from(const MessageReactions &old_reactions, Dialog } } pending_paid_reactions_ = old_reactions.pending_paid_reactions_; + pending_use_default_is_anonymous_ = old_reactions.pending_use_default_is_anonymous_; pending_is_anonymous_ = old_reactions.pending_is_anonymous_; } @@ -843,24 +875,48 @@ bool MessageReactions::do_remove_my_reaction(const ReactionType &reaction_type) return false; } -void MessageReactions::add_my_paid_reaction(Td *td, int32 star_count, bool is_anonymous) { +void MessageReactions::add_my_paid_reaction(Td *td, int32 star_count, bool use_default_is_anonymous, + bool is_anonymous) { if (pending_paid_reactions_ > 1000000000 || star_count > 1000000000) { LOG(ERROR) << "Pending paid reactions overflown"; return; } - td->star_manager_->add_owned_star_count(-star_count); + td->star_manager_->add_pending_owned_star_count(-star_count, false); + if (use_default_is_anonymous) { + if (pending_paid_reactions_ == 0) { + pending_use_default_is_anonymous_ = true; + } + if (pending_use_default_is_anonymous_) { + bool was_me = false; + for (auto &reactor : top_reactors_) { + if (reactor.is_me()) { + was_me = true; + pending_is_anonymous_ = reactor.is_anonymous(); + } + } + if (!was_me) { + pending_is_anonymous_ = td->option_manager_->get_option_boolean("is_paid_reaction_anonymous"); + } + } + } else { + td->option_manager_->set_option_boolean("is_paid_reaction_anonymous", is_anonymous); + + pending_use_default_is_anonymous_ = false; + pending_is_anonymous_ = is_anonymous; + } pending_paid_reactions_ += star_count; - pending_is_anonymous_ = is_anonymous; } -bool MessageReactions::drop_pending_paid_reactions(Td *td) { - if (pending_paid_reactions_ == 0) { - return false; - } - td->star_manager_->add_owned_star_count(pending_paid_reactions_); +bool MessageReactions::has_pending_paid_reactions() const { + return pending_paid_reactions_ != 0; +} + +void MessageReactions::drop_pending_paid_reactions(Td *td) { + CHECK(has_pending_paid_reactions()); + td->star_manager_->add_pending_owned_star_count(pending_paid_reactions_, false); pending_paid_reactions_ = 0; + pending_use_default_is_anonymous_ = false; pending_is_anonymous_ = false; - return true; } void MessageReactions::sort_reactions(const FlatHashMap &active_reaction_pos) { @@ -1068,10 +1124,9 @@ bool MessageReactions::need_update_unread_reactions(const MessageReactions *old_ void MessageReactions::send_paid_message_reaction(Td *td, MessageFullId message_full_id, int64 random_id, Promise &&promise) { - if (pending_paid_reactions_ == 0) { - return promise.set_value(Unit()); - } + CHECK(has_pending_paid_reactions()); auto star_count = pending_paid_reactions_; + auto use_defualt_is_anonymous = pending_use_default_is_anonymous_; auto is_anonymous = pending_is_anonymous_; top_reactors_ = apply_reactor_pending_paid_reactions(td->dialog_manager_->get_my_dialog_id()); if (reactions_.empty() || !reactions_[0].reaction_type_.is_paid_reaction()) { @@ -1081,15 +1136,17 @@ void MessageReactions::send_paid_message_reaction(Td *td, MessageFullId message_ reactions_[0].add_paid_reaction(star_count); } pending_paid_reactions_ = 0; + pending_use_default_is_anonymous_ = false; pending_is_anonymous_ = false; td->create_handler(std::move(promise)) - ->send(message_full_id, star_count, is_anonymous, random_id); + ->send(message_full_id, star_count, use_defualt_is_anonymous, is_anonymous, random_id); } bool MessageReactions::toggle_paid_message_reaction_is_anonymous(Td *td, MessageFullId message_full_id, bool is_anonymous, Promise &&promise) { if (pending_paid_reactions_ != 0) { + pending_use_default_is_anonymous_ = false; pending_is_anonymous_ = is_anonymous; } for (auto &top_reactor : top_reactors_) { @@ -1165,6 +1222,10 @@ void set_message_reactions(Td *td, MessageFullId message_full_id, vectorcreate_handler()->send(); +} + void get_message_added_reactions(Td *td, MessageFullId message_full_id, ReactionType reaction_type, string offset, int32 limit, Promise> &&promise) { if (!td->messages_manager_->have_message_force(message_full_id, "get_message_added_reactions")) { diff --git a/lib/tgchat/ext/td/td/telegram/MessageReaction.h b/lib/tgchat/ext/td/td/telegram/MessageReaction.h index 22ec2812..854ecc18 100644 --- a/lib/tgchat/ext/td/td/telegram/MessageReaction.h +++ b/lib/tgchat/ext/td/td/telegram/MessageReaction.h @@ -158,6 +158,7 @@ struct MessageReactions { vector chosen_reaction_order_; vector top_reactors_; int32 pending_paid_reactions_ = 0; + bool pending_use_default_is_anonymous_ = false; bool pending_is_anonymous_ = false; bool is_min_ = false; bool need_polling_ = true; @@ -182,9 +183,11 @@ struct MessageReactions { bool remove_my_reaction(const ReactionType &reaction_type, DialogId my_dialog_id); - void add_my_paid_reaction(Td *td, int32 star_count, bool is_anonymous); + void add_my_paid_reaction(Td *td, int32 star_count, bool use_default_is_anonymous, bool is_anonymous); - bool drop_pending_paid_reactions(Td *td); + bool has_pending_paid_reactions() const; + + void drop_pending_paid_reactions(Td *td); void sort_reactions(const FlatHashMap &active_reaction_pos); @@ -242,6 +245,8 @@ void send_message_reaction(Td *td, MessageFullId message_full_id, vector reaction_types, bool is_big, Promise &&promise); +void reload_paid_reaction_privacy(Td *td); + void get_message_added_reactions(Td *td, MessageFullId message_full_id, ReactionType reaction_type, string offset, int32 limit, Promise> &&promise); diff --git a/lib/tgchat/ext/td/td/telegram/MessageReactor.h b/lib/tgchat/ext/td/td/telegram/MessageReactor.h index f0b889b7..a92865f3 100644 --- a/lib/tgchat/ext/td/td/telegram/MessageReactor.h +++ b/lib/tgchat/ext/td/td/telegram/MessageReactor.h @@ -49,6 +49,10 @@ class MessageReactor { return is_me_; } + bool is_anonymous() const { + return is_anonymous_; + } + bool fix_is_me(DialogId my_dialog_id); void add_count(int32 count, bool is_anonymous) { diff --git a/lib/tgchat/ext/td/td/telegram/MessagesManager.cpp b/lib/tgchat/ext/td/td/telegram/MessagesManager.cpp index dc328a1c..698aed91 100644 --- a/lib/tgchat/ext/td/td/telegram/MessagesManager.cpp +++ b/lib/tgchat/ext/td/td/telegram/MessagesManager.cpp @@ -82,6 +82,7 @@ #include "td/telegram/SavedMessagesManager.h" #include "td/telegram/SecretChatsManager.h" #include "td/telegram/SponsoredMessageManager.h" +#include "td/telegram/StarManager.h" #include "td/telegram/StickerType.h" #include "td/telegram/StoryId.h" #include "td/telegram/StoryManager.h" @@ -4267,6 +4268,7 @@ void MessagesManager::Message::store(StorerT &storer) const { bool has_via_business_bot_user_id = via_business_bot_user_id.is_valid(); bool has_effect_id = effect_id.is_valid(); bool has_fact_check = fact_check != nullptr; + bool has_initial_sender_dialog_id = !message_id.is_any_server() && initial_sender_dialog_id.is_valid(); BEGIN_STORE_FLAGS(); STORE_FLAG(is_channel_post); STORE_FLAG(is_outgoing); @@ -4355,6 +4357,7 @@ void MessagesManager::Message::store(StorerT &storer) const { STORE_FLAG(is_from_offline); STORE_FLAG(has_effect_id); STORE_FLAG(has_fact_check); + STORE_FLAG(has_initial_sender_dialog_id); END_STORE_FLAGS(); } @@ -4487,6 +4490,9 @@ void MessagesManager::Message::store(StorerT &storer) const { if (has_fact_check) { store(fact_check, storer); } + if (has_initial_sender_dialog_id) { + store(initial_sender_dialog_id, storer); + } } // do not forget to resolve message dependencies @@ -4546,6 +4552,7 @@ void MessagesManager::Message::parse(ParserT &parser) { bool has_via_business_bot_user_id = false; bool has_effect_id = false; bool has_fact_check = false; + bool has_initial_sender_dialog_id = false; BEGIN_PARSE_FLAGS(); PARSE_FLAG(is_channel_post); PARSE_FLAG(is_outgoing); @@ -4634,6 +4641,7 @@ void MessagesManager::Message::parse(ParserT &parser) { PARSE_FLAG(is_from_offline); PARSE_FLAG(has_effect_id); PARSE_FLAG(has_fact_check); + PARSE_FLAG(has_initial_sender_dialog_id); END_PARSE_FLAGS(); } @@ -4830,6 +4838,9 @@ void MessagesManager::Message::parse(ParserT &parser) { if (has_fact_check) { parse(fact_check, parser); } + if (has_initial_sender_dialog_id) { + parse(initial_sender_dialog_id, parser); + } CHECK(content != nullptr); is_content_secret |= ttl.is_secret_message_content(content->get_type()); // repair is_content_secret for old messages @@ -5558,9 +5569,6 @@ MessagesManager::MessagesManager(Td *td, ActorShared<> parent) send_update_chat_read_inbox_timeout_.set_callback(on_send_update_chat_read_inbox_timeout_callback); send_update_chat_read_inbox_timeout_.set_callback_data(static_cast(this)); - - send_paid_reactions_timeout_.set_callback(on_send_paid_reactions_timeout_callback); - send_paid_reactions_timeout_.set_callback_data(static_cast(this)); } MessagesManager::~MessagesManager() { @@ -5704,16 +5712,6 @@ void MessagesManager::on_send_update_chat_read_inbox_timeout_callback(void *mess &MessagesManager::on_send_update_chat_read_inbox_timeout, DialogId(dialog_id_int)); } -void MessagesManager::on_send_paid_reactions_timeout_callback(void *messages_manager_ptr, int64 task_id) { - if (G()->close_flag()) { - return; - } - - auto messages_manager = static_cast(messages_manager_ptr); - send_closure_later(messages_manager->actor_id(messages_manager), &MessagesManager::on_send_paid_reactions_timeout, - task_id); -} - void MessagesManager::on_live_location_expire_timeout_callback(void *messages_manager_ptr) { if (G()->close_flag()) { return; @@ -6115,9 +6113,9 @@ void MessagesManager::on_update_service_notification(tl_object_ptrpopup_) { send_closure(G()->td(), &Td::send_update, td_api::make_object( - update->type_, - get_message_content_object(content.get(), td_, owner_dialog_id, false, date, is_content_secret, - true, -1, update->invert_media_, disable_web_page_preview))); + update->type_, get_message_content_object(content.get(), td_, owner_dialog_id, true, false, date, + is_content_secret, true, -1, update->invert_media_, + disable_web_page_preview))); } if (has_date && is_user) { Dialog *d = get_service_notifications_dialog(); @@ -7681,6 +7679,9 @@ void MessagesManager::set_dialog_available_reactions(Dialog *d, ChatReactions && UNREACHABLE(); break; } + if (td_->dialog_manager_->is_broadcast_channel(d->dialog_id)) { + available_reactions.fix_broadcast_reactions(active_reaction_types_); + } if (d->available_reactions == available_reactions) { if (!d->is_available_reactions_inited) { d->is_available_reactions_inited = true; @@ -12123,42 +12124,6 @@ void MessagesManager::on_send_update_chat_read_inbox_timeout(DialogId dialog_id) } } -void MessagesManager::on_send_paid_reactions_timeout(int64 task_id) { - if (G()->close_flag()) { - return; - } - auto it = paid_reaction_tasks_.find(task_id); - if (it == paid_reaction_tasks_.end()) { - return; - } - auto message_full_id = it->second; - paid_reaction_tasks_.erase(it); - bool is_erased = paid_reaction_task_ids_.erase(message_full_id) > 0; - CHECK(is_erased); - - Dialog *d = get_dialog_force(message_full_id.get_dialog_id(), "on_send_paid_reactions_timeout"); - CHECK(d != nullptr); - auto *m = get_message_force(d, message_full_id.get_message_id(), "on_send_paid_reactions_timeout"); - if (m == nullptr || m->reactions == nullptr) { - return; - } - if (!get_message_available_reactions(d, m, true, nullptr).is_allowed_reaction_type(ReactionType::paid())) { - if (m->reactions->drop_pending_paid_reactions(td_)) { - send_update_message_interaction_info(d->dialog_id, m); - on_message_changed(d, m, true, "on_send_paid_reactions_timeout"); - } - return; - } - - pending_reactions_[message_full_id].query_count++; - - int64 random_id = (static_cast(G()->unix_time()) << 32) | static_cast(Random::secure_uint32()); - auto promise = PromiseCreator::lambda([actor_id = actor_id(this), message_full_id](Result &&result) { - send_closure(actor_id, &MessagesManager::on_set_message_reactions, message_full_id, std::move(result), Auto()); - }); - m->reactions->send_paid_message_reaction(td_, message_full_id, random_id, std::move(promise)); -} - int32 MessagesManager::get_message_date(const tl_object_ptr &message_ptr) { switch (message_ptr->get_id()) { case telegram_api::messageEmpty::ID: @@ -17466,6 +17431,8 @@ void MessagesManager::get_message_properties(DialogId dialog_id, MessageId messa auto can_be_saved = can_save_message(dialog_id, m); auto can_be_edited = can_edit_message(dialog_id, m, false, is_bot); auto can_be_forwarded = can_be_saved && can_forward_message(dialog_id, m); + auto can_be_copied_to_secret_chat = + can_be_forwarded && can_send_message_content_to_secret_chat(m->content->get_type()); auto can_be_paid = get_invoice_message_info({dialog_id, m->message_id}).is_ok(); auto can_be_pinned = can_pin_message(dialog_id, m).is_ok(); auto can_be_replied = @@ -17495,11 +17462,11 @@ void MessagesManager::get_message_properties(DialogId dialog_id, MessageId messa auto can_set_fact_check = can_set_message_fact_check(dialog_id, m); auto need_show_statistics = can_get_statistics && (m->view_count >= 100 || m->forward_count > 0); promise.set_value(td_api::make_object( - can_delete_for_self, can_delete_for_all_users, can_be_edited, can_be_forwarded, can_be_paid, can_be_pinned, - can_be_replied, can_be_replied_in_another_chat, can_be_saved, can_be_shared_in_story, can_edit_scheduling_state, - can_get_embedding_code, can_get_link, can_get_media_timestamp_links, can_get_message_thread, can_get_read_date, - can_get_statistics, can_get_viewers, can_recognize_speech, can_report_chat, can_report_reactions, - can_report_supergroup_spam, can_set_fact_check, need_show_statistics)); + can_be_copied_to_secret_chat, can_delete_for_self, can_delete_for_all_users, can_be_edited, can_be_forwarded, + can_be_paid, can_be_pinned, can_be_replied, can_be_replied_in_another_chat, can_be_saved, can_be_shared_in_story, + can_edit_scheduling_state, can_get_embedding_code, can_get_link, can_get_media_timestamp_links, + can_get_message_thread, can_get_read_date, can_get_statistics, can_get_viewers, can_recognize_speech, + can_report_chat, can_report_reactions, can_report_supergroup_spam, can_set_fact_check, need_show_statistics)); } bool MessagesManager::is_message_edited_recently(MessageFullId message_full_id, int32 seconds) { @@ -22790,7 +22757,8 @@ void MessagesManager::remove_message_reaction(MessageFullId message_full_id, Rea } } -void MessagesManager::add_paid_message_reaction(MessageFullId message_full_id, int64 star_count, bool is_anonymous, +void MessagesManager::add_paid_message_reaction(MessageFullId message_full_id, int64 star_count, + bool use_default_is_anonymous, bool is_anonymous, Promise &&promise) { auto dialog_id = message_full_id.get_dialog_id(); Dialog *d = get_dialog_force(dialog_id, "add_paid_message_reaction"); @@ -22806,7 +22774,10 @@ void MessagesManager::add_paid_message_reaction(MessageFullId message_full_id, i return promise.set_error(Status::Error(400, "The reaction isn't available for the message")); } if (star_count <= 0 || star_count > td_->option_manager_->get_option_integer("paid_reaction_star_count_max")) { - return promise.set_error(Status::Error(400, "Invalid Telegram Star count specified")); + return promise.set_error(Status::Error(400, "Invalid number of Telegram Stars specified")); + } + if (!td_->star_manager_->has_owned_star_count(star_count)) { + return promise.set_error(Status::Error(400, "Have not enough Telegram Stars")); } if (m->reactions == nullptr) { @@ -22815,40 +22786,53 @@ void MessagesManager::add_paid_message_reaction(MessageFullId message_full_id, i } LOG(INFO) << "Have message with " << *m->reactions; - m->reactions->add_my_paid_reaction(td_, narrow_cast(star_count), is_anonymous); + m->reactions->add_my_paid_reaction(td_, narrow_cast(star_count), use_default_is_anonymous, is_anonymous); m->reactions->sort_reactions(active_reaction_pos_); LOG(INFO) << "Update message reactions to " << *m->reactions; send_update_message_interaction_info(d->dialog_id, m); on_message_changed(d, m, true, "add_paid_message_reaction"); - auto &task_id = paid_reaction_task_ids_[message_full_id]; - if (task_id == 0) { - task_id = ++paid_reaction_task_id_; - paid_reaction_tasks_[task_id] = message_full_id; - } - send_paid_reactions_timeout_.set_timeout_in(task_id, 6.0); promise.set_value(Unit()); } -void MessagesManager::remove_paid_message_reactions(MessageFullId message_full_id, Promise &&promise) { - auto it = paid_reaction_task_ids_.find(message_full_id); - if (it == paid_reaction_task_ids_.end()) { +void MessagesManager::drop_message_pending_paid_reactions(const Dialog *d, Message *m) { + m->reactions->drop_pending_paid_reactions(td_); + send_update_message_interaction_info(d->dialog_id, m); + on_message_changed(d, m, true, "drop_message_pending_paid_reactions"); +} + +void MessagesManager::commit_paid_message_reactions(MessageFullId message_full_id, Promise &&promise) { + TRY_RESULT_PROMISE( + promise, d, + check_dialog_access(message_full_id.get_dialog_id(), false, AccessRights::Read, "commit_paid_message_reactions")); + auto *m = get_message_force(d, message_full_id.get_message_id(), "commit_paid_message_reactions"); + if (m == nullptr || m->reactions == nullptr || !m->reactions->has_pending_paid_reactions()) { + return promise.set_value(Unit()); + } + if (!get_message_available_reactions(d, m, true, nullptr).is_allowed_reaction_type(ReactionType::paid())) { + drop_message_pending_paid_reactions(d, m); return promise.set_value(Unit()); } - auto task_id = it->second; - paid_reaction_task_ids_.erase(it); - bool is_erased = paid_reaction_tasks_.erase(task_id) > 0; - CHECK(is_erased); - send_paid_reactions_timeout_.cancel_timeout(task_id); + pending_reactions_[message_full_id].query_count++; - Dialog *d = get_dialog_force(message_full_id.get_dialog_id(), "remove_paid_message_reaction"); - CHECK(d != nullptr); - auto *m = get_message_force(d, message_full_id.get_message_id(), "on_send_paid_reactions_timeout"); - if (m != nullptr && m->reactions != nullptr && m->reactions->drop_pending_paid_reactions(td_)) { - send_update_message_interaction_info(d->dialog_id, m); - on_message_changed(d, m, true, "on_send_paid_reactions_timeout"); + int64 random_id = (static_cast(G()->unix_time()) << 32) | static_cast(Random::secure_uint32()); + auto query_promise = PromiseCreator::lambda( + [actor_id = actor_id(this), message_full_id, promise = std::move(promise)](Result &&result) mutable { + send_closure(actor_id, &MessagesManager::on_set_message_reactions, message_full_id, std::move(result), + std::move(promise)); + }); + m->reactions->send_paid_message_reaction(td_, message_full_id, random_id, std::move(query_promise)); +} + +void MessagesManager::remove_paid_message_reactions(MessageFullId message_full_id, Promise &&promise) { + TRY_RESULT_PROMISE( + promise, d, + check_dialog_access(message_full_id.get_dialog_id(), false, AccessRights::Read, "remove_paid_message_reactions")); + auto *m = get_message_force(d, message_full_id.get_message_id(), "remove_paid_message_reactions"); + if (m != nullptr && m->reactions != nullptr && m->reactions->has_pending_paid_reactions()) { + drop_message_pending_paid_reactions(d, m); } promise.set_value(Unit()); } @@ -23001,9 +22985,10 @@ tl_object_ptr MessagesManager::get_message_sched td_api::object_ptr MessagesManager::get_message_message_content_object(DialogId dialog_id, const Message *m) const { auto live_location_date = m->is_failed_to_send ? 0 : m->date; - return get_message_content_object(m->content.get(), td_, dialog_id, m->is_outgoing, live_location_date, - m->is_content_secret, need_skip_bot_commands(dialog_id, m), - get_message_max_media_timestamp(m), m->invert_media, m->disable_web_page_preview); + return get_message_content_object( + m->content.get(), td_, dialog_id, m->message_id.is_any_server() && dialog_id.get_type() != DialogType::SecretChat, + m->is_outgoing, live_location_date, m->is_content_secret, need_skip_bot_commands(dialog_id, m), + get_message_max_media_timestamp(m), m->invert_media, m->disable_web_page_preview); } td_api::object_ptr MessagesManager::get_dialog_event_log_message_object( @@ -23030,7 +23015,7 @@ td_api::object_ptr MessagesManager::get_dialog_event_log_messag auto edit_date = m->hide_edit_date ? 0 : m->edit_date; auto reply_markup = get_reply_markup_object(td_->user_manager_.get(), m->reply_markup); auto content = - get_message_content_object(m->content.get(), td_, dialog_id, m->is_outgoing, 0, false, true, + get_message_content_object(m->content.get(), td_, dialog_id, true, m->is_outgoing, 0, false, true, get_message_own_max_media_timestamp(m), m->invert_media, m->disable_web_page_preview); return td_api::make_object( m->message_id.get(), std::move(sender), get_chat_id_object(dialog_id, "get_dialog_event_log_message_object"), @@ -23087,7 +23072,7 @@ td_api::object_ptr MessagesManager::get_business_message_messag m->via_business_bot_user_id, "get_business_message_message_object via_business_bot_user_id"); auto reply_to = [&]() -> td_api::object_ptr { if (!m->replied_message_info.is_empty()) { - return m->replied_message_info.get_message_reply_to_message_object(td_, dialog_id); + return m->replied_message_info.get_message_reply_to_message_object(td_, dialog_id, true); } if (m->reply_to_story_full_id.is_valid()) { return td_api::make_object( @@ -23173,7 +23158,7 @@ td_api::object_ptr MessagesManager::get_message_object(DialogId m->replied_message_info.get_same_chat_reply_to_message_id(false) == m->top_thread_message_id) { return nullptr; } - return m->replied_message_info.get_message_reply_to_message_object(td_, dialog_id); + return m->replied_message_info.get_message_reply_to_message_object(td_, dialog_id, m->message_id.is_any_server()); } if (m->reply_to_story_full_id.is_valid()) { return td_api::make_object( @@ -23320,11 +23305,13 @@ unique_ptr MessagesManager::create_message_to_send( if (!is_channel_post || (!is_scheduled && td_->chat_manager_->get_channel_sign_messages(dialog_id.get_channel_id()))) { if (send_as_dialog_id.is_valid()) { + // for resend_messages if (send_as_dialog_id.get_type() == DialogType::User) { m->sender_user_id = send_as_dialog_id.get_user_id(); } else { m->sender_dialog_id = send_as_dialog_id; } + m->has_explicit_sender = true; } else if (d->default_send_message_as_dialog_id.is_valid()) { if (d->default_send_message_as_dialog_id.get_type() == DialogType::User) { m->sender_user_id = my_id; @@ -23345,12 +23332,12 @@ unique_ptr MessagesManager::create_message_to_send( if (is_channel_post && !is_scheduled && td_->chat_manager_->get_channel_sign_messages(dialog_id.get_channel_id())) { auto show_message_sender = td_->chat_manager_->get_channel_show_message_sender(dialog_id.get_channel_id()); if (m->sender_dialog_id != dialog_id || !m->has_explicit_sender) { - m->author_signature = m->sender_dialog_id == dialog_id || m->sender_dialog_id == DialogId() || - (m->has_explicit_sender && !show_message_sender) + m->author_signature = m->sender_dialog_id == dialog_id || m->sender_dialog_id == DialogId() ? td_->user_manager_->get_user_title(my_id) : td_->dialog_manager_->get_dialog_title(m->sender_dialog_id); } if (!show_message_sender) { + m->initial_sender_dialog_id = get_message_sender(m); m->sender_user_id = UserId(); m->sender_dialog_id = dialog_id; } @@ -23810,6 +23797,10 @@ void MessagesManager::get_dialog_send_message_as_dialog_ids( } // checked in on_update_dialog_default_send_message_as_dialog_id CHECK(dialog_id.get_type() == DialogType::Channel); + auto is_broadcast = td_->dialog_manager_->is_broadcast_channel(dialog_id); + if (is_broadcast && !td_->chat_manager_->get_channel_sign_messages(dialog_id.get_channel_id())) { + return promise.set_value(td_api::make_object()); + } if (td_->chat_manager_->are_created_public_broadcasts_inited()) { auto senders = td_api::make_object(); @@ -23819,11 +23810,7 @@ void MessagesManager::get_dialog_send_message_as_dialog_ids( auto sender = get_message_sender_object(td, dialog_id, "add_sender"); senders->senders_.push_back(td_api::make_object(std::move(sender), needs_premium)); }; - auto is_broadcast = td_->dialog_manager_->is_broadcast_channel(dialog_id); if (is_broadcast) { - if (!td_->chat_manager_->get_channel_sign_messages(dialog_id.get_channel_id())) { - return promise.set_value(td_api::make_object()); - } add_sender(td_->dialog_manager_->get_my_dialog_id(), false); } if (td_->dialog_manager_->is_anonymous_administrator(dialog_id, nullptr)) { @@ -24395,7 +24382,8 @@ void MessagesManager::do_send_message(DialogId dialog_id, const Message *m, int3 thumbnail_file_id = FileId(); } - if (content_type == MessageContentType::PaidMedia && !file_view.has_remote_location() && file_view.has_url()) { + if (content_type == MessageContentType::PaidMedia && !file_view.has_full_remote_location() && + file_view.has_url()) { do_send_media(dialog_id, m, static_cast(i), file_id, FileId(), nullptr, nullptr); continue; } @@ -24839,8 +24827,9 @@ void MessagesManager::do_send_message_group(int64 media_album_id) { // TODO return CHECK auto file_id = get_message_content_any_file_id(m->content.get()); auto file_view = td_->file_manager_->get_file_view(file_id); - bool has_remote = file_view.has_remote_location(); - bool is_web = has_remote ? file_view.remote_location().is_web() : false; + const auto *full_remote_location = file_view.get_full_remote_location(); + bool has_remote = full_remote_location != nullptr; + bool is_web = has_remote ? full_remote_location->is_web() : false; LOG(FATAL) << request.dialog_id << " " << request.finished_count << " " << i << " " << request.message_ids << " " << request.is_finished << " " << request.results << " " << m->ttl << " " << has_remote << " " << file_view.has_alive_remote_location() << " " << file_view.has_active_upload_remote_location() << " " @@ -26328,7 +26317,8 @@ tl_object_ptr MessagesManager::get_send_message_as_inpu if (!m->has_explicit_sender) { return nullptr; } - return td_->dialog_manager_->get_input_peer(get_message_sender(m), AccessRights::Write); + auto dialog_id = m->initial_sender_dialog_id != DialogId() ? m->initial_sender_dialog_id : get_message_sender(m); + return td_->dialog_manager_->get_input_peer(dialog_id, AccessRights::Write); } bool MessagesManager::can_set_game_score(MessageFullId message_full_id) const { @@ -36048,6 +36038,9 @@ unique_ptr MessagesManager::parse_dialog(DialogId dialo if (get_active_reactions(d->available_reactions).empty() != ((d->available_reactions_generation & 1) == 1)) { set_dialog_next_available_reactions_generation(d, d->available_reactions_generation); } + if (td_->dialog_manager_->is_broadcast_channel(dialog_id)) { + d->available_reactions.fix_broadcast_reactions(active_reaction_types_); + } break; case DialogType::User: case DialogType::SecretChat: diff --git a/lib/tgchat/ext/td/td/telegram/MessagesManager.h b/lib/tgchat/ext/td/td/telegram/MessagesManager.h index 35bf13bc..973d0a8f 100644 --- a/lib/tgchat/ext/td/td/telegram/MessagesManager.h +++ b/lib/tgchat/ext/td/td/telegram/MessagesManager.h @@ -796,8 +796,10 @@ class MessagesManager final : public Actor { void remove_message_reaction(MessageFullId message_full_id, ReactionType reaction_type, Promise &&promise); - void add_paid_message_reaction(MessageFullId message_full_id, int64 star_count, bool is_anonymous, - Promise &&promise); + void add_paid_message_reaction(MessageFullId message_full_id, int64 star_count, bool use_default_is_anonymous, + bool is_anonymous, Promise &&promise); + + void commit_paid_message_reactions(MessageFullId message_full_id, Promise &&promise); void remove_paid_message_reactions(MessageFullId message_full_id, Promise &&promise); @@ -1068,6 +1070,7 @@ class MessagesManager final : public Actor { MessageId linked_top_thread_message_id; vector local_thread_message_ids; + DialogId initial_sender_dialog_id; // for send_message MessageId initial_top_thread_message_id; // for send_message MessageInputReplyTo input_reply_to; // for send_message int64 reply_to_random_id = 0; // for send_message @@ -2132,8 +2135,6 @@ class MessagesManager final : public Actor { void on_send_update_chat_read_inbox_timeout(DialogId dialog_id); - void on_send_paid_reactions_timeout(int64 task_id); - bool delete_newer_server_messages_at_the_end(Dialog *d, MessageId max_message_id); template @@ -2622,6 +2623,8 @@ class MessagesManager final : public Actor { DialogId get_my_reaction_dialog_id(const Dialog *d) const; + void drop_message_pending_paid_reactions(const Dialog *d, Message *m); + void set_message_reactions(Dialog *d, Message *m, bool is_big, bool add_to_recent, Promise &&promise); void on_set_message_reactions(MessageFullId message_full_id, Result result, Promise promise); @@ -3066,8 +3069,6 @@ class MessagesManager final : public Actor { static void on_send_update_chat_read_inbox_timeout_callback(void *messages_manager_ptr, int64 dialog_id_int); - static void on_send_paid_reactions_timeout_callback(void *messages_manager_ptr, int64 task_id); - static void on_live_location_expire_timeout_callback(void *messages_manager_ptr); void on_live_location_expire_timeout(); @@ -3403,7 +3404,6 @@ class MessagesManager final : public Actor { MultiTimeout preload_folder_dialog_list_timeout_{"PreloadFolderDialogListTimeout"}; MultiTimeout update_viewed_messages_timeout_{"UpdateViewedMessagesTimeout"}; MultiTimeout send_update_chat_read_inbox_timeout_{"SendUpdateChatReadInboxTimeout"}; - MultiTimeout send_paid_reactions_timeout_{"SendPaidReactionsTimeout"}; Timeout live_location_expire_timeout_; @@ -3540,10 +3540,6 @@ class MessagesManager final : public Actor { }; FlatHashMap pending_reactions_; - int64 paid_reaction_task_id_ = 0; - FlatHashMap paid_reaction_task_ids_; - FlatHashMap paid_reaction_tasks_; - FlatHashMap pending_read_reactions_; vector active_reaction_types_; diff --git a/lib/tgchat/ext/td/td/telegram/NotificationManager.cpp b/lib/tgchat/ext/td/td/telegram/NotificationManager.cpp index 59a3a5f6..f224acc1 100644 --- a/lib/tgchat/ext/td/td/telegram/NotificationManager.cpp +++ b/lib/tgchat/ext/td/td/telegram/NotificationManager.cpp @@ -2898,6 +2898,9 @@ string NotificationManager::convert_loc_key(const string &loc_key) { if (loc_key == "MESSAGE_GIVEAWAY") { return "MESSAGE_GIVEAWAY"; } + if (loc_key == "MESSAGE_GIVEAWAY_STARS") { + return "MESSAGE_GIVEAWAY_STARS"; + } break; case 'H': if (loc_key == "PINNED_PHOTO") { @@ -2914,6 +2917,9 @@ string NotificationManager::convert_loc_key(const string &loc_key) { if (loc_key == "PINNED_GIVEAWAY") { return "PINNED_MESSAGE_GIVEAWAY"; } + if (loc_key == "PINNED_GIVEAWAY_STARS") { + return "PINNED_MESSAGE_GIVEAWAY_STARS"; + } if (loc_key == "MESSAGE_INVOICE") { return "MESSAGE_INVOICE"; } @@ -3571,6 +3577,18 @@ Status NotificationManager::process_push_notification_payload(string payload, bo arg = PSTRING() << user_count << ' ' << month_count; loc_args.clear(); } + if (loc_key == "MESSAGE_GIVEAWAY_STARS") { + if (loc_args.size() != 2) { + return Status::Error("Expected 2 arguments for MESSAGE_GIVEAWAY_STARS"); + } + TRY_RESULT(user_count, to_integer_safe(loc_args[0])); + if (user_count <= 0) { + return Status::Error("Expected user count to be non-negative"); + } + TRY_RESULT(star_count, to_integer_safe(loc_args[1])); + arg = PSTRING() << user_count << ' ' << StarManager::get_star_count(star_count); + loc_args.clear(); + } if (loc_key == "MESSAGE_PAID_MEDIA") { if (loc_args.size() != 1) { return Status::Error("Expected 1 argument for MESSAGE_PAID_MEDIA"); diff --git a/lib/tgchat/ext/td/td/telegram/NotificationSettingsManager.cpp b/lib/tgchat/ext/td/td/telegram/NotificationSettingsManager.cpp index b965f9ae..3e8204e6 100644 --- a/lib/tgchat/ext/td/td/telegram/NotificationSettingsManager.cpp +++ b/lib/tgchat/ext/td/td/telegram/NotificationSettingsManager.cpp @@ -1009,8 +1009,9 @@ FileId NotificationSettingsManager::get_saved_ringtone(int64 ringtone_id, Promis auto file_view = td_->file_manager_->get_file_view(file_id); CHECK(!file_view.empty()); CHECK(file_view.get_type() == FileType::Ringtone); - CHECK(file_view.has_remote_location()); - if (file_view.remote_location().get_id() == ringtone_id) { + const auto *full_remote_location = file_view.get_full_remote_location(); + CHECK(full_remote_location != nullptr); + if (full_remote_location->get_id() == ringtone_id) { return file_view.get_main_file_id(); } } @@ -1035,11 +1036,12 @@ void NotificationSettingsManager::send_save_ringtone_query( // TODO log event auto file_view = td_->file_manager_->get_file_view(ringtone_file_id); CHECK(!file_view.empty()); - CHECK(file_view.has_remote_location()); - CHECK(file_view.remote_location().is_document()); - CHECK(!file_view.remote_location().is_web()); + const auto *full_remote_location = file_view.get_full_remote_location(); + CHECK(full_remote_location != nullptr); + CHECK(full_remote_location->is_document()); + CHECK(!full_remote_location->is_web()); td_->create_handler(std::move(promise)) - ->send(ringtone_file_id, file_view.remote_location().as_input_document(), unsave); + ->send(ringtone_file_id, full_remote_location->as_input_document(), unsave); } void NotificationSettingsManager::add_saved_ringtone(td_api::object_ptr &&input_file, @@ -1081,9 +1083,10 @@ void NotificationSettingsManager::add_saved_ringtone(td_api::object_ptr td_->option_manager_->get_option_integer("notification_sound_duration_max")) { return promise.set_error(Status::Error(400, "Notification sound is too long")); } - if (file_view.has_remote_location() && !file_view.is_encrypted()) { - CHECK(file_view.remote_location().is_document()); - if (file_view.main_remote_location().is_web()) { + const auto *main_remote_location = file_view.get_main_remote_location(); + if (main_remote_location != nullptr && !file_view.is_encrypted()) { + CHECK(main_remote_location->is_document()); + if (main_remote_location->is_web()) { return promise.set_error(Status::Error(400, "Can't use web document as notification sound")); } @@ -1092,7 +1095,7 @@ void NotificationSettingsManager::add_saved_ringtone(td_api::object_ptrfile_manager_->register_remote( FullRemoteFileLocation(FileType::Ringtone, remote.get_id(), remote.get_access_hash(), remote.get_dc_id(), remote.get_file_reference().str()), @@ -1158,23 +1161,25 @@ void NotificationSettingsManager::on_upload_ringtone(FileId file_id, FileView file_view = td_->file_manager_->get_file_view(file_id); CHECK(!file_view.is_encrypted()); CHECK(file_view.get_type() == FileType::Ringtone); - if (input_file == nullptr && file_view.has_remote_location()) { - if (file_view.main_remote_location().is_web()) { + const auto *main_remote_location = file_view.get_main_remote_location(); + if (input_file == nullptr && main_remote_location != nullptr) { + if (main_remote_location->is_web()) { return promise.set_error(Status::Error(400, "Can't use web document as notification sound")); } if (is_reupload) { return promise.set_error(Status::Error(400, "Failed to reupload the file")); } + auto main_file_id = file_view.get_main_file_id(); send_save_ringtone_query( - file_view.get_main_file_id(), false, + main_file_id, false, PromiseCreator::lambda( - [actor_id = actor_id(this), file_id = file_view.get_main_file_id(), promise = std::move(promise)]( + [actor_id = actor_id(this), main_file_id, promise = std::move(promise)]( Result> &&result) mutable { if (result.is_error()) { promise.set_error(result.move_as_error()); } else { - send_closure(actor_id, &NotificationSettingsManager::on_add_saved_ringtone, file_id, + send_closure(actor_id, &NotificationSettingsManager::on_add_saved_ringtone, main_file_id, result.move_as_ok(), std::move(promise)); } })); @@ -1273,8 +1278,9 @@ void NotificationSettingsManager::remove_saved_ringtone(int64 ringtone_id, Promi auto file_view = td_->file_manager_->get_file_view(file_id); CHECK(!file_view.empty()); CHECK(file_view.get_type() == FileType::Ringtone); - CHECK(file_view.has_remote_location()); - if (file_view.remote_location().get_id() == ringtone_id) { + const auto *full_remote_location = file_view.get_full_remote_location(); + CHECK(full_remote_location != nullptr); + if (full_remote_location->get_id() == ringtone_id) { send_save_ringtone_query( file_view.get_main_file_id(), true, PromiseCreator::lambda( @@ -1312,8 +1318,9 @@ void NotificationSettingsManager::on_remove_saved_ringtone(int64 ringtone_id, Pr auto file_view = td_->file_manager_->get_file_view(*it); CHECK(!file_view.empty()); CHECK(file_view.get_type() == FileType::Ringtone); - CHECK(file_view.has_remote_location()); - if (file_view.remote_location().get_id() == ringtone_id) { + const auto *full_remote_location = file_view.get_full_remote_location(); + CHECK(full_remote_location != nullptr); + if (full_remote_location->get_id() == ringtone_id) { saved_ringtone_file_ids_.erase(it); saved_ringtone_hash_ = 0; on_saved_ringtones_updated(false); @@ -1483,8 +1490,9 @@ NotificationSettingsManager::get_update_saved_notification_sounds_object() const auto file_view = file_manager->get_file_view(file_id); CHECK(!file_view.empty()); CHECK(file_view.get_type() == FileType::Ringtone); - CHECK(file_view.has_remote_location()); - return file_view.remote_location().get_id(); + const auto *full_remote_location = file_view.get_full_remote_location(); + CHECK(full_remote_location != nullptr); + return full_remote_location->get_id(); }); return td_api::make_object(std::move(ringtone_ids)); } diff --git a/lib/tgchat/ext/td/td/telegram/NotificationType.cpp b/lib/tgchat/ext/td/td/telegram/NotificationType.cpp index 1f49dc27..f249e1f3 100644 --- a/lib/tgchat/ext/td/td/telegram/NotificationType.cpp +++ b/lib/tgchat/ext/td/td/telegram/NotificationType.cpp @@ -269,7 +269,22 @@ class NotificationTypePushMessage final : public NotificationType { user_count = to_integer(user_count_str); month_count = to_integer(month_count_str); } - return td_api::make_object(user_count, month_count, is_pinned); + return td_api::make_object( + user_count, is_pinned ? nullptr : td_api::make_object(month_count), + is_pinned); + } + if (key == "MESSAGE_GIVEAWAY_STARS") { + int32 user_count = 0; + int64 star_count = 0; + if (!is_pinned) { + string user_count_str; + string star_count_str; + std::tie(user_count_str, star_count_str) = split(arg); + user_count = to_integer(user_count_str); + star_count = to_integer(star_count_str); + } + return td_api::make_object( + user_count, is_pinned ? nullptr : td_api::make_object(star_count), is_pinned); } break; case 'I': diff --git a/lib/tgchat/ext/td/td/telegram/OptionManager.cpp b/lib/tgchat/ext/td/td/telegram/OptionManager.cpp index 6ae5bbc1..64f00b13 100644 --- a/lib/tgchat/ext/td/td/telegram/OptionManager.cpp +++ b/lib/tgchat/ext/td/td/telegram/OptionManager.cpp @@ -158,8 +158,8 @@ OptionManager::OptionManager(Td *td) set_default_integer_option("bot_media_preview_count_max", 12); set_default_integer_option("paid_reaction_star_count_max", 2500); set_default_integer_option("subscription_star_count_max", 2500); - set_default_integer_option("usd_to_1000_star_rate", 1410); - set_default_integer_option("1000_star_to_usd_rate", 1200); + set_default_integer_option("usd_to_thousand_star_rate", 1410); + set_default_integer_option("thousand_star_to_usd_rate", 1300); if (options.isset("my_phone_number") || !options.isset("my_id")) { update_premium_options(); @@ -174,6 +174,8 @@ OptionManager::OptionManager(Td *td) set_option_empty("forum_member_count_min"); set_option_empty("themed_emoji_statuses_sticker_set_id"); set_option_empty("themed_premium_statuses_sticker_set_id"); + set_option_empty("usd_to_1000_star_rate"); + set_option_empty("1000_star_to_usd_rate"); } OptionManager::~OptionManager() = default; @@ -714,7 +716,7 @@ td_api::object_ptr OptionManager::get_option_synchronously( break; case 'v': if (name == "version") { - return td_api::make_object("1.8.35"); + return td_api::make_object("1.8.36"); } break; } diff --git a/lib/tgchat/ext/td/td/telegram/PasswordManager.cpp b/lib/tgchat/ext/td/td/telegram/PasswordManager.cpp index ca5a1dfd..5e95fb3f 100644 --- a/lib/tgchat/ext/td/td/telegram/PasswordManager.cpp +++ b/lib/tgchat/ext/td/td/telegram/PasswordManager.cpp @@ -188,11 +188,9 @@ void PasswordManager::set_login_email_address(string new_login_email_address, Pr make_tl_object(), std::move(new_login_email_address))); send_with_promise(std::move(query), PromiseCreator::lambda([promise = std::move(promise)](Result r_query) mutable { - auto r_result = fetch_result(std::move(r_query)); - if (r_result.is_error()) { - return promise.set_error(r_result.move_as_error()); - } - return promise.set_value(SentEmailCode(r_result.move_as_ok())); + TRY_RESULT_PROMISE(promise, result, + fetch_result(std::move(r_query))); + promise.set_value(SentEmailCode(std::move(result))); })); } @@ -214,11 +212,8 @@ void PasswordManager::check_login_email_address_code(EmailVerification &&code, P make_tl_object(), code.get_input_email_verification())); send_with_promise(std::move(query), PromiseCreator::lambda([promise = std::move(promise)](Result r_query) mutable { - auto r_result = fetch_result(std::move(r_query)); - if (r_result.is_error()) { - return promise.set_error(r_result.move_as_error()); - } - return promise.set_value(Unit()); + TRY_STATUS_PROMISE(promise, fetch_result(std::move(r_query))); + promise.set_value(Unit()); })); } @@ -323,11 +318,8 @@ void PasswordManager::do_create_temp_password(string password, int32 timeout, Pa auto hash = get_input_check_password(password, password_state); send_with_promise(G()->net_query_creator().create(telegram_api::account_getTmpPassword(std::move(hash), timeout)), PromiseCreator::lambda([promise = std::move(promise)](Result r_query) mutable { - auto r_result = fetch_result(std::move(r_query)); - if (r_result.is_error()) { - return promise.set_error(r_result.move_as_error()); - } - auto result = r_result.move_as_ok(); + TRY_RESULT_PROMISE(promise, result, + fetch_result(std::move(r_query))); TempPasswordState res; res.has_temp_password = true; res.temp_password = result->tmp_password_.as_slice().str(); @@ -480,11 +472,9 @@ void PasswordManager::send_email_address_verification_code(string email, Promise make_tl_object(), std::move(email))); send_with_promise(std::move(query), PromiseCreator::lambda([promise = std::move(promise)](Result r_query) mutable { - auto r_result = fetch_result(std::move(r_query)); - if (r_result.is_error()) { - return promise.set_error(r_result.move_as_error()); - } - return promise.set_value(SentEmailCode(r_result.move_as_ok())); + TRY_RESULT_PROMISE(promise, result, + fetch_result(std::move(r_query))); + promise.set_value(SentEmailCode(std::move(result))); })); } @@ -502,25 +492,19 @@ void PasswordManager::check_email_address_verification_code(string code, Promise auto verification_code = make_tl_object(std::move(code)); auto query = G()->net_query_creator().create(telegram_api::account_verifyEmail( make_tl_object(), std::move(verification_code))); - send_with_promise(std::move(query), - PromiseCreator::lambda([promise = std::move(promise)](Result r_query) mutable { - auto r_result = fetch_result(std::move(r_query)); - if (r_result.is_error()) { - return promise.set_error(r_result.move_as_error()); - } - return promise.set_value(Unit()); - })); + send_with_promise( + std::move(query), PromiseCreator::lambda([promise = std::move(promise)](Result r_query) mutable { + TRY_STATUS_PROMISE(promise, fetch_result(std::move(r_query))); + promise.set_value(Unit()); + })); } void PasswordManager::request_password_recovery(Promise promise) { // is called only after authorization send_with_promise(G()->net_query_creator().create(telegram_api::auth_requestPasswordRecovery()), PromiseCreator::lambda([promise = std::move(promise)](Result r_query) mutable { - auto r_result = fetch_result(std::move(r_query)); - if (r_result.is_error()) { - return promise.set_error(r_result.move_as_error()); - } - auto result = r_result.move_as_ok(); + TRY_RESULT_PROMISE(promise, result, + fetch_result(std::move(r_query))); return promise.set_value(SentEmailCode(std::move(result->email_pattern_), 0)); })); } @@ -529,14 +513,12 @@ void PasswordManager::check_password_recovery_code(string code, Promise pr // is called only after authorization send_with_promise(G()->net_query_creator().create(telegram_api::auth_checkRecoveryPassword(code)), PromiseCreator::lambda([promise = std::move(promise)](Result r_query) mutable { - auto r_result = fetch_result(std::move(r_query)); - if (r_result.is_error()) { - return promise.set_error(r_result.move_as_error()); - } - if (!r_result.ok()) { + TRY_RESULT_PROMISE(promise, result, + fetch_result(std::move(r_query))); + if (!result) { return promise.set_error(Status::Error(400, "Invalid recovery code")); } - return promise.set_value(Unit()); + promise.set_value(Unit()); })); } @@ -574,25 +556,18 @@ void PasswordManager::do_recover_password(string code, PasswordInputSettings &&n } send_with_promise(G()->net_query_creator().create( telegram_api::auth_recoverPassword(flags, std::move(code), std::move(new_settings))), - PromiseCreator::lambda( - [actor_id = actor_id(this), promise = std::move(promise)](Result r_query) mutable { - auto r_result = fetch_result(std::move(r_query)); - if (r_result.is_error()) { - return promise.set_error(r_result.move_as_error()); - } - send_closure(actor_id, &PasswordManager::get_state, std::move(promise)); - })); + PromiseCreator::lambda([actor_id = actor_id(this), + promise = std::move(promise)](Result r_query) mutable { + TRY_STATUS_PROMISE(promise, fetch_result(std::move(r_query))); + send_closure(actor_id, &PasswordManager::get_state, std::move(promise)); + })); } void PasswordManager::reset_password(Promise promise) { send_with_promise( G()->net_query_creator().create(telegram_api::account_resetPassword()), PromiseCreator::lambda([promise = std::move(promise)](Result r_query) mutable { - auto r_result = fetch_result(std::move(r_query)); - if (r_result.is_error()) { - return promise.set_error(r_result.move_as_error()); - } - auto result_ptr = r_result.move_as_ok(); + TRY_RESULT_PROMISE(promise, result_ptr, fetch_result(std::move(r_query))); switch (result_ptr->get_id()) { case telegram_api::account_resetPasswordOk::ID: return promise.set_value(td_api::make_object()); @@ -795,12 +770,7 @@ void PasswordManager::do_get_state(Promise promise) { std::move(query), PromiseCreator::lambda([actor_id = actor_id(this), code_length = last_code_length_, promise = std::move(promise)](Result r_query) mutable { TRY_STATUS_PROMISE(promise, G()->close_status()); - - auto r_result = fetch_result(std::move(r_query)); - if (r_result.is_error()) { - return promise.set_error(r_result.move_as_error()); - } - auto password = r_result.move_as_ok(); + TRY_RESULT_PROMISE(promise, password, fetch_result(std::move(r_query))); LOG(INFO) << "Receive password info: " << to_string(password); Random::add_seed(password->secure_random_.as_slice()); diff --git a/lib/tgchat/ext/td/td/telegram/Payments.cpp b/lib/tgchat/ext/td/td/telegram/Payments.cpp index 915a3aa9..7e0ce041 100644 --- a/lib/tgchat/ext/td/td/telegram/Payments.cpp +++ b/lib/tgchat/ext/td/td/telegram/Payments.cpp @@ -158,6 +158,20 @@ Result get_input_invoice_info(Td *td, td_api::object_ptr(std::move(purpose)); break; } + case td_api::telegramPaymentPurposeStarGiveaway::ID: { + auto p = static_cast(invoice->purpose_.get()); + if (p->amount_ <= 0 || !check_currency_amount(p->amount_)) { + return Status::Error(400, "Invalid amount of the currency specified"); + } + if (!clean_input_string(p->currency_)) { + return Status::Error(400, "Strings must be encoded in UTF-8"); + } + TRY_RESULT(parameters, GiveawayParameters::get_giveaway_parameters(td, p->parameters_.get())); + auto purpose = parameters.get_input_store_payment_stars_giveaway(td, p->currency_, p->amount_, + p->winner_count_, p->star_count_); + result.input_invoice_ = telegram_api::make_object(std::move(purpose)); + break; + } case td_api::telegramPaymentPurposeJoinChat::ID: { auto p = static_cast(invoice->purpose_.get()); if (!DialogInviteLink::is_valid_invite_link(p->invite_link_)) { @@ -685,6 +699,7 @@ class SendStarPaymentFormQuery final : public Td::ResultHandler { void send(InputInvoiceInfo &&input_invoice_info, int64 payment_form_id) { dialog_id_ = input_invoice_info.dialog_id_; star_count_ = input_invoice_info.star_count_; + td_->star_manager_->add_pending_owned_star_count(-star_count_, false); send_query(G()->net_query_creator().create( telegram_api::payments_sendStarsForm(0, payment_form_id, std::move(input_invoice_info.input_invoice_)))); @@ -699,12 +714,10 @@ class SendStarPaymentFormQuery final : public Td::ResultHandler { auto payment_result = result_ptr.move_as_ok(); LOG(INFO) << "Receive result for SendStarPaymentFormQuery: " << to_string(payment_result); + td_->star_manager_->add_pending_owned_star_count(star_count_, true); switch (payment_result->get_id()) { case telegram_api::payments_paymentResult::ID: { auto result = telegram_api::move_object_as(payment_result); - if (star_count_ != 0) { - td_->star_manager_->add_owned_star_count(-star_count_); - } td_->updates_manager_->on_get_updates( std::move(result->updates_), PromiseCreator::lambda([promise = std::move(promise_)](Unit) mutable { promise.set_value(td_api::make_object(true, string())); @@ -723,6 +736,7 @@ class SendStarPaymentFormQuery final : public Td::ResultHandler { void on_error(Status status) final { td_->dialog_manager_->on_get_dialog_error(dialog_id_, status, "SendStarPaymentFormQuery"); + td_->star_manager_->add_pending_owned_star_count(star_count_, false); promise_.set_error(std::move(status)); } }; @@ -1085,6 +1099,9 @@ void send_payment_form(Td *td, td_api::object_ptr &&input_ if (tip_amount != 0 || !order_info_id.empty() || !shipping_option_id.empty()) { return promise.set_error(Status::Error(400, "Invalid payment form parameters specified")); } + if (!td->star_manager_->has_owned_star_count(input_invoice_info.star_count_)) { + return promise.set_error(Status::Error(400, "Have not enough Telegram Stars to complete payment")); + } td->create_handler(std::move(promise)) ->send(std::move(input_invoice_info), payment_form_id); return; diff --git a/lib/tgchat/ext/td/td/telegram/Photo.cpp b/lib/tgchat/ext/td/td/telegram/Photo.cpp index 88a369cb..9f0a0fa5 100644 --- a/lib/tgchat/ext/td/td/telegram/Photo.cpp +++ b/lib/tgchat/ext/td/td/telegram/Photo.cpp @@ -181,8 +181,9 @@ DialogPhoto as_dialog_photo(FileManager *file_manager, DialogId dialog_id, int64 auto reregister_photo = [&](bool is_big, FileId file_id) { auto file_view = file_manager->get_file_view(file_id); - CHECK(file_view.has_remote_location()); - auto remote = file_view.remote_location(); + const auto *full_remote_location = file_view.get_full_remote_location(); + CHECK(full_remote_location != nullptr); + auto remote = *full_remote_location; CHECK(remote.is_photo()); CHECK(!remote.is_web()); remote.set_source(PhotoSizeSource::dialog_photo(dialog_id, dialog_access_hash, is_big)); @@ -375,8 +376,9 @@ Result create_photo(FileManager *file_manager, FileId file_id, PhotoSize Photo photo; auto file_view = file_manager->get_file_view(file_id); - if (file_view.has_remote_location() && !file_view.remote_location().is_web()) { - photo.id = file_view.remote_location().get_id(); + const auto *full_remote_location = file_view.get_full_remote_location(); + if (full_remote_location != nullptr && !full_remote_location->is_web()) { + photo.id = full_remote_location->get_id(); } if (photo.is_empty()) { photo.id = 0; @@ -533,23 +535,23 @@ void merge_photos(Td *td, const Photo *old_photo, Photo *new_photo, DialogId dia if (need_merge && new_photos_size != 0) { FileId old_file_id = get_photo_upload_file_id(*old_photo); FileView old_file_view = td->file_manager_->get_file_view(old_file_id); + const auto *old_main_remote_location = old_file_view.get_main_remote_location(); FileId new_file_id = new_photo->photos[0].file_id; FileView new_file_view = td->file_manager_->get_file_view(new_file_id); - CHECK(new_file_view.has_remote_location()); + const auto *new_full_remote_location = new_file_view.get_full_remote_location(); + CHECK(new_full_remote_location != nullptr); LOG(DEBUG) << "Trying to merge old file " << old_file_id << " and new file " << new_file_id; - if (new_file_view.remote_location().is_web()) { + + if (new_full_remote_location->is_web()) { LOG(ERROR) << "Have remote web photo location"; - } else if (!old_file_view.has_remote_location() || - old_file_view.main_remote_location().get_file_reference() != - new_file_view.remote_location().get_file_reference() || - old_file_view.main_remote_location().get_access_hash() != - new_file_view.remote_location().get_access_hash()) { + } else if (old_main_remote_location == nullptr || + old_main_remote_location->get_file_reference() != new_full_remote_location->get_file_reference() || + old_main_remote_location->get_access_hash() != new_full_remote_location->get_access_hash()) { FileId file_id = td->file_manager_->register_remote( FullRemoteFileLocation(PhotoSizeSource::thumbnail(new_file_view.get_type(), 'i'), - new_file_view.remote_location().get_id(), - new_file_view.remote_location().get_access_hash(), DcId::invalid(), - new_file_view.remote_location().get_file_reference().str()), + new_full_remote_location->get_id(), new_full_remote_location->get_access_hash(), + DcId::invalid(), new_full_remote_location->get_file_reference().str()), FileLocationSource::FromServer, dialog_id, old_photo->photos.back().size, 0, ""); LOG_STATUS(td->file_manager_->merge(file_id, old_file_id)); } @@ -574,7 +576,7 @@ bool photo_has_input_media(FileManager *file_manager, const Photo &photo, bool i auto file_id = photo.photos.back().file_id; auto file_view = file_manager->get_file_view(file_id); if (is_secret) { - if (!file_view.is_encrypted_secret() || !file_view.has_remote_location()) { + if (!file_view.is_encrypted_secret() || !file_view.has_full_remote_location()) { return false; } @@ -589,10 +591,10 @@ bool photo_has_input_media(FileManager *file_manager, const Photo &photo, bool i if (file_view.is_encrypted()) { return false; } - if (is_bot && file_view.has_remote_location()) { + if (is_bot && file_view.has_full_remote_location()) { return true; } - return /* file_view.has_remote_location() || */ file_view.has_url(); + return /* file_view.has_full_remote_location() || */ file_view.has_url(); } } @@ -605,7 +607,8 @@ tl_object_ptr photo_get_input_media(FileManager *file_ if (file_view.is_encrypted()) { return nullptr; } - if (file_view.has_remote_location() && !file_view.main_remote_location().is_web() && input_file == nullptr) { + const auto *main_remote_location = file_view.get_main_remote_location(); + if (main_remote_location != nullptr && !main_remote_location->is_web() && input_file == nullptr) { int32 flags = 0; if (ttl != 0) { flags |= telegram_api::inputMediaPhoto::TTL_SECONDS_MASK; @@ -614,9 +617,10 @@ tl_object_ptr photo_get_input_media(FileManager *file_ flags |= telegram_api::inputMediaPhoto::SPOILER_MASK; } return make_tl_object(flags, false /*ignored*/, - file_view.main_remote_location().as_input_photo(), ttl); + main_remote_location->as_input_photo(), ttl); } - if (file_view.has_url()) { + const auto *url = file_view.get_url(); + if (url != nullptr) { int32 flags = 0; if (ttl != 0) { flags |= telegram_api::inputMediaPhotoExternal::TTL_SECONDS_MASK; @@ -624,11 +628,11 @@ tl_object_ptr photo_get_input_media(FileManager *file_ if (has_spoiler) { flags |= telegram_api::inputMediaPhotoExternal::SPOILER_MASK; } - LOG(INFO) << "Create inputMediaPhotoExternal with a URL " << file_view.url() << " and self-destruct time " << ttl; - return make_tl_object(flags, false /*ignored*/, file_view.url(), ttl); + LOG(INFO) << "Create inputMediaPhotoExternal with a URL " << *url << " and self-destruct time " << ttl; + return make_tl_object(flags, false /*ignored*/, *url, ttl); } if (input_file == nullptr) { - CHECK(!file_view.has_remote_location()); + CHECK(main_remote_location == nullptr); } } if (input_file != nullptr) { @@ -684,9 +688,10 @@ SecretInputMedia photo_get_secret_input_media(FileManager *file_manager, const P if (!file_view.is_encrypted_secret() || encryption_key.empty()) { return {}; } - if (file_view.has_remote_location()) { + const auto *main_remote_location = file_view.get_main_remote_location(); + if (main_remote_location != nullptr) { LOG(INFO) << "Photo has remote location"; - input_file = file_view.main_remote_location().as_input_encrypted_file(); + input_file = main_remote_location->as_input_encrypted_file(); } if (input_file == nullptr) { return {}; diff --git a/lib/tgchat/ext/td/td/telegram/PhotoSize.cpp b/lib/tgchat/ext/td/td/telegram/PhotoSize.cpp index e9d5531d..483d9731 100644 --- a/lib/tgchat/ext/td/td/telegram/PhotoSize.cpp +++ b/lib/tgchat/ext/td/td/telegram/PhotoSize.cpp @@ -437,8 +437,9 @@ Result get_input_photo_size(FileManager *file_manager, FileId file_id } int32 type = 'i'; - if (file_view.has_remote_location() && !file_view.remote_location().is_web()) { - auto photo_size_source = file_view.remote_location().get_source(); + const auto *full_remote_location = file_view.get_full_remote_location(); + if (full_remote_location != nullptr && !full_remote_location->is_web()) { + auto photo_size_source = full_remote_location->get_source(); if (photo_size_source.get_type("get_input_photo_size") == PhotoSizeSource::Type::Thumbnail) { auto old_type = photo_size_source.thumbnail().thumbnail_type; if (old_type != 't') { @@ -470,7 +471,7 @@ PhotoSize get_input_thumbnail_photo_size(FileManager *file_manager, const td_api CHECK(thumbnail.file_id.is_valid()); FileView thumbnail_file_view = file_manager->get_file_view(thumbnail.file_id); - if (thumbnail_file_view.has_remote_location()) { + if (thumbnail_file_view.has_full_remote_location()) { // TODO file_manager->delete_remote_location(thumbnail.file_id); } } diff --git a/lib/tgchat/ext/td/td/telegram/Premium.cpp b/lib/tgchat/ext/td/td/telegram/Premium.cpp index 84428f4c..f6589cd5 100644 --- a/lib/tgchat/ext/td/td/telegram/Premium.cpp +++ b/lib/tgchat/ext/td/td/telegram/Premium.cpp @@ -24,6 +24,7 @@ #include "td/telegram/misc.h" #include "td/telegram/PremiumGiftOption.h" #include "td/telegram/ServerMessageId.h" +#include "td/telegram/StarManager.h" #include "td/telegram/SuggestedAction.h" #include "td/telegram/Td.h" #include "td/telegram/telegram_api.h" @@ -245,6 +246,21 @@ static Result> get_input_s TRY_RESULT(parameters, GiveawayParameters::get_giveaway_parameters(td, p->parameters_.get())); return parameters.get_input_store_payment_premium_giveaway(td, p->currency_, p->amount_); } + case td_api::storePaymentPurposeStarGiveaway::ID: { + auto p = static_cast(purpose.get()); + if (p->amount_ <= 0 || !check_currency_amount(p->amount_)) { + return Status::Error(400, "Invalid amount of the currency specified"); + } + if (!clean_input_string(p->currency_)) { + return Status::Error(400, "Strings must be encoded in UTF-8"); + } + if (p->winner_count_ <= 0 || p->star_count_ <= 0) { + return Status::Error(400, "Invalid giveaway parameters specified"); + } + TRY_RESULT(parameters, GiveawayParameters::get_giveaway_parameters(td, p->parameters_.get())); + return parameters.get_input_store_payment_stars_giveaway(td, p->currency_, p->amount_, p->winner_count_, + p->star_count_); + } case td_api::storePaymentPurposeStars::ID: { auto p = static_cast(purpose.get()); if (p->amount_ <= 0 || !check_currency_amount(p->amount_)) { @@ -510,12 +526,18 @@ class LaunchPrepaidGiveawayQuery final : public Td::ResultHandler { explicit LaunchPrepaidGiveawayQuery(Promise &&promise) : promise_(std::move(promise)) { } - void send(int64 giveaway_id, const GiveawayParameters ¶meters) { + void send(int64 giveaway_id, const GiveawayParameters ¶meters, int32 user_count, int64 star_count) { auto dialog_id = parameters.get_boosted_dialog_id(); auto input_peer = td_->dialog_manager_->get_input_peer(dialog_id, AccessRights::Write); CHECK(input_peer != nullptr); - send_query(G()->net_query_creator().create(telegram_api::payments_launchPrepaidGiveaway( - std::move(input_peer), giveaway_id, parameters.get_input_store_payment_premium_giveaway(td_, string(), 0)))); + telegram_api::object_ptr purpose; + if (star_count == 0) { + purpose = parameters.get_input_store_payment_premium_giveaway(td_, string(), 0); + } else { + purpose = parameters.get_input_store_payment_stars_giveaway(td_, string(), 12345, user_count, star_count); + } + send_query(G()->net_query_creator().create( + telegram_api::payments_launchPrepaidGiveaway(std::move(input_peer), giveaway_id, std::move(purpose)))); } void on_result(BufferSlice packet) final { @@ -535,11 +557,11 @@ class LaunchPrepaidGiveawayQuery final : public Td::ResultHandler { }; class GetGiveawayInfoQuery final : public Td::ResultHandler { - Promise> promise_; + Promise> promise_; DialogId dialog_id_; public: - explicit GetGiveawayInfoQuery(Promise> &&promise) + explicit GetGiveawayInfoQuery(Promise> &&promise) : promise_(std::move(promise)) { } @@ -564,10 +586,9 @@ class GetGiveawayInfoQuery final : public Td::ResultHandler { switch (ptr->get_id()) { case telegram_api::payments_giveawayInfo::ID: { auto info = telegram_api::move_object_as(ptr); - auto status = [&]() -> td_api::object_ptr { + auto status = [&]() -> td_api::object_ptr { if (info->joined_too_early_date_ > 0) { - return td_api::make_object( - info->joined_too_early_date_); + return td_api::make_object(info->joined_too_early_date_); } if (info->admin_disallowed_chat_id_ > 0) { ChannelId channel_id(info->admin_disallowed_chat_id_); @@ -576,20 +597,19 @@ class GetGiveawayInfoQuery final : public Td::ResultHandler { } else { DialogId dialog_id(channel_id); td_->dialog_manager_->force_create_dialog(dialog_id, "GetGiveawayInfoQuery"); - return td_api::make_object( - td_->dialog_manager_->get_chat_id_object(dialog_id, "premiumGiveawayParticipantStatusAdministrator")); + return td_api::make_object( + td_->dialog_manager_->get_chat_id_object(dialog_id, "giveawayParticipantStatusAdministrator")); } } if (!info->disallowed_country_.empty()) { - return td_api::make_object( - info->disallowed_country_); + return td_api::make_object(info->disallowed_country_); } if (info->participating_) { - return td_api::make_object(); + return td_api::make_object(); } - return td_api::make_object(); + return td_api::make_object(); }(); - promise_.set_value(td_api::make_object( + promise_.set_value(td_api::make_object( max(0, info->start_date_), std::move(status), info->preparing_results_)); break; } @@ -609,9 +629,9 @@ class GetGiveawayInfoQuery final : public Td::ResultHandler { activated_count = winner_count; } } - promise_.set_value(td_api::make_object( - max(0, info->start_date_), max(0, info->finish_date_), info->refunded_, winner_count, activated_count, - info->gift_code_slug_)); + promise_.set_value(td_api::make_object( + max(0, info->start_date_), max(0, info->finish_date_), info->refunded_, info->winner_, winner_count, + activated_count, info->gift_code_slug_, StarManager::get_star_count(info->stars_prize_))); break; } default: @@ -1166,14 +1186,15 @@ void apply_premium_gift_code(Td *td, const string &code, Promise &&promise } void launch_prepaid_premium_giveaway(Td *td, int64 giveaway_id, - td_api::object_ptr &¶meters, - Promise &&promise) { + td_api::object_ptr &¶meters, int32 user_count, + int64 star_count, Promise &&promise) { TRY_RESULT_PROMISE(promise, giveaway_parameters, GiveawayParameters::get_giveaway_parameters(td, parameters.get())); - td->create_handler(std::move(promise))->send(giveaway_id, giveaway_parameters); + td->create_handler(std::move(promise)) + ->send(giveaway_id, giveaway_parameters, user_count, star_count); } void get_premium_giveaway_info(Td *td, MessageFullId message_full_id, - Promise> &&promise) { + Promise> &&promise) { TRY_RESULT_PROMISE(promise, server_message_id, td->messages_manager_->get_giveaway_message_id(message_full_id)); td->create_handler(std::move(promise)) ->send(message_full_id.get_dialog_id(), server_message_id); diff --git a/lib/tgchat/ext/td/td/telegram/Premium.h b/lib/tgchat/ext/td/td/telegram/Premium.h index e3659b73..d8b5f1e3 100644 --- a/lib/tgchat/ext/td/td/telegram/Premium.h +++ b/lib/tgchat/ext/td/td/telegram/Premium.h @@ -48,11 +48,11 @@ void check_premium_gift_code(Td *td, const string &code, void apply_premium_gift_code(Td *td, const string &code, Promise &&promise); void launch_prepaid_premium_giveaway(Td *td, int64 giveaway_id, - td_api::object_ptr &¶meters, - Promise &&promise); + td_api::object_ptr &¶meters, int32 user_count, + int64 star_count, Promise &&promise); void get_premium_giveaway_info(Td *td, MessageFullId message_full_id, - Promise> &&promise); + Promise> &&promise); void can_purchase_premium(Td *td, td_api::object_ptr &&purpose, Promise &&promise); diff --git a/lib/tgchat/ext/td/td/telegram/QuickReplyManager.cpp b/lib/tgchat/ext/td/td/telegram/QuickReplyManager.cpp index c7ee15b0..304400e0 100644 --- a/lib/tgchat/ext/td/td/telegram/QuickReplyManager.cpp +++ b/lib/tgchat/ext/td/td/telegram/QuickReplyManager.cpp @@ -1035,6 +1035,10 @@ unique_ptr QuickReplyManager::create_messa LOG(ERROR) << "Receive invalid quick reply " << shortcut_id << " from " << source; break; } + if (!message_id.is_valid() || !message_id.is_server()) { + LOG(ERROR) << "Receive invalid " << message_id << " in quick reply " << shortcut_id << " from " << source; + break; + } if (deleted_message_full_ids_.count({shortcut_id, message_id})) { // a previously deleted message break; @@ -1186,11 +1190,12 @@ td_api::object_ptr QuickReplyManager::get_message_s td_api::object_ptr QuickReplyManager::get_quick_reply_message_message_content_object( const QuickReplyMessage *m) const { if (m->edited_content != nullptr) { - return get_message_content_object(m->edited_content.get(), td_, DialogId(), false, 0, false, true, -1, + return get_message_content_object(m->edited_content.get(), td_, DialogId(), false, false, 0, false, true, -1, m->edited_invert_media, m->edited_disable_web_page_preview); } - return get_message_content_object(m->content.get(), td_, DialogId(), false, 0, false, true, -1, m->invert_media, - m->disable_web_page_preview); + return get_message_content_object(m->content.get(), td_, DialogId(), + m->message_id.is_valid() && m->message_id.is_server(), false, 0, false, true, -1, + m->invert_media, m->disable_web_page_preview); } td_api::object_ptr QuickReplyManager::get_quick_reply_message_object( diff --git a/lib/tgchat/ext/td/td/telegram/RepliedMessageInfo.cpp b/lib/tgchat/ext/td/td/telegram/RepliedMessageInfo.cpp index 021277c3..a1a3488f 100644 --- a/lib/tgchat/ext/td/td/telegram/RepliedMessageInfo.cpp +++ b/lib/tgchat/ext/td/td/telegram/RepliedMessageInfo.cpp @@ -272,7 +272,7 @@ void RepliedMessageInfo::add_dependencies(Dependencies &dependencies, bool is_bo } td_api::object_ptr RepliedMessageInfo::get_message_reply_to_message_object( - Td *td, DialogId dialog_id) const { + Td *td, DialogId dialog_id, bool is_server) const { if (dialog_id_.is_valid()) { dialog_id = dialog_id_; } else { @@ -291,7 +291,8 @@ td_api::object_ptr RepliedMessageInfo::get_messag td_api::object_ptr content; if (content_ != nullptr) { - content = get_message_content_object(content_.get(), td, dialog_id, false, 0, false, true, -1, false, false); + content = + get_message_content_object(content_.get(), td, dialog_id, is_server, false, 0, false, true, -1, false, false); switch (content->get_id()) { case td_api::messageUnsupported::ID: content = nullptr; diff --git a/lib/tgchat/ext/td/td/telegram/RepliedMessageInfo.h b/lib/tgchat/ext/td/td/telegram/RepliedMessageInfo.h index 6bbf117e..fdeae7bf 100644 --- a/lib/tgchat/ext/td/td/telegram/RepliedMessageInfo.h +++ b/lib/tgchat/ext/td/td/telegram/RepliedMessageInfo.h @@ -87,8 +87,8 @@ class RepliedMessageInfo { void add_dependencies(Dependencies &dependencies, bool is_bot) const; - td_api::object_ptr get_message_reply_to_message_object(Td *td, - DialogId dialog_id) const; + td_api::object_ptr get_message_reply_to_message_object(Td *td, DialogId dialog_id, + bool is_server) const; MessageInputReplyTo get_input_reply_to() const; diff --git a/lib/tgchat/ext/td/td/telegram/RequestedDialogType.h b/lib/tgchat/ext/td/td/telegram/RequestedDialogType.h index aba0e3b7..721dc9c0 100644 --- a/lib/tgchat/ext/td/td/telegram/RequestedDialogType.h +++ b/lib/tgchat/ext/td/td/telegram/RequestedDialogType.h @@ -52,8 +52,8 @@ class RequestedDialogType { explicit RequestedDialogType(td_api::object_ptr &&request_dialog); - explicit RequestedDialogType(telegram_api::object_ptr &&peer_type, int32 button_id, - int32 max_quantity); + RequestedDialogType(telegram_api::object_ptr &&peer_type, int32 button_id, + int32 max_quantity); td_api::object_ptr get_keyboard_button_type_object() const; diff --git a/lib/tgchat/ext/td/td/telegram/Requests.cpp b/lib/tgchat/ext/td/td/telegram/Requests.cpp new file mode 100644 index 00000000..6d77bb0c --- /dev/null +++ b/lib/tgchat/ext/td/td/telegram/Requests.cpp @@ -0,0 +1,7854 @@ +// +// Copyright Aliaksei Levin (levlam@telegram.org), Arseny Smirnov (arseny30@gmail.com) 2014-2024 +// +// 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/Requests.h" + +#include "td/telegram/AccentColorId.h" +#include "td/telegram/AccountManager.h" +#include "td/telegram/AlarmManager.h" +#include "td/telegram/AnimationsManager.h" +#include "td/telegram/Application.h" +#include "td/telegram/AttachMenuManager.h" +#include "td/telegram/AudiosManager.h" +#include "td/telegram/AuthManager.h" +#include "td/telegram/AutoDownloadSettings.h" +#include "td/telegram/AutosaveManager.h" +#include "td/telegram/BackgroundId.h" +#include "td/telegram/BackgroundManager.h" +#include "td/telegram/BackgroundType.h" +#include "td/telegram/Birthdate.h" +#include "td/telegram/BoostManager.h" +#include "td/telegram/BotCommand.h" +#include "td/telegram/BotInfoManager.h" +#include "td/telegram/BotMenuButton.h" +#include "td/telegram/BotQueries.h" +#include "td/telegram/BusinessAwayMessage.h" +#include "td/telegram/BusinessConnectionId.h" +#include "td/telegram/BusinessConnectionManager.h" +#include "td/telegram/BusinessGreetingMessage.h" +#include "td/telegram/BusinessIntro.h" +#include "td/telegram/BusinessManager.h" +#include "td/telegram/BusinessWorkHours.h" +#include "td/telegram/CallbackQueriesManager.h" +#include "td/telegram/CallId.h" +#include "td/telegram/CallManager.h" +#include "td/telegram/ChannelId.h" +#include "td/telegram/ChannelRecommendationManager.h" +#include "td/telegram/ChannelType.h" +#include "td/telegram/ChatId.h" +#include "td/telegram/ChatManager.h" +#include "td/telegram/CommonDialogManager.h" +#include "td/telegram/ConfigManager.h" +#include "td/telegram/ConnectionStateManager.h" +#include "td/telegram/CountryInfoManager.h" +#include "td/telegram/CustomEmojiId.h" +#include "td/telegram/DeviceTokenManager.h" +#include "td/telegram/DialogAction.h" +#include "td/telegram/DialogActionManager.h" +#include "td/telegram/DialogBoostLinkInfo.h" +#include "td/telegram/DialogEventLog.h" +#include "td/telegram/DialogFilterId.h" +#include "td/telegram/DialogFilterManager.h" +#include "td/telegram/DialogId.h" +#include "td/telegram/DialogInviteLinkManager.h" +#include "td/telegram/DialogListId.h" +#include "td/telegram/DialogLocation.h" +#include "td/telegram/DialogManager.h" +#include "td/telegram/DialogParticipant.h" +#include "td/telegram/DialogParticipantFilter.h" +#include "td/telegram/DialogParticipantManager.h" +#include "td/telegram/DownloadManager.h" +#include "td/telegram/DownloadManagerCallback.h" +#include "td/telegram/EmailVerification.h" +#include "td/telegram/EmojiGroupType.h" +#include "td/telegram/EmojiStatus.h" +#include "td/telegram/files/FileGcParameters.h" +#include "td/telegram/files/FileId.h" +#include "td/telegram/files/FileManager.h" +#include "td/telegram/files/FileSourceId.h" +#include "td/telegram/files/FileStats.h" +#include "td/telegram/files/FileType.h" +#include "td/telegram/ForumTopicManager.h" +#include "td/telegram/GameManager.h" +#include "td/telegram/Global.h" +#include "td/telegram/GlobalPrivacySettings.h" +#include "td/telegram/GroupCallId.h" +#include "td/telegram/GroupCallManager.h" +#include "td/telegram/HashtagHints.h" +#include "td/telegram/InlineMessageManager.h" +#include "td/telegram/InlineQueriesManager.h" +#include "td/telegram/JsonValue.h" +#include "td/telegram/LanguagePackManager.h" +#include "td/telegram/LinkManager.h" +#include "td/telegram/Location.h" +#include "td/telegram/MessageCopyOptions.h" +#include "td/telegram/MessageEffectId.h" +#include "td/telegram/MessageEntity.h" +#include "td/telegram/MessageFullId.h" +#include "td/telegram/MessageId.h" +#include "td/telegram/MessageImportManager.h" +#include "td/telegram/MessageLinkInfo.h" +#include "td/telegram/MessageReaction.h" +#include "td/telegram/MessageSearchFilter.h" +#include "td/telegram/MessageSender.h" +#include "td/telegram/MessagesManager.h" +#include "td/telegram/MessageSource.h" +#include "td/telegram/MessageThreadInfo.h" +#include "td/telegram/MessageTtl.h" +#include "td/telegram/misc.h" +#include "td/telegram/net/ConnectionCreator.h" +#include "td/telegram/net/NetQueryDispatcher.h" +#include "td/telegram/net/NetStatsManager.h" +#include "td/telegram/net/NetType.h" +#include "td/telegram/net/Proxy.h" +#include "td/telegram/NotificationGroupId.h" +#include "td/telegram/NotificationId.h" +#include "td/telegram/NotificationManager.h" +#include "td/telegram/NotificationObjectId.h" +#include "td/telegram/NotificationSettingsManager.h" +#include "td/telegram/NotificationSettingsScope.h" +#include "td/telegram/OptionManager.h" +#include "td/telegram/PasswordManager.h" +#include "td/telegram/Payments.h" +#include "td/telegram/PeopleNearbyManager.h" +#include "td/telegram/PhoneNumberManager.h" +#include "td/telegram/Premium.h" +#include "td/telegram/PrivacyManager.h" +#include "td/telegram/PublicDialogType.h" +#include "td/telegram/QuickReplyManager.h" +#include "td/telegram/ReactionManager.h" +#include "td/telegram/ReactionNotificationSettings.h" +#include "td/telegram/ReactionType.h" +#include "td/telegram/ReportReason.h" +#include "td/telegram/RequestActor.h" +#include "td/telegram/SavedMessagesManager.h" +#include "td/telegram/SavedMessagesTopicId.h" +#include "td/telegram/ScopeNotificationSettings.h" +#include "td/telegram/SecretChatId.h" +#include "td/telegram/SecretChatsManager.h" +#include "td/telegram/SecureManager.h" +#include "td/telegram/SecureValue.h" +#include "td/telegram/SentEmailCode.h" +#include "td/telegram/SponsoredMessageManager.h" +#include "td/telegram/StarManager.h" +#include "td/telegram/StarSubscriptionPricing.h" +#include "td/telegram/StateManager.h" +#include "td/telegram/StatisticsManager.h" +#include "td/telegram/StickerFormat.h" +#include "td/telegram/StickerListType.h" +#include "td/telegram/StickerSetId.h" +#include "td/telegram/StickersManager.h" +#include "td/telegram/StickerType.h" +#include "td/telegram/StorageManager.h" +#include "td/telegram/StoryId.h" +#include "td/telegram/StoryListId.h" +#include "td/telegram/StoryManager.h" +#include "td/telegram/SuggestedAction.h" +#include "td/telegram/Support.h" +#include "td/telegram/SynchronousRequests.h" +#include "td/telegram/td_api.hpp" +#include "td/telegram/TdDb.h" +#include "td/telegram/TermsOfServiceManager.h" +#include "td/telegram/TimeZoneManager.h" +#include "td/telegram/TopDialogCategory.h" +#include "td/telegram/TopDialogManager.h" +#include "td/telegram/TranscriptionManager.h" +#include "td/telegram/TranslationManager.h" +#include "td/telegram/UpdatesManager.h" +#include "td/telegram/UserId.h" +#include "td/telegram/UserManager.h" +#include "td/telegram/WebPageId.h" +#include "td/telegram/WebPagesManager.h" + +#include "td/utils/algorithm.h" +#include "td/utils/Slice.h" +#include "td/utils/Status.h" + +#include +#include +#include +#include + +namespace td { + +class GetMeRequest final : public RequestActor<> { + UserId user_id_; + + void do_run(Promise &&promise) final { + user_id_ = td_->user_manager_->get_me(std::move(promise)); + } + + void do_send_result() final { + send_result(td_->user_manager_->get_user_object(user_id_)); + } + + public: + GetMeRequest(ActorShared td, uint64 request_id) : RequestActor(std::move(td), request_id) { + } +}; + +class GetUserRequest final : public RequestActor<> { + UserId user_id_; + + void do_run(Promise &&promise) final { + td_->user_manager_->get_user(user_id_, get_tries(), std::move(promise)); + } + + void do_send_result() final { + send_result(td_->user_manager_->get_user_object(user_id_)); + } + + public: + GetUserRequest(ActorShared td, uint64 request_id, int64 user_id) + : RequestActor(std::move(td), request_id), user_id_(user_id) { + set_tries(3); + } +}; + +class GetUserFullInfoRequest final : public RequestActor<> { + UserId user_id_; + + void do_run(Promise &&promise) final { + td_->user_manager_->load_user_full(user_id_, get_tries() < 2, std::move(promise), "GetUserFullInfoRequest"); + } + + void do_send_result() final { + send_result(td_->user_manager_->get_user_full_info_object(user_id_)); + } + + public: + GetUserFullInfoRequest(ActorShared td, uint64 request_id, int64 user_id) + : RequestActor(std::move(td), request_id), user_id_(user_id) { + } +}; + +class GetGroupRequest final : public RequestActor<> { + ChatId chat_id_; + + void do_run(Promise &&promise) final { + td_->chat_manager_->get_chat(chat_id_, get_tries(), std::move(promise)); + } + + void do_send_result() final { + send_result(td_->chat_manager_->get_basic_group_object(chat_id_)); + } + + public: + GetGroupRequest(ActorShared td, uint64 request_id, int64 chat_id) + : RequestActor(std::move(td), request_id), chat_id_(chat_id) { + set_tries(3); + } +}; + +class GetGroupFullInfoRequest final : public RequestActor<> { + ChatId chat_id_; + + void do_run(Promise &&promise) final { + td_->chat_manager_->load_chat_full(chat_id_, get_tries() < 2, std::move(promise), "getBasicGroupFullInfo"); + } + + void do_send_result() final { + send_result(td_->chat_manager_->get_basic_group_full_info_object(chat_id_)); + } + + public: + GetGroupFullInfoRequest(ActorShared td, uint64 request_id, int64 chat_id) + : RequestActor(std::move(td), request_id), chat_id_(chat_id) { + } +}; + +class GetSupergroupRequest final : public RequestActor<> { + ChannelId channel_id_; + + void do_run(Promise &&promise) final { + td_->chat_manager_->get_channel(channel_id_, get_tries(), std::move(promise)); + } + + void do_send_result() final { + send_result(td_->chat_manager_->get_supergroup_object(channel_id_)); + } + + public: + GetSupergroupRequest(ActorShared td, uint64 request_id, int64 channel_id) + : RequestActor(std::move(td), request_id), channel_id_(channel_id) { + set_tries(3); + } +}; + +class GetSupergroupFullInfoRequest final : public RequestActor<> { + ChannelId channel_id_; + + void do_run(Promise &&promise) final { + td_->chat_manager_->load_channel_full(channel_id_, get_tries() < 2, std::move(promise), + "GetSupergroupFullInfoRequest"); + } + + void do_send_result() final { + send_result(td_->chat_manager_->get_supergroup_full_info_object(channel_id_)); + } + + public: + GetSupergroupFullInfoRequest(ActorShared td, uint64 request_id, int64 channel_id) + : RequestActor(std::move(td), request_id), channel_id_(channel_id) { + } +}; + +class GetSecretChatRequest final : public RequestActor<> { + SecretChatId secret_chat_id_; + + void do_run(Promise &&promise) final { + td_->user_manager_->get_secret_chat(secret_chat_id_, get_tries() < 2, std::move(promise)); + } + + void do_send_result() final { + send_result(td_->user_manager_->get_secret_chat_object(secret_chat_id_)); + } + + public: + GetSecretChatRequest(ActorShared td, uint64 request_id, int32 secret_chat_id) + : RequestActor(std::move(td), request_id), secret_chat_id_(secret_chat_id) { + } +}; + +class GetChatRequest final : public RequestActor<> { + DialogId dialog_id_; + + bool dialog_found_ = false; + + void do_run(Promise &&promise) final { + dialog_found_ = td_->messages_manager_->load_dialog(dialog_id_, get_tries(), std::move(promise)); + } + + void do_send_result() final { + if (!dialog_found_) { + send_error(Status::Error(400, "Chat is not accessible")); + } else { + send_result(td_->messages_manager_->get_chat_object(dialog_id_, "GetChatRequest")); + } + } + + public: + GetChatRequest(ActorShared td, uint64 request_id, int64 dialog_id) + : RequestActor(std::move(td), request_id), dialog_id_(dialog_id) { + set_tries(3); + } +}; + +class SearchUserByPhoneNumberRequest final : public RequestActor<> { + string phone_number_; + bool only_local_; + + UserId user_id_; + + void do_run(Promise &&promise) final { + user_id_ = td_->user_manager_->search_user_by_phone_number(phone_number_, only_local_, std::move(promise)); + } + + void do_send_result() final { + send_result(td_->user_manager_->get_user_object(user_id_)); + } + + public: + SearchUserByPhoneNumberRequest(ActorShared td, uint64 request_id, string &&phone_number, bool only_local) + : RequestActor(std::move(td), request_id), phone_number_(std::move(phone_number)), only_local_(only_local) { + } +}; + +class LoadChatsRequest final : public RequestActor<> { + DialogListId dialog_list_id_; + DialogDate offset_; + int32 limit_; + + void do_run(Promise &&promise) final { + td_->messages_manager_->get_dialogs(dialog_list_id_, offset_, limit_, false, get_tries() < 2, std::move(promise)); + } + + public: + LoadChatsRequest(ActorShared td, uint64 request_id, DialogListId dialog_list_id, DialogDate offset, int32 limit) + : RequestActor(std::move(td), request_id), dialog_list_id_(dialog_list_id), offset_(offset), limit_(limit) { + // 1 for database + 1 for server request + 1 for server request at the end + 1 for return + 1 just in case + set_tries(5); + + if (limit_ > 100) { + limit_ = 100; + } + } +}; + +class SearchPublicChatRequest final : public RequestActor<> { + string username_; + + DialogId dialog_id_; + + void do_run(Promise &&promise) final { + dialog_id_ = td_->dialog_manager_->search_public_dialog(username_, get_tries() < 3, std::move(promise)); + } + + void do_send_result() final { + send_result(td_->messages_manager_->get_chat_object(dialog_id_, "SearchPublicChatRequest")); + } + + public: + SearchPublicChatRequest(ActorShared td, uint64 request_id, string username) + : RequestActor(std::move(td), request_id), username_(std::move(username)) { + set_tries(4); // 1 for server request + 1 for reload voice chat + 1 for reload dialog + 1 for result + } +}; + +class SearchPublicChatsRequest final : public RequestActor<> { + string query_; + + vector dialog_ids_; + + void do_run(Promise &&promise) final { + dialog_ids_ = td_->messages_manager_->search_public_dialogs(query_, std::move(promise)); + } + + void do_send_result() final { + send_result(td_->dialog_manager_->get_chats_object(-1, dialog_ids_, "SearchPublicChatsRequest")); + } + + public: + SearchPublicChatsRequest(ActorShared td, uint64 request_id, string query) + : RequestActor(std::move(td), request_id), query_(std::move(query)) { + } +}; + +class SearchChatsRequest final : public RequestActor<> { + string query_; + int32 limit_; + + std::pair> dialog_ids_; + + void do_run(Promise &&promise) final { + dialog_ids_ = td_->messages_manager_->search_dialogs(query_, limit_, std::move(promise)); + } + + void do_send_result() final { + send_result(td_->dialog_manager_->get_chats_object(dialog_ids_, "SearchChatsRequest")); + } + + public: + SearchChatsRequest(ActorShared td, uint64 request_id, string query, int32 limit) + : RequestActor(std::move(td), request_id), query_(std::move(query)), limit_(limit) { + } +}; + +class SearchChatsOnServerRequest final : public RequestActor<> { + string query_; + int32 limit_; + + vector dialog_ids_; + + void do_run(Promise &&promise) final { + dialog_ids_ = td_->messages_manager_->search_dialogs_on_server(query_, limit_, std::move(promise)); + } + + void do_send_result() final { + send_result(td_->dialog_manager_->get_chats_object(-1, dialog_ids_, "SearchChatsOnServerRequest")); + } + + public: + SearchChatsOnServerRequest(ActorShared td, uint64 request_id, string query, int32 limit) + : RequestActor(std::move(td), request_id), query_(std::move(query)), limit_(limit) { + } +}; + +class GetGroupsInCommonRequest final : public RequestActor<> { + UserId user_id_; + DialogId offset_dialog_id_; + int32 limit_; + + std::pair> dialog_ids_; + + void do_run(Promise &&promise) final { + dialog_ids_ = td_->common_dialog_manager_->get_common_dialogs(user_id_, offset_dialog_id_, limit_, get_tries() < 2, + std::move(promise)); + } + + void do_send_result() final { + send_result(td_->dialog_manager_->get_chats_object(dialog_ids_, "GetGroupsInCommonRequest")); + } + + public: + GetGroupsInCommonRequest(ActorShared td, uint64 request_id, int64 user_id, int64 offset_dialog_id, int32 limit) + : RequestActor(std::move(td), request_id), user_id_(user_id), offset_dialog_id_(offset_dialog_id), limit_(limit) { + } +}; + +class GetSuitableDiscussionChatsRequest final : public RequestActor<> { + vector dialog_ids_; + + void do_run(Promise &&promise) final { + dialog_ids_ = td_->chat_manager_->get_dialogs_for_discussion(std::move(promise)); + } + + void do_send_result() final { + send_result(td_->dialog_manager_->get_chats_object(-1, dialog_ids_, "GetSuitableDiscussionChatsRequest")); + } + + public: + GetSuitableDiscussionChatsRequest(ActorShared td, uint64 request_id) : RequestActor(std::move(td), request_id) { + } +}; + +class GetInactiveSupergroupChatsRequest final : public RequestActor<> { + vector dialog_ids_; + + void do_run(Promise &&promise) final { + dialog_ids_ = td_->chat_manager_->get_inactive_channels(std::move(promise)); + } + + void do_send_result() final { + send_result(td_->dialog_manager_->get_chats_object(-1, dialog_ids_, "GetInactiveSupergroupChatsRequest")); + } + + public: + GetInactiveSupergroupChatsRequest(ActorShared td, uint64 request_id) : RequestActor(std::move(td), request_id) { + } +}; + +class SearchRecentlyFoundChatsRequest final : public RequestActor<> { + string query_; + int32 limit_; + + std::pair> dialog_ids_; + + void do_run(Promise &&promise) final { + dialog_ids_ = td_->messages_manager_->search_recently_found_dialogs(query_, limit_, std::move(promise)); + } + + void do_send_result() final { + send_result(td_->dialog_manager_->get_chats_object(dialog_ids_, "SearchRecentlyFoundChatsRequest")); + } + + public: + SearchRecentlyFoundChatsRequest(ActorShared td, uint64 request_id, string query, int32 limit) + : RequestActor(std::move(td), request_id), query_(std::move(query)), limit_(limit) { + } +}; + +class GetRecentlyOpenedChatsRequest final : public RequestActor<> { + int32 limit_; + + std::pair> dialog_ids_; + + void do_run(Promise &&promise) final { + dialog_ids_ = td_->messages_manager_->get_recently_opened_dialogs(limit_, std::move(promise)); + } + + void do_send_result() final { + send_result(td_->dialog_manager_->get_chats_object(dialog_ids_, "GetRecentlyOpenedChatsRequest")); + } + + public: + GetRecentlyOpenedChatsRequest(ActorShared td, uint64 request_id, int32 limit) + : RequestActor(std::move(td), request_id), limit_(limit) { + } +}; + +class GetMessageRequest final : public RequestOnceActor { + MessageFullId message_full_id_; + + void do_run(Promise &&promise) final { + td_->messages_manager_->get_message(message_full_id_, std::move(promise)); + } + + void do_send_result() final { + send_result(td_->messages_manager_->get_message_object(message_full_id_, "GetMessageRequest")); + } + + public: + GetMessageRequest(ActorShared td, uint64 request_id, int64 dialog_id, int64 message_id) + : RequestOnceActor(std::move(td), request_id), message_full_id_(DialogId(dialog_id), MessageId(message_id)) { + } +}; + +class GetRepliedMessageRequest final : public RequestOnceActor { + DialogId dialog_id_; + MessageId message_id_; + + MessageFullId replied_message_id_; + + void do_run(Promise &&promise) final { + replied_message_id_ = + td_->messages_manager_->get_replied_message(dialog_id_, message_id_, get_tries() < 3, std::move(promise)); + } + + void do_send_result() final { + send_result(td_->messages_manager_->get_message_object(replied_message_id_, "GetRepliedMessageRequest")); + } + + public: + GetRepliedMessageRequest(ActorShared td, uint64 request_id, int64 dialog_id, int64 message_id) + : RequestOnceActor(std::move(td), request_id), dialog_id_(dialog_id), message_id_(message_id) { + set_tries(3); // 1 to get initial message, 1 to get the reply and 1 for result + } +}; + +class GetMessageThreadRequest final : public RequestActor { + DialogId dialog_id_; + MessageId message_id_; + + MessageThreadInfo message_thread_info_; + + void do_run(Promise &&promise) final { + if (get_tries() < 2) { + promise.set_value(std::move(message_thread_info_)); + return; + } + td_->messages_manager_->get_message_thread(dialog_id_, message_id_, std::move(promise)); + } + + void do_set_result(MessageThreadInfo &&result) final { + message_thread_info_ = std::move(result); + } + + void do_send_result() final { + send_result(td_->messages_manager_->get_message_thread_info_object(message_thread_info_)); + } + + public: + GetMessageThreadRequest(ActorShared td, uint64 request_id, int64 dialog_id, int64 message_id) + : RequestActor(std::move(td), request_id), dialog_id_(dialog_id), message_id_(message_id) { + } +}; + +class GetChatPinnedMessageRequest final : public RequestOnceActor { + DialogId dialog_id_; + + MessageId pinned_message_id_; + + void do_run(Promise &&promise) final { + pinned_message_id_ = td_->messages_manager_->get_dialog_pinned_message(dialog_id_, std::move(promise)); + } + + void do_send_result() final { + send_result( + td_->messages_manager_->get_message_object({dialog_id_, pinned_message_id_}, "GetChatPinnedMessageRequest")); + } + + public: + GetChatPinnedMessageRequest(ActorShared td, uint64 request_id, int64 dialog_id) + : RequestOnceActor(std::move(td), request_id), dialog_id_(dialog_id) { + set_tries(3); // 1 to get pinned_message_id, 1 to get the message and 1 for result + } +}; + +class GetCallbackQueryMessageRequest final : public RequestOnceActor { + DialogId dialog_id_; + MessageId message_id_; + int64 callback_query_id_; + + void do_run(Promise &&promise) final { + td_->messages_manager_->get_callback_query_message(dialog_id_, message_id_, callback_query_id_, std::move(promise)); + } + + void do_send_result() final { + send_result( + td_->messages_manager_->get_message_object({dialog_id_, message_id_}, "GetCallbackQueryMessageRequest")); + } + + public: + GetCallbackQueryMessageRequest(ActorShared td, uint64 request_id, int64 dialog_id, int64 message_id, + int64 callback_query_id) + : RequestOnceActor(std::move(td), request_id) + , dialog_id_(dialog_id) + , message_id_(message_id) + , callback_query_id_(callback_query_id) { + } +}; + +class GetMessagesRequest final : public RequestOnceActor { + DialogId dialog_id_; + vector message_ids_; + + void do_run(Promise &&promise) final { + td_->messages_manager_->get_messages(dialog_id_, message_ids_, std::move(promise)); + } + + void do_send_result() final { + send_result(td_->messages_manager_->get_messages_object(-1, dialog_id_, message_ids_, false, "GetMessagesRequest")); + } + + public: + GetMessagesRequest(ActorShared td, uint64 request_id, int64 dialog_id, const vector &message_ids) + : RequestOnceActor(std::move(td), request_id) + , dialog_id_(dialog_id) + , message_ids_(MessageId::get_message_ids(message_ids)) { + } +}; + +class GetMessageEmbeddingCodeRequest final : public RequestActor<> { + MessageFullId message_full_id_; + bool for_group_; + + string html_; + + void do_run(Promise &&promise) final { + html_ = td_->messages_manager_->get_message_embedding_code(message_full_id_, for_group_, std::move(promise)); + } + + void do_send_result() final { + send_result(td_api::make_object(html_)); + } + + public: + GetMessageEmbeddingCodeRequest(ActorShared td, uint64 request_id, int64 dialog_id, int64 message_id, + bool for_group) + : RequestActor(std::move(td), request_id) + , message_full_id_(DialogId(dialog_id), MessageId(message_id)) + , for_group_(for_group) { + } +}; + +class GetMessageLinkInfoRequest final : public RequestActor { + string url_; + + MessageLinkInfo message_link_info_; + + void do_run(Promise &&promise) final { + if (get_tries() < 2) { + promise.set_value(std::move(message_link_info_)); + return; + } + td_->messages_manager_->get_message_link_info(url_, std::move(promise)); + } + + void do_set_result(MessageLinkInfo &&result) final { + message_link_info_ = std::move(result); + } + + void do_send_result() final { + send_result(td_->messages_manager_->get_message_link_info_object(message_link_info_)); + } + + public: + GetMessageLinkInfoRequest(ActorShared td, uint64 request_id, string url) + : RequestActor(std::move(td), request_id), url_(std::move(url)) { + } +}; + +class GetDialogBoostLinkInfoRequest final : public RequestActor { + string url_; + + DialogBoostLinkInfo dialog_boost_link_info_; + + void do_run(Promise &&promise) final { + if (get_tries() < 2) { + promise.set_value(std::move(dialog_boost_link_info_)); + return; + } + td_->boost_manager_->get_dialog_boost_link_info(url_, std::move(promise)); + } + + void do_set_result(DialogBoostLinkInfo &&result) final { + dialog_boost_link_info_ = std::move(result); + } + + void do_send_result() final { + send_result(td_->boost_manager_->get_chat_boost_link_info_object(dialog_boost_link_info_)); + } + + public: + GetDialogBoostLinkInfoRequest(ActorShared td, uint64 request_id, string url) + : RequestActor(std::move(td), request_id), url_(std::move(url)) { + } +}; + +class EditMessageTextRequest final : public RequestOnceActor { + MessageFullId message_full_id_; + td_api::object_ptr reply_markup_; + td_api::object_ptr input_message_content_; + + void do_run(Promise &&promise) final { + td_->messages_manager_->edit_message_text(message_full_id_, std::move(reply_markup_), + std::move(input_message_content_), std::move(promise)); + } + + void do_send_result() final { + send_result(td_->messages_manager_->get_message_object(message_full_id_, "EditMessageTextRequest")); + } + + public: + EditMessageTextRequest(ActorShared td, uint64 request_id, int64 dialog_id, int64 message_id, + td_api::object_ptr reply_markup, + td_api::object_ptr input_message_content) + : RequestOnceActor(std::move(td), request_id) + , message_full_id_(DialogId(dialog_id), MessageId(message_id)) + , reply_markup_(std::move(reply_markup)) + , input_message_content_(std::move(input_message_content)) { + } +}; + +class EditMessageLiveLocationRequest final : public RequestOnceActor { + MessageFullId message_full_id_; + td_api::object_ptr reply_markup_; + td_api::object_ptr location_; + int32 live_period_; + int32 heading_; + int32 proximity_alert_radius_; + + void do_run(Promise &&promise) final { + td_->messages_manager_->edit_message_live_location(message_full_id_, std::move(reply_markup_), std::move(location_), + live_period_, heading_, proximity_alert_radius_, + std::move(promise)); + } + + void do_send_result() final { + send_result(td_->messages_manager_->get_message_object(message_full_id_, "EditMessageLiveLocationRequest")); + } + + public: + EditMessageLiveLocationRequest(ActorShared td, uint64 request_id, int64 dialog_id, int64 message_id, + td_api::object_ptr reply_markup, + td_api::object_ptr location, int32 live_period, int32 heading, + int32 proximity_alert_radius) + : RequestOnceActor(std::move(td), request_id) + , message_full_id_(DialogId(dialog_id), MessageId(message_id)) + , reply_markup_(std::move(reply_markup)) + , location_(std::move(location)) + , live_period_(live_period) + , heading_(heading) + , proximity_alert_radius_(proximity_alert_radius) { + } +}; + +class EditMessageMediaRequest final : public RequestOnceActor { + MessageFullId message_full_id_; + td_api::object_ptr reply_markup_; + td_api::object_ptr input_message_content_; + + void do_run(Promise &&promise) final { + td_->messages_manager_->edit_message_media(message_full_id_, std::move(reply_markup_), + std::move(input_message_content_), std::move(promise)); + } + + void do_send_result() final { + send_result(td_->messages_manager_->get_message_object(message_full_id_, "EditMessageMediaRequest")); + } + + public: + EditMessageMediaRequest(ActorShared td, uint64 request_id, int64 dialog_id, int64 message_id, + td_api::object_ptr reply_markup, + td_api::object_ptr input_message_content) + : RequestOnceActor(std::move(td), request_id) + , message_full_id_(DialogId(dialog_id), MessageId(message_id)) + , reply_markup_(std::move(reply_markup)) + , input_message_content_(std::move(input_message_content)) { + } +}; + +class EditMessageCaptionRequest final : public RequestOnceActor { + MessageFullId message_full_id_; + td_api::object_ptr reply_markup_; + td_api::object_ptr caption_; + bool invert_media_; + + void do_run(Promise &&promise) final { + td_->messages_manager_->edit_message_caption(message_full_id_, std::move(reply_markup_), std::move(caption_), + invert_media_, std::move(promise)); + } + + void do_send_result() final { + send_result(td_->messages_manager_->get_message_object(message_full_id_, "EditMessageCaptionRequest")); + } + + public: + EditMessageCaptionRequest(ActorShared td, uint64 request_id, int64 dialog_id, int64 message_id, + td_api::object_ptr reply_markup, + td_api::object_ptr caption, bool invert_media) + : RequestOnceActor(std::move(td), request_id) + , message_full_id_(DialogId(dialog_id), MessageId(message_id)) + , reply_markup_(std::move(reply_markup)) + , caption_(std::move(caption)) + , invert_media_(invert_media) { + } +}; + +class EditMessageReplyMarkupRequest final : public RequestOnceActor { + MessageFullId message_full_id_; + td_api::object_ptr reply_markup_; + + void do_run(Promise &&promise) final { + td_->messages_manager_->edit_message_reply_markup(message_full_id_, std::move(reply_markup_), std::move(promise)); + } + + void do_send_result() final { + send_result(td_->messages_manager_->get_message_object(message_full_id_, "EditMessageReplyMarkupRequest")); + } + + public: + EditMessageReplyMarkupRequest(ActorShared td, uint64 request_id, int64 dialog_id, int64 message_id, + td_api::object_ptr reply_markup) + : RequestOnceActor(std::move(td), request_id) + , message_full_id_(DialogId(dialog_id), MessageId(message_id)) + , reply_markup_(std::move(reply_markup)) { + } +}; + +class GetChatHistoryRequest final : public RequestActor<> { + DialogId dialog_id_; + MessageId from_message_id_; + int32 offset_; + int32 limit_; + bool only_local_; + + td_api::object_ptr messages_; + + void do_run(Promise &&promise) final { + messages_ = td_->messages_manager_->get_dialog_history(dialog_id_, from_message_id_, offset_, limit_, + get_tries() - 1, only_local_, std::move(promise)); + } + + void do_send_result() final { + send_result(std::move(messages_)); + } + + public: + GetChatHistoryRequest(ActorShared td, uint64 request_id, int64 dialog_id, int64 from_message_id, int32 offset, + int32 limit, bool only_local) + : RequestActor(std::move(td), request_id) + , dialog_id_(dialog_id) + , from_message_id_(from_message_id) + , offset_(offset) + , limit_(limit) + , only_local_(only_local) { + if (!only_local_) { + set_tries(4); + } + } +}; + +class GetMessageThreadHistoryRequest final : public RequestActor<> { + DialogId dialog_id_; + MessageId message_id_; + MessageId from_message_id_; + int32 offset_; + int32 limit_; + int64 random_id_; + + std::pair> messages_; + + void do_run(Promise &&promise) final { + messages_ = td_->messages_manager_->get_message_thread_history(dialog_id_, message_id_, from_message_id_, offset_, + limit_, random_id_, std::move(promise)); + } + + void do_send_result() final { + send_result(td_->messages_manager_->get_messages_object(-1, messages_.first, messages_.second, true, + "GetMessageThreadHistoryRequest")); + } + + public: + GetMessageThreadHistoryRequest(ActorShared td, uint64 request_id, int64 dialog_id, int64 message_id, + int64 from_message_id, int32 offset, int32 limit) + : RequestActor(std::move(td), request_id) + , dialog_id_(dialog_id) + , message_id_(message_id) + , from_message_id_(from_message_id) + , offset_(offset) + , limit_(limit) + , random_id_(0) { + set_tries(3); + } +}; + +class SearchChatMessagesRequest final : public RequestActor<> { + DialogId dialog_id_; + string query_; + td_api::object_ptr sender_id_; + MessageId from_message_id_; + int32 offset_; + int32 limit_; + MessageSearchFilter filter_; + MessageId top_thread_message_id_; + SavedMessagesTopicId saved_messages_topic_id_; + ReactionType tag_; + int64 random_id_; + + MessagesManager::FoundDialogMessages messages_; + + void do_run(Promise &&promise) final { + messages_ = td_->messages_manager_->search_dialog_messages( + dialog_id_, query_, sender_id_, from_message_id_, offset_, limit_, filter_, top_thread_message_id_, + saved_messages_topic_id_, tag_, random_id_, get_tries() == 3, std::move(promise)); + } + + void do_send_result() final { + send_result( + td_->messages_manager_->get_found_chat_messages_object(dialog_id_, messages_, "SearchChatMessagesRequest")); + } + + void do_send_error(Status &&status) final { + if (status.message() == "SEARCH_QUERY_EMPTY") { + messages_ = {}; + return do_send_result(); + } + send_error(std::move(status)); + } + + public: + SearchChatMessagesRequest(ActorShared td, uint64 request_id, int64 dialog_id, string query, + td_api::object_ptr sender_id, int64 from_message_id, int32 offset, + int32 limit, td_api::object_ptr filter, + int64 message_thread_id, SavedMessagesTopicId saved_messages_topic_id, ReactionType tag) + : RequestActor(std::move(td), request_id) + , dialog_id_(dialog_id) + , query_(std::move(query)) + , sender_id_(std::move(sender_id)) + , from_message_id_(from_message_id) + , offset_(offset) + , limit_(limit) + , filter_(get_message_search_filter(filter)) + , top_thread_message_id_(message_thread_id) + , saved_messages_topic_id_(saved_messages_topic_id) + , tag_(std::move(tag)) + , random_id_(0) { + set_tries(3); + } +}; + +class GetChatScheduledMessagesRequest final : public RequestActor<> { + DialogId dialog_id_; + + vector message_ids_; + + void do_run(Promise &&promise) final { + message_ids_ = + td_->messages_manager_->get_dialog_scheduled_messages(dialog_id_, get_tries() < 2, false, std::move(promise)); + } + + void do_send_result() final { + send_result(td_->messages_manager_->get_messages_object(-1, dialog_id_, message_ids_, true, + "GetChatScheduledMessagesRequest")); + } + + public: + GetChatScheduledMessagesRequest(ActorShared td, uint64 request_id, int64 dialog_id) + : RequestActor(std::move(td), request_id), dialog_id_(dialog_id) { + set_tries(4); + } +}; + +class GetWebPageInstantViewRequest final : public RequestActor { + string url_; + bool force_full_; + + WebPageId web_page_id_; + + void do_run(Promise &&promise) final { + if (get_tries() < 2) { + promise.set_value(std::move(web_page_id_)); + return; + } + td_->web_pages_manager_->get_web_page_instant_view(url_, force_full_, std::move(promise)); + } + + void do_set_result(WebPageId &&result) final { + web_page_id_ = result; + } + + void do_send_result() final { + send_result(td_->web_pages_manager_->get_web_page_instant_view_object(web_page_id_)); + } + + public: + GetWebPageInstantViewRequest(ActorShared td, uint64 request_id, string url, bool force_full) + : RequestActor(std::move(td), request_id), url_(std::move(url)), force_full_(force_full) { + } +}; + +class CreateChatRequest final : public RequestActor<> { + DialogId dialog_id_; + bool force_; + + void do_run(Promise &&promise) final { + td_->messages_manager_->create_dialog(dialog_id_, force_, std::move(promise)); + } + + void do_send_result() final { + send_result(td_->messages_manager_->get_chat_object(dialog_id_, "CreateChatRequest")); + } + + public: + CreateChatRequest(ActorShared td, uint64 request_id, DialogId dialog_id, bool force) + : RequestActor<>(std::move(td), request_id), dialog_id_(dialog_id), force_(force) { + } +}; + +class CheckChatInviteLinkRequest final : public RequestActor<> { + string invite_link_; + + void do_run(Promise &&promise) final { + td_->dialog_invite_link_manager_->check_dialog_invite_link(invite_link_, get_tries() < 2, std::move(promise)); + } + + void do_send_result() final { + auto result = td_->dialog_invite_link_manager_->get_chat_invite_link_info_object(invite_link_); + CHECK(result != nullptr); + send_result(std::move(result)); + } + + public: + CheckChatInviteLinkRequest(ActorShared td, uint64 request_id, string invite_link) + : RequestActor(std::move(td), request_id), invite_link_(std::move(invite_link)) { + } +}; + +class JoinChatByInviteLinkRequest final : public RequestActor { + string invite_link_; + + DialogId dialog_id_; + + void do_run(Promise &&promise) final { + if (get_tries() < 2) { + promise.set_value(std::move(dialog_id_)); + return; + } + td_->dialog_invite_link_manager_->import_dialog_invite_link(invite_link_, std::move(promise)); + } + + void do_set_result(DialogId &&result) final { + dialog_id_ = result; + } + + void do_send_result() final { + CHECK(dialog_id_.is_valid()); + td_->dialog_manager_->force_create_dialog(dialog_id_, "join chat via an invite link"); + send_result(td_->messages_manager_->get_chat_object(dialog_id_, "JoinChatByInviteLinkRequest")); + } + + public: + JoinChatByInviteLinkRequest(ActorShared td, uint64 request_id, string invite_link) + : RequestActor(std::move(td), request_id), invite_link_(std::move(invite_link)) { + } +}; + +class ImportContactsRequest final : public RequestActor<> { + vector contacts_; + int64 random_id_; + + std::pair, vector> imported_contacts_; + + void do_run(Promise &&promise) final { + imported_contacts_ = td_->user_manager_->import_contacts(contacts_, random_id_, std::move(promise)); + } + + void do_send_result() final { + CHECK(imported_contacts_.first.size() == contacts_.size()); + CHECK(imported_contacts_.second.size() == contacts_.size()); + send_result(td_api::make_object(transform(imported_contacts_.first, + [this](UserId user_id) { + return td_->user_manager_->get_user_id_object( + user_id, "ImportContactsRequest"); + }), + std::move(imported_contacts_.second))); + } + + public: + ImportContactsRequest(ActorShared td, uint64 request_id, vector &&contacts) + : RequestActor(std::move(td), request_id), contacts_(std::move(contacts)), random_id_(0) { + set_tries(3); // load_contacts + import_contacts + } +}; + +class SearchContactsRequest final : public RequestActor<> { + string query_; + int32 limit_; + + std::pair> user_ids_; + + void do_run(Promise &&promise) final { + user_ids_ = td_->user_manager_->search_contacts(query_, limit_, std::move(promise)); + } + + void do_send_result() final { + send_result(td_->user_manager_->get_users_object(user_ids_.first, user_ids_.second)); + } + + public: + SearchContactsRequest(ActorShared td, uint64 request_id, string query, int32 limit) + : RequestActor(std::move(td), request_id), query_(std::move(query)), limit_(limit) { + } +}; + +class RemoveContactsRequest final : public RequestActor<> { + vector user_ids_; + + void do_run(Promise &&promise) final { + td_->user_manager_->remove_contacts(user_ids_, std::move(promise)); + } + + public: + RemoveContactsRequest(ActorShared td, uint64 request_id, vector &&user_ids) + : RequestActor(std::move(td), request_id), user_ids_(std::move(user_ids)) { + set_tries(3); // load_contacts + delete_contacts + } +}; + +class GetImportedContactCountRequest final : public RequestActor<> { + int32 imported_contact_count_ = 0; + + void do_run(Promise &&promise) final { + imported_contact_count_ = td_->user_manager_->get_imported_contact_count(std::move(promise)); + } + + void do_send_result() final { + send_result(td_api::make_object(imported_contact_count_)); + } + + public: + GetImportedContactCountRequest(ActorShared td, uint64 request_id) : RequestActor(std::move(td), request_id) { + } +}; + +class ChangeImportedContactsRequest final : public RequestActor<> { + vector contacts_; + size_t contacts_size_; + int64 random_id_; + + std::pair, vector> imported_contacts_; + + void do_run(Promise &&promise) final { + imported_contacts_ = td_->user_manager_->change_imported_contacts(contacts_, random_id_, std::move(promise)); + } + + void do_send_result() final { + CHECK(imported_contacts_.first.size() == contacts_size_); + CHECK(imported_contacts_.second.size() == contacts_size_); + send_result(td_api::make_object(transform(imported_contacts_.first, + [this](UserId user_id) { + return td_->user_manager_->get_user_id_object( + user_id, "ChangeImportedContactsRequest"); + }), + std::move(imported_contacts_.second))); + } + + public: + ChangeImportedContactsRequest(ActorShared td, uint64 request_id, vector &&contacts) + : RequestActor(std::move(td), request_id) + , contacts_(std::move(contacts)) + , contacts_size_(contacts_.size()) + , random_id_(0) { + set_tries(4); // load_contacts + load_local_contacts + (import_contacts + delete_contacts) + } +}; + +class GetCloseFriendsRequest final : public RequestActor<> { + vector user_ids_; + + void do_run(Promise &&promise) final { + user_ids_ = td_->user_manager_->get_close_friends(std::move(promise)); + } + + void do_send_result() final { + send_result(td_->user_manager_->get_users_object(-1, user_ids_)); + } + + public: + GetCloseFriendsRequest(ActorShared td, uint64 request_id) : RequestActor(std::move(td), request_id) { + } +}; + +class GetRecentInlineBotsRequest final : public RequestActor<> { + vector user_ids_; + + void do_run(Promise &&promise) final { + user_ids_ = td_->inline_queries_manager_->get_recent_inline_bots(std::move(promise)); + } + + void do_send_result() final { + send_result(td_->user_manager_->get_users_object(-1, user_ids_)); + } + + public: + GetRecentInlineBotsRequest(ActorShared td, uint64 request_id) : RequestActor(std::move(td), request_id) { + } +}; + +class GetChatNotificationSettingsExceptionsRequest final : public RequestActor<> { + NotificationSettingsScope scope_; + bool filter_scope_; + bool compare_sound_; + + vector dialog_ids_; + + void do_run(Promise &&promise) final { + dialog_ids_ = td_->messages_manager_->get_dialog_notification_settings_exceptions( + scope_, filter_scope_, compare_sound_, get_tries() < 3, std::move(promise)); + } + + void do_send_result() final { + send_result( + td_->dialog_manager_->get_chats_object(-1, dialog_ids_, "GetChatNotificationSettingsExceptionsRequest")); + } + + public: + GetChatNotificationSettingsExceptionsRequest(ActorShared td, uint64 request_id, NotificationSettingsScope scope, + bool filter_scope, bool compare_sound) + : RequestActor(std::move(td), request_id) + , scope_(scope) + , filter_scope_(filter_scope) + , compare_sound_(compare_sound) { + set_tries(3); + } +}; + +class GetScopeNotificationSettingsRequest final : public RequestActor<> { + NotificationSettingsScope scope_; + + const ScopeNotificationSettings *notification_settings_ = nullptr; + + void do_run(Promise &&promise) final { + notification_settings_ = + td_->notification_settings_manager_->get_scope_notification_settings(scope_, std::move(promise)); + } + + void do_send_result() final { + CHECK(notification_settings_ != nullptr); + send_result(get_scope_notification_settings_object(notification_settings_)); + } + + public: + GetScopeNotificationSettingsRequest(ActorShared td, uint64 request_id, NotificationSettingsScope scope) + : RequestActor(std::move(td), request_id), scope_(scope) { + } +}; + +class GetStickersRequest final : public RequestActor<> { + StickerType sticker_type_; + string query_; + int32 limit_; + DialogId dialog_id_; + + vector sticker_ids_; + + void do_run(Promise &&promise) final { + sticker_ids_ = td_->stickers_manager_->get_stickers(sticker_type_, query_, limit_, dialog_id_, get_tries() < 2, + std::move(promise)); + } + + void do_send_result() final { + send_result(td_->stickers_manager_->get_stickers_object(sticker_ids_)); + } + + public: + GetStickersRequest(ActorShared td, uint64 request_id, StickerType sticker_type, string &&query, int32 limit, + int64 dialog_id) + : RequestActor(std::move(td), request_id) + , sticker_type_(sticker_type) + , query_(std::move(query)) + , limit_(limit) + , dialog_id_(dialog_id) { + set_tries(4); + } +}; + +class GetAllStickerEmojisRequest final : public RequestActor<> { + StickerType sticker_type_; + string query_; + DialogId dialog_id_; + bool return_only_main_emoji_; + + vector sticker_ids_; + + void do_run(Promise &&promise) final { + sticker_ids_ = td_->stickers_manager_->get_stickers(sticker_type_, query_, 1000000, dialog_id_, get_tries() < 2, + std::move(promise)); + } + + void do_send_result() final { + send_result(td_->stickers_manager_->get_sticker_emojis_object(sticker_ids_, return_only_main_emoji_)); + } + + public: + GetAllStickerEmojisRequest(ActorShared td, uint64 request_id, StickerType sticker_type, string &&query, + int64 dialog_id, bool return_only_main_emoji) + : RequestActor(std::move(td), request_id) + , sticker_type_(sticker_type) + , query_(std::move(query)) + , dialog_id_(dialog_id) + , return_only_main_emoji_(return_only_main_emoji) { + set_tries(4); + } +}; + +class GetInstalledStickerSetsRequest final : public RequestActor<> { + StickerType sticker_type_; + + vector sticker_set_ids_; + + void do_run(Promise &&promise) final { + sticker_set_ids_ = td_->stickers_manager_->get_installed_sticker_sets(sticker_type_, std::move(promise)); + } + + void do_send_result() final { + send_result(td_->stickers_manager_->get_sticker_sets_object(-1, sticker_set_ids_, 1)); + } + + public: + GetInstalledStickerSetsRequest(ActorShared td, uint64 request_id, StickerType sticker_type) + : RequestActor(std::move(td), request_id), sticker_type_(sticker_type) { + } +}; + +class GetArchivedStickerSetsRequest final : public RequestActor<> { + StickerType sticker_type_; + StickerSetId offset_sticker_set_id_; + int32 limit_; + + int32 total_count_ = -1; + vector sticker_set_ids_; + + void do_run(Promise &&promise) final { + std::tie(total_count_, sticker_set_ids_) = td_->stickers_manager_->get_archived_sticker_sets( + sticker_type_, offset_sticker_set_id_, limit_, get_tries() < 2, std::move(promise)); + } + + void do_send_result() final { + send_result(td_->stickers_manager_->get_sticker_sets_object(total_count_, sticker_set_ids_, 1)); + } + + public: + GetArchivedStickerSetsRequest(ActorShared td, uint64 request_id, StickerType sticker_type, + int64 offset_sticker_set_id, int32 limit) + : RequestActor(std::move(td), request_id) + , sticker_type_(sticker_type) + , offset_sticker_set_id_(offset_sticker_set_id) + , limit_(limit) { + } +}; + +class GetTrendingStickerSetsRequest final : public RequestActor<> { + td_api::object_ptr result_; + StickerType sticker_type_; + int32 offset_; + int32 limit_; + + void do_run(Promise &&promise) final { + result_ = td_->stickers_manager_->get_featured_sticker_sets(sticker_type_, offset_, limit_, std::move(promise)); + } + + void do_send_result() final { + send_result(std::move(result_)); + } + + public: + GetTrendingStickerSetsRequest(ActorShared td, uint64 request_id, StickerType sticker_type, int32 offset, + int32 limit) + : RequestActor(std::move(td), request_id), sticker_type_(sticker_type), offset_(offset), limit_(limit) { + set_tries(3); + } +}; + +class GetAttachedStickerSetsRequest final : public RequestActor<> { + FileId file_id_; + + vector sticker_set_ids_; + + void do_run(Promise &&promise) final { + sticker_set_ids_ = td_->stickers_manager_->get_attached_sticker_sets(file_id_, std::move(promise)); + } + + void do_send_result() final { + send_result(td_->stickers_manager_->get_sticker_sets_object(-1, sticker_set_ids_, 5)); + } + + public: + GetAttachedStickerSetsRequest(ActorShared td, uint64 request_id, int32 file_id) + : RequestActor(std::move(td), request_id), file_id_(file_id, 0) { + } +}; + +class GetStickerSetRequest final : public RequestActor<> { + StickerSetId set_id_; + + StickerSetId sticker_set_id_; + + void do_run(Promise &&promise) final { + sticker_set_id_ = td_->stickers_manager_->get_sticker_set(set_id_, std::move(promise)); + } + + void do_send_result() final { + send_result(td_->stickers_manager_->get_sticker_set_object(sticker_set_id_)); + } + + public: + GetStickerSetRequest(ActorShared td, uint64 request_id, int64 set_id) + : RequestActor(std::move(td), request_id), set_id_(set_id) { + set_tries(3); + } +}; + +class SearchStickerSetRequest final : public RequestActor<> { + string name_; + + StickerSetId sticker_set_id_; + + void do_run(Promise &&promise) final { + sticker_set_id_ = td_->stickers_manager_->search_sticker_set(name_, std::move(promise)); + } + + void do_send_result() final { + send_result(td_->stickers_manager_->get_sticker_set_object(sticker_set_id_)); + } + + public: + SearchStickerSetRequest(ActorShared td, uint64 request_id, string &&name) + : RequestActor(std::move(td), request_id), name_(std::move(name)) { + set_tries(3); + } +}; + +class SearchInstalledStickerSetsRequest final : public RequestActor<> { + StickerType sticker_type_; + string query_; + int32 limit_; + + std::pair> sticker_set_ids_; + + void do_run(Promise &&promise) final { + sticker_set_ids_ = + td_->stickers_manager_->search_installed_sticker_sets(sticker_type_, query_, limit_, std::move(promise)); + } + + void do_send_result() final { + send_result(td_->stickers_manager_->get_sticker_sets_object(sticker_set_ids_.first, sticker_set_ids_.second, 5)); + } + + public: + SearchInstalledStickerSetsRequest(ActorShared td, uint64 request_id, StickerType sticker_type, string &&query, + int32 limit) + : RequestActor(std::move(td), request_id), sticker_type_(sticker_type), query_(std::move(query)), limit_(limit) { + } +}; + +class SearchStickerSetsRequest final : public RequestActor<> { + StickerType sticker_type_; + string query_; + + vector sticker_set_ids_; + + void do_run(Promise &&promise) final { + sticker_set_ids_ = td_->stickers_manager_->search_sticker_sets(sticker_type_, query_, std::move(promise)); + } + + void do_send_result() final { + send_result(td_->stickers_manager_->get_sticker_sets_object(-1, sticker_set_ids_, 5)); + } + + public: + SearchStickerSetsRequest(ActorShared td, uint64 request_id, StickerType sticker_type, string &&query) + : RequestActor(std::move(td), request_id), sticker_type_(sticker_type), query_(std::move(query)) { + } +}; + +class ChangeStickerSetRequest final : public RequestOnceActor { + StickerSetId set_id_; + bool is_installed_; + bool is_archived_; + + void do_run(Promise &&promise) final { + td_->stickers_manager_->change_sticker_set(set_id_, is_installed_, is_archived_, std::move(promise)); + } + + public: + ChangeStickerSetRequest(ActorShared td, uint64 request_id, int64 set_id, bool is_installed, bool is_archived) + : RequestOnceActor(std::move(td), request_id) + , set_id_(set_id) + , is_installed_(is_installed) + , is_archived_(is_archived) { + set_tries(4); + } +}; + +class GetRecentStickersRequest final : public RequestActor<> { + bool is_attached_; + + vector sticker_ids_; + + void do_run(Promise &&promise) final { + sticker_ids_ = td_->stickers_manager_->get_recent_stickers(is_attached_, std::move(promise)); + } + + void do_send_result() final { + send_result(td_->stickers_manager_->get_stickers_object(sticker_ids_)); + } + + public: + GetRecentStickersRequest(ActorShared td, uint64 request_id, bool is_attached) + : RequestActor(std::move(td), request_id), is_attached_(is_attached) { + } +}; + +class AddRecentStickerRequest final : public RequestActor<> { + bool is_attached_; + td_api::object_ptr input_file_; + + void do_run(Promise &&promise) final { + td_->stickers_manager_->add_recent_sticker(is_attached_, input_file_, std::move(promise)); + } + + public: + AddRecentStickerRequest(ActorShared td, uint64 request_id, bool is_attached, + td_api::object_ptr &&input_file) + : RequestActor(std::move(td), request_id), is_attached_(is_attached), input_file_(std::move(input_file)) { + set_tries(3); + } +}; + +class RemoveRecentStickerRequest final : public RequestActor<> { + bool is_attached_; + td_api::object_ptr input_file_; + + void do_run(Promise &&promise) final { + td_->stickers_manager_->remove_recent_sticker(is_attached_, input_file_, std::move(promise)); + } + + public: + RemoveRecentStickerRequest(ActorShared td, uint64 request_id, bool is_attached, + td_api::object_ptr &&input_file) + : RequestActor(std::move(td), request_id), is_attached_(is_attached), input_file_(std::move(input_file)) { + set_tries(3); + } +}; + +class ClearRecentStickersRequest final : public RequestActor<> { + bool is_attached_; + + void do_run(Promise &&promise) final { + td_->stickers_manager_->clear_recent_stickers(is_attached_, std::move(promise)); + } + + public: + ClearRecentStickersRequest(ActorShared td, uint64 request_id, bool is_attached) + : RequestActor(std::move(td), request_id), is_attached_(is_attached) { + set_tries(3); + } +}; + +class GetFavoriteStickersRequest final : public RequestActor<> { + vector sticker_ids_; + + void do_run(Promise &&promise) final { + sticker_ids_ = td_->stickers_manager_->get_favorite_stickers(std::move(promise)); + } + + void do_send_result() final { + send_result(td_->stickers_manager_->get_stickers_object(sticker_ids_)); + } + + public: + GetFavoriteStickersRequest(ActorShared td, uint64 request_id) : RequestActor(std::move(td), request_id) { + } +}; + +class AddFavoriteStickerRequest final : public RequestOnceActor { + td_api::object_ptr input_file_; + + void do_run(Promise &&promise) final { + td_->stickers_manager_->add_favorite_sticker(input_file_, std::move(promise)); + } + + public: + AddFavoriteStickerRequest(ActorShared td, uint64 request_id, td_api::object_ptr &&input_file) + : RequestOnceActor(std::move(td), request_id), input_file_(std::move(input_file)) { + set_tries(3); + } +}; + +class RemoveFavoriteStickerRequest final : public RequestOnceActor { + td_api::object_ptr input_file_; + + void do_run(Promise &&promise) final { + td_->stickers_manager_->remove_favorite_sticker(input_file_, std::move(promise)); + } + + public: + RemoveFavoriteStickerRequest(ActorShared td, uint64 request_id, + td_api::object_ptr &&input_file) + : RequestOnceActor(std::move(td), request_id), input_file_(std::move(input_file)) { + set_tries(3); + } +}; + +class GetStickerEmojisRequest final : public RequestActor<> { + td_api::object_ptr input_file_; + + vector emojis_; + + void do_run(Promise &&promise) final { + emojis_ = td_->stickers_manager_->get_sticker_emojis(input_file_, std::move(promise)); + } + + void do_send_result() final { + send_result(td_api::make_object(std::move(emojis_))); + } + + public: + GetStickerEmojisRequest(ActorShared td, uint64 request_id, td_api::object_ptr &&input_file) + : RequestActor(std::move(td), request_id), input_file_(std::move(input_file)) { + set_tries(3); + } +}; + +class SearchEmojisRequest final : public RequestActor<> { + string text_; + vector input_language_codes_; + + vector> emoji_keywords_; + + void do_run(Promise &&promise) final { + emoji_keywords_ = + td_->stickers_manager_->search_emojis(text_, input_language_codes_, get_tries() < 2, std::move(promise)); + } + + void do_send_result() final { + send_result(td_api::make_object( + transform(emoji_keywords_, [](const std::pair &emoji_keyword) { + return td_api::make_object(emoji_keyword.first, emoji_keyword.second); + }))); + } + + public: + SearchEmojisRequest(ActorShared td, uint64 request_id, string &&text, vector &&input_language_codes) + : RequestActor(std::move(td), request_id) + , text_(std::move(text)) + , input_language_codes_(std::move(input_language_codes)) { + set_tries(3); + } +}; + +class GetKeywordEmojisRequest final : public RequestActor<> { + string text_; + vector input_language_codes_; + + vector emojis_; + + void do_run(Promise &&promise) final { + emojis_ = + td_->stickers_manager_->get_keyword_emojis(text_, input_language_codes_, get_tries() < 2, std::move(promise)); + } + + void do_send_result() final { + send_result(td_api::make_object(std::move(emojis_))); + } + + public: + GetKeywordEmojisRequest(ActorShared td, uint64 request_id, string &&text, vector &&input_language_codes) + : RequestActor(std::move(td), request_id) + , text_(std::move(text)) + , input_language_codes_(std::move(input_language_codes)) { + set_tries(3); + } +}; + +class GetEmojiSuggestionsUrlRequest final : public RequestOnceActor { + string language_code_; + + int64 random_id_; + + void do_run(Promise &&promise) final { + random_id_ = td_->stickers_manager_->get_emoji_suggestions_url(language_code_, std::move(promise)); + } + + void do_send_result() final { + send_result(td_->stickers_manager_->get_emoji_suggestions_url_result(random_id_)); + } + + public: + GetEmojiSuggestionsUrlRequest(ActorShared td, uint64 request_id, string &&language_code) + : RequestOnceActor(std::move(td), request_id), language_code_(std::move(language_code)), random_id_(0) { + } +}; + +class GetSavedAnimationsRequest final : public RequestActor<> { + vector animation_ids_; + + void do_run(Promise &&promise) final { + animation_ids_ = td_->animations_manager_->get_saved_animations(std::move(promise)); + } + + void do_send_result() final { + send_result(td_api::make_object(transform(animation_ids_, [td = td_](FileId animation_id) { + return td->animations_manager_->get_animation_object(animation_id); + }))); + } + + public: + GetSavedAnimationsRequest(ActorShared td, uint64 request_id) : RequestActor(std::move(td), request_id) { + } +}; + +class AddSavedAnimationRequest final : public RequestOnceActor { + td_api::object_ptr input_file_; + + void do_run(Promise &&promise) final { + td_->animations_manager_->add_saved_animation(input_file_, std::move(promise)); + } + + public: + AddSavedAnimationRequest(ActorShared td, uint64 request_id, td_api::object_ptr &&input_file) + : RequestOnceActor(std::move(td), request_id), input_file_(std::move(input_file)) { + set_tries(3); + } +}; + +class RemoveSavedAnimationRequest final : public RequestOnceActor { + td_api::object_ptr input_file_; + + void do_run(Promise &&promise) final { + td_->animations_manager_->remove_saved_animation(input_file_, std::move(promise)); + } + + public: + RemoveSavedAnimationRequest(ActorShared td, uint64 request_id, td_api::object_ptr &&input_file) + : RequestOnceActor(std::move(td), request_id), input_file_(std::move(input_file)) { + set_tries(3); + } +}; + +class GetSavedNotificationSoundRequest final : public RequestActor<> { + int64 ringtone_id_; + FileId ringtone_file_id_; + + void do_run(Promise &&promise) final { + ringtone_file_id_ = td_->notification_settings_manager_->get_saved_ringtone(ringtone_id_, std::move(promise)); + } + + void do_send_result() final { + send_result(td_->audios_manager_->get_notification_sound_object(ringtone_file_id_)); + } + + public: + GetSavedNotificationSoundRequest(ActorShared td, uint64 request_id, int64 ringtone_id) + : RequestActor(std::move(td), request_id), ringtone_id_(ringtone_id) { + } +}; + +class GetSavedNotificationSoundsRequest final : public RequestActor<> { + vector ringtone_file_ids_; + + void do_run(Promise &&promise) final { + ringtone_file_ids_ = td_->notification_settings_manager_->get_saved_ringtones(std::move(promise)); + } + + void do_send_result() final { + send_result(td_api::make_object( + transform(ringtone_file_ids_, [td = td_](FileId ringtone_file_id) { + return td->audios_manager_->get_notification_sound_object(ringtone_file_id); + }))); + } + + public: + GetSavedNotificationSoundsRequest(ActorShared td, uint64 request_id) : RequestActor(std::move(td), request_id) { + } +}; + +class RemoveSavedNotificationSoundRequest final : public RequestOnceActor { + int64 ringtone_id_; + + void do_run(Promise &&promise) final { + td_->notification_settings_manager_->remove_saved_ringtone(ringtone_id_, std::move(promise)); + } + + public: + RemoveSavedNotificationSoundRequest(ActorShared td, uint64 request_id, int64 ringtone_id) + : RequestOnceActor(std::move(td), request_id), ringtone_id_(ringtone_id) { + set_tries(3); + } +}; + +class SearchBackgroundRequest final : public RequestActor<> { + string name_; + + std::pair background_; + + void do_run(Promise &&promise) final { + background_ = td_->background_manager_->search_background(name_, std::move(promise)); + } + + void do_send_result() final { + send_result(td_->background_manager_->get_background_object(background_.first, false, &background_.second)); + } + + public: + SearchBackgroundRequest(ActorShared td, uint64 request_id, string &&name) + : RequestActor(std::move(td), request_id), name_(std::move(name)) { + set_tries(3); + } +}; + +class Requests::DownloadFileCallback final : public FileManager::DownloadCallback { + public: + void on_download_ok(FileId file_id) final { + send_closure(G()->td(), &Td::on_file_download_finished, file_id); + } + + void on_download_error(FileId file_id, Status error) final { + send_closure(G()->td(), &Td::on_file_download_finished, file_id); + } +}; + +Requests::Requests(Td *td) + : td_(td), td_actor_(td->actor_id(td)), download_file_callback_(std::make_shared()) { +} + +void Requests::run_request(uint64 id, td_api::object_ptr &&function) { + CHECK(td_ != nullptr); + downcast_call(*function, [this, id](auto &request) { this->on_request(id, request); }); +} + +void Requests::send_error_raw(uint64 id, int32 code, CSlice error) { + send_closure(td_actor_, &Td::send_error_impl, id, td_api::make_object(code, error.str())); +} + +void Requests::answer_ok_query(uint64 id, Status status) { + if (status.is_error()) { + send_closure(td_actor_, &Td::send_error, id, std::move(status)); + } else { + send_closure(td_actor_, &Td::send_result, id, td_api::make_object()); + } +} + +Promise Requests::create_ok_request_promise(uint64 id) { + return PromiseCreator::lambda([actor_id = td_actor_, id](Result result) { + if (result.is_error()) { + send_closure(actor_id, &Td::send_error, id, result.move_as_error()); + } else { + send_closure(actor_id, &Td::send_result, id, td_api::make_object()); + } + }); +} + +Promise Requests::create_text_request_promise(uint64 id) { + return PromiseCreator::lambda([actor_id = td_actor_, id](Result result) mutable { + if (result.is_error()) { + send_closure(actor_id, &Td::send_error, id, result.move_as_error()); + } else { + send_closure(actor_id, &Td::send_result, id, td_api::make_object(result.move_as_ok())); + } + }); +} + +Promise Requests::create_http_url_request_promise(uint64 id) { + return PromiseCreator::lambda([actor_id = td_actor_, id](Result result) mutable { + if (result.is_error()) { + send_closure(actor_id, &Td::send_error, id, result.move_as_error()); + } else { + send_closure(actor_id, &Td::send_result, id, td_api::make_object(result.move_as_ok())); + } + }); +} + +#define CLEAN_INPUT_STRING(field_name) \ + if (!clean_input_string(field_name)) { \ + return send_error_raw(id, 400, "Strings must be encoded in UTF-8"); \ + } +#define CHECK_IS_BOT() \ + if (!td_->auth_manager_->is_bot()) { \ + return send_error_raw(id, 400, "Only bots can use the method"); \ + } +#define CHECK_IS_USER() \ + if (td_->auth_manager_->is_bot()) { \ + return send_error_raw(id, 400, "The method is not available to bots"); \ + } + +#define CREATE_NO_ARGS_REQUEST(name) \ + auto slot_id = td_->request_actors_.create(ActorOwn<>(), Td::RequestActorIdType); \ + td_->inc_request_actor_refcnt(); \ + *td_->request_actors_.get(slot_id) = create_actor(#name, td_->actor_shared(td_, slot_id), id); +#define CREATE_REQUEST(name, ...) \ + auto slot_id = td_->request_actors_.create(ActorOwn<>(), Td::RequestActorIdType); \ + td_->inc_request_actor_refcnt(); \ + *td_->request_actors_.get(slot_id) = create_actor(#name, td_->actor_shared(td_, slot_id), id, __VA_ARGS__); + +#define CREATE_REQUEST_PROMISE() auto promise = create_request_promise::ReturnType>(id) +#define CREATE_OK_REQUEST_PROMISE() \ + static_assert(std::is_same::ReturnType, td_api::object_ptr>::value, ""); \ + auto promise = create_ok_request_promise(id) +#define CREATE_TEXT_REQUEST_PROMISE() \ + static_assert(std::is_same::ReturnType, td_api::object_ptr>::value, \ + ""); \ + auto promise = create_text_request_promise(id) +#define CREATE_HTTP_URL_REQUEST_PROMISE() \ + static_assert(std::is_same::ReturnType, td_api::object_ptr>::value, \ + ""); \ + auto promise = create_http_url_request_promise(id) + +void Requests::on_request(uint64 id, const td_api::setTdlibParameters &request) { + send_error_raw(id, 400, "Unexpected setTdlibParameters"); +} + +void Requests::on_request(uint64 id, td_api::setDatabaseEncryptionKey &request) { + CREATE_OK_REQUEST_PROMISE(); + G()->td_db()->get_binlog()->change_key(TdDb::as_db_key(std::move(request.new_encryption_key_)), std::move(promise)); +} + +void Requests::on_request(uint64 id, const td_api::getAuthorizationState &request) { + send_closure(td_->auth_manager_actor_, &AuthManager::get_state, id); +} + +void Requests::on_request(uint64 id, td_api::setAuthenticationPhoneNumber &request) { + CLEAN_INPUT_STRING(request.phone_number_); + send_closure(td_->auth_manager_actor_, &AuthManager::set_phone_number, id, std::move(request.phone_number_), + std::move(request.settings_)); +} + +void Requests::on_request(uint64 id, td_api::sendAuthenticationFirebaseSms &request) { + CLEAN_INPUT_STRING(request.token_); + send_closure(td_->auth_manager_actor_, &AuthManager::set_firebase_token, id, std::move(request.token_)); +} + +void Requests::on_request(uint64 id, td_api::reportAuthenticationCodeMissing &request) { + CLEAN_INPUT_STRING(request.mobile_network_code_); + send_closure(td_->auth_manager_actor_, &AuthManager::report_missing_code, id, + std::move(request.mobile_network_code_)); +} + +void Requests::on_request(uint64 id, td_api::setAuthenticationEmailAddress &request) { + CLEAN_INPUT_STRING(request.email_address_); + send_closure(td_->auth_manager_actor_, &AuthManager::set_email_address, id, std::move(request.email_address_)); +} + +void Requests::on_request(uint64 id, td_api::resendAuthenticationCode &request) { + send_closure(td_->auth_manager_actor_, &AuthManager::resend_authentication_code, id, std::move(request.reason_)); +} + +void Requests::on_request(uint64 id, td_api::checkAuthenticationEmailCode &request) { + send_closure(td_->auth_manager_actor_, &AuthManager::check_email_code, id, + EmailVerification(std::move(request.code_))); +} + +void Requests::on_request(uint64 id, td_api::checkAuthenticationCode &request) { + CLEAN_INPUT_STRING(request.code_); + send_closure(td_->auth_manager_actor_, &AuthManager::check_code, id, std::move(request.code_)); +} + +void Requests::on_request(uint64 id, td_api::registerUser &request) { + CLEAN_INPUT_STRING(request.first_name_); + CLEAN_INPUT_STRING(request.last_name_); + send_closure(td_->auth_manager_actor_, &AuthManager::register_user, id, std::move(request.first_name_), + std::move(request.last_name_), request.disable_notification_); +} + +void Requests::on_request(uint64 id, td_api::requestQrCodeAuthentication &request) { + send_closure(td_->auth_manager_actor_, &AuthManager::request_qr_code_authentication, id, + UserId::get_user_ids(request.other_user_ids_)); +} + +void Requests::on_request(uint64 id, const td_api::resetAuthenticationEmailAddress &request) { + send_closure(td_->auth_manager_actor_, &AuthManager::reset_email_address, id); +} + +void Requests::on_request(uint64 id, td_api::checkAuthenticationPassword &request) { + CLEAN_INPUT_STRING(request.password_); + send_closure(td_->auth_manager_actor_, &AuthManager::check_password, id, std::move(request.password_)); +} + +void Requests::on_request(uint64 id, const td_api::requestAuthenticationPasswordRecovery &request) { + send_closure(td_->auth_manager_actor_, &AuthManager::request_password_recovery, id); +} + +void Requests::on_request(uint64 id, td_api::checkAuthenticationPasswordRecoveryCode &request) { + CLEAN_INPUT_STRING(request.recovery_code_); + send_closure(td_->auth_manager_actor_, &AuthManager::check_password_recovery_code, id, + std::move(request.recovery_code_)); +} + +void Requests::on_request(uint64 id, td_api::recoverAuthenticationPassword &request) { + CLEAN_INPUT_STRING(request.recovery_code_); + CLEAN_INPUT_STRING(request.new_password_); + CLEAN_INPUT_STRING(request.new_hint_); + send_closure(td_->auth_manager_actor_, &AuthManager::recover_password, id, std::move(request.recovery_code_), + std::move(request.new_password_), std::move(request.new_hint_)); +} + +void Requests::on_request(uint64 id, const td_api::logOut &request) { + // will call Td::destroy later + send_closure(td_->auth_manager_actor_, &AuthManager::log_out, id); +} + +void Requests::on_request(uint64 id, const td_api::close &request) { + // send response before actually closing + send_closure(td_actor_, &Td::send_result, id, td_api::make_object()); + send_closure(td_actor_, &Td::close); +} + +void Requests::on_request(uint64 id, const td_api::destroy &request) { + // send response before actually destroying + send_closure(td_actor_, &Td::send_result, id, td_api::make_object()); + send_closure(td_actor_, &Td::destroy); +} + +void Requests::on_request(uint64 id, td_api::checkAuthenticationBotToken &request) { + CLEAN_INPUT_STRING(request.token_); + send_closure(td_->auth_manager_actor_, &AuthManager::check_bot_token, id, std::move(request.token_)); +} + +void Requests::on_request(uint64 id, td_api::confirmQrCodeAuthentication &request) { + CLEAN_INPUT_STRING(request.link_); + CREATE_REQUEST_PROMISE(); + td_->account_manager_->confirm_qr_code_authentication(request.link_, std::move(promise)); +} + +void Requests::on_request(uint64 id, const td_api::getCurrentState &request) { + vector> updates; + + td_->option_manager_->get_current_state(updates); + + auto state = td_->auth_manager_->get_current_authorization_state_object(); + if (state != nullptr) { + updates.push_back(td_api::make_object(std::move(state))); + } + + td_->connection_state_manager_->get_current_state(updates); + + if (td_->auth_manager_->is_authorized()) { + td_->user_manager_->get_current_state(updates); + + td_->chat_manager_->get_current_state(updates); + + td_->background_manager_->get_current_state(updates); + + td_->animations_manager_->get_current_state(updates); + + td_->attach_menu_manager_->get_current_state(updates); + + td_->stickers_manager_->get_current_state(updates); + + td_->reaction_manager_->get_current_state(updates); + + td_->notification_settings_manager_->get_current_state(updates); + + td_->dialog_filter_manager_->get_current_state(updates); + + td_->messages_manager_->get_current_state(updates); + + td_->dialog_participant_manager_->get_current_state(updates); + + td_->notification_manager_->get_current_state(updates); + + td_->quick_reply_manager_->get_current_state(updates); + + td_->saved_messages_manager_->get_current_state(updates); + + td_->story_manager_->get_current_state(updates); + + td_->config_manager_.get_actor_unsafe()->get_current_state(updates); + + td_->transcription_manager_->get_current_state(updates); + + td_->autosave_manager_->get_current_state(updates); + + td_->account_manager_->get_current_state(updates); + + td_->business_connection_manager_->get_current_state(updates); + + td_->terms_of_service_manager_->get_current_state(updates); + + td_->star_manager_->get_current_state(updates); + + // TODO updateFileGenerationStart generation_id:int64 original_path:string destination_path:string conversion:string = Update; + // TODO updateCall call:call = Update; + // TODO updateGroupCall call:groupCall = Update; + } + + // send response synchronously to prevent "Request aborted" or other changes of the current state + td_->send_result(id, td_api::make_object(std::move(updates))); +} + +void Requests::on_request(uint64 id, const td_api::getPasswordState &request) { + CHECK_IS_USER(); + CREATE_REQUEST_PROMISE(); + send_closure(td_->password_manager_, &PasswordManager::get_state, std::move(promise)); +} + +void Requests::on_request(uint64 id, td_api::setPassword &request) { + CHECK_IS_USER(); + CLEAN_INPUT_STRING(request.old_password_); + CLEAN_INPUT_STRING(request.new_password_); + CLEAN_INPUT_STRING(request.new_hint_); + CLEAN_INPUT_STRING(request.new_recovery_email_address_); + CREATE_REQUEST_PROMISE(); + send_closure(td_->password_manager_, &PasswordManager::set_password, std::move(request.old_password_), + std::move(request.new_password_), std::move(request.new_hint_), request.set_recovery_email_address_, + std::move(request.new_recovery_email_address_), std::move(promise)); +} + +void Requests::on_request(uint64 id, td_api::setLoginEmailAddress &request) { + CHECK_IS_USER(); + CLEAN_INPUT_STRING(request.new_login_email_address_); + CREATE_REQUEST_PROMISE(); + auto query_promise = PromiseCreator::lambda([promise = std::move(promise)](Result result) mutable { + if (result.is_error()) { + promise.set_error(result.move_as_error()); + } else { + promise.set_value(result.ok().get_email_address_authentication_code_info_object()); + } + }); + send_closure(td_->password_manager_, &PasswordManager::set_login_email_address, + std::move(request.new_login_email_address_), std::move(query_promise)); +} + +void Requests::on_request(uint64 id, const td_api::resendLoginEmailAddressCode &request) { + CHECK_IS_USER(); + CREATE_REQUEST_PROMISE(); + auto query_promise = PromiseCreator::lambda([promise = std::move(promise)](Result result) mutable { + if (result.is_error()) { + promise.set_error(result.move_as_error()); + } else { + promise.set_value(result.ok().get_email_address_authentication_code_info_object()); + } + }); + send_closure(td_->password_manager_, &PasswordManager::resend_login_email_address_code, std::move(query_promise)); +} + +void Requests::on_request(uint64 id, td_api::checkLoginEmailAddressCode &request) { + CHECK_IS_USER(); + CREATE_OK_REQUEST_PROMISE(); + send_closure(td_->password_manager_, &PasswordManager::check_login_email_address_code, + EmailVerification(std::move(request.code_)), std::move(promise)); +} + +void Requests::on_request(uint64 id, td_api::setRecoveryEmailAddress &request) { + CHECK_IS_USER(); + CLEAN_INPUT_STRING(request.password_); + CLEAN_INPUT_STRING(request.new_recovery_email_address_); + CREATE_REQUEST_PROMISE(); + send_closure(td_->password_manager_, &PasswordManager::set_recovery_email_address, std::move(request.password_), + std::move(request.new_recovery_email_address_), std::move(promise)); +} + +void Requests::on_request(uint64 id, td_api::getRecoveryEmailAddress &request) { + CHECK_IS_USER(); + CLEAN_INPUT_STRING(request.password_); + CREATE_REQUEST_PROMISE(); + send_closure(td_->password_manager_, &PasswordManager::get_recovery_email_address, std::move(request.password_), + std::move(promise)); +} + +void Requests::on_request(uint64 id, td_api::checkRecoveryEmailAddressCode &request) { + CHECK_IS_USER(); + CLEAN_INPUT_STRING(request.code_); + CREATE_REQUEST_PROMISE(); + send_closure(td_->password_manager_, &PasswordManager::check_recovery_email_address_code, std::move(request.code_), + std::move(promise)); +} + +void Requests::on_request(uint64 id, const td_api::resendRecoveryEmailAddressCode &request) { + CHECK_IS_USER(); + CREATE_REQUEST_PROMISE(); + send_closure(td_->password_manager_, &PasswordManager::resend_recovery_email_address_code, std::move(promise)); +} + +void Requests::on_request(uint64 id, const td_api::cancelRecoveryEmailAddressVerification &request) { + CHECK_IS_USER(); + CREATE_REQUEST_PROMISE(); + send_closure(td_->password_manager_, &PasswordManager::cancel_recovery_email_address_verification, + std::move(promise)); +} + +void Requests::on_request(uint64 id, td_api::requestPasswordRecovery &request) { + CHECK_IS_USER(); + CREATE_REQUEST_PROMISE(); + auto query_promise = PromiseCreator::lambda([promise = std::move(promise)](Result result) mutable { + if (result.is_error()) { + promise.set_error(result.move_as_error()); + } else { + promise.set_value(result.ok().get_email_address_authentication_code_info_object()); + } + }); + send_closure(td_->password_manager_, &PasswordManager::request_password_recovery, std::move(query_promise)); +} + +void Requests::on_request(uint64 id, td_api::checkPasswordRecoveryCode &request) { + CHECK_IS_USER(); + CLEAN_INPUT_STRING(request.recovery_code_); + CREATE_OK_REQUEST_PROMISE(); + send_closure(td_->password_manager_, &PasswordManager::check_password_recovery_code, + std::move(request.recovery_code_), std::move(promise)); +} + +void Requests::on_request(uint64 id, td_api::recoverPassword &request) { + CHECK_IS_USER(); + CLEAN_INPUT_STRING(request.recovery_code_); + CLEAN_INPUT_STRING(request.new_password_); + CLEAN_INPUT_STRING(request.new_hint_); + CREATE_REQUEST_PROMISE(); + send_closure(td_->password_manager_, &PasswordManager::recover_password, std::move(request.recovery_code_), + std::move(request.new_password_), std::move(request.new_hint_), std::move(promise)); +} + +void Requests::on_request(uint64 id, const td_api::resetPassword &request) { + CHECK_IS_USER(); + CREATE_REQUEST_PROMISE(); + send_closure(td_->password_manager_, &PasswordManager::reset_password, std::move(promise)); +} + +void Requests::on_request(uint64 id, const td_api::cancelPasswordReset &request) { + CHECK_IS_USER(); + CREATE_OK_REQUEST_PROMISE(); + send_closure(td_->password_manager_, &PasswordManager::cancel_password_reset, std::move(promise)); +} + +void Requests::on_request(uint64 id, td_api::getTemporaryPasswordState &request) { + CHECK_IS_USER(); + CREATE_REQUEST_PROMISE(); + send_closure(td_->password_manager_, &PasswordManager::get_temp_password_state, std::move(promise)); +} + +void Requests::on_request(uint64 id, td_api::createTemporaryPassword &request) { + CHECK_IS_USER(); + CLEAN_INPUT_STRING(request.password_); + CREATE_REQUEST_PROMISE(); + send_closure(td_->password_manager_, &PasswordManager::create_temp_password, std::move(request.password_), + request.valid_for_, std::move(promise)); +} + +void Requests::on_request(uint64 id, td_api::processPushNotification &request) { + CHECK_IS_USER(); + CLEAN_INPUT_STRING(request.payload_); + CREATE_OK_REQUEST_PROMISE(); + send_closure(G()->notification_manager(), &NotificationManager::process_push_notification, + std::move(request.payload_), std::move(promise)); +} + +void Requests::on_request(uint64 id, td_api::registerDevice &request) { + CHECK_IS_USER(); + CREATE_REQUEST_PROMISE(); + send_closure(td_->device_token_manager_, &DeviceTokenManager::register_device, std::move(request.device_token_), + UserId::get_user_ids(request.other_user_ids_), std::move(promise)); +} + +void Requests::on_request(uint64 id, td_api::getUserPrivacySettingRules &request) { + CHECK_IS_USER(); + CREATE_REQUEST_PROMISE(); + td_->privacy_manager_->get_privacy(std::move(request.setting_), std::move(promise)); +} + +void Requests::on_request(uint64 id, td_api::setUserPrivacySettingRules &request) { + CHECK_IS_USER(); + CREATE_OK_REQUEST_PROMISE(); + td_->privacy_manager_->set_privacy(std::move(request.setting_), std::move(request.rules_), std::move(promise)); +} + +void Requests::on_request(uint64 id, const td_api::getDefaultMessageAutoDeleteTime &request) { + CHECK_IS_USER(); + CREATE_REQUEST_PROMISE(); + auto query_promise = PromiseCreator::lambda([promise = std::move(promise)](Result result) mutable { + if (result.is_error()) { + promise.set_error(result.move_as_error()); + } else { + promise.set_value(td_api::make_object(result.ok())); + } + }); + td_->account_manager_->get_default_message_ttl(std::move(query_promise)); +} + +void Requests::on_request(uint64 id, const td_api::setDefaultMessageAutoDeleteTime &request) { + CHECK_IS_USER(); + if (request.message_auto_delete_time_ == nullptr) { + return send_error_raw(id, 400, "New default message auto-delete time must be non-empty"); + } + CREATE_OK_REQUEST_PROMISE(); + td_->account_manager_->set_default_message_ttl(request.message_auto_delete_time_->time_, std::move(promise)); +} + +void Requests::on_request(uint64 id, const td_api::getAccountTtl &request) { + CHECK_IS_USER(); + CREATE_REQUEST_PROMISE(); + auto query_promise = PromiseCreator::lambda([promise = std::move(promise)](Result result) mutable { + if (result.is_error()) { + promise.set_error(result.move_as_error()); + } else { + promise.set_value(td_api::make_object(result.ok())); + } + }); + td_->account_manager_->get_account_ttl(std::move(query_promise)); +} + +void Requests::on_request(uint64 id, const td_api::setAccountTtl &request) { + CHECK_IS_USER(); + if (request.ttl_ == nullptr) { + return send_error_raw(id, 400, "New account TTL must be non-empty"); + } + CREATE_OK_REQUEST_PROMISE(); + td_->account_manager_->set_account_ttl(request.ttl_->days_, std::move(promise)); +} + +void Requests::on_request(uint64 id, td_api::deleteAccount &request) { + CHECK_IS_USER(); + CLEAN_INPUT_STRING(request.reason_); + send_closure(td_->auth_manager_actor_, &AuthManager::delete_account, id, request.reason_, request.password_); +} + +void Requests::on_request(uint64 id, td_api::sendPhoneNumberCode &request) { + CHECK_IS_USER(); + CLEAN_INPUT_STRING(request.phone_number_); + CREATE_REQUEST_PROMISE(); + td_->phone_number_manager_->set_phone_number(std::move(request.phone_number_), std::move(request.settings_), + std::move(request.type_), std::move(promise)); +} + +void Requests::on_request(uint64 id, td_api::sendPhoneNumberFirebaseSms &request) { + CHECK_IS_USER(); + CLEAN_INPUT_STRING(request.token_); + CREATE_OK_REQUEST_PROMISE(); + td_->phone_number_manager_->send_firebase_sms(std::move(request.token_), std::move(promise)); +} + +void Requests::on_request(uint64 id, td_api::reportPhoneNumberCodeMissing &request) { + CHECK_IS_USER(); + CLEAN_INPUT_STRING(request.mobile_network_code_); + CREATE_OK_REQUEST_PROMISE(); + td_->phone_number_manager_->report_missing_code(std::move(request.mobile_network_code_), std::move(promise)); +} + +void Requests::on_request(uint64 id, td_api::resendPhoneNumberCode &request) { + CHECK_IS_USER(); + CREATE_REQUEST_PROMISE(); + td_->phone_number_manager_->resend_authentication_code(std::move(request.reason_), std::move(promise)); +} + +void Requests::on_request(uint64 id, td_api::checkPhoneNumberCode &request) { + CHECK_IS_USER(); + CLEAN_INPUT_STRING(request.code_); + CREATE_OK_REQUEST_PROMISE(); + td_->phone_number_manager_->check_code(std::move(request.code_), std::move(promise)); +} + +void Requests::on_request(uint64 id, const td_api::getUserLink &request) { + CHECK_IS_USER(); + CREATE_REQUEST_PROMISE(); + td_->account_manager_->get_user_link(std::move(promise)); +} + +void Requests::on_request(uint64 id, td_api::searchUserByToken &request) { + CHECK_IS_USER(); + CLEAN_INPUT_STRING(request.token_); + CREATE_REQUEST_PROMISE(); + td_->account_manager_->import_contact_token(std::move(request.token_), std::move(promise)); +} + +void Requests::on_request(uint64 id, const td_api::getActiveSessions &request) { + CHECK_IS_USER(); + CREATE_REQUEST_PROMISE(); + td_->account_manager_->get_active_sessions(std::move(promise)); +} + +void Requests::on_request(uint64 id, const td_api::terminateSession &request) { + CHECK_IS_USER(); + CREATE_OK_REQUEST_PROMISE(); + td_->account_manager_->terminate_session(request.session_id_, std::move(promise)); +} + +void Requests::on_request(uint64 id, const td_api::terminateAllOtherSessions &request) { + CHECK_IS_USER(); + CREATE_OK_REQUEST_PROMISE(); + td_->account_manager_->terminate_all_other_sessions(std::move(promise)); +} + +void Requests::on_request(uint64 id, const td_api::confirmSession &request) { + CHECK_IS_USER(); + CREATE_OK_REQUEST_PROMISE(); + td_->account_manager_->confirm_session(request.session_id_, std::move(promise)); +} + +void Requests::on_request(uint64 id, const td_api::toggleSessionCanAcceptCalls &request) { + CHECK_IS_USER(); + CREATE_OK_REQUEST_PROMISE(); + td_->account_manager_->toggle_session_can_accept_calls(request.session_id_, request.can_accept_calls_, + std::move(promise)); +} + +void Requests::on_request(uint64 id, const td_api::toggleSessionCanAcceptSecretChats &request) { + CHECK_IS_USER(); + CREATE_OK_REQUEST_PROMISE(); + td_->account_manager_->toggle_session_can_accept_secret_chats(request.session_id_, request.can_accept_secret_chats_, + std::move(promise)); +} + +void Requests::on_request(uint64 id, const td_api::setInactiveSessionTtl &request) { + CHECK_IS_USER(); + CREATE_OK_REQUEST_PROMISE(); + td_->account_manager_->set_inactive_session_ttl_days(request.inactive_session_ttl_days_, std::move(promise)); +} + +void Requests::on_request(uint64 id, const td_api::getConnectedWebsites &request) { + CHECK_IS_USER(); + CREATE_REQUEST_PROMISE(); + td_->account_manager_->get_connected_websites(std::move(promise)); +} + +void Requests::on_request(uint64 id, const td_api::disconnectWebsite &request) { + CHECK_IS_USER(); + CREATE_OK_REQUEST_PROMISE(); + td_->account_manager_->disconnect_website(request.website_id_, std::move(promise)); +} + +void Requests::on_request(uint64 id, const td_api::disconnectAllWebsites &request) { + CHECK_IS_USER(); + CREATE_OK_REQUEST_PROMISE(); + td_->account_manager_->disconnect_all_websites(std::move(promise)); +} + +void Requests::on_request(uint64 id, const td_api::getMe &request) { + CREATE_NO_ARGS_REQUEST(GetMeRequest); +} + +void Requests::on_request(uint64 id, const td_api::getUser &request) { + CREATE_REQUEST(GetUserRequest, request.user_id_); +} + +void Requests::on_request(uint64 id, const td_api::getUserFullInfo &request) { + CREATE_REQUEST(GetUserFullInfoRequest, request.user_id_); +} + +void Requests::on_request(uint64 id, const td_api::getBasicGroup &request) { + CREATE_REQUEST(GetGroupRequest, request.basic_group_id_); +} + +void Requests::on_request(uint64 id, const td_api::getBasicGroupFullInfo &request) { + CREATE_REQUEST(GetGroupFullInfoRequest, request.basic_group_id_); +} + +void Requests::on_request(uint64 id, const td_api::getSupergroup &request) { + CREATE_REQUEST(GetSupergroupRequest, request.supergroup_id_); +} + +void Requests::on_request(uint64 id, const td_api::getSupergroupFullInfo &request) { + CREATE_REQUEST(GetSupergroupFullInfoRequest, request.supergroup_id_); +} + +void Requests::on_request(uint64 id, const td_api::getSecretChat &request) { + CREATE_REQUEST(GetSecretChatRequest, request.secret_chat_id_); +} + +void Requests::on_request(uint64 id, const td_api::getChat &request) { + CREATE_REQUEST(GetChatRequest, request.chat_id_); +} + +void Requests::on_request(uint64 id, const td_api::getMessage &request) { + CREATE_REQUEST(GetMessageRequest, request.chat_id_, request.message_id_); +} + +void Requests::on_request(uint64 id, const td_api::getMessageLocally &request) { + MessageFullId message_full_id(DialogId(request.chat_id_), MessageId(request.message_id_)); + send_closure(td_actor_, &Td::send_result, id, + td_->messages_manager_->get_message_object(message_full_id, "getMessageLocally")); +} + +void Requests::on_request(uint64 id, const td_api::getRepliedMessage &request) { + CREATE_REQUEST(GetRepliedMessageRequest, request.chat_id_, request.message_id_); +} + +void Requests::on_request(uint64 id, const td_api::getChatPinnedMessage &request) { + CREATE_REQUEST(GetChatPinnedMessageRequest, request.chat_id_); +} + +void Requests::on_request(uint64 id, const td_api::getCallbackQueryMessage &request) { + CHECK_IS_BOT(); + CREATE_REQUEST(GetCallbackQueryMessageRequest, request.chat_id_, request.message_id_, request.callback_query_id_); +} + +void Requests::on_request(uint64 id, const td_api::getMessages &request) { + CREATE_REQUEST(GetMessagesRequest, request.chat_id_, request.message_ids_); +} + +void Requests::on_request(uint64 id, const td_api::getMessageProperties &request) { + CREATE_REQUEST_PROMISE(); + td_->messages_manager_->get_message_properties(DialogId(request.chat_id_), MessageId(request.message_id_), + std::move(promise)); +} + +void Requests::on_request(uint64 id, const td_api::getChatSponsoredMessages &request) { + CHECK_IS_USER(); + CREATE_REQUEST_PROMISE(); + td_->sponsored_message_manager_->get_dialog_sponsored_messages(DialogId(request.chat_id_), std::move(promise)); +} + +void Requests::on_request(uint64 id, const td_api::clickChatSponsoredMessage &request) { + CHECK_IS_USER(); + CREATE_OK_REQUEST_PROMISE(); + td_->sponsored_message_manager_->click_sponsored_message(DialogId(request.chat_id_), MessageId(request.message_id_), + std::move(promise)); +} + +void Requests::on_request(uint64 id, const td_api::reportChatSponsoredMessage &request) { + CHECK_IS_USER(); + CREATE_REQUEST_PROMISE(); + td_->sponsored_message_manager_->report_sponsored_message(DialogId(request.chat_id_), MessageId(request.message_id_), + request.option_id_, std::move(promise)); +} + +void Requests::on_request(uint64 id, const td_api::getMessageThread &request) { + CHECK_IS_USER(); + CREATE_REQUEST(GetMessageThreadRequest, request.chat_id_, request.message_id_); +} + +void Requests::on_request(uint64 id, const td_api::getMessageReadDate &request) { + CHECK_IS_USER(); + CREATE_REQUEST_PROMISE(); + td_->messages_manager_->get_message_read_date({DialogId(request.chat_id_), MessageId(request.message_id_)}, + std::move(promise)); +} + +void Requests::on_request(uint64 id, const td_api::getMessageViewers &request) { + CHECK_IS_USER(); + CREATE_REQUEST_PROMISE(); + td_->messages_manager_->get_message_viewers({DialogId(request.chat_id_), MessageId(request.message_id_)}, + std::move(promise)); +} + +void Requests::on_request(uint64 id, const td_api::getMessageLink &request) { + auto r_message_link = td_->messages_manager_->get_message_link( + {DialogId(request.chat_id_), MessageId(request.message_id_)}, request.media_timestamp_, request.for_album_, + request.in_message_thread_); + if (r_message_link.is_error()) { + send_closure(td_actor_, &Td::send_error, id, r_message_link.move_as_error()); + } else { + send_closure(td_actor_, &Td::send_result, id, + td_api::make_object(r_message_link.ok().first, r_message_link.ok().second)); + } +} + +void Requests::on_request(uint64 id, const td_api::getMessageEmbeddingCode &request) { + CHECK_IS_USER(); + CREATE_REQUEST(GetMessageEmbeddingCodeRequest, request.chat_id_, request.message_id_, request.for_album_); +} + +void Requests::on_request(uint64 id, td_api::getMessageLinkInfo &request) { + CLEAN_INPUT_STRING(request.url_); + CREATE_REQUEST(GetMessageLinkInfoRequest, std::move(request.url_)); +} + +void Requests::on_request(uint64 id, td_api::translateText &request) { + CHECK_IS_USER(); + CLEAN_INPUT_STRING(request.to_language_code_); + CREATE_REQUEST_PROMISE(); + td_->translation_manager_->translate_text(std::move(request.text_), request.to_language_code_, std::move(promise)); +} + +void Requests::on_request(uint64 id, td_api::translateMessageText &request) { + CHECK_IS_USER(); + CLEAN_INPUT_STRING(request.to_language_code_); + CREATE_REQUEST_PROMISE(); + td_->messages_manager_->translate_message_text({DialogId(request.chat_id_), MessageId(request.message_id_)}, + request.to_language_code_, std::move(promise)); +} + +void Requests::on_request(uint64 id, const td_api::recognizeSpeech &request) { + CHECK_IS_USER(); + CREATE_OK_REQUEST_PROMISE(); + td_->transcription_manager_->recognize_speech({DialogId(request.chat_id_), MessageId(request.message_id_)}, + std::move(promise)); +} + +void Requests::on_request(uint64 id, const td_api::rateSpeechRecognition &request) { + CHECK_IS_USER(); + CREATE_OK_REQUEST_PROMISE(); + td_->transcription_manager_->rate_speech_recognition({DialogId(request.chat_id_), MessageId(request.message_id_)}, + request.is_good_, std::move(promise)); +} + +void Requests::on_request(uint64 id, const td_api::getFile &request) { + auto file_object = td_->file_manager_->get_file_object(FileId(request.file_id_, 0)); + if (file_object->id_ == 0) { + file_object = nullptr; + } else { + file_object->id_ = request.file_id_; + } + send_closure(td_actor_, &Td::send_result, id, std::move(file_object)); +} + +void Requests::on_request(uint64 id, td_api::getRemoteFile &request) { + CLEAN_INPUT_STRING(request.remote_file_id_); + auto file_type = request.file_type_ == nullptr ? FileType::Temp : get_file_type(*request.file_type_); + auto r_file_id = td_->file_manager_->from_persistent_id(request.remote_file_id_, file_type); + if (r_file_id.is_error()) { + send_closure(td_actor_, &Td::send_error, id, r_file_id.move_as_error()); + } else { + send_closure(td_actor_, &Td::send_result, id, td_->file_manager_->get_file_object(r_file_id.ok())); + } +} + +void Requests::on_request(uint64 id, td_api::getStorageStatistics &request) { + CREATE_REQUEST_PROMISE(); + auto query_promise = PromiseCreator::lambda([promise = std::move(promise)](Result result) mutable { + if (result.is_error()) { + promise.set_error(result.move_as_error()); + } else { + promise.set_value(result.ok().get_storage_statistics_object()); + } + }); + send_closure(td_->storage_manager_, &StorageManager::get_storage_stats, false /*need_all_files*/, request.chat_limit_, + std::move(query_promise)); +} + +void Requests::on_request(uint64 id, td_api::getStorageStatisticsFast &request) { + CHECK_IS_USER(); + CREATE_REQUEST_PROMISE(); + auto query_promise = PromiseCreator::lambda([promise = std::move(promise)](Result result) mutable { + if (result.is_error()) { + promise.set_error(result.move_as_error()); + } else { + promise.set_value(result.ok().get_storage_statistics_fast_object()); + } + }); + send_closure(td_->storage_manager_, &StorageManager::get_storage_stats_fast, std::move(query_promise)); +} + +void Requests::on_request(uint64 id, const td_api::getDatabaseStatistics &request) { + CREATE_REQUEST_PROMISE(); + auto query_promise = PromiseCreator::lambda([promise = std::move(promise)](Result result) mutable { + if (result.is_error()) { + promise.set_error(result.move_as_error()); + } else { + promise.set_value(result.ok().get_database_statistics_object()); + } + }); + send_closure(td_->storage_manager_, &StorageManager::get_database_stats, std::move(query_promise)); +} + +void Requests::on_request(uint64 id, td_api::optimizeStorage &request) { + std::vector file_types; + for (auto &file_type : request.file_types_) { + if (file_type == nullptr) { + return send_error_raw(id, 400, "File type must be non-empty"); + } + + file_types.push_back(get_file_type(*file_type)); + } + FileGcParameters parameters(request.size_, request.ttl_, request.count_, request.immunity_delay_, + std::move(file_types), DialogId::get_dialog_ids(request.chat_ids_), + DialogId::get_dialog_ids(request.exclude_chat_ids_), request.chat_limit_); + + CREATE_REQUEST_PROMISE(); + auto query_promise = PromiseCreator::lambda([promise = std::move(promise)](Result result) mutable { + if (result.is_error()) { + promise.set_error(result.move_as_error()); + } else { + promise.set_value(result.ok().get_storage_statistics_object()); + } + }); + send_closure(td_->storage_manager_, &StorageManager::run_gc, std::move(parameters), + request.return_deleted_file_statistics_, std::move(query_promise)); +} + +void Requests::on_request(uint64 id, td_api::getNetworkStatistics &request) { + if (td_->net_stats_manager_.empty()) { + return send_error_raw(id, 400, "Network statistics are disabled"); + } + if (!request.only_current_ && G()->get_option_boolean("disable_persistent_network_statistics")) { + return send_error_raw(id, 400, "Persistent network statistics are disabled"); + } + CREATE_REQUEST_PROMISE(); + auto query_promise = PromiseCreator::lambda([promise = std::move(promise)](Result result) mutable { + if (result.is_error()) { + promise.set_error(result.move_as_error()); + } else { + promise.set_value(result.ok().get_network_statistics_object()); + } + }); + send_closure(td_->net_stats_manager_, &NetStatsManager::get_network_stats, request.only_current_, + std::move(query_promise)); +} + +void Requests::on_request(uint64 id, td_api::resetNetworkStatistics &request) { + if (td_->net_stats_manager_.empty()) { + return send_error_raw(id, 400, "Network statistics are disabled"); + } + CREATE_OK_REQUEST_PROMISE(); + send_closure(td_->net_stats_manager_, &NetStatsManager::reset_network_stats); + promise.set_value(Unit()); +} + +void Requests::on_request(uint64 id, td_api::addNetworkStatistics &request) { + if (request.entry_ == nullptr) { + return send_error_raw(id, 400, "Network statistics entry must be non-empty"); + } + if (td_->net_stats_manager_.empty()) { + return send_error_raw(id, 400, "Network statistics are disabled"); + } + + NetworkStatsEntry entry; + switch (request.entry_->get_id()) { + case td_api::networkStatisticsEntryFile::ID: { + auto file_entry = move_tl_object_as(request.entry_); + entry.is_call = false; + if (file_entry->file_type_ != nullptr) { + entry.file_type = get_file_type(*file_entry->file_type_); + } + entry.net_type = get_net_type(file_entry->network_type_); + entry.rx = file_entry->received_bytes_; + entry.tx = file_entry->sent_bytes_; + break; + } + case td_api::networkStatisticsEntryCall::ID: { + auto call_entry = move_tl_object_as(request.entry_); + entry.is_call = true; + entry.net_type = get_net_type(call_entry->network_type_); + entry.rx = call_entry->received_bytes_; + entry.tx = call_entry->sent_bytes_; + entry.duration = call_entry->duration_; + break; + } + default: + UNREACHABLE(); + } + + if (entry.net_type == NetType::None) { + return send_error_raw(id, 400, "Network statistics entry can't be increased for NetworkTypeNone"); + } + if (entry.rx > (static_cast(1) << 40) || entry.rx < 0) { + return send_error_raw(id, 400, "Wrong received bytes value"); + } + if (entry.tx > (static_cast(1) << 40) || entry.tx < 0) { + return send_error_raw(id, 400, "Wrong sent bytes value"); + } + if (entry.count > (1 << 30) || entry.count < 0) { + return send_error_raw(id, 400, "Wrong count value"); + } + if (entry.duration > (1 << 30) || entry.duration < 0) { + return send_error_raw(id, 400, "Wrong duration value"); + } + + send_closure(td_->net_stats_manager_, &NetStatsManager::add_network_stats, entry); + send_closure(td_actor_, &Td::send_result, id, td_api::make_object()); +} + +void Requests::on_request(uint64 id, const td_api::setNetworkType &request) { + CREATE_OK_REQUEST_PROMISE(); + send_closure(td_->state_manager_, &StateManager::on_network, get_net_type(request.type_)); + promise.set_value(Unit()); +} + +void Requests::on_request(uint64 id, const td_api::getAutoDownloadSettingsPresets &request) { + CHECK_IS_USER(); + CREATE_REQUEST_PROMISE(); + get_auto_download_settings_presets(td_, std::move(promise)); +} + +void Requests::on_request(uint64 id, const td_api::setAutoDownloadSettings &request) { + CHECK_IS_USER(); + if (request.settings_ == nullptr) { + return send_error_raw(id, 400, "New settings must be non-empty"); + } + CREATE_OK_REQUEST_PROMISE(); + set_auto_download_settings(td_, get_net_type(request.type_), get_auto_download_settings(request.settings_), + std::move(promise)); +} + +void Requests::on_request(uint64 id, const td_api::getAutosaveSettings &request) { + CHECK_IS_USER(); + CREATE_REQUEST_PROMISE(); + td_->autosave_manager_->get_autosave_settings(std::move(promise)); +} + +void Requests::on_request(uint64 id, td_api::setAutosaveSettings &request) { + CHECK_IS_USER(); + CREATE_OK_REQUEST_PROMISE(); + td_->autosave_manager_->set_autosave_settings(std::move(request.scope_), std::move(request.settings_), + std::move(promise)); +} + +void Requests::on_request(uint64 id, const td_api::clearAutosaveSettingsExceptions &request) { + CHECK_IS_USER(); + CREATE_OK_REQUEST_PROMISE(); + td_->autosave_manager_->clear_autosave_settings_exceptions(std::move(promise)); +} + +void Requests::on_request(uint64 id, const td_api::getRecommendedChats &request) { + CHECK_IS_USER(); + CREATE_REQUEST_PROMISE(); + td_->channel_recommendation_manager_->get_recommended_channels(std::move(promise)); +} + +void Requests::on_request(uint64 id, const td_api::getChatSimilarChats &request) { + CHECK_IS_USER(); + CREATE_REQUEST_PROMISE(); + td_->channel_recommendation_manager_->get_channel_recommendations(DialogId(request.chat_id_), false, + std::move(promise), Auto()); +} + +void Requests::on_request(uint64 id, const td_api::getChatSimilarChatCount &request) { + CHECK_IS_USER(); + CREATE_REQUEST_PROMISE(); + td_->channel_recommendation_manager_->get_channel_recommendations(DialogId(request.chat_id_), request.return_local_, + Auto(), std::move(promise)); +} + +void Requests::on_request(uint64 id, const td_api::openChatSimilarChat &request) { + CHECK_IS_USER(); + CREATE_OK_REQUEST_PROMISE(); + td_->channel_recommendation_manager_->open_channel_recommended_channel( + DialogId(request.chat_id_), DialogId(request.opened_chat_id_), std::move(promise)); +} + +void Requests::on_request(uint64 id, const td_api::getTopChats &request) { + CHECK_IS_USER(); + CREATE_REQUEST_PROMISE(); + send_closure(td_->top_dialog_manager_actor_, &TopDialogManager::get_top_dialogs, + get_top_dialog_category(request.category_), request.limit_, std::move(promise)); +} + +void Requests::on_request(uint64 id, const td_api::removeTopChat &request) { + CHECK_IS_USER(); + CREATE_OK_REQUEST_PROMISE(); + send_closure(td_->top_dialog_manager_actor_, &TopDialogManager::remove_dialog, + get_top_dialog_category(request.category_), DialogId(request.chat_id_), std::move(promise)); +} + +void Requests::on_request(uint64 id, const td_api::loadChats &request) { + CHECK_IS_USER(); + + DialogListId dialog_list_id(request.chat_list_); + auto r_offset = td_->messages_manager_->get_dialog_list_last_date(dialog_list_id); + if (r_offset.is_error()) { + return send_error_raw(id, 400, r_offset.error().message()); + } + auto offset = r_offset.move_as_ok(); + if (offset == MAX_DIALOG_DATE) { + return send_closure(td_actor_, &Td::send_result, id, nullptr); + } + + CREATE_REQUEST(LoadChatsRequest, dialog_list_id, offset, request.limit_); +} + +void Requests::on_request(uint64 id, const td_api::getChats &request) { + CHECK_IS_USER(); + CREATE_REQUEST_PROMISE(); + td_->messages_manager_->get_dialogs_from_list(DialogListId(request.chat_list_), request.limit_, std::move(promise)); +} + +void Requests::on_request(uint64 id, const td_api::loadSavedMessagesTopics &request) { + CHECK_IS_USER(); + CREATE_OK_REQUEST_PROMISE(); + td_->saved_messages_manager_->load_saved_messages_topics(request.limit_, std::move(promise)); +} + +void Requests::on_request(uint64 id, const td_api::getSavedMessagesTopicHistory &request) { + CHECK_IS_USER(); + CREATE_REQUEST_PROMISE(); + td_->saved_messages_manager_->get_saved_messages_topic_history( + td_->saved_messages_manager_->get_topic_id(request.saved_messages_topic_id_), MessageId(request.from_message_id_), + request.offset_, request.limit_, std::move(promise)); +} + +void Requests::on_request(uint64 id, const td_api::getSavedMessagesTopicMessageByDate &request) { + CHECK_IS_USER(); + CREATE_REQUEST_PROMISE(); + td_->saved_messages_manager_->get_saved_messages_topic_message_by_date( + td_->saved_messages_manager_->get_topic_id(request.saved_messages_topic_id_), request.date_, std::move(promise)); +} + +void Requests::on_request(uint64 id, const td_api::deleteSavedMessagesTopicHistory &request) { + CHECK_IS_USER(); + CREATE_OK_REQUEST_PROMISE(); + td_->saved_messages_manager_->delete_saved_messages_topic_history( + td_->saved_messages_manager_->get_topic_id(request.saved_messages_topic_id_), std::move(promise)); +} + +void Requests::on_request(uint64 id, const td_api::deleteSavedMessagesTopicMessagesByDate &request) { + CHECK_IS_USER(); + CREATE_OK_REQUEST_PROMISE(); + td_->saved_messages_manager_->delete_saved_messages_topic_messages_by_date( + td_->saved_messages_manager_->get_topic_id(request.saved_messages_topic_id_), request.min_date_, + request.max_date_, std::move(promise)); +} + +void Requests::on_request(uint64 id, const td_api::toggleSavedMessagesTopicIsPinned &request) { + CHECK_IS_USER(); + CREATE_OK_REQUEST_PROMISE(); + td_->saved_messages_manager_->toggle_saved_messages_topic_is_pinned( + td_->saved_messages_manager_->get_topic_id(request.saved_messages_topic_id_), request.is_pinned_, + std::move(promise)); +} + +void Requests::on_request(uint64 id, const td_api::setPinnedSavedMessagesTopics &request) { + CHECK_IS_USER(); + CREATE_OK_REQUEST_PROMISE(); + td_->saved_messages_manager_->set_pinned_saved_messages_topics( + td_->saved_messages_manager_->get_topic_ids(request.saved_messages_topic_ids_), std::move(promise)); +} + +void Requests::on_request(uint64 id, td_api::searchPublicChat &request) { + CLEAN_INPUT_STRING(request.username_); + CREATE_REQUEST(SearchPublicChatRequest, request.username_); +} + +void Requests::on_request(uint64 id, td_api::searchPublicChats &request) { + CHECK_IS_USER(); + CLEAN_INPUT_STRING(request.query_); + CREATE_REQUEST(SearchPublicChatsRequest, request.query_); +} + +void Requests::on_request(uint64 id, td_api::searchChats &request) { + CHECK_IS_USER(); + CLEAN_INPUT_STRING(request.query_); + CREATE_REQUEST(SearchChatsRequest, request.query_, request.limit_); +} + +void Requests::on_request(uint64 id, td_api::searchChatsOnServer &request) { + CHECK_IS_USER(); + CLEAN_INPUT_STRING(request.query_); + CREATE_REQUEST(SearchChatsOnServerRequest, request.query_, request.limit_); +} + +void Requests::on_request(uint64 id, const td_api::searchChatsNearby &request) { + CHECK_IS_USER(); + CREATE_REQUEST_PROMISE(); + td_->people_nearby_manager_->search_dialogs_nearby(Location(request.location_), std::move(promise)); +} + +void Requests::on_request(uint64 id, const td_api::getGroupsInCommon &request) { + CHECK_IS_USER(); + CREATE_REQUEST(GetGroupsInCommonRequest, request.user_id_, request.offset_chat_id_, request.limit_); +} + +void Requests::on_request(uint64 id, td_api::checkChatUsername &request) { + CHECK_IS_USER(); + CLEAN_INPUT_STRING(request.username_); + CREATE_REQUEST_PROMISE(); + auto query_promise = PromiseCreator::lambda( + [promise = std::move(promise)](Result result) mutable { + if (result.is_error()) { + promise.set_error(result.move_as_error()); + } else { + promise.set_value(DialogManager::get_check_chat_username_result_object(result.ok())); + } + }); + td_->dialog_manager_->check_dialog_username(DialogId(request.chat_id_), request.username_, std::move(query_promise)); +} + +void Requests::on_request(uint64 id, const td_api::getCreatedPublicChats &request) { + CHECK_IS_USER(); + CREATE_REQUEST_PROMISE(); + td_->chat_manager_->get_created_public_dialogs(get_public_dialog_type(request.type_), std::move(promise), false); +} + +void Requests::on_request(uint64 id, const td_api::checkCreatedPublicChatsLimit &request) { + CHECK_IS_USER(); + CREATE_OK_REQUEST_PROMISE(); + td_->chat_manager_->check_created_public_dialogs_limit(get_public_dialog_type(request.type_), std::move(promise)); +} + +void Requests::on_request(uint64 id, const td_api::getSuitableDiscussionChats &request) { + CHECK_IS_USER(); + CREATE_NO_ARGS_REQUEST(GetSuitableDiscussionChatsRequest); +} + +void Requests::on_request(uint64 id, const td_api::getInactiveSupergroupChats &request) { + CHECK_IS_USER(); + CREATE_NO_ARGS_REQUEST(GetInactiveSupergroupChatsRequest); +} + +void Requests::on_request(uint64 id, const td_api::getSuitablePersonalChats &request) { + CHECK_IS_USER(); + CREATE_REQUEST_PROMISE(); + td_->chat_manager_->get_created_public_dialogs(PublicDialogType::ForPersonalDialog, std::move(promise), false); +} + +void Requests::on_request(uint64 id, td_api::searchRecentlyFoundChats &request) { + CHECK_IS_USER(); + CLEAN_INPUT_STRING(request.query_); + CREATE_REQUEST(SearchRecentlyFoundChatsRequest, request.query_, request.limit_); +} + +void Requests::on_request(uint64 id, const td_api::addRecentlyFoundChat &request) { + CHECK_IS_USER(); + answer_ok_query(id, td_->messages_manager_->add_recently_found_dialog(DialogId(request.chat_id_))); +} + +void Requests::on_request(uint64 id, const td_api::removeRecentlyFoundChat &request) { + CHECK_IS_USER(); + answer_ok_query(id, td_->messages_manager_->remove_recently_found_dialog(DialogId(request.chat_id_))); +} + +void Requests::on_request(uint64 id, const td_api::clearRecentlyFoundChats &request) { + CHECK_IS_USER(); + td_->messages_manager_->clear_recently_found_dialogs(); + send_closure(td_actor_, &Td::send_result, id, td_api::make_object()); +} + +void Requests::on_request(uint64 id, const td_api::getRecentlyOpenedChats &request) { + CHECK_IS_USER(); + CREATE_REQUEST(GetRecentlyOpenedChatsRequest, request.limit_); +} + +void Requests::on_request(uint64 id, const td_api::openChat &request) { + CHECK_IS_USER(); + answer_ok_query(id, td_->messages_manager_->open_dialog(DialogId(request.chat_id_))); +} + +void Requests::on_request(uint64 id, const td_api::closeChat &request) { + CHECK_IS_USER(); + answer_ok_query(id, td_->messages_manager_->close_dialog(DialogId(request.chat_id_))); +} + +void Requests::on_request(uint64 id, const td_api::viewMessages &request) { + CHECK_IS_USER(); + answer_ok_query(id, td_->messages_manager_->view_messages(DialogId(request.chat_id_), + MessageId::get_message_ids(request.message_ids_), + get_message_source(request.source_), request.force_read_)); +} + +void Requests::on_request(uint64 id, const td_api::openMessageContent &request) { + CHECK_IS_USER(); + answer_ok_query( + id, td_->messages_manager_->open_message_content({DialogId(request.chat_id_), MessageId(request.message_id_)})); +} + +void Requests::on_request(uint64 id, const td_api::clickAnimatedEmojiMessage &request) { + CHECK_IS_USER(); + CREATE_REQUEST_PROMISE(); + td_->messages_manager_->click_animated_emoji_message({DialogId(request.chat_id_), MessageId(request.message_id_)}, + std::move(promise)); +} + +void Requests::on_request(uint64 id, const td_api::getInternalLink &request) { + auto r_link = LinkManager::get_internal_link(request.type_, !request.is_http_); + if (r_link.is_error()) { + send_closure(td_actor_, &Td::send_error, id, r_link.move_as_error()); + } else { + send_closure(td_actor_, &Td::send_result, id, td_api::make_object(r_link.move_as_ok())); + } +} + +void Requests::on_request(uint64 id, const td_api::getInternalLinkType &request) { + auto type = LinkManager::parse_internal_link(request.link_); + send_closure(td_actor_, &Td::send_result, id, type == nullptr ? nullptr : type->get_internal_link_type_object()); +} + +void Requests::on_request(uint64 id, td_api::getExternalLinkInfo &request) { + CHECK_IS_USER(); + CLEAN_INPUT_STRING(request.link_); + CREATE_REQUEST_PROMISE(); + td_->link_manager_->get_external_link_info(std::move(request.link_), std::move(promise)); +} + +void Requests::on_request(uint64 id, td_api::getExternalLink &request) { + CHECK_IS_USER(); + CLEAN_INPUT_STRING(request.link_); + CREATE_REQUEST_PROMISE(); + td_->link_manager_->get_link_login_url(request.link_, request.allow_write_access_, std::move(promise)); +} + +void Requests::on_request(uint64 id, const td_api::getChatHistory &request) { + CHECK_IS_USER(); + CREATE_REQUEST(GetChatHistoryRequest, request.chat_id_, request.from_message_id_, request.offset_, request.limit_, + request.only_local_); +} + +void Requests::on_request(uint64 id, const td_api::deleteChatHistory &request) { + CHECK_IS_USER(); + CREATE_OK_REQUEST_PROMISE(); + td_->messages_manager_->delete_dialog_history(DialogId(request.chat_id_), request.remove_from_chat_list_, + request.revoke_, std::move(promise)); +} + +void Requests::on_request(uint64 id, const td_api::deleteChat &request) { + CHECK_IS_USER(); + CREATE_OK_REQUEST_PROMISE(); + DialogId dialog_id(request.chat_id_); + auto query_promise = [actor_id = td_->messages_manager_actor_.get(), dialog_id, + promise = std::move(promise)](Result &&result) mutable { + if (result.is_error()) { + promise.set_error(result.move_as_error()); + } else { + send_closure(actor_id, &MessagesManager::on_dialog_deleted, dialog_id, std::move(promise)); + } + }; + td_->dialog_manager_->delete_dialog(dialog_id, std::move(query_promise)); +} + +void Requests::on_request(uint64 id, const td_api::getMessageThreadHistory &request) { + CHECK_IS_USER(); + CREATE_REQUEST(GetMessageThreadHistoryRequest, request.chat_id_, request.message_id_, request.from_message_id_, + request.offset_, request.limit_); +} + +void Requests::on_request(uint64 id, const td_api::getChatMessageCalendar &request) { + CHECK_IS_USER(); + CREATE_REQUEST_PROMISE(); + td_->messages_manager_->get_dialog_message_calendar( + DialogId(request.chat_id_), td_->saved_messages_manager_->get_topic_id(request.saved_messages_topic_id_), + MessageId(request.from_message_id_), get_message_search_filter(request.filter_), std::move(promise)); +} + +void Requests::on_request(uint64 id, td_api::searchChatMessages &request) { + CHECK_IS_USER(); + CLEAN_INPUT_STRING(request.query_); + CREATE_REQUEST(SearchChatMessagesRequest, request.chat_id_, std::move(request.query_), std::move(request.sender_id_), + request.from_message_id_, request.offset_, request.limit_, std::move(request.filter_), + request.message_thread_id_, + td_->saved_messages_manager_->get_topic_id(request.saved_messages_topic_id_), ReactionType()); +} + +void Requests::on_request(uint64 id, td_api::searchSecretMessages &request) { + CHECK_IS_USER(); + CLEAN_INPUT_STRING(request.query_); + CLEAN_INPUT_STRING(request.offset_); + CREATE_REQUEST_PROMISE(); + td_->messages_manager_->offline_search_messages(DialogId(request.chat_id_), std::move(request.query_), + std::move(request.offset_), request.limit_, + get_message_search_filter(request.filter_), std::move(promise)); +} + +void Requests::on_request(uint64 id, td_api::searchMessages &request) { + CHECK_IS_USER(); + CLEAN_INPUT_STRING(request.query_); + CLEAN_INPUT_STRING(request.offset_); + CREATE_REQUEST_PROMISE(); + td_->messages_manager_->search_messages( + DialogListId(request.chat_list_), request.chat_list_ == nullptr, request.only_in_channels_, + std::move(request.query_), std::move(request.offset_), request.limit_, get_message_search_filter(request.filter_), + request.min_date_, request.max_date_, std::move(promise)); +} + +void Requests::on_request(uint64 id, td_api::searchSavedMessages &request) { + CHECK_IS_USER(); + CLEAN_INPUT_STRING(request.query_); + CREATE_REQUEST(SearchChatMessagesRequest, td_->dialog_manager_->get_my_dialog_id().get(), std::move(request.query_), + nullptr, request.from_message_id_, request.offset_, request.limit_, nullptr, 0, + td_->saved_messages_manager_->get_topic_id(request.saved_messages_topic_id_), + ReactionType(request.tag_)); +} + +void Requests::on_request(uint64 id, const td_api::searchCallMessages &request) { + CHECK_IS_USER(); + CREATE_REQUEST_PROMISE(); + td_->messages_manager_->search_call_messages(request.offset_, request.limit_, request.only_missed_, + std::move(promise)); +} + +void Requests::on_request(uint64 id, td_api::searchOutgoingDocumentMessages &request) { + CHECK_IS_USER(); + CLEAN_INPUT_STRING(request.query_); + CREATE_REQUEST_PROMISE(); + td_->messages_manager_->search_outgoing_document_messages(request.query_, request.limit_, std::move(promise)); +} + +void Requests::on_request(uint64 id, td_api::searchPublicMessagesByTag &request) { + CHECK_IS_USER(); + CLEAN_INPUT_STRING(request.tag_); + CLEAN_INPUT_STRING(request.offset_); + CREATE_REQUEST_PROMISE(); + td_->messages_manager_->search_hashtag_posts(std::move(request.tag_), std::move(request.offset_), request.limit_, + std::move(promise)); +} + +void Requests::on_request(uint64 id, td_api::searchPublicStoriesByTag &request) { + CHECK_IS_USER(); + CLEAN_INPUT_STRING(request.tag_); + CLEAN_INPUT_STRING(request.offset_); + CREATE_REQUEST_PROMISE(); + td_->story_manager_->search_hashtag_posts(std::move(request.tag_), std::move(request.offset_), request.limit_, + std::move(promise)); +} + +void Requests::on_request(uint64 id, td_api::searchPublicStoriesByLocation &request) { + CHECK_IS_USER(); + if (request.address_ == nullptr) { + return send_error_raw(id, 400, "Address must be non-empty"); + } + CLEAN_INPUT_STRING(request.address_->country_code_); + CLEAN_INPUT_STRING(request.address_->state_); + CLEAN_INPUT_STRING(request.address_->city_); + CLEAN_INPUT_STRING(request.address_->street_); + CLEAN_INPUT_STRING(request.offset_); + CREATE_REQUEST_PROMISE(); + td_->story_manager_->search_location_posts(std::move(request.address_), std::move(request.offset_), request.limit_, + std::move(promise)); +} + +void Requests::on_request(uint64 id, td_api::searchPublicStoriesByVenue &request) { + CHECK_IS_USER(); + CLEAN_INPUT_STRING(request.venue_provider_); + CLEAN_INPUT_STRING(request.venue_id_); + CLEAN_INPUT_STRING(request.offset_); + CREATE_REQUEST_PROMISE(); + td_->story_manager_->search_venue_posts(std::move(request.venue_provider_), std::move(request.venue_id_), + std::move(request.offset_), request.limit_, std::move(promise)); +} + +void Requests::on_request(uint64 id, td_api::getSearchedForTags &request) { + CHECK_IS_USER(); + CLEAN_INPUT_STRING(request.tag_prefix_); + CREATE_REQUEST_PROMISE(); + auto query_promise = PromiseCreator::lambda([promise = std::move(promise)](Result> result) mutable { + if (result.is_error()) { + promise.set_error(result.move_as_error()); + } else { + promise.set_value(td_api::make_object(result.move_as_ok())); + } + }); + send_closure(request.tag_prefix_[0] == '$' ? td_->cashtag_search_hints_ : td_->hashtag_search_hints_, + &HashtagHints::query, std::move(request.tag_prefix_), request.limit_, std::move(query_promise)); +} + +void Requests::on_request(uint64 id, td_api::removeSearchedForTag &request) { + CHECK_IS_USER(); + CLEAN_INPUT_STRING(request.tag_); + CREATE_OK_REQUEST_PROMISE(); + send_closure(request.tag_[0] == '$' ? td_->cashtag_search_hints_ : td_->hashtag_search_hints_, + &HashtagHints::remove_hashtag, std::move(request.tag_), std::move(promise)); +} + +void Requests::on_request(uint64 id, td_api::clearSearchedForTags &request) { + CHECK_IS_USER(); + CREATE_OK_REQUEST_PROMISE(); + send_closure(request.clear_cashtags_ ? td_->cashtag_search_hints_ : td_->hashtag_search_hints_, &HashtagHints::clear, + std::move(promise)); +} + +void Requests::on_request(uint64 id, const td_api::deleteAllCallMessages &request) { + CHECK_IS_USER(); + CREATE_OK_REQUEST_PROMISE(); + td_->messages_manager_->delete_all_call_messages(request.revoke_, std::move(promise)); +} + +void Requests::on_request(uint64 id, const td_api::searchChatRecentLocationMessages &request) { + CHECK_IS_USER(); + CREATE_REQUEST_PROMISE(); + td_->messages_manager_->search_dialog_recent_location_messages(DialogId(request.chat_id_), request.limit_, + std::move(promise)); +} + +void Requests::on_request(uint64 id, const td_api::getChatMessageByDate &request) { + CHECK_IS_USER(); + CREATE_REQUEST_PROMISE(); + td_->messages_manager_->get_dialog_message_by_date(DialogId(request.chat_id_), request.date_, std::move(promise)); +} + +void Requests::on_request(uint64 id, const td_api::getChatSparseMessagePositions &request) { + CHECK_IS_USER(); + CREATE_REQUEST_PROMISE(); + td_->messages_manager_->get_dialog_sparse_message_positions( + DialogId(request.chat_id_), td_->saved_messages_manager_->get_topic_id(request.saved_messages_topic_id_), + get_message_search_filter(request.filter_), MessageId(request.from_message_id_), request.limit_, + std::move(promise)); +} + +void Requests::on_request(uint64 id, const td_api::getChatMessageCount &request) { + CHECK_IS_USER(); + CREATE_REQUEST_PROMISE(); + auto query_promise = PromiseCreator::lambda([promise = std::move(promise)](Result result) mutable { + if (result.is_error()) { + promise.set_error(result.move_as_error()); + } else { + promise.set_value(td_api::make_object(result.move_as_ok())); + } + }); + td_->messages_manager_->get_dialog_message_count( + DialogId(request.chat_id_), td_->saved_messages_manager_->get_topic_id(request.saved_messages_topic_id_), + get_message_search_filter(request.filter_), request.return_local_, std::move(query_promise)); +} + +void Requests::on_request(uint64 id, const td_api::getChatMessagePosition &request) { + CHECK_IS_USER(); + CREATE_REQUEST_PROMISE(); + auto query_promise = PromiseCreator::lambda([promise = std::move(promise)](Result result) mutable { + if (result.is_error()) { + promise.set_error(result.move_as_error()); + } else { + promise.set_value(td_api::make_object(result.move_as_ok())); + } + }); + td_->messages_manager_->get_dialog_message_position( + {DialogId(request.chat_id_), MessageId(request.message_id_)}, get_message_search_filter(request.filter_), + MessageId(request.message_thread_id_), + td_->saved_messages_manager_->get_topic_id(request.saved_messages_topic_id_), std::move(query_promise)); +} + +void Requests::on_request(uint64 id, const td_api::getChatScheduledMessages &request) { + CHECK_IS_USER(); + CREATE_REQUEST(GetChatScheduledMessagesRequest, request.chat_id_); +} + +void Requests::on_request(uint64 id, const td_api::getEmojiReaction &request) { + CHECK_IS_USER(); + CREATE_REQUEST_PROMISE(); + td_->reaction_manager_->get_emoji_reaction(request.emoji_, std::move(promise)); +} + +void Requests::on_request(uint64 id, const td_api::getCustomEmojiReactionAnimations &request) { + CHECK_IS_USER(); + CREATE_REQUEST_PROMISE(); + td_->stickers_manager_->get_custom_emoji_reaction_generic_animations(false, std::move(promise)); +} + +void Requests::on_request(uint64 id, const td_api::getMessageAvailableReactions &request) { + CHECK_IS_USER(); + auto r_reactions = td_->messages_manager_->get_message_available_reactions( + {DialogId(request.chat_id_), MessageId(request.message_id_)}, request.row_size_); + if (r_reactions.is_error()) { + send_closure(td_actor_, &Td::send_error, id, r_reactions.move_as_error()); + } else { + send_closure(td_actor_, &Td::send_result, id, r_reactions.move_as_ok()); + } +} + +void Requests::on_request(uint64 id, const td_api::clearRecentReactions &request) { + CHECK_IS_USER(); + CREATE_OK_REQUEST_PROMISE(); + td_->reaction_manager_->clear_recent_reactions(std::move(promise)); +} + +void Requests::on_request(uint64 id, const td_api::addMessageReaction &request) { + CHECK_IS_USER(); + CREATE_OK_REQUEST_PROMISE(); + td_->messages_manager_->add_message_reaction({DialogId(request.chat_id_), MessageId(request.message_id_)}, + ReactionType(request.reaction_type_), request.is_big_, + request.update_recent_reactions_, std::move(promise)); +} + +void Requests::on_request(uint64 id, const td_api::addPendingPaidMessageReaction &request) { + CHECK_IS_USER(); + CREATE_OK_REQUEST_PROMISE(); + td_->messages_manager_->add_paid_message_reaction({DialogId(request.chat_id_), MessageId(request.message_id_)}, + request.star_count_, request.use_default_is_anonymous_, + request.is_anonymous_, std::move(promise)); +} + +void Requests::on_request(uint64 id, const td_api::commitPendingPaidMessageReactions &request) { + CHECK_IS_USER(); + CREATE_OK_REQUEST_PROMISE(); + td_->messages_manager_->commit_paid_message_reactions({DialogId(request.chat_id_), MessageId(request.message_id_)}, + std::move(promise)); +} + +void Requests::on_request(uint64 id, const td_api::removePendingPaidMessageReactions &request) { + CHECK_IS_USER(); + CREATE_OK_REQUEST_PROMISE(); + td_->messages_manager_->remove_paid_message_reactions({DialogId(request.chat_id_), MessageId(request.message_id_)}, + std::move(promise)); +} + +void Requests::on_request(uint64 id, const td_api::togglePaidMessageReactionIsAnonymous &request) { + CHECK_IS_USER(); + CREATE_OK_REQUEST_PROMISE(); + td_->messages_manager_->toggle_paid_message_reaction_is_anonymous( + {DialogId(request.chat_id_), MessageId(request.message_id_)}, request.is_anonymous_, std::move(promise)); +} + +void Requests::on_request(uint64 id, const td_api::removeMessageReaction &request) { + CHECK_IS_USER(); + CREATE_OK_REQUEST_PROMISE(); + td_->messages_manager_->remove_message_reaction({DialogId(request.chat_id_), MessageId(request.message_id_)}, + ReactionType(request.reaction_type_), std::move(promise)); +} + +void Requests::on_request(uint64 id, const td_api::setMessageReactions &request) { + CHECK_IS_BOT(); + CREATE_OK_REQUEST_PROMISE(); + set_message_reactions(td_, {DialogId(request.chat_id_), MessageId(request.message_id_)}, + ReactionType::get_reaction_types(request.reaction_types_), request.is_big_, std::move(promise)); +} + +void Requests::on_request(uint64 id, td_api::getMessageAddedReactions &request) { + CHECK_IS_USER(); + CLEAN_INPUT_STRING(request.offset_); + CREATE_REQUEST_PROMISE(); + get_message_added_reactions(td_, {DialogId(request.chat_id_), MessageId(request.message_id_)}, + ReactionType(request.reaction_type_), std::move(request.offset_), request.limit_, + std::move(promise)); +} + +void Requests::on_request(uint64 id, const td_api::setDefaultReactionType &request) { + CHECK_IS_USER(); + CREATE_OK_REQUEST_PROMISE(); + td_->reaction_manager_->set_default_reaction(ReactionType(request.reaction_type_), std::move(promise)); +} + +void Requests::on_request(uint64 id, const td_api::getSavedMessagesTags &request) { + CHECK_IS_USER(); + CREATE_REQUEST_PROMISE(); + td_->reaction_manager_->get_saved_messages_tags( + td_->saved_messages_manager_->get_topic_id(request.saved_messages_topic_id_), std::move(promise)); +} + +void Requests::on_request(uint64 id, td_api::setSavedMessagesTagLabel &request) { + CHECK_IS_USER(); + CLEAN_INPUT_STRING(request.label_); + CREATE_OK_REQUEST_PROMISE(); + td_->reaction_manager_->set_saved_messages_tag_title(ReactionType(request.tag_), std::move(request.label_), + std::move(promise)); +} + +void Requests::on_request(uint64 id, const td_api::getMessageEffect &request) { + CHECK_IS_USER(); + CREATE_REQUEST_PROMISE(); + td_->reaction_manager_->get_message_effect(MessageEffectId(request.effect_id_), std::move(promise)); +} + +void Requests::on_request(uint64 id, td_api::getMessagePublicForwards &request) { + CHECK_IS_USER(); + CLEAN_INPUT_STRING(request.offset_); + CREATE_REQUEST_PROMISE(); + td_->statistics_manager_->get_message_public_forwards({DialogId(request.chat_id_), MessageId(request.message_id_)}, + std::move(request.offset_), request.limit_, std::move(promise)); +} + +void Requests::on_request(uint64 id, td_api::getStoryPublicForwards &request) { + CHECK_IS_USER(); + CLEAN_INPUT_STRING(request.offset_); + CREATE_REQUEST_PROMISE(); + td_->statistics_manager_->get_story_public_forwards( + {DialogId(request.story_sender_chat_id_), StoryId(request.story_id_)}, std::move(request.offset_), request.limit_, + std::move(promise)); +} + +void Requests::on_request(uint64 id, const td_api::removeNotification &request) { + CHECK_IS_USER(); + CREATE_OK_REQUEST_PROMISE(); + send_closure(td_->notification_manager_actor_, &NotificationManager::remove_notification, + NotificationGroupId(request.notification_group_id_), NotificationId(request.notification_id_), false, + true, std::move(promise), "td_api::removeNotification"); +} + +void Requests::on_request(uint64 id, const td_api::removeNotificationGroup &request) { + CHECK_IS_USER(); + CREATE_OK_REQUEST_PROMISE(); + send_closure(td_->notification_manager_actor_, &NotificationManager::remove_notification_group, + NotificationGroupId(request.notification_group_id_), NotificationId(request.max_notification_id_), + NotificationObjectId(), -1, true, std::move(promise)); +} + +void Requests::on_request(uint64 id, const td_api::deleteMessages &request) { + CREATE_OK_REQUEST_PROMISE(); + td_->messages_manager_->delete_messages(DialogId(request.chat_id_), MessageId::get_message_ids(request.message_ids_), + request.revoke_, std::move(promise)); +} + +void Requests::on_request(uint64 id, const td_api::deleteChatMessagesBySender &request) { + CHECK_IS_USER(); + CREATE_OK_REQUEST_PROMISE(); + TRY_RESULT_PROMISE(promise, sender_dialog_id, get_message_sender_dialog_id(td_, request.sender_id_, false, false)); + td_->messages_manager_->delete_dialog_messages_by_sender(DialogId(request.chat_id_), sender_dialog_id, + std::move(promise)); +} + +void Requests::on_request(uint64 id, const td_api::deleteChatMessagesByDate &request) { + CHECK_IS_USER(); + CREATE_OK_REQUEST_PROMISE(); + td_->messages_manager_->delete_dialog_messages_by_date(DialogId(request.chat_id_), request.min_date_, + request.max_date_, request.revoke_, std::move(promise)); +} + +void Requests::on_request(uint64 id, const td_api::readAllChatMentions &request) { + CHECK_IS_USER(); + CREATE_OK_REQUEST_PROMISE(); + td_->messages_manager_->read_all_dialog_mentions(DialogId(request.chat_id_), MessageId(), std::move(promise)); +} + +void Requests::on_request(uint64 id, const td_api::readAllMessageThreadMentions &request) { + CHECK_IS_USER(); + if (request.message_thread_id_ == 0) { + return send_error_raw(id, 400, "Invalid message thread identifier specified"); + } + CREATE_OK_REQUEST_PROMISE(); + td_->messages_manager_->read_all_dialog_mentions(DialogId(request.chat_id_), MessageId(request.message_thread_id_), + std::move(promise)); +} + +void Requests::on_request(uint64 id, const td_api::readAllChatReactions &request) { + CHECK_IS_USER(); + CREATE_OK_REQUEST_PROMISE(); + td_->messages_manager_->read_all_dialog_reactions(DialogId(request.chat_id_), MessageId(), std::move(promise)); +} + +void Requests::on_request(uint64 id, const td_api::readAllMessageThreadReactions &request) { + CHECK_IS_USER(); + if (request.message_thread_id_ == 0) { + return send_error_raw(id, 400, "Invalid message thread identifier specified"); + } + CREATE_OK_REQUEST_PROMISE(); + td_->messages_manager_->read_all_dialog_reactions(DialogId(request.chat_id_), MessageId(request.message_thread_id_), + std::move(promise)); +} + +void Requests::on_request(uint64 id, const td_api::getChatAvailableMessageSenders &request) { + CHECK_IS_USER(); + CREATE_REQUEST_PROMISE(); + td_->messages_manager_->get_dialog_send_message_as_dialog_ids(DialogId(request.chat_id_), std::move(promise)); +} + +void Requests::on_request(uint64 id, const td_api::setChatMessageSender &request) { + CHECK_IS_USER(); + CREATE_OK_REQUEST_PROMISE(); + TRY_RESULT_PROMISE(promise, message_sender_dialog_id, + get_message_sender_dialog_id(td_, request.message_sender_id_, true, false)); + td_->messages_manager_->set_dialog_default_send_message_as_dialog_id(DialogId(request.chat_id_), + message_sender_dialog_id, std::move(promise)); +} + +void Requests::on_request(uint64 id, td_api::sendMessage &request) { + auto r_sent_message = td_->messages_manager_->send_message( + DialogId(request.chat_id_), MessageId(request.message_thread_id_), std::move(request.reply_to_), + std::move(request.options_), std::move(request.reply_markup_), std::move(request.input_message_content_)); + if (r_sent_message.is_error()) { + send_closure(td_actor_, &Td::send_error, id, r_sent_message.move_as_error()); + } else { + send_closure(td_actor_, &Td::send_result, id, r_sent_message.move_as_ok()); + } +} + +void Requests::on_request(uint64 id, td_api::sendMessageAlbum &request) { + auto r_messages = td_->messages_manager_->send_message_group( + DialogId(request.chat_id_), MessageId(request.message_thread_id_), std::move(request.reply_to_), + std::move(request.options_), std::move(request.input_message_contents_)); + if (r_messages.is_error()) { + send_closure(td_actor_, &Td::send_error, id, r_messages.move_as_error()); + } else { + send_closure(td_actor_, &Td::send_result, id, r_messages.move_as_ok()); + } +} + +void Requests::on_request(uint64 id, td_api::sendBotStartMessage &request) { + CHECK_IS_USER(); + CLEAN_INPUT_STRING(request.parameter_); + + DialogId dialog_id(request.chat_id_); + auto r_new_message_id = + td_->messages_manager_->send_bot_start_message(UserId(request.bot_user_id_), dialog_id, request.parameter_); + if (r_new_message_id.is_error()) { + return send_closure(td_actor_, &Td::send_error, id, r_new_message_id.move_as_error()); + } + + CHECK(r_new_message_id.ok().is_valid() || r_new_message_id.ok().is_valid_scheduled()); + send_closure(td_actor_, &Td::send_result, id, + td_->messages_manager_->get_message_object({dialog_id, r_new_message_id.ok()}, "sendBotStartMessage")); +} + +void Requests::on_request(uint64 id, td_api::sendInlineQueryResultMessage &request) { + CHECK_IS_USER(); + CLEAN_INPUT_STRING(request.result_id_); + + auto r_sent_message = td_->messages_manager_->send_inline_query_result_message( + DialogId(request.chat_id_), MessageId(request.message_thread_id_), std::move(request.reply_to_), + std::move(request.options_), request.query_id_, request.result_id_, request.hide_via_bot_); + if (r_sent_message.is_error()) { + send_closure(td_actor_, &Td::send_error, id, r_sent_message.move_as_error()); + } else { + send_closure(td_actor_, &Td::send_result, id, r_sent_message.move_as_ok()); + } +} + +void Requests::on_request(uint64 id, td_api::addLocalMessage &request) { + CHECK_IS_USER(); + + DialogId dialog_id(request.chat_id_); + auto r_new_message_id = td_->messages_manager_->add_local_message( + dialog_id, std::move(request.sender_id_), std::move(request.reply_to_), request.disable_notification_, + std::move(request.input_message_content_)); + if (r_new_message_id.is_error()) { + return send_closure(td_actor_, &Td::send_error, id, r_new_message_id.move_as_error()); + } + + CHECK(r_new_message_id.ok().is_valid()); + send_closure(td_actor_, &Td::send_result, id, + td_->messages_manager_->get_message_object({dialog_id, r_new_message_id.ok()}, "addLocalMessage")); +} + +void Requests::on_request(uint64 id, td_api::editMessageText &request) { + CREATE_REQUEST(EditMessageTextRequest, request.chat_id_, request.message_id_, std::move(request.reply_markup_), + std::move(request.input_message_content_)); +} + +void Requests::on_request(uint64 id, td_api::editMessageLiveLocation &request) { + CREATE_REQUEST(EditMessageLiveLocationRequest, request.chat_id_, request.message_id_, + std::move(request.reply_markup_), std::move(request.location_), request.live_period_, request.heading_, + request.proximity_alert_radius_); +} + +void Requests::on_request(uint64 id, td_api::editMessageMedia &request) { + CREATE_REQUEST(EditMessageMediaRequest, request.chat_id_, request.message_id_, std::move(request.reply_markup_), + std::move(request.input_message_content_)); +} + +void Requests::on_request(uint64 id, td_api::editMessageCaption &request) { + CREATE_REQUEST(EditMessageCaptionRequest, request.chat_id_, request.message_id_, std::move(request.reply_markup_), + std::move(request.caption_), request.show_caption_above_media_); +} + +void Requests::on_request(uint64 id, td_api::editMessageReplyMarkup &request) { + CHECK_IS_BOT(); + CREATE_REQUEST(EditMessageReplyMarkupRequest, request.chat_id_, request.message_id_, + std::move(request.reply_markup_)); +} + +void Requests::on_request(uint64 id, td_api::editInlineMessageText &request) { + CHECK_IS_BOT(); + CLEAN_INPUT_STRING(request.inline_message_id_); + CREATE_OK_REQUEST_PROMISE(); + td_->inline_message_manager_->edit_inline_message_text(request.inline_message_id_, std::move(request.reply_markup_), + std::move(request.input_message_content_), std::move(promise)); +} + +void Requests::on_request(uint64 id, td_api::editInlineMessageLiveLocation &request) { + CHECK_IS_BOT(); + CLEAN_INPUT_STRING(request.inline_message_id_); + CREATE_OK_REQUEST_PROMISE(); + td_->inline_message_manager_->edit_inline_message_live_location( + request.inline_message_id_, std::move(request.reply_markup_), std::move(request.location_), request.live_period_, + request.heading_, request.proximity_alert_radius_, std::move(promise)); +} + +void Requests::on_request(uint64 id, td_api::editInlineMessageMedia &request) { + CHECK_IS_BOT(); + CLEAN_INPUT_STRING(request.inline_message_id_); + CREATE_OK_REQUEST_PROMISE(); + td_->inline_message_manager_->edit_inline_message_media(request.inline_message_id_, std::move(request.reply_markup_), + std::move(request.input_message_content_), + std::move(promise)); +} + +void Requests::on_request(uint64 id, td_api::editInlineMessageCaption &request) { + CHECK_IS_BOT(); + CLEAN_INPUT_STRING(request.inline_message_id_); + CREATE_OK_REQUEST_PROMISE(); + td_->inline_message_manager_->edit_inline_message_caption( + request.inline_message_id_, std::move(request.reply_markup_), std::move(request.caption_), + request.show_caption_above_media_, std::move(promise)); +} + +void Requests::on_request(uint64 id, td_api::editInlineMessageReplyMarkup &request) { + CHECK_IS_BOT(); + CLEAN_INPUT_STRING(request.inline_message_id_); + CREATE_OK_REQUEST_PROMISE(); + td_->inline_message_manager_->edit_inline_message_reply_markup(request.inline_message_id_, + std::move(request.reply_markup_), std::move(promise)); +} + +void Requests::on_request(uint64 id, td_api::editMessageSchedulingState &request) { + CHECK_IS_USER(); + CREATE_OK_REQUEST_PROMISE(); + td_->messages_manager_->edit_message_scheduling_state({DialogId(request.chat_id_), MessageId(request.message_id_)}, + std::move(request.scheduling_state_), std::move(promise)); +} + +void Requests::on_request(uint64 id, td_api::setMessageFactCheck &request) { + CHECK_IS_USER(); + CREATE_OK_REQUEST_PROMISE(); + td_->messages_manager_->set_message_fact_check({DialogId(request.chat_id_), MessageId(request.message_id_)}, + std::move(request.text_), std::move(promise)); +} + +void Requests::on_request(uint64 id, td_api::sendBusinessMessage &request) { + CHECK_IS_BOT(); + CREATE_REQUEST_PROMISE(); + td_->business_connection_manager_->send_message(BusinessConnectionId(std::move(request.business_connection_id_)), + DialogId(request.chat_id_), std::move(request.reply_to_), + request.disable_notification_, request.protect_content_, + MessageEffectId(request.effect_id_), std::move(request.reply_markup_), + std::move(request.input_message_content_), std::move(promise)); +} + +void Requests::on_request(uint64 id, td_api::sendBusinessMessageAlbum &request) { + CHECK_IS_BOT(); + CREATE_REQUEST_PROMISE(); + td_->business_connection_manager_->send_message_album( + BusinessConnectionId(std::move(request.business_connection_id_)), DialogId(request.chat_id_), + std::move(request.reply_to_), request.disable_notification_, request.protect_content_, + MessageEffectId(request.effect_id_), std::move(request.input_message_contents_), std::move(promise)); +} + +void Requests::on_request(uint64 id, td_api::editBusinessMessageText &request) { + CHECK_IS_BOT(); + CREATE_REQUEST_PROMISE(); + td_->business_connection_manager_->edit_business_message_text( + BusinessConnectionId(std::move(request.business_connection_id_)), DialogId(request.chat_id_), + MessageId(request.message_id_), std::move(request.reply_markup_), std::move(request.input_message_content_), + std::move(promise)); +} + +void Requests::on_request(uint64 id, td_api::editBusinessMessageLiveLocation &request) { + CHECK_IS_BOT(); + CREATE_REQUEST_PROMISE(); + td_->business_connection_manager_->edit_business_message_live_location( + BusinessConnectionId(std::move(request.business_connection_id_)), DialogId(request.chat_id_), + MessageId(request.message_id_), std::move(request.reply_markup_), std::move(request.location_), + request.live_period_, request.heading_, request.proximity_alert_radius_, std::move(promise)); +} + +void Requests::on_request(uint64 id, td_api::editBusinessMessageMedia &request) { + CHECK_IS_BOT(); + CREATE_REQUEST_PROMISE(); + td_->business_connection_manager_->edit_business_message_media( + BusinessConnectionId(std::move(request.business_connection_id_)), DialogId(request.chat_id_), + MessageId(request.message_id_), std::move(request.reply_markup_), std::move(request.input_message_content_), + std::move(promise)); +} + +void Requests::on_request(uint64 id, td_api::editBusinessMessageCaption &request) { + CHECK_IS_BOT(); + CREATE_REQUEST_PROMISE(); + td_->business_connection_manager_->edit_business_message_caption( + BusinessConnectionId(std::move(request.business_connection_id_)), DialogId(request.chat_id_), + MessageId(request.message_id_), std::move(request.reply_markup_), std::move(request.caption_), + request.show_caption_above_media_, std::move(promise)); +} + +void Requests::on_request(uint64 id, td_api::editBusinessMessageReplyMarkup &request) { + CHECK_IS_BOT(); + CREATE_REQUEST_PROMISE(); + td_->business_connection_manager_->edit_business_message_reply_markup( + BusinessConnectionId(std::move(request.business_connection_id_)), DialogId(request.chat_id_), + MessageId(request.message_id_), std::move(request.reply_markup_), std::move(promise)); +} + +void Requests::on_request(uint64 id, td_api::stopBusinessPoll &request) { + CHECK_IS_BOT(); + CREATE_REQUEST_PROMISE(); + td_->business_connection_manager_->stop_poll(BusinessConnectionId(std::move(request.business_connection_id_)), + DialogId(request.chat_id_), MessageId(request.message_id_), + std::move(request.reply_markup_), std::move(promise)); +} + +void Requests::on_request(uint64 id, td_api::setBusinessMessageIsPinned &request) { + CHECK_IS_BOT(); + CREATE_OK_REQUEST_PROMISE(); + td_->messages_manager_->pin_dialog_message(BusinessConnectionId(std::move(request.business_connection_id_)), + DialogId(request.chat_id_), MessageId(request.message_id_), true, false, + !request.is_pinned_, std::move(promise)); +} + +void Requests::on_request(uint64 id, const td_api::loadQuickReplyShortcuts &request) { + CHECK_IS_USER(); + CREATE_OK_REQUEST_PROMISE(); + td_->quick_reply_manager_->get_quick_reply_shortcuts(std::move(promise)); +} + +void Requests::on_request(uint64 id, const td_api::setQuickReplyShortcutName &request) { + CHECK_IS_USER(); + CREATE_OK_REQUEST_PROMISE(); + td_->quick_reply_manager_->set_quick_reply_shortcut_name(QuickReplyShortcutId(request.shortcut_id_), request.name_, + std::move(promise)); +} + +void Requests::on_request(uint64 id, const td_api::deleteQuickReplyShortcut &request) { + CHECK_IS_USER(); + CREATE_OK_REQUEST_PROMISE(); + td_->quick_reply_manager_->delete_quick_reply_shortcut(QuickReplyShortcutId(request.shortcut_id_), + std::move(promise)); +} + +void Requests::on_request(uint64 id, const td_api::reorderQuickReplyShortcuts &request) { + CHECK_IS_USER(); + CREATE_OK_REQUEST_PROMISE(); + td_->quick_reply_manager_->reorder_quick_reply_shortcuts( + QuickReplyShortcutId::get_quick_reply_shortcut_ids(request.shortcut_ids_), std::move(promise)); +} + +void Requests::on_request(uint64 id, const td_api::loadQuickReplyShortcutMessages &request) { + CHECK_IS_USER(); + CREATE_OK_REQUEST_PROMISE(); + td_->quick_reply_manager_->get_quick_reply_shortcut_messages(QuickReplyShortcutId(request.shortcut_id_), + std::move(promise)); +} + +void Requests::on_request(uint64 id, const td_api::deleteQuickReplyShortcutMessages &request) { + CHECK_IS_USER(); + CREATE_OK_REQUEST_PROMISE(); + td_->quick_reply_manager_->delete_quick_reply_shortcut_messages( + QuickReplyShortcutId(request.shortcut_id_), MessageId::get_message_ids(request.message_ids_), std::move(promise)); +} + +void Requests::on_request(uint64 id, td_api::addQuickReplyShortcutMessage &request) { + CHECK_IS_USER(); + CLEAN_INPUT_STRING(request.shortcut_name_); + auto r_sent_message = td_->quick_reply_manager_->send_message( + request.shortcut_name_, MessageId(request.reply_to_message_id_), std::move(request.input_message_content_)); + if (r_sent_message.is_error()) { + send_closure(td_actor_, &Td::send_error, id, r_sent_message.move_as_error()); + } else { + send_closure(td_actor_, &Td::send_result, id, r_sent_message.move_as_ok()); + } +} + +void Requests::on_request(uint64 id, td_api::addQuickReplyShortcutInlineQueryResultMessage &request) { + CHECK_IS_USER(); + CLEAN_INPUT_STRING(request.shortcut_name_); + CLEAN_INPUT_STRING(request.result_id_); + auto r_sent_message = td_->quick_reply_manager_->send_inline_query_result_message( + request.shortcut_name_, MessageId(request.reply_to_message_id_), request.query_id_, request.result_id_, + request.hide_via_bot_); + if (r_sent_message.is_error()) { + send_closure(td_actor_, &Td::send_error, id, r_sent_message.move_as_error()); + } else { + send_closure(td_actor_, &Td::send_result, id, r_sent_message.move_as_ok()); + } +} + +void Requests::on_request(uint64 id, td_api::addQuickReplyShortcutMessageAlbum &request) { + CHECK_IS_USER(); + CLEAN_INPUT_STRING(request.shortcut_name_); + auto r_messages = td_->quick_reply_manager_->send_message_group( + request.shortcut_name_, MessageId(request.reply_to_message_id_), std::move(request.input_message_contents_)); + if (r_messages.is_error()) { + send_closure(td_actor_, &Td::send_error, id, r_messages.move_as_error()); + } else { + send_closure(td_actor_, &Td::send_result, id, r_messages.move_as_ok()); + } +} + +void Requests::on_request(uint64 id, td_api::readdQuickReplyShortcutMessages &request) { + CHECK_IS_USER(); + CLEAN_INPUT_STRING(request.shortcut_name_); + auto r_messages = td_->quick_reply_manager_->resend_messages(request.shortcut_name_, + MessageId::get_message_ids(request.message_ids_)); + if (r_messages.is_error()) { + return send_closure(td_actor_, &Td::send_error, id, r_messages.move_as_error()); + } + send_closure(td_actor_, &Td::send_result, id, r_messages.move_as_ok()); +} + +void Requests::on_request(uint64 id, td_api::editQuickReplyMessage &request) { + CHECK_IS_USER(); + CREATE_OK_REQUEST_PROMISE(); + td_->quick_reply_manager_->edit_quick_reply_message(QuickReplyShortcutId(request.shortcut_id_), + MessageId(request.message_id_), + std::move(request.input_message_content_), std::move(promise)); +} + +void Requests::on_request(uint64 id, const td_api::getCurrentWeather &request) { + CHECK_IS_USER(); + CREATE_REQUEST_PROMISE(); + td_->inline_queries_manager_->get_weather(Location(request.location_), std::move(promise)); +} + +void Requests::on_request(uint64 id, const td_api::getStory &request) { + CHECK_IS_USER(); + CREATE_REQUEST_PROMISE(); + td_->story_manager_->get_story(DialogId(request.story_sender_chat_id_), StoryId(request.story_id_), + request.only_local_, std::move(promise)); +} + +void Requests::on_request(uint64 id, const td_api::getChatsToSendStories &request) { + CHECK_IS_USER(); + CREATE_REQUEST_PROMISE(); + td_->story_manager_->get_dialogs_to_send_stories(std::move(promise)); +} + +void Requests::on_request(uint64 id, const td_api::canSendStory &request) { + CHECK_IS_USER(); + CREATE_REQUEST_PROMISE(); + td_->story_manager_->can_send_story(DialogId(request.chat_id_), std::move(promise)); +} + +void Requests::on_request(uint64 id, td_api::sendStory &request) { + CHECK_IS_USER(); + CREATE_REQUEST_PROMISE(); + td_->story_manager_->send_story(DialogId(request.chat_id_), std::move(request.content_), std::move(request.areas_), + std::move(request.caption_), std::move(request.privacy_settings_), + request.active_period_, std::move(request.from_story_full_id_), + request.is_posted_to_chat_page_, request.protect_content_, std::move(promise)); +} + +void Requests::on_request(uint64 id, td_api::editStory &request) { + CHECK_IS_USER(); + CREATE_OK_REQUEST_PROMISE(); + td_->story_manager_->edit_story(DialogId(request.story_sender_chat_id_), StoryId(request.story_id_), + std::move(request.content_), std::move(request.areas_), std::move(request.caption_), + std::move(promise)); +} + +void Requests::on_request(uint64 id, const td_api::editStoryCover &request) { + CHECK_IS_USER(); + CREATE_OK_REQUEST_PROMISE(); + td_->story_manager_->edit_story_cover(DialogId(request.story_sender_chat_id_), StoryId(request.story_id_), + request.cover_frame_timestamp_, std::move(promise)); +} + +void Requests::on_request(uint64 id, td_api::setStoryPrivacySettings &request) { + CHECK_IS_USER(); + CREATE_OK_REQUEST_PROMISE(); + td_->story_manager_->set_story_privacy_settings(StoryId(request.story_id_), std::move(request.privacy_settings_), + std::move(promise)); +} + +void Requests::on_request(uint64 id, const td_api::toggleStoryIsPostedToChatPage &request) { + CHECK_IS_USER(); + CREATE_OK_REQUEST_PROMISE(); + td_->story_manager_->toggle_story_is_pinned(DialogId(request.story_sender_chat_id_), StoryId(request.story_id_), + request.is_posted_to_chat_page_, std::move(promise)); +} + +void Requests::on_request(uint64 id, const td_api::deleteStory &request) { + CHECK_IS_USER(); + CREATE_OK_REQUEST_PROMISE(); + td_->story_manager_->delete_story(DialogId(request.story_sender_chat_id_), StoryId(request.story_id_), + std::move(promise)); +} + +void Requests::on_request(uint64 id, const td_api::loadActiveStories &request) { + CHECK_IS_USER(); + CREATE_OK_REQUEST_PROMISE(); + td_->story_manager_->load_active_stories(StoryListId(request.story_list_), std::move(promise)); +} + +void Requests::on_request(uint64 id, const td_api::setChatActiveStoriesList &request) { + CHECK_IS_USER(); + CREATE_OK_REQUEST_PROMISE(); + td_->story_manager_->toggle_dialog_stories_hidden(DialogId(request.chat_id_), StoryListId(request.story_list_), + std::move(promise)); +} + +void Requests::on_request(uint64 id, const td_api::getForumTopicDefaultIcons &request) { + CREATE_REQUEST_PROMISE(); + td_->stickers_manager_->get_default_topic_icons(false, std::move(promise)); +} + +void Requests::on_request(uint64 id, td_api::createForumTopic &request) { + CLEAN_INPUT_STRING(request.name_); + CREATE_REQUEST_PROMISE(); + td_->forum_topic_manager_->create_forum_topic(DialogId(request.chat_id_), std::move(request.name_), + std::move(request.icon_), std::move(promise)); +} + +void Requests::on_request(uint64 id, td_api::editForumTopic &request) { + CLEAN_INPUT_STRING(request.name_); + CREATE_OK_REQUEST_PROMISE(); + td_->forum_topic_manager_->edit_forum_topic(DialogId(request.chat_id_), MessageId(request.message_thread_id_), + std::move(request.name_), request.edit_icon_custom_emoji_, + CustomEmojiId(request.icon_custom_emoji_id_), std::move(promise)); +} + +void Requests::on_request(uint64 id, const td_api::getForumTopic &request) { + CREATE_REQUEST_PROMISE(); + td_->forum_topic_manager_->get_forum_topic(DialogId(request.chat_id_), MessageId(request.message_thread_id_), + std::move(promise)); +} + +void Requests::on_request(uint64 id, const td_api::getForumTopicLink &request) { + CREATE_REQUEST_PROMISE(); + td_->forum_topic_manager_->get_forum_topic_link(DialogId(request.chat_id_), MessageId(request.message_thread_id_), + std::move(promise)); +} + +void Requests::on_request(uint64 id, td_api::getForumTopics &request) { + CHECK_IS_USER(); + CLEAN_INPUT_STRING(request.query_); + CREATE_REQUEST_PROMISE(); + td_->forum_topic_manager_->get_forum_topics(DialogId(request.chat_id_), std::move(request.query_), + request.offset_date_, MessageId(request.offset_message_id_), + MessageId(request.offset_message_thread_id_), request.limit_, + std::move(promise)); +} + +void Requests::on_request(uint64 id, const td_api::toggleForumTopicIsClosed &request) { + CREATE_OK_REQUEST_PROMISE(); + td_->forum_topic_manager_->toggle_forum_topic_is_closed( + DialogId(request.chat_id_), MessageId(request.message_thread_id_), request.is_closed_, std::move(promise)); +} + +void Requests::on_request(uint64 id, const td_api::toggleGeneralForumTopicIsHidden &request) { + CREATE_OK_REQUEST_PROMISE(); + td_->forum_topic_manager_->toggle_forum_topic_is_hidden(DialogId(request.chat_id_), request.is_hidden_, + std::move(promise)); +} + +void Requests::on_request(uint64 id, const td_api::toggleForumTopicIsPinned &request) { + CHECK_IS_USER(); + CREATE_OK_REQUEST_PROMISE(); + td_->forum_topic_manager_->toggle_forum_topic_is_pinned( + DialogId(request.chat_id_), MessageId(request.message_thread_id_), request.is_pinned_, std::move(promise)); +} + +void Requests::on_request(uint64 id, const td_api::setPinnedForumTopics &request) { + CHECK_IS_USER(); + CREATE_OK_REQUEST_PROMISE(); + td_->forum_topic_manager_->set_pinned_forum_topics( + DialogId(request.chat_id_), MessageId::get_message_ids(request.message_thread_ids_), std::move(promise)); +} + +void Requests::on_request(uint64 id, const td_api::deleteForumTopic &request) { + CREATE_OK_REQUEST_PROMISE(); + td_->forum_topic_manager_->delete_forum_topic(DialogId(request.chat_id_), MessageId(request.message_thread_id_), + std::move(promise)); +} + +void Requests::on_request(uint64 id, td_api::setGameScore &request) { + CHECK_IS_BOT(); + CREATE_REQUEST_PROMISE(); + td_->game_manager_->set_game_score({DialogId(request.chat_id_), MessageId(request.message_id_)}, + request.edit_message_, UserId(request.user_id_), request.score_, request.force_, + std::move(promise)); +} + +void Requests::on_request(uint64 id, td_api::setInlineGameScore &request) { + CHECK_IS_BOT(); + CLEAN_INPUT_STRING(request.inline_message_id_); + CREATE_OK_REQUEST_PROMISE(); + td_->inline_message_manager_->set_inline_game_score(request.inline_message_id_, request.edit_message_, + UserId(request.user_id_), request.score_, request.force_, + std::move(promise)); +} + +void Requests::on_request(uint64 id, td_api::getGameHighScores &request) { + CHECK_IS_BOT(); + CREATE_REQUEST_PROMISE(); + td_->game_manager_->get_game_high_scores({DialogId(request.chat_id_), MessageId(request.message_id_)}, + UserId(request.user_id_), std::move(promise)); +} + +void Requests::on_request(uint64 id, td_api::getInlineGameHighScores &request) { + CHECK_IS_BOT(); + CLEAN_INPUT_STRING(request.inline_message_id_); + CREATE_REQUEST_PROMISE(); + td_->inline_message_manager_->get_inline_game_high_scores(request.inline_message_id_, UserId(request.user_id_), + std::move(promise)); +} + +void Requests::on_request(uint64 id, const td_api::deleteChatReplyMarkup &request) { + CHECK_IS_USER(); + answer_ok_query(id, td_->messages_manager_->delete_dialog_reply_markup(DialogId(request.chat_id_), + MessageId(request.message_id_))); +} + +void Requests::on_request(uint64 id, td_api::sendChatAction &request) { + CLEAN_INPUT_STRING(request.business_connection_id_); + CREATE_OK_REQUEST_PROMISE(); + td_->dialog_action_manager_->send_dialog_action(DialogId(request.chat_id_), MessageId(request.message_thread_id_), + BusinessConnectionId(std::move(request.business_connection_id_)), + DialogAction(std::move(request.action_)), std::move(promise)); +} + +void Requests::on_request(uint64 id, td_api::forwardMessages &request) { + auto input_message_ids = MessageId::get_message_ids(request.message_ids_); + auto message_copy_options = + transform(input_message_ids, [send_copy = request.send_copy_, remove_caption = request.remove_caption_]( + MessageId) { return MessageCopyOptions(send_copy, remove_caption); }); + auto r_messages = td_->messages_manager_->forward_messages( + DialogId(request.chat_id_), MessageId(request.message_thread_id_), DialogId(request.from_chat_id_), + std::move(input_message_ids), std::move(request.options_), false, std::move(message_copy_options)); + if (r_messages.is_error()) { + send_closure(td_actor_, &Td::send_error, id, r_messages.move_as_error()); + } else { + send_closure(td_actor_, &Td::send_result, id, r_messages.move_as_ok()); + } +} + +void Requests::on_request(uint64 id, const td_api::sendQuickReplyShortcutMessages &request) { + auto r_messages = td_->messages_manager_->send_quick_reply_shortcut_messages( + DialogId(request.chat_id_), QuickReplyShortcutId(request.shortcut_id_), request.sending_id_); + if (r_messages.is_error()) { + send_closure(td_actor_, &Td::send_error, id, r_messages.move_as_error()); + } else { + send_closure(td_actor_, &Td::send_result, id, r_messages.move_as_ok()); + } +} + +void Requests::on_request(uint64 id, td_api::resendMessages &request) { + DialogId dialog_id(request.chat_id_); + auto r_message_ids = td_->messages_manager_->resend_messages( + dialog_id, MessageId::get_message_ids(request.message_ids_), std::move(request.quote_)); + if (r_message_ids.is_error()) { + return send_closure(td_actor_, &Td::send_error, id, r_message_ids.move_as_error()); + } + + send_closure(td_actor_, &Td::send_result, id, + td_->messages_manager_->get_messages_object(-1, dialog_id, r_message_ids.ok(), false, "resendMessages")); +} + +void Requests::on_request(uint64 id, td_api::getLinkPreview &request) { + CHECK_IS_USER(); + CREATE_REQUEST_PROMISE(); + td_->web_pages_manager_->get_web_page_preview(std::move(request.text_), std::move(request.link_preview_options_), + std::move(promise)); +} + +void Requests::on_request(uint64 id, td_api::getWebPageInstantView &request) { + CHECK_IS_USER(); + CLEAN_INPUT_STRING(request.url_); + CREATE_REQUEST(GetWebPageInstantViewRequest, std::move(request.url_), request.force_full_); +} + +void Requests::on_request(uint64 id, const td_api::createPrivateChat &request) { + CREATE_REQUEST(CreateChatRequest, DialogId(UserId(request.user_id_)), request.force_); +} + +void Requests::on_request(uint64 id, const td_api::createBasicGroupChat &request) { + CREATE_REQUEST(CreateChatRequest, DialogId(ChatId(request.basic_group_id_)), request.force_); +} + +void Requests::on_request(uint64 id, const td_api::createSupergroupChat &request) { + CREATE_REQUEST(CreateChatRequest, DialogId(ChannelId(request.supergroup_id_)), request.force_); +} + +void Requests::on_request(uint64 id, const td_api::createSecretChat &request) { + CREATE_REQUEST(CreateChatRequest, DialogId(SecretChatId(request.secret_chat_id_)), true); +} + +void Requests::on_request(uint64 id, td_api::createNewBasicGroupChat &request) { + CHECK_IS_USER(); + CLEAN_INPUT_STRING(request.title_); + CREATE_REQUEST_PROMISE(); + td_->chat_manager_->create_new_chat(UserId::get_user_ids(request.user_ids_), std::move(request.title_), + MessageTtl(request.message_auto_delete_time_), std::move(promise)); +} + +void Requests::on_request(uint64 id, td_api::createNewSupergroupChat &request) { + CHECK_IS_USER(); + CLEAN_INPUT_STRING(request.title_); + CLEAN_INPUT_STRING(request.description_); + CREATE_REQUEST_PROMISE(); + td_->chat_manager_->create_new_channel(std::move(request.title_), request.is_forum_, !request.is_channel_, + std::move(request.description_), DialogLocation(std::move(request.location_)), + request.for_import_, MessageTtl(request.message_auto_delete_time_), + std::move(promise)); +} + +void Requests::on_request(uint64 id, const td_api::createNewSecretChat &request) { + CHECK_IS_USER(); + CREATE_REQUEST_PROMISE(); + td_->user_manager_->create_new_secret_chat(UserId(request.user_id_), std::move(promise)); +} + +void Requests::on_request(uint64 id, const td_api::createCall &request) { + CHECK_IS_USER(); + + if (request.protocol_ == nullptr) { + return send_error_raw(id, 400, "Call protocol must be non-empty"); + } + + UserId user_id(request.user_id_); + auto r_input_user = td_->user_manager_->get_input_user(user_id); + if (r_input_user.is_error()) { + return send_error_raw(id, r_input_user.error().code(), r_input_user.error().message()); + } + + CREATE_REQUEST_PROMISE(); + auto query_promise = PromiseCreator::lambda([promise = std::move(promise)](Result result) mutable { + if (result.is_error()) { + promise.set_error(result.move_as_error()); + } else { + promise.set_value(result.ok().get_call_id_object()); + } + }); + send_closure(G()->call_manager(), &CallManager::create_call, user_id, r_input_user.move_as_ok(), + CallProtocol(*request.protocol_), request.is_video_, std::move(query_promise)); +} + +void Requests::on_request(uint64 id, const td_api::acceptCall &request) { + CHECK_IS_USER(); + if (request.protocol_ == nullptr) { + return send_error_raw(id, 400, "Call protocol must be non-empty"); + } + CREATE_OK_REQUEST_PROMISE(); + send_closure(G()->call_manager(), &CallManager::accept_call, CallId(request.call_id_), + CallProtocol(*request.protocol_), std::move(promise)); +} + +void Requests::on_request(uint64 id, td_api::sendCallSignalingData &request) { + CHECK_IS_USER(); + CREATE_OK_REQUEST_PROMISE(); + send_closure(G()->call_manager(), &CallManager::send_call_signaling_data, CallId(request.call_id_), + std::move(request.data_), std::move(promise)); +} + +void Requests::on_request(uint64 id, const td_api::discardCall &request) { + CHECK_IS_USER(); + CREATE_OK_REQUEST_PROMISE(); + send_closure(G()->call_manager(), &CallManager::discard_call, CallId(request.call_id_), request.is_disconnected_, + request.duration_, request.is_video_, request.connection_id_, std::move(promise)); +} + +void Requests::on_request(uint64 id, td_api::sendCallRating &request) { + CHECK_IS_USER(); + CLEAN_INPUT_STRING(request.comment_); + CREATE_OK_REQUEST_PROMISE(); + send_closure(G()->call_manager(), &CallManager::rate_call, CallId(request.call_id_), request.rating_, + std::move(request.comment_), std::move(request.problems_), std::move(promise)); +} + +void Requests::on_request(uint64 id, td_api::sendCallDebugInformation &request) { + CHECK_IS_USER(); + CLEAN_INPUT_STRING(request.debug_information_); + CREATE_OK_REQUEST_PROMISE(); + send_closure(G()->call_manager(), &CallManager::send_call_debug_information, CallId(request.call_id_), + std::move(request.debug_information_), std::move(promise)); +} + +void Requests::on_request(uint64 id, td_api::sendCallLog &request) { + CHECK_IS_USER(); + CREATE_OK_REQUEST_PROMISE(); + send_closure(G()->call_manager(), &CallManager::send_call_log, CallId(request.call_id_), std::move(request.log_file_), + std::move(promise)); +} + +void Requests::on_request(uint64 id, const td_api::getVideoChatAvailableParticipants &request) { + CHECK_IS_USER(); + CREATE_REQUEST_PROMISE(); + td_->group_call_manager_->get_group_call_join_as(DialogId(request.chat_id_), std::move(promise)); +} + +void Requests::on_request(uint64 id, const td_api::setVideoChatDefaultParticipant &request) { + CHECK_IS_USER(); + CREATE_OK_REQUEST_PROMISE(); + TRY_RESULT_PROMISE(promise, default_join_as_dialog_id, + get_message_sender_dialog_id(td_, request.default_participant_id_, true, false)); + td_->group_call_manager_->set_group_call_default_join_as(DialogId(request.chat_id_), default_join_as_dialog_id, + std::move(promise)); +} + +void Requests::on_request(uint64 id, td_api::createVideoChat &request) { + CHECK_IS_USER(); + CLEAN_INPUT_STRING(request.title_); + CREATE_REQUEST_PROMISE(); + auto query_promise = PromiseCreator::lambda([promise = std::move(promise)](Result result) mutable { + if (result.is_error()) { + promise.set_error(result.move_as_error()); + } else { + promise.set_value(td_api::make_object(result.ok().get())); + } + }); + td_->group_call_manager_->create_voice_chat(DialogId(request.chat_id_), std::move(request.title_), + request.start_date_, request.is_rtmp_stream_, std::move(query_promise)); +} + +void Requests::on_request(uint64 id, const td_api::getVideoChatRtmpUrl &request) { + CHECK_IS_USER(); + CREATE_REQUEST_PROMISE(); + td_->group_call_manager_->get_voice_chat_rtmp_stream_url(DialogId(request.chat_id_), false, std::move(promise)); +} + +void Requests::on_request(uint64 id, const td_api::replaceVideoChatRtmpUrl &request) { + CHECK_IS_USER(); + CREATE_REQUEST_PROMISE(); + td_->group_call_manager_->get_voice_chat_rtmp_stream_url(DialogId(request.chat_id_), true, std::move(promise)); +} + +void Requests::on_request(uint64 id, const td_api::getGroupCall &request) { + CHECK_IS_USER(); + CREATE_REQUEST_PROMISE(); + td_->group_call_manager_->get_group_call(GroupCallId(request.group_call_id_), std::move(promise)); +} + +void Requests::on_request(uint64 id, const td_api::startScheduledGroupCall &request) { + CHECK_IS_USER(); + CREATE_OK_REQUEST_PROMISE(); + td_->group_call_manager_->start_scheduled_group_call(GroupCallId(request.group_call_id_), std::move(promise)); +} + +void Requests::on_request(uint64 id, const td_api::toggleGroupCallEnabledStartNotification &request) { + CHECK_IS_USER(); + CREATE_OK_REQUEST_PROMISE(); + td_->group_call_manager_->toggle_group_call_start_subscribed(GroupCallId(request.group_call_id_), + request.enabled_start_notification_, std::move(promise)); +} + +void Requests::on_request(uint64 id, td_api::joinGroupCall &request) { + CHECK_IS_USER(); + CLEAN_INPUT_STRING(request.invite_hash_); + CLEAN_INPUT_STRING(request.payload_); + CREATE_TEXT_REQUEST_PROMISE(); + TRY_RESULT_PROMISE(promise, join_as_dialog_id, + get_message_sender_dialog_id(td_, request.participant_id_, true, true)); + td_->group_call_manager_->join_group_call(GroupCallId(request.group_call_id_), join_as_dialog_id, + request.audio_source_id_, std::move(request.payload_), request.is_muted_, + request.is_my_video_enabled_, request.invite_hash_, std::move(promise)); +} + +void Requests::on_request(uint64 id, td_api::startGroupCallScreenSharing &request) { + CHECK_IS_USER(); + CLEAN_INPUT_STRING(request.payload_); + CREATE_TEXT_REQUEST_PROMISE(); + td_->group_call_manager_->start_group_call_screen_sharing( + GroupCallId(request.group_call_id_), request.audio_source_id_, std::move(request.payload_), std::move(promise)); +} + +void Requests::on_request(uint64 id, const td_api::toggleGroupCallScreenSharingIsPaused &request) { + CHECK_IS_USER(); + CREATE_OK_REQUEST_PROMISE(); + td_->group_call_manager_->toggle_group_call_is_my_presentation_paused(GroupCallId(request.group_call_id_), + request.is_paused_, std::move(promise)); +} + +void Requests::on_request(uint64 id, const td_api::endGroupCallScreenSharing &request) { + CHECK_IS_USER(); + CREATE_OK_REQUEST_PROMISE(); + td_->group_call_manager_->end_group_call_screen_sharing(GroupCallId(request.group_call_id_), std::move(promise)); +} + +void Requests::on_request(uint64 id, td_api::setGroupCallTitle &request) { + CHECK_IS_USER(); + CLEAN_INPUT_STRING(request.title_); + CREATE_OK_REQUEST_PROMISE(); + td_->group_call_manager_->set_group_call_title(GroupCallId(request.group_call_id_), std::move(request.title_), + std::move(promise)); +} + +void Requests::on_request(uint64 id, const td_api::toggleGroupCallMuteNewParticipants &request) { + CHECK_IS_USER(); + CREATE_OK_REQUEST_PROMISE(); + td_->group_call_manager_->toggle_group_call_mute_new_participants(GroupCallId(request.group_call_id_), + request.mute_new_participants_, std::move(promise)); +} + +void Requests::on_request(uint64 id, const td_api::revokeGroupCallInviteLink &request) { + CHECK_IS_USER(); + CREATE_OK_REQUEST_PROMISE(); + td_->group_call_manager_->revoke_group_call_invite_link(GroupCallId(request.group_call_id_), std::move(promise)); +} + +void Requests::on_request(uint64 id, const td_api::inviteGroupCallParticipants &request) { + CHECK_IS_USER(); + CREATE_OK_REQUEST_PROMISE(); + td_->group_call_manager_->invite_group_call_participants(GroupCallId(request.group_call_id_), + UserId::get_user_ids(request.user_ids_), std::move(promise)); +} + +void Requests::on_request(uint64 id, const td_api::getGroupCallInviteLink &request) { + CHECK_IS_USER(); + CREATE_HTTP_URL_REQUEST_PROMISE(); + td_->group_call_manager_->get_group_call_invite_link(GroupCallId(request.group_call_id_), request.can_self_unmute_, + std::move(promise)); +} + +void Requests::on_request(uint64 id, td_api::startGroupCallRecording &request) { + CHECK_IS_USER(); + CLEAN_INPUT_STRING(request.title_); + CREATE_OK_REQUEST_PROMISE(); + td_->group_call_manager_->toggle_group_call_recording(GroupCallId(request.group_call_id_), true, + std::move(request.title_), request.record_video_, + request.use_portrait_orientation_, std::move(promise)); +} + +void Requests::on_request(uint64 id, const td_api::endGroupCallRecording &request) { + CHECK_IS_USER(); + CREATE_OK_REQUEST_PROMISE(); + td_->group_call_manager_->toggle_group_call_recording(GroupCallId(request.group_call_id_), false, string(), false, + false, std::move(promise)); +} + +void Requests::on_request(uint64 id, const td_api::toggleGroupCallIsMyVideoPaused &request) { + CHECK_IS_USER(); + CREATE_OK_REQUEST_PROMISE(); + td_->group_call_manager_->toggle_group_call_is_my_video_paused(GroupCallId(request.group_call_id_), + request.is_my_video_paused_, std::move(promise)); +} + +void Requests::on_request(uint64 id, const td_api::toggleGroupCallIsMyVideoEnabled &request) { + CHECK_IS_USER(); + CREATE_OK_REQUEST_PROMISE(); + td_->group_call_manager_->toggle_group_call_is_my_video_enabled(GroupCallId(request.group_call_id_), + request.is_my_video_enabled_, std::move(promise)); +} + +void Requests::on_request(uint64 id, const td_api::setGroupCallParticipantIsSpeaking &request) { + CHECK_IS_USER(); + CREATE_OK_REQUEST_PROMISE(); + td_->group_call_manager_->set_group_call_participant_is_speaking( + GroupCallId(request.group_call_id_), request.audio_source_, request.is_speaking_, std::move(promise)); +} + +void Requests::on_request(uint64 id, const td_api::toggleGroupCallParticipantIsMuted &request) { + CHECK_IS_USER(); + CREATE_OK_REQUEST_PROMISE(); + TRY_RESULT_PROMISE(promise, participant_dialog_id, + get_message_sender_dialog_id(td_, request.participant_id_, true, false)); + td_->group_call_manager_->toggle_group_call_participant_is_muted( + GroupCallId(request.group_call_id_), participant_dialog_id, request.is_muted_, std::move(promise)); +} + +void Requests::on_request(uint64 id, const td_api::setGroupCallParticipantVolumeLevel &request) { + CHECK_IS_USER(); + CREATE_OK_REQUEST_PROMISE(); + TRY_RESULT_PROMISE(promise, participant_dialog_id, + get_message_sender_dialog_id(td_, request.participant_id_, true, false)); + td_->group_call_manager_->set_group_call_participant_volume_level( + GroupCallId(request.group_call_id_), participant_dialog_id, request.volume_level_, std::move(promise)); +} + +void Requests::on_request(uint64 id, const td_api::toggleGroupCallParticipantIsHandRaised &request) { + CHECK_IS_USER(); + CREATE_OK_REQUEST_PROMISE(); + TRY_RESULT_PROMISE(promise, participant_dialog_id, + get_message_sender_dialog_id(td_, request.participant_id_, true, false)); + td_->group_call_manager_->toggle_group_call_participant_is_hand_raised( + GroupCallId(request.group_call_id_), participant_dialog_id, request.is_hand_raised_, std::move(promise)); +} + +void Requests::on_request(uint64 id, const td_api::loadGroupCallParticipants &request) { + CHECK_IS_USER(); + CREATE_OK_REQUEST_PROMISE(); + td_->group_call_manager_->load_group_call_participants(GroupCallId(request.group_call_id_), request.limit_, + std::move(promise)); +} + +void Requests::on_request(uint64 id, const td_api::leaveGroupCall &request) { + CHECK_IS_USER(); + CREATE_OK_REQUEST_PROMISE(); + td_->group_call_manager_->leave_group_call(GroupCallId(request.group_call_id_), std::move(promise)); +} + +void Requests::on_request(uint64 id, const td_api::endGroupCall &request) { + CHECK_IS_USER(); + CREATE_OK_REQUEST_PROMISE(); + td_->group_call_manager_->discard_group_call(GroupCallId(request.group_call_id_), std::move(promise)); +} + +void Requests::on_request(uint64 id, const td_api::getGroupCallStreams &request) { + CHECK_IS_USER(); + CREATE_REQUEST_PROMISE(); + td_->group_call_manager_->get_group_call_streams(GroupCallId(request.group_call_id_), std::move(promise)); +} + +void Requests::on_request(uint64 id, td_api::getGroupCallStreamSegment &request) { + CHECK_IS_USER(); + CREATE_REQUEST_PROMISE(); + auto query_promise = PromiseCreator::lambda([promise = std::move(promise)](Result result) mutable { + if (result.is_error()) { + promise.set_error(result.move_as_error()); + } else { + auto file_part = td_api::make_object(); + file_part->data_ = result.move_as_ok(); + promise.set_value(std::move(file_part)); + } + }); + td_->group_call_manager_->get_group_call_stream_segment(GroupCallId(request.group_call_id_), request.time_offset_, + request.scale_, request.channel_id_, + std::move(request.video_quality_), std::move(query_promise)); +} + +void Requests::on_request(uint64 id, const td_api::upgradeBasicGroupChatToSupergroupChat &request) { + CHECK_IS_USER(); + CREATE_REQUEST_PROMISE(); + td_->dialog_manager_->migrate_dialog_to_megagroup(DialogId(request.chat_id_), std::move(promise)); +} + +void Requests::on_request(uint64 id, const td_api::getChatListsToAddChat &request) { + CHECK_IS_USER(); + auto dialog_lists = td_->messages_manager_->get_dialog_lists_to_add_dialog(DialogId(request.chat_id_)); + auto chat_lists = + transform(dialog_lists, [](DialogListId dialog_list_id) { return dialog_list_id.get_chat_list_object(); }); + send_closure(td_actor_, &Td::send_result, id, td_api::make_object(std::move(chat_lists))); +} + +void Requests::on_request(uint64 id, const td_api::addChatToList &request) { + CHECK_IS_USER(); + CREATE_OK_REQUEST_PROMISE(); + td_->messages_manager_->add_dialog_to_list(DialogId(request.chat_id_), DialogListId(request.chat_list_), + std::move(promise)); +} + +void Requests::on_request(uint64 id, const td_api::getChatFolder &request) { + CHECK_IS_USER(); + CREATE_REQUEST_PROMISE(); + td_->dialog_filter_manager_->get_dialog_filter(DialogFilterId(request.chat_folder_id_), std::move(promise)); +} + +void Requests::on_request(uint64 id, const td_api::getRecommendedChatFolders &request) { + CHECK_IS_USER(); + CREATE_REQUEST_PROMISE(); + td_->dialog_filter_manager_->get_recommended_dialog_filters(std::move(promise)); +} + +void Requests::on_request(uint64 id, td_api::createChatFolder &request) { + CHECK_IS_USER(); + CREATE_REQUEST_PROMISE(); + td_->dialog_filter_manager_->create_dialog_filter(std::move(request.folder_), std::move(promise)); +} + +void Requests::on_request(uint64 id, td_api::editChatFolder &request) { + CHECK_IS_USER(); + CREATE_REQUEST_PROMISE(); + td_->dialog_filter_manager_->edit_dialog_filter(DialogFilterId(request.chat_folder_id_), std::move(request.folder_), + std::move(promise)); +} + +void Requests::on_request(uint64 id, const td_api::deleteChatFolder &request) { + CHECK_IS_USER(); + CREATE_OK_REQUEST_PROMISE(); + td_->dialog_filter_manager_->delete_dialog_filter( + DialogFilterId(request.chat_folder_id_), DialogId::get_dialog_ids(request.leave_chat_ids_), std::move(promise)); +} + +void Requests::on_request(uint64 id, const td_api::getChatFolderChatsToLeave &request) { + CHECK_IS_USER(); + CREATE_REQUEST_PROMISE(); + td_->dialog_filter_manager_->get_leave_dialog_filter_suggestions(DialogFilterId(request.chat_folder_id_), + std::move(promise)); +} + +void Requests::on_request(uint64 id, td_api::getChatFolderChatCount &request) { + CHECK_IS_USER(); + CREATE_REQUEST_PROMISE(); + auto query_promise = PromiseCreator::lambda([promise = std::move(promise)](Result result) mutable { + if (result.is_error()) { + promise.set_error(result.move_as_error()); + } else { + promise.set_value(td_api::make_object(result.move_as_ok())); + } + }); + td_->messages_manager_->get_dialog_filter_dialog_count(std::move(request.folder_), std::move(query_promise)); +} + +void Requests::on_request(uint64 id, const td_api::reorderChatFolders &request) { + CHECK_IS_USER(); + CREATE_OK_REQUEST_PROMISE(); + td_->dialog_filter_manager_->reorder_dialog_filters( + transform(request.chat_folder_ids_, [](int32 id) { return DialogFilterId(id); }), + request.main_chat_list_position_, std::move(promise)); +} + +void Requests::on_request(uint64 id, const td_api::toggleChatFolderTags &request) { + CHECK_IS_USER(); + CREATE_OK_REQUEST_PROMISE(); + td_->dialog_filter_manager_->toggle_dialog_filter_tags(request.are_tags_enabled_, std::move(promise)); +} + +void Requests::on_request(uint64 id, const td_api::getChatsForChatFolderInviteLink &request) { + CHECK_IS_USER(); + CREATE_REQUEST_PROMISE(); + td_->dialog_filter_manager_->get_dialogs_for_dialog_filter_invite_link(DialogFilterId(request.chat_folder_id_), + std::move(promise)); +} + +void Requests::on_request(uint64 id, td_api::createChatFolderInviteLink &request) { + CHECK_IS_USER(); + CLEAN_INPUT_STRING(request.name_); + CREATE_REQUEST_PROMISE(); + td_->dialog_filter_manager_->create_dialog_filter_invite_link( + DialogFilterId(request.chat_folder_id_), std::move(request.name_), DialogId::get_dialog_ids(request.chat_ids_), + std::move(promise)); +} + +void Requests::on_request(uint64 id, td_api::getChatFolderInviteLinks &request) { + CHECK_IS_USER(); + CREATE_REQUEST_PROMISE(); + td_->dialog_filter_manager_->get_dialog_filter_invite_links(DialogFilterId(request.chat_folder_id_), + std::move(promise)); +} + +void Requests::on_request(uint64 id, td_api::editChatFolderInviteLink &request) { + CHECK_IS_USER(); + CLEAN_INPUT_STRING(request.invite_link_); + CLEAN_INPUT_STRING(request.name_); + CREATE_REQUEST_PROMISE(); + td_->dialog_filter_manager_->edit_dialog_filter_invite_link( + DialogFilterId(request.chat_folder_id_), std::move(request.invite_link_), std::move(request.name_), + DialogId::get_dialog_ids(request.chat_ids_), std::move(promise)); +} + +void Requests::on_request(uint64 id, td_api::deleteChatFolderInviteLink &request) { + CHECK_IS_USER(); + CLEAN_INPUT_STRING(request.invite_link_); + CREATE_OK_REQUEST_PROMISE(); + td_->dialog_filter_manager_->delete_dialog_filter_invite_link(DialogFilterId(request.chat_folder_id_), + std::move(request.invite_link_), std::move(promise)); +} + +void Requests::on_request(uint64 id, td_api::checkChatFolderInviteLink &request) { + CHECK_IS_USER(); + CLEAN_INPUT_STRING(request.invite_link_); + CREATE_REQUEST_PROMISE(); + td_->dialog_filter_manager_->check_dialog_filter_invite_link(std::move(request.invite_link_), std::move(promise)); +} + +void Requests::on_request(uint64 id, td_api::addChatFolderByInviteLink &request) { + CHECK_IS_USER(); + CLEAN_INPUT_STRING(request.invite_link_); + CREATE_OK_REQUEST_PROMISE(); + td_->dialog_filter_manager_->add_dialog_filter_by_invite_link( + std::move(request.invite_link_), DialogId::get_dialog_ids(request.chat_ids_), std::move(promise)); +} + +void Requests::on_request(uint64 id, const td_api::getChatFolderNewChats &request) { + CHECK_IS_USER(); + CREATE_REQUEST_PROMISE(); + td_->dialog_filter_manager_->get_dialog_filter_new_chats(DialogFilterId(request.chat_folder_id_), std::move(promise)); +} + +void Requests::on_request(uint64 id, const td_api::processChatFolderNewChats &request) { + CHECK_IS_USER(); + CREATE_OK_REQUEST_PROMISE(); + td_->dialog_filter_manager_->add_dialog_filter_new_chats( + DialogFilterId(request.chat_folder_id_), DialogId::get_dialog_ids(request.added_chat_ids_), std::move(promise)); +} + +void Requests::on_request(uint64 id, const td_api::getArchiveChatListSettings &request) { + CHECK_IS_USER(); + CREATE_REQUEST_PROMISE(); + auto query_promise = + PromiseCreator::lambda([promise = std::move(promise)](Result result) mutable { + if (result.is_error()) { + promise.set_error(result.move_as_error()); + } else { + promise.set_value(result.ok().get_archive_chat_list_settings_object()); + } + }); + GlobalPrivacySettings::get_global_privacy_settings(td_, std::move(query_promise)); +} + +void Requests::on_request(uint64 id, td_api::setArchiveChatListSettings &request) { + CHECK_IS_USER(); + CREATE_OK_REQUEST_PROMISE(); + GlobalPrivacySettings::set_global_privacy_settings(td_, GlobalPrivacySettings(std::move(request.settings_)), + std::move(promise)); +} + +void Requests::on_request(uint64 id, const td_api::getReadDatePrivacySettings &request) { + CHECK_IS_USER(); + CREATE_REQUEST_PROMISE(); + auto query_promise = + PromiseCreator::lambda([promise = std::move(promise)](Result result) mutable { + if (result.is_error()) { + promise.set_error(result.move_as_error()); + } else { + promise.set_value(result.ok().get_read_date_privacy_settings_object()); + } + }); + GlobalPrivacySettings::get_global_privacy_settings(td_, std::move(query_promise)); +} + +void Requests::on_request(uint64 id, td_api::setReadDatePrivacySettings &request) { + CHECK_IS_USER(); + CREATE_OK_REQUEST_PROMISE(); + GlobalPrivacySettings::set_global_privacy_settings(td_, GlobalPrivacySettings(std::move(request.settings_)), + std::move(promise)); +} + +void Requests::on_request(uint64 id, const td_api::getNewChatPrivacySettings &request) { + CHECK_IS_USER(); + CREATE_REQUEST_PROMISE(); + auto query_promise = + PromiseCreator::lambda([promise = std::move(promise)](Result result) mutable { + if (result.is_error()) { + promise.set_error(result.move_as_error()); + } else { + promise.set_value(result.ok().get_new_chat_privacy_settings_object()); + } + }); + GlobalPrivacySettings::get_global_privacy_settings(td_, std::move(query_promise)); +} + +void Requests::on_request(uint64 id, td_api::setNewChatPrivacySettings &request) { + CHECK_IS_USER(); + CREATE_OK_REQUEST_PROMISE(); + GlobalPrivacySettings::set_global_privacy_settings(td_, GlobalPrivacySettings(std::move(request.settings_)), + std::move(promise)); +} + +void Requests::on_request(uint64 id, const td_api::canSendMessageToUser &request) { + CHECK_IS_USER(); + CREATE_REQUEST_PROMISE(); + td_->user_manager_->can_send_message_to_user(UserId(request.user_id_), request.only_local_, std::move(promise)); +} + +void Requests::on_request(uint64 id, td_api::setChatTitle &request) { + CLEAN_INPUT_STRING(request.title_); + CREATE_OK_REQUEST_PROMISE(); + td_->dialog_manager_->set_dialog_title(DialogId(request.chat_id_), request.title_, std::move(promise)); +} + +void Requests::on_request(uint64 id, const td_api::setChatPhoto &request) { + CREATE_OK_REQUEST_PROMISE(); + td_->dialog_manager_->set_dialog_photo(DialogId(request.chat_id_), request.photo_, std::move(promise)); +} + +void Requests::on_request(uint64 id, const td_api::setChatAccentColor &request) { + CHECK_IS_USER(); + CREATE_OK_REQUEST_PROMISE(); + td_->dialog_manager_->set_dialog_accent_color(DialogId(request.chat_id_), AccentColorId(request.accent_color_id_), + CustomEmojiId(request.background_custom_emoji_id_), std::move(promise)); +} + +void Requests::on_request(uint64 id, const td_api::setChatProfileAccentColor &request) { + CHECK_IS_USER(); + CREATE_OK_REQUEST_PROMISE(); + td_->dialog_manager_->set_dialog_profile_accent_color( + DialogId(request.chat_id_), AccentColorId(request.profile_accent_color_id_), + CustomEmojiId(request.profile_background_custom_emoji_id_), std::move(promise)); +} + +void Requests::on_request(uint64 id, const td_api::setChatMessageAutoDeleteTime &request) { + CHECK_IS_USER(); + CREATE_OK_REQUEST_PROMISE(); + td_->messages_manager_->set_dialog_message_ttl(DialogId(request.chat_id_), request.message_auto_delete_time_, + std::move(promise)); +} + +void Requests::on_request(uint64 id, const td_api::setChatEmojiStatus &request) { + CHECK_IS_USER(); + CREATE_OK_REQUEST_PROMISE(); + td_->dialog_manager_->set_dialog_emoji_status(DialogId(request.chat_id_), EmojiStatus(request.emoji_status_), + std::move(promise)); +} + +void Requests::on_request(uint64 id, const td_api::setChatPermissions &request) { + CREATE_OK_REQUEST_PROMISE(); + td_->dialog_manager_->set_dialog_permissions(DialogId(request.chat_id_), request.permissions_, std::move(promise)); +} + +void Requests::on_request(uint64 id, td_api::setChatBackground &request) { + CHECK_IS_USER(); + CREATE_OK_REQUEST_PROMISE(); + td_->background_manager_->set_dialog_background(DialogId(request.chat_id_), request.background_.get(), + request.type_.get(), request.dark_theme_dimming_, + !request.only_for_self_, std::move(promise)); +} + +void Requests::on_request(uint64 id, const td_api::deleteChatBackground &request) { + CHECK_IS_USER(); + CREATE_OK_REQUEST_PROMISE(); + td_->background_manager_->delete_dialog_background(DialogId(request.chat_id_), request.restore_previous_, + std::move(promise)); +} + +void Requests::on_request(uint64 id, td_api::setChatTheme &request) { + CHECK_IS_USER(); + CLEAN_INPUT_STRING(request.theme_name_); + CREATE_OK_REQUEST_PROMISE(); + td_->messages_manager_->set_dialog_theme(DialogId(request.chat_id_), request.theme_name_, std::move(promise)); +} + +void Requests::on_request(uint64 id, td_api::setChatDraftMessage &request) { + CHECK_IS_USER(); + answer_ok_query( + id, td_->messages_manager_->set_dialog_draft_message( + DialogId(request.chat_id_), MessageId(request.message_thread_id_), std::move(request.draft_message_))); +} + +void Requests::on_request(uint64 id, const td_api::toggleChatHasProtectedContent &request) { + CHECK_IS_USER(); + CREATE_OK_REQUEST_PROMISE(); + td_->dialog_manager_->toggle_dialog_has_protected_content(DialogId(request.chat_id_), request.has_protected_content_, + std::move(promise)); +} + +void Requests::on_request(uint64 id, const td_api::toggleChatIsPinned &request) { + CHECK_IS_USER(); + answer_ok_query(id, td_->messages_manager_->toggle_dialog_is_pinned(DialogListId(request.chat_list_), + DialogId(request.chat_id_), request.is_pinned_)); +} + +void Requests::on_request(uint64 id, const td_api::toggleChatViewAsTopics &request) { + CHECK_IS_USER(); + answer_ok_query( + id, td_->messages_manager_->toggle_dialog_view_as_messages(DialogId(request.chat_id_), !request.view_as_topics_)); +} + +void Requests::on_request(uint64 id, const td_api::toggleChatIsTranslatable &request) { + CHECK_IS_USER(); + answer_ok_query( + id, td_->messages_manager_->toggle_dialog_is_translatable(DialogId(request.chat_id_), request.is_translatable_)); +} + +void Requests::on_request(uint64 id, const td_api::toggleChatIsMarkedAsUnread &request) { + CHECK_IS_USER(); + answer_ok_query(id, td_->messages_manager_->toggle_dialog_is_marked_as_unread(DialogId(request.chat_id_), + request.is_marked_as_unread_)); +} + +void Requests::on_request(uint64 id, const td_api::setMessageSenderBlockList &request) { + CHECK_IS_USER(); + answer_ok_query(id, td_->messages_manager_->set_message_sender_block_list(request.sender_id_, request.block_list_)); +} + +void Requests::on_request(uint64 id, const td_api::toggleChatDefaultDisableNotification &request) { + CHECK_IS_USER(); + answer_ok_query(id, td_->messages_manager_->toggle_dialog_silent_send_message(DialogId(request.chat_id_), + request.default_disable_notification_)); +} + +void Requests::on_request(uint64 id, const td_api::setPinnedChats &request) { + CHECK_IS_USER(); + answer_ok_query(id, td_->messages_manager_->set_pinned_dialogs(DialogListId(request.chat_list_), + DialogId::get_dialog_ids(request.chat_ids_))); +} + +void Requests::on_request(uint64 id, const td_api::readChatList &request) { + CHECK_IS_USER(); + CREATE_OK_REQUEST_PROMISE(); + td_->messages_manager_->read_all_dialogs_from_list(DialogListId(request.chat_list_), std::move(promise)); +} + +void Requests::on_request(uint64 id, const td_api::getStoryNotificationSettingsExceptions &request) { + CHECK_IS_USER(); + CREATE_REQUEST_PROMISE(); + td_->notification_settings_manager_->get_story_notification_settings_exceptions(std::move(promise)); +} + +void Requests::on_request(uint64 id, const td_api::getChatActiveStories &request) { + CHECK_IS_USER(); + CREATE_REQUEST_PROMISE(); + td_->story_manager_->get_dialog_expiring_stories(DialogId(request.chat_id_), std::move(promise)); +} + +void Requests::on_request(uint64 id, const td_api::getChatPostedToChatPageStories &request) { + CHECK_IS_USER(); + CREATE_REQUEST_PROMISE(); + td_->story_manager_->get_dialog_pinned_stories(DialogId(request.chat_id_), StoryId(request.from_story_id_), + request.limit_, std::move(promise)); +} + +void Requests::on_request(uint64 id, const td_api::getChatArchivedStories &request) { + CHECK_IS_USER(); + CREATE_REQUEST_PROMISE(); + td_->story_manager_->get_story_archive(DialogId(request.chat_id_), StoryId(request.from_story_id_), request.limit_, + std::move(promise)); +} + +void Requests::on_request(uint64 id, const td_api::setChatPinnedStories &request) { + CHECK_IS_USER(); + CREATE_OK_REQUEST_PROMISE(); + td_->story_manager_->set_pinned_stories(DialogId(request.chat_id_), StoryId::get_story_ids(request.story_ids_), + std::move(promise)); +} + +void Requests::on_request(uint64 id, const td_api::openStory &request) { + CHECK_IS_USER(); + CREATE_OK_REQUEST_PROMISE(); + td_->story_manager_->open_story(DialogId(request.story_sender_chat_id_), StoryId(request.story_id_), + std::move(promise)); +} + +void Requests::on_request(uint64 id, const td_api::closeStory &request) { + CHECK_IS_USER(); + CREATE_OK_REQUEST_PROMISE(); + td_->story_manager_->close_story(DialogId(request.story_sender_chat_id_), StoryId(request.story_id_), + std::move(promise)); +} + +void Requests::on_request(uint64 id, const td_api::getStoryAvailableReactions &request) { + CHECK_IS_USER(); + send_closure(td_actor_, &Td::send_result, id, td_->reaction_manager_->get_available_reactions(request.row_size_)); +} + +void Requests::on_request(uint64 id, const td_api::setStoryReaction &request) { + CHECK_IS_USER(); + CREATE_OK_REQUEST_PROMISE(); + td_->story_manager_->set_story_reaction({DialogId(request.story_sender_chat_id_), StoryId(request.story_id_)}, + ReactionType(request.reaction_type_), request.update_recent_reactions_, + std::move(promise)); +} + +void Requests::on_request(uint64 id, td_api::getStoryInteractions &request) { + CHECK_IS_USER(); + CLEAN_INPUT_STRING(request.query_); + CLEAN_INPUT_STRING(request.offset_); + CREATE_REQUEST_PROMISE(); + td_->story_manager_->get_story_interactions(StoryId(request.story_id_), request.query_, request.only_contacts_, + request.prefer_forwards_, request.prefer_with_reaction_, request.offset_, + request.limit_, std::move(promise)); +} + +void Requests::on_request(uint64 id, td_api::getChatStoryInteractions &request) { + CHECK_IS_USER(); + CLEAN_INPUT_STRING(request.offset_); + CREATE_REQUEST_PROMISE(); + td_->story_manager_->get_dialog_story_interactions( + {DialogId(request.story_sender_chat_id_), StoryId(request.story_id_)}, ReactionType(request.reaction_type_), + request.prefer_forwards_, request.offset_, request.limit_, std::move(promise)); +} + +void Requests::on_request(uint64 id, td_api::reportStory &request) { + CHECK_IS_USER(); + auto r_report_reason = ReportReason::get_report_reason(std::move(request.reason_), std::move(request.text_)); + if (r_report_reason.is_error()) { + return send_error_raw(id, r_report_reason.error().code(), r_report_reason.error().message()); + } + CREATE_OK_REQUEST_PROMISE(); + td_->story_manager_->report_story({DialogId(request.story_sender_chat_id_), StoryId(request.story_id_)}, + r_report_reason.move_as_ok(), std::move(promise)); +} + +void Requests::on_request(uint64 id, const td_api::activateStoryStealthMode &request) { + CREATE_OK_REQUEST_PROMISE(); + td_->story_manager_->activate_stealth_mode(std::move(promise)); +} + +void Requests::on_request(uint64 id, const td_api::getChatBoostLevelFeatures &request) { + CHECK_IS_USER(); + CREATE_REQUEST_PROMISE(); + promise.set_value(td_->boost_manager_->get_chat_boost_level_features_object(!request.is_channel_, request.level_)); +} + +void Requests::on_request(uint64 id, const td_api::getChatBoostFeatures &request) { + CHECK_IS_USER(); + CREATE_REQUEST_PROMISE(); + promise.set_value(td_->boost_manager_->get_chat_boost_features_object(!request.is_channel_)); +} + +void Requests::on_request(uint64 id, const td_api::getAvailableChatBoostSlots &request) { + CHECK_IS_USER(); + CREATE_REQUEST_PROMISE(); + td_->boost_manager_->get_boost_slots(std::move(promise)); +} + +void Requests::on_request(uint64 id, const td_api::getChatBoostStatus &request) { + CHECK_IS_USER(); + CREATE_REQUEST_PROMISE(); + td_->boost_manager_->get_dialog_boost_status(DialogId(request.chat_id_), std::move(promise)); +} + +void Requests::on_request(uint64 id, td_api::boostChat &request) { + CHECK_IS_USER(); + CREATE_REQUEST_PROMISE(); + td_->boost_manager_->boost_dialog(DialogId(request.chat_id_), std::move(request.slot_ids_), std::move(promise)); +} + +void Requests::on_request(uint64 id, const td_api::getChatBoostLink &request) { + auto r_boost_link = td_->boost_manager_->get_dialog_boost_link(DialogId(request.chat_id_)); + if (r_boost_link.is_error()) { + send_closure(td_actor_, &Td::send_error, id, r_boost_link.move_as_error()); + } else { + send_closure(td_actor_, &Td::send_result, id, + td_api::make_object(r_boost_link.ok().first, r_boost_link.ok().second)); + } +} + +void Requests::on_request(uint64 id, td_api::getChatBoostLinkInfo &request) { + CLEAN_INPUT_STRING(request.url_); + CREATE_REQUEST(GetDialogBoostLinkInfoRequest, std::move(request.url_)); +} + +void Requests::on_request(uint64 id, td_api::getChatBoosts &request) { + CHECK_IS_USER(); + CLEAN_INPUT_STRING(request.offset_); + CREATE_REQUEST_PROMISE(); + td_->boost_manager_->get_dialog_boosts(DialogId(request.chat_id_), request.only_gift_codes_, request.offset_, + request.limit_, std::move(promise)); +} + +void Requests::on_request(uint64 id, const td_api::getUserChatBoosts &request) { + CHECK_IS_BOT(); + CREATE_REQUEST_PROMISE(); + td_->boost_manager_->get_user_dialog_boosts(DialogId(request.chat_id_), UserId(request.user_id_), std::move(promise)); +} + +void Requests::on_request(uint64 id, const td_api::getAttachmentMenuBot &request) { + CHECK_IS_USER(); + CREATE_REQUEST_PROMISE(); + td_->attach_menu_manager_->get_attach_menu_bot(UserId(request.bot_user_id_), std::move(promise)); +} + +void Requests::on_request(uint64 id, const td_api::toggleBotIsAddedToAttachmentMenu &request) { + CHECK_IS_USER(); + CREATE_OK_REQUEST_PROMISE(); + td_->attach_menu_manager_->toggle_bot_is_added_to_attach_menu(UserId(request.bot_user_id_), request.is_added_, + request.allow_write_access_, std::move(promise)); +} + +void Requests::on_request(uint64 id, td_api::setChatAvailableReactions &request) { + CREATE_OK_REQUEST_PROMISE(); + td_->messages_manager_->set_dialog_available_reactions(DialogId(request.chat_id_), + std::move(request.available_reactions_), std::move(promise)); +} + +void Requests::on_request(uint64 id, td_api::setChatClientData &request) { + answer_ok_query( + id, td_->messages_manager_->set_dialog_client_data(DialogId(request.chat_id_), std::move(request.client_data_))); +} + +void Requests::on_request(uint64 id, td_api::setChatDescription &request) { + CLEAN_INPUT_STRING(request.description_); + CREATE_OK_REQUEST_PROMISE(); + td_->dialog_manager_->set_dialog_description(DialogId(request.chat_id_), request.description_, std::move(promise)); +} + +void Requests::on_request(uint64 id, const td_api::setChatDiscussionGroup &request) { + CHECK_IS_USER(); + CREATE_OK_REQUEST_PROMISE(); + td_->chat_manager_->set_channel_discussion_group(DialogId(request.chat_id_), DialogId(request.discussion_chat_id_), + std::move(promise)); +} + +void Requests::on_request(uint64 id, td_api::setChatLocation &request) { + CHECK_IS_USER(); + CREATE_OK_REQUEST_PROMISE(); + td_->dialog_manager_->set_dialog_location(DialogId(request.chat_id_), DialogLocation(std::move(request.location_)), + std::move(promise)); +} + +void Requests::on_request(uint64 id, const td_api::setChatSlowModeDelay &request) { + CHECK_IS_USER(); + CREATE_OK_REQUEST_PROMISE(); + td_->chat_manager_->set_channel_slow_mode_delay(DialogId(request.chat_id_), request.slow_mode_delay_, + std::move(promise)); +} + +void Requests::on_request(uint64 id, const td_api::pinChatMessage &request) { + CREATE_OK_REQUEST_PROMISE(); + td_->messages_manager_->pin_dialog_message(BusinessConnectionId(), DialogId(request.chat_id_), + MessageId(request.message_id_), request.disable_notification_, + request.only_for_self_, false, std::move(promise)); +} + +void Requests::on_request(uint64 id, const td_api::unpinChatMessage &request) { + CREATE_OK_REQUEST_PROMISE(); + td_->messages_manager_->pin_dialog_message(BusinessConnectionId(), DialogId(request.chat_id_), + MessageId(request.message_id_), false, false, true, std::move(promise)); +} + +void Requests::on_request(uint64 id, const td_api::unpinAllChatMessages &request) { + CREATE_OK_REQUEST_PROMISE(); + td_->messages_manager_->unpin_all_dialog_messages(DialogId(request.chat_id_), MessageId(), std::move(promise)); +} + +void Requests::on_request(uint64 id, const td_api::unpinAllMessageThreadMessages &request) { + if (request.message_thread_id_ == 0) { + return send_error_raw(id, 400, "Invalid message thread identifier specified"); + } + CREATE_OK_REQUEST_PROMISE(); + td_->messages_manager_->unpin_all_dialog_messages(DialogId(request.chat_id_), MessageId(request.message_thread_id_), + std::move(promise)); +} + +void Requests::on_request(uint64 id, const td_api::joinChat &request) { + CHECK_IS_USER(); + CREATE_OK_REQUEST_PROMISE(); + td_->dialog_participant_manager_->add_dialog_participant( + DialogId(request.chat_id_), td_->user_manager_->get_my_id(), 0, + DialogParticipantManager::wrap_failed_to_add_members_promise(std::move(promise))); +} + +void Requests::on_request(uint64 id, const td_api::leaveChat &request) { + CREATE_OK_REQUEST_PROMISE(); + DialogId dialog_id(request.chat_id_); + td_api::object_ptr new_status = td_api::make_object(); + if (dialog_id.get_type() == DialogType::Channel && td_->dialog_manager_->have_dialog_force(dialog_id, "leaveChat")) { + auto status = td_->chat_manager_->get_channel_status(dialog_id.get_channel_id()); + if (status.is_creator()) { + if (!status.is_member()) { + return promise.set_value(Unit()); + } + + new_status = + td_api::make_object(status.get_rank(), status.is_anonymous(), false); + } + } + td_->dialog_participant_manager_->set_dialog_participant_status(dialog_id, td_->dialog_manager_->get_my_dialog_id(), + std::move(new_status), std::move(promise)); +} + +void Requests::on_request(uint64 id, const td_api::addChatMember &request) { + CHECK_IS_USER(); + CREATE_REQUEST_PROMISE(); + td_->dialog_participant_manager_->add_dialog_participant(DialogId(request.chat_id_), UserId(request.user_id_), + request.forward_limit_, std::move(promise)); +} + +void Requests::on_request(uint64 id, const td_api::addChatMembers &request) { + CHECK_IS_USER(); + CREATE_REQUEST_PROMISE(); + td_->dialog_participant_manager_->add_dialog_participants( + DialogId(request.chat_id_), UserId::get_user_ids(request.user_ids_), std::move(promise)); +} + +void Requests::on_request(uint64 id, td_api::setChatMemberStatus &request) { + CREATE_OK_REQUEST_PROMISE(); + TRY_RESULT_PROMISE(promise, participant_dialog_id, + get_message_sender_dialog_id(td_, request.member_id_, false, false)); + td_->dialog_participant_manager_->set_dialog_participant_status(DialogId(request.chat_id_), participant_dialog_id, + std::move(request.status_), std::move(promise)); +} + +void Requests::on_request(uint64 id, const td_api::banChatMember &request) { + CREATE_OK_REQUEST_PROMISE(); + TRY_RESULT_PROMISE(promise, participant_dialog_id, + get_message_sender_dialog_id(td_, request.member_id_, false, false)); + td_->dialog_participant_manager_->ban_dialog_participant(DialogId(request.chat_id_), participant_dialog_id, + request.banned_until_date_, request.revoke_messages_, + std::move(promise)); +} + +void Requests::on_request(uint64 id, const td_api::canTransferOwnership &request) { + CHECK_IS_USER(); + CREATE_REQUEST_PROMISE(); + auto query_promise = PromiseCreator::lambda( + [promise = std::move(promise)](Result result) mutable { + if (result.is_error()) { + promise.set_error(result.move_as_error()); + } else { + promise.set_value(DialogParticipantManager::get_can_transfer_ownership_result_object(result.ok())); + } + }); + td_->dialog_participant_manager_->can_transfer_ownership(std::move(query_promise)); +} + +void Requests::on_request(uint64 id, td_api::transferChatOwnership &request) { + CHECK_IS_USER(); + CLEAN_INPUT_STRING(request.password_); + CREATE_OK_REQUEST_PROMISE(); + td_->dialog_participant_manager_->transfer_dialog_ownership(DialogId(request.chat_id_), UserId(request.user_id_), + request.password_, std::move(promise)); +} + +void Requests::on_request(uint64 id, const td_api::getChatMember &request) { + CREATE_REQUEST_PROMISE(); + TRY_RESULT_PROMISE(promise, participant_dialog_id, + get_message_sender_dialog_id(td_, request.member_id_, false, false)); + td_->dialog_participant_manager_->get_dialog_participant(DialogId(request.chat_id_), participant_dialog_id, + std::move(promise)); +} + +void Requests::on_request(uint64 id, td_api::searchChatMembers &request) { + CLEAN_INPUT_STRING(request.query_); + CREATE_REQUEST_PROMISE(); + auto query_promise = + PromiseCreator::lambda([promise = std::move(promise), td = td_](Result result) mutable { + if (result.is_error()) { + promise.set_error(result.move_as_error()); + } else { + promise.set_value(result.ok().get_chat_members_object(td, "searchChatMembers")); + } + }); + td_->dialog_participant_manager_->search_dialog_participants(DialogId(request.chat_id_), request.query_, + request.limit_, DialogParticipantFilter(request.filter_), + std::move(query_promise)); +} + +void Requests::on_request(uint64 id, const td_api::getChatAdministrators &request) { + CREATE_REQUEST_PROMISE(); + td_->dialog_participant_manager_->get_dialog_administrators(DialogId(request.chat_id_), std::move(promise)); +} + +void Requests::on_request(uint64 id, const td_api::replacePrimaryChatInviteLink &request) { + CREATE_REQUEST_PROMISE(); + td_->dialog_invite_link_manager_->export_dialog_invite_link( + DialogId(request.chat_id_), string(), 0, 0, false, StarSubscriptionPricing(), false, true, std::move(promise)); +} + +void Requests::on_request(uint64 id, td_api::createChatInviteLink &request) { + CLEAN_INPUT_STRING(request.name_); + CREATE_REQUEST_PROMISE(); + td_->dialog_invite_link_manager_->export_dialog_invite_link( + DialogId(request.chat_id_), std::move(request.name_), request.expiration_date_, request.member_limit_, + request.creates_join_request_, StarSubscriptionPricing(), false, false, std::move(promise)); +} + +void Requests::on_request(uint64 id, td_api::createChatSubscriptionInviteLink &request) { + CLEAN_INPUT_STRING(request.name_); + CREATE_REQUEST_PROMISE(); + td_->dialog_invite_link_manager_->export_dialog_invite_link( + DialogId(request.chat_id_), std::move(request.name_), 0, 0, false, + StarSubscriptionPricing(std::move(request.subscription_pricing_)), true, false, std::move(promise)); +} + +void Requests::on_request(uint64 id, td_api::editChatInviteLink &request) { + CLEAN_INPUT_STRING(request.name_); + CLEAN_INPUT_STRING(request.invite_link_); + CREATE_REQUEST_PROMISE(); + td_->dialog_invite_link_manager_->edit_dialog_invite_link( + DialogId(request.chat_id_), request.invite_link_, std::move(request.name_), request.expiration_date_, + request.member_limit_, request.creates_join_request_, false, std::move(promise)); +} + +void Requests::on_request(uint64 id, td_api::editChatSubscriptionInviteLink &request) { + CLEAN_INPUT_STRING(request.name_); + CLEAN_INPUT_STRING(request.invite_link_); + CREATE_REQUEST_PROMISE(); + td_->dialog_invite_link_manager_->edit_dialog_invite_link(DialogId(request.chat_id_), request.invite_link_, + std::move(request.name_), 0, 0, false, true, + std::move(promise)); +} + +void Requests::on_request(uint64 id, td_api::getChatInviteLink &request) { + CHECK_IS_USER(); + CLEAN_INPUT_STRING(request.invite_link_); + CREATE_REQUEST_PROMISE(); + td_->dialog_invite_link_manager_->get_dialog_invite_link(DialogId(request.chat_id_), request.invite_link_, + std::move(promise)); +} + +void Requests::on_request(uint64 id, const td_api::getChatInviteLinkCounts &request) { + CHECK_IS_USER(); + CREATE_REQUEST_PROMISE(); + td_->dialog_invite_link_manager_->get_dialog_invite_link_counts(DialogId(request.chat_id_), std::move(promise)); +} + +void Requests::on_request(uint64 id, td_api::getChatInviteLinks &request) { + CHECK_IS_USER(); + CLEAN_INPUT_STRING(request.offset_invite_link_); + CREATE_REQUEST_PROMISE(); + td_->dialog_invite_link_manager_->get_dialog_invite_links( + DialogId(request.chat_id_), UserId(request.creator_user_id_), request.is_revoked_, request.offset_date_, + request.offset_invite_link_, request.limit_, std::move(promise)); +} + +void Requests::on_request(uint64 id, td_api::getChatInviteLinkMembers &request) { + CHECK_IS_USER(); + CLEAN_INPUT_STRING(request.invite_link_); + CREATE_REQUEST_PROMISE(); + td_->dialog_invite_link_manager_->get_dialog_invite_link_users( + DialogId(request.chat_id_), request.invite_link_, request.only_with_expired_subscription_, + std::move(request.offset_member_), request.limit_, std::move(promise)); +} + +void Requests::on_request(uint64 id, td_api::getChatJoinRequests &request) { + CHECK_IS_USER(); + CLEAN_INPUT_STRING(request.invite_link_); + CLEAN_INPUT_STRING(request.query_); + CREATE_REQUEST_PROMISE(); + td_->dialog_participant_manager_->get_dialog_join_requests(DialogId(request.chat_id_), request.invite_link_, + request.query_, std::move(request.offset_request_), + request.limit_, std::move(promise)); +} + +void Requests::on_request(uint64 id, const td_api::processChatJoinRequest &request) { + CREATE_OK_REQUEST_PROMISE(); + td_->dialog_participant_manager_->process_dialog_join_request(DialogId(request.chat_id_), UserId(request.user_id_), + request.approve_, std::move(promise)); +} + +void Requests::on_request(uint64 id, td_api::processChatJoinRequests &request) { + CHECK_IS_USER(); + CLEAN_INPUT_STRING(request.invite_link_); + CREATE_OK_REQUEST_PROMISE(); + td_->dialog_participant_manager_->process_dialog_join_requests(DialogId(request.chat_id_), request.invite_link_, + request.approve_, std::move(promise)); +} + +void Requests::on_request(uint64 id, td_api::revokeChatInviteLink &request) { + CLEAN_INPUT_STRING(request.invite_link_); + CREATE_REQUEST_PROMISE(); + td_->dialog_invite_link_manager_->revoke_dialog_invite_link(DialogId(request.chat_id_), request.invite_link_, + std::move(promise)); +} + +void Requests::on_request(uint64 id, td_api::deleteRevokedChatInviteLink &request) { + CHECK_IS_USER(); + CLEAN_INPUT_STRING(request.invite_link_); + CREATE_OK_REQUEST_PROMISE(); + td_->dialog_invite_link_manager_->delete_revoked_dialog_invite_link(DialogId(request.chat_id_), request.invite_link_, + std::move(promise)); +} + +void Requests::on_request(uint64 id, const td_api::deleteAllRevokedChatInviteLinks &request) { + CHECK_IS_USER(); + CREATE_OK_REQUEST_PROMISE(); + td_->dialog_invite_link_manager_->delete_all_revoked_dialog_invite_links( + DialogId(request.chat_id_), UserId(request.creator_user_id_), std::move(promise)); +} + +void Requests::on_request(uint64 id, td_api::checkChatInviteLink &request) { + CHECK_IS_USER(); + CLEAN_INPUT_STRING(request.invite_link_); + CREATE_REQUEST(CheckChatInviteLinkRequest, request.invite_link_); +} + +void Requests::on_request(uint64 id, td_api::joinChatByInviteLink &request) { + CHECK_IS_USER(); + CLEAN_INPUT_STRING(request.invite_link_); + CREATE_REQUEST(JoinChatByInviteLinkRequest, request.invite_link_); +} + +void Requests::on_request(uint64 id, td_api::getChatEventLog &request) { + CHECK_IS_USER(); + CLEAN_INPUT_STRING(request.query_); + CREATE_REQUEST_PROMISE(); + get_dialog_event_log(td_, DialogId(request.chat_id_), std::move(request.query_), request.from_event_id_, + request.limit_, std::move(request.filters_), UserId::get_user_ids(request.user_ids_), + std::move(promise)); +} + +void Requests::on_request(uint64 id, const td_api::getTimeZones &request) { + CREATE_REQUEST_PROMISE(); + td_->time_zone_manager_->get_time_zones(std::move(promise)); +} + +void Requests::on_request(uint64 id, const td_api::clearAllDraftMessages &request) { + CHECK_IS_USER(); + CREATE_OK_REQUEST_PROMISE(); + td_->messages_manager_->clear_all_draft_messages(request.exclude_secret_chats_, std::move(promise)); +} + +void Requests::on_request(uint64 id, const td_api::downloadFile &request) { + auto priority = request.priority_; + if (!(1 <= priority && priority <= 32)) { + return send_error_raw(id, 400, "Download priority must be between 1 and 32"); + } + auto offset = request.offset_; + if (offset < 0) { + return send_error_raw(id, 400, "Download offset must be non-negative"); + } + auto limit = request.limit_; + if (limit < 0) { + return send_error_raw(id, 400, "Download limit must be non-negative"); + } + + FileId file_id(request.file_id_, 0); + auto file_view = td_->file_manager_->get_file_view(file_id); + if (file_view.empty()) { + return send_error_raw(id, 400, "Invalid file identifier"); + } + + auto info_it = pending_file_downloads_.find(file_id); + DownloadInfo *info = info_it == pending_file_downloads_.end() ? nullptr : &info_it->second; + if (info != nullptr && (offset != info->offset || limit != info->limit)) { + // we can't have two pending requests with different offset and limit, so cancel all previous requests + auto request_ids = std::move(info->request_ids); + info->request_ids.clear(); + for (auto request_id : request_ids) { + send_closure(td_actor_, &Td::send_error, request_id, + Status::Error(200, "Canceled by another downloadFile request")); + } + } + if (request.synchronous_) { + if (info == nullptr) { + info = &pending_file_downloads_[file_id]; + } + info->offset = offset; + info->limit = limit; + info->request_ids.push_back(id); + } + Promise> download_promise; + if (!request.synchronous_) { + CREATE_REQUEST_PROMISE(); + download_promise = std::move(promise); + } + td_->file_manager_->download(file_id, download_file_callback_, priority, offset, limit, std::move(download_promise)); +} + +void Requests::on_file_download_finished(FileId file_id) { + auto it = pending_file_downloads_.find(file_id); + if (it == pending_file_downloads_.end()) { + return; + } + for (auto id : it->second.request_ids) { + // there was send_closure to call td_ function + auto file_object = td_->file_manager_->get_file_object(file_id, false); + CHECK(file_object != nullptr); + auto download_offset = file_object->local_->download_offset_; + auto downloaded_size = file_object->local_->downloaded_prefix_size_; + auto file_size = file_object->size_; + auto limit = it->second.limit; + if (limit == 0) { + limit = std::numeric_limits::max(); + } + if (file_object->local_->is_downloading_completed_ || + (download_offset <= it->second.offset && download_offset + downloaded_size >= it->second.offset && + ((file_size != 0 && download_offset + downloaded_size == file_size) || + download_offset + downloaded_size - it->second.offset >= limit))) { + td_->send_result(id, std::move(file_object)); + } else { + td_->send_error_impl(id, td_api::make_object(400, "File download has failed or was canceled")); + } + } + pending_file_downloads_.erase(it); +} + +void Requests::on_request(uint64 id, const td_api::getFileDownloadedPrefixSize &request) { + if (request.offset_ < 0) { + return send_error_raw(id, 400, "Parameter offset must be non-negative"); + } + auto file_view = td_->file_manager_->get_file_view(FileId(request.file_id_, 0)); + if (file_view.empty()) { + return send_closure(td_actor_, &Td::send_error, id, Status::Error(400, "Unknown file ID")); + } + send_closure(td_actor_, &Td::send_result, id, + td_api::make_object(file_view.downloaded_prefix(request.offset_))); +} + +void Requests::on_request(uint64 id, const td_api::cancelDownloadFile &request) { + td_->file_manager_->download(FileId(request.file_id_, 0), nullptr, request.only_if_pending_ ? -1 : 0, + FileManager::KEEP_DOWNLOAD_OFFSET, FileManager::KEEP_DOWNLOAD_LIMIT, + Promise>()); + send_closure(td_actor_, &Td::send_result, id, td_api::make_object()); +} + +void Requests::on_request(uint64 id, const td_api::getSuggestedFileName &request) { + Result r_file_name = + td_->file_manager_->get_suggested_file_name(FileId(request.file_id_, 0), request.directory_); + if (r_file_name.is_error()) { + return send_closure(td_actor_, &Td::send_error, id, r_file_name.move_as_error()); + } + send_closure(td_actor_, &Td::send_result, id, td_api::make_object(r_file_name.ok())); +} + +void Requests::on_request(uint64 id, const td_api::preliminaryUploadFile &request) { + CREATE_REQUEST_PROMISE(); + auto file_type = request.file_type_ == nullptr ? FileType::Temp : get_file_type(*request.file_type_); + td_->file_manager_->preliminary_upload_file(request.file_, file_type, request.priority_, std::move(promise)); +} + +void Requests::on_request(uint64 id, const td_api::cancelPreliminaryUploadFile &request) { + td_->file_manager_->cancel_upload(FileId(request.file_id_, 0)); + + send_closure(td_actor_, &Td::send_result, id, td_api::make_object()); +} + +void Requests::on_request(uint64 id, td_api::writeGeneratedFilePart &request) { + CREATE_OK_REQUEST_PROMISE(); + send_closure(td_->file_manager_actor_, &FileManager::external_file_generate_write_part, request.generation_id_, + request.offset_, std::move(request.data_), std::move(promise)); +} + +void Requests::on_request(uint64 id, const td_api::setFileGenerationProgress &request) { + CREATE_OK_REQUEST_PROMISE(); + send_closure(td_->file_manager_actor_, &FileManager::external_file_generate_progress, request.generation_id_, + request.expected_size_, request.local_prefix_size_, std::move(promise)); +} + +void Requests::on_request(uint64 id, td_api::finishFileGeneration &request) { + Status status; + if (request.error_ != nullptr) { + CLEAN_INPUT_STRING(request.error_->message_); + status = Status::Error(request.error_->code_, request.error_->message_); + } + CREATE_OK_REQUEST_PROMISE(); + send_closure(td_->file_manager_actor_, &FileManager::external_file_generate_finish, request.generation_id_, + std::move(status), std::move(promise)); +} + +void Requests::on_request(uint64 id, const td_api::readFilePart &request) { + CREATE_REQUEST_PROMISE(); + send_closure(td_->file_manager_actor_, &FileManager::read_file_part, FileId(request.file_id_, 0), request.offset_, + request.count_, 2, std::move(promise)); +} + +void Requests::on_request(uint64 id, const td_api::deleteFile &request) { + CREATE_OK_REQUEST_PROMISE(); + send_closure(td_->file_manager_actor_, &FileManager::delete_file, FileId(request.file_id_, 0), std::move(promise), + "td_api::deleteFile"); +} + +void Requests::on_request(uint64 id, const td_api::addFileToDownloads &request) { + if (!(1 <= request.priority_ && request.priority_ <= 32)) { + return send_error_raw(id, 400, "Download priority must be between 1 and 32"); + } + CREATE_REQUEST_PROMISE(); + td_->messages_manager_->add_message_file_to_downloads( + MessageFullId(DialogId(request.chat_id_), MessageId(request.message_id_)), FileId(request.file_id_, 0), + request.priority_, std::move(promise)); +} + +void Requests::on_request(uint64 id, const td_api::toggleDownloadIsPaused &request) { + CREATE_OK_REQUEST_PROMISE(); + send_closure(td_->download_manager_actor_, &DownloadManager::toggle_is_paused, FileId(request.file_id_, 0), + request.is_paused_, std::move(promise)); +} + +void Requests::on_request(uint64 id, const td_api::toggleAllDownloadsArePaused &request) { + CREATE_OK_REQUEST_PROMISE(); + send_closure(td_->download_manager_actor_, &DownloadManager::toggle_all_is_paused, request.are_paused_, + std::move(promise)); +} + +void Requests::on_request(uint64 id, const td_api::removeFileFromDownloads &request) { + CREATE_OK_REQUEST_PROMISE(); + send_closure(td_->download_manager_actor_, &DownloadManager::remove_file, FileId(request.file_id_, 0), FileSourceId(), + request.delete_from_cache_, std::move(promise)); +} + +void Requests::on_request(uint64 id, const td_api::removeAllFilesFromDownloads &request) { + CREATE_OK_REQUEST_PROMISE(); + send_closure(td_->download_manager_actor_, &DownloadManager::remove_all_files, request.only_active_, + request.only_completed_, request.delete_from_cache_, std::move(promise)); +} + +void Requests::on_request(uint64 id, td_api::searchFileDownloads &request) { + CLEAN_INPUT_STRING(request.query_); + CLEAN_INPUT_STRING(request.offset_); + CREATE_REQUEST_PROMISE(); + send_closure(td_->download_manager_actor_, &DownloadManager::search, std::move(request.query_), request.only_active_, + request.only_completed_, std::move(request.offset_), request.limit_, std::move(promise)); +} + +void Requests::on_request(uint64 id, td_api::setApplicationVerificationToken &request) { + CHECK_IS_USER(); + CLEAN_INPUT_STRING(request.token_); + CREATE_OK_REQUEST_PROMISE(); + G()->net_query_dispatcher().set_verification_token(request.verification_id_, std::move(request.token_), + std::move(promise)); +} + +void Requests::on_request(uint64 id, td_api::getMessageFileType &request) { + CHECK_IS_USER(); + CLEAN_INPUT_STRING(request.message_file_head_); + CREATE_REQUEST_PROMISE(); + td_->message_import_manager_->get_message_file_type(request.message_file_head_, std::move(promise)); +} + +void Requests::on_request(uint64 id, const td_api::getMessageImportConfirmationText &request) { + CHECK_IS_USER(); + CREATE_TEXT_REQUEST_PROMISE(); + td_->message_import_manager_->get_message_import_confirmation_text(DialogId(request.chat_id_), std::move(promise)); +} + +void Requests::on_request(uint64 id, const td_api::importMessages &request) { + CHECK_IS_USER(); + CREATE_OK_REQUEST_PROMISE(); + td_->message_import_manager_->import_messages(DialogId(request.chat_id_), request.message_file_, + request.attached_files_, std::move(promise)); +} + +void Requests::on_request(uint64 id, const td_api::blockMessageSenderFromReplies &request) { + CHECK_IS_USER(); + CREATE_OK_REQUEST_PROMISE(); + td_->messages_manager_->block_message_sender_from_replies(MessageId(request.message_id_), request.delete_message_, + request.delete_all_messages_, request.report_spam_, + std::move(promise)); +} + +void Requests::on_request(uint64 id, const td_api::getBlockedMessageSenders &request) { + CHECK_IS_USER(); + CREATE_REQUEST_PROMISE(); + td_->messages_manager_->get_blocked_dialogs(request.block_list_, request.offset_, request.limit_, std::move(promise)); +} + +void Requests::on_request(uint64 id, td_api::addContact &request) { + CHECK_IS_USER(); + auto r_contact = get_contact(td_, std::move(request.contact_)); + if (r_contact.is_error()) { + return send_closure(td_actor_, &Td::send_error, id, r_contact.move_as_error()); + } + CREATE_OK_REQUEST_PROMISE(); + td_->user_manager_->add_contact(r_contact.move_as_ok(), request.share_phone_number_, std::move(promise)); +} + +void Requests::on_request(uint64 id, td_api::importContacts &request) { + CHECK_IS_USER(); + vector contacts; + contacts.reserve(request.contacts_.size()); + for (auto &contact : request.contacts_) { + auto r_contact = get_contact(td_, std::move(contact)); + if (r_contact.is_error()) { + return send_closure(td_actor_, &Td::send_error, id, r_contact.move_as_error()); + } + contacts.push_back(r_contact.move_as_ok()); + } + CREATE_REQUEST(ImportContactsRequest, std::move(contacts)); +} + +void Requests::on_request(uint64 id, const td_api::getContacts &request) { + CHECK_IS_USER(); + CREATE_REQUEST(SearchContactsRequest, string(), 1000000); +} + +void Requests::on_request(uint64 id, td_api::searchContacts &request) { + CHECK_IS_USER(); + CLEAN_INPUT_STRING(request.query_); + CREATE_REQUEST(SearchContactsRequest, request.query_, request.limit_); +} + +void Requests::on_request(uint64 id, td_api::removeContacts &request) { + CHECK_IS_USER(); + CREATE_REQUEST(RemoveContactsRequest, UserId::get_user_ids(request.user_ids_)); +} + +void Requests::on_request(uint64 id, const td_api::getImportedContactCount &request) { + CHECK_IS_USER(); + CREATE_NO_ARGS_REQUEST(GetImportedContactCountRequest); +} + +void Requests::on_request(uint64 id, td_api::changeImportedContacts &request) { + CHECK_IS_USER(); + vector contacts; + contacts.reserve(request.contacts_.size()); + for (auto &contact : request.contacts_) { + auto r_contact = get_contact(td_, std::move(contact)); + if (r_contact.is_error()) { + return send_closure(td_actor_, &Td::send_error, id, r_contact.move_as_error()); + } + contacts.push_back(r_contact.move_as_ok()); + } + CREATE_REQUEST(ChangeImportedContactsRequest, std::move(contacts)); +} + +void Requests::on_request(uint64 id, const td_api::clearImportedContacts &request) { + CHECK_IS_USER(); + CREATE_OK_REQUEST_PROMISE(); + td_->user_manager_->clear_imported_contacts(std::move(promise)); +} + +void Requests::on_request(uint64 id, const td_api::getCloseFriends &request) { + CHECK_IS_USER(); + CREATE_NO_ARGS_REQUEST(GetCloseFriendsRequest); +} + +void Requests::on_request(uint64 id, const td_api::setCloseFriends &request) { + CHECK_IS_USER(); + CREATE_OK_REQUEST_PROMISE(); + td_->user_manager_->set_close_friends(UserId::get_user_ids(request.user_ids_), std::move(promise)); +} + +void Requests::on_request(uint64 id, td_api::setUserPersonalProfilePhoto &request) { + CHECK_IS_USER(); + CREATE_OK_REQUEST_PROMISE(); + td_->user_manager_->set_user_profile_photo(UserId(request.user_id_), request.photo_, false, std::move(promise)); +} + +void Requests::on_request(uint64 id, td_api::suggestUserProfilePhoto &request) { + CHECK_IS_USER(); + CREATE_OK_REQUEST_PROMISE(); + td_->user_manager_->set_user_profile_photo(UserId(request.user_id_), request.photo_, true, std::move(promise)); +} + +void Requests::on_request(uint64 id, td_api::searchUserByPhoneNumber &request) { + CHECK_IS_USER(); + CLEAN_INPUT_STRING(request.phone_number_); + CREATE_REQUEST(SearchUserByPhoneNumberRequest, std::move(request.phone_number_), request.only_local_); +} + +void Requests::on_request(uint64 id, const td_api::sharePhoneNumber &request) { + CHECK_IS_USER(); + CREATE_OK_REQUEST_PROMISE(); + td_->user_manager_->share_phone_number(UserId(request.user_id_), std::move(promise)); +} + +void Requests::on_request(uint64 id, const td_api::getRecentInlineBots &request) { + CHECK_IS_USER(); + CREATE_NO_ARGS_REQUEST(GetRecentInlineBotsRequest); +} + +void Requests::on_request(uint64 id, td_api::setName &request) { + CHECK_IS_USER(); + CLEAN_INPUT_STRING(request.first_name_); + CLEAN_INPUT_STRING(request.last_name_); + CREATE_OK_REQUEST_PROMISE(); + td_->user_manager_->set_name(request.first_name_, request.last_name_, std::move(promise)); +} + +void Requests::on_request(uint64 id, td_api::setBio &request) { + CHECK_IS_USER(); + CLEAN_INPUT_STRING(request.bio_); + CREATE_OK_REQUEST_PROMISE(); + td_->user_manager_->set_bio(request.bio_, std::move(promise)); +} + +void Requests::on_request(uint64 id, td_api::setUsername &request) { + CHECK_IS_USER(); + CLEAN_INPUT_STRING(request.username_); + CREATE_OK_REQUEST_PROMISE(); + td_->user_manager_->set_username(request.username_, std::move(promise)); +} + +void Requests::on_request(uint64 id, td_api::toggleUsernameIsActive &request) { + CHECK_IS_USER(); + CLEAN_INPUT_STRING(request.username_); + CREATE_OK_REQUEST_PROMISE(); + td_->user_manager_->toggle_username_is_active(std::move(request.username_), request.is_active_, std::move(promise)); +} + +void Requests::on_request(uint64 id, td_api::reorderActiveUsernames &request) { + CHECK_IS_USER(); + for (auto &username : request.usernames_) { + CLEAN_INPUT_STRING(username); + } + CREATE_OK_REQUEST_PROMISE(); + td_->user_manager_->reorder_usernames(std::move(request.usernames_), std::move(promise)); +} + +void Requests::on_request(uint64 id, td_api::setBirthdate &request) { + CHECK_IS_USER(); + CREATE_OK_REQUEST_PROMISE(); + td_->user_manager_->set_birthdate(Birthdate(std::move(request.birthdate_)), std::move(promise)); +} + +void Requests::on_request(uint64 id, const td_api::setPersonalChat &request) { + CHECK_IS_USER(); + CREATE_OK_REQUEST_PROMISE(); + td_->user_manager_->set_personal_channel(DialogId(request.chat_id_), std::move(promise)); +} + +void Requests::on_request(uint64 id, const td_api::setEmojiStatus &request) { + CHECK_IS_USER(); + CREATE_OK_REQUEST_PROMISE(); + td_->user_manager_->set_emoji_status(EmojiStatus(request.emoji_status_), std::move(promise)); +} + +void Requests::on_request(uint64 id, const td_api::toggleHasSponsoredMessagesEnabled &request) { + CHECK_IS_USER(); + CREATE_OK_REQUEST_PROMISE(); + td_->user_manager_->toggle_sponsored_messages(request.has_sponsored_messages_enabled_, std::move(promise)); +} + +void Requests::on_request(uint64 id, const td_api::getThemedEmojiStatuses &request) { + CHECK_IS_USER(); + CREATE_REQUEST_PROMISE(); + td_->stickers_manager_->get_default_emoji_statuses(false, std::move(promise)); +} + +void Requests::on_request(uint64 id, const td_api::getThemedChatEmojiStatuses &request) { + CHECK_IS_USER(); + CREATE_REQUEST_PROMISE(); + td_->stickers_manager_->get_default_channel_emoji_statuses(false, std::move(promise)); +} + +void Requests::on_request(uint64 id, const td_api::getDefaultEmojiStatuses &request) { + CHECK_IS_USER(); + CREATE_REQUEST_PROMISE(); + get_default_emoji_statuses(td_, std::move(promise)); +} + +void Requests::on_request(uint64 id, const td_api::getDefaultChatEmojiStatuses &request) { + CHECK_IS_USER(); + CREATE_REQUEST_PROMISE(); + get_default_channel_emoji_statuses(td_, std::move(promise)); +} + +void Requests::on_request(uint64 id, const td_api::getRecentEmojiStatuses &request) { + CHECK_IS_USER(); + CREATE_REQUEST_PROMISE(); + get_recent_emoji_statuses(td_, std::move(promise)); +} + +void Requests::on_request(uint64 id, const td_api::clearRecentEmojiStatuses &request) { + CHECK_IS_USER(); + CREATE_OK_REQUEST_PROMISE(); + clear_recent_emoji_statuses(td_, std::move(promise)); +} + +void Requests::on_request(uint64 id, td_api::setCommands &request) { + CHECK_IS_BOT(); + CREATE_OK_REQUEST_PROMISE(); + set_commands(td_, std::move(request.scope_), std::move(request.language_code_), std::move(request.commands_), + std::move(promise)); +} + +void Requests::on_request(uint64 id, td_api::deleteCommands &request) { + CHECK_IS_BOT(); + CREATE_OK_REQUEST_PROMISE(); + delete_commands(td_, std::move(request.scope_), std::move(request.language_code_), std::move(promise)); +} + +void Requests::on_request(uint64 id, td_api::getCommands &request) { + CHECK_IS_BOT(); + CREATE_REQUEST_PROMISE(); + get_commands(td_, std::move(request.scope_), std::move(request.language_code_), std::move(promise)); +} + +void Requests::on_request(uint64 id, td_api::setMenuButton &request) { + CHECK_IS_BOT(); + CREATE_OK_REQUEST_PROMISE(); + set_menu_button(td_, UserId(request.user_id_), std::move(request.menu_button_), std::move(promise)); +} + +void Requests::on_request(uint64 id, const td_api::getMenuButton &request) { + CHECK_IS_BOT(); + CREATE_REQUEST_PROMISE(); + get_menu_button(td_, UserId(request.user_id_), std::move(promise)); +} + +void Requests::on_request(uint64 id, const td_api::setDefaultGroupAdministratorRights &request) { + CHECK_IS_BOT(); + CREATE_OK_REQUEST_PROMISE(); + td_->bot_info_manager_->set_default_group_administrator_rights( + AdministratorRights(request.default_group_administrator_rights_, ChannelType::Megagroup), std::move(promise)); +} + +void Requests::on_request(uint64 id, const td_api::setDefaultChannelAdministratorRights &request) { + CHECK_IS_BOT(); + CREATE_OK_REQUEST_PROMISE(); + td_->bot_info_manager_->set_default_channel_administrator_rights( + AdministratorRights(request.default_channel_administrator_rights_, ChannelType::Broadcast), std::move(promise)); +} + +void Requests::on_request(uint64 id, const td_api::canBotSendMessages &request) { + CHECK_IS_USER(); + CREATE_OK_REQUEST_PROMISE(); + td_->bot_info_manager_->can_bot_send_messages(UserId(request.bot_user_id_), std::move(promise)); +} + +void Requests::on_request(uint64 id, const td_api::allowBotToSendMessages &request) { + CHECK_IS_USER(); + CREATE_OK_REQUEST_PROMISE(); + td_->bot_info_manager_->allow_bot_to_send_messages(UserId(request.bot_user_id_), std::move(promise)); +} + +void Requests::on_request(uint64 id, td_api::sendWebAppCustomRequest &request) { + CHECK_IS_USER(); + CLEAN_INPUT_STRING(request.method_); + CLEAN_INPUT_STRING(request.parameters_); + CREATE_REQUEST_PROMISE(); + td_->attach_menu_manager_->invoke_web_view_custom_method(UserId(request.bot_user_id_), request.method_, + request.parameters_, std::move(promise)); +} + +void Requests::on_request(uint64 id, const td_api::getBotMediaPreviews &request) { + CHECK_IS_USER(); + CREATE_REQUEST_PROMISE(); + td_->bot_info_manager_->get_bot_media_previews(UserId(request.bot_user_id_), std::move(promise)); +} + +void Requests::on_request(uint64 id, const td_api::getBotMediaPreviewInfo &request) { + CHECK_IS_USER(); + CREATE_REQUEST_PROMISE(); + td_->bot_info_manager_->get_bot_media_preview_info(UserId(request.bot_user_id_), request.language_code_, + std::move(promise)); +} + +void Requests::on_request(uint64 id, td_api::addBotMediaPreview &request) { + CHECK_IS_USER(); + CREATE_REQUEST_PROMISE(); + td_->bot_info_manager_->add_bot_media_preview(UserId(request.bot_user_id_), request.language_code_, + std::move(request.content_), std::move(promise)); +} + +void Requests::on_request(uint64 id, td_api::editBotMediaPreview &request) { + CHECK_IS_USER(); + CREATE_REQUEST_PROMISE(); + td_->bot_info_manager_->edit_bot_media_preview(UserId(request.bot_user_id_), request.language_code_, + FileId(request.file_id_, 0), std::move(request.content_), + std::move(promise)); +} + +void Requests::on_request(uint64 id, const td_api::reorderBotMediaPreviews &request) { + CHECK_IS_USER(); + CREATE_OK_REQUEST_PROMISE(); + td_->bot_info_manager_->reorder_bot_media_previews(UserId(request.bot_user_id_), request.language_code_, + request.file_ids_, std::move(promise)); +} + +void Requests::on_request(uint64 id, const td_api::deleteBotMediaPreviews &request) { + CHECK_IS_USER(); + CREATE_OK_REQUEST_PROMISE(); + td_->bot_info_manager_->delete_bot_media_previews(UserId(request.bot_user_id_), request.language_code_, + request.file_ids_, std::move(promise)); +} + +void Requests::on_request(uint64 id, td_api::setBotName &request) { + CLEAN_INPUT_STRING(request.name_); + CREATE_OK_REQUEST_PROMISE(); + td_->bot_info_manager_->set_bot_name(UserId(request.bot_user_id_), request.language_code_, request.name_, + std::move(promise)); +} + +void Requests::on_request(uint64 id, const td_api::getBotName &request) { + CREATE_TEXT_REQUEST_PROMISE(); + td_->bot_info_manager_->get_bot_name(UserId(request.bot_user_id_), request.language_code_, std::move(promise)); +} + +void Requests::on_request(uint64 id, td_api::setBotProfilePhoto &request) { + CREATE_OK_REQUEST_PROMISE(); + td_->user_manager_->set_bot_profile_photo(UserId(request.bot_user_id_), request.photo_, std::move(promise)); +} + +void Requests::on_request(uint64 id, td_api::toggleBotUsernameIsActive &request) { + CHECK_IS_USER(); + CLEAN_INPUT_STRING(request.username_); + CREATE_OK_REQUEST_PROMISE(); + td_->user_manager_->toggle_bot_username_is_active(UserId(request.bot_user_id_), std::move(request.username_), + request.is_active_, std::move(promise)); +} + +void Requests::on_request(uint64 id, td_api::reorderBotActiveUsernames &request) { + CHECK_IS_USER(); + for (auto &username : request.usernames_) { + CLEAN_INPUT_STRING(username); + } + CREATE_OK_REQUEST_PROMISE(); + td_->user_manager_->reorder_bot_usernames(UserId(request.bot_user_id_), std::move(request.usernames_), + std::move(promise)); +} + +void Requests::on_request(uint64 id, td_api::setBotInfoDescription &request) { + CLEAN_INPUT_STRING(request.description_); + CREATE_OK_REQUEST_PROMISE(); + td_->bot_info_manager_->set_bot_info_description(UserId(request.bot_user_id_), request.language_code_, + request.description_, std::move(promise)); +} + +void Requests::on_request(uint64 id, const td_api::getBotInfoDescription &request) { + CREATE_TEXT_REQUEST_PROMISE(); + td_->bot_info_manager_->get_bot_info_description(UserId(request.bot_user_id_), request.language_code_, + std::move(promise)); +} + +void Requests::on_request(uint64 id, td_api::setBotInfoShortDescription &request) { + CLEAN_INPUT_STRING(request.short_description_); + CREATE_OK_REQUEST_PROMISE(); + td_->bot_info_manager_->set_bot_info_about(UserId(request.bot_user_id_), request.language_code_, + request.short_description_, std::move(promise)); +} + +void Requests::on_request(uint64 id, const td_api::getBotInfoShortDescription &request) { + CREATE_TEXT_REQUEST_PROMISE(); + td_->bot_info_manager_->get_bot_info_about(UserId(request.bot_user_id_), request.language_code_, std::move(promise)); +} + +void Requests::on_request(uint64 id, const td_api::setLocation &request) { + CHECK_IS_USER(); + CREATE_OK_REQUEST_PROMISE(); + td_->people_nearby_manager_->set_location(Location(request.location_), std::move(promise)); +} + +void Requests::on_request(uint64 id, td_api::setBusinessLocation &request) { + CHECK_IS_USER(); + CREATE_OK_REQUEST_PROMISE(); + td_->business_manager_->set_business_location(DialogLocation(std::move(request.location_)), std::move(promise)); +} + +void Requests::on_request(uint64 id, td_api::setBusinessOpeningHours &request) { + CHECK_IS_USER(); + CREATE_OK_REQUEST_PROMISE(); + td_->business_manager_->set_business_work_hours(BusinessWorkHours(std::move(request.opening_hours_)), + std::move(promise)); +} + +void Requests::on_request(uint64 id, td_api::setBusinessGreetingMessageSettings &request) { + CHECK_IS_USER(); + CREATE_OK_REQUEST_PROMISE(); + td_->business_manager_->set_business_greeting_message( + BusinessGreetingMessage(std::move(request.greeting_message_settings_)), std::move(promise)); +} + +void Requests::on_request(uint64 id, td_api::setBusinessAwayMessageSettings &request) { + CHECK_IS_USER(); + CREATE_OK_REQUEST_PROMISE(); + td_->business_manager_->set_business_away_message(BusinessAwayMessage(std::move(request.away_message_settings_)), + std::move(promise)); +} + +void Requests::on_request(uint64 id, td_api::setBusinessStartPage &request) { + CHECK_IS_USER(); + CREATE_OK_REQUEST_PROMISE(); + td_->business_manager_->set_business_intro(BusinessIntro(td_, std::move(request.start_page_)), std::move(promise)); +} + +void Requests::on_request(uint64 id, td_api::setProfilePhoto &request) { + CHECK_IS_USER(); + CREATE_OK_REQUEST_PROMISE(); + td_->user_manager_->set_profile_photo(request.photo_, request.is_public_, std::move(promise)); +} + +void Requests::on_request(uint64 id, const td_api::deleteProfilePhoto &request) { + CHECK_IS_USER(); + CREATE_OK_REQUEST_PROMISE(); + td_->user_manager_->delete_profile_photo(request.profile_photo_id_, false, std::move(promise)); +} + +void Requests::on_request(uint64 id, const td_api::getUserProfilePhotos &request) { + CREATE_REQUEST_PROMISE(); + td_->user_manager_->get_user_profile_photos(UserId(request.user_id_), request.offset_, request.limit_, + std::move(promise)); +} + +void Requests::on_request(uint64 id, const td_api::setAccentColor &request) { + CHECK_IS_USER(); + CREATE_OK_REQUEST_PROMISE(); + td_->user_manager_->set_accent_color(AccentColorId(request.accent_color_id_), + CustomEmojiId(request.background_custom_emoji_id_), std::move(promise)); +} + +void Requests::on_request(uint64 id, const td_api::setProfileAccentColor &request) { + CHECK_IS_USER(); + CREATE_OK_REQUEST_PROMISE(); + td_->user_manager_->set_profile_accent_color(AccentColorId(request.profile_accent_color_id_), + CustomEmojiId(request.profile_background_custom_emoji_id_), + std::move(promise)); +} + +void Requests::on_request(uint64 id, const td_api::getBusinessConnectedBot &request) { + CHECK_IS_USER(); + CREATE_REQUEST_PROMISE(); + td_->business_manager_->get_business_connected_bot(std::move(promise)); +} + +void Requests::on_request(uint64 id, td_api::setBusinessConnectedBot &request) { + CHECK_IS_USER(); + CREATE_OK_REQUEST_PROMISE(); + td_->business_manager_->set_business_connected_bot(std::move(request.bot_), std::move(promise)); +} + +void Requests::on_request(uint64 id, const td_api::deleteBusinessConnectedBot &request) { + CHECK_IS_USER(); + CREATE_OK_REQUEST_PROMISE(); + td_->business_manager_->delete_business_connected_bot(UserId(request.bot_user_id_), std::move(promise)); +} + +void Requests::on_request(uint64 id, const td_api::toggleBusinessConnectedBotChatIsPaused &request) { + CHECK_IS_USER(); + CREATE_OK_REQUEST_PROMISE(); + td_->business_manager_->toggle_business_connected_bot_dialog_is_paused(DialogId(request.chat_id_), request.is_paused_, + std::move(promise)); +} + +void Requests::on_request(uint64 id, const td_api::removeBusinessConnectedBotFromChat &request) { + CHECK_IS_USER(); + CREATE_OK_REQUEST_PROMISE(); + td_->business_manager_->remove_business_connected_bot_from_dialog(DialogId(request.chat_id_), std::move(promise)); +} + +void Requests::on_request(uint64 id, const td_api::getBusinessChatLinks &request) { + CHECK_IS_USER(); + CREATE_REQUEST_PROMISE(); + td_->business_manager_->get_business_chat_links(std::move(promise)); +} + +void Requests::on_request(uint64 id, td_api::createBusinessChatLink &request) { + CHECK_IS_USER(); + CREATE_REQUEST_PROMISE(); + td_->business_manager_->create_business_chat_link(std::move(request.link_info_), std::move(promise)); +} + +void Requests::on_request(uint64 id, td_api::editBusinessChatLink &request) { + CHECK_IS_USER(); + CLEAN_INPUT_STRING(request.link_); + CREATE_REQUEST_PROMISE(); + td_->business_manager_->edit_business_chat_link(request.link_, std::move(request.link_info_), std::move(promise)); +} + +void Requests::on_request(uint64 id, td_api::deleteBusinessChatLink &request) { + CHECK_IS_USER(); + CLEAN_INPUT_STRING(request.link_); + CREATE_OK_REQUEST_PROMISE(); + td_->business_manager_->delete_business_chat_link(request.link_, std::move(promise)); +} + +void Requests::on_request(uint64 id, td_api::getBusinessChatLinkInfo &request) { + CHECK_IS_USER(); + CLEAN_INPUT_STRING(request.link_name_); + CREATE_REQUEST_PROMISE(); + td_->business_manager_->get_business_chat_link_info(request.link_name_, std::move(promise)); +} + +void Requests::on_request(uint64 id, td_api::setSupergroupUsername &request) { + CHECK_IS_USER(); + CLEAN_INPUT_STRING(request.username_); + CREATE_OK_REQUEST_PROMISE(); + td_->chat_manager_->set_channel_username(ChannelId(request.supergroup_id_), request.username_, std::move(promise)); +} + +void Requests::on_request(uint64 id, td_api::toggleSupergroupUsernameIsActive &request) { + CHECK_IS_USER(); + CLEAN_INPUT_STRING(request.username_); + CREATE_OK_REQUEST_PROMISE(); + td_->chat_manager_->toggle_channel_username_is_active(ChannelId(request.supergroup_id_), std::move(request.username_), + request.is_active_, std::move(promise)); +} + +void Requests::on_request(uint64 id, const td_api::disableAllSupergroupUsernames &request) { + CHECK_IS_USER(); + CREATE_OK_REQUEST_PROMISE(); + td_->chat_manager_->disable_all_channel_usernames(ChannelId(request.supergroup_id_), std::move(promise)); +} + +void Requests::on_request(uint64 id, td_api::reorderSupergroupActiveUsernames &request) { + CHECK_IS_USER(); + for (auto &username : request.usernames_) { + CLEAN_INPUT_STRING(username); + } + CREATE_OK_REQUEST_PROMISE(); + td_->chat_manager_->reorder_channel_usernames(ChannelId(request.supergroup_id_), std::move(request.usernames_), + std::move(promise)); +} + +void Requests::on_request(uint64 id, const td_api::setSupergroupStickerSet &request) { + CREATE_OK_REQUEST_PROMISE(); + td_->chat_manager_->set_channel_sticker_set(ChannelId(request.supergroup_id_), StickerSetId(request.sticker_set_id_), + std::move(promise)); +} + +void Requests::on_request(uint64 id, const td_api::setSupergroupCustomEmojiStickerSet &request) { + CREATE_OK_REQUEST_PROMISE(); + td_->chat_manager_->set_channel_emoji_sticker_set( + ChannelId(request.supergroup_id_), StickerSetId(request.custom_emoji_sticker_set_id_), std::move(promise)); +} + +void Requests::on_request(uint64 id, const td_api::setSupergroupUnrestrictBoostCount &request) { + CREATE_OK_REQUEST_PROMISE(); + td_->chat_manager_->set_channel_unrestrict_boost_count(ChannelId(request.supergroup_id_), + request.unrestrict_boost_count_, std::move(promise)); +} + +void Requests::on_request(uint64 id, const td_api::toggleSupergroupSignMessages &request) { + CHECK_IS_USER(); + CREATE_OK_REQUEST_PROMISE(); + td_->chat_manager_->toggle_channel_sign_messages(ChannelId(request.supergroup_id_), request.sign_messages_, + request.show_message_sender_, std::move(promise)); +} + +void Requests::on_request(uint64 id, const td_api::toggleSupergroupJoinToSendMessages &request) { + CHECK_IS_USER(); + CREATE_OK_REQUEST_PROMISE(); + td_->chat_manager_->toggle_channel_join_to_send(ChannelId(request.supergroup_id_), request.join_to_send_messages_, + std::move(promise)); +} + +void Requests::on_request(uint64 id, const td_api::toggleSupergroupJoinByRequest &request) { + CHECK_IS_USER(); + CREATE_OK_REQUEST_PROMISE(); + td_->chat_manager_->toggle_channel_join_request(ChannelId(request.supergroup_id_), request.join_by_request_, + std::move(promise)); +} + +void Requests::on_request(uint64 id, const td_api::toggleSupergroupIsAllHistoryAvailable &request) { + CHECK_IS_USER(); + CREATE_OK_REQUEST_PROMISE(); + td_->chat_manager_->toggle_channel_is_all_history_available(ChannelId(request.supergroup_id_), + request.is_all_history_available_, std::move(promise)); +} + +void Requests::on_request(uint64 id, const td_api::toggleSupergroupCanHaveSponsoredMessages &request) { + CHECK_IS_USER(); + CREATE_OK_REQUEST_PROMISE(); + td_->chat_manager_->toggle_channel_can_have_sponsored_messages( + ChannelId(request.supergroup_id_), request.can_have_sponsored_messages_, std::move(promise)); +} + +void Requests::on_request(uint64 id, const td_api::toggleSupergroupHasHiddenMembers &request) { + CHECK_IS_USER(); + CREATE_OK_REQUEST_PROMISE(); + td_->chat_manager_->toggle_channel_has_hidden_participants(ChannelId(request.supergroup_id_), + request.has_hidden_members_, std::move(promise)); +} + +void Requests::on_request(uint64 id, const td_api::toggleSupergroupHasAggressiveAntiSpamEnabled &request) { + CHECK_IS_USER(); + CREATE_OK_REQUEST_PROMISE(); + td_->chat_manager_->toggle_channel_has_aggressive_anti_spam_enabled( + ChannelId(request.supergroup_id_), request.has_aggressive_anti_spam_enabled_, std::move(promise)); +} + +void Requests::on_request(uint64 id, const td_api::toggleSupergroupIsForum &request) { + CHECK_IS_USER(); + CREATE_OK_REQUEST_PROMISE(); + td_->chat_manager_->toggle_channel_is_forum(ChannelId(request.supergroup_id_), request.is_forum_, std::move(promise)); +} + +void Requests::on_request(uint64 id, const td_api::toggleSupergroupIsBroadcastGroup &request) { + CHECK_IS_USER(); + CREATE_OK_REQUEST_PROMISE(); + td_->chat_manager_->convert_channel_to_gigagroup(ChannelId(request.supergroup_id_), std::move(promise)); +} + +void Requests::on_request(uint64 id, const td_api::reportSupergroupSpam &request) { + CHECK_IS_USER(); + CREATE_OK_REQUEST_PROMISE(); + td_->chat_manager_->report_channel_spam(ChannelId(request.supergroup_id_), + MessageId::get_message_ids(request.message_ids_), std::move(promise)); +} + +void Requests::on_request(uint64 id, const td_api::reportSupergroupAntiSpamFalsePositive &request) { + CHECK_IS_USER(); + CREATE_OK_REQUEST_PROMISE(); + td_->chat_manager_->report_channel_anti_spam_false_positive(ChannelId(request.supergroup_id_), + MessageId(request.message_id_), std::move(promise)); +} + +void Requests::on_request(uint64 id, td_api::getSupergroupMembers &request) { + CREATE_REQUEST_PROMISE(); + auto query_promise = + PromiseCreator::lambda([promise = std::move(promise), td = td_](Result result) mutable { + if (result.is_error()) { + promise.set_error(result.move_as_error()); + } else { + promise.set_value(result.ok().get_chat_members_object(td, "getSupergroupMembers")); + } + }); + td_->dialog_participant_manager_->get_channel_participants(ChannelId(request.supergroup_id_), + std::move(request.filter_), string(), request.offset_, + request.limit_, -1, std::move(query_promise)); +} + +void Requests::on_request(uint64 id, td_api::closeSecretChat &request) { + CREATE_OK_REQUEST_PROMISE(); + send_closure(td_->secret_chats_manager_, &SecretChatsManager::cancel_chat, SecretChatId(request.secret_chat_id_), + false, std::move(promise)); +} + +void Requests::on_request(uint64 id, td_api::getStickers &request) { + CHECK_IS_USER(); + CLEAN_INPUT_STRING(request.query_); + CREATE_REQUEST(GetStickersRequest, get_sticker_type(request.sticker_type_), std::move(request.query_), request.limit_, + request.chat_id_); +} + +void Requests::on_request(uint64 id, td_api::getAllStickerEmojis &request) { + CHECK_IS_USER(); + CLEAN_INPUT_STRING(request.query_); + CREATE_REQUEST(GetAllStickerEmojisRequest, get_sticker_type(request.sticker_type_), std::move(request.query_), + request.chat_id_, request.return_only_main_emoji_); +} + +void Requests::on_request(uint64 id, td_api::searchStickers &request) { + CHECK_IS_USER(); + CLEAN_INPUT_STRING(request.emojis_); + CREATE_REQUEST_PROMISE(); + auto sticker_type = get_sticker_type(request.sticker_type_); + if (sticker_type == StickerType::Regular) { + // legacy + if (request.emojis_ == "⭐️⭐️") { + request.emojis_ = "⭐️"; + } else if (request.emojis_ == "📂⭐️") { + request.emojis_ = "📂"; + } else if (request.emojis_ == "👋⭐️") { + request.emojis_ = "👋"; + } + } + td_->stickers_manager_->search_stickers(sticker_type, std::move(request.emojis_), request.limit_, std::move(promise)); +} + +void Requests::on_request(uint64 id, const td_api::getGreetingStickers &request) { + CHECK_IS_USER(); + CREATE_REQUEST_PROMISE(); + td_->stickers_manager_->search_stickers(StickerType::Regular, "👋⭐️", 100, std::move(promise)); +} + +void Requests::on_request(uint64 id, const td_api::getPremiumStickers &request) { + CHECK_IS_USER(); + CREATE_REQUEST_PROMISE(); + td_->stickers_manager_->get_premium_stickers(request.limit_, std::move(promise)); +} + +void Requests::on_request(uint64 id, const td_api::getInstalledStickerSets &request) { + CHECK_IS_USER(); + CREATE_REQUEST(GetInstalledStickerSetsRequest, get_sticker_type(request.sticker_type_)); +} + +void Requests::on_request(uint64 id, const td_api::getArchivedStickerSets &request) { + CHECK_IS_USER(); + CREATE_REQUEST(GetArchivedStickerSetsRequest, get_sticker_type(request.sticker_type_), request.offset_sticker_set_id_, + request.limit_); +} + +void Requests::on_request(uint64 id, const td_api::getTrendingStickerSets &request) { + CHECK_IS_USER(); + CREATE_REQUEST(GetTrendingStickerSetsRequest, get_sticker_type(request.sticker_type_), request.offset_, + request.limit_); +} + +void Requests::on_request(uint64 id, const td_api::getAttachedStickerSets &request) { + CHECK_IS_USER(); + CREATE_REQUEST(GetAttachedStickerSetsRequest, request.file_id_); +} + +void Requests::on_request(uint64 id, const td_api::getStickerSet &request) { + CREATE_REQUEST(GetStickerSetRequest, request.set_id_); +} + +void Requests::on_request(uint64 id, const td_api::getStickerSetName &request) { + CREATE_TEXT_REQUEST_PROMISE(); + td_->stickers_manager_->get_sticker_set_name(StickerSetId(request.set_id_), std::move(promise)); +} + +void Requests::on_request(uint64 id, td_api::searchStickerSet &request) { + CLEAN_INPUT_STRING(request.name_); + CREATE_REQUEST(SearchStickerSetRequest, std::move(request.name_)); +} + +void Requests::on_request(uint64 id, td_api::searchInstalledStickerSets &request) { + CLEAN_INPUT_STRING(request.query_); + CREATE_REQUEST(SearchInstalledStickerSetsRequest, get_sticker_type(request.sticker_type_), std::move(request.query_), + request.limit_); +} + +void Requests::on_request(uint64 id, td_api::searchStickerSets &request) { + CLEAN_INPUT_STRING(request.query_); + CREATE_REQUEST(SearchStickerSetsRequest, get_sticker_type(request.sticker_type_), std::move(request.query_)); +} + +void Requests::on_request(uint64 id, const td_api::changeStickerSet &request) { + CHECK_IS_USER(); + CREATE_REQUEST(ChangeStickerSetRequest, request.set_id_, request.is_installed_, request.is_archived_); +} + +void Requests::on_request(uint64 id, const td_api::viewTrendingStickerSets &request) { + CHECK_IS_USER(); + td_->stickers_manager_->view_featured_sticker_sets( + StickersManager::convert_sticker_set_ids(request.sticker_set_ids_)); + send_closure(td_actor_, &Td::send_result, id, td_api::make_object()); +} + +void Requests::on_request(uint64 id, td_api::reorderInstalledStickerSets &request) { + CHECK_IS_USER(); + CREATE_OK_REQUEST_PROMISE(); + td_->stickers_manager_->reorder_installed_sticker_sets( + get_sticker_type(request.sticker_type_), StickersManager::convert_sticker_set_ids(request.sticker_set_ids_), + std::move(promise)); +} + +void Requests::on_request(uint64 id, td_api::uploadStickerFile &request) { + CREATE_REQUEST_PROMISE(); + td_->stickers_manager_->upload_sticker_file(UserId(request.user_id_), get_sticker_format(request.sticker_format_), + std::move(request.sticker_), std::move(promise)); +} + +void Requests::on_request(uint64 id, td_api::getSuggestedStickerSetName &request) { + CLEAN_INPUT_STRING(request.title_); + CREATE_TEXT_REQUEST_PROMISE(); + td_->stickers_manager_->get_suggested_sticker_set_name(std::move(request.title_), std::move(promise)); +} + +void Requests::on_request(uint64 id, td_api::checkStickerSetName &request) { + CLEAN_INPUT_STRING(request.name_); + CREATE_REQUEST_PROMISE(); + auto query_promise = PromiseCreator::lambda( + [promise = std::move(promise)](Result result) mutable { + if (result.is_error()) { + promise.set_error(result.move_as_error()); + } else { + promise.set_value(StickersManager::get_check_sticker_set_name_result_object(result.ok())); + } + }); + td_->stickers_manager_->check_sticker_set_name(request.name_, std::move(query_promise)); +} + +void Requests::on_request(uint64 id, td_api::createNewStickerSet &request) { + CLEAN_INPUT_STRING(request.title_); + CLEAN_INPUT_STRING(request.name_); + CLEAN_INPUT_STRING(request.source_); + CREATE_REQUEST_PROMISE(); + td_->stickers_manager_->create_new_sticker_set(UserId(request.user_id_), std::move(request.title_), + std::move(request.name_), get_sticker_type(request.sticker_type_), + request.needs_repainting_, std::move(request.stickers_), + std::move(request.source_), std::move(promise)); +} + +void Requests::on_request(uint64 id, td_api::addStickerToSet &request) { + CLEAN_INPUT_STRING(request.name_); + CREATE_OK_REQUEST_PROMISE(); + td_->stickers_manager_->add_sticker_to_set(UserId(request.user_id_), std::move(request.name_), + std::move(request.sticker_), nullptr, std::move(promise)); +} + +void Requests::on_request(uint64 id, td_api::replaceStickerInSet &request) { + CLEAN_INPUT_STRING(request.name_); + if (request.old_sticker_ == nullptr) { + return send_error_raw(id, 400, "Old sticker must be non-empty"); + } + CREATE_OK_REQUEST_PROMISE(); + td_->stickers_manager_->add_sticker_to_set(UserId(request.user_id_), std::move(request.name_), + std::move(request.new_sticker_), std::move(request.old_sticker_), + std::move(promise)); +} + +void Requests::on_request(uint64 id, td_api::setStickerSetThumbnail &request) { + CLEAN_INPUT_STRING(request.name_); + CREATE_OK_REQUEST_PROMISE(); + td_->stickers_manager_->set_sticker_set_thumbnail(UserId(request.user_id_), std::move(request.name_), + std::move(request.thumbnail_), get_sticker_format(request.format_), + std::move(promise)); +} + +void Requests::on_request(uint64 id, td_api::setCustomEmojiStickerSetThumbnail &request) { + CLEAN_INPUT_STRING(request.name_); + CREATE_OK_REQUEST_PROMISE(); + td_->stickers_manager_->set_custom_emoji_sticker_set_thumbnail( + std::move(request.name_), CustomEmojiId(request.custom_emoji_id_), std::move(promise)); +} + +void Requests::on_request(uint64 id, td_api::setStickerSetTitle &request) { + CLEAN_INPUT_STRING(request.name_); + CLEAN_INPUT_STRING(request.title_); + CREATE_OK_REQUEST_PROMISE(); + td_->stickers_manager_->set_sticker_set_title(std::move(request.name_), std::move(request.title_), + std::move(promise)); +} + +void Requests::on_request(uint64 id, td_api::deleteStickerSet &request) { + CLEAN_INPUT_STRING(request.name_); + CREATE_OK_REQUEST_PROMISE(); + td_->stickers_manager_->delete_sticker_set(std::move(request.name_), std::move(promise)); +} + +void Requests::on_request(uint64 id, td_api::setStickerPositionInSet &request) { + CREATE_OK_REQUEST_PROMISE(); + td_->stickers_manager_->set_sticker_position_in_set(request.sticker_, request.position_, std::move(promise)); +} + +void Requests::on_request(uint64 id, const td_api::removeStickerFromSet &request) { + CREATE_OK_REQUEST_PROMISE(); + td_->stickers_manager_->remove_sticker_from_set(request.sticker_, std::move(promise)); +} + +void Requests::on_request(uint64 id, td_api::setStickerEmojis &request) { + CLEAN_INPUT_STRING(request.emojis_); + CREATE_OK_REQUEST_PROMISE(); + td_->stickers_manager_->set_sticker_emojis(request.sticker_, request.emojis_, std::move(promise)); +} + +void Requests::on_request(uint64 id, td_api::setStickerKeywords &request) { + for (auto &keyword : request.keywords_) { + CLEAN_INPUT_STRING(keyword); + } + CREATE_OK_REQUEST_PROMISE(); + td_->stickers_manager_->set_sticker_keywords(request.sticker_, std::move(request.keywords_), std::move(promise)); +} + +void Requests::on_request(uint64 id, td_api::setStickerMaskPosition &request) { + CREATE_OK_REQUEST_PROMISE(); + td_->stickers_manager_->set_sticker_mask_position(request.sticker_, std::move(request.mask_position_), + std::move(promise)); +} + +void Requests::on_request(uint64 id, const td_api::getOwnedStickerSets &request) { + CHECK_IS_USER(); + CREATE_REQUEST_PROMISE(); + td_->stickers_manager_->get_created_sticker_sets(StickerSetId(request.offset_sticker_set_id_), request.limit_, + std::move(promise)); +} + +void Requests::on_request(uint64 id, const td_api::getRecentStickers &request) { + CHECK_IS_USER(); + CREATE_REQUEST(GetRecentStickersRequest, request.is_attached_); +} + +void Requests::on_request(uint64 id, td_api::addRecentSticker &request) { + CHECK_IS_USER(); + CREATE_REQUEST(AddRecentStickerRequest, request.is_attached_, std::move(request.sticker_)); +} + +void Requests::on_request(uint64 id, td_api::removeRecentSticker &request) { + CHECK_IS_USER(); + CREATE_REQUEST(RemoveRecentStickerRequest, request.is_attached_, std::move(request.sticker_)); +} + +void Requests::on_request(uint64 id, td_api::clearRecentStickers &request) { + CHECK_IS_USER(); + CREATE_REQUEST(ClearRecentStickersRequest, request.is_attached_); +} + +void Requests::on_request(uint64 id, const td_api::getFavoriteStickers &request) { + CHECK_IS_USER(); + CREATE_NO_ARGS_REQUEST(GetFavoriteStickersRequest); +} + +void Requests::on_request(uint64 id, td_api::addFavoriteSticker &request) { + CHECK_IS_USER(); + CREATE_REQUEST(AddFavoriteStickerRequest, std::move(request.sticker_)); +} + +void Requests::on_request(uint64 id, td_api::removeFavoriteSticker &request) { + CHECK_IS_USER(); + CREATE_REQUEST(RemoveFavoriteStickerRequest, std::move(request.sticker_)); +} + +void Requests::on_request(uint64 id, td_api::getStickerEmojis &request) { + CHECK_IS_USER(); + CREATE_REQUEST(GetStickerEmojisRequest, std::move(request.sticker_)); +} + +void Requests::on_request(uint64 id, td_api::searchEmojis &request) { + CHECK_IS_USER(); + CLEAN_INPUT_STRING(request.text_); + for (auto &input_language_code : request.input_language_codes_) { + CLEAN_INPUT_STRING(input_language_code); + } + CREATE_REQUEST(SearchEmojisRequest, std::move(request.text_), std::move(request.input_language_codes_)); +} + +void Requests::on_request(uint64 id, td_api::getKeywordEmojis &request) { + CHECK_IS_USER(); + CLEAN_INPUT_STRING(request.text_); + for (auto &input_language_code : request.input_language_codes_) { + CLEAN_INPUT_STRING(input_language_code); + } + CREATE_REQUEST(GetKeywordEmojisRequest, std::move(request.text_), std::move(request.input_language_codes_)); +} + +void Requests::on_request(uint64 id, const td_api::getEmojiCategories &request) { + CHECK_IS_USER(); + CREATE_REQUEST_PROMISE(); + td_->stickers_manager_->get_emoji_groups(get_emoji_group_type(request.type_), std::move(promise)); +} + +void Requests::on_request(uint64 id, td_api::getAnimatedEmoji &request) { + CHECK_IS_USER(); + CLEAN_INPUT_STRING(request.emoji_); + CREATE_REQUEST_PROMISE(); + td_->stickers_manager_->get_animated_emoji(std::move(request.emoji_), false, std::move(promise)); +} + +void Requests::on_request(uint64 id, td_api::getEmojiSuggestionsUrl &request) { + CHECK_IS_USER(); + CLEAN_INPUT_STRING(request.language_code_); + CREATE_REQUEST(GetEmojiSuggestionsUrlRequest, std::move(request.language_code_)); +} + +void Requests::on_request(uint64 id, const td_api::getCustomEmojiStickers &request) { + CREATE_REQUEST_PROMISE(); + td_->stickers_manager_->get_custom_emoji_stickers(CustomEmojiId::get_custom_emoji_ids(request.custom_emoji_ids_), + true, std::move(promise)); +} + +void Requests::on_request(uint64 id, const td_api::getDefaultChatPhotoCustomEmojiStickers &request) { + CHECK_IS_USER(); + CREATE_REQUEST_PROMISE(); + td_->stickers_manager_->get_default_custom_emoji_stickers(StickerListType::DialogPhoto, false, std::move(promise)); +} + +void Requests::on_request(uint64 id, const td_api::getDefaultProfilePhotoCustomEmojiStickers &request) { + CHECK_IS_USER(); + CREATE_REQUEST_PROMISE(); + td_->stickers_manager_->get_default_custom_emoji_stickers(StickerListType::UserProfilePhoto, false, + std::move(promise)); +} + +void Requests::on_request(uint64 id, const td_api::getDefaultBackgroundCustomEmojiStickers &request) { + CHECK_IS_USER(); + CREATE_REQUEST_PROMISE(); + td_->stickers_manager_->get_default_custom_emoji_stickers(StickerListType::Background, false, std::move(promise)); +} + +void Requests::on_request(uint64 id, const td_api::getDisallowedChatEmojiStatuses &request) { + CHECK_IS_USER(); + CREATE_REQUEST_PROMISE(); + td_->stickers_manager_->get_sticker_list_emoji_statuses(StickerListType::DisallowedChannelEmojiStatus, false, + std::move(promise)); +} + +void Requests::on_request(uint64 id, const td_api::getSavedAnimations &request) { + CHECK_IS_USER(); + CREATE_NO_ARGS_REQUEST(GetSavedAnimationsRequest); +} + +void Requests::on_request(uint64 id, td_api::addSavedAnimation &request) { + CHECK_IS_USER(); + CREATE_REQUEST(AddSavedAnimationRequest, std::move(request.animation_)); +} + +void Requests::on_request(uint64 id, td_api::removeSavedAnimation &request) { + CHECK_IS_USER(); + CREATE_REQUEST(RemoveSavedAnimationRequest, std::move(request.animation_)); +} + +void Requests::on_request(uint64 id, const td_api::getSavedNotificationSound &request) { + CHECK_IS_USER(); + CREATE_REQUEST(GetSavedNotificationSoundRequest, request.notification_sound_id_); +} + +void Requests::on_request(uint64 id, const td_api::getSavedNotificationSounds &request) { + CHECK_IS_USER(); + CREATE_NO_ARGS_REQUEST(GetSavedNotificationSoundsRequest); +} + +void Requests::on_request(uint64 id, td_api::addSavedNotificationSound &request) { + CHECK_IS_USER(); + CREATE_REQUEST_PROMISE(); + td_->notification_settings_manager_->add_saved_ringtone(std::move(request.sound_), std::move(promise)); +} + +void Requests::on_request(uint64 id, const td_api::removeSavedNotificationSound &request) { + CHECK_IS_USER(); + CREATE_REQUEST(RemoveSavedNotificationSoundRequest, request.notification_sound_id_); +} + +void Requests::on_request(uint64 id, const td_api::getChatNotificationSettingsExceptions &request) { + CHECK_IS_USER(); + bool filter_scope = false; + NotificationSettingsScope scope = NotificationSettingsScope::Private; + if (request.scope_ != nullptr) { + filter_scope = true; + scope = get_notification_settings_scope(request.scope_); + } + CREATE_REQUEST(GetChatNotificationSettingsExceptionsRequest, scope, filter_scope, request.compare_sound_); +} + +void Requests::on_request(uint64 id, const td_api::getScopeNotificationSettings &request) { + CHECK_IS_USER(); + if (request.scope_ == nullptr) { + return send_error_raw(id, 400, "Scope must be non-empty"); + } + CREATE_REQUEST(GetScopeNotificationSettingsRequest, get_notification_settings_scope(request.scope_)); +} + +void Requests::on_request(uint64 id, const td_api::removeChatActionBar &request) { + CHECK_IS_USER(); + CREATE_OK_REQUEST_PROMISE(); + td_->messages_manager_->remove_dialog_action_bar(DialogId(request.chat_id_), std::move(promise)); +} + +void Requests::on_request(uint64 id, td_api::reportChat &request) { + CHECK_IS_USER(); + auto r_report_reason = ReportReason::get_report_reason(std::move(request.reason_), std::move(request.text_)); + if (r_report_reason.is_error()) { + return send_error_raw(id, r_report_reason.error().code(), r_report_reason.error().message()); + } + CREATE_OK_REQUEST_PROMISE(); + td_->dialog_manager_->report_dialog(DialogId(request.chat_id_), MessageId::get_message_ids(request.message_ids_), + r_report_reason.move_as_ok(), std::move(promise)); +} + +void Requests::on_request(uint64 id, td_api::reportChatPhoto &request) { + CHECK_IS_USER(); + auto r_report_reason = ReportReason::get_report_reason(std::move(request.reason_), std::move(request.text_)); + if (r_report_reason.is_error()) { + return send_error_raw(id, r_report_reason.error().code(), r_report_reason.error().message()); + } + CREATE_OK_REQUEST_PROMISE(); + td_->dialog_manager_->report_dialog_photo(DialogId(request.chat_id_), FileId(request.file_id_, 0), + r_report_reason.move_as_ok(), std::move(promise)); +} + +void Requests::on_request(uint64 id, const td_api::reportMessageReactions &request) { + CHECK_IS_USER(); + CREATE_OK_REQUEST_PROMISE(); + TRY_RESULT_PROMISE(promise, sender_dialog_id, get_message_sender_dialog_id(td_, request.sender_id_, false, false)); + report_message_reactions(td_, {DialogId(request.chat_id_), MessageId(request.message_id_)}, sender_dialog_id, + std::move(promise)); +} + +void Requests::on_request(uint64 id, const td_api::getChatStatistics &request) { + CHECK_IS_USER(); + CREATE_REQUEST_PROMISE(); + td_->statistics_manager_->get_channel_statistics(DialogId(request.chat_id_), request.is_dark_, std::move(promise)); +} + +void Requests::on_request(uint64 id, const td_api::getChatRevenueStatistics &request) { + CHECK_IS_USER(); + CREATE_REQUEST_PROMISE(); + td_->statistics_manager_->get_channel_revenue_statistics(DialogId(request.chat_id_), request.is_dark_, + std::move(promise)); +} + +void Requests::on_request(uint64 id, const td_api::getChatRevenueWithdrawalUrl &request) { + CHECK_IS_USER(); + CREATE_HTTP_URL_REQUEST_PROMISE(); + td_->statistics_manager_->get_channel_revenue_withdrawal_url(DialogId(request.chat_id_), request.password_, + std::move(promise)); +} + +void Requests::on_request(uint64 id, const td_api::getChatRevenueTransactions &request) { + CHECK_IS_USER(); + CREATE_REQUEST_PROMISE(); + td_->statistics_manager_->get_channel_revenue_transactions(DialogId(request.chat_id_), request.offset_, + request.limit_, std::move(promise)); +} + +void Requests::on_request(uint64 id, const td_api::getStarRevenueStatistics &request) { + CHECK_IS_USER(); + CREATE_REQUEST_PROMISE(); + td_->star_manager_->get_star_revenue_statistics(request.owner_id_, request.is_dark_, std::move(promise)); +} + +void Requests::on_request(uint64 id, const td_api::getStarWithdrawalUrl &request) { + CHECK_IS_USER(); + CREATE_HTTP_URL_REQUEST_PROMISE(); + td_->star_manager_->get_star_withdrawal_url(request.owner_id_, request.star_count_, request.password_, + std::move(promise)); +} + +void Requests::on_request(uint64 id, const td_api::getStarAdAccountUrl &request) { + CHECK_IS_USER(); + CREATE_HTTP_URL_REQUEST_PROMISE(); + td_->star_manager_->get_star_ad_account_url(request.owner_id_, std::move(promise)); +} + +void Requests::on_request(uint64 id, const td_api::getMessageStatistics &request) { + CHECK_IS_USER(); + CREATE_REQUEST_PROMISE(); + td_->statistics_manager_->get_channel_message_statistics({DialogId(request.chat_id_), MessageId(request.message_id_)}, + request.is_dark_, std::move(promise)); +} + +void Requests::on_request(uint64 id, const td_api::getStoryStatistics &request) { + CHECK_IS_USER(); + CREATE_REQUEST_PROMISE(); + td_->statistics_manager_->get_channel_story_statistics({DialogId(request.chat_id_), StoryId(request.story_id_)}, + request.is_dark_, std::move(promise)); +} + +void Requests::on_request(uint64 id, td_api::getStatisticalGraph &request) { + CHECK_IS_USER(); + CLEAN_INPUT_STRING(request.token_); + CREATE_REQUEST_PROMISE(); + td_->statistics_manager_->load_statistics_graph(DialogId(request.chat_id_), std::move(request.token_), request.x_, + std::move(promise)); +} + +void Requests::on_request(uint64 id, td_api::setChatNotificationSettings &request) { + CHECK_IS_USER(); + answer_ok_query(id, td_->messages_manager_->set_dialog_notification_settings( + DialogId(request.chat_id_), std::move(request.notification_settings_))); +} + +void Requests::on_request(uint64 id, td_api::setForumTopicNotificationSettings &request) { + CHECK_IS_USER(); + answer_ok_query(id, td_->forum_topic_manager_->set_forum_topic_notification_settings( + DialogId(request.chat_id_), MessageId(request.message_thread_id_), + std::move(request.notification_settings_))); +} + +void Requests::on_request(uint64 id, td_api::setScopeNotificationSettings &request) { + CHECK_IS_USER(); + if (request.scope_ == nullptr) { + return send_error_raw(id, 400, "Scope must be non-empty"); + } + answer_ok_query(id, td_->notification_settings_manager_->set_scope_notification_settings( + get_notification_settings_scope(request.scope_), std::move(request.notification_settings_))); +} + +void Requests::on_request(uint64 id, td_api::setReactionNotificationSettings &request) { + CHECK_IS_USER(); + answer_ok_query(id, td_->notification_settings_manager_->set_reaction_notification_settings( + ReactionNotificationSettings(std::move(request.notification_settings_)))); +} + +void Requests::on_request(uint64 id, const td_api::resetAllNotificationSettings &request) { + CHECK_IS_USER(); + td_->messages_manager_->reset_all_notification_settings(); + send_closure(td_actor_, &Td::send_result, id, td_api::make_object()); +} + +void Requests::on_request(uint64 id, const td_api::getMapThumbnailFile &request) { + DialogId dialog_id(request.chat_id_); + if (!td_->dialog_manager_->have_dialog_force(dialog_id, "getMapThumbnailFile")) { + dialog_id = DialogId(); + } + + auto r_file_id = td_->file_manager_->get_map_thumbnail_file_id( + Location(request.location_), request.zoom_, request.width_, request.height_, request.scale_, dialog_id); + if (r_file_id.is_error()) { + send_closure(td_actor_, &Td::send_error, id, r_file_id.move_as_error()); + } else { + send_closure(td_actor_, &Td::send_result, id, td_->file_manager_->get_file_object(r_file_id.ok())); + } +} + +void Requests::on_request(uint64 id, const td_api::getLocalizationTargetInfo &request) { + CHECK_IS_USER(); + CREATE_REQUEST_PROMISE(); + send_closure(td_->language_pack_manager_, &LanguagePackManager::get_languages, request.only_local_, + std::move(promise)); +} + +void Requests::on_request(uint64 id, td_api::getLanguagePackInfo &request) { + CHECK_IS_USER(); + CLEAN_INPUT_STRING(request.language_pack_id_); + CREATE_REQUEST_PROMISE(); + send_closure(td_->language_pack_manager_, &LanguagePackManager::search_language_info, request.language_pack_id_, + std::move(promise)); +} + +void Requests::on_request(uint64 id, td_api::getLanguagePackStrings &request) { + CHECK_IS_USER(); + CLEAN_INPUT_STRING(request.language_pack_id_); + for (auto &key : request.keys_) { + CLEAN_INPUT_STRING(key); + } + CREATE_REQUEST_PROMISE(); + send_closure(td_->language_pack_manager_, &LanguagePackManager::get_language_pack_strings, + std::move(request.language_pack_id_), std::move(request.keys_), std::move(promise)); +} + +void Requests::on_request(uint64 id, td_api::synchronizeLanguagePack &request) { + CHECK_IS_USER(); + CLEAN_INPUT_STRING(request.language_pack_id_); + CREATE_OK_REQUEST_PROMISE(); + send_closure(td_->language_pack_manager_, &LanguagePackManager::synchronize_language_pack, + std::move(request.language_pack_id_), std::move(promise)); +} + +void Requests::on_request(uint64 id, td_api::addCustomServerLanguagePack &request) { + CHECK_IS_USER(); + CLEAN_INPUT_STRING(request.language_pack_id_); + CREATE_OK_REQUEST_PROMISE(); + send_closure(td_->language_pack_manager_, &LanguagePackManager::add_custom_server_language, + std::move(request.language_pack_id_), std::move(promise)); +} + +void Requests::on_request(uint64 id, td_api::setCustomLanguagePack &request) { + CHECK_IS_USER(); + CREATE_OK_REQUEST_PROMISE(); + send_closure(td_->language_pack_manager_, &LanguagePackManager::set_custom_language, std::move(request.info_), + std::move(request.strings_), std::move(promise)); +} + +void Requests::on_request(uint64 id, td_api::editCustomLanguagePackInfo &request) { + CHECK_IS_USER(); + CREATE_OK_REQUEST_PROMISE(); + send_closure(td_->language_pack_manager_, &LanguagePackManager::edit_custom_language_info, std::move(request.info_), + std::move(promise)); +} + +void Requests::on_request(uint64 id, td_api::setCustomLanguagePackString &request) { + CHECK_IS_USER(); + CLEAN_INPUT_STRING(request.language_pack_id_); + CREATE_OK_REQUEST_PROMISE(); + send_closure(td_->language_pack_manager_, &LanguagePackManager::set_custom_language_string, + std::move(request.language_pack_id_), std::move(request.new_string_), std::move(promise)); +} + +void Requests::on_request(uint64 id, td_api::deleteLanguagePack &request) { + CHECK_IS_USER(); + CLEAN_INPUT_STRING(request.language_pack_id_); + CREATE_OK_REQUEST_PROMISE(); + send_closure(td_->language_pack_manager_, &LanguagePackManager::delete_language, std::move(request.language_pack_id_), + std::move(promise)); +} + +void Requests::on_request(uint64 id, td_api::getOption &request) { + CLEAN_INPUT_STRING(request.name_); + CREATE_REQUEST_PROMISE(); + td_->option_manager_->get_option(request.name_, std::move(promise)); +} + +void Requests::on_request(uint64 id, td_api::setOption &request) { + CLEAN_INPUT_STRING(request.name_); + CREATE_OK_REQUEST_PROMISE(); + td_->option_manager_->set_option(request.name_, std::move(request.value_), std::move(promise)); +} + +void Requests::on_request(uint64 id, td_api::setPollAnswer &request) { + CHECK_IS_USER(); + CREATE_OK_REQUEST_PROMISE(); + td_->messages_manager_->set_poll_answer({DialogId(request.chat_id_), MessageId(request.message_id_)}, + std::move(request.option_ids_), std::move(promise)); +} + +void Requests::on_request(uint64 id, td_api::getPollVoters &request) { + CHECK_IS_USER(); + CREATE_REQUEST_PROMISE(); + td_->messages_manager_->get_poll_voters({DialogId(request.chat_id_), MessageId(request.message_id_)}, + request.option_id_, request.offset_, request.limit_, std::move(promise)); +} + +void Requests::on_request(uint64 id, td_api::stopPoll &request) { + CREATE_OK_REQUEST_PROMISE(); + td_->messages_manager_->stop_poll({DialogId(request.chat_id_), MessageId(request.message_id_)}, + std::move(request.reply_markup_), std::move(promise)); +} + +void Requests::on_request(uint64 id, const td_api::hideSuggestedAction &request) { + CHECK_IS_USER(); + CREATE_OK_REQUEST_PROMISE(); + dismiss_suggested_action(SuggestedAction(request.action_), std::move(promise)); +} + +void Requests::on_request(uint64 id, const td_api::hideContactCloseBirthdays &request) { + CHECK_IS_USER(); + CREATE_OK_REQUEST_PROMISE(); + td_->option_manager_->set_option_boolean("dismiss_birthday_contact_today", true); + td_->user_manager_->hide_contact_birthdays(std::move(promise)); +} + +void Requests::on_request(uint64 id, td_api::getBusinessConnection &request) { + CHECK_IS_BOT(); + CLEAN_INPUT_STRING(request.connection_id_); + CREATE_REQUEST_PROMISE(); + td_->business_connection_manager_->get_business_connection(BusinessConnectionId(std::move(request.connection_id_)), + std::move(promise)); +} + +void Requests::on_request(uint64 id, const td_api::getLoginUrlInfo &request) { + CHECK_IS_USER(); + CREATE_REQUEST_PROMISE(); + td_->link_manager_->get_login_url_info({DialogId(request.chat_id_), MessageId(request.message_id_)}, + request.button_id_, std::move(promise)); +} + +void Requests::on_request(uint64 id, const td_api::getLoginUrl &request) { + CHECK_IS_USER(); + CREATE_REQUEST_PROMISE(); + td_->link_manager_->get_login_url({DialogId(request.chat_id_), MessageId(request.message_id_)}, request.button_id_, + request.allow_write_access_, std::move(promise)); +} + +void Requests::on_request(uint64 id, const td_api::shareUsersWithBot &request) { + CHECK_IS_USER(); + CREATE_OK_REQUEST_PROMISE(); + auto user_ids = UserId::get_user_ids(request.shared_user_ids_); + auto dialog_ids = transform(user_ids, [](UserId user_id) { return DialogId(user_id); }); + td_->messages_manager_->share_dialogs_with_bot({DialogId(request.chat_id_), MessageId(request.message_id_)}, + request.button_id_, std::move(dialog_ids), true, request.only_check_, + std::move(promise)); +} + +void Requests::on_request(uint64 id, const td_api::shareChatWithBot &request) { + CHECK_IS_USER(); + CREATE_OK_REQUEST_PROMISE(); + td_->messages_manager_->share_dialogs_with_bot({DialogId(request.chat_id_), MessageId(request.message_id_)}, + request.button_id_, {DialogId(request.shared_chat_id_)}, false, + request.only_check_, std::move(promise)); +} + +void Requests::on_request(uint64 id, td_api::getInlineQueryResults &request) { + CHECK_IS_USER(); + CLEAN_INPUT_STRING(request.query_); + CLEAN_INPUT_STRING(request.offset_); + CREATE_REQUEST_PROMISE(); + td_->inline_queries_manager_->send_inline_query(UserId(request.bot_user_id_), DialogId(request.chat_id_), + Location(request.user_location_), request.query_, request.offset_, + std::move(promise)); +} + +void Requests::on_request(uint64 id, td_api::answerInlineQuery &request) { + CHECK_IS_BOT(); + CLEAN_INPUT_STRING(request.next_offset_); + CREATE_OK_REQUEST_PROMISE(); + td_->inline_queries_manager_->answer_inline_query(request.inline_query_id_, request.is_personal_, + std::move(request.button_), std::move(request.results_), + request.cache_time_, request.next_offset_, std::move(promise)); +} + +void Requests::on_request(uint64 id, td_api::getGrossingWebAppBots &request) { + CHECK_IS_USER(); + CLEAN_INPUT_STRING(request.offset_); + CREATE_REQUEST_PROMISE(); + td_->attach_menu_manager_->get_popular_app_bots(request.offset_, request.limit_, std::move(promise)); +} + +void Requests::on_request(uint64 id, td_api::searchWebApp &request) { + CHECK_IS_USER(); + CLEAN_INPUT_STRING(request.web_app_short_name_); + CREATE_REQUEST_PROMISE(); + td_->attach_menu_manager_->get_web_app(UserId(request.bot_user_id_), request.web_app_short_name_, std::move(promise)); +} + +void Requests::on_request(uint64 id, td_api::getWebAppLinkUrl &request) { + CHECK_IS_USER(); + CLEAN_INPUT_STRING(request.web_app_short_name_); + CLEAN_INPUT_STRING(request.start_parameter_); + CLEAN_INPUT_STRING(request.application_name_); + CREATE_HTTP_URL_REQUEST_PROMISE(); + td_->attach_menu_manager_->request_app_web_view( + DialogId(request.chat_id_), UserId(request.bot_user_id_), std::move(request.web_app_short_name_), + std::move(request.start_parameter_), std::move(request.theme_), std::move(request.application_name_), + request.allow_write_access_, std::move(promise)); +} + +void Requests::on_request(uint64 id, td_api::getMainWebApp &request) { + CHECK_IS_USER(); + CLEAN_INPUT_STRING(request.start_parameter_); + CLEAN_INPUT_STRING(request.application_name_); + CREATE_REQUEST_PROMISE(); + td_->attach_menu_manager_->request_main_web_view(DialogId(request.chat_id_), UserId(request.bot_user_id_), + std::move(request.start_parameter_), std::move(request.theme_), + std::move(request.application_name_), std::move(promise)); +} + +void Requests::on_request(uint64 id, td_api::getWebAppUrl &request) { + CHECK_IS_USER(); + CLEAN_INPUT_STRING(request.url_); + CLEAN_INPUT_STRING(request.application_name_); + CREATE_HTTP_URL_REQUEST_PROMISE(); + td_->inline_queries_manager_->get_simple_web_view_url(UserId(request.bot_user_id_), std::move(request.url_), + std::move(request.theme_), std::move(request.application_name_), + std::move(promise)); +} + +void Requests::on_request(uint64 id, td_api::sendWebAppData &request) { + CHECK_IS_USER(); + CLEAN_INPUT_STRING(request.button_text_); + CLEAN_INPUT_STRING(request.data_); + CREATE_OK_REQUEST_PROMISE(); + td_->inline_queries_manager_->send_web_view_data(UserId(request.bot_user_id_), std::move(request.button_text_), + std::move(request.data_), std::move(promise)); +} + +void Requests::on_request(uint64 id, td_api::openWebApp &request) { + CHECK_IS_USER(); + CLEAN_INPUT_STRING(request.url_); + CLEAN_INPUT_STRING(request.application_name_); + CREATE_REQUEST_PROMISE(); + td_->attach_menu_manager_->request_web_view(DialogId(request.chat_id_), UserId(request.bot_user_id_), + MessageId(request.message_thread_id_), std::move(request.reply_to_), + std::move(request.url_), std::move(request.theme_), + std::move(request.application_name_), std::move(promise)); +} + +void Requests::on_request(uint64 id, const td_api::closeWebApp &request) { + CHECK_IS_USER(); + CREATE_OK_REQUEST_PROMISE(); + td_->attach_menu_manager_->close_web_view(request.web_app_launch_id_, std::move(promise)); +} + +void Requests::on_request(uint64 id, td_api::answerWebAppQuery &request) { + CHECK_IS_BOT(); + CLEAN_INPUT_STRING(request.web_app_query_id_); + CREATE_REQUEST_PROMISE(); + td_->inline_queries_manager_->answer_web_view_query(request.web_app_query_id_, std::move(request.result_), + std::move(promise)); +} + +void Requests::on_request(uint64 id, td_api::getCallbackQueryAnswer &request) { + CHECK_IS_USER(); + CREATE_REQUEST_PROMISE(); + td_->callback_queries_manager_->send_callback_query({DialogId(request.chat_id_), MessageId(request.message_id_)}, + std::move(request.payload_), std::move(promise)); +} + +void Requests::on_request(uint64 id, td_api::answerCallbackQuery &request) { + CHECK_IS_BOT(); + CLEAN_INPUT_STRING(request.text_); + CLEAN_INPUT_STRING(request.url_); + CREATE_OK_REQUEST_PROMISE(); + td_->callback_queries_manager_->answer_callback_query(request.callback_query_id_, request.text_, request.show_alert_, + request.url_, request.cache_time_, std::move(promise)); +} + +void Requests::on_request(uint64 id, td_api::answerShippingQuery &request) { + CHECK_IS_BOT(); + CLEAN_INPUT_STRING(request.error_message_); + CREATE_OK_REQUEST_PROMISE(); + answer_shipping_query(td_, request.shipping_query_id_, std::move(request.shipping_options_), request.error_message_, + std::move(promise)); +} + +void Requests::on_request(uint64 id, td_api::answerPreCheckoutQuery &request) { + CHECK_IS_BOT(); + CLEAN_INPUT_STRING(request.error_message_); + CREATE_OK_REQUEST_PROMISE(); + answer_pre_checkout_query(td_, request.pre_checkout_query_id_, request.error_message_, std::move(promise)); +} + +void Requests::on_request(uint64 id, td_api::getBankCardInfo &request) { + CHECK_IS_USER(); + CLEAN_INPUT_STRING(request.bank_card_number_); + CREATE_REQUEST_PROMISE(); + get_bank_card_info(td_, request.bank_card_number_, std::move(promise)); +} + +void Requests::on_request(uint64 id, td_api::getPaymentForm &request) { + CHECK_IS_USER(); + CREATE_REQUEST_PROMISE(); + get_payment_form(td_, std::move(request.input_invoice_), request.theme_, std::move(promise)); +} + +void Requests::on_request(uint64 id, td_api::validateOrderInfo &request) { + CHECK_IS_USER(); + CREATE_REQUEST_PROMISE(); + validate_order_info(td_, std::move(request.input_invoice_), std::move(request.order_info_), request.allow_save_, + std::move(promise)); +} + +void Requests::on_request(uint64 id, td_api::sendPaymentForm &request) { + CHECK_IS_USER(); + CLEAN_INPUT_STRING(request.order_info_id_); + CLEAN_INPUT_STRING(request.shipping_option_id_); + CREATE_REQUEST_PROMISE(); + send_payment_form(td_, std::move(request.input_invoice_), request.payment_form_id_, request.order_info_id_, + request.shipping_option_id_, request.credentials_, request.tip_amount_, std::move(promise)); +} + +void Requests::on_request(uint64 id, const td_api::getPaymentReceipt &request) { + CHECK_IS_USER(); + CREATE_REQUEST_PROMISE(); + get_payment_receipt(td_, {DialogId(request.chat_id_), MessageId(request.message_id_)}, std::move(promise)); +} + +void Requests::on_request(uint64 id, const td_api::getSavedOrderInfo &request) { + CHECK_IS_USER(); + CREATE_REQUEST_PROMISE(); + get_saved_order_info(td_, std::move(promise)); +} + +void Requests::on_request(uint64 id, const td_api::deleteSavedOrderInfo &request) { + CHECK_IS_USER(); + CREATE_OK_REQUEST_PROMISE(); + delete_saved_order_info(td_, std::move(promise)); +} + +void Requests::on_request(uint64 id, const td_api::deleteSavedCredentials &request) { + CHECK_IS_USER(); + CREATE_OK_REQUEST_PROMISE(); + delete_saved_credentials(td_, std::move(promise)); +} + +void Requests::on_request(uint64 id, td_api::createInvoiceLink &request) { + CHECK_IS_BOT(); + CREATE_HTTP_URL_REQUEST_PROMISE(); + export_invoice(td_, std::move(request.invoice_), std::move(promise)); +} + +void Requests::on_request(uint64 id, td_api::refundStarPayment &request) { + CHECK_IS_BOT(); + CLEAN_INPUT_STRING(request.telegram_payment_charge_id_); + CREATE_OK_REQUEST_PROMISE(); + td_->star_manager_->refund_star_payment(UserId(request.user_id_), request.telegram_payment_charge_id_, + std::move(promise)); +} + +void Requests::on_request(uint64 id, td_api::getPassportElement &request) { + CHECK_IS_USER(); + CLEAN_INPUT_STRING(request.password_); + if (request.type_ == nullptr) { + return send_error_raw(id, 400, "Type must be non-empty"); + } + CREATE_REQUEST_PROMISE(); + send_closure(td_->secure_manager_, &SecureManager::get_secure_value, std::move(request.password_), + get_secure_value_type_td_api(request.type_), std::move(promise)); +} + +void Requests::on_request(uint64 id, td_api::getAllPassportElements &request) { + CHECK_IS_USER(); + CLEAN_INPUT_STRING(request.password_); + CREATE_REQUEST_PROMISE(); + send_closure(td_->secure_manager_, &SecureManager::get_all_secure_values, std::move(request.password_), + std::move(promise)); +} + +void Requests::on_request(uint64 id, td_api::setPassportElement &request) { + CHECK_IS_USER(); + CLEAN_INPUT_STRING(request.password_); + auto r_secure_value = get_secure_value(td_->file_manager_.get(), std::move(request.element_)); + if (r_secure_value.is_error()) { + return send_error_raw(id, 400, r_secure_value.error().message()); + } + CREATE_REQUEST_PROMISE(); + send_closure(td_->secure_manager_, &SecureManager::set_secure_value, std::move(request.password_), + r_secure_value.move_as_ok(), std::move(promise)); +} + +void Requests::on_request(uint64 id, const td_api::deletePassportElement &request) { + CHECK_IS_USER(); + if (request.type_ == nullptr) { + return send_error_raw(id, 400, "Type must be non-empty"); + } + CREATE_OK_REQUEST_PROMISE(); + send_closure(td_->secure_manager_, &SecureManager::delete_secure_value, get_secure_value_type_td_api(request.type_), + std::move(promise)); +} + +void Requests::on_request(uint64 id, td_api::setPassportElementErrors &request) { + CHECK_IS_BOT(); + auto r_input_user = td_->user_manager_->get_input_user(UserId(request.user_id_)); + if (r_input_user.is_error()) { + return send_error_raw(id, r_input_user.error().code(), r_input_user.error().message()); + } + CREATE_OK_REQUEST_PROMISE(); + send_closure(td_->secure_manager_, &SecureManager::set_secure_value_errors, td_, r_input_user.move_as_ok(), + std::move(request.errors_), std::move(promise)); +} + +void Requests::on_request(uint64 id, td_api::getPreferredCountryLanguage &request) { + CHECK_IS_USER(); + CLEAN_INPUT_STRING(request.country_code_); + CREATE_REQUEST_PROMISE(); + send_closure(td_->secure_manager_, &SecureManager::get_preferred_country_language, std::move(request.country_code_), + std::move(promise)); +} + +void Requests::on_request(uint64 id, td_api::sendEmailAddressVerificationCode &request) { + CHECK_IS_USER(); + CLEAN_INPUT_STRING(request.email_address_); + CREATE_REQUEST_PROMISE(); + auto query_promise = PromiseCreator::lambda([promise = std::move(promise)](Result result) mutable { + if (result.is_error()) { + promise.set_error(result.move_as_error()); + } else { + promise.set_value(result.ok().get_email_address_authentication_code_info_object()); + } + }); + send_closure(td_->password_manager_, &PasswordManager::send_email_address_verification_code, + std::move(request.email_address_), std::move(query_promise)); +} + +void Requests::on_request(uint64 id, const td_api::resendEmailAddressVerificationCode &request) { + CHECK_IS_USER(); + CREATE_REQUEST_PROMISE(); + auto query_promise = PromiseCreator::lambda([promise = std::move(promise)](Result result) mutable { + if (result.is_error()) { + promise.set_error(result.move_as_error()); + } else { + promise.set_value(result.ok().get_email_address_authentication_code_info_object()); + } + }); + send_closure(td_->password_manager_, &PasswordManager::resend_email_address_verification_code, + std::move(query_promise)); +} + +void Requests::on_request(uint64 id, td_api::checkEmailAddressVerificationCode &request) { + CHECK_IS_USER(); + CLEAN_INPUT_STRING(request.code_); + CREATE_OK_REQUEST_PROMISE(); + send_closure(td_->password_manager_, &PasswordManager::check_email_address_verification_code, + std::move(request.code_), std::move(promise)); +} + +void Requests::on_request(uint64 id, td_api::getPassportAuthorizationForm &request) { + CHECK_IS_USER(); + CLEAN_INPUT_STRING(request.public_key_); + CLEAN_INPUT_STRING(request.scope_); + CLEAN_INPUT_STRING(request.nonce_); + UserId bot_user_id(request.bot_user_id_); + if (!bot_user_id.is_valid()) { + return send_error_raw(id, 400, "Bot user identifier invalid"); + } + if (request.nonce_.empty()) { + return send_error_raw(id, 400, "Nonce must be non-empty"); + } + CREATE_REQUEST_PROMISE(); + send_closure(td_->secure_manager_, &SecureManager::get_passport_authorization_form, bot_user_id, + std::move(request.scope_), std::move(request.public_key_), std::move(request.nonce_), + std::move(promise)); +} + +void Requests::on_request(uint64 id, td_api::getPassportAuthorizationFormAvailableElements &request) { + CHECK_IS_USER(); + CLEAN_INPUT_STRING(request.password_); + CREATE_REQUEST_PROMISE(); + send_closure(td_->secure_manager_, &SecureManager::get_passport_authorization_form_available_elements, + request.authorization_form_id_, std::move(request.password_), std::move(promise)); +} + +void Requests::on_request(uint64 id, td_api::sendPassportAuthorizationForm &request) { + CHECK_IS_USER(); + for (auto &type : request.types_) { + if (type == nullptr) { + return send_error_raw(id, 400, "Type must be non-empty"); + } + } + + CREATE_OK_REQUEST_PROMISE(); + send_closure(td_->secure_manager_, &SecureManager::send_passport_authorization_form, request.authorization_form_id_, + get_secure_value_types_td_api(request.types_), std::move(promise)); +} + +void Requests::on_request(uint64 id, const td_api::getSupportUser &request) { + CHECK_IS_USER(); + CREATE_REQUEST_PROMISE(); + td_->user_manager_->get_support_user(std::move(promise)); +} + +void Requests::on_request(uint64 id, const td_api::getInstalledBackgrounds &request) { + CHECK_IS_USER(); + CREATE_REQUEST_PROMISE(); + td_->background_manager_->get_backgrounds(request.for_dark_theme_, std::move(promise)); +} + +void Requests::on_request(uint64 id, td_api::getBackgroundUrl &request) { + CHECK_IS_USER(); + CLEAN_INPUT_STRING(request.name_); + Result r_url = LinkManager::get_background_url(request.name_, std::move(request.type_)); + if (r_url.is_error()) { + return send_closure(td_actor_, &Td::send_error, id, r_url.move_as_error()); + } + + send_closure(td_actor_, &Td::send_result, id, td_api::make_object(r_url.ok())); +} + +void Requests::on_request(uint64 id, td_api::searchBackground &request) { + CHECK_IS_USER(); + CLEAN_INPUT_STRING(request.name_); + CREATE_REQUEST(SearchBackgroundRequest, std::move(request.name_)); +} + +void Requests::on_request(uint64 id, td_api::setDefaultBackground &request) { + CHECK_IS_USER(); + CREATE_REQUEST_PROMISE(); + td_->background_manager_->set_background(request.background_.get(), request.type_.get(), request.for_dark_theme_, + std::move(promise)); +} + +void Requests::on_request(uint64 id, const td_api::deleteDefaultBackground &request) { + CHECK_IS_USER(); + CREATE_OK_REQUEST_PROMISE(); + td_->background_manager_->delete_background(request.for_dark_theme_, std::move(promise)); +} + +void Requests::on_request(uint64 id, const td_api::removeInstalledBackground &request) { + CHECK_IS_USER(); + CREATE_OK_REQUEST_PROMISE(); + td_->background_manager_->remove_background(BackgroundId(request.background_id_), std::move(promise)); +} + +void Requests::on_request(uint64 id, const td_api::resetInstalledBackgrounds &request) { + CHECK_IS_USER(); + CREATE_OK_REQUEST_PROMISE(); + td_->background_manager_->reset_backgrounds(std::move(promise)); +} + +void Requests::on_request(uint64 id, td_api::getRecentlyVisitedTMeUrls &request) { + CHECK_IS_USER(); + CLEAN_INPUT_STRING(request.referrer_); + CREATE_REQUEST_PROMISE(); + td_->link_manager_->get_recent_me_urls(request.referrer_, std::move(promise)); +} + +void Requests::on_request(uint64 id, td_api::setBotUpdatesStatus &request) { + CHECK_IS_BOT(); + CLEAN_INPUT_STRING(request.error_message_); + CREATE_OK_REQUEST_PROMISE(); + set_bot_updates_status(td_, request.pending_update_count_, request.error_message_, std::move(promise)); +} + +void Requests::on_request(uint64 id, td_api::sendCustomRequest &request) { + CHECK_IS_BOT(); + CLEAN_INPUT_STRING(request.method_); + CLEAN_INPUT_STRING(request.parameters_); + CREATE_REQUEST_PROMISE(); + send_bot_custom_query(td_, request.method_, request.parameters_, std::move(promise)); +} + +void Requests::on_request(uint64 id, td_api::answerCustomQuery &request) { + CHECK_IS_BOT(); + CLEAN_INPUT_STRING(request.data_); + CREATE_OK_REQUEST_PROMISE(); + answer_bot_custom_query(td_, request.custom_query_id_, request.data_, std::move(promise)); +} + +void Requests::on_request(uint64 id, const td_api::setAlarm &request) { + CREATE_OK_REQUEST_PROMISE(); + send_closure(td_->alarm_manager_, &AlarmManager::set_alarm, request.seconds_, std::move(promise)); +} + +void Requests::on_request(uint64 id, td_api::searchHashtags &request) { + CHECK_IS_USER(); + CLEAN_INPUT_STRING(request.prefix_); + CREATE_REQUEST_PROMISE(); + auto query_promise = + PromiseCreator::lambda([promise = std::move(promise)](Result> result) mutable { + if (result.is_error()) { + promise.set_error(result.move_as_error()); + } else { + promise.set_value(td_api::make_object(result.move_as_ok())); + } + }); + send_closure(td_->hashtag_hints_, &HashtagHints::query, std::move(request.prefix_), request.limit_, + std::move(query_promise)); +} + +void Requests::on_request(uint64 id, td_api::removeRecentHashtag &request) { + CHECK_IS_USER(); + CLEAN_INPUT_STRING(request.hashtag_); + CREATE_OK_REQUEST_PROMISE(); + send_closure(td_->hashtag_hints_, &HashtagHints::remove_hashtag, std::move(request.hashtag_), std::move(promise)); +} + +void Requests::on_request(uint64 id, const td_api::getPremiumLimit &request) { + CHECK_IS_USER(); + CREATE_REQUEST_PROMISE(); + get_premium_limit(request.limit_type_, std::move(promise)); +} + +void Requests::on_request(uint64 id, const td_api::getPremiumFeatures &request) { + CHECK_IS_USER(); + CREATE_REQUEST_PROMISE(); + get_premium_features(td_, request.source_, std::move(promise)); +} + +void Requests::on_request(uint64 id, const td_api::getPremiumStickerExamples &request) { + CHECK_IS_USER(); + CREATE_REQUEST_PROMISE(); + td_->stickers_manager_->search_stickers(StickerType::Regular, "⭐️⭐️", 100, std::move(promise)); +} + +void Requests::on_request(uint64 id, const td_api::viewPremiumFeature &request) { + CHECK_IS_USER(); + CREATE_OK_REQUEST_PROMISE(); + view_premium_feature(td_, request.feature_, std::move(promise)); +} + +void Requests::on_request(uint64 id, const td_api::clickPremiumSubscriptionButton &request) { + CHECK_IS_USER(); + CREATE_OK_REQUEST_PROMISE(); + click_premium_subscription_button(td_, std::move(promise)); +} + +void Requests::on_request(uint64 id, const td_api::getPremiumState &request) { + CHECK_IS_USER(); + CREATE_REQUEST_PROMISE(); + get_premium_state(td_, std::move(promise)); +} + +void Requests::on_request(uint64 id, const td_api::getPremiumGiftCodePaymentOptions &request) { + CHECK_IS_USER(); + CREATE_REQUEST_PROMISE(); + get_premium_gift_code_options(td_, DialogId(request.boosted_chat_id_), std::move(promise)); +} + +void Requests::on_request(uint64 id, td_api::checkPremiumGiftCode &request) { + CHECK_IS_USER(); + CLEAN_INPUT_STRING(request.code_); + CREATE_REQUEST_PROMISE(); + check_premium_gift_code(td_, request.code_, std::move(promise)); +} + +void Requests::on_request(uint64 id, td_api::applyPremiumGiftCode &request) { + CHECK_IS_USER(); + CLEAN_INPUT_STRING(request.code_); + CREATE_OK_REQUEST_PROMISE(); + apply_premium_gift_code(td_, request.code_, std::move(promise)); +} + +void Requests::on_request(uint64 id, td_api::launchPrepaidGiveaway &request) { + CHECK_IS_USER(); + CREATE_OK_REQUEST_PROMISE(); + launch_prepaid_premium_giveaway(td_, request.giveaway_id_, std::move(request.parameters_), request.winner_count_, + request.star_count_, std::move(promise)); +} + +void Requests::on_request(uint64 id, const td_api::getGiveawayInfo &request) { + CHECK_IS_USER(); + CREATE_REQUEST_PROMISE(); + get_premium_giveaway_info(td_, {DialogId(request.chat_id_), MessageId(request.message_id_)}, std::move(promise)); +} + +void Requests::on_request(uint64 id, const td_api::getStarPaymentOptions &request) { + CHECK_IS_USER(); + CREATE_REQUEST_PROMISE(); + td_->star_manager_->get_star_payment_options(std::move(promise)); +} + +void Requests::on_request(uint64 id, const td_api::getStarGiftPaymentOptions &request) { + CHECK_IS_USER(); + CREATE_REQUEST_PROMISE(); + td_->star_manager_->get_star_gift_payment_options(UserId(request.user_id_), std::move(promise)); +} + +void Requests::on_request(uint64 id, const td_api::getStarGiveawayPaymentOptions &request) { + CHECK_IS_USER(); + CREATE_REQUEST_PROMISE(); + td_->star_manager_->get_star_giveaway_payment_options(std::move(promise)); +} + +void Requests::on_request(uint64 id, td_api::getStarTransactions &request) { + CLEAN_INPUT_STRING(request.subscription_id_); + CLEAN_INPUT_STRING(request.offset_); + CREATE_REQUEST_PROMISE(); + td_->star_manager_->get_star_transactions(std::move(request.owner_id_), request.subscription_id_, request.offset_, + request.limit_, std::move(request.direction_), std::move(promise)); +} + +void Requests::on_request(uint64 id, td_api::getStarSubscriptions &request) { + CHECK_IS_USER(); + CLEAN_INPUT_STRING(request.offset_); + CREATE_REQUEST_PROMISE(); + td_->star_manager_->get_star_subscriptions(request.only_expiring_, request.offset_, std::move(promise)); +} + +void Requests::on_request(uint64 id, td_api::editStarSubscription &request) { + CHECK_IS_USER(); + CLEAN_INPUT_STRING(request.subscription_id_); + CREATE_OK_REQUEST_PROMISE(); + td_->star_manager_->edit_star_subscriptions(request.subscription_id_, request.is_canceled_, std::move(promise)); +} + +void Requests::on_request(uint64 id, td_api::reuseStarSubscription &request) { + CHECK_IS_USER(); + CLEAN_INPUT_STRING(request.subscription_id_); + CREATE_OK_REQUEST_PROMISE(); + td_->star_manager_->reuse_star_subscriptions(request.subscription_id_, std::move(promise)); +} + +void Requests::on_request(uint64 id, td_api::canPurchaseFromStore &request) { + CHECK_IS_USER(); + CREATE_OK_REQUEST_PROMISE(); + can_purchase_premium(td_, std::move(request.purpose_), std::move(promise)); +} + +void Requests::on_request(uint64 id, td_api::assignAppStoreTransaction &request) { + CHECK_IS_USER(); + CREATE_OK_REQUEST_PROMISE(); + assign_app_store_transaction(td_, request.receipt_, std::move(request.purpose_), std::move(promise)); +} + +void Requests::on_request(uint64 id, td_api::assignGooglePlayTransaction &request) { + CHECK_IS_USER(); + CLEAN_INPUT_STRING(request.package_name_); + CLEAN_INPUT_STRING(request.store_product_id_); + CLEAN_INPUT_STRING(request.purchase_token_); + CREATE_OK_REQUEST_PROMISE(); + assign_play_market_transaction(td_, request.package_name_, request.store_product_id_, request.purchase_token_, + std::move(request.purpose_), std::move(promise)); +} + +void Requests::on_request(uint64 id, const td_api::getBusinessFeatures &request) { + CHECK_IS_USER(); + CREATE_REQUEST_PROMISE(); + get_business_features(td_, request.source_, std::move(promise)); +} + +void Requests::on_request(uint64 id, td_api::acceptTermsOfService &request) { + CHECK_IS_USER(); + CLEAN_INPUT_STRING(request.terms_of_service_id_); + CREATE_OK_REQUEST_PROMISE(); + td_->terms_of_service_manager_->accept_terms_of_service(std::move(request.terms_of_service_id_), std::move(promise)); +} + +void Requests::on_request(uint64 id, const td_api::getCountries &request) { + CREATE_REQUEST_PROMISE(); + td_->country_info_manager_->get_countries(std::move(promise)); +} + +void Requests::on_request(uint64 id, const td_api::getCountryCode &request) { + CREATE_TEXT_REQUEST_PROMISE(); + td_->country_info_manager_->get_current_country_code(std::move(promise)); +} + +void Requests::on_request(uint64 id, const td_api::getPhoneNumberInfo &request) { + CREATE_REQUEST_PROMISE(); + td_->country_info_manager_->get_phone_number_info(request.phone_number_prefix_, std::move(promise)); +} + +void Requests::on_request(uint64 id, td_api::getCollectibleItemInfo &request) { + CREATE_REQUEST_PROMISE(); + get_collectible_info(td_, std::move(request.type_), std::move(promise)); +} + +void Requests::on_request(uint64 id, const td_api::getApplicationDownloadLink &request) { + CHECK_IS_USER(); + CREATE_HTTP_URL_REQUEST_PROMISE(); + get_invite_text(td_, std::move(promise)); +} + +void Requests::on_request(uint64 id, td_api::getDeepLinkInfo &request) { + CLEAN_INPUT_STRING(request.link_); + CREATE_REQUEST_PROMISE(); + td_->link_manager_->get_deep_link_info(request.link_, std::move(promise)); +} + +void Requests::on_request(uint64 id, const td_api::getApplicationConfig &request) { + CHECK_IS_USER(); + CREATE_REQUEST_PROMISE(); + send_closure(G()->config_manager(), &ConfigManager::get_app_config, std::move(promise)); +} + +void Requests::on_request(uint64 id, td_api::saveApplicationLogEvent &request) { + CHECK_IS_USER(); + CLEAN_INPUT_STRING(request.type_); + CREATE_OK_REQUEST_PROMISE(); + save_app_log(td_, request.type_, DialogId(request.chat_id_), convert_json_value(std::move(request.data_)), + std::move(promise)); +} + +void Requests::on_request(uint64 id, td_api::addProxy &request) { + CLEAN_INPUT_STRING(request.server_); + CREATE_REQUEST_PROMISE(); + send_closure(G()->connection_creator(), &ConnectionCreator::add_proxy, -1, std::move(request.server_), request.port_, + request.enable_, std::move(request.type_), std::move(promise)); +} + +void Requests::on_request(uint64 id, td_api::editProxy &request) { + if (request.proxy_id_ < 0) { + return send_error_raw(id, 400, "Proxy identifier invalid"); + } + CLEAN_INPUT_STRING(request.server_); + CREATE_REQUEST_PROMISE(); + send_closure(G()->connection_creator(), &ConnectionCreator::add_proxy, request.proxy_id_, std::move(request.server_), + request.port_, request.enable_, std::move(request.type_), std::move(promise)); +} + +void Requests::on_request(uint64 id, const td_api::enableProxy &request) { + CREATE_OK_REQUEST_PROMISE(); + send_closure(G()->connection_creator(), &ConnectionCreator::enable_proxy, request.proxy_id_, std::move(promise)); +} + +void Requests::on_request(uint64 id, const td_api::disableProxy &request) { + CREATE_OK_REQUEST_PROMISE(); + send_closure(G()->connection_creator(), &ConnectionCreator::disable_proxy, std::move(promise)); +} + +void Requests::on_request(uint64 id, const td_api::removeProxy &request) { + CREATE_OK_REQUEST_PROMISE(); + send_closure(G()->connection_creator(), &ConnectionCreator::remove_proxy, request.proxy_id_, std::move(promise)); +} + +void Requests::on_request(uint64 id, const td_api::getProxies &request) { + CREATE_REQUEST_PROMISE(); + send_closure(G()->connection_creator(), &ConnectionCreator::get_proxies, std::move(promise)); +} + +void Requests::on_request(uint64 id, const td_api::getProxyLink &request) { + CREATE_HTTP_URL_REQUEST_PROMISE(); + send_closure(G()->connection_creator(), &ConnectionCreator::get_proxy_link, request.proxy_id_, std::move(promise)); +} + +void Requests::on_request(uint64 id, const td_api::pingProxy &request) { + CREATE_REQUEST_PROMISE(); + auto query_promise = PromiseCreator::lambda([promise = std::move(promise)](Result result) mutable { + if (result.is_error()) { + promise.set_error(result.move_as_error()); + } else { + promise.set_value(td_api::make_object(result.move_as_ok())); + } + }); + send_closure(G()->connection_creator(), &ConnectionCreator::ping_proxy, request.proxy_id_, std::move(query_promise)); +} + +void Requests::on_request(uint64 id, const td_api::getUserSupportInfo &request) { + CHECK_IS_USER(); + CREATE_REQUEST_PROMISE(); + get_user_info(td_, UserId(request.user_id_), std::move(promise)); +} + +void Requests::on_request(uint64 id, td_api::setUserSupportInfo &request) { + CHECK_IS_USER(); + CREATE_REQUEST_PROMISE(); + set_user_info(td_, UserId(request.user_id_), std::move(request.message_), std::move(promise)); +} + +void Requests::on_request(uint64 id, const td_api::getSupportName &request) { + CHECK_IS_USER(); + CREATE_TEXT_REQUEST_PROMISE(); + get_support_name(td_, std::move(promise)); +} + +void Requests::on_request(uint64 id, const td_api::searchQuote &request) { + UNREACHABLE(); +} + +void Requests::on_request(uint64 id, const td_api::getTextEntities &request) { + UNREACHABLE(); +} + +void Requests::on_request(uint64 id, const td_api::parseTextEntities &request) { + UNREACHABLE(); +} + +void Requests::on_request(uint64 id, const td_api::parseMarkdown &request) { + UNREACHABLE(); +} + +void Requests::on_request(uint64 id, const td_api::getMarkdownText &request) { + UNREACHABLE(); +} + +void Requests::on_request(uint64 id, const td_api::searchStringsByPrefix &request) { + UNREACHABLE(); +} + +void Requests::on_request(uint64 id, const td_api::checkQuickReplyShortcutName &request) { + UNREACHABLE(); +} + +void Requests::on_request(uint64 id, const td_api::getCountryFlagEmoji &request) { + UNREACHABLE(); +} + +void Requests::on_request(uint64 id, const td_api::getFileMimeType &request) { + UNREACHABLE(); +} + +void Requests::on_request(uint64 id, const td_api::getFileExtension &request) { + UNREACHABLE(); +} + +void Requests::on_request(uint64 id, const td_api::cleanFileName &request) { + UNREACHABLE(); +} + +void Requests::on_request(uint64 id, const td_api::getLanguagePackString &request) { + UNREACHABLE(); +} + +void Requests::on_request(uint64 id, const td_api::getPhoneNumberInfoSync &request) { + UNREACHABLE(); +} + +void Requests::on_request(uint64 id, const td_api::getPushReceiverId &request) { + UNREACHABLE(); +} + +void Requests::on_request(uint64 id, const td_api::getChatFolderDefaultIconName &request) { + UNREACHABLE(); +} + +void Requests::on_request(uint64 id, const td_api::getJsonValue &request) { + UNREACHABLE(); +} + +void Requests::on_request(uint64 id, const td_api::getJsonString &request) { + UNREACHABLE(); +} + +void Requests::on_request(uint64 id, const td_api::getThemeParametersJsonString &request) { + UNREACHABLE(); +} + +void Requests::on_request(uint64 id, const td_api::setLogStream &request) { + UNREACHABLE(); +} + +void Requests::on_request(uint64 id, const td_api::getLogStream &request) { + UNREACHABLE(); +} + +void Requests::on_request(uint64 id, const td_api::setLogVerbosityLevel &request) { + UNREACHABLE(); +} + +void Requests::on_request(uint64 id, const td_api::getLogVerbosityLevel &request) { + UNREACHABLE(); +} + +void Requests::on_request(uint64 id, const td_api::getLogTags &request) { + UNREACHABLE(); +} + +void Requests::on_request(uint64 id, const td_api::setLogTagVerbosityLevel &request) { + UNREACHABLE(); +} + +void Requests::on_request(uint64 id, const td_api::getLogTagVerbosityLevel &request) { + UNREACHABLE(); +} + +void Requests::on_request(uint64 id, const td_api::addLogMessage &request) { + UNREACHABLE(); +} + +// test +void Requests::on_request(uint64 id, const td_api::testNetwork &request) { + CREATE_OK_REQUEST_PROMISE(); + auto query_promise = PromiseCreator::lambda([promise = std::move(promise)](Result result) mutable { + if (result.is_error()) { + promise.set_error(result.move_as_error()); + } else { + promise.set_value(Unit()); + } + }); + td_->country_info_manager_->get_current_country_code(std::move(query_promise)); +} + +void Requests::on_request(uint64 id, td_api::testProxy &request) { + auto r_proxy = Proxy::create_proxy(std::move(request.server_), request.port_, request.type_.get()); + if (r_proxy.is_error()) { + return send_closure(td_actor_, &Td::send_error, id, r_proxy.move_as_error()); + } + CREATE_OK_REQUEST_PROMISE(); + send_closure(G()->connection_creator(), &ConnectionCreator::test_proxy, r_proxy.move_as_ok(), request.dc_id_, + request.timeout_, std::move(promise)); +} + +void Requests::on_request(uint64 id, const td_api::testGetDifference &request) { + td_->updates_manager_->get_difference("testGetDifference"); + send_closure(td_actor_, &Td::send_result, id, td_api::make_object()); +} + +void Requests::on_request(uint64 id, const td_api::testUseUpdate &request) { + send_closure(td_actor_, &Td::send_result, id, nullptr); +} + +void Requests::on_request(uint64 id, const td_api::testReturnError &request) { + UNREACHABLE(); +} + +void Requests::on_request(uint64 id, const td_api::testCallEmpty &request) { + send_closure(td_actor_, &Td::send_result, id, td_api::make_object()); +} + +void Requests::on_request(uint64 id, const td_api::testSquareInt &request) { + send_closure(td_actor_, &Td::send_result, id, td_api::make_object(request.x_ * request.x_)); +} + +void Requests::on_request(uint64 id, td_api::testCallString &request) { + send_closure(td_actor_, &Td::send_result, id, td_api::make_object(std::move(request.x_))); +} + +void Requests::on_request(uint64 id, td_api::testCallBytes &request) { + send_closure(td_actor_, &Td::send_result, id, td_api::make_object(std::move(request.x_))); +} + +void Requests::on_request(uint64 id, td_api::testCallVectorInt &request) { + send_closure(td_actor_, &Td::send_result, id, td_api::make_object(std::move(request.x_))); +} + +void Requests::on_request(uint64 id, td_api::testCallVectorIntObject &request) { + send_closure(td_actor_, &Td::send_result, id, + td_api::make_object(std::move(request.x_))); +} + +void Requests::on_request(uint64 id, td_api::testCallVectorString &request) { + send_closure(td_actor_, &Td::send_result, id, td_api::make_object(std::move(request.x_))); +} + +void Requests::on_request(uint64 id, td_api::testCallVectorStringObject &request) { + send_closure(td_actor_, &Td::send_result, id, + td_api::make_object(std::move(request.x_))); +} + +#undef CLEAN_INPUT_STRING +#undef CHECK_IS_BOT +#undef CHECK_IS_USER +#undef CREATE_NO_ARGS_REQUEST +#undef CREATE_REQUEST +#undef CREATE_REQUEST_PROMISE +#undef CREATE_OK_REQUEST_PROMISE +#undef CREATE_TEXT_REQUEST_PROMISE +#undef CREATE_HTTP_URL_REQUEST_PROMISE + +} // namespace td diff --git a/lib/tgchat/ext/td/td/telegram/Requests.h b/lib/tgchat/ext/td/td/telegram/Requests.h new file mode 100644 index 00000000..33de9496 --- /dev/null +++ b/lib/tgchat/ext/td/td/telegram/Requests.h @@ -0,0 +1,1692 @@ +// +// Copyright Aliaksei Levin (levlam@telegram.org), Arseny Smirnov (arseny30@gmail.com) 2014-2024 +// +// 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/files/FileId.h" +#include "td/telegram/Td.h" +#include "td/telegram/td_api.h" + +#include "td/actor/actor.h" + +#include "td/utils/common.h" +#include "td/utils/FlatHashMap.h" +#include "td/utils/MovableValue.h" +#include "td/utils/Promise.h" +#include "td/utils/Slice.h" +#include "td/utils/Status.h" + +#include + +namespace td { + +class Requests { + public: + explicit Requests(Td *td); + + void run_request(uint64 id, td_api::object_ptr &&function); + + void on_file_download_finished(FileId file_id); + + private: + Td *td_ = nullptr; + ActorId td_actor_; + + void send_error_raw(uint64 id, int32 code, CSlice error); + + void answer_ok_query(uint64 id, Status status); + + struct DownloadInfo { + int64 offset = -1; + int64 limit = -1; + vector request_ids; + }; + FlatHashMap pending_file_downloads_; + + class DownloadFileCallback; + + std::shared_ptr download_file_callback_; + + class RequestPromiseBase { + enum class State : int32 { Empty, Ready, Complete }; + ActorId td_actor_; + uint64 request_id_; + MovableValue state_{State::Empty}; + + public: + void set_value(td_api::object_ptr value) { + CHECK(state_.get() == State::Ready); + send_closure(td_actor_, &Td::send_result, request_id_, std::move(value)); + state_ = State::Complete; + } + + void set_error(Status &&error) { + if (state_.get() == State::Ready) { + send_closure(td_actor_, &Td::send_error, request_id_, std::move(error)); + state_ = State::Complete; + } + } + + RequestPromiseBase(const RequestPromiseBase &) = delete; + RequestPromiseBase &operator=(const RequestPromiseBase &) = delete; + RequestPromiseBase(RequestPromiseBase &&) = default; + RequestPromiseBase &operator=(RequestPromiseBase &&) = default; + virtual ~RequestPromiseBase() { + if (state_.get() == State::Ready) { + send_closure(td_actor_, &Td::send_error, request_id_, Status::Error("Lost promise")); + } + } + + RequestPromiseBase(ActorId td_actor, uint64 request_id) + : td_actor_(std::move(td_actor)), request_id_(request_id), state_(State::Ready) { + } + }; + + template + class RequestPromise final + : public PromiseInterface + , private RequestPromiseBase { + public: + void set_value(T &&value) final { + RequestPromiseBase::set_value(std::move(value)); + } + + void set_error(Status &&error) final { + RequestPromiseBase::set_error(std::move(error)); + } + + RequestPromise(ActorId td_actor, uint64 request_id) : RequestPromiseBase(std::move(td_actor), request_id) { + } + }; + + template + Promise create_request_promise(uint64 request_id) const { + return Promise(td::make_unique>(td_actor_, request_id)); + } + + Promise create_ok_request_promise(uint64 id); + + Promise create_text_request_promise(uint64 id); + + Promise create_http_url_request_promise(uint64 id); + + template + void on_request(uint64 id, const T &) = delete; + + void on_request(uint64 id, const td_api::setTdlibParameters &request); + + void on_request(uint64 id, const td_api::getAuthorizationState &request); + + void on_request(uint64 id, td_api::setAuthenticationPhoneNumber &request); + + void on_request(uint64 id, td_api::sendAuthenticationFirebaseSms &request); + + void on_request(uint64 id, td_api::reportAuthenticationCodeMissing &request); + + void on_request(uint64 id, td_api::setAuthenticationEmailAddress &request); + + void on_request(uint64 id, td_api::resendAuthenticationCode &request); + + void on_request(uint64 id, td_api::checkAuthenticationEmailCode &request); + + void on_request(uint64 id, td_api::checkAuthenticationCode &request); + + void on_request(uint64 id, td_api::registerUser &request); + + void on_request(uint64 id, td_api::requestQrCodeAuthentication &request); + + void on_request(uint64 id, const td_api::resetAuthenticationEmailAddress &request); + + void on_request(uint64 id, td_api::checkAuthenticationPassword &request); + + void on_request(uint64 id, const td_api::requestAuthenticationPasswordRecovery &request); + + void on_request(uint64 id, td_api::checkAuthenticationPasswordRecoveryCode &request); + + void on_request(uint64 id, td_api::recoverAuthenticationPassword &request); + + void on_request(uint64 id, const td_api::logOut &request); + + void on_request(uint64 id, const td_api::close &request); + + void on_request(uint64 id, const td_api::destroy &request); + + void on_request(uint64 id, td_api::checkAuthenticationBotToken &request); + + void on_request(uint64 id, td_api::confirmQrCodeAuthentication &request); + + void on_request(uint64 id, td_api::setDatabaseEncryptionKey &request); + + void on_request(uint64 id, const td_api::getCurrentState &request); + + void on_request(uint64 id, const td_api::getPasswordState &request); + + void on_request(uint64 id, td_api::setPassword &request); + + void on_request(uint64 id, td_api::setLoginEmailAddress &request); + + void on_request(uint64 id, const td_api::resendLoginEmailAddressCode &request); + + void on_request(uint64 id, td_api::checkLoginEmailAddressCode &request); + + void on_request(uint64 id, td_api::getRecoveryEmailAddress &request); + + void on_request(uint64 id, td_api::setRecoveryEmailAddress &request); + + void on_request(uint64 id, td_api::checkRecoveryEmailAddressCode &request); + + void on_request(uint64 id, const td_api::resendRecoveryEmailAddressCode &request); + + void on_request(uint64 id, const td_api::cancelRecoveryEmailAddressVerification &request); + + void on_request(uint64 id, td_api::requestPasswordRecovery &request); + + void on_request(uint64 id, td_api::checkPasswordRecoveryCode &request); + + void on_request(uint64 id, td_api::recoverPassword &request); + + void on_request(uint64 id, const td_api::resetPassword &request); + + void on_request(uint64 id, const td_api::cancelPasswordReset &request); + + void on_request(uint64 id, td_api::getTemporaryPasswordState &request); + + void on_request(uint64 id, td_api::createTemporaryPassword &request); + + void on_request(uint64 id, td_api::processPushNotification &request); + + void on_request(uint64 id, td_api::registerDevice &request); + + void on_request(uint64 id, td_api::getUserPrivacySettingRules &request); + + void on_request(uint64 id, td_api::setUserPrivacySettingRules &request); + + void on_request(uint64 id, const td_api::getDefaultMessageAutoDeleteTime &request); + + void on_request(uint64 id, const td_api::setDefaultMessageAutoDeleteTime &request); + + void on_request(uint64 id, const td_api::getAccountTtl &request); + + void on_request(uint64 id, const td_api::setAccountTtl &request); + + void on_request(uint64 id, td_api::deleteAccount &request); + + void on_request(uint64 id, td_api::sendPhoneNumberCode &request); + + void on_request(uint64 id, td_api::sendPhoneNumberFirebaseSms &request); + + void on_request(uint64 id, td_api::reportPhoneNumberCodeMissing &request); + + void on_request(uint64 id, td_api::resendPhoneNumberCode &request); + + void on_request(uint64 id, td_api::checkPhoneNumberCode &request); + + void on_request(uint64 id, const td_api::getUserLink &request); + + void on_request(uint64 id, td_api::searchUserByToken &request); + + void on_request(uint64 id, const td_api::getActiveSessions &request); + + void on_request(uint64 id, const td_api::terminateSession &request); + + void on_request(uint64 id, const td_api::terminateAllOtherSessions &request); + + void on_request(uint64 id, const td_api::confirmSession &request); + + void on_request(uint64 id, const td_api::toggleSessionCanAcceptCalls &request); + + void on_request(uint64 id, const td_api::toggleSessionCanAcceptSecretChats &request); + + void on_request(uint64 id, const td_api::setInactiveSessionTtl &request); + + void on_request(uint64 id, const td_api::getConnectedWebsites &request); + + void on_request(uint64 id, const td_api::disconnectWebsite &request); + + void on_request(uint64 id, const td_api::disconnectAllWebsites &request); + + void on_request(uint64 id, const td_api::getMe &request); + + void on_request(uint64 id, const td_api::getUser &request); + + void on_request(uint64 id, const td_api::getUserFullInfo &request); + + void on_request(uint64 id, const td_api::getBasicGroup &request); + + void on_request(uint64 id, const td_api::getBasicGroupFullInfo &request); + + void on_request(uint64 id, const td_api::getSupergroup &request); + + void on_request(uint64 id, const td_api::getSupergroupFullInfo &request); + + void on_request(uint64 id, const td_api::getSecretChat &request); + + void on_request(uint64 id, const td_api::getChat &request); + + void on_request(uint64 id, const td_api::getMessage &request); + + void on_request(uint64 id, const td_api::getMessageLocally &request); + + void on_request(uint64 id, const td_api::getRepliedMessage &request); + + void on_request(uint64 id, const td_api::getChatPinnedMessage &request); + + void on_request(uint64 id, const td_api::getCallbackQueryMessage &request); + + void on_request(uint64 id, const td_api::getMessageThread &request); + + void on_request(uint64 id, const td_api::getMessageReadDate &request); + + void on_request(uint64 id, const td_api::getMessageViewers &request); + + void on_request(uint64 id, const td_api::getMessages &request); + + void on_request(uint64 id, const td_api::getMessageProperties &request); + + void on_request(uint64 id, const td_api::getChatSponsoredMessages &request); + + void on_request(uint64 id, const td_api::clickChatSponsoredMessage &request); + + void on_request(uint64 id, const td_api::reportChatSponsoredMessage &request); + + void on_request(uint64 id, const td_api::getMessageLink &request); + + void on_request(uint64 id, const td_api::getMessageEmbeddingCode &request); + + void on_request(uint64 id, td_api::getMessageLinkInfo &request); + + void on_request(uint64 id, td_api::translateText &request); + + void on_request(uint64 id, td_api::translateMessageText &request); + + void on_request(uint64 id, const td_api::recognizeSpeech &request); + + void on_request(uint64 id, const td_api::rateSpeechRecognition &request); + + void on_request(uint64 id, const td_api::getFile &request); + + void on_request(uint64 id, td_api::getRemoteFile &request); + + void on_request(uint64 id, td_api::getStorageStatistics &request); + + void on_request(uint64 id, td_api::getStorageStatisticsFast &request); + + void on_request(uint64 id, const td_api::getDatabaseStatistics &request); + + void on_request(uint64 id, td_api::optimizeStorage &request); + + void on_request(uint64 id, td_api::getNetworkStatistics &request); + + void on_request(uint64 id, td_api::resetNetworkStatistics &request); + + void on_request(uint64 id, td_api::addNetworkStatistics &request); + + void on_request(uint64 id, const td_api::setNetworkType &request); + + void on_request(uint64 id, const td_api::getAutoDownloadSettingsPresets &request); + + void on_request(uint64 id, const td_api::setAutoDownloadSettings &request); + + void on_request(uint64 id, const td_api::getAutosaveSettings &request); + + void on_request(uint64 id, td_api::setAutosaveSettings &request); + + void on_request(uint64 id, const td_api::clearAutosaveSettingsExceptions &request); + + void on_request(uint64 id, const td_api::getRecommendedChats &request); + + void on_request(uint64 id, const td_api::getChatSimilarChats &request); + + void on_request(uint64 id, const td_api::getChatSimilarChatCount &request); + + void on_request(uint64 id, const td_api::openChatSimilarChat &request); + + void on_request(uint64 id, const td_api::getTopChats &request); + + void on_request(uint64 id, const td_api::removeTopChat &request); + + void on_request(uint64 id, const td_api::loadChats &request); + + void on_request(uint64 id, const td_api::getChats &request); + + void on_request(uint64 id, const td_api::loadSavedMessagesTopics &request); + + void on_request(uint64 id, const td_api::getSavedMessagesTopicHistory &request); + + void on_request(uint64 id, const td_api::getSavedMessagesTopicMessageByDate &request); + + void on_request(uint64 id, const td_api::deleteSavedMessagesTopicHistory &request); + + void on_request(uint64 id, const td_api::deleteSavedMessagesTopicMessagesByDate &request); + + void on_request(uint64 id, const td_api::toggleSavedMessagesTopicIsPinned &request); + + void on_request(uint64 id, const td_api::setPinnedSavedMessagesTopics &request); + + void on_request(uint64 id, td_api::searchPublicChat &request); + + void on_request(uint64 id, td_api::searchPublicChats &request); + + void on_request(uint64 id, td_api::searchChats &request); + + void on_request(uint64 id, td_api::searchChatsOnServer &request); + + void on_request(uint64 id, const td_api::searchChatsNearby &request); + + void on_request(uint64 id, td_api::searchRecentlyFoundChats &request); + + void on_request(uint64 id, const td_api::addRecentlyFoundChat &request); + + void on_request(uint64 id, const td_api::removeRecentlyFoundChat &request); + + void on_request(uint64 id, const td_api::clearRecentlyFoundChats &request); + + void on_request(uint64 id, const td_api::getRecentlyOpenedChats &request); + + void on_request(uint64 id, const td_api::getGroupsInCommon &request); + + void on_request(uint64 id, td_api::checkChatUsername &request); + + void on_request(uint64 id, const td_api::getCreatedPublicChats &request); + + void on_request(uint64 id, const td_api::checkCreatedPublicChatsLimit &request); + + void on_request(uint64 id, const td_api::getSuitableDiscussionChats &request); + + void on_request(uint64 id, const td_api::getInactiveSupergroupChats &request); + + void on_request(uint64 id, const td_api::getSuitablePersonalChats &request); + + void on_request(uint64 id, const td_api::openChat &request); + + void on_request(uint64 id, const td_api::closeChat &request); + + void on_request(uint64 id, const td_api::viewMessages &request); + + void on_request(uint64 id, const td_api::openMessageContent &request); + + void on_request(uint64 id, const td_api::clickAnimatedEmojiMessage &request); + + void on_request(uint64 id, const td_api::getInternalLink &request); + + void on_request(uint64 id, const td_api::getInternalLinkType &request); + + void on_request(uint64 id, td_api::getExternalLinkInfo &request); + + void on_request(uint64 id, td_api::getExternalLink &request); + + void on_request(uint64 id, const td_api::getChatHistory &request); + + void on_request(uint64 id, const td_api::deleteChatHistory &request); + + void on_request(uint64 id, const td_api::deleteChat &request); + + void on_request(uint64 id, const td_api::getMessageThreadHistory &request); + + void on_request(uint64 id, const td_api::getChatMessageCalendar &request); + + void on_request(uint64 id, td_api::searchChatMessages &request); + + void on_request(uint64 id, td_api::searchSecretMessages &request); + + void on_request(uint64 id, td_api::searchMessages &request); + + void on_request(uint64 id, td_api::searchSavedMessages &request); + + void on_request(uint64 id, const td_api::searchCallMessages &request); + + void on_request(uint64 id, td_api::searchOutgoingDocumentMessages &request); + + void on_request(uint64 id, td_api::searchPublicMessagesByTag &request); + + void on_request(uint64 id, td_api::searchPublicStoriesByTag &request); + + void on_request(uint64 id, td_api::searchPublicStoriesByLocation &request); + + void on_request(uint64 id, td_api::searchPublicStoriesByVenue &request); + + void on_request(uint64 id, td_api::getSearchedForTags &request); + + void on_request(uint64 id, td_api::removeSearchedForTag &request); + + void on_request(uint64 id, td_api::clearSearchedForTags &request); + + void on_request(uint64 id, const td_api::deleteAllCallMessages &request); + + void on_request(uint64 id, const td_api::searchChatRecentLocationMessages &request); + + void on_request(uint64 id, const td_api::getChatMessageByDate &request); + + void on_request(uint64 id, const td_api::getChatSparseMessagePositions &request); + + void on_request(uint64 id, const td_api::getChatMessageCount &request); + + void on_request(uint64 id, const td_api::getChatMessagePosition &request); + + void on_request(uint64 id, const td_api::getChatScheduledMessages &request); + + void on_request(uint64 id, const td_api::getEmojiReaction &request); + + void on_request(uint64 id, const td_api::getCustomEmojiReactionAnimations &request); + + void on_request(uint64 id, const td_api::getMessageAvailableReactions &request); + + void on_request(uint64 id, const td_api::clearRecentReactions &request); + + void on_request(uint64 id, const td_api::addMessageReaction &request); + + void on_request(uint64 id, const td_api::addPendingPaidMessageReaction &request); + + void on_request(uint64 id, const td_api::commitPendingPaidMessageReactions &request); + + void on_request(uint64 id, const td_api::removePendingPaidMessageReactions &request); + + void on_request(uint64 id, const td_api::togglePaidMessageReactionIsAnonymous &request); + + void on_request(uint64 id, const td_api::removeMessageReaction &request); + + void on_request(uint64 id, const td_api::setMessageReactions &request); + + void on_request(uint64 id, td_api::getMessageAddedReactions &request); + + void on_request(uint64 id, const td_api::setDefaultReactionType &request); + + void on_request(uint64 id, const td_api::getSavedMessagesTags &request); + + void on_request(uint64 id, td_api::setSavedMessagesTagLabel &request); + + void on_request(uint64 id, const td_api::getMessageEffect &request); + + void on_request(uint64 id, td_api::getMessagePublicForwards &request); + + void on_request(uint64 id, td_api::getStoryPublicForwards &request); + + void on_request(uint64 id, const td_api::removeNotification &request); + + void on_request(uint64 id, const td_api::removeNotificationGroup &request); + + void on_request(uint64 id, const td_api::deleteMessages &request); + + void on_request(uint64 id, const td_api::deleteChatMessagesBySender &request); + + void on_request(uint64 id, const td_api::deleteChatMessagesByDate &request); + + void on_request(uint64 id, const td_api::readAllChatMentions &request); + + void on_request(uint64 id, const td_api::readAllMessageThreadMentions &request); + + void on_request(uint64 id, const td_api::readAllChatReactions &request); + + void on_request(uint64 id, const td_api::readAllMessageThreadReactions &request); + + void on_request(uint64 id, const td_api::getChatAvailableMessageSenders &request); + + void on_request(uint64 id, const td_api::setChatMessageSender &request); + + void on_request(uint64 id, td_api::sendMessage &request); + + void on_request(uint64 id, td_api::sendMessageAlbum &request); + + void on_request(uint64 id, td_api::sendBotStartMessage &request); + + void on_request(uint64 id, td_api::sendInlineQueryResultMessage &request); + + void on_request(uint64 id, td_api::addLocalMessage &request); + + void on_request(uint64 id, td_api::editMessageText &request); + + void on_request(uint64 id, td_api::editMessageLiveLocation &request); + + void on_request(uint64 id, td_api::editMessageMedia &request); + + void on_request(uint64 id, td_api::editMessageCaption &request); + + void on_request(uint64 id, td_api::editMessageReplyMarkup &request); + + void on_request(uint64 id, td_api::editInlineMessageText &request); + + void on_request(uint64 id, td_api::editInlineMessageLiveLocation &request); + + void on_request(uint64 id, td_api::editInlineMessageMedia &request); + + void on_request(uint64 id, td_api::editInlineMessageCaption &request); + + void on_request(uint64 id, td_api::editInlineMessageReplyMarkup &request); + + void on_request(uint64 id, td_api::editMessageSchedulingState &request); + + void on_request(uint64 id, td_api::setMessageFactCheck &request); + + void on_request(uint64 id, td_api::sendBusinessMessage &request); + + void on_request(uint64 id, td_api::sendBusinessMessageAlbum &request); + + void on_request(uint64 id, td_api::editBusinessMessageText &request); + + void on_request(uint64 id, td_api::editBusinessMessageLiveLocation &request); + + void on_request(uint64 id, td_api::editBusinessMessageMedia &request); + + void on_request(uint64 id, td_api::editBusinessMessageCaption &request); + + void on_request(uint64 id, td_api::editBusinessMessageReplyMarkup &request); + + void on_request(uint64 id, td_api::stopBusinessPoll &request); + + void on_request(uint64 id, td_api::setBusinessMessageIsPinned &request); + + void on_request(uint64 id, const td_api::loadQuickReplyShortcuts &request); + + void on_request(uint64 id, const td_api::setQuickReplyShortcutName &request); + + void on_request(uint64 id, const td_api::deleteQuickReplyShortcut &request); + + void on_request(uint64 id, const td_api::reorderQuickReplyShortcuts &request); + + void on_request(uint64 id, const td_api::loadQuickReplyShortcutMessages &request); + + void on_request(uint64 id, const td_api::deleteQuickReplyShortcutMessages &request); + + void on_request(uint64 id, td_api::addQuickReplyShortcutMessage &request); + + void on_request(uint64 id, td_api::addQuickReplyShortcutInlineQueryResultMessage &request); + + void on_request(uint64 id, td_api::addQuickReplyShortcutMessageAlbum &request); + + void on_request(uint64 id, td_api::readdQuickReplyShortcutMessages &request); + + void on_request(uint64 id, td_api::editQuickReplyMessage &request); + + void on_request(uint64 id, const td_api::getCurrentWeather &request); + + void on_request(uint64 id, const td_api::getStory &request); + + void on_request(uint64 id, const td_api::getChatsToSendStories &request); + + void on_request(uint64 id, const td_api::canSendStory &request); + + void on_request(uint64 id, td_api::sendStory &request); + + void on_request(uint64 id, td_api::editStory &request); + + void on_request(uint64 id, const td_api::editStoryCover &request); + + void on_request(uint64 id, td_api::setStoryPrivacySettings &request); + + void on_request(uint64 id, const td_api::toggleStoryIsPostedToChatPage &request); + + void on_request(uint64 id, const td_api::deleteStory &request); + + void on_request(uint64 id, const td_api::loadActiveStories &request); + + void on_request(uint64 id, const td_api::setChatActiveStoriesList &request); + + void on_request(uint64 id, const td_api::getForumTopicDefaultIcons &request); + + void on_request(uint64 id, td_api::createForumTopic &request); + + void on_request(uint64 id, td_api::editForumTopic &request); + + void on_request(uint64 id, const td_api::getForumTopic &request); + + void on_request(uint64 id, const td_api::getForumTopicLink &request); + + void on_request(uint64 id, td_api::getForumTopics &request); + + void on_request(uint64 id, const td_api::toggleForumTopicIsClosed &request); + + void on_request(uint64 id, const td_api::toggleGeneralForumTopicIsHidden &request); + + void on_request(uint64 id, const td_api::toggleForumTopicIsPinned &request); + + void on_request(uint64 id, const td_api::setPinnedForumTopics &request); + + void on_request(uint64 id, const td_api::deleteForumTopic &request); + + void on_request(uint64 id, td_api::setGameScore &request); + + void on_request(uint64 id, td_api::setInlineGameScore &request); + + void on_request(uint64 id, td_api::getGameHighScores &request); + + void on_request(uint64 id, td_api::getInlineGameHighScores &request); + + void on_request(uint64 id, const td_api::deleteChatReplyMarkup &request); + + void on_request(uint64 id, td_api::sendChatAction &request); + + void on_request(uint64 id, td_api::forwardMessages &request); + + void on_request(uint64 id, const td_api::sendQuickReplyShortcutMessages &request); + + void on_request(uint64 id, td_api::resendMessages &request); + + void on_request(uint64 id, td_api::getLinkPreview &request); + + void on_request(uint64 id, td_api::getWebPageInstantView &request); + + void on_request(uint64 id, const td_api::createPrivateChat &request); + + void on_request(uint64 id, const td_api::createBasicGroupChat &request); + + void on_request(uint64 id, const td_api::createSupergroupChat &request); + + void on_request(uint64 id, const td_api::createSecretChat &request); + + void on_request(uint64 id, td_api::createNewBasicGroupChat &request); + + void on_request(uint64 id, td_api::createNewSupergroupChat &request); + + void on_request(uint64 id, const td_api::createNewSecretChat &request); + + void on_request(uint64 id, const td_api::createCall &request); + + void on_request(uint64 id, const td_api::acceptCall &request); + + void on_request(uint64 id, td_api::sendCallSignalingData &request); + + void on_request(uint64 id, const td_api::discardCall &request); + + void on_request(uint64 id, td_api::sendCallRating &request); + + void on_request(uint64 id, td_api::sendCallDebugInformation &request); + + void on_request(uint64 id, td_api::sendCallLog &request); + + void on_request(uint64 id, const td_api::getVideoChatAvailableParticipants &request); + + void on_request(uint64 id, const td_api::setVideoChatDefaultParticipant &request); + + void on_request(uint64 id, td_api::createVideoChat &request); + + void on_request(uint64 id, const td_api::getVideoChatRtmpUrl &request); + + void on_request(uint64 id, const td_api::replaceVideoChatRtmpUrl &request); + + void on_request(uint64 id, const td_api::getGroupCall &request); + + void on_request(uint64 id, const td_api::startScheduledGroupCall &request); + + void on_request(uint64 id, const td_api::toggleGroupCallEnabledStartNotification &request); + + void on_request(uint64 id, td_api::joinGroupCall &request); + + void on_request(uint64 id, td_api::startGroupCallScreenSharing &request); + + void on_request(uint64 id, const td_api::endGroupCallScreenSharing &request); + + void on_request(uint64 id, td_api::setGroupCallTitle &request); + + void on_request(uint64 id, const td_api::toggleGroupCallMuteNewParticipants &request); + + void on_request(uint64 id, const td_api::revokeGroupCallInviteLink &request); + + void on_request(uint64 id, const td_api::inviteGroupCallParticipants &request); + + void on_request(uint64 id, const td_api::getGroupCallInviteLink &request); + + void on_request(uint64 id, td_api::startGroupCallRecording &request); + + void on_request(uint64 id, const td_api::toggleGroupCallScreenSharingIsPaused &request); + + void on_request(uint64 id, const td_api::endGroupCallRecording &request); + + void on_request(uint64 id, const td_api::toggleGroupCallIsMyVideoPaused &request); + + void on_request(uint64 id, const td_api::toggleGroupCallIsMyVideoEnabled &request); + + void on_request(uint64 id, const td_api::setGroupCallParticipantIsSpeaking &request); + + void on_request(uint64 id, const td_api::toggleGroupCallParticipantIsMuted &request); + + void on_request(uint64 id, const td_api::setGroupCallParticipantVolumeLevel &request); + + void on_request(uint64 id, const td_api::toggleGroupCallParticipantIsHandRaised &request); + + void on_request(uint64 id, const td_api::loadGroupCallParticipants &request); + + void on_request(uint64 id, const td_api::leaveGroupCall &request); + + void on_request(uint64 id, const td_api::endGroupCall &request); + + void on_request(uint64 id, const td_api::getGroupCallStreams &request); + + void on_request(uint64 id, td_api::getGroupCallStreamSegment &request); + + void on_request(uint64 id, const td_api::upgradeBasicGroupChatToSupergroupChat &request); + + void on_request(uint64 id, const td_api::getChatListsToAddChat &request); + + void on_request(uint64 id, const td_api::addChatToList &request); + + void on_request(uint64 id, const td_api::getChatFolder &request); + + void on_request(uint64 id, const td_api::getRecommendedChatFolders &request); + + void on_request(uint64 id, td_api::createChatFolder &request); + + void on_request(uint64 id, td_api::editChatFolder &request); + + void on_request(uint64 id, const td_api::deleteChatFolder &request); + + void on_request(uint64 id, const td_api::getChatFolderChatsToLeave &request); + + void on_request(uint64 id, td_api::getChatFolderChatCount &request); + + void on_request(uint64 id, const td_api::reorderChatFolders &request); + + void on_request(uint64 id, const td_api::toggleChatFolderTags &request); + + void on_request(uint64 id, const td_api::getChatsForChatFolderInviteLink &request); + + void on_request(uint64 id, td_api::createChatFolderInviteLink &request); + + void on_request(uint64 id, td_api::getChatFolderInviteLinks &request); + + void on_request(uint64 id, td_api::editChatFolderInviteLink &request); + + void on_request(uint64 id, td_api::deleteChatFolderInviteLink &request); + + void on_request(uint64 id, td_api::checkChatFolderInviteLink &request); + + void on_request(uint64 id, td_api::addChatFolderByInviteLink &request); + + void on_request(uint64 id, const td_api::getChatFolderNewChats &request); + + void on_request(uint64 id, const td_api::processChatFolderNewChats &request); + + void on_request(uint64 id, const td_api::getArchiveChatListSettings &request); + + void on_request(uint64 id, td_api::setArchiveChatListSettings &request); + + void on_request(uint64 id, const td_api::getReadDatePrivacySettings &request); + + void on_request(uint64 id, td_api::setReadDatePrivacySettings &request); + + void on_request(uint64 id, const td_api::getNewChatPrivacySettings &request); + + void on_request(uint64 id, td_api::setNewChatPrivacySettings &request); + + void on_request(uint64 id, const td_api::canSendMessageToUser &request); + + void on_request(uint64 id, td_api::setChatTitle &request); + + void on_request(uint64 id, const td_api::setChatPhoto &request); + + void on_request(uint64 id, const td_api::setChatAccentColor &request); + + void on_request(uint64 id, const td_api::setChatProfileAccentColor &request); + + void on_request(uint64 id, const td_api::setChatMessageAutoDeleteTime &request); + + void on_request(uint64 id, const td_api::setChatEmojiStatus &request); + + void on_request(uint64 id, const td_api::setChatPermissions &request); + + void on_request(uint64 id, td_api::setChatBackground &request); + + void on_request(uint64 id, const td_api::deleteChatBackground &request); + + void on_request(uint64 id, td_api::setChatTheme &request); + + void on_request(uint64 id, td_api::setChatDraftMessage &request); + + void on_request(uint64 id, const td_api::toggleChatHasProtectedContent &request); + + void on_request(uint64 id, const td_api::toggleChatIsPinned &request); + + void on_request(uint64 id, const td_api::toggleChatViewAsTopics &request); + + void on_request(uint64 id, const td_api::toggleChatIsTranslatable &request); + + void on_request(uint64 id, const td_api::toggleChatIsMarkedAsUnread &request); + + void on_request(uint64 id, const td_api::setMessageSenderBlockList &request); + + void on_request(uint64 id, const td_api::toggleChatDefaultDisableNotification &request); + + void on_request(uint64 id, const td_api::setPinnedChats &request); + + void on_request(uint64 id, const td_api::readChatList &request); + + void on_request(uint64 id, const td_api::getStoryNotificationSettingsExceptions &request); + + void on_request(uint64 id, const td_api::getChatActiveStories &request); + + void on_request(uint64 id, const td_api::getChatPostedToChatPageStories &request); + + void on_request(uint64 id, const td_api::getChatArchivedStories &request); + + void on_request(uint64 id, const td_api::setChatPinnedStories &request); + + void on_request(uint64 id, const td_api::openStory &request); + + void on_request(uint64 id, const td_api::closeStory &request); + + void on_request(uint64 id, const td_api::getStoryAvailableReactions &request); + + void on_request(uint64 id, const td_api::setStoryReaction &request); + + void on_request(uint64 id, td_api::getStoryInteractions &request); + + void on_request(uint64 id, td_api::getChatStoryInteractions &request); + + void on_request(uint64 id, td_api::reportStory &request); + + void on_request(uint64 id, const td_api::activateStoryStealthMode &request); + + void on_request(uint64 id, const td_api::getChatBoostLevelFeatures &request); + + void on_request(uint64 id, const td_api::getChatBoostFeatures &request); + + void on_request(uint64 id, const td_api::getAvailableChatBoostSlots &request); + + void on_request(uint64 id, const td_api::getChatBoostStatus &request); + + void on_request(uint64 id, td_api::boostChat &request); + + void on_request(uint64 id, const td_api::getChatBoostLink &request); + + void on_request(uint64 id, td_api::getChatBoostLinkInfo &request); + + void on_request(uint64 id, td_api::getChatBoosts &request); + + void on_request(uint64 id, const td_api::getUserChatBoosts &request); + + void on_request(uint64 id, const td_api::getAttachmentMenuBot &request); + + void on_request(uint64 id, const td_api::toggleBotIsAddedToAttachmentMenu &request); + + void on_request(uint64 id, td_api::setChatAvailableReactions &request); + + void on_request(uint64 id, td_api::setChatClientData &request); + + void on_request(uint64 id, td_api::setChatDescription &request); + + void on_request(uint64 id, const td_api::setChatDiscussionGroup &request); + + void on_request(uint64 id, td_api::setChatLocation &request); + + void on_request(uint64 id, const td_api::setChatSlowModeDelay &request); + + void on_request(uint64 id, const td_api::pinChatMessage &request); + + void on_request(uint64 id, const td_api::unpinChatMessage &request); + + void on_request(uint64 id, const td_api::unpinAllChatMessages &request); + + void on_request(uint64 id, const td_api::unpinAllMessageThreadMessages &request); + + void on_request(uint64 id, const td_api::joinChat &request); + + void on_request(uint64 id, const td_api::leaveChat &request); + + void on_request(uint64 id, const td_api::addChatMember &request); + + void on_request(uint64 id, const td_api::addChatMembers &request); + + void on_request(uint64 id, td_api::setChatMemberStatus &request); + + void on_request(uint64 id, const td_api::banChatMember &request); + + void on_request(uint64 id, const td_api::canTransferOwnership &request); + + void on_request(uint64 id, td_api::transferChatOwnership &request); + + void on_request(uint64 id, const td_api::getChatMember &request); + + void on_request(uint64 id, td_api::searchChatMembers &request); + + void on_request(uint64 id, const td_api::getChatAdministrators &request); + + void on_request(uint64 id, const td_api::replacePrimaryChatInviteLink &request); + + void on_request(uint64 id, td_api::createChatInviteLink &request); + + void on_request(uint64 id, td_api::createChatSubscriptionInviteLink &request); + + void on_request(uint64 id, td_api::editChatInviteLink &request); + + void on_request(uint64 id, td_api::editChatSubscriptionInviteLink &request); + + void on_request(uint64 id, td_api::getChatInviteLink &request); + + void on_request(uint64 id, const td_api::getChatInviteLinkCounts &request); + + void on_request(uint64 id, td_api::getChatInviteLinks &request); + + void on_request(uint64 id, td_api::getChatInviteLinkMembers &request); + + void on_request(uint64 id, td_api::getChatJoinRequests &request); + + void on_request(uint64 id, const td_api::processChatJoinRequest &request); + + void on_request(uint64 id, td_api::processChatJoinRequests &request); + + void on_request(uint64 id, td_api::revokeChatInviteLink &request); + + void on_request(uint64 id, td_api::deleteRevokedChatInviteLink &request); + + void on_request(uint64 id, const td_api::deleteAllRevokedChatInviteLinks &request); + + void on_request(uint64 id, td_api::checkChatInviteLink &request); + + void on_request(uint64 id, td_api::joinChatByInviteLink &request); + + void on_request(uint64 id, td_api::getChatEventLog &request); + + void on_request(uint64 id, const td_api::getTimeZones &request); + + void on_request(uint64 id, const td_api::clearAllDraftMessages &request); + + void on_request(uint64 id, const td_api::downloadFile &request); + + void on_request(uint64 id, const td_api::getFileDownloadedPrefixSize &request); + + void on_request(uint64 id, const td_api::cancelDownloadFile &request); + + void on_request(uint64 id, const td_api::getSuggestedFileName &request); + + void on_request(uint64 id, const td_api::preliminaryUploadFile &request); + + void on_request(uint64 id, const td_api::cancelPreliminaryUploadFile &request); + + void on_request(uint64 id, td_api::writeGeneratedFilePart &request); + + void on_request(uint64 id, const td_api::setFileGenerationProgress &request); + + void on_request(uint64 id, td_api::finishFileGeneration &request); + + void on_request(uint64 id, const td_api::readFilePart &request); + + void on_request(uint64 id, const td_api::deleteFile &request); + + void on_request(uint64 id, const td_api::addFileToDownloads &request); + + void on_request(uint64 id, const td_api::toggleDownloadIsPaused &request); + + void on_request(uint64 id, const td_api::toggleAllDownloadsArePaused &request); + + void on_request(uint64 id, const td_api::removeFileFromDownloads &request); + + void on_request(uint64 id, const td_api::removeAllFilesFromDownloads &request); + + void on_request(uint64 id, td_api::searchFileDownloads &request); + + void on_request(uint64 id, td_api::setApplicationVerificationToken &request); + + void on_request(uint64 id, td_api::getMessageFileType &request); + + void on_request(uint64 id, const td_api::getMessageImportConfirmationText &request); + + void on_request(uint64 id, const td_api::importMessages &request); + + void on_request(uint64 id, const td_api::blockMessageSenderFromReplies &request); + + void on_request(uint64 id, const td_api::getBlockedMessageSenders &request); + + void on_request(uint64 id, td_api::addContact &request); + + void on_request(uint64 id, td_api::importContacts &request); + + void on_request(uint64 id, const td_api::getContacts &request); + + void on_request(uint64 id, td_api::searchContacts &request); + + void on_request(uint64 id, td_api::removeContacts &request); + + void on_request(uint64 id, const td_api::getImportedContactCount &request); + + void on_request(uint64 id, td_api::changeImportedContacts &request); + + void on_request(uint64 id, const td_api::clearImportedContacts &request); + + void on_request(uint64 id, const td_api::getCloseFriends &request); + + void on_request(uint64 id, const td_api::setCloseFriends &request); + + void on_request(uint64 id, td_api::setUserPersonalProfilePhoto &request); + + void on_request(uint64 id, td_api::suggestUserProfilePhoto &request); + + void on_request(uint64 id, td_api::searchUserByPhoneNumber &request); + + void on_request(uint64 id, const td_api::sharePhoneNumber &request); + + void on_request(uint64 id, const td_api::getRecentInlineBots &request); + + void on_request(uint64 id, td_api::setName &request); + + void on_request(uint64 id, td_api::setBio &request); + + void on_request(uint64 id, td_api::setUsername &request); + + void on_request(uint64 id, td_api::toggleUsernameIsActive &request); + + void on_request(uint64 id, td_api::reorderActiveUsernames &request); + + void on_request(uint64 id, td_api::setBirthdate &request); + + void on_request(uint64 id, const td_api::setPersonalChat &request); + + void on_request(uint64 id, const td_api::setEmojiStatus &request); + + void on_request(uint64 id, const td_api::toggleHasSponsoredMessagesEnabled &request); + + void on_request(uint64 id, const td_api::getThemedEmojiStatuses &request); + + void on_request(uint64 id, const td_api::getThemedChatEmojiStatuses &request); + + void on_request(uint64 id, const td_api::getDefaultEmojiStatuses &request); + + void on_request(uint64 id, const td_api::getDefaultChatEmojiStatuses &request); + + void on_request(uint64 id, const td_api::getRecentEmojiStatuses &request); + + void on_request(uint64 id, const td_api::clearRecentEmojiStatuses &request); + + void on_request(uint64 id, td_api::setCommands &request); + + void on_request(uint64 id, td_api::deleteCommands &request); + + void on_request(uint64 id, td_api::getCommands &request); + + void on_request(uint64 id, td_api::setMenuButton &request); + + void on_request(uint64 id, const td_api::getMenuButton &request); + + void on_request(uint64 id, const td_api::setDefaultGroupAdministratorRights &request); + + void on_request(uint64 id, const td_api::setDefaultChannelAdministratorRights &request); + + void on_request(uint64 id, const td_api::canBotSendMessages &request); + + void on_request(uint64 id, const td_api::allowBotToSendMessages &request); + + void on_request(uint64 id, td_api::sendWebAppCustomRequest &request); + + void on_request(uint64 id, const td_api::getBotMediaPreviews &request); + + void on_request(uint64 id, const td_api::getBotMediaPreviewInfo &request); + + void on_request(uint64 id, td_api::addBotMediaPreview &request); + + void on_request(uint64 id, td_api::editBotMediaPreview &request); + + void on_request(uint64 id, const td_api::reorderBotMediaPreviews &request); + + void on_request(uint64 id, const td_api::deleteBotMediaPreviews &request); + + void on_request(uint64 id, td_api::setBotName &request); + + void on_request(uint64 id, const td_api::getBotName &request); + + void on_request(uint64 id, td_api::setBotProfilePhoto &request); + + void on_request(uint64 id, td_api::toggleBotUsernameIsActive &request); + + void on_request(uint64 id, td_api::reorderBotActiveUsernames &request); + + void on_request(uint64 id, td_api::setBotInfoDescription &request); + + void on_request(uint64 id, const td_api::getBotInfoDescription &request); + + void on_request(uint64 id, td_api::setBotInfoShortDescription &request); + + void on_request(uint64 id, const td_api::getBotInfoShortDescription &request); + + void on_request(uint64 id, const td_api::setLocation &request); + + void on_request(uint64 id, td_api::setBusinessLocation &request); + + void on_request(uint64 id, td_api::setBusinessOpeningHours &request); + + void on_request(uint64 id, td_api::setBusinessGreetingMessageSettings &request); + + void on_request(uint64 id, td_api::setBusinessAwayMessageSettings &request); + + void on_request(uint64 id, td_api::setBusinessStartPage &request); + + void on_request(uint64 id, td_api::setProfilePhoto &request); + + void on_request(uint64 id, const td_api::deleteProfilePhoto &request); + + void on_request(uint64 id, const td_api::getUserProfilePhotos &request); + + void on_request(uint64 id, const td_api::setAccentColor &request); + + void on_request(uint64 id, const td_api::setProfileAccentColor &request); + + void on_request(uint64 id, const td_api::getBusinessConnectedBot &request); + + void on_request(uint64 id, td_api::setBusinessConnectedBot &request); + + void on_request(uint64 id, const td_api::deleteBusinessConnectedBot &request); + + void on_request(uint64 id, const td_api::toggleBusinessConnectedBotChatIsPaused &request); + + void on_request(uint64 id, const td_api::removeBusinessConnectedBotFromChat &request); + + void on_request(uint64 id, const td_api::getBusinessChatLinks &request); + + void on_request(uint64 id, td_api::createBusinessChatLink &request); + + void on_request(uint64 id, td_api::editBusinessChatLink &request); + + void on_request(uint64 id, td_api::deleteBusinessChatLink &request); + + void on_request(uint64 id, td_api::getBusinessChatLinkInfo &request); + + void on_request(uint64 id, td_api::setSupergroupUsername &request); + + void on_request(uint64 id, td_api::toggleSupergroupUsernameIsActive &request); + + void on_request(uint64 id, const td_api::disableAllSupergroupUsernames &request); + + void on_request(uint64 id, td_api::reorderSupergroupActiveUsernames &request); + + void on_request(uint64 id, const td_api::setSupergroupStickerSet &request); + + void on_request(uint64 id, const td_api::setSupergroupCustomEmojiStickerSet &request); + + void on_request(uint64 id, const td_api::setSupergroupUnrestrictBoostCount &request); + + void on_request(uint64 id, const td_api::toggleSupergroupSignMessages &request); + + void on_request(uint64 id, const td_api::toggleSupergroupJoinToSendMessages &request); + + void on_request(uint64 id, const td_api::toggleSupergroupJoinByRequest &request); + + void on_request(uint64 id, const td_api::toggleSupergroupIsAllHistoryAvailable &request); + + void on_request(uint64 id, const td_api::toggleSupergroupCanHaveSponsoredMessages &request); + + void on_request(uint64 id, const td_api::toggleSupergroupHasHiddenMembers &request); + + void on_request(uint64 id, const td_api::toggleSupergroupHasAggressiveAntiSpamEnabled &request); + + void on_request(uint64 id, const td_api::toggleSupergroupIsForum &request); + + void on_request(uint64 id, const td_api::toggleSupergroupIsBroadcastGroup &request); + + void on_request(uint64 id, const td_api::reportSupergroupSpam &request); + + void on_request(uint64 id, const td_api::reportSupergroupAntiSpamFalsePositive &request); + + void on_request(uint64 id, td_api::getSupergroupMembers &request); + + void on_request(uint64 id, td_api::closeSecretChat &request); + + void on_request(uint64 id, td_api::getStickers &request); + + void on_request(uint64 id, td_api::getAllStickerEmojis &request); + + void on_request(uint64 id, td_api::searchStickers &request); + + void on_request(uint64 id, const td_api::getGreetingStickers &request); + + void on_request(uint64 id, const td_api::getPremiumStickers &request); + + void on_request(uint64 id, const td_api::getInstalledStickerSets &request); + + void on_request(uint64 id, const td_api::getArchivedStickerSets &request); + + void on_request(uint64 id, const td_api::getTrendingStickerSets &request); + + void on_request(uint64 id, const td_api::getAttachedStickerSets &request); + + void on_request(uint64 id, const td_api::getStickerSet &request); + + void on_request(uint64 id, const td_api::getStickerSetName &request); + + void on_request(uint64 id, td_api::searchStickerSet &request); + + void on_request(uint64 id, td_api::searchInstalledStickerSets &request); + + void on_request(uint64 id, td_api::searchStickerSets &request); + + void on_request(uint64 id, const td_api::changeStickerSet &request); + + void on_request(uint64 id, const td_api::viewTrendingStickerSets &request); + + void on_request(uint64 id, td_api::reorderInstalledStickerSets &request); + + void on_request(uint64 id, td_api::uploadStickerFile &request); + + void on_request(uint64 id, td_api::getSuggestedStickerSetName &request); + + void on_request(uint64 id, td_api::checkStickerSetName &request); + + void on_request(uint64 id, td_api::createNewStickerSet &request); + + void on_request(uint64 id, td_api::addStickerToSet &request); + + void on_request(uint64 id, td_api::replaceStickerInSet &request); + + void on_request(uint64 id, td_api::setStickerSetThumbnail &request); + + void on_request(uint64 id, td_api::setCustomEmojiStickerSetThumbnail &request); + + void on_request(uint64 id, td_api::setStickerSetTitle &request); + + void on_request(uint64 id, td_api::deleteStickerSet &request); + + void on_request(uint64 id, td_api::setStickerPositionInSet &request); + + void on_request(uint64 id, const td_api::removeStickerFromSet &request); + + void on_request(uint64 id, td_api::setStickerEmojis &request); + + void on_request(uint64 id, td_api::setStickerKeywords &request); + + void on_request(uint64 id, td_api::setStickerMaskPosition &request); + + void on_request(uint64 id, const td_api::getOwnedStickerSets &request); + + void on_request(uint64 id, const td_api::getRecentStickers &request); + + void on_request(uint64 id, td_api::addRecentSticker &request); + + void on_request(uint64 id, td_api::removeRecentSticker &request); + + void on_request(uint64 id, td_api::clearRecentStickers &request); + + void on_request(uint64 id, const td_api::getSavedAnimations &request); + + void on_request(uint64 id, td_api::addSavedAnimation &request); + + void on_request(uint64 id, td_api::removeSavedAnimation &request); + + void on_request(uint64 id, td_api::getStickerEmojis &request); + + void on_request(uint64 id, td_api::searchEmojis &request); + + void on_request(uint64 id, td_api::getKeywordEmojis &request); + + void on_request(uint64 id, const td_api::getEmojiCategories &request); + + void on_request(uint64 id, td_api::getAnimatedEmoji &request); + + void on_request(uint64 id, td_api::getEmojiSuggestionsUrl &request); + + void on_request(uint64 id, const td_api::getCustomEmojiStickers &request); + + void on_request(uint64 id, const td_api::getDefaultChatPhotoCustomEmojiStickers &request); + + void on_request(uint64 id, const td_api::getDefaultProfilePhotoCustomEmojiStickers &request); + + void on_request(uint64 id, const td_api::getDefaultBackgroundCustomEmojiStickers &request); + + void on_request(uint64 id, const td_api::getDisallowedChatEmojiStatuses &request); + + void on_request(uint64 id, const td_api::getFavoriteStickers &request); + + void on_request(uint64 id, td_api::addFavoriteSticker &request); + + void on_request(uint64 id, td_api::removeFavoriteSticker &request); + + void on_request(uint64 id, const td_api::getSavedNotificationSound &request); + + void on_request(uint64 id, const td_api::getSavedNotificationSounds &request); + + void on_request(uint64 id, td_api::addSavedNotificationSound &request); + + void on_request(uint64 id, const td_api::removeSavedNotificationSound &request); + + void on_request(uint64 id, const td_api::getChatNotificationSettingsExceptions &request); + + void on_request(uint64 id, const td_api::getScopeNotificationSettings &request); + + void on_request(uint64 id, td_api::setChatNotificationSettings &request); + + void on_request(uint64 id, td_api::setForumTopicNotificationSettings &request); + + void on_request(uint64 id, td_api::setScopeNotificationSettings &request); + + void on_request(uint64 id, td_api::setReactionNotificationSettings &request); + + void on_request(uint64 id, const td_api::resetAllNotificationSettings &request); + + void on_request(uint64 id, const td_api::removeChatActionBar &request); + + void on_request(uint64 id, td_api::reportChat &request); + + void on_request(uint64 id, td_api::reportChatPhoto &request); + + void on_request(uint64 id, const td_api::reportMessageReactions &request); + + void on_request(uint64 id, const td_api::getChatStatistics &request); + + void on_request(uint64 id, const td_api::getChatRevenueStatistics &request); + + void on_request(uint64 id, const td_api::getChatRevenueWithdrawalUrl &request); + + void on_request(uint64 id, const td_api::getChatRevenueTransactions &request); + + void on_request(uint64 id, const td_api::getStarRevenueStatistics &request); + + void on_request(uint64 id, const td_api::getStarWithdrawalUrl &request); + + void on_request(uint64 id, const td_api::getStarAdAccountUrl &request); + + void on_request(uint64 id, const td_api::getMessageStatistics &request); + + void on_request(uint64 id, const td_api::getStoryStatistics &request); + + void on_request(uint64 id, td_api::getStatisticalGraph &request); + + void on_request(uint64 id, const td_api::getMapThumbnailFile &request); + + void on_request(uint64 id, const td_api::getLocalizationTargetInfo &request); + + void on_request(uint64 id, td_api::getLanguagePackInfo &request); + + void on_request(uint64 id, td_api::getLanguagePackStrings &request); + + void on_request(uint64 id, td_api::synchronizeLanguagePack &request); + + void on_request(uint64 id, td_api::addCustomServerLanguagePack &request); + + void on_request(uint64 id, td_api::setCustomLanguagePack &request); + + void on_request(uint64 id, td_api::editCustomLanguagePackInfo &request); + + void on_request(uint64 id, td_api::setCustomLanguagePackString &request); + + void on_request(uint64 id, td_api::deleteLanguagePack &request); + + void on_request(uint64 id, td_api::getOption &request); + + void on_request(uint64 id, td_api::setOption &request); + + void on_request(uint64 id, td_api::setPollAnswer &request); + + void on_request(uint64 id, td_api::getPollVoters &request); + + void on_request(uint64 id, td_api::stopPoll &request); + + void on_request(uint64 id, const td_api::hideSuggestedAction &request); + + void on_request(uint64 id, const td_api::hideContactCloseBirthdays &request); + + void on_request(uint64 id, td_api::getBusinessConnection &request); + + void on_request(uint64 id, const td_api::getLoginUrlInfo &request); + + void on_request(uint64 id, const td_api::getLoginUrl &request); + + void on_request(uint64 id, const td_api::shareUsersWithBot &request); + + void on_request(uint64 id, const td_api::shareChatWithBot &request); + + void on_request(uint64 id, td_api::getInlineQueryResults &request); + + void on_request(uint64 id, td_api::answerInlineQuery &request); + + void on_request(uint64 id, td_api::getGrossingWebAppBots &request); + + void on_request(uint64 id, td_api::searchWebApp &request); + + void on_request(uint64 id, td_api::getWebAppLinkUrl &request); + + void on_request(uint64 id, td_api::getMainWebApp &request); + + void on_request(uint64 id, td_api::getWebAppUrl &request); + + void on_request(uint64 id, td_api::sendWebAppData &request); + + void on_request(uint64 id, td_api::openWebApp &request); + + void on_request(uint64 id, const td_api::closeWebApp &request); + + void on_request(uint64 id, td_api::answerWebAppQuery &request); + + void on_request(uint64 id, td_api::getCallbackQueryAnswer &request); + + void on_request(uint64 id, td_api::answerCallbackQuery &request); + + void on_request(uint64 id, td_api::answerShippingQuery &request); + + void on_request(uint64 id, td_api::answerPreCheckoutQuery &request); + + void on_request(uint64 id, td_api::getBankCardInfo &request); + + void on_request(uint64 id, td_api::getPaymentForm &request); + + void on_request(uint64 id, td_api::validateOrderInfo &request); + + void on_request(uint64 id, td_api::sendPaymentForm &request); + + void on_request(uint64 id, const td_api::getPaymentReceipt &request); + + void on_request(uint64 id, const td_api::getSavedOrderInfo &request); + + void on_request(uint64 id, const td_api::deleteSavedOrderInfo &request); + + void on_request(uint64 id, const td_api::deleteSavedCredentials &request); + + void on_request(uint64 id, td_api::createInvoiceLink &request); + + void on_request(uint64 id, td_api::refundStarPayment &request); + + void on_request(uint64 id, td_api::getPassportElement &request); + + void on_request(uint64 id, td_api::getAllPassportElements &request); + + void on_request(uint64 id, td_api::setPassportElement &request); + + void on_request(uint64 id, const td_api::deletePassportElement &request); + + void on_request(uint64 id, td_api::setPassportElementErrors &request); + + void on_request(uint64 id, td_api::getPreferredCountryLanguage &request); + + void on_request(uint64 id, td_api::sendEmailAddressVerificationCode &request); + + void on_request(uint64 id, const td_api::resendEmailAddressVerificationCode &request); + + void on_request(uint64 id, td_api::checkEmailAddressVerificationCode &request); + + void on_request(uint64 id, td_api::getPassportAuthorizationForm &request); + + void on_request(uint64 id, td_api::getPassportAuthorizationFormAvailableElements &request); + + void on_request(uint64 id, td_api::sendPassportAuthorizationForm &request); + + void on_request(uint64 id, const td_api::getSupportUser &request); + + void on_request(uint64 id, const td_api::getInstalledBackgrounds &request); + + void on_request(uint64 id, td_api::getBackgroundUrl &request); + + void on_request(uint64 id, td_api::searchBackground &request); + + void on_request(uint64 id, td_api::setDefaultBackground &request); + + void on_request(uint64 id, const td_api::deleteDefaultBackground &request); + + void on_request(uint64 id, const td_api::removeInstalledBackground &request); + + void on_request(uint64 id, const td_api::resetInstalledBackgrounds &request); + + void on_request(uint64 id, td_api::getRecentlyVisitedTMeUrls &request); + + void on_request(uint64 id, td_api::setBotUpdatesStatus &request); + + void on_request(uint64 id, td_api::sendCustomRequest &request); + + void on_request(uint64 id, td_api::answerCustomQuery &request); + + void on_request(uint64 id, const td_api::setAlarm &request); + + void on_request(uint64 id, td_api::searchHashtags &request); + + void on_request(uint64 id, td_api::removeRecentHashtag &request); + + void on_request(uint64 id, const td_api::getPremiumLimit &request); + + void on_request(uint64 id, const td_api::getPremiumFeatures &request); + + void on_request(uint64 id, const td_api::getPremiumStickerExamples &request); + + void on_request(uint64 id, const td_api::viewPremiumFeature &request); + + void on_request(uint64 id, const td_api::clickPremiumSubscriptionButton &request); + + void on_request(uint64 id, const td_api::getPremiumState &request); + + void on_request(uint64 id, const td_api::getPremiumGiftCodePaymentOptions &request); + + void on_request(uint64 id, td_api::checkPremiumGiftCode &request); + + void on_request(uint64 id, td_api::applyPremiumGiftCode &request); + + void on_request(uint64 id, td_api::launchPrepaidGiveaway &request); + + void on_request(uint64 id, const td_api::getGiveawayInfo &request); + + void on_request(uint64 id, const td_api::getStarPaymentOptions &request); + + void on_request(uint64 id, const td_api::getStarGiftPaymentOptions &request); + + void on_request(uint64 id, const td_api::getStarGiveawayPaymentOptions &request); + + void on_request(uint64 id, td_api::getStarTransactions &request); + + void on_request(uint64 id, td_api::getStarSubscriptions &request); + + void on_request(uint64 id, td_api::editStarSubscription &request); + + void on_request(uint64 id, td_api::reuseStarSubscription &request); + + void on_request(uint64 id, td_api::canPurchaseFromStore &request); + + void on_request(uint64 id, td_api::assignAppStoreTransaction &request); + + void on_request(uint64 id, td_api::assignGooglePlayTransaction &request); + + void on_request(uint64 id, const td_api::getBusinessFeatures &request); + + void on_request(uint64 id, td_api::acceptTermsOfService &request); + + void on_request(uint64 id, const td_api::getCountries &request); + + void on_request(uint64 id, const td_api::getCountryCode &request); + + void on_request(uint64 id, const td_api::getPhoneNumberInfo &request); + + void on_request(uint64 id, td_api::getCollectibleItemInfo &request); + + void on_request(uint64 id, const td_api::getApplicationDownloadLink &request); + + void on_request(uint64 id, td_api::getDeepLinkInfo &request); + + void on_request(uint64 id, const td_api::getApplicationConfig &request); + + void on_request(uint64 id, td_api::saveApplicationLogEvent &request); + + void on_request(uint64 id, td_api::addProxy &request); + + void on_request(uint64 id, td_api::editProxy &request); + + void on_request(uint64 id, const td_api::enableProxy &request); + + void on_request(uint64 id, const td_api::disableProxy &request); + + void on_request(uint64 id, const td_api::removeProxy &request); + + void on_request(uint64 id, const td_api::getProxies &request); + + void on_request(uint64 id, const td_api::getProxyLink &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::getSupportName &request); + + void on_request(uint64 id, const td_api::searchQuote &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::parseMarkdown &request); + + void on_request(uint64 id, const td_api::getMarkdownText &request); + + void on_request(uint64 id, const td_api::searchStringsByPrefix &request); + + void on_request(uint64 id, const td_api::checkQuickReplyShortcutName &request); + + void on_request(uint64 id, const td_api::getCountryFlagEmoji &request); + + void on_request(uint64 id, const td_api::getFileMimeType &request); + + void on_request(uint64 id, const td_api::getFileExtension &request); + + void on_request(uint64 id, const td_api::cleanFileName &request); + + void on_request(uint64 id, const td_api::getLanguagePackString &request); + + void on_request(uint64 id, const td_api::getPhoneNumberInfoSync &request); + + void on_request(uint64 id, const td_api::getPushReceiverId &request); + + void on_request(uint64 id, const td_api::getChatFolderDefaultIconName &request); + + void on_request(uint64 id, const td_api::getJsonValue &request); + + void on_request(uint64 id, const td_api::getJsonString &request); + + void on_request(uint64 id, const td_api::getThemeParametersJsonString &request); + + void on_request(uint64 id, const td_api::setLogStream &request); + + void on_request(uint64 id, const td_api::getLogStream &request); + + void on_request(uint64 id, const td_api::setLogVerbosityLevel &request); + + void on_request(uint64 id, const td_api::getLogVerbosityLevel &request); + + void on_request(uint64 id, const td_api::getLogTags &request); + + void on_request(uint64 id, const td_api::setLogTagVerbosityLevel &request); + + void on_request(uint64 id, const td_api::getLogTagVerbosityLevel &request); + + void on_request(uint64 id, const td_api::addLogMessage &request); + + void on_request(uint64 id, const td_api::testNetwork &request); + + void on_request(uint64 id, td_api::testProxy &request); + + void on_request(uint64 id, const td_api::testGetDifference &request); + + void on_request(uint64 id, const td_api::testUseUpdate &request); + + void on_request(uint64 id, const td_api::testReturnError &request); + + void on_request(uint64 id, const td_api::testCallEmpty &request); + + void on_request(uint64 id, const td_api::testSquareInt &request); + + void on_request(uint64 id, td_api::testCallString &request); + + void on_request(uint64 id, td_api::testCallBytes &request); + + void on_request(uint64 id, td_api::testCallVectorInt &request); + + void on_request(uint64 id, td_api::testCallVectorIntObject &request); + + void on_request(uint64 id, td_api::testCallVectorString &request); + + void on_request(uint64 id, td_api::testCallVectorStringObject &request); +}; + +} // namespace td diff --git a/lib/tgchat/ext/td/td/telegram/SecretChatsManager.cpp b/lib/tgchat/ext/td/td/telegram/SecretChatsManager.cpp index 966ce39b..693c30de 100644 --- a/lib/tgchat/ext/td/td/telegram/SecretChatsManager.cpp +++ b/lib/tgchat/ext/td/td/telegram/SecretChatsManager.cpp @@ -13,6 +13,7 @@ #include "td/telegram/logevent/SecretChatEvent.h" #include "td/telegram/MessageId.h" #include "td/telegram/MessagesManager.h" +#include "td/telegram/net/NetQuery.h" #include "td/telegram/net/NetQueryDispatcher.h" #include "td/telegram/SecretChatDb.h" #include "td/telegram/SequenceDispatcher.h" diff --git a/lib/tgchat/ext/td/td/telegram/SecureValue.cpp b/lib/tgchat/ext/td/td/telegram/SecureValue.cpp index caade807..9fc9286b 100644 --- a/lib/tgchat/ext/td/td/telegram/SecureValue.cpp +++ b/lib/tgchat/ext/td/td/telegram/SecureValue.cpp @@ -396,7 +396,10 @@ telegram_api::object_ptr get_input_secure_file_ob file_manager->get_file_view(input_file.file_id).get_main_file_id()); auto res = std::move(input_file.input_file); if (res == nullptr) { - return file_manager->get_file_view(file.file.file_id).remote_location().as_input_secure_file(); + auto file_view = file_manager->get_file_view(file.file.file_id); + const auto *full_remote_location = file_view.get_full_remote_location(); + CHECK(full_remote_location != nullptr); + return full_remote_location->as_input_secure_file(); } CHECK(res->get_id() == telegram_api::inputSecureFileUploaded::ID); auto uploaded = static_cast(res.get()); @@ -420,7 +423,8 @@ static td_api::object_ptr get_dated_file_object(FileManager * auto file_id = dated_file.file_id; CHECK(file_id.is_valid()); auto file_view = file_manager->get_file_view(file_id); - if (!file_view.has_remote_location() || file_view.remote_location().is_web()) { + const auto *full_remote_location = file_view.get_full_remote_location(); + if (full_remote_location == nullptr || full_remote_location->is_web()) { LOG(ERROR) << "Have wrong file in get_dated_file_object"; return nullptr; } @@ -430,9 +434,8 @@ static td_api::object_ptr get_dated_file_object(FileManager * return get_dated_file_object(file_manager, dated_file); } dated_file.file_id = file_manager->register_remote( - FullRemoteFileLocation(FileType::SecureDecrypted, file_view.remote_location().get_id(), - file_view.remote_location().get_access_hash(), file_view.remote_location().get_dc_id(), - ""), + FullRemoteFileLocation(FileType::SecureDecrypted, full_remote_location->get_id(), + full_remote_location->get_access_hash(), full_remote_location->get_dc_id(), ""), FileLocationSource::FromServer, DialogId(), 0, file_view.expected_size(), file_view.suggested_path()); return get_dated_file_object(file_manager, dated_file); } diff --git a/lib/tgchat/ext/td/td/telegram/SponsoredMessageManager.cpp b/lib/tgchat/ext/td/td/telegram/SponsoredMessageManager.cpp index 35fd5cae..745c0f8f 100644 --- a/lib/tgchat/ext/td/td/telegram/SponsoredMessageManager.cpp +++ b/lib/tgchat/ext/td/td/telegram/SponsoredMessageManager.cpp @@ -281,8 +281,8 @@ td_api::object_ptr SponsoredMessageManager::get_sponso } return td_api::make_object( sponsored_message.local_id, sponsored_message.is_recommended, sponsored_message.can_be_reported, - get_message_content_object(sponsored_message.content.get(), td_, dialog_id, false, 0, false, true, -1, false, - true), + get_message_content_object(sponsored_message.content.get(), td_, dialog_id, true, false, 0, false, true, -1, + false, true), std::move(sponsor), sponsored_message.title, sponsored_message.button_text, td_->theme_manager_->get_accent_color_id_object(sponsored_message.peer_color.accent_color_id_, AccentColorId()), sponsored_message.peer_color.background_custom_emoji_id_.get(), sponsored_message.additional_info); diff --git a/lib/tgchat/ext/td/td/telegram/StarManager.cpp b/lib/tgchat/ext/td/td/telegram/StarManager.cpp index 93143d6a..b1775055 100644 --- a/lib/tgchat/ext/td/td/telegram/StarManager.cpp +++ b/lib/tgchat/ext/td/td/telegram/StarManager.cpp @@ -26,6 +26,7 @@ #include "td/telegram/StatisticsManager.h" #include "td/telegram/StickersManager.h" #include "td/telegram/Td.h" +#include "td/telegram/TdDb.h" #include "td/telegram/telegram_api.h" #include "td/telegram/UpdatesManager.h" #include "td/telegram/UserManager.h" @@ -113,6 +114,45 @@ class GetStarsGiftOptionsQuery final : public Td::ResultHandler { } }; +class GetStarsGiveawayOptionsQuery final : public Td::ResultHandler { + Promise> promise_; + + public: + explicit GetStarsGiveawayOptionsQuery(Promise> &&promise) + : promise_(std::move(promise)) { + } + + void send() { + send_query(G()->net_query_creator().create(telegram_api::payments_getStarsGiveawayOptions())); + } + + void on_result(BufferSlice packet) final { + auto result_ptr = fetch_result(packet); + if (result_ptr.is_error()) { + return on_error(result_ptr.move_as_error()); + } + + auto results = result_ptr.move_as_ok(); + vector> options; + for (auto &result : results) { + vector> winner_options; + for (auto &winner : result->winners_) { + winner_options.push_back(td_api::make_object( + winner->users_, StarManager::get_star_count(winner->per_user_stars_), winner->default_)); + } + options.push_back(td_api::make_object( + result->currency_, result->amount_, StarManager::get_star_count(result->stars_), result->store_product_, + result->yearly_boosts_, std::move(winner_options), result->default_, result->extended_)); + } + + promise_.set_value(td_api::make_object(std::move(options))); + } + + void on_error(Status status) final { + promise_.set_error(std::move(status)); + } +}; + class GetStarsTransactionsQuery final : public Td::ResultHandler { Promise> promise_; DialogId dialog_id_; @@ -213,9 +253,8 @@ class GetStarsTransactionsQuery final : public Td::ResultHandler { for (auto &media : extended_media) { media.append_file_ids(td_, file_ids); } - auto extended_media_objects = transform(std::move(extended_media), [td = td_](auto &&media) { - return media.get_message_extended_media_object(td); - }); + auto extended_media_objects = + transform(std::move(extended_media), [td = td_](auto &&media) { return media.get_paid_media_object(td); }); transaction->extended_media_.clear(); return extended_media_objects; }; @@ -233,8 +272,7 @@ class GetStarsTransactionsQuery final : public Td::ResultHandler { if (transaction->gift_) { transaction->gift_ = false; return td_api::make_object( - 0, td_->stickers_manager_->get_premium_gift_sticker_object( - StarManager::get_months_by_star_count(star_count))); + 0, td_->stickers_manager_->get_premium_gift_sticker_object(0, star_count)); } auto state = [&]() -> td_api::object_ptr { if (transaction->transaction_date_ > 0) { @@ -276,8 +314,7 @@ class GetStarsTransactionsQuery final : public Td::ResultHandler { user_id == UserManager::get_service_notifications_user_id() ? 0 : td_->user_manager_->get_user_id_object(user_id, "starTransactionPartnerUser"), - td_->stickers_manager_->get_premium_gift_sticker_object( - StarManager::get_months_by_star_count(star_count))); + td_->stickers_manager_->get_premium_gift_sticker_object(0, star_count)); } if (!transaction->extended_media_.empty()) { // TODO return td_api::make_object( @@ -287,32 +324,39 @@ class GetStarsTransactionsQuery final : public Td::ResultHandler { LOG(ERROR) << "Receive Telegram Star transaction with " << user_id; return td_api::make_object(); } - if ((product_info == nullptr && bot_payload.empty()) || !transaction->extended_media_.empty()) { - if (G()->is_test_dc()) { - bot_payload.clear(); - } + SCOPE_EXIT { + bot_payload.clear(); + }; + if (product_info == nullptr || !transaction->extended_media_.empty()) { return td_api::make_object( td_->user_manager_->get_user_id_object(user_id, "starTransactionPartnerBot"), td_api::make_object( - get_paid_media_object(DialogId(user_id)))); + get_paid_media_object(DialogId(user_id)), bot_payload)); } - SCOPE_EXIT { - bot_payload.clear(); - }; return td_api::make_object( td_->user_manager_->get_user_id_object(user_id, "starTransactionPartnerBot"), td_api::make_object(std::move(product_info), bot_payload)); } + if (dialog_id.get_type() == DialogType::Channel && transaction->giveaway_post_id_ > 0) { + SCOPE_EXIT { + transaction->giveaway_post_id_ = 0; + }; + td_->dialog_manager_->force_create_dialog(dialog_id, "starsTransactionPeer", true); + return td_api::make_object( + td_->dialog_manager_->get_chat_id_object(dialog_id, "starTransactionPartnerChat"), + td_api::make_object( + MessageId(ServerMessageId(transaction->giveaway_post_id_)).get())); + } if (td_->dialog_manager_->is_broadcast_channel(dialog_id)) { if (transaction->subscription_period_ > 0) { SCOPE_EXIT { transaction->subscription_period_ = 0; }; td_->dialog_manager_->force_create_dialog(dialog_id, "starsTransactionPeer", true); - return td_api::make_object( - td_->dialog_manager_->get_chat_id_object(dialog_id, "starTransactionPartnerChannel"), - td_api::make_object(transaction->subscription_period_)); + return td_api::make_object( + td_->dialog_manager_->get_chat_id_object(dialog_id, "starTransactionPartnerChat"), + td_api::make_object(transaction->subscription_period_)); } if (transaction->reaction_) { SCOPE_EXIT { @@ -325,9 +369,9 @@ class GetStarsTransactionsQuery final : public Td::ResultHandler { message_id = MessageId(); } td_->dialog_manager_->force_create_dialog(dialog_id, "starsTransactionPeer", true); - return td_api::make_object( - td_->dialog_manager_->get_chat_id_object(dialog_id, "starTransactionPartnerChannel"), - td_api::make_object(message_id.get())); + return td_api::make_object( + td_->dialog_manager_->get_chat_id_object(dialog_id, "starTransactionPartnerChat"), + td_api::make_object(message_id.get())); } SCOPE_EXIT { @@ -339,10 +383,10 @@ class GetStarsTransactionsQuery final : public Td::ResultHandler { message_id = MessageId(); } td_->dialog_manager_->force_create_dialog(dialog_id, "starsTransactionPeer", true); - return td_api::make_object( - td_->dialog_manager_->get_chat_id_object(dialog_id, "starTransactionPartnerChannel"), - td_api::make_object(message_id.get(), - get_paid_media_object(dialog_id))); + return td_api::make_object( + td_->dialog_manager_->get_chat_id_object(dialog_id, "starTransactionPartnerChat"), + td_api::make_object(message_id.get(), + get_paid_media_object(dialog_id))); } LOG(ERROR) << "Receive Telegram Star transaction with " << dialog_id; return td_api::make_object(); @@ -382,6 +426,9 @@ class GetStarsTransactionsQuery final : public Td::ResultHandler { if (!transaction->extended_media_.empty()) { LOG(ERROR) << "Receive paid media with " << to_string(star_transaction); } + if (transaction->giveaway_post_id_ != 0) { + LOG(ERROR) << "Receive giveaway message with " << to_string(star_transaction); + } } if (!file_ids.empty()) { auto file_source_id = @@ -392,7 +439,7 @@ class GetStarsTransactionsQuery final : public Td::ResultHandler { } transactions.push_back(std::move(star_transaction)); } - if (!td_->auth_manager_->is_bot() && dialog_id_ == td_->dialog_manager_->get_my_dialog_id()) { + if (dialog_id_ == td_->dialog_manager_->get_my_dialog_id()) { td_->star_manager_->on_update_owned_star_count(star_count); } @@ -445,9 +492,7 @@ class GetStarsSubscriptionsQuery final : public Td::ResultHandler { } } auto star_count = StarManager::get_star_count(result->balance_, true); - if (!td_->auth_manager_->is_bot()) { - td_->star_manager_->on_update_owned_star_count(star_count); - } + td_->star_manager_->on_update_owned_star_count(star_count); promise_.set_value(td_api::make_object( star_count, std::move(subscriptions), StarManager::get_star_count(result->subscriptions_missing_balance_), result->subscriptions_next_offset_)); @@ -670,30 +715,68 @@ class GetStarsRevenueAdsAccountUrlQuery final : public Td::ResultHandler { StarManager::StarManager(Td *td, ActorShared<> parent) : td_(td), parent_(std::move(parent)) { } +void StarManager::start_up() { + if (td_->auth_manager_->is_bot() || !td_->auth_manager_->is_authorized()) { + return; + } + auto owned_star_count = G()->td_db()->get_binlog_pmc()->get("owned_star_count"); + if (!owned_star_count.empty()) { + is_owned_star_count_inited_ = true; + owned_star_count_ = to_integer(owned_star_count); + sent_star_count_ = owned_star_count_; + send_closure(G()->td(), &Td::send_update, get_update_owned_star_count_object()); + } +} + void StarManager::tear_down() { parent_.reset(); } td_api::object_ptr StarManager::get_update_owned_star_count_object() const { CHECK(is_owned_star_count_inited_); - return td_api::make_object(owned_star_count_); + // sent_star_count_ can be negative as well as owned_star_count_ + return td_api::make_object(sent_star_count_); } void StarManager::on_update_owned_star_count(int64 star_count) { + if (td_->auth_manager_->is_bot()) { + return; + } if (is_owned_star_count_inited_ && star_count == owned_star_count_) { return; } is_owned_star_count_inited_ = true; owned_star_count_ = star_count; - send_closure(G()->td(), &Td::send_update, get_update_owned_star_count_object()); + if (owned_star_count_ + pending_owned_star_count_ != sent_star_count_) { + sent_star_count_ = owned_star_count_ + pending_owned_star_count_; + send_closure(G()->td(), &Td::send_update, get_update_owned_star_count_object()); + } + G()->td_db()->get_binlog_pmc()->set("owned_star_count", to_string(owned_star_count_)); } -void StarManager::add_owned_star_count(int64 star_count) { +void StarManager::add_pending_owned_star_count(int64 star_count, bool move_to_owned) { + if (star_count == 0) { + return; + } + pending_owned_star_count_ += star_count; if (is_owned_star_count_inited_) { - on_update_owned_star_count(star_count + owned_star_count_); + if (move_to_owned) { + owned_star_count_ -= star_count; + G()->td_db()->get_binlog_pmc()->set("owned_star_count", to_string(owned_star_count_)); + } else { + sent_star_count_ += star_count; + send_closure(G()->td(), &Td::send_update, get_update_owned_star_count_object()); + } } } +bool StarManager::has_owned_star_count(int64 star_count) const { + if (star_count <= 0 || !is_owned_star_count_inited_) { + return true; + } + return sent_star_count_ >= star_count; +} + Status StarManager::can_manage_stars(DialogId dialog_id, bool allow_self) const { switch (dialog_id.get_type()) { case DialogType::User: { @@ -737,6 +820,11 @@ void StarManager::get_star_gift_payment_options(UserId user_id, td_->create_handler(std::move(promise))->send(std::move(input_user)); } +void StarManager::get_star_giveaway_payment_options( + Promise> &&promise) { + td_->create_handler(std::move(promise))->send(); +} + void StarManager::get_star_transactions(td_api::object_ptr owner_id, const string &subscription_id, const string &offset, int32 limit, td_api::object_ptr &&direction, @@ -845,6 +933,10 @@ void StarManager::reload_star_transaction(DialogId dialog_id, const string &tran td_->create_handler(std::move(query_promise))->send(dialog_id, transaction_id, is_refund); } +void StarManager::reload_owned_star_count() { + do_get_star_transactions(td_->dialog_manager_->get_my_dialog_id(), string(), string(), 1, nullptr, Auto()); +} + void StarManager::on_update_stars_revenue_status( telegram_api::object_ptr &&update) { DialogId dialog_id(update->peer_); diff --git a/lib/tgchat/ext/td/td/telegram/StarManager.h b/lib/tgchat/ext/td/td/telegram/StarManager.h index 42410207..188a1fb1 100644 --- a/lib/tgchat/ext/td/td/telegram/StarManager.h +++ b/lib/tgchat/ext/td/td/telegram/StarManager.h @@ -29,12 +29,16 @@ class StarManager final : public Actor { void on_update_owned_star_count(int64 star_count); - void add_owned_star_count(int64 star_count); + void add_pending_owned_star_count(int64 star_count, bool move_to_owned); + + bool has_owned_star_count(int64 star_count) const; void get_star_payment_options(Promise> &&promise); void get_star_gift_payment_options(UserId user_id, Promise> &&promise); + void get_star_giveaway_payment_options(Promise> &&promise); + void get_star_transactions(td_api::object_ptr owner_id, const string &subscription_id, const string &offset, int32 limit, td_api::object_ptr &&direction, @@ -60,6 +64,8 @@ class StarManager final : public Actor { void reload_star_transaction(DialogId dialog_id, const string &transaction_id, bool is_refund, Promise &&promise); + void reload_owned_star_count(); + void on_update_stars_revenue_status(telegram_api::object_ptr &&update); FileSourceId get_star_transaction_file_source_id(DialogId dialog_id, const string &transaction_id, bool is_refund); @@ -71,6 +77,8 @@ class StarManager final : public Actor { void get_current_state(vector> &updates) const; private: + void start_up() final; + void tear_down() final; Status can_manage_stars(DialogId dialog_id, bool allow_self = false) const; @@ -90,6 +98,8 @@ class StarManager final : public Actor { bool is_owned_star_count_inited_ = false; int64 owned_star_count_ = 0; + int64 pending_owned_star_count_ = 0; + int64 sent_star_count_ = 0; FlatHashMap, DialogIdHash> star_transaction_file_source_ids_[2]; }; diff --git a/lib/tgchat/ext/td/td/telegram/StatisticsManager.cpp b/lib/tgchat/ext/td/td/telegram/StatisticsManager.cpp index 8a993e45..f11e716a 100644 --- a/lib/tgchat/ext/td/td/telegram/StatisticsManager.cpp +++ b/lib/tgchat/ext/td/td/telegram/StatisticsManager.cpp @@ -277,8 +277,9 @@ static int64 get_amount(int64 amount, bool allow_negative = false) { static td_api::object_ptr convert_broadcast_revenue_balances( telegram_api::object_ptr obj) { CHECK(obj != nullptr); - return td_api::make_object( - "TON", get_amount(obj->overall_revenue_), get_amount(obj->current_balance_), get_amount(obj->available_balance_)); + return td_api::make_object("TON", get_amount(obj->overall_revenue_), + get_amount(obj->current_balance_), + get_amount(obj->available_balance_), obj->withdrawal_enabled_); } static td_api::object_ptr convert_broadcast_revenue_stats( diff --git a/lib/tgchat/ext/td/td/telegram/StickersManager.cpp b/lib/tgchat/ext/td/td/telegram/StickersManager.cpp index dcd8c3ea..f52c6ac7 100644 --- a/lib/tgchat/ext/td/td/telegram/StickersManager.cpp +++ b/lib/tgchat/ext/td/td/telegram/StickersManager.cpp @@ -33,6 +33,7 @@ #include "td/telegram/QuickReplyManager.h" #include "td/telegram/secret_api.h" #include "td/telegram/SecretChatLayer.h" +#include "td/telegram/StarManager.h" #include "td/telegram/StickersManager.hpp" #include "td/telegram/Td.h" #include "td/telegram/td_api.h" @@ -765,6 +766,29 @@ class GetStickerSetQuery final : public Td::ResultHandler { } }; +class GetStickerSetNameQuery final : public Td::ResultHandler { + StickerSetId sticker_set_id_; + + public: + void send(StickerSetId sticker_set_id, telegram_api::object_ptr &&input_sticker_set) { + sticker_set_id_ = sticker_set_id; + send_query(G()->net_query_creator().create(telegram_api::messages_getStickerSet(std::move(input_sticker_set), 0))); + } + + void on_result(BufferSlice packet) final { + auto result_ptr = fetch_result(packet); + if (result_ptr.is_error()) { + return on_error(result_ptr.move_as_error()); + } + + td_->stickers_manager_->on_get_sticker_set_name(sticker_set_id_, result_ptr.move_as_ok()); + } + + void on_error(Status status) final { + td_->stickers_manager_->on_get_sticker_set_name(sticker_set_id_, nullptr); + } +}; + class ReloadSpecialStickerSetQuery final : public Td::ResultHandler { StickerSetId sticker_set_id_; SpecialStickerSetType type_; @@ -2078,12 +2102,12 @@ bool StickersManager::have_custom_emoji(CustomEmojiId custom_emoji_id) { } int64 StickersManager::get_sticker_id(FileId sticker_id) const { - auto sticker_file_view = td_->file_manager_->get_file_view(sticker_id); - if (sticker_file_view.is_encrypted() || !sticker_file_view.has_remote_location() || - !sticker_file_view.remote_location().is_document()) { + auto file_view = td_->file_manager_->get_file_view(sticker_id); + const auto *full_remote_location = file_view.get_full_remote_location(); + if (file_view.is_encrypted() || full_remote_location == nullptr || !full_remote_location->is_document()) { return 0; } - return sticker_file_view.remote_location().get_id(); + return full_remote_location->get_id(); } CustomEmojiId StickersManager::get_custom_emoji_id(FileId sticker_id) const { @@ -2340,13 +2364,14 @@ tl_object_ptr StickersManager::get_sticker_object(FileId file_i auto thumbnail_format = PhotoFormat::Webp; int64 document_id = 0; if (!sticker->set_id_.is_valid()) { - auto sticker_file_view = td_->file_manager_->get_file_view(sticker->file_id_); - if (sticker_file_view.is_encrypted()) { + auto file_view = td_->file_manager_->get_file_view(sticker->file_id_); + if (file_view.is_encrypted()) { // uploaded to secret chats stickers have JPEG thumbnail instead of server-generated WEBP thumbnail_format = PhotoFormat::Jpeg; } else { - if (sticker_file_view.has_remote_location() && sticker_file_view.remote_location().is_document()) { - document_id = sticker_file_view.remote_location().get_id(); + const auto *full_remote_location = file_view.get_full_remote_location(); + if (full_remote_location != nullptr && full_remote_location->is_document()) { + document_id = full_remote_location->get_id(); } if (thumbnail.file_id.is_valid()) { @@ -2509,8 +2534,9 @@ PhotoFormat StickersManager::get_sticker_set_thumbnail_format(const StickerSet * if (sticker_set->thumbnail_document_id_ != 0 && sticker_set->sticker_type_ == StickerType::CustomEmoji) { for (auto sticker_id : sticker_set->sticker_ids_) { auto file_view = td_->file_manager_->get_file_view(sticker_id); - if (file_view.has_remote_location() && !file_view.remote_location().is_web() && - file_view.remote_location().get_id() == sticker_set->thumbnail_document_id_) { + const auto *full_remote_location = file_view.get_full_remote_location(); + if (full_remote_location != nullptr && !full_remote_location->is_web() && + full_remote_location->get_id() == sticker_set->thumbnail_document_id_) { const Sticker *s = get_sticker(sticker_id); CHECK(s != nullptr); return get_sticker_format_photo_format(s->format_); @@ -2543,8 +2569,9 @@ td_api::object_ptr StickersManager::get_sticker_set_thumbnail if (sticker_set->thumbnail_document_id_ != 0 && sticker_set->sticker_type_ == StickerType::CustomEmoji) { for (auto sticker_id : sticker_set->sticker_ids_) { auto file_view = td_->file_manager_->get_file_view(sticker_id); - if (file_view.has_remote_location() && !file_view.remote_location().is_web() && - file_view.remote_location().get_id() == sticker_set->thumbnail_document_id_) { + const auto *full_remote_location = file_view.get_full_remote_location(); + if (full_remote_location != nullptr && !full_remote_location->is_web() && + full_remote_location->get_id() == sticker_set->thumbnail_document_id_) { const Sticker *s = get_sticker(sticker_id); auto thumbnail_format = get_sticker_format_photo_format(s->format_); PhotoSize thumbnail; @@ -2665,7 +2692,11 @@ tl_object_ptr StickersManager::get_sticker_set_info_obje sticker_set->was_loaded_ ? actual_count : max(actual_count, sticker_set->sticker_count_), std::move(stickers)); } -td_api::object_ptr StickersManager::get_premium_gift_sticker_object(int32 month_count) { +td_api::object_ptr StickersManager::get_premium_gift_sticker_object(int32 month_count, + int64 star_count) { + if (month_count == 0) { + month_count = StarManager::get_months_by_star_count(star_count); + } auto it = premium_gift_messages_.find(month_count); if (it == premium_gift_messages_.end()) { return get_sticker_object(get_premium_gift_option_sticker_id(month_count)); @@ -3500,7 +3531,7 @@ bool StickersManager::has_input_media(FileId sticker_file_id, bool is_secret) co const Sticker *sticker = get_sticker(sticker_file_id); CHECK(sticker != nullptr); if (file_view.is_encrypted_secret()) { - if (!file_view.encryption_key().empty() && file_view.has_remote_location() && + if (!file_view.encryption_key().empty() && file_view.has_full_remote_location() && !sticker->s_thumbnail_.file_id.is_valid()) { return true; } @@ -3517,7 +3548,7 @@ bool StickersManager::has_input_media(FileId sticker_file_id, bool is_secret) co if (file_view.is_encrypted()) { return false; } - if (td_->auth_manager_->is_bot() && file_view.has_remote_location()) { + if (td_->auth_manager_->is_bot() && file_view.has_full_remote_location()) { return true; } const Sticker *sticker = get_sticker(sticker_file_id); @@ -3530,7 +3561,7 @@ bool StickersManager::has_input_media(FileId sticker_file_id, bool is_secret) co // having remote location is not enough to have InputMedia, because the file may not have valid file_reference // also file_id needs to be duped, because upload can be called to repair the file_reference and every upload // request must have unique file_id - if (/* file_view.has_remote_location() || */ file_view.has_url()) { + if (/* file_view.has_full_remote_location() || */ file_view.has_url()) { return true; } } @@ -3545,8 +3576,9 @@ SecretInputMedia StickersManager::get_secret_input_media(FileId sticker_file_id, CHECK(sticker != nullptr); auto file_view = td_->file_manager_->get_file_view(sticker_file_id); if (file_view.is_encrypted_secret()) { - if (file_view.has_remote_location()) { - input_file = file_view.main_remote_location().as_input_encrypted_file(); + const auto *main_remote_location = file_view.get_main_remote_location(); + if (main_remote_location != nullptr) { + input_file = main_remote_location->as_input_encrypted_file(); } if (!input_file) { return {}; @@ -3593,8 +3625,9 @@ SecretInputMedia StickersManager::get_secret_input_media(FileId sticker_file_id, layer}; } else { CHECK(!file_view.is_encrypted()); - auto &remote_location = file_view.remote_location(); - if (remote_location.is_web()) { + const auto *full_remote_location = file_view.get_full_remote_location(); + CHECK(full_remote_location != nullptr); // because it has set_id + if (full_remote_location->is_web()) { // web stickers shouldn't have set_id LOG(ERROR) << "Have a web sticker in " << sticker->set_id_; return {}; @@ -3605,9 +3638,9 @@ SecretInputMedia StickersManager::get_secret_input_media(FileId sticker_file_id, } return SecretInputMedia{ nullptr, make_tl_object( - remote_location.get_id(), remote_location.get_access_hash(), 0 /*date*/, + full_remote_location->get_id(), full_remote_location->get_access_hash(), 0 /*date*/, get_sticker_format_mime_type(sticker->format_), narrow_cast(file_view.size()), - make_tl_object("t"), remote_location.get_dc_id().get_raw_id(), + make_tl_object("t"), full_remote_location->get_dc_id().get_raw_id(), std::move(attributes))}; } } @@ -3619,16 +3652,18 @@ tl_object_ptr StickersManager::get_input_media( if (file_view.is_encrypted()) { return nullptr; } - if (file_view.has_remote_location() && !file_view.main_remote_location().is_web() && input_file == nullptr) { + const auto *main_remote_location = file_view.get_main_remote_location(); + if (main_remote_location != nullptr && !main_remote_location->is_web() && input_file == nullptr) { int32 flags = 0; if (!emoji.empty()) { flags |= telegram_api::inputMediaDocument::QUERY_MASK; } - return make_tl_object( - flags, false /*ignored*/, file_view.main_remote_location().as_input_document(), 0, emoji); + return make_tl_object(flags, false /*ignored*/, + main_remote_location->as_input_document(), 0, emoji); } - if (file_view.has_url()) { - return make_tl_object(0, false /*ignored*/, file_view.url(), 0); + const auto *url = file_view.get_url(); + if (url != nullptr) { + return make_tl_object(0, false /*ignored*/, *url, 0); } if (input_file != nullptr) { @@ -3654,7 +3689,7 @@ tl_object_ptr StickersManager::get_input_media( std::move(input_thumbnail), mime_type, std::move(attributes), vector>(), 0); } else { - CHECK(!file_view.has_remote_location()); + CHECK(main_remote_location == nullptr); } return nullptr; @@ -4076,6 +4111,32 @@ void StickersManager::update_load_request(uint32 load_request_id, const Status & } } +void StickersManager::on_get_sticker_set_name(StickerSetId sticker_set_id, + telegram_api::object_ptr &&set_ptr) { + auto it = sticker_set_name_load_queries_.find(sticker_set_id); + CHECK(it != sticker_set_name_load_queries_.end()); + auto promises = std::move(it->second); + sticker_set_name_load_queries_.erase(it); + if (set_ptr == nullptr || set_ptr->get_id() != telegram_api::messages_stickerSet::ID) { + return fail_promises(promises, Status::Error(500, "Failed to get sticker set name")); + } + auto set = telegram_api::move_object_as(set_ptr); + if (sticker_set_id != StickerSetId(set->set_->id_)) { + LOG(ERROR) << "Expected " << sticker_set_id << ", but receive " << StickerSetId(set->set_->id_); + return fail_promises(promises, Status::Error(500, "Failed to get correct sticker set name")); + } + + StickerSet *sticker_set = get_sticker_set(sticker_set_id); + CHECK(sticker_set != nullptr); + if (!sticker_set->is_inited_) { + sticker_set->short_name_ = std::move(set->set_->short_name_); + } + + for (auto &promise : promises) { + promise.set_value(string(sticker_set->short_name_)); + } +} + void StickersManager::on_get_special_sticker_set(const SpecialStickerSetType &type, StickerSetId sticker_set_id) { auto s = get_sticker_set(sticker_set_id); CHECK(s != nullptr); @@ -4971,6 +5032,26 @@ StickerSetId StickersManager::get_sticker_set(StickerSetId set_id, Promise return set_id; } +void StickersManager::get_sticker_set_name(StickerSetId set_id, Promise &&promise) { + constexpr int64 GREAT_MINDS_COLOR_SET_ID = 151353307481243663; + if (set_id.get() == GREAT_MINDS_SET_ID || set_id.get() == GREAT_MINDS_COLOR_SET_ID) { + return promise.set_value("TelegramGreatMinds"); + } + + const StickerSet *sticker_set = get_sticker_set(set_id); + if (sticker_set == nullptr) { + return promise.set_error(Status::Error(400, "Sticker set not found")); + } + if (!sticker_set->short_name_.empty()) { + return promise.set_value(string(sticker_set->short_name_)); + } + auto &queries = sticker_set_name_load_queries_[set_id]; + queries.push_back(std::move(promise)); + if (queries.size() == 1u) { + td_->create_handler()->send(set_id, get_input_sticker_set(sticker_set)); + } +} + StickerSetId StickersManager::search_sticker_set(const string &short_name_to_search, Promise &&promise) { string short_name = clean_username(short_name_to_search); const StickerSet *sticker_set = get_sticker_set(short_name_to_sticker_set_id_.get(short_name)); @@ -5362,8 +5443,7 @@ void StickersManager::update_sticker_set(StickerSet *sticker_set, const char *so void StickersManager::load_sticker_sets(vector &&sticker_set_ids, Promise &&promise) { if (sticker_set_ids.empty()) { - promise.set_value(Unit()); - return; + return promise.set_value(Unit()); } CHECK(current_sticker_set_load_request_ < std::numeric_limits::max()); @@ -5837,7 +5917,11 @@ void StickersManager::try_update_premium_gift_messages() { } } -void StickersManager::register_premium_gift(int32 months, MessageFullId message_full_id, const char *source) { +void StickersManager::register_premium_gift(int32 months, int64 star_count, MessageFullId message_full_id, + const char *source) { + if (months == 0) { + months = StarManager::get_months_by_star_count(star_count); + } if (td_->auth_manager_->is_bot() || months == 0) { return; } @@ -5857,7 +5941,11 @@ void StickersManager::register_premium_gift(int32 months, MessageFullId message_ LOG_CHECK(is_inserted) << source << ' ' << months << ' ' << message_full_id; } -void StickersManager::unregister_premium_gift(int32 months, MessageFullId message_full_id, const char *source) { +void StickersManager::unregister_premium_gift(int32 months, int64 star_count, MessageFullId message_full_id, + const char *source) { + if (months == 0) { + months = StarManager::get_months_by_star_count(star_count); + } if (td_->auth_manager_->is_bot() || months == 0) { return; } @@ -7620,20 +7708,20 @@ void StickersManager::send_get_attached_stickers_query(FileId file_id, Promiseis_document() && !full_remote_location->is_photo()) || + full_remote_location->is_web()) { return promise.set_value(Unit()); } tl_object_ptr input_stickered_media; string file_reference; - if (file_view.main_remote_location().is_photo()) { - auto input_photo = file_view.main_remote_location().as_input_photo(); + if (full_remote_location->is_photo()) { + auto input_photo = full_remote_location->as_input_photo(); file_reference = input_photo->file_reference_.as_slice().str(); input_stickered_media = make_tl_object(std::move(input_photo)); } else { - auto input_document = file_view.main_remote_location().as_input_document(); + auto input_document = full_remote_location->as_input_document(); file_reference = input_document->file_reference_.as_slice().str(); input_stickered_media = make_tl_object(std::move(input_document)); } @@ -7870,18 +7958,19 @@ Result> StickersManager::prepare_input_file( return Status::Error(400, "Can't use encrypted file"); } - if (file_view.has_remote_location() && file_view.main_remote_location().is_web()) { + const auto *main_remote_location = file_view.get_main_remote_location(); + if (main_remote_location != nullptr && main_remote_location->is_web()) { return Status::Error(400, "Can't use web file to create a sticker"); } bool is_url = false; bool is_local = false; - if (file_view.has_remote_location()) { - CHECK(file_view.main_remote_location().is_document()); + if (main_remote_location != nullptr) { + CHECK(main_remote_location->is_document()); } else { if (file_view.has_url()) { is_url = true; } else { - if (file_view.has_local_location() && + if (file_view.has_full_local_location() && file_view.expected_size() > get_max_sticker_file_size(sticker_format, sticker_type, for_thumbnail)) { return Status::Error(400, "File is too big"); } @@ -7899,47 +7988,51 @@ Result> StickersManager::prepare_input_file( return std::make_tuple(file_id, is_url, is_local); } -FileId StickersManager::upload_sticker_file(UserId user_id, StickerFormat sticker_format, - const td_api::object_ptr &input_file, - Promise &&promise) { +void StickersManager::upload_sticker_file(UserId user_id, StickerFormat sticker_format, + const td_api::object_ptr &input_file, + Promise> &&promise) { bool is_bot = td_->auth_manager_->is_bot(); if (!is_bot) { user_id = td_->user_manager_->get_my_id(); } - auto r_input_user = td_->user_manager_->get_input_user(user_id); - if (r_input_user.is_error()) { - promise.set_error(r_input_user.move_as_error()); - return FileId(); - } + TRY_STATUS_PROMISE(promise, td_->user_manager_->get_input_user(user_id)); // StickerType::Regular has less restrictions - auto r_file_id = prepare_input_file(input_file, sticker_format, StickerType::Regular, false); - if (r_file_id.is_error()) { - promise.set_error(r_file_id.move_as_error()); - return FileId(); - } - auto file_id = std::get<0>(r_file_id.ok()); - auto is_url = std::get<1>(r_file_id.ok()); - auto is_local = std::get<2>(r_file_id.ok()); + TRY_RESULT_PROMISE(promise, file_info, prepare_input_file(input_file, sticker_format, StickerType::Regular, false)); + auto file_id = std::get<0>(file_info); + auto is_url = std::get<1>(file_info); + auto is_local = std::get<2>(file_info); + + auto upload_promise = PromiseCreator::lambda( + [actor_id = actor_id(this), file_id, promise = std::move(promise)](Result &&result) mutable { + if (result.is_error()) { + return promise.set_error(result.move_as_error()); + } + send_closure(actor_id, &StickersManager::finish_upload_sticker_file, file_id, std::move(promise)); + }); if (is_url) { - do_upload_sticker_file(user_id, file_id, nullptr, std::move(promise)); + do_upload_sticker_file(user_id, file_id, nullptr, std::move(upload_promise)); } else if (is_local) { - upload_sticker_file(user_id, file_id, std::move(promise)); + upload_sticker_file(user_id, file_id, std::move(upload_promise)); } else { - promise.set_value(Unit()); + upload_promise.set_value(Unit()); } +} - return file_id; +void StickersManager::finish_upload_sticker_file(FileId file_id, Promise> &&promise) { + TRY_STATUS_PROMISE(promise, G()->close_status()); + promise.set_value(td_->file_manager_->get_file_object(file_id)); } -tl_object_ptr StickersManager::get_input_sticker(const td_api::inputSticker *sticker, - FileId file_id) const { +telegram_api::object_ptr StickersManager::get_input_sticker( + const td_api::inputSticker *sticker, FileId file_id) const { CHECK(sticker != nullptr); FileView file_view = td_->file_manager_->get_file_view(file_id); - CHECK(file_view.has_remote_location()); - auto input_document = file_view.main_remote_location().as_input_document(); + const auto *main_remote_location = file_view.get_main_remote_location(); + CHECK(main_remote_location != nullptr); + auto input_document = main_remote_location->as_input_document(); int32 flags = 0; @@ -8039,13 +8132,10 @@ void StickersManager::create_new_sticker_set(UserId user_id, string title, strin vector local_file_ids; vector url_file_ids; for (auto &sticker : stickers) { - auto r_file_id = prepare_input_sticker(sticker.get(), sticker_type); - if (r_file_id.is_error()) { - return promise.set_error(r_file_id.move_as_error()); - } - auto file_id = std::get<0>(r_file_id.ok()); - auto is_url = std::get<1>(r_file_id.ok()); - auto is_local = std::get<2>(r_file_id.ok()); + TRY_RESULT_PROMISE(promise, file_info, prepare_input_sticker(sticker.get(), sticker_type)); + auto file_id = std::get<0>(file_info); + auto is_url = std::get<1>(file_info); + auto is_local = std::get<2>(file_info); file_ids.push_back(file_id); if (is_url) { @@ -8107,7 +8197,8 @@ void StickersManager::upload_sticker_file(UserId user_id, FileId file_id, Promis td_->file_manager_->upload(upload_file_id, upload_sticker_file_callback_, 2, 0); } -void StickersManager::on_upload_sticker_file(FileId file_id, tl_object_ptr input_file) { +void StickersManager::on_upload_sticker_file(FileId file_id, + telegram_api::object_ptr input_file) { LOG(INFO) << "Sticker file " << file_id << " has been uploaded"; auto it = being_uploaded_files_.find(file_id); @@ -8202,8 +8293,9 @@ void StickersManager::on_uploaded_sticker_file(FileId file_id, bool is_url, // uploaded by a URL WEBP sticker // re-register as document FileView sticker_file_view = td_->file_manager_->get_file_view(parsed_document.file_id); - CHECK(sticker_file_view.has_remote_location()); - auto remote_location = sticker_file_view.main_remote_location(); + const auto *full_remote_location = sticker_file_view.get_full_remote_location(); + CHECK(full_remote_location != nullptr); + auto remote_location = *full_remote_location; CHECK(remote_location.is_common()); remote_location.file_type_ = FileType::Document; auto document_file_id = @@ -8338,13 +8430,10 @@ void StickersManager::do_add_sticker_to_set(UserId user_id, string short_name, sticker->format_ = get_sticker_format_object(format); } } - auto r_file_id = prepare_input_sticker(sticker.get(), sticker_set->sticker_type_); - if (r_file_id.is_error()) { - return promise.set_error(r_file_id.move_as_error()); - } - auto file_id = std::get<0>(r_file_id.ok()); - auto is_url = std::get<1>(r_file_id.ok()); - auto is_local = std::get<2>(r_file_id.ok()); + TRY_RESULT_PROMISE(promise, file_info, prepare_input_sticker(sticker.get(), sticker_set->sticker_type_)); + auto file_id = std::get<0>(file_info); + auto is_url = std::get<1>(file_info); + auto is_local = std::get<2>(file_info); auto pending_add_sticker_to_set = make_unique(); pending_add_sticker_to_set->short_name_ = short_name; @@ -8445,13 +8534,10 @@ void StickersManager::do_set_sticker_set_thumbnail(UserId user_id, string short_ format = guess_sticker_set_format(sticker_set); } - auto r_file_id = prepare_input_file(thumbnail, format, sticker_set->sticker_type_, true); - if (r_file_id.is_error()) { - return promise.set_error(r_file_id.move_as_error()); - } - auto file_id = std::get<0>(r_file_id.ok()); - auto is_url = std::get<1>(r_file_id.ok()); - auto is_local = std::get<2>(r_file_id.ok()); + TRY_RESULT_PROMISE(promise, file_info, prepare_input_file(thumbnail, format, sticker_set->sticker_type_, true)); + auto file_id = std::get<0>(file_info); + auto is_url = std::get<1>(file_info); + auto is_local = std::get<2>(file_info); if (!file_id.is_valid()) { td_->create_handler(std::move(promise)) @@ -8501,10 +8587,11 @@ void StickersManager::on_sticker_set_thumbnail_uploaded(int64 random_id, Result< } FileView file_view = td_->file_manager_->get_file_view(pending_set_sticker_set_thumbnail->file_id_); - CHECK(file_view.has_remote_location()); + const auto *main_remote_location = file_view.get_main_remote_location(); + CHECK(main_remote_location != nullptr); td_->create_handler(std::move(pending_set_sticker_set_thumbnail->promise_)) - ->send(pending_set_sticker_set_thumbnail->short_name_, file_view.main_remote_location().as_input_document()); + ->send(pending_set_sticker_set_thumbnail->short_name_, main_remote_location->as_input_document()); } void StickersManager::set_custom_emoji_sticker_set_thumbnail(string short_name, CustomEmojiId custom_emoji_id, @@ -8576,8 +8663,8 @@ Result StickersManager::get_sticker_input TRY_RESULT(file_id, td_->file_manager_->get_input_file_id(FileType::Sticker, sticker, DialogId(), false, false)); auto file_view = td_->file_manager_->get_file_view(file_id); - if (!file_view.has_remote_location() || !file_view.main_remote_location().is_document() || - file_view.main_remote_location().is_web()) { + const auto *main_remote_location = file_view.get_main_remote_location(); + if (main_remote_location == nullptr || !main_remote_location->is_document() || main_remote_location->is_web()) { return Status::Error(400, "Wrong sticker file specified"); } @@ -8591,7 +8678,7 @@ Result StickersManager::get_sticker_input result.sticker_set_short_name_ = to_string(s->set_id_.get()); } } - result.input_document_ = file_view.main_remote_location().as_input_document(); + result.input_document_ = main_remote_location->as_input_document(); return std::move(result); } @@ -8713,15 +8800,13 @@ vector StickersManager::get_attached_sticker_file_ids(const vectorfile_manager_->get_file_view(file_id); CHECK(!file_view.empty()); - if (!file_view.has_remote_location()) { - LOG(ERROR) << "Sticker " << file_id << " has no remote location"; - continue; - } - if (file_view.remote_location().is_web()) { + const auto *full_remote_location = file_view.get_full_remote_location(); + CHECK(full_remote_location != nullptr); + if (full_remote_location->is_web()) { LOG(ERROR) << "Sticker " << file_id << " is web"; continue; } - if (!file_view.remote_location().is_document()) { + if (!full_remote_location->is_document()) { LOG(ERROR) << "Sticker " << file_id << " is encrypted"; continue; } @@ -9018,13 +9103,13 @@ int64 StickersManager::get_recent_stickers_hash(const vector &sticker_id auto sticker = get_sticker(sticker_id); LOG_CHECK(sticker != nullptr) << sticker_id << ' ' << stickers_.calc_size() << ' ' << source; auto file_view = td_->file_manager_->get_file_view(sticker_id); - CHECK(file_view.has_remote_location()); - if (!file_view.remote_location().is_document()) { - LOG(ERROR) << "Recent sticker remote location is not document: " << file_view.remote_location() << " from " - << source; + const auto *full_remote_location = file_view.get_full_remote_location(); + CHECK(full_remote_location != nullptr); + if (!full_remote_location->is_document()) { + LOG(ERROR) << "Recent sticker remote location is not document: " << *full_remote_location << " from " << source; continue; } - numbers.push_back(file_view.remote_location().get_id()); + numbers.push_back(full_remote_location->get_id()); } return get_vector_hash(numbers); } @@ -9056,11 +9141,12 @@ void StickersManager::send_save_recent_sticker_query(bool is_attached, FileId st // TODO invokeAfter and log event auto file_view = td_->file_manager_->get_file_view(sticker_id); - CHECK(file_view.has_remote_location()); - CHECK(file_view.remote_location().is_document()); - CHECK(!file_view.remote_location().is_web()); + const auto *full_remote_location = file_view.get_full_remote_location(); + CHECK(full_remote_location != nullptr); + CHECK(full_remote_location->is_document()); + CHECK(!full_remote_location->is_web()); td_->create_handler(std::move(promise)) - ->send(is_attached, sticker_id, file_view.remote_location().as_input_document(), unsave); + ->send(is_attached, sticker_id, full_remote_location->as_input_document(), unsave); } void StickersManager::add_recent_sticker_by_id(bool is_attached, FileId sticker_id) { @@ -9113,13 +9199,14 @@ void StickersManager::add_recent_sticker_impl(bool is_attached, FileId sticker_i } auto file_view = td_->file_manager_->get_file_view(sticker_id); - if (!file_view.has_remote_location()) { + const auto *full_remote_location = file_view.get_full_remote_location(); + if (full_remote_location == nullptr) { return promise.set_error(Status::Error(400, "Can save only sent stickers")); } - if (file_view.remote_location().is_web()) { + if (full_remote_location->is_web()) { return promise.set_error(Status::Error(400, "Can't save web stickers")); } - if (!file_view.remote_location().is_document()) { + if (!full_remote_location->is_document()) { return promise.set_error(Status::Error(400, "Can't save encrypted stickers")); } @@ -9442,11 +9529,12 @@ void StickersManager::send_fave_sticker_query(FileId sticker_id, bool unsave, Pr // TODO invokeAfter and log event auto file_view = td_->file_manager_->get_file_view(sticker_id); - CHECK(file_view.has_remote_location()); - CHECK(file_view.remote_location().is_document()); - CHECK(!file_view.remote_location().is_web()); + const auto *full_remote_location = file_view.get_full_remote_location(); + CHECK(full_remote_location != nullptr); + CHECK(full_remote_location->is_document()); + CHECK(!full_remote_location->is_web()); td_->create_handler(std::move(promise)) - ->send(sticker_id, file_view.remote_location().as_input_document(), unsave); + ->send(sticker_id, full_remote_location->as_input_document(), unsave); } void StickersManager::add_favorite_sticker_by_id(FileId sticker_id) { @@ -9496,13 +9584,14 @@ void StickersManager::add_favorite_sticker_impl(FileId sticker_id, bool add_on_s } auto file_view = td_->file_manager_->get_file_view(sticker_id); - if (!file_view.has_remote_location()) { + const auto *full_remote_location = file_view.get_full_remote_location(); + if (full_remote_location == nullptr) { return promise.set_error(Status::Error(400, "Can add to favorites only sent stickers")); } - if (file_view.remote_location().is_web()) { + if (full_remote_location->is_web()) { return promise.set_error(Status::Error(400, "Can't add to favorites web stickers")); } - if (!file_view.remote_location().is_document()) { + if (!full_remote_location->is_document()) { return promise.set_error(Status::Error(400, "Can't add to favorites encrypted stickers")); } @@ -9600,15 +9689,16 @@ vector StickersManager::get_sticker_emojis(const tl_object_ptrfile_manager_->get_file_view(file_id); - if (!file_view.has_remote_location()) { + const auto *full_remote_location = file_view.get_full_remote_location(); + if (full_remote_location == nullptr) { promise.set_value(Unit()); return {}; } - if (!file_view.remote_location().is_document()) { + if (!full_remote_location->is_document()) { promise.set_value(Unit()); return {}; } - if (file_view.remote_location().is_web()) { + if (full_remote_location->is_web()) { promise.set_value(Unit()); return {}; } diff --git a/lib/tgchat/ext/td/td/telegram/StickersManager.h b/lib/tgchat/ext/td/td/telegram/StickersManager.h index e925668a..16206261 100644 --- a/lib/tgchat/ext/td/td/telegram/StickersManager.h +++ b/lib/tgchat/ext/td/td/telegram/StickersManager.h @@ -100,7 +100,7 @@ class StickersManager final : public Actor { const vector &sticker_set_ids, size_t covers_limit) const; - td_api::object_ptr get_premium_gift_sticker_object(int32 month_count); + td_api::object_ptr get_premium_gift_sticker_object(int32 month_count, int64 star_count); td_api::object_ptr get_animated_emoji_object(const string &emoji, CustomEmojiId custom_emoji_id); @@ -109,9 +109,9 @@ class StickersManager final : public Actor { void load_premium_gift_sticker_set(Promise &&promise); - void register_premium_gift(int32 months, MessageFullId message_full_id, const char *source); + void register_premium_gift(int32 months, int64 star_count, MessageFullId message_full_id, const char *source); - void unregister_premium_gift(int32 months, MessageFullId message_full_id, const char *source); + void unregister_premium_gift(int32 months, int64 star_count, MessageFullId message_full_id, const char *source); void register_dice(const string &emoji, int32 value, MessageFullId message_full_id, QuickReplyMessageFullId quick_reply_message_full_id, const char *source); @@ -194,6 +194,8 @@ class StickersManager final : public Actor { StickerSetId get_sticker_set(StickerSetId set_id, Promise &&promise); + void get_sticker_set_name(StickerSetId set_id, Promise &&promise); + StickerSetId search_sticker_set(const string &short_name_to_search, Promise &&promise); std::pair> search_installed_sticker_sets(StickerType sticker_type, const string &query, @@ -224,6 +226,9 @@ class StickersManager final : public Actor { StickerSetId on_get_sticker_set_covered(tl_object_ptr &&set_ptr, bool is_changed, const char *source); + void on_get_sticker_set_name(StickerSetId sticker_set_id, + telegram_api::object_ptr &&set_ptr); + void on_get_special_sticker_set(const SpecialStickerSetType &type, StickerSetId sticker_set_id); void on_load_special_sticker_set(const SpecialStickerSetType &type, Status result); @@ -282,8 +287,9 @@ class StickersManager final : public Actor { void move_sticker_set_to_top_by_custom_emoji_ids(const vector &custom_emoji_ids); - FileId upload_sticker_file(UserId user_id, StickerFormat sticker_format, - const td_api::object_ptr &input_file, Promise &&promise); + void upload_sticker_file(UserId user_id, StickerFormat sticker_format, + const td_api::object_ptr &input_file, + Promise> &&promise); void get_suggested_sticker_set_name(string title, Promise &&promise); @@ -806,12 +812,14 @@ class StickersManager final : public Actor { Result> prepare_input_sticker(td_api::inputSticker *sticker, StickerType sticker_type); - tl_object_ptr get_input_sticker(const td_api::inputSticker *sticker, - FileId file_id) const; + void finish_upload_sticker_file(FileId file_id, Promise> &&promise); + + telegram_api::object_ptr get_input_sticker(const td_api::inputSticker *sticker, + FileId file_id) const; void upload_sticker_file(UserId user_id, FileId file_id, Promise &&promise); - void on_upload_sticker_file(FileId file_id, tl_object_ptr input_file); + void on_upload_sticker_file(FileId file_id, telegram_api::object_ptr input_file); void on_upload_sticker_file_error(FileId file_id, Status status); @@ -1000,6 +1008,7 @@ class StickersManager final : public Actor { WaitFreeHashMap, StickerSetIdHash> sticker_sets_; // sticker_set_id -> StickerSet WaitFreeHashMap short_name_to_sticker_set_id_; + FlatHashMap>, StickerSetIdHash> sticker_set_name_load_queries_; vector installed_sticker_set_ids_[MAX_STICKER_TYPE]; vector featured_sticker_set_ids_[MAX_STICKER_TYPE]; diff --git a/lib/tgchat/ext/td/td/telegram/StoryManager.cpp b/lib/tgchat/ext/td/td/telegram/StoryManager.cpp index d1bafb0f..e88f11f7 100644 --- a/lib/tgchat/ext/td/td/telegram/StoryManager.cpp +++ b/lib/tgchat/ext/td/td/telegram/StoryManager.cpp @@ -64,43 +64,6 @@ namespace td { -static td_api::object_ptr get_can_send_story_result_object(const Status &error, - bool force = false) { - CHECK(error.is_error()); - if (error.message() == "PREMIUM_ACCOUNT_REQUIRED") { - return td_api::make_object(); - } - if (error.message() == "BOOSTS_REQUIRED") { - return td_api::make_object(); - } - if (error.message() == "STORIES_TOO_MUCH") { - return td_api::make_object(); - } - if (begins_with(error.message(), "STORY_SEND_FLOOD_WEEKLY_")) { - auto r_next_date = to_integer_safe(error.message().substr(Slice("STORY_SEND_FLOOD_WEEKLY_").size())); - if (r_next_date.is_ok() && r_next_date.ok() > 0) { - auto retry_after = r_next_date.ok() - G()->unix_time(); - if (retry_after > 0 || force) { - return td_api::make_object(max(retry_after, 0)); - } else { - return td_api::make_object(); - } - } - } - if (begins_with(error.message(), "STORY_SEND_FLOOD_MONTHLY_")) { - auto r_next_date = to_integer_safe(error.message().substr(Slice("STORY_SEND_FLOOD_MONTHLY_").size())); - if (r_next_date.is_ok() && r_next_date.ok() > 0) { - auto retry_after = r_next_date.ok() - G()->unix_time(); - if (retry_after > 0 || force) { - return td_api::make_object(max(retry_after, 0)); - } else { - return td_api::make_object(); - } - } - } - return nullptr; -} - class GetAllStoriesQuery final : public Td::ResultHandler { Promise> promise_; @@ -1091,7 +1054,7 @@ class CanSendStoryQuery final : public Td::ResultHandler { } void on_error(Status status) final { - auto result = get_can_send_story_result_object(status); + auto result = StoryManager::get_can_send_story_result_object(status); if (result != nullptr) { return promise_.set_value(std::move(result)); } @@ -3581,6 +3544,43 @@ td_api::object_ptr StoryManager::get_chat_active_stor story_list_id.get_story_list_object(), order, max_read_story_id.get(), std::move(stories)); } +td_api::object_ptr StoryManager::get_can_send_story_result_object(const Status &error, + bool force) { + CHECK(error.is_error()); + if (error.message() == "PREMIUM_ACCOUNT_REQUIRED") { + return td_api::make_object(); + } + if (error.message() == "BOOSTS_REQUIRED") { + return td_api::make_object(); + } + if (error.message() == "STORIES_TOO_MUCH") { + return td_api::make_object(); + } + if (begins_with(error.message(), "STORY_SEND_FLOOD_WEEKLY_")) { + auto r_next_date = to_integer_safe(error.message().substr(Slice("STORY_SEND_FLOOD_WEEKLY_").size())); + if (r_next_date.is_ok() && r_next_date.ok() > 0) { + auto retry_after = r_next_date.ok() - G()->unix_time(); + if (retry_after > 0 || force) { + return td_api::make_object(max(retry_after, 0)); + } else { + return td_api::make_object(); + } + } + } + if (begins_with(error.message(), "STORY_SEND_FLOOD_MONTHLY_")) { + auto r_next_date = to_integer_safe(error.message().substr(Slice("STORY_SEND_FLOOD_MONTHLY_").size())); + if (r_next_date.is_ok() && r_next_date.ok() > 0) { + auto retry_after = r_next_date.ok() - G()->unix_time(); + if (retry_after > 0 || force) { + return td_api::make_object(max(retry_after, 0)); + } else { + return td_api::make_object(); + } + } + } + return nullptr; +} + vector StoryManager::get_story_file_ids(const Story *story) const { if (story == nullptr || story->content_ == nullptr) { return {}; @@ -5301,8 +5301,9 @@ void StoryManager::on_upload_story(FileId file_id, telegram_api::object_ptrfile_manager_->get_file_view(file_id); CHECK(!file_view.is_encrypted()); - if (input_file == nullptr && file_view.has_remote_location()) { - if (file_view.main_remote_location().is_web()) { + const auto *main_remote_location = file_view.get_main_remote_location(); + if (input_file == nullptr && main_remote_location != nullptr) { + if (main_remote_location->is_web()) { delete_pending_story(file_id, std::move(pending_story), Status::Error(400, "Can't use web photo as a story")); return; } @@ -5313,7 +5314,7 @@ void StoryManager::on_upload_story(FileId file_id, telegram_api::object_ptrwas_reuploaded_ = true; // delete file reference and forcely reupload the file - td_->file_manager_->delete_file_reference(file_id, file_view.main_remote_location().get_file_reference()); + td_->file_manager_->delete_file_reference(file_id, main_remote_location->get_file_reference()); do_send_story(std::move(pending_story), {-1}); return; } diff --git a/lib/tgchat/ext/td/td/telegram/StoryManager.h b/lib/tgchat/ext/td/td/telegram/StoryManager.h index 73eebb77..a2876005 100644 --- a/lib/tgchat/ext/td/td/telegram/StoryManager.h +++ b/lib/tgchat/ext/td/td/telegram/StoryManager.h @@ -357,6 +357,9 @@ class StoryManager final : public Actor { td_api::object_ptr get_stories_object(int32 total_count, const vector &story_full_ids, const vector &pinned_story_ids) const; + static td_api::object_ptr get_can_send_story_result_object(const Status &error, + bool force = false); + FileSourceId get_story_file_source_id(StoryFullId story_full_id); telegram_api::object_ptr get_input_media(StoryFullId story_full_id) const; diff --git a/lib/tgchat/ext/td/td/telegram/Td.cpp b/lib/tgchat/ext/td/td/telegram/Td.cpp index ffbe4986..b3b99311 100644 --- a/lib/tgchat/ext/td/td/telegram/Td.cpp +++ b/lib/tgchat/ext/td/td/telegram/Td.cpp @@ -6,193 +6,107 @@ // #include "td/telegram/Td.h" -#include "td/telegram/AccentColorId.h" #include "td/telegram/AccountManager.h" +#include "td/telegram/AlarmManager.h" #include "td/telegram/AnimationsManager.h" #include "td/telegram/Application.h" #include "td/telegram/AttachMenuManager.h" #include "td/telegram/AudiosManager.h" #include "td/telegram/AuthManager.h" -#include "td/telegram/AutoDownloadSettings.h" #include "td/telegram/AutosaveManager.h" -#include "td/telegram/BackgroundId.h" #include "td/telegram/BackgroundManager.h" -#include "td/telegram/BackgroundType.h" -#include "td/telegram/Birthdate.h" #include "td/telegram/BoostManager.h" -#include "td/telegram/BotCommand.h" #include "td/telegram/BotInfoManager.h" -#include "td/telegram/BotMenuButton.h" -#include "td/telegram/BusinessAwayMessage.h" -#include "td/telegram/BusinessConnectionId.h" #include "td/telegram/BusinessConnectionManager.h" -#include "td/telegram/BusinessGreetingMessage.h" -#include "td/telegram/BusinessIntro.h" #include "td/telegram/BusinessManager.h" -#include "td/telegram/BusinessWorkHours.h" #include "td/telegram/CallbackQueriesManager.h" -#include "td/telegram/CallId.h" #include "td/telegram/CallManager.h" -#include "td/telegram/ChannelId.h" #include "td/telegram/ChannelRecommendationManager.h" -#include "td/telegram/ChannelType.h" -#include "td/telegram/ChatId.h" #include "td/telegram/ChatManager.h" #include "td/telegram/CommonDialogManager.h" #include "td/telegram/ConfigManager.h" #include "td/telegram/ConnectionStateManager.h" #include "td/telegram/CountryInfoManager.h" -#include "td/telegram/CustomEmojiId.h" #include "td/telegram/DeviceTokenManager.h" -#include "td/telegram/DialogAction.h" #include "td/telegram/DialogActionManager.h" -#include "td/telegram/DialogBoostLinkInfo.h" -#include "td/telegram/DialogEventLog.h" -#include "td/telegram/DialogFilterId.h" #include "td/telegram/DialogFilterManager.h" -#include "td/telegram/DialogId.h" #include "td/telegram/DialogInviteLinkManager.h" -#include "td/telegram/DialogListId.h" -#include "td/telegram/DialogLocation.h" #include "td/telegram/DialogManager.h" -#include "td/telegram/DialogParticipant.h" -#include "td/telegram/DialogParticipantFilter.h" #include "td/telegram/DialogParticipantManager.h" #include "td/telegram/DocumentsManager.h" #include "td/telegram/DownloadManager.h" #include "td/telegram/DownloadManagerCallback.h" -#include "td/telegram/EmailVerification.h" -#include "td/telegram/EmojiGroupType.h" -#include "td/telegram/EmojiStatus.h" #include "td/telegram/FileReferenceManager.h" -#include "td/telegram/files/FileGcParameters.h" -#include "td/telegram/files/FileId.h" #include "td/telegram/files/FileManager.h" #include "td/telegram/files/FileSourceId.h" -#include "td/telegram/files/FileStats.h" -#include "td/telegram/files/FileType.h" #include "td/telegram/ForumTopicManager.h" #include "td/telegram/GameManager.h" #include "td/telegram/Global.h" -#include "td/telegram/GlobalPrivacySettings.h" -#include "td/telegram/GroupCallId.h" #include "td/telegram/GroupCallManager.h" #include "td/telegram/HashtagHints.h" #include "td/telegram/InlineMessageManager.h" #include "td/telegram/InlineQueriesManager.h" -#include "td/telegram/JsonValue.h" #include "td/telegram/LanguagePackManager.h" #include "td/telegram/LinkManager.h" -#include "td/telegram/Location.h" -#include "td/telegram/MessageCopyOptions.h" -#include "td/telegram/MessageEffectId.h" -#include "td/telegram/MessageEntity.h" -#include "td/telegram/MessageFullId.h" -#include "td/telegram/MessageId.h" #include "td/telegram/MessageImportManager.h" -#include "td/telegram/MessageLinkInfo.h" -#include "td/telegram/MessageReaction.h" -#include "td/telegram/MessageSearchFilter.h" -#include "td/telegram/MessageSender.h" #include "td/telegram/MessagesManager.h" -#include "td/telegram/MessageSource.h" -#include "td/telegram/MessageThreadInfo.h" -#include "td/telegram/MessageTtl.h" #include "td/telegram/misc.h" #include "td/telegram/net/ConnectionCreator.h" #include "td/telegram/net/MtprotoHeader.h" #include "td/telegram/net/NetQuery.h" -#include "td/telegram/net/NetQueryDelayer.h" #include "td/telegram/net/NetQueryDispatcher.h" #include "td/telegram/net/NetStatsManager.h" -#include "td/telegram/net/NetType.h" #include "td/telegram/net/Proxy.h" #include "td/telegram/net/TempAuthKeyWatchdog.h" -#include "td/telegram/NotificationGroupId.h" -#include "td/telegram/NotificationId.h" #include "td/telegram/NotificationManager.h" -#include "td/telegram/NotificationObjectId.h" #include "td/telegram/NotificationSettingsManager.h" -#include "td/telegram/NotificationSettingsScope.h" #include "td/telegram/OnlineManager.h" #include "td/telegram/OptionManager.h" #include "td/telegram/PasswordManager.h" -#include "td/telegram/Payments.h" #include "td/telegram/PeopleNearbyManager.h" #include "td/telegram/PhoneNumberManager.h" #include "td/telegram/PhotoSizeSource.h" #include "td/telegram/PollManager.h" -#include "td/telegram/Premium.h" #include "td/telegram/PrivacyManager.h" #include "td/telegram/PromoDataManager.h" -#include "td/telegram/PublicDialogType.h" #include "td/telegram/QuickReplyManager.h" #include "td/telegram/ReactionManager.h" -#include "td/telegram/ReactionNotificationSettings.h" -#include "td/telegram/ReactionType.h" -#include "td/telegram/ReportReason.h" #include "td/telegram/RequestActor.h" +#include "td/telegram/Requests.h" #include "td/telegram/SavedMessagesManager.h" -#include "td/telegram/SavedMessagesTopicId.h" -#include "td/telegram/ScopeNotificationSettings.h" -#include "td/telegram/SecretChatId.h" #include "td/telegram/SecretChatsManager.h" #include "td/telegram/SecureManager.h" -#include "td/telegram/SecureValue.h" -#include "td/telegram/SentEmailCode.h" #include "td/telegram/SponsoredMessageManager.h" #include "td/telegram/StarManager.h" -#include "td/telegram/StarSubscriptionPricing.h" #include "td/telegram/StateManager.h" #include "td/telegram/StatisticsManager.h" -#include "td/telegram/StickerFormat.h" -#include "td/telegram/StickerListType.h" -#include "td/telegram/StickerSetId.h" #include "td/telegram/StickersManager.h" -#include "td/telegram/StickerType.h" #include "td/telegram/StorageManager.h" -#include "td/telegram/StoryId.h" -#include "td/telegram/StoryListId.h" #include "td/telegram/StoryManager.h" -#include "td/telegram/SuggestedAction.h" -#include "td/telegram/Support.h" #include "td/telegram/SynchronousRequests.h" -#include "td/telegram/td_api.hpp" #include "td/telegram/TdDb.h" -#include "td/telegram/telegram_api.h" #include "td/telegram/TermsOfServiceManager.h" #include "td/telegram/ThemeManager.h" #include "td/telegram/TimeZoneManager.h" -#include "td/telegram/TopDialogCategory.h" #include "td/telegram/TopDialogManager.h" #include "td/telegram/TranscriptionManager.h" #include "td/telegram/TranslationManager.h" #include "td/telegram/UpdatesManager.h" -#include "td/telegram/UserId.h" #include "td/telegram/UserManager.h" #include "td/telegram/Version.h" #include "td/telegram/VideoNotesManager.h" #include "td/telegram/VideosManager.h" #include "td/telegram/VoiceNotesManager.h" -#include "td/telegram/WebPageId.h" #include "td/telegram/WebPagesManager.h" #include "td/db/binlog/BinlogEvent.h" #include "td/actor/actor.h" -#include "td/utils/algorithm.h" -#include "td/utils/buffer.h" #include "td/utils/misc.h" #include "td/utils/port/uname.h" -#include "td/utils/Slice.h" -#include "td/utils/Status.h" #include "td/utils/Timer.h" -#include -#include -#include - namespace td { int VERBOSITY_NAME(td_init) = VERBOSITY_NAME(DEBUG) + 3; @@ -211,9299 +125,1297 @@ void Td::ResultHandler::send_query(NetQueryPtr query) { G()->net_query_dispatcher().dispatch(std::move(query)); } -class GetRecentMeUrlsQuery final : public Td::ResultHandler { - Promise> promise_; - - public: - explicit GetRecentMeUrlsQuery(Promise> &&promise) : promise_(std::move(promise)) { - } +Td::Td(unique_ptr callback, Options options) + : callback_(std::move(callback)), td_options_(std::move(options)) { + CHECK(callback_ != nullptr); + LOG(INFO) << "Create Td with layer " << MTPROTO_LAYER << ", database version " << current_db_version() + << " and version " << static_cast(Version::Next) - 1 << " on " + << Scheduler::instance()->sched_count() << " threads"; +} - void send(const string &referrer) { - send_query(G()->net_query_creator().create(telegram_api::help_getRecentMeUrls(referrer))); - } +Td::~Td() = default; - void on_result(BufferSlice packet) final { - auto result_ptr = fetch_result(packet); - if (result_ptr.is_error()) { - return on_error(result_ptr.move_as_error()); - } +bool Td::ignore_background_updates() const { + return can_ignore_background_updates_ && option_manager_->get_option_boolean("ignore_background_updates"); +} - auto urls_full = result_ptr.move_as_ok(); - td_->user_manager_->on_get_users(std::move(urls_full->users_), "GetRecentMeUrlsQuery"); - td_->chat_manager_->on_get_chats(std::move(urls_full->chats_), "GetRecentMeUrlsQuery"); - - auto urls = std::move(urls_full->urls_); - auto results = make_tl_object(); - results->urls_.reserve(urls.size()); - for (auto &url_ptr : urls) { - CHECK(url_ptr != nullptr); - tl_object_ptr result = make_tl_object(); - switch (url_ptr->get_id()) { - case telegram_api::recentMeUrlUser::ID: { - auto url = move_tl_object_as(url_ptr); - result->url_ = std::move(url->url_); - UserId user_id(url->user_id_); - if (!user_id.is_valid()) { - LOG(ERROR) << "Receive invalid " << user_id; - result = nullptr; - break; - } - result->type_ = - make_tl_object(td_->user_manager_->get_user_id_object(user_id, "tMeUrlTypeUser")); - break; - } - case telegram_api::recentMeUrlChat::ID: { - auto url = move_tl_object_as(url_ptr); - result->url_ = std::move(url->url_); - ChannelId channel_id(url->chat_id_); - if (!channel_id.is_valid()) { - LOG(ERROR) << "Receive invalid " << channel_id; - result = nullptr; - break; - } - result->type_ = make_tl_object( - td_->chat_manager_->get_supergroup_id_object(channel_id, "tMeUrlTypeSupergroup")); - break; - } - case telegram_api::recentMeUrlChatInvite::ID: { - auto url = move_tl_object_as(url_ptr); - result->url_ = std::move(url->url_); - td_->dialog_invite_link_manager_->on_get_dialog_invite_link_info(result->url_, std::move(url->chat_invite_), - Promise()); - auto info_object = td_->dialog_invite_link_manager_->get_chat_invite_link_info_object(result->url_); - if (info_object == nullptr) { - result = nullptr; - break; - } - result->type_ = make_tl_object(std::move(info_object)); - break; - } - case telegram_api::recentMeUrlStickerSet::ID: { - auto url = move_tl_object_as(url_ptr); - result->url_ = std::move(url->url_); - auto sticker_set_id = - td_->stickers_manager_->on_get_sticker_set_covered(std::move(url->set_), false, "recentMeUrlStickerSet"); - if (!sticker_set_id.is_valid()) { - LOG(ERROR) << "Receive invalid sticker set"; - result = nullptr; - break; - } - result->type_ = make_tl_object(sticker_set_id.get()); - break; - } - case telegram_api::recentMeUrlUnknown::ID: - // skip - result = nullptr; - break; - default: - UNREACHABLE(); - } - if (result != nullptr) { - results->urls_.push_back(std::move(result)); - } - } - promise_.set_value(std::move(results)); +bool Td::is_authentication_request(int32 id) { + switch (id) { + case td_api::setTdlibParameters::ID: + case td_api::getAuthorizationState::ID: + case td_api::setAuthenticationPhoneNumber::ID: + case td_api::sendAuthenticationFirebaseSms::ID: + case td_api::reportAuthenticationCodeMissing::ID: + case td_api::setAuthenticationEmailAddress::ID: + case td_api::resendAuthenticationCode::ID: + case td_api::checkAuthenticationEmailCode::ID: + case td_api::checkAuthenticationCode::ID: + case td_api::registerUser::ID: + case td_api::requestQrCodeAuthentication::ID: + case td_api::resetAuthenticationEmailAddress::ID: + case td_api::checkAuthenticationPassword::ID: + case td_api::requestAuthenticationPasswordRecovery::ID: + case td_api::checkAuthenticationPasswordRecoveryCode::ID: + case td_api::recoverAuthenticationPassword::ID: + case td_api::deleteAccount::ID: + case td_api::logOut::ID: + case td_api::close::ID: + case td_api::destroy::ID: + case td_api::checkAuthenticationBotToken::ID: + return true; + default: + return false; } +} - void on_error(Status status) final { - promise_.set_error(std::move(status)); +bool Td::is_preinitialization_request(int32 id) { + switch (id) { + case td_api::getCurrentState::ID: + case td_api::setAlarm::ID: + case td_api::testUseUpdate::ID: + case td_api::testCallEmpty::ID: + case td_api::testSquareInt::ID: + case td_api::testCallString::ID: + case td_api::testCallBytes::ID: + case td_api::testCallVectorInt::ID: + case td_api::testCallVectorIntObject::ID: + case td_api::testCallVectorString::ID: + case td_api::testCallVectorStringObject::ID: + case td_api::testProxy::ID: + return true; + default: + return false; } -}; - -class SendCustomRequestQuery final : public Td::ResultHandler { - Promise> promise_; +} - public: - explicit SendCustomRequestQuery(Promise> &&promise) - : promise_(std::move(promise)) { +bool Td::is_preauthentication_request(int32 id) { + switch (id) { + case td_api::getInternalLink::ID: + case td_api::getInternalLinkType::ID: + case td_api::getLocalizationTargetInfo::ID: + case td_api::getLanguagePackInfo::ID: + case td_api::getLanguagePackStrings::ID: + case td_api::synchronizeLanguagePack::ID: + case td_api::addCustomServerLanguagePack::ID: + case td_api::setCustomLanguagePack::ID: + case td_api::editCustomLanguagePackInfo::ID: + case td_api::setCustomLanguagePackString::ID: + case td_api::deleteLanguagePack::ID: + case td_api::processPushNotification::ID: + case td_api::getOption::ID: + case td_api::setOption::ID: + case td_api::getStorageStatistics::ID: + case td_api::getStorageStatisticsFast::ID: + case td_api::getDatabaseStatistics::ID: + case td_api::setNetworkType::ID: + case td_api::getNetworkStatistics::ID: + case td_api::addNetworkStatistics::ID: + case td_api::resetNetworkStatistics::ID: + case td_api::setApplicationVerificationToken::ID: + case td_api::getCountries::ID: + case td_api::getCountryCode::ID: + case td_api::getPhoneNumberInfo::ID: + case td_api::getDeepLinkInfo::ID: + case td_api::getApplicationConfig::ID: + case td_api::saveApplicationLogEvent::ID: + case td_api::addProxy::ID: + case td_api::editProxy::ID: + case td_api::enableProxy::ID: + case td_api::disableProxy::ID: + case td_api::removeProxy::ID: + case td_api::getProxies::ID: + case td_api::getProxyLink::ID: + case td_api::pingProxy::ID: + case td_api::testNetwork::ID: + return true; + default: + return false; } +} - void send(const string &method, const string ¶meters) { - send_query(G()->net_query_creator().create( - telegram_api::bots_sendCustomRequest(method, make_tl_object(parameters)))); +td_api::object_ptr Td::get_fake_authorization_state_object() const { + switch (state_) { + case State::WaitParameters: + return td_api::make_object(); + case State::Run: + UNREACHABLE(); + return nullptr; + case State::Close: + if (close_flag_ == 5) { + return td_api::make_object(); + } else { + return td_api::make_object(); + } + default: + UNREACHABLE(); + return nullptr; } +} - void on_result(BufferSlice packet) final { - auto result_ptr = fetch_result(packet); - if (result_ptr.is_error()) { - return on_error(result_ptr.move_as_error()); - } - - auto result = result_ptr.move_as_ok(); - promise_.set_value(td_api::make_object(result->data_)); - } +vector> Td::get_fake_current_state() const { + CHECK(state_ != State::Run); + vector> updates; + OptionManager::get_common_state(updates); + updates.push_back(td_api::make_object(get_fake_authorization_state_object())); + return updates; +} - void on_error(Status status) final { - promise_.set_error(std::move(status)); +void Td::request(uint64 id, tl_object_ptr function) { + if (id == 0) { + LOG(ERROR) << "Ignore request with ID == 0: " << to_string(function); + return; } -}; -class AnswerCustomQueryQuery final : public Td::ResultHandler { - Promise promise_; - - public: - explicit AnswerCustomQueryQuery(Promise &&promise) : promise_(std::move(promise)) { + if (function == nullptr) { + return callback_->on_error(id, make_error(400, "Request is empty")); } - void send(int64 custom_query_id, const string &data) { - send_query(G()->net_query_creator().create( - telegram_api::bots_answerWebhookJSONQuery(custom_query_id, make_tl_object(data)))); + VLOG(td_requests) << "Receive request " << id << ": " << to_string(function); + request_set_.emplace(id, function->get_id()); + if (SynchronousRequests::is_synchronous_request(function.get())) { + // send response synchronously + return send_result(id, static_request(std::move(function))); } - void on_result(BufferSlice packet) final { - auto result_ptr = fetch_result(packet); - if (result_ptr.is_error()) { - return on_error(result_ptr.move_as_error()); - } + run_request(id, std::move(function)); +} - bool result = result_ptr.ok(); - if (!result) { - LOG(INFO) << "Sending answer to a custom query has failed"; - } - promise_.set_value(Unit()); +void Td::run_request(uint64 id, td_api::object_ptr function) { + if (set_parameters_request_id_ > 0) { + pending_set_parameters_requests_.emplace_back(id, std::move(function)); + return; } - void on_error(Status status) final { - promise_.set_error(std::move(status)); + int32 function_id = function->get_id(); + if (state_ != State::Run) { + switch (function_id) { + case td_api::getAuthorizationState::ID: + // send response synchronously to prevent "Request aborted" + return send_result(id, get_fake_authorization_state_object()); + case td_api::getCurrentState::ID: + // send response synchronously to prevent "Request aborted" + return send_result(id, td_api::make_object(get_fake_current_state())); + case td_api::close::ID: + // need to send response before actual closing + send_closure(actor_id(this), &Td::send_result, id, td_api::make_object()); + send_closure(actor_id(this), &Td::close); + return; + default: + break; + } } -}; + switch (state_) { + case State::WaitParameters: { + switch (function_id) { + case td_api::setTdlibParameters::ID: { + auto r_parameters = get_parameters(move_tl_object_as(function)); + if (r_parameters.is_error()) { + return send_closure(actor_id(this), &Td::send_error, id, r_parameters.move_as_error()); + } + auto parameters = r_parameters.move_as_ok(); -class SetBotUpdatesStatusQuery final : public Td::ResultHandler { - public: - void send(int32 pending_update_count, const string &error_message) { - send_query( - G()->net_query_creator().create(telegram_api::help_setBotUpdatesStatus(pending_update_count, error_message))); - } + VLOG(td_init) << "Begin to open database"; + set_parameters_request_id_ = id; + can_ignore_background_updates_ = !parameters.second.use_chat_info_database_ && + !parameters.second.use_message_database_ && + !parameters.first.use_secret_chats_; - void on_result(BufferSlice packet) final { - auto result_ptr = fetch_result(packet); - if (result_ptr.is_error()) { - return on_error(result_ptr.move_as_error()); + auto promise = PromiseCreator::lambda( + [actor_id = actor_id(this), parameters = std::move(parameters.first), + parent = create_reference()](Result r_opened_database) mutable { + send_closure(actor_id, &Td::init, std::move(parameters), std::move(r_opened_database)); + }); + auto use_sqlite_pmc = parameters.second.use_message_database_ || parameters.second.use_chat_info_database_ || + parameters.second.use_file_database_; + return TdDb::open(use_sqlite_pmc ? G()->get_database_scheduler_id() : G()->get_slow_net_scheduler_id(), + std::move(parameters.second), std::move(promise)); + } + default: + if (is_preinitialization_request(function_id)) { + return requests_->run_request(id, std::move(function)); + } + if (is_preauthentication_request(function_id)) { + pending_preauthentication_requests_.emplace_back(id, std::move(function)); + return; + } + return send_error_impl( + id, make_error(400, "Initialization parameters are needed: call setTdlibParameters first")); + } + UNREACHABLE(); } - - bool result = result_ptr.ok(); - LOG_IF(WARNING, !result) << "Set bot updates status has failed"; + case State::Close: + return send_error_impl(id, make_error(destroy_flag_ ? 401 : 500, + destroy_flag_ ? CSlice("Unauthorized") : CSlice("Request aborted"))); + case State::Run: + if (!auth_manager_->is_authorized() && !is_preauthentication_request(function_id) && + !is_preinitialization_request(function_id) && !is_authentication_request(function_id)) { + return send_error_impl(id, make_error(401, "Unauthorized")); + } + return requests_->run_request(id, std::move(function)); + default: + UNREACHABLE(); } +} - void on_error(Status status) final { - if (!G()->is_expected_error(status)) { - LOG(WARNING) << "Receive error for SetBotUpdatesStatusQuery: " << status; - } - status.ignore(); - } -}; +td_api::object_ptr Td::static_request(td_api::object_ptr function) { + return SynchronousRequests::run_request(std::move(function)); +} -class TestNetworkQuery final : public Td::ResultHandler { - Promise promise_; +void Td::add_handler(uint64 id, std::shared_ptr handler) { + result_handlers_[id] = std::move(handler); +} - public: - explicit TestNetworkQuery(Promise &&promise) : promise_(std::move(promise)) { +std::shared_ptr Td::extract_handler(uint64 id) { + auto it = result_handlers_.find(id); + if (it == result_handlers_.end()) { + return nullptr; } + auto result = std::move(it->second); + result_handlers_.erase(it); + return result; +} - void send() { - send_query(G()->net_query_creator().create_unauth(telegram_api::help_getConfig())); +void Td::on_update(telegram_api::object_ptr updates, uint64 auth_key_id) { + if (close_flag_ > 1) { + return; } - void on_result(BufferSlice packet) final { - auto result_ptr = fetch_result(packet); - if (result_ptr.is_error()) { - return on_error(Status::Error(500, "Fetch failed")); + if (updates == nullptr) { + if (auth_manager_->is_bot()) { + G()->net_query_dispatcher().update_mtproto_header(); + } else { + // this could be a min-channel update + updates_manager_->schedule_get_difference("failed to fetch updates"); + } + } else { + updates_manager_->on_update_from_auth_key_id(auth_key_id); + updates_manager_->on_get_updates(std::move(updates), Promise()); + if (auth_manager_->is_bot() && auth_manager_->is_authorized()) { + online_manager_->set_is_bot_online(true); } - - LOG(DEBUG) << "TestNetwork OK: " << to_string(result_ptr.ok()); - promise_.set_value(Unit()); - } - - void on_error(Status status) final { - LOG(ERROR) << "Test query failed: " << status; - promise_.set_error(std::move(status)); - } -}; - -class GetMeRequest final : public RequestActor<> { - UserId user_id_; - - void do_run(Promise &&promise) final { - user_id_ = td_->user_manager_->get_me(std::move(promise)); - } - - void do_send_result() final { - send_result(td_->user_manager_->get_user_object(user_id_)); - } - - public: - GetMeRequest(ActorShared td, uint64 request_id) : RequestActor(std::move(td), request_id) { - } -}; - -class GetUserRequest final : public RequestActor<> { - UserId user_id_; - - void do_run(Promise &&promise) final { - td_->user_manager_->get_user(user_id_, get_tries(), std::move(promise)); - } - - void do_send_result() final { - send_result(td_->user_manager_->get_user_object(user_id_)); - } - - public: - GetUserRequest(ActorShared td, uint64 request_id, int64 user_id) - : RequestActor(std::move(td), request_id), user_id_(user_id) { - set_tries(3); - } -}; - -class GetUserFullInfoRequest final : public RequestActor<> { - UserId user_id_; - - void do_run(Promise &&promise) final { - td_->user_manager_->load_user_full(user_id_, get_tries() < 2, std::move(promise), "GetUserFullInfoRequest"); - } - - void do_send_result() final { - send_result(td_->user_manager_->get_user_full_info_object(user_id_)); - } - - public: - GetUserFullInfoRequest(ActorShared td, uint64 request_id, int64 user_id) - : RequestActor(std::move(td), request_id), user_id_(user_id) { } -}; - -class GetGroupRequest final : public RequestActor<> { - ChatId chat_id_; +} - void do_run(Promise &&promise) final { - td_->chat_manager_->get_chat(chat_id_, get_tries(), std::move(promise)); +void Td::on_result(NetQueryPtr query) { + query->debug("Td: received from DcManager"); + VLOG(net_query) << "Receive result of " << query; + if (close_flag_ > 1) { + return; } - void do_send_result() final { - send_result(td_->chat_manager_->get_basic_group_object(chat_id_)); + auto handler = extract_handler(query->id()); + if (handler != nullptr) { + CHECK(query->is_ready()); + if (query->is_ok()) { + handler->on_result(query->move_as_ok()); + } else { + handler->on_error(query->move_as_error()); + } + } else { + if (!query->is_ok() || query->ok_tl_constructor() != telegram_api::upload_file::ID) { + LOG(WARNING) << query << " is ignored: no handlers found"; + } + query->clear(); } +} - public: - GetGroupRequest(ActorShared td, uint64 request_id, int64 chat_id) - : RequestActor(std::move(td), request_id), chat_id_(chat_id) { - set_tries(3); +void Td::start_up() { + uint64 check_endianness = 0x0706050403020100; + auto check_endianness_raw = reinterpret_cast(&check_endianness); + for (unsigned char c = 0; c < 8; c++) { + auto symbol = check_endianness_raw[static_cast(c)]; + LOG_IF(FATAL, symbol != c) << "TDLib requires little-endian platform"; } -}; -class GetGroupFullInfoRequest final : public RequestActor<> { - ChatId chat_id_; + requests_ = make_unique(this); - void do_run(Promise &&promise) final { - td_->chat_manager_->load_chat_full(chat_id_, get_tries() < 2, std::move(promise), "getBasicGroupFullInfo"); - } + VLOG(td_init) << "Create Global"; + old_context_ = set_context(std::make_shared()); + G()->set_net_query_stats(td_options_.net_query_stats); + inc_request_actor_refcnt(); // guard + inc_actor_refcnt(); // guard - void do_send_result() final { - send_result(td_->chat_manager_->get_basic_group_full_info_object(chat_id_)); - } + alarm_manager_ = create_actor("AlarmManager", create_reference()); - public: - GetGroupFullInfoRequest(ActorShared td, uint64 request_id, int64 chat_id) - : RequestActor(std::move(td), request_id), chat_id_(chat_id) { + CHECK(state_ == State::WaitParameters); + for (auto &update : get_fake_current_state()) { + send_update(std::move(update)); } -}; +} -class GetSupergroupRequest final : public RequestActor<> { - ChannelId channel_id_; +void Td::tear_down() { + LOG_CHECK(close_flag_ == 5) << close_flag_; +} - void do_run(Promise &&promise) final { - td_->chat_manager_->get_channel(channel_id_, get_tries(), std::move(promise)); - } +void Td::hangup_shared() { + auto token = get_link_token(); + auto type = Container::type_from_id(token); - void do_send_result() final { - send_result(td_->chat_manager_->get_supergroup_object(channel_id_)); + if (type == RequestActorIdType) { + request_actors_.erase(token); + dec_request_actor_refcnt(); + } else if (type == ActorIdType) { + dec_actor_refcnt(); + } else { + LOG(FATAL) << "Unknown hangup_shared of type " << type; } +} - public: - GetSupergroupRequest(ActorShared td, uint64 request_id, int64 channel_id) - : RequestActor(std::move(td), request_id), channel_id_(channel_id) { - set_tries(3); - } -}; +void Td::hangup() { + LOG(INFO) << "Receive Td::hangup"; + close(); + dec_stop_cnt(); +} -class GetSupergroupFullInfoRequest final : public RequestActor<> { - ChannelId channel_id_; +ActorShared Td::create_reference() { + inc_actor_refcnt(); + return actor_shared(this, ActorIdType); +} - void do_run(Promise &&promise) final { - td_->chat_manager_->load_channel_full(channel_id_, get_tries() < 2, std::move(promise), - "GetSupergroupFullInfoRequest"); - } +void Td::inc_actor_refcnt() { + actor_refcnt_++; +} - void do_send_result() final { - send_result(td_->chat_manager_->get_supergroup_full_info_object(channel_id_)); +void Td::dec_actor_refcnt() { + actor_refcnt_--; + if (actor_refcnt_ < 3) { + LOG(DEBUG) << "Decrease reference count to " << actor_refcnt_; } + if (actor_refcnt_ == 0) { + if (close_flag_ == 2) { + create_reference(); + close_flag_ = 3; + } else if (close_flag_ == 3) { + LOG(INFO) << "All actors were closed"; + Timer timer; + auto reset_manager = [&timer](auto &manager, Slice name) { + manager.reset(); + LOG(DEBUG) << name << " was cleared" << timer; + }; + reset_manager(account_manager_, "AccountManager"); + reset_manager(animations_manager_, "AnimationsManager"); + reset_manager(attach_menu_manager_, "AttachMenuManager"); + reset_manager(audios_manager_, "AudiosManager"); + reset_manager(auth_manager_, "AuthManager"); + reset_manager(autosave_manager_, "AutosaveManager"); + reset_manager(background_manager_, "BackgroundManager"); + reset_manager(boost_manager_, "BoostManager"); + reset_manager(bot_info_manager_, "BotInfoManager"); + reset_manager(business_connection_manager_, "BusinessConnectionManager"); + reset_manager(business_manager_, "BusinessManager"); + reset_manager(callback_queries_manager_, "CallbackQueriesManager"); + reset_manager(channel_recommendation_manager_, "ChannelRecommendationManager"); + reset_manager(chat_manager_, "ChatManager"); + reset_manager(common_dialog_manager_, "CommonDialogManager"); + reset_manager(connection_state_manager_, "ConnectionStateManager"); + reset_manager(country_info_manager_, "CountryInfoManager"); + reset_manager(dialog_action_manager_, "DialogActionManager"); + reset_manager(dialog_filter_manager_, "DialogFilterManager"); + reset_manager(dialog_invite_link_manager_, "DialogInviteLinkManager"); + reset_manager(dialog_manager_, "DialogManager"); + reset_manager(dialog_participant_manager_, "DialogParticipantManager"); + reset_manager(documents_manager_, "DocumentsManager"); + reset_manager(download_manager_, "DownloadManager"); + reset_manager(file_manager_, "FileManager"); + reset_manager(file_reference_manager_, "FileReferenceManager"); + reset_manager(forum_topic_manager_, "ForumTopicManager"); + reset_manager(game_manager_, "GameManager"); + reset_manager(group_call_manager_, "GroupCallManager"); + reset_manager(inline_message_manager_, "InlineMessageManager"); + reset_manager(inline_queries_manager_, "InlineQueriesManager"); + reset_manager(link_manager_, "LinkManager"); + reset_manager(message_import_manager_, "MessageImportManager"); + reset_manager(messages_manager_, "MessagesManager"); + reset_manager(notification_manager_, "NotificationManager"); + reset_manager(notification_settings_manager_, "NotificationSettingsManager"); + reset_manager(online_manager_, "OnlineManager"); + reset_manager(people_nearby_manager_, "PeopleNearbyManager"); + reset_manager(phone_number_manager_, "PhoneNumberManager"); + reset_manager(poll_manager_, "PollManager"); + reset_manager(privacy_manager_, "PrivacyManager"); + reset_manager(promo_data_manager_, "PromoDataManager"); + reset_manager(quick_reply_manager_, "QuickReplyManager"); + reset_manager(reaction_manager_, "ReactionManager"); + reset_manager(saved_messages_manager_, "SavedMessagesManager"); + reset_manager(sponsored_message_manager_, "SponsoredMessageManager"); + reset_manager(star_manager_, "StarManager"); + reset_manager(statistics_manager_, "StatisticsManager"); + reset_manager(stickers_manager_, "StickersManager"); + reset_manager(story_manager_, "StoryManager"); + reset_manager(terms_of_service_manager_, "TermsOfServiceManager"); + reset_manager(theme_manager_, "ThemeManager"); + reset_manager(time_zone_manager_, "TimeZoneManager"); + reset_manager(top_dialog_manager_, "TopDialogManager"); + reset_manager(transcription_manager_, "TranscriptionManager"); + reset_manager(translation_manager_, "TranslationManager"); + reset_manager(updates_manager_, "UpdatesManager"); + reset_manager(user_manager_, "UserManager"); + reset_manager(video_notes_manager_, "VideoNotesManager"); + reset_manager(videos_manager_, "VideosManager"); + reset_manager(voice_notes_manager_, "VoiceNotesManager"); + reset_manager(web_pages_manager_, "WebPagesManager"); - public: - GetSupergroupFullInfoRequest(ActorShared td, uint64 request_id, int64 channel_id) - : RequestActor(std::move(td), request_id), channel_id_(channel_id) { - } -}; + G()->set_option_manager(nullptr); + option_manager_.reset(); + LOG(DEBUG) << "OptionManager was cleared" << timer; -class GetSecretChatRequest final : public RequestActor<> { - SecretChatId secret_chat_id_; + G()->close_all(destroy_flag_, + PromiseCreator::lambda([actor_id = create_reference()](Unit) mutable { actor_id.reset(); })); - void do_run(Promise &&promise) final { - td_->user_manager_->get_secret_chat(secret_chat_id_, get_tries() < 2, std::move(promise)); + // NetQueryDispatcher will be closed automatically + close_flag_ = 4; + } else if (close_flag_ == 4) { + on_closed(); + } else { + UNREACHABLE(); + } } +} - void do_send_result() final { - send_result(td_->user_manager_->get_secret_chat_object(secret_chat_id_)); - } +void Td::on_closed() { + close_flag_ = 5; + send_update( + td_api::make_object(td_api::make_object())); + dec_stop_cnt(); +} - public: - GetSecretChatRequest(ActorShared td, uint64 request_id, int32 secret_chat_id) - : RequestActor(std::move(td), request_id), secret_chat_id_(secret_chat_id) { +void Td::dec_stop_cnt() { + stop_cnt_--; + if (stop_cnt_ == 0) { + LOG(INFO) << "Stop Td"; + set_context(std::move(old_context_)); + stop(); } -}; - -class GetChatRequest final : public RequestActor<> { - DialogId dialog_id_; +} - bool dialog_found_ = false; +void Td::inc_request_actor_refcnt() { + request_actor_refcnt_++; +} - void do_run(Promise &&promise) final { - dialog_found_ = td_->messages_manager_->load_dialog(dialog_id_, get_tries(), std::move(promise)); +void Td::dec_request_actor_refcnt() { + request_actor_refcnt_--; + LOG(DEBUG) << "Decrease request actor count to " << request_actor_refcnt_; + if (request_actor_refcnt_ == 0) { + clear(); + dec_actor_refcnt(); // remove guard } +} - void do_send_result() final { - if (!dialog_found_) { - send_error(Status::Error(400, "Chat is not accessible")); +void Td::clear_requests() { + while (!request_set_.empty()) { + uint64 id = request_set_.begin()->first; + if (destroy_flag_) { + send_error_impl(id, make_error(401, "Unauthorized")); } else { - send_result(td_->messages_manager_->get_chat_object(dialog_id_, "GetChatRequest")); + send_error_impl(id, make_error(500, "Request aborted")); } } +} - public: - GetChatRequest(ActorShared td, uint64 request_id, int64 dialog_id) - : RequestActor(std::move(td), request_id), dialog_id_(dialog_id) { - set_tries(3); - } -}; - -class SearchUserByPhoneNumberRequest final : public RequestActor<> { - string phone_number_; - bool only_local_; - - UserId user_id_; - - void do_run(Promise &&promise) final { - user_id_ = td_->user_manager_->search_user_by_phone_number(phone_number_, only_local_, std::move(promise)); - } - - void do_send_result() final { - send_result(td_->user_manager_->get_user_object(user_id_)); - } - - public: - SearchUserByPhoneNumberRequest(ActorShared td, uint64 request_id, string &&phone_number, bool only_local) - : RequestActor(std::move(td), request_id), phone_number_(std::move(phone_number)), only_local_(only_local) { - } -}; - -class LoadChatsRequest final : public RequestActor<> { - DialogListId dialog_list_id_; - DialogDate offset_; - int32 limit_; - - void do_run(Promise &&promise) final { - td_->messages_manager_->get_dialogs(dialog_list_id_, offset_, limit_, false, get_tries() < 2, std::move(promise)); +void Td::clear() { + if (close_flag_ >= 2) { + return; } - public: - LoadChatsRequest(ActorShared td, uint64 request_id, DialogListId dialog_list_id, DialogDate offset, int32 limit) - : RequestActor(std::move(td), request_id), dialog_list_id_(dialog_list_id), offset_(offset), limit_(limit) { - // 1 for database + 1 for server request + 1 for server request at the end + 1 for return + 1 just in case - set_tries(5); + LOG(INFO) << "Clear Td"; + close_flag_ = 2; - if (limit_ > 100) { - limit_ = 100; + Timer timer; + if (!auth_manager_->is_bot()) { + if (destroy_flag_) { + notification_manager_->destroy_all_notifications(); + } else { + notification_manager_->flush_all_notifications(); } } -}; -class SearchPublicChatRequest final : public RequestActor<> { - string username_; - - DialogId dialog_id_; + G()->net_query_creator().stop_check(); + result_handlers_.clear(); + LOG(DEBUG) << "Handlers were cleared" << timer; + G()->net_query_dispatcher().stop(); + LOG(DEBUG) << "NetQueryDispatcher was stopped" << timer; + state_manager_.reset(); + LOG(DEBUG) << "StateManager was cleared" << timer; + clear_requests(); - void do_run(Promise &&promise) final { - dialog_id_ = td_->dialog_manager_->search_public_dialog(username_, get_tries() < 3, std::move(promise)); - } + auto reset_actor = [&timer](ActorOwn actor) { + if (!actor.empty()) { + LOG(DEBUG) << "Start clearing " << actor.get().get_name() << timer; + } + }; - void do_send_result() final { - send_result(td_->messages_manager_->get_chat_object(dialog_id_, "SearchPublicChatRequest")); - } + // close all pure actors + reset_actor(ActorOwn(std::move(alarm_manager_))); + reset_actor(ActorOwn(std::move(call_manager_))); + reset_actor(ActorOwn(std::move(cashtag_search_hints_))); + reset_actor(ActorOwn(std::move(config_manager_))); + reset_actor(ActorOwn(std::move(device_token_manager_))); + reset_actor(ActorOwn(std::move(hashtag_hints_))); + reset_actor(ActorOwn(std::move(hashtag_search_hints_))); + reset_actor(ActorOwn(std::move(language_pack_manager_))); + reset_actor(ActorOwn(std::move(net_stats_manager_))); + reset_actor(ActorOwn(std::move(password_manager_))); + reset_actor(ActorOwn(std::move(secure_manager_))); + reset_actor(ActorOwn(std::move(secret_chats_manager_))); + reset_actor(ActorOwn(std::move(storage_manager_))); - public: - SearchPublicChatRequest(ActorShared td, uint64 request_id, string username) - : RequestActor(std::move(td), request_id), username_(std::move(username)) { - set_tries(4); // 1 for server request + 1 for reload voice chat + 1 for reload dialog + 1 for result - } -}; + G()->set_connection_creator(ActorOwn()); + LOG(DEBUG) << "ConnectionCreator was cleared" << timer; + G()->set_temp_auth_key_watchdog(ActorOwn()); + LOG(DEBUG) << "TempAuthKeyWatchdog was cleared" << timer; + + // clear actors which are unique pointers + reset_actor(ActorOwn(std::move(account_manager_actor_))); + reset_actor(ActorOwn(std::move(animations_manager_actor_))); + reset_actor(ActorOwn(std::move(attach_menu_manager_actor_))); + reset_actor(ActorOwn(std::move(auth_manager_actor_))); + reset_actor(ActorOwn(std::move(autosave_manager_actor_))); + reset_actor(ActorOwn(std::move(background_manager_actor_))); + reset_actor(ActorOwn(std::move(boost_manager_actor_))); + reset_actor(ActorOwn(std::move(bot_info_manager_actor_))); + reset_actor(ActorOwn(std::move(business_connection_manager_actor_))); + reset_actor(ActorOwn(std::move(business_manager_actor_))); + reset_actor(ActorOwn(std::move(channel_recommendation_manager_actor_))); + reset_actor(ActorOwn(std::move(chat_manager_actor_))); + reset_actor(ActorOwn(std::move(common_dialog_manager_actor_))); + reset_actor(ActorOwn(std::move(connection_state_manager_actor_))); + reset_actor(ActorOwn(std::move(country_info_manager_actor_))); + reset_actor(ActorOwn(std::move(dialog_action_manager_actor_))); + reset_actor(ActorOwn(std::move(dialog_filter_manager_actor_))); + reset_actor(ActorOwn(std::move(dialog_invite_link_manager_actor_))); + reset_actor(ActorOwn(std::move(dialog_manager_actor_))); + reset_actor(ActorOwn(std::move(dialog_participant_manager_actor_))); + reset_actor(ActorOwn(std::move(download_manager_actor_))); + reset_actor(ActorOwn(std::move(file_manager_actor_))); + reset_actor(ActorOwn(std::move(file_reference_manager_actor_))); + reset_actor(ActorOwn(std::move(forum_topic_manager_actor_))); + reset_actor(ActorOwn(std::move(game_manager_actor_))); + reset_actor(ActorOwn(std::move(group_call_manager_actor_))); + reset_actor(ActorOwn(std::move(inline_message_manager_actor_))); + reset_actor(ActorOwn(std::move(inline_queries_manager_actor_))); + reset_actor(ActorOwn(std::move(link_manager_actor_))); + reset_actor(ActorOwn(std::move(message_import_manager_actor_))); + reset_actor(ActorOwn(std::move(messages_manager_actor_))); + reset_actor(ActorOwn(std::move(notification_manager_actor_))); + reset_actor(ActorOwn(std::move(notification_settings_manager_actor_))); + reset_actor(ActorOwn(std::move(online_manager_actor_))); + reset_actor(ActorOwn(std::move(people_nearby_manager_actor_))); + reset_actor(ActorOwn(std::move(phone_number_manager_actor_))); + reset_actor(ActorOwn(std::move(poll_manager_actor_))); + reset_actor(ActorOwn(std::move(privacy_manager_actor_))); + reset_actor(ActorOwn(std::move(promo_data_manager_actor_))); + reset_actor(ActorOwn(std::move(quick_reply_manager_actor_))); + reset_actor(ActorOwn(std::move(reaction_manager_actor_))); + reset_actor(ActorOwn(std::move(saved_messages_manager_actor_))); + reset_actor(ActorOwn(std::move(sponsored_message_manager_actor_))); + reset_actor(ActorOwn(std::move(star_manager_actor_))); + reset_actor(ActorOwn(std::move(statistics_manager_actor_))); + reset_actor(ActorOwn(std::move(stickers_manager_actor_))); + reset_actor(ActorOwn(std::move(story_manager_actor_))); + reset_actor(ActorOwn(std::move(terms_of_service_manager_actor_))); + reset_actor(ActorOwn(std::move(theme_manager_actor_))); + reset_actor(ActorOwn(std::move(time_zone_manager_actor_))); + reset_actor(ActorOwn(std::move(top_dialog_manager_actor_))); + reset_actor(ActorOwn(std::move(transcription_manager_actor_))); + reset_actor(ActorOwn(std::move(translation_manager_actor_))); + reset_actor(ActorOwn(std::move(updates_manager_actor_))); + reset_actor(ActorOwn(std::move(user_manager_actor_))); + reset_actor(ActorOwn(std::move(video_notes_manager_actor_))); + reset_actor(ActorOwn(std::move(voice_notes_manager_actor_))); + reset_actor(ActorOwn(std::move(web_pages_manager_actor_))); + LOG(DEBUG) << "All actors were cleared" << timer; +} -class SearchPublicChatsRequest final : public RequestActor<> { - string query_; +void Td::close() { + close_impl(false); +} - vector dialog_ids_; +void Td::destroy() { + close_impl(true); +} - void do_run(Promise &&promise) final { - dialog_ids_ = td_->messages_manager_->search_public_dialogs(query_, std::move(promise)); +void Td::close_impl(bool destroy_flag) { + destroy_flag_ |= destroy_flag; + if (close_flag_) { + return; } - void do_send_result() final { - send_result(td_->dialog_manager_->get_chats_object(-1, dialog_ids_, "SearchPublicChatsRequest")); - } + LOG(WARNING) << (destroy_flag ? "Destroy" : "Close") << " Td in state " << static_cast(state_); + if (state_ == State::WaitParameters) { + state_ = State::Close; + close_flag_ = 4; + G()->set_close_flag(); + clear_requests(); + alarm_manager_.reset(); + send_update(td_api::make_object( + td_api::make_object())); - public: - SearchPublicChatsRequest(ActorShared td, uint64 request_id, string query) - : RequestActor(std::move(td), request_id), query_(std::move(query)) { + request_actors_.clear(); + return send_closure_later(actor_id(this), &Td::dec_request_actor_refcnt); // remove guard } -}; -class SearchChatsRequest final : public RequestActor<> { - string query_; - int32 limit_; + state_ = State::Close; + close_flag_ = 1; + G()->set_close_flag(); + send_closure(auth_manager_actor_, &AuthManager::on_closing, destroy_flag); + updates_manager_->timeout_expired(); // save PTS and QTS - std::pair> dialog_ids_; + // wait till all request_actors will stop + request_actors_.clear(); + G()->td_db()->flush_all(); + send_closure_later(actor_id(this), &Td::dec_request_actor_refcnt); // remove guard +} - void do_run(Promise &&promise) final { - dialog_ids_ = td_->messages_manager_->search_dialogs(query_, limit_, std::move(promise)); +template +void Td::complete_pending_preauthentication_requests(const T &func) { + for (auto &request : pending_preauthentication_requests_) { + if (request.second != nullptr && func(request.second->get_id())) { + requests_->run_request(request.first, std::move(request.second)); + request.second = nullptr; + } } +} + +void Td::finish_set_parameters() { + CHECK(set_parameters_request_id_ != 0); + set_parameters_request_id_ = 0; - void do_send_result() final { - send_result(td_->dialog_manager_->get_chats_object(dialog_ids_, "SearchChatsRequest")); + if (pending_set_parameters_requests_.empty()) { + return; } - public: - SearchChatsRequest(ActorShared td, uint64 request_id, string query, int32 limit) - : RequestActor(std::move(td), request_id), query_(std::move(query)), limit_(limit) { + VLOG(td_init) << "Continue to execute " << pending_set_parameters_requests_.size() << " pending requests"; + auto requests = std::move(pending_set_parameters_requests_); + for (auto &request : requests) { + run_request(request.first, std::move(request.second)); } -}; + CHECK(pending_set_parameters_requests_.size() < requests.size()); +} -class SearchChatsOnServerRequest final : public RequestActor<> { - string query_; - int32 limit_; +void Td::init(Parameters parameters, Result r_opened_database) { + CHECK(set_parameters_request_id_ != 0); + if (r_opened_database.is_error()) { + LOG(WARNING) << "Failed to open database: " << r_opened_database.error(); + send_closure(actor_id(this), &Td::send_error, set_parameters_request_id_, r_opened_database.move_as_error()); + return finish_set_parameters(); + } + auto events = r_opened_database.move_as_ok(); - vector dialog_ids_; + VLOG(td_init) << "Successfully inited database"; - void do_run(Promise &&promise) final { - dialog_ids_ = td_->messages_manager_->search_dialogs_on_server(query_, limit_, std::move(promise)); + if (state_ == State::Close) { + LOG(INFO) << "Close asynchronously opened database"; + auto database_ptr = events.database.get(); + auto promise = PromiseCreator::lambda([database = std::move(events.database)](Unit) { + // destroy the database after closing + }); + database_ptr->close( + database_ptr->use_file_database() ? G()->get_database_scheduler_id() : G()->get_slow_net_scheduler_id(), + destroy_flag_, std::move(promise)); + return finish_set_parameters(); } - void do_send_result() final { - send_result(td_->dialog_manager_->get_chats_object(-1, dialog_ids_, "SearchChatsOnServerRequest")); - } + G()->init(actor_id(this), std::move(events.database)).ensure(); - public: - SearchChatsOnServerRequest(ActorShared td, uint64 request_id, string query, int32 limit) - : RequestActor(std::move(td), request_id), query_(std::move(query)), limit_(limit) { - } -}; + init_options_and_network(); -class GetGroupsInCommonRequest final : public RequestActor<> { - UserId user_id_; - DialogId offset_dialog_id_; - int32 limit_; + // we need to process td_api::getOption along with td_api::setOption for consistency + // we need to process td_api::setOption before managers and MTProto header are created, + // because their initialiation may be affected by the options + complete_pending_preauthentication_requests([](int32 id) { + switch (id) { + case td_api::getOption::ID: + case td_api::setOption::ID: + return true; + default: + return false; + } + }); - std::pair> dialog_ids_; + if (!option_manager_->get_option_boolean("disable_network_statistics")) { + net_stats_manager_ = create_actor("NetStatsManager", create_reference()); - void do_run(Promise &&promise) final { - dialog_ids_ = td_->common_dialog_manager_->get_common_dialogs(user_id_, offset_dialog_id_, limit_, get_tries() < 2, - std::move(promise)); + // How else could I let two actor know about each other, without quite complex async logic? + auto net_stats_manager_ptr = net_stats_manager_.get_actor_unsafe(); + net_stats_manager_ptr->init(); + G()->connection_creator().get_actor_unsafe()->set_net_stats_callback( + net_stats_manager_ptr->get_common_stats_callback(), net_stats_manager_ptr->get_media_stats_callback()); + G()->set_net_stats_file_callbacks(net_stats_manager_ptr->get_file_stats_callbacks()); } - void do_send_result() final { - send_result(td_->dialog_manager_->get_chats_object(dialog_ids_, "GetGroupsInCommonRequest")); - } + complete_pending_preauthentication_requests([](int32 id) { + switch (id) { + case td_api::getNetworkStatistics::ID: + case td_api::addNetworkStatistics::ID: + case td_api::resetNetworkStatistics::ID: + return true; + default: + return false; + } + }); - public: - GetGroupsInCommonRequest(ActorShared td, uint64 request_id, int64 user_id, int64 offset_dialog_id, int32 limit) - : RequestActor(std::move(td), request_id), user_id_(user_id), offset_dialog_id_(offset_dialog_id), limit_(limit) { + if (events.since_last_open >= 3600) { + auto old_since_last_open = option_manager_->get_option_integer("since_last_open"); + if (events.since_last_open > old_since_last_open) { + option_manager_->set_option_integer("since_last_open", events.since_last_open); + } } -}; -class GetSuitableDiscussionChatsRequest final : public RequestActor<> { - vector dialog_ids_; + options_.language_pack = option_manager_->get_option_string("localization_target"); + options_.language_code = option_manager_->get_option_string("language_pack_id"); + options_.parameters = option_manager_->get_option_string("connection_parameters"); + options_.tz_offset = static_cast(option_manager_->get_option_integer("utc_time_offset")); + options_.is_emulator = option_manager_->get_option_boolean("is_emulator"); + // options_.proxy = Proxy(); + G()->set_mtproto_header(make_unique(options_)); + G()->set_store_all_files_in_files_directory( + option_manager_->get_option_boolean("store_all_files_in_files_directory")); + + VLOG(td_init) << "Create NetQueryDispatcher"; + auto net_query_dispatcher = make_unique([&] { return create_reference(); }); + G()->set_net_query_dispatcher(std::move(net_query_dispatcher)); - void do_run(Promise &&promise) final { - dialog_ids_ = td_->chat_manager_->get_dialogs_for_discussion(std::move(promise)); - } + complete_pending_preauthentication_requests([](int32 id) { + // pingProxy uses NetQueryDispatcher to get main_dc_id, so must be called after NetQueryDispatcher is created + return id == td_api::pingProxy::ID; + }); - void do_send_result() final { - send_result(td_->dialog_manager_->get_chats_object(-1, dialog_ids_, "GetSuitableDiscussionChatsRequest")); - } + VLOG(td_init) << "Create AuthManager"; + auth_manager_ = td::make_unique(parameters.api_id_, parameters.api_hash_, create_reference()); + auth_manager_actor_ = register_actor("AuthManager", auth_manager_.get()); + G()->set_auth_manager(auth_manager_actor_.get()); - public: - GetSuitableDiscussionChatsRequest(ActorShared td, uint64 request_id) : RequestActor(std::move(td), request_id) { - } -}; + init_file_manager(); -class GetInactiveSupergroupChatsRequest final : public RequestActor<> { - vector dialog_ids_; + init_non_actor_managers(); - void do_run(Promise &&promise) final { - dialog_ids_ = td_->chat_manager_->get_inactive_channels(std::move(promise)); - } + init_managers(); - void do_send_result() final { - send_result(td_->dialog_manager_->get_chats_object(-1, dialog_ids_, "GetInactiveSupergroupChatsRequest")); - } + init_pure_actor_managers(); - public: - GetInactiveSupergroupChatsRequest(ActorShared td, uint64 request_id) : RequestActor(std::move(td), request_id) { - } -}; + secret_chats_manager_ = + create_actor("SecretChatsManager", create_reference(), parameters.use_secret_chats_); + G()->set_secret_chats_manager(secret_chats_manager_.get()); -class SearchRecentlyFoundChatsRequest final : public RequestActor<> { - string query_; - int32 limit_; + storage_manager_ = create_actor("StorageManager", create_reference(), G()->get_gc_scheduler_id()); + G()->set_storage_manager(storage_manager_.get()); - std::pair> dialog_ids_; + option_manager_->on_td_inited(); - void do_run(Promise &&promise) final { - dialog_ids_ = td_->messages_manager_->search_recently_found_dialogs(query_, limit_, std::move(promise)); - } + process_binlog_events(std::move(events)); - void do_send_result() final { - send_result(td_->dialog_manager_->get_chats_object(dialog_ids_, "SearchRecentlyFoundChatsRequest")); + VLOG(td_init) << "Ping datacenter"; + if (!auth_manager_->is_authorized()) { + country_info_manager_->get_current_country_code(Promise()); + } else { + updates_manager_->get_difference("init"); } - public: - SearchRecentlyFoundChatsRequest(ActorShared td, uint64 request_id, string query, int32 limit) - : RequestActor(std::move(td), request_id), query_(std::move(query)), limit_(limit) { - } -}; + complete_pending_preauthentication_requests([](int32 id) { return true; }); -class GetRecentlyOpenedChatsRequest final : public RequestActor<> { - int32 limit_; + VLOG(td_init) << "Finish initialization"; - std::pair> dialog_ids_; + state_ = State::Run; - void do_run(Promise &&promise) final { - dialog_ids_ = td_->messages_manager_->get_recently_opened_dialogs(limit_, std::move(promise)); - } + send_closure(actor_id(this), &Td::send_result, set_parameters_request_id_, td_api::make_object()); + return finish_set_parameters(); +} - void do_send_result() final { - send_result(td_->dialog_manager_->get_chats_object(dialog_ids_, "GetRecentlyOpenedChatsRequest")); +void Td::process_binlog_events(TdDb::OpenedDatabase &&events) { + VLOG(td_init) << "Send binlog events"; + for (auto &event : events.user_events) { + user_manager_->on_binlog_user_event(std::move(event)); } - public: - GetRecentlyOpenedChatsRequest(ActorShared td, uint64 request_id, int32 limit) - : RequestActor(std::move(td), request_id), limit_(limit) { + for (auto &event : events.channel_events) { + chat_manager_->on_binlog_channel_event(std::move(event)); } -}; - -class GetMessageRequest final : public RequestOnceActor { - MessageFullId message_full_id_; - void do_run(Promise &&promise) final { - td_->messages_manager_->get_message(message_full_id_, std::move(promise)); + // chats may contain links to channels, so should be inited after + for (auto &event : events.chat_events) { + chat_manager_->on_binlog_chat_event(std::move(event)); } - void do_send_result() final { - send_result(td_->messages_manager_->get_message_object(message_full_id_, "GetMessageRequest")); + for (auto &event : events.secret_chat_events) { + user_manager_->on_binlog_secret_chat_event(std::move(event)); } - public: - GetMessageRequest(ActorShared td, uint64 request_id, int64 dialog_id, int64 message_id) - : RequestOnceActor(std::move(td), request_id), message_full_id_(DialogId(dialog_id), MessageId(message_id)) { + for (auto &event : events.web_page_events) { + web_pages_manager_->on_binlog_web_page_event(std::move(event)); } -}; - -class GetRepliedMessageRequest final : public RequestOnceActor { - DialogId dialog_id_; - MessageId message_id_; - MessageFullId replied_message_id_; - - void do_run(Promise &&promise) final { - replied_message_id_ = - td_->messages_manager_->get_replied_message(dialog_id_, message_id_, get_tries() < 3, std::move(promise)); - } - - void do_send_result() final { - send_result(td_->messages_manager_->get_message_object(replied_message_id_, "GetRepliedMessageRequest")); - } - - public: - GetRepliedMessageRequest(ActorShared td, uint64 request_id, int64 dialog_id, int64 message_id) - : RequestOnceActor(std::move(td), request_id), dialog_id_(dialog_id), message_id_(message_id) { - set_tries(3); // 1 to get initial message, 1 to get the reply and 1 for result - } -}; - -class GetMessageThreadRequest final : public RequestActor { - DialogId dialog_id_; - MessageId message_id_; - - MessageThreadInfo message_thread_info_; - - void do_run(Promise &&promise) final { - if (get_tries() < 2) { - promise.set_value(std::move(message_thread_info_)); - return; - } - td_->messages_manager_->get_message_thread(dialog_id_, message_id_, std::move(promise)); - } - - void do_set_result(MessageThreadInfo &&result) final { - message_thread_info_ = std::move(result); - } - - void do_send_result() final { - send_result(td_->messages_manager_->get_message_thread_info_object(message_thread_info_)); - } - - public: - GetMessageThreadRequest(ActorShared td, uint64 request_id, int64 dialog_id, int64 message_id) - : RequestActor(std::move(td), request_id), dialog_id_(dialog_id), message_id_(message_id) { - } -}; - -class GetChatPinnedMessageRequest final : public RequestOnceActor { - DialogId dialog_id_; - - MessageId pinned_message_id_; - - void do_run(Promise &&promise) final { - pinned_message_id_ = td_->messages_manager_->get_dialog_pinned_message(dialog_id_, std::move(promise)); - } - - void do_send_result() final { - send_result( - td_->messages_manager_->get_message_object({dialog_id_, pinned_message_id_}, "GetChatPinnedMessageRequest")); - } - - public: - GetChatPinnedMessageRequest(ActorShared td, uint64 request_id, int64 dialog_id) - : RequestOnceActor(std::move(td), request_id), dialog_id_(dialog_id) { - set_tries(3); // 1 to get pinned_message_id, 1 to get the message and 1 for result - } -}; - -class GetCallbackQueryMessageRequest final : public RequestOnceActor { - DialogId dialog_id_; - MessageId message_id_; - int64 callback_query_id_; - - void do_run(Promise &&promise) final { - td_->messages_manager_->get_callback_query_message(dialog_id_, message_id_, callback_query_id_, std::move(promise)); + for (auto &event : events.save_app_log_events) { + on_save_app_log_binlog_event(this, std::move(event)); } - void do_send_result() final { - send_result( - td_->messages_manager_->get_message_object({dialog_id_, message_id_}, "GetCallbackQueryMessageRequest")); - } + // Send binlog events to managers + // + // 1. Actors must receive all binlog events before other queries. + // + // -- All actors have one "entry point". So there is only one way to send query to them. So all queries are ordered + // for each Actor. + // + // 2. An actor must not make some decisions before all binlog events are processed. + // For example, SecretChatActor must not send RequestKey, before it receives log event with RequestKey and understands + // that RequestKey was already sent. + // + // 3. During replay of binlog some queries may be sent to other actors. They shouldn't process such events before all + // their binlog events are processed. So actor may receive some old queries. It must be in its actual state in + // order to handle them properly. + // + // -- Use send_closure_later, so actors don't even start process binlog events, before all binlog events are sent - public: - GetCallbackQueryMessageRequest(ActorShared td, uint64 request_id, int64 dialog_id, int64 message_id, - int64 callback_query_id) - : RequestOnceActor(std::move(td), request_id) - , dialog_id_(dialog_id) - , message_id_(message_id) - , callback_query_id_(callback_query_id) { + for (auto &event : events.to_secret_chats_manager) { + send_closure_later(secret_chats_manager_, &SecretChatsManager::replay_binlog_event, std::move(event)); } -}; -class GetMessagesRequest final : public RequestOnceActor { - DialogId dialog_id_; - vector message_ids_; - - void do_run(Promise &&promise) final { - td_->messages_manager_->get_messages(dialog_id_, message_ids_, std::move(promise)); - } + send_closure_later(account_manager_actor_, &AccountManager::on_binlog_events, std::move(events.to_account_manager)); - void do_send_result() final { - send_result(td_->messages_manager_->get_messages_object(-1, dialog_id_, message_ids_, false, "GetMessagesRequest")); - } + send_closure_later(poll_manager_actor_, &PollManager::on_binlog_events, std::move(events.to_poll_manager)); - public: - GetMessagesRequest(ActorShared td, uint64 request_id, int64 dialog_id, const vector &message_ids) - : RequestOnceActor(std::move(td), request_id) - , dialog_id_(dialog_id) - , message_ids_(MessageId::get_message_ids(message_ids)) { - } -}; + send_closure_later(messages_manager_actor_, &MessagesManager::on_binlog_events, + std::move(events.to_messages_manager)); -class GetMessageEmbeddingCodeRequest final : public RequestActor<> { - MessageFullId message_full_id_; - bool for_group_; + send_closure_later(story_manager_actor_, &StoryManager::on_binlog_events, std::move(events.to_story_manager)); - string html_; + send_closure_later(notification_manager_actor_, &NotificationManager::on_binlog_events, + std::move(events.to_notification_manager)); - void do_run(Promise &&promise) final { - html_ = td_->messages_manager_->get_message_embedding_code(message_full_id_, for_group_, std::move(promise)); - } + send_closure_later(notification_settings_manager_actor_, &NotificationSettingsManager::on_binlog_events, + std::move(events.to_notification_settings_manager)); - void do_send_result() final { - send_result(make_tl_object(html_)); - } + send_closure(secret_chats_manager_, &SecretChatsManager::binlog_replay_finish); +} - public: - GetMessageEmbeddingCodeRequest(ActorShared td, uint64 request_id, int64 dialog_id, int64 message_id, - bool for_group) - : RequestActor(std::move(td), request_id) - , message_full_id_(DialogId(dialog_id), MessageId(message_id)) - , for_group_(for_group) { - } -}; +void Td::init_options_and_network() { + VLOG(td_init) << "Create StateManager"; + state_manager_ = create_actor("State manager", create_reference()); + G()->set_state_manager(state_manager_.get()); -class GetMessageLinkInfoRequest final : public RequestActor { - string url_; + VLOG(td_init) << "Create OptionManager"; + option_manager_ = make_unique(this); + G()->set_option_manager(option_manager_.get()); - MessageLinkInfo message_link_info_; + VLOG(td_init) << "Create ConnectionCreator"; + G()->set_connection_creator(create_actor("ConnectionCreator", create_reference())); - void do_run(Promise &&promise) final { - if (get_tries() < 2) { - promise.set_value(std::move(message_link_info_)); - return; + complete_pending_preauthentication_requests([](int32 id) { + switch (id) { + case td_api::setNetworkType::ID: + case td_api::addProxy::ID: + case td_api::editProxy::ID: + case td_api::enableProxy::ID: + case td_api::disableProxy::ID: + case td_api::removeProxy::ID: + case td_api::getProxies::ID: + case td_api::getProxyLink::ID: + return true; + default: + return false; } - td_->messages_manager_->get_message_link_info(url_, std::move(promise)); - } - - void do_set_result(MessageLinkInfo &&result) final { - message_link_info_ = std::move(result); - } - - void do_send_result() final { - send_result(td_->messages_manager_->get_message_link_info_object(message_link_info_)); - } + }); - public: - GetMessageLinkInfoRequest(ActorShared td, uint64 request_id, string url) - : RequestActor(std::move(td), request_id), url_(std::move(url)) { - } -}; + VLOG(td_init) << "Create TempAuthKeyWatchdog"; + G()->set_temp_auth_key_watchdog(create_actor("TempAuthKeyWatchdog", create_reference())); -class GetDialogBoostLinkInfoRequest final : public RequestActor { - string url_; + VLOG(td_init) << "Create ConfigManager"; + config_manager_ = create_actor("ConfigManager", create_reference()); + G()->set_config_manager(config_manager_.get()); - DialogBoostLinkInfo dialog_boost_link_info_; + VLOG(td_init) << "Create OnlineManager"; + online_manager_ = make_unique(this, create_reference()); + online_manager_actor_ = register_actor("OnlineManager", online_manager_.get()); + G()->set_online_manager(online_manager_actor_.get()); +} - void do_run(Promise &&promise) final { - if (get_tries() < 2) { - promise.set_value(std::move(dialog_boost_link_info_)); - return; +void Td::init_file_manager() { + VLOG(td_init) << "Create FileManager"; + class FileManagerContext final : public FileManager::Context { + public: + explicit FileManagerContext(Td *td) : td_(td) { } - td_->boost_manager_->get_dialog_boost_link_info(url_, std::move(promise)); - } - - void do_set_result(DialogBoostLinkInfo &&result) final { - dialog_boost_link_info_ = std::move(result); - } - - void do_send_result() final { - send_result(td_->boost_manager_->get_chat_boost_link_info_object(dialog_boost_link_info_)); - } - - public: - GetDialogBoostLinkInfoRequest(ActorShared td, uint64 request_id, string url) - : RequestActor(std::move(td), request_id), url_(std::move(url)) { - } -}; - -class EditMessageTextRequest final : public RequestOnceActor { - MessageFullId message_full_id_; - tl_object_ptr reply_markup_; - tl_object_ptr input_message_content_; - - void do_run(Promise &&promise) final { - td_->messages_manager_->edit_message_text(message_full_id_, std::move(reply_markup_), - std::move(input_message_content_), std::move(promise)); - } - - void do_send_result() final { - send_result(td_->messages_manager_->get_message_object(message_full_id_, "EditMessageTextRequest")); - } - - public: - EditMessageTextRequest(ActorShared td, uint64 request_id, int64 dialog_id, int64 message_id, - tl_object_ptr reply_markup, - tl_object_ptr input_message_content) - : RequestOnceActor(std::move(td), request_id) - , message_full_id_(DialogId(dialog_id), MessageId(message_id)) - , reply_markup_(std::move(reply_markup)) - , input_message_content_(std::move(input_message_content)) { - } -}; - -class EditMessageLiveLocationRequest final : public RequestOnceActor { - MessageFullId message_full_id_; - tl_object_ptr reply_markup_; - tl_object_ptr location_; - int32 live_period_; - int32 heading_; - int32 proximity_alert_radius_; - - void do_run(Promise &&promise) final { - td_->messages_manager_->edit_message_live_location(message_full_id_, std::move(reply_markup_), std::move(location_), - live_period_, heading_, proximity_alert_radius_, - std::move(promise)); - } - - void do_send_result() final { - send_result(td_->messages_manager_->get_message_object(message_full_id_, "EditMessageLiveLocationRequest")); - } - - public: - EditMessageLiveLocationRequest(ActorShared td, uint64 request_id, int64 dialog_id, int64 message_id, - tl_object_ptr reply_markup, - tl_object_ptr location, int32 live_period, int32 heading, - int32 proximity_alert_radius) - : RequestOnceActor(std::move(td), request_id) - , message_full_id_(DialogId(dialog_id), MessageId(message_id)) - , reply_markup_(std::move(reply_markup)) - , location_(std::move(location)) - , live_period_(live_period) - , heading_(heading) - , proximity_alert_radius_(proximity_alert_radius) { - } -}; - -class EditMessageMediaRequest final : public RequestOnceActor { - MessageFullId message_full_id_; - tl_object_ptr reply_markup_; - tl_object_ptr input_message_content_; - - void do_run(Promise &&promise) final { - td_->messages_manager_->edit_message_media(message_full_id_, std::move(reply_markup_), - std::move(input_message_content_), std::move(promise)); - } - - void do_send_result() final { - send_result(td_->messages_manager_->get_message_object(message_full_id_, "EditMessageMediaRequest")); - } - - public: - EditMessageMediaRequest(ActorShared td, uint64 request_id, int64 dialog_id, int64 message_id, - tl_object_ptr reply_markup, - tl_object_ptr input_message_content) - : RequestOnceActor(std::move(td), request_id) - , message_full_id_(DialogId(dialog_id), MessageId(message_id)) - , reply_markup_(std::move(reply_markup)) - , input_message_content_(std::move(input_message_content)) { - } -}; - -class EditMessageCaptionRequest final : public RequestOnceActor { - MessageFullId message_full_id_; - tl_object_ptr reply_markup_; - tl_object_ptr caption_; - bool invert_media_; - - void do_run(Promise &&promise) final { - td_->messages_manager_->edit_message_caption(message_full_id_, std::move(reply_markup_), std::move(caption_), - invert_media_, std::move(promise)); - } - - void do_send_result() final { - send_result(td_->messages_manager_->get_message_object(message_full_id_, "EditMessageCaptionRequest")); - } - - public: - EditMessageCaptionRequest(ActorShared td, uint64 request_id, int64 dialog_id, int64 message_id, - tl_object_ptr reply_markup, - tl_object_ptr caption, bool invert_media) - : RequestOnceActor(std::move(td), request_id) - , message_full_id_(DialogId(dialog_id), MessageId(message_id)) - , reply_markup_(std::move(reply_markup)) - , caption_(std::move(caption)) - , invert_media_(invert_media) { - } -}; - -class EditMessageReplyMarkupRequest final : public RequestOnceActor { - MessageFullId message_full_id_; - tl_object_ptr reply_markup_; - void do_run(Promise &&promise) final { - td_->messages_manager_->edit_message_reply_markup(message_full_id_, std::move(reply_markup_), std::move(promise)); - } - - void do_send_result() final { - send_result(td_->messages_manager_->get_message_object(message_full_id_, "EditMessageReplyMarkupRequest")); - } - - public: - EditMessageReplyMarkupRequest(ActorShared td, uint64 request_id, int64 dialog_id, int64 message_id, - tl_object_ptr reply_markup) - : RequestOnceActor(std::move(td), request_id) - , message_full_id_(DialogId(dialog_id), MessageId(message_id)) - , reply_markup_(std::move(reply_markup)) { - } -}; - -class GetChatHistoryRequest final : public RequestActor<> { - DialogId dialog_id_; - MessageId from_message_id_; - int32 offset_; - int32 limit_; - bool only_local_; - - tl_object_ptr messages_; - - void do_run(Promise &&promise) final { - messages_ = td_->messages_manager_->get_dialog_history(dialog_id_, from_message_id_, offset_, limit_, - get_tries() - 1, only_local_, std::move(promise)); - } - - void do_send_result() final { - send_result(std::move(messages_)); - } - - public: - GetChatHistoryRequest(ActorShared td, uint64 request_id, int64 dialog_id, int64 from_message_id, int32 offset, - int32 limit, bool only_local) - : RequestActor(std::move(td), request_id) - , dialog_id_(dialog_id) - , from_message_id_(from_message_id) - , offset_(offset) - , limit_(limit) - , only_local_(only_local) { - if (!only_local_) { - set_tries(4); + bool need_notify_on_new_files() final { + return !td_->auth_manager_->is_bot(); } - } -}; - -class GetMessageThreadHistoryRequest final : public RequestActor<> { - DialogId dialog_id_; - MessageId message_id_; - MessageId from_message_id_; - int32 offset_; - int32 limit_; - int64 random_id_; - std::pair> messages_; - - void do_run(Promise &&promise) final { - messages_ = td_->messages_manager_->get_message_thread_history(dialog_id_, message_id_, from_message_id_, offset_, - limit_, random_id_, std::move(promise)); - } - - void do_send_result() final { - send_result(td_->messages_manager_->get_messages_object(-1, messages_.first, messages_.second, true, - "GetMessageThreadHistoryRequest")); - } - - public: - GetMessageThreadHistoryRequest(ActorShared td, uint64 request_id, int64 dialog_id, int64 message_id, - int64 from_message_id, int32 offset, int32 limit) - : RequestActor(std::move(td), request_id) - , dialog_id_(dialog_id) - , message_id_(message_id) - , from_message_id_(from_message_id) - , offset_(offset) - , limit_(limit) - , random_id_(0) { - set_tries(3); - } -}; - -class SearchChatMessagesRequest final : public RequestActor<> { - DialogId dialog_id_; - string query_; - td_api::object_ptr sender_id_; - MessageId from_message_id_; - int32 offset_; - int32 limit_; - MessageSearchFilter filter_; - MessageId top_thread_message_id_; - SavedMessagesTopicId saved_messages_topic_id_; - ReactionType tag_; - int64 random_id_; - - MessagesManager::FoundDialogMessages messages_; - - void do_run(Promise &&promise) final { - messages_ = td_->messages_manager_->search_dialog_messages( - dialog_id_, query_, sender_id_, from_message_id_, offset_, limit_, filter_, top_thread_message_id_, - saved_messages_topic_id_, tag_, random_id_, get_tries() == 3, std::move(promise)); - } - - void do_send_result() final { - send_result( - td_->messages_manager_->get_found_chat_messages_object(dialog_id_, messages_, "SearchChatMessagesRequest")); - } - - void do_send_error(Status &&status) final { - if (status.message() == "SEARCH_QUERY_EMPTY") { - messages_ = {}; - return do_send_result(); + void on_new_file(int64 size, int64 real_size, int32 cnt) final { + send_closure(G()->storage_manager(), &StorageManager::on_new_file, size, real_size, cnt); } - send_error(std::move(status)); - } - - public: - SearchChatMessagesRequest(ActorShared td, uint64 request_id, int64 dialog_id, string query, - td_api::object_ptr sender_id, int64 from_message_id, int32 offset, - int32 limit, tl_object_ptr filter, int64 message_thread_id, - SavedMessagesTopicId saved_messages_topic_id, ReactionType tag) - : RequestActor(std::move(td), request_id) - , dialog_id_(dialog_id) - , query_(std::move(query)) - , sender_id_(std::move(sender_id)) - , from_message_id_(from_message_id) - , offset_(offset) - , limit_(limit) - , filter_(get_message_search_filter(filter)) - , top_thread_message_id_(message_thread_id) - , saved_messages_topic_id_(saved_messages_topic_id) - , tag_(std::move(tag)) - , random_id_(0) { - set_tries(3); - } -}; - -class GetChatScheduledMessagesRequest final : public RequestActor<> { - DialogId dialog_id_; - vector message_ids_; - - void do_run(Promise &&promise) final { - message_ids_ = - td_->messages_manager_->get_dialog_scheduled_messages(dialog_id_, get_tries() < 2, false, std::move(promise)); - } - - void do_send_result() final { - send_result(td_->messages_manager_->get_messages_object(-1, dialog_id_, message_ids_, true, - "GetChatScheduledMessagesRequest")); - } - - public: - GetChatScheduledMessagesRequest(ActorShared td, uint64 request_id, int64 dialog_id) - : RequestActor(std::move(td), request_id), dialog_id_(dialog_id) { - set_tries(4); - } -}; - -class GetWebPageInstantViewRequest final : public RequestActor { - string url_; - bool force_full_; - - WebPageId web_page_id_; - - void do_run(Promise &&promise) final { - if (get_tries() < 2) { - promise.set_value(std::move(web_page_id_)); - return; + void on_file_updated(FileId file_id) final { + send_closure(G()->td(), &Td::send_update, + make_tl_object(td_->file_manager_->get_file_object(file_id))); } - td_->web_pages_manager_->get_web_page_instant_view(url_, force_full_, std::move(promise)); - } - - void do_set_result(WebPageId &&result) final { - web_page_id_ = result; - } - - void do_send_result() final { - send_result(td_->web_pages_manager_->get_web_page_instant_view_object(web_page_id_)); - } - - public: - GetWebPageInstantViewRequest(ActorShared td, uint64 request_id, string url, bool force_full) - : RequestActor(std::move(td), request_id), url_(std::move(url)), force_full_(force_full) { - } -}; - -class CreateChatRequest final : public RequestActor<> { - DialogId dialog_id_; - bool force_; - - void do_run(Promise &&promise) final { - td_->messages_manager_->create_dialog(dialog_id_, force_, std::move(promise)); - } - - void do_send_result() final { - send_result(td_->messages_manager_->get_chat_object(dialog_id_, "CreateChatRequest")); - } - public: - CreateChatRequest(ActorShared td, uint64 request_id, DialogId dialog_id, bool force) - : RequestActor<>(std::move(td), request_id), dialog_id_(dialog_id), force_(force) { - } -}; - -class CheckChatInviteLinkRequest final : public RequestActor<> { - string invite_link_; - - void do_run(Promise &&promise) final { - td_->dialog_invite_link_manager_->check_dialog_invite_link(invite_link_, get_tries() < 2, std::move(promise)); - } - - void do_send_result() final { - auto result = td_->dialog_invite_link_manager_->get_chat_invite_link_info_object(invite_link_); - CHECK(result != nullptr); - send_result(std::move(result)); - } + bool add_file_source(FileId file_id, FileSourceId file_source_id) final { + return td_->file_reference_manager_->add_file_source(file_id, file_source_id); + } - public: - CheckChatInviteLinkRequest(ActorShared td, uint64 request_id, string invite_link) - : RequestActor(std::move(td), request_id), invite_link_(std::move(invite_link)) { - } -}; + bool remove_file_source(FileId file_id, FileSourceId file_source_id) final { + return td_->file_reference_manager_->remove_file_source(file_id, file_source_id); + } -class JoinChatByInviteLinkRequest final : public RequestActor { - string invite_link_; + void on_merge_files(FileId to_file_id, FileId from_file_id) final { + td_->file_reference_manager_->merge(to_file_id, from_file_id); + } - DialogId dialog_id_; + vector get_some_file_sources(FileId file_id) final { + return td_->file_reference_manager_->get_some_file_sources(file_id); + } - void do_run(Promise &&promise) final { - if (get_tries() < 2) { - promise.set_value(std::move(dialog_id_)); - return; + void repair_file_reference(FileId file_id, Promise promise) final { + send_closure(G()->file_reference_manager(), &FileReferenceManager::repair_file_reference, file_id, + std::move(promise)); } - td_->dialog_invite_link_manager_->import_dialog_invite_link(invite_link_, std::move(promise)); - } - void do_set_result(DialogId &&result) final { - dialog_id_ = result; - } + void reload_photo(PhotoSizeSource source, Promise promise) final { + FileReferenceManager::reload_photo(std::move(source), std::move(promise)); + } - void do_send_result() final { - CHECK(dialog_id_.is_valid()); - td_->dialog_manager_->force_create_dialog(dialog_id_, "join chat via an invite link"); - send_result(td_->messages_manager_->get_chat_object(dialog_id_, "JoinChatByInviteLinkRequest")); - } + bool keep_exact_remote_location() final { + return !td_->auth_manager_->is_bot(); + } - public: - JoinChatByInviteLinkRequest(ActorShared td, uint64 request_id, string invite_link) - : RequestActor(std::move(td), request_id), invite_link_(std::move(invite_link)) { - } -}; + ActorShared<> create_reference() final { + return td_->create_reference(); + } -class ImportContactsRequest final : public RequestActor<> { - vector contacts_; - int64 random_id_; + private: + Td *td_; + }; - std::pair, vector> imported_contacts_; + file_manager_ = make_unique(make_unique(this)); + file_manager_actor_ = register_actor("FileManager", file_manager_.get()); + file_manager_->init_actor(); + G()->set_file_manager(file_manager_actor_.get()); - void do_run(Promise &&promise) final { - imported_contacts_ = td_->user_manager_->import_contacts(contacts_, random_id_, std::move(promise)); - } + file_reference_manager_ = make_unique(create_reference()); + file_reference_manager_actor_ = register_actor("FileReferenceManager", file_reference_manager_.get()); + G()->set_file_reference_manager(file_reference_manager_actor_.get()); +} - void do_send_result() final { - CHECK(imported_contacts_.first.size() == contacts_.size()); - CHECK(imported_contacts_.second.size() == contacts_.size()); - send_result(make_tl_object(transform(imported_contacts_.first, - [this](UserId user_id) { - return td_->user_manager_->get_user_id_object( - user_id, "ImportContactsRequest"); - }), - std::move(imported_contacts_.second))); - } +void Td::init_non_actor_managers() { + VLOG(td_init) << "Create Managers"; + audios_manager_ = make_unique(this); + callback_queries_manager_ = make_unique(this); + documents_manager_ = make_unique(this); + videos_manager_ = make_unique(this); +} - public: - ImportContactsRequest(ActorShared td, uint64 request_id, vector &&contacts) - : RequestActor(std::move(td), request_id), contacts_(std::move(contacts)), random_id_(0) { - set_tries(3); // load_contacts + import_contacts - } -}; - -class SearchContactsRequest final : public RequestActor<> { - string query_; - int32 limit_; - - std::pair> user_ids_; - - void do_run(Promise &&promise) final { - user_ids_ = td_->user_manager_->search_contacts(query_, limit_, std::move(promise)); - } - - void do_send_result() final { - send_result(td_->user_manager_->get_users_object(user_ids_.first, user_ids_.second)); - } - - public: - SearchContactsRequest(ActorShared td, uint64 request_id, string query, int32 limit) - : RequestActor(std::move(td), request_id), query_(std::move(query)), limit_(limit) { - } -}; - -class RemoveContactsRequest final : public RequestActor<> { - vector user_ids_; - - void do_run(Promise &&promise) final { - td_->user_manager_->remove_contacts(user_ids_, std::move(promise)); - } - - public: - RemoveContactsRequest(ActorShared td, uint64 request_id, vector &&user_ids) - : RequestActor(std::move(td), request_id), user_ids_(std::move(user_ids)) { - set_tries(3); // load_contacts + delete_contacts - } -}; - -class GetImportedContactCountRequest final : public RequestActor<> { - int32 imported_contact_count_ = 0; - - void do_run(Promise &&promise) final { - imported_contact_count_ = td_->user_manager_->get_imported_contact_count(std::move(promise)); - } - - void do_send_result() final { - send_result(td_api::make_object(imported_contact_count_)); - } - - public: - GetImportedContactCountRequest(ActorShared td, uint64 request_id) : RequestActor(std::move(td), request_id) { - } -}; - -class ChangeImportedContactsRequest final : public RequestActor<> { - vector contacts_; - size_t contacts_size_; - int64 random_id_; - - std::pair, vector> imported_contacts_; - - void do_run(Promise &&promise) final { - imported_contacts_ = td_->user_manager_->change_imported_contacts(contacts_, random_id_, std::move(promise)); - } - - void do_send_result() final { - CHECK(imported_contacts_.first.size() == contacts_size_); - CHECK(imported_contacts_.second.size() == contacts_size_); - send_result(make_tl_object(transform(imported_contacts_.first, - [this](UserId user_id) { - return td_->user_manager_->get_user_id_object( - user_id, "ChangeImportedContactsRequest"); - }), - std::move(imported_contacts_.second))); - } - - public: - ChangeImportedContactsRequest(ActorShared td, uint64 request_id, vector &&contacts) - : RequestActor(std::move(td), request_id) - , contacts_(std::move(contacts)) - , contacts_size_(contacts_.size()) - , random_id_(0) { - set_tries(4); // load_contacts + load_local_contacts + (import_contacts + delete_contacts) - } -}; - -class GetCloseFriendsRequest final : public RequestActor<> { - vector user_ids_; - - void do_run(Promise &&promise) final { - user_ids_ = td_->user_manager_->get_close_friends(std::move(promise)); - } - - void do_send_result() final { - send_result(td_->user_manager_->get_users_object(-1, user_ids_)); - } - - public: - GetCloseFriendsRequest(ActorShared td, uint64 request_id) : RequestActor(std::move(td), request_id) { - } -}; - -class GetRecentInlineBotsRequest final : public RequestActor<> { - vector user_ids_; - - void do_run(Promise &&promise) final { - user_ids_ = td_->inline_queries_manager_->get_recent_inline_bots(std::move(promise)); - } - - void do_send_result() final { - send_result(td_->user_manager_->get_users_object(-1, user_ids_)); - } - - public: - GetRecentInlineBotsRequest(ActorShared td, uint64 request_id) : RequestActor(std::move(td), request_id) { - } -}; - -class GetChatNotificationSettingsExceptionsRequest final : public RequestActor<> { - NotificationSettingsScope scope_; - bool filter_scope_; - bool compare_sound_; - - vector dialog_ids_; - - void do_run(Promise &&promise) final { - dialog_ids_ = td_->messages_manager_->get_dialog_notification_settings_exceptions( - scope_, filter_scope_, compare_sound_, get_tries() < 3, std::move(promise)); - } - - void do_send_result() final { - send_result( - td_->dialog_manager_->get_chats_object(-1, dialog_ids_, "GetChatNotificationSettingsExceptionsRequest")); - } - - public: - GetChatNotificationSettingsExceptionsRequest(ActorShared td, uint64 request_id, NotificationSettingsScope scope, - bool filter_scope, bool compare_sound) - : RequestActor(std::move(td), request_id) - , scope_(scope) - , filter_scope_(filter_scope) - , compare_sound_(compare_sound) { - set_tries(3); - } -}; - -class GetScopeNotificationSettingsRequest final : public RequestActor<> { - NotificationSettingsScope scope_; - - const ScopeNotificationSettings *notification_settings_ = nullptr; - - void do_run(Promise &&promise) final { - notification_settings_ = - td_->notification_settings_manager_->get_scope_notification_settings(scope_, std::move(promise)); - } - - void do_send_result() final { - CHECK(notification_settings_ != nullptr); - send_result(get_scope_notification_settings_object(notification_settings_)); - } - - public: - GetScopeNotificationSettingsRequest(ActorShared td, uint64 request_id, NotificationSettingsScope scope) - : RequestActor(std::move(td), request_id), scope_(scope) { - } -}; - -class GetStickersRequest final : public RequestActor<> { - StickerType sticker_type_; - string query_; - int32 limit_; - DialogId dialog_id_; - - vector sticker_ids_; - - void do_run(Promise &&promise) final { - sticker_ids_ = td_->stickers_manager_->get_stickers(sticker_type_, query_, limit_, dialog_id_, get_tries() < 2, - std::move(promise)); - } - - void do_send_result() final { - send_result(td_->stickers_manager_->get_stickers_object(sticker_ids_)); - } - - public: - GetStickersRequest(ActorShared td, uint64 request_id, StickerType sticker_type, string &&query, int32 limit, - int64 dialog_id) - : RequestActor(std::move(td), request_id) - , sticker_type_(sticker_type) - , query_(std::move(query)) - , limit_(limit) - , dialog_id_(dialog_id) { - set_tries(4); - } -}; - -class GetAllStickerEmojisRequest final : public RequestActor<> { - StickerType sticker_type_; - string query_; - DialogId dialog_id_; - bool return_only_main_emoji_; - - vector sticker_ids_; - - void do_run(Promise &&promise) final { - sticker_ids_ = td_->stickers_manager_->get_stickers(sticker_type_, query_, 1000000, dialog_id_, get_tries() < 2, - std::move(promise)); - } - - void do_send_result() final { - send_result(td_->stickers_manager_->get_sticker_emojis_object(sticker_ids_, return_only_main_emoji_)); - } - - public: - GetAllStickerEmojisRequest(ActorShared td, uint64 request_id, StickerType sticker_type, string &&query, - int64 dialog_id, bool return_only_main_emoji) - : RequestActor(std::move(td), request_id) - , sticker_type_(sticker_type) - , query_(std::move(query)) - , dialog_id_(dialog_id) - , return_only_main_emoji_(return_only_main_emoji) { - set_tries(4); - } -}; - -class GetInstalledStickerSetsRequest final : public RequestActor<> { - StickerType sticker_type_; - - vector sticker_set_ids_; - - void do_run(Promise &&promise) final { - sticker_set_ids_ = td_->stickers_manager_->get_installed_sticker_sets(sticker_type_, std::move(promise)); - } - - void do_send_result() final { - send_result(td_->stickers_manager_->get_sticker_sets_object(-1, sticker_set_ids_, 1)); - } - - public: - GetInstalledStickerSetsRequest(ActorShared td, uint64 request_id, StickerType sticker_type) - : RequestActor(std::move(td), request_id), sticker_type_(sticker_type) { - } -}; - -class GetArchivedStickerSetsRequest final : public RequestActor<> { - StickerType sticker_type_; - StickerSetId offset_sticker_set_id_; - int32 limit_; - - int32 total_count_ = -1; - vector sticker_set_ids_; - - void do_run(Promise &&promise) final { - std::tie(total_count_, sticker_set_ids_) = td_->stickers_manager_->get_archived_sticker_sets( - sticker_type_, offset_sticker_set_id_, limit_, get_tries() < 2, std::move(promise)); - } - - void do_send_result() final { - send_result(td_->stickers_manager_->get_sticker_sets_object(total_count_, sticker_set_ids_, 1)); - } - - public: - GetArchivedStickerSetsRequest(ActorShared td, uint64 request_id, StickerType sticker_type, - int64 offset_sticker_set_id, int32 limit) - : RequestActor(std::move(td), request_id) - , sticker_type_(sticker_type) - , offset_sticker_set_id_(offset_sticker_set_id) - , limit_(limit) { - } -}; - -class GetTrendingStickerSetsRequest final : public RequestActor<> { - td_api::object_ptr result_; - StickerType sticker_type_; - int32 offset_; - int32 limit_; - - void do_run(Promise &&promise) final { - result_ = td_->stickers_manager_->get_featured_sticker_sets(sticker_type_, offset_, limit_, std::move(promise)); - } - - void do_send_result() final { - send_result(std::move(result_)); - } - - public: - GetTrendingStickerSetsRequest(ActorShared td, uint64 request_id, StickerType sticker_type, int32 offset, - int32 limit) - : RequestActor(std::move(td), request_id), sticker_type_(sticker_type), offset_(offset), limit_(limit) { - set_tries(3); - } -}; - -class GetAttachedStickerSetsRequest final : public RequestActor<> { - FileId file_id_; - - vector sticker_set_ids_; - - void do_run(Promise &&promise) final { - sticker_set_ids_ = td_->stickers_manager_->get_attached_sticker_sets(file_id_, std::move(promise)); - } - - void do_send_result() final { - send_result(td_->stickers_manager_->get_sticker_sets_object(-1, sticker_set_ids_, 5)); - } - - public: - GetAttachedStickerSetsRequest(ActorShared td, uint64 request_id, int32 file_id) - : RequestActor(std::move(td), request_id), file_id_(file_id, 0) { - } -}; - -class GetStickerSetRequest final : public RequestActor<> { - StickerSetId set_id_; - - StickerSetId sticker_set_id_; - - void do_run(Promise &&promise) final { - sticker_set_id_ = td_->stickers_manager_->get_sticker_set(set_id_, std::move(promise)); - } - - void do_send_result() final { - send_result(td_->stickers_manager_->get_sticker_set_object(sticker_set_id_)); - } - - public: - GetStickerSetRequest(ActorShared td, uint64 request_id, int64 set_id) - : RequestActor(std::move(td), request_id), set_id_(set_id) { - set_tries(3); - } -}; - -class SearchStickerSetRequest final : public RequestActor<> { - string name_; - - StickerSetId sticker_set_id_; - - void do_run(Promise &&promise) final { - sticker_set_id_ = td_->stickers_manager_->search_sticker_set(name_, std::move(promise)); - } - - void do_send_result() final { - send_result(td_->stickers_manager_->get_sticker_set_object(sticker_set_id_)); - } - - public: - SearchStickerSetRequest(ActorShared td, uint64 request_id, string &&name) - : RequestActor(std::move(td), request_id), name_(std::move(name)) { - set_tries(3); - } -}; - -class SearchInstalledStickerSetsRequest final : public RequestActor<> { - StickerType sticker_type_; - string query_; - int32 limit_; - - std::pair> sticker_set_ids_; - - void do_run(Promise &&promise) final { - sticker_set_ids_ = - td_->stickers_manager_->search_installed_sticker_sets(sticker_type_, query_, limit_, std::move(promise)); - } - - void do_send_result() final { - send_result(td_->stickers_manager_->get_sticker_sets_object(sticker_set_ids_.first, sticker_set_ids_.second, 5)); - } - - public: - SearchInstalledStickerSetsRequest(ActorShared td, uint64 request_id, StickerType sticker_type, string &&query, - int32 limit) - : RequestActor(std::move(td), request_id), sticker_type_(sticker_type), query_(std::move(query)), limit_(limit) { - } -}; - -class SearchStickerSetsRequest final : public RequestActor<> { - StickerType sticker_type_; - string query_; - - vector sticker_set_ids_; - - void do_run(Promise &&promise) final { - sticker_set_ids_ = td_->stickers_manager_->search_sticker_sets(sticker_type_, query_, std::move(promise)); - } - - void do_send_result() final { - send_result(td_->stickers_manager_->get_sticker_sets_object(-1, sticker_set_ids_, 5)); - } - - public: - SearchStickerSetsRequest(ActorShared td, uint64 request_id, StickerType sticker_type, string &&query) - : RequestActor(std::move(td), request_id), sticker_type_(sticker_type), query_(std::move(query)) { - } -}; - -class ChangeStickerSetRequest final : public RequestOnceActor { - StickerSetId set_id_; - bool is_installed_; - bool is_archived_; - - void do_run(Promise &&promise) final { - td_->stickers_manager_->change_sticker_set(set_id_, is_installed_, is_archived_, std::move(promise)); - } - - public: - ChangeStickerSetRequest(ActorShared td, uint64 request_id, int64 set_id, bool is_installed, bool is_archived) - : RequestOnceActor(std::move(td), request_id) - , set_id_(set_id) - , is_installed_(is_installed) - , is_archived_(is_archived) { - set_tries(4); - } -}; - -class UploadStickerFileRequest final : public RequestOnceActor { - UserId user_id_; - StickerFormat sticker_format_; - td_api::object_ptr input_file_; - - FileId file_id; - - void do_run(Promise &&promise) final { - file_id = td_->stickers_manager_->upload_sticker_file(user_id_, sticker_format_, input_file_, std::move(promise)); - } - - void do_send_result() final { - send_result(td_->file_manager_->get_file_object(file_id)); - } - - public: - UploadStickerFileRequest(ActorShared td, uint64 request_id, int64 user_id, StickerFormat sticker_format, - td_api::object_ptr input_file) - : RequestOnceActor(std::move(td), request_id) - , user_id_(user_id) - , sticker_format_(sticker_format) - , input_file_(std::move(input_file)) { - } -}; - -class GetRecentStickersRequest final : public RequestActor<> { - bool is_attached_; - - vector sticker_ids_; - - void do_run(Promise &&promise) final { - sticker_ids_ = td_->stickers_manager_->get_recent_stickers(is_attached_, std::move(promise)); - } - - void do_send_result() final { - send_result(td_->stickers_manager_->get_stickers_object(sticker_ids_)); - } - - public: - GetRecentStickersRequest(ActorShared td, uint64 request_id, bool is_attached) - : RequestActor(std::move(td), request_id), is_attached_(is_attached) { - } -}; - -class AddRecentStickerRequest final : public RequestActor<> { - bool is_attached_; - tl_object_ptr input_file_; - - void do_run(Promise &&promise) final { - td_->stickers_manager_->add_recent_sticker(is_attached_, input_file_, std::move(promise)); - } - - public: - AddRecentStickerRequest(ActorShared td, uint64 request_id, bool is_attached, - tl_object_ptr &&input_file) - : RequestActor(std::move(td), request_id), is_attached_(is_attached), input_file_(std::move(input_file)) { - set_tries(3); - } -}; - -class RemoveRecentStickerRequest final : public RequestActor<> { - bool is_attached_; - tl_object_ptr input_file_; - - void do_run(Promise &&promise) final { - td_->stickers_manager_->remove_recent_sticker(is_attached_, input_file_, std::move(promise)); - } - - public: - RemoveRecentStickerRequest(ActorShared td, uint64 request_id, bool is_attached, - tl_object_ptr &&input_file) - : RequestActor(std::move(td), request_id), is_attached_(is_attached), input_file_(std::move(input_file)) { - set_tries(3); - } -}; - -class ClearRecentStickersRequest final : public RequestActor<> { - bool is_attached_; - - void do_run(Promise &&promise) final { - td_->stickers_manager_->clear_recent_stickers(is_attached_, std::move(promise)); - } - - public: - ClearRecentStickersRequest(ActorShared td, uint64 request_id, bool is_attached) - : RequestActor(std::move(td), request_id), is_attached_(is_attached) { - set_tries(3); - } -}; - -class GetFavoriteStickersRequest final : public RequestActor<> { - vector sticker_ids_; - - void do_run(Promise &&promise) final { - sticker_ids_ = td_->stickers_manager_->get_favorite_stickers(std::move(promise)); - } - - void do_send_result() final { - send_result(td_->stickers_manager_->get_stickers_object(sticker_ids_)); - } - - public: - GetFavoriteStickersRequest(ActorShared td, uint64 request_id) : RequestActor(std::move(td), request_id) { - } -}; - -class AddFavoriteStickerRequest final : public RequestOnceActor { - tl_object_ptr input_file_; - - void do_run(Promise &&promise) final { - td_->stickers_manager_->add_favorite_sticker(input_file_, std::move(promise)); - } - - public: - AddFavoriteStickerRequest(ActorShared td, uint64 request_id, tl_object_ptr &&input_file) - : RequestOnceActor(std::move(td), request_id), input_file_(std::move(input_file)) { - set_tries(3); - } -}; - -class RemoveFavoriteStickerRequest final : public RequestOnceActor { - tl_object_ptr input_file_; - - void do_run(Promise &&promise) final { - td_->stickers_manager_->remove_favorite_sticker(input_file_, std::move(promise)); - } - - public: - RemoveFavoriteStickerRequest(ActorShared td, uint64 request_id, tl_object_ptr &&input_file) - : RequestOnceActor(std::move(td), request_id), input_file_(std::move(input_file)) { - set_tries(3); - } -}; - -class GetStickerEmojisRequest final : public RequestActor<> { - tl_object_ptr input_file_; - - vector emojis_; - - void do_run(Promise &&promise) final { - emojis_ = td_->stickers_manager_->get_sticker_emojis(input_file_, std::move(promise)); - } - - void do_send_result() final { - send_result(td_api::make_object(std::move(emojis_))); - } - - public: - GetStickerEmojisRequest(ActorShared td, uint64 request_id, tl_object_ptr &&input_file) - : RequestActor(std::move(td), request_id), input_file_(std::move(input_file)) { - set_tries(3); - } -}; - -class SearchEmojisRequest final : public RequestActor<> { - string text_; - vector input_language_codes_; - - vector> emoji_keywords_; - - void do_run(Promise &&promise) final { - emoji_keywords_ = - td_->stickers_manager_->search_emojis(text_, input_language_codes_, get_tries() < 2, std::move(promise)); - } - - void do_send_result() final { - send_result(td_api::make_object( - transform(emoji_keywords_, [](const std::pair &emoji_keyword) { - return td_api::make_object(emoji_keyword.first, emoji_keyword.second); - }))); - } - - public: - SearchEmojisRequest(ActorShared td, uint64 request_id, string &&text, vector &&input_language_codes) - : RequestActor(std::move(td), request_id) - , text_(std::move(text)) - , input_language_codes_(std::move(input_language_codes)) { - set_tries(3); - } -}; - -class GetKeywordEmojisRequest final : public RequestActor<> { - string text_; - vector input_language_codes_; - - vector emojis_; - - void do_run(Promise &&promise) final { - emojis_ = - td_->stickers_manager_->get_keyword_emojis(text_, input_language_codes_, get_tries() < 2, std::move(promise)); - } - - void do_send_result() final { - send_result(td_api::make_object(std::move(emojis_))); - } - - public: - GetKeywordEmojisRequest(ActorShared td, uint64 request_id, string &&text, vector &&input_language_codes) - : RequestActor(std::move(td), request_id) - , text_(std::move(text)) - , input_language_codes_(std::move(input_language_codes)) { - set_tries(3); - } -}; - -class GetEmojiSuggestionsUrlRequest final : public RequestOnceActor { - string language_code_; - - int64 random_id_; - - void do_run(Promise &&promise) final { - random_id_ = td_->stickers_manager_->get_emoji_suggestions_url(language_code_, std::move(promise)); - } - - void do_send_result() final { - send_result(td_->stickers_manager_->get_emoji_suggestions_url_result(random_id_)); - } - - public: - GetEmojiSuggestionsUrlRequest(ActorShared td, uint64 request_id, string &&language_code) - : RequestOnceActor(std::move(td), request_id), language_code_(std::move(language_code)), random_id_(0) { - } -}; - -class GetSavedAnimationsRequest final : public RequestActor<> { - vector animation_ids_; - - void do_run(Promise &&promise) final { - animation_ids_ = td_->animations_manager_->get_saved_animations(std::move(promise)); - } - - void do_send_result() final { - send_result(make_tl_object(transform(animation_ids_, [td = td_](FileId animation_id) { - return td->animations_manager_->get_animation_object(animation_id); - }))); - } - - public: - GetSavedAnimationsRequest(ActorShared td, uint64 request_id) : RequestActor(std::move(td), request_id) { - } -}; - -class AddSavedAnimationRequest final : public RequestOnceActor { - tl_object_ptr input_file_; - - void do_run(Promise &&promise) final { - td_->animations_manager_->add_saved_animation(input_file_, std::move(promise)); - } - - public: - AddSavedAnimationRequest(ActorShared td, uint64 request_id, tl_object_ptr &&input_file) - : RequestOnceActor(std::move(td), request_id), input_file_(std::move(input_file)) { - set_tries(3); - } -}; - -class RemoveSavedAnimationRequest final : public RequestOnceActor { - tl_object_ptr input_file_; - - void do_run(Promise &&promise) final { - td_->animations_manager_->remove_saved_animation(input_file_, std::move(promise)); - } - - public: - RemoveSavedAnimationRequest(ActorShared td, uint64 request_id, tl_object_ptr &&input_file) - : RequestOnceActor(std::move(td), request_id), input_file_(std::move(input_file)) { - set_tries(3); - } -}; - -class GetSavedNotificationSoundRequest final : public RequestActor<> { - int64 ringtone_id_; - FileId ringtone_file_id_; - - void do_run(Promise &&promise) final { - ringtone_file_id_ = td_->notification_settings_manager_->get_saved_ringtone(ringtone_id_, std::move(promise)); - } - - void do_send_result() final { - send_result(td_->audios_manager_->get_notification_sound_object(ringtone_file_id_)); - } - - public: - GetSavedNotificationSoundRequest(ActorShared td, uint64 request_id, int64 ringtone_id) - : RequestActor(std::move(td), request_id), ringtone_id_(ringtone_id) { - } -}; - -class GetSavedNotificationSoundsRequest final : public RequestActor<> { - vector ringtone_file_ids_; - - void do_run(Promise &&promise) final { - ringtone_file_ids_ = td_->notification_settings_manager_->get_saved_ringtones(std::move(promise)); - } - - void do_send_result() final { - send_result(td_api::make_object( - transform(ringtone_file_ids_, [td = td_](FileId ringtone_file_id) { - return td->audios_manager_->get_notification_sound_object(ringtone_file_id); - }))); - } - - public: - GetSavedNotificationSoundsRequest(ActorShared td, uint64 request_id) : RequestActor(std::move(td), request_id) { - } -}; - -class RemoveSavedNotificationSoundRequest final : public RequestOnceActor { - int64 ringtone_id_; - - void do_run(Promise &&promise) final { - td_->notification_settings_manager_->remove_saved_ringtone(ringtone_id_, std::move(promise)); - } - - public: - RemoveSavedNotificationSoundRequest(ActorShared td, uint64 request_id, int64 ringtone_id) - : RequestOnceActor(std::move(td), request_id), ringtone_id_(ringtone_id) { - set_tries(3); - } -}; - -class SearchBackgroundRequest final : public RequestActor<> { - string name_; - - std::pair background_; - - void do_run(Promise &&promise) final { - background_ = td_->background_manager_->search_background(name_, std::move(promise)); - } - - void do_send_result() final { - send_result(td_->background_manager_->get_background_object(background_.first, false, &background_.second)); - } - - public: - SearchBackgroundRequest(ActorShared td, uint64 request_id, string &&name) - : RequestActor(std::move(td), request_id), name_(std::move(name)) { - set_tries(3); - } -}; - -Td::Td(unique_ptr callback, Options options) - : callback_(std::move(callback)), td_options_(std::move(options)) { - CHECK(callback_ != nullptr); - LOG(INFO) << "Create Td with layer " << MTPROTO_LAYER << ", database version " << current_db_version() - << " and version " << static_cast(Version::Next) - 1 << " on " - << Scheduler::instance()->sched_count() << " threads"; -} - -Td::~Td() = default; - -void Td::on_alarm_timeout_callback(void *td_ptr, int64 alarm_id) { - auto td = static_cast(td_ptr); - auto td_id = td->actor_id(td); - send_closure_later(td_id, &Td::on_alarm_timeout, alarm_id); -} - -void Td::on_alarm_timeout(int64 alarm_id) { - if (close_flag_ >= 2) { - // pending_alarms_ was already cleared - return; - } - - auto it = pending_alarms_.find(alarm_id); - CHECK(it != pending_alarms_.end()); - uint64 request_id = it->second; - pending_alarms_.erase(alarm_id); - send_result(request_id, make_tl_object()); -} - -bool Td::ignore_background_updates() const { - return can_ignore_background_updates_ && option_manager_->get_option_boolean("ignore_background_updates"); -} - -bool Td::is_authentication_request(int32 id) { - switch (id) { - case td_api::setTdlibParameters::ID: - case td_api::getAuthorizationState::ID: - case td_api::setAuthenticationPhoneNumber::ID: - case td_api::sendAuthenticationFirebaseSms::ID: - case td_api::reportAuthenticationCodeMissing::ID: - case td_api::setAuthenticationEmailAddress::ID: - case td_api::resendAuthenticationCode::ID: - case td_api::checkAuthenticationEmailCode::ID: - case td_api::checkAuthenticationCode::ID: - case td_api::registerUser::ID: - case td_api::requestQrCodeAuthentication::ID: - case td_api::resetAuthenticationEmailAddress::ID: - case td_api::checkAuthenticationPassword::ID: - case td_api::requestAuthenticationPasswordRecovery::ID: - case td_api::checkAuthenticationPasswordRecoveryCode::ID: - case td_api::recoverAuthenticationPassword::ID: - case td_api::deleteAccount::ID: - case td_api::logOut::ID: - case td_api::close::ID: - case td_api::destroy::ID: - case td_api::checkAuthenticationBotToken::ID: - return true; - default: - return false; - } -} - -bool Td::is_preinitialization_request(int32 id) { - switch (id) { - case td_api::getCurrentState::ID: - case td_api::setAlarm::ID: - case td_api::testUseUpdate::ID: - case td_api::testCallEmpty::ID: - case td_api::testSquareInt::ID: - case td_api::testCallString::ID: - case td_api::testCallBytes::ID: - case td_api::testCallVectorInt::ID: - case td_api::testCallVectorIntObject::ID: - case td_api::testCallVectorString::ID: - case td_api::testCallVectorStringObject::ID: - case td_api::testProxy::ID: - return true; - default: - return false; - } -} - -bool Td::is_preauthentication_request(int32 id) { - switch (id) { - case td_api::getInternalLink::ID: - case td_api::getInternalLinkType::ID: - case td_api::getLocalizationTargetInfo::ID: - case td_api::getLanguagePackInfo::ID: - case td_api::getLanguagePackStrings::ID: - case td_api::synchronizeLanguagePack::ID: - case td_api::addCustomServerLanguagePack::ID: - case td_api::setCustomLanguagePack::ID: - case td_api::editCustomLanguagePackInfo::ID: - case td_api::setCustomLanguagePackString::ID: - case td_api::deleteLanguagePack::ID: - case td_api::processPushNotification::ID: - case td_api::getOption::ID: - case td_api::setOption::ID: - case td_api::getStorageStatistics::ID: - case td_api::getStorageStatisticsFast::ID: - case td_api::getDatabaseStatistics::ID: - case td_api::setNetworkType::ID: - case td_api::getNetworkStatistics::ID: - case td_api::addNetworkStatistics::ID: - case td_api::resetNetworkStatistics::ID: - case td_api::setApplicationVerificationToken::ID: - case td_api::getCountries::ID: - case td_api::getCountryCode::ID: - case td_api::getPhoneNumberInfo::ID: - case td_api::getDeepLinkInfo::ID: - case td_api::getApplicationConfig::ID: - case td_api::saveApplicationLogEvent::ID: - case td_api::addProxy::ID: - case td_api::editProxy::ID: - case td_api::enableProxy::ID: - case td_api::disableProxy::ID: - case td_api::removeProxy::ID: - case td_api::getProxies::ID: - case td_api::getProxyLink::ID: - case td_api::pingProxy::ID: - case td_api::testNetwork::ID: - return true; - default: - return false; - } -} - -td_api::object_ptr Td::get_fake_authorization_state_object() const { - switch (state_) { - case State::WaitParameters: - return td_api::make_object(); - case State::Run: - UNREACHABLE(); - return nullptr; - case State::Close: - if (close_flag_ == 5) { - return td_api::make_object(); - } else { - return td_api::make_object(); - } - default: - UNREACHABLE(); - return nullptr; - } -} - -vector> Td::get_fake_current_state() const { - CHECK(state_ != State::Run); - vector> updates; - OptionManager::get_common_state(updates); - updates.push_back(td_api::make_object(get_fake_authorization_state_object())); - return updates; -} - -void Td::request(uint64 id, tl_object_ptr function) { - if (id == 0) { - LOG(ERROR) << "Ignore request with ID == 0: " << to_string(function); - return; - } - - if (function == nullptr) { - return callback_->on_error(id, make_error(400, "Request is empty")); - } - - VLOG(td_requests) << "Receive request " << id << ": " << to_string(function); - request_set_.emplace(id, function->get_id()); - if (SynchronousRequests::is_synchronous_request(function.get())) { - // send response synchronously - return send_result(id, static_request(std::move(function))); - } - - run_request(id, std::move(function)); -} - -void Td::run_request(uint64 id, td_api::object_ptr function) { - if (set_parameters_request_id_ > 0) { - pending_set_parameters_requests_.emplace_back(id, std::move(function)); - return; - } - - int32 function_id = function->get_id(); - if (state_ != State::Run) { - switch (function_id) { - case td_api::getAuthorizationState::ID: - // send response synchronously to prevent "Request aborted" - return send_result(id, get_fake_authorization_state_object()); - case td_api::getCurrentState::ID: - // send response synchronously to prevent "Request aborted" - return send_result(id, td_api::make_object(get_fake_current_state())); - case td_api::close::ID: - // need to send response before actual closing - send_closure(actor_id(this), &Td::send_result, id, td_api::make_object()); - send_closure(actor_id(this), &Td::close); - return; - default: - break; - } - } - switch (state_) { - case State::WaitParameters: { - switch (function_id) { - case td_api::setTdlibParameters::ID: { - auto r_parameters = get_parameters(move_tl_object_as(function)); - if (r_parameters.is_error()) { - return send_closure(actor_id(this), &Td::send_error, id, r_parameters.move_as_error()); - } - auto parameters = r_parameters.move_as_ok(); - - VLOG(td_init) << "Begin to open database"; - set_parameters_request_id_ = id; - can_ignore_background_updates_ = !parameters.second.use_chat_info_database_ && - !parameters.second.use_message_database_ && - !parameters.first.use_secret_chats_; - - auto promise = PromiseCreator::lambda( - [actor_id = actor_id(this), parameters = std::move(parameters.first), - parent = create_reference()](Result r_opened_database) mutable { - send_closure(actor_id, &Td::init, std::move(parameters), std::move(r_opened_database)); - }); - auto use_sqlite_pmc = parameters.second.use_message_database_ || parameters.second.use_chat_info_database_ || - parameters.second.use_file_database_; - return TdDb::open(use_sqlite_pmc ? G()->get_database_scheduler_id() : G()->get_slow_net_scheduler_id(), - std::move(parameters.second), std::move(promise)); - } - default: - if (is_preinitialization_request(function_id)) { - return do_run_request(id, std::move(function)); - } - if (is_preauthentication_request(function_id)) { - pending_preauthentication_requests_.emplace_back(id, std::move(function)); - return; - } - return send_error_impl( - id, make_error(400, "Initialization parameters are needed: call setTdlibParameters first")); - } - UNREACHABLE(); - } - case State::Close: - return send_error_impl(id, make_error(destroy_flag_ ? 401 : 500, - destroy_flag_ ? CSlice("Unauthorized") : CSlice("Request aborted"))); - case State::Run: - if (!auth_manager_->is_authorized() && !is_preauthentication_request(function_id) && - !is_preinitialization_request(function_id) && !is_authentication_request(function_id)) { - return send_error_impl(id, make_error(401, "Unauthorized")); - } - return do_run_request(id, std::move(function)); - default: - UNREACHABLE(); - } -} - -void Td::do_run_request(uint64 id, td_api::object_ptr &&function) { - downcast_call(*function, [this, id](auto &request) { this->on_request(id, request); }); -} - -td_api::object_ptr Td::static_request(td_api::object_ptr function) { - return SynchronousRequests::run_request(std::move(function)); -} - -void Td::add_handler(uint64 id, std::shared_ptr handler) { - result_handlers_[id] = std::move(handler); -} - -std::shared_ptr Td::extract_handler(uint64 id) { - auto it = result_handlers_.find(id); - if (it == result_handlers_.end()) { - return nullptr; - } - auto result = std::move(it->second); - result_handlers_.erase(it); - return result; -} - -void Td::on_update(telegram_api::object_ptr updates, uint64 auth_key_id) { - if (close_flag_ > 1) { - return; - } - - if (updates == nullptr) { - if (auth_manager_->is_bot()) { - G()->net_query_dispatcher().update_mtproto_header(); - } else { - // this could be a min-channel update - updates_manager_->schedule_get_difference("failed to fetch updates"); - } - } else { - updates_manager_->on_update_from_auth_key_id(auth_key_id); - updates_manager_->on_get_updates(std::move(updates), Promise()); - if (auth_manager_->is_bot() && auth_manager_->is_authorized()) { - online_manager_->set_is_bot_online(true); - } - } -} - -void Td::on_result(NetQueryPtr query) { - query->debug("Td: received from DcManager"); - VLOG(net_query) << "Receive result of " << query; - if (close_flag_ > 1) { - return; - } - - auto handler = extract_handler(query->id()); - if (handler != nullptr) { - CHECK(query->is_ready()); - if (query->is_ok()) { - handler->on_result(query->move_as_ok()); - } else { - handler->on_error(query->move_as_error()); - } - } else { - if (!query->is_ok() || query->ok_tl_constructor() != telegram_api::upload_file::ID) { - LOG(WARNING) << query << " is ignored: no handlers found"; - } - query->clear(); - } -} - -void Td::start_up() { - uint64 check_endianness = 0x0706050403020100; - auto check_endianness_raw = reinterpret_cast(&check_endianness); - for (unsigned char c = 0; c < 8; c++) { - auto symbol = check_endianness_raw[static_cast(c)]; - LOG_IF(FATAL, symbol != c) << "TDLib requires little-endian platform"; - } - - VLOG(td_init) << "Create Global"; - old_context_ = set_context(std::make_shared()); - G()->set_net_query_stats(td_options_.net_query_stats); - inc_request_actor_refcnt(); // guard - inc_actor_refcnt(); // guard - - alarm_timeout_.set_callback(on_alarm_timeout_callback); - alarm_timeout_.set_callback_data(static_cast(this)); - - CHECK(state_ == State::WaitParameters); - for (auto &update : get_fake_current_state()) { - send_update(std::move(update)); - } -} - -void Td::tear_down() { - LOG_CHECK(close_flag_ == 5) << close_flag_; -} - -void Td::hangup_shared() { - auto token = get_link_token(); - auto type = Container::type_from_id(token); - - if (type == RequestActorIdType) { - request_actors_.erase(token); - dec_request_actor_refcnt(); - } else if (type == ActorIdType) { - dec_actor_refcnt(); - } else { - LOG(FATAL) << "Unknown hangup_shared of type " << type; - } -} - -void Td::hangup() { - LOG(INFO) << "Receive Td::hangup"; - close(); - dec_stop_cnt(); -} - -ActorShared Td::create_reference() { - inc_actor_refcnt(); - return actor_shared(this, ActorIdType); -} - -void Td::inc_actor_refcnt() { - actor_refcnt_++; -} - -void Td::dec_actor_refcnt() { - actor_refcnt_--; - if (actor_refcnt_ < 3) { - LOG(DEBUG) << "Decrease reference count to " << actor_refcnt_; - } - if (actor_refcnt_ == 0) { - if (close_flag_ == 2) { - create_reference(); - close_flag_ = 3; - } else if (close_flag_ == 3) { - LOG(INFO) << "All actors were closed"; - Timer timer; - auto reset_manager = [&timer](auto &manager, Slice name) { - manager.reset(); - LOG(DEBUG) << name << " was cleared" << timer; - }; - reset_manager(account_manager_, "AccountManager"); - reset_manager(animations_manager_, "AnimationsManager"); - reset_manager(attach_menu_manager_, "AttachMenuManager"); - reset_manager(audios_manager_, "AudiosManager"); - reset_manager(auth_manager_, "AuthManager"); - reset_manager(autosave_manager_, "AutosaveManager"); - reset_manager(background_manager_, "BackgroundManager"); - reset_manager(boost_manager_, "BoostManager"); - reset_manager(bot_info_manager_, "BotInfoManager"); - reset_manager(business_connection_manager_, "BusinessConnectionManager"); - reset_manager(business_manager_, "BusinessManager"); - reset_manager(callback_queries_manager_, "CallbackQueriesManager"); - reset_manager(channel_recommendation_manager_, "ChannelRecommendationManager"); - reset_manager(chat_manager_, "ChatManager"); - reset_manager(common_dialog_manager_, "CommonDialogManager"); - reset_manager(connection_state_manager_, "ConnectionStateManager"); - reset_manager(country_info_manager_, "CountryInfoManager"); - reset_manager(dialog_action_manager_, "DialogActionManager"); - reset_manager(dialog_filter_manager_, "DialogFilterManager"); - reset_manager(dialog_invite_link_manager_, "DialogInviteLinkManager"); - reset_manager(dialog_manager_, "DialogManager"); - reset_manager(dialog_participant_manager_, "DialogParticipantManager"); - reset_manager(documents_manager_, "DocumentsManager"); - reset_manager(download_manager_, "DownloadManager"); - reset_manager(file_manager_, "FileManager"); - reset_manager(file_reference_manager_, "FileReferenceManager"); - reset_manager(forum_topic_manager_, "ForumTopicManager"); - reset_manager(game_manager_, "GameManager"); - reset_manager(group_call_manager_, "GroupCallManager"); - reset_manager(inline_message_manager_, "InlineMessageManager"); - reset_manager(inline_queries_manager_, "InlineQueriesManager"); - reset_manager(link_manager_, "LinkManager"); - reset_manager(message_import_manager_, "MessageImportManager"); - reset_manager(messages_manager_, "MessagesManager"); - reset_manager(notification_manager_, "NotificationManager"); - reset_manager(notification_settings_manager_, "NotificationSettingsManager"); - reset_manager(online_manager_, "OnlineManager"); - reset_manager(people_nearby_manager_, "PeopleNearbyManager"); - reset_manager(phone_number_manager_, "PhoneNumberManager"); - reset_manager(poll_manager_, "PollManager"); - reset_manager(privacy_manager_, "PrivacyManager"); - reset_manager(promo_data_manager_, "PromoDataManager"); - reset_manager(quick_reply_manager_, "QuickReplyManager"); - reset_manager(reaction_manager_, "ReactionManager"); - reset_manager(saved_messages_manager_, "SavedMessagesManager"); - reset_manager(sponsored_message_manager_, "SponsoredMessageManager"); - reset_manager(star_manager_, "StarManager"); - reset_manager(statistics_manager_, "StatisticsManager"); - reset_manager(stickers_manager_, "StickersManager"); - reset_manager(story_manager_, "StoryManager"); - reset_manager(terms_of_service_manager_, "TermsOfServiceManager"); - reset_manager(theme_manager_, "ThemeManager"); - reset_manager(time_zone_manager_, "TimeZoneManager"); - reset_manager(top_dialog_manager_, "TopDialogManager"); - reset_manager(transcription_manager_, "TranscriptionManager"); - reset_manager(translation_manager_, "TranslationManager"); - reset_manager(updates_manager_, "UpdatesManager"); - reset_manager(user_manager_, "UserManager"); - reset_manager(video_notes_manager_, "VideoNotesManager"); - reset_manager(videos_manager_, "VideosManager"); - reset_manager(voice_notes_manager_, "VoiceNotesManager"); - reset_manager(web_pages_manager_, "WebPagesManager"); - - G()->set_option_manager(nullptr); - option_manager_.reset(); - LOG(DEBUG) << "OptionManager was cleared" << timer; - - G()->close_all(destroy_flag_, - PromiseCreator::lambda([actor_id = create_reference()](Unit) mutable { actor_id.reset(); })); - - // NetQueryDispatcher will be closed automatically - close_flag_ = 4; - } else if (close_flag_ == 4) { - on_closed(); - } else { - UNREACHABLE(); - } - } -} - -void Td::on_closed() { - close_flag_ = 5; - send_update( - td_api::make_object(td_api::make_object())); - dec_stop_cnt(); -} - -void Td::dec_stop_cnt() { - stop_cnt_--; - if (stop_cnt_ == 0) { - LOG(INFO) << "Stop Td"; - set_context(std::move(old_context_)); - stop(); - } -} - -void Td::inc_request_actor_refcnt() { - request_actor_refcnt_++; -} - -void Td::dec_request_actor_refcnt() { - request_actor_refcnt_--; - LOG(DEBUG) << "Decrease request actor count to " << request_actor_refcnt_; - if (request_actor_refcnt_ == 0) { - clear(); - dec_actor_refcnt(); // remove guard - } -} - -void Td::clear_requests() { - while (!pending_alarms_.empty()) { - auto it = pending_alarms_.begin(); - auto alarm_id = it->first; - pending_alarms_.erase(it); - alarm_timeout_.cancel_timeout(alarm_id); - } - while (!request_set_.empty()) { - uint64 id = request_set_.begin()->first; - if (destroy_flag_) { - send_error_impl(id, make_error(401, "Unauthorized")); - } else { - send_error_impl(id, make_error(500, "Request aborted")); - } - } -} - -void Td::clear() { - if (close_flag_ >= 2) { - return; - } - - LOG(INFO) << "Clear Td"; - close_flag_ = 2; - - Timer timer; - if (!auth_manager_->is_bot()) { - if (destroy_flag_) { - notification_manager_->destroy_all_notifications(); - } else { - notification_manager_->flush_all_notifications(); - } - } - - G()->net_query_creator().stop_check(); - result_handlers_.clear(); - LOG(DEBUG) << "Handlers were cleared" << timer; - G()->net_query_dispatcher().stop(); - LOG(DEBUG) << "NetQueryDispatcher was stopped" << timer; - state_manager_.reset(); - LOG(DEBUG) << "StateManager was cleared" << timer; - clear_requests(); - - auto reset_actor = [&timer](ActorOwn actor) { - if (!actor.empty()) { - LOG(DEBUG) << "Start clearing " << actor.get().get_name() << timer; - } - }; - - // close all pure actors - reset_actor(ActorOwn(std::move(call_manager_))); - reset_actor(ActorOwn(std::move(cashtag_search_hints_))); - reset_actor(ActorOwn(std::move(config_manager_))); - reset_actor(ActorOwn(std::move(device_token_manager_))); - reset_actor(ActorOwn(std::move(hashtag_hints_))); - reset_actor(ActorOwn(std::move(hashtag_search_hints_))); - reset_actor(ActorOwn(std::move(language_pack_manager_))); - reset_actor(ActorOwn(std::move(net_stats_manager_))); - reset_actor(ActorOwn(std::move(password_manager_))); - reset_actor(ActorOwn(std::move(secure_manager_))); - reset_actor(ActorOwn(std::move(secret_chats_manager_))); - reset_actor(ActorOwn(std::move(storage_manager_))); - - G()->set_connection_creator(ActorOwn()); - LOG(DEBUG) << "ConnectionCreator was cleared" << timer; - G()->set_temp_auth_key_watchdog(ActorOwn()); - LOG(DEBUG) << "TempAuthKeyWatchdog was cleared" << timer; - - // clear actors which are unique pointers - reset_actor(ActorOwn(std::move(account_manager_actor_))); - reset_actor(ActorOwn(std::move(animations_manager_actor_))); - reset_actor(ActorOwn(std::move(attach_menu_manager_actor_))); - reset_actor(ActorOwn(std::move(auth_manager_actor_))); - reset_actor(ActorOwn(std::move(autosave_manager_actor_))); - reset_actor(ActorOwn(std::move(background_manager_actor_))); - reset_actor(ActorOwn(std::move(boost_manager_actor_))); - reset_actor(ActorOwn(std::move(bot_info_manager_actor_))); - reset_actor(ActorOwn(std::move(business_connection_manager_actor_))); - reset_actor(ActorOwn(std::move(business_manager_actor_))); - reset_actor(ActorOwn(std::move(channel_recommendation_manager_actor_))); - reset_actor(ActorOwn(std::move(chat_manager_actor_))); - reset_actor(ActorOwn(std::move(common_dialog_manager_actor_))); - reset_actor(ActorOwn(std::move(connection_state_manager_actor_))); - reset_actor(ActorOwn(std::move(country_info_manager_actor_))); - reset_actor(ActorOwn(std::move(dialog_action_manager_actor_))); - reset_actor(ActorOwn(std::move(dialog_filter_manager_actor_))); - reset_actor(ActorOwn(std::move(dialog_invite_link_manager_actor_))); - reset_actor(ActorOwn(std::move(dialog_manager_actor_))); - reset_actor(ActorOwn(std::move(dialog_participant_manager_actor_))); - reset_actor(ActorOwn(std::move(download_manager_actor_))); - reset_actor(ActorOwn(std::move(file_manager_actor_))); - reset_actor(ActorOwn(std::move(file_reference_manager_actor_))); - reset_actor(ActorOwn(std::move(forum_topic_manager_actor_))); - reset_actor(ActorOwn(std::move(game_manager_actor_))); - reset_actor(ActorOwn(std::move(group_call_manager_actor_))); - reset_actor(ActorOwn(std::move(inline_message_manager_actor_))); - reset_actor(ActorOwn(std::move(inline_queries_manager_actor_))); - reset_actor(ActorOwn(std::move(link_manager_actor_))); - reset_actor(ActorOwn(std::move(message_import_manager_actor_))); - reset_actor(ActorOwn(std::move(messages_manager_actor_))); - reset_actor(ActorOwn(std::move(notification_manager_actor_))); - reset_actor(ActorOwn(std::move(notification_settings_manager_actor_))); - reset_actor(ActorOwn(std::move(online_manager_actor_))); - reset_actor(ActorOwn(std::move(people_nearby_manager_actor_))); - reset_actor(ActorOwn(std::move(phone_number_manager_actor_))); - reset_actor(ActorOwn(std::move(poll_manager_actor_))); - reset_actor(ActorOwn(std::move(privacy_manager_actor_))); - reset_actor(ActorOwn(std::move(promo_data_manager_actor_))); - reset_actor(ActorOwn(std::move(quick_reply_manager_actor_))); - reset_actor(ActorOwn(std::move(reaction_manager_actor_))); - reset_actor(ActorOwn(std::move(saved_messages_manager_actor_))); - reset_actor(ActorOwn(std::move(sponsored_message_manager_actor_))); - reset_actor(ActorOwn(std::move(star_manager_actor_))); - reset_actor(ActorOwn(std::move(statistics_manager_actor_))); - reset_actor(ActorOwn(std::move(stickers_manager_actor_))); - reset_actor(ActorOwn(std::move(story_manager_actor_))); - reset_actor(ActorOwn(std::move(terms_of_service_manager_actor_))); - reset_actor(ActorOwn(std::move(theme_manager_actor_))); - reset_actor(ActorOwn(std::move(time_zone_manager_actor_))); - reset_actor(ActorOwn(std::move(top_dialog_manager_actor_))); - reset_actor(ActorOwn(std::move(transcription_manager_actor_))); - reset_actor(ActorOwn(std::move(translation_manager_actor_))); - reset_actor(ActorOwn(std::move(updates_manager_actor_))); - reset_actor(ActorOwn(std::move(user_manager_actor_))); - reset_actor(ActorOwn(std::move(video_notes_manager_actor_))); - reset_actor(ActorOwn(std::move(voice_notes_manager_actor_))); - reset_actor(ActorOwn(std::move(web_pages_manager_actor_))); - LOG(DEBUG) << "All actors were cleared" << timer; -} - -void Td::close() { - close_impl(false); -} - -void Td::destroy() { - close_impl(true); -} - -void Td::close_impl(bool destroy_flag) { - destroy_flag_ |= destroy_flag; - if (close_flag_) { - return; - } - - LOG(WARNING) << (destroy_flag ? "Destroy" : "Close") << " Td in state " << static_cast(state_); - if (state_ == State::WaitParameters) { - state_ = State::Close; - close_flag_ = 4; - G()->set_close_flag(); - clear_requests(); - send_update(td_api::make_object( - td_api::make_object())); - - request_actors_.clear(); - return send_closure_later(actor_id(this), &Td::dec_request_actor_refcnt); // remove guard - } - - state_ = State::Close; - close_flag_ = 1; - G()->set_close_flag(); - send_closure(auth_manager_actor_, &AuthManager::on_closing, destroy_flag); - updates_manager_->timeout_expired(); // save PTS and QTS - - // wait till all request_actors will stop - request_actors_.clear(); - G()->td_db()->flush_all(); - send_closure_later(actor_id(this), &Td::dec_request_actor_refcnt); // remove guard -} - -class Td::DownloadFileCallback final : public FileManager::DownloadCallback { - public: - void on_download_ok(FileId file_id) final { - send_closure(G()->td(), &Td::on_file_download_finished, file_id); - } - - void on_download_error(FileId file_id, Status error) final { - send_closure(G()->td(), &Td::on_file_download_finished, file_id); - } -}; - -class Td::UploadFileCallback final : public FileManager::UploadCallback { - public: - void on_upload_ok(FileId file_id, tl_object_ptr input_file) final { - // cancel file upload of the file to allow next upload with the same file to succeed - send_closure(G()->file_manager(), &FileManager::cancel_upload, file_id); - } - - void on_upload_encrypted_ok(FileId file_id, tl_object_ptr input_file) final { - // cancel file upload of the file to allow next upload with the same file to succeed - send_closure(G()->file_manager(), &FileManager::cancel_upload, file_id); - } - - void on_upload_secure_ok(FileId file_id, tl_object_ptr input_file) final { - // cancel file upload of the file to allow next upload with the same file to succeed - send_closure(G()->file_manager(), &FileManager::cancel_upload, file_id); - } - - void on_upload_error(FileId file_id, Status error) final { - } -}; - -template -void Td::complete_pending_preauthentication_requests(const T &func) { - for (auto &request : pending_preauthentication_requests_) { - if (request.second != nullptr && func(request.second->get_id())) { - do_run_request(request.first, std::move(request.second)); - request.second = nullptr; - } - } -} - -void Td::finish_set_parameters() { - CHECK(set_parameters_request_id_ != 0); - set_parameters_request_id_ = 0; - - if (pending_set_parameters_requests_.empty()) { - return; - } - - VLOG(td_init) << "Continue to execute " << pending_set_parameters_requests_.size() << " pending requests"; - auto requests = std::move(pending_set_parameters_requests_); - for (auto &request : requests) { - run_request(request.first, std::move(request.second)); - } - CHECK(pending_set_parameters_requests_.size() < requests.size()); -} - -void Td::init(Parameters parameters, Result r_opened_database) { - CHECK(set_parameters_request_id_ != 0); - if (r_opened_database.is_error()) { - LOG(WARNING) << "Failed to open database: " << r_opened_database.error(); - send_closure(actor_id(this), &Td::send_error, set_parameters_request_id_, r_opened_database.move_as_error()); - return finish_set_parameters(); - } - auto events = r_opened_database.move_as_ok(); - - VLOG(td_init) << "Successfully inited database"; - - if (state_ == State::Close) { - LOG(INFO) << "Close asynchronously opened database"; - auto database_ptr = events.database.get(); - auto promise = PromiseCreator::lambda([database = std::move(events.database)](Unit) { - // destroy the database after closing - }); - database_ptr->close( - database_ptr->use_file_database() ? G()->get_database_scheduler_id() : G()->get_slow_net_scheduler_id(), - destroy_flag_, std::move(promise)); - return finish_set_parameters(); - } - - G()->init(actor_id(this), std::move(events.database)).ensure(); - - init_options_and_network(); - - // we need to process td_api::getOption along with td_api::setOption for consistency - // we need to process td_api::setOption before managers and MTProto header are created, - // because their initialiation may be affected by the options - complete_pending_preauthentication_requests([](int32 id) { - switch (id) { - case td_api::getOption::ID: - case td_api::setOption::ID: - return true; - default: - return false; - } - }); - - if (!option_manager_->get_option_boolean("disable_network_statistics")) { - net_stats_manager_ = create_actor("NetStatsManager", create_reference()); - - // How else could I let two actor know about each other, without quite complex async logic? - auto net_stats_manager_ptr = net_stats_manager_.get_actor_unsafe(); - net_stats_manager_ptr->init(); - G()->connection_creator().get_actor_unsafe()->set_net_stats_callback( - net_stats_manager_ptr->get_common_stats_callback(), net_stats_manager_ptr->get_media_stats_callback()); - G()->set_net_stats_file_callbacks(net_stats_manager_ptr->get_file_stats_callbacks()); - } - - complete_pending_preauthentication_requests([](int32 id) { - switch (id) { - case td_api::getNetworkStatistics::ID: - case td_api::addNetworkStatistics::ID: - case td_api::resetNetworkStatistics::ID: - return true; - default: - return false; - } - }); - - if (events.since_last_open >= 3600) { - auto old_since_last_open = option_manager_->get_option_integer("since_last_open"); - if (events.since_last_open > old_since_last_open) { - option_manager_->set_option_integer("since_last_open", events.since_last_open); - } - } - - options_.language_pack = option_manager_->get_option_string("localization_target"); - options_.language_code = option_manager_->get_option_string("language_pack_id"); - options_.parameters = option_manager_->get_option_string("connection_parameters"); - options_.tz_offset = static_cast(option_manager_->get_option_integer("utc_time_offset")); - options_.is_emulator = option_manager_->get_option_boolean("is_emulator"); - // options_.proxy = Proxy(); - G()->set_mtproto_header(make_unique(options_)); - G()->set_store_all_files_in_files_directory( - option_manager_->get_option_boolean("store_all_files_in_files_directory")); - - VLOG(td_init) << "Create NetQueryDispatcher"; - auto net_query_dispatcher = make_unique([&] { return create_reference(); }); - G()->set_net_query_dispatcher(std::move(net_query_dispatcher)); - - complete_pending_preauthentication_requests([](int32 id) { - // pingProxy uses NetQueryDispatcher to get main_dc_id, so must be called after NetQueryDispatcher is created - return id == td_api::pingProxy::ID; - }); - - VLOG(td_init) << "Create AuthManager"; - auth_manager_ = td::make_unique(parameters.api_id_, parameters.api_hash_, create_reference()); - auth_manager_actor_ = register_actor("AuthManager", auth_manager_.get()); - G()->set_auth_manager(auth_manager_actor_.get()); - - init_file_manager(); - - init_non_actor_managers(); - - init_managers(); - - init_pure_actor_managers(); - - secret_chats_manager_ = - create_actor("SecretChatsManager", create_reference(), parameters.use_secret_chats_); - G()->set_secret_chats_manager(secret_chats_manager_.get()); - - storage_manager_ = create_actor("StorageManager", create_reference(), G()->get_gc_scheduler_id()); - G()->set_storage_manager(storage_manager_.get()); - - option_manager_->on_td_inited(); - - process_binlog_events(std::move(events)); - - VLOG(td_init) << "Ping datacenter"; - if (!auth_manager_->is_authorized()) { - country_info_manager_->get_current_country_code(Promise()); - } else { - updates_manager_->get_difference("init"); - } - - complete_pending_preauthentication_requests([](int32 id) { return true; }); - - VLOG(td_init) << "Finish initialization"; - - state_ = State::Run; - - send_closure(actor_id(this), &Td::send_result, set_parameters_request_id_, td_api::make_object()); - return finish_set_parameters(); -} - -void Td::process_binlog_events(TdDb::OpenedDatabase &&events) { - VLOG(td_init) << "Send binlog events"; - for (auto &event : events.user_events) { - user_manager_->on_binlog_user_event(std::move(event)); - } - - for (auto &event : events.channel_events) { - chat_manager_->on_binlog_channel_event(std::move(event)); - } - - // chats may contain links to channels, so should be inited after - for (auto &event : events.chat_events) { - chat_manager_->on_binlog_chat_event(std::move(event)); - } - - for (auto &event : events.secret_chat_events) { - user_manager_->on_binlog_secret_chat_event(std::move(event)); - } - - for (auto &event : events.web_page_events) { - web_pages_manager_->on_binlog_web_page_event(std::move(event)); - } - - for (auto &event : events.save_app_log_events) { - on_save_app_log_binlog_event(this, std::move(event)); - } - - // Send binlog events to managers - // - // 1. Actors must receive all binlog events before other queries. - // - // -- All actors have one "entry point". So there is only one way to send query to them. So all queries are ordered - // for each Actor. - // - // 2. An actor must not make some decisions before all binlog events are processed. - // For example, SecretChatActor must not send RequestKey, before it receives log event with RequestKey and understands - // that RequestKey was already sent. - // - // 3. During replay of binlog some queries may be sent to other actors. They shouldn't process such events before all - // their binlog events are processed. So actor may receive some old queries. It must be in its actual state in - // order to handle them properly. - // - // -- Use send_closure_later, so actors don't even start process binlog events, before all binlog events are sent - - for (auto &event : events.to_secret_chats_manager) { - send_closure_later(secret_chats_manager_, &SecretChatsManager::replay_binlog_event, std::move(event)); - } - - send_closure_later(account_manager_actor_, &AccountManager::on_binlog_events, std::move(events.to_account_manager)); - - send_closure_later(poll_manager_actor_, &PollManager::on_binlog_events, std::move(events.to_poll_manager)); - - send_closure_later(messages_manager_actor_, &MessagesManager::on_binlog_events, - std::move(events.to_messages_manager)); - - send_closure_later(story_manager_actor_, &StoryManager::on_binlog_events, std::move(events.to_story_manager)); - - send_closure_later(notification_manager_actor_, &NotificationManager::on_binlog_events, - std::move(events.to_notification_manager)); - - send_closure_later(notification_settings_manager_actor_, &NotificationSettingsManager::on_binlog_events, - std::move(events.to_notification_settings_manager)); - - send_closure(secret_chats_manager_, &SecretChatsManager::binlog_replay_finish); -} - -void Td::init_options_and_network() { - VLOG(td_init) << "Create StateManager"; - state_manager_ = create_actor("State manager", create_reference()); - G()->set_state_manager(state_manager_.get()); - - VLOG(td_init) << "Create OptionManager"; - option_manager_ = make_unique(this); - G()->set_option_manager(option_manager_.get()); - - VLOG(td_init) << "Create ConnectionCreator"; - G()->set_connection_creator(create_actor("ConnectionCreator", create_reference())); - - complete_pending_preauthentication_requests([](int32 id) { - switch (id) { - case td_api::setNetworkType::ID: - case td_api::addProxy::ID: - case td_api::editProxy::ID: - case td_api::enableProxy::ID: - case td_api::disableProxy::ID: - case td_api::removeProxy::ID: - case td_api::getProxies::ID: - case td_api::getProxyLink::ID: - return true; - default: - return false; - } - }); - - VLOG(td_init) << "Create TempAuthKeyWatchdog"; - G()->set_temp_auth_key_watchdog(create_actor("TempAuthKeyWatchdog", create_reference())); - - VLOG(td_init) << "Create ConfigManager"; - config_manager_ = create_actor("ConfigManager", create_reference()); - G()->set_config_manager(config_manager_.get()); - - VLOG(td_init) << "Create OnlineManager"; - online_manager_ = make_unique(this, create_reference()); - online_manager_actor_ = register_actor("OnlineManager", online_manager_.get()); - G()->set_online_manager(online_manager_actor_.get()); -} - -void Td::init_file_manager() { - VLOG(td_init) << "Create FileManager"; - download_file_callback_ = std::make_shared(); - upload_file_callback_ = std::make_shared(); - - class FileManagerContext final : public FileManager::Context { - public: - explicit FileManagerContext(Td *td) : td_(td) { - } - - bool need_notify_on_new_files() final { - return !td_->auth_manager_->is_bot(); - } - - void on_new_file(int64 size, int64 real_size, int32 cnt) final { - send_closure(G()->storage_manager(), &StorageManager::on_new_file, size, real_size, cnt); - } - - void on_file_updated(FileId file_id) final { - send_closure(G()->td(), &Td::send_update, - make_tl_object(td_->file_manager_->get_file_object(file_id))); - } - - bool add_file_source(FileId file_id, FileSourceId file_source_id) final { - return td_->file_reference_manager_->add_file_source(file_id, file_source_id); - } - - bool remove_file_source(FileId file_id, FileSourceId file_source_id) final { - return td_->file_reference_manager_->remove_file_source(file_id, file_source_id); - } - - void on_merge_files(FileId to_file_id, FileId from_file_id) final { - td_->file_reference_manager_->merge(to_file_id, from_file_id); - } - - vector get_some_file_sources(FileId file_id) final { - return td_->file_reference_manager_->get_some_file_sources(file_id); - } - - void repair_file_reference(FileId file_id, Promise promise) final { - send_closure(G()->file_reference_manager(), &FileReferenceManager::repair_file_reference, file_id, - std::move(promise)); - } - - void reload_photo(PhotoSizeSource source, Promise promise) final { - FileReferenceManager::reload_photo(std::move(source), std::move(promise)); - } - - bool keep_exact_remote_location() final { - return !td_->auth_manager_->is_bot(); - } - - ActorShared<> create_reference() final { - return td_->create_reference(); - } - - private: - Td *td_; - }; - - file_manager_ = make_unique(make_unique(this)); - file_manager_actor_ = register_actor("FileManager", file_manager_.get()); - file_manager_->init_actor(); - G()->set_file_manager(file_manager_actor_.get()); - - file_reference_manager_ = make_unique(create_reference()); - file_reference_manager_actor_ = register_actor("FileReferenceManager", file_reference_manager_.get()); - G()->set_file_reference_manager(file_reference_manager_actor_.get()); -} - -void Td::init_non_actor_managers() { - VLOG(td_init) << "Create Managers"; - audios_manager_ = make_unique(this); - callback_queries_manager_ = make_unique(this); - documents_manager_ = make_unique(this); - videos_manager_ = make_unique(this); -} - -void Td::init_managers() { - account_manager_ = make_unique(this, create_reference()); - account_manager_actor_ = register_actor("AccountManager", account_manager_.get()); - G()->set_account_manager(account_manager_actor_.get()); - animations_manager_ = make_unique(this, create_reference()); - animations_manager_actor_ = register_actor("AnimationsManager", animations_manager_.get()); - G()->set_animations_manager(animations_manager_actor_.get()); - attach_menu_manager_ = make_unique(this, create_reference()); - attach_menu_manager_actor_ = register_actor("AttachMenuManager", attach_menu_manager_.get()); - G()->set_attach_menu_manager(attach_menu_manager_actor_.get()); - autosave_manager_ = make_unique(this, create_reference()); - autosave_manager_actor_ = register_actor("AutosaveManager", autosave_manager_.get()); - G()->set_autosave_manager(autosave_manager_actor_.get()); - background_manager_ = make_unique(this, create_reference()); - background_manager_actor_ = register_actor("BackgroundManager", background_manager_.get()); - G()->set_background_manager(background_manager_actor_.get()); - boost_manager_ = make_unique(this, create_reference()); - boost_manager_actor_ = register_actor("BoostManager", boost_manager_.get()); - G()->set_boost_manager(boost_manager_actor_.get()); - bot_info_manager_ = make_unique(this, create_reference()); - bot_info_manager_actor_ = register_actor("BotInfoManager", bot_info_manager_.get()); - G()->set_bot_info_manager(bot_info_manager_actor_.get()); - business_connection_manager_ = make_unique(this, create_reference()); - business_connection_manager_actor_ = register_actor("BusinessConnectionManager", business_connection_manager_.get()); - G()->set_business_connection_manager(business_connection_manager_actor_.get()); - business_manager_ = make_unique(this, create_reference()); - business_manager_actor_ = register_actor("BusinessManager", business_manager_.get()); - G()->set_business_manager(business_manager_actor_.get()); - channel_recommendation_manager_ = make_unique(this, create_reference()); - channel_recommendation_manager_actor_ = - register_actor("ChannelRecommendationManager", channel_recommendation_manager_.get()); - chat_manager_ = make_unique(this, create_reference()); - chat_manager_actor_ = register_actor("ChatManager", chat_manager_.get()); - G()->set_chat_manager(chat_manager_actor_.get()); - common_dialog_manager_ = make_unique(this, create_reference()); - common_dialog_manager_actor_ = register_actor("CommonDialogManager", common_dialog_manager_.get()); - connection_state_manager_ = make_unique(this, create_reference()); - connection_state_manager_actor_ = register_actor("ConnectionStateManager", connection_state_manager_.get()); - country_info_manager_ = make_unique(this, create_reference()); - country_info_manager_actor_ = register_actor("CountryInfoManager", country_info_manager_.get()); - dialog_action_manager_ = make_unique(this, create_reference()); - dialog_action_manager_actor_ = register_actor("DialogActionManager", dialog_action_manager_.get()); - G()->set_dialog_action_manager(dialog_action_manager_actor_.get()); - dialog_filter_manager_ = make_unique(this, create_reference()); - dialog_filter_manager_actor_ = register_actor("DialogFilterManager", dialog_filter_manager_.get()); - G()->set_dialog_filter_manager(dialog_filter_manager_actor_.get()); - dialog_invite_link_manager_ = make_unique(this, create_reference()); - dialog_invite_link_manager_actor_ = register_actor("DialogInviteLinkManager", dialog_invite_link_manager_.get()); - G()->set_dialog_invite_link_manager(dialog_invite_link_manager_actor_.get()); - dialog_manager_ = make_unique(this, create_reference()); - dialog_manager_actor_ = register_actor("DialogManager", dialog_manager_.get()); - G()->set_dialog_manager(dialog_manager_actor_.get()); - dialog_participant_manager_ = make_unique(this, create_reference()); - dialog_participant_manager_actor_ = register_actor("DialogParticipantManager", dialog_participant_manager_.get()); - G()->set_dialog_participant_manager(dialog_participant_manager_actor_.get()); - download_manager_ = DownloadManager::create(td::make_unique(this, create_reference())); - download_manager_actor_ = register_actor("DownloadManager", download_manager_.get()); - G()->set_download_manager(download_manager_actor_.get()); - forum_topic_manager_ = make_unique(this, create_reference()); - forum_topic_manager_actor_ = register_actor("ForumTopicManager", forum_topic_manager_.get()); - G()->set_forum_topic_manager(forum_topic_manager_actor_.get()); - game_manager_ = make_unique(this, create_reference()); - game_manager_actor_ = register_actor("GameManager", game_manager_.get()); - G()->set_game_manager(game_manager_actor_.get()); - group_call_manager_ = make_unique(this, create_reference()); - group_call_manager_actor_ = register_actor("GroupCallManager", group_call_manager_.get()); - G()->set_group_call_manager(group_call_manager_actor_.get()); - inline_message_manager_ = make_unique(this, create_reference()); - inline_message_manager_actor_ = register_actor("InlineMessageManager", inline_message_manager_.get()); - G()->set_inline_message_manager(inline_message_manager_actor_.get()); - inline_queries_manager_ = make_unique(this, create_reference()); - inline_queries_manager_actor_ = register_actor("InlineQueriesManager", inline_queries_manager_.get()); - link_manager_ = make_unique(this, create_reference()); - link_manager_actor_ = register_actor("LinkManager", link_manager_.get()); - G()->set_link_manager(link_manager_actor_.get()); - message_import_manager_ = make_unique(this, create_reference()); - message_import_manager_actor_ = register_actor("MessageImportManager", message_import_manager_.get()); - G()->set_message_import_manager(message_import_manager_actor_.get()); - messages_manager_ = make_unique(this, create_reference()); - messages_manager_actor_ = register_actor("MessagesManager", messages_manager_.get()); - G()->set_messages_manager(messages_manager_actor_.get()); - notification_manager_ = make_unique(this, create_reference()); - notification_manager_actor_ = register_actor("NotificationManager", notification_manager_.get()); - G()->set_notification_manager(notification_manager_actor_.get()); - notification_settings_manager_ = make_unique(this, create_reference()); - notification_settings_manager_actor_ = - register_actor("NotificationSettingsManager", notification_settings_manager_.get()); - G()->set_notification_settings_manager(notification_settings_manager_actor_.get()); - people_nearby_manager_ = make_unique(this, create_reference()); - people_nearby_manager_actor_ = register_actor("PeopleNearbyManager", people_nearby_manager_.get()); - G()->set_people_nearby_manager(people_nearby_manager_actor_.get()); - phone_number_manager_ = make_unique(this, create_reference()); - phone_number_manager_actor_ = register_actor("PhoneNumberManager", phone_number_manager_.get()); - poll_manager_ = make_unique(this, create_reference()); - poll_manager_actor_ = register_actor("PollManager", poll_manager_.get()); - privacy_manager_ = make_unique(this, create_reference()); - privacy_manager_actor_ = register_actor("PrivacyManager", privacy_manager_.get()); - promo_data_manager_ = make_unique(this, create_reference()); - promo_data_manager_actor_ = register_actor("PromoDataManager", promo_data_manager_.get()); - G()->set_promo_data_manager(promo_data_manager_actor_.get()); - quick_reply_manager_ = make_unique(this, create_reference()); - quick_reply_manager_actor_ = register_actor("QuickReplyManager", quick_reply_manager_.get()); - G()->set_quick_reply_manager(quick_reply_manager_actor_.get()); - reaction_manager_ = make_unique(this, create_reference()); - reaction_manager_actor_ = register_actor("ReactionManager", reaction_manager_.get()); - G()->set_reaction_manager(reaction_manager_actor_.get()); - saved_messages_manager_ = make_unique(this, create_reference()); - saved_messages_manager_actor_ = register_actor("SavedMessagesManager", saved_messages_manager_.get()); - G()->set_saved_messages_manager(saved_messages_manager_actor_.get()); - sponsored_message_manager_ = make_unique(this, create_reference()); - sponsored_message_manager_actor_ = register_actor("SponsoredMessageManager", sponsored_message_manager_.get()); - G()->set_sponsored_message_manager(sponsored_message_manager_actor_.get()); - star_manager_ = make_unique(this, create_reference()); - star_manager_actor_ = register_actor("StarManager", star_manager_.get()); - G()->set_star_manager(star_manager_actor_.get()); - statistics_manager_ = make_unique(this, create_reference()); - statistics_manager_actor_ = register_actor("StatisticsManager", statistics_manager_.get()); - stickers_manager_ = make_unique(this, create_reference()); - stickers_manager_actor_ = register_actor("StickersManager", stickers_manager_.get()); - G()->set_stickers_manager(stickers_manager_actor_.get()); - story_manager_ = make_unique(this, create_reference()); - story_manager_actor_ = register_actor("StoryManager", story_manager_.get()); - G()->set_story_manager(story_manager_actor_.get()); - terms_of_service_manager_ = make_unique(this, create_reference()); - terms_of_service_manager_actor_ = register_actor("TermsOfServiceManager", terms_of_service_manager_.get()); - theme_manager_ = make_unique(this, create_reference()); - theme_manager_actor_ = register_actor("ThemeManager", theme_manager_.get()); - G()->set_theme_manager(theme_manager_actor_.get()); - time_zone_manager_ = make_unique(this, create_reference()); - time_zone_manager_actor_ = register_actor("TimeZoneManager", time_zone_manager_.get()); - G()->set_time_zone_manager(time_zone_manager_actor_.get()); - top_dialog_manager_ = make_unique(this, create_reference()); - top_dialog_manager_actor_ = register_actor("TopDialogManager", top_dialog_manager_.get()); - G()->set_top_dialog_manager(top_dialog_manager_actor_.get()); - transcription_manager_ = make_unique(this, create_reference()); - transcription_manager_actor_ = register_actor("TranscriptionManager", transcription_manager_.get()); - G()->set_transcription_manager(transcription_manager_actor_.get()); - translation_manager_ = make_unique(this, create_reference()); - translation_manager_actor_ = register_actor("TranslationManager", translation_manager_.get()); - updates_manager_ = make_unique(this, create_reference()); - updates_manager_actor_ = register_actor("UpdatesManager", updates_manager_.get()); - G()->set_updates_manager(updates_manager_actor_.get()); - user_manager_ = make_unique(this, create_reference()); - user_manager_actor_ = register_actor("UserManager", user_manager_.get()); - G()->set_user_manager(user_manager_actor_.get()); - video_notes_manager_ = make_unique(this, create_reference()); - video_notes_manager_actor_ = register_actor("VideoNotesManager", video_notes_manager_.get()); - voice_notes_manager_ = make_unique(this, create_reference()); - voice_notes_manager_actor_ = register_actor("VoiceNotesManager", voice_notes_manager_.get()); - web_pages_manager_ = make_unique(this, create_reference()); - web_pages_manager_actor_ = register_actor("WebPagesManager", web_pages_manager_.get()); - G()->set_web_pages_manager(web_pages_manager_actor_.get()); -} - -void Td::init_pure_actor_managers() { - call_manager_ = create_actor("CallManager", create_reference()); - G()->set_call_manager(call_manager_.get()); - cashtag_search_hints_ = create_actor("CashtagSearchHints", "cashtag_search", '$', create_reference()); - device_token_manager_ = create_actor("DeviceTokenManager", create_reference()); - hashtag_hints_ = create_actor("HashtagHints", "text", '#', create_reference()); - hashtag_search_hints_ = create_actor("HashtagSearchHints", "search", '#', create_reference()); - language_pack_manager_ = create_actor("LanguagePackManager", create_reference()); - G()->set_language_pack_manager(language_pack_manager_.get()); - password_manager_ = create_actor("PasswordManager", create_reference()); - G()->set_password_manager(password_manager_.get()); - secure_manager_ = create_actor("SecureManager", create_reference()); -} - -void Td::send_update(tl_object_ptr &&object) { - CHECK(object != nullptr); - auto object_id = object->get_id(); - if (close_flag_ >= 5 && object_id != td_api::updateAuthorizationState::ID) { - // just in case - return; - } - - switch (object_id) { - case td_api::updateAccentColors::ID: - case td_api::updateChatThemes::ID: - case td_api::updateFavoriteStickers::ID: - case td_api::updateInstalledStickerSets::ID: - case td_api::updateProfileAccentColors::ID: - case td_api::updateRecentStickers::ID: - case td_api::updateSavedAnimations::ID: - case td_api::updateSavedNotificationSounds::ID: - case td_api::updateUserStatus::ID: - VLOG(td_requests) << "Sending update: " << oneline(to_string(object)); - break; - case td_api::updateTrendingStickerSets::ID: { - auto update = static_cast(object.get()); - auto sticker_sets = update->sticker_sets_.get(); - VLOG(td_requests) << "Sending update: updateTrendingStickerSets { " << oneline(to_string(update->sticker_type_)) - << ", total_count = " << sticker_sets->total_count_ - << ", count = " << sticker_sets->sets_.size() << " }"; - break; - } - case td_api::updateOption::ID: - if (auth_manager_ == nullptr || !auth_manager_->is_bot()) { - VLOG(td_requests) << "Sending update: " << to_string(object); - } - break; - case td_api::updateDefaultReactionType::ID / 2: - LOG(ERROR) << "Sending update: " << oneline(to_string(object)); - break; - default: - VLOG(td_requests) << "Sending update: " << to_string(object); - } - - callback_->on_result(0, std::move(object)); -} - -void Td::send_result(uint64 id, tl_object_ptr object) { - if (id == 0) { - LOG(ERROR) << "Sending " << to_string(object) << " through send_result"; - return; - } - - auto it = request_set_.find(id); - if (it != request_set_.end()) { - if (object == nullptr) { - object = make_tl_object(404, "Not Found"); - } - VLOG(td_requests) << "Sending result for request " << id << ": " << to_string(object); - request_set_.erase(it); - callback_->on_result(id, std::move(object)); - } -} - -void Td::send_error_impl(uint64 id, tl_object_ptr error) { - CHECK(id != 0); - CHECK(error != nullptr); - auto it = request_set_.find(id); - if (it != request_set_.end()) { - if (error->code_ == 0 && error->message_ == "Lost promise") { - LOG(FATAL) << "Lost promise for query " << id << " of type " << it->second << " in close state " << close_flag_; - } - VLOG(td_requests) << "Sending error for request " << id << ": " << oneline(to_string(error)); - request_set_.erase(it); - callback_->on_error(id, std::move(error)); - } -} - -void Td::send_error(uint64 id, Status error) { - send_error_impl(id, make_tl_object(error.code(), error.message().str())); - error.ignore(); -} - -void Td::send_error_raw(uint64 id, int32 code, CSlice error) { - send_closure(actor_id(this), &Td::send_error_impl, id, make_error(code, error)); -} - -void Td::answer_ok_query(uint64 id, Status status) { - if (status.is_error()) { - send_closure(actor_id(this), &Td::send_error, id, std::move(status)); - } else { - send_closure(actor_id(this), &Td::send_result, id, make_tl_object()); - } -} - -Promise Td::create_ok_request_promise(uint64 id) { - return PromiseCreator::lambda([actor_id = actor_id(this), id](Result result) { - if (result.is_error()) { - send_closure(actor_id, &Td::send_error, id, result.move_as_error()); - } else { - send_closure(actor_id, &Td::send_result, id, td_api::make_object()); - } - }); -} - -#define CLEAN_INPUT_STRING(field_name) \ - if (!clean_input_string(field_name)) { \ - return send_error_raw(id, 400, "Strings must be encoded in UTF-8"); \ - } -#define CHECK_IS_BOT() \ - if (!auth_manager_->is_bot()) { \ - return send_error_raw(id, 400, "Only bots can use the method"); \ - } -#define CHECK_IS_USER() \ - if (auth_manager_->is_bot()) { \ - return send_error_raw(id, 400, "The method is not available to bots"); \ - } - -#define CREATE_NO_ARGS_REQUEST(name) \ - auto slot_id = request_actors_.create(ActorOwn<>(), RequestActorIdType); \ - inc_request_actor_refcnt(); \ - *request_actors_.get(slot_id) = create_actor(#name, actor_shared(this, slot_id), id); -#define CREATE_REQUEST(name, ...) \ - auto slot_id = request_actors_.create(ActorOwn<>(), RequestActorIdType); \ - inc_request_actor_refcnt(); \ - *request_actors_.get(slot_id) = create_actor(#name, actor_shared(this, slot_id), id, __VA_ARGS__); -#define CREATE_REQUEST_PROMISE() auto promise = create_request_promise::ReturnType>(id) -#define CREATE_OK_REQUEST_PROMISE() \ - static_assert(std::is_same::ReturnType, td_api::object_ptr>::value, ""); \ - auto promise = create_ok_request_promise(id) - -Result> Td::get_parameters( - td_api::object_ptr parameters) { - VLOG(td_init) << "Begin to set TDLib parameters"; - if (!clean_input_string(parameters->api_hash_) || !clean_input_string(parameters->system_language_code_) || - !clean_input_string(parameters->device_model_) || !clean_input_string(parameters->system_version_) || - !clean_input_string(parameters->application_version_)) { - VLOG(td_init) << "Wrong string encoding"; - return Status::Error(400, "Strings must be encoded in UTF-8"); - } - - if (parameters->api_id_ <= 0) { - return Status::Error(400, "Valid api_id must be provided. Can be obtained at https://my.telegram.org"); - } - if (parameters->api_hash_.empty()) { - return Status::Error(400, "Valid api_hash must be provided. Can be obtained at https://my.telegram.org"); - } - - std::pair result; - result.first.api_id_ = parameters->api_id_; - result.first.api_hash_ = std::move(parameters->api_hash_); - result.first.use_secret_chats_ = parameters->use_secret_chats_; - - result.second.encryption_key_ = TdDb::as_db_key(std::move(parameters->database_encryption_key_)); - result.second.database_directory_ = std::move(parameters->database_directory_); - result.second.files_directory_ = std::move(parameters->files_directory_); - result.second.is_test_dc_ = parameters->use_test_dc_; - result.second.use_file_database_ = parameters->use_file_database_; - result.second.use_chat_info_database_ = parameters->use_chat_info_database_; - result.second.use_message_database_ = parameters->use_message_database_; - - VLOG(td_init) << "Create MtprotoHeader::Options"; - options_.api_id = parameters->api_id_; - options_.system_language_code = trim(parameters->system_language_code_); - options_.device_model = trim(parameters->device_model_); - options_.system_version = trim(parameters->system_version_); - options_.application_version = trim(parameters->application_version_); - if (options_.system_language_code.empty()) { - return Status::Error(400, "System language code must be non-empty"); - } - if (options_.device_model.empty()) { - return Status::Error(400, "Device model must be non-empty"); - } - if (options_.system_version.empty()) { - options_.system_version = get_operating_system_version().str(); - VLOG(td_init) << "Set system version to " << options_.system_version; - } - if (options_.application_version.empty()) { - return Status::Error(400, "Application version must be non-empty"); - } - if (options_.api_id != 21724) { - options_.application_version += ", TDLib "; - auto version = OptionManager::get_option_synchronously("version"); - CHECK(version->get_id() == td_api::optionValueString::ID); - options_.application_version += static_cast(version.get())->value_; - } - options_.language_pack = string(); - options_.language_code = string(); - options_.parameters = string(); - options_.is_emulator = false; - options_.proxy = Proxy(); - - return std::move(result); -} - -void Td::on_request(uint64 id, const td_api::setTdlibParameters &request) { - send_error_raw(id, 400, "Unexpected setTdlibParameters"); -} - -void Td::on_request(uint64 id, td_api::setDatabaseEncryptionKey &request) { - CREATE_OK_REQUEST_PROMISE(); - G()->td_db()->get_binlog()->change_key(TdDb::as_db_key(std::move(request.new_encryption_key_)), std::move(promise)); -} - -void Td::on_request(uint64 id, const td_api::getAuthorizationState &request) { - send_closure(auth_manager_actor_, &AuthManager::get_state, id); -} - -void Td::on_request(uint64 id, td_api::setAuthenticationPhoneNumber &request) { - CLEAN_INPUT_STRING(request.phone_number_); - send_closure(auth_manager_actor_, &AuthManager::set_phone_number, id, std::move(request.phone_number_), - std::move(request.settings_)); -} - -void Td::on_request(uint64 id, td_api::sendAuthenticationFirebaseSms &request) { - CLEAN_INPUT_STRING(request.token_); - send_closure(auth_manager_actor_, &AuthManager::set_firebase_token, id, std::move(request.token_)); -} - -void Td::on_request(uint64 id, td_api::reportAuthenticationCodeMissing &request) { - CLEAN_INPUT_STRING(request.mobile_network_code_); - send_closure(auth_manager_actor_, &AuthManager::report_missing_code, id, std::move(request.mobile_network_code_)); -} - -void Td::on_request(uint64 id, td_api::setAuthenticationEmailAddress &request) { - CLEAN_INPUT_STRING(request.email_address_); - send_closure(auth_manager_actor_, &AuthManager::set_email_address, id, std::move(request.email_address_)); -} - -void Td::on_request(uint64 id, td_api::resendAuthenticationCode &request) { - send_closure(auth_manager_actor_, &AuthManager::resend_authentication_code, id, std::move(request.reason_)); -} - -void Td::on_request(uint64 id, td_api::checkAuthenticationEmailCode &request) { - send_closure(auth_manager_actor_, &AuthManager::check_email_code, id, EmailVerification(std::move(request.code_))); -} - -void Td::on_request(uint64 id, td_api::checkAuthenticationCode &request) { - CLEAN_INPUT_STRING(request.code_); - send_closure(auth_manager_actor_, &AuthManager::check_code, id, std::move(request.code_)); -} - -void Td::on_request(uint64 id, td_api::registerUser &request) { - CLEAN_INPUT_STRING(request.first_name_); - CLEAN_INPUT_STRING(request.last_name_); - send_closure(auth_manager_actor_, &AuthManager::register_user, id, std::move(request.first_name_), - std::move(request.last_name_), request.disable_notification_); -} - -void Td::on_request(uint64 id, td_api::requestQrCodeAuthentication &request) { - send_closure(auth_manager_actor_, &AuthManager::request_qr_code_authentication, id, - UserId::get_user_ids(request.other_user_ids_)); -} - -void Td::on_request(uint64 id, const td_api::resetAuthenticationEmailAddress &request) { - send_closure(auth_manager_actor_, &AuthManager::reset_email_address, id); -} - -void Td::on_request(uint64 id, td_api::checkAuthenticationPassword &request) { - CLEAN_INPUT_STRING(request.password_); - send_closure(auth_manager_actor_, &AuthManager::check_password, id, std::move(request.password_)); -} - -void Td::on_request(uint64 id, const td_api::requestAuthenticationPasswordRecovery &request) { - send_closure(auth_manager_actor_, &AuthManager::request_password_recovery, id); -} - -void Td::on_request(uint64 id, td_api::checkAuthenticationPasswordRecoveryCode &request) { - CLEAN_INPUT_STRING(request.recovery_code_); - send_closure(auth_manager_actor_, &AuthManager::check_password_recovery_code, id, std::move(request.recovery_code_)); -} - -void Td::on_request(uint64 id, td_api::recoverAuthenticationPassword &request) { - CLEAN_INPUT_STRING(request.recovery_code_); - CLEAN_INPUT_STRING(request.new_password_); - CLEAN_INPUT_STRING(request.new_hint_); - send_closure(auth_manager_actor_, &AuthManager::recover_password, id, std::move(request.recovery_code_), - std::move(request.new_password_), std::move(request.new_hint_)); -} - -void Td::on_request(uint64 id, const td_api::logOut &request) { - // will call Td::destroy later - send_closure(auth_manager_actor_, &AuthManager::log_out, id); -} - -void Td::on_request(uint64 id, const td_api::close &request) { - // send response before actually closing - send_closure(actor_id(this), &Td::send_result, id, td_api::make_object()); - send_closure(actor_id(this), &Td::close); -} - -void Td::on_request(uint64 id, const td_api::destroy &request) { - // send response before actually destroying - send_closure(actor_id(this), &Td::send_result, id, td_api::make_object()); - send_closure(actor_id(this), &Td::destroy); -} - -void Td::on_request(uint64 id, td_api::checkAuthenticationBotToken &request) { - CLEAN_INPUT_STRING(request.token_); - send_closure(auth_manager_actor_, &AuthManager::check_bot_token, id, std::move(request.token_)); -} - -void Td::on_request(uint64 id, td_api::confirmQrCodeAuthentication &request) { - CLEAN_INPUT_STRING(request.link_); - CREATE_REQUEST_PROMISE(); - account_manager_->confirm_qr_code_authentication(request.link_, std::move(promise)); -} - -void Td::on_request(uint64 id, const td_api::getCurrentState &request) { - vector> updates; - - option_manager_->get_current_state(updates); - - auto state = auth_manager_->get_current_authorization_state_object(); - if (state != nullptr) { - updates.push_back(td_api::make_object(std::move(state))); - } - - connection_state_manager_->get_current_state(updates); - - if (auth_manager_->is_authorized()) { - user_manager_->get_current_state(updates); - - chat_manager_->get_current_state(updates); - - background_manager_->get_current_state(updates); - - animations_manager_->get_current_state(updates); - - attach_menu_manager_->get_current_state(updates); - - stickers_manager_->get_current_state(updates); - - reaction_manager_->get_current_state(updates); - - notification_settings_manager_->get_current_state(updates); - - dialog_filter_manager_->get_current_state(updates); - - messages_manager_->get_current_state(updates); - - dialog_participant_manager_->get_current_state(updates); - - notification_manager_->get_current_state(updates); - - quick_reply_manager_->get_current_state(updates); - - saved_messages_manager_->get_current_state(updates); - - story_manager_->get_current_state(updates); - - config_manager_.get_actor_unsafe()->get_current_state(updates); - - transcription_manager_->get_current_state(updates); - - autosave_manager_->get_current_state(updates); - - account_manager_->get_current_state(updates); - - business_connection_manager_->get_current_state(updates); - - terms_of_service_manager_->get_current_state(updates); - - star_manager_->get_current_state(updates); - - // TODO updateFileGenerationStart generation_id:int64 original_path:string destination_path:string conversion:string = Update; - // TODO updateCall call:call = Update; - // TODO updateGroupCall call:groupCall = Update; - } - - // send response synchronously to prevent "Request aborted" or other changes of the current state - send_result(id, td_api::make_object(std::move(updates))); -} - -void Td::on_request(uint64 id, const td_api::getPasswordState &request) { - CHECK_IS_USER(); - CREATE_REQUEST_PROMISE(); - send_closure(password_manager_, &PasswordManager::get_state, std::move(promise)); -} - -void Td::on_request(uint64 id, td_api::setPassword &request) { - CHECK_IS_USER(); - CLEAN_INPUT_STRING(request.old_password_); - CLEAN_INPUT_STRING(request.new_password_); - CLEAN_INPUT_STRING(request.new_hint_); - CLEAN_INPUT_STRING(request.new_recovery_email_address_); - CREATE_REQUEST_PROMISE(); - send_closure(password_manager_, &PasswordManager::set_password, std::move(request.old_password_), - std::move(request.new_password_), std::move(request.new_hint_), request.set_recovery_email_address_, - std::move(request.new_recovery_email_address_), std::move(promise)); -} - -void Td::on_request(uint64 id, td_api::setLoginEmailAddress &request) { - CHECK_IS_USER(); - CLEAN_INPUT_STRING(request.new_login_email_address_); - CREATE_REQUEST_PROMISE(); - auto query_promise = PromiseCreator::lambda([promise = std::move(promise)](Result result) mutable { - if (result.is_error()) { - promise.set_error(result.move_as_error()); - } else { - promise.set_value(result.ok().get_email_address_authentication_code_info_object()); - } - }); - send_closure(password_manager_, &PasswordManager::set_login_email_address, - std::move(request.new_login_email_address_), std::move(query_promise)); -} - -void Td::on_request(uint64 id, const td_api::resendLoginEmailAddressCode &request) { - CHECK_IS_USER(); - CREATE_REQUEST_PROMISE(); - auto query_promise = PromiseCreator::lambda([promise = std::move(promise)](Result result) mutable { - if (result.is_error()) { - promise.set_error(result.move_as_error()); - } else { - promise.set_value(result.ok().get_email_address_authentication_code_info_object()); - } - }); - send_closure(password_manager_, &PasswordManager::resend_login_email_address_code, std::move(query_promise)); -} - -void Td::on_request(uint64 id, td_api::checkLoginEmailAddressCode &request) { - CHECK_IS_USER(); - CREATE_OK_REQUEST_PROMISE(); - send_closure(password_manager_, &PasswordManager::check_login_email_address_code, - EmailVerification(std::move(request.code_)), std::move(promise)); -} - -void Td::on_request(uint64 id, td_api::setRecoveryEmailAddress &request) { - CHECK_IS_USER(); - CLEAN_INPUT_STRING(request.password_); - CLEAN_INPUT_STRING(request.new_recovery_email_address_); - CREATE_REQUEST_PROMISE(); - send_closure(password_manager_, &PasswordManager::set_recovery_email_address, std::move(request.password_), - std::move(request.new_recovery_email_address_), std::move(promise)); -} - -void Td::on_request(uint64 id, td_api::getRecoveryEmailAddress &request) { - CHECK_IS_USER(); - CLEAN_INPUT_STRING(request.password_); - CREATE_REQUEST_PROMISE(); - send_closure(password_manager_, &PasswordManager::get_recovery_email_address, std::move(request.password_), - std::move(promise)); -} - -void Td::on_request(uint64 id, td_api::checkRecoveryEmailAddressCode &request) { - CHECK_IS_USER(); - CLEAN_INPUT_STRING(request.code_); - CREATE_REQUEST_PROMISE(); - send_closure(password_manager_, &PasswordManager::check_recovery_email_address_code, std::move(request.code_), - std::move(promise)); -} - -void Td::on_request(uint64 id, const td_api::resendRecoveryEmailAddressCode &request) { - CHECK_IS_USER(); - CREATE_REQUEST_PROMISE(); - send_closure(password_manager_, &PasswordManager::resend_recovery_email_address_code, std::move(promise)); -} - -void Td::on_request(uint64 id, const td_api::cancelRecoveryEmailAddressVerification &request) { - CHECK_IS_USER(); - CREATE_REQUEST_PROMISE(); - send_closure(password_manager_, &PasswordManager::cancel_recovery_email_address_verification, std::move(promise)); -} - -void Td::on_request(uint64 id, td_api::requestPasswordRecovery &request) { - CHECK_IS_USER(); - CREATE_REQUEST_PROMISE(); - auto query_promise = PromiseCreator::lambda([promise = std::move(promise)](Result result) mutable { - if (result.is_error()) { - promise.set_error(result.move_as_error()); - } else { - promise.set_value(result.ok().get_email_address_authentication_code_info_object()); - } - }); - send_closure(password_manager_, &PasswordManager::request_password_recovery, std::move(query_promise)); -} - -void Td::on_request(uint64 id, td_api::checkPasswordRecoveryCode &request) { - CHECK_IS_USER(); - CLEAN_INPUT_STRING(request.recovery_code_); - CREATE_OK_REQUEST_PROMISE(); - send_closure(password_manager_, &PasswordManager::check_password_recovery_code, std::move(request.recovery_code_), - std::move(promise)); -} - -void Td::on_request(uint64 id, td_api::recoverPassword &request) { - CHECK_IS_USER(); - CLEAN_INPUT_STRING(request.recovery_code_); - CLEAN_INPUT_STRING(request.new_password_); - CLEAN_INPUT_STRING(request.new_hint_); - CREATE_REQUEST_PROMISE(); - send_closure(password_manager_, &PasswordManager::recover_password, std::move(request.recovery_code_), - std::move(request.new_password_), std::move(request.new_hint_), std::move(promise)); -} - -void Td::on_request(uint64 id, const td_api::resetPassword &request) { - CHECK_IS_USER(); - CREATE_REQUEST_PROMISE(); - send_closure(password_manager_, &PasswordManager::reset_password, std::move(promise)); -} - -void Td::on_request(uint64 id, const td_api::cancelPasswordReset &request) { - CHECK_IS_USER(); - CREATE_OK_REQUEST_PROMISE(); - send_closure(password_manager_, &PasswordManager::cancel_password_reset, std::move(promise)); -} - -void Td::on_request(uint64 id, td_api::getTemporaryPasswordState &request) { - CHECK_IS_USER(); - CREATE_REQUEST_PROMISE(); - send_closure(password_manager_, &PasswordManager::get_temp_password_state, std::move(promise)); -} - -void Td::on_request(uint64 id, td_api::createTemporaryPassword &request) { - CHECK_IS_USER(); - CLEAN_INPUT_STRING(request.password_); - CREATE_REQUEST_PROMISE(); - send_closure(password_manager_, &PasswordManager::create_temp_password, std::move(request.password_), - request.valid_for_, std::move(promise)); -} - -void Td::on_request(uint64 id, td_api::processPushNotification &request) { - CHECK_IS_USER(); - CLEAN_INPUT_STRING(request.payload_); - CREATE_OK_REQUEST_PROMISE(); - send_closure(G()->notification_manager(), &NotificationManager::process_push_notification, - std::move(request.payload_), std::move(promise)); -} - -void Td::on_request(uint64 id, td_api::registerDevice &request) { - CHECK_IS_USER(); - CREATE_REQUEST_PROMISE(); - send_closure(device_token_manager_, &DeviceTokenManager::register_device, std::move(request.device_token_), - UserId::get_user_ids(request.other_user_ids_), std::move(promise)); -} - -void Td::on_request(uint64 id, td_api::getUserPrivacySettingRules &request) { - CHECK_IS_USER(); - CREATE_REQUEST_PROMISE(); - privacy_manager_->get_privacy(std::move(request.setting_), std::move(promise)); -} - -void Td::on_request(uint64 id, td_api::setUserPrivacySettingRules &request) { - CHECK_IS_USER(); - CREATE_OK_REQUEST_PROMISE(); - privacy_manager_->set_privacy(std::move(request.setting_), std::move(request.rules_), std::move(promise)); -} - -void Td::on_request(uint64 id, const td_api::getDefaultMessageAutoDeleteTime &request) { - CHECK_IS_USER(); - CREATE_REQUEST_PROMISE(); - auto query_promise = PromiseCreator::lambda([promise = std::move(promise)](Result result) mutable { - if (result.is_error()) { - promise.set_error(result.move_as_error()); - } else { - promise.set_value(td_api::make_object(result.ok())); - } - }); - account_manager_->get_default_message_ttl(std::move(query_promise)); -} - -void Td::on_request(uint64 id, const td_api::setDefaultMessageAutoDeleteTime &request) { - CHECK_IS_USER(); - if (request.message_auto_delete_time_ == nullptr) { - return send_error_raw(id, 400, "New default message auto-delete time must be non-empty"); - } - CREATE_OK_REQUEST_PROMISE(); - account_manager_->set_default_message_ttl(request.message_auto_delete_time_->time_, std::move(promise)); -} - -void Td::on_request(uint64 id, const td_api::getAccountTtl &request) { - CHECK_IS_USER(); - CREATE_REQUEST_PROMISE(); - auto query_promise = PromiseCreator::lambda([promise = std::move(promise)](Result result) mutable { - if (result.is_error()) { - promise.set_error(result.move_as_error()); - } else { - promise.set_value(td_api::make_object(result.ok())); - } - }); - account_manager_->get_account_ttl(std::move(query_promise)); -} - -void Td::on_request(uint64 id, const td_api::setAccountTtl &request) { - CHECK_IS_USER(); - if (request.ttl_ == nullptr) { - return send_error_raw(id, 400, "New account TTL must be non-empty"); - } - CREATE_OK_REQUEST_PROMISE(); - account_manager_->set_account_ttl(request.ttl_->days_, std::move(promise)); -} - -void Td::on_request(uint64 id, td_api::deleteAccount &request) { - CHECK_IS_USER(); - CLEAN_INPUT_STRING(request.reason_); - send_closure(auth_manager_actor_, &AuthManager::delete_account, id, request.reason_, request.password_); -} - -void Td::on_request(uint64 id, td_api::sendPhoneNumberCode &request) { - CHECK_IS_USER(); - CLEAN_INPUT_STRING(request.phone_number_); - CREATE_REQUEST_PROMISE(); - phone_number_manager_->set_phone_number(std::move(request.phone_number_), std::move(request.settings_), - std::move(request.type_), std::move(promise)); -} - -void Td::on_request(uint64 id, td_api::sendPhoneNumberFirebaseSms &request) { - CHECK_IS_USER(); - CLEAN_INPUT_STRING(request.token_); - CREATE_OK_REQUEST_PROMISE(); - phone_number_manager_->send_firebase_sms(std::move(request.token_), std::move(promise)); -} - -void Td::on_request(uint64 id, td_api::reportPhoneNumberCodeMissing &request) { - CHECK_IS_USER(); - CLEAN_INPUT_STRING(request.mobile_network_code_); - CREATE_OK_REQUEST_PROMISE(); - phone_number_manager_->report_missing_code(std::move(request.mobile_network_code_), std::move(promise)); -} - -void Td::on_request(uint64 id, td_api::resendPhoneNumberCode &request) { - CHECK_IS_USER(); - CREATE_REQUEST_PROMISE(); - phone_number_manager_->resend_authentication_code(std::move(request.reason_), std::move(promise)); -} - -void Td::on_request(uint64 id, td_api::checkPhoneNumberCode &request) { - CHECK_IS_USER(); - CLEAN_INPUT_STRING(request.code_); - CREATE_OK_REQUEST_PROMISE(); - phone_number_manager_->check_code(std::move(request.code_), std::move(promise)); -} - -void Td::on_request(uint64 id, const td_api::getUserLink &request) { - CHECK_IS_USER(); - CREATE_REQUEST_PROMISE(); - account_manager_->get_user_link(std::move(promise)); -} - -void Td::on_request(uint64 id, td_api::searchUserByToken &request) { - CHECK_IS_USER(); - CLEAN_INPUT_STRING(request.token_); - CREATE_REQUEST_PROMISE(); - account_manager_->import_contact_token(std::move(request.token_), std::move(promise)); -} - -void Td::on_request(uint64 id, const td_api::getActiveSessions &request) { - CHECK_IS_USER(); - CREATE_REQUEST_PROMISE(); - account_manager_->get_active_sessions(std::move(promise)); -} - -void Td::on_request(uint64 id, const td_api::terminateSession &request) { - CHECK_IS_USER(); - CREATE_OK_REQUEST_PROMISE(); - account_manager_->terminate_session(request.session_id_, std::move(promise)); -} - -void Td::on_request(uint64 id, const td_api::terminateAllOtherSessions &request) { - CHECK_IS_USER(); - CREATE_OK_REQUEST_PROMISE(); - account_manager_->terminate_all_other_sessions(std::move(promise)); -} - -void Td::on_request(uint64 id, const td_api::confirmSession &request) { - CHECK_IS_USER(); - CREATE_OK_REQUEST_PROMISE(); - account_manager_->confirm_session(request.session_id_, std::move(promise)); -} - -void Td::on_request(uint64 id, const td_api::toggleSessionCanAcceptCalls &request) { - CHECK_IS_USER(); - CREATE_OK_REQUEST_PROMISE(); - account_manager_->toggle_session_can_accept_calls(request.session_id_, request.can_accept_calls_, std::move(promise)); -} - -void Td::on_request(uint64 id, const td_api::toggleSessionCanAcceptSecretChats &request) { - CHECK_IS_USER(); - CREATE_OK_REQUEST_PROMISE(); - account_manager_->toggle_session_can_accept_secret_chats(request.session_id_, request.can_accept_secret_chats_, - std::move(promise)); -} - -void Td::on_request(uint64 id, const td_api::setInactiveSessionTtl &request) { - CHECK_IS_USER(); - CREATE_OK_REQUEST_PROMISE(); - account_manager_->set_inactive_session_ttl_days(request.inactive_session_ttl_days_, std::move(promise)); -} - -void Td::on_request(uint64 id, const td_api::getConnectedWebsites &request) { - CHECK_IS_USER(); - CREATE_REQUEST_PROMISE(); - account_manager_->get_connected_websites(std::move(promise)); -} - -void Td::on_request(uint64 id, const td_api::disconnectWebsite &request) { - CHECK_IS_USER(); - CREATE_OK_REQUEST_PROMISE(); - account_manager_->disconnect_website(request.website_id_, std::move(promise)); -} - -void Td::on_request(uint64 id, const td_api::disconnectAllWebsites &request) { - CHECK_IS_USER(); - CREATE_OK_REQUEST_PROMISE(); - account_manager_->disconnect_all_websites(std::move(promise)); -} - -void Td::on_request(uint64 id, const td_api::getMe &request) { - CREATE_NO_ARGS_REQUEST(GetMeRequest); -} - -void Td::on_request(uint64 id, const td_api::getUser &request) { - CREATE_REQUEST(GetUserRequest, request.user_id_); -} - -void Td::on_request(uint64 id, const td_api::getUserFullInfo &request) { - CREATE_REQUEST(GetUserFullInfoRequest, request.user_id_); -} - -void Td::on_request(uint64 id, const td_api::getBasicGroup &request) { - CREATE_REQUEST(GetGroupRequest, request.basic_group_id_); -} - -void Td::on_request(uint64 id, const td_api::getBasicGroupFullInfo &request) { - CREATE_REQUEST(GetGroupFullInfoRequest, request.basic_group_id_); -} - -void Td::on_request(uint64 id, const td_api::getSupergroup &request) { - CREATE_REQUEST(GetSupergroupRequest, request.supergroup_id_); -} - -void Td::on_request(uint64 id, const td_api::getSupergroupFullInfo &request) { - CREATE_REQUEST(GetSupergroupFullInfoRequest, request.supergroup_id_); -} - -void Td::on_request(uint64 id, const td_api::getSecretChat &request) { - CREATE_REQUEST(GetSecretChatRequest, request.secret_chat_id_); -} - -void Td::on_request(uint64 id, const td_api::getChat &request) { - CREATE_REQUEST(GetChatRequest, request.chat_id_); -} - -void Td::on_request(uint64 id, const td_api::getMessage &request) { - CREATE_REQUEST(GetMessageRequest, request.chat_id_, request.message_id_); -} - -void Td::on_request(uint64 id, const td_api::getMessageLocally &request) { - MessageFullId message_full_id(DialogId(request.chat_id_), MessageId(request.message_id_)); - send_closure(actor_id(this), &Td::send_result, id, - messages_manager_->get_message_object(message_full_id, "getMessageLocally")); -} - -void Td::on_request(uint64 id, const td_api::getRepliedMessage &request) { - CREATE_REQUEST(GetRepliedMessageRequest, request.chat_id_, request.message_id_); -} - -void Td::on_request(uint64 id, const td_api::getChatPinnedMessage &request) { - CREATE_REQUEST(GetChatPinnedMessageRequest, request.chat_id_); -} - -void Td::on_request(uint64 id, const td_api::getCallbackQueryMessage &request) { - CHECK_IS_BOT(); - CREATE_REQUEST(GetCallbackQueryMessageRequest, request.chat_id_, request.message_id_, request.callback_query_id_); -} - -void Td::on_request(uint64 id, const td_api::getMessages &request) { - CREATE_REQUEST(GetMessagesRequest, request.chat_id_, request.message_ids_); -} - -void Td::on_request(uint64 id, const td_api::getMessageProperties &request) { - CREATE_REQUEST_PROMISE(); - messages_manager_->get_message_properties(DialogId(request.chat_id_), MessageId(request.message_id_), - std::move(promise)); -} - -void Td::on_request(uint64 id, const td_api::getChatSponsoredMessages &request) { - CHECK_IS_USER(); - CREATE_REQUEST_PROMISE(); - sponsored_message_manager_->get_dialog_sponsored_messages(DialogId(request.chat_id_), std::move(promise)); -} - -void Td::on_request(uint64 id, const td_api::clickChatSponsoredMessage &request) { - CHECK_IS_USER(); - CREATE_OK_REQUEST_PROMISE(); - sponsored_message_manager_->click_sponsored_message(DialogId(request.chat_id_), MessageId(request.message_id_), - std::move(promise)); -} - -void Td::on_request(uint64 id, const td_api::reportChatSponsoredMessage &request) { - CHECK_IS_USER(); - CREATE_REQUEST_PROMISE(); - sponsored_message_manager_->report_sponsored_message(DialogId(request.chat_id_), MessageId(request.message_id_), - request.option_id_, std::move(promise)); -} - -void Td::on_request(uint64 id, const td_api::getMessageThread &request) { - CHECK_IS_USER(); - CREATE_REQUEST(GetMessageThreadRequest, request.chat_id_, request.message_id_); -} - -void Td::on_request(uint64 id, const td_api::getMessageReadDate &request) { - CHECK_IS_USER(); - CREATE_REQUEST_PROMISE(); - messages_manager_->get_message_read_date({DialogId(request.chat_id_), MessageId(request.message_id_)}, - std::move(promise)); -} - -void Td::on_request(uint64 id, const td_api::getMessageViewers &request) { - CHECK_IS_USER(); - CREATE_REQUEST_PROMISE(); - messages_manager_->get_message_viewers({DialogId(request.chat_id_), MessageId(request.message_id_)}, - std::move(promise)); -} - -void Td::on_request(uint64 id, const td_api::getMessageLink &request) { - auto r_message_link = - messages_manager_->get_message_link({DialogId(request.chat_id_), MessageId(request.message_id_)}, - request.media_timestamp_, request.for_album_, request.in_message_thread_); - if (r_message_link.is_error()) { - send_closure(actor_id(this), &Td::send_error, id, r_message_link.move_as_error()); - } else { - send_closure(actor_id(this), &Td::send_result, id, - td_api::make_object(r_message_link.ok().first, r_message_link.ok().second)); - } -} - -void Td::on_request(uint64 id, const td_api::getMessageEmbeddingCode &request) { - CHECK_IS_USER(); - CREATE_REQUEST(GetMessageEmbeddingCodeRequest, request.chat_id_, request.message_id_, request.for_album_); -} - -void Td::on_request(uint64 id, td_api::getMessageLinkInfo &request) { - CLEAN_INPUT_STRING(request.url_); - CREATE_REQUEST(GetMessageLinkInfoRequest, std::move(request.url_)); -} - -void Td::on_request(uint64 id, td_api::translateText &request) { - CHECK_IS_USER(); - CLEAN_INPUT_STRING(request.to_language_code_); - CREATE_REQUEST_PROMISE(); - translation_manager_->translate_text(std::move(request.text_), request.to_language_code_, std::move(promise)); -} - -void Td::on_request(uint64 id, td_api::translateMessageText &request) { - CHECK_IS_USER(); - CLEAN_INPUT_STRING(request.to_language_code_); - CREATE_REQUEST_PROMISE(); - messages_manager_->translate_message_text({DialogId(request.chat_id_), MessageId(request.message_id_)}, - request.to_language_code_, std::move(promise)); -} - -void Td::on_request(uint64 id, const td_api::recognizeSpeech &request) { - CHECK_IS_USER(); - CREATE_OK_REQUEST_PROMISE(); - transcription_manager_->recognize_speech({DialogId(request.chat_id_), MessageId(request.message_id_)}, - std::move(promise)); -} - -void Td::on_request(uint64 id, const td_api::rateSpeechRecognition &request) { - CHECK_IS_USER(); - CREATE_OK_REQUEST_PROMISE(); - transcription_manager_->rate_speech_recognition({DialogId(request.chat_id_), MessageId(request.message_id_)}, - request.is_good_, std::move(promise)); -} - -void Td::on_request(uint64 id, const td_api::getFile &request) { - auto file_object = file_manager_->get_file_object(FileId(request.file_id_, 0)); - if (file_object->id_ == 0) { - file_object = nullptr; - } else { - file_object->id_ = request.file_id_; - } - send_closure(actor_id(this), &Td::send_result, id, std::move(file_object)); -} - -void Td::on_request(uint64 id, td_api::getRemoteFile &request) { - CLEAN_INPUT_STRING(request.remote_file_id_); - auto file_type = request.file_type_ == nullptr ? FileType::Temp : get_file_type(*request.file_type_); - auto r_file_id = file_manager_->from_persistent_id(request.remote_file_id_, file_type); - if (r_file_id.is_error()) { - send_closure(actor_id(this), &Td::send_error, id, r_file_id.move_as_error()); - } else { - send_closure(actor_id(this), &Td::send_result, id, file_manager_->get_file_object(r_file_id.ok())); - } -} - -void Td::on_request(uint64 id, td_api::getStorageStatistics &request) { - CREATE_REQUEST_PROMISE(); - auto query_promise = PromiseCreator::lambda([promise = std::move(promise)](Result result) mutable { - if (result.is_error()) { - promise.set_error(result.move_as_error()); - } else { - promise.set_value(result.ok().get_storage_statistics_object()); - } - }); - send_closure(storage_manager_, &StorageManager::get_storage_stats, false /*need_all_files*/, request.chat_limit_, - std::move(query_promise)); -} - -void Td::on_request(uint64 id, td_api::getStorageStatisticsFast &request) { - CHECK_IS_USER(); - CREATE_REQUEST_PROMISE(); - auto query_promise = PromiseCreator::lambda([promise = std::move(promise)](Result result) mutable { - if (result.is_error()) { - promise.set_error(result.move_as_error()); - } else { - promise.set_value(result.ok().get_storage_statistics_fast_object()); - } - }); - send_closure(storage_manager_, &StorageManager::get_storage_stats_fast, std::move(query_promise)); -} - -void Td::on_request(uint64 id, const td_api::getDatabaseStatistics &request) { - CREATE_REQUEST_PROMISE(); - auto query_promise = PromiseCreator::lambda([promise = std::move(promise)](Result result) mutable { - if (result.is_error()) { - promise.set_error(result.move_as_error()); - } else { - promise.set_value(result.ok().get_database_statistics_object()); - } - }); - send_closure(storage_manager_, &StorageManager::get_database_stats, std::move(query_promise)); -} - -void Td::on_request(uint64 id, td_api::optimizeStorage &request) { - std::vector file_types; - for (auto &file_type : request.file_types_) { - if (file_type == nullptr) { - return send_error_raw(id, 400, "File type must be non-empty"); - } - - file_types.push_back(get_file_type(*file_type)); - } - FileGcParameters parameters(request.size_, request.ttl_, request.count_, request.immunity_delay_, - std::move(file_types), DialogId::get_dialog_ids(request.chat_ids_), - DialogId::get_dialog_ids(request.exclude_chat_ids_), request.chat_limit_); - - CREATE_REQUEST_PROMISE(); - auto query_promise = PromiseCreator::lambda([promise = std::move(promise)](Result result) mutable { - if (result.is_error()) { - promise.set_error(result.move_as_error()); - } else { - promise.set_value(result.ok().get_storage_statistics_object()); - } - }); - send_closure(storage_manager_, &StorageManager::run_gc, std::move(parameters), - request.return_deleted_file_statistics_, std::move(query_promise)); -} - -void Td::on_request(uint64 id, td_api::getNetworkStatistics &request) { - if (net_stats_manager_.empty()) { - return send_error_raw(id, 400, "Network statistics are disabled"); - } - if (!request.only_current_ && G()->get_option_boolean("disable_persistent_network_statistics")) { - return send_error_raw(id, 400, "Persistent network statistics are disabled"); - } - CREATE_REQUEST_PROMISE(); - auto query_promise = PromiseCreator::lambda([promise = std::move(promise)](Result result) mutable { - if (result.is_error()) { - promise.set_error(result.move_as_error()); - } else { - promise.set_value(result.ok().get_network_statistics_object()); - } - }); - send_closure(net_stats_manager_, &NetStatsManager::get_network_stats, request.only_current_, - std::move(query_promise)); -} - -void Td::on_request(uint64 id, td_api::resetNetworkStatistics &request) { - if (net_stats_manager_.empty()) { - return send_error_raw(id, 400, "Network statistics are disabled"); - } - CREATE_OK_REQUEST_PROMISE(); - send_closure(net_stats_manager_, &NetStatsManager::reset_network_stats); - promise.set_value(Unit()); -} - -void Td::on_request(uint64 id, td_api::addNetworkStatistics &request) { - if (request.entry_ == nullptr) { - return send_error_raw(id, 400, "Network statistics entry must be non-empty"); - } - if (net_stats_manager_.empty()) { - return send_error_raw(id, 400, "Network statistics are disabled"); - } - - NetworkStatsEntry entry; - switch (request.entry_->get_id()) { - case td_api::networkStatisticsEntryFile::ID: { - auto file_entry = move_tl_object_as(request.entry_); - entry.is_call = false; - if (file_entry->file_type_ != nullptr) { - entry.file_type = get_file_type(*file_entry->file_type_); - } - entry.net_type = get_net_type(file_entry->network_type_); - entry.rx = file_entry->received_bytes_; - entry.tx = file_entry->sent_bytes_; - break; - } - case td_api::networkStatisticsEntryCall::ID: { - auto call_entry = move_tl_object_as(request.entry_); - entry.is_call = true; - entry.net_type = get_net_type(call_entry->network_type_); - entry.rx = call_entry->received_bytes_; - entry.tx = call_entry->sent_bytes_; - entry.duration = call_entry->duration_; - break; - } - default: - UNREACHABLE(); - } - - if (entry.net_type == NetType::None) { - return send_error_raw(id, 400, "Network statistics entry can't be increased for NetworkTypeNone"); - } - if (entry.rx > (static_cast(1) << 40) || entry.rx < 0) { - return send_error_raw(id, 400, "Wrong received bytes value"); - } - if (entry.tx > (static_cast(1) << 40) || entry.tx < 0) { - return send_error_raw(id, 400, "Wrong sent bytes value"); - } - if (entry.count > (1 << 30) || entry.count < 0) { - return send_error_raw(id, 400, "Wrong count value"); - } - if (entry.duration > (1 << 30) || entry.duration < 0) { - return send_error_raw(id, 400, "Wrong duration value"); - } - - send_closure(net_stats_manager_, &NetStatsManager::add_network_stats, entry); - send_closure(actor_id(this), &Td::send_result, id, make_tl_object()); -} - -void Td::on_request(uint64 id, const td_api::setNetworkType &request) { - CREATE_OK_REQUEST_PROMISE(); - send_closure(state_manager_, &StateManager::on_network, get_net_type(request.type_)); - promise.set_value(Unit()); -} - -void Td::on_request(uint64 id, const td_api::getAutoDownloadSettingsPresets &request) { - CHECK_IS_USER(); - CREATE_REQUEST_PROMISE(); - get_auto_download_settings_presets(this, std::move(promise)); -} - -void Td::on_request(uint64 id, const td_api::setAutoDownloadSettings &request) { - CHECK_IS_USER(); - if (request.settings_ == nullptr) { - return send_error_raw(id, 400, "New settings must be non-empty"); - } - CREATE_OK_REQUEST_PROMISE(); - set_auto_download_settings(this, get_net_type(request.type_), get_auto_download_settings(request.settings_), - std::move(promise)); -} - -void Td::on_request(uint64 id, const td_api::getAutosaveSettings &request) { - CHECK_IS_USER(); - CREATE_REQUEST_PROMISE(); - autosave_manager_->get_autosave_settings(std::move(promise)); -} - -void Td::on_request(uint64 id, td_api::setAutosaveSettings &request) { - CHECK_IS_USER(); - CREATE_OK_REQUEST_PROMISE(); - autosave_manager_->set_autosave_settings(std::move(request.scope_), std::move(request.settings_), std::move(promise)); -} - -void Td::on_request(uint64 id, const td_api::clearAutosaveSettingsExceptions &request) { - CHECK_IS_USER(); - CREATE_OK_REQUEST_PROMISE(); - autosave_manager_->clear_autosave_settings_exceptions(std::move(promise)); -} - -void Td::on_request(uint64 id, const td_api::getRecommendedChats &request) { - CHECK_IS_USER(); - CREATE_REQUEST_PROMISE(); - channel_recommendation_manager_->get_recommended_channels(std::move(promise)); -} - -void Td::on_request(uint64 id, const td_api::getChatSimilarChats &request) { - CHECK_IS_USER(); - CREATE_REQUEST_PROMISE(); - channel_recommendation_manager_->get_channel_recommendations(DialogId(request.chat_id_), false, std::move(promise), - Auto()); -} - -void Td::on_request(uint64 id, const td_api::getChatSimilarChatCount &request) { - CHECK_IS_USER(); - CREATE_REQUEST_PROMISE(); - channel_recommendation_manager_->get_channel_recommendations(DialogId(request.chat_id_), request.return_local_, - Auto(), std::move(promise)); -} - -void Td::on_request(uint64 id, const td_api::openChatSimilarChat &request) { - CHECK_IS_USER(); - CREATE_OK_REQUEST_PROMISE(); - channel_recommendation_manager_->open_channel_recommended_channel( - DialogId(request.chat_id_), DialogId(request.opened_chat_id_), std::move(promise)); -} - -void Td::on_request(uint64 id, const td_api::getTopChats &request) { - CHECK_IS_USER(); - CREATE_REQUEST_PROMISE(); - send_closure(top_dialog_manager_actor_, &TopDialogManager::get_top_dialogs, - get_top_dialog_category(request.category_), request.limit_, std::move(promise)); -} - -void Td::on_request(uint64 id, const td_api::removeTopChat &request) { - CHECK_IS_USER(); - CREATE_OK_REQUEST_PROMISE(); - send_closure(top_dialog_manager_actor_, &TopDialogManager::remove_dialog, get_top_dialog_category(request.category_), - DialogId(request.chat_id_), std::move(promise)); -} - -void Td::on_request(uint64 id, const td_api::loadChats &request) { - CHECK_IS_USER(); - - DialogListId dialog_list_id(request.chat_list_); - auto r_offset = messages_manager_->get_dialog_list_last_date(dialog_list_id); - if (r_offset.is_error()) { - return send_error_raw(id, 400, r_offset.error().message()); - } - auto offset = r_offset.move_as_ok(); - if (offset == MAX_DIALOG_DATE) { - return send_closure(actor_id(this), &Td::send_result, id, nullptr); - } - - CREATE_REQUEST(LoadChatsRequest, dialog_list_id, offset, request.limit_); -} - -void Td::on_request(uint64 id, const td_api::getChats &request) { - CHECK_IS_USER(); - CREATE_REQUEST_PROMISE(); - messages_manager_->get_dialogs_from_list(DialogListId(request.chat_list_), request.limit_, std::move(promise)); -} - -void Td::on_request(uint64 id, const td_api::loadSavedMessagesTopics &request) { - CHECK_IS_USER(); - CREATE_OK_REQUEST_PROMISE(); - saved_messages_manager_->load_saved_messages_topics(request.limit_, std::move(promise)); -} - -void Td::on_request(uint64 id, const td_api::getSavedMessagesTopicHistory &request) { - CHECK_IS_USER(); - CREATE_REQUEST_PROMISE(); - saved_messages_manager_->get_saved_messages_topic_history( - saved_messages_manager_->get_topic_id(request.saved_messages_topic_id_), MessageId(request.from_message_id_), - request.offset_, request.limit_, std::move(promise)); -} - -void Td::on_request(uint64 id, const td_api::getSavedMessagesTopicMessageByDate &request) { - CHECK_IS_USER(); - CREATE_REQUEST_PROMISE(); - saved_messages_manager_->get_saved_messages_topic_message_by_date( - saved_messages_manager_->get_topic_id(request.saved_messages_topic_id_), request.date_, std::move(promise)); -} - -void Td::on_request(uint64 id, const td_api::deleteSavedMessagesTopicHistory &request) { - CHECK_IS_USER(); - CREATE_OK_REQUEST_PROMISE(); - saved_messages_manager_->delete_saved_messages_topic_history( - saved_messages_manager_->get_topic_id(request.saved_messages_topic_id_), std::move(promise)); -} - -void Td::on_request(uint64 id, const td_api::deleteSavedMessagesTopicMessagesByDate &request) { - CHECK_IS_USER(); - CREATE_OK_REQUEST_PROMISE(); - saved_messages_manager_->delete_saved_messages_topic_messages_by_date( - saved_messages_manager_->get_topic_id(request.saved_messages_topic_id_), request.min_date_, request.max_date_, - std::move(promise)); -} - -void Td::on_request(uint64 id, const td_api::toggleSavedMessagesTopicIsPinned &request) { - CHECK_IS_USER(); - CREATE_OK_REQUEST_PROMISE(); - saved_messages_manager_->toggle_saved_messages_topic_is_pinned( - saved_messages_manager_->get_topic_id(request.saved_messages_topic_id_), request.is_pinned_, std::move(promise)); -} - -void Td::on_request(uint64 id, const td_api::setPinnedSavedMessagesTopics &request) { - CHECK_IS_USER(); - CREATE_OK_REQUEST_PROMISE(); - saved_messages_manager_->set_pinned_saved_messages_topics( - saved_messages_manager_->get_topic_ids(request.saved_messages_topic_ids_), std::move(promise)); -} - -void Td::on_request(uint64 id, td_api::searchPublicChat &request) { - CLEAN_INPUT_STRING(request.username_); - CREATE_REQUEST(SearchPublicChatRequest, request.username_); -} - -void Td::on_request(uint64 id, td_api::searchPublicChats &request) { - CHECK_IS_USER(); - CLEAN_INPUT_STRING(request.query_); - CREATE_REQUEST(SearchPublicChatsRequest, request.query_); -} - -void Td::on_request(uint64 id, td_api::searchChats &request) { - CHECK_IS_USER(); - CLEAN_INPUT_STRING(request.query_); - CREATE_REQUEST(SearchChatsRequest, request.query_, request.limit_); -} - -void Td::on_request(uint64 id, td_api::searchChatsOnServer &request) { - CHECK_IS_USER(); - CLEAN_INPUT_STRING(request.query_); - CREATE_REQUEST(SearchChatsOnServerRequest, request.query_, request.limit_); -} - -void Td::on_request(uint64 id, const td_api::searchChatsNearby &request) { - CHECK_IS_USER(); - CREATE_REQUEST_PROMISE(); - people_nearby_manager_->search_dialogs_nearby(Location(request.location_), std::move(promise)); -} - -void Td::on_request(uint64 id, const td_api::getGroupsInCommon &request) { - CHECK_IS_USER(); - CREATE_REQUEST(GetGroupsInCommonRequest, request.user_id_, request.offset_chat_id_, request.limit_); -} - -void Td::on_request(uint64 id, td_api::checkChatUsername &request) { - CHECK_IS_USER(); - CLEAN_INPUT_STRING(request.username_); - CREATE_REQUEST_PROMISE(); - auto query_promise = PromiseCreator::lambda( - [promise = std::move(promise)](Result result) mutable { - if (result.is_error()) { - promise.set_error(result.move_as_error()); - } else { - promise.set_value(DialogManager::get_check_chat_username_result_object(result.ok())); - } - }); - dialog_manager_->check_dialog_username(DialogId(request.chat_id_), request.username_, std::move(query_promise)); -} - -void Td::on_request(uint64 id, const td_api::getCreatedPublicChats &request) { - CHECK_IS_USER(); - CREATE_REQUEST_PROMISE(); - chat_manager_->get_created_public_dialogs(get_public_dialog_type(request.type_), std::move(promise), false); -} - -void Td::on_request(uint64 id, const td_api::checkCreatedPublicChatsLimit &request) { - CHECK_IS_USER(); - CREATE_OK_REQUEST_PROMISE(); - chat_manager_->check_created_public_dialogs_limit(get_public_dialog_type(request.type_), std::move(promise)); -} - -void Td::on_request(uint64 id, const td_api::getSuitableDiscussionChats &request) { - CHECK_IS_USER(); - CREATE_NO_ARGS_REQUEST(GetSuitableDiscussionChatsRequest); -} - -void Td::on_request(uint64 id, const td_api::getInactiveSupergroupChats &request) { - CHECK_IS_USER(); - CREATE_NO_ARGS_REQUEST(GetInactiveSupergroupChatsRequest); -} - -void Td::on_request(uint64 id, const td_api::getSuitablePersonalChats &request) { - CHECK_IS_USER(); - CREATE_REQUEST_PROMISE(); - chat_manager_->get_created_public_dialogs(PublicDialogType::ForPersonalDialog, std::move(promise), false); -} - -void Td::on_request(uint64 id, td_api::searchRecentlyFoundChats &request) { - CHECK_IS_USER(); - CLEAN_INPUT_STRING(request.query_); - CREATE_REQUEST(SearchRecentlyFoundChatsRequest, request.query_, request.limit_); -} - -void Td::on_request(uint64 id, const td_api::addRecentlyFoundChat &request) { - CHECK_IS_USER(); - answer_ok_query(id, messages_manager_->add_recently_found_dialog(DialogId(request.chat_id_))); -} - -void Td::on_request(uint64 id, const td_api::removeRecentlyFoundChat &request) { - CHECK_IS_USER(); - answer_ok_query(id, messages_manager_->remove_recently_found_dialog(DialogId(request.chat_id_))); -} - -void Td::on_request(uint64 id, const td_api::clearRecentlyFoundChats &request) { - CHECK_IS_USER(); - messages_manager_->clear_recently_found_dialogs(); - send_closure(actor_id(this), &Td::send_result, id, make_tl_object()); -} - -void Td::on_request(uint64 id, const td_api::getRecentlyOpenedChats &request) { - CHECK_IS_USER(); - CREATE_REQUEST(GetRecentlyOpenedChatsRequest, request.limit_); -} - -void Td::on_request(uint64 id, const td_api::openChat &request) { - CHECK_IS_USER(); - answer_ok_query(id, messages_manager_->open_dialog(DialogId(request.chat_id_))); -} - -void Td::on_request(uint64 id, const td_api::closeChat &request) { - CHECK_IS_USER(); - answer_ok_query(id, messages_manager_->close_dialog(DialogId(request.chat_id_))); -} - -void Td::on_request(uint64 id, const td_api::viewMessages &request) { - CHECK_IS_USER(); - answer_ok_query( - id, messages_manager_->view_messages(DialogId(request.chat_id_), MessageId::get_message_ids(request.message_ids_), - get_message_source(request.source_), request.force_read_)); -} - -void Td::on_request(uint64 id, const td_api::openMessageContent &request) { - CHECK_IS_USER(); - answer_ok_query( - id, messages_manager_->open_message_content({DialogId(request.chat_id_), MessageId(request.message_id_)})); -} - -void Td::on_request(uint64 id, const td_api::clickAnimatedEmojiMessage &request) { - CHECK_IS_USER(); - CREATE_REQUEST_PROMISE(); - messages_manager_->click_animated_emoji_message({DialogId(request.chat_id_), MessageId(request.message_id_)}, - std::move(promise)); -} - -void Td::on_request(uint64 id, const td_api::getInternalLink &request) { - auto r_link = LinkManager::get_internal_link(request.type_, !request.is_http_); - if (r_link.is_error()) { - send_closure(actor_id(this), &Td::send_error, id, r_link.move_as_error()); - } else { - send_closure(actor_id(this), &Td::send_result, id, td_api::make_object(r_link.move_as_ok())); - } -} - -void Td::on_request(uint64 id, const td_api::getInternalLinkType &request) { - auto type = LinkManager::parse_internal_link(request.link_); - send_closure(actor_id(this), &Td::send_result, id, type == nullptr ? nullptr : type->get_internal_link_type_object()); -} - -void Td::on_request(uint64 id, td_api::getExternalLinkInfo &request) { - CHECK_IS_USER(); - CLEAN_INPUT_STRING(request.link_); - CREATE_REQUEST_PROMISE(); - link_manager_->get_external_link_info(std::move(request.link_), std::move(promise)); -} - -void Td::on_request(uint64 id, td_api::getExternalLink &request) { - CHECK_IS_USER(); - CLEAN_INPUT_STRING(request.link_); - CREATE_REQUEST_PROMISE(); - link_manager_->get_link_login_url(request.link_, request.allow_write_access_, std::move(promise)); -} - -void Td::on_request(uint64 id, const td_api::getChatHistory &request) { - CHECK_IS_USER(); - CREATE_REQUEST(GetChatHistoryRequest, request.chat_id_, request.from_message_id_, request.offset_, request.limit_, - request.only_local_); -} - -void Td::on_request(uint64 id, const td_api::deleteChatHistory &request) { - CHECK_IS_USER(); - CREATE_OK_REQUEST_PROMISE(); - messages_manager_->delete_dialog_history(DialogId(request.chat_id_), request.remove_from_chat_list_, request.revoke_, - std::move(promise)); -} - -void Td::on_request(uint64 id, const td_api::deleteChat &request) { - CHECK_IS_USER(); - CREATE_OK_REQUEST_PROMISE(); - DialogId dialog_id(request.chat_id_); - auto query_promise = [actor_id = messages_manager_actor_.get(), dialog_id, - promise = std::move(promise)](Result &&result) mutable { - if (result.is_error()) { - promise.set_error(result.move_as_error()); - } else { - send_closure(actor_id, &MessagesManager::on_dialog_deleted, dialog_id, std::move(promise)); - } - }; - dialog_manager_->delete_dialog(dialog_id, std::move(query_promise)); -} - -void Td::on_request(uint64 id, const td_api::getMessageThreadHistory &request) { - CHECK_IS_USER(); - CREATE_REQUEST(GetMessageThreadHistoryRequest, request.chat_id_, request.message_id_, request.from_message_id_, - request.offset_, request.limit_); -} - -void Td::on_request(uint64 id, const td_api::getChatMessageCalendar &request) { - CHECK_IS_USER(); - CREATE_REQUEST_PROMISE(); - messages_manager_->get_dialog_message_calendar( - DialogId(request.chat_id_), saved_messages_manager_->get_topic_id(request.saved_messages_topic_id_), - MessageId(request.from_message_id_), get_message_search_filter(request.filter_), std::move(promise)); -} - -void Td::on_request(uint64 id, td_api::searchChatMessages &request) { - CHECK_IS_USER(); - CLEAN_INPUT_STRING(request.query_); - CREATE_REQUEST(SearchChatMessagesRequest, request.chat_id_, std::move(request.query_), std::move(request.sender_id_), - request.from_message_id_, request.offset_, request.limit_, std::move(request.filter_), - request.message_thread_id_, saved_messages_manager_->get_topic_id(request.saved_messages_topic_id_), - ReactionType()); -} - -void Td::on_request(uint64 id, td_api::searchSecretMessages &request) { - CHECK_IS_USER(); - CLEAN_INPUT_STRING(request.query_); - CLEAN_INPUT_STRING(request.offset_); - CREATE_REQUEST_PROMISE(); - messages_manager_->offline_search_messages(DialogId(request.chat_id_), std::move(request.query_), - std::move(request.offset_), request.limit_, - get_message_search_filter(request.filter_), std::move(promise)); -} - -void Td::on_request(uint64 id, td_api::searchMessages &request) { - CHECK_IS_USER(); - CLEAN_INPUT_STRING(request.query_); - CLEAN_INPUT_STRING(request.offset_); - CREATE_REQUEST_PROMISE(); - messages_manager_->search_messages(DialogListId(request.chat_list_), request.chat_list_ == nullptr, - request.only_in_channels_, std::move(request.query_), std::move(request.offset_), - request.limit_, get_message_search_filter(request.filter_), request.min_date_, - request.max_date_, std::move(promise)); -} - -void Td::on_request(uint64 id, td_api::searchSavedMessages &request) { - CHECK_IS_USER(); - CLEAN_INPUT_STRING(request.query_); - CREATE_REQUEST(SearchChatMessagesRequest, dialog_manager_->get_my_dialog_id().get(), std::move(request.query_), - nullptr, request.from_message_id_, request.offset_, request.limit_, nullptr, 0, - saved_messages_manager_->get_topic_id(request.saved_messages_topic_id_), ReactionType(request.tag_)); -} - -void Td::on_request(uint64 id, const td_api::searchCallMessages &request) { - CHECK_IS_USER(); - CREATE_REQUEST_PROMISE(); - messages_manager_->search_call_messages(request.offset_, request.limit_, request.only_missed_, std::move(promise)); -} - -void Td::on_request(uint64 id, td_api::searchOutgoingDocumentMessages &request) { - CHECK_IS_USER(); - CLEAN_INPUT_STRING(request.query_); - CREATE_REQUEST_PROMISE(); - messages_manager_->search_outgoing_document_messages(request.query_, request.limit_, std::move(promise)); -} - -void Td::on_request(uint64 id, td_api::searchPublicMessagesByTag &request) { - CHECK_IS_USER(); - CLEAN_INPUT_STRING(request.tag_); - CLEAN_INPUT_STRING(request.offset_); - CREATE_REQUEST_PROMISE(); - messages_manager_->search_hashtag_posts(std::move(request.tag_), std::move(request.offset_), request.limit_, - std::move(promise)); -} - -void Td::on_request(uint64 id, td_api::searchPublicStoriesByTag &request) { - CHECK_IS_USER(); - CLEAN_INPUT_STRING(request.tag_); - CLEAN_INPUT_STRING(request.offset_); - CREATE_REQUEST_PROMISE(); - story_manager_->search_hashtag_posts(std::move(request.tag_), std::move(request.offset_), request.limit_, - std::move(promise)); -} - -void Td::on_request(uint64 id, td_api::searchPublicStoriesByLocation &request) { - CHECK_IS_USER(); - if (request.address_ == nullptr) { - return send_error_raw(id, 400, "Address must be non-empty"); - } - CLEAN_INPUT_STRING(request.address_->country_code_); - CLEAN_INPUT_STRING(request.address_->state_); - CLEAN_INPUT_STRING(request.address_->city_); - CLEAN_INPUT_STRING(request.address_->street_); - CLEAN_INPUT_STRING(request.offset_); - CREATE_REQUEST_PROMISE(); - story_manager_->search_location_posts(std::move(request.address_), std::move(request.offset_), request.limit_, - std::move(promise)); -} - -void Td::on_request(uint64 id, td_api::searchPublicStoriesByVenue &request) { - CHECK_IS_USER(); - CLEAN_INPUT_STRING(request.venue_provider_); - CLEAN_INPUT_STRING(request.venue_id_); - CLEAN_INPUT_STRING(request.offset_); - CREATE_REQUEST_PROMISE(); - story_manager_->search_venue_posts(std::move(request.venue_provider_), std::move(request.venue_id_), - std::move(request.offset_), request.limit_, std::move(promise)); -} - -void Td::on_request(uint64 id, td_api::getSearchedForTags &request) { - CHECK_IS_USER(); - CLEAN_INPUT_STRING(request.tag_prefix_); - CREATE_REQUEST_PROMISE(); - auto query_promise = PromiseCreator::lambda([promise = std::move(promise)](Result> result) mutable { - if (result.is_error()) { - promise.set_error(result.move_as_error()); - } else { - promise.set_value(td_api::make_object(result.move_as_ok())); - } - }); - send_closure(request.tag_prefix_[0] == '$' ? cashtag_search_hints_ : hashtag_search_hints_, &HashtagHints::query, - std::move(request.tag_prefix_), request.limit_, std::move(query_promise)); -} - -void Td::on_request(uint64 id, td_api::removeSearchedForTag &request) { - CHECK_IS_USER(); - CLEAN_INPUT_STRING(request.tag_); - CREATE_OK_REQUEST_PROMISE(); - send_closure(request.tag_[0] == '$' ? cashtag_search_hints_ : hashtag_search_hints_, &HashtagHints::remove_hashtag, - std::move(request.tag_), std::move(promise)); -} - -void Td::on_request(uint64 id, td_api::clearSearchedForTags &request) { - CHECK_IS_USER(); - CREATE_OK_REQUEST_PROMISE(); - send_closure(request.clear_cashtags_ ? cashtag_search_hints_ : hashtag_search_hints_, &HashtagHints::clear, - std::move(promise)); -} - -void Td::on_request(uint64 id, const td_api::deleteAllCallMessages &request) { - CHECK_IS_USER(); - CREATE_OK_REQUEST_PROMISE(); - messages_manager_->delete_all_call_messages(request.revoke_, std::move(promise)); -} - -void Td::on_request(uint64 id, const td_api::searchChatRecentLocationMessages &request) { - CHECK_IS_USER(); - CREATE_REQUEST_PROMISE(); - messages_manager_->search_dialog_recent_location_messages(DialogId(request.chat_id_), request.limit_, - std::move(promise)); -} - -void Td::on_request(uint64 id, const td_api::getChatMessageByDate &request) { - CHECK_IS_USER(); - CREATE_REQUEST_PROMISE(); - messages_manager_->get_dialog_message_by_date(DialogId(request.chat_id_), request.date_, std::move(promise)); -} - -void Td::on_request(uint64 id, const td_api::getChatSparseMessagePositions &request) { - CHECK_IS_USER(); - CREATE_REQUEST_PROMISE(); - messages_manager_->get_dialog_sparse_message_positions( - DialogId(request.chat_id_), saved_messages_manager_->get_topic_id(request.saved_messages_topic_id_), - get_message_search_filter(request.filter_), MessageId(request.from_message_id_), request.limit_, - std::move(promise)); -} - -void Td::on_request(uint64 id, const td_api::getChatMessageCount &request) { - CHECK_IS_USER(); - CREATE_REQUEST_PROMISE(); - auto query_promise = PromiseCreator::lambda([promise = std::move(promise)](Result result) mutable { - if (result.is_error()) { - promise.set_error(result.move_as_error()); - } else { - promise.set_value(make_tl_object(result.move_as_ok())); - } - }); - messages_manager_->get_dialog_message_count( - DialogId(request.chat_id_), saved_messages_manager_->get_topic_id(request.saved_messages_topic_id_), - get_message_search_filter(request.filter_), request.return_local_, std::move(query_promise)); -} - -void Td::on_request(uint64 id, const td_api::getChatMessagePosition &request) { - CHECK_IS_USER(); - CREATE_REQUEST_PROMISE(); - auto query_promise = PromiseCreator::lambda([promise = std::move(promise)](Result result) mutable { - if (result.is_error()) { - promise.set_error(result.move_as_error()); - } else { - promise.set_value(make_tl_object(result.move_as_ok())); - } - }); - messages_manager_->get_dialog_message_position( - {DialogId(request.chat_id_), MessageId(request.message_id_)}, get_message_search_filter(request.filter_), - MessageId(request.message_thread_id_), saved_messages_manager_->get_topic_id(request.saved_messages_topic_id_), - std::move(query_promise)); -} - -void Td::on_request(uint64 id, const td_api::getChatScheduledMessages &request) { - CHECK_IS_USER(); - CREATE_REQUEST(GetChatScheduledMessagesRequest, request.chat_id_); -} - -void Td::on_request(uint64 id, const td_api::getEmojiReaction &request) { - CHECK_IS_USER(); - CREATE_REQUEST_PROMISE(); - reaction_manager_->get_emoji_reaction(request.emoji_, std::move(promise)); -} - -void Td::on_request(uint64 id, const td_api::getCustomEmojiReactionAnimations &request) { - CHECK_IS_USER(); - CREATE_REQUEST_PROMISE(); - stickers_manager_->get_custom_emoji_reaction_generic_animations(false, std::move(promise)); -} - -void Td::on_request(uint64 id, const td_api::getMessageAvailableReactions &request) { - CHECK_IS_USER(); - auto r_reactions = messages_manager_->get_message_available_reactions( - {DialogId(request.chat_id_), MessageId(request.message_id_)}, request.row_size_); - if (r_reactions.is_error()) { - send_closure(actor_id(this), &Td::send_error, id, r_reactions.move_as_error()); - } else { - send_closure(actor_id(this), &Td::send_result, id, r_reactions.move_as_ok()); - } -} - -void Td::on_request(uint64 id, const td_api::clearRecentReactions &request) { - CHECK_IS_USER(); - CREATE_OK_REQUEST_PROMISE(); - reaction_manager_->clear_recent_reactions(std::move(promise)); -} - -void Td::on_request(uint64 id, const td_api::addMessageReaction &request) { - CHECK_IS_USER(); - CREATE_OK_REQUEST_PROMISE(); - messages_manager_->add_message_reaction({DialogId(request.chat_id_), MessageId(request.message_id_)}, - ReactionType(request.reaction_type_), request.is_big_, - request.update_recent_reactions_, std::move(promise)); -} - -void Td::on_request(uint64 id, const td_api::addPaidMessageReaction &request) { - CHECK_IS_USER(); - CREATE_OK_REQUEST_PROMISE(); - messages_manager_->add_paid_message_reaction({DialogId(request.chat_id_), MessageId(request.message_id_)}, - request.star_count_, request.is_anonymous_, std::move(promise)); -} - -void Td::on_request(uint64 id, const td_api::removePendingPaidMessageReactions &request) { - CHECK_IS_USER(); - CREATE_OK_REQUEST_PROMISE(); - messages_manager_->remove_paid_message_reactions({DialogId(request.chat_id_), MessageId(request.message_id_)}, - std::move(promise)); -} - -void Td::on_request(uint64 id, const td_api::togglePaidMessageReactionIsAnonymous &request) { - CHECK_IS_USER(); - CREATE_OK_REQUEST_PROMISE(); - messages_manager_->toggle_paid_message_reaction_is_anonymous( - {DialogId(request.chat_id_), MessageId(request.message_id_)}, request.is_anonymous_, std::move(promise)); -} - -void Td::on_request(uint64 id, const td_api::removeMessageReaction &request) { - CHECK_IS_USER(); - CREATE_OK_REQUEST_PROMISE(); - messages_manager_->remove_message_reaction({DialogId(request.chat_id_), MessageId(request.message_id_)}, - ReactionType(request.reaction_type_), std::move(promise)); -} - -void Td::on_request(uint64 id, const td_api::setMessageReactions &request) { - CHECK_IS_BOT(); - CREATE_OK_REQUEST_PROMISE(); - set_message_reactions(this, {DialogId(request.chat_id_), MessageId(request.message_id_)}, - ReactionType::get_reaction_types(request.reaction_types_), request.is_big_, std::move(promise)); -} - -void Td::on_request(uint64 id, td_api::getMessageAddedReactions &request) { - CHECK_IS_USER(); - CLEAN_INPUT_STRING(request.offset_); - CREATE_REQUEST_PROMISE(); - get_message_added_reactions(this, {DialogId(request.chat_id_), MessageId(request.message_id_)}, - ReactionType(request.reaction_type_), std::move(request.offset_), request.limit_, - std::move(promise)); -} - -void Td::on_request(uint64 id, const td_api::setDefaultReactionType &request) { - CHECK_IS_USER(); - CREATE_OK_REQUEST_PROMISE(); - reaction_manager_->set_default_reaction(ReactionType(request.reaction_type_), std::move(promise)); -} - -void Td::on_request(uint64 id, const td_api::getSavedMessagesTags &request) { - CHECK_IS_USER(); - CREATE_REQUEST_PROMISE(); - reaction_manager_->get_saved_messages_tags(saved_messages_manager_->get_topic_id(request.saved_messages_topic_id_), - std::move(promise)); -} - -void Td::on_request(uint64 id, td_api::setSavedMessagesTagLabel &request) { - CHECK_IS_USER(); - CLEAN_INPUT_STRING(request.label_); - CREATE_OK_REQUEST_PROMISE(); - reaction_manager_->set_saved_messages_tag_title(ReactionType(request.tag_), std::move(request.label_), - std::move(promise)); -} - -void Td::on_request(uint64 id, const td_api::getMessageEffect &request) { - CHECK_IS_USER(); - CREATE_REQUEST_PROMISE(); - reaction_manager_->get_message_effect(MessageEffectId(request.effect_id_), std::move(promise)); -} - -void Td::on_request(uint64 id, td_api::getMessagePublicForwards &request) { - CHECK_IS_USER(); - CLEAN_INPUT_STRING(request.offset_); - CREATE_REQUEST_PROMISE(); - statistics_manager_->get_message_public_forwards({DialogId(request.chat_id_), MessageId(request.message_id_)}, - std::move(request.offset_), request.limit_, std::move(promise)); -} - -void Td::on_request(uint64 id, td_api::getStoryPublicForwards &request) { - CHECK_IS_USER(); - CLEAN_INPUT_STRING(request.offset_); - CREATE_REQUEST_PROMISE(); - statistics_manager_->get_story_public_forwards({DialogId(request.story_sender_chat_id_), StoryId(request.story_id_)}, - std::move(request.offset_), request.limit_, std::move(promise)); -} - -void Td::on_request(uint64 id, const td_api::removeNotification &request) { - CHECK_IS_USER(); - CREATE_OK_REQUEST_PROMISE(); - send_closure(notification_manager_actor_, &NotificationManager::remove_notification, - NotificationGroupId(request.notification_group_id_), NotificationId(request.notification_id_), false, - true, std::move(promise), "td_api::removeNotification"); -} - -void Td::on_request(uint64 id, const td_api::removeNotificationGroup &request) { - CHECK_IS_USER(); - CREATE_OK_REQUEST_PROMISE(); - send_closure(notification_manager_actor_, &NotificationManager::remove_notification_group, - NotificationGroupId(request.notification_group_id_), NotificationId(request.max_notification_id_), - NotificationObjectId(), -1, true, std::move(promise)); -} - -void Td::on_request(uint64 id, const td_api::deleteMessages &request) { - CREATE_OK_REQUEST_PROMISE(); - messages_manager_->delete_messages(DialogId(request.chat_id_), MessageId::get_message_ids(request.message_ids_), - request.revoke_, std::move(promise)); -} - -void Td::on_request(uint64 id, const td_api::deleteChatMessagesBySender &request) { - CHECK_IS_USER(); - CREATE_OK_REQUEST_PROMISE(); - TRY_RESULT_PROMISE(promise, sender_dialog_id, get_message_sender_dialog_id(this, request.sender_id_, false, false)); - messages_manager_->delete_dialog_messages_by_sender(DialogId(request.chat_id_), sender_dialog_id, std::move(promise)); -} - -void Td::on_request(uint64 id, const td_api::deleteChatMessagesByDate &request) { - CHECK_IS_USER(); - CREATE_OK_REQUEST_PROMISE(); - messages_manager_->delete_dialog_messages_by_date(DialogId(request.chat_id_), request.min_date_, request.max_date_, - request.revoke_, std::move(promise)); -} - -void Td::on_request(uint64 id, const td_api::readAllChatMentions &request) { - CHECK_IS_USER(); - CREATE_OK_REQUEST_PROMISE(); - messages_manager_->read_all_dialog_mentions(DialogId(request.chat_id_), MessageId(), std::move(promise)); -} - -void Td::on_request(uint64 id, const td_api::readAllMessageThreadMentions &request) { - CHECK_IS_USER(); - if (request.message_thread_id_ == 0) { - return send_error_raw(id, 400, "Invalid message thread identifier specified"); - } - CREATE_OK_REQUEST_PROMISE(); - messages_manager_->read_all_dialog_mentions(DialogId(request.chat_id_), MessageId(request.message_thread_id_), - std::move(promise)); -} - -void Td::on_request(uint64 id, const td_api::readAllChatReactions &request) { - CHECK_IS_USER(); - CREATE_OK_REQUEST_PROMISE(); - messages_manager_->read_all_dialog_reactions(DialogId(request.chat_id_), MessageId(), std::move(promise)); -} - -void Td::on_request(uint64 id, const td_api::readAllMessageThreadReactions &request) { - CHECK_IS_USER(); - if (request.message_thread_id_ == 0) { - return send_error_raw(id, 400, "Invalid message thread identifier specified"); - } - CREATE_OK_REQUEST_PROMISE(); - messages_manager_->read_all_dialog_reactions(DialogId(request.chat_id_), MessageId(request.message_thread_id_), - std::move(promise)); -} - -void Td::on_request(uint64 id, const td_api::getChatAvailableMessageSenders &request) { - CHECK_IS_USER(); - CREATE_REQUEST_PROMISE(); - messages_manager_->get_dialog_send_message_as_dialog_ids(DialogId(request.chat_id_), std::move(promise)); -} - -void Td::on_request(uint64 id, const td_api::setChatMessageSender &request) { - CHECK_IS_USER(); - CREATE_OK_REQUEST_PROMISE(); - TRY_RESULT_PROMISE(promise, message_sender_dialog_id, - get_message_sender_dialog_id(this, request.message_sender_id_, true, false)); - messages_manager_->set_dialog_default_send_message_as_dialog_id(DialogId(request.chat_id_), message_sender_dialog_id, - std::move(promise)); -} - -void Td::on_request(uint64 id, td_api::sendMessage &request) { - auto r_sent_message = messages_manager_->send_message( - DialogId(request.chat_id_), MessageId(request.message_thread_id_), std::move(request.reply_to_), - std::move(request.options_), std::move(request.reply_markup_), std::move(request.input_message_content_)); - if (r_sent_message.is_error()) { - send_closure(actor_id(this), &Td::send_error, id, r_sent_message.move_as_error()); - } else { - send_closure(actor_id(this), &Td::send_result, id, r_sent_message.move_as_ok()); - } -} - -void Td::on_request(uint64 id, td_api::sendMessageAlbum &request) { - auto r_messages = messages_manager_->send_message_group( - DialogId(request.chat_id_), MessageId(request.message_thread_id_), std::move(request.reply_to_), - std::move(request.options_), std::move(request.input_message_contents_)); - if (r_messages.is_error()) { - send_closure(actor_id(this), &Td::send_error, id, r_messages.move_as_error()); - } else { - send_closure(actor_id(this), &Td::send_result, id, r_messages.move_as_ok()); - } -} - -void Td::on_request(uint64 id, td_api::sendBotStartMessage &request) { - CHECK_IS_USER(); - CLEAN_INPUT_STRING(request.parameter_); - - DialogId dialog_id(request.chat_id_); - auto r_new_message_id = - messages_manager_->send_bot_start_message(UserId(request.bot_user_id_), dialog_id, request.parameter_); - if (r_new_message_id.is_error()) { - return send_closure(actor_id(this), &Td::send_error, id, r_new_message_id.move_as_error()); - } - - CHECK(r_new_message_id.ok().is_valid() || r_new_message_id.ok().is_valid_scheduled()); - send_closure(actor_id(this), &Td::send_result, id, - messages_manager_->get_message_object({dialog_id, r_new_message_id.ok()}, "sendBotStartMessage")); -} - -void Td::on_request(uint64 id, td_api::sendInlineQueryResultMessage &request) { - CHECK_IS_USER(); - CLEAN_INPUT_STRING(request.result_id_); - - auto r_sent_message = messages_manager_->send_inline_query_result_message( - DialogId(request.chat_id_), MessageId(request.message_thread_id_), std::move(request.reply_to_), - std::move(request.options_), request.query_id_, request.result_id_, request.hide_via_bot_); - if (r_sent_message.is_error()) { - send_closure(actor_id(this), &Td::send_error, id, r_sent_message.move_as_error()); - } else { - send_closure(actor_id(this), &Td::send_result, id, r_sent_message.move_as_ok()); - } -} - -void Td::on_request(uint64 id, td_api::addLocalMessage &request) { - CHECK_IS_USER(); - - DialogId dialog_id(request.chat_id_); - auto r_new_message_id = - messages_manager_->add_local_message(dialog_id, std::move(request.sender_id_), std::move(request.reply_to_), - request.disable_notification_, std::move(request.input_message_content_)); - if (r_new_message_id.is_error()) { - return send_closure(actor_id(this), &Td::send_error, id, r_new_message_id.move_as_error()); - } - - CHECK(r_new_message_id.ok().is_valid()); - send_closure(actor_id(this), &Td::send_result, id, - messages_manager_->get_message_object({dialog_id, r_new_message_id.ok()}, "addLocalMessage")); -} - -void Td::on_request(uint64 id, td_api::editMessageText &request) { - CREATE_REQUEST(EditMessageTextRequest, request.chat_id_, request.message_id_, std::move(request.reply_markup_), - std::move(request.input_message_content_)); -} - -void Td::on_request(uint64 id, td_api::editMessageLiveLocation &request) { - CREATE_REQUEST(EditMessageLiveLocationRequest, request.chat_id_, request.message_id_, - std::move(request.reply_markup_), std::move(request.location_), request.live_period_, request.heading_, - request.proximity_alert_radius_); -} - -void Td::on_request(uint64 id, td_api::editMessageMedia &request) { - CREATE_REQUEST(EditMessageMediaRequest, request.chat_id_, request.message_id_, std::move(request.reply_markup_), - std::move(request.input_message_content_)); -} - -void Td::on_request(uint64 id, td_api::editMessageCaption &request) { - CREATE_REQUEST(EditMessageCaptionRequest, request.chat_id_, request.message_id_, std::move(request.reply_markup_), - std::move(request.caption_), request.show_caption_above_media_); -} - -void Td::on_request(uint64 id, td_api::editMessageReplyMarkup &request) { - CHECK_IS_BOT(); - CREATE_REQUEST(EditMessageReplyMarkupRequest, request.chat_id_, request.message_id_, - std::move(request.reply_markup_)); -} - -void Td::on_request(uint64 id, td_api::editInlineMessageText &request) { - CHECK_IS_BOT(); - CLEAN_INPUT_STRING(request.inline_message_id_); - CREATE_OK_REQUEST_PROMISE(); - inline_message_manager_->edit_inline_message_text(request.inline_message_id_, std::move(request.reply_markup_), - std::move(request.input_message_content_), std::move(promise)); -} - -void Td::on_request(uint64 id, td_api::editInlineMessageLiveLocation &request) { - CHECK_IS_BOT(); - CLEAN_INPUT_STRING(request.inline_message_id_); - CREATE_OK_REQUEST_PROMISE(); - inline_message_manager_->edit_inline_message_live_location( - request.inline_message_id_, std::move(request.reply_markup_), std::move(request.location_), request.live_period_, - request.heading_, request.proximity_alert_radius_, std::move(promise)); -} - -void Td::on_request(uint64 id, td_api::editInlineMessageMedia &request) { - CHECK_IS_BOT(); - CLEAN_INPUT_STRING(request.inline_message_id_); - CREATE_OK_REQUEST_PROMISE(); - inline_message_manager_->edit_inline_message_media(request.inline_message_id_, std::move(request.reply_markup_), - std::move(request.input_message_content_), std::move(promise)); -} - -void Td::on_request(uint64 id, td_api::editInlineMessageCaption &request) { - CHECK_IS_BOT(); - CLEAN_INPUT_STRING(request.inline_message_id_); - CREATE_OK_REQUEST_PROMISE(); - inline_message_manager_->edit_inline_message_caption(request.inline_message_id_, std::move(request.reply_markup_), - std::move(request.caption_), request.show_caption_above_media_, - std::move(promise)); -} - -void Td::on_request(uint64 id, td_api::editInlineMessageReplyMarkup &request) { - CHECK_IS_BOT(); - CLEAN_INPUT_STRING(request.inline_message_id_); - CREATE_OK_REQUEST_PROMISE(); - inline_message_manager_->edit_inline_message_reply_markup(request.inline_message_id_, - std::move(request.reply_markup_), std::move(promise)); -} - -void Td::on_request(uint64 id, td_api::editMessageSchedulingState &request) { - CHECK_IS_USER(); - CREATE_OK_REQUEST_PROMISE(); - messages_manager_->edit_message_scheduling_state({DialogId(request.chat_id_), MessageId(request.message_id_)}, - std::move(request.scheduling_state_), std::move(promise)); -} - -void Td::on_request(uint64 id, td_api::setMessageFactCheck &request) { - CHECK_IS_USER(); - CREATE_OK_REQUEST_PROMISE(); - messages_manager_->set_message_fact_check({DialogId(request.chat_id_), MessageId(request.message_id_)}, - std::move(request.text_), std::move(promise)); -} - -void Td::on_request(uint64 id, td_api::sendBusinessMessage &request) { - CHECK_IS_BOT(); - CREATE_REQUEST_PROMISE(); - business_connection_manager_->send_message(BusinessConnectionId(std::move(request.business_connection_id_)), - DialogId(request.chat_id_), std::move(request.reply_to_), - request.disable_notification_, request.protect_content_, - MessageEffectId(request.effect_id_), std::move(request.reply_markup_), - std::move(request.input_message_content_), std::move(promise)); -} - -void Td::on_request(uint64 id, td_api::sendBusinessMessageAlbum &request) { - CHECK_IS_BOT(); - CREATE_REQUEST_PROMISE(); - business_connection_manager_->send_message_album( - BusinessConnectionId(std::move(request.business_connection_id_)), DialogId(request.chat_id_), - std::move(request.reply_to_), request.disable_notification_, request.protect_content_, - MessageEffectId(request.effect_id_), std::move(request.input_message_contents_), std::move(promise)); -} - -void Td::on_request(uint64 id, td_api::editBusinessMessageText &request) { - CHECK_IS_BOT(); - CREATE_REQUEST_PROMISE(); - business_connection_manager_->edit_business_message_text( - BusinessConnectionId(std::move(request.business_connection_id_)), DialogId(request.chat_id_), - MessageId(request.message_id_), std::move(request.reply_markup_), std::move(request.input_message_content_), - std::move(promise)); -} - -void Td::on_request(uint64 id, td_api::editBusinessMessageLiveLocation &request) { - CHECK_IS_BOT(); - CREATE_REQUEST_PROMISE(); - business_connection_manager_->edit_business_message_live_location( - BusinessConnectionId(std::move(request.business_connection_id_)), DialogId(request.chat_id_), - MessageId(request.message_id_), std::move(request.reply_markup_), std::move(request.location_), - request.live_period_, request.heading_, request.proximity_alert_radius_, std::move(promise)); -} - -void Td::on_request(uint64 id, td_api::editBusinessMessageMedia &request) { - CHECK_IS_BOT(); - CREATE_REQUEST_PROMISE(); - business_connection_manager_->edit_business_message_media( - BusinessConnectionId(std::move(request.business_connection_id_)), DialogId(request.chat_id_), - MessageId(request.message_id_), std::move(request.reply_markup_), std::move(request.input_message_content_), - std::move(promise)); -} - -void Td::on_request(uint64 id, td_api::editBusinessMessageCaption &request) { - CHECK_IS_BOT(); - CREATE_REQUEST_PROMISE(); - business_connection_manager_->edit_business_message_caption( - BusinessConnectionId(std::move(request.business_connection_id_)), DialogId(request.chat_id_), - MessageId(request.message_id_), std::move(request.reply_markup_), std::move(request.caption_), - request.show_caption_above_media_, std::move(promise)); -} - -void Td::on_request(uint64 id, td_api::editBusinessMessageReplyMarkup &request) { - CHECK_IS_BOT(); - CREATE_REQUEST_PROMISE(); - business_connection_manager_->edit_business_message_reply_markup( - BusinessConnectionId(std::move(request.business_connection_id_)), DialogId(request.chat_id_), - MessageId(request.message_id_), std::move(request.reply_markup_), std::move(promise)); -} - -void Td::on_request(uint64 id, td_api::stopBusinessPoll &request) { - CHECK_IS_BOT(); - CREATE_REQUEST_PROMISE(); - business_connection_manager_->stop_poll(BusinessConnectionId(std::move(request.business_connection_id_)), - DialogId(request.chat_id_), MessageId(request.message_id_), - std::move(request.reply_markup_), std::move(promise)); -} - -void Td::on_request(uint64 id, td_api::setBusinessMessageIsPinned &request) { - CHECK_IS_BOT(); - CREATE_OK_REQUEST_PROMISE(); - messages_manager_->pin_dialog_message(BusinessConnectionId(std::move(request.business_connection_id_)), - DialogId(request.chat_id_), MessageId(request.message_id_), true, false, - !request.is_pinned_, std::move(promise)); -} - -void Td::on_request(uint64 id, const td_api::loadQuickReplyShortcuts &request) { - CHECK_IS_USER(); - CREATE_OK_REQUEST_PROMISE(); - quick_reply_manager_->get_quick_reply_shortcuts(std::move(promise)); -} - -void Td::on_request(uint64 id, const td_api::setQuickReplyShortcutName &request) { - CHECK_IS_USER(); - CREATE_OK_REQUEST_PROMISE(); - quick_reply_manager_->set_quick_reply_shortcut_name(QuickReplyShortcutId(request.shortcut_id_), request.name_, - std::move(promise)); -} - -void Td::on_request(uint64 id, const td_api::deleteQuickReplyShortcut &request) { - CHECK_IS_USER(); - CREATE_OK_REQUEST_PROMISE(); - quick_reply_manager_->delete_quick_reply_shortcut(QuickReplyShortcutId(request.shortcut_id_), std::move(promise)); -} - -void Td::on_request(uint64 id, const td_api::reorderQuickReplyShortcuts &request) { - CHECK_IS_USER(); - CREATE_OK_REQUEST_PROMISE(); - quick_reply_manager_->reorder_quick_reply_shortcuts( - QuickReplyShortcutId::get_quick_reply_shortcut_ids(request.shortcut_ids_), std::move(promise)); -} - -void Td::on_request(uint64 id, const td_api::loadQuickReplyShortcutMessages &request) { - CHECK_IS_USER(); - CREATE_OK_REQUEST_PROMISE(); - quick_reply_manager_->get_quick_reply_shortcut_messages(QuickReplyShortcutId(request.shortcut_id_), - std::move(promise)); -} - -void Td::on_request(uint64 id, const td_api::deleteQuickReplyShortcutMessages &request) { - CHECK_IS_USER(); - CREATE_OK_REQUEST_PROMISE(); - quick_reply_manager_->delete_quick_reply_shortcut_messages( - QuickReplyShortcutId(request.shortcut_id_), MessageId::get_message_ids(request.message_ids_), std::move(promise)); -} - -void Td::on_request(uint64 id, td_api::addQuickReplyShortcutMessage &request) { - CHECK_IS_USER(); - CLEAN_INPUT_STRING(request.shortcut_name_); - auto r_sent_message = quick_reply_manager_->send_message( - request.shortcut_name_, MessageId(request.reply_to_message_id_), std::move(request.input_message_content_)); - if (r_sent_message.is_error()) { - send_closure(actor_id(this), &Td::send_error, id, r_sent_message.move_as_error()); - } else { - send_closure(actor_id(this), &Td::send_result, id, r_sent_message.move_as_ok()); - } -} - -void Td::on_request(uint64 id, td_api::addQuickReplyShortcutInlineQueryResultMessage &request) { - CHECK_IS_USER(); - CLEAN_INPUT_STRING(request.shortcut_name_); - CLEAN_INPUT_STRING(request.result_id_); - auto r_sent_message = quick_reply_manager_->send_inline_query_result_message( - request.shortcut_name_, MessageId(request.reply_to_message_id_), request.query_id_, request.result_id_, - request.hide_via_bot_); - if (r_sent_message.is_error()) { - send_closure(actor_id(this), &Td::send_error, id, r_sent_message.move_as_error()); - } else { - send_closure(actor_id(this), &Td::send_result, id, r_sent_message.move_as_ok()); - } -} - -void Td::on_request(uint64 id, td_api::addQuickReplyShortcutMessageAlbum &request) { - CHECK_IS_USER(); - CLEAN_INPUT_STRING(request.shortcut_name_); - auto r_messages = quick_reply_manager_->send_message_group( - request.shortcut_name_, MessageId(request.reply_to_message_id_), std::move(request.input_message_contents_)); - if (r_messages.is_error()) { - send_closure(actor_id(this), &Td::send_error, id, r_messages.move_as_error()); - } else { - send_closure(actor_id(this), &Td::send_result, id, r_messages.move_as_ok()); - } -} - -void Td::on_request(uint64 id, td_api::readdQuickReplyShortcutMessages &request) { - CHECK_IS_USER(); - CLEAN_INPUT_STRING(request.shortcut_name_); - auto r_messages = - quick_reply_manager_->resend_messages(request.shortcut_name_, MessageId::get_message_ids(request.message_ids_)); - if (r_messages.is_error()) { - return send_closure(actor_id(this), &Td::send_error, id, r_messages.move_as_error()); - } - send_closure(actor_id(this), &Td::send_result, id, r_messages.move_as_ok()); -} - -void Td::on_request(uint64 id, td_api::editQuickReplyMessage &request) { - CHECK_IS_USER(); - CREATE_OK_REQUEST_PROMISE(); - quick_reply_manager_->edit_quick_reply_message(QuickReplyShortcutId(request.shortcut_id_), - MessageId(request.message_id_), - std::move(request.input_message_content_), std::move(promise)); -} - -void Td::on_request(uint64 id, const td_api::getCurrentWeather &request) { - CHECK_IS_USER(); - CREATE_REQUEST_PROMISE(); - inline_queries_manager_->get_weather(Location(request.location_), std::move(promise)); -} - -void Td::on_request(uint64 id, const td_api::getStory &request) { - CHECK_IS_USER(); - CREATE_REQUEST_PROMISE(); - story_manager_->get_story(DialogId(request.story_sender_chat_id_), StoryId(request.story_id_), request.only_local_, - std::move(promise)); -} - -void Td::on_request(uint64 id, const td_api::getChatsToSendStories &request) { - CHECK_IS_USER(); - CREATE_REQUEST_PROMISE(); - story_manager_->get_dialogs_to_send_stories(std::move(promise)); -} - -void Td::on_request(uint64 id, const td_api::canSendStory &request) { - CHECK_IS_USER(); - CREATE_REQUEST_PROMISE(); - story_manager_->can_send_story(DialogId(request.chat_id_), std::move(promise)); -} - -void Td::on_request(uint64 id, td_api::sendStory &request) { - CHECK_IS_USER(); - CREATE_REQUEST_PROMISE(); - story_manager_->send_story(DialogId(request.chat_id_), std::move(request.content_), std::move(request.areas_), - std::move(request.caption_), std::move(request.privacy_settings_), request.active_period_, - std::move(request.from_story_full_id_), request.is_posted_to_chat_page_, - request.protect_content_, std::move(promise)); -} - -void Td::on_request(uint64 id, td_api::editStory &request) { - CHECK_IS_USER(); - CREATE_OK_REQUEST_PROMISE(); - story_manager_->edit_story(DialogId(request.story_sender_chat_id_), StoryId(request.story_id_), - std::move(request.content_), std::move(request.areas_), std::move(request.caption_), - std::move(promise)); -} - -void Td::on_request(uint64 id, const td_api::editStoryCover &request) { - CHECK_IS_USER(); - CREATE_OK_REQUEST_PROMISE(); - story_manager_->edit_story_cover(DialogId(request.story_sender_chat_id_), StoryId(request.story_id_), - request.cover_frame_timestamp_, std::move(promise)); -} - -void Td::on_request(uint64 id, td_api::setStoryPrivacySettings &request) { - CHECK_IS_USER(); - CREATE_OK_REQUEST_PROMISE(); - story_manager_->set_story_privacy_settings(StoryId(request.story_id_), std::move(request.privacy_settings_), - std::move(promise)); -} - -void Td::on_request(uint64 id, const td_api::toggleStoryIsPostedToChatPage &request) { - CHECK_IS_USER(); - CREATE_OK_REQUEST_PROMISE(); - story_manager_->toggle_story_is_pinned(DialogId(request.story_sender_chat_id_), StoryId(request.story_id_), - request.is_posted_to_chat_page_, std::move(promise)); -} - -void Td::on_request(uint64 id, const td_api::deleteStory &request) { - CHECK_IS_USER(); - CREATE_OK_REQUEST_PROMISE(); - story_manager_->delete_story(DialogId(request.story_sender_chat_id_), StoryId(request.story_id_), std::move(promise)); -} - -void Td::on_request(uint64 id, const td_api::loadActiveStories &request) { - CHECK_IS_USER(); - CREATE_OK_REQUEST_PROMISE(); - story_manager_->load_active_stories(StoryListId(request.story_list_), std::move(promise)); -} - -void Td::on_request(uint64 id, const td_api::setChatActiveStoriesList &request) { - CHECK_IS_USER(); - CREATE_OK_REQUEST_PROMISE(); - story_manager_->toggle_dialog_stories_hidden(DialogId(request.chat_id_), StoryListId(request.story_list_), - std::move(promise)); -} - -void Td::on_request(uint64 id, const td_api::getForumTopicDefaultIcons &request) { - CREATE_REQUEST_PROMISE(); - stickers_manager_->get_default_topic_icons(false, std::move(promise)); -} - -void Td::on_request(uint64 id, td_api::createForumTopic &request) { - CLEAN_INPUT_STRING(request.name_); - CREATE_REQUEST_PROMISE(); - forum_topic_manager_->create_forum_topic(DialogId(request.chat_id_), std::move(request.name_), - std::move(request.icon_), std::move(promise)); -} - -void Td::on_request(uint64 id, td_api::editForumTopic &request) { - CLEAN_INPUT_STRING(request.name_); - CREATE_OK_REQUEST_PROMISE(); - forum_topic_manager_->edit_forum_topic(DialogId(request.chat_id_), MessageId(request.message_thread_id_), - std::move(request.name_), request.edit_icon_custom_emoji_, - CustomEmojiId(request.icon_custom_emoji_id_), std::move(promise)); -} - -void Td::on_request(uint64 id, const td_api::getForumTopic &request) { - CREATE_REQUEST_PROMISE(); - forum_topic_manager_->get_forum_topic(DialogId(request.chat_id_), MessageId(request.message_thread_id_), - std::move(promise)); -} - -void Td::on_request(uint64 id, const td_api::getForumTopicLink &request) { - CREATE_REQUEST_PROMISE(); - forum_topic_manager_->get_forum_topic_link(DialogId(request.chat_id_), MessageId(request.message_thread_id_), - std::move(promise)); -} - -void Td::on_request(uint64 id, td_api::getForumTopics &request) { - CHECK_IS_USER(); - CLEAN_INPUT_STRING(request.query_); - CREATE_REQUEST_PROMISE(); - forum_topic_manager_->get_forum_topics(DialogId(request.chat_id_), std::move(request.query_), request.offset_date_, - MessageId(request.offset_message_id_), - MessageId(request.offset_message_thread_id_), request.limit_, - std::move(promise)); -} - -void Td::on_request(uint64 id, const td_api::toggleForumTopicIsClosed &request) { - CREATE_OK_REQUEST_PROMISE(); - forum_topic_manager_->toggle_forum_topic_is_closed(DialogId(request.chat_id_), MessageId(request.message_thread_id_), - request.is_closed_, std::move(promise)); -} - -void Td::on_request(uint64 id, const td_api::toggleGeneralForumTopicIsHidden &request) { - CREATE_OK_REQUEST_PROMISE(); - forum_topic_manager_->toggle_forum_topic_is_hidden(DialogId(request.chat_id_), request.is_hidden_, - std::move(promise)); -} - -void Td::on_request(uint64 id, const td_api::toggleForumTopicIsPinned &request) { - CHECK_IS_USER(); - CREATE_OK_REQUEST_PROMISE(); - forum_topic_manager_->toggle_forum_topic_is_pinned(DialogId(request.chat_id_), MessageId(request.message_thread_id_), - request.is_pinned_, std::move(promise)); -} - -void Td::on_request(uint64 id, const td_api::setPinnedForumTopics &request) { - CHECK_IS_USER(); - CREATE_OK_REQUEST_PROMISE(); - forum_topic_manager_->set_pinned_forum_topics( - DialogId(request.chat_id_), MessageId::get_message_ids(request.message_thread_ids_), std::move(promise)); -} - -void Td::on_request(uint64 id, const td_api::deleteForumTopic &request) { - CREATE_OK_REQUEST_PROMISE(); - forum_topic_manager_->delete_forum_topic(DialogId(request.chat_id_), MessageId(request.message_thread_id_), - std::move(promise)); -} - -void Td::on_request(uint64 id, td_api::setGameScore &request) { - CHECK_IS_BOT(); - CREATE_REQUEST_PROMISE(); - game_manager_->set_game_score({DialogId(request.chat_id_), MessageId(request.message_id_)}, request.edit_message_, - UserId(request.user_id_), request.score_, request.force_, std::move(promise)); -} - -void Td::on_request(uint64 id, td_api::setInlineGameScore &request) { - CHECK_IS_BOT(); - CLEAN_INPUT_STRING(request.inline_message_id_); - CREATE_OK_REQUEST_PROMISE(); - inline_message_manager_->set_inline_game_score(request.inline_message_id_, request.edit_message_, - UserId(request.user_id_), request.score_, request.force_, - std::move(promise)); -} - -void Td::on_request(uint64 id, td_api::getGameHighScores &request) { - CHECK_IS_BOT(); - CREATE_REQUEST_PROMISE(); - game_manager_->get_game_high_scores({DialogId(request.chat_id_), MessageId(request.message_id_)}, - UserId(request.user_id_), std::move(promise)); -} - -void Td::on_request(uint64 id, td_api::getInlineGameHighScores &request) { - CHECK_IS_BOT(); - CLEAN_INPUT_STRING(request.inline_message_id_); - CREATE_REQUEST_PROMISE(); - inline_message_manager_->get_inline_game_high_scores(request.inline_message_id_, UserId(request.user_id_), - std::move(promise)); -} - -void Td::on_request(uint64 id, const td_api::deleteChatReplyMarkup &request) { - CHECK_IS_USER(); - answer_ok_query( - id, messages_manager_->delete_dialog_reply_markup(DialogId(request.chat_id_), MessageId(request.message_id_))); -} - -void Td::on_request(uint64 id, td_api::sendChatAction &request) { - CLEAN_INPUT_STRING(request.business_connection_id_); - CREATE_OK_REQUEST_PROMISE(); - dialog_action_manager_->send_dialog_action(DialogId(request.chat_id_), MessageId(request.message_thread_id_), - BusinessConnectionId(std::move(request.business_connection_id_)), - DialogAction(std::move(request.action_)), std::move(promise)); -} - -void Td::on_request(uint64 id, td_api::forwardMessages &request) { - auto input_message_ids = MessageId::get_message_ids(request.message_ids_); - auto message_copy_options = - transform(input_message_ids, [send_copy = request.send_copy_, remove_caption = request.remove_caption_]( - MessageId) { return MessageCopyOptions(send_copy, remove_caption); }); - auto r_messages = messages_manager_->forward_messages( - DialogId(request.chat_id_), MessageId(request.message_thread_id_), DialogId(request.from_chat_id_), - std::move(input_message_ids), std::move(request.options_), false, std::move(message_copy_options)); - if (r_messages.is_error()) { - send_closure(actor_id(this), &Td::send_error, id, r_messages.move_as_error()); - } else { - send_closure(actor_id(this), &Td::send_result, id, r_messages.move_as_ok()); - } -} - -void Td::on_request(uint64 id, const td_api::sendQuickReplyShortcutMessages &request) { - auto r_messages = messages_manager_->send_quick_reply_shortcut_messages( - DialogId(request.chat_id_), QuickReplyShortcutId(request.shortcut_id_), request.sending_id_); - if (r_messages.is_error()) { - send_closure(actor_id(this), &Td::send_error, id, r_messages.move_as_error()); - } else { - send_closure(actor_id(this), &Td::send_result, id, r_messages.move_as_ok()); - } -} - -void Td::on_request(uint64 id, td_api::resendMessages &request) { - DialogId dialog_id(request.chat_id_); - auto r_message_ids = messages_manager_->resend_messages(dialog_id, MessageId::get_message_ids(request.message_ids_), - std::move(request.quote_)); - if (r_message_ids.is_error()) { - return send_closure(actor_id(this), &Td::send_error, id, r_message_ids.move_as_error()); - } - - send_closure(actor_id(this), &Td::send_result, id, - messages_manager_->get_messages_object(-1, dialog_id, r_message_ids.ok(), false, "resendMessages")); -} - -void Td::on_request(uint64 id, td_api::getLinkPreview &request) { - CHECK_IS_USER(); - CREATE_REQUEST_PROMISE(); - web_pages_manager_->get_web_page_preview(std::move(request.text_), std::move(request.link_preview_options_), - std::move(promise)); -} - -void Td::on_request(uint64 id, td_api::getWebPageInstantView &request) { - CHECK_IS_USER(); - CLEAN_INPUT_STRING(request.url_); - CREATE_REQUEST(GetWebPageInstantViewRequest, std::move(request.url_), request.force_full_); -} - -void Td::on_request(uint64 id, const td_api::createPrivateChat &request) { - CREATE_REQUEST(CreateChatRequest, DialogId(UserId(request.user_id_)), request.force_); -} - -void Td::on_request(uint64 id, const td_api::createBasicGroupChat &request) { - CREATE_REQUEST(CreateChatRequest, DialogId(ChatId(request.basic_group_id_)), request.force_); -} - -void Td::on_request(uint64 id, const td_api::createSupergroupChat &request) { - CREATE_REQUEST(CreateChatRequest, DialogId(ChannelId(request.supergroup_id_)), request.force_); -} - -void Td::on_request(uint64 id, const td_api::createSecretChat &request) { - CREATE_REQUEST(CreateChatRequest, DialogId(SecretChatId(request.secret_chat_id_)), true); -} - -void Td::on_request(uint64 id, td_api::createNewBasicGroupChat &request) { - CHECK_IS_USER(); - CLEAN_INPUT_STRING(request.title_); - CREATE_REQUEST_PROMISE(); - chat_manager_->create_new_chat(UserId::get_user_ids(request.user_ids_), std::move(request.title_), - MessageTtl(request.message_auto_delete_time_), std::move(promise)); -} - -void Td::on_request(uint64 id, td_api::createNewSupergroupChat &request) { - CHECK_IS_USER(); - CLEAN_INPUT_STRING(request.title_); - CLEAN_INPUT_STRING(request.description_); - CREATE_REQUEST_PROMISE(); - chat_manager_->create_new_channel(std::move(request.title_), request.is_forum_, !request.is_channel_, - std::move(request.description_), DialogLocation(std::move(request.location_)), - request.for_import_, MessageTtl(request.message_auto_delete_time_), - std::move(promise)); -} - -void Td::on_request(uint64 id, const td_api::createNewSecretChat &request) { - CHECK_IS_USER(); - CREATE_REQUEST_PROMISE(); - user_manager_->create_new_secret_chat(UserId(request.user_id_), std::move(promise)); -} - -void Td::on_request(uint64 id, const td_api::createCall &request) { - CHECK_IS_USER(); - - if (request.protocol_ == nullptr) { - return send_error_raw(id, 400, "Call protocol must be non-empty"); - } - - UserId user_id(request.user_id_); - auto r_input_user = user_manager_->get_input_user(user_id); - if (r_input_user.is_error()) { - return send_error_raw(id, r_input_user.error().code(), r_input_user.error().message()); - } - - CREATE_REQUEST_PROMISE(); - auto query_promise = PromiseCreator::lambda([promise = std::move(promise)](Result result) mutable { - if (result.is_error()) { - promise.set_error(result.move_as_error()); - } else { - promise.set_value(result.ok().get_call_id_object()); - } - }); - send_closure(G()->call_manager(), &CallManager::create_call, user_id, r_input_user.move_as_ok(), - CallProtocol(*request.protocol_), request.is_video_, std::move(query_promise)); -} - -void Td::on_request(uint64 id, const td_api::acceptCall &request) { - CHECK_IS_USER(); - if (request.protocol_ == nullptr) { - return send_error_raw(id, 400, "Call protocol must be non-empty"); - } - CREATE_OK_REQUEST_PROMISE(); - send_closure(G()->call_manager(), &CallManager::accept_call, CallId(request.call_id_), - CallProtocol(*request.protocol_), std::move(promise)); -} - -void Td::on_request(uint64 id, td_api::sendCallSignalingData &request) { - CHECK_IS_USER(); - CREATE_OK_REQUEST_PROMISE(); - send_closure(G()->call_manager(), &CallManager::send_call_signaling_data, CallId(request.call_id_), - std::move(request.data_), std::move(promise)); -} - -void Td::on_request(uint64 id, const td_api::discardCall &request) { - CHECK_IS_USER(); - CREATE_OK_REQUEST_PROMISE(); - send_closure(G()->call_manager(), &CallManager::discard_call, CallId(request.call_id_), request.is_disconnected_, - request.duration_, request.is_video_, request.connection_id_, std::move(promise)); -} - -void Td::on_request(uint64 id, td_api::sendCallRating &request) { - CHECK_IS_USER(); - CLEAN_INPUT_STRING(request.comment_); - CREATE_OK_REQUEST_PROMISE(); - send_closure(G()->call_manager(), &CallManager::rate_call, CallId(request.call_id_), request.rating_, - std::move(request.comment_), std::move(request.problems_), std::move(promise)); -} - -void Td::on_request(uint64 id, td_api::sendCallDebugInformation &request) { - CHECK_IS_USER(); - CLEAN_INPUT_STRING(request.debug_information_); - CREATE_OK_REQUEST_PROMISE(); - send_closure(G()->call_manager(), &CallManager::send_call_debug_information, CallId(request.call_id_), - std::move(request.debug_information_), std::move(promise)); -} - -void Td::on_request(uint64 id, td_api::sendCallLog &request) { - CHECK_IS_USER(); - CREATE_OK_REQUEST_PROMISE(); - send_closure(G()->call_manager(), &CallManager::send_call_log, CallId(request.call_id_), std::move(request.log_file_), - std::move(promise)); -} - -void Td::on_request(uint64 id, const td_api::getVideoChatAvailableParticipants &request) { - CHECK_IS_USER(); - CREATE_REQUEST_PROMISE(); - group_call_manager_->get_group_call_join_as(DialogId(request.chat_id_), std::move(promise)); -} - -void Td::on_request(uint64 id, const td_api::setVideoChatDefaultParticipant &request) { - CHECK_IS_USER(); - CREATE_OK_REQUEST_PROMISE(); - TRY_RESULT_PROMISE(promise, default_join_as_dialog_id, - get_message_sender_dialog_id(this, request.default_participant_id_, true, false)); - group_call_manager_->set_group_call_default_join_as(DialogId(request.chat_id_), default_join_as_dialog_id, - std::move(promise)); -} - -void Td::on_request(uint64 id, td_api::createVideoChat &request) { - CHECK_IS_USER(); - CLEAN_INPUT_STRING(request.title_); - CREATE_REQUEST_PROMISE(); - auto query_promise = PromiseCreator::lambda([promise = std::move(promise)](Result result) mutable { - if (result.is_error()) { - promise.set_error(result.move_as_error()); - } else { - promise.set_value(td_api::make_object(result.ok().get())); - } - }); - group_call_manager_->create_voice_chat(DialogId(request.chat_id_), std::move(request.title_), request.start_date_, - request.is_rtmp_stream_, std::move(query_promise)); -} - -void Td::on_request(uint64 id, const td_api::getVideoChatRtmpUrl &request) { - CHECK_IS_USER(); - CREATE_REQUEST_PROMISE(); - group_call_manager_->get_voice_chat_rtmp_stream_url(DialogId(request.chat_id_), false, std::move(promise)); -} - -void Td::on_request(uint64 id, const td_api::replaceVideoChatRtmpUrl &request) { - CHECK_IS_USER(); - CREATE_REQUEST_PROMISE(); - group_call_manager_->get_voice_chat_rtmp_stream_url(DialogId(request.chat_id_), true, std::move(promise)); -} - -void Td::on_request(uint64 id, const td_api::getGroupCall &request) { - CHECK_IS_USER(); - CREATE_REQUEST_PROMISE(); - group_call_manager_->get_group_call(GroupCallId(request.group_call_id_), std::move(promise)); -} - -void Td::on_request(uint64 id, const td_api::startScheduledGroupCall &request) { - CHECK_IS_USER(); - CREATE_OK_REQUEST_PROMISE(); - group_call_manager_->start_scheduled_group_call(GroupCallId(request.group_call_id_), std::move(promise)); -} - -void Td::on_request(uint64 id, const td_api::toggleGroupCallEnabledStartNotification &request) { - CHECK_IS_USER(); - CREATE_OK_REQUEST_PROMISE(); - group_call_manager_->toggle_group_call_start_subscribed(GroupCallId(request.group_call_id_), - request.enabled_start_notification_, std::move(promise)); -} - -void Td::on_request(uint64 id, td_api::joinGroupCall &request) { - CHECK_IS_USER(); - CLEAN_INPUT_STRING(request.invite_hash_); - CLEAN_INPUT_STRING(request.payload_); - CREATE_REQUEST_PROMISE(); - TRY_RESULT_PROMISE(promise, join_as_dialog_id, - get_message_sender_dialog_id(this, request.participant_id_, true, true)); - auto query_promise = PromiseCreator::lambda([promise = std::move(promise)](Result result) mutable { - if (result.is_error()) { - promise.set_error(result.move_as_error()); - } else { - promise.set_value(make_tl_object(result.move_as_ok())); - } - }); - group_call_manager_->join_group_call(GroupCallId(request.group_call_id_), join_as_dialog_id, request.audio_source_id_, - std::move(request.payload_), request.is_muted_, request.is_my_video_enabled_, - request.invite_hash_, std::move(query_promise)); -} - -void Td::on_request(uint64 id, td_api::startGroupCallScreenSharing &request) { - CHECK_IS_USER(); - CLEAN_INPUT_STRING(request.payload_); - CREATE_REQUEST_PROMISE(); - auto query_promise = PromiseCreator::lambda([promise = std::move(promise)](Result result) mutable { - if (result.is_error()) { - promise.set_error(result.move_as_error()); - } else { - promise.set_value(make_tl_object(result.move_as_ok())); - } - }); - group_call_manager_->start_group_call_screen_sharing(GroupCallId(request.group_call_id_), request.audio_source_id_, - std::move(request.payload_), std::move(query_promise)); -} - -void Td::on_request(uint64 id, const td_api::toggleGroupCallScreenSharingIsPaused &request) { - CHECK_IS_USER(); - CREATE_OK_REQUEST_PROMISE(); - group_call_manager_->toggle_group_call_is_my_presentation_paused(GroupCallId(request.group_call_id_), - request.is_paused_, std::move(promise)); -} - -void Td::on_request(uint64 id, const td_api::endGroupCallScreenSharing &request) { - CHECK_IS_USER(); - CREATE_OK_REQUEST_PROMISE(); - group_call_manager_->end_group_call_screen_sharing(GroupCallId(request.group_call_id_), std::move(promise)); -} - -void Td::on_request(uint64 id, td_api::setGroupCallTitle &request) { - CHECK_IS_USER(); - CLEAN_INPUT_STRING(request.title_); - CREATE_OK_REQUEST_PROMISE(); - group_call_manager_->set_group_call_title(GroupCallId(request.group_call_id_), std::move(request.title_), - std::move(promise)); -} - -void Td::on_request(uint64 id, const td_api::toggleGroupCallMuteNewParticipants &request) { - CHECK_IS_USER(); - CREATE_OK_REQUEST_PROMISE(); - group_call_manager_->toggle_group_call_mute_new_participants(GroupCallId(request.group_call_id_), - request.mute_new_participants_, std::move(promise)); -} - -void Td::on_request(uint64 id, const td_api::revokeGroupCallInviteLink &request) { - CHECK_IS_USER(); - CREATE_OK_REQUEST_PROMISE(); - group_call_manager_->revoke_group_call_invite_link(GroupCallId(request.group_call_id_), std::move(promise)); -} - -void Td::on_request(uint64 id, const td_api::inviteGroupCallParticipants &request) { - CHECK_IS_USER(); - CREATE_OK_REQUEST_PROMISE(); - group_call_manager_->invite_group_call_participants(GroupCallId(request.group_call_id_), - UserId::get_user_ids(request.user_ids_), std::move(promise)); -} - -void Td::on_request(uint64 id, const td_api::getGroupCallInviteLink &request) { - CHECK_IS_USER(); - CREATE_REQUEST_PROMISE(); - auto query_promise = PromiseCreator::lambda([promise = std::move(promise)](Result result) mutable { - if (result.is_error()) { - promise.set_error(result.move_as_error()); - } else { - promise.set_value(td_api::make_object(result.move_as_ok())); - } - }); - group_call_manager_->get_group_call_invite_link(GroupCallId(request.group_call_id_), request.can_self_unmute_, - std::move(query_promise)); -} - -void Td::on_request(uint64 id, td_api::startGroupCallRecording &request) { - CHECK_IS_USER(); - CLEAN_INPUT_STRING(request.title_); - CREATE_OK_REQUEST_PROMISE(); - group_call_manager_->toggle_group_call_recording(GroupCallId(request.group_call_id_), true, std::move(request.title_), - request.record_video_, request.use_portrait_orientation_, - std::move(promise)); -} - -void Td::on_request(uint64 id, const td_api::endGroupCallRecording &request) { - CHECK_IS_USER(); - CREATE_OK_REQUEST_PROMISE(); - group_call_manager_->toggle_group_call_recording(GroupCallId(request.group_call_id_), false, string(), false, false, - std::move(promise)); -} - -void Td::on_request(uint64 id, const td_api::toggleGroupCallIsMyVideoPaused &request) { - CHECK_IS_USER(); - CREATE_OK_REQUEST_PROMISE(); - group_call_manager_->toggle_group_call_is_my_video_paused(GroupCallId(request.group_call_id_), - request.is_my_video_paused_, std::move(promise)); -} - -void Td::on_request(uint64 id, const td_api::toggleGroupCallIsMyVideoEnabled &request) { - CHECK_IS_USER(); - CREATE_OK_REQUEST_PROMISE(); - group_call_manager_->toggle_group_call_is_my_video_enabled(GroupCallId(request.group_call_id_), - request.is_my_video_enabled_, std::move(promise)); -} - -void Td::on_request(uint64 id, const td_api::setGroupCallParticipantIsSpeaking &request) { - CHECK_IS_USER(); - CREATE_OK_REQUEST_PROMISE(); - group_call_manager_->set_group_call_participant_is_speaking( - GroupCallId(request.group_call_id_), request.audio_source_, request.is_speaking_, std::move(promise)); -} - -void Td::on_request(uint64 id, const td_api::toggleGroupCallParticipantIsMuted &request) { - CHECK_IS_USER(); - CREATE_OK_REQUEST_PROMISE(); - TRY_RESULT_PROMISE(promise, participant_dialog_id, - get_message_sender_dialog_id(this, request.participant_id_, true, false)); - group_call_manager_->toggle_group_call_participant_is_muted( - GroupCallId(request.group_call_id_), participant_dialog_id, request.is_muted_, std::move(promise)); -} - -void Td::on_request(uint64 id, const td_api::setGroupCallParticipantVolumeLevel &request) { - CHECK_IS_USER(); - CREATE_OK_REQUEST_PROMISE(); - TRY_RESULT_PROMISE(promise, participant_dialog_id, - get_message_sender_dialog_id(this, request.participant_id_, true, false)); - group_call_manager_->set_group_call_participant_volume_level( - GroupCallId(request.group_call_id_), participant_dialog_id, request.volume_level_, std::move(promise)); -} - -void Td::on_request(uint64 id, const td_api::toggleGroupCallParticipantIsHandRaised &request) { - CHECK_IS_USER(); - CREATE_OK_REQUEST_PROMISE(); - TRY_RESULT_PROMISE(promise, participant_dialog_id, - get_message_sender_dialog_id(this, request.participant_id_, true, false)); - group_call_manager_->toggle_group_call_participant_is_hand_raised( - GroupCallId(request.group_call_id_), participant_dialog_id, request.is_hand_raised_, std::move(promise)); -} - -void Td::on_request(uint64 id, const td_api::loadGroupCallParticipants &request) { - CHECK_IS_USER(); - CREATE_OK_REQUEST_PROMISE(); - group_call_manager_->load_group_call_participants(GroupCallId(request.group_call_id_), request.limit_, - std::move(promise)); -} - -void Td::on_request(uint64 id, const td_api::leaveGroupCall &request) { - CHECK_IS_USER(); - CREATE_OK_REQUEST_PROMISE(); - group_call_manager_->leave_group_call(GroupCallId(request.group_call_id_), std::move(promise)); -} - -void Td::on_request(uint64 id, const td_api::endGroupCall &request) { - CHECK_IS_USER(); - CREATE_OK_REQUEST_PROMISE(); - group_call_manager_->discard_group_call(GroupCallId(request.group_call_id_), std::move(promise)); -} - -void Td::on_request(uint64 id, const td_api::getGroupCallStreams &request) { - CHECK_IS_USER(); - CREATE_REQUEST_PROMISE(); - group_call_manager_->get_group_call_streams(GroupCallId(request.group_call_id_), std::move(promise)); -} - -void Td::on_request(uint64 id, td_api::getGroupCallStreamSegment &request) { - CHECK_IS_USER(); - CREATE_REQUEST_PROMISE(); - auto query_promise = PromiseCreator::lambda([promise = std::move(promise)](Result result) mutable { - if (result.is_error()) { - promise.set_error(result.move_as_error()); - } else { - auto file_part = td_api::make_object(); - file_part->data_ = result.move_as_ok(); - promise.set_value(std::move(file_part)); - } - }); - group_call_manager_->get_group_call_stream_segment(GroupCallId(request.group_call_id_), request.time_offset_, - request.scale_, request.channel_id_, - std::move(request.video_quality_), std::move(query_promise)); -} - -void Td::on_request(uint64 id, const td_api::upgradeBasicGroupChatToSupergroupChat &request) { - CHECK_IS_USER(); - CREATE_REQUEST_PROMISE(); - dialog_manager_->migrate_dialog_to_megagroup(DialogId(request.chat_id_), std::move(promise)); -} - -void Td::on_request(uint64 id, const td_api::getChatListsToAddChat &request) { - CHECK_IS_USER(); - auto dialog_lists = messages_manager_->get_dialog_lists_to_add_dialog(DialogId(request.chat_id_)); - auto chat_lists = - transform(dialog_lists, [](DialogListId dialog_list_id) { return dialog_list_id.get_chat_list_object(); }); - send_closure(actor_id(this), &Td::send_result, id, td_api::make_object(std::move(chat_lists))); -} - -void Td::on_request(uint64 id, const td_api::addChatToList &request) { - CHECK_IS_USER(); - CREATE_OK_REQUEST_PROMISE(); - messages_manager_->add_dialog_to_list(DialogId(request.chat_id_), DialogListId(request.chat_list_), - std::move(promise)); -} - -void Td::on_request(uint64 id, const td_api::getChatFolder &request) { - CHECK_IS_USER(); - CREATE_REQUEST_PROMISE(); - dialog_filter_manager_->get_dialog_filter(DialogFilterId(request.chat_folder_id_), std::move(promise)); -} - -void Td::on_request(uint64 id, const td_api::getRecommendedChatFolders &request) { - CHECK_IS_USER(); - CREATE_REQUEST_PROMISE(); - dialog_filter_manager_->get_recommended_dialog_filters(std::move(promise)); -} - -void Td::on_request(uint64 id, td_api::createChatFolder &request) { - CHECK_IS_USER(); - CREATE_REQUEST_PROMISE(); - dialog_filter_manager_->create_dialog_filter(std::move(request.folder_), std::move(promise)); -} - -void Td::on_request(uint64 id, td_api::editChatFolder &request) { - CHECK_IS_USER(); - CREATE_REQUEST_PROMISE(); - dialog_filter_manager_->edit_dialog_filter(DialogFilterId(request.chat_folder_id_), std::move(request.folder_), - std::move(promise)); -} - -void Td::on_request(uint64 id, const td_api::deleteChatFolder &request) { - CHECK_IS_USER(); - CREATE_OK_REQUEST_PROMISE(); - dialog_filter_manager_->delete_dialog_filter(DialogFilterId(request.chat_folder_id_), - DialogId::get_dialog_ids(request.leave_chat_ids_), std::move(promise)); -} - -void Td::on_request(uint64 id, const td_api::getChatFolderChatsToLeave &request) { - CHECK_IS_USER(); - CREATE_REQUEST_PROMISE(); - dialog_filter_manager_->get_leave_dialog_filter_suggestions(DialogFilterId(request.chat_folder_id_), - std::move(promise)); -} - -void Td::on_request(uint64 id, td_api::getChatFolderChatCount &request) { - CHECK_IS_USER(); - CREATE_REQUEST_PROMISE(); - auto query_promise = PromiseCreator::lambda([promise = std::move(promise)](Result result) mutable { - if (result.is_error()) { - promise.set_error(result.move_as_error()); - } else { - promise.set_value(make_tl_object(result.move_as_ok())); - } - }); - messages_manager_->get_dialog_filter_dialog_count(std::move(request.folder_), std::move(query_promise)); -} - -void Td::on_request(uint64 id, const td_api::reorderChatFolders &request) { - CHECK_IS_USER(); - CREATE_OK_REQUEST_PROMISE(); - dialog_filter_manager_->reorder_dialog_filters( - transform(request.chat_folder_ids_, [](int32 id) { return DialogFilterId(id); }), - request.main_chat_list_position_, std::move(promise)); -} - -void Td::on_request(uint64 id, const td_api::toggleChatFolderTags &request) { - CHECK_IS_USER(); - CREATE_OK_REQUEST_PROMISE(); - dialog_filter_manager_->toggle_dialog_filter_tags(request.are_tags_enabled_, std::move(promise)); -} - -void Td::on_request(uint64 id, const td_api::getChatsForChatFolderInviteLink &request) { - CHECK_IS_USER(); - CREATE_REQUEST_PROMISE(); - dialog_filter_manager_->get_dialogs_for_dialog_filter_invite_link(DialogFilterId(request.chat_folder_id_), - std::move(promise)); -} - -void Td::on_request(uint64 id, td_api::createChatFolderInviteLink &request) { - CHECK_IS_USER(); - CLEAN_INPUT_STRING(request.name_); - CREATE_REQUEST_PROMISE(); - dialog_filter_manager_->create_dialog_filter_invite_link( - DialogFilterId(request.chat_folder_id_), std::move(request.name_), DialogId::get_dialog_ids(request.chat_ids_), - std::move(promise)); -} - -void Td::on_request(uint64 id, td_api::getChatFolderInviteLinks &request) { - CHECK_IS_USER(); - CREATE_REQUEST_PROMISE(); - dialog_filter_manager_->get_dialog_filter_invite_links(DialogFilterId(request.chat_folder_id_), std::move(promise)); -} - -void Td::on_request(uint64 id, td_api::editChatFolderInviteLink &request) { - CHECK_IS_USER(); - CLEAN_INPUT_STRING(request.invite_link_); - CLEAN_INPUT_STRING(request.name_); - CREATE_REQUEST_PROMISE(); - dialog_filter_manager_->edit_dialog_filter_invite_link( - DialogFilterId(request.chat_folder_id_), std::move(request.invite_link_), std::move(request.name_), - DialogId::get_dialog_ids(request.chat_ids_), std::move(promise)); -} - -void Td::on_request(uint64 id, td_api::deleteChatFolderInviteLink &request) { - CHECK_IS_USER(); - CLEAN_INPUT_STRING(request.invite_link_); - CREATE_OK_REQUEST_PROMISE(); - dialog_filter_manager_->delete_dialog_filter_invite_link(DialogFilterId(request.chat_folder_id_), - std::move(request.invite_link_), std::move(promise)); -} - -void Td::on_request(uint64 id, td_api::checkChatFolderInviteLink &request) { - CHECK_IS_USER(); - CLEAN_INPUT_STRING(request.invite_link_); - CREATE_REQUEST_PROMISE(); - dialog_filter_manager_->check_dialog_filter_invite_link(std::move(request.invite_link_), std::move(promise)); -} - -void Td::on_request(uint64 id, td_api::addChatFolderByInviteLink &request) { - CHECK_IS_USER(); - CLEAN_INPUT_STRING(request.invite_link_); - CREATE_OK_REQUEST_PROMISE(); - dialog_filter_manager_->add_dialog_filter_by_invite_link( - std::move(request.invite_link_), DialogId::get_dialog_ids(request.chat_ids_), std::move(promise)); -} - -void Td::on_request(uint64 id, const td_api::getChatFolderNewChats &request) { - CHECK_IS_USER(); - CREATE_REQUEST_PROMISE(); - dialog_filter_manager_->get_dialog_filter_new_chats(DialogFilterId(request.chat_folder_id_), std::move(promise)); -} - -void Td::on_request(uint64 id, const td_api::processChatFolderNewChats &request) { - CHECK_IS_USER(); - CREATE_OK_REQUEST_PROMISE(); - dialog_filter_manager_->add_dialog_filter_new_chats( - DialogFilterId(request.chat_folder_id_), DialogId::get_dialog_ids(request.added_chat_ids_), std::move(promise)); -} - -void Td::on_request(uint64 id, const td_api::getArchiveChatListSettings &request) { - CHECK_IS_USER(); - CREATE_REQUEST_PROMISE(); - auto query_promise = - PromiseCreator::lambda([promise = std::move(promise)](Result result) mutable { - if (result.is_error()) { - promise.set_error(result.move_as_error()); - } else { - promise.set_value(result.ok().get_archive_chat_list_settings_object()); - } - }); - GlobalPrivacySettings::get_global_privacy_settings(this, std::move(query_promise)); -} - -void Td::on_request(uint64 id, td_api::setArchiveChatListSettings &request) { - CHECK_IS_USER(); - CREATE_OK_REQUEST_PROMISE(); - GlobalPrivacySettings::set_global_privacy_settings(this, GlobalPrivacySettings(std::move(request.settings_)), - std::move(promise)); -} - -void Td::on_request(uint64 id, const td_api::getReadDatePrivacySettings &request) { - CHECK_IS_USER(); - CREATE_REQUEST_PROMISE(); - auto query_promise = - PromiseCreator::lambda([promise = std::move(promise)](Result result) mutable { - if (result.is_error()) { - promise.set_error(result.move_as_error()); - } else { - promise.set_value(result.ok().get_read_date_privacy_settings_object()); - } - }); - GlobalPrivacySettings::get_global_privacy_settings(this, std::move(query_promise)); -} - -void Td::on_request(uint64 id, td_api::setReadDatePrivacySettings &request) { - CHECK_IS_USER(); - CREATE_OK_REQUEST_PROMISE(); - GlobalPrivacySettings::set_global_privacy_settings(this, GlobalPrivacySettings(std::move(request.settings_)), - std::move(promise)); -} - -void Td::on_request(uint64 id, const td_api::getNewChatPrivacySettings &request) { - CHECK_IS_USER(); - CREATE_REQUEST_PROMISE(); - auto query_promise = - PromiseCreator::lambda([promise = std::move(promise)](Result result) mutable { - if (result.is_error()) { - promise.set_error(result.move_as_error()); - } else { - promise.set_value(result.ok().get_new_chat_privacy_settings_object()); - } - }); - GlobalPrivacySettings::get_global_privacy_settings(this, std::move(query_promise)); -} - -void Td::on_request(uint64 id, td_api::setNewChatPrivacySettings &request) { - CHECK_IS_USER(); - CREATE_OK_REQUEST_PROMISE(); - GlobalPrivacySettings::set_global_privacy_settings(this, GlobalPrivacySettings(std::move(request.settings_)), - std::move(promise)); -} - -void Td::on_request(uint64 id, const td_api::canSendMessageToUser &request) { - CHECK_IS_USER(); - CREATE_REQUEST_PROMISE(); - user_manager_->can_send_message_to_user(UserId(request.user_id_), request.only_local_, std::move(promise)); -} - -void Td::on_request(uint64 id, td_api::setChatTitle &request) { - CLEAN_INPUT_STRING(request.title_); - CREATE_OK_REQUEST_PROMISE(); - dialog_manager_->set_dialog_title(DialogId(request.chat_id_), request.title_, std::move(promise)); -} - -void Td::on_request(uint64 id, const td_api::setChatPhoto &request) { - CREATE_OK_REQUEST_PROMISE(); - dialog_manager_->set_dialog_photo(DialogId(request.chat_id_), request.photo_, std::move(promise)); -} - -void Td::on_request(uint64 id, const td_api::setChatAccentColor &request) { - CHECK_IS_USER(); - CREATE_OK_REQUEST_PROMISE(); - dialog_manager_->set_dialog_accent_color(DialogId(request.chat_id_), AccentColorId(request.accent_color_id_), - CustomEmojiId(request.background_custom_emoji_id_), std::move(promise)); -} - -void Td::on_request(uint64 id, const td_api::setChatProfileAccentColor &request) { - CHECK_IS_USER(); - CREATE_OK_REQUEST_PROMISE(); - dialog_manager_->set_dialog_profile_accent_color( - DialogId(request.chat_id_), AccentColorId(request.profile_accent_color_id_), - CustomEmojiId(request.profile_background_custom_emoji_id_), std::move(promise)); -} - -void Td::on_request(uint64 id, const td_api::setChatMessageAutoDeleteTime &request) { - CHECK_IS_USER(); - CREATE_OK_REQUEST_PROMISE(); - messages_manager_->set_dialog_message_ttl(DialogId(request.chat_id_), request.message_auto_delete_time_, - std::move(promise)); -} - -void Td::on_request(uint64 id, const td_api::setChatEmojiStatus &request) { - CHECK_IS_USER(); - CREATE_OK_REQUEST_PROMISE(); - dialog_manager_->set_dialog_emoji_status(DialogId(request.chat_id_), EmojiStatus(request.emoji_status_), - std::move(promise)); -} - -void Td::on_request(uint64 id, const td_api::setChatPermissions &request) { - CREATE_OK_REQUEST_PROMISE(); - dialog_manager_->set_dialog_permissions(DialogId(request.chat_id_), request.permissions_, std::move(promise)); -} - -void Td::on_request(uint64 id, td_api::setChatBackground &request) { - CHECK_IS_USER(); - CREATE_OK_REQUEST_PROMISE(); - background_manager_->set_dialog_background(DialogId(request.chat_id_), request.background_.get(), request.type_.get(), - request.dark_theme_dimming_, !request.only_for_self_, std::move(promise)); -} - -void Td::on_request(uint64 id, const td_api::deleteChatBackground &request) { - CHECK_IS_USER(); - CREATE_OK_REQUEST_PROMISE(); - background_manager_->delete_dialog_background(DialogId(request.chat_id_), request.restore_previous_, - std::move(promise)); -} - -void Td::on_request(uint64 id, td_api::setChatTheme &request) { - CHECK_IS_USER(); - CLEAN_INPUT_STRING(request.theme_name_); - CREATE_OK_REQUEST_PROMISE(); - messages_manager_->set_dialog_theme(DialogId(request.chat_id_), request.theme_name_, std::move(promise)); -} - -void Td::on_request(uint64 id, td_api::setChatDraftMessage &request) { - CHECK_IS_USER(); - answer_ok_query( - id, messages_manager_->set_dialog_draft_message(DialogId(request.chat_id_), MessageId(request.message_thread_id_), - std::move(request.draft_message_))); -} - -void Td::on_request(uint64 id, const td_api::toggleChatHasProtectedContent &request) { - CHECK_IS_USER(); - CREATE_OK_REQUEST_PROMISE(); - dialog_manager_->toggle_dialog_has_protected_content(DialogId(request.chat_id_), request.has_protected_content_, - std::move(promise)); -} - -void Td::on_request(uint64 id, const td_api::toggleChatIsPinned &request) { - CHECK_IS_USER(); - answer_ok_query(id, messages_manager_->toggle_dialog_is_pinned(DialogListId(request.chat_list_), - DialogId(request.chat_id_), request.is_pinned_)); -} - -void Td::on_request(uint64 id, const td_api::toggleChatViewAsTopics &request) { - CHECK_IS_USER(); - answer_ok_query( - id, messages_manager_->toggle_dialog_view_as_messages(DialogId(request.chat_id_), !request.view_as_topics_)); -} - -void Td::on_request(uint64 id, const td_api::toggleChatIsTranslatable &request) { - CHECK_IS_USER(); - answer_ok_query( - id, messages_manager_->toggle_dialog_is_translatable(DialogId(request.chat_id_), request.is_translatable_)); -} - -void Td::on_request(uint64 id, const td_api::toggleChatIsMarkedAsUnread &request) { - CHECK_IS_USER(); - answer_ok_query(id, messages_manager_->toggle_dialog_is_marked_as_unread(DialogId(request.chat_id_), - request.is_marked_as_unread_)); -} - -void Td::on_request(uint64 id, const td_api::setMessageSenderBlockList &request) { - CHECK_IS_USER(); - answer_ok_query(id, messages_manager_->set_message_sender_block_list(request.sender_id_, request.block_list_)); -} - -void Td::on_request(uint64 id, const td_api::toggleChatDefaultDisableNotification &request) { - CHECK_IS_USER(); - answer_ok_query(id, messages_manager_->toggle_dialog_silent_send_message(DialogId(request.chat_id_), - request.default_disable_notification_)); -} - -void Td::on_request(uint64 id, const td_api::setPinnedChats &request) { - CHECK_IS_USER(); - answer_ok_query(id, messages_manager_->set_pinned_dialogs(DialogListId(request.chat_list_), - DialogId::get_dialog_ids(request.chat_ids_))); -} - -void Td::on_request(uint64 id, const td_api::readChatList &request) { - CHECK_IS_USER(); - CREATE_OK_REQUEST_PROMISE(); - messages_manager_->read_all_dialogs_from_list(DialogListId(request.chat_list_), std::move(promise)); -} - -void Td::on_request(uint64 id, const td_api::getStoryNotificationSettingsExceptions &request) { - CHECK_IS_USER(); - CREATE_REQUEST_PROMISE(); - notification_settings_manager_->get_story_notification_settings_exceptions(std::move(promise)); -} - -void Td::on_request(uint64 id, const td_api::getChatActiveStories &request) { - CHECK_IS_USER(); - CREATE_REQUEST_PROMISE(); - story_manager_->get_dialog_expiring_stories(DialogId(request.chat_id_), std::move(promise)); -} - -void Td::on_request(uint64 id, const td_api::getChatPostedToChatPageStories &request) { - CHECK_IS_USER(); - CREATE_REQUEST_PROMISE(); - story_manager_->get_dialog_pinned_stories(DialogId(request.chat_id_), StoryId(request.from_story_id_), request.limit_, - std::move(promise)); -} - -void Td::on_request(uint64 id, const td_api::getChatArchivedStories &request) { - CHECK_IS_USER(); - CREATE_REQUEST_PROMISE(); - story_manager_->get_story_archive(DialogId(request.chat_id_), StoryId(request.from_story_id_), request.limit_, - std::move(promise)); -} - -void Td::on_request(uint64 id, const td_api::setChatPinnedStories &request) { - CHECK_IS_USER(); - CREATE_OK_REQUEST_PROMISE(); - story_manager_->set_pinned_stories(DialogId(request.chat_id_), StoryId::get_story_ids(request.story_ids_), - std::move(promise)); -} - -void Td::on_request(uint64 id, const td_api::openStory &request) { - CHECK_IS_USER(); - CREATE_OK_REQUEST_PROMISE(); - story_manager_->open_story(DialogId(request.story_sender_chat_id_), StoryId(request.story_id_), std::move(promise)); -} - -void Td::on_request(uint64 id, const td_api::closeStory &request) { - CHECK_IS_USER(); - CREATE_OK_REQUEST_PROMISE(); - story_manager_->close_story(DialogId(request.story_sender_chat_id_), StoryId(request.story_id_), std::move(promise)); -} - -void Td::on_request(uint64 id, const td_api::getStoryAvailableReactions &request) { - CHECK_IS_USER(); - send_closure(actor_id(this), &Td::send_result, id, reaction_manager_->get_available_reactions(request.row_size_)); -} - -void Td::on_request(uint64 id, const td_api::setStoryReaction &request) { - CHECK_IS_USER(); - CREATE_OK_REQUEST_PROMISE(); - story_manager_->set_story_reaction({DialogId(request.story_sender_chat_id_), StoryId(request.story_id_)}, - ReactionType(request.reaction_type_), request.update_recent_reactions_, - std::move(promise)); -} - -void Td::on_request(uint64 id, td_api::getStoryInteractions &request) { - CHECK_IS_USER(); - CLEAN_INPUT_STRING(request.query_); - CLEAN_INPUT_STRING(request.offset_); - CREATE_REQUEST_PROMISE(); - story_manager_->get_story_interactions(StoryId(request.story_id_), request.query_, request.only_contacts_, - request.prefer_forwards_, request.prefer_with_reaction_, request.offset_, - request.limit_, std::move(promise)); -} - -void Td::on_request(uint64 id, td_api::getChatStoryInteractions &request) { - CHECK_IS_USER(); - CLEAN_INPUT_STRING(request.offset_); - CREATE_REQUEST_PROMISE(); - story_manager_->get_dialog_story_interactions({DialogId(request.story_sender_chat_id_), StoryId(request.story_id_)}, - ReactionType(request.reaction_type_), request.prefer_forwards_, - request.offset_, request.limit_, std::move(promise)); -} - -void Td::on_request(uint64 id, td_api::reportStory &request) { - CHECK_IS_USER(); - auto r_report_reason = ReportReason::get_report_reason(std::move(request.reason_), std::move(request.text_)); - if (r_report_reason.is_error()) { - return send_error_raw(id, r_report_reason.error().code(), r_report_reason.error().message()); - } - CREATE_OK_REQUEST_PROMISE(); - story_manager_->report_story({DialogId(request.story_sender_chat_id_), StoryId(request.story_id_)}, - r_report_reason.move_as_ok(), std::move(promise)); -} - -void Td::on_request(uint64 id, const td_api::activateStoryStealthMode &request) { - CREATE_OK_REQUEST_PROMISE(); - story_manager_->activate_stealth_mode(std::move(promise)); -} - -void Td::on_request(uint64 id, const td_api::getChatBoostLevelFeatures &request) { - CHECK_IS_USER(); - CREATE_REQUEST_PROMISE(); - promise.set_value(boost_manager_->get_chat_boost_level_features_object(!request.is_channel_, request.level_)); -} - -void Td::on_request(uint64 id, const td_api::getChatBoostFeatures &request) { - CHECK_IS_USER(); - CREATE_REQUEST_PROMISE(); - promise.set_value(boost_manager_->get_chat_boost_features_object(!request.is_channel_)); -} - -void Td::on_request(uint64 id, const td_api::getAvailableChatBoostSlots &request) { - CHECK_IS_USER(); - CREATE_REQUEST_PROMISE(); - boost_manager_->get_boost_slots(std::move(promise)); -} - -void Td::on_request(uint64 id, const td_api::getChatBoostStatus &request) { - CHECK_IS_USER(); - CREATE_REQUEST_PROMISE(); - boost_manager_->get_dialog_boost_status(DialogId(request.chat_id_), std::move(promise)); -} - -void Td::on_request(uint64 id, td_api::boostChat &request) { - CHECK_IS_USER(); - CREATE_REQUEST_PROMISE(); - boost_manager_->boost_dialog(DialogId(request.chat_id_), std::move(request.slot_ids_), std::move(promise)); -} - -void Td::on_request(uint64 id, const td_api::getChatBoostLink &request) { - auto r_boost_link = boost_manager_->get_dialog_boost_link(DialogId(request.chat_id_)); - if (r_boost_link.is_error()) { - send_closure(actor_id(this), &Td::send_error, id, r_boost_link.move_as_error()); - } else { - send_closure(actor_id(this), &Td::send_result, id, - td_api::make_object(r_boost_link.ok().first, r_boost_link.ok().second)); - } -} - -void Td::on_request(uint64 id, td_api::getChatBoostLinkInfo &request) { - CLEAN_INPUT_STRING(request.url_); - CREATE_REQUEST(GetDialogBoostLinkInfoRequest, std::move(request.url_)); -} - -void Td::on_request(uint64 id, td_api::getChatBoosts &request) { - CHECK_IS_USER(); - CLEAN_INPUT_STRING(request.offset_); - CREATE_REQUEST_PROMISE(); - boost_manager_->get_dialog_boosts(DialogId(request.chat_id_), request.only_gift_codes_, request.offset_, - request.limit_, std::move(promise)); -} - -void Td::on_request(uint64 id, const td_api::getUserChatBoosts &request) { - CHECK_IS_BOT(); - CREATE_REQUEST_PROMISE(); - boost_manager_->get_user_dialog_boosts(DialogId(request.chat_id_), UserId(request.user_id_), std::move(promise)); -} - -void Td::on_request(uint64 id, const td_api::getAttachmentMenuBot &request) { - CHECK_IS_USER(); - CREATE_REQUEST_PROMISE(); - attach_menu_manager_->get_attach_menu_bot(UserId(request.bot_user_id_), std::move(promise)); -} - -void Td::on_request(uint64 id, const td_api::toggleBotIsAddedToAttachmentMenu &request) { - CHECK_IS_USER(); - CREATE_OK_REQUEST_PROMISE(); - attach_menu_manager_->toggle_bot_is_added_to_attach_menu(UserId(request.bot_user_id_), request.is_added_, - request.allow_write_access_, std::move(promise)); -} - -void Td::on_request(uint64 id, td_api::setChatAvailableReactions &request) { - CREATE_OK_REQUEST_PROMISE(); - messages_manager_->set_dialog_available_reactions(DialogId(request.chat_id_), std::move(request.available_reactions_), - std::move(promise)); -} - -void Td::on_request(uint64 id, td_api::setChatClientData &request) { - answer_ok_query( - id, messages_manager_->set_dialog_client_data(DialogId(request.chat_id_), std::move(request.client_data_))); -} - -void Td::on_request(uint64 id, td_api::setChatDescription &request) { - CLEAN_INPUT_STRING(request.description_); - CREATE_OK_REQUEST_PROMISE(); - dialog_manager_->set_dialog_description(DialogId(request.chat_id_), request.description_, std::move(promise)); -} - -void Td::on_request(uint64 id, const td_api::setChatDiscussionGroup &request) { - CHECK_IS_USER(); - CREATE_OK_REQUEST_PROMISE(); - chat_manager_->set_channel_discussion_group(DialogId(request.chat_id_), DialogId(request.discussion_chat_id_), - std::move(promise)); -} - -void Td::on_request(uint64 id, td_api::setChatLocation &request) { - CHECK_IS_USER(); - CREATE_OK_REQUEST_PROMISE(); - dialog_manager_->set_dialog_location(DialogId(request.chat_id_), DialogLocation(std::move(request.location_)), - std::move(promise)); -} - -void Td::on_request(uint64 id, const td_api::setChatSlowModeDelay &request) { - CHECK_IS_USER(); - CREATE_OK_REQUEST_PROMISE(); - chat_manager_->set_channel_slow_mode_delay(DialogId(request.chat_id_), request.slow_mode_delay_, std::move(promise)); -} - -void Td::on_request(uint64 id, const td_api::pinChatMessage &request) { - CREATE_OK_REQUEST_PROMISE(); - messages_manager_->pin_dialog_message(BusinessConnectionId(), DialogId(request.chat_id_), - MessageId(request.message_id_), request.disable_notification_, - request.only_for_self_, false, std::move(promise)); -} - -void Td::on_request(uint64 id, const td_api::unpinChatMessage &request) { - CREATE_OK_REQUEST_PROMISE(); - messages_manager_->pin_dialog_message(BusinessConnectionId(), DialogId(request.chat_id_), - MessageId(request.message_id_), false, false, true, std::move(promise)); -} - -void Td::on_request(uint64 id, const td_api::unpinAllChatMessages &request) { - CREATE_OK_REQUEST_PROMISE(); - messages_manager_->unpin_all_dialog_messages(DialogId(request.chat_id_), MessageId(), std::move(promise)); -} - -void Td::on_request(uint64 id, const td_api::unpinAllMessageThreadMessages &request) { - if (request.message_thread_id_ == 0) { - return send_error_raw(id, 400, "Invalid message thread identifier specified"); - } - CREATE_OK_REQUEST_PROMISE(); - messages_manager_->unpin_all_dialog_messages(DialogId(request.chat_id_), MessageId(request.message_thread_id_), - std::move(promise)); -} - -void Td::on_request(uint64 id, const td_api::joinChat &request) { - CHECK_IS_USER(); - CREATE_OK_REQUEST_PROMISE(); - dialog_participant_manager_->add_dialog_participant( - DialogId(request.chat_id_), user_manager_->get_my_id(), 0, - DialogParticipantManager::wrap_failed_to_add_members_promise(std::move(promise))); -} - -void Td::on_request(uint64 id, const td_api::leaveChat &request) { - CREATE_OK_REQUEST_PROMISE(); - DialogId dialog_id(request.chat_id_); - td_api::object_ptr new_status = td_api::make_object(); - if (dialog_id.get_type() == DialogType::Channel && dialog_manager_->have_dialog_force(dialog_id, "leaveChat")) { - auto status = chat_manager_->get_channel_status(dialog_id.get_channel_id()); - if (status.is_creator()) { - if (!status.is_member()) { - return promise.set_value(Unit()); - } - - new_status = - td_api::make_object(status.get_rank(), status.is_anonymous(), false); - } - } - dialog_participant_manager_->set_dialog_participant_status(dialog_id, dialog_manager_->get_my_dialog_id(), - std::move(new_status), std::move(promise)); -} - -void Td::on_request(uint64 id, const td_api::addChatMember &request) { - CHECK_IS_USER(); - CREATE_REQUEST_PROMISE(); - dialog_participant_manager_->add_dialog_participant(DialogId(request.chat_id_), UserId(request.user_id_), - request.forward_limit_, std::move(promise)); -} - -void Td::on_request(uint64 id, const td_api::addChatMembers &request) { - CHECK_IS_USER(); - CREATE_REQUEST_PROMISE(); - dialog_participant_manager_->add_dialog_participants(DialogId(request.chat_id_), - UserId::get_user_ids(request.user_ids_), std::move(promise)); -} - -void Td::on_request(uint64 id, td_api::setChatMemberStatus &request) { - CREATE_OK_REQUEST_PROMISE(); - TRY_RESULT_PROMISE(promise, participant_dialog_id, - get_message_sender_dialog_id(this, request.member_id_, false, false)); - dialog_participant_manager_->set_dialog_participant_status(DialogId(request.chat_id_), participant_dialog_id, - std::move(request.status_), std::move(promise)); -} - -void Td::on_request(uint64 id, const td_api::banChatMember &request) { - CREATE_OK_REQUEST_PROMISE(); - TRY_RESULT_PROMISE(promise, participant_dialog_id, - get_message_sender_dialog_id(this, request.member_id_, false, false)); - dialog_participant_manager_->ban_dialog_participant(DialogId(request.chat_id_), participant_dialog_id, - request.banned_until_date_, request.revoke_messages_, - std::move(promise)); -} - -void Td::on_request(uint64 id, const td_api::canTransferOwnership &request) { - CHECK_IS_USER(); - CREATE_REQUEST_PROMISE(); - auto query_promise = PromiseCreator::lambda( - [promise = std::move(promise)](Result result) mutable { - if (result.is_error()) { - promise.set_error(result.move_as_error()); - } else { - promise.set_value(DialogParticipantManager::get_can_transfer_ownership_result_object(result.ok())); - } - }); - dialog_participant_manager_->can_transfer_ownership(std::move(query_promise)); -} - -void Td::on_request(uint64 id, td_api::transferChatOwnership &request) { - CHECK_IS_USER(); - CLEAN_INPUT_STRING(request.password_); - CREATE_OK_REQUEST_PROMISE(); - dialog_participant_manager_->transfer_dialog_ownership(DialogId(request.chat_id_), UserId(request.user_id_), - request.password_, std::move(promise)); -} - -void Td::on_request(uint64 id, const td_api::getChatMember &request) { - CREATE_REQUEST_PROMISE(); - TRY_RESULT_PROMISE(promise, participant_dialog_id, - get_message_sender_dialog_id(this, request.member_id_, false, false)); - dialog_participant_manager_->get_dialog_participant(DialogId(request.chat_id_), participant_dialog_id, - std::move(promise)); -} - -void Td::on_request(uint64 id, td_api::searchChatMembers &request) { - CLEAN_INPUT_STRING(request.query_); - CREATE_REQUEST_PROMISE(); - auto query_promise = - PromiseCreator::lambda([promise = std::move(promise), td = this](Result result) mutable { - if (result.is_error()) { - promise.set_error(result.move_as_error()); - } else { - promise.set_value(result.ok().get_chat_members_object(td, "searchChatMembers")); - } - }); - dialog_participant_manager_->search_dialog_participants(DialogId(request.chat_id_), request.query_, request.limit_, - DialogParticipantFilter(request.filter_), - std::move(query_promise)); -} - -void Td::on_request(uint64 id, const td_api::getChatAdministrators &request) { - CREATE_REQUEST_PROMISE(); - dialog_participant_manager_->get_dialog_administrators(DialogId(request.chat_id_), std::move(promise)); -} - -void Td::on_request(uint64 id, const td_api::replacePrimaryChatInviteLink &request) { - CREATE_REQUEST_PROMISE(); - dialog_invite_link_manager_->export_dialog_invite_link(DialogId(request.chat_id_), string(), 0, 0, false, - StarSubscriptionPricing(), false, true, std::move(promise)); -} - -void Td::on_request(uint64 id, td_api::createChatInviteLink &request) { - CLEAN_INPUT_STRING(request.name_); - CREATE_REQUEST_PROMISE(); - dialog_invite_link_manager_->export_dialog_invite_link( - DialogId(request.chat_id_), std::move(request.name_), request.expiration_date_, request.member_limit_, - request.creates_join_request_, StarSubscriptionPricing(), false, false, std::move(promise)); -} - -void Td::on_request(uint64 id, td_api::createChatSubscriptionInviteLink &request) { - CLEAN_INPUT_STRING(request.name_); - CREATE_REQUEST_PROMISE(); - dialog_invite_link_manager_->export_dialog_invite_link( - DialogId(request.chat_id_), std::move(request.name_), 0, 0, false, - StarSubscriptionPricing(std::move(request.subscription_pricing_)), true, false, std::move(promise)); -} - -void Td::on_request(uint64 id, td_api::editChatInviteLink &request) { - CLEAN_INPUT_STRING(request.name_); - CLEAN_INPUT_STRING(request.invite_link_); - CREATE_REQUEST_PROMISE(); - dialog_invite_link_manager_->edit_dialog_invite_link( - DialogId(request.chat_id_), request.invite_link_, std::move(request.name_), request.expiration_date_, - request.member_limit_, request.creates_join_request_, false, std::move(promise)); -} - -void Td::on_request(uint64 id, td_api::editChatSubscriptionInviteLink &request) { - CLEAN_INPUT_STRING(request.name_); - CLEAN_INPUT_STRING(request.invite_link_); - CREATE_REQUEST_PROMISE(); - dialog_invite_link_manager_->edit_dialog_invite_link(DialogId(request.chat_id_), request.invite_link_, - std::move(request.name_), 0, 0, false, true, std::move(promise)); -} - -void Td::on_request(uint64 id, td_api::getChatInviteLink &request) { - CHECK_IS_USER(); - CLEAN_INPUT_STRING(request.invite_link_); - CREATE_REQUEST_PROMISE(); - dialog_invite_link_manager_->get_dialog_invite_link(DialogId(request.chat_id_), request.invite_link_, - std::move(promise)); -} - -void Td::on_request(uint64 id, const td_api::getChatInviteLinkCounts &request) { - CHECK_IS_USER(); - CREATE_REQUEST_PROMISE(); - dialog_invite_link_manager_->get_dialog_invite_link_counts(DialogId(request.chat_id_), std::move(promise)); -} - -void Td::on_request(uint64 id, td_api::getChatInviteLinks &request) { - CHECK_IS_USER(); - CLEAN_INPUT_STRING(request.offset_invite_link_); - CREATE_REQUEST_PROMISE(); - dialog_invite_link_manager_->get_dialog_invite_links(DialogId(request.chat_id_), UserId(request.creator_user_id_), - request.is_revoked_, request.offset_date_, - request.offset_invite_link_, request.limit_, std::move(promise)); -} - -void Td::on_request(uint64 id, td_api::getChatInviteLinkMembers &request) { - CHECK_IS_USER(); - CLEAN_INPUT_STRING(request.invite_link_); - CREATE_REQUEST_PROMISE(); - dialog_invite_link_manager_->get_dialog_invite_link_users( - DialogId(request.chat_id_), request.invite_link_, request.only_with_expired_subscription_, - std::move(request.offset_member_), request.limit_, std::move(promise)); -} - -void Td::on_request(uint64 id, td_api::getChatJoinRequests &request) { - CHECK_IS_USER(); - CLEAN_INPUT_STRING(request.invite_link_); - CLEAN_INPUT_STRING(request.query_); - CREATE_REQUEST_PROMISE(); - dialog_participant_manager_->get_dialog_join_requests(DialogId(request.chat_id_), request.invite_link_, - request.query_, std::move(request.offset_request_), - request.limit_, std::move(promise)); -} - -void Td::on_request(uint64 id, const td_api::processChatJoinRequest &request) { - CREATE_OK_REQUEST_PROMISE(); - dialog_participant_manager_->process_dialog_join_request(DialogId(request.chat_id_), UserId(request.user_id_), - request.approve_, std::move(promise)); -} - -void Td::on_request(uint64 id, td_api::processChatJoinRequests &request) { - CHECK_IS_USER(); - CLEAN_INPUT_STRING(request.invite_link_); - CREATE_OK_REQUEST_PROMISE(); - dialog_participant_manager_->process_dialog_join_requests(DialogId(request.chat_id_), request.invite_link_, - request.approve_, std::move(promise)); -} - -void Td::on_request(uint64 id, td_api::revokeChatInviteLink &request) { - CLEAN_INPUT_STRING(request.invite_link_); - CREATE_REQUEST_PROMISE(); - dialog_invite_link_manager_->revoke_dialog_invite_link(DialogId(request.chat_id_), request.invite_link_, - std::move(promise)); -} - -void Td::on_request(uint64 id, td_api::deleteRevokedChatInviteLink &request) { - CHECK_IS_USER(); - CLEAN_INPUT_STRING(request.invite_link_); - CREATE_OK_REQUEST_PROMISE(); - dialog_invite_link_manager_->delete_revoked_dialog_invite_link(DialogId(request.chat_id_), request.invite_link_, - std::move(promise)); -} - -void Td::on_request(uint64 id, const td_api::deleteAllRevokedChatInviteLinks &request) { - CHECK_IS_USER(); - CREATE_OK_REQUEST_PROMISE(); - dialog_invite_link_manager_->delete_all_revoked_dialog_invite_links( - DialogId(request.chat_id_), UserId(request.creator_user_id_), std::move(promise)); -} - -void Td::on_request(uint64 id, td_api::checkChatInviteLink &request) { - CHECK_IS_USER(); - CLEAN_INPUT_STRING(request.invite_link_); - CREATE_REQUEST(CheckChatInviteLinkRequest, request.invite_link_); -} - -void Td::on_request(uint64 id, td_api::joinChatByInviteLink &request) { - CHECK_IS_USER(); - CLEAN_INPUT_STRING(request.invite_link_); - CREATE_REQUEST(JoinChatByInviteLinkRequest, request.invite_link_); -} - -void Td::on_request(uint64 id, td_api::getChatEventLog &request) { - CHECK_IS_USER(); - CLEAN_INPUT_STRING(request.query_); - CREATE_REQUEST_PROMISE(); - get_dialog_event_log(this, DialogId(request.chat_id_), std::move(request.query_), request.from_event_id_, - request.limit_, std::move(request.filters_), UserId::get_user_ids(request.user_ids_), - std::move(promise)); -} - -void Td::on_request(uint64 id, const td_api::getTimeZones &request) { - CREATE_REQUEST_PROMISE(); - time_zone_manager_->get_time_zones(std::move(promise)); -} - -void Td::on_request(uint64 id, const td_api::clearAllDraftMessages &request) { - CHECK_IS_USER(); - CREATE_OK_REQUEST_PROMISE(); - messages_manager_->clear_all_draft_messages(request.exclude_secret_chats_, std::move(promise)); -} - -void Td::on_request(uint64 id, const td_api::downloadFile &request) { - auto priority = request.priority_; - if (!(1 <= priority && priority <= 32)) { - return send_error_raw(id, 400, "Download priority must be between 1 and 32"); - } - auto offset = request.offset_; - if (offset < 0) { - return send_error_raw(id, 400, "Download offset must be non-negative"); - } - auto limit = request.limit_; - if (limit < 0) { - return send_error_raw(id, 400, "Download limit must be non-negative"); - } - - FileId file_id(request.file_id_, 0); - auto file_view = file_manager_->get_file_view(file_id); - if (file_view.empty()) { - return send_error_raw(id, 400, "Invalid file identifier"); - } - - auto info_it = pending_file_downloads_.find(file_id); - DownloadInfo *info = info_it == pending_file_downloads_.end() ? nullptr : &info_it->second; - if (info != nullptr && (offset != info->offset || limit != info->limit)) { - // we can't have two pending requests with different offset and limit, so cancel all previous requests - auto request_ids = std::move(info->request_ids); - info->request_ids.clear(); - for (auto request_id : request_ids) { - send_closure(actor_id(this), &Td::send_error, request_id, - Status::Error(200, "Canceled by another downloadFile request")); - } - } - if (request.synchronous_) { - if (info == nullptr) { - info = &pending_file_downloads_[file_id]; - } - info->offset = offset; - info->limit = limit; - info->request_ids.push_back(id); - } - Promise> download_promise; - if (!request.synchronous_) { - CREATE_REQUEST_PROMISE(); - download_promise = std::move(promise); - } - file_manager_->download(file_id, download_file_callback_, priority, offset, limit, std::move(download_promise)); -} - -void Td::on_file_download_finished(FileId file_id) { - auto it = pending_file_downloads_.find(file_id); - if (it == pending_file_downloads_.end()) { - return; - } - for (auto id : it->second.request_ids) { - // there was send_closure to call this function - auto file_object = file_manager_->get_file_object(file_id, false); - CHECK(file_object != nullptr); - auto download_offset = file_object->local_->download_offset_; - auto downloaded_size = file_object->local_->downloaded_prefix_size_; - auto file_size = file_object->size_; - auto limit = it->second.limit; - if (limit == 0) { - limit = std::numeric_limits::max(); - } - if (file_object->local_->is_downloading_completed_ || - (download_offset <= it->second.offset && download_offset + downloaded_size >= it->second.offset && - ((file_size != 0 && download_offset + downloaded_size == file_size) || - download_offset + downloaded_size - it->second.offset >= limit))) { - send_result(id, std::move(file_object)); - } else { - send_error_impl(id, td_api::make_object(400, "File download has failed or was canceled")); - } - } - pending_file_downloads_.erase(it); -} - -void Td::on_request(uint64 id, const td_api::getFileDownloadedPrefixSize &request) { - if (request.offset_ < 0) { - return send_error_raw(id, 400, "Parameter offset must be non-negative"); - } - auto file_view = file_manager_->get_file_view(FileId(request.file_id_, 0)); - if (file_view.empty()) { - return send_closure(actor_id(this), &Td::send_error, id, Status::Error(400, "Unknown file ID")); - } - send_closure(actor_id(this), &Td::send_result, id, - td_api::make_object(file_view.downloaded_prefix(request.offset_))); -} - -void Td::on_request(uint64 id, const td_api::cancelDownloadFile &request) { - file_manager_->download(FileId(request.file_id_, 0), nullptr, request.only_if_pending_ ? -1 : 0, - FileManager::KEEP_DOWNLOAD_OFFSET, FileManager::KEEP_DOWNLOAD_LIMIT, - Promise>()); - send_closure(actor_id(this), &Td::send_result, id, make_tl_object()); -} - -void Td::on_request(uint64 id, const td_api::getSuggestedFileName &request) { - Result r_file_name = file_manager_->get_suggested_file_name(FileId(request.file_id_, 0), request.directory_); - if (r_file_name.is_error()) { - return send_closure(actor_id(this), &Td::send_error, id, r_file_name.move_as_error()); - } - send_closure(actor_id(this), &Td::send_result, id, td_api::make_object(r_file_name.ok())); -} - -void Td::on_request(uint64 id, const td_api::preliminaryUploadFile &request) { - auto priority = request.priority_; - if (!(1 <= priority && priority <= 32)) { - return send_error_raw(id, 400, "Upload priority must be between 1 and 32"); - } - - auto file_type = request.file_type_ == nullptr ? FileType::Temp : get_file_type(*request.file_type_); - bool is_secret = file_type == FileType::Encrypted || file_type == FileType::EncryptedThumbnail; - bool is_secure = file_type == FileType::SecureEncrypted; - auto r_file_id = file_manager_->get_input_file_id(file_type, request.file_, DialogId(), false, is_secret, - !is_secure && !is_secret, is_secure); - if (r_file_id.is_error()) { - return send_error_raw(id, r_file_id.error().code(), r_file_id.error().message()); - } - auto file_id = r_file_id.ok(); - auto upload_file_id = file_manager_->dup_file_id(file_id, "preliminaryUploadFile"); - - file_manager_->upload(upload_file_id, upload_file_callback_, priority, 0); - - send_closure(actor_id(this), &Td::send_result, id, file_manager_->get_file_object(upload_file_id, false)); -} - -void Td::on_request(uint64 id, const td_api::cancelPreliminaryUploadFile &request) { - file_manager_->cancel_upload(FileId(request.file_id_, 0)); - - send_closure(actor_id(this), &Td::send_result, id, make_tl_object()); -} - -void Td::on_request(uint64 id, td_api::writeGeneratedFilePart &request) { - CREATE_OK_REQUEST_PROMISE(); - send_closure(file_manager_actor_, &FileManager::external_file_generate_write_part, request.generation_id_, - request.offset_, std::move(request.data_), std::move(promise)); -} - -void Td::on_request(uint64 id, const td_api::setFileGenerationProgress &request) { - CREATE_OK_REQUEST_PROMISE(); - send_closure(file_manager_actor_, &FileManager::external_file_generate_progress, request.generation_id_, - request.expected_size_, request.local_prefix_size_, std::move(promise)); -} - -void Td::on_request(uint64 id, td_api::finishFileGeneration &request) { - Status status; - if (request.error_ != nullptr) { - CLEAN_INPUT_STRING(request.error_->message_); - status = Status::Error(request.error_->code_, request.error_->message_); - } - CREATE_OK_REQUEST_PROMISE(); - send_closure(file_manager_actor_, &FileManager::external_file_generate_finish, request.generation_id_, - std::move(status), std::move(promise)); -} - -void Td::on_request(uint64 id, const td_api::readFilePart &request) { - CREATE_REQUEST_PROMISE(); - send_closure(file_manager_actor_, &FileManager::read_file_part, FileId(request.file_id_, 0), request.offset_, - request.count_, 2, std::move(promise)); -} - -void Td::on_request(uint64 id, const td_api::deleteFile &request) { - CREATE_OK_REQUEST_PROMISE(); - send_closure(file_manager_actor_, &FileManager::delete_file, FileId(request.file_id_, 0), std::move(promise), - "td_api::deleteFile"); -} - -void Td::on_request(uint64 id, const td_api::addFileToDownloads &request) { - if (!(1 <= request.priority_ && request.priority_ <= 32)) { - return send_error_raw(id, 400, "Download priority must be between 1 and 32"); - } - CREATE_REQUEST_PROMISE(); - messages_manager_->add_message_file_to_downloads( - MessageFullId(DialogId(request.chat_id_), MessageId(request.message_id_)), FileId(request.file_id_, 0), - request.priority_, std::move(promise)); -} - -void Td::on_request(uint64 id, const td_api::toggleDownloadIsPaused &request) { - CREATE_OK_REQUEST_PROMISE(); - send_closure(download_manager_actor_, &DownloadManager::toggle_is_paused, FileId(request.file_id_, 0), - request.is_paused_, std::move(promise)); -} - -void Td::on_request(uint64 id, const td_api::toggleAllDownloadsArePaused &request) { - CREATE_OK_REQUEST_PROMISE(); - send_closure(download_manager_actor_, &DownloadManager::toggle_all_is_paused, request.are_paused_, - std::move(promise)); -} - -void Td::on_request(uint64 id, const td_api::removeFileFromDownloads &request) { - CREATE_OK_REQUEST_PROMISE(); - send_closure(download_manager_actor_, &DownloadManager::remove_file, FileId(request.file_id_, 0), FileSourceId(), - request.delete_from_cache_, std::move(promise)); -} - -void Td::on_request(uint64 id, const td_api::removeAllFilesFromDownloads &request) { - CREATE_OK_REQUEST_PROMISE(); - send_closure(download_manager_actor_, &DownloadManager::remove_all_files, request.only_active_, - request.only_completed_, request.delete_from_cache_, std::move(promise)); -} - -void Td::on_request(uint64 id, td_api::searchFileDownloads &request) { - CLEAN_INPUT_STRING(request.query_); - CLEAN_INPUT_STRING(request.offset_); - CREATE_REQUEST_PROMISE(); - send_closure(download_manager_actor_, &DownloadManager::search, std::move(request.query_), request.only_active_, - request.only_completed_, std::move(request.offset_), request.limit_, std::move(promise)); -} - -void Td::on_request(uint64 id, td_api::setApplicationVerificationToken &request) { - CHECK_IS_USER(); - CLEAN_INPUT_STRING(request.token_); - CREATE_OK_REQUEST_PROMISE(); - G()->net_query_dispatcher().set_verification_token(request.verification_id_, std::move(request.token_), - std::move(promise)); -} - -void Td::on_request(uint64 id, td_api::getMessageFileType &request) { - CHECK_IS_USER(); - CLEAN_INPUT_STRING(request.message_file_head_); - CREATE_REQUEST_PROMISE(); - message_import_manager_->get_message_file_type(request.message_file_head_, std::move(promise)); -} - -void Td::on_request(uint64 id, const td_api::getMessageImportConfirmationText &request) { - CHECK_IS_USER(); - CREATE_REQUEST_PROMISE(); - auto query_promise = PromiseCreator::lambda([promise = std::move(promise)](Result result) mutable { - if (result.is_error()) { - promise.set_error(result.move_as_error()); - } else { - promise.set_value(make_tl_object(result.move_as_ok())); - } - }); - message_import_manager_->get_message_import_confirmation_text(DialogId(request.chat_id_), std::move(query_promise)); -} - -void Td::on_request(uint64 id, const td_api::importMessages &request) { - CHECK_IS_USER(); - CREATE_OK_REQUEST_PROMISE(); - message_import_manager_->import_messages(DialogId(request.chat_id_), request.message_file_, request.attached_files_, - std::move(promise)); -} - -void Td::on_request(uint64 id, const td_api::blockMessageSenderFromReplies &request) { - CHECK_IS_USER(); - CREATE_OK_REQUEST_PROMISE(); - messages_manager_->block_message_sender_from_replies(MessageId(request.message_id_), request.delete_message_, - request.delete_all_messages_, request.report_spam_, - std::move(promise)); -} - -void Td::on_request(uint64 id, const td_api::getBlockedMessageSenders &request) { - CHECK_IS_USER(); - CREATE_REQUEST_PROMISE(); - messages_manager_->get_blocked_dialogs(request.block_list_, request.offset_, request.limit_, std::move(promise)); -} - -void Td::on_request(uint64 id, td_api::addContact &request) { - CHECK_IS_USER(); - auto r_contact = get_contact(this, std::move(request.contact_)); - if (r_contact.is_error()) { - return send_closure(actor_id(this), &Td::send_error, id, r_contact.move_as_error()); - } - CREATE_OK_REQUEST_PROMISE(); - user_manager_->add_contact(r_contact.move_as_ok(), request.share_phone_number_, std::move(promise)); -} - -void Td::on_request(uint64 id, td_api::importContacts &request) { - CHECK_IS_USER(); - vector contacts; - contacts.reserve(request.contacts_.size()); - for (auto &contact : request.contacts_) { - auto r_contact = get_contact(this, std::move(contact)); - if (r_contact.is_error()) { - return send_closure(actor_id(this), &Td::send_error, id, r_contact.move_as_error()); - } - contacts.push_back(r_contact.move_as_ok()); - } - CREATE_REQUEST(ImportContactsRequest, std::move(contacts)); -} - -void Td::on_request(uint64 id, const td_api::getContacts &request) { - CHECK_IS_USER(); - CREATE_REQUEST(SearchContactsRequest, string(), 1000000); -} - -void Td::on_request(uint64 id, td_api::searchContacts &request) { - CHECK_IS_USER(); - CLEAN_INPUT_STRING(request.query_); - CREATE_REQUEST(SearchContactsRequest, request.query_, request.limit_); -} - -void Td::on_request(uint64 id, td_api::removeContacts &request) { - CHECK_IS_USER(); - CREATE_REQUEST(RemoveContactsRequest, UserId::get_user_ids(request.user_ids_)); -} - -void Td::on_request(uint64 id, const td_api::getImportedContactCount &request) { - CHECK_IS_USER(); - CREATE_NO_ARGS_REQUEST(GetImportedContactCountRequest); -} - -void Td::on_request(uint64 id, td_api::changeImportedContacts &request) { - CHECK_IS_USER(); - vector contacts; - contacts.reserve(request.contacts_.size()); - for (auto &contact : request.contacts_) { - auto r_contact = get_contact(this, std::move(contact)); - if (r_contact.is_error()) { - return send_closure(actor_id(this), &Td::send_error, id, r_contact.move_as_error()); - } - contacts.push_back(r_contact.move_as_ok()); - } - CREATE_REQUEST(ChangeImportedContactsRequest, std::move(contacts)); -} - -void Td::on_request(uint64 id, const td_api::clearImportedContacts &request) { - CHECK_IS_USER(); - CREATE_OK_REQUEST_PROMISE(); - user_manager_->clear_imported_contacts(std::move(promise)); -} - -void Td::on_request(uint64 id, const td_api::getCloseFriends &request) { - CHECK_IS_USER(); - CREATE_NO_ARGS_REQUEST(GetCloseFriendsRequest); -} - -void Td::on_request(uint64 id, const td_api::setCloseFriends &request) { - CHECK_IS_USER(); - CREATE_OK_REQUEST_PROMISE(); - user_manager_->set_close_friends(UserId::get_user_ids(request.user_ids_), std::move(promise)); -} - -void Td::on_request(uint64 id, td_api::setUserPersonalProfilePhoto &request) { - CHECK_IS_USER(); - CREATE_OK_REQUEST_PROMISE(); - user_manager_->set_user_profile_photo(UserId(request.user_id_), request.photo_, false, std::move(promise)); -} - -void Td::on_request(uint64 id, td_api::suggestUserProfilePhoto &request) { - CHECK_IS_USER(); - CREATE_OK_REQUEST_PROMISE(); - user_manager_->set_user_profile_photo(UserId(request.user_id_), request.photo_, true, std::move(promise)); -} - -void Td::on_request(uint64 id, td_api::searchUserByPhoneNumber &request) { - CHECK_IS_USER(); - CLEAN_INPUT_STRING(request.phone_number_); - CREATE_REQUEST(SearchUserByPhoneNumberRequest, std::move(request.phone_number_), request.only_local_); -} - -void Td::on_request(uint64 id, const td_api::sharePhoneNumber &request) { - CHECK_IS_USER(); - CREATE_OK_REQUEST_PROMISE(); - user_manager_->share_phone_number(UserId(request.user_id_), std::move(promise)); -} - -void Td::on_request(uint64 id, const td_api::getRecentInlineBots &request) { - CHECK_IS_USER(); - CREATE_NO_ARGS_REQUEST(GetRecentInlineBotsRequest); -} - -void Td::on_request(uint64 id, td_api::setName &request) { - CHECK_IS_USER(); - CLEAN_INPUT_STRING(request.first_name_); - CLEAN_INPUT_STRING(request.last_name_); - CREATE_OK_REQUEST_PROMISE(); - user_manager_->set_name(request.first_name_, request.last_name_, std::move(promise)); -} - -void Td::on_request(uint64 id, td_api::setBio &request) { - CHECK_IS_USER(); - CLEAN_INPUT_STRING(request.bio_); - CREATE_OK_REQUEST_PROMISE(); - user_manager_->set_bio(request.bio_, std::move(promise)); -} - -void Td::on_request(uint64 id, td_api::setUsername &request) { - CHECK_IS_USER(); - CLEAN_INPUT_STRING(request.username_); - CREATE_OK_REQUEST_PROMISE(); - user_manager_->set_username(request.username_, std::move(promise)); -} - -void Td::on_request(uint64 id, td_api::toggleUsernameIsActive &request) { - CHECK_IS_USER(); - CLEAN_INPUT_STRING(request.username_); - CREATE_OK_REQUEST_PROMISE(); - user_manager_->toggle_username_is_active(std::move(request.username_), request.is_active_, std::move(promise)); -} - -void Td::on_request(uint64 id, td_api::reorderActiveUsernames &request) { - CHECK_IS_USER(); - for (auto &username : request.usernames_) { - CLEAN_INPUT_STRING(username); - } - CREATE_OK_REQUEST_PROMISE(); - user_manager_->reorder_usernames(std::move(request.usernames_), std::move(promise)); -} - -void Td::on_request(uint64 id, td_api::setBirthdate &request) { - CHECK_IS_USER(); - CREATE_OK_REQUEST_PROMISE(); - user_manager_->set_birthdate(Birthdate(std::move(request.birthdate_)), std::move(promise)); -} - -void Td::on_request(uint64 id, const td_api::setPersonalChat &request) { - CHECK_IS_USER(); - CREATE_OK_REQUEST_PROMISE(); - user_manager_->set_personal_channel(DialogId(request.chat_id_), std::move(promise)); -} - -void Td::on_request(uint64 id, const td_api::setEmojiStatus &request) { - CHECK_IS_USER(); - CREATE_OK_REQUEST_PROMISE(); - user_manager_->set_emoji_status(EmojiStatus(request.emoji_status_), std::move(promise)); -} - -void Td::on_request(uint64 id, const td_api::toggleHasSponsoredMessagesEnabled &request) { - CHECK_IS_USER(); - CREATE_OK_REQUEST_PROMISE(); - user_manager_->toggle_sponsored_messages(request.has_sponsored_messages_enabled_, std::move(promise)); -} - -void Td::on_request(uint64 id, const td_api::getThemedEmojiStatuses &request) { - CHECK_IS_USER(); - CREATE_REQUEST_PROMISE(); - stickers_manager_->get_default_emoji_statuses(false, std::move(promise)); -} - -void Td::on_request(uint64 id, const td_api::getThemedChatEmojiStatuses &request) { - CHECK_IS_USER(); - CREATE_REQUEST_PROMISE(); - stickers_manager_->get_default_channel_emoji_statuses(false, std::move(promise)); -} - -void Td::on_request(uint64 id, const td_api::getDefaultEmojiStatuses &request) { - CHECK_IS_USER(); - CREATE_REQUEST_PROMISE(); - get_default_emoji_statuses(this, std::move(promise)); -} - -void Td::on_request(uint64 id, const td_api::getDefaultChatEmojiStatuses &request) { - CHECK_IS_USER(); - CREATE_REQUEST_PROMISE(); - get_default_channel_emoji_statuses(this, std::move(promise)); -} - -void Td::on_request(uint64 id, const td_api::getRecentEmojiStatuses &request) { - CHECK_IS_USER(); - CREATE_REQUEST_PROMISE(); - get_recent_emoji_statuses(this, std::move(promise)); -} - -void Td::on_request(uint64 id, const td_api::clearRecentEmojiStatuses &request) { - CHECK_IS_USER(); - CREATE_OK_REQUEST_PROMISE(); - clear_recent_emoji_statuses(this, std::move(promise)); -} - -void Td::on_request(uint64 id, td_api::setCommands &request) { - CHECK_IS_BOT(); - CREATE_OK_REQUEST_PROMISE(); - set_commands(this, std::move(request.scope_), std::move(request.language_code_), std::move(request.commands_), - std::move(promise)); -} - -void Td::on_request(uint64 id, td_api::deleteCommands &request) { - CHECK_IS_BOT(); - CREATE_OK_REQUEST_PROMISE(); - delete_commands(this, std::move(request.scope_), std::move(request.language_code_), std::move(promise)); -} - -void Td::on_request(uint64 id, td_api::getCommands &request) { - CHECK_IS_BOT(); - CREATE_REQUEST_PROMISE(); - get_commands(this, std::move(request.scope_), std::move(request.language_code_), std::move(promise)); -} - -void Td::on_request(uint64 id, td_api::setMenuButton &request) { - CHECK_IS_BOT(); - CREATE_OK_REQUEST_PROMISE(); - set_menu_button(this, UserId(request.user_id_), std::move(request.menu_button_), std::move(promise)); -} - -void Td::on_request(uint64 id, const td_api::getMenuButton &request) { - CHECK_IS_BOT(); - CREATE_REQUEST_PROMISE(); - get_menu_button(this, UserId(request.user_id_), std::move(promise)); -} - -void Td::on_request(uint64 id, const td_api::setDefaultGroupAdministratorRights &request) { - CHECK_IS_BOT(); - CREATE_OK_REQUEST_PROMISE(); - bot_info_manager_->set_default_group_administrator_rights( - AdministratorRights(request.default_group_administrator_rights_, ChannelType::Megagroup), std::move(promise)); -} - -void Td::on_request(uint64 id, const td_api::setDefaultChannelAdministratorRights &request) { - CHECK_IS_BOT(); - CREATE_OK_REQUEST_PROMISE(); - bot_info_manager_->set_default_channel_administrator_rights( - AdministratorRights(request.default_channel_administrator_rights_, ChannelType::Broadcast), std::move(promise)); -} - -void Td::on_request(uint64 id, const td_api::canBotSendMessages &request) { - CHECK_IS_USER(); - CREATE_OK_REQUEST_PROMISE(); - bot_info_manager_->can_bot_send_messages(UserId(request.bot_user_id_), std::move(promise)); -} - -void Td::on_request(uint64 id, const td_api::allowBotToSendMessages &request) { - CHECK_IS_USER(); - CREATE_OK_REQUEST_PROMISE(); - bot_info_manager_->allow_bot_to_send_messages(UserId(request.bot_user_id_), std::move(promise)); -} - -void Td::on_request(uint64 id, td_api::sendWebAppCustomRequest &request) { - CHECK_IS_USER(); - CLEAN_INPUT_STRING(request.method_); - CLEAN_INPUT_STRING(request.parameters_); - CREATE_REQUEST_PROMISE(); - attach_menu_manager_->invoke_web_view_custom_method(UserId(request.bot_user_id_), request.method_, - request.parameters_, std::move(promise)); -} - -void Td::on_request(uint64 id, const td_api::getBotMediaPreviews &request) { - CHECK_IS_USER(); - CREATE_REQUEST_PROMISE(); - bot_info_manager_->get_bot_media_previews(UserId(request.bot_user_id_), std::move(promise)); -} - -void Td::on_request(uint64 id, const td_api::getBotMediaPreviewInfo &request) { - CHECK_IS_USER(); - CREATE_REQUEST_PROMISE(); - bot_info_manager_->get_bot_media_preview_info(UserId(request.bot_user_id_), request.language_code_, - std::move(promise)); -} - -void Td::on_request(uint64 id, td_api::addBotMediaPreview &request) { - CHECK_IS_USER(); - CREATE_REQUEST_PROMISE(); - bot_info_manager_->add_bot_media_preview(UserId(request.bot_user_id_), request.language_code_, - std::move(request.content_), std::move(promise)); -} - -void Td::on_request(uint64 id, td_api::editBotMediaPreview &request) { - CHECK_IS_USER(); - CREATE_REQUEST_PROMISE(); - bot_info_manager_->edit_bot_media_preview(UserId(request.bot_user_id_), request.language_code_, - FileId(request.file_id_, 0), std::move(request.content_), - std::move(promise)); -} - -void Td::on_request(uint64 id, const td_api::reorderBotMediaPreviews &request) { - CHECK_IS_USER(); - CREATE_OK_REQUEST_PROMISE(); - bot_info_manager_->reorder_bot_media_previews(UserId(request.bot_user_id_), request.language_code_, request.file_ids_, - std::move(promise)); -} - -void Td::on_request(uint64 id, const td_api::deleteBotMediaPreviews &request) { - CHECK_IS_USER(); - CREATE_OK_REQUEST_PROMISE(); - bot_info_manager_->delete_bot_media_previews(UserId(request.bot_user_id_), request.language_code_, request.file_ids_, - std::move(promise)); -} - -void Td::on_request(uint64 id, td_api::setBotName &request) { - CLEAN_INPUT_STRING(request.name_); - CREATE_OK_REQUEST_PROMISE(); - bot_info_manager_->set_bot_name(UserId(request.bot_user_id_), request.language_code_, request.name_, - std::move(promise)); -} - -void Td::on_request(uint64 id, const td_api::getBotName &request) { - CREATE_REQUEST_PROMISE(); - auto query_promise = PromiseCreator::lambda([promise = std::move(promise)](Result result) mutable { - if (result.is_error()) { - promise.set_error(result.move_as_error()); - } else { - promise.set_value(td_api::make_object(result.move_as_ok())); - } - }); - bot_info_manager_->get_bot_name(UserId(request.bot_user_id_), request.language_code_, std::move(query_promise)); -} - -void Td::on_request(uint64 id, td_api::setBotProfilePhoto &request) { - CREATE_OK_REQUEST_PROMISE(); - user_manager_->set_bot_profile_photo(UserId(request.bot_user_id_), request.photo_, std::move(promise)); -} - -void Td::on_request(uint64 id, td_api::toggleBotUsernameIsActive &request) { - CHECK_IS_USER(); - CLEAN_INPUT_STRING(request.username_); - CREATE_OK_REQUEST_PROMISE(); - user_manager_->toggle_bot_username_is_active(UserId(request.bot_user_id_), std::move(request.username_), - request.is_active_, std::move(promise)); -} - -void Td::on_request(uint64 id, td_api::reorderBotActiveUsernames &request) { - CHECK_IS_USER(); - for (auto &username : request.usernames_) { - CLEAN_INPUT_STRING(username); - } - CREATE_OK_REQUEST_PROMISE(); - user_manager_->reorder_bot_usernames(UserId(request.bot_user_id_), std::move(request.usernames_), std::move(promise)); -} - -void Td::on_request(uint64 id, td_api::setBotInfoDescription &request) { - CLEAN_INPUT_STRING(request.description_); - CREATE_OK_REQUEST_PROMISE(); - bot_info_manager_->set_bot_info_description(UserId(request.bot_user_id_), request.language_code_, - request.description_, std::move(promise)); -} - -void Td::on_request(uint64 id, const td_api::getBotInfoDescription &request) { - CREATE_REQUEST_PROMISE(); - auto query_promise = PromiseCreator::lambda([promise = std::move(promise)](Result result) mutable { - if (result.is_error()) { - promise.set_error(result.move_as_error()); - } else { - promise.set_value(td_api::make_object(result.move_as_ok())); - } - }); - bot_info_manager_->get_bot_info_description(UserId(request.bot_user_id_), request.language_code_, - std::move(query_promise)); -} - -void Td::on_request(uint64 id, td_api::setBotInfoShortDescription &request) { - CLEAN_INPUT_STRING(request.short_description_); - CREATE_OK_REQUEST_PROMISE(); - bot_info_manager_->set_bot_info_about(UserId(request.bot_user_id_), request.language_code_, - request.short_description_, std::move(promise)); -} - -void Td::on_request(uint64 id, const td_api::getBotInfoShortDescription &request) { - CREATE_REQUEST_PROMISE(); - auto query_promise = PromiseCreator::lambda([promise = std::move(promise)](Result result) mutable { - if (result.is_error()) { - promise.set_error(result.move_as_error()); - } else { - promise.set_value(td_api::make_object(result.move_as_ok())); - } - }); - bot_info_manager_->get_bot_info_about(UserId(request.bot_user_id_), request.language_code_, std::move(query_promise)); -} - -void Td::on_request(uint64 id, const td_api::setLocation &request) { - CHECK_IS_USER(); - CREATE_OK_REQUEST_PROMISE(); - people_nearby_manager_->set_location(Location(request.location_), std::move(promise)); -} - -void Td::on_request(uint64 id, td_api::setBusinessLocation &request) { - CHECK_IS_USER(); - CREATE_OK_REQUEST_PROMISE(); - business_manager_->set_business_location(DialogLocation(std::move(request.location_)), std::move(promise)); -} - -void Td::on_request(uint64 id, td_api::setBusinessOpeningHours &request) { - CHECK_IS_USER(); - CREATE_OK_REQUEST_PROMISE(); - business_manager_->set_business_work_hours(BusinessWorkHours(std::move(request.opening_hours_)), std::move(promise)); -} - -void Td::on_request(uint64 id, td_api::setBusinessGreetingMessageSettings &request) { - CHECK_IS_USER(); - CREATE_OK_REQUEST_PROMISE(); - business_manager_->set_business_greeting_message( - BusinessGreetingMessage(std::move(request.greeting_message_settings_)), std::move(promise)); -} - -void Td::on_request(uint64 id, td_api::setBusinessAwayMessageSettings &request) { - CHECK_IS_USER(); - CREATE_OK_REQUEST_PROMISE(); - business_manager_->set_business_away_message(BusinessAwayMessage(std::move(request.away_message_settings_)), - std::move(promise)); -} - -void Td::on_request(uint64 id, td_api::setBusinessStartPage &request) { - CHECK_IS_USER(); - CREATE_OK_REQUEST_PROMISE(); - business_manager_->set_business_intro(BusinessIntro(this, std::move(request.start_page_)), std::move(promise)); -} - -void Td::on_request(uint64 id, td_api::setProfilePhoto &request) { - CHECK_IS_USER(); - CREATE_OK_REQUEST_PROMISE(); - user_manager_->set_profile_photo(request.photo_, request.is_public_, std::move(promise)); -} - -void Td::on_request(uint64 id, const td_api::deleteProfilePhoto &request) { - CHECK_IS_USER(); - CREATE_OK_REQUEST_PROMISE(); - user_manager_->delete_profile_photo(request.profile_photo_id_, false, std::move(promise)); -} - -void Td::on_request(uint64 id, const td_api::getUserProfilePhotos &request) { - CREATE_REQUEST_PROMISE(); - user_manager_->get_user_profile_photos(UserId(request.user_id_), request.offset_, request.limit_, std::move(promise)); -} - -void Td::on_request(uint64 id, const td_api::setAccentColor &request) { - CHECK_IS_USER(); - CREATE_OK_REQUEST_PROMISE(); - user_manager_->set_accent_color(AccentColorId(request.accent_color_id_), - CustomEmojiId(request.background_custom_emoji_id_), std::move(promise)); -} - -void Td::on_request(uint64 id, const td_api::setProfileAccentColor &request) { - CHECK_IS_USER(); - CREATE_OK_REQUEST_PROMISE(); - user_manager_->set_profile_accent_color(AccentColorId(request.profile_accent_color_id_), - CustomEmojiId(request.profile_background_custom_emoji_id_), - std::move(promise)); -} - -void Td::on_request(uint64 id, const td_api::getBusinessConnectedBot &request) { - CHECK_IS_USER(); - CREATE_REQUEST_PROMISE(); - business_manager_->get_business_connected_bot(std::move(promise)); -} - -void Td::on_request(uint64 id, td_api::setBusinessConnectedBot &request) { - CHECK_IS_USER(); - CREATE_OK_REQUEST_PROMISE(); - business_manager_->set_business_connected_bot(std::move(request.bot_), std::move(promise)); -} - -void Td::on_request(uint64 id, const td_api::deleteBusinessConnectedBot &request) { - CHECK_IS_USER(); - CREATE_OK_REQUEST_PROMISE(); - business_manager_->delete_business_connected_bot(UserId(request.bot_user_id_), std::move(promise)); -} - -void Td::on_request(uint64 id, const td_api::toggleBusinessConnectedBotChatIsPaused &request) { - CHECK_IS_USER(); - CREATE_OK_REQUEST_PROMISE(); - business_manager_->toggle_business_connected_bot_dialog_is_paused(DialogId(request.chat_id_), request.is_paused_, - std::move(promise)); -} - -void Td::on_request(uint64 id, const td_api::removeBusinessConnectedBotFromChat &request) { - CHECK_IS_USER(); - CREATE_OK_REQUEST_PROMISE(); - business_manager_->remove_business_connected_bot_from_dialog(DialogId(request.chat_id_), std::move(promise)); -} - -void Td::on_request(uint64 id, const td_api::getBusinessChatLinks &request) { - CHECK_IS_USER(); - CREATE_REQUEST_PROMISE(); - business_manager_->get_business_chat_links(std::move(promise)); -} - -void Td::on_request(uint64 id, td_api::createBusinessChatLink &request) { - CHECK_IS_USER(); - CREATE_REQUEST_PROMISE(); - business_manager_->create_business_chat_link(std::move(request.link_info_), std::move(promise)); -} - -void Td::on_request(uint64 id, td_api::editBusinessChatLink &request) { - CHECK_IS_USER(); - CLEAN_INPUT_STRING(request.link_); - CREATE_REQUEST_PROMISE(); - business_manager_->edit_business_chat_link(request.link_, std::move(request.link_info_), std::move(promise)); -} - -void Td::on_request(uint64 id, td_api::deleteBusinessChatLink &request) { - CHECK_IS_USER(); - CLEAN_INPUT_STRING(request.link_); - CREATE_OK_REQUEST_PROMISE(); - business_manager_->delete_business_chat_link(request.link_, std::move(promise)); -} - -void Td::on_request(uint64 id, td_api::getBusinessChatLinkInfo &request) { - CHECK_IS_USER(); - CLEAN_INPUT_STRING(request.link_name_); - CREATE_REQUEST_PROMISE(); - business_manager_->get_business_chat_link_info(request.link_name_, std::move(promise)); -} - -void Td::on_request(uint64 id, td_api::setSupergroupUsername &request) { - CHECK_IS_USER(); - CLEAN_INPUT_STRING(request.username_); - CREATE_OK_REQUEST_PROMISE(); - chat_manager_->set_channel_username(ChannelId(request.supergroup_id_), request.username_, std::move(promise)); -} - -void Td::on_request(uint64 id, td_api::toggleSupergroupUsernameIsActive &request) { - CHECK_IS_USER(); - CLEAN_INPUT_STRING(request.username_); - CREATE_OK_REQUEST_PROMISE(); - chat_manager_->toggle_channel_username_is_active(ChannelId(request.supergroup_id_), std::move(request.username_), - request.is_active_, std::move(promise)); -} - -void Td::on_request(uint64 id, const td_api::disableAllSupergroupUsernames &request) { - CHECK_IS_USER(); - CREATE_OK_REQUEST_PROMISE(); - chat_manager_->disable_all_channel_usernames(ChannelId(request.supergroup_id_), std::move(promise)); -} - -void Td::on_request(uint64 id, td_api::reorderSupergroupActiveUsernames &request) { - CHECK_IS_USER(); - for (auto &username : request.usernames_) { - CLEAN_INPUT_STRING(username); - } - CREATE_OK_REQUEST_PROMISE(); - chat_manager_->reorder_channel_usernames(ChannelId(request.supergroup_id_), std::move(request.usernames_), - std::move(promise)); -} - -void Td::on_request(uint64 id, const td_api::setSupergroupStickerSet &request) { - CREATE_OK_REQUEST_PROMISE(); - chat_manager_->set_channel_sticker_set(ChannelId(request.supergroup_id_), StickerSetId(request.sticker_set_id_), - std::move(promise)); -} - -void Td::on_request(uint64 id, const td_api::setSupergroupCustomEmojiStickerSet &request) { - CREATE_OK_REQUEST_PROMISE(); - chat_manager_->set_channel_emoji_sticker_set(ChannelId(request.supergroup_id_), - StickerSetId(request.custom_emoji_sticker_set_id_), std::move(promise)); -} - -void Td::on_request(uint64 id, const td_api::setSupergroupUnrestrictBoostCount &request) { - CREATE_OK_REQUEST_PROMISE(); - chat_manager_->set_channel_unrestrict_boost_count(ChannelId(request.supergroup_id_), request.unrestrict_boost_count_, - std::move(promise)); -} - -void Td::on_request(uint64 id, const td_api::toggleSupergroupSignMessages &request) { - CHECK_IS_USER(); - CREATE_OK_REQUEST_PROMISE(); - chat_manager_->toggle_channel_sign_messages(ChannelId(request.supergroup_id_), request.sign_messages_, - request.show_message_sender_, std::move(promise)); -} - -void Td::on_request(uint64 id, const td_api::toggleSupergroupJoinToSendMessages &request) { - CHECK_IS_USER(); - CREATE_OK_REQUEST_PROMISE(); - chat_manager_->toggle_channel_join_to_send(ChannelId(request.supergroup_id_), request.join_to_send_messages_, - std::move(promise)); -} - -void Td::on_request(uint64 id, const td_api::toggleSupergroupJoinByRequest &request) { - CHECK_IS_USER(); - CREATE_OK_REQUEST_PROMISE(); - chat_manager_->toggle_channel_join_request(ChannelId(request.supergroup_id_), request.join_by_request_, - std::move(promise)); -} - -void Td::on_request(uint64 id, const td_api::toggleSupergroupIsAllHistoryAvailable &request) { - CHECK_IS_USER(); - CREATE_OK_REQUEST_PROMISE(); - chat_manager_->toggle_channel_is_all_history_available(ChannelId(request.supergroup_id_), - request.is_all_history_available_, std::move(promise)); -} - -void Td::on_request(uint64 id, const td_api::toggleSupergroupCanHaveSponsoredMessages &request) { - CHECK_IS_USER(); - CREATE_OK_REQUEST_PROMISE(); - chat_manager_->toggle_channel_can_have_sponsored_messages(ChannelId(request.supergroup_id_), - request.can_have_sponsored_messages_, std::move(promise)); -} - -void Td::on_request(uint64 id, const td_api::toggleSupergroupHasHiddenMembers &request) { - CHECK_IS_USER(); - CREATE_OK_REQUEST_PROMISE(); - chat_manager_->toggle_channel_has_hidden_participants(ChannelId(request.supergroup_id_), request.has_hidden_members_, - std::move(promise)); -} - -void Td::on_request(uint64 id, const td_api::toggleSupergroupHasAggressiveAntiSpamEnabled &request) { - CHECK_IS_USER(); - CREATE_OK_REQUEST_PROMISE(); - chat_manager_->toggle_channel_has_aggressive_anti_spam_enabled( - ChannelId(request.supergroup_id_), request.has_aggressive_anti_spam_enabled_, std::move(promise)); -} - -void Td::on_request(uint64 id, const td_api::toggleSupergroupIsForum &request) { - CHECK_IS_USER(); - CREATE_OK_REQUEST_PROMISE(); - chat_manager_->toggle_channel_is_forum(ChannelId(request.supergroup_id_), request.is_forum_, std::move(promise)); -} - -void Td::on_request(uint64 id, const td_api::toggleSupergroupIsBroadcastGroup &request) { - CHECK_IS_USER(); - CREATE_OK_REQUEST_PROMISE(); - chat_manager_->convert_channel_to_gigagroup(ChannelId(request.supergroup_id_), std::move(promise)); -} - -void Td::on_request(uint64 id, const td_api::reportSupergroupSpam &request) { - CHECK_IS_USER(); - CREATE_OK_REQUEST_PROMISE(); - chat_manager_->report_channel_spam(ChannelId(request.supergroup_id_), - MessageId::get_message_ids(request.message_ids_), std::move(promise)); -} - -void Td::on_request(uint64 id, const td_api::reportSupergroupAntiSpamFalsePositive &request) { - CHECK_IS_USER(); - CREATE_OK_REQUEST_PROMISE(); - chat_manager_->report_channel_anti_spam_false_positive(ChannelId(request.supergroup_id_), - MessageId(request.message_id_), std::move(promise)); -} - -void Td::on_request(uint64 id, td_api::getSupergroupMembers &request) { - CREATE_REQUEST_PROMISE(); - auto query_promise = - PromiseCreator::lambda([promise = std::move(promise), td = this](Result result) mutable { - if (result.is_error()) { - promise.set_error(result.move_as_error()); - } else { - promise.set_value(result.ok().get_chat_members_object(td, "getSupergroupMembers")); - } - }); - dialog_participant_manager_->get_channel_participants(ChannelId(request.supergroup_id_), std::move(request.filter_), - string(), request.offset_, request.limit_, -1, - std::move(query_promise)); -} - -void Td::on_request(uint64 id, td_api::closeSecretChat &request) { - CREATE_OK_REQUEST_PROMISE(); - send_closure(secret_chats_manager_, &SecretChatsManager::cancel_chat, SecretChatId(request.secret_chat_id_), false, - std::move(promise)); -} - -void Td::on_request(uint64 id, td_api::getStickers &request) { - CHECK_IS_USER(); - CLEAN_INPUT_STRING(request.query_); - CREATE_REQUEST(GetStickersRequest, get_sticker_type(request.sticker_type_), std::move(request.query_), request.limit_, - request.chat_id_); -} - -void Td::on_request(uint64 id, td_api::getAllStickerEmojis &request) { - CHECK_IS_USER(); - CLEAN_INPUT_STRING(request.query_); - CREATE_REQUEST(GetAllStickerEmojisRequest, get_sticker_type(request.sticker_type_), std::move(request.query_), - request.chat_id_, request.return_only_main_emoji_); -} - -void Td::on_request(uint64 id, td_api::searchStickers &request) { - CHECK_IS_USER(); - CLEAN_INPUT_STRING(request.emojis_); - CREATE_REQUEST_PROMISE(); - auto sticker_type = get_sticker_type(request.sticker_type_); - if (sticker_type == StickerType::Regular) { - // legacy - if (request.emojis_ == "⭐️⭐️") { - request.emojis_ = "⭐️"; - } else if (request.emojis_ == "📂⭐️") { - request.emojis_ = "📂"; - } else if (request.emojis_ == "👋⭐️") { - request.emojis_ = "👋"; - } - } - stickers_manager_->search_stickers(sticker_type, std::move(request.emojis_), request.limit_, std::move(promise)); -} - -void Td::on_request(uint64 id, const td_api::getGreetingStickers &request) { - CHECK_IS_USER(); - CREATE_REQUEST_PROMISE(); - stickers_manager_->search_stickers(StickerType::Regular, "👋⭐️", 100, std::move(promise)); -} - -void Td::on_request(uint64 id, const td_api::getPremiumStickers &request) { - CHECK_IS_USER(); - CREATE_REQUEST_PROMISE(); - stickers_manager_->get_premium_stickers(request.limit_, std::move(promise)); -} - -void Td::on_request(uint64 id, const td_api::getInstalledStickerSets &request) { - CHECK_IS_USER(); - CREATE_REQUEST(GetInstalledStickerSetsRequest, get_sticker_type(request.sticker_type_)); -} - -void Td::on_request(uint64 id, const td_api::getArchivedStickerSets &request) { - CHECK_IS_USER(); - CREATE_REQUEST(GetArchivedStickerSetsRequest, get_sticker_type(request.sticker_type_), request.offset_sticker_set_id_, - request.limit_); -} - -void Td::on_request(uint64 id, const td_api::getTrendingStickerSets &request) { - CHECK_IS_USER(); - CREATE_REQUEST(GetTrendingStickerSetsRequest, get_sticker_type(request.sticker_type_), request.offset_, - request.limit_); -} - -void Td::on_request(uint64 id, const td_api::getAttachedStickerSets &request) { - CHECK_IS_USER(); - CREATE_REQUEST(GetAttachedStickerSetsRequest, request.file_id_); -} - -void Td::on_request(uint64 id, const td_api::getStickerSet &request) { - CREATE_REQUEST(GetStickerSetRequest, request.set_id_); -} - -void Td::on_request(uint64 id, td_api::searchStickerSet &request) { - CLEAN_INPUT_STRING(request.name_); - CREATE_REQUEST(SearchStickerSetRequest, std::move(request.name_)); -} - -void Td::on_request(uint64 id, td_api::searchInstalledStickerSets &request) { - CLEAN_INPUT_STRING(request.query_); - CREATE_REQUEST(SearchInstalledStickerSetsRequest, get_sticker_type(request.sticker_type_), std::move(request.query_), - request.limit_); -} - -void Td::on_request(uint64 id, td_api::searchStickerSets &request) { - CLEAN_INPUT_STRING(request.query_); - CREATE_REQUEST(SearchStickerSetsRequest, get_sticker_type(request.sticker_type_), std::move(request.query_)); -} - -void Td::on_request(uint64 id, const td_api::changeStickerSet &request) { - CHECK_IS_USER(); - CREATE_REQUEST(ChangeStickerSetRequest, request.set_id_, request.is_installed_, request.is_archived_); -} - -void Td::on_request(uint64 id, const td_api::viewTrendingStickerSets &request) { - CHECK_IS_USER(); - stickers_manager_->view_featured_sticker_sets(StickersManager::convert_sticker_set_ids(request.sticker_set_ids_)); - send_closure(actor_id(this), &Td::send_result, id, make_tl_object()); -} - -void Td::on_request(uint64 id, td_api::reorderInstalledStickerSets &request) { - CHECK_IS_USER(); - CREATE_OK_REQUEST_PROMISE(); - stickers_manager_->reorder_installed_sticker_sets(get_sticker_type(request.sticker_type_), - StickersManager::convert_sticker_set_ids(request.sticker_set_ids_), - std::move(promise)); -} - -void Td::on_request(uint64 id, td_api::uploadStickerFile &request) { - CREATE_REQUEST(UploadStickerFileRequest, request.user_id_, get_sticker_format(request.sticker_format_), - std::move(request.sticker_)); -} - -void Td::on_request(uint64 id, td_api::getSuggestedStickerSetName &request) { - CLEAN_INPUT_STRING(request.title_); - CREATE_REQUEST_PROMISE(); - auto query_promise = PromiseCreator::lambda([promise = std::move(promise)](Result result) mutable { - if (result.is_error()) { - promise.set_error(result.move_as_error()); - } else { - promise.set_value(make_tl_object(result.move_as_ok())); - } - }); - stickers_manager_->get_suggested_sticker_set_name(std::move(request.title_), std::move(query_promise)); -} - -void Td::on_request(uint64 id, td_api::checkStickerSetName &request) { - CLEAN_INPUT_STRING(request.name_); - CREATE_REQUEST_PROMISE(); - auto query_promise = PromiseCreator::lambda( - [promise = std::move(promise)](Result result) mutable { - if (result.is_error()) { - promise.set_error(result.move_as_error()); - } else { - promise.set_value(StickersManager::get_check_sticker_set_name_result_object(result.ok())); - } - }); - stickers_manager_->check_sticker_set_name(request.name_, std::move(query_promise)); -} - -void Td::on_request(uint64 id, td_api::createNewStickerSet &request) { - CLEAN_INPUT_STRING(request.title_); - CLEAN_INPUT_STRING(request.name_); - CLEAN_INPUT_STRING(request.source_); - CREATE_REQUEST_PROMISE(); - stickers_manager_->create_new_sticker_set(UserId(request.user_id_), std::move(request.title_), - std::move(request.name_), get_sticker_type(request.sticker_type_), - request.needs_repainting_, std::move(request.stickers_), - std::move(request.source_), std::move(promise)); -} - -void Td::on_request(uint64 id, td_api::addStickerToSet &request) { - CLEAN_INPUT_STRING(request.name_); - CREATE_OK_REQUEST_PROMISE(); - stickers_manager_->add_sticker_to_set(UserId(request.user_id_), std::move(request.name_), std::move(request.sticker_), - nullptr, std::move(promise)); -} - -void Td::on_request(uint64 id, td_api::replaceStickerInSet &request) { - CLEAN_INPUT_STRING(request.name_); - if (request.old_sticker_ == nullptr) { - return send_error_raw(id, 400, "Old sticker must be non-empty"); - } - CREATE_OK_REQUEST_PROMISE(); - stickers_manager_->add_sticker_to_set(UserId(request.user_id_), std::move(request.name_), - std::move(request.new_sticker_), std::move(request.old_sticker_), - std::move(promise)); -} - -void Td::on_request(uint64 id, td_api::setStickerSetThumbnail &request) { - CLEAN_INPUT_STRING(request.name_); - CREATE_OK_REQUEST_PROMISE(); - stickers_manager_->set_sticker_set_thumbnail(UserId(request.user_id_), std::move(request.name_), - std::move(request.thumbnail_), get_sticker_format(request.format_), - std::move(promise)); -} - -void Td::on_request(uint64 id, td_api::setCustomEmojiStickerSetThumbnail &request) { - CLEAN_INPUT_STRING(request.name_); - CREATE_OK_REQUEST_PROMISE(); - stickers_manager_->set_custom_emoji_sticker_set_thumbnail( - std::move(request.name_), CustomEmojiId(request.custom_emoji_id_), std::move(promise)); -} - -void Td::on_request(uint64 id, td_api::setStickerSetTitle &request) { - CLEAN_INPUT_STRING(request.name_); - CLEAN_INPUT_STRING(request.title_); - CREATE_OK_REQUEST_PROMISE(); - stickers_manager_->set_sticker_set_title(std::move(request.name_), std::move(request.title_), std::move(promise)); -} - -void Td::on_request(uint64 id, td_api::deleteStickerSet &request) { - CLEAN_INPUT_STRING(request.name_); - CREATE_OK_REQUEST_PROMISE(); - stickers_manager_->delete_sticker_set(std::move(request.name_), std::move(promise)); -} - -void Td::on_request(uint64 id, td_api::setStickerPositionInSet &request) { - CREATE_OK_REQUEST_PROMISE(); - stickers_manager_->set_sticker_position_in_set(request.sticker_, request.position_, std::move(promise)); -} - -void Td::on_request(uint64 id, const td_api::removeStickerFromSet &request) { - CREATE_OK_REQUEST_PROMISE(); - stickers_manager_->remove_sticker_from_set(request.sticker_, std::move(promise)); -} - -void Td::on_request(uint64 id, td_api::setStickerEmojis &request) { - CLEAN_INPUT_STRING(request.emojis_); - CREATE_OK_REQUEST_PROMISE(); - stickers_manager_->set_sticker_emojis(request.sticker_, request.emojis_, std::move(promise)); -} - -void Td::on_request(uint64 id, td_api::setStickerKeywords &request) { - for (auto &keyword : request.keywords_) { - CLEAN_INPUT_STRING(keyword); - } - CREATE_OK_REQUEST_PROMISE(); - stickers_manager_->set_sticker_keywords(request.sticker_, std::move(request.keywords_), std::move(promise)); -} - -void Td::on_request(uint64 id, td_api::setStickerMaskPosition &request) { - CREATE_OK_REQUEST_PROMISE(); - stickers_manager_->set_sticker_mask_position(request.sticker_, std::move(request.mask_position_), std::move(promise)); -} - -void Td::on_request(uint64 id, const td_api::getOwnedStickerSets &request) { - CHECK_IS_USER(); - CREATE_REQUEST_PROMISE(); - stickers_manager_->get_created_sticker_sets(StickerSetId(request.offset_sticker_set_id_), request.limit_, - std::move(promise)); -} - -void Td::on_request(uint64 id, const td_api::getRecentStickers &request) { - CHECK_IS_USER(); - CREATE_REQUEST(GetRecentStickersRequest, request.is_attached_); -} - -void Td::on_request(uint64 id, td_api::addRecentSticker &request) { - CHECK_IS_USER(); - CREATE_REQUEST(AddRecentStickerRequest, request.is_attached_, std::move(request.sticker_)); -} - -void Td::on_request(uint64 id, td_api::removeRecentSticker &request) { - CHECK_IS_USER(); - CREATE_REQUEST(RemoveRecentStickerRequest, request.is_attached_, std::move(request.sticker_)); -} - -void Td::on_request(uint64 id, td_api::clearRecentStickers &request) { - CHECK_IS_USER(); - CREATE_REQUEST(ClearRecentStickersRequest, request.is_attached_); -} - -void Td::on_request(uint64 id, const td_api::getFavoriteStickers &request) { - CHECK_IS_USER(); - CREATE_NO_ARGS_REQUEST(GetFavoriteStickersRequest); -} - -void Td::on_request(uint64 id, td_api::addFavoriteSticker &request) { - CHECK_IS_USER(); - CREATE_REQUEST(AddFavoriteStickerRequest, std::move(request.sticker_)); -} - -void Td::on_request(uint64 id, td_api::removeFavoriteSticker &request) { - CHECK_IS_USER(); - CREATE_REQUEST(RemoveFavoriteStickerRequest, std::move(request.sticker_)); -} - -void Td::on_request(uint64 id, td_api::getStickerEmojis &request) { - CHECK_IS_USER(); - CREATE_REQUEST(GetStickerEmojisRequest, std::move(request.sticker_)); -} - -void Td::on_request(uint64 id, td_api::searchEmojis &request) { - CHECK_IS_USER(); - CLEAN_INPUT_STRING(request.text_); - for (auto &input_language_code : request.input_language_codes_) { - CLEAN_INPUT_STRING(input_language_code); - } - CREATE_REQUEST(SearchEmojisRequest, std::move(request.text_), std::move(request.input_language_codes_)); -} - -void Td::on_request(uint64 id, td_api::getKeywordEmojis &request) { - CHECK_IS_USER(); - CLEAN_INPUT_STRING(request.text_); - for (auto &input_language_code : request.input_language_codes_) { - CLEAN_INPUT_STRING(input_language_code); - } - CREATE_REQUEST(GetKeywordEmojisRequest, std::move(request.text_), std::move(request.input_language_codes_)); -} - -void Td::on_request(uint64 id, const td_api::getEmojiCategories &request) { - CHECK_IS_USER(); - CREATE_REQUEST_PROMISE(); - stickers_manager_->get_emoji_groups(get_emoji_group_type(request.type_), std::move(promise)); -} - -void Td::on_request(uint64 id, td_api::getAnimatedEmoji &request) { - CHECK_IS_USER(); - CLEAN_INPUT_STRING(request.emoji_); - CREATE_REQUEST_PROMISE(); - stickers_manager_->get_animated_emoji(std::move(request.emoji_), false, std::move(promise)); -} - -void Td::on_request(uint64 id, td_api::getEmojiSuggestionsUrl &request) { - CHECK_IS_USER(); - CLEAN_INPUT_STRING(request.language_code_); - CREATE_REQUEST(GetEmojiSuggestionsUrlRequest, std::move(request.language_code_)); -} - -void Td::on_request(uint64 id, const td_api::getCustomEmojiStickers &request) { - CREATE_REQUEST_PROMISE(); - stickers_manager_->get_custom_emoji_stickers(CustomEmojiId::get_custom_emoji_ids(request.custom_emoji_ids_), true, - std::move(promise)); -} - -void Td::on_request(uint64 id, const td_api::getDefaultChatPhotoCustomEmojiStickers &request) { - CHECK_IS_USER(); - CREATE_REQUEST_PROMISE(); - stickers_manager_->get_default_custom_emoji_stickers(StickerListType::DialogPhoto, false, std::move(promise)); -} - -void Td::on_request(uint64 id, const td_api::getDefaultProfilePhotoCustomEmojiStickers &request) { - CHECK_IS_USER(); - CREATE_REQUEST_PROMISE(); - stickers_manager_->get_default_custom_emoji_stickers(StickerListType::UserProfilePhoto, false, std::move(promise)); -} - -void Td::on_request(uint64 id, const td_api::getDefaultBackgroundCustomEmojiStickers &request) { - CHECK_IS_USER(); - CREATE_REQUEST_PROMISE(); - stickers_manager_->get_default_custom_emoji_stickers(StickerListType::Background, false, std::move(promise)); -} - -void Td::on_request(uint64 id, const td_api::getDisallowedChatEmojiStatuses &request) { - CHECK_IS_USER(); - CREATE_REQUEST_PROMISE(); - stickers_manager_->get_sticker_list_emoji_statuses(StickerListType::DisallowedChannelEmojiStatus, false, - std::move(promise)); -} - -void Td::on_request(uint64 id, const td_api::getSavedAnimations &request) { - CHECK_IS_USER(); - CREATE_NO_ARGS_REQUEST(GetSavedAnimationsRequest); -} - -void Td::on_request(uint64 id, td_api::addSavedAnimation &request) { - CHECK_IS_USER(); - CREATE_REQUEST(AddSavedAnimationRequest, std::move(request.animation_)); -} - -void Td::on_request(uint64 id, td_api::removeSavedAnimation &request) { - CHECK_IS_USER(); - CREATE_REQUEST(RemoveSavedAnimationRequest, std::move(request.animation_)); -} - -void Td::on_request(uint64 id, const td_api::getSavedNotificationSound &request) { - CHECK_IS_USER(); - CREATE_REQUEST(GetSavedNotificationSoundRequest, request.notification_sound_id_); -} - -void Td::on_request(uint64 id, const td_api::getSavedNotificationSounds &request) { - CHECK_IS_USER(); - CREATE_NO_ARGS_REQUEST(GetSavedNotificationSoundsRequest); -} - -void Td::on_request(uint64 id, td_api::addSavedNotificationSound &request) { - CHECK_IS_USER(); - CREATE_REQUEST_PROMISE(); - notification_settings_manager_->add_saved_ringtone(std::move(request.sound_), std::move(promise)); -} - -void Td::on_request(uint64 id, const td_api::removeSavedNotificationSound &request) { - CHECK_IS_USER(); - CREATE_REQUEST(RemoveSavedNotificationSoundRequest, request.notification_sound_id_); -} - -void Td::on_request(uint64 id, const td_api::getChatNotificationSettingsExceptions &request) { - CHECK_IS_USER(); - bool filter_scope = false; - NotificationSettingsScope scope = NotificationSettingsScope::Private; - if (request.scope_ != nullptr) { - filter_scope = true; - scope = get_notification_settings_scope(request.scope_); - } - CREATE_REQUEST(GetChatNotificationSettingsExceptionsRequest, scope, filter_scope, request.compare_sound_); -} - -void Td::on_request(uint64 id, const td_api::getScopeNotificationSettings &request) { - CHECK_IS_USER(); - if (request.scope_ == nullptr) { - return send_error_raw(id, 400, "Scope must be non-empty"); - } - CREATE_REQUEST(GetScopeNotificationSettingsRequest, get_notification_settings_scope(request.scope_)); -} - -void Td::on_request(uint64 id, const td_api::removeChatActionBar &request) { - CHECK_IS_USER(); - CREATE_OK_REQUEST_PROMISE(); - messages_manager_->remove_dialog_action_bar(DialogId(request.chat_id_), std::move(promise)); -} - -void Td::on_request(uint64 id, td_api::reportChat &request) { - CHECK_IS_USER(); - auto r_report_reason = ReportReason::get_report_reason(std::move(request.reason_), std::move(request.text_)); - if (r_report_reason.is_error()) { - return send_error_raw(id, r_report_reason.error().code(), r_report_reason.error().message()); - } - CREATE_OK_REQUEST_PROMISE(); - dialog_manager_->report_dialog(DialogId(request.chat_id_), MessageId::get_message_ids(request.message_ids_), - r_report_reason.move_as_ok(), std::move(promise)); -} - -void Td::on_request(uint64 id, td_api::reportChatPhoto &request) { - CHECK_IS_USER(); - auto r_report_reason = ReportReason::get_report_reason(std::move(request.reason_), std::move(request.text_)); - if (r_report_reason.is_error()) { - return send_error_raw(id, r_report_reason.error().code(), r_report_reason.error().message()); - } - CREATE_OK_REQUEST_PROMISE(); - dialog_manager_->report_dialog_photo(DialogId(request.chat_id_), FileId(request.file_id_, 0), - r_report_reason.move_as_ok(), std::move(promise)); -} - -void Td::on_request(uint64 id, const td_api::reportMessageReactions &request) { - CHECK_IS_USER(); - CREATE_OK_REQUEST_PROMISE(); - TRY_RESULT_PROMISE(promise, sender_dialog_id, get_message_sender_dialog_id(this, request.sender_id_, false, false)); - report_message_reactions(this, {DialogId(request.chat_id_), MessageId(request.message_id_)}, sender_dialog_id, - std::move(promise)); -} - -void Td::on_request(uint64 id, const td_api::getChatStatistics &request) { - CHECK_IS_USER(); - CREATE_REQUEST_PROMISE(); - statistics_manager_->get_channel_statistics(DialogId(request.chat_id_), request.is_dark_, std::move(promise)); -} - -void Td::on_request(uint64 id, const td_api::getChatRevenueStatistics &request) { - CHECK_IS_USER(); - CREATE_REQUEST_PROMISE(); - statistics_manager_->get_channel_revenue_statistics(DialogId(request.chat_id_), request.is_dark_, std::move(promise)); -} - -void Td::on_request(uint64 id, const td_api::getChatRevenueWithdrawalUrl &request) { - CHECK_IS_USER(); - CREATE_REQUEST_PROMISE(); - auto query_promise = PromiseCreator::lambda([promise = std::move(promise)](Result result) mutable { - if (result.is_error()) { - promise.set_error(result.move_as_error()); - } else { - promise.set_value(td_api::make_object(result.move_as_ok())); - } - }); - statistics_manager_->get_channel_revenue_withdrawal_url(DialogId(request.chat_id_), request.password_, - std::move(query_promise)); -} - -void Td::on_request(uint64 id, const td_api::getChatRevenueTransactions &request) { - CHECK_IS_USER(); - CREATE_REQUEST_PROMISE(); - statistics_manager_->get_channel_revenue_transactions(DialogId(request.chat_id_), request.offset_, request.limit_, - std::move(promise)); -} - -void Td::on_request(uint64 id, const td_api::getStarRevenueStatistics &request) { - CHECK_IS_USER(); - CREATE_REQUEST_PROMISE(); - star_manager_->get_star_revenue_statistics(request.owner_id_, request.is_dark_, std::move(promise)); -} - -void Td::on_request(uint64 id, const td_api::getStarWithdrawalUrl &request) { - CHECK_IS_USER(); - CREATE_REQUEST_PROMISE(); - auto query_promise = PromiseCreator::lambda([promise = std::move(promise)](Result result) mutable { - if (result.is_error()) { - promise.set_error(result.move_as_error()); - } else { - promise.set_value(td_api::make_object(result.move_as_ok())); - } - }); - star_manager_->get_star_withdrawal_url(request.owner_id_, request.star_count_, request.password_, - std::move(query_promise)); -} - -void Td::on_request(uint64 id, const td_api::getStarAdAccountUrl &request) { - CHECK_IS_USER(); - CREATE_REQUEST_PROMISE(); - auto query_promise = PromiseCreator::lambda([promise = std::move(promise)](Result result) mutable { - if (result.is_error()) { - promise.set_error(result.move_as_error()); - } else { - promise.set_value(td_api::make_object(result.move_as_ok())); - } - }); - star_manager_->get_star_ad_account_url(request.owner_id_, std::move(query_promise)); -} - -void Td::on_request(uint64 id, const td_api::getMessageStatistics &request) { - CHECK_IS_USER(); - CREATE_REQUEST_PROMISE(); - statistics_manager_->get_channel_message_statistics({DialogId(request.chat_id_), MessageId(request.message_id_)}, - request.is_dark_, std::move(promise)); -} - -void Td::on_request(uint64 id, const td_api::getStoryStatistics &request) { - CHECK_IS_USER(); - CREATE_REQUEST_PROMISE(); - statistics_manager_->get_channel_story_statistics({DialogId(request.chat_id_), StoryId(request.story_id_)}, - request.is_dark_, std::move(promise)); -} - -void Td::on_request(uint64 id, td_api::getStatisticalGraph &request) { - CHECK_IS_USER(); - CLEAN_INPUT_STRING(request.token_); - CREATE_REQUEST_PROMISE(); - statistics_manager_->load_statistics_graph(DialogId(request.chat_id_), std::move(request.token_), request.x_, - std::move(promise)); -} - -void Td::on_request(uint64 id, td_api::setChatNotificationSettings &request) { - CHECK_IS_USER(); - answer_ok_query(id, messages_manager_->set_dialog_notification_settings(DialogId(request.chat_id_), - std::move(request.notification_settings_))); -} - -void Td::on_request(uint64 id, td_api::setForumTopicNotificationSettings &request) { - CHECK_IS_USER(); - answer_ok_query(id, forum_topic_manager_->set_forum_topic_notification_settings( - DialogId(request.chat_id_), MessageId(request.message_thread_id_), - std::move(request.notification_settings_))); -} - -void Td::on_request(uint64 id, td_api::setScopeNotificationSettings &request) { - CHECK_IS_USER(); - if (request.scope_ == nullptr) { - return send_error_raw(id, 400, "Scope must be non-empty"); - } - answer_ok_query(id, notification_settings_manager_->set_scope_notification_settings( - get_notification_settings_scope(request.scope_), std::move(request.notification_settings_))); -} - -void Td::on_request(uint64 id, td_api::setReactionNotificationSettings &request) { - CHECK_IS_USER(); - answer_ok_query(id, notification_settings_manager_->set_reaction_notification_settings( - ReactionNotificationSettings(std::move(request.notification_settings_)))); -} - -void Td::on_request(uint64 id, const td_api::resetAllNotificationSettings &request) { - CHECK_IS_USER(); - messages_manager_->reset_all_notification_settings(); - send_closure(actor_id(this), &Td::send_result, id, make_tl_object()); -} - -void Td::on_request(uint64 id, const td_api::getMapThumbnailFile &request) { - DialogId dialog_id(request.chat_id_); - if (!dialog_manager_->have_dialog_force(dialog_id, "getMapThumbnailFile")) { - dialog_id = DialogId(); - } - - auto r_file_id = file_manager_->get_map_thumbnail_file_id(Location(request.location_), request.zoom_, request.width_, - request.height_, request.scale_, dialog_id); - if (r_file_id.is_error()) { - send_closure(actor_id(this), &Td::send_error, id, r_file_id.move_as_error()); - } else { - send_closure(actor_id(this), &Td::send_result, id, file_manager_->get_file_object(r_file_id.ok())); - } -} - -void Td::on_request(uint64 id, const td_api::getLocalizationTargetInfo &request) { - CHECK_IS_USER(); - CREATE_REQUEST_PROMISE(); - send_closure(language_pack_manager_, &LanguagePackManager::get_languages, request.only_local_, std::move(promise)); -} - -void Td::on_request(uint64 id, td_api::getLanguagePackInfo &request) { - CHECK_IS_USER(); - CLEAN_INPUT_STRING(request.language_pack_id_); - CREATE_REQUEST_PROMISE(); - send_closure(language_pack_manager_, &LanguagePackManager::search_language_info, request.language_pack_id_, - std::move(promise)); -} - -void Td::on_request(uint64 id, td_api::getLanguagePackStrings &request) { - CHECK_IS_USER(); - CLEAN_INPUT_STRING(request.language_pack_id_); - for (auto &key : request.keys_) { - CLEAN_INPUT_STRING(key); - } - CREATE_REQUEST_PROMISE(); - send_closure(language_pack_manager_, &LanguagePackManager::get_language_pack_strings, - std::move(request.language_pack_id_), std::move(request.keys_), std::move(promise)); -} - -void Td::on_request(uint64 id, td_api::synchronizeLanguagePack &request) { - CHECK_IS_USER(); - CLEAN_INPUT_STRING(request.language_pack_id_); - CREATE_OK_REQUEST_PROMISE(); - send_closure(language_pack_manager_, &LanguagePackManager::synchronize_language_pack, - std::move(request.language_pack_id_), std::move(promise)); -} - -void Td::on_request(uint64 id, td_api::addCustomServerLanguagePack &request) { - CHECK_IS_USER(); - CLEAN_INPUT_STRING(request.language_pack_id_); - CREATE_OK_REQUEST_PROMISE(); - send_closure(language_pack_manager_, &LanguagePackManager::add_custom_server_language, - std::move(request.language_pack_id_), std::move(promise)); -} - -void Td::on_request(uint64 id, td_api::setCustomLanguagePack &request) { - CHECK_IS_USER(); - CREATE_OK_REQUEST_PROMISE(); - send_closure(language_pack_manager_, &LanguagePackManager::set_custom_language, std::move(request.info_), - std::move(request.strings_), std::move(promise)); -} - -void Td::on_request(uint64 id, td_api::editCustomLanguagePackInfo &request) { - CHECK_IS_USER(); - CREATE_OK_REQUEST_PROMISE(); - send_closure(language_pack_manager_, &LanguagePackManager::edit_custom_language_info, std::move(request.info_), - std::move(promise)); -} - -void Td::on_request(uint64 id, td_api::setCustomLanguagePackString &request) { - CHECK_IS_USER(); - CLEAN_INPUT_STRING(request.language_pack_id_); - CREATE_OK_REQUEST_PROMISE(); - send_closure(language_pack_manager_, &LanguagePackManager::set_custom_language_string, - std::move(request.language_pack_id_), std::move(request.new_string_), std::move(promise)); -} - -void Td::on_request(uint64 id, td_api::deleteLanguagePack &request) { - CHECK_IS_USER(); - CLEAN_INPUT_STRING(request.language_pack_id_); - CREATE_OK_REQUEST_PROMISE(); - send_closure(language_pack_manager_, &LanguagePackManager::delete_language, std::move(request.language_pack_id_), - std::move(promise)); -} - -void Td::on_request(uint64 id, td_api::getOption &request) { - CLEAN_INPUT_STRING(request.name_); - CREATE_REQUEST_PROMISE(); - option_manager_->get_option(request.name_, std::move(promise)); -} - -void Td::on_request(uint64 id, td_api::setOption &request) { - CLEAN_INPUT_STRING(request.name_); - CREATE_OK_REQUEST_PROMISE(); - option_manager_->set_option(request.name_, std::move(request.value_), std::move(promise)); -} - -void Td::on_request(uint64 id, td_api::setPollAnswer &request) { - CHECK_IS_USER(); - CREATE_OK_REQUEST_PROMISE(); - messages_manager_->set_poll_answer({DialogId(request.chat_id_), MessageId(request.message_id_)}, - std::move(request.option_ids_), std::move(promise)); -} - -void Td::on_request(uint64 id, td_api::getPollVoters &request) { - CHECK_IS_USER(); - CREATE_REQUEST_PROMISE(); - messages_manager_->get_poll_voters({DialogId(request.chat_id_), MessageId(request.message_id_)}, request.option_id_, - request.offset_, request.limit_, std::move(promise)); -} - -void Td::on_request(uint64 id, td_api::stopPoll &request) { - CREATE_OK_REQUEST_PROMISE(); - messages_manager_->stop_poll({DialogId(request.chat_id_), MessageId(request.message_id_)}, - std::move(request.reply_markup_), std::move(promise)); -} - -void Td::on_request(uint64 id, const td_api::hideSuggestedAction &request) { - CHECK_IS_USER(); - CREATE_OK_REQUEST_PROMISE(); - dismiss_suggested_action(SuggestedAction(request.action_), std::move(promise)); -} - -void Td::on_request(uint64 id, const td_api::hideContactCloseBirthdays &request) { - CHECK_IS_USER(); - CREATE_OK_REQUEST_PROMISE(); - option_manager_->set_option_boolean("dismiss_birthday_contact_today", true); - user_manager_->hide_contact_birthdays(std::move(promise)); -} - -void Td::on_request(uint64 id, td_api::getBusinessConnection &request) { - CHECK_IS_BOT(); - CLEAN_INPUT_STRING(request.connection_id_); - CREATE_REQUEST_PROMISE(); - business_connection_manager_->get_business_connection(BusinessConnectionId(std::move(request.connection_id_)), - std::move(promise)); -} - -void Td::on_request(uint64 id, const td_api::getLoginUrlInfo &request) { - CHECK_IS_USER(); - CREATE_REQUEST_PROMISE(); - link_manager_->get_login_url_info({DialogId(request.chat_id_), MessageId(request.message_id_)}, request.button_id_, - std::move(promise)); -} - -void Td::on_request(uint64 id, const td_api::getLoginUrl &request) { - CHECK_IS_USER(); - CREATE_REQUEST_PROMISE(); - link_manager_->get_login_url({DialogId(request.chat_id_), MessageId(request.message_id_)}, request.button_id_, - request.allow_write_access_, std::move(promise)); -} - -void Td::on_request(uint64 id, const td_api::shareUsersWithBot &request) { - CHECK_IS_USER(); - CREATE_OK_REQUEST_PROMISE(); - auto user_ids = UserId::get_user_ids(request.shared_user_ids_); - auto dialog_ids = transform(user_ids, [](UserId user_id) { return DialogId(user_id); }); - messages_manager_->share_dialogs_with_bot({DialogId(request.chat_id_), MessageId(request.message_id_)}, - request.button_id_, std::move(dialog_ids), true, request.only_check_, - std::move(promise)); -} - -void Td::on_request(uint64 id, const td_api::shareChatWithBot &request) { - CHECK_IS_USER(); - CREATE_OK_REQUEST_PROMISE(); - messages_manager_->share_dialogs_with_bot({DialogId(request.chat_id_), MessageId(request.message_id_)}, - request.button_id_, {DialogId(request.shared_chat_id_)}, false, - request.only_check_, std::move(promise)); -} - -void Td::on_request(uint64 id, td_api::getInlineQueryResults &request) { - CHECK_IS_USER(); - CLEAN_INPUT_STRING(request.query_); - CLEAN_INPUT_STRING(request.offset_); - CREATE_REQUEST_PROMISE(); - inline_queries_manager_->send_inline_query(UserId(request.bot_user_id_), DialogId(request.chat_id_), - Location(request.user_location_), request.query_, request.offset_, - std::move(promise)); -} - -void Td::on_request(uint64 id, td_api::answerInlineQuery &request) { - CHECK_IS_BOT(); - CLEAN_INPUT_STRING(request.next_offset_); - CREATE_OK_REQUEST_PROMISE(); - inline_queries_manager_->answer_inline_query(request.inline_query_id_, request.is_personal_, - std::move(request.button_), std::move(request.results_), - request.cache_time_, request.next_offset_, std::move(promise)); -} - -void Td::on_request(uint64 id, td_api::getPopularWebAppBots &request) { - CHECK_IS_USER(); - CLEAN_INPUT_STRING(request.offset_); - CREATE_REQUEST_PROMISE(); - attach_menu_manager_->get_popular_app_bots(request.offset_, request.limit_, std::move(promise)); -} - -void Td::on_request(uint64 id, td_api::searchWebApp &request) { - CHECK_IS_USER(); - CLEAN_INPUT_STRING(request.web_app_short_name_); - CREATE_REQUEST_PROMISE(); - attach_menu_manager_->get_web_app(UserId(request.bot_user_id_), request.web_app_short_name_, std::move(promise)); -} - -void Td::on_request(uint64 id, td_api::getWebAppLinkUrl &request) { - CHECK_IS_USER(); - CLEAN_INPUT_STRING(request.web_app_short_name_); - CLEAN_INPUT_STRING(request.start_parameter_); - CLEAN_INPUT_STRING(request.application_name_); - CREATE_REQUEST_PROMISE(); - auto query_promise = PromiseCreator::lambda([promise = std::move(promise)](Result result) mutable { - if (result.is_error()) { - promise.set_error(result.move_as_error()); - } else { - promise.set_value(td_api::make_object(result.move_as_ok())); - } - }); - attach_menu_manager_->request_app_web_view( - DialogId(request.chat_id_), UserId(request.bot_user_id_), std::move(request.web_app_short_name_), - std::move(request.start_parameter_), std::move(request.theme_), std::move(request.application_name_), - request.allow_write_access_, std::move(query_promise)); -} - -void Td::on_request(uint64 id, td_api::getMainWebApp &request) { - CHECK_IS_USER(); - CLEAN_INPUT_STRING(request.start_parameter_); - CLEAN_INPUT_STRING(request.application_name_); - CREATE_REQUEST_PROMISE(); - attach_menu_manager_->request_main_web_view(DialogId(request.chat_id_), UserId(request.bot_user_id_), - std::move(request.start_parameter_), std::move(request.theme_), - std::move(request.application_name_), std::move(promise)); -} - -void Td::on_request(uint64 id, td_api::getWebAppUrl &request) { - CHECK_IS_USER(); - CLEAN_INPUT_STRING(request.url_); - CLEAN_INPUT_STRING(request.application_name_); - CREATE_REQUEST_PROMISE(); - auto query_promise = PromiseCreator::lambda([promise = std::move(promise)](Result result) mutable { - if (result.is_error()) { - promise.set_error(result.move_as_error()); - } else { - promise.set_value(td_api::make_object(result.move_as_ok())); - } - }); - inline_queries_manager_->get_simple_web_view_url(UserId(request.bot_user_id_), std::move(request.url_), - std::move(request.theme_), std::move(request.application_name_), - std::move(query_promise)); -} - -void Td::on_request(uint64 id, td_api::sendWebAppData &request) { - CHECK_IS_USER(); - CLEAN_INPUT_STRING(request.button_text_); - CLEAN_INPUT_STRING(request.data_); - CREATE_OK_REQUEST_PROMISE(); - inline_queries_manager_->send_web_view_data(UserId(request.bot_user_id_), std::move(request.button_text_), - std::move(request.data_), std::move(promise)); -} - -void Td::on_request(uint64 id, td_api::openWebApp &request) { - CHECK_IS_USER(); - CLEAN_INPUT_STRING(request.url_); - CLEAN_INPUT_STRING(request.application_name_); - CREATE_REQUEST_PROMISE(); - attach_menu_manager_->request_web_view(DialogId(request.chat_id_), UserId(request.bot_user_id_), - MessageId(request.message_thread_id_), std::move(request.reply_to_), - std::move(request.url_), std::move(request.theme_), - std::move(request.application_name_), std::move(promise)); -} - -void Td::on_request(uint64 id, const td_api::closeWebApp &request) { - CHECK_IS_USER(); - CREATE_OK_REQUEST_PROMISE(); - attach_menu_manager_->close_web_view(request.web_app_launch_id_, std::move(promise)); -} - -void Td::on_request(uint64 id, td_api::answerWebAppQuery &request) { - CHECK_IS_BOT(); - CLEAN_INPUT_STRING(request.web_app_query_id_); - CREATE_REQUEST_PROMISE(); - inline_queries_manager_->answer_web_view_query(request.web_app_query_id_, std::move(request.result_), - std::move(promise)); -} - -void Td::on_request(uint64 id, td_api::getCallbackQueryAnswer &request) { - CHECK_IS_USER(); - CREATE_REQUEST_PROMISE(); - callback_queries_manager_->send_callback_query({DialogId(request.chat_id_), MessageId(request.message_id_)}, - std::move(request.payload_), std::move(promise)); -} - -void Td::on_request(uint64 id, td_api::answerCallbackQuery &request) { - CHECK_IS_BOT(); - CLEAN_INPUT_STRING(request.text_); - CLEAN_INPUT_STRING(request.url_); - CREATE_OK_REQUEST_PROMISE(); - callback_queries_manager_->answer_callback_query(request.callback_query_id_, request.text_, request.show_alert_, - request.url_, request.cache_time_, std::move(promise)); -} - -void Td::on_request(uint64 id, td_api::answerShippingQuery &request) { - CHECK_IS_BOT(); - CLEAN_INPUT_STRING(request.error_message_); - CREATE_OK_REQUEST_PROMISE(); - answer_shipping_query(this, request.shipping_query_id_, std::move(request.shipping_options_), request.error_message_, - std::move(promise)); -} - -void Td::on_request(uint64 id, td_api::answerPreCheckoutQuery &request) { - CHECK_IS_BOT(); - CLEAN_INPUT_STRING(request.error_message_); - CREATE_OK_REQUEST_PROMISE(); - answer_pre_checkout_query(this, request.pre_checkout_query_id_, request.error_message_, std::move(promise)); -} - -void Td::on_request(uint64 id, td_api::getBankCardInfo &request) { - CHECK_IS_USER(); - CLEAN_INPUT_STRING(request.bank_card_number_); - CREATE_REQUEST_PROMISE(); - get_bank_card_info(this, request.bank_card_number_, std::move(promise)); -} - -void Td::on_request(uint64 id, td_api::getPaymentForm &request) { - CHECK_IS_USER(); - CREATE_REQUEST_PROMISE(); - get_payment_form(this, std::move(request.input_invoice_), request.theme_, std::move(promise)); -} - -void Td::on_request(uint64 id, td_api::validateOrderInfo &request) { - CHECK_IS_USER(); - CREATE_REQUEST_PROMISE(); - validate_order_info(this, std::move(request.input_invoice_), std::move(request.order_info_), request.allow_save_, - std::move(promise)); -} - -void Td::on_request(uint64 id, td_api::sendPaymentForm &request) { - CHECK_IS_USER(); - CLEAN_INPUT_STRING(request.order_info_id_); - CLEAN_INPUT_STRING(request.shipping_option_id_); - CREATE_REQUEST_PROMISE(); - send_payment_form(this, std::move(request.input_invoice_), request.payment_form_id_, request.order_info_id_, - request.shipping_option_id_, request.credentials_, request.tip_amount_, std::move(promise)); -} - -void Td::on_request(uint64 id, const td_api::getPaymentReceipt &request) { - CHECK_IS_USER(); - CREATE_REQUEST_PROMISE(); - get_payment_receipt(this, {DialogId(request.chat_id_), MessageId(request.message_id_)}, std::move(promise)); -} - -void Td::on_request(uint64 id, const td_api::getSavedOrderInfo &request) { - CHECK_IS_USER(); - CREATE_REQUEST_PROMISE(); - get_saved_order_info(this, std::move(promise)); -} - -void Td::on_request(uint64 id, const td_api::deleteSavedOrderInfo &request) { - CHECK_IS_USER(); - CREATE_OK_REQUEST_PROMISE(); - delete_saved_order_info(this, std::move(promise)); -} - -void Td::on_request(uint64 id, const td_api::deleteSavedCredentials &request) { - CHECK_IS_USER(); - CREATE_OK_REQUEST_PROMISE(); - delete_saved_credentials(this, std::move(promise)); -} - -void Td::on_request(uint64 id, td_api::createInvoiceLink &request) { - CHECK_IS_BOT(); - CREATE_REQUEST_PROMISE(); - auto query_promise = PromiseCreator::lambda([promise = std::move(promise)](Result result) mutable { - if (result.is_error()) { - promise.set_error(result.move_as_error()); - } else { - promise.set_value(td_api::make_object(result.move_as_ok())); - } - }); - export_invoice(this, std::move(request.invoice_), std::move(query_promise)); -} - -void Td::on_request(uint64 id, td_api::refundStarPayment &request) { - CHECK_IS_BOT(); - CLEAN_INPUT_STRING(request.telegram_payment_charge_id_); - CREATE_OK_REQUEST_PROMISE(); - star_manager_->refund_star_payment(UserId(request.user_id_), request.telegram_payment_charge_id_, std::move(promise)); -} - -void Td::on_request(uint64 id, td_api::getPassportElement &request) { - CHECK_IS_USER(); - CLEAN_INPUT_STRING(request.password_); - if (request.type_ == nullptr) { - return send_error_raw(id, 400, "Type must be non-empty"); - } - CREATE_REQUEST_PROMISE(); - send_closure(secure_manager_, &SecureManager::get_secure_value, std::move(request.password_), - get_secure_value_type_td_api(request.type_), std::move(promise)); -} - -void Td::on_request(uint64 id, td_api::getAllPassportElements &request) { - CHECK_IS_USER(); - CLEAN_INPUT_STRING(request.password_); - CREATE_REQUEST_PROMISE(); - send_closure(secure_manager_, &SecureManager::get_all_secure_values, std::move(request.password_), - std::move(promise)); -} - -void Td::on_request(uint64 id, td_api::setPassportElement &request) { - CHECK_IS_USER(); - CLEAN_INPUT_STRING(request.password_); - auto r_secure_value = get_secure_value(file_manager_.get(), std::move(request.element_)); - if (r_secure_value.is_error()) { - return send_error_raw(id, 400, r_secure_value.error().message()); - } - CREATE_REQUEST_PROMISE(); - send_closure(secure_manager_, &SecureManager::set_secure_value, std::move(request.password_), - r_secure_value.move_as_ok(), std::move(promise)); -} - -void Td::on_request(uint64 id, const td_api::deletePassportElement &request) { - CHECK_IS_USER(); - if (request.type_ == nullptr) { - return send_error_raw(id, 400, "Type must be non-empty"); - } - CREATE_OK_REQUEST_PROMISE(); - send_closure(secure_manager_, &SecureManager::delete_secure_value, get_secure_value_type_td_api(request.type_), - std::move(promise)); -} - -void Td::on_request(uint64 id, td_api::setPassportElementErrors &request) { - CHECK_IS_BOT(); - auto r_input_user = user_manager_->get_input_user(UserId(request.user_id_)); - if (r_input_user.is_error()) { - return send_error_raw(id, r_input_user.error().code(), r_input_user.error().message()); - } - CREATE_OK_REQUEST_PROMISE(); - send_closure(secure_manager_, &SecureManager::set_secure_value_errors, this, r_input_user.move_as_ok(), - std::move(request.errors_), std::move(promise)); -} - -void Td::on_request(uint64 id, td_api::getPreferredCountryLanguage &request) { - CHECK_IS_USER(); - CLEAN_INPUT_STRING(request.country_code_); - CREATE_REQUEST_PROMISE(); - send_closure(secure_manager_, &SecureManager::get_preferred_country_language, std::move(request.country_code_), - std::move(promise)); -} - -void Td::on_request(uint64 id, td_api::sendEmailAddressVerificationCode &request) { - CHECK_IS_USER(); - CLEAN_INPUT_STRING(request.email_address_); - CREATE_REQUEST_PROMISE(); - auto query_promise = PromiseCreator::lambda([promise = std::move(promise)](Result result) mutable { - if (result.is_error()) { - promise.set_error(result.move_as_error()); - } else { - promise.set_value(result.ok().get_email_address_authentication_code_info_object()); - } - }); - send_closure(password_manager_, &PasswordManager::send_email_address_verification_code, - std::move(request.email_address_), std::move(query_promise)); -} - -void Td::on_request(uint64 id, const td_api::resendEmailAddressVerificationCode &request) { - CHECK_IS_USER(); - CREATE_REQUEST_PROMISE(); - auto query_promise = PromiseCreator::lambda([promise = std::move(promise)](Result result) mutable { - if (result.is_error()) { - promise.set_error(result.move_as_error()); - } else { - promise.set_value(result.ok().get_email_address_authentication_code_info_object()); - } - }); - send_closure(password_manager_, &PasswordManager::resend_email_address_verification_code, std::move(query_promise)); -} - -void Td::on_request(uint64 id, td_api::checkEmailAddressVerificationCode &request) { - CHECK_IS_USER(); - CLEAN_INPUT_STRING(request.code_); - CREATE_OK_REQUEST_PROMISE(); - send_closure(password_manager_, &PasswordManager::check_email_address_verification_code, std::move(request.code_), - std::move(promise)); -} - -void Td::on_request(uint64 id, td_api::getPassportAuthorizationForm &request) { - CHECK_IS_USER(); - CLEAN_INPUT_STRING(request.public_key_); - CLEAN_INPUT_STRING(request.scope_); - CLEAN_INPUT_STRING(request.nonce_); - UserId bot_user_id(request.bot_user_id_); - if (!bot_user_id.is_valid()) { - return send_error_raw(id, 400, "Bot user identifier invalid"); - } - if (request.nonce_.empty()) { - return send_error_raw(id, 400, "Nonce must be non-empty"); - } - CREATE_REQUEST_PROMISE(); - send_closure(secure_manager_, &SecureManager::get_passport_authorization_form, bot_user_id, std::move(request.scope_), - std::move(request.public_key_), std::move(request.nonce_), std::move(promise)); -} - -void Td::on_request(uint64 id, td_api::getPassportAuthorizationFormAvailableElements &request) { - CHECK_IS_USER(); - CLEAN_INPUT_STRING(request.password_); - CREATE_REQUEST_PROMISE(); - send_closure(secure_manager_, &SecureManager::get_passport_authorization_form_available_elements, - request.authorization_form_id_, std::move(request.password_), std::move(promise)); -} - -void Td::on_request(uint64 id, td_api::sendPassportAuthorizationForm &request) { - CHECK_IS_USER(); - for (auto &type : request.types_) { - if (type == nullptr) { - return send_error_raw(id, 400, "Type must be non-empty"); - } - } - - CREATE_OK_REQUEST_PROMISE(); - send_closure(secure_manager_, &SecureManager::send_passport_authorization_form, request.authorization_form_id_, - get_secure_value_types_td_api(request.types_), std::move(promise)); -} - -void Td::on_request(uint64 id, const td_api::getSupportUser &request) { - CHECK_IS_USER(); - CREATE_REQUEST_PROMISE(); - user_manager_->get_support_user(std::move(promise)); -} - -void Td::on_request(uint64 id, const td_api::getInstalledBackgrounds &request) { - CHECK_IS_USER(); - CREATE_REQUEST_PROMISE(); - background_manager_->get_backgrounds(request.for_dark_theme_, std::move(promise)); -} - -void Td::on_request(uint64 id, td_api::getBackgroundUrl &request) { - CHECK_IS_USER(); - CLEAN_INPUT_STRING(request.name_); - Result r_url = LinkManager::get_background_url(request.name_, std::move(request.type_)); - if (r_url.is_error()) { - return send_closure(actor_id(this), &Td::send_error, id, r_url.move_as_error()); - } - - send_closure(actor_id(this), &Td::send_result, id, td_api::make_object(r_url.ok())); -} - -void Td::on_request(uint64 id, td_api::searchBackground &request) { - CHECK_IS_USER(); - CLEAN_INPUT_STRING(request.name_); - CREATE_REQUEST(SearchBackgroundRequest, std::move(request.name_)); -} - -void Td::on_request(uint64 id, td_api::setDefaultBackground &request) { - CHECK_IS_USER(); - CREATE_REQUEST_PROMISE(); - background_manager_->set_background(request.background_.get(), request.type_.get(), request.for_dark_theme_, - std::move(promise)); -} - -void Td::on_request(uint64 id, const td_api::deleteDefaultBackground &request) { - CHECK_IS_USER(); - CREATE_OK_REQUEST_PROMISE(); - background_manager_->delete_background(request.for_dark_theme_, std::move(promise)); -} - -void Td::on_request(uint64 id, const td_api::removeInstalledBackground &request) { - CHECK_IS_USER(); - CREATE_OK_REQUEST_PROMISE(); - background_manager_->remove_background(BackgroundId(request.background_id_), std::move(promise)); -} - -void Td::on_request(uint64 id, const td_api::resetInstalledBackgrounds &request) { - CHECK_IS_USER(); - CREATE_OK_REQUEST_PROMISE(); - background_manager_->reset_backgrounds(std::move(promise)); -} - -void Td::on_request(uint64 id, td_api::getRecentlyVisitedTMeUrls &request) { - CHECK_IS_USER(); - CLEAN_INPUT_STRING(request.referrer_); - CREATE_REQUEST_PROMISE(); - create_handler(std::move(promise))->send(request.referrer_); -} - -void Td::on_request(uint64 id, td_api::setBotUpdatesStatus &request) { - CHECK_IS_BOT(); - CLEAN_INPUT_STRING(request.error_message_); - create_handler()->send(request.pending_update_count_, request.error_message_); - send_closure(actor_id(this), &Td::send_result, id, make_tl_object()); -} - -void Td::on_request(uint64 id, td_api::sendCustomRequest &request) { - CHECK_IS_BOT(); - CLEAN_INPUT_STRING(request.method_); - CLEAN_INPUT_STRING(request.parameters_); - CREATE_REQUEST_PROMISE(); - create_handler(std::move(promise))->send(request.method_, request.parameters_); -} - -void Td::on_request(uint64 id, td_api::answerCustomQuery &request) { - CHECK_IS_BOT(); - CLEAN_INPUT_STRING(request.data_); - CREATE_OK_REQUEST_PROMISE(); - create_handler(std::move(promise))->send(request.custom_query_id_, request.data_); -} - -void Td::on_request(uint64 id, const td_api::setAlarm &request) { - if (request.seconds_ < 0 || request.seconds_ > 3e9) { - return send_error_raw(id, 400, "Wrong parameter seconds specified"); - } - - int64 alarm_id = alarm_id_++; - pending_alarms_.emplace(alarm_id, id); - alarm_timeout_.set_timeout_in(alarm_id, request.seconds_); -} - -void Td::on_request(uint64 id, td_api::searchHashtags &request) { - CHECK_IS_USER(); - CLEAN_INPUT_STRING(request.prefix_); - CREATE_REQUEST_PROMISE(); - auto query_promise = - PromiseCreator::lambda([promise = std::move(promise)](Result> result) mutable { - if (result.is_error()) { - promise.set_error(result.move_as_error()); - } else { - promise.set_value(make_tl_object(result.move_as_ok())); - } - }); - send_closure(hashtag_hints_, &HashtagHints::query, std::move(request.prefix_), request.limit_, - std::move(query_promise)); -} - -void Td::on_request(uint64 id, td_api::removeRecentHashtag &request) { - CHECK_IS_USER(); - CLEAN_INPUT_STRING(request.hashtag_); - CREATE_OK_REQUEST_PROMISE(); - send_closure(hashtag_hints_, &HashtagHints::remove_hashtag, std::move(request.hashtag_), std::move(promise)); -} - -void Td::on_request(uint64 id, const td_api::getPremiumLimit &request) { - CHECK_IS_USER(); - CREATE_REQUEST_PROMISE(); - get_premium_limit(request.limit_type_, std::move(promise)); -} - -void Td::on_request(uint64 id, const td_api::getPremiumFeatures &request) { - CHECK_IS_USER(); - CREATE_REQUEST_PROMISE(); - get_premium_features(this, request.source_, std::move(promise)); -} - -void Td::on_request(uint64 id, const td_api::getPremiumStickerExamples &request) { - CHECK_IS_USER(); - CREATE_REQUEST_PROMISE(); - stickers_manager_->search_stickers(StickerType::Regular, "⭐️⭐️", 100, std::move(promise)); -} - -void Td::on_request(uint64 id, const td_api::viewPremiumFeature &request) { - CHECK_IS_USER(); - CREATE_OK_REQUEST_PROMISE(); - view_premium_feature(this, request.feature_, std::move(promise)); -} - -void Td::on_request(uint64 id, const td_api::clickPremiumSubscriptionButton &request) { - CHECK_IS_USER(); - CREATE_OK_REQUEST_PROMISE(); - click_premium_subscription_button(this, std::move(promise)); -} - -void Td::on_request(uint64 id, const td_api::getPremiumState &request) { - CHECK_IS_USER(); - CREATE_REQUEST_PROMISE(); - get_premium_state(this, std::move(promise)); -} - -void Td::on_request(uint64 id, const td_api::getPremiumGiftCodePaymentOptions &request) { - CHECK_IS_USER(); - CREATE_REQUEST_PROMISE(); - get_premium_gift_code_options(this, DialogId(request.boosted_chat_id_), std::move(promise)); -} - -void Td::on_request(uint64 id, td_api::checkPremiumGiftCode &request) { - CHECK_IS_USER(); - CLEAN_INPUT_STRING(request.code_); - CREATE_REQUEST_PROMISE(); - check_premium_gift_code(this, request.code_, std::move(promise)); -} - -void Td::on_request(uint64 id, td_api::applyPremiumGiftCode &request) { - CHECK_IS_USER(); - CLEAN_INPUT_STRING(request.code_); - CREATE_OK_REQUEST_PROMISE(); - apply_premium_gift_code(this, request.code_, std::move(promise)); -} - -void Td::on_request(uint64 id, td_api::launchPrepaidPremiumGiveaway &request) { - CHECK_IS_USER(); - CREATE_OK_REQUEST_PROMISE(); - launch_prepaid_premium_giveaway(this, request.giveaway_id_, std::move(request.parameters_), std::move(promise)); -} - -void Td::on_request(uint64 id, const td_api::getPremiumGiveawayInfo &request) { - CHECK_IS_USER(); - CREATE_REQUEST_PROMISE(); - get_premium_giveaway_info(this, {DialogId(request.chat_id_), MessageId(request.message_id_)}, std::move(promise)); -} - -void Td::on_request(uint64 id, const td_api::getStarPaymentOptions &request) { - CHECK_IS_USER(); - CREATE_REQUEST_PROMISE(); - star_manager_->get_star_payment_options(std::move(promise)); -} - -void Td::on_request(uint64 id, const td_api::getStarGiftPaymentOptions &request) { - CHECK_IS_USER(); - CREATE_REQUEST_PROMISE(); - star_manager_->get_star_gift_payment_options(UserId(request.user_id_), std::move(promise)); -} - -void Td::on_request(uint64 id, td_api::getStarTransactions &request) { - CLEAN_INPUT_STRING(request.subscription_id_); - CLEAN_INPUT_STRING(request.offset_); - CREATE_REQUEST_PROMISE(); - star_manager_->get_star_transactions(std::move(request.owner_id_), request.subscription_id_, request.offset_, - request.limit_, std::move(request.direction_), std::move(promise)); -} - -void Td::on_request(uint64 id, td_api::getStarSubscriptions &request) { - CHECK_IS_USER(); - CLEAN_INPUT_STRING(request.offset_); - CREATE_REQUEST_PROMISE(); - star_manager_->get_star_subscriptions(request.only_expiring_, request.offset_, std::move(promise)); -} - -void Td::on_request(uint64 id, td_api::editStarSubscription &request) { - CHECK_IS_USER(); - CLEAN_INPUT_STRING(request.subscription_id_); - CREATE_OK_REQUEST_PROMISE(); - star_manager_->edit_star_subscriptions(request.subscription_id_, request.is_canceled_, std::move(promise)); -} - -void Td::on_request(uint64 id, td_api::reuseStarSubscription &request) { - CHECK_IS_USER(); - CLEAN_INPUT_STRING(request.subscription_id_); - CREATE_OK_REQUEST_PROMISE(); - star_manager_->reuse_star_subscriptions(request.subscription_id_, std::move(promise)); -} - -void Td::on_request(uint64 id, td_api::canPurchaseFromStore &request) { - CHECK_IS_USER(); - CREATE_OK_REQUEST_PROMISE(); - can_purchase_premium(this, std::move(request.purpose_), std::move(promise)); -} - -void Td::on_request(uint64 id, td_api::assignAppStoreTransaction &request) { - CHECK_IS_USER(); - CREATE_OK_REQUEST_PROMISE(); - assign_app_store_transaction(this, request.receipt_, std::move(request.purpose_), std::move(promise)); -} - -void Td::on_request(uint64 id, td_api::assignGooglePlayTransaction &request) { - CHECK_IS_USER(); - CLEAN_INPUT_STRING(request.package_name_); - CLEAN_INPUT_STRING(request.store_product_id_); - CLEAN_INPUT_STRING(request.purchase_token_); - CREATE_OK_REQUEST_PROMISE(); - assign_play_market_transaction(this, request.package_name_, request.store_product_id_, request.purchase_token_, - std::move(request.purpose_), std::move(promise)); -} - -void Td::on_request(uint64 id, const td_api::getBusinessFeatures &request) { - CHECK_IS_USER(); - CREATE_REQUEST_PROMISE(); - get_business_features(this, request.source_, std::move(promise)); -} - -void Td::on_request(uint64 id, td_api::acceptTermsOfService &request) { - CHECK_IS_USER(); - CLEAN_INPUT_STRING(request.terms_of_service_id_); - CREATE_OK_REQUEST_PROMISE(); - terms_of_service_manager_->accept_terms_of_service(std::move(request.terms_of_service_id_), std::move(promise)); -} - -void Td::on_request(uint64 id, const td_api::getCountries &request) { - CREATE_REQUEST_PROMISE(); - country_info_manager_->get_countries(std::move(promise)); -} - -void Td::on_request(uint64 id, const td_api::getCountryCode &request) { - CREATE_REQUEST_PROMISE(); - auto query_promise = PromiseCreator::lambda([promise = std::move(promise)](Result result) mutable { - if (result.is_error()) { - promise.set_error(result.move_as_error()); - } else { - promise.set_value(make_tl_object(result.move_as_ok())); - } - }); - country_info_manager_->get_current_country_code(std::move(query_promise)); +void Td::init_managers() { + account_manager_ = make_unique(this, create_reference()); + account_manager_actor_ = register_actor("AccountManager", account_manager_.get()); + G()->set_account_manager(account_manager_actor_.get()); + animations_manager_ = make_unique(this, create_reference()); + animations_manager_actor_ = register_actor("AnimationsManager", animations_manager_.get()); + G()->set_animations_manager(animations_manager_actor_.get()); + attach_menu_manager_ = make_unique(this, create_reference()); + attach_menu_manager_actor_ = register_actor("AttachMenuManager", attach_menu_manager_.get()); + G()->set_attach_menu_manager(attach_menu_manager_actor_.get()); + autosave_manager_ = make_unique(this, create_reference()); + autosave_manager_actor_ = register_actor("AutosaveManager", autosave_manager_.get()); + G()->set_autosave_manager(autosave_manager_actor_.get()); + background_manager_ = make_unique(this, create_reference()); + background_manager_actor_ = register_actor("BackgroundManager", background_manager_.get()); + G()->set_background_manager(background_manager_actor_.get()); + boost_manager_ = make_unique(this, create_reference()); + boost_manager_actor_ = register_actor("BoostManager", boost_manager_.get()); + G()->set_boost_manager(boost_manager_actor_.get()); + bot_info_manager_ = make_unique(this, create_reference()); + bot_info_manager_actor_ = register_actor("BotInfoManager", bot_info_manager_.get()); + G()->set_bot_info_manager(bot_info_manager_actor_.get()); + business_connection_manager_ = make_unique(this, create_reference()); + business_connection_manager_actor_ = register_actor("BusinessConnectionManager", business_connection_manager_.get()); + G()->set_business_connection_manager(business_connection_manager_actor_.get()); + business_manager_ = make_unique(this, create_reference()); + business_manager_actor_ = register_actor("BusinessManager", business_manager_.get()); + G()->set_business_manager(business_manager_actor_.get()); + channel_recommendation_manager_ = make_unique(this, create_reference()); + channel_recommendation_manager_actor_ = + register_actor("ChannelRecommendationManager", channel_recommendation_manager_.get()); + chat_manager_ = make_unique(this, create_reference()); + chat_manager_actor_ = register_actor("ChatManager", chat_manager_.get()); + G()->set_chat_manager(chat_manager_actor_.get()); + common_dialog_manager_ = make_unique(this, create_reference()); + common_dialog_manager_actor_ = register_actor("CommonDialogManager", common_dialog_manager_.get()); + connection_state_manager_ = make_unique(this, create_reference()); + connection_state_manager_actor_ = register_actor("ConnectionStateManager", connection_state_manager_.get()); + country_info_manager_ = make_unique(this, create_reference()); + country_info_manager_actor_ = register_actor("CountryInfoManager", country_info_manager_.get()); + dialog_action_manager_ = make_unique(this, create_reference()); + dialog_action_manager_actor_ = register_actor("DialogActionManager", dialog_action_manager_.get()); + G()->set_dialog_action_manager(dialog_action_manager_actor_.get()); + dialog_filter_manager_ = make_unique(this, create_reference()); + dialog_filter_manager_actor_ = register_actor("DialogFilterManager", dialog_filter_manager_.get()); + G()->set_dialog_filter_manager(dialog_filter_manager_actor_.get()); + dialog_invite_link_manager_ = make_unique(this, create_reference()); + dialog_invite_link_manager_actor_ = register_actor("DialogInviteLinkManager", dialog_invite_link_manager_.get()); + G()->set_dialog_invite_link_manager(dialog_invite_link_manager_actor_.get()); + dialog_manager_ = make_unique(this, create_reference()); + dialog_manager_actor_ = register_actor("DialogManager", dialog_manager_.get()); + G()->set_dialog_manager(dialog_manager_actor_.get()); + dialog_participant_manager_ = make_unique(this, create_reference()); + dialog_participant_manager_actor_ = register_actor("DialogParticipantManager", dialog_participant_manager_.get()); + G()->set_dialog_participant_manager(dialog_participant_manager_actor_.get()); + download_manager_ = DownloadManager::create(td::make_unique(this, create_reference())); + download_manager_actor_ = register_actor("DownloadManager", download_manager_.get()); + G()->set_download_manager(download_manager_actor_.get()); + forum_topic_manager_ = make_unique(this, create_reference()); + forum_topic_manager_actor_ = register_actor("ForumTopicManager", forum_topic_manager_.get()); + G()->set_forum_topic_manager(forum_topic_manager_actor_.get()); + game_manager_ = make_unique(this, create_reference()); + game_manager_actor_ = register_actor("GameManager", game_manager_.get()); + G()->set_game_manager(game_manager_actor_.get()); + group_call_manager_ = make_unique(this, create_reference()); + group_call_manager_actor_ = register_actor("GroupCallManager", group_call_manager_.get()); + G()->set_group_call_manager(group_call_manager_actor_.get()); + inline_message_manager_ = make_unique(this, create_reference()); + inline_message_manager_actor_ = register_actor("InlineMessageManager", inline_message_manager_.get()); + G()->set_inline_message_manager(inline_message_manager_actor_.get()); + inline_queries_manager_ = make_unique(this, create_reference()); + inline_queries_manager_actor_ = register_actor("InlineQueriesManager", inline_queries_manager_.get()); + link_manager_ = make_unique(this, create_reference()); + link_manager_actor_ = register_actor("LinkManager", link_manager_.get()); + G()->set_link_manager(link_manager_actor_.get()); + message_import_manager_ = make_unique(this, create_reference()); + message_import_manager_actor_ = register_actor("MessageImportManager", message_import_manager_.get()); + G()->set_message_import_manager(message_import_manager_actor_.get()); + messages_manager_ = make_unique(this, create_reference()); + messages_manager_actor_ = register_actor("MessagesManager", messages_manager_.get()); + G()->set_messages_manager(messages_manager_actor_.get()); + notification_manager_ = make_unique(this, create_reference()); + notification_manager_actor_ = register_actor("NotificationManager", notification_manager_.get()); + G()->set_notification_manager(notification_manager_actor_.get()); + notification_settings_manager_ = make_unique(this, create_reference()); + notification_settings_manager_actor_ = + register_actor("NotificationSettingsManager", notification_settings_manager_.get()); + G()->set_notification_settings_manager(notification_settings_manager_actor_.get()); + people_nearby_manager_ = make_unique(this, create_reference()); + people_nearby_manager_actor_ = register_actor("PeopleNearbyManager", people_nearby_manager_.get()); + G()->set_people_nearby_manager(people_nearby_manager_actor_.get()); + phone_number_manager_ = make_unique(this, create_reference()); + phone_number_manager_actor_ = register_actor("PhoneNumberManager", phone_number_manager_.get()); + poll_manager_ = make_unique(this, create_reference()); + poll_manager_actor_ = register_actor("PollManager", poll_manager_.get()); + privacy_manager_ = make_unique(this, create_reference()); + privacy_manager_actor_ = register_actor("PrivacyManager", privacy_manager_.get()); + promo_data_manager_ = make_unique(this, create_reference()); + promo_data_manager_actor_ = register_actor("PromoDataManager", promo_data_manager_.get()); + G()->set_promo_data_manager(promo_data_manager_actor_.get()); + quick_reply_manager_ = make_unique(this, create_reference()); + quick_reply_manager_actor_ = register_actor("QuickReplyManager", quick_reply_manager_.get()); + G()->set_quick_reply_manager(quick_reply_manager_actor_.get()); + reaction_manager_ = make_unique(this, create_reference()); + reaction_manager_actor_ = register_actor("ReactionManager", reaction_manager_.get()); + G()->set_reaction_manager(reaction_manager_actor_.get()); + saved_messages_manager_ = make_unique(this, create_reference()); + saved_messages_manager_actor_ = register_actor("SavedMessagesManager", saved_messages_manager_.get()); + G()->set_saved_messages_manager(saved_messages_manager_actor_.get()); + sponsored_message_manager_ = make_unique(this, create_reference()); + sponsored_message_manager_actor_ = register_actor("SponsoredMessageManager", sponsored_message_manager_.get()); + G()->set_sponsored_message_manager(sponsored_message_manager_actor_.get()); + star_manager_ = make_unique(this, create_reference()); + star_manager_actor_ = register_actor("StarManager", star_manager_.get()); + G()->set_star_manager(star_manager_actor_.get()); + statistics_manager_ = make_unique(this, create_reference()); + statistics_manager_actor_ = register_actor("StatisticsManager", statistics_manager_.get()); + stickers_manager_ = make_unique(this, create_reference()); + stickers_manager_actor_ = register_actor("StickersManager", stickers_manager_.get()); + G()->set_stickers_manager(stickers_manager_actor_.get()); + story_manager_ = make_unique(this, create_reference()); + story_manager_actor_ = register_actor("StoryManager", story_manager_.get()); + G()->set_story_manager(story_manager_actor_.get()); + terms_of_service_manager_ = make_unique(this, create_reference()); + terms_of_service_manager_actor_ = register_actor("TermsOfServiceManager", terms_of_service_manager_.get()); + theme_manager_ = make_unique(this, create_reference()); + theme_manager_actor_ = register_actor("ThemeManager", theme_manager_.get()); + G()->set_theme_manager(theme_manager_actor_.get()); + time_zone_manager_ = make_unique(this, create_reference()); + time_zone_manager_actor_ = register_actor("TimeZoneManager", time_zone_manager_.get()); + G()->set_time_zone_manager(time_zone_manager_actor_.get()); + top_dialog_manager_ = make_unique(this, create_reference()); + top_dialog_manager_actor_ = register_actor("TopDialogManager", top_dialog_manager_.get()); + G()->set_top_dialog_manager(top_dialog_manager_actor_.get()); + transcription_manager_ = make_unique(this, create_reference()); + transcription_manager_actor_ = register_actor("TranscriptionManager", transcription_manager_.get()); + G()->set_transcription_manager(transcription_manager_actor_.get()); + translation_manager_ = make_unique(this, create_reference()); + translation_manager_actor_ = register_actor("TranslationManager", translation_manager_.get()); + updates_manager_ = make_unique(this, create_reference()); + updates_manager_actor_ = register_actor("UpdatesManager", updates_manager_.get()); + G()->set_updates_manager(updates_manager_actor_.get()); + user_manager_ = make_unique(this, create_reference()); + user_manager_actor_ = register_actor("UserManager", user_manager_.get()); + G()->set_user_manager(user_manager_actor_.get()); + video_notes_manager_ = make_unique(this, create_reference()); + video_notes_manager_actor_ = register_actor("VideoNotesManager", video_notes_manager_.get()); + voice_notes_manager_ = make_unique(this, create_reference()); + voice_notes_manager_actor_ = register_actor("VoiceNotesManager", voice_notes_manager_.get()); + web_pages_manager_ = make_unique(this, create_reference()); + web_pages_manager_actor_ = register_actor("WebPagesManager", web_pages_manager_.get()); + G()->set_web_pages_manager(web_pages_manager_actor_.get()); } -void Td::on_request(uint64 id, const td_api::getPhoneNumberInfo &request) { - CREATE_REQUEST_PROMISE(); - country_info_manager_->get_phone_number_info(request.phone_number_prefix_, std::move(promise)); +void Td::init_pure_actor_managers() { + call_manager_ = create_actor("CallManager", create_reference()); + G()->set_call_manager(call_manager_.get()); + cashtag_search_hints_ = create_actor("CashtagSearchHints", "cashtag_search", '$', create_reference()); + device_token_manager_ = create_actor("DeviceTokenManager", create_reference()); + hashtag_hints_ = create_actor("HashtagHints", "text", '#', create_reference()); + hashtag_search_hints_ = create_actor("HashtagSearchHints", "search", '#', create_reference()); + language_pack_manager_ = create_actor("LanguagePackManager", create_reference()); + G()->set_language_pack_manager(language_pack_manager_.get()); + password_manager_ = create_actor("PasswordManager", create_reference()); + G()->set_password_manager(password_manager_.get()); + secure_manager_ = create_actor("SecureManager", create_reference()); } -void Td::on_request(uint64 id, td_api::getCollectibleItemInfo &request) { - CREATE_REQUEST_PROMISE(); - get_collectible_info(this, std::move(request.type_), std::move(promise)); -} +void Td::send_update(tl_object_ptr &&object) { + CHECK(object != nullptr); + auto object_id = object->get_id(); + if (close_flag_ >= 5 && object_id != td_api::updateAuthorizationState::ID) { + // just in case + return; + } -void Td::on_request(uint64 id, const td_api::getApplicationDownloadLink &request) { - CHECK_IS_USER(); - CREATE_REQUEST_PROMISE(); - auto query_promise = PromiseCreator::lambda([promise = std::move(promise)](Result result) mutable { - if (result.is_error()) { - promise.set_error(result.move_as_error()); - } else { - promise.set_value(make_tl_object(result.move_as_ok())); + switch (object_id) { + case td_api::updateAccentColors::ID: + case td_api::updateChatThemes::ID: + case td_api::updateFavoriteStickers::ID: + case td_api::updateInstalledStickerSets::ID: + case td_api::updateProfileAccentColors::ID: + case td_api::updateRecentStickers::ID: + case td_api::updateSavedAnimations::ID: + case td_api::updateSavedNotificationSounds::ID: + case td_api::updateUserStatus::ID: + VLOG(td_requests) << "Sending update: " << oneline(to_string(object)); + break; + case td_api::updateTrendingStickerSets::ID: { + auto update = static_cast(object.get()); + auto sticker_sets = update->sticker_sets_.get(); + VLOG(td_requests) << "Sending update: updateTrendingStickerSets { " << oneline(to_string(update->sticker_type_)) + << ", total_count = " << sticker_sets->total_count_ + << ", count = " << sticker_sets->sets_.size() << " }"; + break; } - }); - get_invite_text(this, std::move(query_promise)); -} - -void Td::on_request(uint64 id, td_api::getDeepLinkInfo &request) { - CLEAN_INPUT_STRING(request.link_); - CREATE_REQUEST_PROMISE(); - link_manager_->get_deep_link_info(request.link_, std::move(promise)); -} - -void Td::on_request(uint64 id, const td_api::getApplicationConfig &request) { - CHECK_IS_USER(); - CREATE_REQUEST_PROMISE(); - send_closure(G()->config_manager(), &ConfigManager::get_app_config, std::move(promise)); -} - -void Td::on_request(uint64 id, td_api::saveApplicationLogEvent &request) { - CHECK_IS_USER(); - CLEAN_INPUT_STRING(request.type_); - CREATE_OK_REQUEST_PROMISE(); - save_app_log(this, request.type_, DialogId(request.chat_id_), convert_json_value(std::move(request.data_)), - std::move(promise)); -} - -void Td::on_request(uint64 id, td_api::addProxy &request) { - CLEAN_INPUT_STRING(request.server_); - CREATE_REQUEST_PROMISE(); - send_closure(G()->connection_creator(), &ConnectionCreator::add_proxy, -1, std::move(request.server_), request.port_, - request.enable_, std::move(request.type_), std::move(promise)); -} - -void Td::on_request(uint64 id, td_api::editProxy &request) { - if (request.proxy_id_ < 0) { - return send_error_raw(id, 400, "Proxy identifier invalid"); + case td_api::updateOption::ID: + if (auth_manager_ == nullptr || !auth_manager_->is_bot()) { + VLOG(td_requests) << "Sending update: " << to_string(object); + } + break; + case td_api::updateDefaultReactionType::ID / 2: + LOG(ERROR) << "Sending update: " << oneline(to_string(object)); + break; + default: + VLOG(td_requests) << "Sending update: " << to_string(object); } - CLEAN_INPUT_STRING(request.server_); - CREATE_REQUEST_PROMISE(); - send_closure(G()->connection_creator(), &ConnectionCreator::add_proxy, request.proxy_id_, std::move(request.server_), - request.port_, request.enable_, std::move(request.type_), std::move(promise)); -} - -void Td::on_request(uint64 id, const td_api::enableProxy &request) { - CREATE_OK_REQUEST_PROMISE(); - send_closure(G()->connection_creator(), &ConnectionCreator::enable_proxy, request.proxy_id_, std::move(promise)); -} - -void Td::on_request(uint64 id, const td_api::disableProxy &request) { - CREATE_OK_REQUEST_PROMISE(); - send_closure(G()->connection_creator(), &ConnectionCreator::disable_proxy, std::move(promise)); -} - -void Td::on_request(uint64 id, const td_api::removeProxy &request) { - CREATE_OK_REQUEST_PROMISE(); - send_closure(G()->connection_creator(), &ConnectionCreator::remove_proxy, request.proxy_id_, std::move(promise)); -} -void Td::on_request(uint64 id, const td_api::getProxies &request) { - CREATE_REQUEST_PROMISE(); - send_closure(G()->connection_creator(), &ConnectionCreator::get_proxies, std::move(promise)); + callback_->on_result(0, std::move(object)); } -void Td::on_request(uint64 id, const td_api::getProxyLink &request) { - CREATE_REQUEST_PROMISE(); - auto query_promise = PromiseCreator::lambda([promise = std::move(promise)](Result result) mutable { - if (result.is_error()) { - promise.set_error(result.move_as_error()); - } else { - promise.set_value(make_tl_object(result.move_as_ok())); - } - }); - send_closure(G()->connection_creator(), &ConnectionCreator::get_proxy_link, request.proxy_id_, - std::move(query_promise)); -} +void Td::send_result(uint64 id, tl_object_ptr object) { + if (id == 0) { + LOG(ERROR) << "Sending " << to_string(object) << " through send_result"; + return; + } -void Td::on_request(uint64 id, const td_api::pingProxy &request) { - CREATE_REQUEST_PROMISE(); - auto query_promise = PromiseCreator::lambda([promise = std::move(promise)](Result result) mutable { - if (result.is_error()) { - promise.set_error(result.move_as_error()); - } else { - promise.set_value(make_tl_object(result.move_as_ok())); + auto it = request_set_.find(id); + if (it != request_set_.end()) { + if (object == nullptr) { + object = make_tl_object(404, "Not Found"); } - }); - 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)); + VLOG(td_requests) << "Sending result for request " << id << ": " << to_string(object); + request_set_.erase(it); + callback_->on_result(id, std::move(object)); + } } -void Td::on_request(uint64 id, const td_api::getSupportName &request) { - CHECK_IS_USER(); - CREATE_REQUEST_PROMISE(); - auto query_promise = PromiseCreator::lambda([promise = std::move(promise)](Result result) mutable { - if (result.is_error()) { - promise.set_error(result.move_as_error()); - } else { - promise.set_value(make_tl_object(result.move_as_ok())); +void Td::send_error_impl(uint64 id, tl_object_ptr error) { + CHECK(id != 0); + CHECK(error != nullptr); + auto it = request_set_.find(id); + if (it != request_set_.end()) { + if (error->code_ == 0 && error->message_ == "Lost promise") { + LOG(FATAL) << "Lost promise for query " << id << " of type " << it->second << " in close state " << close_flag_; } - }); - get_support_name(this, std::move(query_promise)); -} - -void Td::on_request(uint64 id, const td_api::searchQuote &request) { - UNREACHABLE(); -} - -void Td::on_request(uint64 id, const td_api::getTextEntities &request) { - UNREACHABLE(); -} - -void Td::on_request(uint64 id, const td_api::parseTextEntities &request) { - UNREACHABLE(); -} - -void Td::on_request(uint64 id, const td_api::parseMarkdown &request) { - UNREACHABLE(); -} - -void Td::on_request(uint64 id, const td_api::getMarkdownText &request) { - UNREACHABLE(); -} - -void Td::on_request(uint64 id, const td_api::searchStringsByPrefix &request) { - UNREACHABLE(); -} - -void Td::on_request(uint64 id, const td_api::checkQuickReplyShortcutName &request) { - UNREACHABLE(); -} - -void Td::on_request(uint64 id, const td_api::getCountryFlagEmoji &request) { - UNREACHABLE(); -} - -void Td::on_request(uint64 id, const td_api::getFileMimeType &request) { - UNREACHABLE(); -} - -void Td::on_request(uint64 id, const td_api::getFileExtension &request) { - UNREACHABLE(); -} - -void Td::on_request(uint64 id, const td_api::cleanFileName &request) { - UNREACHABLE(); -} - -void Td::on_request(uint64 id, const td_api::getLanguagePackString &request) { - UNREACHABLE(); -} - -void Td::on_request(uint64 id, const td_api::getPhoneNumberInfoSync &request) { - UNREACHABLE(); -} - -void Td::on_request(uint64 id, const td_api::getPushReceiverId &request) { - UNREACHABLE(); -} - -void Td::on_request(uint64 id, const td_api::getChatFolderDefaultIconName &request) { - UNREACHABLE(); -} - -void Td::on_request(uint64 id, const td_api::getJsonValue &request) { - UNREACHABLE(); -} - -void Td::on_request(uint64 id, const td_api::getJsonString &request) { - UNREACHABLE(); -} - -void Td::on_request(uint64 id, const td_api::getThemeParametersJsonString &request) { - UNREACHABLE(); -} - -void Td::on_request(uint64 id, const td_api::setLogStream &request) { - UNREACHABLE(); -} - -void Td::on_request(uint64 id, const td_api::getLogStream &request) { - UNREACHABLE(); -} - -void Td::on_request(uint64 id, const td_api::setLogVerbosityLevel &request) { - UNREACHABLE(); -} - -void Td::on_request(uint64 id, const td_api::getLogVerbosityLevel &request) { - UNREACHABLE(); -} - -void Td::on_request(uint64 id, const td_api::getLogTags &request) { - UNREACHABLE(); -} - -void Td::on_request(uint64 id, const td_api::setLogTagVerbosityLevel &request) { - UNREACHABLE(); -} - -void Td::on_request(uint64 id, const td_api::getLogTagVerbosityLevel &request) { - UNREACHABLE(); -} - -void Td::on_request(uint64 id, const td_api::addLogMessage &request) { - UNREACHABLE(); -} - -// test -void Td::on_request(uint64 id, const td_api::testNetwork &request) { - CREATE_OK_REQUEST_PROMISE(); - create_handler(std::move(promise))->send(); -} - -void Td::on_request(uint64 id, td_api::testProxy &request) { - auto r_proxy = Proxy::create_proxy(std::move(request.server_), request.port_, request.type_.get()); - if (r_proxy.is_error()) { - return send_closure(actor_id(this), &Td::send_error, id, r_proxy.move_as_error()); + VLOG(td_requests) << "Sending error for request " << id << ": " << oneline(to_string(error)); + request_set_.erase(it); + callback_->on_error(id, std::move(error)); } - CREATE_OK_REQUEST_PROMISE(); - send_closure(G()->connection_creator(), &ConnectionCreator::test_proxy, r_proxy.move_as_ok(), request.dc_id_, - request.timeout_, std::move(promise)); -} - -void Td::on_request(uint64 id, const td_api::testGetDifference &request) { - updates_manager_->get_difference("testGetDifference"); - send_closure(actor_id(this), &Td::send_result, id, make_tl_object()); -} - -void Td::on_request(uint64 id, const td_api::testUseUpdate &request) { - send_closure(actor_id(this), &Td::send_result, id, nullptr); -} - -void Td::on_request(uint64 id, const td_api::testReturnError &request) { - UNREACHABLE(); } -void Td::on_request(uint64 id, const td_api::testCallEmpty &request) { - send_closure(actor_id(this), &Td::send_result, id, make_tl_object()); +void Td::send_error(uint64 id, Status error) { + send_error_impl(id, make_tl_object(error.code(), error.message().str())); + error.ignore(); } -void Td::on_request(uint64 id, const td_api::testSquareInt &request) { - send_closure(actor_id(this), &Td::send_result, id, make_tl_object(request.x_ * request.x_)); -} +Result> Td::get_parameters( + td_api::object_ptr parameters) { + VLOG(td_init) << "Begin to set TDLib parameters"; + if (!clean_input_string(parameters->api_hash_) || !clean_input_string(parameters->system_language_code_) || + !clean_input_string(parameters->device_model_) || !clean_input_string(parameters->system_version_) || + !clean_input_string(parameters->application_version_)) { + VLOG(td_init) << "Wrong string encoding"; + return Status::Error(400, "Strings must be encoded in UTF-8"); + } -void Td::on_request(uint64 id, td_api::testCallString &request) { - send_closure(actor_id(this), &Td::send_result, id, make_tl_object(std::move(request.x_))); -} + if (parameters->api_id_ <= 0) { + return Status::Error(400, "Valid api_id must be provided. Can be obtained at https://my.telegram.org"); + } + if (parameters->api_hash_.empty()) { + return Status::Error(400, "Valid api_hash must be provided. Can be obtained at https://my.telegram.org"); + } -void Td::on_request(uint64 id, td_api::testCallBytes &request) { - send_closure(actor_id(this), &Td::send_result, id, make_tl_object(std::move(request.x_))); -} + std::pair result; + result.first.api_id_ = parameters->api_id_; + result.first.api_hash_ = std::move(parameters->api_hash_); + result.first.use_secret_chats_ = parameters->use_secret_chats_; -void Td::on_request(uint64 id, td_api::testCallVectorInt &request) { - send_closure(actor_id(this), &Td::send_result, id, make_tl_object(std::move(request.x_))); -} + result.second.encryption_key_ = TdDb::as_db_key(std::move(parameters->database_encryption_key_)); + result.second.database_directory_ = std::move(parameters->database_directory_); + result.second.files_directory_ = std::move(parameters->files_directory_); + result.second.is_test_dc_ = parameters->use_test_dc_; + result.second.use_file_database_ = parameters->use_file_database_; + result.second.use_chat_info_database_ = parameters->use_chat_info_database_; + result.second.use_message_database_ = parameters->use_message_database_; -void Td::on_request(uint64 id, td_api::testCallVectorIntObject &request) { - send_closure(actor_id(this), &Td::send_result, id, - make_tl_object(std::move(request.x_))); -} + VLOG(td_init) << "Create MtprotoHeader::Options"; + options_.api_id = parameters->api_id_; + options_.system_language_code = trim(parameters->system_language_code_); + options_.device_model = trim(parameters->device_model_); + options_.system_version = trim(parameters->system_version_); + options_.application_version = trim(parameters->application_version_); + if (options_.system_language_code.empty()) { + return Status::Error(400, "System language code must be non-empty"); + } + if (options_.device_model.empty()) { + return Status::Error(400, "Device model must be non-empty"); + } + if (options_.system_version.empty()) { + options_.system_version = get_operating_system_version().str(); + VLOG(td_init) << "Set system version to " << options_.system_version; + } + if (options_.application_version.empty()) { + return Status::Error(400, "Application version must be non-empty"); + } + if (options_.api_id != 21724) { + options_.application_version += ", TDLib "; + auto version = OptionManager::get_option_synchronously("version"); + CHECK(version->get_id() == td_api::optionValueString::ID); + options_.application_version += static_cast(version.get())->value_; + } + options_.language_pack = string(); + options_.language_code = string(); + options_.parameters = string(); + options_.is_emulator = false; + options_.proxy = Proxy(); -void Td::on_request(uint64 id, td_api::testCallVectorString &request) { - send_closure(actor_id(this), &Td::send_result, id, make_tl_object(std::move(request.x_))); + return std::move(result); } -void Td::on_request(uint64 id, td_api::testCallVectorStringObject &request) { - send_closure(actor_id(this), &Td::send_result, id, - make_tl_object(std::move(request.x_))); +void Td::on_file_download_finished(FileId file_id) { + requests_->on_file_download_finished(file_id); } -#undef CLEAN_INPUT_STRING -#undef CHECK_IS_BOT -#undef CHECK_IS_USER -#undef CREATE_NO_ARGS_REQUEST -#undef CREATE_REQUEST -#undef CREATE_REQUEST_PROMISE -#undef CREATE_OK_REQUEST_PROMISE - } // namespace td diff --git a/lib/tgchat/ext/td/td/telegram/Td.h b/lib/tgchat/ext/td/td/telegram/Td.h index 8a812a8c..27374be2 100644 --- a/lib/tgchat/ext/td/td/telegram/Td.h +++ b/lib/tgchat/ext/td/td/telegram/Td.h @@ -16,7 +16,6 @@ #include "td/telegram/telegram_api.h" #include "td/actor/actor.h" -#include "td/actor/MultiTimeout.h" #include "td/utils/buffer.h" #include "td/utils/common.h" @@ -34,6 +33,7 @@ namespace td { class AccountManager; +class AlarmManager; class AnimationsManager; class AttachMenuManager; class AudiosManager; @@ -85,6 +85,7 @@ class PrivacyManager; class PromoDataManager; class QuickReplyManager; class ReactionManager; +class Requests; class SavedMessagesManager; class SecureManager; class SecretChatsManager; @@ -271,6 +272,7 @@ class Td final : public Actor { unique_ptr web_pages_manager_; ActorOwn web_pages_manager_actor_; + ActorOwn alarm_manager_; ActorOwn call_manager_; ActorOwn cashtag_search_hints_; ActorOwn config_manager_; @@ -331,13 +333,11 @@ class Td final : public Actor { private: void run_request(uint64 id, td_api::object_ptr function); - void do_run_request(uint64 id, td_api::object_ptr &&function); - void send_result(uint64 id, tl_object_ptr object); + void send_error(uint64 id, Status error); + void send_error_impl(uint64 id, tl_object_ptr error); - void send_error_raw(uint64 id, int32 code, CSlice error); - void answer_ok_query(uint64 id, Status status); ActorShared create_reference(); @@ -357,6 +357,7 @@ class Td final : public Actor { MtprotoHeader::Options options_; + unique_ptr requests_; std::unordered_multimap request_set_; int actor_refcnt_ = 0; int request_actor_refcnt_ = 0; @@ -373,17 +374,6 @@ class Td final : public Actor { bool can_ignore_background_updates_ = false; - int64 alarm_id_ = 1; - FlatHashMap pending_alarms_; - MultiTimeout alarm_timeout_{"AlarmTimeout"}; - - struct DownloadInfo { - int64 offset = -1; - int64 limit = -1; - vector request_ids; - }; - FlatHashMap pending_file_downloads_; - vector>> pending_preauthentication_requests_; vector>> pending_set_parameters_requests_; @@ -397,13 +387,10 @@ class Td final : public Actor { vector> get_fake_current_state() const; - static void on_alarm_timeout_callback(void *td_ptr, int64 alarm_id); - - void on_alarm_timeout(int64 alarm_id); - template friend class RequestActor; // uses send_result/send_error friend class AuthManager; // uses send_result/send_error, TODO pass Promise<> + friend class Requests; void add_handler(uint64 id, std::shared_ptr handler); std::shared_ptr extract_handler(uint64 id); @@ -412,1597 +399,14 @@ class Td final : public Actor { void on_file_download_finished(FileId file_id); - class OnRequest; - - class DownloadFileCallback; - - std::shared_ptr download_file_callback_; - - class UploadFileCallback; - - std::shared_ptr upload_file_callback_; - std::shared_ptr old_context_; - static int *get_log_verbosity_level(Slice name); - - template - Promise create_request_promise(uint64 id) { - return PromiseCreator::lambda([actor_id = actor_id(this), id](Result r_state) { - if (r_state.is_error()) { - send_closure(actor_id, &Td::send_error, id, r_state.move_as_error()); - } else { - send_closure(actor_id, &Td::send_result, id, r_state.move_as_ok()); - } - }); - } - - Promise create_ok_request_promise(uint64 id); - static bool is_authentication_request(int32 id); static bool is_preinitialization_request(int32 id); static bool is_preauthentication_request(int32 id); - template - void on_request(uint64 id, const T &) = delete; - - void on_request(uint64 id, const td_api::setTdlibParameters &request); - - void on_request(uint64 id, const td_api::getAuthorizationState &request); - - void on_request(uint64 id, td_api::setAuthenticationPhoneNumber &request); - - void on_request(uint64 id, td_api::sendAuthenticationFirebaseSms &request); - - void on_request(uint64 id, td_api::reportAuthenticationCodeMissing &request); - - void on_request(uint64 id, td_api::setAuthenticationEmailAddress &request); - - void on_request(uint64 id, td_api::resendAuthenticationCode &request); - - void on_request(uint64 id, td_api::checkAuthenticationEmailCode &request); - - void on_request(uint64 id, td_api::checkAuthenticationCode &request); - - void on_request(uint64 id, td_api::registerUser &request); - - void on_request(uint64 id, td_api::requestQrCodeAuthentication &request); - - void on_request(uint64 id, const td_api::resetAuthenticationEmailAddress &request); - - void on_request(uint64 id, td_api::checkAuthenticationPassword &request); - - void on_request(uint64 id, const td_api::requestAuthenticationPasswordRecovery &request); - - void on_request(uint64 id, td_api::checkAuthenticationPasswordRecoveryCode &request); - - void on_request(uint64 id, td_api::recoverAuthenticationPassword &request); - - void on_request(uint64 id, const td_api::logOut &request); - - void on_request(uint64 id, const td_api::close &request); - - void on_request(uint64 id, const td_api::destroy &request); - - void on_request(uint64 id, td_api::checkAuthenticationBotToken &request); - - void on_request(uint64 id, td_api::confirmQrCodeAuthentication &request); - - void on_request(uint64 id, td_api::setDatabaseEncryptionKey &request); - - void on_request(uint64 id, const td_api::getCurrentState &request); - - void on_request(uint64 id, const td_api::getPasswordState &request); - - void on_request(uint64 id, td_api::setPassword &request); - - void on_request(uint64 id, td_api::setLoginEmailAddress &request); - - void on_request(uint64 id, const td_api::resendLoginEmailAddressCode &request); - - void on_request(uint64 id, td_api::checkLoginEmailAddressCode &request); - - void on_request(uint64 id, td_api::getRecoveryEmailAddress &request); - - void on_request(uint64 id, td_api::setRecoveryEmailAddress &request); - - void on_request(uint64 id, td_api::checkRecoveryEmailAddressCode &request); - - void on_request(uint64 id, const td_api::resendRecoveryEmailAddressCode &request); - - void on_request(uint64 id, const td_api::cancelRecoveryEmailAddressVerification &request); - - void on_request(uint64 id, td_api::requestPasswordRecovery &request); - - void on_request(uint64 id, td_api::checkPasswordRecoveryCode &request); - - void on_request(uint64 id, td_api::recoverPassword &request); - - void on_request(uint64 id, const td_api::resetPassword &request); - - void on_request(uint64 id, const td_api::cancelPasswordReset &request); - - void on_request(uint64 id, td_api::getTemporaryPasswordState &request); - - void on_request(uint64 id, td_api::createTemporaryPassword &request); - - void on_request(uint64 id, td_api::processPushNotification &request); - - void on_request(uint64 id, td_api::registerDevice &request); - - void on_request(uint64 id, td_api::getUserPrivacySettingRules &request); - - void on_request(uint64 id, td_api::setUserPrivacySettingRules &request); - - void on_request(uint64 id, const td_api::getDefaultMessageAutoDeleteTime &request); - - void on_request(uint64 id, const td_api::setDefaultMessageAutoDeleteTime &request); - - void on_request(uint64 id, const td_api::getAccountTtl &request); - - void on_request(uint64 id, const td_api::setAccountTtl &request); - - void on_request(uint64 id, td_api::deleteAccount &request); - - void on_request(uint64 id, td_api::sendPhoneNumberCode &request); - - void on_request(uint64 id, td_api::sendPhoneNumberFirebaseSms &request); - - void on_request(uint64 id, td_api::reportPhoneNumberCodeMissing &request); - - void on_request(uint64 id, td_api::resendPhoneNumberCode &request); - - void on_request(uint64 id, td_api::checkPhoneNumberCode &request); - - void on_request(uint64 id, const td_api::getUserLink &request); - - void on_request(uint64 id, td_api::searchUserByToken &request); - - void on_request(uint64 id, const td_api::getActiveSessions &request); - - void on_request(uint64 id, const td_api::terminateSession &request); - - void on_request(uint64 id, const td_api::terminateAllOtherSessions &request); - - void on_request(uint64 id, const td_api::confirmSession &request); - - void on_request(uint64 id, const td_api::toggleSessionCanAcceptCalls &request); - - void on_request(uint64 id, const td_api::toggleSessionCanAcceptSecretChats &request); - - void on_request(uint64 id, const td_api::setInactiveSessionTtl &request); - - void on_request(uint64 id, const td_api::getConnectedWebsites &request); - - void on_request(uint64 id, const td_api::disconnectWebsite &request); - - void on_request(uint64 id, const td_api::disconnectAllWebsites &request); - - void on_request(uint64 id, const td_api::getMe &request); - - void on_request(uint64 id, const td_api::getUser &request); - - void on_request(uint64 id, const td_api::getUserFullInfo &request); - - void on_request(uint64 id, const td_api::getBasicGroup &request); - - void on_request(uint64 id, const td_api::getBasicGroupFullInfo &request); - - void on_request(uint64 id, const td_api::getSupergroup &request); - - void on_request(uint64 id, const td_api::getSupergroupFullInfo &request); - - void on_request(uint64 id, const td_api::getSecretChat &request); - - void on_request(uint64 id, const td_api::getChat &request); - - void on_request(uint64 id, const td_api::getMessage &request); - - void on_request(uint64 id, const td_api::getMessageLocally &request); - - void on_request(uint64 id, const td_api::getRepliedMessage &request); - - void on_request(uint64 id, const td_api::getChatPinnedMessage &request); - - void on_request(uint64 id, const td_api::getCallbackQueryMessage &request); - - void on_request(uint64 id, const td_api::getMessageThread &request); - - void on_request(uint64 id, const td_api::getMessageReadDate &request); - - void on_request(uint64 id, const td_api::getMessageViewers &request); - - void on_request(uint64 id, const td_api::getMessages &request); - - void on_request(uint64 id, const td_api::getMessageProperties &request); - - void on_request(uint64 id, const td_api::getChatSponsoredMessages &request); - - void on_request(uint64 id, const td_api::clickChatSponsoredMessage &request); - - void on_request(uint64 id, const td_api::reportChatSponsoredMessage &request); - - void on_request(uint64 id, const td_api::getMessageLink &request); - - void on_request(uint64 id, const td_api::getMessageEmbeddingCode &request); - - void on_request(uint64 id, td_api::getMessageLinkInfo &request); - - void on_request(uint64 id, td_api::translateText &request); - - void on_request(uint64 id, td_api::translateMessageText &request); - - void on_request(uint64 id, const td_api::recognizeSpeech &request); - - void on_request(uint64 id, const td_api::rateSpeechRecognition &request); - - void on_request(uint64 id, const td_api::getFile &request); - - void on_request(uint64 id, td_api::getRemoteFile &request); - - void on_request(uint64 id, td_api::getStorageStatistics &request); - - void on_request(uint64 id, td_api::getStorageStatisticsFast &request); - - void on_request(uint64 id, const td_api::getDatabaseStatistics &request); - - void on_request(uint64 id, td_api::optimizeStorage &request); - - void on_request(uint64 id, td_api::getNetworkStatistics &request); - - void on_request(uint64 id, td_api::resetNetworkStatistics &request); - - void on_request(uint64 id, td_api::addNetworkStatistics &request); - - void on_request(uint64 id, const td_api::setNetworkType &request); - - void on_request(uint64 id, const td_api::getAutoDownloadSettingsPresets &request); - - void on_request(uint64 id, const td_api::setAutoDownloadSettings &request); - - void on_request(uint64 id, const td_api::getAutosaveSettings &request); - - void on_request(uint64 id, td_api::setAutosaveSettings &request); - - void on_request(uint64 id, const td_api::clearAutosaveSettingsExceptions &request); - - void on_request(uint64 id, const td_api::getRecommendedChats &request); - - void on_request(uint64 id, const td_api::getChatSimilarChats &request); - - void on_request(uint64 id, const td_api::getChatSimilarChatCount &request); - - void on_request(uint64 id, const td_api::openChatSimilarChat &request); - - void on_request(uint64 id, const td_api::getTopChats &request); - - void on_request(uint64 id, const td_api::removeTopChat &request); - - void on_request(uint64 id, const td_api::loadChats &request); - - void on_request(uint64 id, const td_api::getChats &request); - - void on_request(uint64 id, const td_api::loadSavedMessagesTopics &request); - - void on_request(uint64 id, const td_api::getSavedMessagesTopicHistory &request); - - void on_request(uint64 id, const td_api::getSavedMessagesTopicMessageByDate &request); - - void on_request(uint64 id, const td_api::deleteSavedMessagesTopicHistory &request); - - void on_request(uint64 id, const td_api::deleteSavedMessagesTopicMessagesByDate &request); - - void on_request(uint64 id, const td_api::toggleSavedMessagesTopicIsPinned &request); - - void on_request(uint64 id, const td_api::setPinnedSavedMessagesTopics &request); - - void on_request(uint64 id, td_api::searchPublicChat &request); - - void on_request(uint64 id, td_api::searchPublicChats &request); - - void on_request(uint64 id, td_api::searchChats &request); - - void on_request(uint64 id, td_api::searchChatsOnServer &request); - - void on_request(uint64 id, const td_api::searchChatsNearby &request); - - void on_request(uint64 id, td_api::searchRecentlyFoundChats &request); - - void on_request(uint64 id, const td_api::addRecentlyFoundChat &request); - - void on_request(uint64 id, const td_api::removeRecentlyFoundChat &request); - - void on_request(uint64 id, const td_api::clearRecentlyFoundChats &request); - - void on_request(uint64 id, const td_api::getRecentlyOpenedChats &request); - - void on_request(uint64 id, const td_api::getGroupsInCommon &request); - - void on_request(uint64 id, td_api::checkChatUsername &request); - - void on_request(uint64 id, const td_api::getCreatedPublicChats &request); - - void on_request(uint64 id, const td_api::checkCreatedPublicChatsLimit &request); - - void on_request(uint64 id, const td_api::getSuitableDiscussionChats &request); - - void on_request(uint64 id, const td_api::getInactiveSupergroupChats &request); - - void on_request(uint64 id, const td_api::getSuitablePersonalChats &request); - - void on_request(uint64 id, const td_api::openChat &request); - - void on_request(uint64 id, const td_api::closeChat &request); - - void on_request(uint64 id, const td_api::viewMessages &request); - - void on_request(uint64 id, const td_api::openMessageContent &request); - - void on_request(uint64 id, const td_api::clickAnimatedEmojiMessage &request); - - void on_request(uint64 id, const td_api::getInternalLink &request); - - void on_request(uint64 id, const td_api::getInternalLinkType &request); - - void on_request(uint64 id, td_api::getExternalLinkInfo &request); - - void on_request(uint64 id, td_api::getExternalLink &request); - - void on_request(uint64 id, const td_api::getChatHistory &request); - - void on_request(uint64 id, const td_api::deleteChatHistory &request); - - void on_request(uint64 id, const td_api::deleteChat &request); - - void on_request(uint64 id, const td_api::getMessageThreadHistory &request); - - void on_request(uint64 id, const td_api::getChatMessageCalendar &request); - - void on_request(uint64 id, td_api::searchChatMessages &request); - - void on_request(uint64 id, td_api::searchSecretMessages &request); - - void on_request(uint64 id, td_api::searchMessages &request); - - void on_request(uint64 id, td_api::searchSavedMessages &request); - - void on_request(uint64 id, const td_api::searchCallMessages &request); - - void on_request(uint64 id, td_api::searchOutgoingDocumentMessages &request); - - void on_request(uint64 id, td_api::searchPublicMessagesByTag &request); - - void on_request(uint64 id, td_api::searchPublicStoriesByTag &request); - - void on_request(uint64 id, td_api::searchPublicStoriesByLocation &request); - - void on_request(uint64 id, td_api::searchPublicStoriesByVenue &request); - - void on_request(uint64 id, td_api::getSearchedForTags &request); - - void on_request(uint64 id, td_api::removeSearchedForTag &request); - - void on_request(uint64 id, td_api::clearSearchedForTags &request); - - void on_request(uint64 id, const td_api::deleteAllCallMessages &request); - - void on_request(uint64 id, const td_api::searchChatRecentLocationMessages &request); - - void on_request(uint64 id, const td_api::getChatMessageByDate &request); - - void on_request(uint64 id, const td_api::getChatSparseMessagePositions &request); - - void on_request(uint64 id, const td_api::getChatMessageCount &request); - - void on_request(uint64 id, const td_api::getChatMessagePosition &request); - - void on_request(uint64 id, const td_api::getChatScheduledMessages &request); - - void on_request(uint64 id, const td_api::getEmojiReaction &request); - - void on_request(uint64 id, const td_api::getCustomEmojiReactionAnimations &request); - - void on_request(uint64 id, const td_api::getMessageAvailableReactions &request); - - void on_request(uint64 id, const td_api::clearRecentReactions &request); - - void on_request(uint64 id, const td_api::addMessageReaction &request); - - void on_request(uint64 id, const td_api::addPaidMessageReaction &request); - - void on_request(uint64 id, const td_api::removePendingPaidMessageReactions &request); - - void on_request(uint64 id, const td_api::togglePaidMessageReactionIsAnonymous &request); - - void on_request(uint64 id, const td_api::removeMessageReaction &request); - - void on_request(uint64 id, const td_api::setMessageReactions &request); - - void on_request(uint64 id, td_api::getMessageAddedReactions &request); - - void on_request(uint64 id, const td_api::setDefaultReactionType &request); - - void on_request(uint64 id, const td_api::getSavedMessagesTags &request); - - void on_request(uint64 id, td_api::setSavedMessagesTagLabel &request); - - void on_request(uint64 id, const td_api::getMessageEffect &request); - - void on_request(uint64 id, td_api::getMessagePublicForwards &request); - - void on_request(uint64 id, td_api::getStoryPublicForwards &request); - - void on_request(uint64 id, const td_api::removeNotification &request); - - void on_request(uint64 id, const td_api::removeNotificationGroup &request); - - void on_request(uint64 id, const td_api::deleteMessages &request); - - void on_request(uint64 id, const td_api::deleteChatMessagesBySender &request); - - void on_request(uint64 id, const td_api::deleteChatMessagesByDate &request); - - void on_request(uint64 id, const td_api::readAllChatMentions &request); - - void on_request(uint64 id, const td_api::readAllMessageThreadMentions &request); - - void on_request(uint64 id, const td_api::readAllChatReactions &request); - - void on_request(uint64 id, const td_api::readAllMessageThreadReactions &request); - - void on_request(uint64 id, const td_api::getChatAvailableMessageSenders &request); - - void on_request(uint64 id, const td_api::setChatMessageSender &request); - - void on_request(uint64 id, td_api::sendMessage &request); - - void on_request(uint64 id, td_api::sendMessageAlbum &request); - - void on_request(uint64 id, td_api::sendBotStartMessage &request); - - void on_request(uint64 id, td_api::sendInlineQueryResultMessage &request); - - void on_request(uint64 id, td_api::addLocalMessage &request); - - void on_request(uint64 id, td_api::editMessageText &request); - - void on_request(uint64 id, td_api::editMessageLiveLocation &request); - - void on_request(uint64 id, td_api::editMessageMedia &request); - - void on_request(uint64 id, td_api::editMessageCaption &request); - - void on_request(uint64 id, td_api::editMessageReplyMarkup &request); - - void on_request(uint64 id, td_api::editInlineMessageText &request); - - void on_request(uint64 id, td_api::editInlineMessageLiveLocation &request); - - void on_request(uint64 id, td_api::editInlineMessageMedia &request); - - void on_request(uint64 id, td_api::editInlineMessageCaption &request); - - void on_request(uint64 id, td_api::editInlineMessageReplyMarkup &request); - - void on_request(uint64 id, td_api::editMessageSchedulingState &request); - - void on_request(uint64 id, td_api::setMessageFactCheck &request); - - void on_request(uint64 id, td_api::sendBusinessMessage &request); - - void on_request(uint64 id, td_api::sendBusinessMessageAlbum &request); - - void on_request(uint64 id, td_api::editBusinessMessageText &request); - - void on_request(uint64 id, td_api::editBusinessMessageLiveLocation &request); - - void on_request(uint64 id, td_api::editBusinessMessageMedia &request); - - void on_request(uint64 id, td_api::editBusinessMessageCaption &request); - - void on_request(uint64 id, td_api::editBusinessMessageReplyMarkup &request); - - void on_request(uint64 id, td_api::stopBusinessPoll &request); - - void on_request(uint64 id, td_api::setBusinessMessageIsPinned &request); - - void on_request(uint64 id, const td_api::loadQuickReplyShortcuts &request); - - void on_request(uint64 id, const td_api::setQuickReplyShortcutName &request); - - void on_request(uint64 id, const td_api::deleteQuickReplyShortcut &request); - - void on_request(uint64 id, const td_api::reorderQuickReplyShortcuts &request); - - void on_request(uint64 id, const td_api::loadQuickReplyShortcutMessages &request); - - void on_request(uint64 id, const td_api::deleteQuickReplyShortcutMessages &request); - - void on_request(uint64 id, td_api::addQuickReplyShortcutMessage &request); - - void on_request(uint64 id, td_api::addQuickReplyShortcutInlineQueryResultMessage &request); - - void on_request(uint64 id, td_api::addQuickReplyShortcutMessageAlbum &request); - - void on_request(uint64 id, td_api::readdQuickReplyShortcutMessages &request); - - void on_request(uint64 id, td_api::editQuickReplyMessage &request); - - void on_request(uint64 id, const td_api::getCurrentWeather &request); - - void on_request(uint64 id, const td_api::getStory &request); - - void on_request(uint64 id, const td_api::getChatsToSendStories &request); - - void on_request(uint64 id, const td_api::canSendStory &request); - - void on_request(uint64 id, td_api::sendStory &request); - - void on_request(uint64 id, td_api::editStory &request); - - void on_request(uint64 id, const td_api::editStoryCover &request); - - void on_request(uint64 id, td_api::setStoryPrivacySettings &request); - - void on_request(uint64 id, const td_api::toggleStoryIsPostedToChatPage &request); - - void on_request(uint64 id, const td_api::deleteStory &request); - - void on_request(uint64 id, const td_api::loadActiveStories &request); - - void on_request(uint64 id, const td_api::setChatActiveStoriesList &request); - - void on_request(uint64 id, const td_api::getForumTopicDefaultIcons &request); - - void on_request(uint64 id, td_api::createForumTopic &request); - - void on_request(uint64 id, td_api::editForumTopic &request); - - void on_request(uint64 id, const td_api::getForumTopic &request); - - void on_request(uint64 id, const td_api::getForumTopicLink &request); - - void on_request(uint64 id, td_api::getForumTopics &request); - - void on_request(uint64 id, const td_api::toggleForumTopicIsClosed &request); - - void on_request(uint64 id, const td_api::toggleGeneralForumTopicIsHidden &request); - - void on_request(uint64 id, const td_api::toggleForumTopicIsPinned &request); - - void on_request(uint64 id, const td_api::setPinnedForumTopics &request); - - void on_request(uint64 id, const td_api::deleteForumTopic &request); - - void on_request(uint64 id, td_api::setGameScore &request); - - void on_request(uint64 id, td_api::setInlineGameScore &request); - - void on_request(uint64 id, td_api::getGameHighScores &request); - - void on_request(uint64 id, td_api::getInlineGameHighScores &request); - - void on_request(uint64 id, const td_api::deleteChatReplyMarkup &request); - - void on_request(uint64 id, td_api::sendChatAction &request); - - void on_request(uint64 id, td_api::forwardMessages &request); - - void on_request(uint64 id, const td_api::sendQuickReplyShortcutMessages &request); - - void on_request(uint64 id, td_api::resendMessages &request); - - void on_request(uint64 id, td_api::getLinkPreview &request); - - void on_request(uint64 id, td_api::getWebPageInstantView &request); - - void on_request(uint64 id, const td_api::createPrivateChat &request); - - void on_request(uint64 id, const td_api::createBasicGroupChat &request); - - void on_request(uint64 id, const td_api::createSupergroupChat &request); - - void on_request(uint64 id, const td_api::createSecretChat &request); - - void on_request(uint64 id, td_api::createNewBasicGroupChat &request); - - void on_request(uint64 id, td_api::createNewSupergroupChat &request); - - void on_request(uint64 id, const td_api::createNewSecretChat &request); - - void on_request(uint64 id, const td_api::createCall &request); - - void on_request(uint64 id, const td_api::acceptCall &request); - - void on_request(uint64 id, td_api::sendCallSignalingData &request); - - void on_request(uint64 id, const td_api::discardCall &request); - - void on_request(uint64 id, td_api::sendCallRating &request); - - void on_request(uint64 id, td_api::sendCallDebugInformation &request); - - void on_request(uint64 id, td_api::sendCallLog &request); - - void on_request(uint64 id, const td_api::getVideoChatAvailableParticipants &request); - - void on_request(uint64 id, const td_api::setVideoChatDefaultParticipant &request); - - void on_request(uint64 id, td_api::createVideoChat &request); - - void on_request(uint64 id, const td_api::getVideoChatRtmpUrl &request); - - void on_request(uint64 id, const td_api::replaceVideoChatRtmpUrl &request); - - void on_request(uint64 id, const td_api::getGroupCall &request); - - void on_request(uint64 id, const td_api::startScheduledGroupCall &request); - - void on_request(uint64 id, const td_api::toggleGroupCallEnabledStartNotification &request); - - void on_request(uint64 id, td_api::joinGroupCall &request); - - void on_request(uint64 id, td_api::startGroupCallScreenSharing &request); - - void on_request(uint64 id, const td_api::endGroupCallScreenSharing &request); - - void on_request(uint64 id, td_api::setGroupCallTitle &request); - - void on_request(uint64 id, const td_api::toggleGroupCallMuteNewParticipants &request); - - void on_request(uint64 id, const td_api::revokeGroupCallInviteLink &request); - - void on_request(uint64 id, const td_api::inviteGroupCallParticipants &request); - - void on_request(uint64 id, const td_api::getGroupCallInviteLink &request); - - void on_request(uint64 id, td_api::startGroupCallRecording &request); - - void on_request(uint64 id, const td_api::toggleGroupCallScreenSharingIsPaused &request); - - void on_request(uint64 id, const td_api::endGroupCallRecording &request); - - void on_request(uint64 id, const td_api::toggleGroupCallIsMyVideoPaused &request); - - void on_request(uint64 id, const td_api::toggleGroupCallIsMyVideoEnabled &request); - - void on_request(uint64 id, const td_api::setGroupCallParticipantIsSpeaking &request); - - void on_request(uint64 id, const td_api::toggleGroupCallParticipantIsMuted &request); - - void on_request(uint64 id, const td_api::setGroupCallParticipantVolumeLevel &request); - - void on_request(uint64 id, const td_api::toggleGroupCallParticipantIsHandRaised &request); - - void on_request(uint64 id, const td_api::loadGroupCallParticipants &request); - - void on_request(uint64 id, const td_api::leaveGroupCall &request); - - void on_request(uint64 id, const td_api::endGroupCall &request); - - void on_request(uint64 id, const td_api::getGroupCallStreams &request); - - void on_request(uint64 id, td_api::getGroupCallStreamSegment &request); - - void on_request(uint64 id, const td_api::upgradeBasicGroupChatToSupergroupChat &request); - - void on_request(uint64 id, const td_api::getChatListsToAddChat &request); - - void on_request(uint64 id, const td_api::addChatToList &request); - - void on_request(uint64 id, const td_api::getChatFolder &request); - - void on_request(uint64 id, const td_api::getRecommendedChatFolders &request); - - void on_request(uint64 id, td_api::createChatFolder &request); - - void on_request(uint64 id, td_api::editChatFolder &request); - - void on_request(uint64 id, const td_api::deleteChatFolder &request); - - void on_request(uint64 id, const td_api::getChatFolderChatsToLeave &request); - - void on_request(uint64 id, td_api::getChatFolderChatCount &request); - - void on_request(uint64 id, const td_api::reorderChatFolders &request); - - void on_request(uint64 id, const td_api::toggleChatFolderTags &request); - - void on_request(uint64 id, const td_api::getChatsForChatFolderInviteLink &request); - - void on_request(uint64 id, td_api::createChatFolderInviteLink &request); - - void on_request(uint64 id, td_api::getChatFolderInviteLinks &request); - - void on_request(uint64 id, td_api::editChatFolderInviteLink &request); - - void on_request(uint64 id, td_api::deleteChatFolderInviteLink &request); - - void on_request(uint64 id, td_api::checkChatFolderInviteLink &request); - - void on_request(uint64 id, td_api::addChatFolderByInviteLink &request); - - void on_request(uint64 id, const td_api::getChatFolderNewChats &request); - - void on_request(uint64 id, const td_api::processChatFolderNewChats &request); - - void on_request(uint64 id, const td_api::getArchiveChatListSettings &request); - - void on_request(uint64 id, td_api::setArchiveChatListSettings &request); - - void on_request(uint64 id, const td_api::getReadDatePrivacySettings &request); - - void on_request(uint64 id, td_api::setReadDatePrivacySettings &request); - - void on_request(uint64 id, const td_api::getNewChatPrivacySettings &request); - - void on_request(uint64 id, td_api::setNewChatPrivacySettings &request); - - void on_request(uint64 id, const td_api::canSendMessageToUser &request); - - void on_request(uint64 id, td_api::setChatTitle &request); - - void on_request(uint64 id, const td_api::setChatPhoto &request); - - void on_request(uint64 id, const td_api::setChatAccentColor &request); - - void on_request(uint64 id, const td_api::setChatProfileAccentColor &request); - - void on_request(uint64 id, const td_api::setChatMessageAutoDeleteTime &request); - - void on_request(uint64 id, const td_api::setChatEmojiStatus &request); - - void on_request(uint64 id, const td_api::setChatPermissions &request); - - void on_request(uint64 id, td_api::setChatBackground &request); - - void on_request(uint64 id, const td_api::deleteChatBackground &request); - - void on_request(uint64 id, td_api::setChatTheme &request); - - void on_request(uint64 id, td_api::setChatDraftMessage &request); - - void on_request(uint64 id, const td_api::toggleChatHasProtectedContent &request); - - void on_request(uint64 id, const td_api::toggleChatIsPinned &request); - - void on_request(uint64 id, const td_api::toggleChatViewAsTopics &request); - - void on_request(uint64 id, const td_api::toggleChatIsTranslatable &request); - - void on_request(uint64 id, const td_api::toggleChatIsMarkedAsUnread &request); - - void on_request(uint64 id, const td_api::setMessageSenderBlockList &request); - - void on_request(uint64 id, const td_api::toggleChatDefaultDisableNotification &request); - - void on_request(uint64 id, const td_api::setPinnedChats &request); - - void on_request(uint64 id, const td_api::readChatList &request); - - void on_request(uint64 id, const td_api::getStoryNotificationSettingsExceptions &request); - - void on_request(uint64 id, const td_api::getChatActiveStories &request); - - void on_request(uint64 id, const td_api::getChatPostedToChatPageStories &request); - - void on_request(uint64 id, const td_api::getChatArchivedStories &request); - - void on_request(uint64 id, const td_api::setChatPinnedStories &request); - - void on_request(uint64 id, const td_api::openStory &request); - - void on_request(uint64 id, const td_api::closeStory &request); - - void on_request(uint64 id, const td_api::getStoryAvailableReactions &request); - - void on_request(uint64 id, const td_api::setStoryReaction &request); - - void on_request(uint64 id, td_api::getStoryInteractions &request); - - void on_request(uint64 id, td_api::getChatStoryInteractions &request); - - void on_request(uint64 id, td_api::reportStory &request); - - void on_request(uint64 id, const td_api::activateStoryStealthMode &request); - - void on_request(uint64 id, const td_api::getChatBoostLevelFeatures &request); - - void on_request(uint64 id, const td_api::getChatBoostFeatures &request); - - void on_request(uint64 id, const td_api::getAvailableChatBoostSlots &request); - - void on_request(uint64 id, const td_api::getChatBoostStatus &request); - - void on_request(uint64 id, td_api::boostChat &request); - - void on_request(uint64 id, const td_api::getChatBoostLink &request); - - void on_request(uint64 id, td_api::getChatBoostLinkInfo &request); - - void on_request(uint64 id, td_api::getChatBoosts &request); - - void on_request(uint64 id, const td_api::getUserChatBoosts &request); - - void on_request(uint64 id, const td_api::getAttachmentMenuBot &request); - - void on_request(uint64 id, const td_api::toggleBotIsAddedToAttachmentMenu &request); - - void on_request(uint64 id, td_api::setChatAvailableReactions &request); - - void on_request(uint64 id, td_api::setChatClientData &request); - - void on_request(uint64 id, td_api::setChatDescription &request); - - void on_request(uint64 id, const td_api::setChatDiscussionGroup &request); - - void on_request(uint64 id, td_api::setChatLocation &request); - - void on_request(uint64 id, const td_api::setChatSlowModeDelay &request); - - void on_request(uint64 id, const td_api::pinChatMessage &request); - - void on_request(uint64 id, const td_api::unpinChatMessage &request); - - void on_request(uint64 id, const td_api::unpinAllChatMessages &request); - - void on_request(uint64 id, const td_api::unpinAllMessageThreadMessages &request); - - void on_request(uint64 id, const td_api::joinChat &request); - - void on_request(uint64 id, const td_api::leaveChat &request); - - void on_request(uint64 id, const td_api::addChatMember &request); - - void on_request(uint64 id, const td_api::addChatMembers &request); - - void on_request(uint64 id, td_api::setChatMemberStatus &request); - - void on_request(uint64 id, const td_api::banChatMember &request); - - void on_request(uint64 id, const td_api::canTransferOwnership &request); - - void on_request(uint64 id, td_api::transferChatOwnership &request); - - void on_request(uint64 id, const td_api::getChatMember &request); - - void on_request(uint64 id, td_api::searchChatMembers &request); - - void on_request(uint64 id, const td_api::getChatAdministrators &request); - - void on_request(uint64 id, const td_api::replacePrimaryChatInviteLink &request); - - void on_request(uint64 id, td_api::createChatInviteLink &request); - - void on_request(uint64 id, td_api::createChatSubscriptionInviteLink &request); - - void on_request(uint64 id, td_api::editChatInviteLink &request); - - void on_request(uint64 id, td_api::editChatSubscriptionInviteLink &request); - - void on_request(uint64 id, td_api::getChatInviteLink &request); - - void on_request(uint64 id, const td_api::getChatInviteLinkCounts &request); - - void on_request(uint64 id, td_api::getChatInviteLinks &request); - - void on_request(uint64 id, td_api::getChatInviteLinkMembers &request); - - void on_request(uint64 id, td_api::getChatJoinRequests &request); - - void on_request(uint64 id, const td_api::processChatJoinRequest &request); - - void on_request(uint64 id, td_api::processChatJoinRequests &request); - - void on_request(uint64 id, td_api::revokeChatInviteLink &request); - - void on_request(uint64 id, td_api::deleteRevokedChatInviteLink &request); - - void on_request(uint64 id, const td_api::deleteAllRevokedChatInviteLinks &request); - - void on_request(uint64 id, td_api::checkChatInviteLink &request); - - void on_request(uint64 id, td_api::joinChatByInviteLink &request); - - void on_request(uint64 id, td_api::getChatEventLog &request); - - void on_request(uint64 id, const td_api::getTimeZones &request); - - void on_request(uint64 id, const td_api::clearAllDraftMessages &request); - - void on_request(uint64 id, const td_api::downloadFile &request); - - void on_request(uint64 id, const td_api::getFileDownloadedPrefixSize &request); - - void on_request(uint64 id, const td_api::cancelDownloadFile &request); - - void on_request(uint64 id, const td_api::getSuggestedFileName &request); - - void on_request(uint64 id, const td_api::preliminaryUploadFile &request); - - void on_request(uint64 id, const td_api::cancelPreliminaryUploadFile &request); - - void on_request(uint64 id, td_api::writeGeneratedFilePart &request); - - void on_request(uint64 id, const td_api::setFileGenerationProgress &request); - - void on_request(uint64 id, td_api::finishFileGeneration &request); - - void on_request(uint64 id, const td_api::readFilePart &request); - - void on_request(uint64 id, const td_api::deleteFile &request); - - void on_request(uint64 id, const td_api::addFileToDownloads &request); - - void on_request(uint64 id, const td_api::toggleDownloadIsPaused &request); - - void on_request(uint64 id, const td_api::toggleAllDownloadsArePaused &request); - - void on_request(uint64 id, const td_api::removeFileFromDownloads &request); - - void on_request(uint64 id, const td_api::removeAllFilesFromDownloads &request); - - void on_request(uint64 id, td_api::searchFileDownloads &request); - - void on_request(uint64 id, td_api::setApplicationVerificationToken &request); - - void on_request(uint64 id, td_api::getMessageFileType &request); - - void on_request(uint64 id, const td_api::getMessageImportConfirmationText &request); - - void on_request(uint64 id, const td_api::importMessages &request); - - void on_request(uint64 id, const td_api::blockMessageSenderFromReplies &request); - - void on_request(uint64 id, const td_api::getBlockedMessageSenders &request); - - void on_request(uint64 id, td_api::addContact &request); - - void on_request(uint64 id, td_api::importContacts &request); - - void on_request(uint64 id, const td_api::getContacts &request); - - void on_request(uint64 id, td_api::searchContacts &request); - - void on_request(uint64 id, td_api::removeContacts &request); - - void on_request(uint64 id, const td_api::getImportedContactCount &request); - - void on_request(uint64 id, td_api::changeImportedContacts &request); - - void on_request(uint64 id, const td_api::clearImportedContacts &request); - - void on_request(uint64 id, const td_api::getCloseFriends &request); - - void on_request(uint64 id, const td_api::setCloseFriends &request); - - void on_request(uint64 id, td_api::setUserPersonalProfilePhoto &request); - - void on_request(uint64 id, td_api::suggestUserProfilePhoto &request); - - void on_request(uint64 id, td_api::searchUserByPhoneNumber &request); - - void on_request(uint64 id, const td_api::sharePhoneNumber &request); - - void on_request(uint64 id, const td_api::getRecentInlineBots &request); - - void on_request(uint64 id, td_api::setName &request); - - void on_request(uint64 id, td_api::setBio &request); - - void on_request(uint64 id, td_api::setUsername &request); - - void on_request(uint64 id, td_api::toggleUsernameIsActive &request); - - void on_request(uint64 id, td_api::reorderActiveUsernames &request); - - void on_request(uint64 id, td_api::setBirthdate &request); - - void on_request(uint64 id, const td_api::setPersonalChat &request); - - void on_request(uint64 id, const td_api::setEmojiStatus &request); - - void on_request(uint64 id, const td_api::toggleHasSponsoredMessagesEnabled &request); - - void on_request(uint64 id, const td_api::getThemedEmojiStatuses &request); - - void on_request(uint64 id, const td_api::getThemedChatEmojiStatuses &request); - - void on_request(uint64 id, const td_api::getDefaultEmojiStatuses &request); - - void on_request(uint64 id, const td_api::getDefaultChatEmojiStatuses &request); - - void on_request(uint64 id, const td_api::getRecentEmojiStatuses &request); - - void on_request(uint64 id, const td_api::clearRecentEmojiStatuses &request); - - void on_request(uint64 id, td_api::setCommands &request); - - void on_request(uint64 id, td_api::deleteCommands &request); - - void on_request(uint64 id, td_api::getCommands &request); - - void on_request(uint64 id, td_api::setMenuButton &request); - - void on_request(uint64 id, const td_api::getMenuButton &request); - - void on_request(uint64 id, const td_api::setDefaultGroupAdministratorRights &request); - - void on_request(uint64 id, const td_api::setDefaultChannelAdministratorRights &request); - - void on_request(uint64 id, const td_api::canBotSendMessages &request); - - void on_request(uint64 id, const td_api::allowBotToSendMessages &request); - - void on_request(uint64 id, td_api::sendWebAppCustomRequest &request); - - void on_request(uint64 id, const td_api::getBotMediaPreviews &request); - - void on_request(uint64 id, const td_api::getBotMediaPreviewInfo &request); - - void on_request(uint64 id, td_api::addBotMediaPreview &request); - - void on_request(uint64 id, td_api::editBotMediaPreview &request); - - void on_request(uint64 id, const td_api::reorderBotMediaPreviews &request); - - void on_request(uint64 id, const td_api::deleteBotMediaPreviews &request); - - void on_request(uint64 id, td_api::setBotName &request); - - void on_request(uint64 id, const td_api::getBotName &request); - - void on_request(uint64 id, td_api::setBotProfilePhoto &request); - - void on_request(uint64 id, td_api::toggleBotUsernameIsActive &request); - - void on_request(uint64 id, td_api::reorderBotActiveUsernames &request); - - void on_request(uint64 id, td_api::setBotInfoDescription &request); - - void on_request(uint64 id, const td_api::getBotInfoDescription &request); - - void on_request(uint64 id, td_api::setBotInfoShortDescription &request); - - void on_request(uint64 id, const td_api::getBotInfoShortDescription &request); - - void on_request(uint64 id, const td_api::setLocation &request); - - void on_request(uint64 id, td_api::setBusinessLocation &request); - - void on_request(uint64 id, td_api::setBusinessOpeningHours &request); - - void on_request(uint64 id, td_api::setBusinessGreetingMessageSettings &request); - - void on_request(uint64 id, td_api::setBusinessAwayMessageSettings &request); - - void on_request(uint64 id, td_api::setBusinessStartPage &request); - - void on_request(uint64 id, td_api::setProfilePhoto &request); - - void on_request(uint64 id, const td_api::deleteProfilePhoto &request); - - void on_request(uint64 id, const td_api::getUserProfilePhotos &request); - - void on_request(uint64 id, const td_api::setAccentColor &request); - - void on_request(uint64 id, const td_api::setProfileAccentColor &request); - - void on_request(uint64 id, const td_api::getBusinessConnectedBot &request); - - void on_request(uint64 id, td_api::setBusinessConnectedBot &request); - - void on_request(uint64 id, const td_api::deleteBusinessConnectedBot &request); - - void on_request(uint64 id, const td_api::toggleBusinessConnectedBotChatIsPaused &request); - - void on_request(uint64 id, const td_api::removeBusinessConnectedBotFromChat &request); - - void on_request(uint64 id, const td_api::getBusinessChatLinks &request); - - void on_request(uint64 id, td_api::createBusinessChatLink &request); - - void on_request(uint64 id, td_api::editBusinessChatLink &request); - - void on_request(uint64 id, td_api::deleteBusinessChatLink &request); - - void on_request(uint64 id, td_api::getBusinessChatLinkInfo &request); - - void on_request(uint64 id, td_api::setSupergroupUsername &request); - - void on_request(uint64 id, td_api::toggleSupergroupUsernameIsActive &request); - - void on_request(uint64 id, const td_api::disableAllSupergroupUsernames &request); - - void on_request(uint64 id, td_api::reorderSupergroupActiveUsernames &request); - - void on_request(uint64 id, const td_api::setSupergroupStickerSet &request); - - void on_request(uint64 id, const td_api::setSupergroupCustomEmojiStickerSet &request); - - void on_request(uint64 id, const td_api::setSupergroupUnrestrictBoostCount &request); - - void on_request(uint64 id, const td_api::toggleSupergroupSignMessages &request); - - void on_request(uint64 id, const td_api::toggleSupergroupJoinToSendMessages &request); - - void on_request(uint64 id, const td_api::toggleSupergroupJoinByRequest &request); - - void on_request(uint64 id, const td_api::toggleSupergroupIsAllHistoryAvailable &request); - - void on_request(uint64 id, const td_api::toggleSupergroupCanHaveSponsoredMessages &request); - - void on_request(uint64 id, const td_api::toggleSupergroupHasHiddenMembers &request); - - void on_request(uint64 id, const td_api::toggleSupergroupHasAggressiveAntiSpamEnabled &request); - - void on_request(uint64 id, const td_api::toggleSupergroupIsForum &request); - - void on_request(uint64 id, const td_api::toggleSupergroupIsBroadcastGroup &request); - - void on_request(uint64 id, const td_api::reportSupergroupSpam &request); - - void on_request(uint64 id, const td_api::reportSupergroupAntiSpamFalsePositive &request); - - void on_request(uint64 id, td_api::getSupergroupMembers &request); - - void on_request(uint64 id, td_api::closeSecretChat &request); - - void on_request(uint64 id, td_api::getStickers &request); - - void on_request(uint64 id, td_api::getAllStickerEmojis &request); - - void on_request(uint64 id, td_api::searchStickers &request); - - void on_request(uint64 id, const td_api::getGreetingStickers &request); - - void on_request(uint64 id, const td_api::getPremiumStickers &request); - - void on_request(uint64 id, const td_api::getInstalledStickerSets &request); - - void on_request(uint64 id, const td_api::getArchivedStickerSets &request); - - void on_request(uint64 id, const td_api::getTrendingStickerSets &request); - - void on_request(uint64 id, const td_api::getAttachedStickerSets &request); - - void on_request(uint64 id, const td_api::getStickerSet &request); - - void on_request(uint64 id, td_api::searchStickerSet &request); - - void on_request(uint64 id, td_api::searchInstalledStickerSets &request); - - void on_request(uint64 id, td_api::searchStickerSets &request); - - void on_request(uint64 id, const td_api::changeStickerSet &request); - - void on_request(uint64 id, const td_api::viewTrendingStickerSets &request); - - void on_request(uint64 id, td_api::reorderInstalledStickerSets &request); - - void on_request(uint64 id, td_api::uploadStickerFile &request); - - void on_request(uint64 id, td_api::getSuggestedStickerSetName &request); - - void on_request(uint64 id, td_api::checkStickerSetName &request); - - void on_request(uint64 id, td_api::createNewStickerSet &request); - - void on_request(uint64 id, td_api::addStickerToSet &request); - - void on_request(uint64 id, td_api::replaceStickerInSet &request); - - void on_request(uint64 id, td_api::setStickerSetThumbnail &request); - - void on_request(uint64 id, td_api::setCustomEmojiStickerSetThumbnail &request); - - void on_request(uint64 id, td_api::setStickerSetTitle &request); - - void on_request(uint64 id, td_api::deleteStickerSet &request); - - void on_request(uint64 id, td_api::setStickerPositionInSet &request); - - void on_request(uint64 id, const td_api::removeStickerFromSet &request); - - void on_request(uint64 id, td_api::setStickerEmojis &request); - - void on_request(uint64 id, td_api::setStickerKeywords &request); - - void on_request(uint64 id, td_api::setStickerMaskPosition &request); - - void on_request(uint64 id, const td_api::getOwnedStickerSets &request); - - void on_request(uint64 id, const td_api::getRecentStickers &request); - - void on_request(uint64 id, td_api::addRecentSticker &request); - - void on_request(uint64 id, td_api::removeRecentSticker &request); - - void on_request(uint64 id, td_api::clearRecentStickers &request); - - void on_request(uint64 id, const td_api::getSavedAnimations &request); - - void on_request(uint64 id, td_api::addSavedAnimation &request); - - void on_request(uint64 id, td_api::removeSavedAnimation &request); - - void on_request(uint64 id, td_api::getStickerEmojis &request); - - void on_request(uint64 id, td_api::searchEmojis &request); - - void on_request(uint64 id, td_api::getKeywordEmojis &request); - - void on_request(uint64 id, const td_api::getEmojiCategories &request); - - void on_request(uint64 id, td_api::getAnimatedEmoji &request); - - void on_request(uint64 id, td_api::getEmojiSuggestionsUrl &request); - - void on_request(uint64 id, const td_api::getCustomEmojiStickers &request); - - void on_request(uint64 id, const td_api::getDefaultChatPhotoCustomEmojiStickers &request); - - void on_request(uint64 id, const td_api::getDefaultProfilePhotoCustomEmojiStickers &request); - - void on_request(uint64 id, const td_api::getDefaultBackgroundCustomEmojiStickers &request); - - void on_request(uint64 id, const td_api::getDisallowedChatEmojiStatuses &request); - - void on_request(uint64 id, const td_api::getFavoriteStickers &request); - - void on_request(uint64 id, td_api::addFavoriteSticker &request); - - void on_request(uint64 id, td_api::removeFavoriteSticker &request); - - void on_request(uint64 id, const td_api::getSavedNotificationSound &request); - - void on_request(uint64 id, const td_api::getSavedNotificationSounds &request); - - void on_request(uint64 id, td_api::addSavedNotificationSound &request); - - void on_request(uint64 id, const td_api::removeSavedNotificationSound &request); - - void on_request(uint64 id, const td_api::getChatNotificationSettingsExceptions &request); - - void on_request(uint64 id, const td_api::getScopeNotificationSettings &request); - - void on_request(uint64 id, td_api::setChatNotificationSettings &request); - - void on_request(uint64 id, td_api::setForumTopicNotificationSettings &request); - - void on_request(uint64 id, td_api::setScopeNotificationSettings &request); - - void on_request(uint64 id, td_api::setReactionNotificationSettings &request); - - void on_request(uint64 id, const td_api::resetAllNotificationSettings &request); - - void on_request(uint64 id, const td_api::removeChatActionBar &request); - - void on_request(uint64 id, td_api::reportChat &request); - - void on_request(uint64 id, td_api::reportChatPhoto &request); - - void on_request(uint64 id, const td_api::reportMessageReactions &request); - - void on_request(uint64 id, const td_api::getChatStatistics &request); - - void on_request(uint64 id, const td_api::getChatRevenueStatistics &request); - - void on_request(uint64 id, const td_api::getChatRevenueWithdrawalUrl &request); - - void on_request(uint64 id, const td_api::getChatRevenueTransactions &request); - - void on_request(uint64 id, const td_api::getStarRevenueStatistics &request); - - void on_request(uint64 id, const td_api::getStarWithdrawalUrl &request); - - void on_request(uint64 id, const td_api::getStarAdAccountUrl &request); - - void on_request(uint64 id, const td_api::getMessageStatistics &request); - - void on_request(uint64 id, const td_api::getStoryStatistics &request); - - void on_request(uint64 id, td_api::getStatisticalGraph &request); - - void on_request(uint64 id, const td_api::getMapThumbnailFile &request); - - void on_request(uint64 id, const td_api::getLocalizationTargetInfo &request); - - void on_request(uint64 id, td_api::getLanguagePackInfo &request); - - void on_request(uint64 id, td_api::getLanguagePackStrings &request); - - void on_request(uint64 id, td_api::synchronizeLanguagePack &request); - - void on_request(uint64 id, td_api::addCustomServerLanguagePack &request); - - void on_request(uint64 id, td_api::setCustomLanguagePack &request); - - void on_request(uint64 id, td_api::editCustomLanguagePackInfo &request); - - void on_request(uint64 id, td_api::setCustomLanguagePackString &request); - - void on_request(uint64 id, td_api::deleteLanguagePack &request); - - void on_request(uint64 id, td_api::getOption &request); - - void on_request(uint64 id, td_api::setOption &request); - - void on_request(uint64 id, td_api::setPollAnswer &request); - - void on_request(uint64 id, td_api::getPollVoters &request); - - void on_request(uint64 id, td_api::stopPoll &request); - - void on_request(uint64 id, const td_api::hideSuggestedAction &request); - - void on_request(uint64 id, const td_api::hideContactCloseBirthdays &request); - - void on_request(uint64 id, td_api::getBusinessConnection &request); - - void on_request(uint64 id, const td_api::getLoginUrlInfo &request); - - void on_request(uint64 id, const td_api::getLoginUrl &request); - - void on_request(uint64 id, const td_api::shareUsersWithBot &request); - - void on_request(uint64 id, const td_api::shareChatWithBot &request); - - void on_request(uint64 id, td_api::getInlineQueryResults &request); - - void on_request(uint64 id, td_api::answerInlineQuery &request); - - void on_request(uint64 id, td_api::getPopularWebAppBots &request); - - void on_request(uint64 id, td_api::searchWebApp &request); - - void on_request(uint64 id, td_api::getWebAppLinkUrl &request); - - void on_request(uint64 id, td_api::getMainWebApp &request); - - void on_request(uint64 id, td_api::getWebAppUrl &request); - - void on_request(uint64 id, td_api::sendWebAppData &request); - - void on_request(uint64 id, td_api::openWebApp &request); - - void on_request(uint64 id, const td_api::closeWebApp &request); - - void on_request(uint64 id, td_api::answerWebAppQuery &request); - - void on_request(uint64 id, td_api::getCallbackQueryAnswer &request); - - void on_request(uint64 id, td_api::answerCallbackQuery &request); - - void on_request(uint64 id, td_api::answerShippingQuery &request); - - void on_request(uint64 id, td_api::answerPreCheckoutQuery &request); - - void on_request(uint64 id, td_api::getBankCardInfo &request); - - void on_request(uint64 id, td_api::getPaymentForm &request); - - void on_request(uint64 id, td_api::validateOrderInfo &request); - - void on_request(uint64 id, td_api::sendPaymentForm &request); - - void on_request(uint64 id, const td_api::getPaymentReceipt &request); - - void on_request(uint64 id, const td_api::getSavedOrderInfo &request); - - void on_request(uint64 id, const td_api::deleteSavedOrderInfo &request); - - void on_request(uint64 id, const td_api::deleteSavedCredentials &request); - - void on_request(uint64 id, td_api::createInvoiceLink &request); - - void on_request(uint64 id, td_api::refundStarPayment &request); - - void on_request(uint64 id, td_api::getPassportElement &request); - - void on_request(uint64 id, td_api::getAllPassportElements &request); - - void on_request(uint64 id, td_api::setPassportElement &request); - - void on_request(uint64 id, const td_api::deletePassportElement &request); - - void on_request(uint64 id, td_api::setPassportElementErrors &request); - - void on_request(uint64 id, td_api::getPreferredCountryLanguage &request); - - void on_request(uint64 id, td_api::sendEmailAddressVerificationCode &request); - - void on_request(uint64 id, const td_api::resendEmailAddressVerificationCode &request); - - void on_request(uint64 id, td_api::checkEmailAddressVerificationCode &request); - - void on_request(uint64 id, td_api::getPassportAuthorizationForm &request); - - void on_request(uint64 id, td_api::getPassportAuthorizationFormAvailableElements &request); - - void on_request(uint64 id, td_api::sendPassportAuthorizationForm &request); - - void on_request(uint64 id, const td_api::getSupportUser &request); - - void on_request(uint64 id, const td_api::getInstalledBackgrounds &request); - - void on_request(uint64 id, td_api::getBackgroundUrl &request); - - void on_request(uint64 id, td_api::searchBackground &request); - - void on_request(uint64 id, td_api::setDefaultBackground &request); - - void on_request(uint64 id, const td_api::deleteDefaultBackground &request); - - void on_request(uint64 id, const td_api::removeInstalledBackground &request); - - void on_request(uint64 id, const td_api::resetInstalledBackgrounds &request); - - void on_request(uint64 id, td_api::getRecentlyVisitedTMeUrls &request); - - void on_request(uint64 id, td_api::setBotUpdatesStatus &request); - - void on_request(uint64 id, td_api::sendCustomRequest &request); - - void on_request(uint64 id, td_api::answerCustomQuery &request); - - void on_request(uint64 id, const td_api::setAlarm &request); - - void on_request(uint64 id, td_api::searchHashtags &request); - - void on_request(uint64 id, td_api::removeRecentHashtag &request); - - void on_request(uint64 id, const td_api::getPremiumLimit &request); - - void on_request(uint64 id, const td_api::getPremiumFeatures &request); - - void on_request(uint64 id, const td_api::getPremiumStickerExamples &request); - - void on_request(uint64 id, const td_api::viewPremiumFeature &request); - - void on_request(uint64 id, const td_api::clickPremiumSubscriptionButton &request); - - void on_request(uint64 id, const td_api::getPremiumState &request); - - void on_request(uint64 id, const td_api::getPremiumGiftCodePaymentOptions &request); - - void on_request(uint64 id, td_api::checkPremiumGiftCode &request); - - void on_request(uint64 id, td_api::applyPremiumGiftCode &request); - - void on_request(uint64 id, td_api::launchPrepaidPremiumGiveaway &request); - - void on_request(uint64 id, const td_api::getPremiumGiveawayInfo &request); - - void on_request(uint64 id, const td_api::getStarPaymentOptions &request); - - void on_request(uint64 id, const td_api::getStarGiftPaymentOptions &request); - - void on_request(uint64 id, td_api::getStarTransactions &request); - - void on_request(uint64 id, td_api::getStarSubscriptions &request); - - void on_request(uint64 id, td_api::editStarSubscription &request); - - void on_request(uint64 id, td_api::reuseStarSubscription &request); - - void on_request(uint64 id, td_api::canPurchaseFromStore &request); - - void on_request(uint64 id, td_api::assignAppStoreTransaction &request); - - void on_request(uint64 id, td_api::assignGooglePlayTransaction &request); - - void on_request(uint64 id, const td_api::getBusinessFeatures &request); - - void on_request(uint64 id, td_api::acceptTermsOfService &request); - - void on_request(uint64 id, const td_api::getCountries &request); - - void on_request(uint64 id, const td_api::getCountryCode &request); - - void on_request(uint64 id, const td_api::getPhoneNumberInfo &request); - - void on_request(uint64 id, td_api::getCollectibleItemInfo &request); - - void on_request(uint64 id, const td_api::getApplicationDownloadLink &request); - - void on_request(uint64 id, td_api::getDeepLinkInfo &request); - - void on_request(uint64 id, const td_api::getApplicationConfig &request); - - void on_request(uint64 id, td_api::saveApplicationLogEvent &request); - - void on_request(uint64 id, td_api::addProxy &request); - - void on_request(uint64 id, td_api::editProxy &request); - - void on_request(uint64 id, const td_api::enableProxy &request); - - void on_request(uint64 id, const td_api::disableProxy &request); - - void on_request(uint64 id, const td_api::removeProxy &request); - - void on_request(uint64 id, const td_api::getProxies &request); - - void on_request(uint64 id, const td_api::getProxyLink &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::getSupportName &request); - - void on_request(uint64 id, const td_api::searchQuote &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::parseMarkdown &request); - - void on_request(uint64 id, const td_api::getMarkdownText &request); - - void on_request(uint64 id, const td_api::searchStringsByPrefix &request); - - void on_request(uint64 id, const td_api::checkQuickReplyShortcutName &request); - - void on_request(uint64 id, const td_api::getCountryFlagEmoji &request); - - void on_request(uint64 id, const td_api::getFileMimeType &request); - - void on_request(uint64 id, const td_api::getFileExtension &request); - - void on_request(uint64 id, const td_api::cleanFileName &request); - - void on_request(uint64 id, const td_api::getLanguagePackString &request); - - void on_request(uint64 id, const td_api::getPhoneNumberInfoSync &request); - - void on_request(uint64 id, const td_api::getPushReceiverId &request); - - void on_request(uint64 id, const td_api::getChatFolderDefaultIconName &request); - - void on_request(uint64 id, const td_api::getJsonValue &request); - - void on_request(uint64 id, const td_api::getJsonString &request); - - void on_request(uint64 id, const td_api::getThemeParametersJsonString &request); - - void on_request(uint64 id, const td_api::setLogStream &request); - - void on_request(uint64 id, const td_api::getLogStream &request); - - void on_request(uint64 id, const td_api::setLogVerbosityLevel &request); - - void on_request(uint64 id, const td_api::getLogVerbosityLevel &request); - - void on_request(uint64 id, const td_api::getLogTags &request); - - void on_request(uint64 id, const td_api::setLogTagVerbosityLevel &request); - - void on_request(uint64 id, const td_api::getLogTagVerbosityLevel &request); - - void on_request(uint64 id, const td_api::addLogMessage &request); - - // test - void on_request(uint64 id, const td_api::testNetwork &request); - void on_request(uint64 id, td_api::testProxy &request); - void on_request(uint64 id, const td_api::testGetDifference &request); - void on_request(uint64 id, const td_api::testUseUpdate &request); - void on_request(uint64 id, const td_api::testReturnError &request); - void on_request(uint64 id, const td_api::testCallEmpty &request); - void on_request(uint64 id, const td_api::testSquareInt &request); - void on_request(uint64 id, td_api::testCallString &request); - void on_request(uint64 id, td_api::testCallBytes &request); - void on_request(uint64 id, td_api::testCallVectorInt &request); - void on_request(uint64 id, td_api::testCallVectorIntObject &request); - void on_request(uint64 id, td_api::testCallVectorString &request); - void on_request(uint64 id, td_api::testCallVectorStringObject &request); - struct Parameters { int32 api_id_ = 0; string api_hash_; diff --git a/lib/tgchat/ext/td/td/telegram/ThemeManager.cpp b/lib/tgchat/ext/td/td/telegram/ThemeManager.cpp index 9c567bde..8cf852f2 100644 --- a/lib/tgchat/ext/td/td/telegram/ThemeManager.cpp +++ b/lib/tgchat/ext/td/td/telegram/ThemeManager.cpp @@ -573,6 +573,7 @@ string ThemeManager::get_theme_parameters_json_string(const td_api::object_ptrbutton_color_)); o("button_text_color", get_color(theme->button_text_color_)); o("header_bg_color", get_color(theme->header_background_color_)); + o("bottom_bar_bg_color", get_color(theme->bottom_bar_background_color_)); o("section_bg_color", get_color(theme->section_background_color_)); o("section_separator_color", get_color(theme->section_separator_color_)); o("accent_text_color", get_color(theme->accent_text_color_)); diff --git a/lib/tgchat/ext/td/td/telegram/TopDialogManager.cpp b/lib/tgchat/ext/td/td/telegram/TopDialogManager.cpp index 8837ec7e..d2dafbf4 100644 --- a/lib/tgchat/ext/td/td/telegram/TopDialogManager.cpp +++ b/lib/tgchat/ext/td/td/telegram/TopDialogManager.cpp @@ -15,7 +15,6 @@ #include "td/telegram/logevent/LogEvent.h" #include "td/telegram/MessagesManager.h" #include "td/telegram/misc.h" -#include "td/telegram/net/NetQuery.h" #include "td/telegram/net/NetQueryDispatcher.h" #include "td/telegram/StateManager.h" #include "td/telegram/Td.h" diff --git a/lib/tgchat/ext/td/td/telegram/UpdatesManager.cpp b/lib/tgchat/ext/td/td/telegram/UpdatesManager.cpp index e9cd82dc..2f0fb7ba 100644 --- a/lib/tgchat/ext/td/td/telegram/UpdatesManager.cpp +++ b/lib/tgchat/ext/td/td/telegram/UpdatesManager.cpp @@ -39,12 +39,12 @@ #include "td/telegram/LanguagePackManager.h" #include "td/telegram/Location.h" #include "td/telegram/MessageId.h" +#include "td/telegram/MessageReaction.h" #include "td/telegram/MessageSender.h" #include "td/telegram/MessagesManager.h" #include "td/telegram/MessageTtl.h" #include "td/telegram/misc.h" #include "td/telegram/net/DcOptions.h" -#include "td/telegram/net/NetQuery.h" #include "td/telegram/NotificationManager.h" #include "td/telegram/NotificationSettingsManager.h" #include "td/telegram/NotificationSettingsScope.h" @@ -109,23 +109,6 @@ namespace td { int VERBOSITY_NAME(get_difference) = VERBOSITY_NAME(INFO); -class OnUpdate { - UpdatesManager *updates_manager_; - tl_object_ptr &update_; - mutable Promise promise_; - - public: - OnUpdate(UpdatesManager *updates_manager, tl_object_ptr &update, Promise &&promise) - : updates_manager_(updates_manager), update_(update), promise_(std::move(promise)) { - } - - template - void operator()(T &obj) const { - CHECK(&*update_ == &obj); - updates_manager_->on_update(move_tl_object_as(update_), std::move(promise_)); - } -}; - class GetUpdatesStateQuery final : public Td::ResultHandler { Promise> promise_; @@ -375,6 +358,11 @@ void UpdatesManager::fill_pts_gap(void *td) { CHECK(td != nullptr); auto updates_manager = static_cast(td)->updates_manager_.get(); + if (updates_manager->expect_pts_gap_) { + updates_manager->expect_pts_gap_ = false; + return fill_gap(td, string()); + } + auto min_pts = std::numeric_limits::max(); auto min_pts_count = 0; const telegram_api::Update *first_update = nullptr; @@ -998,6 +986,7 @@ bool UpdatesManager::is_acceptable_message(const telegram_api::Message *message_ case telegram_api::messageActionBoostApply::ID: case telegram_api::messageActionRequestedPeerSentMe::ID: case telegram_api::messageActionGiftStars::ID: + case telegram_api::messageActionPrizeStars::ID: break; case telegram_api::messageActionChatCreate::ID: { auto chat_create = static_cast(action); @@ -2264,6 +2253,7 @@ void UpdatesManager::try_reload_data() { td_->chat_manager_->reload_created_public_dialogs(PublicDialogType::ForPersonalDialog, Auto()); get_default_emoji_statuses(td_, Auto()); get_default_channel_emoji_statuses(td_, Auto()); + reload_paid_reaction_privacy(td_); td_->notification_settings_manager_->reload_saved_ringtones(Auto()); td_->notification_settings_manager_->send_get_reaction_notification_settings_query(Auto()); td_->notification_settings_manager_->send_get_scope_notification_settings_query(NotificationSettingsScope::Private, @@ -2275,12 +2265,11 @@ void UpdatesManager::try_reload_data() { td_->quick_reply_manager_->reload_quick_reply_shortcuts(); td_->reaction_manager_->reload_reactions(); td_->reaction_manager_->reload_message_effects(); - for (int32 type = 0; type < MAX_REACTION_LIST_TYPE; type++) { auto reaction_list_type = static_cast(type); td_->reaction_manager_->reload_reaction_list(reaction_list_type, "try_reload_data"); } - + td_->star_manager_->reload_owned_star_count(); for (int32 type = 0; type < MAX_STICKER_TYPE; type++) { auto sticker_type = static_cast(type); td_->stickers_manager_->get_installed_sticker_sets(sticker_type, Auto()); @@ -2926,6 +2915,11 @@ void UpdatesManager::add_pending_pts_update(tl_object_ptr return; } + if (pts_count == 0 && receive_time < Time::now() - MAX_UNFILLED_GAP_TIME && update->get_id() == dummyUpdate::ID) { + // don't warn about fetching of affected history + expect_pts_gap_ = true; + } + pending_pts_updates_.emplace(std::move(update), new_pts, pts_count, receive_time, std::move(promise)); if (old_pts < accumulated_pts_ - accumulated_pts_count_) { @@ -3069,8 +3063,8 @@ void UpdatesManager::process_qts_update(tl_object_ptr &&up auto message_id = MessageId(ServerMessageId(update->msg_id_)); auto date = update->date_; if (!dialog_id.is_valid() || !message_id.is_valid() || date <= 0) { - LOG(ERROR) << "Receive invalid " << to_string(update->reactions_); - return; + LOG(ERROR) << "Receive invalid " << to_string(update); + break; } vector> message_reactions; for (const auto &reaction_count : update->reactions_) { @@ -3090,6 +3084,19 @@ void UpdatesManager::process_qts_update(tl_object_ptr &&up message_id.get(), date, std::move(message_reactions))); break; } + case telegram_api::updateBotPurchasedPaidMedia::ID: { + auto update = move_tl_object_as(update_ptr); + auto user_id = UserId(update->user_id_); + if (!user_id.is_valid()) { + LOG(ERROR) << "Receive invalid " << to_string(update); + break; + } + send_closure( + G()->td(), &Td::send_update, + td_api::make_object( + td_->user_manager_->get_user_id_object(user_id, "updatePaidMediaPurchased"), update->payload_)); + break; + } case telegram_api::updateBotBusinessConnect::ID: { auto update = move_tl_object_as(update_ptr); td_->business_connection_manager_->on_update_bot_business_connect(std::move(update->connection_)); @@ -3762,6 +3769,11 @@ void UpdatesManager::on_update(tl_object_ptr update, Promise &&promise) { + td_->option_manager_->set_option_boolean("is_paid_reaction_anonymous", update->private_); + promise.set_value(Unit()); +} + void UpdatesManager::on_update(tl_object_ptr update, Promise &&promise) { td_->attach_menu_manager_->reload_attach_menu_bots(std::move(promise)); } @@ -3908,6 +3920,7 @@ bool UpdatesManager::is_qts_update(const telegram_api::Update *update) { case telegram_api::updateBotNewBusinessMessage::ID: case telegram_api::updateBotEditBusinessMessage::ID: case telegram_api::updateBotDeleteBusinessMessage::ID: + case telegram_api::updateBotPurchasedPaidMedia::ID: return true; default: return false; @@ -3942,6 +3955,8 @@ int32 UpdatesManager::get_update_qts(const telegram_api::Update *update) { return static_cast(update)->qts_; case telegram_api::updateBotDeleteBusinessMessage::ID: return static_cast(update)->qts_; + case telegram_api::updateBotPurchasedPaidMedia::ID: + return static_cast(update)->qts_; default: return 0; } @@ -4447,6 +4462,12 @@ void UpdatesManager::on_update(tl_object_ptr update, + Promise &&promise) { + auto qts = update->qts_; + add_pending_qts_update(std::move(update), qts, std::move(promise)); +} + void UpdatesManager::on_update(tl_object_ptr update, Promise &&promise) { td_->theme_manager_->on_update_theme(std::move(update->theme_), std::move(promise)); } diff --git a/lib/tgchat/ext/td/td/telegram/UpdatesManager.h b/lib/tgchat/ext/td/td/telegram/UpdatesManager.h index 83275393..939050c9 100644 --- a/lib/tgchat/ext/td/td/telegram/UpdatesManager.h +++ b/lib/tgchat/ext/td/td/telegram/UpdatesManager.h @@ -149,7 +149,23 @@ class UpdatesManager final : public Actor { static constexpr bool DROP_PTS_UPDATES = false; static constexpr const char *AFTER_GET_DIFFERENCE_SOURCE = "after get difference"; - friend class OnUpdate; + class OnUpdate { + UpdatesManager *updates_manager_; + telegram_api::object_ptr &update_; + mutable Promise promise_; + + public: + OnUpdate(UpdatesManager *updates_manager, telegram_api::object_ptr &update, + Promise &&promise) + : updates_manager_(updates_manager), update_(update), promise_(std::move(promise)) { + } + + template + void operator()(T &obj) const { + CHECK(&*update_ == &obj); + updates_manager_->on_update(move_tl_object_as(update_), std::move(promise_)); + } + }; class PendingPtsUpdate { public: @@ -266,6 +282,7 @@ class UpdatesManager final : public Actor { bool is_ping_sent_ = false; + bool expect_pts_gap_ = false; bool running_get_difference_ = false; int32 skipped_postponed_updates_after_start_ = 50000; int32 last_confirmed_pts_ = 0; @@ -490,6 +507,8 @@ class UpdatesManager final : public Actor { void on_update(tl_object_ptr update, Promise &&promise); + void on_update(tl_object_ptr update, Promise &&promise); + void on_update(tl_object_ptr update, Promise &&promise); void on_update(tl_object_ptr update, Promise &&promise); @@ -625,6 +644,7 @@ class UpdatesManager final : public Actor { void on_update(tl_object_ptr update, Promise &&promise); void on_update(tl_object_ptr update, Promise &&promise); void on_update(tl_object_ptr update, Promise &&promise); + void on_update(tl_object_ptr update, Promise &&promise); void on_update(tl_object_ptr update, Promise &&promise); diff --git a/lib/tgchat/ext/td/td/telegram/UserManager.cpp b/lib/tgchat/ext/td/td/telegram/UserManager.cpp index ad034f8e..ec06b9f9 100644 --- a/lib/tgchat/ext/td/td/telegram/UserManager.cpp +++ b/lib/tgchat/ext/td/td/telegram/UserManager.cpp @@ -41,7 +41,6 @@ #include "td/telegram/MessagesManager.h" #include "td/telegram/MessageTtl.h" #include "td/telegram/misc.h" -#include "td/telegram/net/NetQuery.h" #include "td/telegram/NotificationManager.h" #include "td/telegram/OnlineManager.h" #include "td/telegram/OptionManager.h" @@ -4755,8 +4754,10 @@ void UserManager::send_update_profile_photo_query(UserId user_id, FileId file_id Promise &&promise) { TRY_STATUS_PROMISE(promise, G()->close_status()); FileView file_view = td_->file_manager_->get_file_view(file_id); + const auto *main_remote_location = file_view.get_main_remote_location(); + CHECK(main_remote_location != nullptr); td_->create_handler(std::move(promise)) - ->send(user_id, file_id, old_photo_id, is_fallback, file_view.main_remote_location().as_input_photo()); + ->send(user_id, file_id, old_photo_id, is_fallback, main_remote_location->as_input_photo()); } void UserManager::upload_profile_photo(UserId user_id, FileId file_id, bool is_fallback, bool only_suggest, @@ -4793,8 +4794,9 @@ void UserManager::on_upload_profile_photo(FileId file_id, LOG(INFO) << "Uploaded " << (is_animation ? "animated" : "static") << " profile photo " << file_id << " for " << user_id << " with reupload_count = " << reupload_count; FileView file_view = td_->file_manager_->get_file_view(file_id); - if (file_view.has_remote_location() && input_file == nullptr) { - if (file_view.main_remote_location().is_web()) { + const auto *main_remote_location = file_view.get_main_remote_location(); + if (main_remote_location != nullptr && input_file == nullptr) { + if (main_remote_location->is_web()) { return promise.set_error(Status::Error(400, "Can't use web photo as profile photo")); } if (reupload_count == 3) { // upload, ForceReupload repair file reference, reupload @@ -4804,14 +4806,13 @@ void UserManager::on_upload_profile_photo(FileId file_id, // delete file reference and forcely reupload the file if (is_animation) { CHECK(file_view.get_type() == FileType::Animation); - LOG_CHECK(file_view.main_remote_location().is_common()) << file_view.main_remote_location(); + LOG_CHECK(main_remote_location->is_common()) << *main_remote_location; } else { CHECK(file_view.get_type() == FileType::Photo); - LOG_CHECK(file_view.main_remote_location().is_photo()) << file_view.main_remote_location(); + LOG_CHECK(main_remote_location->is_photo()) << *main_remote_location; } - auto file_reference = - is_animation ? FileManager::extract_file_reference(file_view.main_remote_location().as_input_document()) - : FileManager::extract_file_reference(file_view.main_remote_location().as_input_photo()); + auto file_reference = is_animation ? FileManager::extract_file_reference(main_remote_location->as_input_document()) + : FileManager::extract_file_reference(main_remote_location->as_input_photo()); td_->file_manager_->delete_file_reference(file_id, file_reference); upload_profile_photo(user_id, file_id, is_fallback, only_suggest, is_animation, main_frame_timestamp, std::move(promise), reupload_count + 1, {-1}); diff --git a/lib/tgchat/ext/td/td/telegram/Version.h b/lib/tgchat/ext/td/td/telegram/Version.h index de2fbe96..83704d26 100644 --- a/lib/tgchat/ext/td/td/telegram/Version.h +++ b/lib/tgchat/ext/td/td/telegram/Version.h @@ -10,7 +10,7 @@ namespace td { -constexpr int32 MTPROTO_LAYER = 186; +constexpr int32 MTPROTO_LAYER = 187; enum class Version : int32 { Initial, // 0 @@ -67,6 +67,7 @@ enum class Version : int32 { SupportRepliesInOtherChats, SupportMultipleSharedUsers, SupportMoreEmojiGroups, + SupportStarGiveaways, Next }; diff --git a/lib/tgchat/ext/td/td/telegram/VideoNotesManager.cpp b/lib/tgchat/ext/td/td/telegram/VideoNotesManager.cpp index ec94f262..c66c3840 100644 --- a/lib/tgchat/ext/td/td/telegram/VideoNotesManager.cpp +++ b/lib/tgchat/ext/td/td/telegram/VideoNotesManager.cpp @@ -185,8 +185,9 @@ SecretInputMedia VideoNotesManager::get_secret_input_media(FileId video_note_fil if (!file_view.is_encrypted_secret() || file_view.encryption_key().empty()) { return SecretInputMedia{}; } - if (file_view.has_remote_location()) { - input_file = file_view.main_remote_location().as_input_encrypted_file(); + const auto *main_remote_location = file_view.get_main_remote_location(); + if (main_remote_location != nullptr) { + input_file = main_remote_location->as_input_encrypted_file(); } if (!input_file) { return SecretInputMedia{}; @@ -216,20 +217,22 @@ tl_object_ptr VideoNotesManager::get_input_media( if (file_view.is_encrypted()) { return nullptr; } - if (file_view.has_remote_location() && !file_view.main_remote_location().is_web() && input_file == nullptr) { + const auto *main_remote_location = file_view.get_main_remote_location(); + if (main_remote_location != nullptr && !main_remote_location->is_web() && input_file == nullptr) { int32 flags = 0; if (ttl != 0) { flags |= telegram_api::inputMediaDocument::TTL_SECONDS_MASK; } - return make_tl_object( - flags, false /*ignored*/, file_view.main_remote_location().as_input_document(), ttl, string()); + return make_tl_object(flags, false /*ignored*/, + main_remote_location->as_input_document(), ttl, string()); } - if (file_view.has_url()) { + const auto *url = file_view.get_url(); + if (url != nullptr) { int32 flags = 0; if (ttl != 0) { flags |= telegram_api::inputMediaDocumentExternal::TTL_SECONDS_MASK; } - return make_tl_object(flags, false /*ignored*/, file_view.url(), ttl); + return make_tl_object(flags, false /*ignored*/, *url, ttl); } if (input_file != nullptr) { @@ -256,7 +259,7 @@ tl_object_ptr VideoNotesManager::get_input_media( std::move(input_thumbnail), "video/mp4", std::move(attributes), vector>(), ttl); } else { - CHECK(!file_view.has_remote_location()); + CHECK(main_remote_location == nullptr); } return nullptr; diff --git a/lib/tgchat/ext/td/td/telegram/VideosManager.cpp b/lib/tgchat/ext/td/td/telegram/VideosManager.cpp index 2dc508e7..582e8a49 100644 --- a/lib/tgchat/ext/td/td/telegram/VideosManager.cpp +++ b/lib/tgchat/ext/td/td/telegram/VideosManager.cpp @@ -226,8 +226,9 @@ SecretInputMedia VideosManager::get_secret_input_media(FileId video_file_id, if (!file_view.is_encrypted_secret() || file_view.encryption_key().empty()) { return SecretInputMedia{}; } - if (file_view.has_remote_location()) { - input_file = file_view.main_remote_location().as_input_encrypted_file(); + const auto *main_remote_location = file_view.get_main_remote_location(); + if (main_remote_location != nullptr) { + input_file = main_remote_location->as_input_encrypted_file(); } if (!input_file) { return {}; @@ -260,7 +261,8 @@ tl_object_ptr VideosManager::get_input_media( if (file_view.is_encrypted()) { return nullptr; } - if (file_view.has_remote_location() && !file_view.main_remote_location().is_web() && input_file == nullptr) { + const auto *main_remote_location = file_view.get_main_remote_location(); + if (main_remote_location != nullptr && !main_remote_location->is_web() && input_file == nullptr) { int32 flags = 0; if (ttl != 0) { flags |= telegram_api::inputMediaDocument::TTL_SECONDS_MASK; @@ -268,10 +270,11 @@ tl_object_ptr VideosManager::get_input_media( if (has_spoiler) { flags |= telegram_api::inputMediaDocument::SPOILER_MASK; } - return make_tl_object( - flags, false /*ignored*/, file_view.main_remote_location().as_input_document(), ttl, string()); + return make_tl_object(flags, false /*ignored*/, + main_remote_location->as_input_document(), ttl, string()); } - if (file_view.has_url()) { + const auto *url = file_view.get_url(); + if (url != nullptr) { int32 flags = 0; if (ttl != 0) { flags |= telegram_api::inputMediaDocumentExternal::TTL_SECONDS_MASK; @@ -279,7 +282,7 @@ tl_object_ptr VideosManager::get_input_media( if (has_spoiler) { flags |= telegram_api::inputMediaDocumentExternal::SPOILER_MASK; } - return make_tl_object(flags, false /*ignored*/, file_view.url(), ttl); + return make_tl_object(flags, false /*ignored*/, *url, ttl); } if (input_file != nullptr) { @@ -328,7 +331,7 @@ tl_object_ptr VideosManager::get_input_media( flags, false /*ignored*/, false /*ignored*/, false /*ignored*/, std::move(input_file), std::move(input_thumbnail), mime_type, std::move(attributes), std::move(added_stickers), ttl); } else { - CHECK(!file_view.has_remote_location()); + CHECK(main_remote_location == nullptr); } return nullptr; @@ -337,7 +340,11 @@ tl_object_ptr VideosManager::get_input_media( telegram_api::object_ptr VideosManager::get_story_document_input_media( FileId file_id, double main_frame_timestamp) const { auto file_view = td_->file_manager_->get_file_view(file_id); - if (file_view.is_encrypted() || !file_view.has_remote_location() || file_view.main_remote_location().is_web()) { + if (file_view.is_encrypted()) { + return nullptr; + } + const auto *main_remote_location = file_view.get_main_remote_location(); + if (main_remote_location == nullptr || main_remote_location->is_web()) { return nullptr; } @@ -375,8 +382,7 @@ telegram_api::object_ptr VideosManager::get_story_docu } return telegram_api::make_object( flags, false /*ignored*/, false /*ignored*/, false /*ignored*/, - telegram_api::make_object( - file_view.main_remote_location().as_input_document()), + telegram_api::make_object(main_remote_location->as_input_document()), nullptr, mime_type, std::move(attributes), std::move(added_stickers), 0); } diff --git a/lib/tgchat/ext/td/td/telegram/VoiceNotesManager.cpp b/lib/tgchat/ext/td/td/telegram/VoiceNotesManager.cpp index 826ae3db..a2c7db8c 100644 --- a/lib/tgchat/ext/td/td/telegram/VoiceNotesManager.cpp +++ b/lib/tgchat/ext/td/td/telegram/VoiceNotesManager.cpp @@ -148,8 +148,9 @@ SecretInputMedia VoiceNotesManager::get_secret_input_media(FileId voice_note_fil if (!file_view.is_encrypted_secret() || file_view.encryption_key().empty()) { return SecretInputMedia{}; } - if (file_view.has_remote_location()) { - input_file = file_view.main_remote_location().as_input_encrypted_file(); + const auto *main_remote_location = file_view.get_main_remote_location(); + if (main_remote_location != nullptr) { + input_file = main_remote_location->as_input_encrypted_file(); } if (!input_file) { return SecretInputMedia{}; @@ -172,20 +173,22 @@ tl_object_ptr VoiceNotesManager::get_input_media( if (file_view.is_encrypted()) { return nullptr; } - if (file_view.has_remote_location() && !file_view.main_remote_location().is_web() && input_file == nullptr) { + const auto *main_remote_location = file_view.get_main_remote_location(); + if (main_remote_location != nullptr && !main_remote_location->is_web() && input_file == nullptr) { int32 flags = 0; if (ttl != 0) { flags |= telegram_api::inputMediaDocument::TTL_SECONDS_MASK; } - return make_tl_object( - flags, false /*ignored*/, file_view.main_remote_location().as_input_document(), ttl, string()); + return make_tl_object(flags, false /*ignored*/, + main_remote_location->as_input_document(), ttl, string()); } - if (file_view.has_url()) { + const auto *url = file_view.get_url(); + if (url != nullptr) { int32 flags = 0; if (ttl != 0) { flags |= telegram_api::inputMediaDocumentExternal::TTL_SECONDS_MASK; } - return make_tl_object(flags, false /*ignored*/, file_view.url(), ttl); + return make_tl_object(flags, false /*ignored*/, *url, ttl); } if (input_file != nullptr) { @@ -213,7 +216,7 @@ tl_object_ptr VoiceNotesManager::get_input_media( flags, false /*ignored*/, false /*ignored*/, false /*ignored*/, std::move(input_file), nullptr, mime_type, std::move(attributes), vector>(), ttl); } else { - CHECK(!file_view.has_remote_location()); + CHECK(main_remote_location == nullptr); } return nullptr; diff --git a/lib/tgchat/ext/td/td/telegram/WebPagesManager.cpp b/lib/tgchat/ext/td/td/telegram/WebPagesManager.cpp index ccb16dde..211b29ce 100644 --- a/lib/tgchat/ext/td/td/telegram/WebPagesManager.cpp +++ b/lib/tgchat/ext/td/td/telegram/WebPagesManager.cpp @@ -1591,17 +1591,17 @@ td_api::object_ptr WebPagesManager::get_link_preview_ty if (web_page->type_ == "audio") { return td_api::make_object( web_page->embed_url_, get_photo_object(td_->file_manager_.get(), web_page->photo_), web_page->duration_, - web_page->author_, web_page->embed_dimensions_.width, web_page->embed_dimensions_.height); + web_page->embed_dimensions_.width, web_page->embed_dimensions_.height); } if (web_page->type_ == "gif") { return td_api::make_object( web_page->embed_url_, get_photo_object(td_->file_manager_.get(), web_page->photo_), web_page->duration_, - web_page->author_, web_page->embed_dimensions_.width, web_page->embed_dimensions_.height); + web_page->embed_dimensions_.width, web_page->embed_dimensions_.height); } if (web_page->type_ == "video") { return td_api::make_object( web_page->embed_url_, get_photo_object(td_->file_manager_.get(), web_page->photo_), web_page->duration_, - web_page->author_, web_page->embed_dimensions_.width, web_page->embed_dimensions_.height); + web_page->embed_dimensions_.width, web_page->embed_dimensions_.height); } } else { // ordinary animation/audio/video @@ -1612,13 +1612,15 @@ td_api::object_ptr WebPagesManager::get_link_preview_ty auto audio = web_page->document_.type == Document::Type::Audio ? td_->audios_manager_->get_audio_object(web_page->document_.file_id) : nullptr; - if (audio != nullptr || !web_page->embed_url_.empty()) { - return td_api::make_object( - web_page->embed_url_, web_page->embed_type_, std::move(audio), web_page->duration_, web_page->author_); + if (audio != nullptr) { + return td_api::make_object(std::move(audio)); + } else if (!web_page->embed_url_.empty()) { + return td_api::make_object(web_page->embed_url_, web_page->embed_type_, + web_page->duration_); } else { if (!web_page->photo_.is_empty()) { return td_api::make_object( - get_photo_object(td_->file_manager_.get(), web_page->photo_), web_page->author_); + get_photo_object(td_->file_manager_.get(), web_page->photo_)); } return td_api::make_object(); } @@ -1631,11 +1633,11 @@ td_api::object_ptr WebPagesManager::get_link_preview_ty ? td_->animations_manager_->get_animation_object(web_page->document_.file_id) : nullptr; if (animation != nullptr) { - return td_api::make_object(std::move(animation), web_page->author_); + return td_api::make_object(std::move(animation)); } else { if (!web_page->photo_.is_empty()) { return td_api::make_object( - get_photo_object(td_->file_manager_.get(), web_page->photo_), web_page->author_); + get_photo_object(td_->file_manager_.get(), web_page->photo_)); } return td_api::make_object(); } @@ -1647,14 +1649,16 @@ td_api::object_ptr WebPagesManager::get_link_preview_ty auto video = web_page->document_.type == Document::Type::Video ? td_->videos_manager_->get_video_object(web_page->document_.file_id) : nullptr; - if (video != nullptr || !web_page->embed_url_.empty()) { - return td_api::make_object( - web_page->embed_url_, web_page->embed_type_, std::move(video), web_page->embed_dimensions_.width, - web_page->embed_dimensions_.height, web_page->duration_, web_page->author_); + if (video != nullptr) { + return td_api::make_object(std::move(video)); + } else if (!web_page->embed_url_.empty()) { + return td_api::make_object( + web_page->embed_url_, web_page->embed_type_, web_page->embed_dimensions_.width, + web_page->embed_dimensions_.height, web_page->duration_); } else { if (!web_page->photo_.is_empty()) { return td_api::make_object( - get_photo_object(td_->file_manager_.get(), web_page->photo_), web_page->author_); + get_photo_object(td_->file_manager_.get(), web_page->photo_)); } return td_api::make_object(); } @@ -1667,8 +1671,8 @@ td_api::object_ptr WebPagesManager::get_link_preview_ty if (web_page->type_ == "app") { LOG_IF(ERROR, web_page->document_.type != Document::Type::Unknown) << "Receive wrong document for " << web_page->url_; - return td_api::make_object(get_photo_object(td_->file_manager_.get(), web_page->photo_), - web_page->author_); + return td_api::make_object( + get_photo_object(td_->file_manager_.get(), web_page->photo_)); } if (web_page->type_ == "audio" || (web_page->document_.type == Document::Type::Audio && is_generic)) { LOG_IF(ERROR, !web_page->photo_.is_empty()) << "Receive photo for " << web_page->url_; @@ -1676,9 +1680,7 @@ td_api::object_ptr WebPagesManager::get_link_preview_ty ? td_->audios_manager_->get_audio_object(web_page->document_.file_id) : nullptr; if (audio != nullptr) { - auto duration = audio->duration_; - return td_api::make_object(string(), string(), std::move(audio), duration, - web_page->author_); + return td_api::make_object(std::move(audio)); } else { LOG(ERROR) << "Receive audio without audio for " << web_page->url_; return td_api::make_object(); @@ -1687,18 +1689,18 @@ td_api::object_ptr WebPagesManager::get_link_preview_ty if (web_page->document_.type == Document::Type::General && is_generic) { LOG_IF(ERROR, !web_page->photo_.is_empty()) << "Receive photo for " << web_page->url_; auto document = td_->documents_manager_->get_document_object(web_page->document_.file_id, PhotoFormat::Jpeg); - return td_api::make_object(std::move(document), web_page->author_); + return td_api::make_object(std::move(document)); } if (web_page->type_ == "gif" || (web_page->document_.type == Document::Type::Animation && is_generic)) { auto animation = web_page->document_.type == Document::Type::Animation ? td_->animations_manager_->get_animation_object(web_page->document_.file_id) : nullptr; if (animation != nullptr) { - return td_api::make_object(std::move(animation), web_page->author_); + return td_api::make_object(std::move(animation)); } else { if (!web_page->photo_.is_empty()) { return td_api::make_object( - get_photo_object(td_->file_manager_.get(), web_page->photo_), web_page->author_); + get_photo_object(td_->file_manager_.get(), web_page->photo_)); } LOG(ERROR) << "Receive animation without animation for " << web_page->url_; return td_api::make_object(); @@ -1710,7 +1712,7 @@ td_api::object_ptr WebPagesManager::get_link_preview_ty << "Receive wrong document for " << web_page->url_; auto photo = get_photo_object(td_->file_manager_.get(), web_page->photo_); if (photo != nullptr) { - return td_api::make_object(std::move(photo), web_page->author_); + return td_api::make_object(std::move(photo)); } else { LOG(ERROR) << "Receive photo without photo for " << web_page->url_; return td_api::make_object(); @@ -1725,18 +1727,14 @@ td_api::object_ptr WebPagesManager::get_link_preview_ty ? td_->videos_manager_->get_video_object(web_page->document_.file_id) : nullptr; if (video != nullptr) { - auto width = video->width_; - auto height = video->height_; - auto duration = video->duration_; - return td_api::make_object(string(), string(), std::move(video), width, height, - duration, web_page->author_); + return td_api::make_object(std::move(video)); } else { if (!web_page->photo_.is_empty()) { return td_api::make_object( - get_photo_object(td_->file_manager_.get(), web_page->photo_), web_page->author_); + get_photo_object(td_->file_manager_.get(), web_page->photo_)); } - return td_api::make_object(web_page->url_, "video/mp4", nullptr, 0, 0, - web_page->duration_, web_page->author_); + return td_api::make_object(web_page->url_, "video/mp4", 0, 0, + web_page->duration_); } } if (web_page->document_.type == Document::Type::VideoNote && is_generic) { @@ -1751,7 +1749,7 @@ td_api::object_ptr WebPagesManager::get_link_preview_ty } if (web_page->type_ == "article") { return td_api::make_object( - get_photo_object(td_->file_manager_.get(), web_page->photo_), web_page->author_); + get_photo_object(td_->file_manager_.get(), web_page->photo_)); } LOG(ERROR) << "Receive link preview of unsupported type " << web_page->type_; @@ -1908,8 +1906,8 @@ td_api::object_ptr WebPagesManager::get_link_preview_object web_page->url_, web_page->display_url_, web_page->site_name_, web_page->title_, get_formatted_text_object(td_->user_manager_.get(), description, true, duration == 0 ? std::numeric_limits::max() : duration), - std::move(link_preview_type), web_page->has_large_media_, show_large_media, show_media_above_description, - skip_confirmation, invert_media, instant_view_version); + web_page->author_, std::move(link_preview_type), web_page->has_large_media_, show_large_media, + show_media_above_description, skip_confirmation, invert_media, instant_view_version); } td_api::object_ptr WebPagesManager::get_web_page_instant_view_object( @@ -2149,8 +2147,9 @@ void WebPagesManager::on_get_web_page_instant_view(WebPage *web_page, tl_object_ auto add_document = [&](const Document &document) { auto file_view = td_->file_manager_->get_file_view(document.file_id); - if (file_view.has_remote_location()) { - auto document_id = file_view.remote_location().get_id(); + const auto *full_remote_location = file_view.get_full_remote_location(); + if (full_remote_location != nullptr) { + auto document_id = full_remote_location->get_id(); if (document_id != 0) { get_map(document.type)->emplace(document_id, document.file_id); } else { diff --git a/lib/tgchat/ext/td/td/telegram/cli.cpp b/lib/tgchat/ext/td/td/telegram/cli.cpp index 1ea91980..a07bee05 100644 --- a/lib/tgchat/ext/td/td/telegram/cli.cpp +++ b/lib/tgchat/ext/td/td/telegram/cli.cpp @@ -630,6 +630,9 @@ class CliClient final : public Actor { if (str == "me") { return my_id_; } + if (str == ".") { + return opened_chat_id_; + } if (str[0] == '@') { str.remove_prefix(1); } @@ -650,9 +653,12 @@ class CliClient final : public Actor { return transform(autosplit(user_ids), [this](Slice str) { return as_user_id(str); }); } - static int64 as_basic_group_id(Slice str) { + int64 as_basic_group_id(Slice str) const { str = trim(str); auto result = to_integer(str); + if (str == ".") { + result = opened_chat_id_; + } if (result < 0) { return -result; } @@ -672,6 +678,9 @@ class CliClient final : public Actor { return it->second; } auto result = to_integer(str); + if (str == ".") { + result = opened_chat_id_; + } auto shift = static_cast(-1000000000000ll); if (result <= shift) { return shift - result; @@ -679,9 +688,12 @@ class CliClient final : public Actor { return result; } - static int32 as_secret_chat_id(Slice str) { + int32 as_secret_chat_id(Slice str) const { str = trim(str); auto result = to_integer(str); + if (str == ".") { + result = opened_chat_id_; + } auto shift = static_cast(-2000000000000ll); if (result <= shift + std::numeric_limits::max()) { return static_cast(result - shift); @@ -1046,23 +1058,23 @@ class CliClient final : public Actor { } } - struct PremiumGiveawayParameters { + struct GiveawayParameters { int64 chat_id = 0; vector additional_chat_ids; int32 date; vector country_codes; - operator td_api::object_ptr() const { + operator td_api::object_ptr() const { if (chat_id == 0) { return nullptr; } - return td_api::make_object(chat_id, vector(additional_chat_ids), date, - rand_bool(), rand_bool(), - vector(country_codes), "prize"); + return td_api::make_object(chat_id, vector(additional_chat_ids), date, + rand_bool(), rand_bool(), vector(country_codes), + "prize"); } }; - void get_args(string &args, PremiumGiveawayParameters &arg) const { + void get_args(string &args, GiveawayParameters &arg) const { auto parts = autosplit(args); if (args.size() < 3) { return; @@ -2323,8 +2335,8 @@ class CliClient final : public Actor { } static td_api::object_ptr as_theme_parameters() { - return td_api::make_object(0, 1, -1, 256, 65536, 123456789, 65535, 5, 55, 555, 5555, 55555, - 555555, 123); + return td_api::make_object(0, 1, -1, 123, 256, 65536, 123456789, 65535, 5, 55, 555, 5555, + 55555, 555555, 123); } static td_api::object_ptr as_background_fill(int32 color) { @@ -2970,12 +2982,18 @@ class CliClient final : public Actor { auto reaction_types = transform(autosplit_str(reactions), as_reaction_type); send_request(td_api::make_object(chat_id, message_id, std::move(reaction_types), op == "reactbotbig")); - } else if (op == "apmr" || op == "apmra") { + } else if (op == "appmr" || op == "appmra" || op == "appmrd") { ChatId chat_id; MessageId message_id; int64 star_count; get_args(args, chat_id, message_id, star_count); - send_request(td_api::make_object(chat_id, message_id, star_count, op == "apmra")); + send_request(td_api::make_object(chat_id, message_id, star_count, + op == "appmrd", op == "appmra")); + } else if (op == "cppmr") { + ChatId chat_id; + MessageId message_id; + get_args(args, chat_id, message_id); + send_request(td_api::make_object(chat_id, message_id)); } else if (op == "rppmr") { ChatId chat_id; MessageId message_id; @@ -3452,22 +3470,26 @@ class CliClient final : public Actor { send_request(td_api::make_object(args)); } else if (op == "apgc") { send_request(td_api::make_object(args)); - } else if (op == "lppg") { + } else if (op == "lpg") { int64 giveaway_id; - PremiumGiveawayParameters parameters; - get_args(args, giveaway_id, parameters); - send_request(td_api::make_object(giveaway_id, parameters)); - } else if (op == "gpgi") { + int32 user_count; + int64 star_count; + GiveawayParameters parameters; + get_args(args, giveaway_id, user_count, star_count, parameters); + send_request(td_api::make_object(giveaway_id, parameters, user_count, star_count)); + } else if (op == "ggi") { ChatId chat_id; MessageId message_id; get_args(args, chat_id, message_id); - send_request(td_api::make_object(chat_id, message_id)); + send_request(td_api::make_object(chat_id, message_id)); } else if (op == "gspo") { send_request(td_api::make_object()); } else if (op == "gsgpo") { UserId user_id; get_args(args, user_id); send_request(td_api::make_object(user_id)); + } else if (op == "gsgapo") { + send_request(td_api::make_object()); } else if (op == "gsta" || op == "gsti" || op == "gsto") { string owner_id; string subscription_id; @@ -3514,12 +3536,22 @@ class CliClient final : public Actor { vector{user_id}))); } } else if (op == "cpfsg") { - PremiumGiveawayParameters parameters; + GiveawayParameters parameters; string currency; int64 amount; get_args(args, parameters, currency, amount); send_request(td_api::make_object( td_api::make_object(parameters, currency, amount))); + } else if (op == "cpfssg") { + GiveawayParameters parameters; + string currency; + int64 amount; + int32 user_count; + int64 star_count; + get_args(args, parameters, currency, amount, user_count, star_count); + send_request(td_api::make_object( + td_api::make_object(parameters, currency, amount, user_count, + star_count))); } else if (op == "cpfss") { string currency; int64 amount; @@ -3581,6 +3613,10 @@ class CliClient final : public Actor { int64 sticker_set_id; get_args(args, sticker_set_id); send_request(td_api::make_object(sticker_set_id)); + } else if (op == "gssn") { + int64 sticker_set_id; + get_args(args, sticker_set_id); + send_request(td_api::make_object(sticker_set_id)); } else if (op == "giss" || op == "gissm" || op == "gisse") { send_request(td_api::make_object(as_sticker_type(op))); } else if (op == "gass" || op == "gassm" || op == "gasse") { @@ -4913,11 +4949,11 @@ class CliClient final : public Actor { get_args(args, user_id, is_added, allow_write_access); send_request( td_api::make_object(user_id, is_added, allow_write_access)); - } else if (op == "gpwab") { + } else if (op == "ggwab") { string offset; string limit; get_args(args, offset, limit); - send_request(td_api::make_object(offset, as_limit(limit))); + send_request(td_api::make_object(offset, as_limit(limit))); } else if (op == "swa") { UserId bot_user_id; string short_name; @@ -5070,8 +5106,8 @@ class CliClient final : public Actor { return td_api::make_object(td_api::make_object(), as_input_file(photo), nullptr, vector(), 0, 0); }); - send_message(chat_id, td_api::make_object(11, std::move(paid_media), - as_caption("12_3_ __4__"), rand_bool())); + send_message(chat_id, td_api::make_object( + 11, std::move(paid_media), as_caption("12_3_ __4__"), rand_bool(), "photo")); } else if (op == "spmv") { ChatId chat_id; get_args(args, chat_id, args); @@ -5080,8 +5116,8 @@ class CliClient final : public Actor { td_api::make_object(10, true), as_input_file(video), nullptr, vector(), 0, 0); }); - send_message(chat_id, td_api::make_object(12, std::move(paid_media), - as_caption("12_3_ __4__"), rand_bool())); + send_message(chat_id, td_api::make_object( + 12, std::move(paid_media), as_caption("12_3_ __4__"), rand_bool(), "video")); } else if (op == "smap") { ChatId chat_id; get_args(args, chat_id, args); diff --git a/lib/tgchat/ext/td/td/telegram/files/FileDownloadManager.h b/lib/tgchat/ext/td/td/telegram/files/FileDownloadManager.h index e1052799..9366c084 100644 --- a/lib/tgchat/ext/td/td/telegram/files/FileDownloadManager.h +++ b/lib/tgchat/ext/td/td/telegram/files/FileDownloadManager.h @@ -39,7 +39,7 @@ class FileDownloadManager final : public Actor { virtual void on_error(QueryId query_id, Status status) = 0; }; - explicit FileDownloadManager(unique_ptr callback, ActorShared<> parent); + FileDownloadManager(unique_ptr callback, ActorShared<> parent); void download(QueryId query_id, const FullRemoteFileLocation &remote_location, const LocalFileLocation &local, int64 size, string name, const FileEncryptionKey &encryption_key, bool need_search_file, int64 offset, diff --git a/lib/tgchat/ext/td/td/telegram/files/FileGenerateManager.cpp b/lib/tgchat/ext/td/td/telegram/files/FileGenerateManager.cpp index 55ee9036..61a32029 100644 --- a/lib/tgchat/ext/td/td/telegram/files/FileGenerateManager.cpp +++ b/lib/tgchat/ext/td/td/telegram/files/FileGenerateManager.cpp @@ -97,8 +97,9 @@ class FileDownloadGenerateActor final : public FileGenerateActor { [file_type = file_type_, file_id = file_id_, callback = std::move(callback_)]() mutable { auto file_view = G()->td().get_actor_unsafe()->file_manager_->get_file_view(file_id); CHECK(!file_view.empty()); - if (file_view.has_local_location()) { - auto location = file_view.local_location(); + const auto *full_local_location = file_view.get_full_local_location(); + if (full_local_location != nullptr) { + auto location = *full_local_location; location.file_type_ = file_type; callback->on_ok(std::move(location)); } else { diff --git a/lib/tgchat/ext/td/td/telegram/files/FileHashUploader.h b/lib/tgchat/ext/td/td/telegram/files/FileHashUploader.h index 509753c1..33b936ce 100644 --- a/lib/tgchat/ext/td/td/telegram/files/FileHashUploader.h +++ b/lib/tgchat/ext/td/td/telegram/files/FileHashUploader.h @@ -9,6 +9,7 @@ #include "td/telegram/files/FileLoaderActor.h" #include "td/telegram/files/FileLocation.h" #include "td/telegram/files/ResourceManager.h" +#include "td/telegram/net/NetQuery.h" #include "td/actor/actor.h" diff --git a/lib/tgchat/ext/td/td/telegram/files/FileLoaderUtils.cpp b/lib/tgchat/ext/td/td/telegram/files/FileLoaderUtils.cpp index a205fa8e..23589451 100644 --- a/lib/tgchat/ext/td/td/telegram/files/FileLoaderUtils.cpp +++ b/lib/tgchat/ext/td/td/telegram/files/FileLoaderUtils.cpp @@ -305,7 +305,7 @@ Result check_full_local_location(FullLocalLocationInfo lo return Status::Error(400, "File must be non-empty"); } - if (size == 0) { + if (size <= 0) { size = stat.size_; } if (location.mtime_nsec_ == 0) { diff --git a/lib/tgchat/ext/td/td/telegram/files/FileManager.cpp b/lib/tgchat/ext/td/td/telegram/files/FileManager.cpp index 541482e0..2e928ec4 100644 --- a/lib/tgchat/ext/td/td/telegram/files/FileManager.cpp +++ b/lib/tgchat/ext/td/td/telegram/files/FileManager.cpp @@ -533,16 +533,18 @@ string FileNode::suggested_path() const { } /*** FileView ***/ -bool FileView::has_local_location() const { +bool FileView::has_full_local_location() const { return node_->local_.type() == LocalFileLocation::Type::Full; } -const FullLocalFileLocation &FileView::local_location() const { - CHECK(has_local_location()); - return node_->local_.full(); +const FullLocalFileLocation *FileView::get_full_local_location() const { + if (!has_full_local_location()) { + return nullptr; + } + return &node_->local_.full(); } -bool FileView::has_remote_location() const { +bool FileView::has_full_remote_location() const { return static_cast(node_->remote_.full); } @@ -551,50 +553,54 @@ bool FileView::has_alive_remote_location() const { } bool FileView::has_active_upload_remote_location() const { - if (!has_remote_location()) { + const auto *main_remote_location = get_main_remote_location(); + if (main_remote_location == nullptr) { return false; } if (!has_alive_remote_location()) { return false; } - if (main_remote_location().is_encrypted_any()) { + if (main_remote_location->is_encrypted_any()) { return true; } - return main_remote_location().has_file_reference(); + return main_remote_location->has_file_reference(); } bool FileView::has_active_download_remote_location() const { - if (!has_remote_location()) { + const auto *full_remote_location = get_full_remote_location(); + if (full_remote_location == nullptr) { return false; } - auto &remote = remote_location(); - if (remote.is_encrypted_any()) { + if (full_remote_location->is_encrypted_any()) { return true; } - return remote.has_file_reference(); + return full_remote_location->has_file_reference(); } -const FullRemoteFileLocation &FileView::remote_location() const { - CHECK(has_remote_location()); - auto *remote = node_.get_remote(); - if (remote) { - return *remote; +const FullRemoteFileLocation *FileView::get_full_remote_location() const { + const auto *remote = node_.get_remote(); + if (remote != nullptr) { + return remote; + } + if (!has_full_remote_location()) { + return nullptr; } - return node_->remote_.full.value(); + return &node_->remote_.full.value(); } -const FullRemoteFileLocation &FileView::main_remote_location() const { - CHECK(has_remote_location()); - return node_->remote_.full.value(); +const FullRemoteFileLocation *FileView::get_main_remote_location() const { + if (!has_full_remote_location()) { + return nullptr; + } + return &node_->remote_.full.value(); } bool FileView::has_generate_location() const { return node_->generate_ != nullptr; } -const FullGenerateFileLocation &FileView::generate_location() const { - CHECK(has_generate_location()); - return *node_->generate_; +const FullGenerateFileLocation *FileView::get_generate_location() const { + return node_->generate_.get(); } int64 FileView::size() const { @@ -759,11 +765,14 @@ bool FileView::has_url() const { return !node_->url_.empty(); } -const string &FileView::url() const { - return node_->url_; +const string *FileView::get_url() const { + if (!has_url()) { + return nullptr; + } + return &node_->url_; } -const string &FileView::remote_name() const { +string FileView::remote_name() const { return node_->remote_name_; } @@ -787,20 +796,20 @@ bool FileView::empty() const { } bool FileView::can_download_from_server() const { - if (!has_remote_location()) { + const auto *full_remote_location = get_full_remote_location(); + if (full_remote_location == nullptr) { return false; } - auto &remote = remote_location(); - if (remote.file_type_ == FileType::Encrypted && encryption_key().empty()) { + if (full_remote_location->file_type_ == FileType::Encrypted && encryption_key().empty()) { return false; } - if (remote.is_web()) { + if (full_remote_location->is_web()) { return true; } - if (remote.get_dc_id().is_empty()) { + if (full_remote_location->get_dc_id().is_empty()) { return false; } - if (!remote.is_encrypted_any() && !remote.has_file_reference() && + if (!full_remote_location->is_encrypted_any() && !full_remote_location->has_file_reference() && ((node_->download_id_ == 0 && node_->download_was_update_file_reference_) || !node_->remote_.is_full_alive)) { return false; } @@ -1198,9 +1207,8 @@ FileId FileManager::copy_file_id(FileId file_id, FileType file_type, DialogId ow auto file_view = get_file_view(file_id); auto download_file_id = dup_file_id(file_id, source); auto result_file_id = - register_generate(file_type, FileLocationSource::FromServer, file_view.suggested_path(), - PSTRING() << "#file_id#" << download_file_id.get(), owner_dialog_id, file_view.size()) - .ok(); + register_generate(file_type, file_view.suggested_path(), PSTRING() << "#file_id#" << download_file_id.get(), + owner_dialog_id, file_view.size()); LOG(INFO) << "Copy file " << file_id << " to " << result_file_id << " from " << source; return result_file_id; } @@ -1212,18 +1220,18 @@ FileId FileManager::create_file_id(int32 file_node_id, FileNode *file_node) { return file_id; } -void FileManager::try_forget_file_id(FileId file_id) { +bool FileManager::try_forget_file_id(FileId file_id) { auto *info = get_file_id_info(file_id); if (info->send_updates_flag_ || info->pin_flag_ || info->sent_file_id_flag_) { LOG(DEBUG) << "Can't forget file " << file_id << ", because of" << (info->send_updates_flag_ ? " (sent updates)" : "") << (info->pin_flag_ ? " (pin)" : "") << (info->sent_file_id_flag_ ? " (sent file identifier)" : ""); - return; + return false; } auto file_node = get_file_node(file_id); if (file_node->main_file_id_ == file_id) { LOG(DEBUG) << "Can't forget main file " << file_id; - return; + return false; } LOG(DEBUG) << "Forget file " << file_id; @@ -1231,10 +1239,28 @@ void FileManager::try_forget_file_id(FileId file_id) { CHECK(is_removed); *info = FileIdInfo(); empty_file_ids_.push_back(file_id.get()); + return true; } FileId FileManager::register_empty(FileType type) { - return register_local(FullLocalFileLocation(type, "", 0), DialogId(), 0, false, true).ok(); + auto location = FullLocalFileLocation(type, "", 0); + auto &file_id = local_location_to_file_id_[location]; + if (file_id.is_valid()) { + return file_id; + } + file_id = next_file_id(); + + LOG(INFO) << "Register empty file as " << file_id; + auto file_node_id = next_file_node_id(); + file_nodes_[file_node_id] = + td::make_unique(LocalFileLocation(std::move(location)), NewRemoteFileLocation(), nullptr, 0, 0, + string(), string(), DialogId(), FileEncryptionKey(), file_id, static_cast(0)); + + auto file_id_info = get_file_id_info(file_id); + file_id_info->node_id_ = file_node_id; + file_id_info->pin_flag_ = true; + + return file_id; } void FileManager::on_file_unlink(const FullLocalFileLocation &location) { @@ -1252,48 +1278,135 @@ void FileManager::on_file_unlink(const FullLocalFileLocation &location) { } Result FileManager::register_local(FullLocalFileLocation location, DialogId owner_dialog_id, int64 size, - bool get_by_hash, bool force, bool skip_file_size_checks, - FileId merge_file_id) { - // TODO: use get_by_hash - FileData data; - data.local_ = LocalFileLocation(std::move(location)); - data.owner_dialog_id_ = owner_dialog_id; - data.size_ = size; - return register_file(std::move(data), FileLocationSource::None /*won't be used*/, merge_file_id, "register_local", - force, skip_file_size_checks); + bool get_by_hash, bool skip_file_size_checks, FileId merge_file_id) { + TRY_RESULT(info, check_full_local_location({std::move(location), size}, skip_file_size_checks)); + location = std::move(info.location_); + size = info.size_; + + if (bad_paths_.count(location.path_) != 0) { + return Status::Error(400, "Sending of internal database files is forbidden"); + } + + auto &file_id = local_location_to_file_id_[location]; + bool is_new = false; + if (!file_id.is_valid()) { + file_id = next_file_id(); + LOG(INFO) << "Register " << location << " as " << file_id; + + auto file_node_id = next_file_node_id(); + auto &node = file_nodes_[file_node_id]; + node = td::make_unique(LocalFileLocation(std::move(location)), NewRemoteFileLocation(), nullptr, size, 0, + string(), string(), owner_dialog_id, FileEncryptionKey(), file_id, + static_cast(0)); + node->need_load_from_pmc_ = true; + get_file_id_info(file_id)->node_id_ = file_node_id; + is_new = true; + } + + if (merge_file_id.is_valid()) { + auto status = merge(file_id, merge_file_id); + if (status.is_ok()) { + auto node = get_file_node(file_id); + auto main_file_id = node->main_file_id_; + if (main_file_id != file_id) { + if (is_new) { + bool is_removed = try_forget_file_id(file_id); + CHECK(is_removed); + node = get_file_node(main_file_id); + } + file_id = main_file_id; + } + try_flush_node(node, "register_local"); + } + if (is_new) { + get_file_id_info(file_id)->pin_flag_ = true; + } + if (status.is_error()) { + return std::move(status); + } + } else if (is_new) { + get_file_id_info(file_id)->pin_flag_ = true; + } + return file_id; } FileId FileManager::register_remote(FullRemoteFileLocation location, FileLocationSource file_location_source, DialogId owner_dialog_id, int64 size, int64 expected_size, string remote_name) { - FileData data; + if (size < 0) { + LOG(ERROR) << "Receive file " << location << " of size " << size; + size = 0; + } + if (expected_size < 0) { + LOG(ERROR) << "Receive file " << location << " of expected size " << expected_size; + expected_size = 0; + } auto url = location.get_url(); - data.remote_ = RemoteFileLocation(std::move(location)); - data.owner_dialog_id_ = owner_dialog_id; - data.size_ = size; - data.expected_size_ = expected_size; - data.remote_name_ = std::move(remote_name); - - auto file_id = register_file(std::move(data), file_location_source, FileId(), "register_remote", false).move_as_ok(); - if (!url.empty()) { - auto file_node = get_file_node(file_id); - CHECK(file_node); - file_node->set_url(url); + + FileId file_id; + FileId merge_file_id; + int32 remote_key = 0; + if (context_->keep_exact_remote_location()) { + file_id = next_file_id(); + RemoteInfo info{location, file_location_source, file_id}; + remote_key = remote_location_info_.add(info); + auto &stored_info = remote_location_info_.get(remote_key); + if (stored_info.file_id_ != file_id) { + merge_file_id = stored_info.file_id_; + if (merge_choose_remote_location(location, file_location_source, stored_info.remote_, + stored_info.file_location_source_) == 0) { + stored_info.remote_ = location; + stored_info.file_location_source_ = file_location_source; + } + } + } else { + auto &other_id = remote_location_to_file_id_[location]; + if (other_id.is_valid() && get_file_node(other_id)->remote_.full_source == FileLocationSource::FromServer) { + // if the file has already been received from the server, then we don't need merge or create new file + // skip merging of dc_id, file_reference, and access_hash + return other_id; + } + + file_id = next_file_id(); + if (other_id.empty()) { + other_id = file_id; + } else { + merge_file_id = other_id; + } } - return file_id; + + LOG(INFO) << "Register " << location << " as " << file_id; + auto file_node_id = next_file_node_id(); + auto &node = file_nodes_[file_node_id]; + node = td::make_unique(LocalFileLocation(), + NewRemoteFileLocation(RemoteFileLocation(std::move(location)), file_location_source), + nullptr, size, expected_size, std::move(remote_name), std::move(url), + owner_dialog_id, FileEncryptionKey(), file_id, static_cast(1)); + get_file_id_info(file_id)->node_id_ = file_node_id; + + auto main_file_id = file_id; + if (!merge_file_id.is_valid()) { + node->need_load_from_pmc_ = true; + get_file_id_info(main_file_id)->pin_flag_ = true; + } else { + // may invalidate node + merge(file_id, merge_file_id, true).ignore(); + try_flush_node(get_file_node(file_id), "register_remote"); + + main_file_id = get_file_node(file_id)->main_file_id_; + if (main_file_id != file_id) { + try_forget_file_id(file_id); + } + } + return FileId(main_file_id.get(), remote_key); } -FileId FileManager::register_url(string url, FileType file_type, FileLocationSource file_location_source, - DialogId owner_dialog_id) { - auto file_id = register_generate(file_type, file_location_source, url, "#url#", owner_dialog_id, 0).ok(); - auto file_node = get_file_node(file_id); - CHECK(file_node); - file_node->set_url(url); - return file_id; +FileId FileManager::register_url(string url, FileType file_type, DialogId owner_dialog_id) { + return do_register_generate(td::make_unique(file_type, url, "#url#"), owner_dialog_id, 0, + url); } -Result FileManager::register_generate(FileType file_type, FileLocationSource file_location_source, - string original_path, string conversion, DialogId owner_dialog_id, - int64 expected_size) { +FileId FileManager::register_generate(FileType file_type, string original_path, string conversion, + DialogId owner_dialog_id, int64 expected_size) { // add #mtime# into conversion if (!original_path.empty() && conversion[0] != '#' && PathView(original_path).is_absolute()) { auto file_paths = log_interface->get_file_paths(); @@ -1303,21 +1416,37 @@ Result FileManager::register_generate(FileType file_type, FileLocationSo conversion = PSTRING() << "#mtime#" << lpad0(to_string(mtime), 20) << '#' << conversion; } } + return do_register_generate( + td::make_unique(file_type, std::move(original_path), std::move(conversion)), + owner_dialog_id, max(expected_size, static_cast(0)), string()); +} - FileData data; - data.generate_ = - td::make_unique(file_type, std::move(original_path), std::move(conversion)); - data.owner_dialog_id_ = owner_dialog_id; - data.expected_size_ = expected_size; - return register_file(std::move(data), file_location_source, FileId(), "register_generate", false); +FileId FileManager::do_register_generate(unique_ptr generate, DialogId owner_dialog_id, + int64 expected_size, string url) { + auto &file_id = generate_location_to_file_id_[*generate]; + if (!file_id.is_valid()) { + file_id = next_file_id(); + LOG(INFO) << "Register " << *generate << " as " << file_id; + + auto file_node_id = next_file_node_id(); + auto &node = file_nodes_[file_node_id]; + node = td::make_unique(LocalFileLocation(), NewRemoteFileLocation(), std::move(generate), 0, + expected_size, string(), std::move(url), owner_dialog_id, FileEncryptionKey(), + file_id, static_cast(0)); + node->need_load_from_pmc_ = true; + + auto file_id_info = get_file_id_info(file_id); + file_id_info->node_id_ = file_node_id; + file_id_info->pin_flag_ = true; + } + return file_id; } Result FileManager::register_file(FileData &&data, FileLocationSource file_location_source, - FileId merge_file_id, const char *source, bool force, - bool skip_file_size_checks) { + const char *source) { bool has_remote = data.remote_.type() == RemoteFileLocation::Type::Full; bool has_generate = data.generate_ != nullptr; - if (data.local_.type() == LocalFileLocation::Type::Full && !force) { + if (data.local_.type() == LocalFileLocation::Type::Full) { bool is_from_database = file_location_source == FileLocationSource::FromBinlog || file_location_source == FileLocationSource::FromDatabase; if (is_from_database) { @@ -1330,7 +1459,7 @@ Result FileManager::register_file(FileData &&data, FileLocationSource fi if (file_location_source != FileLocationSource::FromDatabase) { Status status; - auto r_info = check_full_local_location({data.local_.full(), data.size_}, skip_file_size_checks); + auto r_info = check_full_local_location({data.local_.full(), data.size_}, false); if (r_info.is_error()) { status = r_info.move_as_error(); } else if (bad_paths_.count(r_info.ok().location_.path_) != 0) { @@ -1352,7 +1481,7 @@ Result FileManager::register_file(FileData &&data, FileLocationSource fi } } else { // the location has been checked previously, but recheck it just in case - recheck_full_local_location({data.local_.full(), data.size_}, skip_file_size_checks); + recheck_full_local_location({data.local_.full(), data.size_}, false); } } bool has_local = data.local_.type() == LocalFileLocation::Type::Full; @@ -1382,7 +1511,6 @@ Result FileManager::register_file(FileData &&data, FileLocationSource fi std::move(data.encryption_key_), file_id, static_cast(has_remote)); node->pmc_id_ = FileDbId(data.pmc_id_); get_file_id_info(file_id)->node_id_ = file_node_id; - node->file_ids_.push_back(file_id); FileView file_view(get_file_node(file_id)); @@ -1400,9 +1528,10 @@ Result FileManager::register_file(FileData &&data, FileLocationSource fi bool new_remote = false; FileId *new_remote_file_id = nullptr; int32 remote_key = 0; - if (file_view.has_remote_location()) { + const auto *full_remote_location = file_view.get_full_remote_location(); + if (full_remote_location != nullptr) { if (context_->keep_exact_remote_location()) { - RemoteInfo info{file_view.remote_location(), file_location_source, file_id}; + RemoteInfo info{*full_remote_location, file_location_source, file_id}; remote_key = remote_location_info_.add(info); auto &stored_info = remote_location_info_.get(remote_key); if (stored_info.file_id_ == file_id) { @@ -1410,29 +1539,31 @@ Result FileManager::register_file(FileData &&data, FileLocationSource fi new_remote = true; } else { to_merge.push_back(stored_info.file_id_); - if (merge_choose_remote_location(file_view.remote_location(), file_location_source, stored_info.remote_, + if (merge_choose_remote_location(*full_remote_location, file_location_source, stored_info.remote_, stored_info.file_location_source_) == 0) { - stored_info.remote_ = file_view.remote_location(); + stored_info.remote_ = *full_remote_location; stored_info.file_location_source_ = file_location_source; } } } else { - new_remote_file_id = register_location(file_view.remote_location(), remote_location_to_file_id_); + new_remote_file_id = register_location(*full_remote_location, remote_location_to_file_id_); new_remote = new_remote_file_id != nullptr; } } FileId *new_local_file_id = nullptr; - if (file_view.has_local_location()) { - new_local_file_id = register_location(file_view.local_location(), local_location_to_file_id_); + const auto *full_local_location = file_view.get_full_local_location(); + if (full_local_location != nullptr) { + new_local_file_id = register_location(*full_local_location, local_location_to_file_id_); } FileId *new_generate_file_id = nullptr; - if (file_view.has_generate_location()) { - new_generate_file_id = register_location(file_view.generate_location(), generate_location_to_file_id_); + const auto *generate_location = file_view.get_generate_location(); + if (generate_location != nullptr) { + new_generate_file_id = register_location(*generate_location, generate_location_to_file_id_); } td::unique(to_merge); int new_cnt = new_remote + (new_local_file_id != nullptr) + (new_generate_file_id != nullptr); - if (data.pmc_id_ == 0 && file_db_ && new_cnt > 0) { + if (data.pmc_id_ == 0 && new_cnt > 0) { node->need_load_from_pmc_ = true; } bool no_sync_merge = to_merge.size() == 1 && new_cnt == 0; @@ -1440,10 +1571,6 @@ Result FileManager::register_file(FileData &&data, FileLocationSource fi // may invalidate node merge(file_id, id, no_sync_merge).ignore(); } - Status status; - if (merge_file_id.is_valid()) { - status = merge(file_id, merge_file_id); - } try_flush_node(get_file_node(file_id), "register_file"); auto main_file_id = get_file_node(file_id)->main_file_id_; @@ -1470,9 +1597,6 @@ Result FileManager::register_file(FileData &&data, FileLocationSource fi context_->add_file_source(main_file_id, file_source_id); } } - if (status.is_error()) { - return std::move(status); - } return FileId(main_file_id.get(), remote_key); } @@ -1883,7 +2007,7 @@ Status FileManager::merge(FileId x_file_id, FileId y_file_id, bool no_sync) { // Check if some download/upload queries are ready for (auto file_id : vector(node->file_ids_)) { auto *info = get_file_id_info(file_id); - if (info->download_priority_ != 0 && file_view.has_local_location()) { + if (info->download_priority_ != 0 && file_view.has_full_local_location()) { info->download_priority_ = 0; if (info->download_callback_) { info->download_callback_->on_download_ok(file_id); @@ -1922,16 +2046,16 @@ void FileManager::try_merge_documents(FileId old_file_id, FileId new_file_id) { FileView new_file_view = get_file_view(new_file_id); // if file type has changed, but file size remains the same, we are trying to update local location of the new // file with the old local location - if (old_file_view.has_local_location() && !new_file_view.has_local_location() && old_file_view.size() != 0 && - old_file_view.size() == new_file_view.size()) { + if (old_file_view.has_full_local_location() && !new_file_view.has_full_local_location() && + old_file_view.size() != 0 && old_file_view.size() == new_file_view.size()) { auto old_file_type = old_file_view.get_type(); auto new_file_type = new_file_view.get_type(); if (is_document_file_type(old_file_type) && is_document_file_type(new_file_type)) { - auto &old_location = old_file_view.local_location(); + const auto *old_location = old_file_view.get_full_local_location(); auto r_file_id = - register_local(FullLocalFileLocation(new_file_type, old_location.path_, old_location.mtime_nsec_), DialogId(), - old_file_view.size()); + register_local(FullLocalFileLocation(new_file_type, old_location->path_, old_location->mtime_nsec_), + DialogId(), old_file_view.size()); if (r_file_id.is_ok()) { LOG_STATUS(merge(new_file_id, r_file_id.ok())); } @@ -2074,11 +2198,11 @@ void FileManager::clear_from_pmc(FileNodePtr node) { LOG(INFO) << "Delete files " << format::as_array(node->file_ids_) << " from pmc"; FileData data; auto file_view = FileView(node); - if (file_view.has_local_location()) { + if (file_view.has_full_local_location()) { data.local_ = node->local_; prepare_path_for_pmc(data.local_.full().file_type_, data.local_.full().path_); } - if (file_view.has_remote_location()) { + if (file_view.has_full_remote_location()) { data.remote_ = RemoteFileLocation(*node->remote_.full); } if (file_view.has_generate_location()) { @@ -2093,7 +2217,7 @@ void FileManager::flush_to_pmc(FileNodePtr node, bool new_remote, bool new_local if (!file_db_) { return; } - FileView view(node); + FileView file_view(node); bool create_flag = false; if (node->pmc_id_.empty()) { create_flag = true; @@ -2130,8 +2254,8 @@ void FileManager::flush_to_pmc(FileNodePtr node, bool new_remote, bool new_local data.encryption_key_ = node->encryption_key_; data.url_ = node->url_; data.owner_dialog_id_ = node->owner_dialog_id_; - data.file_source_ids_ = context_->get_some_file_sources(view.get_main_file_id()); - VLOG(file_references) << "Save file " << view.get_main_file_id() << " to database with " << data.file_source_ids_ + data.file_source_ids_ = context_->get_some_file_sources(file_view.get_main_file_id()); + VLOG(file_references) << "Save file " << file_view.get_main_file_id() << " to database with " << data.file_source_ids_ << " from " << source; file_db_->set_file_data(node->pmc_id_, data, (create_flag || new_remote), (create_flag || new_local), @@ -2165,37 +2289,48 @@ void FileManager::load_from_pmc(FileNodePtr node, bool new_remote, bool new_loca if (!node->need_load_from_pmc_) { return; } - auto file_id = node->main_file_id_; node->need_load_from_pmc_ = false; if (!file_db_) { return; } + auto file_id = node->main_file_id_; auto file_view = get_file_view(file_id); CHECK(!file_view.empty()); FullRemoteFileLocation remote; FullLocalFileLocation local; FullGenerateFileLocation generate; - new_remote &= file_view.has_remote_location(); if (new_remote) { - remote = file_view.remote_location(); + const auto *full_remote_location = file_view.get_full_remote_location(); + if (full_remote_location != nullptr) { + remote = *full_remote_location; + } else { + new_remote = false; + } } - new_local &= file_view.has_local_location(); if (new_local) { - local = file_view.local_location(); - prepare_path_for_pmc(local.file_type_, local.path_); + const auto *full_local_location = file_view.get_full_local_location(); + if (full_local_location != nullptr) { + local = *full_local_location; + prepare_path_for_pmc(local.file_type_, local.path_); + } else { + new_local = false; + } } - new_generate &= file_view.has_generate_location(); if (new_generate) { - generate = file_view.generate_location(); + const auto *generate_location = file_view.get_generate_location(); + if (generate_location != nullptr) { + generate = *generate_location; + } else { + new_generate = false; + } } LOG(DEBUG) << "Load from pmc file " << file_id << '/' << file_view.get_main_file_id() << ", new_remote = " << new_remote << ", new_local = " << new_local << ", new_generate = " << new_generate; auto load = [&](auto location, const char *source) { TRY_RESULT(file_data, file_db_->get_file_data_sync(location)); - TRY_RESULT(new_file_id, - register_file(std::move(file_data), FileLocationSource::FromDatabase, FileId(), source, false)); + TRY_RESULT(new_file_id, register_file(std::move(file_data), FileLocationSource::FromDatabase, source)); TRY_STATUS(merge(file_id, new_file_id)); // merge manually to keep merge parameters order return Status::OK(); }; @@ -2215,8 +2350,8 @@ bool FileManager::set_encryption_key(FileId file_id, FileEncryptionKey key) { if (!node) { return false; } - auto view = FileView(node); - if (view.has_local_location() && view.has_remote_location()) { + auto file_view = FileView(node); + if (file_view.has_full_local_location() && file_view.has_full_remote_location()) { return false; } if (!node->encryption_key_.empty()) { @@ -2270,11 +2405,12 @@ void FileManager::get_content(FileId file_id, Promise promise) { check_local_location(node, true).ignore(); auto file_view = FileView(node); - if (!file_view.has_local_location()) { + const auto *full_local_location = file_view.get_full_local_location(); + if (full_local_location == nullptr) { return promise.set_error(Status::Error("No local location")); } - send_closure(file_load_manager_, &FileLoadManager::get_content, node->local_.full().path_, std::move(promise)); + send_closure(file_load_manager_, &FileLoadManager::get_content, full_local_location->path_, std::move(promise)); } void FileManager::read_file_part(FileId file_id, int64 offset, int64 count, int left_tries, @@ -2312,8 +2448,9 @@ void FileManager::read_file_part(FileId file_id, int64 offset, int64 count, int const string *path = nullptr; bool is_partial = false; - if (file_view.has_local_location()) { - path = &file_view.local_location().path_; + const auto *full_local_location = file_view.get_full_local_location(); + if (full_local_location != nullptr) { + path = &full_local_location->path_; if (!begins_with(*path, get_files_dir(file_view.get_type()))) { return promise.set_error(Status::Error(400, "File is not inside the cache")); } @@ -2362,8 +2499,8 @@ void FileManager::delete_file(FileId file_id, Promise promise, const char send_closure(G()->download_manager(), &DownloadManager::remove_file_if_finished, file_view.get_main_file_id()); string path; - if (file_view.has_local_location()) { - if (begins_with(file_view.local_location().path_, get_files_dir(file_view.get_type()))) { + if (file_view.has_full_local_location()) { + if (begins_with(file_view.get_full_local_location()->path_, get_files_dir(file_view.get_type()))) { clear_from_pmc(node); if (context_->need_notify_on_new_files()) { context_->on_new_file(-file_view.size(), -file_view.get_allocated_local_size(), -1); @@ -2566,7 +2703,7 @@ void FileManager::run_download(FileNodePtr node, bool force_update_priority) { FileDownloadManager::QueryId query_id = download_queries_.create(DownloadQuery{file_id, DownloadQuery::Type::DownloadReloadDialog}); node->download_id_ = query_id; - context_->reload_photo(file_view.remote_location().get_source(), + context_->reload_photo(file_view.get_full_remote_location()->get_source(), PromiseCreator::lambda([actor_id = actor_id(this), query_id, file_id](Result res) { Status error; if (res.is_ok()) { @@ -2817,14 +2954,15 @@ void FileManager::resume_upload(FileId file_id, vector bad_parts, std::shar return; } - if (file_view.has_local_location() && new_priority != 0) { + if (file_view.has_full_local_location() && new_priority != 0) { auto status = check_local_location(node, false); if (status.is_error()) { LOG(INFO) << "Full local location of file " << file_id << " for upload is invalid: " << status; } } - if (!file_view.has_local_location() && !file_view.has_generate_location() && !file_view.has_alive_remote_location()) { + if (!file_view.has_full_local_location() && !file_view.has_generate_location() && + !file_view.has_alive_remote_location()) { LOG(INFO) << "File " << file_id << " can't be uploaded"; if (callback) { callback->on_upload_error( @@ -2833,7 +2971,7 @@ void FileManager::resume_upload(FileId file_id, vector bad_parts, std::shar return; } if (file_view.get_type() == FileType::Thumbnail && - (!file_view.has_local_location() && file_view.can_download_from_server())) { + (!file_view.has_full_local_location() && file_view.can_download_from_server())) { // TODO if (callback) { callback->on_upload_error(file_id, Status::Error(400, "Failed to upload thumbnail without local location")); @@ -2958,7 +3096,7 @@ void FileManager::run_generate(FileNodePtr node) { // LOG(INFO) << "Skip run_generate, because file " << node->main_file_id_ << " can't be generated"; return; } - if (file_view.has_local_location()) { + if (file_view.has_full_local_location()) { LOG(INFO) << "Skip run_generate, because file " << node->main_file_id_ << " has local location"; return; } @@ -3063,13 +3201,14 @@ void FileManager::run_upload(FileNodePtr node, vector bad_parts) { } FileView file_view(node); - if (!file_view.has_local_location() && !file_view.has_remote_location()) { + if (!file_view.has_full_local_location() && !file_view.has_full_remote_location()) { if (node->get_by_hash_ || node->generate_id_ == 0 || !node->generate_was_update_) { LOG(INFO) << "Have no local location for file: get_by_hash = " << node->get_by_hash_ << ", generate_id = " << node->generate_id_ << ", generate_was_update = " << node->generate_was_update_; return; } - if (file_view.has_generate_location() && file_view.generate_location().file_type_ == FileType::SecureEncrypted) { + auto generate_location = file_view.get_generate_location(); + if (generate_location != nullptr && generate_location->file_type_ == FileType::SecureEncrypted) { // Can't upload secure file before its size is known LOG(INFO) << "Can't upload secure file " << node->main_file_id_ << " before it's size is known"; return; @@ -3078,9 +3217,12 @@ void FileManager::run_upload(FileNodePtr node, vector bad_parts) { node->set_upload_priority(priority); + auto generate_location = file_view.get_generate_location(); + auto full_local_location = file_view.get_full_local_location(); + // create encryption key if necessary - if (((file_view.has_generate_location() && file_view.generate_location().file_type_ == FileType::Encrypted) || - (file_view.has_local_location() && file_view.local_location().file_type_ == FileType::Encrypted)) && + if (((generate_location != nullptr && generate_location->file_type_ == FileType::Encrypted) || + (full_local_location != nullptr && full_local_location->file_type_ == FileType::Encrypted)) && file_view.encryption_key().empty()) { CHECK(!node->file_ids_.empty()); bool success = set_encryption_key(node->file_ids_[0], FileEncryptionKey::create()); @@ -3088,7 +3230,7 @@ void FileManager::run_upload(FileNodePtr node, vector bad_parts) { } // create encryption key if necessary - if (file_view.has_local_location() && file_view.local_location().file_type_ == FileType::SecureEncrypted && + if (full_local_location != nullptr && full_local_location->file_type_ == FileType::SecureEncrypted && file_view.encryption_key().empty()) { CHECK(!node->file_ids_.empty()); bool success = set_encryption_key(node->file_ids_[0], FileEncryptionKey::create_secure_key()); @@ -3172,7 +3314,7 @@ Result FileManager::from_persistent_id(CSlice persistent_id, FileType fi if (!clean_input_string(url)) { return Status::Error(400, "URL must be in UTF-8"); } - return register_url(std::move(url), file_type, FileLocationSource::FromUser, DialogId()); + return register_url(std::move(url), file_type, DialogId()); } auto r_binary = base64url_decode(persistent_id); @@ -3211,10 +3353,8 @@ Result FileManager::from_persistent_id_generated(Slice binary, FileType if (!is_remotely_generated_file(generate_location.conversion_)) { return Status::Error(400, "Unexpected conversion type"); } - FileData data; - data.generate_ = make_unique(std::move(generate_location)); - return register_file(std::move(data), FileLocationSource::FromUser, FileId(), "from_persistent_id_generated", false) - .move_as_ok(); + return do_register_generate(make_unique(std::move(generate_location)), DialogId(), 0, + string()); } Result FileManager::from_persistent_id_v23(Slice binary, FileType file_type, int32 version) { @@ -3239,11 +3379,7 @@ Result FileManager::from_persistent_id_v23(Slice binary, FileType file_t } else if (real_file_type != file_type && file_type != FileType::Temp) { return Status::Error(400, PSLICE() << "Can't use file of type " << real_file_type << " as " << file_type); } - FileData data; - data.remote_ = RemoteFileLocation(std::move(remote_location)); - auto file_id = register_file(std::move(data), FileLocationSource::FromUser, FileId(), "from_persistent_id_v23", false) - .move_as_ok(); - return file_id; + return register_remote(std::move(remote_location), FileLocationSource::FromUser, DialogId(), 0, 0, string()); } Result FileManager::from_persistent_id_v2(Slice binary, FileType file_type) { @@ -3368,7 +3504,8 @@ Result FileManager::check_input_file_id(FileType type, Result re } } - if (!file_view.has_remote_location()) { + const auto *full_remote_location = file_view.get_full_remote_location(); + if (full_remote_location == nullptr) { // There are no reasons to dup file_id, because it will be duped anyway before upload/reupload // It will not be duped in dup_message_content only if has_input_media(), // but currently in this case the file never needs to be reuploaded @@ -3384,7 +3521,7 @@ Result FileManager::check_input_file_id(FileType type, Result re int32 remote_id = file_id.get_remote(); if (remote_id == 0 && context_->keep_exact_remote_location()) { - RemoteInfo info{file_view.remote_location(), FileLocationSource::FromUser, file_id}; + RemoteInfo info{*full_remote_location, FileLocationSource::FromUser, file_id}; remote_id = remote_location_info_.add(info); if (remote_location_info_.get(remote_id).file_id_ == file_id) { get_file_id_info(file_id)->pin_flag_ = true; @@ -3413,8 +3550,8 @@ Result FileManager::get_input_thumbnail_file_id(const tl_object_ptr(thumbnail_input_file.get()); return register_generate(is_encrypted ? FileType::EncryptedThumbnail : FileType::Thumbnail, - FileLocationSource::FromUser, generated_thumbnail->original_path_, - generated_thumbnail->conversion_, owner_dialog_id, generated_thumbnail->expected_size_); + generated_thumbnail->original_path_, generated_thumbnail->conversion_, owner_dialog_id, + generated_thumbnail->expected_size_); } default: UNREACHABLE(); @@ -3462,7 +3599,8 @@ Result FileManager::get_input_file_id(FileType type, const tl_object_ptr if (force_reuse) { return file_id; } - if (file_view.has_remote_location() && !file_view.remote_location().is_web()) { + const auto *full_remote_location = file_view.get_full_remote_location(); + if (full_remote_location != nullptr && !full_remote_location->is_web()) { return file_id; } if (file_view.is_uploading()) { @@ -3500,8 +3638,8 @@ Result FileManager::get_input_file_id(FileType type, const tl_object_ptr } case td_api::inputFileGenerated::ID: { auto *generated_file = static_cast(file.get()); - return register_generate(new_type, FileLocationSource::FromUser, generated_file->original_path_, - generated_file->conversion_, owner_dialog_id, generated_file->expected_size_); + return register_generate(new_type, generated_file->original_path_, generated_file->conversion_, owner_dialog_id, + generated_file->expected_size_); } default: UNREACHABLE(); @@ -3542,7 +3680,7 @@ Result FileManager::get_map_thumbnail_file_id(Location location, int32 z << scale << '#'; return register_generate( owner_dialog_id.get_type() == DialogType::SecretChat ? FileType::EncryptedThumbnail : FileType::Thumbnail, - FileLocationSource::FromUser, string(), std::move(conversion), owner_dialog_id, 0); + string(), std::move(conversion), owner_dialog_id, 0); } Result FileManager::get_audio_thumbnail_file_id(string title, string performer, bool is_small, @@ -3572,7 +3710,7 @@ Result FileManager::get_audio_thumbnail_file_id(string title, string per string conversion = PSTRING() << "#audio_t#" << title << '#' << performer << '#' << (is_small ? '1' : '0') << '#'; return register_generate( owner_dialog_id.get_type() == DialogType::SecretChat ? FileType::EncryptedThumbnail : FileType::Thumbnail, - FileLocationSource::FromUser, string(), std::move(conversion), owner_dialog_id, 0); + string(), std::move(conversion), owner_dialog_id, 0); } FileType FileManager::guess_file_type(const tl_object_ptr &file) { @@ -3617,9 +3755,10 @@ vector> FileManager::get_input_docume for (auto file_id : file_ids) { auto file_view = get_file_view(file_id); CHECK(!file_view.empty()); - CHECK(file_view.has_remote_location()); - CHECK(!file_view.remote_location().is_web()); - result.push_back(file_view.remote_location().as_input_document()); + const auto *full_remote_location = file_view.get_full_remote_location(); + CHECK(full_remote_location != nullptr); + CHECK(!full_remote_location->is_web()); + result.push_back(full_remote_location->as_input_document()); } return result; } @@ -3875,7 +4014,7 @@ void FileManager::on_download_ok(FileDownloadManager::QueryId query_id, FullLoca std::tie(query, was_active) = finish_download_query(query_id); auto file_id = query.file_id_; LOG(INFO) << "ON DOWNLOAD OK of " << (is_new ? "new" : "checked") << " file " << file_id << " of size " << size; - auto r_new_file_id = register_local(std::move(local), DialogId(), size, false, false, true, file_id); + auto r_new_file_id = register_local(std::move(local), DialogId(), size, false, true, file_id); Status status = Status::OK(); if (r_new_file_id.is_error()) { status = Status::Error(PSLICE() << "Can't register local file after download: " << r_new_file_id.error().message()); @@ -4035,7 +4174,7 @@ void FileManager::on_generate_ok(FileGenerateManager::QueryId query_id, FullLoca auto old_upload_id = file_node->upload_id_; - auto r_new_file_id = register_local(local, DialogId(), 0, false, false, false, generate_file_id); + auto r_new_file_id = register_local(local, DialogId(), 0, false, false, generate_file_id); file_node = get_file_node(generate_file_id); if (r_new_file_id.is_error()) { return on_generate_error_impl( @@ -4046,7 +4185,8 @@ void FileManager::on_generate_ok(FileGenerateManager::QueryId query_id, FullLoca FileView file_view(file_node); if (context_->need_notify_on_new_files()) { - if (!file_view.has_generate_location() || !begins_with(file_view.generate_location().conversion_, "#file_id#")) { + auto generate_location = file_view.get_generate_location(); + if (generate_location == nullptr || !begins_with(generate_location->conversion_, "#file_id#")) { context_->on_new_file(file_view.size(), file_view.get_allocated_local_size(), 1); } } @@ -4361,6 +4501,48 @@ FullRemoteFileLocation *FileManager::get_remote(int32 key) { return &remote_location_info_.get(key).remote_; } +class FileManager::PreliminaryUploadFileCallback final : public UploadCallback { + public: + void on_upload_ok(FileId file_id, tl_object_ptr input_file) final { + // cancel file upload of the file to allow next upload with the same file to succeed + send_closure(G()->file_manager(), &FileManager::cancel_upload, file_id); + } + + void on_upload_encrypted_ok(FileId file_id, tl_object_ptr input_file) final { + // cancel file upload of the file to allow next upload with the same file to succeed + send_closure(G()->file_manager(), &FileManager::cancel_upload, file_id); + } + + void on_upload_secure_ok(FileId file_id, tl_object_ptr input_file) final { + // cancel file upload of the file to allow next upload with the same file to succeed + send_closure(G()->file_manager(), &FileManager::cancel_upload, file_id); + } + + void on_upload_error(FileId file_id, Status error) final { + } +}; + +void FileManager::preliminary_upload_file(const td_api::object_ptr &input_file, FileType file_type, + int32 priority, Promise> &&promise) { + if (!(1 <= priority && priority <= 32)) { + return promise.set_error(Status::Error(400, "Upload priority must be between 1 and 32")); + } + + bool is_secret = file_type == FileType::Encrypted || file_type == FileType::EncryptedThumbnail; + bool is_secure = file_type == FileType::SecureEncrypted; + auto r_file_id = + get_input_file_id(file_type, input_file, DialogId(), false, is_secret, !is_secure && !is_secret, is_secure); + if (r_file_id.is_error()) { + return promise.set_error(Status::Error(r_file_id.error().code(), r_file_id.error().message())); + } + auto file_id = r_file_id.ok(); + auto upload_file_id = dup_file_id(file_id, "preliminary_upload_file"); + + upload(upload_file_id, std::make_shared(), priority, 0); + + promise.set_value(get_file_object(upload_file_id, false)); +} + Result FileManager::get_suggested_file_name(FileId file_id, const string &directory) { if (!file_id.is_valid()) { return Status::Error(400, "Invalid file identifier"); diff --git a/lib/tgchat/ext/td/td/telegram/files/FileManager.h b/lib/tgchat/ext/td/td/telegram/files/FileManager.h index 24be50da..d83937b9 100644 --- a/lib/tgchat/ext/td/td/telegram/files/FileManager.h +++ b/lib/tgchat/ext/td/td/telegram/files/FileManager.h @@ -87,6 +87,7 @@ class FileNode { , main_file_id_(main_file_id) , main_file_id_priority_(main_file_id_priority) { init_ready_size(); + file_ids_.push_back(main_file_id); } void drop_local_location(); void set_local_location(const LocalFileLocation &local, int64 ready_size, int64 prefix_offset, @@ -290,21 +291,31 @@ class FileView { bool empty() const; - bool has_local_location() const; - const FullLocalFileLocation &local_location() const; - bool has_remote_location() const; + bool has_full_local_location() const; + + const FullLocalFileLocation *get_full_local_location() const; + + bool has_generate_location() const; + + const FullGenerateFileLocation *get_generate_location() const; + + bool has_full_remote_location() const; + bool has_alive_remote_location() const; + bool has_active_upload_remote_location() const; + bool has_active_download_remote_location() const; - const FullRemoteFileLocation &remote_location() const; - const FullRemoteFileLocation &main_remote_location() const; - bool has_generate_location() const; - const FullGenerateFileLocation &generate_location() const; + + const FullRemoteFileLocation *get_full_remote_location() const; + + const FullRemoteFileLocation *get_main_remote_location() const; bool has_url() const; - const string &url() const; - const string &remote_name() const; + const string *get_url() const; + + string remote_name() const; string suggested_path() const; @@ -356,13 +367,14 @@ class FileView { } bool may_reload_photo() const { - if (!has_remote_location()) { + const auto *full_remote_location = get_full_remote_location(); + if (full_remote_location == nullptr) { return false; } - if (!remote_location().is_photo()) { + if (!full_remote_location->is_photo()) { return false; } - auto type = remote_location().get_source().get_type("may_reload_photo"); + auto type = full_remote_location->get_source().get_type("may_reload_photo"); return type != PhotoSizeSource::Type::Legacy && type != PhotoSizeSource::Type::FullLegacy && type != PhotoSizeSource::Type::Thumbnail; } @@ -462,15 +474,17 @@ class FileManager final : public Actor { void on_file_unlink(const FullLocalFileLocation &location); FileId register_empty(FileType type); + Result register_local(FullLocalFileLocation location, DialogId owner_dialog_id, int64 size, - bool get_by_hash = false, bool force = false, bool skip_file_size_checks = false, + bool get_by_hash = false, bool skip_file_size_checks = false, FileId merge_file_id = FileId()) TD_WARN_UNUSED_RESULT; + FileId register_remote(FullRemoteFileLocation location, FileLocationSource file_location_source, DialogId owner_dialog_id, int64 size, int64 expected_size, string remote_name) TD_WARN_UNUSED_RESULT; - Result register_generate(FileType file_type, FileLocationSource file_location_source, string original_path, - string conversion, DialogId owner_dialog_id, - int64 expected_size) TD_WARN_UNUSED_RESULT; + + FileId register_generate(FileType file_type, string original_path, string conversion, DialogId owner_dialog_id, + int64 expected_size) TD_WARN_UNUSED_RESULT; Status merge(FileId x_file_id, FileId y_file_id, bool no_sync = false); @@ -503,6 +517,9 @@ class FileManager final : public Actor { void delete_file_reference(FileId file_id, Slice file_reference); void get_content(FileId file_id, Promise promise); + void preliminary_upload_file(const td_api::object_ptr &input_file, FileType file_type, + int32 priority, Promise> &&promise); + Result get_suggested_file_name(FileId file_id, const string &directory); void read_file_part(FileId file_id, int64 offset, int64 count, int left_tries, @@ -618,13 +635,17 @@ class FileManager final : public Actor { } }; + class PreliminaryUploadFileCallback; + Result check_input_file_id(FileType type, Result result, bool is_encrypted, bool allow_zero, bool is_secure) TD_WARN_UNUSED_RESULT; - FileId register_url(string url, FileType file_type, FileLocationSource file_location_source, - DialogId owner_dialog_id); - Result register_file(FileData &&data, FileLocationSource file_location_source, FileId merge_file_id, - const char *source, bool force, bool skip_file_size_checks = false); + FileId do_register_generate(unique_ptr generate, DialogId owner_dialog_id, + int64 expected_size, string url) TD_WARN_UNUSED_RESULT; + + FileId register_url(string url, FileType file_type, DialogId owner_dialog_id); + + Result register_file(FileData &&data, FileLocationSource file_location_source, const char *source); static constexpr int8 FROM_BYTES_PRIORITY = 10; @@ -721,7 +742,7 @@ class FileManager final : public Actor { FileNodeId next_file_node_id(); int32 next_pmc_file_id(); FileId create_file_id(int32 file_node_id, FileNode *file_node); - void try_forget_file_id(FileId file_id); + bool try_forget_file_id(FileId file_id); void load_from_pmc(FileId file_id, FullLocalFileLocation full_local); void load_from_pmc(FileId file_id, const FullRemoteFileLocation &full_remote); diff --git a/lib/tgchat/ext/td/td/telegram/files/FileManager.hpp b/lib/tgchat/ext/td/td/telegram/files/FileManager.hpp index ea70efe9..5a187832 100644 --- a/lib/tgchat/ext/td/td/telegram/files/FileManager.hpp +++ b/lib/tgchat/ext/td/td/telegram/files/FileManager.hpp @@ -31,13 +31,13 @@ void FileManager::store_file(FileId file_id, StorerT &storer, int32 ttl) const { auto file_store_type = FileStoreType::Empty; auto file_view = get_file_view(file_id); if (file_view.empty() || ttl <= 0) { - } else if (file_view.has_remote_location()) { + } else if (file_view.has_full_remote_location()) { file_store_type = FileStoreType::Remote; } else if (file_view.has_url()) { file_store_type = FileStoreType::Url; } else if (file_view.has_generate_location()) { file_store_type = FileStoreType::Generate; - } else if (file_view.has_local_location()) { + } else if (file_view.has_full_local_location()) { file_store_type = FileStoreType::Local; } @@ -70,11 +70,12 @@ void FileManager::store_file(FileId file_id, StorerT &storer, int32 ttl) const { break; case FileStoreType::Url: store(file_view.get_type(), storer); - store(file_view.url(), storer); + store(*file_view.get_url(), storer); store(file_view.owner_dialog_id(), storer); break; case FileStoreType::Remote: { - store(file_view.remote_location(), storer); + const auto *full_remote_location = file_view.get_full_remote_location(); + store(*full_remote_location, storer); if (has_64bit_size) { store(size, storer); } else { @@ -85,7 +86,7 @@ void FileManager::store_file(FileId file_id, StorerT &storer, int32 ttl) const { break; } case FileStoreType::Local: { - store(file_view.local_location(), storer); + store(*file_view.get_full_local_location(), storer); if (has_64bit_size) { store(size, storer); } else { @@ -96,7 +97,7 @@ void FileManager::store_file(FileId file_id, StorerT &storer, int32 ttl) const { break; } case FileStoreType::Generate: { - auto generate_location = file_view.generate_location(); + auto generate_location = *file_view.get_generate_location(); FileId from_file_id; bool have_file_id = false; if (generate_location.conversion_ == "#_file_id#") { @@ -244,13 +245,8 @@ FileId FileManager::parse_file(ParserT &parser) { full_generated_location.conversion_ = PSTRING() << "#file_id#" << download_file_id.get(); } - auto r_file_id = register_generate(full_generated_location.file_type_, FileLocationSource::FromBinlog, - full_generated_location.original_path_, full_generated_location.conversion_, - owner_dialog_id, expected_size); - if (r_file_id.is_ok()) { - return r_file_id.move_as_ok(); - } - return register_empty(full_generated_location.file_type_); + return register_generate(full_generated_location.file_type_, full_generated_location.original_path_, + full_generated_location.conversion_, owner_dialog_id, expected_size); } case FileStoreType::Url: { FileType type; @@ -261,7 +257,7 @@ FileId FileManager::parse_file(ParserT &parser) { if (parser.version() >= static_cast(Version::StoreFileOwnerId)) { parse(owner_dialog_id, parser); } - return register_url(url, type, FileLocationSource::FromBinlog, owner_dialog_id); + return register_url(url, type, owner_dialog_id); } } return FileId(); diff --git a/lib/tgchat/ext/td/td/telegram/files/FileUploadManager.h b/lib/tgchat/ext/td/td/telegram/files/FileUploadManager.h index 8ef9a914..a2e3eef6 100644 --- a/lib/tgchat/ext/td/td/telegram/files/FileUploadManager.h +++ b/lib/tgchat/ext/td/td/telegram/files/FileUploadManager.h @@ -37,7 +37,7 @@ class FileUploadManager final : public Actor { virtual void on_error(QueryId query_id, Status status) = 0; }; - explicit FileUploadManager(unique_ptr callback, ActorShared<> parent); + FileUploadManager(unique_ptr callback, ActorShared<> parent); void upload(QueryId query_id, const LocalFileLocation &local_location, const RemoteFileLocation &remote_location, int64 expected_size, const FileEncryptionKey &encryption_key, int8 priority, vector bad_parts); diff --git a/lib/tgchat/ext/td/td/telegram/net/ConnectionCreator.cpp b/lib/tgchat/ext/td/td/telegram/net/ConnectionCreator.cpp index bc33ef27..3c49bc5a 100644 --- a/lib/tgchat/ext/td/td/telegram/net/ConnectionCreator.cpp +++ b/lib/tgchat/ext/td/td/telegram/net/ConnectionCreator.cpp @@ -859,9 +859,9 @@ ActorOwn<> ConnectionCreator::prepare_connection(IPAddress ip_address, SocketFd VLOG(connections) << "Create new transparent proxy connection " << debug_str; class Callback final : public TransparentProxy::Callback { public: - explicit Callback(Promise promise, IPAddress ip_address, - unique_ptr stats_callback, bool use_connection_token, - bool was_connected) + Callback(Promise promise, IPAddress ip_address, + unique_ptr stats_callback, bool use_connection_token, + bool was_connected) : promise_(std::move(promise)) , ip_address_(std::move(ip_address)) , stats_callback_(std::move(stats_callback)) diff --git a/lib/tgchat/ext/td/td/telegram/net/PublicRsaKeySharedCdn.cpp b/lib/tgchat/ext/td/td/telegram/net/PublicRsaKeySharedCdn.cpp index 31de0a10..8fa12374 100644 --- a/lib/tgchat/ext/td/td/telegram/net/PublicRsaKeySharedCdn.cpp +++ b/lib/tgchat/ext/td/td/telegram/net/PublicRsaKeySharedCdn.cpp @@ -37,7 +37,7 @@ Result PublicRsaKeySharedCdn::get_rsa_ke return RsaKey{rsa_key->rsa.clone(), fingerprint}; } } - return Status::Error(PSLICE() << "Unknown fingerprints " << format::as_array(fingerprints)); + return Status::Error(PSLICE() << "Unknown CDN fingerprints " << format::as_array(fingerprints)); } void PublicRsaKeySharedCdn::drop_keys() { diff --git a/lib/tgchat/ext/td/td/telegram/net/PublicRsaKeySharedMain.cpp b/lib/tgchat/ext/td/td/telegram/net/PublicRsaKeySharedMain.cpp index 779696b8..e32f579c 100644 --- a/lib/tgchat/ext/td/td/telegram/net/PublicRsaKeySharedMain.cpp +++ b/lib/tgchat/ext/td/td/telegram/net/PublicRsaKeySharedMain.cpp @@ -60,7 +60,7 @@ Result PublicRsaKeySharedMain::get_rsa_k } } } - return Status::Error(PSLICE() << "Unknown fingerprints " << format::as_array(fingerprints)); + return Status::Error(PSLICE() << "Unknown Main fingerprints " << format::as_array(fingerprints)); } void PublicRsaKeySharedMain::drop_keys() { diff --git a/lib/tgchat/ext/td/td/telegram/net/PublicRsaKeyWatchdog.h b/lib/tgchat/ext/td/td/telegram/net/PublicRsaKeyWatchdog.h index c64b3191..52d837f3 100644 --- a/lib/tgchat/ext/td/td/telegram/net/PublicRsaKeyWatchdog.h +++ b/lib/tgchat/ext/td/td/telegram/net/PublicRsaKeyWatchdog.h @@ -7,6 +7,7 @@ #pragma once #include "td/telegram/net/NetActor.h" +#include "td/telegram/net/NetQuery.h" #include "td/telegram/net/NetQueryCreator.h" #include "td/telegram/net/NetQueryDispatcher.h" #include "td/telegram/net/PublicRsaKeySharedCdn.h" diff --git a/lib/tgchat/ext/td/td/telegram/net/Session.cpp b/lib/tgchat/ext/td/td/telegram/net/Session.cpp index 06e18865..dc1973ac 100644 --- a/lib/tgchat/ext/td/td/telegram/net/Session.cpp +++ b/lib/tgchat/ext/td/td/telegram/net/Session.cpp @@ -373,7 +373,7 @@ void Session::connection_online_update(double now, bool force) { void Session::send(NetQueryPtr &&query) { last_activity_timestamp_ = Time::now(); - // query->debug(PSTRING() << get_name() << ": received from SessionProxy"); + // query->debug(PSTRING() << get_name() << ": received by Session"); query->set_session_id(auth_data_.get_session_id()); VLOG(net_query) << "Receive query " << query; if (query->update_is_ready()) { diff --git a/lib/tgchat/ext/td/td/telegram/net/TempAuthKeyWatchdog.h b/lib/tgchat/ext/td/td/telegram/net/TempAuthKeyWatchdog.h index 259e9e4e..2da94648 100644 --- a/lib/tgchat/ext/td/td/telegram/net/TempAuthKeyWatchdog.h +++ b/lib/tgchat/ext/td/td/telegram/net/TempAuthKeyWatchdog.h @@ -7,6 +7,7 @@ #pragma once #include "td/telegram/Global.h" +#include "td/telegram/net/NetQuery.h" #include "td/telegram/net/NetQueryCreator.h" #include "td/telegram/net/NetQueryDispatcher.h" #include "td/telegram/telegram_api.h" diff --git a/lib/tgchat/ext/td/td/tl/tl_jni_object.cpp b/lib/tgchat/ext/td/td/tl/tl_jni_object.cpp index f79c4aef..2ede2266 100644 --- a/lib/tgchat/ext/td/td/tl/tl_jni_object.cpp +++ b/lib/tgchat/ext/td/td/tl/tl_jni_object.cpp @@ -40,6 +40,10 @@ static void fatal_error(JNIEnv *env, CSlice error) { env->FatalError(error.c_str()); } +void set_fatal_error(JNIEnv *env, const std::string &error) { + fatal_error(env, error); +} + jclass get_jclass(JNIEnv *env, const char *class_name) { jclass clazz = env->FindClass(class_name); if (!clazz) { @@ -72,6 +76,14 @@ jfieldID get_field_id(JNIEnv *env, jclass clazz, const char *name, const char *s return res; } +jfieldID get_static_field_id(JNIEnv *env, jclass clazz, const char *name, const char *signature) { + jfieldID res = env->GetStaticFieldID(clazz, name, signature); + if (!res) { + fatal_error(env, PSLICE() << "Can't find static field [" << name << "] with signature [" << signature << "]"); + } + return res; +} + void register_native_method(JNIEnv *env, jclass clazz, std::string name, std::string signature, void *function_ptr) { JNINativeMethod native_method{&name[0], &signature[0], function_ptr}; if (env->RegisterNatives(clazz, &native_method, 1) != 0) { @@ -211,6 +223,17 @@ std::string fetch_string(JNIEnv *env, jobject o, jfieldID id) { return res; } +std::string fetch_static_string(JNIEnv *env, jclass clazz, jfieldID id) { + jstring s = (jstring)env->GetStaticObjectField(clazz, id); + if (s == nullptr) { + // treat null as an empty string + return std::string(); + } + std::string res = from_jstring(env, s); + env->DeleteLocalRef(s); + return res; +} + std::string from_jstring(JNIEnv *env, jstring s) { if (!s) { return std::string(); diff --git a/lib/tgchat/ext/td/td/tl/tl_jni_object.h b/lib/tgchat/ext/td/td/tl/tl_jni_object.h index f6a05993..dcc2c1cf 100644 --- a/lib/tgchat/ext/td/td/tl/tl_jni_object.h +++ b/lib/tgchat/ext/td/td/tl/tl_jni_object.h @@ -33,12 +33,16 @@ extern jmethodID IntegerGetValueMethodID; extern jmethodID LongGetValueMethodID; extern jmethodID DoubleGetValueMethodID; +void set_fatal_error(JNIEnv *env, const std::string &error); + jclass get_jclass(JNIEnv *env, const char *class_name); jmethodID get_method_id(JNIEnv *env, jclass clazz, const char *name, const char *signature); jfieldID get_field_id(JNIEnv *env, jclass clazz, const char *name, const char *signature); +jfieldID get_static_field_id(JNIEnv *env, jclass clazz, const char *name, const char *signature); + void register_native_method(JNIEnv *env, jclass clazz, std::string name, std::string signature, void *function_ptr); class JvmThreadDetacher { @@ -74,6 +78,8 @@ std::unique_ptr get_jni_env(JavaVM *java_vm, jint jni std::string fetch_string(JNIEnv *env, jobject o, jfieldID id); +std::string fetch_static_string(JNIEnv *env, jclass clazz, jfieldID id); + inline jobject fetch_object(JNIEnv *env, const jobject &o, const jfieldID &id) { // null return object is implicitly allowed return env->GetObjectField(o, id); diff --git a/lib/tgchat/ext/td/tdnet/td/net/Wget.h b/lib/tgchat/ext/td/tdnet/td/net/Wget.h index a9d3e77d..bc017a1d 100644 --- a/lib/tgchat/ext/td/tdnet/td/net/Wget.h +++ b/lib/tgchat/ext/td/tdnet/td/net/Wget.h @@ -22,9 +22,9 @@ namespace td { class Wget final : public HttpOutboundConnection::Callback { public: - explicit Wget(Promise> promise, string url, std::vector> headers = {}, - int32 timeout_in = 10, int32 ttl = 3, bool prefer_ipv6 = false, - SslCtx::VerifyPeer verify_peer = SslCtx::VerifyPeer::On, string content = {}, string content_type = {}); + Wget(Promise> promise, string url, std::vector> headers = {}, + int32 timeout_in = 10, int32 ttl = 3, bool prefer_ipv6 = false, + SslCtx::VerifyPeer verify_peer = SslCtx::VerifyPeer::On, string content = {}, string content_type = {}); private: Status try_init(); diff --git a/lib/tgchat/ext/td/tdutils/CMakeLists.txt b/lib/tgchat/ext/td/tdutils/CMakeLists.txt index 9783a5d9..4760aab0 100644 --- a/lib/tgchat/ext/td/tdutils/CMakeLists.txt +++ b/lib/tgchat/ext/td/tdutils/CMakeLists.txt @@ -3,12 +3,13 @@ if ((CMAKE_MAJOR_VERSION LESS 3) OR (CMAKE_VERSION VERSION_LESS "3.0.2")) endif() option(TDUTILS_MIME_TYPE "Generate MIME types conversion; requires gperf" ON) +option(TDUTILS_USE_EXTERNAL_DEPENDENCIES "Use external libraries if available" ON) if (NOT DEFINED CMAKE_INSTALL_LIBDIR) set(CMAKE_INSTALL_LIBDIR "lib") endif() -if (NOT ZLIB_FOUND) +if (NOT ZLIB_FOUND AND TDUTILS_USE_EXTERNAL_DEPENDENCIES) find_package(ZLIB) endif() if (ZLIB_FOUND) @@ -24,14 +25,14 @@ if (ZLIB_FOUND) endif() endif() -if (NOT CRC32C_FOUND) +if (NOT CRC32C_FOUND AND TDUTILS_USE_EXTERNAL_DEPENDENCIES) find_package(Crc32c QUIET) endif() if (CRC32C_FOUND) set(TD_HAVE_CRC32C 1) endif() -if (TD_WITH_ABSEIL) +if (TD_WITH_ABSEIL AND TDUTILS_USE_EXTERNAL_DEPENDENCIES) find_package(ABSL QUIET) if (ABSL_FOUND) set(TD_HAVE_ABSL 1) @@ -413,7 +414,7 @@ install(TARGETS tdutils EXPORT TdStaticTargets ARCHIVE DESTINATION "${CMAKE_INSTALL_LIBDIR}" ) -if (TD_TEST_FOLLY AND ABSL_FOUND) +if (TD_TEST_FOLLY AND ABSL_FOUND AND TDUTILS_USE_EXTERNAL_DEPENDENCIES) find_package(benchmark QUIET) find_package(folly QUIET) find_package(gflags QUIET) diff --git a/lib/tgchat/ext/td/tdutils/td/utils/FlatHashMapChunks.h b/lib/tgchat/ext/td/tdutils/td/utils/FlatHashMapChunks.h index c5fcf4a3..fcf9d89d 100644 --- a/lib/tgchat/ext/td/tdutils/td/utils/FlatHashMapChunks.h +++ b/lib/tgchat/ext/td/tdutils/td/utils/FlatHashMapChunks.h @@ -399,13 +399,16 @@ class FlatHashTableChunks { } template - void remove_if(F &&f) { + bool remove_if(F &&f) { + bool is_removed = false; for (auto it = nodes_.begin(), end = nodes_.end(); it != end; ++it) { if (!it->empty() && f(it->get_public())) { erase_node(it); + is_removed = true; } } try_shrink(); + return is_removed; } private: @@ -568,8 +571,8 @@ template , class EqT = std::equal_to> using FlatHashSetChunks = FlatHashTableChunks, HashT, EqT>; template -void table_remove_if(FlatHashTableChunks &table, FuncT &&func) { - table.remove_if(func); +bool table_remove_if(FlatHashTableChunks &table, FuncT &&func) { + return table.remove_if(func); } } // namespace td diff --git a/lib/tgchat/ext/td/tdutils/td/utils/FlatHashTable.h b/lib/tgchat/ext/td/tdutils/td/utils/FlatHashTable.h index f2af44b8..cd7e7509 100644 --- a/lib/tgchat/ext/td/tdutils/td/utils/FlatHashTable.h +++ b/lib/tgchat/ext/td/tdutils/td/utils/FlatHashTable.h @@ -385,9 +385,9 @@ class FlatHashTable { } template - void remove_if(F &&f) { + bool remove_if(F &&f) { if (empty()) { - return; + return false; } auto it = begin_impl(); @@ -401,9 +401,11 @@ class FlatHashTable { } while (!it->empty()); } auto first_empty = it; + bool is_removed = false; while (it != end) { if (!it->empty() && f(it->get_public())) { erase_node(it); + is_removed = true; } else { ++it; } @@ -411,11 +413,13 @@ class FlatHashTable { for (it = nodes_; it != first_empty;) { if (!it->empty() && f(it->get_public())) { erase_node(it); + is_removed = true; } else { ++it; } } try_shrink(); + return is_removed; } private: diff --git a/lib/tgchat/ext/td/tdutils/td/utils/algorithm.h b/lib/tgchat/ext/td/tdutils/td/utils/algorithm.h index b883999f..7046c8e6 100644 --- a/lib/tgchat/ext/td/tdutils/td/utils/algorithm.h +++ b/lib/tgchat/ext/td/tdutils/td/utils/algorithm.h @@ -254,22 +254,25 @@ detail::reversion_wrapper reversed(T &iterable) { } template -void table_remove_if(TableT &table, FuncT &&func) { +bool table_remove_if(TableT &table, FuncT &&func) { + bool is_removed = false; for (auto it = table.begin(); it != table.end();) { if (func(*it)) { it = table.erase(it); + is_removed = true; } else { ++it; } } + return is_removed; } template class FlatHashTable; template -void table_remove_if(FlatHashTable &table, FuncT &&func) { - table.remove_if(func); +bool table_remove_if(FlatHashTable &table, FuncT &&func) { + return table.remove_if(func); } } // namespace td diff --git a/lib/tgchat/ext/td/tdutils/td/utils/crypto.cpp b/lib/tgchat/ext/td/tdutils/td/utils/crypto.cpp index ff7b5016..dee0e251 100644 --- a/lib/tgchat/ext/td/tdutils/td/utils/crypto.cpp +++ b/lib/tgchat/ext/td/tdutils/td/utils/crypto.cpp @@ -721,7 +721,7 @@ void AesCtrState::decrypt(Slice from, MutableSlice to) { } #if OPENSSL_VERSION_NUMBER >= 0x30000000L && !defined(LIBRESSL_VERSION_NUMBER) -static void make_digest(Slice data, MutableSlice output, const EVP_MD *evp_md) { +static void make_digest(Slice data, MutableSlice output, const EVP_MD_CTX *evp_md_ctx) { static TD_THREAD_LOCAL EVP_MD_CTX *ctx; if (unlikely(ctx == nullptr)) { ctx = EVP_MD_CTX_new(); @@ -731,7 +731,7 @@ static void make_digest(Slice data, MutableSlice output, const EVP_MD *evp_md) { ctx = nullptr; })); } - int res = EVP_DigestInit_ex(ctx, evp_md, nullptr); + int res = EVP_MD_CTX_copy_ex(ctx, evp_md_ctx); LOG_IF(FATAL, res != 1); res = EVP_DigestUpdate(ctx, data.ubegin(), data.size()); LOG_IF(FATAL, res != 1); @@ -740,23 +740,27 @@ static void make_digest(Slice data, MutableSlice output, const EVP_MD *evp_md) { EVP_MD_CTX_reset(ctx); } -static void init_thread_local_evp_md(const EVP_MD *&evp_md, const char *algorithm) { - evp_md = EVP_MD_fetch(nullptr, algorithm, nullptr); +static void init_thread_local_evp_md_ctx(const EVP_MD_CTX *&evp_md_ctx, const char *algorithm) { + EVP_MD *evp_md = EVP_MD_fetch(nullptr, algorithm, nullptr); LOG_IF(FATAL, evp_md == nullptr); - detail::add_thread_local_destructor(create_destructor([&evp_md]() mutable { - EVP_MD_free(const_cast(evp_md)); - evp_md = nullptr; + evp_md_ctx = EVP_MD_CTX_new(); + int res = EVP_DigestInit_ex(const_cast(evp_md_ctx), evp_md, nullptr); + LOG_IF(FATAL, res != 1); + EVP_MD_free(evp_md); + detail::add_thread_local_destructor(create_destructor([&evp_md_ctx]() mutable { + EVP_MD_CTX_free(const_cast(evp_md_ctx)); + evp_md_ctx = nullptr; })); } #endif void sha1(Slice data, unsigned char output[20]) { #if OPENSSL_VERSION_NUMBER >= 0x30000000L && !defined(LIBRESSL_VERSION_NUMBER) - static TD_THREAD_LOCAL const EVP_MD *evp_md; - if (unlikely(evp_md == nullptr)) { - init_thread_local_evp_md(evp_md, "sha1"); + static TD_THREAD_LOCAL const EVP_MD_CTX *evp_md_ctx; + if (unlikely(evp_md_ctx == nullptr)) { + init_thread_local_evp_md_ctx(evp_md_ctx, "sha1"); } - make_digest(data, MutableSlice(output, 20), evp_md); + make_digest(data, MutableSlice(output, 20), evp_md_ctx); #else auto result = SHA1(data.ubegin(), data.size(), output); CHECK(result == output); @@ -766,11 +770,11 @@ void sha1(Slice data, unsigned char output[20]) { void sha256(Slice data, MutableSlice output) { CHECK(output.size() >= 32); #if OPENSSL_VERSION_NUMBER >= 0x30000000L && !defined(LIBRESSL_VERSION_NUMBER) - static TD_THREAD_LOCAL const EVP_MD *evp_md; - if (unlikely(evp_md == nullptr)) { - init_thread_local_evp_md(evp_md, "sha256"); + static TD_THREAD_LOCAL const EVP_MD_CTX *evp_md_ctx; + if (unlikely(evp_md_ctx == nullptr)) { + init_thread_local_evp_md_ctx(evp_md_ctx, "sha256"); } - make_digest(data, output, evp_md); + make_digest(data, output, evp_md_ctx); #else auto result = SHA256(data.ubegin(), data.size(), output.ubegin()); CHECK(result == output.ubegin()); @@ -780,11 +784,11 @@ void sha256(Slice data, MutableSlice output) { void sha512(Slice data, MutableSlice output) { CHECK(output.size() >= 64); #if OPENSSL_VERSION_NUMBER >= 0x30000000L && !defined(LIBRESSL_VERSION_NUMBER) - static TD_THREAD_LOCAL const EVP_MD *evp_md; - if (unlikely(evp_md == nullptr)) { - init_thread_local_evp_md(evp_md, "sha512"); + static TD_THREAD_LOCAL const EVP_MD_CTX *evp_md_ctx; + if (unlikely(evp_md_ctx == nullptr)) { + init_thread_local_evp_md_ctx(evp_md_ctx, "sha512"); } - make_digest(data, output, evp_md); + make_digest(data, output, evp_md_ctx); #else auto result = SHA512(data.ubegin(), data.size(), output.ubegin()); CHECK(result == output.ubegin()); @@ -864,11 +868,11 @@ void Sha256State::init() { } CHECK(!is_inited_); #if OPENSSL_VERSION_NUMBER >= 0x30000000L && !defined(LIBRESSL_VERSION_NUMBER) - static TD_THREAD_LOCAL const EVP_MD *evp_md; - if (unlikely(evp_md == nullptr)) { - init_thread_local_evp_md(evp_md, "sha256"); + static TD_THREAD_LOCAL const EVP_MD_CTX *evp_md_ctx; + if (unlikely(evp_md_ctx == nullptr)) { + init_thread_local_evp_md_ctx(evp_md_ctx, "sha256"); } - int err = EVP_DigestInit_ex(impl_->ctx_, evp_md, nullptr); + int err = EVP_MD_CTX_copy_ex(impl_->ctx_, evp_md_ctx); #else int err = SHA256_Init(&impl_->ctx_); #endif @@ -906,11 +910,11 @@ void Sha256State::extract(MutableSlice output, bool destroy) { void md5(Slice input, MutableSlice output) { CHECK(output.size() >= 16); #if OPENSSL_VERSION_NUMBER >= 0x30000000L && !defined(LIBRESSL_VERSION_NUMBER) - static TD_THREAD_LOCAL const EVP_MD *evp_md; - if (unlikely(evp_md == nullptr)) { - init_thread_local_evp_md(evp_md, "md5"); + static TD_THREAD_LOCAL const EVP_MD_CTX *evp_md_ctx; + if (unlikely(evp_md_ctx == nullptr)) { + init_thread_local_evp_md_ctx(evp_md_ctx, "md5"); } - make_digest(input, output, evp_md); + make_digest(input, output, evp_md_ctx); #else auto result = MD5(input.ubegin(), input.size(), output.ubegin()); CHECK(result == output.ubegin()); diff --git a/lib/tgchat/ext/td/test/link.cpp b/lib/tgchat/ext/td/test/link.cpp index 4225a237..6403b989 100644 --- a/lib/tgchat/ext/td/test/link.cpp +++ b/lib/tgchat/ext/td/test/link.cpp @@ -80,6 +80,7 @@ TEST(Link, check_link) { check_link("..", "http://../"); check_link("https://.", ""); check_link("tOnSiTe://google", "tonsite://google/"); + check_link("tOnSiTe://google.ton?t=1#we", "tonsite://google.ton?t=1#we"); } static td::td_api::object_ptr get_internal_link_type_object( diff --git a/lib/tgchat/ext/td/test/mtproto.cpp b/lib/tgchat/ext/td/test/mtproto.cpp index 39087599..c7bf876e 100644 --- a/lib/tgchat/ext/td/test/mtproto.cpp +++ b/lib/tgchat/ext/td/test/mtproto.cpp @@ -6,7 +6,6 @@ // #include "td/telegram/ConfigManager.h" #include "td/telegram/net/PublicRsaKeySharedMain.h" -#include "td/telegram/net/Session.h" #include "td/telegram/NotificationManager.h" #include "td/telegram/telegram_api.h" diff --git a/lib/tgchat/ext/td/test/secret.cpp b/lib/tgchat/ext/td/test/secret.cpp index 15802756..48523ec2 100644 --- a/lib/tgchat/ext/td/test/secret.cpp +++ b/lib/tgchat/ext/td/test/secret.cpp @@ -9,6 +9,8 @@ #include "td/telegram/Global.h" #include "td/telegram/logevent/LogEvent.h" #include "td/telegram/MessageId.h" +#include "td/telegram/net/NetQuery.h" +#include "td/telegram/net/NetQueryCreator.h" #include "td/telegram/secret_api.h" #include "td/telegram/SecretChatActor.h" #include "td/telegram/SecretChatDb.h" diff --git a/lib/tgchat/src/tgchat.cpp b/lib/tgchat/src/tgchat.cpp index e2b1fa8e..d6143e1b 100644 --- a/lib/tgchat/src/tgchat.cpp +++ b/lib/tgchat/src/tgchat.cpp @@ -41,7 +41,7 @@ // #define SIMULATED_SPONSORED_MESSAGES -static const int s_TdlibDate = 20240814; +static const int s_TdlibDate = 20240906; namespace detail { diff --git a/src/nchat.1 b/src/nchat.1 index d64aefdc..0d12a749 100644 --- a/src/nchat.1 +++ b/src/nchat.1 @@ -1,5 +1,5 @@ .\" DO NOT MODIFY THIS FILE! It was generated by help2man. -.TH NCHAT "1" "September 2024" "nchat 5.2.8" "User Commands" +.TH NCHAT "1" "September 2024" "nchat 5.2.9" "User Commands" .SH NAME nchat \- ncurses chat .SH SYNOPSIS