Merge commit '1d9989cbd700492ffe636385d5578946f62139d9'

Conflicts:
	td/telegram/ContactsManager.cpp
	td/telegram/ContactsManager.h
	td/telegram/MessagesDb.cpp
	td/telegram/MessagesManager.cpp
This commit is contained in:
Andrea Cavalli 2020-10-01 13:22:37 +02:00
commit c83fc13a60
100 changed files with 3834 additions and 2169 deletions

View File

@ -443,6 +443,7 @@ set(TDLIB_SOURCE
td/telegram/JsonValue.cpp
td/telegram/LanguagePackManager.cpp
td/telegram/Location.cpp
td/telegram/logevent/LogEventHelper.cpp
td/telegram/Logging.cpp
td/telegram/MessageContent.cpp
td/telegram/MessageContentType.cpp

View File

@ -273,7 +273,7 @@ function split_file($file, $chunks, $undo) {
'HashtagHints' => 'HashtagHints',
'inline_queries_manager[_(-][^.]|InlineQueriesManager' => 'InlineQueriesManager',
'language_pack_manager[_(-][^.]|LanguagePackManager' => 'LanguagePackManager',
'get_erase_logevent_promise|parse_time|store_time' => 'logevent/LogEventHelper',
'LogeventIdWithGeneration|add_log_event|delete_log_event|get_erase_log_event_promise|parse_time|store_time' => 'logevent/LogEventHelper',
'MessageCopyOptions' => 'MessageCopyOptions',
'messages_manager[_(-][^.]|MessagesManager' => 'MessagesManager',
'notification_manager[_(-][^.]|NotificationManager|notifications[)]' => 'NotificationManager',

View File

@ -56,12 +56,12 @@ class RingBench : public td::Benchmark {
send_closure_later(next_actor, &PassActor::pass, n - 1);
} else {
// TODO: it is three times faster than send_event
// may be send event could be further optimized?
// maybe send event could be further optimized?
::td::Scheduler::instance()->hack(static_cast<td::ActorId<Actor>>(next_actor),
td::Event::raw(static_cast<td::uint32>(n - 1)));
}
} else if (type == 4) {
send_lambda(next_actor, [=, ptr = next_actor.get_actor_unsafe()] { ptr->pass(n - 1); });
send_lambda(next_actor, [n, ptr = next_actor.get_actor_unsafe()] { ptr->pass(n - 1); });
}
}
}

View File

@ -13,8 +13,8 @@
#include "td/utils/Slice.h"
#include "td/utils/UInt.h"
#include <openssl/sha.h>
#include <openssl/evp.h>
#include <openssl/sha.h>
#include <array>
#include <atomic>
@ -168,7 +168,6 @@ class AesCtrBench : public td::Benchmark {
class AesCtrOpenSSLBench : public td::Benchmark {
public:
alignas(64) unsigned char data[DATA_SIZE];
alignas(64) unsigned char dest[DATA_SIZE];
td::UInt256 key;
td::UInt128 iv;
@ -185,35 +184,56 @@ class AesCtrOpenSSLBench : public td::Benchmark {
}
void run(int n) override {
EVP_CIPHER_CTX *ctx;
int len;
ctx = EVP_CIPHER_CTX_new();
EVP_EncryptInit_ex(ctx, EVP_aes_128_ctr(), NULL, key.raw, iv.raw);
EVP_CIPHER_CTX *ctx = EVP_CIPHER_CTX_new();
EVP_EncryptInit_ex(ctx, EVP_aes_256_ctr(), NULL, key.raw, iv.raw);
td::MutableSlice data_slice(data, DATA_SIZE);
td::MutableSlice dest_slice(dest, DATA_SIZE);
td::AesCtrState state;
state.init(as_slice(key), as_slice(iv));
for (int i = 0; i < n; i++) {
//state.encrypt(data_slice, data_slice);
len = (int)data_slice.size();
EVP_EncryptUpdate(ctx, dest_slice.ubegin(), &len, data_slice.ubegin(), len);
int len = 0;
EVP_EncryptUpdate(ctx, data_slice.ubegin(), &len, data_slice.ubegin(), DATA_SIZE);
CHECK(len == DATA_SIZE);
}
//EVP_EncryptFinal_ex(ctx, ciphertext + len, &len);
EVP_CIPHER_CTX_free(ctx);
}
};
class AesCbcBench : public td::Benchmark {
class AesCbcDecryptBench : public td::Benchmark {
public:
alignas(64) unsigned char data[DATA_SIZE];
td::UInt256 key;
td::UInt128 iv;
std::string get_description() const override {
return PSTRING() << "AES CBC OpenSSL [" << (DATA_SIZE >> 10) << "KB]";
return PSTRING() << "AES CBC Decrypt OpenSSL [" << (DATA_SIZE >> 10) << "KB]";
}
void start_up() override {
for (int i = 0; i < DATA_SIZE; i++) {
data[i] = 123;
}
td::Random::secure_bytes(as_slice(key));
td::Random::secure_bytes(as_slice(iv));
}
void run(int n) override {
td::MutableSlice data_slice(data, DATA_SIZE);
for (int i = 0; i < n; i++) {
td::aes_cbc_decrypt(as_slice(key), as_slice(iv), data_slice, data_slice);
}
}
};
class AesCbcEncryptBench : public td::Benchmark {
public:
alignas(64) unsigned char data[DATA_SIZE];
td::UInt256 key;
td::UInt128 iv;
std::string get_description() const override {
return PSTRING() << "AES CBC Encrypt OpenSSL [" << (DATA_SIZE >> 10) << "KB]";
}
void start_up() override {
@ -391,6 +411,8 @@ int main() {
td::bench(AesCtrBench());
td::bench(AesCtrOpenSSLBench());
td::bench(AesCbcDecryptBench());
td::bench(AesCbcEncryptBench());
td::bench(AesIgeShortBench<true>());
td::bench(AesIgeShortBench<false>());
td::bench(AesIgeEncryptBench());

View File

@ -62,7 +62,8 @@ class MessagesDbBench : public Benchmark {
// use async on same thread.
messages_db_async_->add_message({dialog_id, message_id}, unique_message_id, sender_user_id, random_id,
ttl_expires_at, 0, 0, "", NotificationId(), std::move(data), Promise<>());
ttl_expires_at, 0, 0, "", NotificationId(), MessageId(), std::move(data),
Promise<>());
}
}
}

View File

@ -209,7 +209,7 @@ namespace TdExample
TdApi.ReplyMarkup replyMarkup = new TdApi.ReplyMarkupInlineKeyboard(new TdApi.InlineKeyboardButton[][] { row, row, row });
TdApi.InputMessageContent content = new TdApi.InputMessageText(new TdApi.FormattedText(message, null), false, true);
_client.Send(new TdApi.SendMessage(chatId, 0, null, replyMarkup, content), _defaultHandler);
_client.Send(new TdApi.SendMessage(chatId, 0, 0, null, replyMarkup, content), _defaultHandler);
}
static void Main()

View File

@ -299,7 +299,7 @@ public final class Example {
TdApi.ReplyMarkup replyMarkup = new TdApi.ReplyMarkupInlineKeyboard(new TdApi.InlineKeyboardButton[][]{row, row, row});
TdApi.InputMessageContent content = new TdApi.InputMessageText(new TdApi.FormattedText(message, null), false, true);
client.send(new TdApi.SendMessage(chatId, 0, null, replyMarkup, content), defaultHandler);
client.send(new TdApi.SendMessage(chatId, 0, 0, null, replyMarkup, content), defaultHandler);
}
public static void main(String[] args) throws InterruptedException {

View File

@ -226,7 +226,7 @@ EOT
* auto get_authorization_state_request = td::td_api::make_object<td::td_api::getAuthorizationState>();
* auto message_text = td::td_api::make_object<td::td_api::formattedText>("Hello, world!!!",
* std::vector<td::td_api::object_ptr<td::td_api::textEntity>>());
* auto send_message_request = td::td_api::make_object<td::td_api::sendMessage>(chat_id, 0, nullptr, nullptr,
* auto send_message_request = td::td_api::make_object<td::td_api::sendMessage>(chat_id, 0, 0, nullptr, nullptr,
* td::td_api::make_object<td::td_api::inputMessageText>(std::move(message_text), false, true));
* \\endcode
*

View File

@ -405,7 +405,6 @@ user id:int32 first_name:string last_name:string username:string phone_number:st
//@description Contains full information about a user
//@photo User profile photo; may be null
//@is_blocked True, if the user is blocked by the current user
//@can_be_called True, if the user can be called
//@supports_video_calls True, if a video call can be created with the user
//@has_private_calls True, if the user can't be called due to their privacy settings
@ -413,7 +412,7 @@ user id:int32 first_name:string last_name:string username:string phone_number:st
//@bio A short user bio @share_text For bots, the text that is included with the link when users share the bot
//@group_in_common_count Number of group chats where both the other user and the current user are a member; 0 for the current user
//@bot_info If the user is a bot, information about the bot; may be null
userFullInfo photo:chatPhoto is_blocked:Bool can_be_called:Bool supports_video_calls:Bool has_private_calls:Bool need_phone_number_privacy_exception:Bool bio:string share_text:string group_in_common_count:int32 bot_info:botInfo = UserFullInfo;
userFullInfo photo:chatPhoto can_be_called:Bool supports_video_calls:Bool has_private_calls:Bool need_phone_number_privacy_exception:Bool bio:string share_text:string group_in_common_count:int32 bot_info:botInfo = UserFullInfo;
//@description Represents a list of users @total_count Approximate total count of users found @user_ids A list of user identifiers
users total_count:int32 user_ids:vector<int32> = Users;
@ -441,13 +440,12 @@ chatPermissions can_send_messages:Bool can_send_media_messages:Bool can_send_pol
//@class ChatMemberStatus @description Provides information about the status of a member in a chat
//@description The user is the owner of a chat and has all the administrator privileges
//@is_anonymous True, if the creator isn't shown in the chat member list and sends messages anonymously
//@custom_title A custom title of the owner; 0-16 characters without emojis; applicable to supergroups only
//@is_anonymous True, if the creator isn't shown in the chat member list and sends messages anonymously
//@is_member True, if the user is a member of the chat
chatMemberStatusCreator is_anonymous:Bool custom_title:string is_member:Bool = ChatMemberStatus;
chatMemberStatusCreator custom_title:string is_anonymous:Bool is_member:Bool = ChatMemberStatus;
//@description The user is a member of a chat and has some additional privileges. In basic groups, administrators can edit and delete messages sent by others, add new members, and ban unprivileged members. In supergroups and channels, there are more detailed options for administrator privileges
//@is_anonymous True, if the administrator isn't shown in the chat member list and sends messages anonymously
//@custom_title A custom title of the administrator; 0-16 characters without emojis; applicable to supergroups only
//@can_be_edited True, if the current user can edit the administrator privileges for the called user
//@can_change_info True, if the administrator can change the chat title, photo, and other settings
@ -458,7 +456,8 @@ chatMemberStatusCreator is_anonymous:Bool custom_title:string is_member:Bool = C
//@can_restrict_members True, if the administrator can restrict, ban, or unban chat members
//@can_pin_messages True, if the administrator can pin messages; applicable to groups only
//@can_promote_members True, if the administrator can add new administrators with a subset of their own privileges or demote administrators that were directly or indirectly promoted by them
chatMemberStatusAdministrator is_anonymous:Bool custom_title:string can_be_edited:Bool can_change_info:Bool can_post_messages:Bool can_edit_messages:Bool can_delete_messages:Bool can_invite_users:Bool can_restrict_members:Bool can_pin_messages:Bool can_promote_members:Bool = ChatMemberStatus;
//@is_anonymous True, if the administrator isn't shown in the chat member list and sends messages anonymously
chatMemberStatusAdministrator custom_title:string can_be_edited:Bool can_change_info:Bool can_post_messages:Bool can_edit_messages:Bool can_delete_messages:Bool can_invite_users:Bool can_restrict_members:Bool can_pin_messages:Bool can_promote_members:Bool is_anonymous:Bool = ChatMemberStatus;
//@description The user is a member of a chat, without any additional privileges or restrictions
chatMemberStatusMember = ChatMemberStatus;
@ -636,16 +635,19 @@ messageForwardOriginChannel chat_id:int53 message_id:int53 author_signature:stri
//@origin Origin of a forwarded message
//@date Point in time (Unix timestamp) when the message was originally sent
//@public_service_announcement_type The type of a public service announcement for the forwarded message
//@from_chat_id For messages forwarded to the chat with the current user (Saved Messages) or to the channel's discussion group, the identifier of the chat from which the message was forwarded last time; 0 if unknown
//@from_message_id For messages forwarded to the chat with the current user (Saved Messages) or to the channel's discussion group, the identifier of the original message from which the new message was forwarded last time; 0 if unknown
//@from_chat_id For messages forwarded to the chat with the current user (Saved Messages), to the Replies bot chat, or to the channel's discussion group, the identifier of the chat from which the message was forwarded last time; 0 if unknown
//@from_message_id For messages forwarded to the chat with the current user (Saved Messages), to the Replies bot chat, or to the channel's discussion group, the identifier of the original message from which the new message was forwarded last time; 0 if unknown
messageForwardInfo origin:MessageForwardOrigin date:int32 public_service_announcement_type:string from_chat_id:int53 from_message_id:int53 = MessageForwardInfo;
//@description Contains information about interactions with a message
//@view_count Number of times the message was viewed
//@forward_count Number of times the message was forwarded
//@reply_count Number of times the message was directly or indirectly replied; supergroups and linked channels only
//@recent_replier_user_ids User identifiers of the recent repliers to the message
messageInteractionInfo view_count:int32 forward_count:int32 reply_count:int32 recent_replier_user_ids:vector<int32> = MessageInteractionInfo;
//@reply_count Number of times the message was directly or indirectly replied; available in discussion supergroups and channels with a discussion supergroup
//@recent_replier_user_ids User identifiers of the recent repliers to the message; available in channels with a discussion supergroup
//@last_read_inbox_comment_message_id Identifier of the last read incoming comment to the message
//@last_read_outbox_comment_message_id Identifier of the last read outgoing comment to the message
//@last_comment_message_id Identifier of the last comment to the message
messageInteractionInfo view_count:int32 forward_count:int32 reply_count:int32 recent_replier_user_ids:vector<int32> last_read_inbox_comment_message_id:int53 last_read_outbox_comment_message_id:int53 last_comment_message_id:int53 = MessageInteractionInfo;
//@class MessageSendingState @description Contains information about the sending state of the message
@ -659,7 +661,7 @@ messageSendingStateFailed error_code:int32 error_message:string can_retry:Bool r
//@description Describes a message
//@id Message identifier, unique for the chat to which the message belongs
//@id Message identifier; unique for the chat to which the message belongs
//@sender_user_id Identifier of the user who sent the message; 0 if unknown. Currently, it is unknown for channel posts, for channel posts automatically forwarded to discussion group and for anonimously sent supergroup messages
//@sender_chat_id Identifier of the chat on behalf of which the message was sent; 0 if none
//@chat_id Chat identifier
@ -671,7 +673,7 @@ messageSendingStateFailed error_code:int32 error_message:string can_retry:Bool r
//@can_be_deleted_only_for_self True, if the message can be deleted only for the current user while other users will continue to see it
//@can_be_deleted_for_all_users True, if the message can be deleted for all users
//@can_get_statistics True, if the message statistics are available
//@can_get_replies True, if the message replies are available
//@can_get_message_thread True, if the message thread info is available
//@is_channel_post True, if the message is a channel post. All messages to channels are channel posts, all other messages are not channel posts
//@contains_unread_mention True, if the message contains an unread mention for the current user
//@date Point in time (Unix timestamp) when the message was sent
@ -680,7 +682,7 @@ messageSendingStateFailed error_code:int32 error_message:string can_retry:Bool r
//@interaction_info Information about interactions with the message; may be null
//@reply_in_chat_id If non-zero, the identifier of the chat to which the replied message belongs; Currently, only messages in the Replies chat can have different reply_in_chat_id and chat_id
//@reply_to_message_id If non-zero, the identifier of the message this message is replying to; can be the identifier of a deleted message
//@message_thread_id If non-zero, the identifier of the message thread the message belongs to
//@message_thread_id If non-zero, the identifier of the message thread the message belongs to; unique within the chat to which the message belongs
//@ttl For self-destructing messages, the message's TTL (Time To Live), in seconds; 0 if none. TDLib will send updateDeleteMessages or updateMessageContent once the TTL expires
//@ttl_expires_in Time left before the message expires, in seconds
//@via_bot_user_id If non-zero, the user identifier of the bot through which this message was sent
@ -689,7 +691,7 @@ messageSendingStateFailed error_code:int32 error_message:string can_retry:Bool r
//@restriction_reason If non-empty, contains a human-readable description of the reason why access to this message must be restricted
//@content Content of the message
//@reply_markup Reply markup for the message; may be null
message id:int53 sender_user_id:int32 sender_chat_id:int53 chat_id:int53 sending_state:MessageSendingState scheduling_state:MessageSchedulingState is_outgoing:Bool can_be_edited:Bool can_be_forwarded:Bool can_be_deleted_only_for_self:Bool can_be_deleted_for_all_users:Bool can_get_statistics:Bool can_get_replies:Bool is_channel_post:Bool contains_unread_mention:Bool date:int32 edit_date:int32 forward_info:messageForwardInfo interaction_info:messageInteractionInfo reply_in_chat_id:int53 reply_to_message_id:int53 message_thread_id:int53 ttl:int32 ttl_expires_in:double via_bot_user_id:int32 author_signature:string media_album_id:int64 restriction_reason:string content:MessageContent reply_markup:ReplyMarkup = Message;
message id:int53 sender_user_id:int32 sender_chat_id:int53 chat_id:int53 sending_state:MessageSendingState scheduling_state:MessageSchedulingState is_outgoing:Bool can_be_edited:Bool can_be_forwarded:Bool can_be_deleted_only_for_self:Bool can_be_deleted_for_all_users:Bool can_get_statistics:Bool can_get_message_thread:Bool is_channel_post:Bool contains_unread_mention:Bool date:int32 edit_date:int32 forward_info:messageForwardInfo interaction_info:messageInteractionInfo reply_in_chat_id:int53 reply_to_message_id:int53 message_thread_id:int53 ttl:int32 ttl_expires_in:double via_bot_user_id:int32 author_signature:string media_album_id:int64 restriction_reason:string content:MessageContent reply_markup:ReplyMarkup = Message;
//@description Contains a list of messages @total_count Approximate total count of messages found @messages List of messages; messages may be null
messages total_count:int32 messages:vector<message> = Messages;
@ -820,6 +822,7 @@ chatPosition list:ChatList order:int64 is_pinned:Bool source:ChatSource = ChatPo
//@last_message Last message in the chat; may be null
//@positions Positions of the chat in chat lists
//@is_marked_as_unread True, if the chat is marked as unread
//@is_blocked True, if the chat is blocked by the current user and private messages from the chat can't be received
//@has_scheduled_messages True, if the chat has scheduled messages
//@can_be_deleted_only_for_self True, if the chat messages can be deleted only for the current user while other users will continue to see the messages
//@can_be_deleted_for_all_users True, if the chat messages can be deleted for all users
@ -835,10 +838,10 @@ chatPosition list:ChatList order:int64 is_pinned:Bool source:ChatSource = ChatPo
//@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
//@draft_message A draft of a message in the chat; may be null
//@client_data Contains application-specific data associated with the chat. (For example, the chat scroll position or local chat notification settings can be stored here.) Persistent if the message database is used
chat id:int53 type:ChatType title:string photo:chatPhotoInfo permissions:chatPermissions last_message:message positions:vector<chatPosition> is_marked_as_unread:Bool has_scheduled_messages:Bool can_be_deleted_only_for_self:Bool can_be_deleted_for_all_users:Bool can_be_reported:Bool default_disable_notification:Bool unread_count:int32 last_read_inbox_message_id:int53 last_read_outbox_message_id:int53 unread_mention_count:int32 notification_settings:chatNotificationSettings action_bar:ChatActionBar pinned_message_id:int53 reply_markup_message_id:int53 draft_message:draftMessage client_data:string = Chat;
chat id:int53 type:ChatType title:string photo:chatPhotoInfo permissions:chatPermissions last_message:message positions:vector<chatPosition> is_marked_as_unread:Bool is_blocked:Bool has_scheduled_messages:Bool can_be_deleted_only_for_self:Bool can_be_deleted_for_all_users:Bool can_be_reported:Bool default_disable_notification:Bool unread_count:int32 last_read_inbox_message_id:int53 last_read_outbox_message_id:int53 unread_mention_count:int32 notification_settings:chatNotificationSettings action_bar:ChatActionBar pinned_message_id:int53 reply_markup_message_id:int53 draft_message:draftMessage client_data:string = Chat;
//@description Represents a list of chats @chat_ids List of chat identifiers
chats chat_ids:vector<int53> = Chats;
//@description Represents a list of chats @total_count Approximate total count of chats found @chat_ids List of chat identifiers
chats total_count:int32 chat_ids:vector<int53> = Chats;
//@description Describes a chat located nearby @chat_id Chat identifier @distance Distance to the chat location in meters
@ -972,6 +975,14 @@ loginUrlInfoOpen url:string skip_confirm:Bool = LoginUrlInfo;
loginUrlInfoRequestConfirmation url:string domain:string bot_user_id:int32 request_write_access:Bool = LoginUrlInfo;
//@description Contains information about a message thread
//@chat_id Identifier of the chat to which the message thread belongs
//@message_thread_id Message thread identifier, unique within the chat
//@messages The messages from which the thread starts. The messages are returned in a reverse chronological order (i.e., in order of decreasing message_id)
//@draft_message A draft of a message in the message thread; may be null
messageThreadInfo chat_id:int53 message_thread_id:int53 messages:vector<message> draft_message:draftMessage = MessageThreadInfo;
//@class RichText @description Describes a text object inside an instant-view web page
//@description A plain text @text Text
@ -1750,8 +1761,8 @@ inputMessageAnimation animation:InputFile thumbnail:inputThumbnail added_sticker
//@performer Performer of the audio; 0-64 characters, may be replaced by the server @caption Audio caption; 0-GetOption("message_caption_length_max") characters
inputMessageAudio audio:InputFile album_cover_thumbnail:inputThumbnail duration:int32 title:string performer:string caption:formattedText = InputMessageContent;
//@description A document message (general file) @document Document to be sent @thumbnail Document thumbnail, if available @force_file If true, automatic file type detection will be disabled and the document will be always sent as file. Always true for files sent to secret chats @caption Document caption; 0-GetOption("message_caption_length_max") characters
inputMessageDocument document:InputFile thumbnail:inputThumbnail force_file:Bool caption:formattedText = InputMessageContent;
//@description A document message (general file) @document Document to be sent @thumbnail Document thumbnail, if available @disable_content_type_detection If true, automatic file type detection will be disabled and the document will be always sent as file. Always true for files sent to secret chats @caption Document caption; 0-GetOption("message_caption_length_max") characters
inputMessageDocument document:InputFile thumbnail:inputThumbnail disable_content_type_detection:Bool caption:formattedText = InputMessageContent;
//@description A photo message @photo Photo to send @thumbnail Photo thumbnail to be sent, this is sent to the other party in secret chats only @added_sticker_file_ids File identifiers of the stickers added to the photo, if applicable @width Photo width @height Photo height @caption Photo caption; 0-GetOption("message_caption_length_max") characters
//@ttl Photo TTL (Time To Live), in seconds (0-60). A non-zero TTL can be specified only in private chats
@ -1964,7 +1975,7 @@ callProtocol udp_p2p:Bool udp_reflector:Bool min_layer:int32 max_layer:int32 lib
//@description A Telegram call reflector @peer_tag A peer tag to be used with the reflector
callServerTypeTelegramReflector peer_tag:bytes = CallServerType;
//@description A WebRTC server @username Username to be used for authentification @password Authentication password @supports_turn True, if the server supports TURN @supports_stun True, if the server supports STUN
//@description A WebRTC server @username Username to be used for authentication @password Authentication password @supports_turn True, if the server supports TURN @supports_stun True, if the server supports STUN
callServerTypeWebrtc username:string password:string supports_turn:Bool supports_stun:Bool = CallServerType;
@ -2584,7 +2595,7 @@ optionValueBoolean value:Bool = OptionValue;
optionValueEmpty = OptionValue;
//@description Represents an integer option @value The value of the option
optionValueInteger value:int32 = OptionValue;
optionValueInteger value:int64 = OptionValue;
//@description Represents a string option @value The value of the option
optionValueString value:string = OptionValue;
@ -2729,15 +2740,16 @@ chatReportReasonUnrelatedLocation = ChatReportReason;
chatReportReasonCustom text:string = ChatReportReason;
//@description Contains a public HTTPS link to a message in a supergroup or channel with a username @link Message link @html HTML-code for embedding the message
publicMessageLink link:string html:string = PublicMessageLink;
//@description Contains an HTTPS link to a message in a supergroup or channel @link Message link @is_public True, if the link will work for non-members of the chat
messageLink link:string is_public:Bool = MessageLink;
//@description Contains information about a link to a message in a chat
//@is_public True, if the link is a public link for a message in a chat
//@chat_id If found, identifier of the chat to which the message belongs, 0 otherwise
//@message If found, the linked message; may be null
//@for_album True, if the whole media album to which the message belongs is linked
messageLinkInfo is_public:Bool chat_id:int53 message:message for_album:Bool = MessageLinkInfo;
//@for_comment True, if the message is linked as a channel post comment or from a message thread
messageLinkInfo is_public:Bool chat_id:int53 message:message for_album:Bool for_comment:Bool = MessageLinkInfo;
//@description Contains a part of a file @data File bytes
@ -3140,6 +3152,9 @@ updateChatPosition chat_id:int53 position:chatPosition = Update;
//@description A chat was marked as unread or was read @chat_id Chat identifier @is_marked_as_unread New value of is_marked_as_unread
updateChatIsMarkedAsUnread chat_id:int53 is_marked_as_unread:Bool = Update;
//@description A chat was blocked or unblocked @chat_id Chat identifier @is_blocked New value of is_blocked
updateChatIsBlocked chat_id:int53 is_blocked:Bool = Update;
//@description A chat's has_scheduled_messages field has changed @chat_id Chat identifier @has_scheduled_messages New value of has_scheduled_messages
updateChatHasScheduledMessages chat_id:int53 has_scheduled_messages:Bool = Update;
@ -3206,8 +3221,8 @@ updateHavePendingNotifications have_delayed_notifications:Bool have_unreceived_n
//@from_cache True, if the messages are deleted only from the cache and can possibly be retrieved again in the future
updateDeleteMessages chat_id:int53 message_ids:vector<int53> is_permanent:Bool from_cache:Bool = Update;
//@description User activity in the chat has changed @chat_id Chat identifier @user_id Identifier of a user performing an action @action The action description
updateUserChatAction chat_id:int53 user_id:int32 action:ChatAction = Update;
//@description User activity in the chat has changed @chat_id Chat identifier @message_thread_id If not 0, a message thread identifier in which the action was performed @user_id Identifier of a user performing an action @action The action description
updateUserChatAction chat_id:int53 message_thread_id:int53 user_id:int32 action:ChatAction = Update;
//@description The user went online or offline @user_id User identifier @status New status of the user
updateUserStatus user_id:int32 status:UserStatus = Update;
@ -3362,8 +3377,11 @@ updates updates:vector<Update> = Updates;
//@description The log is written to stderr or an OS specific log
logStreamDefault = LogStream;
//@description The log is written to a file @path Path to the file to where the internal TDLib log will be written @max_file_size The maximum size of the file to where the internal TDLib log is written before the file will be auto-rotated
logStreamFile path:string max_file_size:int53 = LogStream;
//@description The log is written to a file
//@path Path to the file to where the internal TDLib log will be written
//@max_file_size The maximum size of the file to where the internal TDLib log is written before the file will be auto-rotated
//@redirect_stderr Pass true to additionally redirect stderr to the log file. Ignored on Windows
logStreamFile path:string max_file_size:int53 redirect_stderr:Bool = LogStream;
//@description The log is written nowhere
logStreamEmpty = LogStream;
@ -3523,7 +3541,8 @@ getMessage chat_id:int53 message_id:int53 = Message;
//@description Returns information about a message, if it is available locally without sending network request. This is an offline request @chat_id Identifier of the chat the message belongs to @message_id Identifier of the message to get
getMessageLocally chat_id:int53 message_id:int53 = Message;
//@description Returns information about a message that is replied by given message @chat_id Identifier of the chat the message belongs to @message_id Identifier of the message reply to which get
//@description Returns information about a message that is replied by a given message. Also returns the pinned message, the game message, and the invoice message for messages of the types messagePinMessage, messageGameScore, and messagePaymentSuccessful respectively
//@chat_id Identifier of the chat the message belongs to @message_id Identifier of the message reply to which to get
getRepliedMessage chat_id:int53 message_id:int53 = Message;
//@description Returns information about a pinned chat message @chat_id Identifier of the chat the message belongs to
@ -3532,6 +3551,9 @@ getChatPinnedMessage chat_id:int53 = Message;
//@description Returns information about messages. If a message is not found, returns null on the corresponding position of the result @chat_id Identifier of the chat the messages belong to @message_ids Identifiers of the messages to get
getMessages chat_id:int53 message_ids:vector<int53> = Messages;
//@description Returns information about a message thread. Can be used only if message.can_get_message_thread == true @chat_id Chat identifier @message_id Identifier of the message
getMessageThread chat_id:int53 message_id:int53 = MessageThreadInfo;
//@description Returns information about a file; this is an offline request @file_id Identifier of the file to get
getFile file_id:int32 = File;
@ -3678,44 +3700,51 @@ removeNotification notification_group_id:int32 notification_id:int32 = Ok;
removeNotificationGroup notification_group_id:int32 max_notification_id:int32 = Ok;
//@description Returns a public HTTPS link to a message. Available only for messages in supergroups and channels with a username
//@description Returns an HTTPS link to a message in a chat. Available only for already sent messages in supergroups and channels. This is an offline request
//@chat_id Identifier of the chat to which the message belongs
//@message_id Identifier of the message
//@for_album Pass true to create a link for a whole media album
//@for_comment Pass true to create a link to a message as a channel message comment
getPublicMessageLink chat_id:int53 message_id:int53 for_album:Bool for_comment:Bool = PublicMessageLink;
//@for_album Pass true to create a link for the whole media album
//@for_comment Pass true to create a link to the message as a channel post comment, or from a message thread
getMessageLink chat_id:int53 message_id:int53 for_album:Bool for_comment:Bool = MessageLink;
//@description Returns a private HTTPS link to a message in a chat. Available only for already sent messages in supergroups and channels. The link will work only for members of the chat
//@description Returns an HTML code for embedding the message. Available only for messages in supergroups and channels with a username
//@chat_id Identifier of the chat to which the message belongs
//@message_id Identifier of the message
getMessageLink chat_id:int53 message_id:int53 = HttpUrl;
//@for_album Pass true to return an HTML code for embedding of the whole media album
getMessageEmbeddingCode chat_id:int53 message_id:int53 for_album:Bool = Text;
//@description Returns information about a public or private message link @url The message link in the format "https://t.me/c/...", or "tg://privatepost?...", or "https://t.me/username/...", or "tg://resolve?..."
getMessageLinkInfo url:string = MessageLinkInfo;
//@description Sends a message. Returns the sent message
//@chat_id Target chat @reply_to_message_id Identifier of the message to reply to or 0
//@chat_id Target chat
//@message_thread_id If not 0, a message thread identifier in which the message will be sent
//@reply_to_message_id Identifier of the message to reply to or 0
//@options Options to be used to send the message
//@reply_markup Markup for replying to the message; for bots only @input_message_content The content of the message to be sent
sendMessage chat_id:int53 reply_to_message_id:int53 options:messageSendOptions reply_markup:ReplyMarkup input_message_content:InputMessageContent = Message;
sendMessage chat_id:int53 message_thread_id:int53 reply_to_message_id:int53 options:messageSendOptions reply_markup:ReplyMarkup input_message_content:InputMessageContent = Message;
//@description Sends messages grouped together into an album. Currently only photo and video messages can be grouped into an album. Returns sent messages
//@chat_id Target chat @reply_to_message_id Identifier of a message to reply to or 0
//@chat_id Target chat
//@message_thread_id If not 0, a message thread identifier in which the messages will be sent
//@reply_to_message_id Identifier of a message to reply to or 0
//@options Options to be used to send the messages
//@input_message_contents Contents of messages to be sent
sendMessageAlbum chat_id:int53 reply_to_message_id:int53 options:messageSendOptions input_message_contents:vector<InputMessageContent> = Messages;
sendMessageAlbum chat_id:int53 message_thread_id:int53 reply_to_message_id:int53 options:messageSendOptions input_message_contents:vector<InputMessageContent> = Messages;
//@description Invites a bot to a chat (if it is not yet a member) and sends it the /start command. Bots can't be invited to a private chat other than the chat with the bot. Bots can't be invited to channels (although they can be added as admins) and secret chats. Returns the sent message
//@bot_user_id Identifier of the bot @chat_id Identifier of the target chat @parameter A hidden parameter sent to the bot for deep linking purposes (https://core.telegram.org/bots#deep-linking)
sendBotStartMessage bot_user_id:int32 chat_id:int53 parameter:string = Message;
//@description Sends the result of an inline query as a message. Returns the sent message. Always clears a chat draft message
//@chat_id Target chat @reply_to_message_id Identifier of a message to reply to or 0
//@chat_id Target chat
//@message_thread_id If not 0, a message thread identifier in which the message will be sent
//@reply_to_message_id Identifier of a message to reply to or 0
//@options Options to be used to send the message
//@query_id Identifier of the inline query @result_id Identifier of the inline result
//@hide_via_bot If true, there will be no mention of a bot, via which the message is sent. Can be used only for bots GetOption("animation_search_bot_username"), GetOption("photo_search_bot_username") and GetOption("venue_search_bot_username")
sendInlineQueryResultMessage chat_id:int53 reply_to_message_id:int53 options:messageSendOptions query_id:int64 result_id:string hide_via_bot:Bool = Message;
sendInlineQueryResultMessage chat_id:int53 message_thread_id:int53 reply_to_message_id:int53 options:messageSendOptions query_id:int64 result_id:string hide_via_bot:Bool = Message;
//@description Forwards previously sent messages. Returns the forwarded messages in the same order as the message identifiers passed in message_ids. If a message can't be forwarded, null will be returned instead of the message
//@chat_id Identifier of the chat to which to forward messages @from_chat_id Identifier of the chat from which to forward messages @message_ids Identifiers of the messages to forward. Message identifiers must be in a strictly increasing order
@ -3895,8 +3924,8 @@ getInlineGameHighScores inline_message_id:string user_id:int32 = GameHighScores;
deleteChatReplyMarkup chat_id:int53 message_id:int53 = Ok;
//@description Sends a notification about user activity in a chat @chat_id Chat identifier @action The action description
sendChatAction chat_id:int53 action:ChatAction = Ok;
//@description Sends a notification about user activity in a chat @chat_id Chat identifier @message_thread_id If not 0, a message thread identifier in which the action was performed @action The action description
sendChatAction chat_id:int53 message_thread_id:int53 action:ChatAction = Ok;
//@description Informs TDLib that the chat is opened by the user. Many useful activities depend on the chat being opened or closed (e.g., in supergroups and channels all updates are received only for opened chats) @chat_id Chat identifier
@ -3905,9 +3934,12 @@ openChat chat_id:int53 = Ok;
//@description Informs TDLib that the chat is closed by the user. Many useful activities depend on the chat being opened or closed @chat_id Chat identifier
closeChat chat_id:int53 = Ok;
//@description Informs TDLib that messages are being viewed by the user. Many useful activities depend on whether the messages are currently being viewed or not (e.g., marking messages as read, incrementing a view counter, updating a view counter, removing deleted messages in supergroups and channels) @chat_id Chat identifier @message_ids The identifiers of the messages being viewed
//@force_read True, if messages in closed chats should be marked as read
viewMessages chat_id:int53 message_ids:vector<int53> force_read:Bool = Ok;
//@description Informs TDLib that messages are being viewed by the user. Many useful activities depend on whether the messages are currently being viewed or not (e.g., marking messages as read, incrementing a view counter, updating a view counter, removing deleted messages in supergroups and channels)
//@chat_id Chat identifier
//@message_thread_id If not 0, a message thread identifier in which the messages are being viewed
//@message_ids The identifiers of the messages being viewed
//@force_read True, if messages in closed chats should be marked as read by the request
viewMessages chat_id:int53 message_thread_id:int53 message_ids:vector<int53> force_read:Bool = Ok;
//@description Informs TDLib that the message content has been opened (e.g., the user has opened a photo, video, document, location or venue, or has listened to an audio file or voice note message). An updateMessageContentOpened update will be generated if something has changed @chat_id Chat identifier of the message @message_id Identifier of the message with the opened content
openMessageContent chat_id:int53 message_id:int53 = Ok;
@ -3983,8 +4015,8 @@ setChatPhoto chat_id:int53 photo:InputChatPhoto = Ok;
//@chat_id Chat identifier @permissions New non-administrator members permissions in the chat
setChatPermissions chat_id:int53 permissions:chatPermissions = Ok;
//@description Changes the draft message in a chat @chat_id Chat identifier @draft_message New draft message; may be null
setChatDraftMessage chat_id:int53 draft_message:draftMessage = 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
setChatDraftMessage chat_id:int53 message_thread_id:int53 draft_message:draftMessage = Ok;
//@description Changes the notification settings of a chat. Notification settings of a chat with the current user (Saved Messages) can't be changed
//@chat_id Chat identifier @notification_settings New notification settings for the chat. If the chat is muted for more than 1 week, it is considered to be muted forever
@ -3993,6 +4025,9 @@ setChatNotificationSettings chat_id:int53 notification_settings:chatNotification
//@description Changes the marked as unread state of a chat @chat_id Chat identifier @is_marked_as_unread New value of is_marked_as_unread
toggleChatIsMarkedAsUnread chat_id:int53 is_marked_as_unread:Bool = Ok;
//@description Changes the block state of a chat. Currently, only private chats and supergroups can be blocked @chat_id Chat identifier @is_blocked New value of is_blocked
toggleChatIsBlocked chat_id:int53 is_blocked:Bool = Ok;
//@description Changes the value of the default disable_notification parameter, used when a message is sent to a chat @chat_id Chat identifier @default_disable_notification New value of default_disable_notification
toggleChatDefaultDisableNotification chat_id:int53 default_disable_notification:Bool = Ok;
@ -4156,15 +4191,15 @@ sendCallRating call_id:int32 rating:int32 comment:string problems:vector<CallPro
sendCallDebugInformation call_id:int32 debug_information:string = Ok;
//@description Blocks an original sender of a message in the Replies chat
//@message_id The identifier of an incoming message in the Replies chat
//@delete_message Pass true if the message must be deleted
//@delete_all_messages Pass true if all messages from the same sender must be deleted
//@report_spam Pass true if the sender must be reported to the Telegram moderators
blockChatFromReplies message_id:int53 delete_message:Bool delete_all_messages:Bool report_spam:Bool = Ok;
//@description Blocks a user @user_id User identifier
blockUser user_id:int32 = Ok;
//@description Unblocks a user @user_id User identifier
unblockUser user_id:int32 = Ok;
//@description Returns users that were blocked by the current user @offset Number of users to skip in the result; must be non-negative @limit The maximum number of users to return; up to 100
getBlockedUsers offset:int32 limit:int32 = Users;
//@description Returns chats that were blocked by the current user @offset Number of chats to skip in the result; must be non-negative @limit The maximum number of chats to return; up to 100
getBlockedChats offset:int32 limit:int32 = Chats;
//@description Adds a user to the contact list or edits an existing contact by their user identifier @contact The contact to add or edit; phone number can be empty and needs to be specified only if known, vCard is ignored

Binary file not shown.

View File

@ -115,7 +115,7 @@ channel#d31a961e flags:# creator:flags.0?true left:flags.2?true broadcast:flags.
channelForbidden#289da732 flags:# broadcast:flags.5?true megagroup:flags.8?true id:int access_hash:long title:string until_date:flags.16?int = Chat;
chatFull#1b7c9db3 flags:# can_set_username:flags.7?true has_scheduled:flags.8?true id:int about:string participants:ChatParticipants chat_photo:flags.2?Photo notify_settings:PeerNotifySettings exported_invite:ExportedChatInvite bot_info:flags.3?Vector<BotInfo> pinned_msg_id:flags.6?int folder_id:flags.11?int = ChatFull;
channelFull#f0e6672a flags:# can_view_participants:flags.3?true can_set_username:flags.6?true can_set_stickers:flags.7?true hidden_prehistory:flags.10?true can_set_location:flags.16?true has_scheduled:flags.19?true can_view_stats:flags.20?true id:int about:string participants_count:flags.0?int admins_count:flags.1?int kicked_count:flags.2?int banned_count:flags.2?int online_count:flags.13?int read_inbox_max_id:int read_outbox_max_id:int unread_count:int chat_photo:Photo notify_settings:PeerNotifySettings exported_invite:ExportedChatInvite bot_info:Vector<BotInfo> migrated_from_chat_id:flags.4?int migrated_from_max_id:flags.4?int pinned_msg_id:flags.5?int stickerset:flags.8?StickerSet available_min_id:flags.9?int folder_id:flags.11?int linked_chat_id:flags.14?int location:flags.15?ChannelLocation slowmode_seconds:flags.17?int slowmode_next_send_date:flags.18?int stats_dc:flags.12?int pts:int = ChatFull;
channelFull#f0e6672a flags:# can_view_participants:flags.3?true can_set_username:flags.6?true can_set_stickers:flags.7?true hidden_prehistory:flags.10?true can_set_location:flags.16?true has_scheduled:flags.19?true can_view_stats:flags.20?true blocked:flags.22?true id:int about:string participants_count:flags.0?int admins_count:flags.1?int kicked_count:flags.2?int banned_count:flags.2?int online_count:flags.13?int read_inbox_max_id:int read_outbox_max_id:int unread_count:int chat_photo:Photo notify_settings:PeerNotifySettings exported_invite:ExportedChatInvite bot_info:Vector<BotInfo> migrated_from_chat_id:flags.4?int migrated_from_max_id:flags.4?int pinned_msg_id:flags.5?int stickerset:flags.8?StickerSet available_min_id:flags.9?int folder_id:flags.11?int linked_chat_id:flags.14?int location:flags.15?ChannelLocation slowmode_seconds:flags.17?int slowmode_next_send_date:flags.18?int stats_dc:flags.12?int pts:int = ChatFull;
chatParticipant#c8d7493e user_id:int inviter_id:int date:int = ChatParticipant;
chatParticipantCreator#da13538a user_id:int = ChatParticipant;
@ -219,8 +219,6 @@ contact#f911c994 user_id:int mutual:Bool = Contact;
importedContact#d0028438 user_id:int client_id:long = ImportedContact;
contactBlocked#561bc879 user_id:int date:int = ContactBlocked;
contactStatus#d3680c61 user_id:int status:UserStatus = ContactStatus;
contacts.contactsNotModified#b74ba9d2 = contacts.Contacts;
@ -228,8 +226,8 @@ contacts.contacts#eae87e42 contacts:Vector<Contact> saved_count:int users:Vector
contacts.importedContacts#77d01c3b imported:Vector<ImportedContact> popular_invites:Vector<PopularContact> retry_contacts:Vector<long> users:Vector<User> = contacts.ImportedContacts;
contacts.blocked#1c138d15 blocked:Vector<ContactBlocked> users:Vector<User> = contacts.Blocked;
contacts.blockedSlice#900802a1 count:int blocked:Vector<ContactBlocked> users:Vector<User> = contacts.Blocked;
contacts.blocked#ade1591 blocked:Vector<PeerBlocked> chats:Vector<Chat> users:Vector<User> = contacts.Blocked;
contacts.blockedSlice#e1664194 count:int blocked:Vector<PeerBlocked> chats:Vector<Chat> users:Vector<User> = contacts.Blocked;
messages.dialogs#15ba6c40 dialogs:Vector<Dialog> messages:Vector<Message> chats:Vector<Chat> users:Vector<User> = messages.Dialogs;
messages.dialogsSlice#71e094f3 count:int dialogs:Vector<Dialog> messages:Vector<Message> chats:Vector<Chat> users:Vector<User> = messages.Dialogs;
@ -280,7 +278,6 @@ updateEncryptedMessagesRead#38fe25b7 chat_id:int max_date:int date:int = Update;
updateChatParticipantAdd#ea4b0e5c chat_id:int user_id:int inviter_id:int date:int version:int = Update;
updateChatParticipantDelete#6e5f8c22 chat_id:int user_id:int version:int = Update;
updateDcOptions#8e5e9873 dc_options:Vector<DcOption> = Update;
updateUserBlocked#80ece81a user_id:int blocked:Bool = Update;
updateNotifySettings#bec268ef peer:NotifyPeer notify_settings:PeerNotifySettings = Update;
updateServiceNotification#ebe46819 flags:# popup:flags.0?true inbox_date:flags.1?int type:string message:string media:MessageMedia entities:Vector<MessageEntity> = Update;
updatePrivacy#ee3b272a key:PrivacyKey rules:Vector<PrivacyRule> = Update;
@ -347,7 +344,10 @@ updateDialogFilters#3504914f = Update;
updatePhoneCallSignalingData#2661bf09 phone_call_id:long data:bytes = Update;
updateChannelParticipant#65d2b464 flags:# channel_id:int date:int user_id:int prev_participant:flags.0?ChannelParticipant new_participant:flags.1?ChannelParticipant qts:int = Update;
updateChannelMessageForwards#6e8a84df channel_id:int id:int forwards:int = Update;
updateReadDiscussion#119fb587 peer:Peer msg_id:int read_max_id:int = Update;
updateReadChannelDiscussionInbox#1cc7de54 flags:# channel_id:int top_msg_id:int read_max_id:int broadcast_id:flags.0?int broadcast_post:flags.0?int = Update;
updateReadChannelDiscussionOutbox#4638a26c channel_id:int top_msg_id:int read_max_id:int = Update;
updatePeerBlocked#246a4b22 peer_id:Peer blocked:Bool = Update;
updateChannelUserTyping#ff2abe9f flags:# channel_id:int top_msg_id:flags.0?int user_id:int action:SendMessageAction = Update;
updates.state#a56c2a3e pts:int qts:int date:int seq:int unread_count:int = updates.State;
@ -1149,16 +1149,18 @@ help.countriesList#87d0759e countries:Vector<help.Country> hash:int = help.Count
messageViews#455b853d flags:# views:flags.0?int forwards:flags.1?int replies:flags.2?MessageReplies = MessageViews;
messages.messageViews#2c3f2ae2 views:Vector<MessageViews> users:Vector<User> = messages.MessageViews;
messages.messageViews#b6c4f543 views:Vector<MessageViews> chats:Vector<Chat> users:Vector<User> = messages.MessageViews;
stats.messageStats#8999f295 views_graph:StatsGraph = stats.MessageStats;
messages.discussionMessage#d25fad90 message:Message read_max_id:int chats:Vector<Chat> users:Vector<User> = messages.DiscussionMessage;
messages.discussionMessage#f5dd8f9d flags:# messages:Vector<Message> max_id:flags.0?int read_inbox_max_id:flags.1?int read_outbox_max_id:flags.2?int chats:Vector<Chat> users:Vector<User> = messages.DiscussionMessage;
messageReplyHeader#a6d57763 flags:# reply_to_msg_id:int reply_to_peer_id:flags.0?Peer reply_to_top_id:flags.1?int = MessageReplyHeader;
messageReplies#4128faac flags:# comments:flags.0?true replies:int replies_pts:int recent_repliers:flags.1?Vector<Peer> channel_id:flags.0?int max_id:flags.2?int read_max_id:flags.3?int = MessageReplies;
peerBlocked#e8fd8014 peer_id:Peer date:int = PeerBlocked;
---functions---
invokeAfterMsg#cb9f372d {X:Type} msg_id:long query:!X = X;
@ -1266,8 +1268,8 @@ contacts.getContacts#c023849f hash:int = contacts.Contacts;
contacts.importContacts#2c800be5 contacts:Vector<InputContact> = contacts.ImportedContacts;
contacts.deleteContacts#96a0e00 id:Vector<InputUser> = Updates;
contacts.deleteByPhones#1013fd9e phones:Vector<string> = Bool;
contacts.block#332b49fc id:InputUser = Bool;
contacts.unblock#e54100bd id:InputUser = Bool;
contacts.block#68cc1411 id:InputPeer = Bool;
contacts.unblock#bea65d50 id:InputPeer = Bool;
contacts.getBlocked#f57c350f offset:int limit:int = contacts.Blocked;
contacts.search#11f812d8 q:string limit:int = contacts.Found;
contacts.resolveUsername#f93ccba3 username:string = contacts.ResolvedPeer;
@ -1279,6 +1281,7 @@ contacts.toggleTopPeers#8514bdda enabled:Bool = Bool;
contacts.addContact#e8f463d0 flags:# add_phone_privacy_exception:flags.0?true id:InputUser first_name:string last_name:string phone:string = Updates;
contacts.acceptContact#f831a20f id:InputUser = Updates;
contacts.getLocated#d348bc44 flags:# background:flags.1?true geo_point:InputGeoPoint self_expires:flags.0?int = Updates;
contacts.blockFromReplies#29a8962c flags:# delete_message:flags.0?true delete_history:flags.1?true report_spam:flags.2?true msg_id:int = Updates;
messages.getMessages#63c66506 id:Vector<InputMessage> = messages.Messages;
messages.getDialogs#a0ee3b73 flags:# exclude_pinned:flags.0?true folder_id:flags.1?int offset_date:int offset_id:int offset_peer:InputPeer limit:int hash:int = messages.Dialogs;
@ -1288,7 +1291,7 @@ messages.readHistory#e306d3a peer:InputPeer max_id:int = messages.AffectedMessag
messages.deleteHistory#1c015b09 flags:# just_clear:flags.0?true revoke:flags.1?true peer:InputPeer max_id:int = messages.AffectedHistory;
messages.deleteMessages#e58e95d2 flags:# revoke:flags.0?true id:Vector<int> = messages.AffectedMessages;
messages.receivedMessages#5a954c0 max_id:int = Vector<ReceivedNotifyMessage>;
messages.setTyping#a3825e50 peer:InputPeer action:SendMessageAction = Bool;
messages.setTyping#58943ee2 flags:# peer:InputPeer top_msg_id:flags.0?int action:SendMessageAction = Bool;
messages.sendMessage#520c3870 flags:# no_webpage:flags.1?true silent:flags.5?true background:flags.6?true clear_draft:flags.7?true peer:InputPeer reply_to_msg_id:flags.0?int message:string random_id:long reply_markup:flags.2?ReplyMarkup entities:flags.3?Vector<MessageEntity> schedule_date:flags.10?int = Updates;
messages.sendMedia#3491eba9 flags:# silent:flags.5?true background:flags.6?true clear_draft:flags.7?true peer:InputPeer reply_to_msg_id:flags.0?int media:InputMedia message:string random_id:long reply_markup:flags.2?ReplyMarkup entities:flags.3?Vector<MessageEntity> schedule_date:flags.10?int = Updates;
messages.forwardMessages#d9fee60e flags:# silent:flags.5?true background:flags.6?true with_my_score:flags.8?true from_peer:InputPeer id:Vector<int> random_id:Vector<long> to_peer:InputPeer schedule_date:flags.10?int = Updates;
@ -1403,7 +1406,7 @@ messages.getSuggestedDialogFilters#a29cd42c = Vector<DialogFilterSuggested>;
messages.updateDialogFilter#1ad4a04a flags:# id:int filter:flags.0?DialogFilter = Bool;
messages.updateDialogFiltersOrder#c563c1e4 order:Vector<int> = Bool;
messages.getOldFeaturedStickers#5fe7025b offset:int limit:int hash:int = messages.FeaturedStickers;
messages.getReplies#fda52fdc peer:InputPeer msg_id:int offset_id:int add_offset:int limit:int max_id:int min_id:int hash:int = messages.Messages;
messages.getReplies#24b581ba peer:InputPeer msg_id:int offset_id:int offset_date:int add_offset:int limit:int max_id:int min_id:int hash:int = messages.Messages;
messages.getDiscussionMessage#446972fd peer:InputPeer msg_id:int = messages.DiscussionMessage;
messages.readDiscussion#f731a9f4 peer:InputPeer msg_id:int read_max_id:int = Bool;
@ -1467,7 +1470,7 @@ channels.joinChannel#24b524c5 channel:InputChannel = Updates;
channels.leaveChannel#f836aa95 channel:InputChannel = Updates;
channels.inviteToChannel#199f3a6c channel:InputChannel users:Vector<InputUser> = Updates;
channels.deleteChannel#c0111fe3 channel:InputChannel = Updates;
channels.exportMessageLink#ceb77163 channel:InputChannel id:int grouped:Bool = ExportedMessageLink;
channels.exportMessageLink#e63fadeb flags:# grouped:flags.0?true thread:flags.1?true channel:InputChannel id:int = ExportedMessageLink;
channels.toggleSignatures#1f69b606 channel:InputChannel enabled:Bool = Updates;
channels.getAdminedPublicChannels#f8b036af flags:# by_location:flags.0?true check_limit:flags.1?true = messages.Chats;
channels.editBanned#72796912 channel:InputChannel user_id:InputUser banned_rights:ChatBannedRights = Updates;

Binary file not shown.

View File

@ -10,6 +10,6 @@
namespace td {
enum class AccessRights : int32 { Read, Edit, Write };
enum class AccessRights : int32 { Know, Read, Edit, Write };
} // namespace td

View File

@ -144,30 +144,18 @@ void AuthManager::get_state(uint64 query_id) {
void AuthManager::check_bot_token(uint64 query_id, string bot_token) {
if (state_ == State::WaitPhoneNumber && net_query_id_ == 0) {
// can ignore previous checks
was_check_bot_token_ = false; // TODO can we remove was_check_bot_token_ after State::Ok is disallowed?
was_check_bot_token_ = false; // TODO can we remove was_check_bot_token_?
}
if (state_ != State::WaitPhoneNumber && state_ != State::Ok) {
// TODO do not allow State::Ok
if (state_ != State::WaitPhoneNumber) {
return on_query_error(query_id, Status::Error(400, "Call to checkAuthenticationBotToken unexpected"));
}
if (!send_code_helper_.phone_number().empty() || was_qr_code_request_) {
return on_query_error(
query_id, Status::Error(400, "Cannot set bot token after authentication beginning. You need to log out first"));
query_id, Status::Error(400, "Cannot set bot token after authentication began. You need to log out first"));
}
if (was_check_bot_token_ && bot_token_ != bot_token) {
return on_query_error(query_id, Status::Error(8, "Cannot change bot token. You need to log out first"));
}
if (state_ == State::Ok) {
if (!is_bot_) {
// fix old bots
const int32 AUTH_IS_BOT_FIXED_DATE = 1500940800;
if (G()->shared_config().get_option_integer("authorization_date") < AUTH_IS_BOT_FIXED_DATE) {
G()->td_db()->get_binlog_pmc()->set("auth_is_bot", "true");
is_bot_ = true;
}
}
return send_ok(query_id);
}
on_new_query(query_id);
bot_token_ = bot_token;

View File

@ -66,7 +66,8 @@ class GetBackgroundQuery : public Td::ResultHandler {
}
void on_error(uint64 id, Status status) override {
LOG(INFO) << "Receive error for getBackground " << background_id_ << "/" << background_name_ << ": " << status;
LOG(INFO) << "Receive error for GetBackgroundQuery for " << background_id_ << "/" << background_name_ << ": "
<< status;
promise_.set_error(std::move(status));
}
};
@ -320,22 +321,22 @@ class BackgroundManager::BackgroundLogEvent {
void BackgroundManager::start_up() {
for (int i = 0; i < 2; i++) {
bool for_dark_theme = i != 0;
auto logevent_string = G()->td_db()->get_binlog_pmc()->get(get_background_database_key(for_dark_theme));
if (!logevent_string.empty()) {
BackgroundLogEvent logevent;
log_event_parse(logevent, logevent_string).ensure();
auto log_event_string = G()->td_db()->get_binlog_pmc()->get(get_background_database_key(for_dark_theme));
if (!log_event_string.empty()) {
BackgroundLogEvent log_event;
log_event_parse(log_event, log_event_string).ensure();
CHECK(logevent.background_.id.is_valid());
bool needs_file_id = logevent.background_.type.type != BackgroundType::Type::Fill;
if (logevent.background_.file_id.is_valid() != needs_file_id) {
LOG(ERROR) << "Failed to load " << logevent.background_.id << " of " << logevent.background_.type;
CHECK(log_event.background_.id.is_valid());
bool needs_file_id = log_event.background_.type.type != BackgroundType::Type::Fill;
if (log_event.background_.file_id.is_valid() != needs_file_id) {
LOG(ERROR) << "Failed to load " << log_event.background_.id << " of " << log_event.background_.type;
G()->td_db()->get_binlog_pmc()->erase(get_background_database_key(for_dark_theme));
continue;
}
set_background_id_[for_dark_theme] = logevent.background_.id;
set_background_type_[for_dark_theme] = logevent.set_type_;
set_background_id_[for_dark_theme] = log_event.background_.id;
set_background_type_[for_dark_theme] = log_event.set_type_;
add_background(logevent.background_);
add_background(log_event.background_);
}
send_update_selected_background(for_dark_theme);
@ -664,8 +665,8 @@ void BackgroundManager::save_background_id(bool for_dark_theme) const {
if (background_id.is_valid()) {
const Background *background = get_background(background_id);
CHECK(background != nullptr);
BackgroundLogEvent logevent{*background, set_background_type_[for_dark_theme]};
G()->td_db()->get_binlog_pmc()->set(key, log_event_store(logevent).as_slice().str());
BackgroundLogEvent log_event{*background, set_background_type_[for_dark_theme]};
G()->td_db()->get_binlog_pmc()->set(key, log_event_store(log_event).as_slice().str());
} else {
G()->td_db()->get_binlog_pmc()->erase(key);
}

View File

@ -370,7 +370,7 @@ Status CallActor::do_update_call(telegram_api::phoneCallWaiting &call) {
if ((call.flags_ & telegram_api::phoneCallWaiting::RECEIVE_DATE_MASK) != 0) {
call_state_.is_received = true;
call_state_need_flush_ = true;
int32 call_ring_timeout_ms = G()->shared_config().get_option_integer("call_ring_timeout_ms", 90000);
int64 call_ring_timeout_ms = G()->shared_config().get_option_integer("call_ring_timeout_ms", 90000);
set_timeout_in(call_ring_timeout_ms * 0.001);
}
}
@ -453,7 +453,7 @@ Status CallActor::do_update_call(telegram_api::phoneCallAccepted &call) {
void CallActor::on_begin_exchanging_key() {
call_state_.type = CallState::Type::ExchangingKey;
call_state_need_flush_ = true;
int32 call_receive_timeout_ms = G()->shared_config().get_option_integer("call_receive_timeout_ms", 20000);
int64 call_receive_timeout_ms = G()->shared_config().get_option_integer("call_receive_timeout_ms", 20000);
double timeout = call_receive_timeout_ms * 0.001;
LOG(INFO) << "Set call timeout to " << timeout;
set_timeout_in(timeout);
@ -631,7 +631,7 @@ void CallActor::try_send_request_query() {
call_state_.protocol.get_input_phone_call_protocol());
auto query = G()->net_query_creator().create(tl_query);
state_ = State::WaitRequestResult;
int32 call_receive_timeout_ms = G()->shared_config().get_option_integer("call_receive_timeout_ms", 20000);
int64 call_receive_timeout_ms = G()->shared_config().get_option_integer("call_receive_timeout_ms", 20000);
double timeout = call_receive_timeout_ms * 0.001;
LOG(INFO) << "Set call timeout to " << timeout;
set_timeout_in(timeout);

View File

@ -48,6 +48,7 @@ void CallManager::update_call_signaling_data(int64 call_id, string data) {
auto info_it = call_info_.find(call_id);
if (info_it == call_info_.end() || !info_it->second.call_id.is_valid()) {
LOG(INFO) << "Ignore signaling data for " << call_id;
return;
}
auto actor = get_call_actor(info_it->second.call_id);

View File

@ -39,7 +39,7 @@ void ConfigShared::set_option_empty(Slice name) {
}
}
void ConfigShared::set_option_integer(Slice name, int32 value) {
void ConfigShared::set_option_integer(Slice name, int64 value) {
if (set_option(name, PSLICE() << "I" << value)) {
on_option_updated(name);
}
@ -78,7 +78,7 @@ bool ConfigShared::get_option_boolean(Slice name, bool default_value) const {
return default_value;
}
int32 ConfigShared::get_option_integer(Slice name, int32 default_value) const {
int64 ConfigShared::get_option_integer(Slice name, int64 default_value) const {
auto str_value = get_option(name);
if (str_value.empty()) {
return default_value;
@ -87,7 +87,7 @@ int32 ConfigShared::get_option_integer(Slice name, int32 default_value) const {
LOG(ERROR) << "Found \"" << str_value << "\" instead of integer option";
return default_value;
}
return to_integer<int32>(str_value.substr(1));
return to_integer<int64>(str_value.substr(1));
}
string ConfigShared::get_option_string(Slice name, string default_value) const {
@ -129,7 +129,7 @@ tl_object_ptr<td_api::OptionValue> ConfigShared::get_option_value_object(Slice v
}
break;
case 'I':
return make_tl_object<td_api::optionValueInteger>(to_integer<int32>(value.substr(1)));
return make_tl_object<td_api::optionValueInteger>(to_integer<int64>(value.substr(1)));
case 'S':
return make_tl_object<td_api::optionValueString>(value.substr(1).str());
}

View File

@ -37,14 +37,14 @@ class ConfigShared {
void set_option_boolean(Slice name, bool value);
void set_option_empty(Slice name);
void set_option_integer(Slice name, int32 value);
void set_option_integer(Slice name, int64 value);
void set_option_string(Slice name, Slice value);
bool have_option(Slice name) const;
std::unordered_map<string, string> get_options() const;
bool get_option_boolean(Slice name, bool default_value = false) const;
int32 get_option_integer(Slice name, int32 default_value = 0) const;
int64 get_option_integer(Slice name, int64 default_value = 0) const;
string get_option_string(Slice name, string default_value = "") const;
tl_object_ptr<td_api::OptionValue> get_option_value(Slice name) const;

File diff suppressed because it is too large Load Diff

View File

@ -177,7 +177,6 @@ class ContactsManager : public Actor {
void on_update_user_photo(UserId user_id, tl_object_ptr<telegram_api::UserProfilePhoto> &&photo_ptr);
void on_update_user_online(UserId user_id, tl_object_ptr<telegram_api::UserStatus> &&status);
void on_update_user_local_was_online(UserId user_id, int32 local_was_online);
void on_update_user_is_blocked(UserId user_id, bool is_blocked);
void on_update_user_common_chat_count(UserId user_id, int32 common_chat_count);
void on_update_user_need_phone_number_privacy_exception(UserId user_id, bool need_phone_number_privacy_exception);
@ -263,7 +262,11 @@ class ContactsManager : public Actor {
MyOnlineStatusInfo get_my_online_status() const;
UserId get_service_notifications_user_id();
static UserId get_service_notifications_user_id();
UserId add_service_notifications_user();
static UserId get_replies_bot_user_id();
void on_update_online_status_privacy();
@ -294,17 +297,6 @@ class ContactsManager : public Actor {
void disconnect_website(int64 authorizations_id, Promise<Unit> &&promise) const;
void disconnect_all_websites(Promise<Unit> &&promise) const;
Status set_user_is_blocked(UserId user_id, bool is_blocked);
int64 get_blocked_users(int32 offset, int32 limit, Promise<Unit> &&promise);
void on_get_blocked_users_result(int32 offset, int32 limit, int64 random_id, int32 total_count,
vector<tl_object_ptr<telegram_api::contactBlocked>> &&blocked_users);
void on_failed_get_blocked_users(int64 random_id);
tl_object_ptr<td_api::users> get_blocked_users_object(int64 random_id);
void add_contact(td_api::object_ptr<td_api::contact> &&contact, bool share_phone_number, Promise<Unit> &&promise);
std::pair<vector<UserId>, vector<int32>> import_contacts(const vector<tl_object_ptr<td_api::contact>> &contacts,
@ -429,8 +421,6 @@ class ContactsManager : public Actor {
bool is_user_contact(UserId user_id) const;
bool is_user_blocked(UserId user_id);
bool is_user_deleted(UserId user_id) const;
bool is_user_bot(UserId user_id) const;
@ -452,7 +442,7 @@ class ContactsManager : public Actor {
UserId get_me(Promise<Unit> &&promise);
bool get_user(UserId user_id, int left_tries, Promise<Unit> &&promise);
void reload_user(UserId user_id, Promise<Unit> &&promise);
bool get_user_full(UserId user_id, bool force, Promise<Unit> &&promise);
bool load_user_full(UserId user_id, bool force, Promise<Unit> &&promise);
void reload_user_full(UserId user_id);
std::pair<int32, vector<const Photo *>> get_user_profile_photos(UserId user_id, int32 offset, int32 limit,
@ -464,7 +454,7 @@ class ContactsManager : public Actor {
bool have_chat_force(ChatId chat_id);
bool get_chat(ChatId chat_id, int left_tries, Promise<Unit> &&promise);
void reload_chat(ChatId chat_id, Promise<Unit> &&promise);
bool get_chat_full(ChatId chat_id, bool force, Promise<Unit> &&promise);
bool load_chat_full(ChatId chat_id, bool force, Promise<Unit> &&promise);
FileSourceId get_chat_full_file_source_id(ChatId chat_id);
void reload_chat_full(ChatId chat_id, Promise<Unit> &&promise);
@ -478,8 +468,8 @@ class ContactsManager : public Actor {
bool have_channel_force(ChannelId channel_id);
bool get_channel(ChannelId channel_id, int left_tries, Promise<Unit> &&promise);
void reload_channel(ChannelId chnanel_id, Promise<Unit> &&promise);
bool get_channel_full(ChannelId channel_id, bool force, Promise<Unit> &&promise);
bool get_channel_full_internal(ChannelId channel_id, bool force, Promise<Unit> &&promise);
bool load_channel_full(ChannelId channel_id, bool force, Promise<Unit> &&promise);
bool load_channel_full_internal(ChannelId channel_id, bool force, Promise<Unit> &&promise);
FileSourceId get_channel_full_file_source_id(ChannelId channel_id);
void reload_channel_full(ChannelId channel_id, Promise<Unit> &&promise, const char *source);
@ -661,7 +651,7 @@ class ContactsManager : public Actor {
bool is_received_from_server = false; // true, if the user was received from the server and not the database
uint64 logevent_id = 0;
uint64 log_event_id = 0;
template <class StorerT>
void store(StorerT &storer) const;
@ -698,14 +688,12 @@ class ContactsManager : public Actor {
int32 common_chat_count = 0;
bool is_blocked = false;
bool can_be_called = false;
bool supports_video_calls = false;
bool has_private_calls = false;
bool can_pin_messages = false;
bool need_phone_number_privacy_exception = false;
bool is_is_blocked_changed = true;
bool is_common_chat_count_changed = true;
bool is_changed = true; // have new changes that need to be sent to the client and database
bool need_send_update = true; // have new changes that need only to be sent to the client
@ -755,7 +743,7 @@ class ContactsManager : public Actor {
bool is_received_from_server = false; // true, if the chat was received from the server and not the database
uint64 logevent_id = 0;
uint64 log_event_id = 0;
template <class StorerT>
void store(StorerT &storer) const;
@ -832,7 +820,7 @@ class ContactsManager : public Actor {
bool is_received_from_server = false; // true, if the channel was received from the server and not the database
uint64 logevent_id = 0;
uint64 log_event_id = 0;
template <class StorerT>
void store(StorerT &storer) const;
@ -915,7 +903,7 @@ class ContactsManager : public Actor {
bool is_saved = false; // is current secret chat version being saved/is saved to the database
bool is_being_saved = false; // is current secret chat being saved to the database
uint64 logevent_id = 0;
uint64 log_event_id = 0;
template <class StorerT>
void store(StorerT &storer) const;
@ -1057,6 +1045,7 @@ class ContactsManager : public Actor {
static constexpr int32 CHANNEL_FULL_FLAG_HAS_SLOW_MODE_NEXT_SEND_DATE = 1 << 18;
static constexpr int32 CHANNEL_FULL_FLAG_HAS_SCHEDULED_MESSAGES = 1 << 19;
static constexpr int32 CHANNEL_FULL_FLAG_CAN_VIEW_STATISTICS = 1 << 20;
static constexpr int32 CHANNEL_FULL_FLAG_IS_BLOCKED = 1 << 22;
static constexpr int32 CHAT_INVITE_FLAG_IS_CHANNEL = 1 << 0;
static constexpr int32 CHAT_INVITE_FLAG_IS_BROADCAST = 1 << 1;
@ -1175,7 +1164,6 @@ class ContactsManager : public Actor {
void register_user_photo(User *u, UserId user_id, const Photo &photo);
void on_update_user_full_is_blocked(UserFull *user_full, UserId user_id, bool is_blocked);
void on_update_user_full_common_chat_count(UserFull *user_full, UserId user_id, int32 common_chat_count);
void on_update_user_full_need_phone_number_privacy_exception(UserFull *user_full, UserId user_id,
bool need_phone_number_privacy_exception);
@ -1185,8 +1173,6 @@ class ContactsManager : public Actor {
void drop_user_photos(UserId user_id, bool is_empty, bool drop_user_full_photo, const char *source);
void drop_user_full(UserId user_id);
void on_set_user_is_blocked_failed(UserId user_id, bool is_blocked, Status error);
void on_update_chat_status(Chat *c, ChatId chat_id, DialogParticipantStatus status);
void on_update_chat_default_permissions(Chat *c, ChatId chat_id, RestrictedRights default_permissions, int32 version);
void on_update_chat_participant_count(Chat *c, ChatId chat_id, int32 participant_count, int32 version,
@ -1583,9 +1569,6 @@ class ContactsManager : public Actor {
std::unordered_map<ChannelId, vector<DialogParticipant>, ChannelIdHash> cached_channel_participants_;
std::unordered_map<int64, std::pair<int32, vector<UserId>>>
found_blocked_users_; // random_id -> [total_count, [user_id]...]
bool are_contacts_loaded_ = false;
int32 next_contacts_sync_date_ = 0;
Hints contacts_hints_; // search contacts by first name, last name and username

View File

@ -11,10 +11,16 @@
#include "td/telegram/Td.h"
#include "td/telegram/telegram_api.h"
#include "td/utils/base64.h"
#include "td/utils/buffer.h"
#include "td/utils/Gzip.h"
#include "td/utils/logging.h"
#include "td/utils/misc.h"
#include "td/utils/Random.h"
#include "td/utils/Slice.h"
#include "td/utils/Status.h"
#include "td/utils/Time.h"
#include "td/utils/tl_parsers.h"
namespace td {
@ -56,6 +62,7 @@ class GetCountriesListQuery : public Td::ResultHandler {
}
void send(const string &language_code, int32 hash) {
hash = 0;
send_query(G()->net_query_creator().create_unauth(telegram_api::help_getCountriesList(language_code, hash)));
}
@ -110,6 +117,8 @@ struct CountryInfoManager::CountryList {
CountryInfoManager::CountryInfoManager(Td *td, ActorShared<> parent) : td_(td), parent_(std::move(parent)) {
}
CountryInfoManager::~CountryInfoManager() = default;
void CountryInfoManager::tear_down() {
parent_.reset();
}
@ -284,10 +293,10 @@ void CountryInfoManager::on_get_country_list(const string &language_code,
CHECK(!promises.empty());
pending_load_country_queries_.erase(query_it);
auto &countries = countries_[language_code];
if (r_country_list.is_error()) {
if (countries != nullptr) {
countries->next_reload_time = Time::now() + Random::fast(60, 120);
auto it = countries_.find(language_code);
if (it != countries_.end()) {
it->second->next_reload_time = Time::now() + Random::fast(60, 120);
}
for (auto &promise : promises) {
promise.set_error(r_country_list.error().clone());
@ -295,8 +304,18 @@ void CountryInfoManager::on_get_country_list(const string &language_code,
return;
}
auto country_list = r_country_list.move_as_ok();
on_get_country_list_impl(language_code, r_country_list.move_as_ok());
for (auto &promise : promises) {
promise.set_value(Unit());
}
}
void CountryInfoManager::on_get_country_list_impl(const string &language_code,
tl_object_ptr<telegram_api::help_CountriesList> country_list) {
LOG(ERROR) << to_string(country_list);
CHECK(country_list != nullptr);
auto &countries = countries_[language_code];
switch (country_list->get_id()) {
case telegram_api::help_countriesListNotModified::ID:
if (countries == nullptr) {
@ -348,15 +367,94 @@ void CountryInfoManager::on_get_country_list(const string &language_code,
default:
UNREACHABLE();
}
for (auto &promise : promises) {
promise.set_value(Unit());
}
}
const CountryInfoManager::CountryList *CountryInfoManager::get_country_list(const string &language_code) {
auto it = countries_.find(language_code);
if (it == countries_.end()) {
if (language_code == "en") {
static const BufferSlice en = gzdecode(
base64url_decode(
"eJyNW81y6kiWzmv8f3-qbnd19SwmKhQxET3dEV0doH8tAQPGIMxF4Gt7l0AWZFlILiHZbb9A7-YRZjOLjl7MbuYJ7sx-"
"IuYdZjGbeYU5AhsJ6ZC6EbbBIk_myfP7nZPJP0f_9Zff_Me___3_EkL-4Z_-8gVeyF71jBxVvakfBDT-7A08-7__LNX24LWkGPrrs-"
"Pra2n1s0XbIN-NPB6yqVQN6FhqLHhAQ7aEz3JzWUbl9dnb1USr3-tkriZ5W_1pNqceX4bUy9LvWQpJ0W8mSOhb5GPVC_"
"ksotLvpBoNxtGU5vnYr8i6meLv-"
"JWRrX21yXHVm0XcdSmyl3gOtXCOLsjVHcN2ELlqmlgWNtAGC4bSGurrs9OENrXuJTkE3n3gPEcrq6pYhgNyUg1mDMToZWS3-lxTU-"
"s45EN1wQI-oZ7k0IWfX2-_opvFchrCXqNlGOT3uqcmOj9dU15v73UE_"
"Ma01OWIrvf0SspmVvQZOX8mB9UgGiO0JdkyxHzfktPqMwvGlP9MPcTeLVWo41qVfFfzl6BiMNdzFjyzmf-wEnt-"
"LsU0hDqv1chxbPF06mO-B_"
"aq6kV6qJ2R0xr1Zi6dsuU8z4NplsU8NMhRjbkzHi1yelDkzXzvrl8DSSaW1JrkXS0K7kAEUpMufUwOsqxvy3T9k8zRAjlE7owGPCtHsv"
"Y7Kxl7DvzSeUB5LtZArFJen51cJ8JKaNtAGwWRN-"
"V5HrWMrqRtm61dkIMaeLaH7s8Sy9iOZRwsILLldayqlUId98jHGrDNuHRGg2i5pC5dIHzoyf7xeS6BD9_lD0h80qzKts9m9_-J_"
"FDzPcoD9kfJ4V4oNcCDacijJTiCQ8c0rzfNSultQA5rAX3mbt7fNW3z7P3LwnndOSu90wVdYn4iF8pwCOvPoxD1eUMT6-"
"8z2KcfLh8p7ueyXuDnNysfi1WH5AVxTqndAt_M5c8MkW-5shlXr5LDOvA33dZDCV7fVNY8_z6mUctKSTONkmGWS6aslWRFB9svl_"
"SyCvYjlwzDLMnwXlUqML9eMspWySrDc1OO_"
"RhykVWSTaukqEpJ0bWSWtFhrFHSKlZJU82SXlFKugrzl7WSWTaANh5jwhj4hXW0ilrSDBhrVkom0JgGzAPr6Aq8T-"
"T4LpXntvRYPyMf6z4kSun3Z2zxJ2nA7v_0B0wnqiKUa71JvqtDxoQcJFV_WqfDeC5Uv4o4ftVb5N0LTy_"
"sYPzIYn7OyVvnkYeQmlzqTfM5NZ0TMfo2-VD_8m8hk6b_2H7wwU2xOCW283on3od_J7WXMQ_ZnLSyOd2Uk_"
"FdclCfc5chOVzTxTm8bpPjOgUg4vseLvONLaCxvN5brZ3FO6u1TT0dT1Krp-kvYX3f9RfjXM5Z829kcx9iiwNyWvchCkoDsJ_8HsB_"
"xHsYkf36CsYg62cxVCYe169gbXrPpCsWTDFdK6YwHtYhptWjgH75K83m7Dcvsfv12RsrTXcDcebpHkIZgne0Ap3dgo0-"
"s8k89rRo7PJJfg5VLqfsPI91zwCvtCCXUu8p7yPWar79tc42Qov3_aGiSanpyPuKIemb_"
"2EtRS9XJLVimem1Lsjx2c987EchR21UU4Rx4axDjs6Yt6DBXZ7XJOehsjoD_"
"zjzF9yLLQvDhoZukIKcd3ZJPrzO8RLd4vGlrXnMsrVjntQY-SvGqLvGJPzcxrXVjCE1Q0muKBl_y2PNRp0cNSYRwOUAwS_"
"ieN8Au2ksQx-vzWShLhotctCYPd2HiJ_K5XScSIeaFP0A1g54GDBk3wnuOknMM0XrkAPnnmK4c09RxbV1Y0iOG-Gc-_"
"dojAP7Fdf2TcDLTe5l8xFZ-7qZjLsg-03-c9ZHVuN0I8GAzQ75tkndu3hCUY7RyuWExianNp8EvseWHMGYupVgoOYled-kgc-SyRF5b-"
"LiUVZeTcCozYB6k3w83VOUVE6Rtgx0Q9-qkoMWHftojaBu4-sX4oS2Rj689GQ63JtN_UWeB3Vb36-"
"ldTLHGcTGgMUgEKkzDKXIP1ur2OoHM8RHLEsT2lqrCbKHtSG4tyJOsT4E-KiajD8HWc1z415yl9iXW21y0uJjgG4hDbC6WysL_"
"bnVBfqAsZVlozZi7bSRlk0OW3SFGhB8VRbLtwe0EfcYSivu8bT65LQFoY-5fnSP5HvN2qy9M362PpGPjV8iGvoQgV3phRXMVsU5uAV-"
"EssP9ZOteIjjptYQ5A9ssAV1sfW1srzlK1ns0wLcBPQLJKbtV3SjsJ5ufSbv15v_"
"scahmo5QGWjiOW5iXT7FBozYeYKRzzvk5BxqA6kDf5B1TE281_MeOQb6KUA1tD-rlVWhrZ9D7qkHPhTqSN4zxfXA-"
"ZAcnFMegx9kXUu87ogcnUfejAZ5nKboRGhf7TNy0vamLyEf6Q8mfanTJAwma7chjrUDhtVREBvEsaXdJYftZUBZvk9RsgxxDdeGmgT4R"
"nm2Ktux-4XrhPaSvDvjDGrIFg0mO_K1qgttsv2J7LcD-gtGa-lqoV-"
"2Byt6rB7bs8xiv247IPfJLrmrYt7B1tohdZ8wnGOJ7eXCJkcXdEEB5ubjgWkU9lAvLsnhhR9M0d6QntI5Usde9MnBBb2nGD4zK2mZ4di"
"w0yAHHeY9oXFYE-eEToucdp6C2dPzEu9rWbrQTzrnqxp87E9xezM1cXzotMlxhwd8TPH6SDfF9W8H9Fb3F37g5_"
"tism4JddbpkV87NO5DdngYxj3IHnvgSG_"
"Q1Avrkk6fvO35QTiHIJ3B6GQthwSPdgbkrQMFITJ2rXM5basbnSf0n8lhJ3qEqIrZmiaW1w3Uz_QJat8NwM3vV4HKsmi_"
"t2A39JnezXN2s-oXGmv6eL43evL_GvtuDGEb-3arZL9L0XMMkJ-eopdSppSir5GjLhtTz0f6-"
"npFaIfdOuhkZQvdaJLPc1Ara4Vnh902ed_lbDIPmbcMWbbeWtmBKivJeMjrTsClLvXu0HivZu1gO250IS93-RivhRVxXdZ1Ylkt_"
"XDuI36ji2UF2KvLw3kUn3Bi2NnYws6vDZSEfkROu9GfGUSNKJhh2DudI_"
"Mxq3tFDrs0fMDws2JUxGvfkAOQGR4rK6ZQZnaVHNkQaSYTRGYVcV636-TQ9j068TGexT0v-"
"yxe1536D1jfQRHqym5A7et7YJFsFvh5e1RSvVgbcoENhd-"
"MLidQFCF2sZHtu7QPpn3APiff2jRYzqnrCnvAKXxrd8g369hp0wmb4v0VU3w-ZnfJvk1dvMcmi8_"
"0bMghNsDwBQ2yfO5ZWmoc4Gg77tG7eK6zjIzfZHC4fUkOYIdorWBqBTz2yd-tZMQCD8QUxOXxDvm-"
"1jDlonhlf4r1HYTc479E2NmQpSdjB_HYKODhyukRGYv7X7aztsMlCwKaz1vAb_G9CnsYyw8KdrReF5-v2CNysuafR2hPRxHX-_"
"YV6J66U_6w446LLq7bbcjZQE8fOeZX4vM7-xpo2Z_5JO-_"
"e5qcWuNmxSN9WuLnEfpX9Bnt21hPz3F3ImsTL3hSHCN7ECN7dMHHWE7SxfcienXyvscepTp111EAPTsykvGAe3t8xrD-"
"jSwbQnvoNckH8KeffPf1qArrOyYxqteCffEdfWdFLZRrr01OelBcBHQWYfarlcW4rdcFfMli91-5fL6-qWzwVra3-"
"N4yEp625oSaBWTwSJ-QPmFydoXzAzVLj91TF42DRrE8BkAP_hhhOjaSHl9vRPZ7HCwRtYUES_VuY_"
"k8SreMomefuirez6VN9i8XaN0Kvm0KaftVctiHeLxAz-_Eub3fIPt9FosBOb_brvdzOKjfJN--9Ev7vvv00urA5JT0z_"
"st8m2f3kdUiqX12r7DdKAlNOfkbX_OXX5_D8Pztqcr6biC1_"
"X9Djnu07vVBT9sr1bunhAyRxfk7Od8dW2vZoGsbPLbNb7vc0hBDIo9O45w7natQNY6S84l-lCr9SMWhH58QOu_-"
"liqLjB3naElYyylsH7sO-SkD3FvCdkYOQsHn8r2U7djZ38I8gV8EM1il8TyY0Usn8_kANbPYpMX-0lq1_"
"5NrMdVFHvC1tEKevyfquTgE8V77lbB_"
"cZBgxwPvvwt8viO835dXDcMLsnRwF9g9zL31LLYfgYOOXRYgPbsFVNcaw1G5FeDaAne6UlNNmUAgOIdZOdJ18g7fWAAOGLwCC6AYTAta"
"yPbe3Cq5J1DoylfXdndgWF1XbgXp0a-ceI7D_6mgYDEjiRHO3Vy6rCnyZy5YNxYP9JMdJ4krYT-"
"jBw40RTrjcX3iMS8NkBnjyDwvKz31K3-MULbgtqcezN67wfY3RS94OzdOY9lHcebc-"
"ayzZ2vvbScZNVInRdtdHeYtXunTY4d139gHq4zxRTX605nTQ_hF6VXZXFscLqwlzhqUqnLfC-"
"bi18wkCzmwQY7oOvSxUNrYLPQ9p0eOXLiQpa6CN4T-6ADvu-A77sYftMKeB-A_KB0gAyP7l0ruC_sOK_9vpUlI72DAt6H5Hvny7_"
"40tBffPkbZK5-8OVfvQnHzvBkJd3zfIV8KV6uyNuGKznUfcDvQJTFdahzHdsCmLVNoXJkWByGnChXSEG-c27Ar58CtH9k6YrYHm_"
"JcWP5SOPCFbXFArw2rJPvh1FwF3d86xSy-lLQC9WL76QMz8h-"
"fU6nuF9kartMHTJskf2hP9tx59kU2uXwnBwP55Svj6CRGFVwf254QU6H9Gf-gsryerDEPa1hhxwN_TsGqCGfA6wEMwyhdhnyhR_"
"82AV8w5B8kRprk3exbuJvQOzAisBX2kbXNr6lX4gTQ0AJS_SOkDhWDi_JwdCHuI9i4qQfMhyQw5hPhtRO1lecXw-"
"H5OMQQgqf0imY4dAf09gI8vZnFn9nZXgV8_JA3QjDbgmWHQJ2GFL-iOnaNHWhzw3B54bUe6Y7cpBc8L2WUZUcje7iK_"
"csR6sk3y9I7txl-oqjFjkczXbhHjFmGTmkNHKqObxV-Qq8NboBvoMohrtI3N_GLtl-3-iWnI6ex2y3f2X9e5v-qk5-WGOIK-5NGLz-"
"TgrnTFrfz4lLMSz2Fn_v5qpBTq4gjz5D-YPE3z3tK85pr1rk-1rcTVvOgbtgxkXnSfJX8NQmH0dOdir0bKpcOBf4_xVnIeTrrD_"
"smanvMV2NYBz1Ihoi8ctI_OZzk3zzmboujxNGMwojL3--p5vJHbLP8X271deiMH9c1dXxs73rFvmh5YLnu5Ltj7nLIC2HgJN5CO-"
"eIFIu8vRmap3rDjns-Ev_AcNT5s48vl77inzf9kIWeKtiBFjosfDRh6SYx6mmKafeJz2XmwY5uGELhmFzSzd2xZPV-jdQy9_8mKvlV5-"
"pcnJ2qK7ros2at3ENs8JS6xv3SCzakw0ijAe3Njm83XX_Kunj4rSfyfEtX4zp-BHHwTp6N2T6P3_97_8HHeuAFA==")
.ok());
TlBufferParser parser(&en);
auto result = telegram_api::help_getCountriesList::fetch_result(parser);
parser.fetch_end();
CHECK(parser.get_error() == nullptr);
on_get_country_list_impl(language_code, std::move(result));
it = countries_.find(language_code);
CHECK(it != countries_.end())
auto *country = it->second.get();
load_country_list(language_code, country->hash, Auto());
return country;
}
return nullptr;
}

View File

@ -23,7 +23,7 @@ class Td;
class CountryInfoManager : public Actor {
public:
explicit CountryInfoManager(Td *td, ActorShared<> parent);
CountryInfoManager(Td *td, ActorShared<> parent);
void get_countries(Promise<td_api::object_ptr<td_api::countries>> &&promise);
@ -32,6 +32,12 @@ class CountryInfoManager : public Actor {
void get_phone_number_info(string phone_number_prefix,
Promise<td_api::object_ptr<td_api::phoneNumberInfo>> &&promise);
CountryInfoManager(const CountryInfoManager &) = delete;
CountryInfoManager &operator=(const CountryInfoManager &) = delete;
CountryInfoManager(CountryInfoManager &&) = delete;
CountryInfoManager &operator=(CountryInfoManager &&) = delete;
~CountryInfoManager() override;
private:
void tear_down() override;
@ -52,6 +58,9 @@ class CountryInfoManager : public Actor {
void on_get_country_list(const string &language_code,
Result<tl_object_ptr<telegram_api::help_CountriesList>> r_country_list);
void on_get_country_list_impl(const string &language_code,
tl_object_ptr<telegram_api::help_CountriesList> country_list);
const CountryList *get_country_list(const string &language_code);
std::unordered_map<string, vector<Promise<Unit>>> pending_load_country_queries_;

View File

@ -11,6 +11,7 @@
#include "td/telegram/Td.h"
#include "td/telegram/WebPagesManager.h"
#include "td/utils/common.h"
#include "td/utils/logging.h"
namespace td {

View File

@ -144,10 +144,10 @@ class DialogDbAsync : public DialogDbAsyncInterface {
void add_dialog(DialogId dialog_id, FolderId folder_id, int64 order, BufferSlice data,
vector<NotificationGroupKey> notification_groups, Promise<> promise) {
add_write_query([=, promise = std::move(promise), data = std::move(data),
add_write_query([this, dialog_id, folder_id, order, promise = std::move(promise), data = std::move(data),
notification_groups = std::move(notification_groups)](Unit) mutable {
this->on_write_result(std::move(promise), sync_db_->add_dialog(dialog_id, folder_id, order, std::move(data),
std::move(notification_groups)));
on_write_result(std::move(promise), sync_db_->add_dialog(dialog_id, folder_id, order, std::move(data),
std::move(notification_groups)));
});
}

View File

@ -47,13 +47,12 @@ DialogParticipantStatus DialogParticipantStatus::Administrator(bool is_anonymous
(static_cast<uint32>(can_invite_users) * CAN_INVITE_USERS_ADMIN) |
(static_cast<uint32>(can_restrict_members) * CAN_RESTRICT_MEMBERS) |
(static_cast<uint32>(can_pin_messages) * CAN_PIN_MESSAGES_ADMIN) |
(static_cast<uint32>(can_promote_members) * CAN_PROMOTE_MEMBERS);
(static_cast<uint32>(can_promote_members) * CAN_PROMOTE_MEMBERS) |
(static_cast<uint32>(is_anonymous) * IS_ANONYMOUS);
if (flags == 0 || flags == CAN_BE_EDITED) {
return Member();
}
return DialogParticipantStatus(Type::Administrator,
IS_MEMBER | ALL_RESTRICTED_RIGHTS | flags | (is_anonymous ? IS_ANONYMOUS : 0), 0,
std::move(rank));
return DialogParticipantStatus(Type::Administrator, IS_MEMBER | ALL_RESTRICTED_RIGHTS | flags, 0, std::move(rank));
}
DialogParticipantStatus DialogParticipantStatus::Member() {
@ -111,12 +110,12 @@ RestrictedRights DialogParticipantStatus::get_restricted_rights() const {
tl_object_ptr<td_api::ChatMemberStatus> DialogParticipantStatus::get_chat_member_status_object() const {
switch (type_) {
case Type::Creator:
return td_api::make_object<td_api::chatMemberStatusCreator>(is_anonymous(), rank_, is_member());
return td_api::make_object<td_api::chatMemberStatusCreator>(rank_, is_anonymous(), is_member());
case Type::Administrator:
return td_api::make_object<td_api::chatMemberStatusAdministrator>(
is_anonymous(), rank_, can_be_edited(), can_change_info_and_settings(), can_post_messages(),
can_edit_messages(), can_delete_messages(), can_invite_users(), can_restrict_members(), can_pin_messages(),
can_promote_members());
rank_, can_be_edited(), can_change_info_and_settings(), can_post_messages(), can_edit_messages(),
can_delete_messages(), can_invite_users(), can_restrict_members(), can_pin_messages(), can_promote_members(),
is_anonymous());
case Type::Member:
return td_api::make_object<td_api::chatMemberStatusMember>();
case Type::Restricted:
@ -395,9 +394,9 @@ DialogParticipantStatus get_dialog_participant_status(const tl_object_ptr<td_api
case td_api::chatMemberStatusAdministrator::ID: {
auto st = static_cast<const td_api::chatMemberStatusAdministrator *>(status.get());
return DialogParticipantStatus::Administrator(
st->is_anonymous_, st->custom_title_, st->can_be_edited_, st->can_change_info_, st->can_post_messages_,
st->can_edit_messages_, st->can_delete_messages_, st->can_invite_users_, st->can_restrict_members_,
st->can_pin_messages_, st->can_promote_members_);
st->is_anonymous_, st->custom_title_, true /*st->can_be_edited_*/, st->can_change_info_,
st->can_post_messages_, st->can_edit_messages_, st->can_delete_messages_, st->can_invite_users_,
st->can_restrict_members_, st->can_pin_messages_, st->can_promote_members_);
}
case td_api::chatMemberStatusMember::ID:
return DialogParticipantStatus::Member();

View File

@ -19,6 +19,7 @@
#include "td/utils/format.h"
#include "td/utils/logging.h"
#include "td/utils/misc.h"
#include "td/utils/port/Clocks.h"
#include "td/utils/tl_helpers.h"
@ -200,7 +201,7 @@ double Global::get_dns_time_difference() const {
DcId Global::get_webfile_dc_id() const {
CHECK(shared_config_ != nullptr);
int32 dc_id = shared_config_->get_option_integer("webfile_dc_id");
auto dc_id = narrow_cast<int32>(shared_config_->get_option_integer("webfile_dc_id"));
if (!DcId::is_valid(dc_id)) {
if (is_test_dc()) {
dc_id = 2;
@ -220,7 +221,8 @@ bool Global::ignore_backgrond_updates() const {
}
void Global::set_net_query_stats(std::shared_ptr<NetQueryStats> net_query_stats) {
net_query_creator_.set_create_func([=] { return td::make_unique<NetQueryCreator>(net_query_stats); });
net_query_creator_.set_create_func(
[net_query_stats = std::move(net_query_stats)] { return td::make_unique<NetQueryCreator>(net_query_stats); });
}
void Global::set_net_query_dispatcher(unique_ptr<NetQueryDispatcher> net_query_dispatcher) {

View File

@ -363,7 +363,7 @@ void LanguagePackManager::on_language_pack_version_changed(bool is_base, int32 n
if (new_version < 0) {
Slice version_key = is_base ? Slice("base_language_pack_version") : Slice("language_pack_version");
new_version = G()->shared_config().get_option_integer(version_key, -1);
new_version = narrow_cast<int32>(G()->shared_config().get_option_integer(version_key, -1));
}
if (new_version <= 0) {
return;

View File

@ -35,7 +35,8 @@ bool Log::set_file_path(string file_path) {
return Logging::set_current_stream(td_api::make_object<td_api::logStreamDefault>()).is_ok();
}
if (Logging::set_current_stream(td_api::make_object<td_api::logStreamFile>(file_path, max_log_file_size)).is_ok()) {
if (Logging::set_current_stream(td_api::make_object<td_api::logStreamFile>(file_path, max_log_file_size, true))
.is_ok()) {
log_file_path = std::move(file_path);
return true;
}
@ -46,7 +47,8 @@ bool Log::set_file_path(string file_path) {
void Log::set_max_file_size(int64 max_file_size) {
std::lock_guard<std::mutex> lock(log_mutex);
max_log_file_size = max(max_file_size, static_cast<int64>(1));
Logging::set_current_stream(td_api::make_object<td_api::logStreamFile>(log_file_path, max_log_file_size)).ignore();
Logging::set_current_stream(td_api::make_object<td_api::logStreamFile>(log_file_path, max_log_file_size, true))
.ignore();
}
void Log::set_verbosity_level(int new_verbosity_level) {

View File

@ -61,8 +61,9 @@ Status Logging::set_current_stream(td_api::object_ptr<td_api::LogStream> stream)
if (max_log_file_size <= 0) {
return Status::Error("Max log file size must be positive");
}
auto redirect_stderr = file_stream->redirect_stderr_;
TRY_STATUS(file_log.init(file_stream->path_, max_log_file_size));
TRY_STATUS(file_log.init(file_stream->path_, max_log_file_size, redirect_stderr));
std::atomic_thread_fence(std::memory_order_release); // better than nothing
log_interface = &ts_log;
return Status::OK();
@ -85,7 +86,8 @@ Result<td_api::object_ptr<td_api::LogStream>> Logging::get_current_stream() {
return td_api::make_object<td_api::logStreamEmpty>();
}
if (log_interface == &ts_log) {
return td_api::make_object<td_api::logStreamFile>(file_log.get_path().str(), file_log.get_rotate_threshold());
return td_api::make_object<td_api::logStreamFile>(file_log.get_path().str(), file_log.get_rotate_threshold(),
file_log.get_redirect_stderr());
}
return Status::Error("Log stream is unrecognized");
}

View File

@ -1859,7 +1859,7 @@ Result<InputMessageContent> get_input_message_content(
}
case td_api::inputMessageDocument::ID: {
auto input_message = static_cast<td_api::inputMessageDocument *>(input_message_content.get());
auto file_type = input_message->force_file_ ? FileType::DocumentAsFile : FileType::Document;
auto file_type = input_message->disable_content_type_detection_ ? FileType::DocumentAsFile : FileType::Document;
r_file_id =
td->file_manager_->get_input_file_id(file_type, input_message->document_, dialog_id, false, is_secret, true);
input_thumbnail = std::move(input_message->thumbnail_);

View File

@ -7,6 +7,7 @@
#pragma once
#include "td/telegram/MessageEntity.h"
#include "td/telegram/MessageId.h"
#include "td/telegram/ReplyMarkup.h"
#include "td/utils/common.h"
@ -18,6 +19,7 @@ struct MessageCopyOptions {
bool send_copy = false;
bool replace_caption = false;
FormattedText new_caption;
MessageId top_thread_message_id;
MessageId reply_to_message_id;
unique_ptr<ReplyMarkup> reply_markup;
@ -32,8 +34,11 @@ inline StringBuilder &operator<<(StringBuilder &string_builder, MessageCopyOptio
if (copy_options.replace_caption) {
string_builder << ", new_caption = " << copy_options.new_caption;
}
if (copy_options.top_thread_message_id.is_valid()) {
string_builder << ", in thread of " << copy_options.top_thread_message_id;
}
if (copy_options.reply_to_message_id.is_valid()) {
string_builder << ", reply to = " << copy_options.reply_to_message_id;
string_builder << ", in reply to " << copy_options.reply_to_message_id;
}
if (copy_options.reply_markup != nullptr) {
string_builder << ", with reply markup";

View File

@ -3873,10 +3873,10 @@ FormattedText get_message_text(const ContactsManager *contacts_manager, string m
auto debug_entities = entities;
auto status = fix_formatted_text(message_text, entities, true, skip_new_entities, true, false);
if (status.is_error()) {
if (!from_album && (send_date == 0 || send_date > 1579219200)) { // approximate fix date
LOG(ERROR) << "Receive error " << status << " while parsing message text from " << source << " with content \""
<< debug_message_text << "\" -> \"" << message_text << "\" sent at " << send_date << " with entities "
<< format::as_array(debug_entities) << " -> " << format::as_array(entities);
if (!from_album && (send_date == 0 || send_date > 1600340000)) { // approximate fix date
LOG(ERROR) << "Receive error " << status << " while parsing message text from " << source << " sent at "
<< send_date << " with content \"" << debug_message_text << "\" -> \"" << message_text
<< "\" with entities " << format::as_array(debug_entities) << " -> " << format::as_array(entities);
}
if (!clean_input_string(message_text)) {
message_text.clear();

View File

@ -6,7 +6,10 @@
//
#include "td/telegram/MessageReplyInfo.h"
#include "td/telegram/ServerMessageId.h"
#include "td/utils/logging.h"
#include "td/utils/misc.h"
namespace td {
@ -21,23 +24,40 @@ MessageReplyInfo::MessageReplyInfo(tl_object_ptr<telegram_api::messageReplies> &
reply_count = reply_info->replies_;
pts = reply_info->replies_pts_;
for (auto &peer : reply_info->recent_repliers_) {
DialogId dialog_id(peer);
if (dialog_id.is_valid()) {
recent_replier_dialog_ids.push_back(dialog_id);
} else {
LOG(ERROR) << "Receive " << dialog_id << " as a recent replier";
}
}
is_comment = reply_info->comments_;
if (is_comment) {
channel_id = ChannelId(reply_info->channel_id_);
if (!channel_id.is_valid()) {
LOG(ERROR) << "Receive invalid " << channel_id;
channel_id = ChannelId();
is_comment = false;
}
}
if (is_comment) {
for (auto &peer : reply_info->recent_repliers_) {
DialogId dialog_id(peer);
if (dialog_id.is_valid()) {
recent_replier_dialog_ids.push_back(dialog_id);
} else {
LOG(ERROR) << "Receive " << dialog_id << " as a recent replier";
}
}
}
if ((reply_info->flags_ & telegram_api::messageReplies::MAX_ID_MASK) != 0 &&
ServerMessageId(reply_info->max_id_).is_valid()) {
max_message_id = MessageId(ServerMessageId(reply_info->max_id_));
}
if ((reply_info->flags_ & telegram_api::messageReplies::READ_MAX_ID_MASK) != 0 &&
ServerMessageId(reply_info->read_max_id_).is_valid()) {
last_read_inbox_message_id = MessageId(ServerMessageId(reply_info->read_max_id_));
}
if (last_read_inbox_message_id > max_message_id) {
LOG(ERROR) << "Receive last_read_inbox_message_id = " << last_read_inbox_message_id
<< ", but max_message_id = " << max_message_id;
max_message_id = last_read_inbox_message_id;
}
}
bool MessageReplyInfo::need_update_to(const MessageReplyInfo &other) const {
@ -47,11 +67,43 @@ bool MessageReplyInfo::need_update_to(const MessageReplyInfo &other) const {
return reply_count != other.reply_count || recent_replier_dialog_ids != other.recent_replier_dialog_ids;
}
void MessageReplyInfo::add_reply(DialogId replier_dialog_id) {
bool MessageReplyInfo::update_max_message_ids(const MessageReplyInfo &other) {
return update_max_message_ids(other.max_message_id, other.last_read_inbox_message_id,
other.last_read_outbox_message_id);
}
bool MessageReplyInfo::update_max_message_ids(MessageId other_max_message_id,
MessageId other_last_read_inbox_message_id,
MessageId other_last_read_outbox_message_id) {
bool result = false;
if (other_max_message_id > max_message_id) {
max_message_id = other_max_message_id;
result = true;
}
if (other_last_read_inbox_message_id > last_read_inbox_message_id) {
last_read_inbox_message_id = other_last_read_inbox_message_id;
result = true;
}
if (other_last_read_outbox_message_id > last_read_outbox_message_id) {
last_read_outbox_message_id = other_last_read_outbox_message_id;
result = true;
}
if (last_read_inbox_message_id > max_message_id) {
max_message_id = last_read_inbox_message_id;
result = true;
}
if (last_read_outbox_message_id > max_message_id) {
max_message_id = last_read_outbox_message_id;
result = true;
}
return result;
}
void MessageReplyInfo::add_reply(DialogId replier_dialog_id, MessageId reply_message_id) {
CHECK(!is_empty());
reply_count++;
if (replier_dialog_id.is_valid() &&
if (is_comment && replier_dialog_id.is_valid() &&
(recent_replier_dialog_ids.empty() || recent_replier_dialog_ids[0] != replier_dialog_id)) {
td::remove(recent_replier_dialog_ids, replier_dialog_id);
recent_replier_dialog_ids.insert(recent_replier_dialog_ids.begin(), replier_dialog_id);
@ -59,10 +111,21 @@ void MessageReplyInfo::add_reply(DialogId replier_dialog_id) {
recent_replier_dialog_ids.pop_back();
}
}
if (reply_message_id > max_message_id) {
max_message_id = reply_message_id;
}
}
StringBuilder &operator<<(StringBuilder &string_builder, const MessageReplyInfo &reply_info) {
return string_builder << reply_info.reply_count << " replies by " << reply_info.recent_replier_dialog_ids;
if (reply_info.is_comment) {
return string_builder << reply_info.reply_count << " comments in " << reply_info.channel_id << " by "
<< reply_info.recent_replier_dialog_ids << " read up to "
<< reply_info.last_read_inbox_message_id << "/" << reply_info.last_read_outbox_message_id;
} else {
return string_builder << reply_info.reply_count << " replies read up to " << reply_info.last_read_inbox_message_id
<< "/" << reply_info.last_read_outbox_message_id;
}
}
} // namespace td

View File

@ -8,6 +8,7 @@
#include "td/telegram/ChannelId.h"
#include "td/telegram/DialogId.h"
#include "td/telegram/MessageId.h"
#include "td/telegram/telegram_api.h"
#include "td/utils/common.h"
@ -19,8 +20,11 @@ namespace td {
struct MessageReplyInfo {
int32 reply_count = -1;
int32 pts = -1;
vector<DialogId> recent_replier_dialog_ids;
ChannelId channel_id;
vector<DialogId> recent_replier_dialog_ids; // comments only
ChannelId channel_id; // comments only
MessageId max_message_id;
MessageId last_read_inbox_message_id;
MessageId last_read_outbox_message_id;
bool is_comment = false;
MessageReplyInfo() = default;
@ -33,17 +37,28 @@ struct MessageReplyInfo {
bool need_update_to(const MessageReplyInfo &other) const;
void add_reply(DialogId replier_dialog_id);
bool update_max_message_ids(MessageId other_max_message_id, MessageId other_last_read_inbox_message_id,
MessageId other_last_read_outbox_message_id);
bool update_max_message_ids(const MessageReplyInfo &other);
void add_reply(DialogId replier_dialog_id, MessageId reply_message_id);
template <class StorerT>
void store(StorerT &storer) const {
CHECK(!is_empty());
bool has_recent_replier_dialog_ids = !recent_replier_dialog_ids.empty();
bool has_channel_id = channel_id.is_valid();
bool has_max_message_id = max_message_id.is_valid();
bool has_last_read_inbox_message_id = last_read_inbox_message_id.is_valid();
bool has_last_read_outbox_message_id = last_read_outbox_message_id.is_valid();
BEGIN_STORE_FLAGS();
STORE_FLAG(is_comment);
STORE_FLAG(has_recent_replier_dialog_ids);
STORE_FLAG(has_channel_id);
STORE_FLAG(has_max_message_id);
STORE_FLAG(has_last_read_inbox_message_id);
STORE_FLAG(has_last_read_outbox_message_id);
END_STORE_FLAGS();
td::store(reply_count, storer);
td::store(pts, storer);
@ -53,16 +68,31 @@ struct MessageReplyInfo {
if (has_channel_id) {
td::store(channel_id, storer);
}
if (has_max_message_id) {
td::store(max_message_id, storer);
}
if (has_last_read_inbox_message_id) {
td::store(last_read_inbox_message_id, storer);
}
if (has_last_read_outbox_message_id) {
td::store(last_read_outbox_message_id, storer);
}
}
template <class ParserT>
void parse(ParserT &parser) {
bool has_recent_replier_dialog_ids = !recent_replier_dialog_ids.empty();
bool has_channel_id = channel_id.is_valid();
bool has_recent_replier_dialog_ids;
bool has_channel_id;
bool has_max_message_id;
bool has_last_read_inbox_message_id;
bool has_last_read_outbox_message_id;
BEGIN_PARSE_FLAGS();
PARSE_FLAG(is_comment);
PARSE_FLAG(has_recent_replier_dialog_ids);
PARSE_FLAG(has_channel_id);
PARSE_FLAG(has_max_message_id);
PARSE_FLAG(has_last_read_inbox_message_id);
PARSE_FLAG(has_last_read_outbox_message_id);
END_PARSE_FLAGS();
td::parse(reply_count, parser);
td::parse(pts, parser);
@ -72,6 +102,15 @@ struct MessageReplyInfo {
if (has_channel_id) {
td::parse(channel_id, parser);
}
if (has_max_message_id) {
td::parse(max_message_id, parser);
}
if (has_last_read_inbox_message_id) {
td::parse(last_read_inbox_message_id, parser);
}
if (has_last_read_outbox_message_id) {
td::parse(last_read_outbox_message_id, parser);
}
}
};

View File

@ -113,10 +113,9 @@ Status init_messages_db(SqliteDb &db, int32 version) {
if (version == 0) {
LOG(INFO) << "Create new message database";
TRY_STATUS(
db.exec("CREATE TABLE IF NOT EXISTS messages (dialog_id INT8, message_id INT8, "
"unique_message_id INT4, sender_user_id INT4, random_id INT8, data BLOB, "
"ttl_expires_at INT4, index_mask INT4, search_id INT8, text STRING, notification_id INT4, seqno INT32, PRIMARY KEY "
"(dialog_id, message_id))"));
db.exec("CREATE TABLE IF NOT EXISTS messages (dialog_id INT8, message_id INT8, unique_message_id INT4, "
"sender_user_id INT4, random_id INT8, data BLOB, ttl_expires_at INT4, index_mask INT4, search_id INT8, "
"text STRING, notification_id INT4, top_thread_message_id INT8, seqno INT32, PRIMARY KEY (dialog_id, message_id))"));
TRY_STATUS(
db.exec("CREATE INDEX IF NOT EXISTS message_by_random_id ON messages (dialog_id, random_id) "
@ -164,6 +163,9 @@ Status init_messages_db(SqliteDb &db, int32 version) {
if (version < static_cast<int32>(DbVersion::AddScheduledMessages)) {
TRY_STATUS(add_scheduled_messages_table());
}
if (version < static_cast<int32>(DbVersion::AddMessageThreadSupport)) {
TRY_STATUS(db.exec("ALTER TABLE messages ADD COLUMN top_thread_message_id INT8"));
}
return Status::OK();
}
@ -187,7 +189,7 @@ class MessagesDbImpl : public MessagesDbSyncInterface {
TRY_RESULT_ASSIGN(
add_message_stmt_,
db_memory_.get_statement("INSERT OR REPLACE INTO messages VALUES(?1, ?2, ?3, ?4, ?5, ?6, ?7, ?8, ?9, ?10, ?11, ?12)"));
db_memory_.get_statement("INSERT OR REPLACE INTO messages VALUES(?1, ?2, ?3, ?4, ?5, ?6, ?7, ?8, ?9, ?10, ?11, ?12, ?13)"));
TRY_RESULT_ASSIGN(delete_message_stmt_,
db_memory_.get_statement("DELETE FROM messages WHERE dialog_id = ?1 AND message_id = ?2"));
TRY_RESULT_ASSIGN(delete_all_dialog_messages_stmt_,
@ -280,7 +282,7 @@ class MessagesDbImpl : public MessagesDbSyncInterface {
Status add_message(FullMessageId full_message_id, ServerMessageId unique_message_id, UserId sender_user_id,
int64 random_id, int32 ttl_expires_at, int32 index_mask, int64 search_id, string text,
NotificationId notification_id, BufferSlice data) override {
NotificationId notification_id, MessageId top_thread_message_id, BufferSlice data) override {
LOG(INFO) << "Add " << full_message_id << " to database";
auto dialog_id = full_message_id.get_dialog_id();
auto message_id = full_message_id.get_message_id();
@ -358,6 +360,11 @@ class MessagesDbImpl : public MessagesDbSyncInterface {
} else {
add_message_stmt_.bind_null(11).ensure();
}
if (top_thread_message_id.is_valid()) {
add_message_stmt_.bind_int64(12, top_thread_message_id.get()).ensure();
} else {
add_message_stmt_.bind_null(12).ensure();
}
add_message_stmt_.step().ensure();
@ -961,10 +968,11 @@ class MessagesDbAsync : public MessagesDbAsyncInterface {
void add_message(FullMessageId full_message_id, ServerMessageId unique_message_id, UserId sender_user_id,
int64 random_id, int32 ttl_expires_at, int32 index_mask, int64 search_id, string text,
NotificationId notification_id, BufferSlice data, Promise<> promise) override {
NotificationId notification_id, MessageId top_thread_message_id, BufferSlice data,
Promise<> promise) override {
send_closure_later(impl_, &Impl::add_message, full_message_id, unique_message_id, sender_user_id, random_id,
ttl_expires_at, index_mask, search_id, std::move(text), notification_id, std::move(data),
std::move(promise));
ttl_expires_at, index_mask, search_id, std::move(text), notification_id, top_thread_message_id,
std::move(data), std::move(promise));
}
void add_scheduled_message(FullMessageId full_message_id, BufferSlice data, Promise<> promise) override {
send_closure_later(impl_, &Impl::add_scheduled_message, full_message_id, std::move(data), std::move(promise));
@ -1034,23 +1042,26 @@ class MessagesDbAsync : public MessagesDbAsyncInterface {
}
void add_message(FullMessageId full_message_id, ServerMessageId unique_message_id, UserId sender_user_id,
int64 random_id, int32 ttl_expires_at, int32 index_mask, int64 search_id, string text,
NotificationId notification_id, BufferSlice data, Promise<> promise) {
add_write_query([=, promise = std::move(promise), data = std::move(data), text = std::move(text)](Unit) mutable {
this->on_write_result(
std::move(promise),
sync_db_->add_message(full_message_id, unique_message_id, sender_user_id, random_id, ttl_expires_at,
index_mask, search_id, std::move(text), notification_id, std::move(data)));
NotificationId notification_id, MessageId top_thread_message_id, BufferSlice data,
Promise<> promise) {
add_write_query([this, full_message_id, unique_message_id, sender_user_id, random_id, ttl_expires_at, index_mask,
search_id, text = std::move(text), notification_id, top_thread_message_id,
data = std::move(data), promise = std::move(promise)](Unit) mutable {
on_write_result(std::move(promise),
sync_db_->add_message(full_message_id, unique_message_id, sender_user_id, random_id,
ttl_expires_at, index_mask, search_id, std::move(text), notification_id,
top_thread_message_id, std::move(data)));
});
}
void add_scheduled_message(FullMessageId full_message_id, BufferSlice data, Promise<> promise) {
add_write_query([this, full_message_id, promise = std::move(promise), data = std::move(data)](Unit) mutable {
this->on_write_result(std::move(promise), sync_db_->add_scheduled_message(full_message_id, std::move(data)));
on_write_result(std::move(promise), sync_db_->add_scheduled_message(full_message_id, std::move(data)));
});
}
void delete_message(FullMessageId full_message_id, Promise<> promise) {
add_write_query([=, promise = std::move(promise)](Unit) mutable {
this->on_write_result(std::move(promise), sync_db_->delete_message(full_message_id));
add_write_query([this, full_message_id, promise = std::move(promise)](Unit) mutable {
on_write_result(std::move(promise), sync_db_->delete_message(full_message_id));
});
}
void on_write_result(Promise<> promise, Status status) {

View File

@ -69,7 +69,7 @@ class MessagesDbSyncInterface {
virtual Status add_message(FullMessageId full_message_id, ServerMessageId unique_message_id, UserId sender_user_id,
int64 random_id, int32 ttl_expires_at, int32 index_mask, int64 search_id, string text,
NotificationId notification_id, BufferSlice data) = 0;
NotificationId notification_id, MessageId top_thread_message_id, BufferSlice data) = 0;
virtual Status add_scheduled_message(FullMessageId full_message_id, BufferSlice data) = 0;
virtual Status delete_message(FullMessageId full_message_id) = 0;
@ -117,7 +117,8 @@ class MessagesDbAsyncInterface {
virtual void add_message(FullMessageId full_message_id, ServerMessageId unique_message_id, UserId sender_user_id,
int64 random_id, int32 ttl_expires_at, int32 index_mask, int64 search_id, string text,
NotificationId notification_id, BufferSlice data, Promise<> promise) = 0;
NotificationId notification_id, MessageId top_thread_message_id, BufferSlice data,
Promise<> promise) = 0;
virtual void add_scheduled_message(FullMessageId full_message_id, BufferSlice data, Promise<> promise) = 0;
virtual void delete_message(FullMessageId full_message_id, Promise<> promise) = 0;

File diff suppressed because it is too large Load Diff

View File

@ -24,6 +24,7 @@
#include "td/telegram/FullMessageId.h"
#include "td/telegram/Global.h"
#include "td/telegram/InputDialogId.h"
#include "td/telegram/logevent/LogEventHelper.h"
#include "td/telegram/MessageContentType.h"
#include "td/telegram/MessageCopyOptions.h"
#include "td/telegram/MessageId.h"
@ -196,7 +197,7 @@ class MessagesManager : public Actor {
static MessageId get_message_id(const tl_object_ptr<telegram_api::Message> &message_ptr, bool is_scheduled);
DialogId get_message_dialog_id(const tl_object_ptr<telegram_api::Message> &message_ptr) const;
static DialogId get_message_dialog_id(const tl_object_ptr<telegram_api::Message> &message_ptr);
tl_object_ptr<telegram_api::InputPeer> get_input_peer(DialogId dialog_id, AccessRights access_rights) const;
@ -259,7 +260,7 @@ class MessagesManager : public Actor {
vector<tl_object_ptr<telegram_api::Message>> &&messages);
void on_failed_get_message_public_forwards(int64 random_id);
// if message is from_update, flags have_previous and have_next are ignored and should be both true
// if message is from_update, flags have_previous and have_next are ignored and must be both true
FullMessageId on_get_message(tl_object_ptr<telegram_api::Message> message_ptr, bool from_update,
bool is_channel_message, bool is_scheduled, bool have_previous, bool have_next,
const char *source);
@ -312,6 +313,8 @@ class MessagesManager : public Actor {
void on_update_dialog_is_marked_as_unread(DialogId dialog_id, bool is_marked_as_unread);
void on_update_dialog_is_blocked(DialogId dialog_id, bool is_blocked);
void on_update_dialog_pinned_message_id(DialogId dialog_id, MessageId pinned_message_id);
void on_update_dialog_has_scheduled_server_messages(DialogId dialog_id, bool has_scheduled_server_messages);
@ -334,6 +337,9 @@ class MessagesManager : public Actor {
void on_update_read_channel_messages_contents(
tl_object_ptr<telegram_api::updateChannelReadMessagesContents> &&update);
void on_update_read_message_comments(DialogId dialog_id, MessageId message_id, MessageId max_message_id,
MessageId last_read_inbox_message_id, MessageId last_read_outbox_message_id);
void on_update_channel_too_long(tl_object_ptr<telegram_api::updateChannelTooLong> &&update, bool force_apply);
void on_update_message_view_count(FullMessageId full_message_id, int32 view_count);
@ -361,7 +367,8 @@ class MessagesManager : public Actor {
void on_update_delete_scheduled_messages(DialogId dialog_id, vector<ScheduledServerMessageId> &&server_message_ids);
void on_user_dialog_action(DialogId dialog_id, UserId user_id, tl_object_ptr<td_api::ChatAction> &&action, int32 date,
void on_user_dialog_action(DialogId dialog_id, MessageId top_thread_message_id, UserId user_id,
tl_object_ptr<td_api::ChatAction> &&action, int32 date,
MessageContentType message_content_type = MessageContentType::None);
void read_history_inbox(DialogId dialog_id, MessageId max_message_id, int32 unread_count, const char *source);
@ -387,18 +394,20 @@ class MessagesManager : public Actor {
DialogId search_public_dialog(const string &username_to_search, bool force, Promise<Unit> &&promise);
Result<MessageId> send_message(
DialogId dialog_id, MessageId reply_to_message_id, tl_object_ptr<td_api::messageSendOptions> &&options,
tl_object_ptr<td_api::ReplyMarkup> &&reply_markup,
DialogId dialog_id, MessageId top_thread_message_id, MessageId reply_to_message_id,
tl_object_ptr<td_api::messageSendOptions> &&options, tl_object_ptr<td_api::ReplyMarkup> &&reply_markup,
tl_object_ptr<td_api::InputMessageContent> &&input_message_content) TD_WARN_UNUSED_RESULT;
Result<vector<MessageId>> send_message_group(
DialogId dialog_id, MessageId reply_to_message_id, tl_object_ptr<td_api::messageSendOptions> &&options,
DialogId dialog_id, MessageId top_thread_message_id, MessageId reply_to_message_id,
tl_object_ptr<td_api::messageSendOptions> &&options,
vector<tl_object_ptr<td_api::InputMessageContent>> &&input_message_contents) TD_WARN_UNUSED_RESULT;
Result<MessageId> send_bot_start_message(UserId bot_user_id, DialogId dialog_id,
const string &parameter) TD_WARN_UNUSED_RESULT;
Result<MessageId> send_inline_query_result_message(DialogId dialog_id, MessageId reply_to_message_id,
Result<MessageId> send_inline_query_result_message(DialogId dialog_id, MessageId top_thread_message_id,
MessageId reply_to_message_id,
tl_object_ptr<td_api::messageSendOptions> &&options,
int64 query_id, const string &result_id,
bool hide_via_bot) TD_WARN_UNUSED_RESULT;
@ -469,7 +478,8 @@ class MessagesManager : public Actor {
tl_object_ptr<td_api::gameHighScores> get_game_high_scores_object(int64 random_id);
void send_dialog_action(DialogId dialog_id, const tl_object_ptr<td_api::ChatAction> &action, Promise<Unit> &&promise);
void send_dialog_action(DialogId dialog_id, MessageId top_thread_message_id,
const tl_object_ptr<td_api::ChatAction> &action, Promise<Unit> &&promise);
vector<DialogListId> get_dialog_lists_to_add_dialog(DialogId dialog_id);
@ -532,19 +542,30 @@ class MessagesManager : public Actor {
void get_recommended_dialog_filters(Promise<td_api::object_ptr<td_api::recommendedChatFilters>> &&promise);
vector<DialogId> get_dialogs(DialogListId dialog_list_id, DialogDate offset, int32 limit, bool force,
Promise<Unit> &&promise);
std::pair<int32, vector<DialogId>> get_dialogs(DialogListId dialog_list_id, DialogDate offset, int32 limit,
bool force, Promise<Unit> &&promise);
vector<DialogId> search_public_dialogs(const string &query, Promise<Unit> &&promise);
std::pair<size_t, vector<DialogId>> search_dialogs(const string &query, int32 limit, Promise<Unit> &&promise);
std::pair<int32, vector<DialogId>> search_dialogs(const string &query, int32 limit, Promise<Unit> &&promise);
vector<DialogId> search_dialogs_on_server(const string &query, int32 limit, Promise<Unit> &&promise);
void drop_common_dialogs_cache(UserId user_id);
vector<DialogId> get_common_dialogs(UserId user_id, DialogId offset_dialog_id, int32 limit, bool force,
Promise<Unit> &&promise);
std::pair<int32, vector<DialogId>> get_common_dialogs(UserId user_id, DialogId offset_dialog_id, int32 limit,
bool force, Promise<Unit> &&promise);
void block_dialog_from_replies(MessageId message_id, bool delete_message, bool delete_all_messages, bool report_spam,
Promise<Unit> &&promise);
std::pair<int32, vector<DialogId>> get_blocked_dialogs(int32 offset, int32 limit, int64 &random_id,
Promise<Unit> &&promise);
void on_get_blocked_dialogs(int32 offset, int32 limit, int64 random_id, int32 total_count,
vector<tl_object_ptr<telegram_api::peerBlocked>> &&blocked_peers);
void on_failed_get_blocked_dialogs(int64 random_id);
bool can_get_message_statistics(FullMessageId full_message_id);
@ -554,6 +575,17 @@ class MessagesManager : public Actor {
FullMessageId get_replied_message(DialogId dialog_id, MessageId message_id, bool force, Promise<Unit> &&promise);
struct MessageThreadInfo {
DialogId dialog_id;
vector<MessageId> message_ids;
};
void get_message_thread(DialogId dialog_id, MessageId message_id, Promise<MessageThreadInfo> &&promise);
td_api::object_ptr<td_api::messageThreadInfo> get_message_thread_info_object(const MessageThreadInfo &info);
void on_get_discussion_message(DialogId dialog_id, MessageId message_id, vector<FullMessageId> full_message_ids,
Promise<MessageThreadInfo> &&promise);
MessageId get_dialog_pinned_message(DialogId dialog_id, Promise<Unit> &&promise);
bool get_messages(DialogId dialog_id, const vector<MessageId> &message_ids, Promise<Unit> &&promise);
@ -566,13 +598,12 @@ class MessagesManager : public Actor {
bool is_message_edited_recently(FullMessageId full_message_id, int32 seconds);
std::pair<string, string> get_public_message_link(FullMessageId full_message_id, bool for_group, bool &for_comment,
Promise<Unit> &&promise);
Result<std::pair<string, bool>> get_message_link(FullMessageId full_message_id, bool for_group, bool for_comment);
string get_message_embedding_code(FullMessageId full_message_id, bool for_group, Promise<Unit> &&promise);
void on_get_public_message_link(FullMessageId full_message_id, bool for_group, string url, string html);
string get_message_link(FullMessageId full_message_id, Promise<Unit> &&promise);
struct MessageLinkInfo {
string username;
// or
@ -580,6 +611,10 @@ class MessagesManager : public Actor {
MessageId message_id;
bool is_single = false;
DialogId comment_dialog_id;
MessageId comment_message_id;
bool for_comment = false;
};
void get_message_link_info(Slice url, Promise<MessageLinkInfo> &&promise);
@ -597,7 +632,7 @@ class MessagesManager : public Actor {
Status delete_dialog_reply_markup(DialogId dialog_id, MessageId message_id) TD_WARN_UNUSED_RESULT;
Status set_dialog_draft_message(DialogId dialog_id,
Status set_dialog_draft_message(DialogId dialog_id, MessageId top_thread_message_id,
tl_object_ptr<td_api::draftMessage> &&draft_message) TD_WARN_UNUSED_RESULT;
void clear_all_draft_messages(bool exclude_secret_chats, Promise<Unit> &&promise);
@ -606,6 +641,8 @@ class MessagesManager : public Actor {
Status toggle_dialog_is_marked_as_unread(DialogId dialog_id, bool is_marked_as_unread) TD_WARN_UNUSED_RESULT;
Status toggle_dialog_is_blocked(DialogId dialog_id, bool is_blocked) TD_WARN_UNUSED_RESULT;
Status toggle_dialog_silent_send_message(DialogId dialog_id, bool silent_send_message) TD_WARN_UNUSED_RESULT;
Status set_pinned_dialogs(DialogListId dialog_list_id, vector<DialogId> dialog_ids) TD_WARN_UNUSED_RESULT;
@ -628,7 +665,8 @@ class MessagesManager : public Actor {
Status close_dialog(DialogId dialog_id) TD_WARN_UNUSED_RESULT;
Status view_messages(DialogId dialog_id, const vector<MessageId> &message_ids, bool force_read) TD_WARN_UNUSED_RESULT;
Status view_messages(DialogId dialog_id, MessageId top_thread_message_id, const vector<MessageId> &message_ids,
bool force_read) TD_WARN_UNUSED_RESULT;
Status open_message_content(FullMessageId full_message_id) TD_WARN_UNUSED_RESULT;
@ -653,7 +691,9 @@ class MessagesManager : public Actor {
tl_object_ptr<td_api::chat> get_chat_object(DialogId dialog_id) const;
static tl_object_ptr<td_api::chats> get_chats_object(const vector<DialogId> &dialogs);
static tl_object_ptr<td_api::chats> get_chats_object(int32 total_count, const vector<DialogId> &dialog_ids);
static tl_object_ptr<td_api::chats> get_chats_object(const std::pair<int32, vector<DialogId>> &dialog_ids);
tl_object_ptr<td_api::chatFilter> get_chat_filter_object(DialogFilterId dialog_filter_id) const;
@ -735,7 +775,6 @@ class MessagesManager : public Actor {
void on_dialog_permissions_updated(DialogId dialog_id);
void on_dialog_user_is_contact_updated(DialogId dialog_id, bool is_contact);
void on_dialog_user_is_blocked_updated(DialogId dialog_id, bool is_blocked);
void on_dialog_user_is_deleted_updated(DialogId dialog_id, bool is_deleted);
void on_dialog_linked_channel_updated(DialogId dialog_id, ChannelId old_linked_channel_id,
@ -995,7 +1034,7 @@ class MessagesManager : public Actor {
MessageId reply_to_message_id;
int64 reply_to_random_id = 0; // for send_message
DialogId reply_in_dialog_id;
MessageId top_reply_message_id;
MessageId top_thread_message_id;
UserId via_bot_user_id;
@ -1037,6 +1076,7 @@ class MessagesManager : public Actor {
int32 view_count = 0;
int32 forward_count = 0;
MessageReplyInfo reply_info;
unique_ptr<DraftMessage> thread_draft_message;
int32 legacy_layer = 0;
@ -1064,7 +1104,7 @@ class MessagesManager : public Actor {
mutable int32 last_access_date = 0;
mutable uint64 send_message_logevent_id = 0;
mutable uint64 send_message_log_event_id = 0;
mutable NetQueryRef send_query_ref;
@ -1117,14 +1157,11 @@ class MessagesManager : public Actor {
MessageId reply_markup_message_id;
DialogNotificationSettings notification_settings;
unique_ptr<DraftMessage> draft_message;
uint64 save_draft_message_logevent_id = 0;
uint64 save_draft_message_logevent_id_generation = 0;
uint64 save_notification_settings_logevent_id = 0;
uint64 save_notification_settings_logevent_id_generation = 0;
uint64 read_history_logevent_id = 0;
uint64 read_history_logevent_id_generation = 0;
uint64 set_folder_id_logevent_id = 0;
uint64 set_folder_id_logevent_id_generation = 0;
LogEventIdWithGeneration save_draft_message_log_event_id;
LogEventIdWithGeneration save_notification_settings_log_event_id;
std::unordered_map<int64, LogEventIdWithGeneration> read_history_log_event_ids;
std::unordered_set<MessageId, MessageIdHash> updated_read_history_message_ids;
LogEventIdWithGeneration set_folder_id_log_event_id;
FolderId folder_id;
vector<DialogListId> dialog_list_ids; // TODO replace with mask
@ -1187,6 +1224,8 @@ class MessagesManager : public Actor {
bool need_repair_server_unread_count = false;
bool need_repair_channel_server_unread_count = false;
bool is_marked_as_unread = false;
bool is_blocked = false;
bool is_is_blocked_inited = false;
bool last_sent_has_scheduled_messages = false;
bool has_scheduled_server_messages = false;
bool has_scheduled_database_messages = false;
@ -1556,6 +1595,7 @@ class MessagesManager : public Actor {
}
};
class BlockDialogFromRepliesOnServerLogEvent;
class ChangeDialogReportSpamStateOnServerLogEvent;
class DeleteAllChannelMessagesFromUserOnServerLogEvent;
class DeleteDialogHistoryFromServerLogEvent;
@ -1566,9 +1606,10 @@ class MessagesManager : public Actor {
class GetChannelDifferenceLogEvent;
class GetDialogFromServerLogEvent;
class ReadAllDialogMentionsOnServerLogEvent;
class ReadHistoryOnServerLogEvent;
class ReadHistoryInSecretChatLogEvent;
class ReadHistoryOnServerLogEvent;
class ReadMessageContentsOnServerLogEvent;
class ReadMessageThreadHistoryOnServerLogEvent;
class ReorderPinnedDialogsOnServerLogEvent;
class ResetAllNotificationSettingsOnServerLogEvent;
class SaveDialogDraftMessageOnServerLogEvent;
@ -1577,8 +1618,9 @@ class MessagesManager : public Actor {
class SendMessageLogEvent;
class SendScreenshotTakenNotificationMessageLogEvent;
class SetDialogFolderIdOnServerLogEvent;
class ToggleDialogIsPinnedOnServerLogEvent;
class ToggleDialogIsBlockedOnServerLogEvent;
class ToggleDialogIsMarkedAsUnreadOnServerLogEvent;
class ToggleDialogIsPinnedOnServerLogEvent;
class UpdateDialogNotificationSettingsOnServerLogEvent;
class UpdateScopeNotificationSettingsOnServerLogEvent;
@ -1638,7 +1680,7 @@ class MessagesManager : public Actor {
static constexpr bool DROP_UPDATES = false;
FullMessageId get_full_message_id(const tl_object_ptr<telegram_api::Message> &message_ptr, bool is_scheduled) const;
static FullMessageId get_full_message_id(const tl_object_ptr<telegram_api::Message> &message_ptr, bool is_scheduled);
static int32 get_message_date(const tl_object_ptr<telegram_api::Message> &message_ptr);
@ -1695,13 +1737,16 @@ class MessagesManager : public Actor {
const unique_ptr<MessageContent> &content, int32 ttl);
static Status can_use_message_send_options(const MessageSendOptions &options, const InputMessageContent &content);
Status can_use_top_thread_message_id(Dialog *d, MessageId top_thread_message_id, MessageId reply_to_message_id);
bool is_anonymous_administrator(DialogId dialog_id) const;
bool is_anonymous_administrator(UserId sender_user_id, DialogId dialog_id, string *author_signature) const;
Message *get_message_to_send(Dialog *d, MessageId reply_to_message_id, const MessageSendOptions &options,
unique_ptr<MessageContent> &&content, bool *need_update_dialog_pos,
unique_ptr<MessageForwardInfo> forward_info = nullptr, bool is_copy = false);
Message *get_message_to_send(Dialog *d, MessageId top_thread_message_id, MessageId reply_to_message_id,
const MessageSendOptions &options, unique_ptr<MessageContent> &&content,
bool *need_update_dialog_pos, unique_ptr<MessageForwardInfo> forward_info = nullptr,
bool is_copy = false);
int64 begin_send_message(DialogId dialog_id, const Message *m);
@ -1726,7 +1771,7 @@ class MessagesManager : public Actor {
static FullMessageId get_replied_message_id(DialogId dialog_id, const Message *m);
MessageId get_reply_to_message_id(Dialog *d, MessageId message_id);
MessageId get_reply_to_message_id(Dialog *d, MessageId top_thread_message_id, MessageId message_id);
static void fix_server_reply_to_message_id(DialogId dialog_id, MessageId message_id, DialogId reply_in_dialog_id,
MessageId &reply_to_message_id);
@ -1747,7 +1792,7 @@ class MessagesManager : public Actor {
bool skip_update_for_not_found_messages);
void do_forward_messages(DialogId to_dialog_id, DialogId from_dialog_id, const vector<Message *> &messages,
const vector<MessageId> &message_ids, uint64 logevent_id);
const vector<MessageId> &message_ids, uint64 log_event_id);
Result<MessageId> forward_message(DialogId to_dialog_id, DialogId from_dialog_id, MessageId message_id,
tl_object_ptr<td_api::messageSendOptions> &&options, bool in_game_share,
@ -1780,22 +1825,22 @@ class MessagesManager : public Actor {
void on_yet_unsent_media_queue_updated(DialogId dialog_id);
void save_send_bot_start_message_logevent(UserId bot_user_id, DialogId dialog_id, const string &parameter,
const Message *m);
void save_send_bot_start_message_log_event(UserId bot_user_id, DialogId dialog_id, const string &parameter,
const Message *m);
void do_send_bot_start_message(UserId bot_user_id, DialogId dialog_id, const string &parameter, const Message *m);
void save_send_inline_query_result_message_logevent(DialogId dialog_id, const Message *m, int64 query_id,
const string &result_id);
void save_send_inline_query_result_message_log_event(DialogId dialog_id, const Message *m, int64 query_id,
const string &result_id);
void do_send_inline_query_result_message(DialogId dialog_id, const Message *m, int64 query_id,
const string &result_id);
uint64 save_send_screenshot_taken_notification_message_logevent(DialogId dialog_id, const Message *m);
uint64 save_send_screenshot_taken_notification_message_log_event(DialogId dialog_id, const Message *m);
void do_send_screenshot_taken_notification_message(DialogId dialog_id, const Message *m, uint64 logevent_id);
void do_send_screenshot_taken_notification_message(DialogId dialog_id, const Message *m, uint64 log_event_id);
Message *continue_send_message(DialogId dialog_id, unique_ptr<Message> &&m, uint64 logevent_id);
Message *continue_send_message(DialogId dialog_id, unique_ptr<Message> &&m, uint64 log_event_id);
bool is_message_unload_enabled() const;
@ -1837,19 +1882,22 @@ class MessagesManager : public Actor {
void delete_message_from_server(DialogId dialog_id, MessageId message_ids, bool revoke);
void delete_messages_from_server(DialogId dialog_id, vector<MessageId> message_ids, bool revoke, uint64 logevent_id,
void delete_messages_from_server(DialogId dialog_id, vector<MessageId> message_ids, bool revoke, uint64 log_event_id,
Promise<Unit> &&promise);
void delete_scheduled_messages_from_server(DialogId dialog_id, vector<MessageId> message_ids, uint64 logevent_id,
void delete_scheduled_messages_from_server(DialogId dialog_id, vector<MessageId> message_ids, uint64 log_event_id,
Promise<Unit> &&promise);
void delete_dialog_history_from_server(DialogId dialog_id, MessageId max_message_id, bool remove_from_dialog_list,
bool revoke, bool allow_error, uint64 logevent_id, Promise<Unit> &&promise);
bool revoke, bool allow_error, uint64 log_event_id, Promise<Unit> &&promise);
void delete_all_channel_messages_from_user_on_server(ChannelId channel_id, UserId user_id, uint64 logevent_id,
void block_dialog_from_replies_on_server(MessageId message_id, bool delete_message, bool delete_all_messages,
bool report_spam, uint64 log_event_id, Promise<Unit> &&promise);
void delete_all_channel_messages_from_user_on_server(ChannelId channel_id, UserId user_id, uint64 log_event_id,
Promise<Unit> &&promise);
void read_all_dialog_mentions_on_server(DialogId dialog_id, uint64 logevent_id, Promise<Unit> &&promise);
void read_all_dialog_mentions_on_server(DialogId dialog_id, uint64 log_event_id, Promise<Unit> &&promise);
static MessageId find_message_by_date(const Message *m, int32 date);
@ -1858,6 +1906,9 @@ class MessagesManager : public Actor {
static void find_messages_from_user(const Message *m, UserId user_id, vector<MessageId> &message_ids);
static void find_incoming_messages_forwarded_from_user(const Message *m, UserId user_id,
vector<MessageId> &message_ids);
static void find_unread_mentions(const Message *m, vector<MessageId> &message_ids);
static void find_old_messages(const Message *m, MessageId max_message_id, vector<MessageId> &message_ids);
@ -1874,6 +1925,8 @@ class MessagesManager : public Actor {
bool is_active_message_reply_info(DialogId dialog_id, const MessageReplyInfo &info) const;
bool is_visible_message_reply_info(DialogId dialog_id, const Message *m) const;
td_api::object_ptr<td_api::messageInteractionInfo> get_message_interaction_info_object(DialogId dialog_id,
const Message *m) const;
@ -1888,8 +1941,8 @@ class MessagesManager : public Actor {
bool read_message_content(Dialog *d, Message *m, bool is_local_read, const char *source);
void read_message_contents_on_server(DialogId dialog_id, vector<MessageId> message_ids, uint64 logevent_id,
Promise<Unit> &&promise, bool skip_logevent = false);
void read_message_contents_on_server(DialogId dialog_id, vector<MessageId> message_ids, uint64 log_event_id,
Promise<Unit> &&promise, bool skip_log_event = false);
bool has_incoming_notification(DialogId dialog_id, const Message *m) const;
@ -1908,9 +1961,16 @@ class MessagesManager : public Actor {
void read_history_on_server(Dialog *d, MessageId max_message_id);
void read_history_on_server_impl(DialogId dialog_id, MessageId max_message_id);
void do_read_history_on_server(DialogId dialog_id);
void on_read_history_finished(DialogId dialog_id, uint64 generation);
void read_history_on_server_impl(Dialog *d, MessageId max_message_id);
void read_message_thread_history_on_server_impl(Dialog *d, MessageId top_thread_message_id, MessageId max_message_id);
void on_read_history_finished(DialogId dialog_id, MessageId top_thread_message_id, uint64 generation);
void read_message_thread_history_on_server(Dialog *d, MessageId top_thread_message_id, MessageId max_message_id,
MessageId last_message_id);
void read_secret_chat_outbox_inner(DialogId dialog_id, int32 up_to_date, int32 read_date);
@ -2028,7 +2088,7 @@ class MessagesManager : public Actor {
NotificationId prev_last_notification_id,
Result<vector<Notification>> result);
void do_delete_message_logevent(const DeleteMessageLogEvent &logevent) const;
void do_delete_message_log_event(const DeleteMessageLogEvent &log_event) const;
void attach_message_to_previous(Dialog *d, MessageId message_id, const char *source);
@ -2212,6 +2272,8 @@ class MessagesManager : public Actor {
void set_dialog_is_marked_as_unread(Dialog *d, bool is_marked_as_unread);
void set_dialog_is_blocked(Dialog *d, bool is_blocked);
void set_dialog_pinned_message_id(Dialog *d, MessageId pinned_message_id);
void repair_dialog_scheduled_messages(Dialog *d);
@ -2226,11 +2288,13 @@ class MessagesManager : public Actor {
void do_set_dialog_folder_id(Dialog *d, FolderId folder_id);
void toggle_dialog_is_pinned_on_server(DialogId dialog_id, bool is_pinned, uint64 logevent_id);
void toggle_dialog_is_pinned_on_server(DialogId dialog_id, bool is_pinned, uint64 log_event_id);
void toggle_dialog_is_marked_as_unread_on_server(DialogId dialog_id, bool is_marked_as_unread, uint64 logevent_id);
void toggle_dialog_is_marked_as_unread_on_server(DialogId dialog_id, bool is_marked_as_unread, uint64 log_event_id);
void reorder_pinned_dialogs_on_server(FolderId folder_id, const vector<DialogId> &dialog_ids, uint64 logevent_id);
void toggle_dialog_is_blocked_on_server(DialogId dialog_id, bool is_blocked, uint64 log_event_id);
void reorder_pinned_dialogs_on_server(FolderId folder_id, const vector<DialogId> &dialog_ids, uint64 log_event_id);
void set_dialog_reply_markup(Dialog *d, MessageId message_id);
@ -2270,7 +2334,7 @@ class MessagesManager : public Actor {
bool update_dialog_silent_send_message(Dialog *d, bool silent_send_message);
bool is_dialog_action_unneded(DialogId dialog_id) const;
bool is_dialog_action_unneeded(DialogId dialog_id) const;
void on_send_dialog_action_timeout(DialogId dialog_id);
@ -2318,7 +2382,7 @@ class MessagesManager : public Actor {
void on_get_dialogs_from_database(FolderId folder_id, int32 limit, DialogDbGetDialogsResult &&dialogs,
Promise<Unit> &&promise);
void send_get_dialog_query(DialogId dialog_id, Promise<Unit> &&promise, uint64 logevent_id = 0);
void send_get_dialog_query(DialogId dialog_id, Promise<Unit> &&promise, uint64 log_event_id = 0);
void send_search_public_dialogs_query(const string &query, Promise<Unit> &&promise);
@ -2478,6 +2542,8 @@ class MessagesManager : public Actor {
void cancel_send_deleted_message(DialogId dialog_id, Message *m, bool is_permanently_deleted);
bool is_discussion_message(DialogId dialog_id, const Message *m) const;
bool has_message_sender_user_id(DialogId dialog_id, const Message *m) const;
static bool get_message_disable_web_page_preview(const Message *m);
@ -2521,6 +2587,11 @@ class MessagesManager : public Actor {
void on_get_message_link_dialog(MessageLinkInfo &&info, Promise<MessageLinkInfo> &&promise);
void on_get_message_link_message(MessageLinkInfo &&info, DialogId dialog_id, Promise<MessageLinkInfo> &&promise);
void on_get_message_link_discussion_message(MessageLinkInfo &&info, DialogId comment_dialog_id,
Promise<MessageLinkInfo> &&promise);
static MessageId get_first_database_message_id_by_index(const Dialog *d, MessageSearchFilter filter);
void on_search_dialog_messages_db_result(int64 random_id, DialogId dialog_id, MessageId from_message_id,
@ -2597,11 +2668,11 @@ class MessagesManager : public Actor {
void on_updated_dialog_notification_settings(DialogId dialog_id, uint64 generation);
void update_scope_notification_settings_on_server(NotificationSettingsScope scope, uint64 logevent_id);
void update_scope_notification_settings_on_server(NotificationSettingsScope scope, uint64 log_event_id);
void reset_all_notification_settings_on_server(uint64 logevent_id);
void reset_all_notification_settings_on_server(uint64 log_event_id);
void change_dialog_report_spam_state_on_server(DialogId dialog_id, bool is_spam_dialog, uint64 logevent_id,
void change_dialog_report_spam_state_on_server(DialogId dialog_id, bool is_spam_dialog, uint64 log_event_id,
Promise<Unit> &&promise);
void set_dialog_folder_id_on_server(DialogId dialog_id, bool from_binlog);
@ -2773,38 +2844,43 @@ class MessagesManager : public Actor {
static void add_message_dependencies(Dependencies &dependencies, DialogId dialog_id, const Message *m);
void save_send_message_logevent(DialogId dialog_id, const Message *m);
void save_send_message_log_event(DialogId dialog_id, const Message *m);
uint64 save_change_dialog_report_spam_state_on_server_logevent(DialogId dialog_id, bool is_spam_dialog);
uint64 save_change_dialog_report_spam_state_on_server_log_event(DialogId dialog_id, bool is_spam_dialog);
uint64 save_delete_messages_from_server_logevent(DialogId dialog_id, const vector<MessageId> &message_ids,
bool revoke);
uint64 save_delete_messages_from_server_log_event(DialogId dialog_id, const vector<MessageId> &message_ids,
bool revoke);
uint64 save_delete_scheduled_messages_from_server_logevent(DialogId dialog_id, const vector<MessageId> &message_ids);
uint64 save_delete_scheduled_messages_from_server_log_event(DialogId dialog_id, const vector<MessageId> &message_ids);
uint64 save_delete_dialog_history_from_server_logevent(DialogId dialog_id, MessageId max_message_id,
bool remove_from_dialog_list, bool revoke);
uint64 save_delete_dialog_history_from_server_log_event(DialogId dialog_id, MessageId max_message_id,
bool remove_from_dialog_list, bool revoke);
uint64 save_delete_all_channel_messages_from_user_on_server_logevent(ChannelId channel_id, UserId user_id);
uint64 save_block_dialog_from_replies_on_server_log_event(MessageId message_id, bool delete_message,
bool delete_all_messages, bool report_spam);
uint64 save_read_all_dialog_mentions_on_server_logevent(DialogId dialog_id);
uint64 save_delete_all_channel_messages_from_user_on_server_log_event(ChannelId channel_id, UserId user_id);
uint64 save_toggle_dialog_is_pinned_on_server_logevent(DialogId dialog_id, bool is_pinned);
uint64 save_read_all_dialog_mentions_on_server_log_event(DialogId dialog_id);
uint64 save_reorder_pinned_dialogs_on_server_logevent(FolderId folder_id, const vector<DialogId> &dialog_ids);
uint64 save_toggle_dialog_is_pinned_on_server_log_event(DialogId dialog_id, bool is_pinned);
uint64 save_toggle_dialog_is_marked_as_unread_on_server_logevent(DialogId dialog_id, bool is_marked_as_unread);
uint64 save_reorder_pinned_dialogs_on_server_log_event(FolderId folder_id, const vector<DialogId> &dialog_ids);
uint64 save_read_message_contents_on_server_logevent(DialogId dialog_id, const vector<MessageId> &message_ids);
uint64 save_toggle_dialog_is_marked_as_unread_on_server_log_event(DialogId dialog_id, bool is_marked_as_unread);
uint64 save_update_scope_notification_settings_on_server_logevent(NotificationSettingsScope scope);
uint64 save_toggle_dialog_is_blocked_on_server_log_event(DialogId dialog_id, bool is_blocked);
uint64 save_reset_all_notification_settings_on_server_logevent();
uint64 save_read_message_contents_on_server_log_event(DialogId dialog_id, const vector<MessageId> &message_ids);
uint64 save_get_dialog_from_server_logevent(DialogId dialog_id);
uint64 save_update_scope_notification_settings_on_server_log_event(NotificationSettingsScope scope);
uint64 save_forward_messages_logevent(DialogId to_dialog_id, DialogId from_dialog_id,
const vector<Message *> &messages, const vector<MessageId> &message_ids);
uint64 save_reset_all_notification_settings_on_server_log_event();
uint64 save_get_dialog_from_server_log_event(DialogId dialog_id);
uint64 save_forward_messages_log_event(DialogId to_dialog_id, DialogId from_dialog_id,
const vector<Message *> &messages, const vector<MessageId> &message_ids);
void suffix_load_loop(Dialog *d);
void suffix_load_update_first_message_id(Dialog *d);
@ -2963,10 +3039,14 @@ class MessagesManager : public Actor {
struct CommonDialogs {
vector<DialogId> dialog_ids;
double received_date = 0;
int32 total_count = 0;
bool is_outdated = false;
};
std::unordered_map<UserId, CommonDialogs, UserIdHash> found_common_dialogs_;
std::unordered_map<int64, std::pair<int32, vector<DialogId>>>
found_blocked_dialogs_; // random_id -> [total_count, [dialog_id]...]
std::unordered_map<int64, FullMessageId> get_dialog_message_by_date_results_;
std::unordered_map<int64, std::pair<int32, vector<MessageId>>>
@ -2993,18 +3073,19 @@ class MessagesManager : public Actor {
std::unordered_map<DialogId, vector<Promise<Unit>>, DialogIdHash> get_dialog_notification_settings_queries_;
std::unordered_map<DialogId, vector<Promise<Unit>>, DialogIdHash> get_dialog_queries_;
std::unordered_map<DialogId, uint64, DialogIdHash> get_dialog_query_logevent_id_;
std::unordered_map<DialogId, uint64, DialogIdHash> get_dialog_query_log_event_id_;
std::unordered_map<FullMessageId, int32, FullMessageIdHash> replied_by_yet_unsent_messages_;
struct ActiveDialogAction {
MessageId top_thread_message_id;
UserId user_id;
int32 action_id;
int32 progress;
double start_time;
ActiveDialogAction(UserId user_id, int32 action_id, double start_time)
: user_id(user_id), action_id(action_id), start_time(start_time) {
ActiveDialogAction(MessageId top_thread_message_id, UserId user_id, int32 action_id, double start_time)
: top_thread_message_id(top_thread_message_id), user_id(user_id), action_id(action_id), start_time(start_time) {
}
};
@ -3038,7 +3119,7 @@ class MessagesManager : public Actor {
vector<Promise<Unit>> dialog_filter_reload_queries_;
std::unordered_map<DialogId, string, DialogIdHash> active_get_channel_differencies_;
std::unordered_map<DialogId, uint64, DialogIdHash> get_channel_difference_to_logevent_id_;
std::unordered_map<DialogId, uint64, DialogIdHash> get_channel_difference_to_log_event_id_;
MultiTimeout channel_get_difference_timeout_{"ChannelGetDifferenceTimeout"};
MultiTimeout channel_get_difference_retry_timeout_{"ChannelGetDifferenceRetryTimeout"};

View File

@ -1658,25 +1658,25 @@ void NotificationManager::on_notification_processed(NotificationId notification_
void NotificationManager::on_notification_removed(NotificationId notification_id) {
VLOG(notifications) << "In on_notification_removed with " << notification_id;
auto add_it = temporary_notification_logevent_ids_.find(notification_id);
if (add_it == temporary_notification_logevent_ids_.end()) {
auto add_it = temporary_notification_log_event_ids_.find(notification_id);
if (add_it == temporary_notification_log_event_ids_.end()) {
return;
}
auto edit_it = temporary_edit_notification_logevent_ids_.find(notification_id);
if (edit_it != temporary_edit_notification_logevent_ids_.end()) {
VLOG(notifications) << "Remove from binlog edit of " << notification_id << " with logevent " << edit_it->second;
auto edit_it = temporary_edit_notification_log_event_ids_.find(notification_id);
if (edit_it != temporary_edit_notification_log_event_ids_.end()) {
VLOG(notifications) << "Remove from binlog edit of " << notification_id << " with log event " << edit_it->second;
if (!is_being_destroyed_) {
binlog_erase(G()->td_db()->get_binlog(), edit_it->second);
}
temporary_edit_notification_logevent_ids_.erase(edit_it);
temporary_edit_notification_log_event_ids_.erase(edit_it);
}
VLOG(notifications) << "Remove from binlog " << notification_id << " with logevent " << add_it->second;
VLOG(notifications) << "Remove from binlog " << notification_id << " with log event " << add_it->second;
if (!is_being_destroyed_) {
binlog_erase(G()->td_db()->get_binlog(), add_it->second);
}
temporary_notification_logevent_ids_.erase(add_it);
temporary_notification_log_event_ids_.erase(add_it);
auto erased_notification_count = temporary_notifications_.erase(temporary_notification_message_ids_[notification_id]);
auto erased_message_id_count = temporary_notification_message_ids_.erase(notification_id);
@ -2366,8 +2366,8 @@ void NotificationManager::on_notification_group_count_max_changed(bool send_upda
return;
}
auto new_max_notification_group_count =
G()->shared_config().get_option_integer("notification_group_count_max", DEFAULT_GROUP_COUNT_MAX);
auto new_max_notification_group_count = narrow_cast<int32>(
G()->shared_config().get_option_integer("notification_group_count_max", DEFAULT_GROUP_COUNT_MAX));
CHECK(MIN_NOTIFICATION_GROUP_COUNT_MAX <= new_max_notification_group_count &&
new_max_notification_group_count <= MAX_NOTIFICATION_GROUP_COUNT_MAX);
@ -2429,8 +2429,8 @@ void NotificationManager::on_notification_group_size_max_changed() {
return;
}
auto new_max_notification_group_size =
G()->shared_config().get_option_integer("notification_group_size_max", DEFAULT_GROUP_SIZE_MAX);
auto new_max_notification_group_size = narrow_cast<int32>(
G()->shared_config().get_option_integer("notification_group_size_max", DEFAULT_GROUP_SIZE_MAX));
CHECK(MIN_NOTIFICATION_GROUP_SIZE_MAX <= new_max_notification_group_size &&
new_max_notification_group_size <= MAX_NOTIFICATION_GROUP_SIZE_MAX);
@ -2512,8 +2512,8 @@ void NotificationManager::on_online_cloud_timeout_changed() {
return;
}
online_cloud_timeout_ms_ =
G()->shared_config().get_option_integer("online_cloud_timeout_ms", DEFAULT_ONLINE_CLOUD_TIMEOUT_MS);
online_cloud_timeout_ms_ = narrow_cast<int32>(
G()->shared_config().get_option_integer("online_cloud_timeout_ms", DEFAULT_ONLINE_CLOUD_TIMEOUT_MS));
VLOG(notifications) << "Set online_cloud_timeout_ms to " << online_cloud_timeout_ms_;
}
@ -2522,8 +2522,8 @@ void NotificationManager::on_notification_cloud_delay_changed() {
return;
}
notification_cloud_delay_ms_ =
G()->shared_config().get_option_integer("notification_cloud_delay_ms", DEFAULT_ONLINE_CLOUD_DELAY_MS);
notification_cloud_delay_ms_ = narrow_cast<int32>(
G()->shared_config().get_option_integer("notification_cloud_delay_ms", DEFAULT_ONLINE_CLOUD_DELAY_MS));
VLOG(notifications) << "Set notification_cloud_delay_ms to " << notification_cloud_delay_ms_;
}
@ -2532,8 +2532,8 @@ void NotificationManager::on_notification_default_delay_changed() {
return;
}
notification_default_delay_ms_ =
G()->shared_config().get_option_integer("notification_default_delay_ms", DEFAULT_DEFAULT_DELAY_MS);
notification_default_delay_ms_ = narrow_cast<int32>(
G()->shared_config().get_option_integer("notification_default_delay_ms", DEFAULT_DEFAULT_DELAY_MS));
VLOG(notifications) << "Set notification_default_delay_ms to " << notification_default_delay_ms_;
}
@ -3551,18 +3551,18 @@ void NotificationManager::add_message_push_notification(DialogId dialog_id, Mess
string sender_name, int32 date, bool is_from_scheduled,
bool contains_mention, bool initial_is_silent, bool is_silent,
string loc_key, string arg, Photo photo, Document document,
NotificationId notification_id, uint64 logevent_id,
NotificationId notification_id, uint64 log_event_id,
Promise<Unit> promise) {
auto is_pinned = begins_with(loc_key, "PINNED_");
auto r_info = td_->messages_manager_->get_message_push_notification_info(
dialog_id, message_id, random_id, sender_user_id, sender_dialog_id, date, is_from_scheduled, contains_mention,
is_pinned, logevent_id != 0);
is_pinned, log_event_id != 0);
if (r_info.is_error()) {
VLOG(notifications) << "Don't need message push notification for " << message_id << "/" << random_id << " from "
<< dialog_id << " sent by " << sender_user_id << "/" << sender_dialog_id << " at " << date
<< ": " << r_info.error();
if (logevent_id != 0) {
binlog_erase(G()->td_db()->get_binlog(), logevent_id);
if (log_event_id != 0) {
binlog_erase(G()->td_db()->get_binlog(), log_event_id);
}
if (r_info.error().code() == 406) {
promise.set_error(r_info.move_as_error());
@ -3580,24 +3580,24 @@ void NotificationManager::add_message_push_notification(DialogId dialog_id, Mess
// TODO support secret chat notifications
// main problem: there is no message_id yet
// also don't forget to delete newSecretChat notification
CHECK(logevent_id == 0);
CHECK(log_event_id == 0);
return promise.set_error(Status::Error(406, "Secret chat push notifications are unsupported"));
}
CHECK(random_id == 0);
if (is_disabled() || max_notification_group_count_ == 0) {
CHECK(logevent_id == 0);
CHECK(log_event_id == 0);
return promise.set_error(Status::Error(200, "Immediate success"));
}
if (!notification_id.is_valid()) {
CHECK(logevent_id == 0);
CHECK(log_event_id == 0);
notification_id = get_next_notification_id();
if (!notification_id.is_valid()) {
return promise.set_value(Unit());
}
} else {
CHECK(logevent_id != 0);
CHECK(log_event_id != 0);
}
if (sender_user_id.is_valid() && !td_->contacts_manager_->have_user_force(sender_user_id)) {
@ -3611,13 +3611,13 @@ void NotificationManager::add_message_push_notification(DialogId dialog_id, Mess
td_->contacts_manager_->on_get_user(std::move(user), "add_message_push_notification");
}
if (logevent_id == 0 && G()->parameters().use_message_db) {
AddMessagePushNotificationLogEvent logevent{
if (log_event_id == 0 && G()->parameters().use_message_db) {
AddMessagePushNotificationLogEvent log_event{
dialog_id, message_id, random_id, sender_user_id, sender_dialog_id, sender_name,
date, is_from_scheduled, contains_mention, initial_is_silent, loc_key, arg,
photo, document, notification_id};
auto storer = LogEventStorerImpl<AddMessagePushNotificationLogEvent>(logevent);
logevent_id = binlog_add(G()->td_db()->get_binlog(), LogEvent::HandlerType::AddMessagePushNotification, storer);
log_event_id = binlog_add(G()->td_db()->get_binlog(), LogEvent::HandlerType::AddMessagePushNotification,
get_log_event_storer(log_event));
}
auto group_id = info.group_id;
@ -3625,9 +3625,9 @@ void NotificationManager::add_message_push_notification(DialogId dialog_id, Mess
bool is_outgoing =
sender_user_id.is_valid() ? td_->contacts_manager_->get_my_id() == sender_user_id : is_from_scheduled;
if (logevent_id != 0) {
VLOG(notifications) << "Register temporary " << notification_id << " with logevent " << logevent_id;
temporary_notification_logevent_ids_[notification_id] = logevent_id;
if (log_event_id != 0) {
VLOG(notifications) << "Register temporary " << notification_id << " with log event " << log_event_id;
temporary_notification_log_event_ids_[notification_id] = log_event_id;
temporary_notifications_[FullMessageId(dialog_id, message_id)] = {group_id, notification_id, sender_user_id,
sender_dialog_id, sender_name, is_outgoing};
temporary_notification_message_ids_[notification_id] = FullMessageId(dialog_id, message_id);
@ -3720,9 +3720,9 @@ class NotificationManager::EditMessagePushNotificationLogEvent {
void NotificationManager::edit_message_push_notification(DialogId dialog_id, MessageId message_id, int32 edit_date,
string loc_key, string arg, Photo photo, Document document,
uint64 logevent_id, Promise<Unit> promise) {
uint64 log_event_id, Promise<Unit> promise) {
if (is_disabled() || max_notification_group_count_ == 0) {
CHECK(logevent_id == 0);
CHECK(log_event_id == 0);
return promise.set_error(Status::Error(200, "Immediate success"));
}
@ -3742,23 +3742,23 @@ void NotificationManager::edit_message_push_notification(DialogId dialog_id, Mes
CHECK(group_id.is_valid());
CHECK(notification_id.is_valid());
if (logevent_id == 0 && G()->parameters().use_message_db) {
EditMessagePushNotificationLogEvent logevent{dialog_id, message_id, edit_date, loc_key, arg, photo, document};
auto storer = LogEventStorerImpl<EditMessagePushNotificationLogEvent>(logevent);
auto &cur_logevent_id = temporary_edit_notification_logevent_ids_[notification_id];
if (cur_logevent_id == 0) {
logevent_id = binlog_add(G()->td_db()->get_binlog(), LogEvent::HandlerType::EditMessagePushNotification, storer);
cur_logevent_id = logevent_id;
VLOG(notifications) << "Add edit message push notification logevent " << logevent_id;
if (log_event_id == 0 && G()->parameters().use_message_db) {
EditMessagePushNotificationLogEvent log_event{dialog_id, message_id, edit_date, loc_key, arg, photo, document};
auto storer = get_log_event_storer(log_event);
auto &cur_log_event_id = temporary_edit_notification_log_event_ids_[notification_id];
if (cur_log_event_id == 0) {
log_event_id = binlog_add(G()->td_db()->get_binlog(), LogEvent::HandlerType::EditMessagePushNotification, storer);
cur_log_event_id = log_event_id;
VLOG(notifications) << "Add edit message push notification log event " << log_event_id;
} else {
auto new_logevent_id = binlog_rewrite(G()->td_db()->get_binlog(), cur_logevent_id,
LogEvent::HandlerType::EditMessagePushNotification, storer);
VLOG(notifications) << "Rewrite edit message push notification logevent " << cur_logevent_id << " with "
<< new_logevent_id;
auto new_log_event_id = binlog_rewrite(G()->td_db()->get_binlog(), cur_log_event_id,
LogEvent::HandlerType::EditMessagePushNotification, storer);
VLOG(notifications) << "Rewrite edit message push notification log event " << cur_log_event_id << " with "
<< new_log_event_id;
}
} else if (logevent_id != 0) {
VLOG(notifications) << "Register edit of temporary " << notification_id << " with logevent " << logevent_id;
temporary_edit_notification_logevent_ids_[notification_id] = logevent_id;
} else if (log_event_id != 0) {
VLOG(notifications) << "Register edit of temporary " << notification_id << " with log event " << log_event_id;
temporary_edit_notification_log_event_ids_[notification_id] = log_event_id;
}
push_notification_promises_[notification_id].push_back(std::move(promise));
@ -4117,7 +4117,7 @@ void NotificationManager::on_binlog_events(vector<BinlogEvent> &&events) {
break;
}
default:
LOG(FATAL) << "Unsupported logevent type " << event.type_;
LOG(FATAL) << "Unsupported log event type " << event.type_;
}
}
if (is_inited_) {

View File

@ -310,10 +310,10 @@ class NotificationManager : public Actor {
DialogId sender_dialog_id, string sender_name, int32 date, bool is_from_scheduled,
bool contains_mention, bool initial_is_silent, bool is_silent, string loc_key,
string arg, Photo photo, Document document, NotificationId notification_id,
uint64 logevent_id, Promise<Unit> promise);
uint64 log_event_id, Promise<Unit> promise);
void edit_message_push_notification(DialogId dialog_id, MessageId message_id, int32 edit_date, string loc_key,
string arg, Photo photo, Document document, uint64 logevent_id,
string arg, Photo photo, Document document, uint64 log_event_id,
Promise<Unit> promise);
void after_get_difference_impl();
@ -382,8 +382,8 @@ class NotificationManager : public Actor {
std::unordered_set<NotificationGroupId, NotificationGroupIdHash> available_call_notification_group_ids_;
std::unordered_map<DialogId, NotificationGroupId, DialogIdHash> dialog_id_to_call_notification_group_id_;
std::unordered_map<NotificationId, uint64, NotificationIdHash> temporary_notification_logevent_ids_;
std::unordered_map<NotificationId, uint64, NotificationIdHash> temporary_edit_notification_logevent_ids_;
std::unordered_map<NotificationId, uint64, NotificationIdHash> temporary_notification_log_event_ids_;
std::unordered_map<NotificationId, uint64, NotificationIdHash> temporary_edit_notification_log_event_ids_;
struct TemporaryNotification {
NotificationGroupId group_id;
NotificationId notification_id;

View File

@ -500,7 +500,7 @@ void PasswordManager::update_password_settings(UpdateSettings update_settings, P
auto password = update_settings.current_password;
get_full_state(
std::move(password),
PromiseCreator::lambda([=, actor_id = actor_id(this), result_promise = std::move(result_promise),
PromiseCreator::lambda([actor_id = actor_id(this), result_promise = std::move(result_promise),
update_settings = std::move(update_settings)](Result<PasswordFullState> r_state) mutable {
if (r_state.is_error()) {
return result_promise.set_error(r_state.move_as_error());

View File

@ -223,7 +223,7 @@ class StopPollActor : public NetActorOnce {
}
auto result = result_ptr.move_as_ok();
LOG(INFO) << "Receive result for stopPoll: " << to_string(result);
LOG(INFO) << "Receive result for StopPollQuery: " << to_string(result);
td->updates_manager_->on_get_updates(std::move(result));
promise_.set_value(Unit());
@ -749,7 +749,7 @@ class PollManager::SetPollAnswerLogEvent {
};
void PollManager::do_set_poll_answer(PollId poll_id, FullMessageId full_message_id, vector<string> &&options,
uint64 logevent_id, Promise<Unit> &&promise) {
uint64 log_event_id, Promise<Unit> &&promise) {
LOG(INFO) << "Set answer in " << poll_id << " from " << full_message_id;
auto &pending_answer = pending_answers_[poll_id];
if (!pending_answer.promises_.empty() && pending_answer.options_ == options) {
@ -757,27 +757,27 @@ void PollManager::do_set_poll_answer(PollId poll_id, FullMessageId full_message_
return;
}
if (pending_answer.logevent_id_ != 0 && logevent_id != 0) {
LOG(ERROR) << "Duplicate SetPollAnswer log event: " << pending_answer.logevent_id_ << " and " << logevent_id;
binlog_erase(G()->td_db()->get_binlog(), logevent_id);
if (pending_answer.log_event_id_ != 0 && log_event_id != 0) {
LOG(ERROR) << "Duplicate SetPollAnswer log event: " << pending_answer.log_event_id_ << " and " << log_event_id;
binlog_erase(G()->td_db()->get_binlog(), log_event_id);
return;
}
if (logevent_id == 0 && G()->parameters().use_message_db) {
SetPollAnswerLogEvent logevent;
logevent.poll_id_ = poll_id;
logevent.full_message_id_ = full_message_id;
logevent.options_ = options;
auto storer = LogEventStorerImpl<SetPollAnswerLogEvent>(logevent);
if (log_event_id == 0 && G()->parameters().use_message_db) {
SetPollAnswerLogEvent log_event;
log_event.poll_id_ = poll_id;
log_event.full_message_id_ = full_message_id;
log_event.options_ = options;
auto storer = get_log_event_storer(log_event);
if (pending_answer.generation_ == 0) {
CHECK(pending_answer.logevent_id_ == 0);
logevent_id = binlog_add(G()->td_db()->get_binlog(), LogEvent::HandlerType::SetPollAnswer, storer);
LOG(INFO) << "Add set poll answer logevent " << logevent_id;
CHECK(pending_answer.log_event_id_ == 0);
log_event_id = binlog_add(G()->td_db()->get_binlog(), LogEvent::HandlerType::SetPollAnswer, storer);
LOG(INFO) << "Add set poll answer log event " << log_event_id;
} else {
CHECK(pending_answer.logevent_id_ != 0);
logevent_id = pending_answer.logevent_id_;
auto new_logevent_id = binlog_rewrite(G()->td_db()->get_binlog(), pending_answer.logevent_id_,
LogEvent::HandlerType::SetPollAnswer, storer);
LOG(INFO) << "Rewrite set poll answer logevent " << logevent_id << " with " << new_logevent_id;
CHECK(pending_answer.log_event_id_ != 0);
log_event_id = pending_answer.log_event_id_;
auto new_log_event_id = binlog_rewrite(G()->td_db()->get_binlog(), pending_answer.log_event_id_,
LogEvent::HandlerType::SetPollAnswer, storer);
LOG(INFO) << "Rewrite set poll answer log event " << log_event_id << " with " << new_log_event_id;
}
}
@ -803,7 +803,7 @@ void PollManager::do_set_poll_answer(PollId poll_id, FullMessageId full_message_
pending_answer.options_ = std::move(options);
pending_answer.promises_.push_back(std::move(promise));
pending_answer.generation_ = generation;
pending_answer.logevent_id_ = logevent_id;
pending_answer.log_event_id_ = log_event_id;
notify_on_poll_update(poll_id);
@ -833,9 +833,9 @@ void PollManager::on_set_poll_answer(PollId poll_id, uint64 generation,
return;
}
if (pending_answer.logevent_id_ != 0) {
LOG(INFO) << "Delete set poll answer logevent " << pending_answer.logevent_id_;
binlog_erase(G()->td_db()->get_binlog(), pending_answer.logevent_id_);
if (pending_answer.log_event_id_ != 0) {
LOG(INFO) << "Delete set poll answer log event " << pending_answer.log_event_id_;
binlog_erase(G()->td_db()->get_binlog(), pending_answer.log_event_id_);
}
auto promises = std::move(pending_answer.promises_);
@ -1104,17 +1104,17 @@ class PollManager::StopPollLogEvent {
};
void PollManager::do_stop_poll(PollId poll_id, FullMessageId full_message_id, unique_ptr<ReplyMarkup> &&reply_markup,
uint64 logevent_id, Promise<Unit> &&promise) {
uint64 log_event_id, Promise<Unit> &&promise) {
LOG(INFO) << "Stop " << poll_id << " from " << full_message_id;
if (logevent_id == 0 && G()->parameters().use_message_db && reply_markup == nullptr) {
StopPollLogEvent logevent{poll_id, full_message_id};
auto storer = LogEventStorerImpl<StopPollLogEvent>(logevent);
logevent_id = binlog_add(G()->td_db()->get_binlog(), LogEvent::HandlerType::StopPoll, storer);
if (log_event_id == 0 && G()->parameters().use_message_db && reply_markup == nullptr) {
StopPollLogEvent log_event{poll_id, full_message_id};
log_event_id =
binlog_add(G()->td_db()->get_binlog(), LogEvent::HandlerType::StopPoll, get_log_event_storer(log_event));
}
bool is_inserted = being_closed_polls_.insert(poll_id).second;
CHECK(is_inserted);
auto new_promise = get_erase_logevent_promise(logevent_id, std::move(promise));
auto new_promise = get_erase_log_event_promise(log_event_id, std::move(promise));
send_closure(td_->create_net_actor<StopPollActor>(std::move(new_promise)), &StopPollActor::send, full_message_id,
std::move(reply_markup));
@ -1678,7 +1678,7 @@ void PollManager::on_binlog_events(vector<BinlogEvent> &&events) {
break;
}
default:
LOG(FATAL) << "Unsupported logevent type " << event.type_;
LOG(FATAL) << "Unsupported log event type " << event.type_;
}
}
}

View File

@ -181,7 +181,7 @@ class PollManager : public Actor {
void on_get_poll_results(PollId poll_id, uint64 generation, Result<tl_object_ptr<telegram_api::Updates>> result);
void do_set_poll_answer(PollId poll_id, FullMessageId full_message_id, vector<string> &&options, uint64 logevent_id,
void do_set_poll_answer(PollId poll_id, FullMessageId full_message_id, vector<string> &&options, uint64 log_event_id,
Promise<Unit> &&promise);
void on_set_poll_answer(PollId poll_id, uint64 generation, Result<tl_object_ptr<telegram_api::Updates>> &&result);
@ -196,7 +196,7 @@ class PollManager : public Actor {
Result<tl_object_ptr<telegram_api::messages_votesList>> &&result);
void do_stop_poll(PollId poll_id, FullMessageId full_message_id, unique_ptr<ReplyMarkup> &&reply_markup,
uint64 logevent_id, Promise<Unit> &&promise);
uint64 log_event_id, Promise<Unit> &&promise);
MultiTimeout update_poll_timeout_{"UpdatePollTimeout"};
MultiTimeout close_poll_timeout_{"ClosePollTimeout"};
@ -211,7 +211,7 @@ class PollManager : public Actor {
vector<string> options_;
vector<Promise<Unit>> promises_;
uint64 generation_ = 0;
uint64 logevent_id_ = 0;
uint64 log_event_id_ = 0;
NetQueryRef query_ref_;
};
std::unordered_map<PollId, PendingPollAnswer, PollIdHash> pending_answers_;

View File

@ -66,8 +66,8 @@ void store(const ReplyMarkup &reply_markup, StorerT &storer) {
template <class ParserT>
void parse(ReplyMarkup &reply_markup, ParserT &parser) {
bool has_keyboard = !reply_markup.keyboard.empty();
bool has_inline_keyboard = !reply_markup.inline_keyboard.empty();
bool has_keyboard;
bool has_inline_keyboard;
BEGIN_PARSE_FLAGS();
PARSE_FLAG(reply_markup.is_personal);
PARSE_FLAG(reply_markup.need_resize_keyboard);

View File

@ -96,11 +96,11 @@ void SecretChatActor::create_chat(int32 user_id, int64 user_access_hash, int32 r
return;
}
auto event = make_unique<logevent::CreateSecretChat>();
auto event = make_unique<log_event::CreateSecretChat>();
event->user_id = user_id;
event->user_access_hash = user_access_hash;
event->random_id = random_id;
event->set_logevent_id(binlog_add(context_->binlog(), LogEvent::HandlerType::SecretChats, create_storer(*event)));
event->set_log_event_id(binlog_add(context_->binlog(), LogEvent::HandlerType::SecretChats, create_storer(*event)));
do_create_chat_impl(std::move(event));
promise.set_value(SecretChatId(random_id));
loop();
@ -139,18 +139,18 @@ void SecretChatActor::on_result_resendable(NetQueryPtr net_query, Promise<NetQue
loop();
}
void SecretChatActor::replay_close_chat(unique_ptr<logevent::CloseSecretChat> event) {
void SecretChatActor::replay_close_chat(unique_ptr<log_event::CloseSecretChat> event) {
do_close_chat_impl(std::move(event));
}
void SecretChatActor::replay_create_chat(unique_ptr<logevent::CreateSecretChat> event) {
void SecretChatActor::replay_create_chat(unique_ptr<log_event::CreateSecretChat> event) {
if (close_flag_) {
return;
}
do_create_chat_impl(std::move(event));
}
void SecretChatActor::add_inbound_message(unique_ptr<logevent::InboundSecretMessage> message) {
void SecretChatActor::add_inbound_message(unique_ptr<log_event::InboundSecretMessage> message) {
SCOPE_EXIT {
if (message) {
message->promise.set_value(Unit());
@ -167,7 +167,7 @@ void SecretChatActor::add_inbound_message(unique_ptr<logevent::InboundSecretMess
loop();
}
void SecretChatActor::replay_inbound_message(unique_ptr<logevent::InboundSecretMessage> message) {
void SecretChatActor::replay_inbound_message(unique_ptr<log_event::InboundSecretMessage> message) {
if (close_flag_) {
return;
}
@ -190,7 +190,7 @@ void SecretChatActor::replay_inbound_message(unique_ptr<logevent::InboundSecretM
loop();
}
void SecretChatActor::replay_outbound_message(unique_ptr<logevent::OutboundSecretMessage> message) {
void SecretChatActor::replay_outbound_message(unique_ptr<log_event::OutboundSecretMessage> message) {
if (close_flag_) {
return;
}
@ -331,10 +331,10 @@ void SecretChatActor::send_message_impl(tl_object_ptr<secret_api::DecryptedMessa
return on_outbound_outer_send_message_promise(it->second, std::move(promise));
}
auto binlog_event = make_unique<logevent::OutboundSecretMessage>();
auto binlog_event = make_unique<log_event::OutboundSecretMessage>();
binlog_event->chat_id = auth_state_.id;
binlog_event->random_id = random_id;
binlog_event->file = logevent::EncryptedInputFile::from_input_encrypted_file(file);
binlog_event->file = log_event::EncryptedInputFile::from_input_encrypted_file(file);
binlog_event->message_id = seq_no_state_.message_id + 1;
binlog_event->my_in_seq_no = seq_no_state_.my_in_seq_no;
binlog_event->my_out_seq_no = seq_no_state_.my_out_seq_no + 1;
@ -719,23 +719,23 @@ void SecretChatActor::cancel_chat(Promise<> promise) {
}
close_flag_ = true;
std::vector<logevent::LogEvent::Id> to_delete;
std::vector<log_event::LogEvent::Id> to_delete;
outbound_message_states_.for_each(
[&](auto state_id, auto &state) { to_delete.push_back(state.message->logevent_id()); });
inbound_message_states_.for_each([&](auto state_id, auto &state) { to_delete.push_back(state.logevent_id); });
[&](auto state_id, auto &state) { to_delete.push_back(state.message->log_event_id()); });
inbound_message_states_.for_each([&](auto state_id, auto &state) { to_delete.push_back(state.log_event_id); });
// TODO: It must be a transaction
for (auto id : to_delete) {
binlog_erase(context_->binlog(), id);
}
if (create_logevent_id_ != 0) {
binlog_erase(context_->binlog(), create_logevent_id_);
create_logevent_id_ = 0;
if (create_log_event_id_ != 0) {
binlog_erase(context_->binlog(), create_log_event_id_);
create_log_event_id_ = 0;
}
auto event = make_unique<logevent::CloseSecretChat>();
auto event = make_unique<log_event::CloseSecretChat>();
event->chat_id = auth_state_.id;
event->set_logevent_id(binlog_add(context_->binlog(), LogEvent::HandlerType::SecretChats, create_storer(*event)));
event->set_log_event_id(binlog_add(context_->binlog(), LogEvent::HandlerType::SecretChats, create_storer(*event)));
auto on_sync = PromiseCreator::lambda(
[actor_id = actor_id(this), event = std::move(event), promise = std::move(promise)](Result<Unit> result) mutable {
@ -752,9 +752,9 @@ void SecretChatActor::cancel_chat(Promise<> promise) {
yield();
}
void SecretChatActor::do_close_chat_impl(unique_ptr<logevent::CloseSecretChat> event) {
void SecretChatActor::do_close_chat_impl(unique_ptr<log_event::CloseSecretChat> event) {
close_flag_ = true;
close_logevent_id_ = event->logevent_id();
close_log_event_id_ = event->log_event_id();
LOG(INFO) << "Send messages.discardEncryption";
auth_state_.state = State::Closed;
context_->secret_chat_db()->set_value(auth_state_);
@ -768,10 +768,10 @@ void SecretChatActor::do_close_chat_impl(unique_ptr<logevent::CloseSecretChat> e
context_->send_net_query(std::move(query), actor_shared(this), true);
}
void SecretChatActor::do_create_chat_impl(unique_ptr<logevent::CreateSecretChat> event) {
void SecretChatActor::do_create_chat_impl(unique_ptr<log_event::CreateSecretChat> event) {
LOG(INFO) << *event;
CHECK(event->random_id == auth_state_.id);
create_logevent_id_ = event->logevent_id();
create_log_event_id_ = event->log_event_id();
if (auth_state_.state == State::Empty) {
auth_state_.user_id = event->user_id;
@ -784,19 +784,19 @@ void SecretChatActor::do_create_chat_impl(unique_ptr<logevent::CreateSecretChat>
} else if (auth_state_.state == State::SendRequest) {
} else if (auth_state_.state == State::WaitRequestResponse) {
} else {
binlog_erase(context_->binlog(), create_logevent_id_);
create_logevent_id_ = 0;
binlog_erase(context_->binlog(), create_log_event_id_);
create_log_event_id_ = 0;
}
}
void SecretChatActor::on_discard_encryption_result(NetQueryPtr result) {
CHECK(close_flag_);
CHECK(close_logevent_id_ != 0);
CHECK(close_log_event_id_ != 0);
if (context_->close_flag()) {
return;
}
LOG(INFO) << "Got result for messages.discardEncryption";
context_->secret_chat_db()->erase_value(auth_state_);
binlog_erase(context_->binlog(), close_logevent_id_);
binlog_erase(context_->binlog(), close_log_event_id_);
// skip flush
stop();
}
@ -877,7 +877,7 @@ Result<std::tuple<uint64, BufferSlice, int32>> SecretChatActor::decrypt(BufferSl
}
}
Status SecretChatActor::do_inbound_message_encrypted(unique_ptr<logevent::InboundSecretMessage> message) {
Status SecretChatActor::do_inbound_message_encrypted(unique_ptr<log_event::InboundSecretMessage> message) {
SCOPE_EXIT {
if (message) {
message->promise.set_value(Unit());
@ -970,7 +970,7 @@ Status SecretChatActor::check_seq_no(int in_seq_no, int out_seq_no, int32 his_la
return Status::OK();
}
Status SecretChatActor::do_inbound_message_decrypted_unchecked(unique_ptr<logevent::InboundSecretMessage> message) {
Status SecretChatActor::do_inbound_message_decrypted_unchecked(unique_ptr<log_event::InboundSecretMessage> message) {
SCOPE_EXIT {
CHECK(message == nullptr || !message->promise);
};
@ -979,9 +979,9 @@ Status SecretChatActor::do_inbound_message_decrypted_unchecked(unique_ptr<logeve
auto status = check_seq_no(in_seq_no, out_seq_no, message->his_layer());
if (status.is_error() && status.code() != 2 /* not gap found */) {
message->promise.set_value(Unit());
if (message->logevent_id()) {
LOG(INFO) << "Erase binlog event: " << tag("logevent_id", message->logevent_id());
binlog_erase(context_->binlog(), message->logevent_id());
if (message->log_event_id()) {
LOG(INFO) << "Erase binlog event: " << tag("log_event_id", message->log_event_id());
binlog_erase(context_->binlog(), message->log_event_id());
}
auto warning_message = PSTRING() << status << tag("seq_no_state_.my_in_seq_no", seq_no_state_.my_in_seq_no)
<< tag("seq_no_state_.my_out_seq_no", seq_no_state_.my_out_seq_no)
@ -1049,7 +1049,7 @@ Status SecretChatActor::do_inbound_message_decrypted_unchecked(unique_ptr<logeve
return do_inbound_message_decrypted(std::move(message));
}
void SecretChatActor::do_outbound_message_impl(unique_ptr<logevent::OutboundSecretMessage> binlog_event,
void SecretChatActor::do_outbound_message_impl(unique_ptr<log_event::OutboundSecretMessage> binlog_event,
Promise<> promise) {
binlog_event->crc = crc64(binlog_event->encrypted_message.as_slice());
LOG(INFO) << "Do outbound message: " << *binlog_event << tag("crc", binlog_event->crc);
@ -1064,13 +1064,13 @@ void SecretChatActor::do_outbound_message_impl(unique_ptr<logevent::OutboundSecr
// OutboundSecretMessage
//
// 1. [] => Save logevent. [save_logevent]
// 2. [save_logevent] => Save SeqNoState [save_changes]
// 3. [save_logevent] => Send NetQuery [send_message]
// 1. [] => Save log_event. [save_log_event]
// 2. [save_log_event] => Save SeqNoState [save_changes]
// 3. [save_log_event] => Send NetQuery [send_message]
// Note: we have to force binlog to flush
// 4.0 [send_message]:Fail => rewrite
// 4. [save_changes; send_message] => Mark logevent as sent [rewrite_logevent]
// 5. [save_changes; send_message; ack] => [remove_logevent]
// 4. [save_changes; send_message] => Mark log event as sent [rewrite_log_event]
// 5. [save_changes; send_message; ack] => [remove_log_event]
auto message = state->message.get();
@ -1112,20 +1112,20 @@ void SecretChatActor::do_outbound_message_impl(unique_ptr<logevent::OutboundSecr
out_seq_no_to_outbound_message_state_token_[out_seq_no] = state_id;
}
// save_logevent => [send_message; save_changes]
auto save_logevent_finish = PromiseCreator::join(std::move(send_message_start), std::move(save_changes_start));
// save_log_event => [send_message; save_changes]
auto save_log_event_finish = PromiseCreator::join(std::move(send_message_start), std::move(save_changes_start));
auto logevent_id = state->message->logevent_id();
if (logevent_id == 0) {
logevent_id = binlog_add(context_->binlog(), LogEvent::HandlerType::SecretChats, create_storer(*state->message));
LOG(INFO) << "Outbound secret message [save_logevent] start " << tag("logevent_id", logevent_id);
context_->binlog()->force_sync(std::move(save_logevent_finish));
state->message->set_logevent_id(logevent_id);
auto log_event_id = state->message->log_event_id();
if (log_event_id == 0) {
log_event_id = binlog_add(context_->binlog(), LogEvent::HandlerType::SecretChats, create_storer(*state->message));
LOG(INFO) << "Outbound secret message [save_log_event] start " << tag("log_event_id", log_event_id);
context_->binlog()->force_sync(std::move(save_log_event_finish));
state->message->set_log_event_id(log_event_id);
} else {
LOG(INFO) << "Outbound secret message [save_logevent] skip " << tag("logevent_id", logevent_id);
save_logevent_finish.set_value(Unit());
LOG(INFO) << "Outbound secret message [save_log_event] skip " << tag("log_event_id", log_event_id);
save_log_event_finish.set_value(Unit());
}
promise.set_value(Unit()); // logevent was sent to binlog;
promise.set_value(Unit()); // log event was sent to binlog
}
void SecretChatActor::on_his_in_seq_no_updated() {
@ -1197,66 +1197,66 @@ void SecretChatActor::update_seq_no_state(const T &new_seq_no_state) {
return on_seq_no_state_changed();
}
void SecretChatActor::do_inbound_message_decrypted_pending(unique_ptr<logevent::InboundSecretMessage> message) {
// Just save logevent if necessary
auto logevent_id = message->logevent_id();
void SecretChatActor::do_inbound_message_decrypted_pending(unique_ptr<log_event::InboundSecretMessage> message) {
// Just save log event if necessary
auto log_event_id = message->log_event_id();
// qts
auto qts_promise = std::move(message->promise);
if (logevent_id == 0) {
if (log_event_id == 0) {
message->is_pending = true;
message->set_logevent_id(binlog_add(context_->binlog(), LogEvent::HandlerType::SecretChats, create_storer(*message),
std::move(qts_promise)));
LOG(INFO) << "Inbound PENDING secret message [save_logevent] start (do not expect finish) "
<< tag("logevent_id", message->logevent_id());
message->set_log_event_id(binlog_add(context_->binlog(), LogEvent::HandlerType::SecretChats,
create_storer(*message), std::move(qts_promise)));
LOG(INFO) << "Inbound PENDING secret message [save_log_event] start (do not expect finish) "
<< tag("log_event_id", message->log_event_id());
} else {
LOG(INFO) << "Inbound PENDING secret message [save_logevent] skip " << tag("logevent_id", logevent_id);
LOG(INFO) << "Inbound PENDING secret message [save_log_event] skip " << tag("log_event_id", log_event_id);
CHECK(!qts_promise);
}
LOG(INFO) << "Inbound PENDING secret message start " << tag("logevent_id", logevent_id) << tag("message", *message);
LOG(INFO) << "Inbound PENDING secret message start " << tag("log_event_id", log_event_id) << tag("message", *message);
auto seq_no = message->decrypted_message_layer->out_seq_no_ / 2;
pending_inbound_messages_[seq_no] = std::move(message);
}
Status SecretChatActor::do_inbound_message_decrypted(unique_ptr<logevent::InboundSecretMessage> message) {
Status SecretChatActor::do_inbound_message_decrypted(unique_ptr<log_event::InboundSecretMessage> message) {
// InboundSecretMessage
//
// 1. [] => Add logevent. [save_logevent]
// 2. [save_logevent] => Save SeqNoState [save_changes]
// 3. [save_logevent] => Add message to MessageManager [save_message]
// Note: if we are able to add message by random_id, we may not wait for (logevent). Otherwise we should force
// 1. [] => Add log event. [save_log_event]
// 2. [save_log_event] => Save SeqNoState [save_changes]
// 3. [save_log_event] => Add message to MessageManager [save_message]
// Note: if we are able to add message by random_id, we may not wait for (log event). Otherwise we should force
// binlog flush.
// 4. [save_logevent] => Update qts [qts]
// 5. [save_changes; save_message; ?qts) => Remove logevent [remove_logevent]
// 4. [save_log_event] => Update qts [qts]
// 5. [save_changes; save_message; ?qts) => Remove log event [remove_log_event]
// Note: It is easier not to wait for qts. In the worst case old update will be handled again after restart.
auto state_id = inbound_message_states_.create();
InboundMessageState &state = *inbound_message_states_.get(state_id);
// save logevent
auto logevent_id = message->logevent_id();
// save log event
auto log_event_id = message->log_event_id();
bool need_sync = false;
if (logevent_id == 0) {
logevent_id = binlog_add(context_->binlog(), LogEvent::HandlerType::SecretChats, create_storer(*message));
LOG(INFO) << "Inbound secret message [save_logevent] start " << tag("logevent_id", logevent_id);
if (log_event_id == 0) {
log_event_id = binlog_add(context_->binlog(), LogEvent::HandlerType::SecretChats, create_storer(*message));
LOG(INFO) << "Inbound secret message [save_log_event] start " << tag("log_event_id", log_event_id);
need_sync = true;
} else {
if (message->is_pending) {
message->is_pending = false;
auto old_logevent_id = logevent_id;
logevent_id = binlog_add(context_->binlog(), LogEvent::HandlerType::SecretChats, create_storer(*message));
binlog_erase(context_->binlog(), old_logevent_id);
LOG(INFO) << "Inbound secret message [save_logevent] rewrite (after pending state) "
<< tag("logevent_id", logevent_id) << tag("old_logevent_id", old_logevent_id);
auto old_log_event_id = log_event_id;
log_event_id = binlog_add(context_->binlog(), LogEvent::HandlerType::SecretChats, create_storer(*message));
binlog_erase(context_->binlog(), old_log_event_id);
LOG(INFO) << "Inbound secret message [save_log_event] rewrite (after pending state) "
<< tag("log_event_id", log_event_id) << tag("old_log_event_id", old_log_event_id);
need_sync = true;
} else {
LOG(INFO) << "Inbound secret message [save_logevent] skip " << tag("logevent_id", logevent_id);
LOG(INFO) << "Inbound secret message [save_log_event] skip " << tag("log_event_id", log_event_id);
}
}
LOG(INFO) << "Inbound secret message start " << tag("logevent_id", logevent_id) << tag("message", *message);
state.logevent_id = logevent_id;
LOG(INFO) << "Inbound secret message start " << tag("log_event_id", log_event_id) << tag("message", *message);
state.log_event_id = log_event_id;
// save_message
auto save_message_finish = PromiseCreator::lambda([actor_id = actor_id(this), state_id](Result<> result) {
@ -1305,7 +1305,7 @@ Status SecretChatActor::do_inbound_message_decrypted(unique_ptr<logevent::Inboun
// Send update through context_
// Note, that update may be sent multiple times and should be somehow protected from replay.
// Luckily all updates seems to be idempotent.
// We could use ChangesProcessor to mark logevent as sent to context_, but I don't see any advantages of this
// We could use ChangesProcessor to mark log event as sent to context_, but I don't see any advantages of this
// approach.
if (message->decrypted_message_layer->message_->get_id() == secret_api::decryptedMessage::ID) {
auto decrypted_message =
@ -1319,7 +1319,7 @@ Status SecretChatActor::do_inbound_message_decrypted(unique_ptr<logevent::Inboun
auto action = std::move(decrypted_message_service->action_);
switch (action->get_id()) {
case secret_api::decryptedMessageActionDeleteMessages::ID:
// Corresponding logevent won't be deleted before promise returned by add_changes is set.
// Corresponding log event won't be deleted before promise returned by add_changes is set.
context_->on_delete_messages(
static_cast<const secret_api::decryptedMessageActionDeleteMessages &>(*action).random_ids_,
std::move(save_message_finish));
@ -1385,13 +1385,13 @@ decryptedMessageActionNoop#a82fdd63 = DecryptedMessageAction;
});
auto save_changes_start = add_changes(std::move(save_changes_finish));
// save_logevent
auto save_logevent_finish = PromiseCreator::join(std::move(save_changes_start), std::move(qts_promise));
// save_log_event
auto save_log_event_finish = PromiseCreator::join(std::move(save_changes_start), std::move(qts_promise));
if (need_sync) {
// TODO: lazy sync is enough
context_->binlog()->force_sync(std::move(save_logevent_finish));
context_->binlog()->force_sync(std::move(save_log_event_finish));
} else {
save_logevent_finish.set_value(Unit());
save_log_event_finish.set_value(Unit());
}
return Status::OK();
}
@ -1433,7 +1433,7 @@ void SecretChatActor::on_inbound_save_message_finish(uint64 state_id) {
}
auto *state = inbound_message_states_.get(state_id);
CHECK(state);
LOG(INFO) << "Inbound message [save_message] finish " << tag("logevent_id", state->logevent_id);
LOG(INFO) << "Inbound message [save_message] finish " << tag("log_event_id", state->log_event_id);
state->save_message_finish = true;
inbound_loop(state, state_id);
}
@ -1444,7 +1444,7 @@ void SecretChatActor::on_inbound_save_changes_finish(uint64 state_id) {
}
auto *state = inbound_message_states_.get(state_id);
CHECK(state);
LOG(INFO) << "Inbound message [save_changes] finish " << tag("logevent_id", state->logevent_id);
LOG(INFO) << "Inbound message [save_changes] finish " << tag("log_event_id", state->log_event_id);
state->save_changes_finish = true;
inbound_loop(state, state_id);
}
@ -1456,13 +1456,13 @@ void SecretChatActor::inbound_loop(InboundMessageState *state, uint64 state_id)
if (!state->save_changes_finish || !state->save_message_finish) {
return;
}
LOG(INFO) << "Inbound message [remove_logevent] start " << tag("logevent_id", state->logevent_id);
binlog_erase(context_->binlog(), state->logevent_id);
LOG(INFO) << "Inbound message [remove_log_event] start " << tag("log_event_id", state->log_event_id);
binlog_erase(context_->binlog(), state->log_event_id);
inbound_message_states_.erase(state_id);
}
NetQueryPtr SecretChatActor::create_net_query(const logevent::OutboundSecretMessage &message) {
NetQueryPtr SecretChatActor::create_net_query(const log_event::OutboundSecretMessage &message) {
NetQueryPtr query;
if (message.need_notify_user) {
CHECK(message.file.empty());
@ -1510,14 +1510,14 @@ void SecretChatActor::on_outbound_send_message_start(uint64 state_id) {
auto *message = state->message.get();
if (!message->is_sent) {
LOG(INFO) << "Outbound message [send_message] start " << tag("logevent_id", state->message->logevent_id());
LOG(INFO) << "Outbound message [send_message] start " << tag("log_event_id", state->message->log_event_id());
auto query = create_net_query(*message);
state->net_query_id = query->id();
state->net_query_ref = query.get_weak();
state->net_query_may_fail = state->message->is_rewritable;
context_->send_net_query(std::move(query), actor_shared(this, state_id), true);
} else {
LOG(INFO) << "Outbound message [send_message] start dummy " << tag("logevent_id", state->message->logevent_id());
LOG(INFO) << "Outbound message [send_message] start dummy " << tag("log_event_id", state->message->log_event_id());
on_outbound_send_message_finish(state_id);
}
}
@ -1532,10 +1532,10 @@ void SecretChatActor::outbound_resend(uint64 state_id) {
state->message->is_sent = false;
state->net_query_id = 0;
state->net_query_ref = NetQueryRef();
LOG(INFO) << "Outbound message [resend] " << tag("logevent_id", state->message->logevent_id())
LOG(INFO) << "Outbound message [resend] " << tag("log_event_id", state->message->log_event_id())
<< tag("state_id", state_id);
binlog_rewrite(context_->binlog(), state->message->logevent_id(), LogEvent::HandlerType::SecretChats,
binlog_rewrite(context_->binlog(), state->message->log_event_id(), LogEvent::HandlerType::SecretChats,
create_storer(*state->message));
auto send_message_start = PromiseCreator::lambda([actor_id = actor_id(this), state_id](Result<> result) {
if (result.is_ok()) {
@ -1574,8 +1574,8 @@ Status SecretChatActor::outbound_rewrite_with_empty(uint64 state_id) {
state->message->is_external = false;
state->message->need_notify_user = false;
state->message->is_silent = true;
state->message->file = logevent::EncryptedInputFile::from_input_encrypted_file(nullptr);
binlog_rewrite(context_->binlog(), state->message->logevent_id(), LogEvent::HandlerType::SecretChats,
state->message->file = log_event::EncryptedInputFile::from_input_encrypted_file(nullptr);
binlog_rewrite(context_->binlog(), state->message->log_event_id(), LogEvent::HandlerType::SecretChats,
create_storer(*state->message));
return Status::OK();
}
@ -1593,7 +1593,7 @@ void SecretChatActor::on_outbound_send_message_result(NetQueryPtr query, Promise
}
CHECK(state);
if (state->net_query_id != query->id()) {
LOG(INFO) << "Ignore old net query result " << tag("logevent_id", state->message->logevent_id())
LOG(INFO) << "Ignore old net query result " << tag("log_event_id", state->message->log_event_id())
<< tag("query_id", query->id()) << tag("state_query_id", state->net_query_id) << query;
query->clear();
return;
@ -1620,7 +1620,7 @@ void SecretChatActor::on_outbound_send_message_result(NetQueryPtr query, Promise
if (state->message->is_external) {
LOG(INFO) << "Outbound secret message [send_message] failed, rewrite it with dummy "
<< tag("logevent_id", state->message->logevent_id()) << tag("error", error);
<< tag("log_event_id", state->message->log_event_id()) << tag("error", error);
state->send_result_ = [this, random_id = state->message->random_id, error_code = error.code(),
error_message = error.message()](Promise<> promise) {
this->context_->on_send_message_error(random_id, Status::Error(error_code, error_message), std::move(promise));
@ -1629,7 +1629,7 @@ void SecretChatActor::on_outbound_send_message_result(NetQueryPtr query, Promise
} else {
// Just resend.
LOG(INFO) << "Outbound secret message [send_message] failed, resend it "
<< tag("logevent_id", state->message->logevent_id()) << tag("error", error);
<< tag("log_event_id", state->message->log_event_id()) << tag("error", error);
send_message_error_promise.set_value(Unit());
}
return;
@ -1666,14 +1666,14 @@ void SecretChatActor::on_outbound_send_message_result(NetQueryPtr query, Promise
telegram_api::downcast_call(
*sent->file_, overloaded(
[&](telegram_api::encryptedFileEmpty &) {
state->message->file = logevent::EncryptedInputFile::from_input_encrypted_file(
state->message->file = log_event::EncryptedInputFile::from_input_encrypted_file(
telegram_api::inputEncryptedFileEmpty());
get_file = [] {
return telegram_api::make_object<telegram_api::encryptedFileEmpty>();
};
},
[&](telegram_api::encryptedFile &file) {
state->message->file = logevent::EncryptedInputFile::from_input_encrypted_file(
state->message->file = log_event::EncryptedInputFile::from_input_encrypted_file(
telegram_api::inputEncryptedFile(file.id_, file.access_hash_));
get_file = [id = file.id_, access_hash = file.access_hash_, size = file.size_,
dc_id = file.dc_id_, key_fingerprint = file.key_fingerprint_] {
@ -1758,7 +1758,7 @@ void SecretChatActor::on_outbound_send_message_finish(uint64 state_id) {
if (!state) {
return;
}
LOG(INFO) << "Outbound secret message [send_message] finish " << tag("logevent_id", state->message->logevent_id());
LOG(INFO) << "Outbound secret message [send_message] finish " << tag("log_event_id", state->message->log_event_id());
state->send_message_finish_flag = true;
state->outer_send_message_finish.set_value(Unit());
@ -1771,7 +1771,7 @@ void SecretChatActor::on_outbound_save_changes_finish(uint64 state_id) {
}
auto *state = outbound_message_states_.get(state_id);
CHECK(state);
LOG(INFO) << "Outbound secret message [save_changes] finish " << tag("logevent_id", state->message->logevent_id());
LOG(INFO) << "Outbound secret message [save_changes] finish " << tag("log_event_id", state->message->log_event_id());
state->save_changes_finish_flag = true;
outbound_loop(state, state_id);
}
@ -1782,7 +1782,7 @@ void SecretChatActor::on_outbound_ack(uint64 state_id) {
}
auto *state = outbound_message_states_.get(state_id);
CHECK(state);
LOG(INFO) << "Outbound secret message [ack] finish " << tag("logevent_id", state->message->logevent_id());
LOG(INFO) << "Outbound secret message [ack] finish " << tag("log_event_id", state->message->log_event_id());
state->ack_flag = true;
outbound_loop(state, state_id);
}
@ -1794,7 +1794,7 @@ void SecretChatActor::on_outbound_outer_send_message_promise(uint64 state_id, Pr
}
auto *state = outbound_message_states_.get(state_id);
CHECK(state);
LOG(INFO) << "Outbound secret message [TODO] " << tag("logevent_id", state->message->logevent_id());
LOG(INFO) << "Outbound secret message [TODO] " << tag("log_event_id", state->message->log_event_id());
promise.set_value(Unit()); // Seems like this message is at least stored to binlog already
if (state->send_result_) {
state->send_result_({});
@ -1809,20 +1809,20 @@ void SecretChatActor::outbound_loop(OutboundMessageState *state, uint64 state_id
return;
}
if (state->save_changes_finish_flag /*&& state->send_message_finish_flag*/ && state->ack_flag) {
LOG(INFO) << "Outbound message [remove_logevent] start " << tag("logevent_id", state->message->logevent_id());
binlog_erase(context_->binlog(), state->message->logevent_id());
LOG(INFO) << "Outbound message [remove_log_event] start " << tag("log_event_id", state->message->log_event_id());
binlog_erase(context_->binlog(), state->message->log_event_id());
random_id_to_outbound_message_state_token_.erase(state->message->random_id);
LOG(INFO) << "Outbound message finish (lazy) " << tag("logevent_id", state->message->logevent_id());
LOG(INFO) << "Outbound message finish (lazy) " << tag("log_event_id", state->message->log_event_id());
outbound_message_states_.erase(state_id);
return;
}
if (state->save_changes_finish_flag && state->send_message_finish_flag &&
!state->message->is_sent) { // [rewrite_logevent]
LOG(INFO) << "Outbound message [rewrite_logevent] start " << tag("logevent_id", state->message->logevent_id());
!state->message->is_sent) { // [rewrite_log_event]
LOG(INFO) << "Outbound message [rewrite_log_event] start " << tag("log_event_id", state->message->log_event_id());
state->message->is_sent = true;
binlog_rewrite(context_->binlog(), state->message->logevent_id(), LogEvent::HandlerType::SecretChats,
binlog_rewrite(context_->binlog(), state->message->log_event_id(), LogEvent::HandlerType::SecretChats,
create_storer(*state->message));
}
}
@ -1884,9 +1884,9 @@ Status SecretChatActor::on_update_chat(telegram_api::encryptedChat &update) {
return Status::Error("Key fingerprint mismatch");
}
auth_state_.state = State::Ready;
if (create_logevent_id_ != 0) {
binlog_erase(context_->binlog(), create_logevent_id_);
create_logevent_id_ = 0;
if (create_log_event_id_ != 0) {
binlog_erase(context_->binlog(), create_log_event_id_);
create_log_event_id_ = 0;
}
// NB: order is important
@ -2044,7 +2044,7 @@ void SecretChatActor::on_outbound_action(secret_api::decryptedMessageActionReadM
// TODO
}
void SecretChatActor::on_outbound_action(secret_api::decryptedMessageActionDeleteMessages &delete_messages) {
// Corresponding logevent won't be deleted before promise returned by add_changes is set.
// Corresponding log event won't be deleted before promise returned by add_changes is set.
on_delete_messages(delete_messages.random_ids_).ensure();
}
void SecretChatActor::on_outbound_action(secret_api::decryptedMessageActionScreenshotMessages &screenshot) {

View File

@ -119,10 +119,10 @@ class SecretChatActor : public NetQueryCallback {
// Inbound messages
// Logevent is created by SecretChatsManager, because it must contain qts
void add_inbound_message(unique_ptr<logevent::InboundSecretMessage> message);
void add_inbound_message(unique_ptr<log_event::InboundSecretMessage> message);
// Outbound messages
// Promise will be set just after corresponding logevent will be SENT to binlog.
// Promise will be set just after corresponding log event will be SENT to binlog.
void send_message(tl_object_ptr<secret_api::DecryptedMessage> message,
tl_object_ptr<telegram_api::InputEncryptedFile> file, Promise<> promise);
void send_message_action(tl_object_ptr<secret_api::SendMessageAction> action);
@ -136,10 +136,10 @@ class SecretChatActor : public NetQueryCallback {
void send_set_ttl_message(int32 ttl, int64 random_id, Promise<> promise);
// Binlog replay interface
void replay_inbound_message(unique_ptr<logevent::InboundSecretMessage> message);
void replay_outbound_message(unique_ptr<logevent::OutboundSecretMessage> message);
void replay_close_chat(unique_ptr<logevent::CloseSecretChat> event);
void replay_create_chat(unique_ptr<logevent::CreateSecretChat> event);
void replay_inbound_message(unique_ptr<log_event::InboundSecretMessage> message);
void replay_outbound_message(unique_ptr<log_event::OutboundSecretMessage> message);
void replay_close_chat(unique_ptr<log_event::CloseSecretChat> event);
void replay_create_chat(unique_ptr<log_event::CreateSecretChat> event);
void binlog_replay_finish();
private:
@ -461,9 +461,9 @@ class SecretChatActor : public NetQueryCallback {
bool binlog_replay_finish_flag_ = false;
bool close_flag_ = false;
LogEvent::Id close_logevent_id_ = 0;
LogEvent::Id close_log_event_id_ = 0;
LogEvent::Id create_logevent_id_ = 0;
LogEvent::Id create_log_event_id_ = 0;
enum class QueryType : uint8 { DhConfig, EncryptedChat, Message, Ignore, DiscardEncryption, ReadHistory };
@ -560,19 +560,19 @@ class SecretChatActor : public NetQueryCallback {
struct InboundMessageState {
bool save_changes_finish = false;
bool save_message_finish = false;
LogEvent::Id logevent_id = 0;
LogEvent::Id log_event_id = 0;
int32 message_id;
};
Container<InboundMessageState> inbound_message_states_;
std::map<int32, unique_ptr<logevent::InboundSecretMessage>> pending_inbound_messages_;
std::map<int32, unique_ptr<log_event::InboundSecretMessage>> pending_inbound_messages_;
Result<std::tuple<uint64, BufferSlice, int32>> decrypt(BufferSlice &encrypted_message);
Status do_inbound_message_encrypted(unique_ptr<logevent::InboundSecretMessage> message);
Status do_inbound_message_decrypted_unchecked(unique_ptr<logevent::InboundSecretMessage> message);
Status do_inbound_message_decrypted(unique_ptr<logevent::InboundSecretMessage> message);
void do_inbound_message_decrypted_pending(unique_ptr<logevent::InboundSecretMessage> message);
Status do_inbound_message_encrypted(unique_ptr<log_event::InboundSecretMessage> message);
Status do_inbound_message_decrypted_unchecked(unique_ptr<log_event::InboundSecretMessage> message);
Status do_inbound_message_decrypted(unique_ptr<log_event::InboundSecretMessage> message);
void do_inbound_message_decrypted_pending(unique_ptr<log_event::InboundSecretMessage> message);
void on_inbound_save_message_finish(uint64 state_id);
void on_inbound_save_changes_finish(uint64 state_id);
@ -580,7 +580,7 @@ class SecretChatActor : public NetQueryCallback {
// OutboundMessage
struct OutboundMessageState {
unique_ptr<logevent::OutboundSecretMessage> message;
unique_ptr<log_event::OutboundSecretMessage> message;
Promise<> outer_send_message_finish;
Promise<> send_message_finish;
@ -618,11 +618,11 @@ class SecretChatActor : public NetQueryCallback {
void send_message_impl(tl_object_ptr<secret_api::DecryptedMessage> message,
tl_object_ptr<telegram_api::InputEncryptedFile> file, int32 flags, Promise<> promise);
void do_outbound_message_impl(unique_ptr<logevent::OutboundSecretMessage>, Promise<> promise);
void do_outbound_message_impl(unique_ptr<log_event::OutboundSecretMessage>, Promise<> promise);
Result<BufferSlice> create_encrypted_message(int32 layer, int32 my_in_seq_no, int32 my_out_seq_no,
tl_object_ptr<secret_api::DecryptedMessage> &message);
NetQueryPtr create_net_query(const logevent::OutboundSecretMessage &message);
NetQueryPtr create_net_query(const log_event::OutboundSecretMessage &message);
void outbound_resend(uint64 state_id);
Status outbound_rewrite_with_empty(uint64 state_id);
@ -637,7 +637,7 @@ class SecretChatActor : public NetQueryCallback {
// DiscardEncryption
void on_fatal_error(Status status);
void do_close_chat_impl(unique_ptr<logevent::CloseSecretChat> event);
void do_close_chat_impl(unique_ptr<log_event::CloseSecretChat> event);
void on_discard_encryption_result(NetQueryPtr result);
// Other
@ -693,7 +693,7 @@ class SecretChatActor : public NetQueryCallback {
void on_dh_config(telegram_api::messages_dhConfigNotModified &dh_not_modified);
void on_dh_config(telegram_api::messages_dhConfig &dh);
void do_create_chat_impl(unique_ptr<logevent::CreateSecretChat> event);
void do_create_chat_impl(unique_ptr<log_event::CreateSecretChat> event);
SecretChatId get_secret_chat_id() {
return SecretChatId(auth_state_.id);

View File

@ -188,7 +188,7 @@ void SecretChatsManager::on_new_message(tl_object_ptr<telegram_api::EncryptedMes
}
CHECK(message_ptr != nullptr);
auto event = make_unique<logevent::InboundSecretMessage>();
auto event = make_unique<log_event::InboundSecretMessage>();
event->promise = std::move(promise);
downcast_call(*message_ptr, [&](auto &x) {
event->chat_id = x.chat_id_;
@ -217,26 +217,26 @@ void SecretChatsManager::replay_binlog_event(BinlogEvent &&binlog_event) {
binlog_erase(G()->td_db()->get_binlog(), binlog_event.id_);
return;
}
auto r_message = logevent::SecretChatEvent::from_buffer_slice(binlog_event.data_as_buffer_slice());
auto r_message = log_event::SecretChatEvent::from_buffer_slice(binlog_event.data_as_buffer_slice());
LOG_IF(FATAL, r_message.is_error()) << "Failed to deserialize event: " << r_message.error();
auto message = r_message.move_as_ok();
message->set_logevent_id(binlog_event.id_);
message->set_log_event_id(binlog_event.id_);
LOG(INFO) << "Process binlog event " << *message;
switch (message->get_type()) {
case logevent::SecretChatEvent::Type::InboundSecretMessage:
return replay_inbound_message(
unique_ptr<logevent::InboundSecretMessage>(static_cast<logevent::InboundSecretMessage *>(message.release())));
case logevent::SecretChatEvent::Type::OutboundSecretMessage:
return replay_outbound_message(unique_ptr<logevent::OutboundSecretMessage>(
static_cast<logevent::OutboundSecretMessage *>(message.release())));
case logevent::SecretChatEvent::Type::CloseSecretChat:
case log_event::SecretChatEvent::Type::InboundSecretMessage:
return replay_inbound_message(unique_ptr<log_event::InboundSecretMessage>(
static_cast<log_event::InboundSecretMessage *>(message.release())));
case log_event::SecretChatEvent::Type::OutboundSecretMessage:
return replay_outbound_message(unique_ptr<log_event::OutboundSecretMessage>(
static_cast<log_event::OutboundSecretMessage *>(message.release())));
case log_event::SecretChatEvent::Type::CloseSecretChat:
return replay_close_chat(
unique_ptr<logevent::CloseSecretChat>(static_cast<logevent::CloseSecretChat *>(message.release())));
case logevent::SecretChatEvent::Type::CreateSecretChat:
unique_ptr<log_event::CloseSecretChat>(static_cast<log_event::CloseSecretChat *>(message.release())));
case log_event::SecretChatEvent::Type::CreateSecretChat:
return replay_create_chat(
unique_ptr<logevent::CreateSecretChat>(static_cast<logevent::CreateSecretChat *>(message.release())));
unique_ptr<log_event::CreateSecretChat>(static_cast<log_event::CreateSecretChat *>(message.release())));
}
LOG(FATAL) << "Unknown logevent type " << tag("type", format::as_hex(static_cast<int32>(message->get_type())));
LOG(FATAL) << "Unknown log event type " << tag("type", format::as_hex(static_cast<int32>(message->get_type())));
}
void SecretChatsManager::binlog_replay_finish() {
@ -246,34 +246,34 @@ void SecretChatsManager::binlog_replay_finish() {
}
}
void SecretChatsManager::replay_inbound_message(unique_ptr<logevent::InboundSecretMessage> message) {
void SecretChatsManager::replay_inbound_message(unique_ptr<log_event::InboundSecretMessage> message) {
LOG(INFO) << "Replay inbound secret message in chat " << message->chat_id;
auto actor = get_chat_actor(message->chat_id);
send_closure_later(actor, &SecretChatActor::replay_inbound_message, std::move(message));
}
void SecretChatsManager::add_inbound_message(unique_ptr<logevent::InboundSecretMessage> message) {
void SecretChatsManager::add_inbound_message(unique_ptr<log_event::InboundSecretMessage> message) {
LOG(INFO) << "Process inbound secret message in chat " << message->chat_id;
auto actor = get_chat_actor(message->chat_id);
send_closure(actor, &SecretChatActor::add_inbound_message, std::move(message));
}
void SecretChatsManager::replay_close_chat(unique_ptr<logevent::CloseSecretChat> message) {
void SecretChatsManager::replay_close_chat(unique_ptr<log_event::CloseSecretChat> message) {
LOG(INFO) << "Replay close secret chat " << message->chat_id;
auto actor = get_chat_actor(message->chat_id);
send_closure_later(actor, &SecretChatActor::replay_close_chat, std::move(message));
}
void SecretChatsManager::replay_create_chat(unique_ptr<logevent::CreateSecretChat> message) {
void SecretChatsManager::replay_create_chat(unique_ptr<log_event::CreateSecretChat> message) {
LOG(INFO) << "Replay create secret chat " << message->random_id;
auto actor = create_chat_actor(message->random_id);
send_closure_later(actor, &SecretChatActor::replay_create_chat, std::move(message));
}
void SecretChatsManager::replay_outbound_message(unique_ptr<logevent::OutboundSecretMessage> message) {
void SecretChatsManager::replay_outbound_message(unique_ptr<log_event::OutboundSecretMessage> message) {
LOG(INFO) << "Replay outbound secret message in chat " << message->chat_id;
auto actor = get_chat_actor(message->chat_id);

View File

@ -64,11 +64,11 @@ class SecretChatsManager : public Actor {
void flush_pending_chat_updates();
void do_update_chat(tl_object_ptr<telegram_api::updateEncryption> update);
void replay_inbound_message(unique_ptr<logevent::InboundSecretMessage> message);
void add_inbound_message(unique_ptr<logevent::InboundSecretMessage> message);
void replay_outbound_message(unique_ptr<logevent::OutboundSecretMessage> message);
void replay_close_chat(unique_ptr<logevent::CloseSecretChat> message);
void replay_create_chat(unique_ptr<logevent::CreateSecretChat> message);
void replay_inbound_message(unique_ptr<log_event::InboundSecretMessage> message);
void add_inbound_message(unique_ptr<log_event::InboundSecretMessage> message);
void replay_outbound_message(unique_ptr<log_event::OutboundSecretMessage> message);
void replay_close_chat(unique_ptr<log_event::CloseSecretChat> message);
void replay_create_chat(unique_ptr<log_event::CreateSecretChat> message);
unique_ptr<SecretChatActor::Context> make_secret_chat_context(int32 id);
ActorId<SecretChatActor> get_chat_actor(int32 id);

View File

@ -146,7 +146,7 @@ class SetSecureValueErrorsQuery : public Td::ResultHandler {
}
bool ptr = result_ptr.move_as_ok();
LOG(DEBUG) << "Receive result for SetSecureValueErrorsQuery " << ptr;
LOG(DEBUG) << "Receive result for SetSecureValueErrorsQuery: " << ptr;
promise_.set_value(Unit());
}

View File

@ -260,7 +260,7 @@ class GetArchivedStickerSetsQuery : public Td::ResultHandler {
}
auto ptr = result_ptr.move_as_ok();
LOG(INFO) << "Receive result for GetArchivedStickerSetsQuery " << to_string(ptr);
LOG(INFO) << "Receive result for GetArchivedStickerSetsQuery: " << to_string(ptr);
td->stickers_manager_->on_get_archived_sticker_sets(is_masks_, offset_sticker_set_id_, std::move(ptr->sets_),
ptr->count_);
@ -286,7 +286,7 @@ class GetFeaturedStickerSetsQuery : public Td::ResultHandler {
}
auto ptr = result_ptr.move_as_ok();
LOG(DEBUG) << "Receive result for GetFeaturedStickerSetsQuery " << to_string(ptr);
LOG(DEBUG) << "Receive result for GetFeaturedStickerSetsQuery: " << to_string(ptr);
td->stickers_manager_->on_get_featured_sticker_sets(-1, -1, 0, std::move(ptr));
}
@ -316,7 +316,7 @@ class GetOldFeaturedStickerSetsQuery : public Td::ResultHandler {
}
auto ptr = result_ptr.move_as_ok();
LOG(DEBUG) << "Receive result for GetOldFeaturedStickerSetsQuery " << to_string(ptr);
LOG(DEBUG) << "Receive result for GetOldFeaturedStickerSetsQuery: " << to_string(ptr);
td->stickers_manager_->on_get_featured_sticker_sets(offset_, limit_, generation_, std::move(ptr));
}
@ -690,7 +690,7 @@ class GetStickerSetQuery : public Td::ResultHandler {
}
void on_error(uint64 id, Status status) override {
LOG(INFO) << "Receive error for getStickerSet: " << status;
LOG(INFO) << "Receive error for GetStickerSetQuery: " << status;
td->stickers_manager_->on_load_sticker_set_fail(sticker_set_id_, status);
promise_.set_error(std::move(status));
}
@ -1132,8 +1132,10 @@ class StickersManager::UploadStickerFileCallback : public FileManager::UploadCal
StickersManager::StickersManager(Td *td, ActorShared<> parent) : td_(td), parent_(std::move(parent)) {
upload_sticker_file_callback_ = std::make_shared<UploadStickerFileCallback>();
on_update_recent_stickers_limit(G()->shared_config().get_option_integer("recent_stickers_limit", 200));
on_update_favorite_stickers_limit(G()->shared_config().get_option_integer("favorite_stickers_limit", 5));
on_update_recent_stickers_limit(
narrow_cast<int32>(G()->shared_config().get_option_integer("recent_stickers_limit", 200)));
on_update_favorite_stickers_limit(
narrow_cast<int32>(G()->shared_config().get_option_integer("favorite_stickers_limit", 5)));
on_update_dice_emojis();
}
@ -4277,7 +4279,7 @@ Result<std::tuple<FileId, bool, bool, bool>> StickersManager::prepare_input_file
if (is_animated) {
int32 width = for_thumbnail ? 100 : 512;
td_->stickers_manager_->create_sticker(file_id, PhotoSize(), get_dimensions(width, width), nullptr, true, nullptr);
create_sticker(file_id, PhotoSize(), get_dimensions(width, width), nullptr, true, nullptr);
} else {
td_->documents_manager_->create_document(file_id, string(), PhotoSize(), "sticker.png", "image/png", false);
}

View File

@ -360,7 +360,7 @@ class SetBotUpdatesStatusQuery : public Td::ResultHandler {
void on_error(uint64 id, Status status) override {
if (!G()->is_expected_error(status)) {
LOG(WARNING) << "Receive error for SetBotUpdatesStatus: " << status;
LOG(WARNING) << "Receive error for SetBotUpdatesStatusQuery: " << status;
}
status.ignore();
}
@ -690,7 +690,7 @@ class GetUserFullInfoRequest : public RequestActor<> {
UserId user_id_;
void do_run(Promise<Unit> &&promise) override {
td->contacts_manager_->get_user_full(user_id_, get_tries() < 2, std::move(promise));
td->contacts_manager_->load_user_full(user_id_, get_tries() < 2, std::move(promise));
}
void do_send_result() override {
@ -725,7 +725,7 @@ class GetGroupFullInfoRequest : public RequestActor<> {
ChatId chat_id_;
void do_run(Promise<Unit> &&promise) override {
td->contacts_manager_->get_chat_full(chat_id_, get_tries() < 2, std::move(promise));
td->contacts_manager_->load_chat_full(chat_id_, get_tries() < 2, std::move(promise));
}
void do_send_result() override {
@ -760,7 +760,7 @@ class GetSupergroupFullInfoRequest : public RequestActor<> {
ChannelId channel_id_;
void do_run(Promise<Unit> &&promise) override {
td->contacts_manager_->get_channel_full(channel_id_, get_tries() < 2, std::move(promise));
td->contacts_manager_->load_channel_full(channel_id_, get_tries() < 2, std::move(promise));
}
void do_send_result() override {
@ -837,7 +837,7 @@ class GetChatsRequest : public RequestActor<> {
DialogDate offset_;
int32 limit_;
vector<DialogId> dialog_ids_;
std::pair<int32, vector<DialogId>> dialog_ids_;
void do_run(Promise<Unit> &&promise) override {
dialog_ids_ =
@ -890,7 +890,7 @@ class SearchPublicChatsRequest : public RequestActor<> {
}
void do_send_result() override {
send_result(MessagesManager::get_chats_object(dialog_ids_));
send_result(MessagesManager::get_chats_object(-1, dialog_ids_));
}
public:
@ -903,10 +903,10 @@ class SearchChatsRequest : public RequestActor<> {
string query_;
int32 limit_;
vector<DialogId> dialog_ids_;
std::pair<int32, vector<DialogId>> dialog_ids_;
void do_run(Promise<Unit> &&promise) override {
dialog_ids_ = td->messages_manager_->search_dialogs(query_, limit_, std::move(promise)).second;
dialog_ids_ = td->messages_manager_->search_dialogs(query_, limit_, std::move(promise));
}
void do_send_result() override {
@ -930,7 +930,7 @@ class SearchChatsOnServerRequest : public RequestActor<> {
}
void do_send_result() override {
send_result(MessagesManager::get_chats_object(dialog_ids_));
send_result(MessagesManager::get_chats_object(-1, dialog_ids_));
}
public:
@ -944,7 +944,7 @@ class GetGroupsInCommonRequest : public RequestActor<> {
DialogId offset_dialog_id_;
int32 limit_;
vector<DialogId> dialog_ids_;
std::pair<int32, vector<DialogId>> dialog_ids_;
void do_run(Promise<Unit> &&promise) override {
dialog_ids_ = td->messages_manager_->get_common_dialogs(user_id_, offset_dialog_id_, limit_, get_tries() < 2,
@ -970,7 +970,7 @@ class GetCreatedPublicChatsRequest : public RequestActor<> {
}
void do_send_result() override {
send_result(MessagesManager::get_chats_object(dialog_ids_));
send_result(MessagesManager::get_chats_object(-1, dialog_ids_));
}
public:
@ -987,7 +987,7 @@ class GetSuitableDiscussionChatsRequest : public RequestActor<> {
}
void do_send_result() override {
send_result(MessagesManager::get_chats_object(dialog_ids_));
send_result(MessagesManager::get_chats_object(-1, dialog_ids_));
}
public:
@ -1003,7 +1003,7 @@ class GetInactiveSupergroupChatsRequest : public RequestActor<> {
}
void do_send_result() override {
send_result(MessagesManager::get_chats_object(dialog_ids_));
send_result(MessagesManager::get_chats_object(-1, dialog_ids_));
}
public:
@ -1050,6 +1050,34 @@ class GetRepliedMessageRequest : public RequestOnceActor {
}
};
class GetMessageThreadRequest : public RequestActor<MessagesManager::MessageThreadInfo> {
DialogId dialog_id_;
MessageId message_id_;
MessagesManager::MessageThreadInfo message_thread_info_;
void do_run(Promise<MessagesManager::MessageThreadInfo> &&promise) override {
if (get_tries() < 2) {
promise.set_value(std::move(message_thread_info_));
return;
}
td->messages_manager_->get_message_thread(dialog_id_, message_id_, std::move(promise));
}
void do_set_result(MessagesManager::MessageThreadInfo &&result) override {
message_thread_info_ = std::move(result);
}
void do_send_result() override {
send_result(td->messages_manager_->get_message_thread_info_object(message_thread_info_));
}
public:
GetMessageThreadRequest(ActorShared<Td> td, uint64 request_id, int64 dialog_id, int64 message_id)
: RequestActor(std::move(td), request_id), dialog_id_(dialog_id), message_id_(message_id) {
}
};
class GetChatPinnedMessageRequest : public RequestOnceActor {
DialogId dialog_id_;
@ -1090,50 +1118,26 @@ class GetMessagesRequest : public RequestOnceActor {
}
};
class GetPublicMessageLinkRequest : public RequestActor<> {
class GetMessageEmbeddingCodeRequest : public RequestActor<> {
FullMessageId full_message_id_;
bool for_group_;
bool for_comment_;
string link_;
string html_;
void do_run(Promise<Unit> &&promise) override {
std::tie(link_, html_) =
td->messages_manager_->get_public_message_link(full_message_id_, for_group_, for_comment_, std::move(promise));
html_ = td->messages_manager_->get_message_embedding_code(full_message_id_, for_group_, std::move(promise));
}
void do_send_result() override {
send_result(make_tl_object<td_api::publicMessageLink>(link_, html_));
send_result(make_tl_object<td_api::text>(html_));
}
public:
GetPublicMessageLinkRequest(ActorShared<Td> td, uint64 request_id, int64 dialog_id, int64 message_id, bool for_group,
bool for_comment)
GetMessageEmbeddingCodeRequest(ActorShared<Td> td, uint64 request_id, int64 dialog_id, int64 message_id,
bool for_group)
: RequestActor(std::move(td), request_id)
, full_message_id_(DialogId(dialog_id), MessageId(message_id))
, for_group_(for_group)
, for_comment_(for_comment) {
set_tries(5); // get top message + get linked channel message + get message HTML + get linked channel message link
}
};
class GetMessageLinkRequest : public RequestActor<> {
FullMessageId full_message_id_;
string link_;
void do_run(Promise<Unit> &&promise) override {
link_ = td->messages_manager_->get_message_link(full_message_id_, std::move(promise));
}
void do_send_result() override {
send_result(td_api::make_object<td_api::httpUrl>(link_));
}
public:
GetMessageLinkRequest(ActorShared<Td> td, uint64 request_id, int64 dialog_id, int64 message_id)
: RequestActor(std::move(td), request_id), full_message_id_(DialogId(dialog_id), MessageId(message_id)) {
, for_group_(for_group) {
}
};
@ -2051,23 +2055,24 @@ class GetChatEventLogRequest : public RequestOnceActor {
}
};
class GetBlockedUsersRequest : public RequestOnceActor {
class GetBlockedChatsRequest : public RequestActor<> {
int32 offset_;
int32 limit_;
int64 random_id_;
std::pair<int32, vector<DialogId>> dialog_ids_;
void do_run(Promise<Unit> &&promise) override {
random_id_ = td->contacts_manager_->get_blocked_users(offset_, limit_, std::move(promise));
dialog_ids_ = td->messages_manager_->get_blocked_dialogs(offset_, limit_, random_id_, std::move(promise));
}
void do_send_result() override {
send_result(td->contacts_manager_->get_blocked_users_object(random_id_));
send_result(MessagesManager::get_chats_object(dialog_ids_));
}
public:
GetBlockedUsersRequest(ActorShared<Td> td, uint64 request_id, int32 offset, int32 limit)
: RequestOnceActor(std::move(td), request_id), offset_(offset), limit_(limit), random_id_(0) {
GetBlockedChatsRequest(ActorShared<Td> td, uint64 request_id, int32 offset, int32 limit)
: RequestActor(std::move(td), request_id), offset_(offset), limit_(limit), random_id_(0) {
}
};
@ -2279,7 +2284,7 @@ class GetChatNotificationSettingsExceptionsRequest : public RequestActor<> {
}
void do_send_result() override {
send_result(MessagesManager::get_chats_object(dialog_ids_));
send_result(MessagesManager::get_chats_object(-1, dialog_ids_));
}
public:
@ -3150,7 +3155,7 @@ void Td::on_get_promo_data(Result<telegram_api::object_ptr<telegram_api::help_Pr
}
if (r_promo_data.is_error()) {
LOG(ERROR) << "Receive error for getPromoData: " << r_promo_data.error();
LOG(ERROR) << "Receive error for GetPromoDataQuery: " << r_promo_data.error();
return schedule_get_promo_data(60);
}
@ -3613,17 +3618,20 @@ void Td::on_config_option_updated(const string &name) {
if (name == "auth") {
return on_authorization_lost();
} else if (name == "saved_animations_limit") {
return animations_manager_->on_update_saved_animations_limit(G()->shared_config().get_option_integer(name));
return animations_manager_->on_update_saved_animations_limit(
narrow_cast<int32>(G()->shared_config().get_option_integer(name)));
} else if (name == "animation_search_emojis") {
return animations_manager_->on_update_animation_search_emojis(G()->shared_config().get_option_string(name));
} else if (name == "animation_search_provider") {
return animations_manager_->on_update_animation_search_provider(G()->shared_config().get_option_string(name));
} else if (name == "recent_stickers_limit") {
return stickers_manager_->on_update_recent_stickers_limit(G()->shared_config().get_option_integer(name));
return stickers_manager_->on_update_recent_stickers_limit(
narrow_cast<int32>(G()->shared_config().get_option_integer(name)));
} else if (name == "favorite_stickers_limit") {
stickers_manager_->on_update_favorite_stickers_limit(G()->shared_config().get_option_integer(name));
stickers_manager_->on_update_favorite_stickers_limit(
narrow_cast<int32>(G()->shared_config().get_option_integer(name)));
} else if (name == "my_id") {
G()->set_my_id(G()->shared_config().get_option_integer(name));
G()->set_my_id(static_cast<int32>(G()->shared_config().get_option_integer(name)));
} else if (name == "session_count") {
G()->net_query_dispatcher().update_session_count();
} else if (name == "use_pfs") {
@ -4158,6 +4166,8 @@ Status Td::init(DbKey key) {
init_managers();
G()->set_my_id(static_cast<int32>(G()->shared_config().get_option_integer("my_id")));
storage_manager_ = create_actor<StorageManager>("StorageManager", create_reference(),
min(current_scheduler_id + 2, scheduler_count - 1));
G()->set_storage_manager(storage_manager_.get());
@ -4199,7 +4209,7 @@ Status Td::init(DbKey key) {
// for each Actor.
//
// 2. An actor must not make some decisions before all binlog events are processed.
// For example, SecretChatActor must not send RequestKey, before it receives logevent with RequestKey and understands
// For example, SecretChatActor must not send RequestKey, before it receives log event with RequestKey and understands
// that RequestKey was already sent.
//
// 3. During replay of binlog some queries may be sent to other actors. They shouldn't process such events before all
@ -5102,19 +5112,29 @@ void Td::on_request(uint64 id, const td_api::getChatPinnedMessage &request) {
CREATE_REQUEST(GetChatPinnedMessageRequest, request.chat_id_);
}
void Td::on_request(uint64 id, const td_api::getMessageThread &request) {
CHECK_IS_USER();
CREATE_REQUEST(GetMessageThreadRequest, request.chat_id_, request.message_id_);
}
void Td::on_request(uint64 id, const td_api::getMessages &request) {
CREATE_REQUEST(GetMessagesRequest, request.chat_id_, request.message_ids_);
}
void Td::on_request(uint64 id, const td_api::getPublicMessageLink &request) {
CHECK_IS_USER();
CREATE_REQUEST(GetPublicMessageLinkRequest, request.chat_id_, request.message_id_, request.for_album_,
request.for_comment_);
void Td::on_request(uint64 id, const td_api::getMessageLink &request) {
auto r_message_link = messages_manager_->get_message_link(
{DialogId(request.chat_id_), MessageId(request.message_id_)}, request.for_album_, request.for_comment_);
if (r_message_link.is_error()) {
send_closure(actor_id(this), &Td::send_error, id, r_message_link.move_as_error());
} else {
send_closure(actor_id(this), &Td::send_result, id,
td_api::make_object<td_api::messageLink>(r_message_link.ok().first, r_message_link.ok().second));
}
}
void Td::on_request(uint64 id, const td_api::getMessageLink &request) {
void Td::on_request(uint64 id, const td_api::getMessageEmbeddingCode &request) {
CHECK_IS_USER();
CREATE_REQUEST(GetMessageLinkRequest, request.chat_id_, request.message_id_);
CREATE_REQUEST(GetMessageEmbeddingCodeRequest, request.chat_id_, request.message_id_, request.for_album_);
}
void Td::on_request(uint64 id, td_api::getMessageLinkInfo &request) {
@ -5336,7 +5356,7 @@ void Td::on_request(uint64 id, td_api::getTopChats &request) {
if (result.is_error()) {
promise.set_error(result.move_as_error());
} else {
promise.set_value(MessagesManager::get_chats_object(result.ok()));
promise.set_value(MessagesManager::get_chats_object(-1, result.ok()));
}
});
send_closure(top_dialog_manager_, &TopDialogManager::get_top_dialogs, get_top_dialog_category(*request.category_),
@ -5462,9 +5482,9 @@ void Td::on_request(uint64 id, const td_api::closeChat &request) {
void Td::on_request(uint64 id, const td_api::viewMessages &request) {
CHECK_IS_USER();
answer_ok_query(
id, messages_manager_->view_messages(
DialogId(request.chat_id_), MessagesManager::get_message_ids(request.message_ids_), request.force_read_));
answer_ok_query(id, messages_manager_->view_messages(
DialogId(request.chat_id_), MessageId(request.message_thread_id_),
MessagesManager::get_message_ids(request.message_ids_), request.force_read_));
}
void Td::on_request(uint64 id, const td_api::openMessageContent &request) {
@ -5587,9 +5607,9 @@ void Td::on_request(uint64 id, const td_api::readAllChatMentions &request) {
void Td::on_request(uint64 id, td_api::sendMessage &request) {
DialogId dialog_id(request.chat_id_);
auto r_new_message_id =
messages_manager_->send_message(dialog_id, MessageId(request.reply_to_message_id_), std::move(request.options_),
std::move(request.reply_markup_), std::move(request.input_message_content_));
auto r_new_message_id = messages_manager_->send_message(
dialog_id, MessageId(request.message_thread_id_), MessageId(request.reply_to_message_id_),
std::move(request.options_), std::move(request.reply_markup_), std::move(request.input_message_content_));
if (r_new_message_id.is_error()) {
return send_closure(actor_id(this), &Td::send_error, id, r_new_message_id.move_as_error());
}
@ -5601,9 +5621,9 @@ void Td::on_request(uint64 id, td_api::sendMessage &request) {
void Td::on_request(uint64 id, td_api::sendMessageAlbum &request) {
DialogId dialog_id(request.chat_id_);
auto r_message_ids =
messages_manager_->send_message_group(dialog_id, MessageId(request.reply_to_message_id_),
std::move(request.options_), std::move(request.input_message_contents_));
auto r_message_ids = messages_manager_->send_message_group(
dialog_id, MessageId(request.message_thread_id_), MessageId(request.reply_to_message_id_),
std::move(request.options_), std::move(request.input_message_contents_));
if (r_message_ids.is_error()) {
return send_closure(actor_id(this), &Td::send_error, id, r_message_ids.move_as_error());
}
@ -5634,8 +5654,8 @@ void Td::on_request(uint64 id, td_api::sendInlineQueryResultMessage &request) {
DialogId dialog_id(request.chat_id_);
auto r_new_message_id = messages_manager_->send_inline_query_result_message(
dialog_id, MessageId(request.reply_to_message_id_), std::move(request.options_), request.query_id_,
request.result_id_, request.hide_via_bot_);
dialog_id, MessageId(request.message_thread_id_), MessageId(request.reply_to_message_id_),
std::move(request.options_), request.query_id_, request.result_id_, request.hide_via_bot_);
if (r_new_message_id.is_error()) {
return send_closure(actor_id(this), &Td::send_error, id, r_new_message_id.move_as_error());
}
@ -5782,7 +5802,8 @@ void Td::on_request(uint64 id, const td_api::deleteChatReplyMarkup &request) {
void Td::on_request(uint64 id, td_api::sendChatAction &request) {
CREATE_OK_REQUEST_PROMISE();
messages_manager_->send_dialog_action(DialogId(request.chat_id_), std::move(request.action_), std::move(promise));
messages_manager_->send_dialog_action(DialogId(request.chat_id_), MessageId(request.message_thread_id_),
std::move(request.action_), std::move(promise));
}
void Td::on_request(uint64 id, td_api::sendChatScreenshotTakenNotification &request) {
@ -6018,7 +6039,8 @@ void Td::on_request(uint64 id, const td_api::setChatPermissions &request) {
void Td::on_request(uint64 id, td_api::setChatDraftMessage &request) {
CHECK_IS_USER();
answer_ok_query(
id, messages_manager_->set_dialog_draft_message(DialogId(request.chat_id_), std::move(request.draft_message_)));
id, messages_manager_->set_dialog_draft_message(DialogId(request.chat_id_), MessageId(request.message_thread_id_),
std::move(request.draft_message_)));
}
void Td::on_request(uint64 id, const td_api::toggleChatIsPinned &request) {
@ -6033,6 +6055,11 @@ void Td::on_request(uint64 id, const td_api::toggleChatIsMarkedAsUnread &request
request.is_marked_as_unread_));
}
void Td::on_request(uint64 id, const td_api::toggleChatIsBlocked &request) {
CHECK_IS_USER();
answer_ok_query(id, messages_manager_->toggle_dialog_is_blocked(DialogId(request.chat_id_), request.is_blocked_));
}
void Td::on_request(uint64 id, const td_api::toggleChatDefaultDisableNotification &request) {
CHECK_IS_USER();
answer_ok_query(id, messages_manager_->toggle_dialog_silent_send_message(DialogId(request.chat_id_),
@ -6108,7 +6135,7 @@ void Td::on_request(uint64 id, const td_api::leaveChat &request) {
}
new_status =
td_api::make_object<td_api::chatMemberStatusCreator>(status.is_anonymous(), status.get_rank(), false);
td_api::make_object<td_api::chatMemberStatusCreator>(status.get_rank(), status.is_anonymous(), false);
}
}
messages_manager_->set_dialog_participant_status(dialog_id, contacts_manager_->get_my_id(), std::move(new_status),
@ -6356,19 +6383,16 @@ void Td::on_request(uint64 id, const td_api::deleteFile &request) {
"td_api::deleteFile");
}
void Td::on_request(uint64 id, const td_api::blockUser &request) {
void Td::on_request(uint64 id, const td_api::blockChatFromReplies &request) {
CHECK_IS_USER();
answer_ok_query(id, contacts_manager_->set_user_is_blocked(UserId(request.user_id_), true));
CREATE_OK_REQUEST_PROMISE();
messages_manager_->block_dialog_from_replies(MessageId(request.message_id_), request.delete_message_,
request.delete_all_messages_, request.report_spam_, std::move(promise));
}
void Td::on_request(uint64 id, const td_api::unblockUser &request) {
void Td::on_request(uint64 id, const td_api::getBlockedChats &request) {
CHECK_IS_USER();
answer_ok_query(id, contacts_manager_->set_user_is_blocked(UserId(request.user_id_), false));
}
void Td::on_request(uint64 id, const td_api::getBlockedUsers &request) {
CHECK_IS_USER();
CREATE_REQUEST(GetBlockedUsersRequest, request.offset_, request.limit_);
CREATE_REQUEST(GetBlockedChatsRequest, request.offset_, request.limit_);
}
void Td::on_request(uint64 id, td_api::addContact &request) {
@ -6973,7 +6997,7 @@ void Td::on_request(uint64 id, td_api::setOption &request) {
LOG(INFO) << "Set option " << request.name_;
auto set_integer_option = [&](Slice name, int32 min = 0, int32 max = std::numeric_limits<int32>::max()) {
auto set_integer_option = [&](Slice name, int64 min = 0, int64 max = std::numeric_limits<int32>::max()) {
if (request.name_ != name) {
return false;
}
@ -6985,7 +7009,7 @@ void Td::on_request(uint64 id, td_api::setOption &request) {
if (value_constructor_id == td_api::optionValueEmpty::ID) {
G()->shared_config().set_option_empty(name);
} else {
int32 value = static_cast<td_api::optionValueInteger *>(request.value_.get())->value_;
int64 value = static_cast<td_api::optionValueInteger *>(request.value_.get())->value_;
if (value < min || value > max) {
send_error_raw(id, 3,
PSLICE() << "Option's \"" << name << "\" value " << value << " is outside of a valid range ["

View File

@ -498,12 +498,14 @@ class Td final : public NetQueryCallback {
void on_request(uint64 id, const td_api::getChatPinnedMessage &request);
void on_request(uint64 id, const td_api::getMessageThread &request);
void on_request(uint64 id, const td_api::getMessages &request);
void on_request(uint64 id, const td_api::getPublicMessageLink &request);
void on_request(uint64 id, const td_api::getMessageLink &request);
void on_request(uint64 id, const td_api::getMessageEmbeddingCode &request);
void on_request(uint64 id, td_api::getMessageLinkInfo &request);
void on_request(uint64 id, const td_api::getFile &request);
@ -718,6 +720,8 @@ class Td final : public NetQueryCallback {
void on_request(uint64 id, const td_api::toggleChatIsMarkedAsUnread &request);
void on_request(uint64 id, const td_api::toggleChatIsBlocked &request);
void on_request(uint64 id, const td_api::toggleChatDefaultDisableNotification &request);
void on_request(uint64 id, const td_api::setPinnedChats &request);
@ -786,11 +790,9 @@ class Td final : public NetQueryCallback {
void on_request(uint64 id, const td_api::deleteFile &request);
void on_request(uint64 id, const td_api::blockUser &request);
void on_request(uint64 id, const td_api::blockChatFromReplies &request);
void on_request(uint64 id, const td_api::unblockUser &request);
void on_request(uint64 id, const td_api::getBlockedUsers &request);
void on_request(uint64 id, const td_api::getBlockedChats &request);
void on_request(uint64 id, td_api::addContact &request);

View File

@ -112,6 +112,9 @@ Status init_binlog(Binlog &binlog, string path, BinlogKeyValue<Binlog> &binlog_p
case LogEvent::HandlerType::ToggleDialogIsMarkedAsUnreadOnServer:
case LogEvent::HandlerType::SetDialogFolderIdOnServer:
case LogEvent::HandlerType::DeleteScheduledMessagesFromServer:
case LogEvent::HandlerType::ToggleDialogIsBlockedOnServer:
case LogEvent::HandlerType::ReadMessageThreadHistoryOnServer:
case LogEvent::HandlerType::BlockDialogFromRepliesOnServer:
events.to_messages_manager.push_back(event.clone());
break;
case LogEvent::HandlerType::AddMessagePushNotification:
@ -125,7 +128,7 @@ Status init_binlog(Binlog &binlog, string path, BinlogKeyValue<Binlog> &binlog_p
config_pmc.external_init_handle(event);
break;
default:
LOG(FATAL) << "Unsupported logevent type " << event.type_;
LOG(FATAL) << "Unsupported log event type " << event.type_;
}
};

View File

@ -240,7 +240,7 @@ void TopDialogManager::update_rating_e_decay() {
if (!is_active_) {
return;
}
rating_e_decay_ = G()->shared_config().get_option_integer("rating_e_decay", rating_e_decay_);
rating_e_decay_ = narrow_cast<int32>(G()->shared_config().get_option_integer("rating_e_decay", rating_e_decay_));
}
template <class StorerT>

View File

@ -404,7 +404,7 @@ bool UpdatesManager::is_acceptable_message_reply_header(
return true;
}
if (is_acceptable_peer(header->reply_to_peer_id_)) {
if (!is_acceptable_peer(header->reply_to_peer_id_)) {
return false;
}
return true;
@ -1335,13 +1335,8 @@ void UpdatesManager::on_pending_updates(vector<tl_object_ptr<telegram_api::Updat
return;
}
if (processed_updates == updates.size()) {
if (seq_begin || seq_end) {
LOG(ERROR) << "All updates from " << source << " was processed but seq = " << seq_
<< ", seq_begin = " << seq_begin << ", seq_end = " << seq_end;
} else {
LOG(INFO) << "All updates was processed";
}
if (processed_updates == updates.size() && seq_begin == 0 && seq_end == 0) {
LOG(INFO) << "All updates was processed";
return;
}
@ -1719,6 +1714,25 @@ void UpdatesManager::on_update(tl_object_ptr<telegram_api::updateChannelAvailabl
ChannelId(update->channel_id_), MessageId(ServerMessageId(update->available_min_id_)));
}
void UpdatesManager::on_update(tl_object_ptr<telegram_api::updateReadChannelDiscussionInbox> update,
bool /*force_apply*/) {
td_->messages_manager_->on_update_read_message_comments(
DialogId(ChannelId(update->channel_id_)), MessageId(ServerMessageId(update->top_msg_id_)), MessageId(),
MessageId(ServerMessageId(update->read_max_id_)), MessageId());
if ((update->flags_ & telegram_api::updateReadChannelDiscussionInbox::BROADCAST_ID_MASK) != 0) {
td_->messages_manager_->on_update_read_message_comments(
DialogId(ChannelId(update->broadcast_id_)), MessageId(ServerMessageId(update->broadcast_post_)), MessageId(),
MessageId(ServerMessageId(update->read_max_id_)), MessageId());
}
}
void UpdatesManager::on_update(tl_object_ptr<telegram_api::updateReadChannelDiscussionOutbox> update,
bool /*force_apply*/) {
td_->messages_manager_->on_update_read_message_comments(
DialogId(ChannelId(update->channel_id_)), MessageId(ServerMessageId(update->top_msg_id_)), MessageId(),
MessageId(), MessageId(ServerMessageId(update->read_max_id_)));
}
void UpdatesManager::on_update(tl_object_ptr<telegram_api::updateUserPinnedMessage> update, bool /*force_apply*/) {
td_->messages_manager_->on_update_dialog_pinned_message_id(DialogId(UserId(update->user_id_)),
MessageId(ServerMessageId(update->id_)));
@ -1869,8 +1883,9 @@ void UpdatesManager::on_update(tl_object_ptr<telegram_api::updateUserTyping> upd
LOG(DEBUG) << "Ignore user typing in unknown " << dialog_id;
return;
}
td_->messages_manager_->on_user_dialog_action(
dialog_id, user_id, convert_send_message_action(std::move(update->action_)), get_short_update_date());
td_->messages_manager_->on_user_dialog_action(dialog_id, MessageId(), user_id,
convert_send_message_action(std::move(update->action_)),
get_short_update_date());
}
void UpdatesManager::on_update(tl_object_ptr<telegram_api::updateChatUserTyping> update, bool /*force_apply*/) {
@ -1879,18 +1894,38 @@ void UpdatesManager::on_update(tl_object_ptr<telegram_api::updateChatUserTyping>
LOG(DEBUG) << "Ignore user chat typing of unknown " << user_id;
return;
}
ChatId chat_id(update->chat_id_);
DialogId dialog_id(chat_id);
DialogId dialog_id(ChatId(update->chat_id_));
if (!td_->messages_manager_->have_dialog(dialog_id)) {
ChannelId channel_id(update->chat_id_);
dialog_id = DialogId(channel_id);
if (!td_->messages_manager_->have_dialog(dialog_id)) {
LOG(DEBUG) << "Ignore user chat typing in unknown " << dialog_id;
LOG(DEBUG) << "Ignore user chat typing in unknown " << dialog_id;
return;
}
td_->messages_manager_->on_user_dialog_action(dialog_id, MessageId(), user_id,
convert_send_message_action(std::move(update->action_)),
get_short_update_date());
}
void UpdatesManager::on_update(tl_object_ptr<telegram_api::updateChannelUserTyping> update, bool /*force_apply*/) {
UserId user_id(update->user_id_);
if (!td_->contacts_manager_->have_min_user(user_id)) {
LOG(DEBUG) << "Ignore user channel typing of unknown " << user_id;
return;
}
DialogId dialog_id(ChannelId(update->channel_id_));
if (!td_->messages_manager_->have_dialog(dialog_id)) {
LOG(DEBUG) << "Ignore user channel typing in unknown " << dialog_id;
return;
}
MessageId top_thread_message_id;
if ((update->flags_ & telegram_api::updateChannelUserTyping::TOP_MSG_ID_MASK) != 0) {
top_thread_message_id = MessageId(ServerMessageId(update->top_msg_id_));
if (!top_thread_message_id.is_valid() && top_thread_message_id != MessageId()) {
LOG(ERROR) << "Ignore user channel typing in the message thread of " << top_thread_message_id;
return;
}
}
td_->messages_manager_->on_user_dialog_action(
dialog_id, user_id, convert_send_message_action(std::move(update->action_)), get_short_update_date());
td_->messages_manager_->on_user_dialog_action(dialog_id, top_thread_message_id, user_id,
convert_send_message_action(std::move(update->action_)),
get_short_update_date());
}
void UpdatesManager::on_update(tl_object_ptr<telegram_api::updateEncryptedChatTyping> update, bool /*force_apply*/) {
@ -1908,8 +1943,8 @@ void UpdatesManager::on_update(tl_object_ptr<telegram_api::updateEncryptedChatTy
return;
}
td_->messages_manager_->on_user_dialog_action(dialog_id, user_id, make_tl_object<td_api::chatActionTyping>(),
get_short_update_date());
td_->messages_manager_->on_user_dialog_action(dialog_id, MessageId(), user_id,
make_tl_object<td_api::chatActionTyping>(), get_short_update_date());
}
void UpdatesManager::on_update(tl_object_ptr<telegram_api::updateUserStatus> update, bool /*force_apply*/) {
@ -1930,8 +1965,8 @@ void UpdatesManager::on_update(tl_object_ptr<telegram_api::updateUserPhoto> upda
td_->contacts_manager_->on_update_user_photo(UserId(update->user_id_), std::move(update->photo_));
}
void UpdatesManager::on_update(tl_object_ptr<telegram_api::updateUserBlocked> update, bool /*force_apply*/) {
td_->contacts_manager_->on_update_user_is_blocked(UserId(update->user_id_), update->blocked_);
void UpdatesManager::on_update(tl_object_ptr<telegram_api::updatePeerBlocked> update, bool /*force_apply*/) {
td_->messages_manager_->on_update_dialog_is_blocked(DialogId(update->peer_id_), update->blocked_);
}
void UpdatesManager::on_update(tl_object_ptr<telegram_api::updateChatParticipants> update, bool /*force_apply*/) {
@ -2200,7 +2235,4 @@ void UpdatesManager::on_update(tl_object_ptr<telegram_api::updateChannelParticip
void UpdatesManager::on_update(tl_object_ptr<telegram_api::updateTheme> update, bool /*force_apply*/) {
}
void UpdatesManager::on_update(tl_object_ptr<telegram_api::updateReadDiscussion> update, bool /*force_apply*/) {
}
} // namespace td

View File

@ -218,13 +218,15 @@ class UpdatesManager : public Actor {
void on_update(tl_object_ptr<telegram_api::updateUserTyping> update, bool /*force_apply*/);
void on_update(tl_object_ptr<telegram_api::updateChatUserTyping> update, bool /*force_apply*/);
void on_update(tl_object_ptr<telegram_api::updateChannelUserTyping> update, bool /*force_apply*/);
void on_update(tl_object_ptr<telegram_api::updateEncryptedChatTyping> update, bool /*force_apply*/);
void on_update(tl_object_ptr<telegram_api::updateUserStatus> update, bool /*force_apply*/);
void on_update(tl_object_ptr<telegram_api::updateUserName> update, bool /*force_apply*/);
void on_update(tl_object_ptr<telegram_api::updateUserPhone> update, bool /*force_apply*/);
void on_update(tl_object_ptr<telegram_api::updateUserPhoto> update, bool /*force_apply*/);
void on_update(tl_object_ptr<telegram_api::updateUserBlocked> update, bool /*force_apply*/);
void on_update(tl_object_ptr<telegram_api::updatePeerBlocked> update, bool /*force_apply*/);
void on_update(tl_object_ptr<telegram_api::updateChatParticipants> update, bool /*force_apply*/);
void on_update(tl_object_ptr<telegram_api::updateChatParticipantAdd> update, bool /*force_apply*/);
@ -249,6 +251,9 @@ class UpdatesManager : public Actor {
void on_update(tl_object_ptr<telegram_api::updateChannelMessageForwards> update, bool force_apply);
void on_update(tl_object_ptr<telegram_api::updateChannelAvailableMessages> update, bool /*force_apply*/);
void on_update(tl_object_ptr<telegram_api::updateReadChannelDiscussionInbox> update, bool /*force_apply*/);
void on_update(tl_object_ptr<telegram_api::updateReadChannelDiscussionOutbox> update, bool /*force_apply*/);
void on_update(tl_object_ptr<telegram_api::updateUserPinnedMessage> update, bool /*force_apply*/);
void on_update(tl_object_ptr<telegram_api::updateChatPinnedMessage> update, bool /*force_apply*/);
void on_update(tl_object_ptr<telegram_api::updateChannelPinnedMessage> update, bool /*force_apply*/);
@ -318,8 +323,6 @@ class UpdatesManager : public Actor {
// unsupported updates
void on_update(tl_object_ptr<telegram_api::updateTheme> update, bool /*force_apply*/);
void on_update(tl_object_ptr<telegram_api::updateReadDiscussion> update, bool /*force_apply*/);
};
} // namespace td

View File

@ -54,6 +54,7 @@ enum class DbVersion : int32 {
AddFolders,
AddScheduledMessages,
StorePinnedDialogsInBinlog,
AddMessageThreadSupport,
Next
};

View File

@ -81,7 +81,7 @@ class GetWebPagePreviewQuery : public Td::ResultHandler {
}
auto ptr = result_ptr.move_as_ok();
LOG(INFO) << "Receive result for GetWebPagePreviewQuery " << to_string(ptr);
LOG(INFO) << "Receive result for GetWebPagePreviewQuery: " << to_string(ptr);
td->web_pages_manager_->on_get_web_page_preview_success(request_id_, url_, std::move(ptr), std::move(promise_));
}
@ -112,7 +112,7 @@ class GetWebPageQuery : public Td::ResultHandler {
}
auto ptr = result_ptr.move_as_ok();
LOG(INFO) << "Receive result for GetWebPageQuery " << to_string(ptr);
LOG(INFO) << "Receive result for GetWebPageQuery: " << to_string(ptr);
if (ptr->get_id() == telegram_api::webPageNotModified::ID) {
if (web_page_id_.is_valid()) {
auto web_page = move_tl_object_as<telegram_api::webPageNotModified>(ptr);
@ -230,7 +230,7 @@ class WebPagesManager::WebPage {
FileSourceId file_source_id;
mutable uint64 logevent_id = 0;
mutable uint64 log_event_id = 0;
template <class StorerT>
void store(StorerT &storer) const {
@ -427,10 +427,10 @@ WebPageId WebPagesManager::on_get_web_page(tl_object_ptr<telegram_api::WebPage>
LOG(INFO) << "Got empty " << web_page_id;
const WebPage *web_page_to_delete = get_web_page(web_page_id);
if (web_page_to_delete != nullptr) {
if (web_page_to_delete->logevent_id != 0) {
if (web_page_to_delete->log_event_id != 0) {
LOG(INFO) << "Erase " << web_page_id << " from binlog";
binlog_erase(G()->td_db()->get_binlog(), web_page_to_delete->logevent_id);
web_page_to_delete->logevent_id = 0;
binlog_erase(G()->td_db()->get_binlog(), web_page_to_delete->log_event_id);
web_page_to_delete->log_event_id = 0;
}
if (web_page_to_delete->file_source_id.is_valid()) {
td_->file_manager_->change_files_source(web_page_to_delete->file_source_id,
@ -559,7 +559,7 @@ void WebPagesManager::update_web_page(unique_ptr<WebPage> web_page, WebPageId we
}
old_instant_view = std::move(page->instant_view);
web_page->logevent_id = page->logevent_id;
web_page->log_event_id = page->log_event_id;
} else {
auto it = url_to_file_source_id_.find(web_page->url);
if (it != url_to_file_source_id_.end()) {
@ -1552,12 +1552,12 @@ void WebPagesManager::save_web_page(const WebPage *web_page, WebPageId web_page_
return;
}
if (!from_binlog) {
WebPageLogEvent logevent(web_page_id, web_page);
LogEventStorerImpl<WebPageLogEvent> storer(logevent);
if (web_page->logevent_id == 0) {
web_page->logevent_id = binlog_add(G()->td_db()->get_binlog(), LogEvent::HandlerType::WebPages, storer);
WebPageLogEvent log_event(web_page_id, web_page);
auto storer = get_log_event_storer(log_event);
if (web_page->log_event_id == 0) {
web_page->log_event_id = binlog_add(G()->td_db()->get_binlog(), LogEvent::HandlerType::WebPages, storer);
} else {
binlog_rewrite(G()->td_db()->get_binlog(), web_page->logevent_id, LogEvent::HandlerType::WebPages, storer);
binlog_rewrite(G()->td_db()->get_binlog(), web_page->log_event_id, LogEvent::HandlerType::WebPages, storer);
}
}
@ -1590,7 +1590,7 @@ void WebPagesManager::on_binlog_web_page_event(BinlogEvent &&event) {
return;
}
web_page->logevent_id = event.id_;
web_page->log_event_id = event.id_;
update_web_page(std::move(web_page), web_page_id, true, false);
}
@ -1611,13 +1611,13 @@ void WebPagesManager::on_save_web_page_to_database(WebPageId web_page_id, bool s
if (!success) {
LOG(ERROR) << "Failed to save " << web_page_id << " to database";
save_web_page(web_page, web_page_id, web_page->logevent_id != 0);
save_web_page(web_page, web_page_id, web_page->log_event_id != 0);
} else {
LOG(INFO) << "Successfully saved " << web_page_id << " to database";
if (web_page->logevent_id != 0) {
if (web_page->log_event_id != 0) {
LOG(INFO) << "Erase " << web_page_id << " from binlog";
binlog_erase(G()->td_db()->get_binlog(), web_page->logevent_id);
web_page->logevent_id = 0;
binlog_erase(G()->td_db()->get_binlog(), web_page->log_event_id);
web_page->log_event_id = 0;
}
}
}

View File

@ -290,11 +290,9 @@ class CliClient final : public Actor {
}
void update_option(const td_api::updateOption &option) {
if (option.name_ == "my_id") {
if (option.value_->get_id() == td_api::optionValueInteger::ID) {
my_id_ = static_cast<const td_api::optionValueInteger *>(option.value_.get())->value_;
LOG(INFO) << "Set my id to " << my_id_;
}
if (option.name_ == "my_id" && option.value_->get_id() == td_api::optionValueInteger::ID) {
my_id_ = static_cast<int32>(static_cast<const td_api::optionValueInteger *>(option.value_.get())->value_);
LOG(INFO) << "Set my id to " << my_id_;
}
}
@ -1399,7 +1397,7 @@ class CliClient final : public Actor {
bool disable_notification = false, bool from_background = false, int64 reply_to_message_id = 0) {
auto chat = as_chat_id(chat_id);
auto id = send_request(td_api::make_object<td_api::sendMessage>(
chat, reply_to_message_id,
chat, as_message_thread_id(message_thread_id_), reply_to_message_id,
td_api::make_object<td_api::messageSendOptions>(disable_notification, from_background,
as_message_scheduling_state(schedule_date_)),
nullptr, std::move(input_message_content)));
@ -1873,6 +1871,7 @@ class CliClient final : public Actor {
string chat_id;
string message_thread_id;
std::tie(chat_id, message_thread_id) = split(args);
send_request(td_api::make_object<td_api::searchChatMessages>(as_chat_id(chat_id), "", 0, 0, 0, 100, nullptr,
as_message_thread_id(message_thread_id)));
} else if (op == "spvf") {
@ -2194,7 +2193,7 @@ class CliClient final : public Actor {
string value;
std::tie(name, value) = split(args);
int32 value_int = to_integer<int32>(value);
auto value_int = to_integer<int64>(value);
send_request(
td_api::make_object<td_api::setOption>(name, td_api::make_object<td_api::optionValueInteger>(value_int)));
} else if (op == "sos") {
@ -2297,11 +2296,7 @@ class CliClient final : public Actor {
send_request(td_api::make_object<td_api::getDeepLinkInfo>(args));
} else if (op == "tme") {
send_request(td_api::make_object<td_api::getRecentlyVisitedTMeUrls>(args));
} else if (op == "bu") {
send_request(td_api::make_object<td_api::blockUser>(as_user_id(args)));
} else if (op == "ubu") {
send_request(td_api::make_object<td_api::unblockUser>(as_user_id(args)));
} else if (op == "gbu") {
} else if (op == "gbc") {
string offset;
string limit;
@ -2312,7 +2307,7 @@ class CliClient final : public Actor {
if (limit.empty()) {
limit = "10";
}
send_request(td_api::make_object<td_api::getBlockedUsers>(to_integer<int32>(offset), to_integer<int32>(limit)));
send_request(td_api::make_object<td_api::getBlockedChats>(to_integer<int32>(offset), to_integer<int32>(limit)));
} else if (op == "gu") {
send_request(td_api::make_object<td_api::getUser>(as_user_id(args)));
} else if (op == "gsu") {
@ -2608,6 +2603,11 @@ class CliClient final : public Actor {
string message_id;
std::tie(chat_id, message_id) = split(args);
send_request(td_api::make_object<td_api::getRepliedMessage>(as_chat_id(chat_id), as_message_id(message_id)));
} else if (op == "gmt") {
string chat_id;
string message_id;
std::tie(chat_id, message_id) = split(args);
send_request(td_api::make_object<td_api::getMessageThread>(as_chat_id(chat_id), as_message_id(message_id)));
} else if (op == "gcpm") {
string chat_id = args;
send_request(td_api::make_object<td_api::getChatPinnedMessage>(as_chat_id(chat_id)));
@ -2616,7 +2616,7 @@ class CliClient final : public Actor {
string message_ids;
std::tie(chat_id, message_ids) = split(args);
send_request(td_api::make_object<td_api::getMessages>(as_chat_id(chat_id), as_message_ids(message_ids)));
} else if (op == "gpml") {
} else if (op == "gmlink") {
string chat_id;
string message_id;
string for_album;
@ -2624,13 +2624,16 @@ class CliClient final : public Actor {
std::tie(chat_id, args) = split(args);
std::tie(message_id, args) = split(args);
std::tie(for_album, for_comment) = split(args);
send_request(td_api::make_object<td_api::getPublicMessageLink>(as_chat_id(chat_id), as_message_id(message_id),
as_bool(for_album), as_bool(for_comment)));
} else if (op == "gmlink") {
send_request(td_api::make_object<td_api::getMessageLink>(as_chat_id(chat_id), as_message_id(message_id),
as_bool(for_album), as_bool(for_comment)));
} else if (op == "gmec") {
string chat_id;
string message_id;
std::tie(chat_id, message_id) = split(args);
send_request(td_api::make_object<td_api::getMessageLink>(as_chat_id(chat_id), as_message_id(message_id)));
string for_album;
std::tie(chat_id, args) = split(args);
std::tie(message_id, for_album) = split(args);
send_request(td_api::make_object<td_api::getMessageEmbeddingCode>(as_chat_id(chat_id), as_message_id(message_id),
as_bool(for_album)));
} else if (op == "gmli") {
send_request(td_api::make_object<td_api::getMessageLinkInfo>(args));
} else if (op == "gcmbd") {
@ -2883,11 +2886,15 @@ class CliClient final : public Actor {
op_not_found_count++;
}
if (op == "scdm") {
if (op == "scdm" || op == "scdmt") {
string chat_id;
string message_thread_id;
string reply_to_message_id;
string message;
std::tie(chat_id, args) = split(args);
if (op == "scdmt") {
std::tie(message_thread_id, args) = split(args);
}
std::tie(reply_to_message_id, message) = split(args);
td_api::object_ptr<td_api::draftMessage> draft_message;
if (!reply_to_message_id.empty() || !message.empty()) {
@ -2900,7 +2907,8 @@ class CliClient final : public Actor {
td_api::make_object<td_api::inputMessageText>(as_formatted_text(message, std::move(entities)), true,
false));
}
send_request(td_api::make_object<td_api::setChatDraftMessage>(as_chat_id(chat_id), std::move(draft_message)));
send_request(td_api::make_object<td_api::setChatDraftMessage>(
as_chat_id(chat_id), as_message_thread_id(message_thread_id), std::move(draft_message)));
} else if (op == "cadm") {
send_request(td_api::make_object<td_api::clearAllDraftMessages>());
} else if (op == "tcip" || op == "tcipa" || begins_with(op, "tcip-")) {
@ -2909,12 +2917,27 @@ class CliClient final : public Actor {
std::tie(chat_id, is_pinned) = split(args);
send_request(
td_api::make_object<td_api::toggleChatIsPinned>(as_chat_list(op), as_chat_id(chat_id), as_bool(is_pinned)));
} else if (op == "tcimar") {
} else if (op == "tcimau") {
string chat_id;
string is_marked_as_read;
std::tie(chat_id, is_marked_as_read) = split(args);
send_request(
td_api::make_object<td_api::toggleChatIsMarkedAsUnread>(as_chat_id(chat_id), as_bool(is_marked_as_read)));
} else if (op == "tcib") {
string chat_id;
string is_blocked;
std::tie(chat_id, is_blocked) = split(args);
send_request(td_api::make_object<td_api::toggleChatIsBlocked>(as_chat_id(chat_id), as_bool(is_blocked)));
} else if (op == "bcfr") {
string message_id;
string delete_message;
string delete_all_messages;
string report_spam;
std::tie(message_id, args) = split(args);
std::tie(delete_message, args) = split(args);
std::tie(delete_all_messages, report_spam) = split(args);
send_request(td_api::make_object<td_api::blockChatFromReplies>(
as_message_id(message_id), as_bool(delete_message), as_bool(delete_all_messages), as_bool(report_spam)));
} else if (op == "tcddn") {
string chat_id;
string default_disable_notification;
@ -2930,9 +2953,12 @@ class CliClient final : public Actor {
send_request(td_api::make_object<td_api::setPinnedChats>(as_chat_list(op), std::move(chat_ids)));
} else if (op == "sca") {
string chat_id;
string message_thread_id;
string action;
std::tie(chat_id, action) = split(args);
send_request(td_api::make_object<td_api::sendChatAction>(as_chat_id(chat_id), get_chat_action(action)));
std::tie(chat_id, args) = split(args);
std::tie(message_thread_id, action) = split(args);
send_request(td_api::make_object<td_api::sendChatAction>(
as_chat_id(chat_id), as_message_thread_id(message_thread_id), get_chat_action(action)));
} else if (op == "smt" || op == "smtp" || op == "smtf" || op == "smtpf") {
const string &chat_id = args;
for (int i = 1; i <= 200; i++) {
@ -2963,6 +2989,8 @@ class CliClient final : public Actor {
as_chat_id(chat_id), query, offset, to_integer<int32>(limit), as_search_messages_filter(filter)));
} else if (op == "ssd") {
schedule_date_ = args;
} else if (op == "smti") {
message_thread_id_ = args;
} else if (op == "sm" || op == "sms" || op == "smr" || op == "smf") {
string chat_id;
string reply_to_message_id;
@ -3005,8 +3033,8 @@ class CliClient final : public Actor {
photos = full_split(args);
send_request(td_api::make_object<td_api::sendMessageAlbum>(
as_chat_id(chat_id), as_message_id(reply_to_message_id), default_message_send_options(),
transform(photos, [](const string &photo_path) {
as_chat_id(chat_id), as_message_thread_id(message_thread_id_), as_message_id(reply_to_message_id),
default_message_send_options(), transform(photos, [](const string &photo_path) {
td_api::object_ptr<td_api::InputMessageContent> content = td_api::make_object<td_api::inputMessagePhoto>(
as_input_file(photo_path), nullptr, Auto(), 0, 0, as_caption(""), 0);
return content;
@ -3134,7 +3162,8 @@ class CliClient final : public Actor {
auto chat = as_chat_id(chat_id);
send_request(td_api::make_object<td_api::sendInlineQueryResultMessage>(
chat, 0, default_message_send_options(), to_integer<int64>(query_id), result_id, op == "siqrh"));
chat, as_message_thread_id(message_thread_id_), 0, default_message_send_options(),
to_integer<int64>(query_id), result_id, op == "siqrh"));
} else if (op == "gcqa") {
string chat_id;
string message_id;
@ -3732,25 +3761,28 @@ class CliClient final : public Actor {
} else if (status_str == "banned") {
status = td_api::make_object<td_api::chatMemberStatusBanned>(std::numeric_limits<int32>::max());
} else if (status_str == "creator") {
status = td_api::make_object<td_api::chatMemberStatusCreator>(false, "", true);
status = td_api::make_object<td_api::chatMemberStatusCreator>("", false, true);
} else if (status_str == "creatoranon") {
status = td_api::make_object<td_api::chatMemberStatusCreator>(true, "", true);
status = td_api::make_object<td_api::chatMemberStatusCreator>("", true, true);
} else if (status_str == "uncreator") {
status = td_api::make_object<td_api::chatMemberStatusCreator>(false, "", false);
status = td_api::make_object<td_api::chatMemberStatusCreator>("", false, false);
} else if (status_str == "anon") {
status = td_api::make_object<td_api::chatMemberStatusAdministrator>(true, "anon", true, true, true, true, true,
status = td_api::make_object<td_api::chatMemberStatusAdministrator>("anon", true, true, true, true, true, true,
true, true, true, true);
} else if (status_str == "anonadmin") {
status = td_api::make_object<td_api::chatMemberStatusAdministrator>("anon", false, false, false, false, false,
false, false, false, false, true);
} else if (status_str == "admin") {
status = td_api::make_object<td_api::chatMemberStatusAdministrator>(false, "", true, true, true, true, true,
true, true, true, true);
status = td_api::make_object<td_api::chatMemberStatusAdministrator>("", true, true, true, true, true, true,
true, true, true, false);
} else if (status_str == "adminq") {
status = td_api::make_object<td_api::chatMemberStatusAdministrator>(false, "title", true, true, true, true,
true, true, true, true, true);
status = td_api::make_object<td_api::chatMemberStatusAdministrator>("title", true, true, true, true, true, true,
true, true, true, false);
} else if (status_str == "minadmin") {
status = td_api::make_object<td_api::chatMemberStatusAdministrator>(false, "", true, true, false, false, false,
status = td_api::make_object<td_api::chatMemberStatusAdministrator>("", true, true, false, false, false, false,
false, false, false, false);
} else if (status_str == "unadmin") {
status = td_api::make_object<td_api::chatMemberStatusAdministrator>(false, "", true, false, false, false, false,
status = td_api::make_object<td_api::chatMemberStatusAdministrator>("", true, false, false, false, false, false,
false, false, false, false);
} else if (status_str == "rest") {
status = td_api::make_object<td_api::chatMemberStatusRestricted>(
@ -3952,12 +3984,17 @@ class CliClient final : public Actor {
} else if (op == "rrh") {
auto hashtag = std::move(args);
send_request(td_api::make_object<td_api::removeRecentHashtag>(hashtag));
} else if (op == "view") {
} else if (op == "view" || op == "viewt") {
string chat_id;
string message_thread_id;
string message_ids;
std::tie(chat_id, message_ids) = split(args);
if (op == "viewt") {
std::tie(message_thread_id, message_ids) = split(message_ids);
}
send_request(td_api::make_object<td_api::viewMessages>(as_chat_id(chat_id), as_message_ids(message_ids), true));
send_request(td_api::make_object<td_api::viewMessages>(
as_chat_id(chat_id), as_message_thread_id(message_thread_id), as_message_ids(message_ids), true));
} else if (op == "omc") {
string chat_id;
string message_id;
@ -4364,6 +4401,7 @@ class CliClient final : public Actor {
int32 my_id_ = 0;
string schedule_date_;
string message_thread_id_;
ConcurrentScheduler *scheduler_{nullptr};
@ -4469,8 +4507,8 @@ void main(int argc, char **argv) {
[&](Slice parameter) { api_id = to_integer<int32>(parameter); });
options.add_option('\0', "api_id", "Set Telegram API ID",
[&](Slice parameter) { api_id = to_integer<int32>(parameter); });
options.add_option('\0', "api-hash", "Set Telegram API hash", [&](Slice parameter) { api_hash = parameter.str(); });
options.add_option('\0', "api_hash", "Set Telegram API hash", [&](Slice parameter) { api_hash = parameter.str(); });
options.add_option('\0', "api-hash", "Set Telegram API hash", OptionParser::parse_string(api_hash));
options.add_option('\0', "api_hash", "Set Telegram API hash", OptionParser::parse_string(api_hash));
options.add_check([&] {
if (api_id == 0 || api_hash.empty()) {
return Status::Error("You must provide valid api-id and api-hash obtained at https://my.telegram.org");

View File

@ -278,7 +278,7 @@ class FileDb : public FileDbInterface {
//LOG(DEBUG) << "By id " << id.get() << " found data " << format::as_hex_dump<4>(Slice(data_str));
//LOG(INFO) << attempt_count;
logevent::WithVersion<TlParser> parser(data_str);
log_event::WithVersion<TlParser> parser(data_str);
parser.set_version(static_cast<int32>(Version::Initial));
FileData data;
data.parse(parser, true);
@ -316,7 +316,7 @@ Status fix_file_remote_location_key_bug(SqliteDb &db) {
CHECK(TlParser(key).fetch_int() == OLD_KEY_MAGIC);
auto remote_str = PSTRING() << key.substr(4, 4) << Slice("\0\0\0\0") << key.substr(8);
FullRemoteFileLocation remote;
logevent::WithVersion<TlParser> parser(remote_str);
log_event::WithVersion<TlParser> parser(remote_str);
parser.set_version(static_cast<int32>(Version::Initial));
parse(remote, parser);
parser.fetch_end();

View File

@ -10,6 +10,7 @@
#include "td/telegram/Global.h"
#include "td/utils/format.h"
#include "td/utils/misc.h"
namespace td {
@ -21,16 +22,17 @@ FileGcParameters::FileGcParameters(int64 size, int32 ttl, int32 count, int32 imm
, exclude_owner_dialog_ids(std::move(exclude_owner_dialog_ids))
, dialog_limit(dialog_limit) {
auto &config = G()->shared_config();
this->max_files_size =
size >= 0 ? size : static_cast<int64>(config.get_option_integer("storage_max_files_size", 100 << 10)) << 10;
this->max_files_size = size >= 0 ? size : config.get_option_integer("storage_max_files_size", 100 << 10) << 10;
this->max_time_from_last_access =
ttl >= 0 ? ttl : config.get_option_integer("storage_max_time_from_last_access", 60 * 60 * 23);
ttl >= 0 ? ttl : narrow_cast<int32>(config.get_option_integer("storage_max_time_from_last_access", 60 * 60 * 23));
this->max_file_count = count >= 0 ? count : config.get_option_integer("storage_max_file_count", 40000);
this->max_file_count =
count >= 0 ? count : narrow_cast<int32>(config.get_option_integer("storage_max_file_count", 40000));
this->immunity_delay =
immunity_delay >= 0 ? immunity_delay : config.get_option_integer("storage_immunity_delay", 60 * 60);
this->immunity_delay = immunity_delay >= 0
? immunity_delay
: narrow_cast<int32>(config.get_option_integer("storage_immunity_delay", 60 * 60));
}
StringBuilder &operator<<(StringBuilder &string_builder, const FileGcParameters &parameters) {

View File

@ -1192,7 +1192,7 @@ Result<FileId> FileManager::register_file(FileData &&data, FileLocationSource fi
auto status = check_local_location(data.local_.full(), data.size_, skip_file_size_checks);
if (status.is_error()) {
LOG(WARNING) << "Invalid " << data.local_.full() << ": " << status << " from " << source;
LOG(INFO) << "Invalid " << data.local_.full() << ": " << status << " from " << source;
data.local_ = LocalFileLocation();
if (data.remote_.type() == RemoteFileLocation::Type::Partial) {
data.remote_ = {};
@ -2940,7 +2940,7 @@ Result<FileId> FileManager::from_persistent_id_v23(Slice binary, FileType file_t
}
auto decoded_binary = zero_decode(binary);
FullRemoteFileLocation remote_location;
logevent::WithVersion<TlParser> parser(decoded_binary);
log_event::WithVersion<TlParser> parser(decoded_binary);
parser.set_version(version);
parse(remote_location, parser);
parser.fetch_end();

View File

@ -58,7 +58,7 @@ void scan_db(CancellationToken &token, CallbackT &&callback) {
if (value.substr(0, 2) == "@@") {
return true;
}
logevent::WithVersion<TlParser> parser(value);
log_event::WithVersion<TlParser> parser(value);
FileData data;
data.parse(parser, false);
if (parser.get_status().is_error()) {

View File

@ -9,7 +9,6 @@
#include "td/utils/format.h"
#include "td/utils/logging.h"
#include "td/utils/misc.h"
#include "td/utils/ScopeGuard.h"
#include <limits>
#include <numeric>

View File

@ -25,7 +25,7 @@
#include <type_traits>
namespace td {
namespace logevent {
namespace log_event {
template <class ParentT>
class WithVersion : public ParentT {
@ -96,6 +96,9 @@ class LogEvent {
ToggleDialogIsMarkedAsUnreadOnServer = 0x115,
SetDialogFolderIdOnServer = 0x116,
DeleteScheduledMessagesFromServer = 0x117,
ToggleDialogIsBlockedOnServer = 0x118,
ReadMessageThreadHistoryOnServer = 0x119,
BlockDialogFromRepliesOnServer = 0x120,
GetChannelDifference = 0x140,
AddMessagePushNotification = 0x200,
EditMessagePushNotification = 0x201,
@ -105,19 +108,19 @@ class LogEvent {
using Id = uint64;
Id logevent_id() const {
return logevent_id_;
Id log_event_id() const {
return log_event_id_;
}
void set_logevent_id(Id logevent_id) {
logevent_id_ = logevent_id;
void set_log_event_id(Id log_event_id) {
log_event_id_ = log_event_id;
}
virtual StringBuilder &print(StringBuilder &sb) const {
return sb << "[Logevent " << tag("id", logevent_id()) << "]";
return sb << "[Logevent " << tag("id", log_event_id()) << "]";
}
private:
Id logevent_id_{};
Id log_event_id_{};
};
inline StringBuilder &operator<<(StringBuilder &sb, const LogEvent &log_event) {
return log_event.print(sb);
@ -230,24 +233,6 @@ class LogEventStorerUnsafe : public WithContext<TlStorerUnsafe, Global *> {
}
};
} // namespace logevent
using LogEvent = logevent::LogEvent;
using LogEventParser = logevent::LogEventParser;
using LogEventStorerCalcLength = logevent::LogEventStorerCalcLength;
using LogEventStorerUnsafe = logevent::LogEventStorerUnsafe;
template <class T>
Status log_event_parse(T &data, Slice slice) TD_WARN_UNUSED_RESULT;
template <class T>
Status log_event_parse(T &data, Slice slice) {
LogEventParser parser(slice);
parse(data, parser);
parser.fetch_end();
return parser.get_status();
}
template <class T>
class LogEventStorerImpl : public Storer {
public:
@ -273,6 +258,24 @@ class LogEventStorerImpl : public Storer {
const T &event_;
};
} // namespace log_event
using LogEvent = log_event::LogEvent;
using LogEventParser = log_event::LogEventParser;
using LogEventStorerCalcLength = log_event::LogEventStorerCalcLength;
using LogEventStorerUnsafe = log_event::LogEventStorerUnsafe;
template <class T>
Status log_event_parse(T &data, Slice slice) TD_WARN_UNUSED_RESULT;
template <class T>
Status log_event_parse(T &data, Slice slice) {
LogEventParser parser(slice);
parse(data, parser);
parser.fetch_end();
return parser.get_status();
}
template <class T>
BufferSlice log_event_store(const T &data) {
LogEventStorerCalcLength storer_calc_length;
@ -292,4 +295,9 @@ BufferSlice log_event_store(const T &data) {
return value_buffer;
}
template <class T>
log_event::LogEventStorerImpl<T> get_log_event_storer(const T &event) {
return log_event::LogEventStorerImpl<T>(event);
}
} // namespace td

View File

@ -0,0 +1,56 @@
//
// Copyright Aliaksei Levin (levlam@telegram.org), Arseny Smirnov (arseny30@gmail.com) 2014-2020
//
// 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/logevent/LogEventHelper.h"
#include "td/telegram/Global.h"
#include "td/telegram/TdDb.h"
#include "tddb/td/db/binlog/BinlogHelper.h"
#include "td/utils/logging.h"
#include "td/utils/Status.h"
namespace td {
void add_log_event(LogEventIdWithGeneration &log_event_id, const Storer &storer, uint32 type, Slice name) {
LOG(INFO) << "Save " << name << " to binlog";
if (log_event_id.log_event_id == 0) {
log_event_id.log_event_id = binlog_add(G()->td_db()->get_binlog(), type, storer);
LOG(INFO) << "Add " << name << " log event " << log_event_id.log_event_id;
} else {
auto new_log_event_id = binlog_rewrite(G()->td_db()->get_binlog(), log_event_id.log_event_id, type, storer);
LOG(INFO) << "Rewrite " << name << " log event " << log_event_id.log_event_id << " with " << new_log_event_id;
}
log_event_id.generation++;
}
void delete_log_event(LogEventIdWithGeneration &log_event_id, uint64 generation, Slice name) {
LOG(INFO) << "Finish to process " << name << " log event " << log_event_id.log_event_id << " with generation "
<< generation;
if (log_event_id.generation == generation) {
CHECK(log_event_id.log_event_id != 0);
LOG(INFO) << "Delete " << name << " log event " << log_event_id.log_event_id;
binlog_erase(G()->td_db()->get_binlog(), log_event_id.log_event_id);
log_event_id.log_event_id = 0;
}
}
Promise<Unit> get_erase_log_event_promise(uint64 log_event_id, Promise<Unit> promise) {
if (log_event_id == 0) {
return promise;
}
return PromiseCreator::lambda([log_event_id, promise = std::move(promise)](Result<Unit> result) mutable {
if (!G()->close_flag()) {
binlog_erase(G()->td_db()->get_binlog(), log_event_id);
}
promise.set_result(std::move(result));
});
}
} // namespace td

View File

@ -8,31 +8,24 @@
#include "td/actor/PromiseFuture.h"
#include "td/db/binlog/BinlogHelper.h"
#include "td/telegram/Global.h"
#include "td/telegram/TdDb.h"
#include "td/utils/common.h"
#include "td/utils/Status.h"
#include "td/utils/Slice.h"
#include "td/utils/StorerBase.h"
#include "td/utils/Time.h"
#include "td/utils/tl_helpers.h"
namespace td {
inline Promise<Unit> get_erase_logevent_promise(uint64 logevent_id, Promise<Unit> promise = Promise<Unit>()) {
if (logevent_id == 0) {
return promise;
}
struct LogEventIdWithGeneration {
uint64 log_event_id = 0;
uint64 generation = 0;
};
return PromiseCreator::lambda([logevent_id, promise = std::move(promise)](Result<Unit> result) mutable {
if (!G()->close_flag()) {
binlog_erase(G()->td_db()->get_binlog(), logevent_id);
}
void add_log_event(LogEventIdWithGeneration &log_event_id, const Storer &storer, uint32 type, Slice name);
promise.set_result(std::move(result));
});
}
void delete_log_event(LogEventIdWithGeneration &log_event_id, uint64 generation, Slice name);
Promise<Unit> get_erase_log_event_promise(uint64 log_event_id, Promise<Unit> promise = Promise<Unit>());
template <class StorerT>
void store_time(double time_at, StorerT &storer) {

View File

@ -20,7 +20,7 @@
#include "td/telegram/telegram_api.h"
namespace td {
namespace logevent {
namespace log_event {
class SecretChatEvent : public LogEventBase<SecretChatEvent> {
public:
@ -296,7 +296,7 @@ class InboundSecretMessage : public SecretChatLogEventBase<InboundSecretMessage>
}
StringBuilder &print(StringBuilder &sb) const override {
return sb << "[Logevent InboundSecretMessage " << tag("id", logevent_id()) << tag("chat_id", chat_id)
return sb << "[Logevent InboundSecretMessage " << tag("id", log_event_id()) << tag("chat_id", chat_id)
<< tag("date", date) << tag("auth_key_id", format::as_hex(auth_key_id)) << tag("message_id", message_id)
<< tag("my_in_seq_no", my_in_seq_no) << tag("my_out_seq_no", my_out_seq_no)
<< tag("his_in_seq_no", his_in_seq_no) << tag("message", to_string(decrypted_message_layer))
@ -402,7 +402,7 @@ class OutboundSecretMessage : public SecretChatLogEventBase<OutboundSecretMessag
}
StringBuilder &print(StringBuilder &sb) const override {
return sb << "[Logevent OutboundSecretMessage " << tag("id", logevent_id()) << tag("chat_id", chat_id)
return sb << "[Logevent OutboundSecretMessage " << tag("id", log_event_id()) << tag("chat_id", chat_id)
<< tag("is_sent", is_sent) << tag("need_notify_user", need_notify_user)
<< tag("is_rewritable", is_rewritable) << tag("is_external", is_external) << tag("message_id", message_id)
<< tag("random_id", random_id) << tag("my_in_seq_no", my_in_seq_no) << tag("my_out_seq_no", my_out_seq_no)
@ -428,7 +428,7 @@ class CloseSecretChat : public SecretChatLogEventBase<CloseSecretChat> {
}
StringBuilder &print(StringBuilder &sb) const override {
return sb << "[Logevent CloseSecretChat " << tag("id", logevent_id()) << tag("chat_id", chat_id) << "]";
return sb << "[Logevent CloseSecretChat " << tag("id", log_event_id()) << tag("chat_id", chat_id) << "]";
}
};
@ -456,7 +456,7 @@ class CreateSecretChat : public SecretChatLogEventBase<CreateSecretChat> {
}
StringBuilder &print(StringBuilder &sb) const override {
return sb << "[Logevent CreateSecretChat " << tag("id", logevent_id()) << tag("chat_id", random_id)
return sb << "[Logevent CreateSecretChat " << tag("id", log_event_id()) << tag("chat_id", random_id)
<< tag("user_id", user_id) << "]";
}
};
@ -480,10 +480,10 @@ void SecretChatEvent::downcast_call(Type type, F &&f) {
break;
}
}
} // namespace logevent
} // namespace log_event
inline auto create_storer(logevent::SecretChatEvent &event) {
return logevent::detail::StorerImpl<logevent::SecretChatEvent>(event);
inline auto create_storer(log_event::SecretChatEvent &event) {
return log_event::detail::StorerImpl<log_event::SecretChatEvent>(event);
}
} // namespace td

View File

@ -271,7 +271,7 @@ bool NetQueryDispatcher::is_dc_inited(int32 raw_dc_id) {
return dcs_[raw_dc_id - 1].is_valid_.load(std::memory_order_relaxed);
}
int32 NetQueryDispatcher::get_session_count() {
return max(G()->shared_config().get_option_integer("session_count"), 1);
return max(narrow_cast<int32>(G()->shared_config().get_option_integer("session_count")), 1);
}
bool NetQueryDispatcher::get_use_pfs() {

View File

@ -219,7 +219,7 @@ void NetStatsManager::start_up() {
since_total_ = unix_time;
G()->td_db()->get_binlog_pmc()->set("net_stats_since", to_string(since_total_));
} else if (since < authorization_date - 3600) {
since_total_ = authorization_date;
since_total_ = narrow_cast<int32>(authorization_date);
G()->td_db()->get_binlog_pmc()->set("net_stats_since", to_string(since_total_));
} else {
since_total_ = since;

View File

@ -77,7 +77,7 @@ void PublicRsaKeyWatchdog::on_result(NetQueryPtr net_query) {
has_query_ = false;
yield();
if (net_query->is_error()) {
LOG(ERROR) << "Receive error for getCdnConfig: " << net_query->move_as_error();
LOG(ERROR) << "Receive error for GetCdnConfigQuery: " << net_query->move_as_error();
return;
}

View File

@ -127,7 +127,6 @@ class Session final
// Do not invalidate iterators of these two containers!
// TODO: better data structures
struct PriorityQueue {
public:
void push(NetQueryPtr query);
NetQueryPtr pop();
bool empty() const;

View File

@ -124,6 +124,7 @@ class unique_ptr {
return *this;
}
void reset(T *new_ptr = nullptr) noexcept {
static_assert(sizeof(T) > 0, "Can't destroy unique_ptr with incomplete type");
delete ptr_;
ptr_ = new_ptr;
}
@ -186,7 +187,7 @@ using tl_object_ptr = tl::unique_ptr<Type>;
* auto get_authorization_state_request = td::make_tl_object<td::td_api::getAuthorizationState>();
* auto message_text = td::make_tl_object<td::td_api::formattedText>("Hello, world!!!",
* std::vector<td::tl_object_ptr<td::td_api::textEntity>>());
* auto send_message_request = td::make_tl_object<td::td_api::sendMessage>(chat_id, 0, nullptr, nullptr,
* auto send_message_request = td::make_tl_object<td::td_api::sendMessage>(chat_id, 0, 0, nullptr, nullptr,
* td::make_tl_object<td::td_api::inputMessageText>(std::move(message_text), false, true));
* \endcode
*

View File

@ -128,8 +128,7 @@ ActorId<SelfT> Actor::actor_id(SelfT *self) {
template <class SelfT>
ActorShared<SelfT> Actor::actor_shared(SelfT *self, uint64 id) {
CHECK(static_cast<Actor *>(self) == this);
// TODO replace with CHECK
LOG_IF(ERROR, id == 0) << "ActorShared with token 0 must not be created";
CHECK(id != 0);
return ActorShared<SelfT>(actor_id(self), id);
}

View File

@ -113,8 +113,8 @@ class TQueueImpl : public TQueue {
auto it = q.events.end();
--it;
if (it->second.data.empty()) {
if (callback_ != nullptr && it->second.logevent_id != 0) {
callback_->pop(it->second.logevent_id);
if (callback_ != nullptr && it->second.log_event_id != 0) {
callback_->pop(it->second.log_event_id);
}
q.events.erase(it);
}
@ -123,8 +123,8 @@ class TQueueImpl : public TQueue {
schedule_queue_gc(queue_id, q, raw_event.expires_at);
}
if (raw_event.logevent_id == 0 && callback_ != nullptr) {
raw_event.logevent_id = callback_->push(queue_id, raw_event);
if (raw_event.log_event_id == 0 && callback_ != nullptr) {
raw_event.log_event_id = callback_->push(queue_id, raw_event);
}
q.tail_id = event_id.next().move_as_ok();
q.total_event_length += raw_event.data.size();
@ -307,7 +307,7 @@ class TQueueImpl : public TQueue {
void pop(Queue &q, QueueId queue_id, std::map<EventId, RawEvent>::iterator &it, EventId tail_id) {
auto &event = it->second;
if (callback_ == nullptr || event.logevent_id == 0) {
if (callback_ == nullptr || event.log_event_id == 0) {
remove_event(q, it);
return;
}
@ -319,7 +319,7 @@ class TQueueImpl : public TQueue {
}
++it;
} else {
callback_->pop(event.logevent_id);
callback_->pop(event.log_event_id);
remove_event(q, it);
}
}
@ -438,16 +438,16 @@ uint64 TQueueBinlog<BinlogT>::push(QueueId queue_id, const RawEvent &event) {
log_event.data = event.data;
log_event.extra = event.extra;
auto magic = BINLOG_EVENT_TYPE + (log_event.extra != 0);
if (event.logevent_id == 0) {
if (event.log_event_id == 0) {
return binlog_->add(magic, log_event);
}
binlog_->rewrite(event.logevent_id, magic, log_event);
return event.logevent_id;
binlog_->rewrite(event.log_event_id, magic, log_event);
return event.log_event_id;
}
template <class BinlogT>
void TQueueBinlog<BinlogT>::pop(uint64 logevent_id) {
binlog_->erase(logevent_id);
void TQueueBinlog<BinlogT>::pop(uint64 log_event_id) {
binlog_->erase(log_event_id);
}
template <class BinlogT>
@ -463,7 +463,7 @@ Status TQueueBinlog<BinlogT>::replay(const BinlogEvent &binlog_event, TQueue &q)
TRY_STATUS(parser.get_status());
TRY_RESULT(event_id, EventId::from_int32(event.event_id));
RawEvent raw_event;
raw_event.logevent_id = binlog_event.id_;
raw_event.log_event_id = binlog_event.id_;
raw_event.event_id = event_id;
raw_event.expires_at = event.expires_at;
raw_event.data = event.data.str();
@ -483,19 +483,19 @@ template class TQueueBinlog<BinlogInterface>;
template class TQueueBinlog<Binlog>;
uint64 TQueueMemoryStorage::push(QueueId queue_id, const RawEvent &event) {
auto logevent_id = event.logevent_id == 0 ? next_logevent_id_++ : event.logevent_id;
events_[logevent_id] = std::make_pair(queue_id, event);
return logevent_id;
auto log_event_id = event.log_event_id == 0 ? next_log_event_id_++ : event.log_event_id;
events_[log_event_id] = std::make_pair(queue_id, event);
return log_event_id;
}
void TQueueMemoryStorage::pop(uint64 logevent_id) {
events_.erase(logevent_id);
void TQueueMemoryStorage::pop(uint64 log_event_id) {
events_.erase(log_event_id);
}
void TQueueMemoryStorage::replay(TQueue &q) const {
for (auto &e : events_) {
auto x = e.second;
x.second.logevent_id = e.first;
x.second.log_event_id = e.first;
bool is_added = q.do_push(x.first, std::move(x.second));
CHECK(is_added);
}

View File

@ -60,7 +60,7 @@ class TQueue {
};
struct RawEvent {
uint64 logevent_id{0};
uint64 log_event_id{0};
EventId event_id;
string data;
int64 extra{0};
@ -82,7 +82,7 @@ class TQueue {
virtual ~StorageCallback() = default;
virtual uint64 push(QueueId queue_id, const RawEvent &event) = 0;
virtual void pop(uint64 logevent_id) = 0;
virtual void pop(uint64 log_event_id) = 0;
virtual void close(Promise<> promise) = 0;
};
@ -125,7 +125,7 @@ template <class BinlogT>
class TQueueBinlog : public TQueue::StorageCallback {
public:
uint64 push(QueueId queue_id, const RawEvent &event) override;
void pop(uint64 logevent_id) override;
void pop(uint64 log_event_id) override;
Status replay(const BinlogEvent &binlog_event, TQueue &q) const TD_WARN_UNUSED_RESULT;
void set_binlog(std::shared_ptr<BinlogT> binlog) {
@ -141,12 +141,12 @@ class TQueueBinlog : public TQueue::StorageCallback {
class TQueueMemoryStorage : public TQueue::StorageCallback {
public:
uint64 push(QueueId queue_id, const RawEvent &event) override;
void pop(uint64 logevent_id) override;
void pop(uint64 log_event_id) override;
void replay(TQueue &q) const;
virtual void close(Promise<> promise) override;
private:
uint64 next_logevent_id_{1};
uint64 next_log_event_id_{1};
std::map<uint64, std::pair<QueueId, RawEvent>> events_;
};

View File

@ -72,20 +72,20 @@ class Binlog {
}
uint64 add(int32 type, const Storer &storer) {
auto logevent_id = next_id();
add_raw_event(BinlogEvent::create_raw(logevent_id, type, 0, storer), {});
return logevent_id;
auto log_event_id = next_id();
add_raw_event(BinlogEvent::create_raw(log_event_id, type, 0, storer), {});
return log_event_id;
}
uint64 rewrite(uint64 logevent_id, int32 type, const Storer &storer) {
uint64 rewrite(uint64 log_event_id, int32 type, const Storer &storer) {
auto seq_no = next_id();
add_raw_event(BinlogEvent::create_raw(logevent_id, type, BinlogEvent::Flags::Rewrite, storer), {});
add_raw_event(BinlogEvent::create_raw(log_event_id, type, BinlogEvent::Flags::Rewrite, storer), {});
return seq_no;
}
uint64 erase(uint64 logevent_id) {
uint64 erase(uint64 log_event_id) {
auto seq_no = next_id();
add_raw_event(BinlogEvent::create_raw(logevent_id, BinlogEvent::ServiceTypes::Empty, BinlogEvent::Flags::Rewrite,
add_raw_event(BinlogEvent::create_raw(log_event_id, BinlogEvent::ServiceTypes::Empty, BinlogEvent::Flags::Rewrite,
EmptyStorer()),
{});
return seq_no;

View File

@ -21,13 +21,13 @@ inline uint64 binlog_add(BinlogInterface *binlog_ptr, int32 type, const Storer &
return binlog_ptr->add(type, storer, std::move(promise));
}
inline uint64 binlog_rewrite(BinlogInterface *binlog_ptr, uint64 logevent_id, int32 type, const Storer &storer,
inline uint64 binlog_rewrite(BinlogInterface *binlog_ptr, uint64 log_event_id, int32 type, const Storer &storer,
Promise<> promise = Promise<>()) {
return binlog_ptr->rewrite(logevent_id, type, storer, std::move(promise));
return binlog_ptr->rewrite(log_event_id, type, storer, std::move(promise));
}
inline uint64 binlog_erase(BinlogInterface *binlog_ptr, uint64 logevent_id, Promise<> promise = Promise<>()) {
return binlog_ptr->erase(logevent_id, std::move(promise));
inline uint64 binlog_erase(BinlogInterface *binlog_ptr, uint64 log_event_id, Promise<> promise = Promise<>()) {
return binlog_ptr->erase(log_event_id, std::move(promise));
}
} // namespace td

View File

@ -43,22 +43,22 @@ class BinlogInterface {
}
uint64 add(int32 type, const Storer &storer, Promise<> promise = Promise<>()) {
auto logevent_id = next_id();
add_raw_event_impl(logevent_id, BinlogEvent::create_raw(logevent_id, type, 0, storer), std::move(promise), {});
return logevent_id;
auto log_event_id = next_id();
add_raw_event_impl(log_event_id, BinlogEvent::create_raw(log_event_id, type, 0, storer), std::move(promise), {});
return log_event_id;
}
uint64 rewrite(uint64 logevent_id, int32 type, const Storer &storer, Promise<> promise = Promise<>()) {
uint64 rewrite(uint64 log_event_id, int32 type, const Storer &storer, Promise<> promise = Promise<>()) {
auto seq_no = next_id();
add_raw_event_impl(seq_no, BinlogEvent::create_raw(logevent_id, type, BinlogEvent::Flags::Rewrite, storer),
add_raw_event_impl(seq_no, BinlogEvent::create_raw(log_event_id, type, BinlogEvent::Flags::Rewrite, storer),
std::move(promise), {});
return seq_no;
}
uint64 erase(uint64 logevent_id, Promise<> promise = Promise<>()) {
uint64 erase(uint64 log_event_id, Promise<> promise = Promise<>()) {
auto seq_no = next_id();
add_raw_event_impl(seq_no,
BinlogEvent::create_raw(logevent_id, BinlogEvent::ServiceTypes::Empty,
BinlogEvent::create_raw(log_event_id, BinlogEvent::ServiceTypes::Empty,
BinlogEvent::Flags::Rewrite, EmptyStorer()),
std::move(promise), {});
return seq_no;

View File

@ -20,7 +20,7 @@ Status BinlogEventsProcessor::do_event(BinlogEvent &&event) {
if ((event.flags_ & BinlogEvent::Flags::Rewrite) && !ids_.empty() && ids_.back() >= fixed_id) {
auto it = std::lower_bound(ids_.begin(), ids_.end(), fixed_id);
if (it == ids_.end() || *it != fixed_id) {
return Status::Error(PSLICE() << "Ignore rewrite logevent " << event.public_to_string());
return Status::Error(PSLICE() << "Ignore rewrite log event " << event.public_to_string());
}
auto pos = it - ids_.begin();
total_raw_events_size_ -= static_cast<int64>(events_[pos].raw_event_.size());

View File

@ -24,30 +24,6 @@ namespace td {
constexpr const char HttpReader::TEMP_DIRECTORY_PREFIX[];
static size_t urldecode(Slice from, MutableSlice to, bool decode_plus_sign_as_space) {
size_t to_i = 0;
CHECK(to.size() >= from.size());
for (size_t from_i = 0, n = from.size(); from_i < n; from_i++) {
if (from[from_i] == '%' && from_i + 2 < n) {
int high = hex_to_int(from[from_i + 1]);
int low = hex_to_int(from[from_i + 2]);
if (high < 16 && low < 16) {
to[to_i++] = static_cast<char>(high * 16 + low);
from_i += 2;
continue;
}
}
to[to_i++] = decode_plus_sign_as_space && from[from_i] == '+' ? ' ' : from[from_i];
}
return to_i;
}
static MutableSlice urldecode_inplace(MutableSlice str, bool decode_plus_sign_as_space) {
size_t result_size = urldecode(str, str, decode_plus_sign_as_space);
str.truncate(result_size);
return str;
}
void HttpReader::init(ChainBufferReader *input, size_t max_post_size, size_t max_files) {
input_ = input;
state_ = State::ReadHeaders;
@ -571,7 +547,7 @@ Status HttpReader::parse_url(MutableSlice url) {
url_path_size++;
}
query_->url_path_ = urldecode_inplace({url.data(), url_path_size}, false);
query_->url_path_ = url_decode_inplace({url.data(), url_path_size}, false);
if (url_path_size == url.size() || url[url_path_size] != '?') {
return Status::OK();
@ -591,9 +567,9 @@ Status HttpReader::parse_parameters(MutableSlice parameters) {
auto key_value = parser.read_till_nofail('&');
parser.skip_nofail('&');
Parser kv_parser(key_value);
auto key = urldecode_inplace(kv_parser.read_till_nofail('='), true);
auto key = url_decode_inplace(kv_parser.read_till_nofail('='), true);
kv_parser.skip_nofail('=');
auto value = urldecode_inplace(kv_parser.data(), true);
auto value = url_decode_inplace(kv_parser.data(), true);
query_->args_.emplace_back(key, value);
}

View File

@ -291,7 +291,7 @@ Result<SslCtx> create_ssl_ctx(CSlice cert_file, SslStream::VerifyPeer verify_pee
class SslStreamImpl {
public:
Status init(CSlice host, CSlice cert_file, SslStream::VerifyPeer verify_peer) {
Status init(CSlice host, CSlice cert_file, SslStream::VerifyPeer verify_peer, bool check_ip_address_as_host) {
static bool init_openssl = [] {
#if OPENSSL_VERSION_NUMBER >= 0x10100000L
return OPENSSL_init_ssl(0, nullptr) != 0;
@ -317,7 +317,7 @@ class SslStreamImpl {
#if OPENSSL_VERSION_NUMBER >= 0x10002000L
X509_VERIFY_PARAM *param = SSL_get0_param(ssl_handle.get());
X509_VERIFY_PARAM_set_hostflags(param, 0);
if (r_ip_address.is_ok()) {
if (r_ip_address.is_ok() && !check_ip_address_as_host) {
LOG(DEBUG) << "Set verification IP address to " << r_ip_address.ok().get_ip_str();
X509_VERIFY_PARAM_set1_ip_asc(param, r_ip_address.ok().get_ip_str().c_str());
} else {
@ -509,9 +509,10 @@ SslStream::SslStream(SslStream &&) = default;
SslStream &SslStream::operator=(SslStream &&) = default;
SslStream::~SslStream() = default;
Result<SslStream> SslStream::create(CSlice host, CSlice cert_file, VerifyPeer verify_peer) {
Result<SslStream> SslStream::create(CSlice host, CSlice cert_file, VerifyPeer verify_peer,
bool use_ip_address_as_host) {
auto impl = make_unique<detail::SslStreamImpl>();
TRY_STATUS(impl->init(host, cert_file, verify_peer));
TRY_STATUS(impl->init(host, cert_file, verify_peer, use_ip_address_as_host));
return SslStream(std::move(impl));
}
SslStream::SslStream(unique_ptr<detail::SslStreamImpl> impl) : impl_(std::move(impl)) {

View File

@ -25,7 +25,8 @@ class SslStream {
enum class VerifyPeer { On, Off };
static Result<SslStream> create(CSlice host, CSlice cert_file = CSlice(), VerifyPeer verify_peer = VerifyPeer::On);
static Result<SslStream> create(CSlice host, CSlice cert_file = CSlice(), VerifyPeer verify_peer = VerifyPeer::On,
bool check_ip_address_as_host = false);
ByteFlowInterface &read_byte_flow();
ByteFlowInterface &write_byte_flow();

View File

@ -339,6 +339,9 @@ if (WIN32)
else()
target_link_libraries(tdutils PRIVATE ws2_32 Mswsock Normaliz psapi)
endif()
if (NOT CMAKE_SYSTEM_NAME STREQUAL "WindowsStore")
target_link_libraries(tdutils PRIVATE shell32)
endif()
endif()
if (ANDROID)

View File

@ -65,6 +65,10 @@ int64 FileLog::get_rotate_threshold() const {
return rotate_threshold_;
}
bool FileLog::get_redirect_stderr() const {
return redirect_stderr_;
}
void FileLog::append(CSlice cslice, int log_level) {
Slice slice = cslice;
while (!slice.empty()) {

View File

@ -32,6 +32,8 @@ class FileLog : public LogInterface {
int64 get_rotate_threshold() const;
bool get_redirect_stderr() const;
void append(CSlice cslice, int log_level) override;
void rotate() override;

View File

@ -7,12 +7,25 @@
#include "td/utils/OptionParser.h"
#include "td/utils/logging.h"
#include "td/utils/PathView.h"
#if TD_PORT_WINDOWS && WINAPI_FAMILY_PARTITION(WINAPI_PARTITION_DESKTOP)
#include "td/utils/port/wstring_convert.h"
#endif
#include <cstring>
#include <unordered_map>
#if TD_PORT_WINDOWS && WINAPI_FAMILY_PARTITION(WINAPI_PARTITION_DESKTOP)
#include <shellapi.h>
#endif
namespace td {
void OptionParser::set_usage(Slice executable_name, Slice usage) {
PathView path_view(executable_name);
usage_ = PSTRING() << path_view.file_name() << " " << usage;
}
void OptionParser::set_description(string description) {
description_ = std::move(description);
}
@ -57,6 +70,21 @@ void OptionParser::add_check(std::function<Status()> check) {
}
Result<vector<char *>> OptionParser::run(int argc, char *argv[], int expected_non_option_count) {
#if TD_PORT_WINDOWS && WINAPI_FAMILY_PARTITION(WINAPI_PARTITION_DESKTOP)
LPWSTR *utf16_argv = CommandLineToArgvW(GetCommandLineW(), &argc);
if (utf16_argv == nullptr) {
return Status::Error("Failed to parse command line");
}
vector<string> args_storage(argc);
vector<char *> args(argc);
for (int i = 0; i < argc; i++) {
TRY_RESULT_ASSIGN(args_storage[i], from_wstring(utf16_argv[i]));
args[i] = &args_storage[i][0];
}
LocalFree(utf16_argv);
argv = &args[0];
#endif
std::unordered_map<char, const Option *> short_options;
std::unordered_map<string, const Option *> long_options;
for (auto &opt : options_) {
@ -85,7 +113,7 @@ Result<vector<char *>> OptionParser::run(int argc, char *argv[], int expected_no
if (arg[1] == '-') {
// long option
Slice long_arg(arg + 2, std::strlen(arg + 2));
Slice long_arg(arg + 2);
Slice parameter;
auto equal_pos = long_arg.find('=');
bool has_equal = equal_pos != Slice::npos;
@ -96,22 +124,22 @@ Result<vector<char *>> OptionParser::run(int argc, char *argv[], int expected_no
auto it = long_options.find(long_arg.str());
if (it == long_options.end()) {
return Status::Error(PSLICE() << "Option " << long_arg << " was unrecognized");
return Status::Error(PSLICE() << "Option \"" << long_arg << "\" is unrecognized");
}
auto option = it->second;
switch (option->type) {
case Option::Type::NoArg:
if (has_equal) {
return Status::Error(PSLICE() << "Option " << long_arg << " must not have argument");
return Status::Error(PSLICE() << "Option \"" << long_arg << "\" must not have an argument");
}
break;
case Option::Type::Arg:
if (!has_equal) {
if (++arg_pos == argc) {
return Status::Error(PSLICE() << "Option " << long_arg << " must have argument");
return Status::Error(PSLICE() << "Option \"" << long_arg << "\" requires an argument");
}
parameter = Slice(argv[arg_pos], std::strlen(argv[arg_pos]));
parameter = Slice(argv[arg_pos]);
}
break;
default:
@ -125,7 +153,7 @@ Result<vector<char *>> OptionParser::run(int argc, char *argv[], int expected_no
for (size_t opt_pos = 1; arg[opt_pos] != '\0'; opt_pos++) {
auto it = short_options.find(arg[opt_pos]);
if (it == short_options.end()) {
return Status::Error(PSLICE() << "Option " << arg[opt_pos] << " was unrecognized");
return Status::Error(PSLICE() << "Option \"" << arg[opt_pos] << "\" is unrecognized");
}
auto option = it->second;
@ -137,11 +165,11 @@ Result<vector<char *>> OptionParser::run(int argc, char *argv[], int expected_no
case Option::Type::Arg:
if (arg[opt_pos + 1] == '\0') {
if (++arg_pos == argc) {
return Status::Error(PSLICE() << "Option " << arg[opt_pos] << " must have argument");
return Status::Error(PSLICE() << "Option \"" << arg[opt_pos] << "\" requires an argument");
}
parameter = Slice(argv[arg_pos], std::strlen(argv[arg_pos]));
parameter = Slice(argv[arg_pos]);
} else {
parameter = Slice(arg + opt_pos + 1, std::strlen(arg + opt_pos + 1));
parameter = Slice(arg + opt_pos + 1);
opt_pos += parameter.size();
}
break;
@ -170,6 +198,9 @@ Result<vector<char *>> OptionParser::run(int argc, char *argv[], int expected_no
}
StringBuilder &operator<<(StringBuilder &sb, const OptionParser &o) {
if (!o.usage_.empty()) {
sb << "Usage: " << o.usage_ << "\n\n";
}
if (!o.description_.empty()) {
sb << o.description_ << ". ";
}
@ -177,9 +208,10 @@ StringBuilder &operator<<(StringBuilder &sb, const OptionParser &o) {
size_t max_length = 0;
for (auto &opt : o.options_) {
bool has_short_key = opt.short_key != '\0';
bool has_long_key = !opt.long_key.empty();
size_t length = (has_short_key ? 2 : 0) + (has_long_key ? 2 + opt.long_key.size() + 2 * has_short_key : 0);
size_t length = 2;
if (!opt.long_key.empty()) {
length += 4 + opt.long_key.size();
}
if (opt.type != OptionParser::Option::Type::NoArg) {
length += 5;
}
@ -195,15 +227,18 @@ StringBuilder &operator<<(StringBuilder &sb, const OptionParser &o) {
size_t length = max_length;
if (has_short_key) {
sb << '-' << opt.short_key;
length -= 2;
} else {
sb << " ";
}
length -= 2;
if (!opt.long_key.empty()) {
if (has_short_key) {
sb << ", ";
length -= 2;
} else {
sb << " ";
}
sb << "--" << opt.long_key;
length -= 2 + opt.long_key.size();
length -= 4 + opt.long_key.size();
}
if (opt.type != OptionParser::Option::Type::NoArg) {
sb << "<arg>";

View File

@ -7,6 +7,7 @@
#pragma once
#include "td/utils/common.h"
#include "td/utils/misc.h"
#include "td/utils/Slice.h"
#include "td/utils/Status.h"
#include "td/utils/StringBuilder.h"
@ -30,6 +31,22 @@ class OptionParser {
std::function<Status(Slice)> callback);
public:
template <class T>
static std::function<Status(Slice)> parse_integer(T &value) {
return [&value](Slice value_str) {
TRY_RESULT_ASSIGN(value, to_integer_safe<T>(value_str));
return Status::OK();
};
}
static std::function<void(Slice)> parse_string(string &value) {
return [&value](Slice value_str) {
value = value_str.str();
};
}
void set_usage(Slice executable_name, Slice usage);
void set_description(string description);
void add_checked_option(char short_key, Slice long_key, Slice description, std::function<Status(Slice)> callback);
@ -54,6 +71,7 @@ class OptionParser {
private:
vector<Option> options_;
vector<std::function<Status()>> checks_;
string usage_;
string description_;
};

View File

@ -81,11 +81,10 @@ template <class T>
static char *print_int(char *current_ptr, T x) {
if (x < 0) {
if (x == std::numeric_limits<T>::min()) {
std::stringstream ss;
ss << x;
auto len = narrow_cast<int>(static_cast<std::streamoff>(ss.tellp()));
ss.read(current_ptr, len);
return current_ptr + len;
current_ptr = print_int(current_ptr, x + 1);
CHECK(current_ptr[-1] != '9');
current_ptr[-1]++;
return current_ptr;
}
*current_ptr++ = '-';

View File

@ -310,61 +310,6 @@ struct AesBlock {
static_assert(sizeof(AesBlock) == 16, "");
static_assert(sizeof(AesBlock) == AES_BLOCK_SIZE, "");
class XorBytes {
public:
static void run(const uint8 *a, const uint8 *b, uint8 *c, size_t n) {
static constexpr int BLOCK_SIZE = 16;
auto block_cnt = n / BLOCK_SIZE;
n -= block_cnt * BLOCK_SIZE;
while (block_cnt-- > 0) {
Block<BLOCK_SIZE> a_big = as<Block<BLOCK_SIZE>>(a);
Block<BLOCK_SIZE> b_big = as<Block<BLOCK_SIZE>>(b);
as<Block<BLOCK_SIZE>>(c) = a_big ^ b_big;
a += BLOCK_SIZE;
b += BLOCK_SIZE;
c += BLOCK_SIZE;
}
while (n-- > 0) {
c[n] = a[n] ^ b[n];
}
}
private:
template <size_t N>
struct alignas(N) Block {
uint8 data[N];
Block operator^(const Block &b) const & {
Block res;
for (size_t i = 0; i < N; i++) {
res.data[i] = data[i] ^ b.data[i];
}
return res;
}
};
};
struct AesCtrCounterPack {
static constexpr size_t BLOCK_COUNT = 32;
AesBlock blocks[BLOCK_COUNT];
uint8 *raw() {
return reinterpret_cast<uint8 *>(this);
}
const uint8 *raw() const {
return reinterpret_cast<const uint8 *>(this);
}
static size_t size() {
return sizeof(blocks);
}
void init(AesBlock block) {
blocks[0] = block;
for (size_t i = 1; i < BLOCK_COUNT; i++) {
blocks[i] = blocks[i - 1].inc();
}
}
};
class Evp {
public:
Evp() {
@ -396,6 +341,10 @@ class Evp {
init(Type::Cbc, false, EVP_aes_256_cbc(), key);
}
void init_encrypt_ctr(Slice key) {
init(Type::Ctr, true, EVP_aes_256_ctr(), key);
}
void init_iv(Slice iv) {
int res = EVP_CipherInit_ex(ctx_, nullptr, nullptr, nullptr, iv.ubegin(), -1);
LOG_IF(FATAL, res != 1);
@ -403,7 +352,7 @@ class Evp {
void encrypt(const uint8 *src, uint8 *dst, int size) {
// CHECK(type_ != Type::Empty && is_encrypt_);
CHECK(size % AES_BLOCK_SIZE == 0);
// CHECK(size % AES_BLOCK_SIZE == 0);
int len;
int res = EVP_EncryptUpdate(ctx_, dst, &len, src, size);
LOG_IF(FATAL, res != 1);
@ -421,7 +370,7 @@ class Evp {
private:
EVP_CIPHER_CTX *ctx_{nullptr};
enum class Type : int8 { Empty, Ecb, Cbc };
enum class Type : int8 { Empty, Ecb, Cbc, Ctr };
// Type type_{Type::Empty};
// bool is_encrypt_ = false;
@ -479,6 +428,13 @@ class AesIgeStateImpl {
encrypted_iv_.load(iv.ubegin());
plaintext_iv_.load(iv.ubegin() + AES_BLOCK_SIZE);
}
void get_iv(MutableSlice iv) {
CHECK(iv.size() == 32);
encrypted_iv_.store(iv.ubegin());
plaintext_iv_.store(iv.ubegin() + AES_BLOCK_SIZE);
}
void encrypt(Slice from, MutableSlice to) {
CHECK(from.size() % AES_BLOCK_SIZE == 0);
CHECK(to.size() >= from.size());
@ -575,92 +531,91 @@ void aes_ige_encrypt(Slice aes_key, MutableSlice aes_iv, Slice from, MutableSlic
AesIgeStateImpl state;
state.init(aes_key, aes_iv, true);
state.encrypt(from, to);
state.get_iv(aes_iv);
}
void aes_ige_decrypt(Slice aes_key, MutableSlice aes_iv, Slice from, MutableSlice to) {
AesIgeStateImpl state;
state.init(aes_key, aes_iv, false);
state.decrypt(from, to);
}
static void aes_cbc_xcrypt(Slice aes_key, MutableSlice aes_iv, Slice from, MutableSlice to, bool encrypt_flag) {
CHECK(aes_key.size() == 32);
CHECK(aes_iv.size() == 16);
AES_KEY key;
int err;
if (encrypt_flag) {
err = AES_set_encrypt_key(aes_key.ubegin(), 256, &key);
} else {
err = AES_set_decrypt_key(aes_key.ubegin(), 256, &key);
}
LOG_IF(FATAL, err != 0);
CHECK(from.size() <= to.size());
AES_cbc_encrypt(from.ubegin(), to.ubegin(), from.size(), &key, aes_iv.ubegin(), encrypt_flag);
state.get_iv(aes_iv);
}
void aes_cbc_encrypt(Slice aes_key, MutableSlice aes_iv, Slice from, MutableSlice to) {
aes_cbc_xcrypt(aes_key, aes_iv, from, to, true);
CHECK(from.size() <= to.size());
CHECK(from.size() % 16 == 0);
Evp evp;
evp.init_encrypt_cbc(aes_key);
evp.init_iv(aes_iv);
evp.encrypt(from.ubegin(), to.ubegin(), from.size());
aes_iv.copy_from(to.substr(from.size() - 16));
}
void aes_cbc_decrypt(Slice aes_key, MutableSlice aes_iv, Slice from, MutableSlice to) {
aes_cbc_xcrypt(aes_key, aes_iv, from, to, false);
CHECK(from.size() <= to.size());
CHECK(from.size() % 16 == 0);
Evp evp;
evp.init_decrypt_cbc(aes_key);
evp.init_iv(aes_iv);
aes_iv.copy_from(from.substr(from.size() - 16));
evp.decrypt(from.ubegin(), to.ubegin(), from.size());
}
struct AesCbcState::Impl {
Evp evp_;
};
AesCbcState::AesCbcState(Slice key256, Slice iv128) : raw_{SecureString(key256), SecureString(iv128)} {
CHECK(raw_.key.size() == 32);
CHECK(raw_.iv.size() == 16);
}
AesCbcState::AesCbcState(AesCbcState &&from) = default;
AesCbcState &AesCbcState::operator=(AesCbcState &&from) = default;
AesCbcState::~AesCbcState() = default;
void AesCbcState::encrypt(Slice from, MutableSlice to) {
::td::aes_cbc_encrypt(raw_.key.as_slice(), raw_.iv.as_mutable_slice(), from, to);
if (from.empty()) {
return;
}
CHECK(from.size() <= to.size());
CHECK(from.size() % 16 == 0);
if (ctx_ == nullptr) {
ctx_ = make_unique<AesCbcState::Impl>();
ctx_->evp_.init_encrypt_cbc(raw_.key.as_slice());
ctx_->evp_.init_iv(raw_.iv.as_slice());
is_encrypt_ = true;
} else {
CHECK(is_encrypt_);
}
ctx_->evp_.encrypt(from.ubegin(), to.ubegin(), from.size());
raw_.iv.as_mutable_slice().copy_from(to.substr(from.size() - 16));
}
void AesCbcState::decrypt(Slice from, MutableSlice to) {
::td::aes_cbc_decrypt(raw_.key.as_slice(), raw_.iv.as_mutable_slice(), from, to);
if (from.empty()) {
return;
}
CHECK(from.size() <= to.size());
CHECK(from.size() % 16 == 0);
if (ctx_ == nullptr) {
ctx_ = make_unique<AesCbcState::Impl>();
ctx_->evp_.init_decrypt_cbc(raw_.key.as_slice());
ctx_->evp_.init_iv(raw_.iv.as_slice());
is_encrypt_ = false;
} else {
CHECK(!is_encrypt_);
}
raw_.iv.as_mutable_slice().copy_from(from.substr(from.size() - 16));
ctx_->evp_.decrypt(from.ubegin(), to.ubegin(), from.size());
}
class AesCtrState::Impl {
public:
Impl(Slice key, Slice iv) {
CHECK(key.size() == 32);
CHECK(iv.size() == 16);
static_assert(AES_BLOCK_SIZE == 16, "");
evp_.init_encrypt_ecb(key);
counter_.load(iv.ubegin());
fill();
}
void encrypt(Slice from, MutableSlice to) {
auto *src = from.ubegin();
auto *dst = to.ubegin();
auto n = from.size();
while (n != 0) {
size_t left = encrypted_counter_.raw() + AesCtrCounterPack::size() - current_;
if (left == 0) {
fill();
left = AesCtrCounterPack::size();
}
size_t min_n = td::min(n, left);
XorBytes::run(src, current_, dst, min_n);
src += min_n;
dst += min_n;
n -= min_n;
current_ += min_n;
}
}
private:
struct AesCtrState::Impl {
Evp evp_;
uint8 *current_;
AesBlock counter_;
AesCtrCounterPack encrypted_counter_;
void fill() {
encrypted_counter_.init(counter_);
counter_ = encrypted_counter_.blocks[AesCtrCounterPack::BLOCK_COUNT - 1].inc();
current_ = encrypted_counter_.raw();
evp_.encrypt(current_, current_, static_cast<int>(AesCtrCounterPack::size()));
}
};
AesCtrState::AesCtrState() = default;
@ -669,15 +624,20 @@ AesCtrState &AesCtrState::operator=(AesCtrState &&from) = default;
AesCtrState::~AesCtrState() = default;
void AesCtrState::init(Slice key, Slice iv) {
ctx_ = make_unique<AesCtrState::Impl>(key, iv);
CHECK(key.size() == 32);
CHECK(iv.size() == 16);
ctx_ = make_unique<AesCtrState::Impl>();
ctx_->evp_.init_encrypt_ctr(key);
ctx_->evp_.init_iv(iv);
}
void AesCtrState::encrypt(Slice from, MutableSlice to) {
ctx_->encrypt(from, to);
CHECK(from.size() <= to.size());
ctx_->evp_.encrypt(from.ubegin(), to.ubegin(), from.size());
}
void AesCtrState::decrypt(Slice from, MutableSlice to) {
encrypt(from, to); // it is the same as decrypt
encrypt(from, to);
}
void sha1(Slice data, unsigned char output[20]) {

View File

@ -84,13 +84,18 @@ class AesCtrState {
void decrypt(Slice from, MutableSlice to);
private:
class Impl;
struct Impl;
unique_ptr<Impl> ctx_;
};
class AesCbcState {
public:
AesCbcState(Slice key256, Slice iv128);
AesCbcState(const AesCbcState &from) = delete;
AesCbcState &operator=(const AesCbcState &from) = delete;
AesCbcState(AesCbcState &&from);
AesCbcState &operator=(AesCbcState &&from);
~AesCbcState();
void encrypt(Slice from, MutableSlice to);
void decrypt(Slice from, MutableSlice to);
@ -104,7 +109,11 @@ class AesCbcState {
}
private:
struct Impl;
unique_ptr<Impl> ctx_;
Raw raw_;
bool is_encrypt_ = false;
};
void sha1(Slice data, unsigned char output[20]);

View File

@ -137,6 +137,30 @@ string url_encode(Slice data) {
return result;
}
size_t url_decode(Slice from, MutableSlice to, bool decode_plus_sign_as_space) {
size_t to_i = 0;
CHECK(to.size() >= from.size());
for (size_t from_i = 0, n = from.size(); from_i < n; from_i++) {
if (from[from_i] == '%' && from_i + 2 < n) {
int high = hex_to_int(from[from_i + 1]);
int low = hex_to_int(from[from_i + 2]);
if (high < 16 && low < 16) {
to[to_i++] = static_cast<char>(high * 16 + low);
from_i += 2;
continue;
}
}
to[to_i++] = decode_plus_sign_as_space && from[from_i] == '+' ? ' ' : from[from_i];
}
return to_i;
}
MutableSlice url_decode_inplace(MutableSlice str, bool decode_plus_sign_as_space) {
size_t result_size = url_decode(str, str, decode_plus_sign_as_space);
str.truncate(result_size);
return str;
}
string buffer_to_hex(Slice buffer) {
const char *hex = "0123456789ABCDEF";
string res(2 * buffer.size(), '\0');

View File

@ -380,6 +380,10 @@ string hex_encode(Slice data);
string url_encode(Slice data);
size_t url_decode(Slice from, MutableSlice to, bool decode_plus_sign_as_space);
MutableSlice url_decode_inplace(MutableSlice str, bool decode_plus_sign_as_space);
// run-time checked narrowing cast (type conversion):
namespace detail {

View File

@ -12,6 +12,7 @@
#include "td/utils/PathView.h"
#include "td/utils/port/path.h"
#include "td/utils/port/Stat.h"
#include "td/utils/Random.h"
#include "td/utils/ScopeGuard.h"
#include "td/utils/StringBuilder.h"
#include "td/utils/Time.h"
@ -20,10 +21,35 @@
namespace td {
string rand_string(int from, int to, size_t len) {
string res(len, '\0');
for (auto &c : res) {
c = static_cast<char>(Random::fast(from, to));
}
return res;
}
vector<string> rand_split(Slice str) {
vector<string> res;
size_t pos = 0;
while (pos < str.size()) {
size_t len;
if (Random::fast(0, 1) == 1) {
len = Random::fast(1, 10);
} else {
len = Random::fast(100, 200);
}
res.push_back(str.substr(pos, len).str());
pos += len;
}
return res;
}
struct TestInfo {
string name;
string result_hash; // base64
};
StringBuilder &operator<<(StringBuilder &sb, const TestInfo &info) {
// should I use JSON?
CHECK(!info.name.empty());

View File

@ -11,7 +11,6 @@
#include "td/utils/format.h"
#include "td/utils/logging.h"
#include "td/utils/port/thread.h"
#include "td/utils/Random.h"
#include "td/utils/Slice.h"
#include "td/utils/Status.h"
@ -146,29 +145,9 @@ class Stage {
std::atomic<uint64> value_{0};
};
inline string rand_string(int from, int to, size_t len) {
string res(len, '\0');
for (auto &c : res) {
c = static_cast<char>(Random::fast(from, to));
}
return res;
}
string rand_string(int from, int to, size_t len);
inline vector<string> rand_split(Slice str) {
vector<string> res;
size_t pos = 0;
while (pos < str.size()) {
size_t len;
if (Random::fast(0, 1) == 1) {
len = Random::fast(1, 10);
} else {
len = Random::fast(100, 200);
}
res.push_back(str.substr(pos, len).str());
pos += len;
}
return res;
}
vector<string> rand_split(Slice str);
template <class T1, class T2>
void assert_eq_impl(const T1 &expected, const T2 &got, const char *file, int line) {

View File

@ -46,6 +46,7 @@ class unique_ptr final {
return *this;
}
void reset(T *new_ptr = nullptr) noexcept {
static_assert(sizeof(T) > 0, "Can't destroy unique_ptr with incomplete type");
delete ptr_;
ptr_ = new_ptr;
}

View File

@ -71,17 +71,32 @@ TEST(Crypto, AesCtrState) {
td::AesCtrState state;
state.init(as_slice(key), as_slice(iv));
td::string t(length, '\0');
state.encrypt(s, t);
std::size_t pos = 0;
for (auto str : td::rand_split(td::string(length, '\0'))) {
auto len = str.size();
state.encrypt(td::Slice(s).substr(pos, len), td::MutableSlice(t).substr(pos, len));
pos += len;
}
ASSERT_EQ(answers1[i], td::crc32(t));
state.init(as_slice(key), as_slice(iv));
state.decrypt(t, t);
pos = 0;
for (auto str : td::rand_split(td::string(length, '\0'))) {
auto len = str.size();
state.decrypt(td::Slice(t).substr(pos, len), td::MutableSlice(t).substr(pos, len));
pos += len;
}
ASSERT_STREQ(td::base64_encode(s), td::base64_encode(t));
for (auto &c : iv.raw) {
c = 0xFF;
}
state.init(as_slice(key), as_slice(iv));
state.encrypt(s, t);
pos = 0;
for (auto str : td::rand_split(td::string(length, '\0'))) {
auto len = str.size();
state.encrypt(td::Slice(s).substr(pos, len), td::MutableSlice(t).substr(pos, len));
pos += len;
}
ASSERT_EQ(answers2[i], td::crc32(t));
i++;
@ -89,10 +104,10 @@ TEST(Crypto, AesCtrState) {
}
TEST(Crypto, AesIgeState) {
td::vector<td::uint32> answers1{0u, 2045698207u, 2423540300u, 525522475u, 1545267325u};
td::vector<td::uint32> answers1{0u, 2045698207u, 2423540300u, 525522475u, 1545267325u, 724143417u};
std::size_t i = 0;
for (auto length : {0, 16, 32, 256, 1024}) {
for (auto length : {0, 16, 32, 256, 1024, 65536}) {
td::uint32 seed = length;
td::string s(length, '\0');
for (auto &c : s) {
@ -114,22 +129,42 @@ TEST(Crypto, AesIgeState) {
td::AesIgeState state;
state.init(as_slice(key), as_slice(iv), true);
td::string t(length, '\0');
state.encrypt(s, t);
td::UInt256 iv_copy = iv;
td::string u(length, '\0');
std::size_t pos = 0;
for (auto str : td::rand_split(td::string(length / 16, '\0'))) {
auto len = 16 * str.size();
state.encrypt(td::Slice(s).substr(pos, len), td::MutableSlice(t).substr(pos, len));
td::aes_ige_encrypt(as_slice(key), as_slice(iv_copy), td::Slice(s).substr(pos, len),
td::MutableSlice(u).substr(pos, len));
pos += len;
}
ASSERT_EQ(answers1[i], td::crc32(t));
ASSERT_EQ(answers1[i], td::crc32(u));
state.init(as_slice(key), as_slice(iv), false);
state.decrypt(t, t);
iv_copy = iv;
pos = 0;
for (auto str : td::rand_split(td::string(length / 16, '\0'))) {
auto len = 16 * str.size();
state.decrypt(td::Slice(t).substr(pos, len), td::MutableSlice(t).substr(pos, len));
td::aes_ige_decrypt(as_slice(key), as_slice(iv_copy), td::Slice(u).substr(pos, len),
td::MutableSlice(u).substr(pos, len));
pos += len;
}
ASSERT_STREQ(td::base64_encode(s), td::base64_encode(t));
ASSERT_STREQ(td::base64_encode(s), td::base64_encode(u));
i++;
}
}
TEST(Crypto, AesCbcState) {
td::vector<td::uint32> answers1{0u, 3617355989u, 3449188102u, 186999968u, 4244808847u};
td::vector<td::uint32> answers1{0u, 3617355989u, 3449188102u, 186999968u, 4244808847u, 2626031206u};
std::size_t i = 0;
for (auto length : {0, 16, 32, 256, 1024}) {
for (auto length : {0, 16, 32, 256, 1024, 65536}) {
td::uint32 seed = length;
td::string s(length, '\0');
for (auto &c : s) {
@ -149,16 +184,34 @@ TEST(Crypto, AesCbcState) {
}
td::AesCbcState state(as_slice(key), as_slice(iv));
//state.init(as_slice(key), as_slice(iv), true);
td::string t(length, '\0');
state.encrypt(s, t);
td::UInt128 iv_copy = iv;
td::string u(length, '\0');
std::size_t pos = 0;
for (auto str : td::rand_split(td::string(length / 16, '\0'))) {
auto len = 16 * str.size();
state.encrypt(td::Slice(s).substr(pos, len), td::MutableSlice(t).substr(pos, len));
td::aes_cbc_encrypt(as_slice(key), as_slice(iv_copy), td::Slice(s).substr(pos, len),
td::MutableSlice(u).substr(pos, len));
pos += len;
}
ASSERT_EQ(answers1[i], td::crc32(t));
ASSERT_EQ(answers1[i], td::crc32(u));
//state.init(as_slice(key), as_slice(iv), false);
state = td::AesCbcState(as_slice(key), as_slice(iv));
state.decrypt(t, t);
iv_copy = iv;
pos = 0;
for (auto str : td::rand_split(td::string(length / 16, '\0'))) {
auto len = 16 * str.size();
state.decrypt(td::Slice(t).substr(pos, len), td::MutableSlice(t).substr(pos, len));
td::aes_cbc_decrypt(as_slice(key), as_slice(iv_copy), td::Slice(u).substr(pos, len),
td::MutableSlice(u).substr(pos, len));
pos += len;
}
ASSERT_STREQ(td::base64_encode(s), td::base64_encode(t));
ASSERT_STREQ(td::base64_encode(s), td::base64_encode(u));
i++;
}
}

View File

@ -589,7 +589,7 @@ class Master : public Actor {
void add_inbound_message(int32 chat_id, BufferSlice data, uint64 crc) {
CHECK(crc64(data.as_slice()) == crc);
auto event = make_unique<logevent::InboundSecretMessage>();
auto event = make_unique<log_event::InboundSecretMessage>();
event->chat_id = chat_id;
event->date = 0;
event->encrypted_message = std::move(data);
@ -668,21 +668,21 @@ class Master : public Actor {
for (auto &event : events) {
CHECK(event.type_ == LogEvent::HandlerType::SecretChats);
auto r_message = logevent::SecretChatEvent::from_buffer_slice(event.data_as_buffer_slice());
auto r_message = log_event::SecretChatEvent::from_buffer_slice(event.data_as_buffer_slice());
LOG_IF(FATAL, r_message.is_error()) << "Failed to deserialize event: " << r_message.error();
auto message = r_message.move_as_ok();
message->set_logevent_id(event.id_);
message->set_log_event_id(event.id_);
LOG(INFO) << "Process binlog event " << *message;
switch (message->get_type()) {
case logevent::SecretChatEvent::Type::InboundSecretMessage:
case log_event::SecretChatEvent::Type::InboundSecretMessage:
send_closure_later(actor_, &SecretChatActor::replay_inbound_message,
unique_ptr<logevent::InboundSecretMessage>(
static_cast<logevent::InboundSecretMessage *>(message.release())));
unique_ptr<log_event::InboundSecretMessage>(
static_cast<log_event::InboundSecretMessage *>(message.release())));
break;
case logevent::SecretChatEvent::Type::OutboundSecretMessage:
case log_event::SecretChatEvent::Type::OutboundSecretMessage:
send_closure_later(actor_, &SecretChatActor::replay_outbound_message,
unique_ptr<logevent::OutboundSecretMessage>(
static_cast<logevent::OutboundSecretMessage *>(message.release())));
unique_ptr<log_event::OutboundSecretMessage>(
static_cast<log_event::OutboundSecretMessage *>(message.release())));
break;
default:
UNREACHABLE();

View File

@ -309,7 +309,7 @@ class SetUsername : public Task {
auto chat = move_tl_object_as<td_api::chat>(res);
this->send_query(
make_tl_object<td_api::sendMessage>(
chat->id_, 0, nullptr, nullptr,
chat->id_, 0, 0, nullptr, nullptr,
make_tl_object<td_api::inputMessageText>(
make_tl_object<td_api::formattedText>(PSTRING() << tag_ << " INIT", Auto()), false, false)),
[](auto res) {});
@ -376,7 +376,7 @@ class TestA : public Task {
auto chat = move_tl_object_as<td_api::chat>(res);
for (int i = 0; i < 20; i++) {
this->send_query(make_tl_object<td_api::sendMessage>(
chat->id_, 0, nullptr, nullptr,
chat->id_, 0, 0, nullptr, nullptr,
make_tl_object<td_api::inputMessageText>(
make_tl_object<td_api::formattedText>(PSTRING() << tag_ << " " << (1000 + i), Auto()),
false, false)),
@ -424,7 +424,7 @@ class TestSecretChat : public Task {
LOG(INFO) << "SEND ENCRYPTED MESSAGES";
for (int i = 0; i < 20; i++) {
send_query(make_tl_object<td_api::sendMessage>(
chat_id_, 0, nullptr, nullptr,
chat_id_, 0, 0, nullptr, nullptr,
make_tl_object<td_api::inputMessageText>(
make_tl_object<td_api::formattedText>(PSTRING() << tag_ << " " << (1000 + i), Auto()), false,
false)),
@ -486,7 +486,7 @@ class TestFileGenerated : public Task {
file.flush_write().ensure(); // important
file.close();
this->send_query(make_tl_object<td_api::sendMessage>(
chat_id_, 0, nullptr, nullptr,
chat_id_, 0, 0, nullptr, nullptr,
make_tl_object<td_api::inputMessageDocument>(
make_tl_object<td_api::inputFileGenerated>(file_path, "square", 0),
make_tl_object<td_api::inputThumbnail>(
@ -495,7 +495,7 @@ class TestFileGenerated : public Task {
[](auto res) { check_td_error(res); });
this->send_query(
make_tl_object<td_api::sendMessage>(chat_id_, 0, nullptr, nullptr,
make_tl_object<td_api::sendMessage>(chat_id_, 0, 0, nullptr, nullptr,
make_tl_object<td_api::inputMessageDocument>(
make_tl_object<td_api::inputFileGenerated>(file_path, "square", 0),
nullptr, true, make_tl_object<td_api::formattedText>(tag_, Auto()))),
@ -601,7 +601,7 @@ class CheckTestC : public Task {
void one_file() {
this->send_query(
make_tl_object<td_api::sendMessage>(
chat_id_, 0, nullptr, nullptr,
chat_id_, 0, 0, nullptr, nullptr,
make_tl_object<td_api::inputMessageText>(
make_tl_object<td_api::formattedText>(PSTRING() << tag_ << " ONE_FILE", Auto()), false, false)),
[](auto res) { check_td_error(res); });