From 52f45abf651a885a19641c1bae05a76bc98322d2 Mon Sep 17 00:00:00 2001 From: levlam Date: Tue, 13 Mar 2018 20:48:08 +0300 Subject: [PATCH] Handle chatAction timeouts. GitOrigin-RevId: acd087bf97f6ff39af8111b1c8d984f72f041467 --- CMakeLists.txt | 2 +- README.md | 2 +- example/cpp/CMakeLists.txt | 2 +- example/uwp/extension.vsixmanifest | 2 +- td/telegram/MessagesManager.cpp | 120 ++++++++++++++++++++++++++++- td/telegram/MessagesManager.h | 24 +++++- td/telegram/Td.h | 2 +- td/telegram/UpdatesManager.cpp | 1 + 8 files changed, 146 insertions(+), 9 deletions(-) diff --git a/CMakeLists.txt b/CMakeLists.txt index 9a004034..3c222ddb 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -1,6 +1,6 @@ cmake_minimum_required(VERSION 3.0.2 FATAL_ERROR) -project(TDLib VERSION 1.1.5 LANGUAGES CXX C) +project(TDLib VERSION 1.1.6 LANGUAGES CXX C) # Prevent in-source build get_filename_component(TD_REAL_SOURCE_DIR "${CMAKE_CURRENT_SOURCE_DIR}" REALPATH) diff --git a/README.md b/README.md index dbe0cff4..275b4a5c 100644 --- a/README.md +++ b/README.md @@ -111,7 +111,7 @@ target_link_libraries(YourTarget PRIVATE Td::TdStatic) Or you could install `TDLib` and then reference it in your CMakeLists.txt like this: ``` -find_package(Td 1.1.5 REQUIRED) +find_package(Td 1.1.6 REQUIRED) target_link_libraries(YourTarget PRIVATE Td::TdStatic) ``` See [example/cpp/CMakeLists.txt](https://github.com/tdlib/td/tree/master/example/cpp/CMakeLists.txt). diff --git a/example/cpp/CMakeLists.txt b/example/cpp/CMakeLists.txt index 6c25b650..3afa2298 100644 --- a/example/cpp/CMakeLists.txt +++ b/example/cpp/CMakeLists.txt @@ -2,7 +2,7 @@ cmake_minimum_required(VERSION 3.1 FATAL_ERROR) project(TdExample VERSION 1.0 LANGUAGES CXX) -find_package(Td 1.1.5 REQUIRED) +find_package(Td 1.1.6 REQUIRED) add_executable(tdjson_example tdjson_example.cpp) target_link_libraries(tdjson_example PRIVATE Td::TdJson) diff --git a/example/uwp/extension.vsixmanifest b/example/uwp/extension.vsixmanifest index 6bc523b7..3f03fe24 100644 --- a/example/uwp/extension.vsixmanifest +++ b/example/uwp/extension.vsixmanifest @@ -1,6 +1,6 @@ - + TDLib for Universal Windows Platform TDLib is a library for building Telegram clients https://core.telegram.org/tdlib diff --git a/td/telegram/MessagesManager.cpp b/td/telegram/MessagesManager.cpp index 26ddd12d..70b9144b 100644 --- a/td/telegram/MessagesManager.cpp +++ b/td/telegram/MessagesManager.cpp @@ -4504,6 +4504,9 @@ MessagesManager::MessagesManager(Td *td, ActorShared<> parent) : td_(td), 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(this)); + active_dialog_action_timeout_.set_callback(on_active_dialog_action_timeout_callback); + active_dialog_action_timeout_.set_callback_data(static_cast(this)); + sequence_dispatcher_ = create_actor("multi sequence dispatcher"); if (G()->parameters().use_message_db) { @@ -4637,6 +4640,16 @@ 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(messages_manager_ptr); + send_closure_later(messages_manager->actor_id(messages_manager), &MessagesManager::on_active_dialog_action_timeout, + DialogId(dialog_id_int)); +} + BufferSlice MessagesManager::get_dialog_database_value(const Dialog *d) { // can't use log_event_store, because it tries to parse stored Dialog LogEventStorerCalcLength storer_calc_length; @@ -5620,6 +5633,77 @@ void MessagesManager::on_update_channel_max_unavailable_message_id(ChannelId cha void MessagesManager::on_user_dialog_action(DialogId dialog_id, UserId user_id, tl_object_ptr &&action) { + if (td_->auth_manager_->is_bot() || !user_id.is_valid() || is_broadcast_channel(dialog_id)) { + return; + } + + bool is_canceled = action == nullptr || action->get_id() == td_api::chatActionCancel::ID; + if (is_canceled) { + 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(), + [user_id](const ActiveDialogAction &action) { return action.user_id == user_id; }); + if (it == active_actions.end()) { + return; + } + + LOG(DEBUG) << "Cancel action of " << user_id << " in " << dialog_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()); + } + if (action == nullptr) { + action = make_tl_object(); + } + } else { + auto &active_actions = active_dialog_actions_[dialog_id]; + auto it = std::find_if(active_actions.begin(), active_actions.end(), + [user_id](const ActiveDialogAction &action) { return action.user_id == user_id; }); + int32 prev_action_id = 0; + int32 prev_progress = 0; + if (it != active_actions.end()) { + LOG(DEBUG) << "Re-add action of " << user_id << " in " << dialog_id; + prev_action_id = it->action_id; + prev_progress = it->progress; + active_actions.erase(it); + } else { + LOG(DEBUG) << "Add action of " << user_id << " in " << dialog_id; + } + + auto action_id = action->get_id(); + auto progress = [&] { + switch (action_id) { + case td_api::chatActionUploadingVideo::ID: + return static_cast(*action).progress_; + case td_api::chatActionUploadingVoiceNote::ID: + return static_cast(*action).progress_; + case td_api::chatActionUploadingPhoto::ID: + return static_cast(*action).progress_; + case td_api::chatActionUploadingDocument::ID: + return static_cast(*action).progress_; + case td_api::chatActionUploadingVideoNote::ID: + return static_cast(*action).progress_; + default: + return 0; + } + }(); + active_actions.emplace_back(user_id, action_id, Time::now()); + if (action_id == prev_action_id && progress <= prev_progress) { + return; + } + 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); + } + } + + LOG(DEBUG) << "Send action of " << user_id << " in " << dialog_id << ": " << to_string(action); send_closure(G()->td(), &Td::send_update, make_tl_object( dialog_id.get(), td_->contacts_manager_->get_user_id_object(user_id, "on_user_dialog_action"), @@ -18058,12 +18142,13 @@ void MessagesManager::send_update_message_content(DialogId dialog_id, MessageId dialog_id.get(), message_id.get(), get_message_content_object(content, message_date, is_content_secret))); } -void MessagesManager::send_update_message_edited(FullMessageId full_message_id) const { +void MessagesManager::send_update_message_edited(FullMessageId full_message_id) { return send_update_message_edited(full_message_id.get_dialog_id(), get_message(full_message_id)); } -void MessagesManager::send_update_message_edited(DialogId dialog_id, const Message *m) const { +void MessagesManager::send_update_message_edited(DialogId dialog_id, const Message *m) { CHECK(m != nullptr); + on_user_dialog_action(dialog_id, m->sender_user_id, nullptr); send_closure(G()->td(), &Td::send_update, make_tl_object(dialog_id.get(), m->message_id.get(), m->edit_date, get_reply_markup_object(m->reply_markup))); @@ -19323,6 +19408,33 @@ void MessagesManager::on_send_dialog_action_timeout(DialogId dialog_id) { send_dialog_action(dialog_id, std::move(action), Auto()); } +void MessagesManager::on_active_dialog_action_timeout(DialogId dialog_id) { + LOG(DEBUG) << "Receive active dialog action timeout in " << dialog_id; + Dialog *d = get_dialog(dialog_id); + CHECK(d != nullptr); + + 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(); + while (actions_it->second[0].start_time + DIALOG_ACTION_TIMEOUT < now + 0.1) { + on_user_dialog_action(dialog_id, actions_it->second[0].user_id, nullptr); + + 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); +} + tl_object_ptr MessagesManager::get_input_chat_photo(FileId file_id) const { if (!file_id.is_valid()) { return make_tl_object(); @@ -21320,6 +21432,10 @@ MessagesManager::Message *MessagesManager::add_message_to_dialog(Dialog *d, uniq message->reply_markup = nullptr; } + if (from_update) { + on_user_dialog_action(dialog_id, message->sender_user_id, nullptr); + } + unique_ptr *v = &d->messages; while (*v != nullptr && (*v)->random_y >= message->random_y) { if ((*v)->message_id.get() < message_id.get()) { diff --git a/td/telegram/MessagesManager.h b/td/telegram/MessagesManager.h index 0337a3b9..1490ceed 100644 --- a/td/telegram/MessagesManager.h +++ b/td/telegram/MessagesManager.h @@ -1792,6 +1792,8 @@ class MessagesManager : public Actor { static constexpr int32 MAX_PRELOADED_DIALOGS = 1000; + static constexpr double DIALOG_ACTION_TIMEOUT = 5.5; + static constexpr const char *DELETE_MESSAGE_USER_REQUEST_SOURCE = "user request"; static constexpr bool DROP_UPDATES = false; @@ -2077,9 +2079,9 @@ class MessagesManager : public Actor { void send_update_message_content(DialogId dialog_id, MessageId message_id, const MessageContent *content, int32 message_date, bool is_content_secret, const char *source) const; - void send_update_message_edited(FullMessageId full_message_id) const; + void send_update_message_edited(FullMessageId full_message_id); - void send_update_message_edited(DialogId dialog_id, const Message *m) const; + void send_update_message_edited(DialogId dialog_id, const Message *m); void send_update_delete_messages(DialogId dialog_id, vector &&message_ids, bool is_permanent, bool from_cache) const; @@ -2156,6 +2158,8 @@ class MessagesManager : public Actor { void on_send_dialog_action_timeout(DialogId dialog_id); + void on_active_dialog_action_timeout(DialogId dialog_id); + Dialog *get_dialog_by_message_id(MessageId message_id); MessageId get_message_id_by_random_id(Dialog *d, int64 random_id); @@ -2419,6 +2423,8 @@ class MessagesManager : 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); + void load_secret_thumbnail(FileId thumbnail_file_id); static tl_object_ptr get_channel_admin_log_events_filter( @@ -2628,6 +2634,19 @@ class MessagesManager : public Actor { std::unordered_set waiting_for_web_page_messages_; + struct ActiveDialogAction { + 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) { + } + }; + + std::unordered_map, DialogIdHash> active_dialog_actions_; + NotificationSettings users_notification_settings_; NotificationSettings chats_notification_settings_; NotificationSettings dialogs_notification_settings_; @@ -2668,6 +2687,7 @@ class MessagesManager : public Actor { MultiTimeout pending_unload_dialog_timeout_; MultiTimeout dialog_unmute_timeout_; MultiTimeout pending_send_dialog_action_timeout_; + MultiTimeout active_dialog_action_timeout_; Hints dialogs_hints_; // search dialogs by title and username diff --git a/td/telegram/Td.h b/td/telegram/Td.h index 2038e26c..99eb386c 100644 --- a/td/telegram/Td.h +++ b/td/telegram/Td.h @@ -193,7 +193,7 @@ class Td final : public NetQueryCallback { static td_api::object_ptr static_request(td_api::object_ptr function); private: - static constexpr const char *tdlib_version = "1.1.5"; + static constexpr const char *tdlib_version = "1.1.6"; static constexpr int64 ONLINE_ALARM_ID = 0; static constexpr int32 ONLINE_TIMEOUT = 240; static constexpr int64 PING_SERVER_ALARM_ID = -1; diff --git a/td/telegram/UpdatesManager.cpp b/td/telegram/UpdatesManager.cpp index 207d6c1f..43153d96 100644 --- a/td/telegram/UpdatesManager.cpp +++ b/td/telegram/UpdatesManager.cpp @@ -1540,6 +1540,7 @@ tl_object_ptr UpdatesManager::convert_send_message_action( } default: UNREACHABLE(); + return make_tl_object(); } }