Merge remote-tracking branch 'td/master'
This commit is contained in:
commit
6e1836a024
@ -392,6 +392,7 @@ set(TDLIB_SOURCE
|
|||||||
td/telegram/PhotoSizeSource.cpp
|
td/telegram/PhotoSizeSource.cpp
|
||||||
td/telegram/PollManager.cpp
|
td/telegram/PollManager.cpp
|
||||||
td/telegram/QueryCombiner.cpp
|
td/telegram/QueryCombiner.cpp
|
||||||
|
td/telegram/RecentDialogList.cpp
|
||||||
td/telegram/ReplyMarkup.cpp
|
td/telegram/ReplyMarkup.cpp
|
||||||
td/telegram/ReportReason.cpp
|
td/telegram/ReportReason.cpp
|
||||||
td/telegram/RestrictionReason.cpp
|
td/telegram/RestrictionReason.cpp
|
||||||
@ -601,6 +602,7 @@ set(TDLIB_SOURCE
|
|||||||
td/telegram/PtsManager.h
|
td/telegram/PtsManager.h
|
||||||
td/telegram/PublicDialogType.h
|
td/telegram/PublicDialogType.h
|
||||||
td/telegram/QueryCombiner.h
|
td/telegram/QueryCombiner.h
|
||||||
|
td/telegram/RecentDialogList.h
|
||||||
td/telegram/ReplyMarkup.h
|
td/telegram/ReplyMarkup.h
|
||||||
td/telegram/ReportReason.h
|
td/telegram/ReportReason.h
|
||||||
td/telegram/RequestActor.h
|
td/telegram/RequestActor.h
|
||||||
|
12
build.html
12
build.html
@ -61,7 +61,7 @@ select.large { font-size: large; }
|
|||||||
<option>CentOS 8</option>
|
<option>CentOS 8</option>
|
||||||
<option>Debian 8</option>
|
<option>Debian 8</option>
|
||||||
<option>Debian 9</option>
|
<option>Debian 9</option>
|
||||||
<option>Debian 10</option>
|
<option>Debian 10+</option>
|
||||||
<option>Ubuntu 14</option>
|
<option>Ubuntu 14</option>
|
||||||
<option>Ubuntu 16</option>
|
<option>Ubuntu 16</option>
|
||||||
<option>Ubuntu 18</option>
|
<option>Ubuntu 18</option>
|
||||||
@ -639,7 +639,7 @@ function onOptionsChanged() {
|
|||||||
break;
|
break;
|
||||||
case 'Debian 8':
|
case 'Debian 8':
|
||||||
case 'Debian 9':
|
case 'Debian 9':
|
||||||
case 'Debian 10':
|
case 'Debian 10+':
|
||||||
case 'Ubuntu 14':
|
case 'Ubuntu 14':
|
||||||
case 'Ubuntu 16':
|
case 'Ubuntu 16':
|
||||||
case 'Ubuntu 18':
|
case 'Ubuntu 18':
|
||||||
@ -668,7 +668,7 @@ function onOptionsChanged() {
|
|||||||
}
|
}
|
||||||
if (use_clang) {
|
if (use_clang) {
|
||||||
packages += ' clang' + getClangVersionSuffix() + ' libc++-dev';
|
packages += ' clang' + getClangVersionSuffix() + ' libc++-dev';
|
||||||
if (linux_distro === 'Debian 10' || linux_distro === 'Ubuntu 18' || linux_distro === 'Ubuntu 20') {
|
if (linux_distro === 'Debian 10+' || linux_distro === 'Ubuntu 18' || linux_distro === 'Ubuntu 20') {
|
||||||
packages += ' libc++abi-dev';
|
packages += ' libc++abi-dev';
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
@ -725,12 +725,12 @@ function onOptionsChanged() {
|
|||||||
commands.push('cd vcpkg');
|
commands.push('cd vcpkg');
|
||||||
commands.push(local + 'bootstrap-vcpkg.bat');
|
commands.push(local + 'bootstrap-vcpkg.bat');
|
||||||
if (target === 'C++/CX') {
|
if (target === 'C++/CX') {
|
||||||
commands.push(local + 'vcpkg.exe install gperf openssl-uwp:arm-uwp openssl-uwp:x64-uwp openssl-uwp:x86-uwp zlib:arm-uwp zlib:x64-uwp zlib:x86-uwp');
|
commands.push(local + 'vcpkg.exe install gperf:x86-windows openssl-uwp:arm-uwp openssl-uwp:x64-uwp openssl-uwp:x86-uwp zlib:arm-uwp zlib:x64-uwp zlib:x86-uwp');
|
||||||
} else {
|
} else {
|
||||||
if (build_64bit) {
|
if (build_64bit) {
|
||||||
commands.push(local + 'vcpkg.exe install gperf openssl:x64-windows zlib:x64-windows');
|
commands.push(local + 'vcpkg.exe install gperf:x64-windows openssl:x64-windows zlib:x64-windows');
|
||||||
} else {
|
} else {
|
||||||
commands.push(local + 'vcpkg.exe install gperf openssl:x86-windows zlib:x86-windows');
|
commands.push(local + 'vcpkg.exe install gperf:x86-windows openssl:x86-windows zlib:x86-windows');
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
commands.push('cd ..');
|
commands.push('cd ..');
|
||||||
|
@ -7,13 +7,12 @@ This is an example of building TDLib with `C++/CLI` support and an example of TD
|
|||||||
* Download and install Microsoft Visual Studio 2015 or later.
|
* Download and install Microsoft Visual Studio 2015 or later.
|
||||||
* Download and install [CMake](https://cmake.org/download/); choose "Add CMake to the system PATH" option while installing.
|
* Download and install [CMake](https://cmake.org/download/); choose "Add CMake to the system PATH" option while installing.
|
||||||
* Install [vcpkg](https://github.com/Microsoft/vcpkg#quick-start) or update it to the latest version using `vcpkg update` and following received instructions.
|
* Install [vcpkg](https://github.com/Microsoft/vcpkg#quick-start) or update it to the latest version using `vcpkg update` and following received instructions.
|
||||||
* Install `zlib` and `openssl` using `vcpkg`:
|
* Install `gperf`, `zlib`, and `openssl` using `vcpkg`:
|
||||||
```
|
```
|
||||||
cd <path to vcpkg>
|
cd <path to vcpkg>
|
||||||
.\vcpkg.exe install openssl:x64-windows openssl:x86-windows zlib:x64-windows zlib:x86-windows
|
.\vcpkg.exe install gperf:x64-windows gperf:x86-windows openssl:x64-windows openssl:x86-windows zlib:x64-windows zlib:x86-windows
|
||||||
```
|
```
|
||||||
* (Optional. For XML documentation generation.) Download [PHP](https://windows.php.net/download#php-7.2). Add the path to php.exe to the PATH environment variable.
|
* (Optional. For XML documentation generation.) Download [PHP](https://windows.php.net/download#php-7.2). Add the path to php.exe to the PATH environment variable.
|
||||||
* Download and install [gperf](https://sourceforge.net/projects/gnuwin32/files/gperf/3.0.1/). Add the path to gperf.exe to the PATH environment variable.
|
|
||||||
* Build `TDLib` with CMake enabling `.NET` support and specifying correct path to `vcpkg` toolchain file:
|
* Build `TDLib` with CMake enabling `.NET` support and specifying correct path to `vcpkg` toolchain file:
|
||||||
```
|
```
|
||||||
cd <path to TDLib sources>/example/csharp
|
cd <path to TDLib sources>/example/csharp
|
||||||
|
@ -7,13 +7,12 @@ This is an example of building TDLib SDK for Universal Windows Platform and an e
|
|||||||
* Download and install Microsoft Visual Studio 2015+ with Windows 10 SDK. We recommend to use the latest available versions of Microsoft Visual Studio and Windows 10 SDK.
|
* Download and install Microsoft Visual Studio 2015+ with Windows 10 SDK. We recommend to use the latest available versions of Microsoft Visual Studio and Windows 10 SDK.
|
||||||
* Download and install [CMake](https://cmake.org/download/).
|
* Download and install [CMake](https://cmake.org/download/).
|
||||||
* Install [vcpkg](https://github.com/Microsoft/vcpkg#quick-start) or update it to the latest version using `vcpkg update` and following received instructions.
|
* Install [vcpkg](https://github.com/Microsoft/vcpkg#quick-start) or update it to the latest version using `vcpkg update` and following received instructions.
|
||||||
* Install `zlib` and `openssl` for all UWP architectures using `vcpkg`:
|
* Install `zlib` and `openssl` for all UWP architectures and `gperf` for x86 using `vcpkg`:
|
||||||
```
|
```
|
||||||
cd <path to vcpkg>
|
cd <path to vcpkg>
|
||||||
.\vcpkg.exe install openssl-uwp:arm-uwp openssl-uwp:x64-uwp openssl-uwp:x86-uwp zlib:arm-uwp zlib:x64-uwp zlib:x86-uwp
|
.\vcpkg.exe install gperf:x86-windows openssl-uwp:arm-uwp openssl-uwp:x64-uwp openssl-uwp:x86-uwp zlib:arm-uwp zlib:x64-uwp zlib:x86-uwp
|
||||||
```
|
```
|
||||||
* (Optional. For XML documentation generation.) Download [PHP](https://windows.php.net/download#php-7.2). Add the path to php.exe to the PATH environment variable.
|
* (Optional. For XML documentation generation.) Download [PHP](https://windows.php.net/download#php-7.2). Add the path to php.exe to the PATH environment variable.
|
||||||
* Download and install [gperf](https://sourceforge.net/projects/gnuwin32/files/gperf/3.0.1/). Add the path to gperf.exe to the PATH environment variable.
|
|
||||||
* Download and install [7-Zip](http://www.7-zip.org/download.html) archiver, which is used by the `build.ps1` script to create a Telegram.Td.UWP Visual Studio Extension. Add the path to 7z.exe to the PATH environment variable.
|
* Download and install [7-Zip](http://www.7-zip.org/download.html) archiver, which is used by the `build.ps1` script to create a Telegram.Td.UWP Visual Studio Extension. Add the path to 7z.exe to the PATH environment variable.
|
||||||
Alternatively `build.ps1` supports compressing using [WinRAR](https://en.wikipedia.org/wiki/WinRAR) with option `-compress winrar` and compressing using [zip](http://gnuwin32.sourceforge.net/packages/zip.htm) with `-compress zip`.
|
Alternatively `build.ps1` supports compressing using [WinRAR](https://en.wikipedia.org/wiki/WinRAR) with option `-compress winrar` and compressing using [zip](http://gnuwin32.sourceforge.net/packages/zip.htm) with `-compress zip`.
|
||||||
* Build `TDLib` using provided `build.ps1` script (TDLib should be built 6 times for multiple platforms in Debug and Release configurations, so it make take few hours). Pass path to vcpkg.exe as `-vcpkg-root` argument, for example:
|
* Build `TDLib` using provided `build.ps1` script (TDLib should be built 6 times for multiple platforms in Debug and Release configurations, so it make take few hours). Pass path to vcpkg.exe as `-vcpkg-root` argument, for example:
|
||||||
@ -23,7 +22,7 @@ powershell -ExecutionPolicy ByPass .\build.ps1 -vcpkg_root C:\vcpkg
|
|||||||
If you need to restart the build from scratch, call `.\build.ps1 -mode clean` first.
|
If you need to restart the build from scratch, call `.\build.ps1 -mode clean` first.
|
||||||
* Install Visual Studio Extension "TDLib for Universal Windows Platform" located at `build-uwp\vsix\tdlib.vsix`, which was created on the previous step by `build.ps1` script.
|
* Install Visual Studio Extension "TDLib for Universal Windows Platform" located at `build-uwp\vsix\tdlib.vsix`, which was created on the previous step by `build.ps1` script.
|
||||||
|
|
||||||
Now `TDLib` can be freely used from any UWP project, built in Visual Studio.
|
Now `TDLib` can be used from any UWP project, built in Visual Studio.
|
||||||
|
|
||||||
## Example of usage
|
## Example of usage
|
||||||
The `app/` directory contains a simple example of a C# application for Universal Windows Platform. Just open it with Visual Studio 2015 or later and run.
|
The `app/` directory contains a simple example of a C# application for Universal Windows Platform. Just open it with Visual Studio 2015 or later and run.
|
||||||
|
@ -950,7 +950,7 @@ voiceChat group_call_id:int32 has_participants:Bool default_participant_id:Messa
|
|||||||
//@unread_mention_count Number of unread messages with a mention/reply in the chat
|
//@unread_mention_count Number of unread messages with a mention/reply in the chat
|
||||||
//@notification_settings Notification settings for this chat
|
//@notification_settings Notification settings for this chat
|
||||||
//@message_ttl_setting Current message Time To Live setting (self-destruct timer) for the chat; 0 if not defined. TTL is counted from the time message or its content is viewed in secret chats and from the send date in other chats
|
//@message_ttl_setting Current message Time To Live setting (self-destruct timer) for the chat; 0 if not defined. TTL is counted from the time message or its content is viewed in secret chats and from the send date in other chats
|
||||||
//@theme_name If non-empty, name of the theme set for the chat
|
//@theme_name If non-empty, name of a theme set for the chat
|
||||||
//@action_bar Describes actions which should be possible to do through a chat action bar; may be null
|
//@action_bar Describes actions which should be possible to do through a chat action bar; may be null
|
||||||
//@voice_chat Contains information about voice chat of the chat
|
//@voice_chat Contains information about voice chat of the chat
|
||||||
//@reply_markup_message_id Identifier of the message from which reply markup needs to be used; 0 if there is no default custom reply markup in the chat
|
//@reply_markup_message_id Identifier of the message from which reply markup needs to be used; 0 if there is no default custom reply markup in the chat
|
||||||
@ -1790,7 +1790,7 @@ messagePinMessage message_id:int53 = MessageContent;
|
|||||||
//@description A screenshot of a message in the chat has been taken
|
//@description A screenshot of a message in the chat has been taken
|
||||||
messageScreenshotTaken = MessageContent;
|
messageScreenshotTaken = MessageContent;
|
||||||
|
|
||||||
//@description A theme in the chat has been changed @theme_name If non-empty, name of the new theme set for the chat. Otherwise chat theme was reset to the default one
|
//@description A theme in the chat has been changed @theme_name If non-empty, name of a new theme set for the chat. Otherwise chat theme was reset to the default one
|
||||||
messageChatSetTheme theme_name:string = MessageContent;
|
messageChatSetTheme theme_name:string = MessageContent;
|
||||||
|
|
||||||
//@description The TTL (Time To Live) setting for messages in the chat has been changed @ttl New message TTL setting
|
//@description The TTL (Time To Live) setting for messages in the chat has been changed @ttl New message TTL setting
|
||||||
@ -2532,7 +2532,7 @@ chatEventUsernameChanged old_username:string new_username:string = ChatEventActi
|
|||||||
//@description The chat photo was changed @old_photo Previous chat photo value; may be null @new_photo New chat photo value; may be null
|
//@description The chat photo was changed @old_photo Previous chat photo value; may be null @new_photo New chat photo value; may be null
|
||||||
chatEventPhotoChanged old_photo:chatPhoto new_photo:chatPhoto = ChatEventAction;
|
chatEventPhotoChanged old_photo:chatPhoto new_photo:chatPhoto = ChatEventAction;
|
||||||
|
|
||||||
//@description The chat theme was changed @old_theme_name Previous chat theme name; empty if default one @new_theme_name New chat theme name; empty if default one
|
//@description The chat theme was changed. This event shouldn't be received until chat themes would be supported in supergroups @old_theme_name Previous chat theme name; empty if the previous theme was default one @new_theme_name New chat theme name; empty if the new theme is default one
|
||||||
chatEventThemeChanged old_theme_name:string new_theme_name:string = ChatEventAction;
|
chatEventThemeChanged old_theme_name:string new_theme_name:string = ChatEventAction;
|
||||||
|
|
||||||
//@description The can_invite_users permission of a supergroup chat was toggled @can_invite_users New value of can_invite_users permission
|
//@description The can_invite_users permission of a supergroup chat was toggled @can_invite_users New value of can_invite_users permission
|
||||||
@ -2702,9 +2702,10 @@ backgroundTypeWallpaper is_blurred:Bool is_moving:Bool = BackgroundType;
|
|||||||
|
|
||||||
//@description A PNG or TGV (gzipped subset of SVG with MIME type "application/x-tgwallpattern") pattern to be combined with the background fill chosen by the user
|
//@description A PNG or TGV (gzipped subset of SVG with MIME type "application/x-tgwallpattern") pattern to be combined with the background fill chosen by the user
|
||||||
//@fill Description of the background fill
|
//@fill Description of the background fill
|
||||||
//@intensity Intensity of the pattern when it is shown above the filled background; -100-100. If negative, the pattern color and the filled background colors needs to be inverted
|
//@intensity Intensity of the pattern when it is shown above the filled background; 0-100.
|
||||||
|
//@is_inverted True, if the background fill must be applied only to the pattern itself. All other pixels are black in this case. For dark themes only
|
||||||
//@is_moving True, if the background needs to be slightly moved when device is tilted
|
//@is_moving True, if the background needs to be slightly moved when device is tilted
|
||||||
backgroundTypePattern fill:BackgroundFill intensity:int32 is_moving:Bool = BackgroundType;
|
backgroundTypePattern fill:BackgroundFill intensity:int32 is_inverted:Bool is_moving:Bool = BackgroundType;
|
||||||
|
|
||||||
//@description A filled background @fill Description of the background fill
|
//@description A filled background @fill Description of the background fill
|
||||||
backgroundTypeFill fill:BackgroundFill = BackgroundType;
|
backgroundTypeFill fill:BackgroundFill = BackgroundType;
|
||||||
@ -2747,9 +2748,6 @@ themeSettings accent_color:int32 background:background message_fill:BackgroundFi
|
|||||||
//@dark_settings Theme settings for a dark chat theme
|
//@dark_settings Theme settings for a dark chat theme
|
||||||
chatTheme name:string light_settings:themeSettings dark_settings:themeSettings = ChatTheme;
|
chatTheme name:string light_settings:themeSettings dark_settings:themeSettings = ChatTheme;
|
||||||
|
|
||||||
//@description Contains a list of chat themes @chat_themes A list of chat themes
|
|
||||||
chatThemes chat_themes:vector<chatTheme> = ChatThemes;
|
|
||||||
|
|
||||||
|
|
||||||
//@description Contains a list of hashtags @hashtags A list of hashtags
|
//@description Contains a list of hashtags @hashtags A list of hashtags
|
||||||
hashtags hashtags:vector<string> = Hashtags;
|
hashtags hashtags:vector<string> = Hashtags;
|
||||||
@ -2893,7 +2891,7 @@ pushMessageContentChatChangePhoto = PushMessageContent;
|
|||||||
//@description A chat title was edited @title New chat title
|
//@description A chat title was edited @title New chat title
|
||||||
pushMessageContentChatChangeTitle title:string = PushMessageContent;
|
pushMessageContentChatChangeTitle title:string = PushMessageContent;
|
||||||
|
|
||||||
//@description A chat theme was edited @theme_name If non-empty, name of the new theme set for the chat. Otherwise chat theme was reset to the default one
|
//@description A chat theme was edited @theme_name If non-empty, name of a new theme set for the chat. Otherwise chat theme was reset to the default one
|
||||||
pushMessageContentChatChangeTheme theme_name:string = PushMessageContent;
|
pushMessageContentChatChangeTheme theme_name:string = PushMessageContent;
|
||||||
|
|
||||||
//@description A chat member was deleted @member_name Name of the deleted member @is_current_user True, if the current user was deleted from the group
|
//@description A chat member was deleted @member_name Name of the deleted member @is_current_user True, if the current user was deleted from the group
|
||||||
@ -3700,7 +3698,7 @@ updateChatMessageTtlSetting chat_id:int53 message_ttl_setting:int32 = Update;
|
|||||||
//@description The chat action bar was changed @chat_id Chat identifier @action_bar The new value of the action bar; may be null
|
//@description The chat action bar was changed @chat_id Chat identifier @action_bar The new value of the action bar; may be null
|
||||||
updateChatActionBar chat_id:int53 action_bar:ChatActionBar = Update;
|
updateChatActionBar chat_id:int53 action_bar:ChatActionBar = Update;
|
||||||
|
|
||||||
//@description The chat theme was changed @chat_id Chat identifier @theme_name The new name of the chat theme; may be empty if none
|
//@description The chat theme was changed @chat_id Chat identifier @theme_name The new name of the chat theme; may be empty if theme was reset to default
|
||||||
updateChatTheme chat_id:int53 theme_name:string = Update;
|
updateChatTheme chat_id:int53 theme_name:string = Update;
|
||||||
|
|
||||||
//@description The default chat reply markup was changed. Can occur because new messages with reply markup were received or because an old reply markup was hidden by the user
|
//@description The default chat reply markup was changed. Can occur because new messages with reply markup were received or because an old reply markup was hidden by the user
|
||||||
@ -3841,6 +3839,9 @@ updateSavedAnimations animation_ids:vector<int32> = Update;
|
|||||||
//@description The selected background has changed @for_dark_theme True, if background for dark theme has changed @background The new selected background; may be null
|
//@description The selected background has changed @for_dark_theme True, if background for dark theme has changed @background The new selected background; may be null
|
||||||
updateSelectedBackground for_dark_theme:Bool background:background = Update;
|
updateSelectedBackground for_dark_theme:Bool background:background = Update;
|
||||||
|
|
||||||
|
//@description The list of available chat themes has changed @chat_themes The new list of chat themes
|
||||||
|
updateChatThemes chat_themes:vector<chatTheme> = Update;
|
||||||
|
|
||||||
//@description Some language pack strings have been updated @localization_target Localization target to which the language pack belongs @language_pack_id Identifier of the updated language pack @strings List of changed language pack strings
|
//@description Some language pack strings have been updated @localization_target Localization target to which the language pack belongs @language_pack_id Identifier of the updated language pack @strings List of changed language pack strings
|
||||||
updateLanguagePackStrings localization_target:string language_pack_id:string strings:vector<languagePackString> = Update;
|
updateLanguagePackStrings localization_target:string language_pack_id:string strings:vector<languagePackString> = Update;
|
||||||
|
|
||||||
@ -4156,6 +4157,9 @@ removeRecentlyFoundChat chat_id:int53 = Ok;
|
|||||||
//@description Clears the list of recently found chats
|
//@description Clears the list of recently found chats
|
||||||
clearRecentlyFoundChats = Ok;
|
clearRecentlyFoundChats = Ok;
|
||||||
|
|
||||||
|
//@description Returns recently opened chats, this is an offline request. Returns chats in the order of last opening @limit The maximum number of chats to be returned
|
||||||
|
getRecentlyOpenedChats limit:int32 = Chats;
|
||||||
|
|
||||||
//@description Checks whether a username can be set for a chat @chat_id Chat identifier; should be identifier of a supergroup chat, or a channel chat, or a private chat with self, or zero if the chat is being created @username Username to be checked
|
//@description Checks whether a username can be set for a chat @chat_id Chat identifier; should be identifier of a supergroup chat, or a channel chat, or a private chat with self, or zero if the chat is being created @username Username to be checked
|
||||||
checkChatUsername chat_id:int53 username:string = CheckChatUsernameResult;
|
checkChatUsername chat_id:int53 username:string = CheckChatUsernameResult;
|
||||||
|
|
||||||
@ -4624,8 +4628,7 @@ setChatMessageTtlSetting chat_id:int53 ttl:int32 = Ok;
|
|||||||
//@chat_id Chat identifier @permissions New non-administrator members permissions in the chat
|
//@chat_id Chat identifier @permissions New non-administrator members permissions in the chat
|
||||||
setChatPermissions chat_id:int53 permissions:chatPermissions = Ok;
|
setChatPermissions chat_id:int53 permissions:chatPermissions = Ok;
|
||||||
|
|
||||||
//@description Changes the chat theme. Supported only in private and secret chats @chat_id Chat identifier
|
//@description Changes the chat theme. Supported only in private and secret chats @chat_id Chat identifier @theme_name Name of the new chat theme; may be empty to return the default theme
|
||||||
//@theme_name Name of the new chat theme; may be empty to return the default theme
|
|
||||||
setChatTheme chat_id:int53 theme_name:string = Ok;
|
setChatTheme chat_id:int53 theme_name:string = Ok;
|
||||||
|
|
||||||
//@description Changes the draft message in a chat @chat_id Chat identifier @message_thread_id If not 0, a message thread identifier in which the draft was changed @draft_message New draft message; may be null
|
//@description Changes the draft message in a chat @chat_id Chat identifier @message_thread_id If not 0, a message thread identifier in which the draft was changed @draft_message New draft message; may be null
|
||||||
@ -5290,10 +5293,6 @@ removeBackground background_id:int64 = Ok;
|
|||||||
resetBackgrounds = Ok;
|
resetBackgrounds = Ok;
|
||||||
|
|
||||||
|
|
||||||
//@description Returns the list of available chat themes
|
|
||||||
getChatThemes = ChatThemes;
|
|
||||||
|
|
||||||
|
|
||||||
//@description Returns information about the current localization target. This is an offline request if only_local is true. Can be called before authorization @only_local If true, returns only locally available information without sending network requests
|
//@description Returns information about the current localization target. This is an offline request if only_local is true. Can be called before authorization @only_local If true, returns only locally available information without sending network requests
|
||||||
getLocalizationTargetInfo only_local:Bool = LocalizationTargetInfo;
|
getLocalizationTargetInfo only_local:Bool = LocalizationTargetInfo;
|
||||||
|
|
||||||
|
@ -25,12 +25,14 @@
|
|||||||
#include "td/utils/SliceBuilder.h"
|
#include "td/utils/SliceBuilder.h"
|
||||||
#include "td/utils/Time.h"
|
#include "td/utils/Time.h"
|
||||||
#include "td/utils/tl_parsers.h"
|
#include "td/utils/tl_parsers.h"
|
||||||
|
#include "td/utils/TlDowncastHelper.h"
|
||||||
|
|
||||||
#include "td/mtproto/mtproto_api.h"
|
#include "td/mtproto/mtproto_api.h"
|
||||||
#include "td/mtproto/mtproto_api.hpp"
|
#include "td/mtproto/mtproto_api.hpp"
|
||||||
|
|
||||||
#include <algorithm>
|
#include <algorithm>
|
||||||
#include <iterator>
|
#include <iterator>
|
||||||
|
#include <type_traits>
|
||||||
|
|
||||||
namespace td {
|
namespace td {
|
||||||
|
|
||||||
@ -171,22 +173,6 @@ namespace mtproto {
|
|||||||
*
|
*
|
||||||
*/
|
*/
|
||||||
|
|
||||||
class OnPacket {
|
|
||||||
const MsgInfo &info_;
|
|
||||||
SessionConnection *connection_;
|
|
||||||
Status *status_;
|
|
||||||
|
|
||||||
public:
|
|
||||||
OnPacket(const MsgInfo &info, SessionConnection *connection, Status *status)
|
|
||||||
: info_(info), connection_(connection), status_(status) {
|
|
||||||
}
|
|
||||||
|
|
||||||
template <class T>
|
|
||||||
void operator()(const T &func) const {
|
|
||||||
*status_ = connection_->on_packet(info_, func);
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
unique_ptr<RawConnection> SessionConnection::move_as_raw_connection() {
|
unique_ptr<RawConnection> SessionConnection::move_as_raw_connection() {
|
||||||
return std::move(raw_connection_);
|
return std::move(raw_connection_);
|
||||||
}
|
}
|
||||||
@ -230,7 +216,6 @@ Status SessionConnection::on_packet_container(const MsgInfo &info, Slice packet)
|
|||||||
};
|
};
|
||||||
|
|
||||||
TlParser parser(packet);
|
TlParser parser(packet);
|
||||||
parser.fetch_int();
|
|
||||||
int32 size = parser.fetch_int();
|
int32 size = parser.fetch_int();
|
||||||
if (parser.get_error()) {
|
if (parser.get_error()) {
|
||||||
return Status::Error(PSLICE() << "Failed to parse mtproto_api::rpc_container: " << parser.get_error());
|
return Status::Error(PSLICE() << "Failed to parse mtproto_api::rpc_container: " << parser.get_error());
|
||||||
@ -243,7 +228,6 @@ Status SessionConnection::on_packet_container(const MsgInfo &info, Slice packet)
|
|||||||
|
|
||||||
Status SessionConnection::on_packet_rpc_result(const MsgInfo &info, Slice packet) {
|
Status SessionConnection::on_packet_rpc_result(const MsgInfo &info, Slice packet) {
|
||||||
TlParser parser(packet);
|
TlParser parser(packet);
|
||||||
parser.fetch_int();
|
|
||||||
uint64 req_msg_id = parser.fetch_long();
|
uint64 req_msg_id = parser.fetch_long();
|
||||||
if (parser.get_error()) {
|
if (parser.get_error()) {
|
||||||
return Status::Error(PSLICE() << "Failed to parse mtproto_api::rpc_result: " << parser.get_error());
|
return Status::Error(PSLICE() << "Failed to parse mtproto_api::rpc_result: " << parser.get_error());
|
||||||
@ -275,7 +259,7 @@ Status SessionConnection::on_packet_rpc_result(const MsgInfo &info, Slice packet
|
|||||||
return callback_->on_message_result_ok(req_msg_id, std::move(object), info.size);
|
return callback_->on_message_result_ok(req_msg_id, std::move(object), info.size);
|
||||||
}
|
}
|
||||||
default:
|
default:
|
||||||
packet.remove_prefix(4 + sizeof(req_msg_id));
|
packet.remove_prefix(sizeof(req_msg_id));
|
||||||
return callback_->on_message_result_ok(req_msg_id, as_buffer_slice(packet), info.size);
|
return callback_->on_message_result_ok(req_msg_id, as_buffer_slice(packet), info.size);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -285,12 +269,15 @@ Status SessionConnection::on_packet(const MsgInfo &info, const T &packet) {
|
|||||||
LOG(ERROR) << "Unsupported: " << to_string(packet);
|
LOG(ERROR) << "Unsupported: " << to_string(packet);
|
||||||
return Status::OK();
|
return Status::OK();
|
||||||
}
|
}
|
||||||
|
|
||||||
Status SessionConnection::on_packet(const MsgInfo &info, const mtproto_api::destroy_auth_key_ok &destroy_auth_key) {
|
Status SessionConnection::on_packet(const MsgInfo &info, const mtproto_api::destroy_auth_key_ok &destroy_auth_key) {
|
||||||
return on_destroy_auth_key(destroy_auth_key);
|
return on_destroy_auth_key(destroy_auth_key);
|
||||||
}
|
}
|
||||||
|
|
||||||
Status SessionConnection::on_packet(const MsgInfo &info, const mtproto_api::destroy_auth_key_none &destroy_auth_key) {
|
Status SessionConnection::on_packet(const MsgInfo &info, const mtproto_api::destroy_auth_key_none &destroy_auth_key) {
|
||||||
return on_destroy_auth_key(destroy_auth_key);
|
return on_destroy_auth_key(destroy_auth_key);
|
||||||
}
|
}
|
||||||
|
|
||||||
Status SessionConnection::on_packet(const MsgInfo &info, const mtproto_api::destroy_auth_key_fail &destroy_auth_key) {
|
Status SessionConnection::on_packet(const MsgInfo &info, const mtproto_api::destroy_auth_key_fail &destroy_auth_key) {
|
||||||
return on_destroy_auth_key(destroy_auth_key);
|
return on_destroy_auth_key(destroy_auth_key);
|
||||||
}
|
}
|
||||||
@ -479,52 +466,66 @@ Status SessionConnection::on_slice_packet(const MsgInfo &info, Slice packet) {
|
|||||||
if (info.seq_no & 1) {
|
if (info.seq_no & 1) {
|
||||||
send_ack(info.message_id);
|
send_ack(info.message_id);
|
||||||
}
|
}
|
||||||
TlParser parser(packet);
|
if (packet.size() < 4) {
|
||||||
tl_object_ptr<mtproto_api::Object> object = mtproto_api::Object::fetch(parser);
|
callback_->on_session_failed(Status::Error("Receive too small packet"));
|
||||||
parser.fetch_end();
|
return Status::Error(PSLICE() << "Receive packet of size " << packet.size());
|
||||||
if (parser.get_error()) {
|
|
||||||
// msg_container is not real tl object
|
|
||||||
if (packet.size() >= 4 && as<int32>(packet.begin()) == mtproto_api::msg_container::ID) {
|
|
||||||
return on_packet_container(info, packet);
|
|
||||||
}
|
|
||||||
if (packet.size() >= 4 && as<int32>(packet.begin()) == mtproto_api::rpc_result::ID) {
|
|
||||||
return on_packet_rpc_result(info, packet);
|
|
||||||
}
|
|
||||||
|
|
||||||
// It is an update... I hope.
|
|
||||||
auto status = auth_data_->check_update(info.message_id);
|
|
||||||
auto recheck_status = auth_data_->recheck_update(info.message_id);
|
|
||||||
if (recheck_status.is_error() && recheck_status.code() == 2) {
|
|
||||||
LOG(WARNING) << "Receive very old update from " << get_name() << " created in " << (Time::now() - created_at_)
|
|
||||||
<< " in container " << container_id_ << " from session " << auth_data_->get_session_id()
|
|
||||||
<< " with message_id " << info.message_id << ", main_message_id = " << main_message_id_
|
|
||||||
<< ", seq_no = " << info.seq_no << " and original size " << info.size << ": " << status << ' '
|
|
||||||
<< recheck_status;
|
|
||||||
}
|
|
||||||
if (status.is_error()) {
|
|
||||||
if (status.code() == 2) {
|
|
||||||
LOG(WARNING) << "Receive too old update from " << get_name() << " created in " << (Time::now() - created_at_)
|
|
||||||
<< " in container " << container_id_ << " from session " << auth_data_->get_session_id()
|
|
||||||
<< " with message_id " << info.message_id << ", main_message_id = " << main_message_id_
|
|
||||||
<< ", seq_no = " << info.seq_no << " and original size " << info.size << ": " << status;
|
|
||||||
callback_->on_session_failed(Status::Error("Receive too old update"));
|
|
||||||
return status;
|
|
||||||
}
|
|
||||||
VLOG(mtproto) << "Skip update " << info.message_id << " of size " << info.size << " with seq_no " << info.seq_no
|
|
||||||
<< " from " << get_name() << " created in " << (Time::now() - created_at_) << ": " << status;
|
|
||||||
return Status::OK();
|
|
||||||
} else {
|
|
||||||
VLOG(mtproto) << "Got update from " << get_name() << " created in " << (Time::now() - created_at_)
|
|
||||||
<< " in container " << container_id_ << " from session " << auth_data_->get_session_id()
|
|
||||||
<< " with message_id " << info.message_id << ", main_message_id = " << main_message_id_
|
|
||||||
<< ", seq_no = " << info.seq_no << " and original size " << info.size;
|
|
||||||
return callback_->on_update(as_buffer_slice(packet));
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
int32 constructor_id = as<int32>(packet.begin());
|
||||||
|
if (constructor_id == mtproto_api::msg_container::ID) {
|
||||||
|
return on_packet_container(info, packet.substr(4));
|
||||||
|
}
|
||||||
|
if (constructor_id == mtproto_api::rpc_result::ID) {
|
||||||
|
return on_packet_rpc_result(info, packet.substr(4));
|
||||||
|
}
|
||||||
|
|
||||||
|
TlDowncastHelper<mtproto_api::Object> helper(constructor_id);
|
||||||
Status status;
|
Status status;
|
||||||
downcast_call(*object, OnPacket(info, this, &status));
|
bool is_mtproto_api = downcast_call(static_cast<mtproto_api::Object &>(helper), [&](auto &dummy) {
|
||||||
return status;
|
// a constructor from mtproto_api
|
||||||
|
using Type = std::decay_t<decltype(dummy)>;
|
||||||
|
TlParser parser(packet.substr(4));
|
||||||
|
auto object = Type::fetch(parser);
|
||||||
|
parser.fetch_end();
|
||||||
|
if (parser.get_error()) {
|
||||||
|
status = parser.get_status();
|
||||||
|
} else {
|
||||||
|
status = this->on_packet(info, static_cast<const Type &>(*object));
|
||||||
|
}
|
||||||
|
});
|
||||||
|
if (is_mtproto_api) {
|
||||||
|
return status;
|
||||||
|
}
|
||||||
|
|
||||||
|
// It is an update... I hope.
|
||||||
|
status = auth_data_->check_update(info.message_id);
|
||||||
|
auto recheck_status = auth_data_->recheck_update(info.message_id);
|
||||||
|
if (recheck_status.is_error() && recheck_status.code() == 2) {
|
||||||
|
LOG(WARNING) << "Receive very old update from " << get_name() << " created in " << (Time::now() - created_at_)
|
||||||
|
<< " in container " << container_id_ << " from session " << auth_data_->get_session_id()
|
||||||
|
<< " with message_id " << info.message_id << ", main_message_id = " << main_message_id_
|
||||||
|
<< ", seq_no = " << info.seq_no << " and original size " << info.size << ": " << status << ' '
|
||||||
|
<< recheck_status;
|
||||||
|
}
|
||||||
|
if (status.is_error()) {
|
||||||
|
if (status.code() == 2) {
|
||||||
|
LOG(WARNING) << "Receive too old update from " << get_name() << " created in " << (Time::now() - created_at_)
|
||||||
|
<< " in container " << container_id_ << " from session " << auth_data_->get_session_id()
|
||||||
|
<< " with message_id " << info.message_id << ", main_message_id = " << main_message_id_
|
||||||
|
<< ", seq_no = " << info.seq_no << " and original size " << info.size << ": " << status;
|
||||||
|
callback_->on_session_failed(Status::Error("Receive too old update"));
|
||||||
|
return status;
|
||||||
|
}
|
||||||
|
VLOG(mtproto) << "Skip update " << info.message_id << " of size " << info.size << " with seq_no " << info.seq_no
|
||||||
|
<< " from " << get_name() << " created in " << (Time::now() - created_at_) << ": " << status;
|
||||||
|
return Status::OK();
|
||||||
|
} else {
|
||||||
|
VLOG(mtproto) << "Got update from " << get_name() << " created in " << (Time::now() - created_at_)
|
||||||
|
<< " in container " << container_id_ << " from session " << auth_data_->get_session_id()
|
||||||
|
<< " with message_id " << info.message_id << ", main_message_id = " << main_message_id_
|
||||||
|
<< ", seq_no = " << info.seq_no << " and original size " << info.size;
|
||||||
|
return callback_->on_update(as_buffer_slice(packet));
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
Status SessionConnection::parse_packet(TlParser &parser) {
|
Status SessionConnection::parse_packet(TlParser &parser) {
|
||||||
@ -579,6 +580,7 @@ void SessionConnection::on_message_failed(uint64 id, Status status) {
|
|||||||
on_message_failed_inner(id);
|
on_message_failed_inner(id);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void SessionConnection::on_message_failed_inner(uint64 id) {
|
void SessionConnection::on_message_failed_inner(uint64 id) {
|
||||||
auto it = service_queries_.find(id);
|
auto it = service_queries_.find(id);
|
||||||
if (it == service_queries_.end()) {
|
if (it == service_queries_.end()) {
|
||||||
|
@ -203,8 +203,6 @@ class SessionConnection final
|
|||||||
SessionConnection::Callback *callback_ = nullptr;
|
SessionConnection::Callback *callback_ = nullptr;
|
||||||
BufferSlice *current_buffer_slice_;
|
BufferSlice *current_buffer_slice_;
|
||||||
|
|
||||||
friend class OnPacket;
|
|
||||||
|
|
||||||
BufferSlice as_buffer_slice(Slice packet);
|
BufferSlice as_buffer_slice(Slice packet);
|
||||||
auto set_buffer_slice(BufferSlice *buffer_slice) TD_WARN_UNUSED_RESULT {
|
auto set_buffer_slice(BufferSlice *buffer_slice) TD_WARN_UNUSED_RESULT {
|
||||||
auto old_buffer_slice = current_buffer_slice_;
|
auto old_buffer_slice = current_buffer_slice_;
|
||||||
|
@ -26,6 +26,7 @@
|
|||||||
#include "td/telegram/StickersManager.h"
|
#include "td/telegram/StickersManager.h"
|
||||||
#include "td/telegram/Td.h"
|
#include "td/telegram/Td.h"
|
||||||
#include "td/telegram/TdDb.h"
|
#include "td/telegram/TdDb.h"
|
||||||
|
#include "td/telegram/ThemeManager.h"
|
||||||
#include "td/telegram/TopDialogManager.h"
|
#include "td/telegram/TopDialogManager.h"
|
||||||
#include "td/telegram/UpdatesManager.h"
|
#include "td/telegram/UpdatesManager.h"
|
||||||
|
|
||||||
@ -782,6 +783,7 @@ void AuthManager::on_get_authorization(tl_object_ptr<telegram_api::auth_Authoriz
|
|||||||
td->messages_manager_->on_authorization_success();
|
td->messages_manager_->on_authorization_success();
|
||||||
td->notification_manager_->init();
|
td->notification_manager_->init();
|
||||||
td->stickers_manager_->init();
|
td->stickers_manager_->init();
|
||||||
|
td->theme_manager_->init();
|
||||||
send_closure(td->top_dialog_manager_, &TopDialogManager::do_start_up);
|
send_closure(td->top_dialog_manager_, &TopDialogManager::do_start_up);
|
||||||
td->updates_manager_->get_difference("on_get_authorization");
|
td->updates_manager_->get_difference("on_get_authorization");
|
||||||
td->on_online_updated(false, true);
|
td->on_online_updated(false, true);
|
||||||
|
@ -1060,7 +1060,9 @@ string BackgroundManager::get_background_name_database_key(const string &name) {
|
|||||||
std::pair<BackgroundId, BackgroundType> BackgroundManager::on_get_background(
|
std::pair<BackgroundId, BackgroundType> BackgroundManager::on_get_background(
|
||||||
BackgroundId expected_background_id, const string &expected_background_name,
|
BackgroundId expected_background_id, const string &expected_background_name,
|
||||||
telegram_api::object_ptr<telegram_api::WallPaper> wallpaper_ptr, bool replace_type) {
|
telegram_api::object_ptr<telegram_api::WallPaper> wallpaper_ptr, bool replace_type) {
|
||||||
if (!(wallpaper_ptr != nullptr)) return {};
|
if (wallpaper_ptr == nullptr) {
|
||||||
|
return {};
|
||||||
|
}
|
||||||
|
|
||||||
if (wallpaper_ptr->get_id() == telegram_api::wallPaperNoFile::ID) {
|
if (wallpaper_ptr->get_id() == telegram_api::wallPaperNoFile::ID) {
|
||||||
auto wallpaper = move_tl_object_as<telegram_api::wallPaperNoFile>(wallpaper_ptr);
|
auto wallpaper = move_tl_object_as<telegram_api::wallPaperNoFile>(wallpaper_ptr);
|
||||||
@ -1071,10 +1073,13 @@ std::pair<BackgroundId, BackgroundType> BackgroundManager::on_get_background(
|
|||||||
}
|
}
|
||||||
|
|
||||||
auto background_id = BackgroundId(wallpaper->id_);
|
auto background_id = BackgroundId(wallpaper->id_);
|
||||||
if (!background_id.is_valid() || background_id.is_local()) {
|
if (background_id.is_local()) {
|
||||||
LOG(ERROR) << "Receive " << to_string(wallpaper);
|
LOG(ERROR) << "Receive " << to_string(wallpaper);
|
||||||
return {};
|
return {};
|
||||||
}
|
}
|
||||||
|
if (!background_id.is_valid()) {
|
||||||
|
background_id = get_next_local_background_id();
|
||||||
|
}
|
||||||
|
|
||||||
Background background;
|
Background background;
|
||||||
background.id = background_id;
|
background.id = background_id;
|
||||||
|
@ -26,10 +26,23 @@ static bool is_valid_color(int32 color) {
|
|||||||
return 0 <= color && color <= 0xFFFFFF;
|
return 0 <= color && color <= 0xFFFFFF;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static bool validate_alpha_color(int32 &color) {
|
||||||
|
if (-0x1000000 <= color && color <= 0xFFFFFF) {
|
||||||
|
color &= 0xFFFFFF;
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
color = 0;
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
static bool is_valid_rotation_angle(int32 rotation_angle) {
|
static bool is_valid_rotation_angle(int32 rotation_angle) {
|
||||||
return 0 <= rotation_angle && rotation_angle < 360 && rotation_angle % 45 == 0;
|
return 0 <= rotation_angle && rotation_angle < 360 && rotation_angle % 45 == 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static bool is_valid_intensity(int32 intensity, bool allow_negative) {
|
||||||
|
return (allow_negative ? -100 : 0) <= intensity && intensity <= 100;
|
||||||
|
}
|
||||||
|
|
||||||
BackgroundFill::BackgroundFill(const telegram_api::wallPaperSettings *settings) {
|
BackgroundFill::BackgroundFill(const telegram_api::wallPaperSettings *settings) {
|
||||||
if (settings == nullptr) {
|
if (settings == nullptr) {
|
||||||
return;
|
return;
|
||||||
@ -38,35 +51,30 @@ BackgroundFill::BackgroundFill(const telegram_api::wallPaperSettings *settings)
|
|||||||
auto flags = settings->flags_;
|
auto flags = settings->flags_;
|
||||||
if ((flags & telegram_api::wallPaperSettings::BACKGROUND_COLOR_MASK) != 0) {
|
if ((flags & telegram_api::wallPaperSettings::BACKGROUND_COLOR_MASK) != 0) {
|
||||||
top_color_ = settings->background_color_;
|
top_color_ = settings->background_color_;
|
||||||
if (!is_valid_color(top_color_)) {
|
if (!validate_alpha_color(top_color_)) {
|
||||||
LOG(ERROR) << "Receive " << to_string(*settings);
|
LOG(ERROR) << "Receive " << to_string(*settings);
|
||||||
top_color_ = 0;
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
if ((flags & telegram_api::wallPaperSettings::FOURTH_BACKGROUND_COLOR_MASK) != 0 ||
|
if ((flags & telegram_api::wallPaperSettings::FOURTH_BACKGROUND_COLOR_MASK) != 0 ||
|
||||||
(flags & telegram_api::wallPaperSettings::THIRD_BACKGROUND_COLOR_MASK) != 0) {
|
(flags & telegram_api::wallPaperSettings::THIRD_BACKGROUND_COLOR_MASK) != 0) {
|
||||||
bottom_color_ = settings->second_background_color_;
|
bottom_color_ = settings->second_background_color_;
|
||||||
if (!is_valid_color(bottom_color_)) {
|
if (!validate_alpha_color(bottom_color_)) {
|
||||||
LOG(ERROR) << "Receive " << to_string(*settings);
|
LOG(ERROR) << "Receive " << to_string(*settings);
|
||||||
bottom_color_ = 0;
|
|
||||||
}
|
}
|
||||||
third_color_ = settings->third_background_color_;
|
third_color_ = settings->third_background_color_;
|
||||||
if (!is_valid_color(third_color_)) {
|
if (!validate_alpha_color(third_color_)) {
|
||||||
LOG(ERROR) << "Receive " << to_string(*settings);
|
LOG(ERROR) << "Receive " << to_string(*settings);
|
||||||
third_color_ = 0;
|
|
||||||
}
|
}
|
||||||
if ((flags & telegram_api::wallPaperSettings::FOURTH_BACKGROUND_COLOR_MASK) != 0) {
|
if ((flags & telegram_api::wallPaperSettings::FOURTH_BACKGROUND_COLOR_MASK) != 0) {
|
||||||
fourth_color_ = settings->fourth_background_color_;
|
fourth_color_ = settings->fourth_background_color_;
|
||||||
if (!is_valid_color(fourth_color_)) {
|
if (!validate_alpha_color(fourth_color_)) {
|
||||||
LOG(ERROR) << "Receive " << to_string(*settings);
|
LOG(ERROR) << "Receive " << to_string(*settings);
|
||||||
fourth_color_ = 0;
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
} else if ((flags & telegram_api::wallPaperSettings::SECOND_BACKGROUND_COLOR_MASK) != 0) {
|
} else if ((flags & telegram_api::wallPaperSettings::SECOND_BACKGROUND_COLOR_MASK) != 0) {
|
||||||
bottom_color_ = settings->second_background_color_;
|
bottom_color_ = settings->second_background_color_;
|
||||||
if (!is_valid_color(bottom_color_)) {
|
if (!validate_alpha_color(bottom_color_)) {
|
||||||
LOG(ERROR) << "Receive " << to_string(*settings);
|
LOG(ERROR) << "Receive " << to_string(*settings);
|
||||||
bottom_color_ = 0;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
rotation_angle_ = settings->rotation_;
|
rotation_angle_ = settings->rotation_;
|
||||||
@ -203,10 +211,6 @@ string BackgroundFill::get_link(bool is_first) const {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
static bool is_valid_intensity(int32 intensity) {
|
|
||||||
return -100 <= intensity && intensity <= 100;
|
|
||||||
}
|
|
||||||
|
|
||||||
bool BackgroundFill::is_dark() const {
|
bool BackgroundFill::is_dark() const {
|
||||||
switch (get_type()) {
|
switch (get_type()) {
|
||||||
case Type::Solid:
|
case Type::Solid:
|
||||||
@ -254,7 +258,7 @@ void BackgroundType::apply_parameters_from_link(Slice name) {
|
|||||||
if (!intensity_arg.empty()) {
|
if (!intensity_arg.empty()) {
|
||||||
intensity_ = to_integer<int32>(intensity_arg);
|
intensity_ = to_integer<int32>(intensity_arg);
|
||||||
}
|
}
|
||||||
if (!is_valid_intensity(intensity_)) {
|
if (!is_valid_intensity(intensity_, true)) {
|
||||||
intensity_ = 50;
|
intensity_ = 50;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -341,10 +345,11 @@ Result<BackgroundType> BackgroundType::get_background_type(const td_api::Backgro
|
|||||||
case td_api::backgroundTypePattern::ID: {
|
case td_api::backgroundTypePattern::ID: {
|
||||||
auto pattern_type = static_cast<const td_api::backgroundTypePattern *>(background_type);
|
auto pattern_type = static_cast<const td_api::backgroundTypePattern *>(background_type);
|
||||||
TRY_RESULT(background_fill, BackgroundFill::get_background_fill(pattern_type->fill_.get()));
|
TRY_RESULT(background_fill, BackgroundFill::get_background_fill(pattern_type->fill_.get()));
|
||||||
if (!is_valid_intensity(pattern_type->intensity_)) {
|
if (!is_valid_intensity(pattern_type->intensity_, false)) {
|
||||||
return Status::Error(400, "Wrong intensity value");
|
return Status::Error(400, "Wrong intensity value");
|
||||||
}
|
}
|
||||||
return BackgroundType(pattern_type->is_moving_, std::move(background_fill), pattern_type->intensity_);
|
auto intensity = pattern_type->is_inverted_ ? -max(pattern_type->intensity_, 1) : pattern_type->intensity_;
|
||||||
|
return BackgroundType(pattern_type->is_moving_, std::move(background_fill), intensity);
|
||||||
}
|
}
|
||||||
case td_api::backgroundTypeFill::ID: {
|
case td_api::backgroundTypeFill::ID: {
|
||||||
auto fill_type = static_cast<const td_api::backgroundTypeFill *>(background_type);
|
auto fill_type = static_cast<const td_api::backgroundTypeFill *>(background_type);
|
||||||
@ -375,7 +380,7 @@ BackgroundType::BackgroundType(bool is_fill, bool is_pattern,
|
|||||||
is_moving_ = (settings->flags_ & telegram_api::wallPaperSettings::MOTION_MASK) != 0;
|
is_moving_ = (settings->flags_ & telegram_api::wallPaperSettings::MOTION_MASK) != 0;
|
||||||
if ((settings->flags_ & telegram_api::wallPaperSettings::INTENSITY_MASK) != 0) {
|
if ((settings->flags_ & telegram_api::wallPaperSettings::INTENSITY_MASK) != 0) {
|
||||||
intensity_ = settings->intensity_;
|
intensity_ = settings->intensity_;
|
||||||
if (!is_valid_intensity(intensity_)) {
|
if (!is_valid_intensity(intensity_, true)) {
|
||||||
LOG(ERROR) << "Receive " << to_string(settings);
|
LOG(ERROR) << "Receive " << to_string(settings);
|
||||||
intensity_ = 50;
|
intensity_ = 50;
|
||||||
}
|
}
|
||||||
@ -414,8 +419,8 @@ td_api::object_ptr<td_api::BackgroundType> BackgroundType::get_background_type_o
|
|||||||
case Type::Wallpaper:
|
case Type::Wallpaper:
|
||||||
return td_api::make_object<td_api::backgroundTypeWallpaper>(is_blurred_, is_moving_);
|
return td_api::make_object<td_api::backgroundTypeWallpaper>(is_blurred_, is_moving_);
|
||||||
case Type::Pattern:
|
case Type::Pattern:
|
||||||
return td_api::make_object<td_api::backgroundTypePattern>(fill_.get_background_fill_object(), intensity_,
|
return td_api::make_object<td_api::backgroundTypePattern>(
|
||||||
is_moving_);
|
fill_.get_background_fill_object(), intensity_ < 0 ? -intensity_ : intensity_, intensity_ < 0, is_moving_);
|
||||||
case Type::Fill:
|
case Type::Fill:
|
||||||
return td_api::make_object<td_api::backgroundTypeFill>(fill_.get_background_fill_object());
|
return td_api::make_object<td_api::backgroundTypeFill>(fill_.get_background_fill_object());
|
||||||
default:
|
default:
|
||||||
|
@ -49,7 +49,7 @@ void store(const Document &document, StorerT &storer) {
|
|||||||
td->documents_manager_->store_document(document.file_id, storer);
|
td->documents_manager_->store_document(document.file_id, storer);
|
||||||
break;
|
break;
|
||||||
case Document::Type::Sticker:
|
case Document::Type::Sticker:
|
||||||
td->stickers_manager_->store_sticker(document.file_id, false, storer);
|
td->stickers_manager_->store_sticker(document.file_id, false, storer, "Document");
|
||||||
break;
|
break;
|
||||||
case Document::Type::Video:
|
case Document::Type::Video:
|
||||||
td->videos_manager_->store_video(document.file_id, storer);
|
td->videos_manager_->store_video(document.file_id, storer);
|
||||||
|
@ -496,8 +496,7 @@ class Global final : public ActorContext {
|
|||||||
|
|
||||||
inline Global *G_impl(const char *file, int line) {
|
inline Global *G_impl(const char *file, int line) {
|
||||||
ActorContext *context = Scheduler::context();
|
ActorContext *context = Scheduler::context();
|
||||||
CHECK(context);
|
LOG_CHECK(context != nullptr && context->get_id() == Global::ID) << "In " << file << " at " << line;
|
||||||
LOG_CHECK(context->get_id() == Global::ID) << "In " << file << " at " << line;
|
|
||||||
return static_cast<Global *>(context);
|
return static_cast<Global *>(context);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -803,7 +803,7 @@ static void store(const MessageContent *content, StorerT &storer) {
|
|||||||
}
|
}
|
||||||
case MessageContentType::Sticker: {
|
case MessageContentType::Sticker: {
|
||||||
auto m = static_cast<const MessageSticker *>(content);
|
auto m = static_cast<const MessageSticker *>(content);
|
||||||
td->stickers_manager_->store_sticker(m->file_id, false, storer);
|
td->stickers_manager_->store_sticker(m->file_id, false, storer, "MessageSticker");
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
case MessageContentType::Text: {
|
case MessageContentType::Text: {
|
||||||
|
@ -5708,7 +5708,11 @@ MessagesManager::Dialog::~Dialog() {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
MessagesManager::MessagesManager(Td *td, ActorShared<> parent) : td_(td), parent_(std::move(parent)) {
|
MessagesManager::MessagesManager(Td *td, ActorShared<> parent)
|
||||||
|
: recently_found_dialogs_{td, "recently_found", MAX_RECENT_DIALOGS}
|
||||||
|
, recently_opened_dialogs_{td, "recently_opened", MAX_RECENT_DIALOGS}
|
||||||
|
, td_(td)
|
||||||
|
, parent_(std::move(parent)) {
|
||||||
upload_media_callback_ = std::make_shared<UploadMediaCallback>();
|
upload_media_callback_ = std::make_shared<UploadMediaCallback>();
|
||||||
upload_thumbnail_callback_ = std::make_shared<UploadThumbnailCallback>();
|
upload_thumbnail_callback_ = std::make_shared<UploadThumbnailCallback>();
|
||||||
upload_dialog_photo_callback_ = std::make_shared<UploadDialogPhotoCallback>();
|
upload_dialog_photo_callback_ = std::make_shared<UploadDialogPhotoCallback>();
|
||||||
@ -11172,9 +11176,8 @@ void MessagesManager::on_dialog_deleted(DialogId dialog_id, Promise<Unit> &&prom
|
|||||||
d->is_empty = false;
|
d->is_empty = false;
|
||||||
d->need_restore_reply_markup = true;
|
d->need_restore_reply_markup = true;
|
||||||
}
|
}
|
||||||
if (remove_recently_found_dialog_internal(dialog_id)) {
|
recently_found_dialogs_.remove_dialog(dialog_id);
|
||||||
save_recently_found_dialogs();
|
recently_opened_dialogs_.remove_dialog(dialog_id);
|
||||||
}
|
|
||||||
if (dialog_id.get_type() == DialogType::Channel) {
|
if (dialog_id.get_type() == DialogType::Channel) {
|
||||||
G()->td_db()->get_binlog_pmc()->erase(get_channel_pts_key(dialog_id));
|
G()->td_db()->get_binlog_pmc()->erase(get_channel_pts_key(dialog_id));
|
||||||
}
|
}
|
||||||
@ -13865,6 +13868,14 @@ FullMessageId MessagesManager::on_get_message(MessageInfo &&message_info, bool f
|
|||||||
if (need_update_dialog_pos && d != nullptr) {
|
if (need_update_dialog_pos && d != nullptr) {
|
||||||
send_update_chat_last_message(d, "on_get_message");
|
send_update_chat_last_message(d, "on_get_message");
|
||||||
}
|
}
|
||||||
|
if (old_message_id.is_valid() || old_message_id.is_valid_scheduled()) {
|
||||||
|
CHECK(d != nullptr);
|
||||||
|
if (!old_message_id.is_valid() || !message_id.is_valid() || old_message_id <= message_id) {
|
||||||
|
LOG(ERROR) << "Failed to add just sent " << old_message_id << " to " << dialog_id << " as " << message_id
|
||||||
|
<< " from " << source << ": " << debug_add_message_to_dialog_fail_reason_;
|
||||||
|
}
|
||||||
|
send_update_delete_messages(dialog_id, {message_id.get()}, true, false);
|
||||||
|
}
|
||||||
|
|
||||||
return FullMessageId();
|
return FullMessageId();
|
||||||
}
|
}
|
||||||
@ -16559,17 +16570,7 @@ std::pair<int32, vector<DialogId>> MessagesManager::search_dialogs(const string
|
|||||||
return {};
|
return {};
|
||||||
}
|
}
|
||||||
if (query.empty()) {
|
if (query.empty()) {
|
||||||
if (!load_recently_found_dialogs(promise)) {
|
return recently_found_dialogs_.get_dialogs(limit, std::move(promise));
|
||||||
return {};
|
|
||||||
}
|
|
||||||
|
|
||||||
promise.set_value(Unit());
|
|
||||||
|
|
||||||
update_recently_found_dialogs();
|
|
||||||
|
|
||||||
size_t result_size = min(static_cast<size_t>(limit), recently_found_dialog_ids_.size());
|
|
||||||
return {narrow_cast<int32>(recently_found_dialog_ids_.size()),
|
|
||||||
vector<DialogId>(recently_found_dialog_ids_.begin(), recently_found_dialog_ids_.begin() + result_size)};
|
|
||||||
}
|
}
|
||||||
|
|
||||||
auto result = dialogs_hints_.search(query, limit);
|
auto result = dialogs_hints_.search(query, limit);
|
||||||
@ -16583,6 +16584,10 @@ std::pair<int32, vector<DialogId>> MessagesManager::search_dialogs(const string
|
|||||||
return {narrow_cast<int32>(result.first), std::move(dialog_ids)};
|
return {narrow_cast<int32>(result.first), std::move(dialog_ids)};
|
||||||
}
|
}
|
||||||
|
|
||||||
|
std::pair<int32, vector<DialogId>> MessagesManager::get_recently_opened_dialogs(int32 limit, Promise<Unit> &&promise) {
|
||||||
|
return recently_opened_dialogs_.get_dialogs(limit, std::move(promise));
|
||||||
|
}
|
||||||
|
|
||||||
vector<DialogId> MessagesManager::sort_dialogs_by_order(const vector<DialogId> &dialog_ids, int32 limit) const {
|
vector<DialogId> MessagesManager::sort_dialogs_by_order(const vector<DialogId> &dialog_ids, int32 limit) const {
|
||||||
CHECK(!td_->auth_manager_->is_bot());
|
CHECK(!td_->auth_manager_->is_bot());
|
||||||
int64 fake_order = static_cast<int64>(dialog_ids.size()) + 1;
|
int64 fake_order = static_cast<int64>(dialog_ids.size()) + 1;
|
||||||
@ -19246,10 +19251,13 @@ Status MessagesManager::toggle_message_sender_is_blocked(const td_api::object_pt
|
|||||||
dialog_id = DialogId(sender_user_id);
|
dialog_id = DialogId(sender_user_id);
|
||||||
}
|
}
|
||||||
if (dialog_id == get_my_dialog_id()) {
|
if (dialog_id == get_my_dialog_id()) {
|
||||||
return Status::Error(5, is_blocked ? Slice("Can't block self") : Slice("Can't unblock self"));
|
return Status::Error(400, is_blocked ? Slice("Can't block self") : Slice("Can't unblock self"));
|
||||||
}
|
}
|
||||||
|
|
||||||
Dialog *d = get_dialog_force(dialog_id, "toggle_message_sender_is_blocked");
|
Dialog *d = get_dialog_force(dialog_id, "toggle_message_sender_is_blocked");
|
||||||
|
if (!have_input_peer(dialog_id, AccessRights::Know)) {
|
||||||
|
return Status::Error(400, "Message sender isn't accessible");
|
||||||
|
}
|
||||||
if (d != nullptr) {
|
if (d != nullptr) {
|
||||||
if (is_blocked == d->is_blocked) {
|
if (is_blocked == d->is_blocked) {
|
||||||
return Status::OK();
|
return Status::OK();
|
||||||
@ -19295,11 +19303,6 @@ uint64 MessagesManager::save_toggle_dialog_is_blocked_on_server_log_event(Dialog
|
|||||||
}
|
}
|
||||||
|
|
||||||
void MessagesManager::toggle_dialog_is_blocked_on_server(DialogId dialog_id, bool is_blocked, uint64 log_event_id) {
|
void MessagesManager::toggle_dialog_is_blocked_on_server(DialogId dialog_id, bool is_blocked, uint64 log_event_id) {
|
||||||
if (log_event_id == 0 && dialog_id.get_type() == DialogType::SecretChat) {
|
|
||||||
// don't even create new binlog events
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (log_event_id == 0 && G()->parameters().use_message_db) {
|
if (log_event_id == 0 && G()->parameters().use_message_db) {
|
||||||
log_event_id = save_toggle_dialog_is_blocked_on_server_log_event(dialog_id, is_blocked);
|
log_event_id = save_toggle_dialog_is_blocked_on_server_log_event(dialog_id, is_blocked);
|
||||||
}
|
}
|
||||||
@ -19875,7 +19878,11 @@ void MessagesManager::read_message_contents_on_server(DialogId dialog_id, vector
|
|||||||
|
|
||||||
void MessagesManager::open_dialog(Dialog *d) {
|
void MessagesManager::open_dialog(Dialog *d) {
|
||||||
DialogId dialog_id = d->dialog_id;
|
DialogId dialog_id = d->dialog_id;
|
||||||
if (d->is_opened || !have_input_peer(dialog_id, AccessRights::Read)) {
|
if (!have_input_peer(dialog_id, AccessRights::Read)) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
recently_opened_dialogs_.add_dialog(dialog_id);
|
||||||
|
if (d->is_opened) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
d->is_opened = true;
|
d->is_opened = true;
|
||||||
@ -21767,8 +21774,7 @@ void MessagesManager::delete_bot_command_message_id(DialogId dialog_id, MessageI
|
|||||||
if (it == dialog_bot_command_message_ids_.end()) {
|
if (it == dialog_bot_command_message_ids_.end()) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
it->second.message_ids.erase(message_id);
|
if (it->second.message_ids.erase(message_id) && it->second.message_ids.empty()) {
|
||||||
if (it->second.message_ids.empty()) {
|
|
||||||
dialog_bot_command_message_ids_.erase(it);
|
dialog_bot_command_message_ids_.erase(it);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -25125,6 +25131,10 @@ bool MessagesManager::is_broadcast_channel(DialogId dialog_id) const {
|
|||||||
ContactsManager::ChannelType::Broadcast;
|
ContactsManager::ChannelType::Broadcast;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
bool MessagesManager::is_deleted_secret_chat(DialogId dialog_id) const {
|
||||||
|
return is_deleted_secret_chat(get_dialog(dialog_id));
|
||||||
|
}
|
||||||
|
|
||||||
bool MessagesManager::is_deleted_secret_chat(const Dialog *d) const {
|
bool MessagesManager::is_deleted_secret_chat(const Dialog *d) const {
|
||||||
if (d == nullptr) {
|
if (d == nullptr) {
|
||||||
return true;
|
return true;
|
||||||
@ -29217,25 +29227,27 @@ FullMessageId MessagesManager::on_send_message_success(int64 random_id, MessageI
|
|||||||
sent_message->have_previous = true;
|
sent_message->have_previous = true;
|
||||||
sent_message->have_next = true;
|
sent_message->have_next = true;
|
||||||
|
|
||||||
|
send_update_message_send_succeeded(d, old_message_id, sent_message.get());
|
||||||
|
|
||||||
bool need_update = true;
|
bool need_update = true;
|
||||||
Message *m = add_message_to_dialog(d, std::move(sent_message), true, &need_update, &need_update_dialog_pos, source);
|
Message *m = add_message_to_dialog(d, std::move(sent_message), true, &need_update, &need_update_dialog_pos, source);
|
||||||
if (m == nullptr) {
|
|
||||||
if (old_message_id.is_valid() && new_message_id < old_message_id) {
|
|
||||||
// the message ID has decreased. This could happen if some messages were lost.
|
|
||||||
// In this case the failure is possible
|
|
||||||
return {};
|
|
||||||
}
|
|
||||||
LOG(FATAL) << td_->contacts_manager_->get_my_id() << " " << dialog_id << " " << old_message_id << " "
|
|
||||||
<< new_message_id << " " << d->last_clear_history_message_id << " " << d->max_unavailable_message_id
|
|
||||||
<< " " << d->last_message_id << " " << d->last_new_message_id << " " << d->last_assigned_message_id
|
|
||||||
<< " " << have_input_peer(dialog_id, AccessRights::Read) << " "
|
|
||||||
<< debug_add_message_to_dialog_fail_reason_ << " " << source;
|
|
||||||
}
|
|
||||||
|
|
||||||
send_update_message_send_succeeded(d, old_message_id, m);
|
|
||||||
if (need_update_dialog_pos) {
|
if (need_update_dialog_pos) {
|
||||||
send_update_chat_last_message(d, "on_send_message_success");
|
send_update_chat_last_message(d, "on_send_message_success");
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (m == nullptr) {
|
||||||
|
if (!(old_message_id.is_valid() && new_message_id < old_message_id) &&
|
||||||
|
!(ttl_period > 0 && date + ttl_period <= G()->server_time())) {
|
||||||
|
// if message ID has decreased, which could happen if some messages were lost,
|
||||||
|
// or the message has already been deleted after TTL period, then the error is expected
|
||||||
|
LOG(ERROR) << "Failed to add just sent " << old_message_id << " to " << dialog_id << " as " << new_message_id
|
||||||
|
<< " from " << source << ": " << debug_add_message_to_dialog_fail_reason_;
|
||||||
|
}
|
||||||
|
send_update_delete_messages(dialog_id, {new_message_id.get()}, true, false);
|
||||||
|
being_readded_message_id_ = FullMessageId();
|
||||||
|
return {};
|
||||||
|
}
|
||||||
|
|
||||||
try_add_active_live_location(dialog_id, m);
|
try_add_active_live_location(dialog_id, m);
|
||||||
update_reply_count_by_message(d, +1, m);
|
update_reply_count_by_message(d, +1, m);
|
||||||
update_forward_count(dialog_id, m);
|
update_forward_count(dialog_id, m);
|
||||||
@ -30445,7 +30457,9 @@ void MessagesManager::set_dialog_has_bots(Dialog *d, bool has_bots) {
|
|||||||
auto it = dialog_bot_command_message_ids_.find(d->dialog_id);
|
auto it = dialog_bot_command_message_ids_.find(d->dialog_id);
|
||||||
if (it != dialog_bot_command_message_ids_.end()) {
|
if (it != dialog_bot_command_message_ids_.end()) {
|
||||||
for (auto message_id : it->second.message_ids) {
|
for (auto message_id : it->second.message_ids) {
|
||||||
send_update_message_content_impl(d->dialog_id, get_message(d, message_id), "set_dialog_has_bots");
|
auto m = get_message(d, message_id);
|
||||||
|
LOG_CHECK(m != nullptr) << d->dialog_id << ' ' << message_id;
|
||||||
|
send_update_message_content_impl(d->dialog_id, m, "set_dialog_has_bots");
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -37630,8 +37644,8 @@ void MessagesManager::on_binlog_events(vector<BinlogEvent> &&events) {
|
|||||||
log_event_parse(log_event, event.data_).ensure();
|
log_event_parse(log_event, event.data_).ensure();
|
||||||
|
|
||||||
auto dialog_id = log_event.dialog_id_;
|
auto dialog_id = log_event.dialog_id_;
|
||||||
Dialog *d = get_dialog_force(dialog_id, "ToggleDialogIsBlockedOnServerLogEvent");
|
if (dialog_id.get_type() == DialogType::SecretChat || !have_dialog_info_force(dialog_id) ||
|
||||||
if (d == nullptr || !have_input_peer(dialog_id, AccessRights::Read)) {
|
!have_input_peer(dialog_id, AccessRights::Know)) {
|
||||||
binlog_erase(G()->td_db()->get_binlog(), event.id_);
|
binlog_erase(G()->td_db()->get_binlog(), event.id_);
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
@ -37794,213 +37808,24 @@ void MessagesManager::on_binlog_events(vector<BinlogEvent> &&events) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void MessagesManager::save_recently_found_dialogs() {
|
|
||||||
if (recently_found_dialogs_loaded_ < 2) {
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
string value;
|
|
||||||
for (auto &dialog_id : recently_found_dialog_ids_) {
|
|
||||||
if (!value.empty()) {
|
|
||||||
value += ',';
|
|
||||||
}
|
|
||||||
if (!G()->parameters().use_message_db) {
|
|
||||||
// if there is no dialog database, prefer to save dialogs by username
|
|
||||||
auto username = get_dialog_username(dialog_id);
|
|
||||||
if (dialog_id.get_type() != DialogType::SecretChat && !username.empty()) {
|
|
||||||
value += '@';
|
|
||||||
value += username;
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
value += to_string(dialog_id.get());
|
|
||||||
}
|
|
||||||
LOG(DEBUG) << "Save recently found chats " << value;
|
|
||||||
G()->td_db()->get_binlog_pmc()->set("recently_found_dialog_usernames_and_ids", value);
|
|
||||||
}
|
|
||||||
|
|
||||||
bool MessagesManager::load_recently_found_dialogs(Promise<Unit> &promise) {
|
|
||||||
CHECK(!td_->auth_manager_->is_bot());
|
|
||||||
if (recently_found_dialogs_loaded_ >= 2) {
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
|
|
||||||
string found_dialogs_str = G()->td_db()->get_binlog_pmc()->get("recently_found_dialog_usernames_and_ids");
|
|
||||||
if (found_dialogs_str.empty()) {
|
|
||||||
recently_found_dialogs_loaded_ = 2;
|
|
||||||
if (!recently_found_dialog_ids_.empty()) {
|
|
||||||
save_recently_found_dialogs();
|
|
||||||
}
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
|
|
||||||
LOG(DEBUG) << "Loaded recently found chats " << found_dialogs_str;
|
|
||||||
auto found_dialogs = full_split(found_dialogs_str, ',');
|
|
||||||
if (recently_found_dialogs_loaded_ == 1 && resolve_recently_found_dialogs_multipromise_.promise_count() == 0) {
|
|
||||||
// queries was sent and have already been finished
|
|
||||||
auto newly_found_dialogs = std::move(recently_found_dialog_ids_);
|
|
||||||
recently_found_dialog_ids_.clear();
|
|
||||||
|
|
||||||
for (auto it = found_dialogs.rbegin(); it != found_dialogs.rend(); ++it) {
|
|
||||||
if ((*it)[0] == '@') {
|
|
||||||
auto dialog_id = resolve_dialog_username(it->substr(1));
|
|
||||||
if (dialog_id.is_valid() && have_input_peer(dialog_id, AccessRights::Read)) {
|
|
||||||
force_create_dialog(dialog_id, "recently found resolved dialog");
|
|
||||||
add_recently_found_dialog_internal(dialog_id);
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
auto dialog_id = DialogId(to_integer<int64>(*it));
|
|
||||||
CHECK(dialog_id.is_valid());
|
|
||||||
if (have_input_peer(dialog_id, AccessRights::Read)) {
|
|
||||||
force_create_dialog(dialog_id, "recently found dialog");
|
|
||||||
add_recently_found_dialog_internal(dialog_id);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
for (auto it = newly_found_dialogs.rbegin(); it != newly_found_dialogs.rend(); ++it) {
|
|
||||||
add_recently_found_dialog_internal(*it);
|
|
||||||
}
|
|
||||||
recently_found_dialogs_loaded_ = 2;
|
|
||||||
if (!newly_found_dialogs.empty()) {
|
|
||||||
save_recently_found_dialogs();
|
|
||||||
}
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
|
|
||||||
resolve_recently_found_dialogs_multipromise_.add_promise(std::move(promise));
|
|
||||||
if (recently_found_dialogs_loaded_ == 0) {
|
|
||||||
recently_found_dialogs_loaded_ = 1;
|
|
||||||
|
|
||||||
resolve_recently_found_dialogs_multipromise_.set_ignore_errors(true);
|
|
||||||
auto lock = resolve_recently_found_dialogs_multipromise_.get_promise();
|
|
||||||
|
|
||||||
for (auto &found_dialog : found_dialogs) {
|
|
||||||
if (found_dialog[0] == '@') {
|
|
||||||
search_public_dialog(found_dialog, false, resolve_recently_found_dialogs_multipromise_.get_promise());
|
|
||||||
}
|
|
||||||
}
|
|
||||||
if (G()->parameters().use_message_db) {
|
|
||||||
for (auto &found_dialog : found_dialogs) {
|
|
||||||
if (found_dialog[0] != '@') {
|
|
||||||
auto dialog_id = DialogId(to_integer<int64>(found_dialog));
|
|
||||||
CHECK(dialog_id.is_valid());
|
|
||||||
// TODO use asynchronous load
|
|
||||||
// get_dialog(dialog_id, resolve_recently_found_dialogs_multipromise_.get_promise());
|
|
||||||
get_dialog_force(dialog_id, "load_recently_found_dialogs");
|
|
||||||
}
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
get_dialogs_from_list(DialogListId(FolderId::main()), MAX_GET_DIALOGS + 2,
|
|
||||||
PromiseCreator::lambda(
|
|
||||||
[promise = resolve_recently_found_dialogs_multipromise_.get_promise()](
|
|
||||||
td_api::object_ptr<td_api::chats> &&chats) mutable { promise.set_value(Unit()); }));
|
|
||||||
td_->contacts_manager_->search_contacts("", 1, resolve_recently_found_dialogs_multipromise_.get_promise());
|
|
||||||
}
|
|
||||||
|
|
||||||
lock.set_value(Unit());
|
|
||||||
}
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
Status MessagesManager::add_recently_found_dialog(DialogId dialog_id) {
|
Status MessagesManager::add_recently_found_dialog(DialogId dialog_id) {
|
||||||
if (!have_dialog_force(dialog_id, "add_recently_found_dialog")) {
|
if (!have_dialog_force(dialog_id, "add_recently_found_dialog")) {
|
||||||
return Status::Error(5, "Chat not found");
|
return Status::Error(400, "Chat not found");
|
||||||
}
|
}
|
||||||
if (add_recently_found_dialog_internal(dialog_id)) {
|
recently_found_dialogs_.add_dialog(dialog_id);
|
||||||
save_recently_found_dialogs();
|
|
||||||
}
|
|
||||||
|
|
||||||
return Status::OK();
|
return Status::OK();
|
||||||
}
|
}
|
||||||
|
|
||||||
Status MessagesManager::remove_recently_found_dialog(DialogId dialog_id) {
|
Status MessagesManager::remove_recently_found_dialog(DialogId dialog_id) {
|
||||||
if (!have_dialog_force(dialog_id, "remove_recently_found_dialog")) {
|
if (!have_dialog_force(dialog_id, "remove_recently_found_dialog")) {
|
||||||
return Status::Error(5, "Chat not found");
|
return Status::Error(400, "Chat not found");
|
||||||
}
|
}
|
||||||
if (remove_recently_found_dialog_internal(dialog_id)) {
|
recently_found_dialogs_.remove_dialog(dialog_id);
|
||||||
save_recently_found_dialogs();
|
|
||||||
}
|
|
||||||
|
|
||||||
return Status::OK();
|
return Status::OK();
|
||||||
}
|
}
|
||||||
|
|
||||||
void MessagesManager::clear_recently_found_dialogs() {
|
void MessagesManager::clear_recently_found_dialogs() {
|
||||||
recently_found_dialogs_loaded_ = 2;
|
recently_found_dialogs_.clear_dialogs();
|
||||||
if (recently_found_dialog_ids_.empty()) {
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
recently_found_dialog_ids_.clear();
|
|
||||||
save_recently_found_dialogs();
|
|
||||||
}
|
|
||||||
|
|
||||||
bool MessagesManager::add_recently_found_dialog_internal(DialogId dialog_id) {
|
|
||||||
CHECK(have_dialog(dialog_id));
|
|
||||||
|
|
||||||
if (!recently_found_dialog_ids_.empty() && recently_found_dialog_ids_[0] == dialog_id) {
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
// TODO create function
|
|
||||||
auto it = std::find(recently_found_dialog_ids_.begin(), recently_found_dialog_ids_.end(), dialog_id);
|
|
||||||
if (it == recently_found_dialog_ids_.end()) {
|
|
||||||
if (narrow_cast<int32>(recently_found_dialog_ids_.size()) == MAX_RECENTLY_FOUND_DIALOGS) {
|
|
||||||
CHECK(!recently_found_dialog_ids_.empty());
|
|
||||||
recently_found_dialog_ids_.back() = dialog_id;
|
|
||||||
} else {
|
|
||||||
recently_found_dialog_ids_.push_back(dialog_id);
|
|
||||||
}
|
|
||||||
it = recently_found_dialog_ids_.end() - 1;
|
|
||||||
}
|
|
||||||
std::rotate(recently_found_dialog_ids_.begin(), it, it + 1);
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
|
|
||||||
bool MessagesManager::remove_recently_found_dialog_internal(DialogId dialog_id) {
|
|
||||||
CHECK(have_dialog(dialog_id));
|
|
||||||
return td::remove(recently_found_dialog_ids_, dialog_id);
|
|
||||||
}
|
|
||||||
|
|
||||||
void MessagesManager::update_recently_found_dialogs() {
|
|
||||||
vector<DialogId> dialog_ids;
|
|
||||||
for (auto dialog_id : recently_found_dialog_ids_) {
|
|
||||||
const Dialog *d = get_dialog(dialog_id);
|
|
||||||
if (d == nullptr) {
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
switch (dialog_id.get_type()) {
|
|
||||||
case DialogType::User:
|
|
||||||
// always keep
|
|
||||||
break;
|
|
||||||
case DialogType::Chat: {
|
|
||||||
auto channel_id = td_->contacts_manager_->get_chat_migrated_to_channel_id(dialog_id.get_chat_id());
|
|
||||||
if (channel_id.is_valid() && get_dialog(DialogId(channel_id)) != nullptr) {
|
|
||||||
dialog_id = DialogId(channel_id);
|
|
||||||
}
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
case DialogType::Channel:
|
|
||||||
// always keep
|
|
||||||
break;
|
|
||||||
case DialogType::SecretChat:
|
|
||||||
if (is_deleted_secret_chat(d)) {
|
|
||||||
dialog_id = DialogId();
|
|
||||||
}
|
|
||||||
break;
|
|
||||||
case DialogType::None:
|
|
||||||
default:
|
|
||||||
UNREACHABLE();
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
if (dialog_id.is_valid()) {
|
|
||||||
dialog_ids.push_back(dialog_id);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
if (dialog_ids != recently_found_dialog_ids_) {
|
|
||||||
recently_found_dialog_ids_ = std::move(dialog_ids);
|
|
||||||
save_recently_found_dialogs();
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void MessagesManager::suffix_load_loop(Dialog *d) {
|
void MessagesManager::suffix_load_loop(Dialog *d) {
|
||||||
|
@ -42,6 +42,7 @@
|
|||||||
#include "td/telegram/NotificationGroupType.h"
|
#include "td/telegram/NotificationGroupType.h"
|
||||||
#include "td/telegram/NotificationId.h"
|
#include "td/telegram/NotificationId.h"
|
||||||
#include "td/telegram/NotificationSettings.h"
|
#include "td/telegram/NotificationSettings.h"
|
||||||
|
#include "td/telegram/RecentDialogList.h"
|
||||||
#include "td/telegram/ReplyMarkup.h"
|
#include "td/telegram/ReplyMarkup.h"
|
||||||
#include "td/telegram/ReportReason.h"
|
#include "td/telegram/ReportReason.h"
|
||||||
#include "td/telegram/RestrictionReason.h"
|
#include "td/telegram/RestrictionReason.h"
|
||||||
@ -374,6 +375,8 @@ class MessagesManager final : public Actor {
|
|||||||
|
|
||||||
void clear_recently_found_dialogs();
|
void clear_recently_found_dialogs();
|
||||||
|
|
||||||
|
std::pair<int32, vector<DialogId>> get_recently_opened_dialogs(int32 limit, Promise<Unit> &&promise);
|
||||||
|
|
||||||
DialogId resolve_dialog_username(const string &username) const;
|
DialogId resolve_dialog_username(const string &username) const;
|
||||||
|
|
||||||
DialogId search_public_dialog(const string &username_to_search, bool force, Promise<Unit> &&promise);
|
DialogId search_public_dialog(const string &username_to_search, bool force, Promise<Unit> &&promise);
|
||||||
@ -581,6 +584,8 @@ class MessagesManager final : public Actor {
|
|||||||
|
|
||||||
bool is_message_edited_recently(FullMessageId full_message_id, int32 seconds);
|
bool is_message_edited_recently(FullMessageId full_message_id, int32 seconds);
|
||||||
|
|
||||||
|
bool is_deleted_secret_chat(DialogId dialog_id) const;
|
||||||
|
|
||||||
Result<std::pair<string, bool>> get_message_link(FullMessageId full_message_id, int32 media_timestamp, bool for_group,
|
Result<std::pair<string, bool>> get_message_link(FullMessageId full_message_id, int32 media_timestamp, bool for_group,
|
||||||
bool for_comment);
|
bool for_comment);
|
||||||
|
|
||||||
@ -1670,7 +1675,7 @@ class MessagesManager final : public Actor {
|
|||||||
static constexpr int32 MIN_CHANNEL_DIFFERENCE = 1;
|
static constexpr int32 MIN_CHANNEL_DIFFERENCE = 1;
|
||||||
static constexpr int32 MAX_CHANNEL_DIFFERENCE = 100;
|
static constexpr int32 MAX_CHANNEL_DIFFERENCE = 100;
|
||||||
static constexpr int32 MAX_BOT_CHANNEL_DIFFERENCE = 100000; // server side limit
|
static constexpr int32 MAX_BOT_CHANNEL_DIFFERENCE = 100000; // server side limit
|
||||||
static constexpr int32 MAX_RECENTLY_FOUND_DIALOGS = 50; // some reasonable value
|
static constexpr int32 MAX_RECENT_DIALOGS = 50; // some reasonable value
|
||||||
static constexpr size_t MAX_TITLE_LENGTH = 128; // server side limit for chat title
|
static constexpr size_t MAX_TITLE_LENGTH = 128; // server side limit for chat title
|
||||||
static constexpr size_t MAX_DESCRIPTION_LENGTH = 255; // server side limit for chat description
|
static constexpr size_t MAX_DESCRIPTION_LENGTH = 255; // server side limit for chat description
|
||||||
static constexpr size_t MAX_DIALOG_FILTER_TITLE_LENGTH = 12; // server side limit for dialog filter title
|
static constexpr size_t MAX_DIALOG_FILTER_TITLE_LENGTH = 12; // server side limit for dialog filter title
|
||||||
@ -2987,16 +2992,6 @@ class MessagesManager final : public Actor {
|
|||||||
|
|
||||||
static MessageId get_next_yet_unsent_scheduled_message_id(Dialog *d, int32 date);
|
static MessageId get_next_yet_unsent_scheduled_message_id(Dialog *d, int32 date);
|
||||||
|
|
||||||
bool add_recently_found_dialog_internal(DialogId dialog_id);
|
|
||||||
|
|
||||||
bool remove_recently_found_dialog_internal(DialogId dialog_id);
|
|
||||||
|
|
||||||
void update_recently_found_dialogs();
|
|
||||||
|
|
||||||
void save_recently_found_dialogs();
|
|
||||||
|
|
||||||
bool load_recently_found_dialogs(Promise<Unit> &promise);
|
|
||||||
|
|
||||||
void reget_message_from_server_if_needed(DialogId dialog_id, const Message *m);
|
void reget_message_from_server_if_needed(DialogId dialog_id, const Message *m);
|
||||||
|
|
||||||
void speculatively_update_active_group_call_id(Dialog *d, const Message *m);
|
void speculatively_update_active_group_call_id(Dialog *d, const Message *m);
|
||||||
@ -3091,10 +3086,8 @@ class MessagesManager final : public Actor {
|
|||||||
|
|
||||||
static DialogId get_message_original_sender(const Message *m);
|
static DialogId get_message_original_sender(const Message *m);
|
||||||
|
|
||||||
int32 recently_found_dialogs_loaded_ = 0; // 0 - not loaded, 1 - load request was sent, 2 - loaded
|
RecentDialogList recently_found_dialogs_;
|
||||||
MultiPromiseActor resolve_recently_found_dialogs_multipromise_{"ResolveRecentlyFoundDialogsMultiPromiseActor"};
|
RecentDialogList recently_opened_dialogs_;
|
||||||
|
|
||||||
vector<DialogId> recently_found_dialog_ids_;
|
|
||||||
|
|
||||||
class UploadMediaCallback;
|
class UploadMediaCallback;
|
||||||
class UploadThumbnailCallback;
|
class UploadThumbnailCallback;
|
||||||
|
255
td/telegram/RecentDialogList.cpp
Normal file
255
td/telegram/RecentDialogList.cpp
Normal file
@ -0,0 +1,255 @@
|
|||||||
|
//
|
||||||
|
// Copyright Aliaksei Levin (levlam@telegram.org), Arseny Smirnov (arseny30@gmail.com) 2014-2021
|
||||||
|
//
|
||||||
|
// 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/RecentDialogList.h"
|
||||||
|
|
||||||
|
#include "td/telegram/ContactsManager.h"
|
||||||
|
#include "td/telegram/Global.h"
|
||||||
|
#include "td/telegram/MessagesManager.h"
|
||||||
|
#include "td/telegram/Td.h"
|
||||||
|
#include "td/telegram/TdDb.h"
|
||||||
|
#include "td/telegram/TdParameters.h"
|
||||||
|
|
||||||
|
#include "td/utils/algorithm.h"
|
||||||
|
#include "td/utils/misc.h"
|
||||||
|
#include "td/utils/SliceBuilder.h"
|
||||||
|
|
||||||
|
namespace td {
|
||||||
|
|
||||||
|
RecentDialogList::RecentDialogList(Td *td, const char *name, size_t max_size)
|
||||||
|
: td_(td), name_(name), max_size_(max_size) {
|
||||||
|
register_actor(PSLICE() << name << "_chats", this).release();
|
||||||
|
}
|
||||||
|
|
||||||
|
string RecentDialogList::get_binlog_key() const {
|
||||||
|
return PSTRING() << name_ << "_dialog_usernames_and_ids";
|
||||||
|
}
|
||||||
|
|
||||||
|
void RecentDialogList::save_dialogs() const {
|
||||||
|
if (!is_loaded_) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
CHECK(removed_dialog_ids_.empty());
|
||||||
|
|
||||||
|
SliceBuilder sb;
|
||||||
|
for (auto &dialog_id : dialog_ids_) {
|
||||||
|
sb << ',';
|
||||||
|
if (!G()->parameters().use_message_db) {
|
||||||
|
// if there is no dialog database, prefer to save dialogs by username
|
||||||
|
string username;
|
||||||
|
switch (dialog_id.get_type()) {
|
||||||
|
case DialogType::User:
|
||||||
|
username = td_->contacts_manager_->get_user_username(dialog_id.get_user_id());
|
||||||
|
break;
|
||||||
|
case DialogType::Chat:
|
||||||
|
break;
|
||||||
|
case DialogType::Channel:
|
||||||
|
username = td_->contacts_manager_->get_channel_username(dialog_id.get_channel_id());
|
||||||
|
break;
|
||||||
|
case DialogType::SecretChat:
|
||||||
|
break;
|
||||||
|
case DialogType::None:
|
||||||
|
default:
|
||||||
|
UNREACHABLE();
|
||||||
|
}
|
||||||
|
if (!username.empty() && username.find(',') == string::npos) {
|
||||||
|
sb << '@' << username;
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
sb << dialog_id.get();
|
||||||
|
}
|
||||||
|
auto result = sb.as_cslice();
|
||||||
|
if (!result.empty()) {
|
||||||
|
result.remove_prefix(1);
|
||||||
|
}
|
||||||
|
G()->td_db()->get_binlog_pmc()->set(get_binlog_key(), result.str());
|
||||||
|
}
|
||||||
|
|
||||||
|
void RecentDialogList::load_dialogs(Promise<Unit> &&promise) {
|
||||||
|
if (is_loaded_) {
|
||||||
|
return promise.set_value(Unit());
|
||||||
|
}
|
||||||
|
|
||||||
|
load_list_queries_.push_back(std::move(promise));
|
||||||
|
if (load_list_queries_.size() != 1) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
auto found_dialogs = full_split(G()->td_db()->get_binlog_pmc()->get(get_binlog_key()), ',');
|
||||||
|
MultiPromiseActorSafe mpas{"LoadRecentDialogListMultiPromiseActor"};
|
||||||
|
mpas.add_promise(PromiseCreator::lambda([actor_id = actor_id(this), found_dialogs](Unit) mutable {
|
||||||
|
send_closure(actor_id, &RecentDialogList::on_load_dialogs, std::move(found_dialogs));
|
||||||
|
}));
|
||||||
|
mpas.set_ignore_errors(true);
|
||||||
|
auto lock = mpas.get_promise();
|
||||||
|
|
||||||
|
vector<DialogId> dialog_ids;
|
||||||
|
for (auto &found_dialog : found_dialogs) {
|
||||||
|
if (found_dialog[0] == '@') {
|
||||||
|
td_->messages_manager_->search_public_dialog(found_dialog, false, mpas.get_promise());
|
||||||
|
} else {
|
||||||
|
dialog_ids.push_back(DialogId(to_integer<int64>(found_dialog)));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (!dialog_ids.empty()) {
|
||||||
|
if (G()->parameters().use_message_db) {
|
||||||
|
td_->messages_manager_->load_dialogs(std::move(dialog_ids), mpas.get_promise());
|
||||||
|
} else {
|
||||||
|
td_->messages_manager_->get_dialogs_from_list(
|
||||||
|
DialogListId(FolderId::main()), 102,
|
||||||
|
PromiseCreator::lambda([promise = mpas.get_promise()](td_api::object_ptr<td_api::chats> &&chats) mutable {
|
||||||
|
promise.set_value(Unit());
|
||||||
|
}));
|
||||||
|
td_->contacts_manager_->search_contacts("", 1, mpas.get_promise());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
lock.set_value(Unit());
|
||||||
|
}
|
||||||
|
|
||||||
|
void RecentDialogList::on_load_dialogs(vector<string> &&found_dialogs) {
|
||||||
|
auto promises = std::move(load_list_queries_);
|
||||||
|
CHECK(!promises.empty());
|
||||||
|
|
||||||
|
auto newly_found_dialogs = std::move(dialog_ids_);
|
||||||
|
reset_to_empty(dialog_ids_);
|
||||||
|
|
||||||
|
for (auto it = found_dialogs.rbegin(); it != found_dialogs.rend(); ++it) {
|
||||||
|
DialogId dialog_id;
|
||||||
|
if ((*it)[0] == '@') {
|
||||||
|
dialog_id = td_->messages_manager_->resolve_dialog_username(it->substr(1));
|
||||||
|
} else {
|
||||||
|
dialog_id = DialogId(to_integer<int64>(*it));
|
||||||
|
}
|
||||||
|
if (dialog_id.is_valid() && removed_dialog_ids_.count(dialog_id) == 0 &&
|
||||||
|
td_->messages_manager_->have_input_peer(dialog_id, AccessRights::Read)) {
|
||||||
|
td_->messages_manager_->force_create_dialog(dialog_id, "recent dialog");
|
||||||
|
do_add_dialog(dialog_id);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
for (auto it = newly_found_dialogs.rbegin(); it != newly_found_dialogs.rend(); ++it) {
|
||||||
|
do_add_dialog(*it);
|
||||||
|
}
|
||||||
|
is_loaded_ = true;
|
||||||
|
removed_dialog_ids_.clear();
|
||||||
|
if (!newly_found_dialogs.empty()) {
|
||||||
|
save_dialogs();
|
||||||
|
}
|
||||||
|
|
||||||
|
for (auto &promise : promises) {
|
||||||
|
promise.set_value(Unit());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void RecentDialogList::add_dialog(DialogId dialog_id) {
|
||||||
|
if (!is_loaded_) {
|
||||||
|
load_dialogs(Promise<Unit>());
|
||||||
|
}
|
||||||
|
if (do_add_dialog(dialog_id)) {
|
||||||
|
save_dialogs();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
bool RecentDialogList::do_add_dialog(DialogId dialog_id) {
|
||||||
|
if (!dialog_ids_.empty() && dialog_ids_[0] == dialog_id) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
// TODO create function
|
||||||
|
auto it = std::find(dialog_ids_.begin(), dialog_ids_.end(), dialog_id);
|
||||||
|
if (it == dialog_ids_.end()) {
|
||||||
|
if (dialog_ids_.size() == max_size_) {
|
||||||
|
CHECK(!dialog_ids_.empty());
|
||||||
|
dialog_ids_.back() = dialog_id;
|
||||||
|
} else {
|
||||||
|
dialog_ids_.push_back(dialog_id);
|
||||||
|
}
|
||||||
|
it = dialog_ids_.end() - 1;
|
||||||
|
}
|
||||||
|
std::rotate(dialog_ids_.begin(), it, it + 1);
|
||||||
|
removed_dialog_ids_.erase(dialog_id);
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
void RecentDialogList::remove_dialog(DialogId dialog_id) {
|
||||||
|
if (!is_loaded_) {
|
||||||
|
load_dialogs(Promise<Unit>());
|
||||||
|
}
|
||||||
|
if (td::remove(dialog_ids_, dialog_id)) {
|
||||||
|
save_dialogs();
|
||||||
|
} else if (!is_loaded_) {
|
||||||
|
removed_dialog_ids_.insert(dialog_id);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void RecentDialogList::update_dialogs() {
|
||||||
|
CHECK(is_loaded_);
|
||||||
|
vector<DialogId> dialog_ids;
|
||||||
|
for (auto dialog_id : dialog_ids_) {
|
||||||
|
if (!td_->messages_manager_->have_dialog(dialog_id)) {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
switch (dialog_id.get_type()) {
|
||||||
|
case DialogType::User:
|
||||||
|
// always keep
|
||||||
|
break;
|
||||||
|
case DialogType::Chat: {
|
||||||
|
auto channel_id = td_->contacts_manager_->get_chat_migrated_to_channel_id(dialog_id.get_chat_id());
|
||||||
|
if (channel_id.is_valid() && td_->messages_manager_->have_dialog(DialogId(channel_id))) {
|
||||||
|
dialog_id = DialogId(channel_id);
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
case DialogType::Channel:
|
||||||
|
// always keep
|
||||||
|
break;
|
||||||
|
case DialogType::SecretChat:
|
||||||
|
if (td_->messages_manager_->is_deleted_secret_chat(dialog_id)) {
|
||||||
|
dialog_id = DialogId();
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
case DialogType::None:
|
||||||
|
default:
|
||||||
|
UNREACHABLE();
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
if (dialog_id.is_valid()) {
|
||||||
|
dialog_ids.push_back(dialog_id);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (dialog_ids != dialog_ids_) {
|
||||||
|
dialog_ids_ = std::move(dialog_ids);
|
||||||
|
save_dialogs();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
std::pair<int32, vector<DialogId>> RecentDialogList::get_dialogs(int32 limit, Promise<Unit> &&promise) {
|
||||||
|
load_dialogs(std::move(promise));
|
||||||
|
if (!is_loaded_) {
|
||||||
|
return {};
|
||||||
|
}
|
||||||
|
|
||||||
|
update_dialogs();
|
||||||
|
|
||||||
|
CHECK(limit >= 0);
|
||||||
|
int32 total_count = narrow_cast<int32>(dialog_ids_.size());
|
||||||
|
return {total_count, vector<DialogId>(dialog_ids_.begin(), dialog_ids_.begin() + min(limit, total_count))};
|
||||||
|
}
|
||||||
|
|
||||||
|
void RecentDialogList::clear_dialogs() {
|
||||||
|
if (dialog_ids_.empty() && is_loaded_) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
is_loaded_ = true;
|
||||||
|
dialog_ids_.clear();
|
||||||
|
removed_dialog_ids_.clear();
|
||||||
|
save_dialogs();
|
||||||
|
}
|
||||||
|
|
||||||
|
} // namespace td
|
59
td/telegram/RecentDialogList.h
Normal file
59
td/telegram/RecentDialogList.h
Normal file
@ -0,0 +1,59 @@
|
|||||||
|
//
|
||||||
|
// Copyright Aliaksei Levin (levlam@telegram.org), Arseny Smirnov (arseny30@gmail.com) 2014-2021
|
||||||
|
//
|
||||||
|
// 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/DialogId.h"
|
||||||
|
|
||||||
|
#include "td/actor/actor.h"
|
||||||
|
#include "td/actor/PromiseFuture.h"
|
||||||
|
|
||||||
|
#include "td/utils/common.h"
|
||||||
|
|
||||||
|
#include <unordered_set>
|
||||||
|
#include <utility>
|
||||||
|
|
||||||
|
namespace td {
|
||||||
|
|
||||||
|
class Td;
|
||||||
|
|
||||||
|
// stores list of Dialog identifiers of a limited size
|
||||||
|
class RecentDialogList : public Actor {
|
||||||
|
public:
|
||||||
|
RecentDialogList(Td *td, const char *name, size_t max_size);
|
||||||
|
|
||||||
|
void add_dialog(DialogId dialog_id);
|
||||||
|
|
||||||
|
void remove_dialog(DialogId dialog_id);
|
||||||
|
|
||||||
|
std::pair<int32, vector<DialogId>> get_dialogs(int32 limit, Promise<Unit> &&promise);
|
||||||
|
|
||||||
|
void clear_dialogs();
|
||||||
|
|
||||||
|
private:
|
||||||
|
Td *td_;
|
||||||
|
const char *name_;
|
||||||
|
size_t max_size_;
|
||||||
|
vector<DialogId> dialog_ids_;
|
||||||
|
std::unordered_set<DialogId, DialogIdHash> removed_dialog_ids_;
|
||||||
|
|
||||||
|
bool is_loaded_ = false;
|
||||||
|
vector<Promise<Unit>> load_list_queries_;
|
||||||
|
|
||||||
|
void load_dialogs(Promise<Unit> &&promise);
|
||||||
|
|
||||||
|
void on_load_dialogs(vector<string> &&found_dialogs);
|
||||||
|
|
||||||
|
bool do_add_dialog(DialogId dialog_id);
|
||||||
|
|
||||||
|
string get_binlog_key() const;
|
||||||
|
|
||||||
|
void update_dialogs();
|
||||||
|
|
||||||
|
void save_dialogs() const;
|
||||||
|
};
|
||||||
|
|
||||||
|
} // namespace td
|
@ -1132,7 +1132,7 @@ class StickersManager::StickerListLogEvent {
|
|||||||
StickersManager *stickers_manager = storer.context()->td().get_actor_unsafe()->stickers_manager_.get();
|
StickersManager *stickers_manager = storer.context()->td().get_actor_unsafe()->stickers_manager_.get();
|
||||||
td::store(narrow_cast<int32>(sticker_ids.size()), storer);
|
td::store(narrow_cast<int32>(sticker_ids.size()), storer);
|
||||||
for (auto sticker_id : sticker_ids) {
|
for (auto sticker_id : sticker_ids) {
|
||||||
stickers_manager->store_sticker(sticker_id, false, storer);
|
stickers_manager->store_sticker(sticker_id, false, storer, "StickerListLogEvent");
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -270,7 +270,7 @@ class StickersManager final : public Actor {
|
|||||||
void merge_stickers(FileId new_id, FileId old_id, bool can_delete_old);
|
void merge_stickers(FileId new_id, FileId old_id, bool can_delete_old);
|
||||||
|
|
||||||
template <class StorerT>
|
template <class StorerT>
|
||||||
void store_sticker(FileId file_id, bool in_sticker_set, StorerT &storer) const;
|
void store_sticker(FileId file_id, bool in_sticker_set, StorerT &storer, const char *source) const;
|
||||||
|
|
||||||
template <class ParserT>
|
template <class ParserT>
|
||||||
FileId parse_sticker(bool in_sticker_set, ParserT &parser);
|
FileId parse_sticker(bool in_sticker_set, ParserT &parser);
|
||||||
|
@ -21,7 +21,7 @@
|
|||||||
namespace td {
|
namespace td {
|
||||||
|
|
||||||
template <class StorerT>
|
template <class StorerT>
|
||||||
void StickersManager::store_sticker(FileId file_id, bool in_sticker_set, StorerT &storer) const {
|
void StickersManager::store_sticker(FileId file_id, bool in_sticker_set, StorerT &storer, const char *source) const {
|
||||||
auto it = stickers_.find(file_id);
|
auto it = stickers_.find(file_id);
|
||||||
if (it == stickers_.end() || it->second == nullptr) {
|
if (it == stickers_.end() || it->second == nullptr) {
|
||||||
return;
|
return;
|
||||||
@ -171,7 +171,7 @@ void StickersManager::store_sticker_set(const StickerSet *sticker_set, bool with
|
|||||||
store(stored_sticker_count, storer);
|
store(stored_sticker_count, storer);
|
||||||
for (uint32 i = 0; i < stored_sticker_count; i++) {
|
for (uint32 i = 0; i < stored_sticker_count; i++) {
|
||||||
auto sticker_id = sticker_set->sticker_ids[i];
|
auto sticker_id = sticker_set->sticker_ids[i];
|
||||||
store_sticker(sticker_id, true, storer);
|
store_sticker(sticker_id, true, storer, "store_sticker_set");
|
||||||
|
|
||||||
if (was_loaded) {
|
if (was_loaded) {
|
||||||
auto it = sticker_set->sticker_emojis_map_.find(sticker_id);
|
auto it = sticker_set->sticker_emojis_map_.find(sticker_id);
|
||||||
|
@ -964,6 +964,25 @@ class GetInactiveSupergroupChatsRequest final : public RequestActor<> {
|
|||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
|
class GetRecentlyOpenedChatsRequest final : public RequestActor<> {
|
||||||
|
int32 limit_;
|
||||||
|
|
||||||
|
std::pair<int32, vector<DialogId>> dialog_ids_;
|
||||||
|
|
||||||
|
void do_run(Promise<Unit> &&promise) final {
|
||||||
|
dialog_ids_ = td->messages_manager_->get_recently_opened_dialogs(limit_, std::move(promise));
|
||||||
|
}
|
||||||
|
|
||||||
|
void do_send_result() final {
|
||||||
|
send_result(MessagesManager::get_chats_object(dialog_ids_));
|
||||||
|
}
|
||||||
|
|
||||||
|
public:
|
||||||
|
GetRecentlyOpenedChatsRequest(ActorShared<Td> td, uint64 request_id, int32 limit)
|
||||||
|
: RequestActor(std::move(td), request_id), limit_(limit) {
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
class GetMessageRequest final : public RequestOnceActor {
|
class GetMessageRequest final : public RequestOnceActor {
|
||||||
FullMessageId full_message_id_;
|
FullMessageId full_message_id_;
|
||||||
|
|
||||||
@ -4369,6 +4388,7 @@ void Td::send_update(tl_object_ptr<td_api::Update> &&object) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
switch (object_id) {
|
switch (object_id) {
|
||||||
|
case td_api::updateChatThemes::ID:
|
||||||
case td_api::updateFavoriteStickers::ID:
|
case td_api::updateFavoriteStickers::ID:
|
||||||
case td_api::updateInstalledStickerSets::ID:
|
case td_api::updateInstalledStickerSets::ID:
|
||||||
case td_api::updateRecentStickers::ID:
|
case td_api::updateRecentStickers::ID:
|
||||||
@ -5435,6 +5455,11 @@ void Td::on_request(uint64 id, const td_api::clearRecentlyFoundChats &request) {
|
|||||||
send_closure(actor_id(this), &Td::send_result, id, make_tl_object<td_api::ok>());
|
send_closure(actor_id(this), &Td::send_result, id, make_tl_object<td_api::ok>());
|
||||||
}
|
}
|
||||||
|
|
||||||
|
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) {
|
void Td::on_request(uint64 id, const td_api::openChat &request) {
|
||||||
CHECK_IS_USER();
|
CHECK_IS_USER();
|
||||||
answer_ok_query(id, messages_manager_->open_dialog(DialogId(request.chat_id_)));
|
answer_ok_query(id, messages_manager_->open_dialog(DialogId(request.chat_id_)));
|
||||||
@ -8135,12 +8160,6 @@ void Td::on_request(uint64 id, const td_api::resetBackgrounds &request) {
|
|||||||
background_manager_->reset_backgrounds(std::move(promise));
|
background_manager_->reset_backgrounds(std::move(promise));
|
||||||
}
|
}
|
||||||
|
|
||||||
void Td::on_request(uint64 id, const td_api::getChatThemes &request) {
|
|
||||||
CHECK_IS_USER();
|
|
||||||
CREATE_REQUEST_PROMISE();
|
|
||||||
theme_manager_->get_chat_themes(std::move(promise));
|
|
||||||
}
|
|
||||||
|
|
||||||
void Td::on_request(uint64 id, td_api::getRecentlyVisitedTMeUrls &request) {
|
void Td::on_request(uint64 id, td_api::getRecentlyVisitedTMeUrls &request) {
|
||||||
CHECK_IS_USER();
|
CHECK_IS_USER();
|
||||||
CLEAN_INPUT_STRING(request.referrer_);
|
CLEAN_INPUT_STRING(request.referrer_);
|
||||||
|
@ -595,6 +595,8 @@ class Td final : public Actor {
|
|||||||
|
|
||||||
void on_request(uint64 id, const td_api::clearRecentlyFoundChats &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, const td_api::getGroupsInCommon &request);
|
||||||
|
|
||||||
void on_request(uint64 id, td_api::checkChatUsername &request);
|
void on_request(uint64 id, td_api::checkChatUsername &request);
|
||||||
@ -1195,8 +1197,6 @@ class Td final : public Actor {
|
|||||||
|
|
||||||
void on_request(uint64 id, const td_api::resetBackgrounds &request);
|
void on_request(uint64 id, const td_api::resetBackgrounds &request);
|
||||||
|
|
||||||
void on_request(uint64 id, const td_api::getChatThemes &request);
|
|
||||||
|
|
||||||
void on_request(uint64 id, td_api::getRecentlyVisitedTMeUrls &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::setBotUpdatesStatus &request);
|
||||||
|
@ -6,6 +6,7 @@
|
|||||||
//
|
//
|
||||||
#include "td/telegram/ThemeManager.h"
|
#include "td/telegram/ThemeManager.h"
|
||||||
|
|
||||||
|
#include "td/telegram/AuthManager.h"
|
||||||
#include "td/telegram/BackgroundManager.h"
|
#include "td/telegram/BackgroundManager.h"
|
||||||
#include "td/telegram/Global.h"
|
#include "td/telegram/Global.h"
|
||||||
#include "td/telegram/net/NetQueryCreator.h"
|
#include "td/telegram/net/NetQueryCreator.h"
|
||||||
@ -14,6 +15,7 @@
|
|||||||
#include "td/utils/algorithm.h"
|
#include "td/utils/algorithm.h"
|
||||||
#include "td/utils/buffer.h"
|
#include "td/utils/buffer.h"
|
||||||
#include "td/utils/logging.h"
|
#include "td/utils/logging.h"
|
||||||
|
#include "td/utils/Random.h"
|
||||||
#include "td/utils/Time.h"
|
#include "td/utils/Time.h"
|
||||||
|
|
||||||
namespace td {
|
namespace td {
|
||||||
@ -44,33 +46,73 @@ class GetChatThemesQuery final : public Td::ResultHandler {
|
|||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
|
bool operator==(const ThemeManager::ThemeSettings &lhs, const ThemeManager::ThemeSettings &rhs) {
|
||||||
|
return lhs.accent_color == rhs.accent_color && lhs.background_id == rhs.background_id &&
|
||||||
|
lhs.background_type == rhs.background_type && lhs.base_theme == rhs.base_theme &&
|
||||||
|
lhs.message_colors == rhs.message_colors && lhs.animate_message_colors == rhs.animate_message_colors;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool operator!=(const ThemeManager::ThemeSettings &lhs, const ThemeManager::ThemeSettings &rhs) {
|
||||||
|
return !(lhs == rhs);
|
||||||
|
}
|
||||||
|
|
||||||
ThemeManager::ThemeManager(Td *td, ActorShared<> parent) : td_(td), parent_(std::move(parent)) {
|
ThemeManager::ThemeManager(Td *td, ActorShared<> parent) : td_(td), parent_(std::move(parent)) {
|
||||||
chat_themes_.next_reload_time = Time::now();
|
}
|
||||||
|
|
||||||
|
void ThemeManager::start_up() {
|
||||||
|
init();
|
||||||
|
}
|
||||||
|
|
||||||
|
void ThemeManager::init() {
|
||||||
|
if (!td_->auth_manager_->is_authorized() || td_->auth_manager_->is_bot()) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
chat_themes_.next_reload_time = Time::now(); // TODO load chat themes from binlog
|
||||||
|
loop();
|
||||||
}
|
}
|
||||||
|
|
||||||
void ThemeManager::tear_down() {
|
void ThemeManager::tear_down() {
|
||||||
parent_.reset();
|
parent_.reset();
|
||||||
}
|
}
|
||||||
|
|
||||||
void ThemeManager::get_chat_themes(Promise<td_api::object_ptr<td_api::chatThemes>> &&promise) {
|
void ThemeManager::loop() {
|
||||||
|
if (!td_->auth_manager_->is_authorized() || td_->auth_manager_->is_bot()) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
if (Time::now() < chat_themes_.next_reload_time) {
|
if (Time::now() < chat_themes_.next_reload_time) {
|
||||||
return promise.set_value(get_chat_themes_object());
|
return set_timeout_at(chat_themes_.next_reload_time);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!chat_themes_.themes.empty()) {
|
auto request_promise = PromiseCreator::lambda(
|
||||||
promise.set_value(get_chat_themes_object());
|
[actor_id = actor_id(this)](Result<telegram_api::object_ptr<telegram_api::account_ChatThemes>> result) {
|
||||||
pending_get_chat_themes_queries_.push_back(Promise<td_api::object_ptr<td_api::chatThemes>>());
|
send_closure(actor_id, &ThemeManager::on_get_chat_themes, std::move(result));
|
||||||
} else {
|
});
|
||||||
pending_get_chat_themes_queries_.push_back(std::move(promise));
|
|
||||||
}
|
|
||||||
if (pending_get_chat_themes_queries_.size() == 1) {
|
|
||||||
auto request_promise = PromiseCreator::lambda(
|
|
||||||
[actor_id = actor_id(this)](Result<telegram_api::object_ptr<telegram_api::account_ChatThemes>> result) {
|
|
||||||
send_closure(actor_id, &ThemeManager::on_get_chat_themes, std::move(result));
|
|
||||||
});
|
|
||||||
|
|
||||||
td_->create_handler<GetChatThemesQuery>(std::move(request_promise))->send(chat_themes_.hash);
|
td_->create_handler<GetChatThemesQuery>(std::move(request_promise))->send(chat_themes_.hash);
|
||||||
|
}
|
||||||
|
|
||||||
|
void ThemeManager::on_update_theme(telegram_api::object_ptr<telegram_api::theme> &&theme, Promise<Unit> &&promise) {
|
||||||
|
CHECK(theme != nullptr);
|
||||||
|
bool is_changed = false;
|
||||||
|
for (auto &chat_theme : chat_themes_.themes) {
|
||||||
|
if (chat_theme.light_id == theme->id_ || chat_theme.dark_id == theme->id_) {
|
||||||
|
auto theme_settings = get_chat_theme_settings(std::move(theme->settings_));
|
||||||
|
if (chat_theme.light_id == theme->id_ && chat_theme.light_theme != theme_settings) {
|
||||||
|
chat_theme.light_theme = theme_settings;
|
||||||
|
is_changed = true;
|
||||||
|
}
|
||||||
|
if (chat_theme.dark_id == theme->id_ && chat_theme.dark_theme != theme_settings) {
|
||||||
|
chat_theme.dark_theme = theme_settings;
|
||||||
|
is_changed = true;
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
if (is_changed) {
|
||||||
|
send_update_chat_themes();
|
||||||
|
}
|
||||||
|
promise.set_value(Unit());
|
||||||
}
|
}
|
||||||
|
|
||||||
td_api::object_ptr<td_api::themeSettings> ThemeManager::get_theme_settings_object(const ThemeSettings &settings) const {
|
td_api::object_ptr<td_api::themeSettings> ThemeManager::get_theme_settings_object(const ThemeSettings &settings) const {
|
||||||
@ -97,54 +139,52 @@ td_api::object_ptr<td_api::chatTheme> ThemeManager::get_chat_theme_object(const
|
|||||||
get_theme_settings_object(theme.dark_theme));
|
get_theme_settings_object(theme.dark_theme));
|
||||||
}
|
}
|
||||||
|
|
||||||
td_api::object_ptr<td_api::chatThemes> ThemeManager::get_chat_themes_object() const {
|
td_api::object_ptr<td_api::updateChatThemes> ThemeManager::get_update_chat_themes_object() const {
|
||||||
return td_api::make_object<td_api::chatThemes>(
|
return td_api::make_object<td_api::updateChatThemes>(
|
||||||
transform(chat_themes_.themes, [this](const ChatTheme &theme) { return get_chat_theme_object(theme); }));
|
transform(chat_themes_.themes, [this](const ChatTheme &theme) { return get_chat_theme_object(theme); }));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void ThemeManager::send_update_chat_themes() const {
|
||||||
|
send_closure(G()->td(), &Td::send_update, get_update_chat_themes_object());
|
||||||
|
}
|
||||||
|
|
||||||
void ThemeManager::on_get_chat_themes(Result<telegram_api::object_ptr<telegram_api::account_ChatThemes>> result) {
|
void ThemeManager::on_get_chat_themes(Result<telegram_api::object_ptr<telegram_api::account_ChatThemes>> result) {
|
||||||
auto promises = std::move(pending_get_chat_themes_queries_);
|
|
||||||
CHECK(!promises.empty());
|
|
||||||
reset_to_empty(pending_get_chat_themes_queries_);
|
|
||||||
|
|
||||||
if (result.is_error()) {
|
if (result.is_error()) {
|
||||||
// do not clear chat_themes_
|
set_timeout_in(Random::fast(40, 60));
|
||||||
|
|
||||||
auto error = result.move_as_error();
|
|
||||||
for (auto &promise : promises) {
|
|
||||||
promise.set_error(error.clone());
|
|
||||||
}
|
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
chat_themes_.next_reload_time = Time::now() + THEME_CACHE_TIME;
|
chat_themes_.next_reload_time = Time::now() + THEME_CACHE_TIME;
|
||||||
|
set_timeout_at(chat_themes_.next_reload_time);
|
||||||
|
|
||||||
auto chat_themes_ptr = result.move_as_ok();
|
auto chat_themes_ptr = result.move_as_ok();
|
||||||
LOG(DEBUG) << "Receive " << to_string(chat_themes_ptr);
|
LOG(DEBUG) << "Receive " << to_string(chat_themes_ptr);
|
||||||
if (chat_themes_ptr->get_id() != telegram_api::account_chatThemesNotModified::ID) {
|
if (chat_themes_ptr->get_id() == telegram_api::account_chatThemesNotModified::ID) {
|
||||||
CHECK(chat_themes_ptr->get_id() == telegram_api::account_chatThemes::ID);
|
return;
|
||||||
auto chat_themes = telegram_api::move_object_as<telegram_api::account_chatThemes>(chat_themes_ptr);
|
}
|
||||||
chat_themes_.hash = chat_themes->hash_;
|
CHECK(chat_themes_ptr->get_id() == telegram_api::account_chatThemes::ID);
|
||||||
chat_themes_.themes.clear();
|
auto chat_themes = telegram_api::move_object_as<telegram_api::account_chatThemes>(chat_themes_ptr);
|
||||||
for (auto &chat_theme : chat_themes->themes_) {
|
chat_themes_.hash = chat_themes->hash_;
|
||||||
if (chat_theme->emoticon_.empty()) {
|
chat_themes_.themes.clear();
|
||||||
LOG(ERROR) << "Receive " << to_string(chat_theme);
|
for (auto &chat_theme : chat_themes->themes_) {
|
||||||
continue;
|
if (chat_theme->emoticon_.empty()) {
|
||||||
}
|
LOG(ERROR) << "Receive " << to_string(chat_theme);
|
||||||
|
continue;
|
||||||
ChatTheme theme;
|
|
||||||
theme.emoji = std::move(chat_theme->emoticon_);
|
|
||||||
theme.light_theme = get_chat_theme_settings(std::move(chat_theme->theme_->settings_));
|
|
||||||
theme.dark_theme = get_chat_theme_settings(std::move(chat_theme->dark_theme_->settings_));
|
|
||||||
chat_themes_.themes.push_back(std::move(theme));
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
ChatTheme theme;
|
||||||
|
theme.emoji = std::move(chat_theme->emoticon_);
|
||||||
|
theme.light_id = chat_theme->theme_->id_;
|
||||||
|
theme.dark_id = chat_theme->dark_theme_->id_;
|
||||||
|
theme.light_theme = get_chat_theme_settings(std::move(chat_theme->theme_->settings_));
|
||||||
|
theme.dark_theme = get_chat_theme_settings(std::move(chat_theme->dark_theme_->settings_));
|
||||||
|
if (theme.light_theme.message_colors.empty() || theme.dark_theme.message_colors.empty()) {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
chat_themes_.themes.push_back(std::move(theme));
|
||||||
}
|
}
|
||||||
|
|
||||||
for (auto &promise : promises) {
|
send_update_chat_themes();
|
||||||
if (promise) {
|
|
||||||
promise.set_value(get_chat_themes_object());
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
ThemeManager::BaseTheme ThemeManager::get_base_theme(
|
ThemeManager::BaseTheme ThemeManager::get_base_theme(
|
||||||
@ -184,4 +224,12 @@ ThemeManager::ThemeSettings ThemeManager::get_chat_theme_settings(
|
|||||||
return result;
|
return result;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void ThemeManager::get_current_state(vector<td_api::object_ptr<td_api::Update>> &updates) const {
|
||||||
|
if (!td_->auth_manager_->is_authorized() || td_->auth_manager_->is_bot() || chat_themes_.themes.empty()) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
updates.push_back(get_update_chat_themes_object());
|
||||||
|
}
|
||||||
|
|
||||||
} // namespace td
|
} // namespace td
|
||||||
|
@ -25,7 +25,11 @@ class ThemeManager final : public Actor {
|
|||||||
public:
|
public:
|
||||||
ThemeManager(Td *td, ActorShared<> parent);
|
ThemeManager(Td *td, ActorShared<> parent);
|
||||||
|
|
||||||
void get_chat_themes(Promise<td_api::object_ptr<td_api::chatThemes>> &&promise);
|
void init();
|
||||||
|
|
||||||
|
void on_update_theme(telegram_api::object_ptr<telegram_api::theme> &&theme, Promise<Unit> &&promise);
|
||||||
|
|
||||||
|
void get_current_state(vector<td_api::object_ptr<td_api::Update>> &updates) const;
|
||||||
|
|
||||||
private:
|
private:
|
||||||
enum class BaseTheme : int32 { Classic, Day, Night, Tinted, Arctic };
|
enum class BaseTheme : int32 { Classic, Day, Night, Tinted, Arctic };
|
||||||
@ -41,8 +45,14 @@ class ThemeManager final : public Actor {
|
|||||||
bool animate_message_colors = false;
|
bool animate_message_colors = false;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
friend bool operator==(const ThemeSettings &lhs, const ThemeSettings &rhs);
|
||||||
|
|
||||||
|
friend bool operator!=(const ThemeSettings &lhs, const ThemeSettings &rhs);
|
||||||
|
|
||||||
struct ChatTheme {
|
struct ChatTheme {
|
||||||
string emoji;
|
string emoji;
|
||||||
|
int64 light_id = 0;
|
||||||
|
int64 dark_id = 0;
|
||||||
ThemeSettings light_theme;
|
ThemeSettings light_theme;
|
||||||
ThemeSettings dark_theme;
|
ThemeSettings dark_theme;
|
||||||
};
|
};
|
||||||
@ -53,6 +63,10 @@ class ThemeManager final : public Actor {
|
|||||||
vector<ChatTheme> themes;
|
vector<ChatTheme> themes;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
void start_up() final;
|
||||||
|
|
||||||
|
void loop() final;
|
||||||
|
|
||||||
void tear_down() final;
|
void tear_down() final;
|
||||||
|
|
||||||
void on_get_chat_themes(Result<telegram_api::object_ptr<telegram_api::account_ChatThemes>> result);
|
void on_get_chat_themes(Result<telegram_api::object_ptr<telegram_api::account_ChatThemes>> result);
|
||||||
@ -61,14 +75,14 @@ class ThemeManager final : public Actor {
|
|||||||
|
|
||||||
td_api::object_ptr<td_api::chatTheme> get_chat_theme_object(const ChatTheme &theme) const;
|
td_api::object_ptr<td_api::chatTheme> get_chat_theme_object(const ChatTheme &theme) const;
|
||||||
|
|
||||||
td_api::object_ptr<td_api::chatThemes> get_chat_themes_object() const;
|
td_api::object_ptr<td_api::updateChatThemes> get_update_chat_themes_object() const;
|
||||||
|
|
||||||
|
void send_update_chat_themes() const;
|
||||||
|
|
||||||
static BaseTheme get_base_theme(const telegram_api::object_ptr<telegram_api::BaseTheme> &base_theme);
|
static BaseTheme get_base_theme(const telegram_api::object_ptr<telegram_api::BaseTheme> &base_theme);
|
||||||
|
|
||||||
ThemeSettings get_chat_theme_settings(telegram_api::object_ptr<telegram_api::themeSettings> settings);
|
ThemeSettings get_chat_theme_settings(telegram_api::object_ptr<telegram_api::themeSettings> settings);
|
||||||
|
|
||||||
vector<Promise<td_api::object_ptr<td_api::chatThemes>>> pending_get_chat_themes_queries_;
|
|
||||||
|
|
||||||
ChatThemes chat_themes_;
|
ChatThemes chat_themes_;
|
||||||
|
|
||||||
Td *td_;
|
Td *td_;
|
||||||
|
@ -47,6 +47,7 @@
|
|||||||
#include "td/telegram/StickersManager.h"
|
#include "td/telegram/StickersManager.h"
|
||||||
#include "td/telegram/Td.h"
|
#include "td/telegram/Td.h"
|
||||||
#include "td/telegram/TdDb.h"
|
#include "td/telegram/TdDb.h"
|
||||||
|
#include "td/telegram/ThemeManager.h"
|
||||||
#include "td/telegram/WebPagesManager.h"
|
#include "td/telegram/WebPagesManager.h"
|
||||||
|
|
||||||
#include "td/actor/MultiPromise.h"
|
#include "td/actor/MultiPromise.h"
|
||||||
@ -3206,10 +3207,10 @@ void UpdatesManager::on_update(tl_object_ptr<telegram_api::updateChannelParticip
|
|||||||
add_pending_qts_update(std::move(update), qts, std::move(promise));
|
add_pending_qts_update(std::move(update), qts, std::move(promise));
|
||||||
}
|
}
|
||||||
|
|
||||||
// unsupported updates
|
|
||||||
|
|
||||||
void UpdatesManager::on_update(tl_object_ptr<telegram_api::updateTheme> update, Promise<Unit> &&promise) {
|
void UpdatesManager::on_update(tl_object_ptr<telegram_api::updateTheme> update, Promise<Unit> &&promise) {
|
||||||
promise.set_value(Unit());
|
td_->theme_manager_->on_update_theme(std::move(update->theme_), std::move(promise));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// unsupported updates
|
||||||
|
|
||||||
} // namespace td
|
} // namespace td
|
||||||
|
@ -486,9 +486,9 @@ class UpdatesManager final : public Actor {
|
|||||||
void on_update(tl_object_ptr<telegram_api::updateChatParticipant> update, Promise<Unit> &&promise);
|
void on_update(tl_object_ptr<telegram_api::updateChatParticipant> update, Promise<Unit> &&promise);
|
||||||
void on_update(tl_object_ptr<telegram_api::updateChannelParticipant> update, Promise<Unit> &&promise);
|
void on_update(tl_object_ptr<telegram_api::updateChannelParticipant> update, Promise<Unit> &&promise);
|
||||||
|
|
||||||
// unsupported updates
|
|
||||||
|
|
||||||
void on_update(tl_object_ptr<telegram_api::updateTheme> update, Promise<Unit> &&promise);
|
void on_update(tl_object_ptr<telegram_api::updateTheme> update, Promise<Unit> &&promise);
|
||||||
|
|
||||||
|
// unsupported updates
|
||||||
};
|
};
|
||||||
|
|
||||||
} // namespace td
|
} // namespace td
|
||||||
|
@ -1535,20 +1535,22 @@ class CliClient final : public Actor {
|
|||||||
|
|
||||||
static td_api::object_ptr<td_api::BackgroundType> get_solid_pattern_background(int32 color, int32 intensity,
|
static td_api::object_ptr<td_api::BackgroundType> get_solid_pattern_background(int32 color, int32 intensity,
|
||||||
bool is_moving) {
|
bool is_moving) {
|
||||||
return get_gradient_pattern_background(color, color, intensity, is_moving);
|
return get_gradient_pattern_background(color, color, intensity, false, is_moving);
|
||||||
}
|
}
|
||||||
|
|
||||||
static td_api::object_ptr<td_api::BackgroundType> get_gradient_pattern_background(int32 top_color, int32 bottom_color,
|
static td_api::object_ptr<td_api::BackgroundType> get_gradient_pattern_background(int32 top_color, int32 bottom_color,
|
||||||
int32 intensity, bool is_moving) {
|
int32 intensity, bool is_inverted,
|
||||||
|
bool is_moving) {
|
||||||
return td_api::make_object<td_api::backgroundTypePattern>(get_background_fill(top_color, bottom_color), intensity,
|
return td_api::make_object<td_api::backgroundTypePattern>(get_background_fill(top_color, bottom_color), intensity,
|
||||||
is_moving);
|
is_inverted, is_moving);
|
||||||
}
|
}
|
||||||
|
|
||||||
static td_api::object_ptr<td_api::BackgroundType> get_freeform_gradient_pattern_background(vector<int32> colors,
|
static td_api::object_ptr<td_api::BackgroundType> get_freeform_gradient_pattern_background(vector<int32> colors,
|
||||||
int32 intensity,
|
int32 intensity,
|
||||||
|
bool is_inverted,
|
||||||
bool is_moving) {
|
bool is_moving) {
|
||||||
return td_api::make_object<td_api::backgroundTypePattern>(get_background_fill(std::move(colors)), intensity,
|
return td_api::make_object<td_api::backgroundTypePattern>(get_background_fill(std::move(colors)), intensity,
|
||||||
is_moving);
|
is_inverted, is_moving);
|
||||||
}
|
}
|
||||||
|
|
||||||
static td_api::object_ptr<td_api::BackgroundType> get_solid_background(int32 color) {
|
static td_api::object_ptr<td_api::BackgroundType> get_solid_background(int32 color) {
|
||||||
@ -2229,14 +2231,16 @@ class CliClient final : public Actor {
|
|||||||
send_get_background_url(get_solid_pattern_background(0, 0, false));
|
send_get_background_url(get_solid_pattern_background(0, 0, false));
|
||||||
send_get_background_url(get_solid_pattern_background(0xFFFFFF, 100, true));
|
send_get_background_url(get_solid_pattern_background(0xFFFFFF, 100, true));
|
||||||
send_get_background_url(get_solid_pattern_background(0xABCDEF, 49, true));
|
send_get_background_url(get_solid_pattern_background(0xABCDEF, 49, true));
|
||||||
send_get_background_url(get_gradient_pattern_background(0, 0, 0, false));
|
send_get_background_url(get_gradient_pattern_background(0, 0, 0, false, false));
|
||||||
send_get_background_url(get_gradient_pattern_background(0xFFFFFF, 0, 100, true));
|
send_get_background_url(get_gradient_pattern_background(0, 0, 0, true, false));
|
||||||
send_get_background_url(get_gradient_pattern_background(0xABCDEF, 0xFEDCBA, 49, true));
|
send_get_background_url(get_gradient_pattern_background(0xFFFFFF, 0, 100, false, true));
|
||||||
send_get_background_url(get_gradient_pattern_background(0, 0x1000000, 49, true));
|
send_get_background_url(get_gradient_pattern_background(0xFFFFFF, 0, 100, true, true));
|
||||||
send_get_background_url(get_freeform_gradient_pattern_background({0xABCDEF, 0xFEDCBA}, 49, true));
|
send_get_background_url(get_gradient_pattern_background(0xABCDEF, 0xFEDCBA, 49, false, true));
|
||||||
send_get_background_url(get_freeform_gradient_pattern_background({0xABCDEF, 0x111111, 0x222222}, 49, true));
|
send_get_background_url(get_gradient_pattern_background(0, 0x1000000, 49, false, true));
|
||||||
|
send_get_background_url(get_freeform_gradient_pattern_background({0xABCDEF, 0xFEDCBA}, 49, false, true));
|
||||||
|
send_get_background_url(get_freeform_gradient_pattern_background({0xABCDEF, 0x111111, 0x222222}, 49, true, true));
|
||||||
send_get_background_url(
|
send_get_background_url(
|
||||||
get_freeform_gradient_pattern_background({0xABCDEF, 0xFEDCBA, 0x111111, 0x222222}, 49, true));
|
get_freeform_gradient_pattern_background({0xABCDEF, 0xFEDCBA, 0x111111, 0x222222}, 49, false, true));
|
||||||
send_get_background_url(get_solid_background(-1));
|
send_get_background_url(get_solid_background(-1));
|
||||||
send_get_background_url(get_solid_background(0xABCDEF));
|
send_get_background_url(get_solid_background(0xABCDEF));
|
||||||
send_get_background_url(get_solid_background(0x1000000));
|
send_get_background_url(get_solid_background(0x1000000));
|
||||||
@ -2261,7 +2265,7 @@ class CliClient final : public Actor {
|
|||||||
} else if (op == "sbggp" || op == "sbggpd") {
|
} else if (op == "sbggp" || op == "sbggpd") {
|
||||||
send_request(td_api::make_object<td_api::setBackground>(
|
send_request(td_api::make_object<td_api::setBackground>(
|
||||||
td_api::make_object<td_api::inputBackgroundLocal>(as_input_file(args)),
|
td_api::make_object<td_api::inputBackgroundLocal>(as_input_file(args)),
|
||||||
get_gradient_pattern_background(0xABCDEF, 0xFE, 51, false), op == "sbggpd"));
|
get_gradient_pattern_background(0xABCDEF, 0xFE, 51, op == "sbggpd", false), op == "sbggpd"));
|
||||||
} else if (op == "sbgs" || op == "sbgsd") {
|
} else if (op == "sbgs" || op == "sbgsd") {
|
||||||
int32 color;
|
int32 color;
|
||||||
get_args(args, color);
|
get_args(args, color);
|
||||||
@ -2296,8 +2300,6 @@ class CliClient final : public Actor {
|
|||||||
send_request(td_api::make_object<td_api::removeBackground>(to_integer<int64>(args)));
|
send_request(td_api::make_object<td_api::removeBackground>(to_integer<int64>(args)));
|
||||||
} else if (op == "rbgs") {
|
} else if (op == "rbgs") {
|
||||||
send_request(td_api::make_object<td_api::resetBackgrounds>());
|
send_request(td_api::make_object<td_api::resetBackgrounds>());
|
||||||
} else if (op == "gcts") {
|
|
||||||
send_request(td_api::make_object<td_api::getChatThemes>());
|
|
||||||
} else if (op == "gcos") {
|
} else if (op == "gcos") {
|
||||||
send_request(td_api::make_object<td_api::getCountries>());
|
send_request(td_api::make_object<td_api::getCountries>());
|
||||||
} else if (op == "gcoc") {
|
} else if (op == "gcoc") {
|
||||||
@ -4050,6 +4052,8 @@ class CliClient final : public Actor {
|
|||||||
send_request(td_api::make_object<td_api::removeRecentlyFoundChat>(as_chat_id(args)));
|
send_request(td_api::make_object<td_api::removeRecentlyFoundChat>(as_chat_id(args)));
|
||||||
} else if (op == "crfcs") {
|
} else if (op == "crfcs") {
|
||||||
send_request(td_api::make_object<td_api::clearRecentlyFoundChats>());
|
send_request(td_api::make_object<td_api::clearRecentlyFoundChats>());
|
||||||
|
} else if (op == "groc") {
|
||||||
|
send_request(td_api::make_object<td_api::getRecentlyOpenedChats>(as_limit(args)));
|
||||||
} else if (op == "gwpp") {
|
} else if (op == "gwpp") {
|
||||||
send_request(td_api::make_object<td_api::getWebPagePreview>(as_caption(args)));
|
send_request(td_api::make_object<td_api::getWebPagePreview>(as_caption(args)));
|
||||||
} else if (op == "gwpiv") {
|
} else if (op == "gwpiv") {
|
||||||
|
@ -172,7 +172,7 @@ class DcOption {
|
|||||||
|
|
||||||
friend bool operator==(const DcOption &lhs, const DcOption &rhs);
|
friend bool operator==(const DcOption &lhs, const DcOption &rhs);
|
||||||
|
|
||||||
friend StringBuilder &operator<<(StringBuilder &sb, const DcOption::PrintFlags &flags);
|
friend StringBuilder &operator<<(StringBuilder &sb, const PrintFlags &flags);
|
||||||
|
|
||||||
friend StringBuilder &operator<<(StringBuilder &sb, const DcOption &dc_option);
|
friend StringBuilder &operator<<(StringBuilder &sb, const DcOption &dc_option);
|
||||||
|
|
||||||
|
@ -17,6 +17,7 @@
|
|||||||
#include "td/utils/SliceBuilder.h"
|
#include "td/utils/SliceBuilder.h"
|
||||||
#include "td/utils/Status.h"
|
#include "td/utils/Status.h"
|
||||||
#include "td/utils/tl_storers.h"
|
#include "td/utils/tl_storers.h"
|
||||||
|
#include "td/utils/TlDowncastHelper.h"
|
||||||
|
|
||||||
#include <type_traits>
|
#include <type_traits>
|
||||||
|
|
||||||
@ -149,21 +150,6 @@ Status from_json(std::vector<T> &to, JsonValue from) {
|
|||||||
return Status::OK();
|
return Status::OK();
|
||||||
}
|
}
|
||||||
|
|
||||||
template <class T>
|
|
||||||
class DowncastHelper final : public T {
|
|
||||||
public:
|
|
||||||
explicit DowncastHelper(int32 constructor) : constructor_(constructor) {
|
|
||||||
}
|
|
||||||
int32 get_id() const final {
|
|
||||||
return constructor_;
|
|
||||||
}
|
|
||||||
void store(TlStorerToString &s, const char *field_name) const final {
|
|
||||||
}
|
|
||||||
|
|
||||||
private:
|
|
||||||
int32 constructor_{0};
|
|
||||||
};
|
|
||||||
|
|
||||||
template <class T>
|
template <class T>
|
||||||
std::enable_if_t<!std::is_constructible<T>::value, Status> from_json(tl_object_ptr<T> &to, JsonValue from) {
|
std::enable_if_t<!std::is_constructible<T>::value, Status> from_json(tl_object_ptr<T> &to, JsonValue from) {
|
||||||
if (from.type() != JsonValue::Type::Object) {
|
if (from.type() != JsonValue::Type::Object) {
|
||||||
@ -185,7 +171,7 @@ std::enable_if_t<!std::is_constructible<T>::value, Status> from_json(tl_object_p
|
|||||||
return Status::Error(PSLICE() << "Expected String or Integer, got " << constructor_value.type());
|
return Status::Error(PSLICE() << "Expected String or Integer, got " << constructor_value.type());
|
||||||
}
|
}
|
||||||
|
|
||||||
DowncastHelper<T> helper(constructor);
|
TlDowncastHelper<T> helper(constructor);
|
||||||
Status status;
|
Status status;
|
||||||
bool ok = downcast_call(static_cast<T &>(helper), [&](auto &dummy) {
|
bool ok = downcast_call(static_cast<T &>(helper), [&](auto &dummy) {
|
||||||
auto result = make_tl_object<std::decay_t<decltype(dummy)>>();
|
auto result = make_tl_object<std::decay_t<decltype(dummy)>>();
|
||||||
|
@ -256,10 +256,10 @@ set(TDUTILS_SOURCE
|
|||||||
td/utils/Time.h
|
td/utils/Time.h
|
||||||
td/utils/TimedStat.h
|
td/utils/TimedStat.h
|
||||||
td/utils/Timer.h
|
td/utils/Timer.h
|
||||||
td/utils/TsFileLog.h
|
|
||||||
td/utils/tl_helpers.h
|
td/utils/tl_helpers.h
|
||||||
td/utils/tl_parsers.h
|
td/utils/tl_parsers.h
|
||||||
td/utils/tl_storers.h
|
td/utils/tl_storers.h
|
||||||
|
td/utils/TlDowncastHelper.h
|
||||||
td/utils/translit.h
|
td/utils/translit.h
|
||||||
td/utils/TsCerr.h
|
td/utils/TsCerr.h
|
||||||
td/utils/TsFileLog.h
|
td/utils/TsFileLog.h
|
||||||
|
26
tdutils/td/utils/TlDowncastHelper.h
Normal file
26
tdutils/td/utils/TlDowncastHelper.h
Normal file
@ -0,0 +1,26 @@
|
|||||||
|
//
|
||||||
|
// Copyright Aliaksei Levin (levlam@telegram.org), Arseny Smirnov (arseny30@gmail.com) 2014-2021
|
||||||
|
//
|
||||||
|
// 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
|
||||||
|
|
||||||
|
namespace td {
|
||||||
|
|
||||||
|
template <class T>
|
||||||
|
class TlDowncastHelper final : public T {
|
||||||
|
public:
|
||||||
|
explicit TlDowncastHelper(int32 constructor) : constructor_(constructor) {
|
||||||
|
}
|
||||||
|
int32 get_id() const final {
|
||||||
|
return constructor_;
|
||||||
|
}
|
||||||
|
void store(TlStorerToString &s, const char *field_name) const final {
|
||||||
|
}
|
||||||
|
|
||||||
|
private:
|
||||||
|
int32 constructor_{0};
|
||||||
|
};
|
||||||
|
|
||||||
|
} // namespace td
|
@ -10,6 +10,8 @@ char disable_linker_warning_about_empty_file_wstring_convert_cpp TD_UNUSED;
|
|||||||
|
|
||||||
#if TD_PORT_WINDOWS
|
#if TD_PORT_WINDOWS
|
||||||
|
|
||||||
|
#include "td/utils/base64.h"
|
||||||
|
#include "td/utils/SliceBuilder.h"
|
||||||
#include "td/utils/utf8.h"
|
#include "td/utils/utf8.h"
|
||||||
|
|
||||||
#include <cwchar>
|
#include <cwchar>
|
||||||
@ -18,7 +20,7 @@ namespace td {
|
|||||||
|
|
||||||
Result<std::wstring> to_wstring(CSlice slice) {
|
Result<std::wstring> to_wstring(CSlice slice) {
|
||||||
if (!check_utf8(slice)) {
|
if (!check_utf8(slice)) {
|
||||||
return Status::Error("Wrong string encoding");
|
return Status::Error(PSLICE() << "String was expected to be encoded in UTF-8: " << base64_encode(slice));
|
||||||
}
|
}
|
||||||
|
|
||||||
size_t wstring_len = utf8_utf16_length(slice);
|
size_t wstring_len = utf8_utf16_length(slice);
|
||||||
|
Loading…
x
Reference in New Issue
Block a user