Move some methods to DialogActionManager.

This commit is contained in:
levlam 2024-01-07 00:46:36 +03:00
parent 4bc9f8d72e
commit b684039566
8 changed files with 476 additions and 415 deletions

View File

@ -6,13 +6,389 @@
//
#include "td/telegram/DialogActionManager.h"
#include "td/telegram/AuthManager.h"
#include "td/telegram/ContactsManager.h"
#include "td/telegram/DialogManager.h"
#include "td/telegram/Global.h"
#include "td/telegram/MessageContent.h"
#include "td/telegram/MessageSender.h"
#include "td/telegram/MessagesManager.h"
#include "td/telegram/net/NetQuery.h"
#include "td/telegram/SecretChatsManager.h"
#include "td/telegram/Td.h"
#include "td/telegram/telegram_api.h"
#include "td/utils/buffer.h"
#include "td/utils/logging.h"
#include "td/utils/Time.h"
#include <algorithm>
namespace td {
class SetTypingQuery final : public Td::ResultHandler {
Promise<Unit> promise_;
DialogId dialog_id_;
int32 generation_ = 0;
public:
explicit SetTypingQuery(Promise<Unit> &&promise) : promise_(std::move(promise)) {
}
NetQueryRef send(DialogId dialog_id, tl_object_ptr<telegram_api::InputPeer> &&input_peer,
MessageId top_thread_message_id, tl_object_ptr<telegram_api::SendMessageAction> &&action) {
dialog_id_ = dialog_id;
CHECK(input_peer != nullptr);
int32 flags = 0;
if (top_thread_message_id.is_valid()) {
flags |= telegram_api::messages_setTyping::TOP_MSG_ID_MASK;
}
auto query = G()->net_query_creator().create(telegram_api::messages_setTyping(
flags, std::move(input_peer), top_thread_message_id.get_server_message_id().get(), std::move(action)));
query->total_timeout_limit_ = 2;
auto result = query.get_weak();
generation_ = result.generation();
send_query(std::move(query));
return result;
}
void on_result(BufferSlice packet) final {
auto result_ptr = fetch_result<telegram_api::messages_setTyping>(packet);
if (result_ptr.is_error()) {
return on_error(result_ptr.move_as_error());
}
// ignore result
promise_.set_value(Unit());
send_closure_later(G()->dialog_action_manager(), &DialogActionManager::after_set_typing_query, dialog_id_,
generation_);
}
void on_error(Status status) final {
if (status.code() == NetQuery::Canceled) {
return promise_.set_value(Unit());
}
if (!td_->dialog_manager_->on_get_dialog_error(dialog_id_, status, "SetTypingQuery")) {
LOG(INFO) << "Receive error for set typing: " << status;
}
promise_.set_error(std::move(status));
send_closure_later(G()->dialog_action_manager(), &DialogActionManager::after_set_typing_query, dialog_id_,
generation_);
}
};
DialogActionManager::DialogActionManager(Td *td, ActorShared<> parent) : td_(td), parent_(std::move(parent)) {
active_dialog_action_timeout_.set_callback(on_active_dialog_action_timeout_callback);
active_dialog_action_timeout_.set_callback_data(static_cast<void *>(this));
}
void DialogActionManager::tear_down() {
parent_.reset();
}
void DialogActionManager::on_active_dialog_action_timeout_callback(void *dialog_action_manager_ptr,
int64 dialog_id_int) {
if (G()->close_flag()) {
return;
}
auto dialog_action_manager = static_cast<DialogActionManager *>(dialog_action_manager_ptr);
send_closure_later(dialog_action_manager->actor_id(dialog_action_manager),
&DialogActionManager::on_active_dialog_action_timeout, DialogId(dialog_id_int));
}
void DialogActionManager::on_dialog_action(DialogId dialog_id, MessageId top_thread_message_id,
DialogId typing_dialog_id, DialogAction action, int32 date,
MessageContentType message_content_type) {
if (td_->auth_manager_->is_bot() || !typing_dialog_id.is_valid()) {
return;
}
if (top_thread_message_id != MessageId() && !top_thread_message_id.is_valid()) {
LOG(ERROR) << "Ignore " << action << " in the message thread of " << top_thread_message_id;
return;
}
auto dialog_type = dialog_id.get_type();
if (action == DialogAction::get_speaking_action()) {
if ((dialog_type != DialogType::Chat && dialog_type != DialogType::Channel) || top_thread_message_id.is_valid()) {
LOG(ERROR) << "Receive " << action << " in thread of " << top_thread_message_id << " in " << dialog_id;
return;
}
return td_->messages_manager_->on_dialog_speaking_action(dialog_id, typing_dialog_id, date);
}
if (td_->dialog_manager_->is_broadcast_channel(dialog_id)) {
return;
}
auto typing_dialog_type = typing_dialog_id.get_type();
if (typing_dialog_type != DialogType::User && dialog_type != DialogType::Chat && dialog_type != DialogType::Channel) {
LOG(ERROR) << "Ignore " << action << " of " << typing_dialog_id << " in " << dialog_id;
return;
}
{
auto message_import_progress = action.get_importing_messages_action_progress();
if (message_import_progress >= 0) {
// TODO
return;
}
}
{
auto clicking_info = action.get_clicking_animated_emoji_action_info();
if (!clicking_info.data.empty()) {
if (date > G()->unix_time() - 10 && dialog_type == DialogType::User && dialog_id == typing_dialog_id) {
td_->messages_manager_->on_message_animated_emoji_clicked(
{dialog_id, MessageId(ServerMessageId(clicking_info.message_id))}, std::move(clicking_info.emoji),
std::move(clicking_info.data));
}
return;
}
}
if (is_unsent_animated_emoji_click(td_, dialog_id, action)) {
LOG(DEBUG) << "Ignore unsent " << action;
return;
}
if (!td_->messages_manager_->have_dialog(dialog_id)) {
LOG(DEBUG) << "Ignore " << action << " in unknown " << dialog_id;
return;
}
if (typing_dialog_type == DialogType::User) {
if (!td_->contacts_manager_->have_min_user(typing_dialog_id.get_user_id())) {
LOG(DEBUG) << "Ignore " << action << " of unknown " << typing_dialog_id.get_user_id();
return;
}
} else {
if (!td_->dialog_manager_->have_dialog_info_force(typing_dialog_id, "on_dialog_action")) {
LOG(DEBUG) << "Ignore " << action << " of unknown " << typing_dialog_id;
return;
}
td_->dialog_manager_->force_create_dialog(typing_dialog_id, "on_dialog_action", true);
if (!td_->messages_manager_->have_dialog(typing_dialog_id)) {
LOG(ERROR) << "Failed to create typing " << typing_dialog_id;
return;
}
}
bool is_canceled = action == DialogAction();
if ((!is_canceled || message_content_type != MessageContentType::None) && typing_dialog_type == DialogType::User) {
td_->contacts_manager_->on_update_user_local_was_online(typing_dialog_id.get_user_id(), date);
}
if (dialog_type == DialogType::User || dialog_type == DialogType::SecretChat) {
CHECK(typing_dialog_type == DialogType::User);
auto user_id = typing_dialog_id.get_user_id();
if (!td_->contacts_manager_->is_user_bot(user_id) && !td_->contacts_manager_->is_user_status_exact(user_id) &&
!td_->messages_manager_->is_dialog_opened(dialog_id) && !is_canceled) {
return;
}
}
if (is_canceled) {
// passed top_thread_message_id must be ignored
auto actions_it = active_dialog_actions_.find(dialog_id);
if (actions_it == active_dialog_actions_.end()) {
return;
}
auto &active_actions = actions_it->second;
auto it = std::find_if(
active_actions.begin(), active_actions.end(),
[typing_dialog_id](const ActiveDialogAction &action) { return action.typing_dialog_id == typing_dialog_id; });
if (it == active_actions.end()) {
return;
}
if (!(typing_dialog_type == DialogType::User &&
td_->contacts_manager_->is_user_bot(typing_dialog_id.get_user_id())) &&
!it->action.is_canceled_by_message_of_type(message_content_type)) {
return;
}
LOG(DEBUG) << "Cancel action of " << typing_dialog_id << " in " << dialog_id;
top_thread_message_id = it->top_thread_message_id;
active_actions.erase(it);
if (active_actions.empty()) {
active_dialog_actions_.erase(dialog_id);
LOG(DEBUG) << "Cancel action timeout in " << dialog_id;
active_dialog_action_timeout_.cancel_timeout(dialog_id.get());
}
} else {
if (date < G()->unix_time() - DIALOG_ACTION_TIMEOUT - 60) {
LOG(DEBUG) << "Ignore too old action of " << typing_dialog_id << " in " << dialog_id << " sent at " << date;
return;
}
auto &active_actions = active_dialog_actions_[dialog_id];
auto it = std::find_if(
active_actions.begin(), active_actions.end(),
[typing_dialog_id](const ActiveDialogAction &action) { return action.typing_dialog_id == typing_dialog_id; });
MessageId prev_top_thread_message_id;
DialogAction prev_action;
if (it != active_actions.end()) {
LOG(DEBUG) << "Re-add action of " << typing_dialog_id << " in " << dialog_id;
prev_top_thread_message_id = it->top_thread_message_id;
prev_action = it->action;
active_actions.erase(it);
} else {
LOG(DEBUG) << "Add action of " << typing_dialog_id << " in " << dialog_id;
}
active_actions.emplace_back(top_thread_message_id, typing_dialog_id, action, Time::now());
if (top_thread_message_id == prev_top_thread_message_id && action == prev_action) {
return;
}
if (top_thread_message_id != prev_top_thread_message_id && prev_top_thread_message_id.is_valid()) {
send_update_chat_action(dialog_id, prev_top_thread_message_id, typing_dialog_id, DialogAction());
}
if (active_actions.size() == 1u) {
LOG(DEBUG) << "Set action timeout in " << dialog_id;
active_dialog_action_timeout_.set_timeout_in(dialog_id.get(), DIALOG_ACTION_TIMEOUT);
}
}
if (top_thread_message_id.is_valid()) {
send_update_chat_action(dialog_id, MessageId(), typing_dialog_id, action);
}
send_update_chat_action(dialog_id, top_thread_message_id, typing_dialog_id, action);
}
void DialogActionManager::send_update_chat_action(DialogId dialog_id, MessageId top_thread_message_id,
DialogId typing_dialog_id, const DialogAction &action) {
if (td_->auth_manager_->is_bot()) {
return;
}
LOG(DEBUG) << "Send " << action << " of " << typing_dialog_id << " in thread of " << top_thread_message_id << " in "
<< dialog_id;
send_closure(G()->td(), &Td::send_update,
td_api::make_object<td_api::updateChatAction>(
td_->dialog_manager_->get_chat_id_object(dialog_id, "updateChatAction"), top_thread_message_id.get(),
get_message_sender_object(td_, typing_dialog_id, "send_update_chat_action"),
action.get_chat_action_object()));
}
void DialogActionManager::send_dialog_action(DialogId dialog_id, MessageId top_thread_message_id, DialogAction action,
Promise<Unit> &&promise) {
if (!td_->dialog_manager_->have_dialog_force(dialog_id, "send_dialog_action")) {
return promise.set_error(Status::Error(400, "Chat not found"));
}
if (top_thread_message_id != MessageId() &&
(!top_thread_message_id.is_valid() || !top_thread_message_id.is_server())) {
return promise.set_error(Status::Error(400, "Invalid message thread specified"));
}
if (td_->dialog_manager_->is_forum_channel(dialog_id) && !top_thread_message_id.is_valid()) {
top_thread_message_id = MessageId(ServerMessageId(1));
}
tl_object_ptr<telegram_api::InputPeer> input_peer;
if (action == DialogAction::get_speaking_action()) {
input_peer = td_->dialog_manager_->get_input_peer(dialog_id, AccessRights::Read);
if (input_peer == nullptr) {
return promise.set_error(Status::Error(400, "Have no access to the chat"));
}
} else {
if (!td_->dialog_manager_->have_input_peer(dialog_id, AccessRights::Write)) {
if (td_->auth_manager_->is_bot()) {
return promise.set_error(Status::Error(400, "Have no write access to the chat"));
}
return promise.set_value(Unit());
}
if (td_->dialog_manager_->is_dialog_action_unneeded(dialog_id)) {
LOG(INFO) << "Skip unneeded " << action << " in " << dialog_id;
return promise.set_value(Unit());
}
input_peer = td_->dialog_manager_->get_input_peer(dialog_id, AccessRights::Write);
CHECK(input_peer != nullptr);
}
if (dialog_id.get_type() == DialogType::SecretChat) {
send_closure(G()->secret_chats_manager(), &SecretChatsManager::send_message_action, dialog_id.get_secret_chat_id(),
action.get_secret_input_send_message_action());
promise.set_value(Unit());
return;
}
auto new_query_ref =
td_->create_handler<SetTypingQuery>(std::move(promise))
->send(dialog_id, std::move(input_peer), top_thread_message_id, action.get_input_send_message_action());
if (td_->auth_manager_->is_bot()) {
return;
}
auto &query_ref = set_typing_query_[dialog_id];
if (!query_ref.empty()) {
LOG(INFO) << "Cancel previous send chat action query";
cancel_query(query_ref);
}
query_ref = std::move(new_query_ref);
}
void DialogActionManager::cancel_send_dialog_action_queries(DialogId dialog_id) {
auto it = set_typing_query_.find(dialog_id);
if (it == set_typing_query_.end()) {
return;
}
if (!it->second.empty()) {
cancel_query(it->second);
}
set_typing_query_.erase(it);
}
void DialogActionManager::after_set_typing_query(DialogId dialog_id, int32 generation) {
auto it = set_typing_query_.find(dialog_id);
if (it != set_typing_query_.end() && (!it->second.is_alive() || it->second.generation() == generation)) {
set_typing_query_.erase(it);
}
}
void DialogActionManager::on_active_dialog_action_timeout(DialogId dialog_id) {
LOG(DEBUG) << "Receive active dialog action timeout in " << dialog_id;
auto actions_it = active_dialog_actions_.find(dialog_id);
if (actions_it == active_dialog_actions_.end()) {
return;
}
CHECK(!actions_it->second.empty());
auto now = Time::now();
DialogId prev_typing_dialog_id;
while (actions_it->second[0].start_time + DIALOG_ACTION_TIMEOUT < now + 0.1) {
CHECK(actions_it->second[0].typing_dialog_id != prev_typing_dialog_id);
prev_typing_dialog_id = actions_it->second[0].typing_dialog_id;
on_dialog_action(dialog_id, actions_it->second[0].top_thread_message_id, actions_it->second[0].typing_dialog_id,
DialogAction(), 0);
actions_it = active_dialog_actions_.find(dialog_id);
if (actions_it == active_dialog_actions_.end()) {
return;
}
CHECK(!actions_it->second.empty());
}
LOG(DEBUG) << "Schedule next action timeout in " << dialog_id;
active_dialog_action_timeout_.add_timeout_in(dialog_id.get(),
actions_it->second[0].start_time + DIALOG_ACTION_TIMEOUT - now);
}
void DialogActionManager::clear_active_dialog_actions(DialogId dialog_id) {
LOG(DEBUG) << "Clear active dialog actions in " << dialog_id;
auto actions_it = active_dialog_actions_.find(dialog_id);
while (actions_it != active_dialog_actions_.end()) {
CHECK(!actions_it->second.empty());
on_dialog_action(dialog_id, actions_it->second[0].top_thread_message_id, actions_it->second[0].typing_dialog_id,
DialogAction(), 0);
actions_it = active_dialog_actions_.find(dialog_id);
}
}
} // namespace td

