// // Copyright Aliaksei Levin (levlam@telegram.org), Arseny Smirnov (arseny30@gmail.com) 2014-2026 // // Distributed under the Boost Software License, Version 1.0. (See accompanying // file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) // #pragma once #include "td/telegram/AffectedHistory.h" #include "td/telegram/BusinessConnectionId.h" #include "td/telegram/ChannelId.h" #include "td/telegram/DialogId.h" #include "td/telegram/DialogListId.h" #include "td/telegram/EmojiGameInfo.h" #include "td/telegram/EphemeralMessageId.h" #include "td/telegram/files/FileId.h" #include "td/telegram/files/FileSourceId.h" #include "td/telegram/files/FileUploadId.h" #include "td/telegram/ForumTopicId.h" #include "td/telegram/MessageCover.h" #include "td/telegram/MessageFullId.h" #include "td/telegram/MessageId.h" #include "td/telegram/MessageSearchFilter.h" #include "td/telegram/MessageThreadInfo.h" #include "td/telegram/MessageTopic.h" #include "td/telegram/MessageViewer.h" #include "td/telegram/SavedMessagesTopicId.h" #include "td/telegram/td_api.h" #include "td/telegram/telegram_api.h" #include "td/telegram/UserId.h" #include "td/actor/actor.h" #include "td/actor/MultiTimeout.h" #include "td/utils/common.h" #include "td/utils/FlatHashMap.h" #include "td/utils/FlatHashSet.h" #include "td/utils/Promise.h" #include "td/utils/Status.h" #include "td/utils/WaitFreeHashMap.h" #include #include namespace td { struct BinlogEvent; struct FormattedText; struct MessageSearchOffset; class RichMessage; class Td; class MessageQueryManager final : public Actor { public: MessageQueryManager(Td *td, ActorShared<> parent); MessageQueryManager(const MessageQueryManager &) = delete; MessageQueryManager &operator=(const MessageQueryManager &) = delete; MessageQueryManager(MessageQueryManager &&) = delete; MessageQueryManager &operator=(MessageQueryManager &&) = delete; ~MessageQueryManager() final; using AffectedHistoryQuery = std::function)>; void run_affected_history_query_until_complete(DialogId dialog_id, AffectedHistoryQuery query, bool get_affected_messages, Promise &&promise); void get_full_rich_message(MessageFullId message_full_id, Promise> &&promise); void reload_full_rich_message(MessageFullId message_full_id, Promise &&promise); FileSourceId get_rich_message_file_source_id(MessageFullId message_full_id); void upload_message_covers(BusinessConnectionId business_connection_id, DialogId dialog_id, vector covers, Promise &&promise); void upload_message_cover(BusinessConnectionId business_connection_id, DialogId dialog_id, MessageCover message_cover, FileUploadId file_upload_id, Promise &&promise, vector bad_parts = {}); void complete_upload_message_cover(BusinessConnectionId business_connection_id, DialogId dialog_id, MessageCover cover, FileUploadId file_upload_id, telegram_api::object_ptr &&media_ptr, Promise &&promise); void report_message_delivery(MessageFullId message_full_id, int32 until_date, bool from_push); void share_dialogs_with_bot(const td_api::object_ptr &source_ptr, int32 button_id, vector shared_dialog_ids, bool expect_user, bool only_check, Promise &&promise); void reload_message_extended_media(DialogId dialog_id, vector message_ids); void finish_get_message_extended_media(DialogId dialog_id, const vector &message_ids); void reload_message_fact_checks(DialogId dialog_id, vector message_ids); void set_message_fact_check(MessageFullId message_full_id, const FormattedText &fact_check_text, Promise &&promise); void toggle_suggested_post_approval(MessageFullId message_full_id, bool is_rejected, int32 schedule_date, const string &comment, Promise &&promise); void search_messages(DialogListId dialog_list_id, bool ignore_folder_id, const string &query, const string &offset_str, int32 limit, MessageSearchFilter filter, td_api::object_ptr &&dialog_type_filter, int32 min_date, int32 max_date, Promise> &&promise); void on_get_messages_search_result(const string &query, int32 offset_date, DialogId offset_dialog_id, MessageId offset_message_id, int32 limit, MessageSearchFilter filter, int32 min_date, int32 max_date, int32 total_count, vector> &&messages, int32 next_rate, Promise> &&promise); void search_outgoing_document_messages(const string &query, int32 limit, Promise> &&promise); void on_get_outgoing_document_messages(vector> &&messages, Promise> &&promise); void check_search_posts_flood(const string &query, Promise> promise); void search_public_posts(const string &query, const string &offset_str, int32 limit, int64 star_count, Promise> &&promise); void on_get_public_post_search_result(const string &hashtag, const MessageSearchOffset &old_offset, int32 limit, int64 star_count, telegram_api::object_ptr flood, vector> &&messages, int32 next_rate, Promise> &&promise); void search_hashtag_posts(string hashtag, string offset_str, int32 limit, Promise> &&promise); void on_get_hashtag_search_result(const string &hashtag, const MessageSearchOffset &old_offset, int32 limit, int32 total_count, vector> &&messages, int32 next_rate, Promise> &&promise); void search_dialog_recent_location_messages(DialogId dialog_id, int32 limit, Promise> &&promise); void on_get_recent_locations(DialogId dialog_id, int32 limit, int32 total_count, vector> &&messages, Promise> &&promise); void get_dialog_message_position_from_server(DialogId dialog_id, MessageTopic message_topic, MessageSearchFilter filter, MessageId message_id, Promise &&promise); void report_music_listen(FileId file_id, int32 duration, Promise &&promise); void send_message_view_metrics(DialogId dialog_id, MessageId message_id, int32 time_in_view_ms, int32 active_time_in_view_ms, int32 height_to_viewport_ratio_per_mille, int32 seen_range_ratio_per_mille, Promise &&promise); void get_message_read_date_from_server(MessageFullId message_full_id, Promise> &&promise); void get_message_viewers(MessageFullId message_full_id, Promise> &&promise); void view_messages(DialogId dialog_id, const vector &message_ids, bool increment_view_counter); void finish_get_message_views(DialogId dialog_id, const vector &message_ids); void queue_message_reactions_reload(MessageFullId message_full_id); void queue_message_reactions_reload(DialogId dialog_id, const vector &message_ids); void try_reload_message_reactions(DialogId dialog_id, bool is_finished); bool has_message_pending_read_reactions(MessageFullId message_full_id) const; bool has_message_pending_read_poll_votes(MessageFullId message_full_id) const; void get_paid_message_reaction_senders(DialogId dialog_id, Promise> &&promise); void summarize_message_text(MessageFullId message_full_id, const string &to_language_code, string tone, Promise> &&promise); void add_to_do_list_tasks(MessageFullId message_full_id, vector> &&tasks, Promise &&promise); void mark_to_do_list_tasks_as_done(MessageFullId message_full_id, vector done_task_ids, vector not_done_task_ids, Promise &&promise); void get_discussion_message(DialogId dialog_id, MessageId message_id, DialogId expected_dialog_id, MessageId expected_message_id, Promise &&promise); void process_discussion_message(telegram_api::object_ptr &&result, DialogId dialog_id, MessageId message_id, DialogId expected_dialog_id, MessageId expected_message_id, Promise promise); void get_emoji_game_info(Promise> &&promise); void block_message_sender_from_replies_on_server(MessageId message_id, bool need_delete_message, bool need_delete_all_messages, bool report_spam, uint64 log_event_id, Promise &&promise); void edit_ephemeral_message(DialogId dialog_id, UserId receiver_user_id, EphemeralMessageId ephemeral_message_id, td_api::object_ptr &&reply_markup, td_api::object_ptr &&input_message_content, Promise &&promise); void delete_dialog_messages_by_sender(DialogId dialog_id, DialogId sender_dialog_id, Promise &&promise); void delete_dialog_messages_by_date(DialogId dialog_id, int32 min_date, int32 max_date, bool revoke, Promise &&promise); void delete_all_call_messages(bool revoke, Promise &&promise); void delete_dialog_history_on_server(DialogId dialog_id, MessageId max_message_id, bool remove_from_dialog_list, bool revoke, bool allow_error, uint64 log_event_id, Promise &&promise); static Status fix_delete_message_min_max_dates(int32 &min_date, int32 &max_date); void delete_messages_on_server(DialogId dialog_id, vector message_ids, bool revoke, uint64 log_event_id, Promise &&promise); void delete_scheduled_messages_on_server(DialogId dialog_id, vector message_ids, uint64 log_event_id, Promise &&promise); void delete_ephemeral_message_on_server(DialogId dialog_id, DialogId receiver_dialog_id, EphemeralMessageId ephemeral_message_id, uint64 log_event_id, Promise &&promise); void delete_topic_history(DialogId dialog_id, ForumTopicId forum_topic_id, Promise &&promise); void delete_reactions_by_sender(DialogId dialog_id, DialogId sender_dialog_id, Promise &&promise); void delete_reaction_by_sender(DialogId dialog_id, MessageId message_id, DialogId sender_dialog_id, Promise &&promise); void get_personal_chat_history(UserId user_id, int32 limit, Promise> &&promise); void read_all_dialog_mentions_on_server(DialogId dialog_id, uint64 log_event_id, Promise &&promise); void read_all_dialog_reactions_on_server(DialogId dialog_id, uint64 log_event_id, Promise &&promise); void read_all_topic_mentions_on_server(DialogId dialog_id, ForumTopicId forum_topic_id, uint64 log_event_id, Promise &&promise); void read_all_topic_reactions_on_server(DialogId dialog_id, ForumTopicId forum_topic_id, SavedMessagesTopicId saved_messages_topic_id, uint64 log_event_id, Promise &&promise); void read_all_dialog_poll_votes_on_server(DialogId dialog_id, ForumTopicId forum_topic_id, uint64 log_event_id, Promise &&promise); void read_message_contents_on_server(DialogId dialog_id, vector message_ids, uint64 log_event_id, Promise &&promise, bool skip_log_event = false); void read_message_reactions_on_server(DialogId dialog_id, vector message_ids); void read_message_poll_votes_on_server(DialogId dialog_id, vector message_ids); void unpin_all_dialog_messages_on_server(DialogId dialog_id, uint64 log_event_id, Promise &&promise); void unpin_all_topic_messages_on_server(DialogId dialog_id, ForumTopicId forum_topic_id, SavedMessagesTopicId saved_messages_topic_id, uint64 log_event_id, Promise &&promise); void on_update_emoji_game_info(telegram_api::object_ptr &&game_info); void get_current_state(vector> &updates) const; void on_binlog_events(vector &&events); private: class BlockMessageSenderFromRepliesOnServerLogEvent; class DeleteAllCallMessagesOnServerLogEvent; class DeleteAllChannelMessagesFromSenderOnServerLogEvent; class DeleteDialogHistoryOnServerLogEvent; class DeleteDialogMessagesByDateOnServerLogEvent; class DeleteMessagesOnServerLogEvent; class DeleteScheduledMessagesOnServerLogEvent; class DeleteEphemeralMessageOnServerLogEvent; class DeleteTopicHistoryOnServerLogEvent; class ReadAllDialogMentionsOnServerLogEvent; class ReadAllDialogReactionsOnServerLogEvent; class ReadAllPollVotesOnServerLogEvent; class ReadMessageContentsOnServerLogEvent; class UnpinAllDialogMessagesOnServerLogEvent; class UploadCoverCallback; static constexpr int32 MAX_SEARCH_MESSAGES = 100; // server-side limit struct BeingUploadedCover { BusinessConnectionId business_connection_id_; DialogId dialog_id_; MessageCover cover_; telegram_api::object_ptr input_file_; Promise promise_; }; void tear_down() final; static void on_send_message_view_metrics_timeout_callback(void *message_query_manager_ptr, int64 dialog_id_int); void send_message_view_metrics_timeout(DialogId dialog_id); void on_get_affected_history(DialogId dialog_id, AffectedHistoryQuery query, bool get_affected_messages, AffectedHistory affected_history, Promise &&promise); void on_get_full_rich_message(MessageFullId message_full_id, Result &&r_rich_message); void on_upload_cover(FileUploadId file_upload_id, telegram_api::object_ptr input_file); void on_upload_cover_error(FileUploadId file_upload_id, Status status); void do_upload_cover(FileUploadId file_upload_id, BeingUploadedCover &&being_uploaded_cover); void on_reload_message_fact_checks(DialogId dialog_id, const vector &message_ids, Result>> r_fact_checks); void on_get_message_viewers(DialogId dialog_id, MessageViewers message_viewers, bool is_recursive, Promise> &&promise); void on_read_message_reactions(DialogId dialog_id, vector &&message_ids, Result &&result); void on_read_message_poll_votes(DialogId dialog_id, vector &&message_ids, Result &&result); void do_get_paid_message_reaction_senders(DialogId dialog_id, Promise> &&promise); void process_discussion_message_impl(telegram_api::object_ptr &&result, DialogId dialog_id, MessageId message_id, DialogId expected_dialog_id, MessageId expected_message_id, Promise promise); void on_get_emoji_game_info(telegram_api::object_ptr &&result, Promise> &&promise); void erase_delete_messages_log_event(uint64 log_event_id); void delete_all_channel_messages_by_sender_on_server(ChannelId channel_id, DialogId sender_dialog_id, uint64 log_event_id, Promise &&promise); void delete_dialog_messages_by_date_on_server(DialogId dialog_id, int32 min_date, int32 max_date, bool revoke, uint64 log_event_id, Promise &&promise); void delete_all_call_messages_on_server(bool revoke, uint64 log_event_id, Promise &&promise); void delete_topic_history_on_server(DialogId dialog_id, ForumTopicId forum_topic_id, uint64 log_event_id, Promise &&promise); static uint64 save_block_message_sender_from_replies_on_server_log_event(MessageId message_id, bool need_delete_message, bool need_delete_all_messages, bool report_spam); static uint64 save_delete_all_call_messages_on_server_log_event(bool revoke); static uint64 save_delete_all_channel_messages_by_sender_on_server_log_event(ChannelId channel_id, DialogId sender_dialog_id); static uint64 save_delete_dialog_history_on_server_log_event(DialogId dialog_id, MessageId max_message_id, bool remove_from_dialog_list, bool revoke); static uint64 save_delete_dialog_messages_by_date_on_server_log_event(DialogId dialog_id, int32 min_date, int32 max_date, bool revoke); static uint64 save_delete_messages_on_server_log_event(DialogId dialog_id, const vector &message_ids, bool revoke); static uint64 save_delete_scheduled_messages_on_server_log_event(DialogId dialog_id, const vector &message_ids); static uint64 save_delete_ephemeral_message_on_server_log_event(DialogId dialog_id, DialogId receiver_dialog_id, EphemeralMessageId ephemeral_message_id); static uint64 save_delete_topic_history_on_server_log_event(DialogId dialog_id, ForumTopicId forum_topic_id); static uint64 save_read_all_dialog_mentions_on_server_log_event(DialogId dialog_id); static uint64 save_read_all_dialog_reactions_on_server_log_event(DialogId dialog_id); static uint64 save_read_all_dialog_poll_votes_on_server_log_event(DialogId dialog_id, ForumTopicId forum_topic_id); static uint64 save_read_message_contents_on_server_log_event(DialogId dialog_id, const vector &message_ids); static uint64 save_unpin_all_dialog_messages_on_server_log_event(DialogId dialog_id); FlatHashMap being_uploaded_covers_; FlatHashSet being_reloaded_extended_media_message_full_ids_; FlatHashSet being_reloaded_fact_checks_; FlatHashSet need_view_counter_increment_message_full_ids_; FlatHashSet being_reloaded_views_message_full_ids_; struct ReactionsToReload { FlatHashSet message_ids; bool is_request_sent = false; }; FlatHashMap being_reloaded_reactions_; FlatHashMap pending_read_reactions_; FlatHashMap pending_read_poll_votes_; struct MessageViewMetrics { MessageId message_id_; int32 time_in_view_ms_ = 0; int32 active_time_in_view_ms_ = 0; int32 height_to_viewport_ratio_per_mille_ = 0; int32 seen_range_ratio_per_mille_ = 0; }; FlatHashMap, DialogIdHash> pending_message_view_metrics_; std::shared_ptr upload_cover_callback_; bool is_emoji_game_info_inited_ = false; double emoji_game_info_receive_time_ = 0.0; EmojiGameInfo emoji_game_info_; FlatHashMap>>, MessageFullIdHash> get_full_rich_message_queries_; FlatHashMap, MessageFullIdHash> rich_message_file_ids_; WaitFreeHashMap rich_message_full_id_to_file_source_id_; MultiTimeout send_message_view_metrics_timeout_{"SendMessageViewMetricsTimeout"}; Td *td_; ActorShared<> parent_; }; } // namespace td