View File

@ -6,9 +6,18 @@
//
#pragma once
#include "td/telegram/DialogAction.h"
#include "td/telegram/DialogId.h"
#include "td/telegram/MessageContentType.h"
#include "td/telegram/MessageId.h"
#include "td/telegram/net/NetQuery.h"
#include "td/telegram/td_api.h"
#include "td/actor/actor.h"
#include "td/actor/MultiTimeout.h"
#include "td/utils/common.h"
#include "td/utils/FlatHashMap.h"
namespace td {
@ -18,9 +27,51 @@ class DialogActionManager final : public Actor {
public:
DialogActionManager(Td *td, ActorShared<> parent);
void on_dialog_action(DialogId dialog_id, MessageId top_thread_message_id, DialogId typing_dialog_id,
DialogAction action, int32 date,
MessageContentType message_content_type = MessageContentType::None);
void send_dialog_action(DialogId dialog_id, MessageId top_thread_message_id, DialogAction action,
Promise<Unit> &&promise);
void cancel_send_dialog_action_queries(DialogId dialog_id);
void after_set_typing_query(DialogId dialog_id, int32 generation);
void clear_active_dialog_actions(DialogId dialog_id);
private:
static constexpr double DIALOG_ACTION_TIMEOUT = 5.5;
void tear_down() final;
void send_update_chat_action(DialogId dialog_id, MessageId top_thread_message_id, DialogId typing_dialog_id,
const DialogAction &action);
static void on_active_dialog_action_timeout_callback(void *dialog_action_manager_ptr, int64 dialog_id_int);
void on_active_dialog_action_timeout(DialogId dialog_id);
struct ActiveDialogAction {
MessageId top_thread_message_id;
DialogId typing_dialog_id;
DialogAction action;
double start_time;
ActiveDialogAction(MessageId top_thread_message_id, DialogId typing_dialog_id, DialogAction action,
double start_time)
: top_thread_message_id(top_thread_message_id)
, typing_dialog_id(typing_dialog_id)
, action(std::move(action))
, start_time(start_time) {
}
};
FlatHashMap<DialogId, std::vector<ActiveDialogAction>, DialogIdHash> active_dialog_actions_;
MultiTimeout active_dialog_action_timeout_{"ActiveDialogActionTimeout"};
FlatHashMap<DialogId, NetQueryRef, DialogIdHash> set_typing_query_;
Td *td_;
ActorShared<> parent_;
};

View File

@ -41,6 +41,7 @@ class CallManager;
class ConfigManager;
class ConnectionCreator;
class ContactsManager;
class DialogActionManager;
class DialogFilterManager;
class DialogManager;
class DownloadManager;
@ -246,6 +247,13 @@ class Global final : public ActorContext {
contacts_manager_ = contacts_manager;
}
ActorId<DialogActionManager> dialog_action_manager() const {
return dialog_action_manager_;
}
void set_dialog_action_manager(ActorId<DialogActionManager> dialog_action_manager) {
dialog_action_manager_ = std::move(dialog_action_manager);
}
ActorId<DialogFilterManager> dialog_filter_manager() const {
return dialog_filter_manager_;
}
@ -562,6 +570,7 @@ class Global final : public ActorContext {
ActorId<CallManager> call_manager_;
ActorId<ConfigManager> config_manager_;
ActorId<ContactsManager> contacts_manager_;
ActorId<DialogActionManager> dialog_action_manager_;
ActorId<DialogFilterManager> dialog_filter_manager_;
ActorId<DialogManager> dialog_manager_;
ActorId<DownloadManager> download_manager_;

View File

@ -10,6 +10,7 @@
#include "td/telegram/AuthManager.h"
#include "td/telegram/ContactsManager.h"
#include "td/telegram/DialogAction.h"
#include "td/telegram/DialogActionManager.h"
#include "td/telegram/DialogManager.h"
#include "td/telegram/DialogParticipantFilter.h"
#include "td/telegram/Global.h"
@ -1099,8 +1100,8 @@ void GroupCallManager::on_send_speaking_action_timeout(GroupCallId group_call_id
pending_send_speaking_action_timeout_.add_timeout_in(group_call_id.get(), 4.0);
td_->messages_manager_->send_dialog_action(group_call->dialog_id, MessageId(), DialogAction::get_speaking_action(),
Promise<Unit>());
td_->dialog_action_manager_->send_dialog_action(group_call->dialog_id, MessageId(),
DialogAction::get_speaking_action(), Promise<Unit>());
}
void GroupCallManager::on_recent_speaker_update_timeout_callback(void *group_call_manager_ptr,

View File

@ -16,7 +16,9 @@
#include "td/telegram/ChatReactions.hpp"
#include "td/telegram/ContactsManager.h"
#include "td/telegram/Dependencies.h"
#include "td/telegram/DialogAction.h"
#include "td/telegram/DialogActionBar.h"
#include "td/telegram/DialogActionManager.h"
#include "td/telegram/DialogDb.h"
#include "td/telegram/DialogFilter.h"
#include "td/telegram/DialogFilterManager.h"
@ -52,7 +54,6 @@
#include "td/telegram/MessageSender.h"
#include "td/telegram/misc.h"
#include "td/telegram/net/DcId.h"
#include "td/telegram/net/NetQuery.h"
#include "td/telegram/NotificationGroupInfo.hpp"
#include "td/telegram/NotificationGroupType.h"
#include "td/telegram/NotificationManager.h"
@ -3561,59 +3562,6 @@ class SendBotRequestedPeerQuery final : public Td::ResultHandler {
}
};
class SetTypingQuery final : public Td::ResultHandler {
Promise<Unit> promise_;
DialogId dialog_id_;
int32 generation_ = 0;
public:
explicit SetTypingQuery(Promise<Unit> &&promise) : promise_(std::move(promise)) {
}
NetQueryRef send(DialogId dialog_id, tl_object_ptr<telegram_api::InputPeer> &&input_peer,
MessageId top_thread_message_id, tl_object_ptr<telegram_api::SendMessageAction> &&action) {
dialog_id_ = dialog_id;
CHECK(input_peer != nullptr);
int32 flags = 0;
if (top_thread_message_id.is_valid()) {
flags |= telegram_api::messages_setTyping::TOP_MSG_ID_MASK;
}
auto query = G()->net_query_creator().create(telegram_api::messages_setTyping(
flags, std::move(input_peer), top_thread_message_id.get_server_message_id().get(), std::move(action)));
query->total_timeout_limit_ = 2;
auto result = query.get_weak();
generation_ = result.generation();
send_query(std::move(query));
return result;
}
void on_result(BufferSlice packet) final {
auto result_ptr = fetch_result<telegram_api::messages_setTyping>(packet);
if (result_ptr.is_error()) {
return on_error(result_ptr.move_as_error());
}
// ignore result
promise_.set_value(Unit());
send_closure_later(G()->messages_manager(), &MessagesManager::after_set_typing_query, dialog_id_, generation_);
}
void on_error(Status status) final {
if (status.code() == NetQuery::Canceled) {
return promise_.set_value(Unit());
}
if (!td_->dialog_manager_->on_get_dialog_error(dialog_id_, status, "SetTypingQuery")) {
LOG(INFO) << "Receive error for set typing: " << status;
}
promise_.set_error(std::move(status));
send_closure_later(G()->messages_manager(), &MessagesManager::after_set_typing_query, dialog_id_, generation_);
}
};
class DeleteMessagesQuery final : public Td::ResultHandler {
Promise<Unit> promise_;
DialogId dialog_id_;
@ -5282,9 +5230,6 @@ MessagesManager::MessagesManager(Td *td, ActorShared<> parent)
pending_send_dialog_action_timeout_.set_callback(on_pending_send_dialog_action_timeout_callback);
pending_send_dialog_action_timeout_.set_callback_data(static_cast<void *>(this));
active_dialog_action_timeout_.set_callback(on_active_dialog_action_timeout_callback);
active_dialog_action_timeout_.set_callback_data(static_cast<void *>(this));
preload_folder_dialog_list_timeout_.set_callback(on_preload_folder_dialog_list_timeout_callback);
preload_folder_dialog_list_timeout_.set_callback_data(static_cast<void *>(this));
@ -5407,16 +5352,6 @@ void MessagesManager::on_pending_send_dialog_action_timeout_callback(void *messa
DialogId(dialog_id_int));
}
void MessagesManager::on_active_dialog_action_timeout_callback(void *messages_manager_ptr, int64 dialog_id_int) {
if (G()->close_flag()) {
return;
}
auto messages_manager = static_cast<MessagesManager *>(messages_manager_ptr);
send_closure_later(messages_manager->actor_id(messages_manager), &MessagesManager::on_active_dialog_action_timeout,
DialogId(dialog_id_int));
}
void MessagesManager::on_preload_folder_dialog_list_timeout_callback(void *messages_manager_ptr, int64 folder_id_int) {
if (G()->close_flag()) {
return;
@ -6740,170 +6675,20 @@ void MessagesManager::on_update_created_public_broadcasts(vector<ChannelId> chan
created_public_broadcasts_ = std::move(channel_ids);
}
void MessagesManager::on_dialog_action(DialogId dialog_id, MessageId top_thread_message_id, DialogId typing_dialog_id,
DialogAction action, int32 date, MessageContentType message_content_type) {
if (td_->auth_manager_->is_bot() || !typing_dialog_id.is_valid()) {
return;
void MessagesManager::on_dialog_speaking_action(DialogId dialog_id, DialogId speaking_dialog_id, int32 date) {
const Dialog *d = get_dialog_force(dialog_id, "on_dialog_speaking_action");
if (d != nullptr && d->active_group_call_id.is_valid()) {
auto group_call_id = td_->group_call_manager_->get_group_call_id(d->active_group_call_id, dialog_id);
td_->group_call_manager_->on_user_speaking_in_group_call(group_call_id, speaking_dialog_id, false, date);
}
if (top_thread_message_id != MessageId() && !top_thread_message_id.is_valid()) {
LOG(ERROR) << "Ignore " << action << " in the message thread of " << top_thread_message_id;
return;
}
void MessagesManager::on_message_animated_emoji_clicked(MessageFullId message_full_id, string &&emoji, string &&data) {
const auto *m = get_message_force(message_full_id, "on_message_animated_emoji_clicked");
if (m != nullptr) {
on_message_content_animated_emoji_clicked(m->content.get(), message_full_id, td_, std::move(emoji),
std::move(data));
}
auto dialog_type = dialog_id.get_type();
if (action == DialogAction::get_speaking_action()) {
if ((dialog_type != DialogType::Chat && dialog_type != DialogType::Channel) || top_thread_message_id.is_valid()) {
LOG(ERROR) << "Receive " << action << " in thread of " << top_thread_message_id << " in " << dialog_id;
return;
}
const Dialog *d = get_dialog_force(dialog_id, "on_dialog_action");
if (d != nullptr && d->active_group_call_id.is_valid()) {
auto group_call_id = td_->group_call_manager_->get_group_call_id(d->active_group_call_id, dialog_id);
td_->group_call_manager_->on_user_speaking_in_group_call(group_call_id, typing_dialog_id, false, date);
}
return;
}
if (td_->dialog_manager_->is_broadcast_channel(dialog_id)) {
return;
}
auto typing_dialog_type = typing_dialog_id.get_type();
if (typing_dialog_type != DialogType::User && dialog_type != DialogType::Chat && dialog_type != DialogType::Channel) {
LOG(ERROR) << "Ignore " << action << " of " << typing_dialog_id << " in " << dialog_id;
return;
}
{
auto message_import_progress = action.get_importing_messages_action_progress();
if (message_import_progress >= 0) {
// TODO
return;
}
}
{
auto clicking_info = action.get_clicking_animated_emoji_action_info();
if (!clicking_info.data.empty()) {
if (date > G()->unix_time() - 10 && dialog_type == DialogType::User && dialog_id == typing_dialog_id) {
MessageFullId message_full_id{dialog_id, MessageId(ServerMessageId(clicking_info.message_id))};
auto *m = get_message_force(message_full_id, "on_dialog_action");
if (m != nullptr) {
on_message_content_animated_emoji_clicked(m->content.get(), message_full_id, td_,
std::move(clicking_info.emoji), std::move(clicking_info.data));
}
}
return;
}
}
if (is_unsent_animated_emoji_click(td_, dialog_id, action)) {
LOG(DEBUG) << "Ignore unsent " << action;
return;
}
if (!have_dialog(dialog_id)) {
LOG(DEBUG) << "Ignore " << action << " in unknown " << dialog_id;
return;
}
if (typing_dialog_type == DialogType::User) {
if (!td_->contacts_manager_->have_min_user(typing_dialog_id.get_user_id())) {
LOG(DEBUG) << "Ignore " << action << " of unknown " << typing_dialog_id.get_user_id();
return;
}
} else {
if (!td_->dialog_manager_->have_dialog_info_force(typing_dialog_id, "on_dialog_action")) {
LOG(DEBUG) << "Ignore " << action << " of unknown " << typing_dialog_id;
return;
}
force_create_dialog(typing_dialog_id, "on_dialog_action", true);
if (!have_dialog(typing_dialog_id)) {
LOG(ERROR) << "Failed to create typing " << typing_dialog_id;
return;
}
}
bool is_canceled = action == DialogAction();
if ((!is_canceled || message_content_type != MessageContentType::None) && typing_dialog_type == DialogType::User) {
td_->contacts_manager_->on_update_user_local_was_online(typing_dialog_id.get_user_id(), date);
}
if (dialog_type == DialogType::User || dialog_type == DialogType::SecretChat) {
CHECK(typing_dialog_type == DialogType::User);
auto user_id = typing_dialog_id.get_user_id();
if (!td_->contacts_manager_->is_user_bot(user_id) && !td_->contacts_manager_->is_user_status_exact(user_id) &&
!is_dialog_opened(dialog_id) && !is_canceled) {
return;
}
}
if (is_canceled) {
// passed top_thread_message_id must be ignored
auto actions_it = active_dialog_actions_.find(dialog_id);
if (actions_it == active_dialog_actions_.end()) {
return;
}
auto &active_actions = actions_it->second;
auto it = std::find_if(
active_actions.begin(), active_actions.end(),
[typing_dialog_id](const ActiveDialogAction &action) { return action.typing_dialog_id == typing_dialog_id; });
if (it == active_actions.end()) {
return;
}
if (!(typing_dialog_type == DialogType::User &&
td_->contacts_manager_->is_user_bot(typing_dialog_id.get_user_id())) &&
!it->action.is_canceled_by_message_of_type(message_content_type)) {
return;
}
LOG(DEBUG) << "Cancel action of " << typing_dialog_id << " in " << dialog_id;
top_thread_message_id = it->top_thread_message_id;
active_actions.erase(it);
if (active_actions.empty()) {
active_dialog_actions_.erase(dialog_id);
LOG(DEBUG) << "Cancel action timeout in " << dialog_id;
active_dialog_action_timeout_.cancel_timeout(dialog_id.get());
}
} else {
if (date < G()->unix_time() - DIALOG_ACTION_TIMEOUT - 60) {
LOG(DEBUG) << "Ignore too old action of " << typing_dialog_id << " in " << dialog_id << " sent at " << date;
return;
}
auto &active_actions = active_dialog_actions_[dialog_id];
auto it = std::find_if(
active_actions.begin(), active_actions.end(),
[typing_dialog_id](const ActiveDialogAction &action) { return action.typing_dialog_id == typing_dialog_id; });
MessageId prev_top_thread_message_id;
DialogAction prev_action;
if (it != active_actions.end()) {
LOG(DEBUG) << "Re-add action of " << typing_dialog_id << " in " << dialog_id;
prev_top_thread_message_id = it->top_thread_message_id;
prev_action = it->action;
active_actions.erase(it);
} else {
LOG(DEBUG) << "Add action of " << typing_dialog_id << " in " << dialog_id;
}
active_actions.emplace_back(top_thread_message_id, typing_dialog_id, action, Time::now());
if (top_thread_message_id == prev_top_thread_message_id && action == prev_action) {
return;
}
if (top_thread_message_id != prev_top_thread_message_id && prev_top_thread_message_id.is_valid()) {
send_update_chat_action(dialog_id, prev_top_thread_message_id, typing_dialog_id, DialogAction());
}
if (active_actions.size() == 1u) {
LOG(DEBUG) << "Set action timeout in " << dialog_id;
active_dialog_action_timeout_.set_timeout_in(dialog_id.get(), DIALOG_ACTION_TIMEOUT);
}
}
if (top_thread_message_id.is_valid()) {
send_update_chat_action(dialog_id, MessageId(), typing_dialog_id, action);
}
send_update_chat_action(dialog_id, top_thread_message_id, typing_dialog_id, action);
}
void MessagesManager::cancel_dialog_action(DialogId dialog_id, const Message *m) {
@ -6913,8 +6698,8 @@ void MessagesManager::cancel_dialog_action(DialogId dialog_id, const Message *m)
return;
}
on_dialog_action(dialog_id, MessageId() /*ignored*/, get_message_sender(m), DialogAction(), m->date,
m->content->get_type());
td_->dialog_action_manager_->on_dialog_action(dialog_id, MessageId() /*ignored*/, get_message_sender(m),
DialogAction(), m->date, m->content->get_type());
}
void MessagesManager::add_postponed_channel_update(DialogId dialog_id, tl_object_ptr<telegram_api::Update> &&update,
@ -23460,15 +23245,7 @@ void MessagesManager::set_dialog_default_send_message_as_dialog_id(DialogId dial
return promise.set_error(Status::Error(400, "Can't access specified message sender chat"));
}
{
auto it = set_typing_query_.find(dialog_id);
if (it != set_typing_query_.end()) {
if (!it->second.empty()) {
cancel_query(it->second);
}
set_typing_query_.erase(it);
}
}
td_->dialog_action_manager_->cancel_send_dialog_action_queries(dialog_id);
td_->create_handler<SaveDefaultSendAsQuery>(std::move(promise))->send(dialog_id, message_sender_dialog_id);
@ -29091,21 +28868,6 @@ void MessagesManager::send_update_chat_has_scheduled_messages(Dialog *d, bool fr
get_chat_id_object(d->dialog_id, "updateChatHasScheduledMessages"), has_scheduled_messages));
}
void MessagesManager::send_update_chat_action(DialogId dialog_id, MessageId top_thread_message_id,
DialogId typing_dialog_id, const DialogAction &action) {
if (td_->auth_manager_->is_bot()) {
return;
}
LOG(DEBUG) << "Send " << action << " of " << typing_dialog_id << " in thread of " << top_thread_message_id << " in "
<< dialog_id;
send_closure(G()->td(), &Td::send_update,
td_api::make_object<td_api::updateChatAction>(
get_chat_id_object(dialog_id, "updateChatAction"), top_thread_message_id.get(),
get_message_sender_object(td_, typing_dialog_id, "send_update_chat_action"),
action.get_chat_action_object()));
}
void MessagesManager::on_send_message_get_quick_ack(int64 random_id) {
auto it = being_sent_messages_.find(random_id);
if (it == being_sent_messages_.end()) {
@ -31388,72 +31150,6 @@ MessagesManager::NotificationInfo *MessagesManager::add_dialog_notification_info
return d->notification_info.get();
}
void MessagesManager::send_dialog_action(DialogId dialog_id, MessageId top_thread_message_id, DialogAction action,
Promise<Unit> &&promise) {
if (!have_dialog_force(dialog_id, "send_dialog_action")) {
return promise.set_error(Status::Error(400, "Chat not found"));
}
if (top_thread_message_id != MessageId() &&
(!top_thread_message_id.is_valid() || !top_thread_message_id.is_server())) {
return promise.set_error(Status::Error(400, "Invalid message thread specified"));
}
if (td_->dialog_manager_->is_forum_channel(dialog_id) && !top_thread_message_id.is_valid()) {
top_thread_message_id = MessageId(ServerMessageId(1));
}
tl_object_ptr<telegram_api::InputPeer> input_peer;
if (action == DialogAction::get_speaking_action()) {
input_peer = td_->dialog_manager_->get_input_peer(dialog_id, AccessRights::Read);
if (input_peer == nullptr) {
return promise.set_error(Status::Error(400, "Have no access to the chat"));
}
} else {
auto can_send_status = can_send_message(dialog_id);
if (can_send_status.is_error()) {
if (td_->auth_manager_->is_bot()) {
return promise.set_error(std::move(can_send_status));
}
return promise.set_value(Unit());
}
if (td_->dialog_manager_->is_dialog_action_unneeded(dialog_id)) {
LOG(INFO) << "Skip unneeded " << action << " in " << dialog_id;
return promise.set_value(Unit());
}
input_peer = td_->dialog_manager_->get_input_peer(dialog_id, AccessRights::Write);
}
if (dialog_id.get_type() == DialogType::SecretChat) {
send_closure(G()->secret_chats_manager(), &SecretChatsManager::send_message_action, dialog_id.get_secret_chat_id(),
action.get_secret_input_send_message_action());
promise.set_value(Unit());
return;
}
auto new_query_ref =
td_->create_handler<SetTypingQuery>(std::move(promise))
->send(dialog_id, std::move(input_peer), top_thread_message_id, action.get_input_send_message_action());
if (td_->auth_manager_->is_bot()) {
return;
}
auto &query_ref = set_typing_query_[dialog_id];
if (!query_ref.empty()) {
LOG(INFO) << "Cancel previous send chat action query";
cancel_query(query_ref);
}
query_ref = std::move(new_query_ref);
}
void MessagesManager::after_set_typing_query(DialogId dialog_id, int32 generation) {
auto it = set_typing_query_.find(dialog_id);
if (it != set_typing_query_.end() && (!it->second.is_alive() || it->second.generation() == generation)) {
set_typing_query_.erase(it);
}
}
void MessagesManager::on_send_dialog_action_timeout(DialogId dialog_id) {
LOG(INFO) << "Receive send_chat_action timeout in " << dialog_id;
Dialog *d = get_dialog(dialog_id);
@ -31509,46 +31205,8 @@ void MessagesManager::on_send_dialog_action_timeout(DialogId dialog_id) {
return;
}
LOG(INFO) << "Send " << action << " in " << dialog_id;
send_dialog_action(dialog_id, m->top_thread_message_id, std::move(action), Promise<Unit>());
}
void MessagesManager::on_active_dialog_action_timeout(DialogId dialog_id) {
LOG(DEBUG) << "Receive active dialog action timeout in " << dialog_id;
auto actions_it = active_dialog_actions_.find(dialog_id);
if (actions_it == active_dialog_actions_.end()) {
return;
}
CHECK(!actions_it->second.empty());
auto now = Time::now();
DialogId prev_typing_dialog_id;
while (actions_it->second[0].start_time + DIALOG_ACTION_TIMEOUT < now + 0.1) {
CHECK(actions_it->second[0].typing_dialog_id != prev_typing_dialog_id);
prev_typing_dialog_id = actions_it->second[0].typing_dialog_id;
on_dialog_action(dialog_id, actions_it->second[0].top_thread_message_id, actions_it->second[0].typing_dialog_id,
DialogAction(), 0);
actions_it = active_dialog_actions_.find(dialog_id);
if (actions_it == active_dialog_actions_.end()) {
return;
}
CHECK(!actions_it->second.empty());
}
LOG(DEBUG) << "Schedule next action timeout in " << dialog_id;
active_dialog_action_timeout_.add_timeout_in(dialog_id.get(),
actions_it->second[0].start_time + DIALOG_ACTION_TIMEOUT - now);
}
void MessagesManager::clear_active_dialog_actions(DialogId dialog_id) {
LOG(DEBUG) << "Clear active dialog actions in " << dialog_id;
auto actions_it = active_dialog_actions_.find(dialog_id);
while (actions_it != active_dialog_actions_.end()) {
CHECK(!actions_it->second.empty());
on_dialog_action(dialog_id, actions_it->second[0].top_thread_message_id, actions_it->second[0].typing_dialog_id,
DialogAction(), 0);
actions_it = active_dialog_actions_.find(dialog_id);
}
td_->dialog_action_manager_->send_dialog_action(dialog_id, m->top_thread_message_id, std::move(action),
Promise<Unit>());
}
void MessagesManager::get_dialog_filter_dialog_count(td_api::object_ptr<td_api::chatFolder> filter,
@ -35520,7 +35178,7 @@ bool MessagesManager::set_dialog_order(Dialog *d, int64 new_order, bool need_sen
if (dialog_type == DialogType::Channel && is_removed) {
remove_all_dialog_notifications(d, false, source);
remove_all_dialog_notifications(d, true, source);
clear_active_dialog_actions(dialog_id);
td_->dialog_action_manager_->clear_active_dialog_actions(dialog_id);
}
}

View File

@ -10,7 +10,6 @@
#include "td/telegram/BackgroundInfo.h"
#include "td/telegram/ChannelId.h"
#include "td/telegram/ChatReactions.h"
#include "td/telegram/DialogAction.h"
#include "td/telegram/DialogDate.h"
#include "td/telegram/DialogDb.h"
#include "td/telegram/DialogFilterDialogInfo.h"
@ -342,9 +341,9 @@ class MessagesManager final : public Actor {
void on_update_created_public_broadcasts(vector<ChannelId> channel_ids);
void on_dialog_action(DialogId dialog_id, MessageId top_thread_message_id, DialogId typing_dialog_id,
DialogAction action, int32 date,
MessageContentType message_content_type = MessageContentType::None);
void on_dialog_speaking_action(DialogId dialog_id, DialogId speaking_dialog_id, int32 date);
void on_message_animated_emoji_clicked(MessageFullId message_full_id, string &&emoji, string &&data);
void read_history_inbox(DialogId dialog_id, MessageId max_message_id, int32 unread_count, const char *source);
@ -491,11 +490,6 @@ class MessagesManager final : public Actor {
td_api::object_ptr<td_api::MessageSchedulingState> &&scheduling_state,
Promise<Unit> &&promise);
void send_dialog_action(DialogId dialog_id, MessageId top_thread_message_id, DialogAction action,
Promise<Unit> &&promise);
void after_set_typing_query(DialogId dialog_id, int32 generation);
void get_dialog_filter_dialog_count(td_api::object_ptr<td_api::chatFolder> filter, Promise<int32> &&promise);
void add_dialog_list_for_dialog_filter(DialogFilterId dialog_filter_id);
@ -1642,8 +1636,6 @@ class MessagesManager final : public Actor {
static constexpr int32 SCHEDULE_WHEN_ONLINE_DATE = 2147483646;
static constexpr double DIALOG_ACTION_TIMEOUT = 5.5;
static constexpr const char *DELETE_MESSAGE_USER_REQUEST_SOURCE = "user request";
static constexpr bool DROP_SEND_MESSAGE_UPDATES = false;
@ -2403,9 +2395,6 @@ class MessagesManager final : public Actor {
void send_update_chat_has_scheduled_messages(Dialog *d, bool from_deletion);
void send_update_chat_action(DialogId dialog_id, MessageId top_thread_message_id, DialogId typing_dialog_id,
const DialogAction &action);
void repair_dialog_action_bar(Dialog *d, const char *source);
void hide_dialog_action_bar(Dialog *d);
@ -2601,10 +2590,6 @@ class MessagesManager final : public Actor {
void on_send_dialog_action_timeout(DialogId dialog_id);
void on_active_dialog_action_timeout(DialogId dialog_id);
void clear_active_dialog_actions(DialogId dialog_id);
void cancel_dialog_action(DialogId dialog_id, const Message *m);
Dialog *get_dialog_by_message_id(MessageId message_id);
@ -2999,8 +2984,6 @@ class MessagesManager final : public Actor {
static void on_pending_send_dialog_action_timeout_callback(void *messages_manager_ptr, int64 dialog_id_int);
static void on_active_dialog_action_timeout_callback(void *messages_manager_ptr, int64 dialog_id_int);
static void on_preload_folder_dialog_list_timeout_callback(void *messages_manager_ptr, int64 folder_id_int);
static void on_update_viewed_messages_timeout_callback(void *messages_manager_ptr, int64 dialog_id_int);
@ -3274,23 +3257,6 @@ class MessagesManager final : public Actor {
FlatHashMap<StoryFullId, FlatHashSet<MessageFullId, MessageFullIdHash>, StoryFullIdHash>
story_to_replied_media_timestamp_messages_;
struct ActiveDialogAction {
MessageId top_thread_message_id;
DialogId typing_dialog_id;
DialogAction action;
double start_time;
ActiveDialogAction(MessageId top_thread_message_id, DialogId typing_dialog_id, DialogAction action,
double start_time)
: top_thread_message_id(top_thread_message_id)
, typing_dialog_id(typing_dialog_id)
, action(std::move(action))
, start_time(start_time) {
}
};
FlatHashMap<DialogId, std::vector<ActiveDialogAction>, DialogIdHash> active_dialog_actions_;
FlatHashMap<NotificationGroupId, DialogId, NotificationGroupIdHash> notification_group_id_to_dialog_id_;
uint64 current_message_edit_generation_ = 0;
@ -3343,7 +3309,6 @@ class MessagesManager final : public Actor {
MultiTimeout pending_unload_dialog_timeout_{"PendingUnloadDialogTimeout"};
MultiTimeout dialog_unmute_timeout_{"DialogUnmuteTimeout"};
MultiTimeout pending_send_dialog_action_timeout_{"PendingSendDialogActionTimeout"};
MultiTimeout active_dialog_action_timeout_{"ActiveDialogActionTimeout"};
MultiTimeout preload_folder_dialog_list_timeout_{"PreloadFolderDialogListTimeout"};
MultiTimeout update_viewed_messages_timeout_{"UpdateViewedMessagesTimeout"};
MultiTimeout send_update_chat_read_inbox_timeout_{"SendUpdateChatReadInboxTimeout"};
@ -3445,8 +3410,6 @@ class MessagesManager final : public Actor {
};
FlatHashMap<uint64, UnsentMediaQueue> yet_unsent_media_queues_;
FlatHashMap<DialogId, NetQueryRef, DialogIdHash> set_typing_query_;
WaitFreeHashMap<MessageFullId, FileSourceId, MessageFullIdHash> message_full_id_to_file_source_id_;
FlatHashMap<DialogId, int32, DialogIdHash> last_outgoing_forwarded_message_date_;

View File

@ -4016,6 +4016,7 @@ void Td::init_managers() {
country_info_manager_actor_ = register_actor("CountryInfoManager", country_info_manager_.get());
dialog_action_manager_ = make_unique<DialogActionManager>(this, create_reference());
dialog_action_manager_actor_ = register_actor("DialogActionManager", dialog_action_manager_.get());
G()->set_dialog_action_manager(dialog_action_manager_actor_.get());
dialog_filter_manager_ = make_unique<DialogFilterManager>(this, create_reference());
dialog_filter_manager_actor_ = register_actor("DialogFilterManager", dialog_filter_manager_.get());
G()->set_dialog_filter_manager(dialog_filter_manager_actor_.get());
@ -5980,8 +5981,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_), MessageId(request.message_thread_id_),
DialogAction(std::move(request.action_)), std::move(promise));
dialog_action_manager_->send_dialog_action(DialogId(request.chat_id_), MessageId(request.message_thread_id_),
DialogAction(std::move(request.action_)), std::move(promise));
}
void Td::on_request(uint64 id, td_api::forwardMessages &request) {

View File

@ -20,6 +20,7 @@
#include "td/telegram/ConfigManager.h"
#include "td/telegram/ContactsManager.h"
#include "td/telegram/DialogAction.h"
#include "td/telegram/DialogActionManager.h"
#include "td/telegram/DialogFilterManager.h"
#include "td/telegram/DialogId.h"
#include "td/telegram/DialogInviteLink.h"
@ -3888,29 +3889,30 @@ bool UpdatesManager::is_channel_pts_update(const telegram_api::Update *update) {
void UpdatesManager::on_update(tl_object_ptr<telegram_api::updateUserTyping> update, Promise<Unit> &&promise) {
DialogId dialog_id(UserId(update->user_id_));
td_->messages_manager_->on_dialog_action(dialog_id, MessageId(), dialog_id, DialogAction(std::move(update->action_)),
get_short_update_date());
td_->dialog_action_manager_->on_dialog_action(dialog_id, MessageId(), dialog_id,
DialogAction(std::move(update->action_)), get_short_update_date());
promise.set_value(Unit());
}
void UpdatesManager::on_update(tl_object_ptr<telegram_api::updateChatUserTyping> update, Promise<Unit> &&promise) {
td_->messages_manager_->on_dialog_action(DialogId(ChatId(update->chat_id_)), MessageId(), DialogId(update->from_id_),
DialogAction(std::move(update->action_)), get_short_update_date());
td_->dialog_action_manager_->on_dialog_action(DialogId(ChatId(update->chat_id_)), MessageId(),
DialogId(update->from_id_), DialogAction(std::move(update->action_)),
get_short_update_date());
promise.set_value(Unit());
}
void UpdatesManager::on_update(tl_object_ptr<telegram_api::updateChannelUserTyping> update, Promise<Unit> &&promise) {
td_->messages_manager_->on_dialog_action(DialogId(ChannelId(update->channel_id_)),
MessageId(ServerMessageId(update->top_msg_id_)), DialogId(update->from_id_),
DialogAction(std::move(update->action_)), get_short_update_date());
td_->dialog_action_manager_->on_dialog_action(
DialogId(ChannelId(update->channel_id_)), MessageId(ServerMessageId(update->top_msg_id_)),
DialogId(update->from_id_), DialogAction(std::move(update->action_)), get_short_update_date());
promise.set_value(Unit());
}
void UpdatesManager::on_update(tl_object_ptr<telegram_api::updateEncryptedChatTyping> update, Promise<Unit> &&promise) {
SecretChatId secret_chat_id(update->chat_id_);
UserId user_id = td_->contacts_manager_->get_secret_chat_user_id(secret_chat_id);
td_->messages_manager_->on_dialog_action(DialogId(secret_chat_id), MessageId(), DialogId(user_id),
DialogAction::get_typing_action(), get_short_update_date());
td_->dialog_action_manager_->on_dialog_action(DialogId(secret_chat_id), MessageId(), DialogId(user_id),
DialogAction::get_typing_action(), get_short_update_date());
promise.set_value(Unit());
}