Handle chatAction timeouts.

GitOrigin-RevId: acd087bf97f6ff39af8111b1c8d984f72f041467
This commit is contained in:
levlam 2018-03-13 20:48:08 +03:00
parent 8eaea5d4af
commit 52f45abf65
8 changed files with 146 additions and 9 deletions

View File

@ -1,6 +1,6 @@
cmake_minimum_required(VERSION 3.0.2 FATAL_ERROR) 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 # Prevent in-source build
get_filename_component(TD_REAL_SOURCE_DIR "${CMAKE_CURRENT_SOURCE_DIR}" REALPATH) get_filename_component(TD_REAL_SOURCE_DIR "${CMAKE_CURRENT_SOURCE_DIR}" REALPATH)

View File

@ -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: 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) target_link_libraries(YourTarget PRIVATE Td::TdStatic)
``` ```
See [example/cpp/CMakeLists.txt](https://github.com/tdlib/td/tree/master/example/cpp/CMakeLists.txt). See [example/cpp/CMakeLists.txt](https://github.com/tdlib/td/tree/master/example/cpp/CMakeLists.txt).

View File

@ -2,7 +2,7 @@ cmake_minimum_required(VERSION 3.1 FATAL_ERROR)
project(TdExample VERSION 1.0 LANGUAGES CXX) 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) add_executable(tdjson_example tdjson_example.cpp)
target_link_libraries(tdjson_example PRIVATE Td::TdJson) target_link_libraries(tdjson_example PRIVATE Td::TdJson)

View File

@ -1,6 +1,6 @@
<PackageManifest Version="2.0.0" xmlns="http://schemas.microsoft.com/developer/vsx-schema/2011"> <PackageManifest Version="2.0.0" xmlns="http://schemas.microsoft.com/developer/vsx-schema/2011">
<Metadata> <Metadata>
<Identity Id="TDLib.UWP" Version="1.1.5" Language="en-US" Publisher="Telegram team" /> <Identity Id="TDLib.UWP" Version="1.1.6" Language="en-US" Publisher="Telegram team" />
<DisplayName>TDLib for Universal Windows Platform</DisplayName> <DisplayName>TDLib for Universal Windows Platform</DisplayName>
<Description>TDLib is a library for building Telegram clients</Description> <Description>TDLib is a library for building Telegram clients</Description>
<MoreInfo>https://core.telegram.org/tdlib</MoreInfo> <MoreInfo>https://core.telegram.org/tdlib</MoreInfo>

View File

@ -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(on_pending_send_dialog_action_timeout_callback);
pending_send_dialog_action_timeout_.set_callback_data(static_cast<void *>(this)); 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));
sequence_dispatcher_ = create_actor<MultiSequenceDispatcher>("multi sequence dispatcher"); sequence_dispatcher_ = create_actor<MultiSequenceDispatcher>("multi sequence dispatcher");
if (G()->parameters().use_message_db) { 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)); 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));
}
BufferSlice MessagesManager::get_dialog_database_value(const Dialog *d) { BufferSlice MessagesManager::get_dialog_database_value(const Dialog *d) {
// can't use log_event_store, because it tries to parse stored Dialog // can't use log_event_store, because it tries to parse stored Dialog
LogEventStorerCalcLength storer_calc_length; 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, void MessagesManager::on_user_dialog_action(DialogId dialog_id, UserId user_id,
tl_object_ptr<td_api::ChatAction> &&action) { tl_object_ptr<td_api::ChatAction> &&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<td_api::chatActionCancel>();
}
} 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<td_api::chatActionUploadingVideo &>(*action).progress_;
case td_api::chatActionUploadingVoiceNote::ID:
return static_cast<td_api::chatActionUploadingVoiceNote &>(*action).progress_;
case td_api::chatActionUploadingPhoto::ID:
return static_cast<td_api::chatActionUploadingPhoto &>(*action).progress_;
case td_api::chatActionUploadingDocument::ID:
return static_cast<td_api::chatActionUploadingDocument &>(*action).progress_;
case td_api::chatActionUploadingVideoNote::ID:
return static_cast<td_api::chatActionUploadingVideoNote &>(*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, send_closure(G()->td(), &Td::send_update,
make_tl_object<td_api::updateUserChatAction>( make_tl_object<td_api::updateUserChatAction>(
dialog_id.get(), td_->contacts_manager_->get_user_id_object(user_id, "on_user_dialog_action"), 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))); 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)); 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); CHECK(m != nullptr);
on_user_dialog_action(dialog_id, m->sender_user_id, nullptr);
send_closure(G()->td(), &Td::send_update, send_closure(G()->td(), &Td::send_update,
make_tl_object<td_api::updateMessageEdited>(dialog_id.get(), m->message_id.get(), m->edit_date, make_tl_object<td_api::updateMessageEdited>(dialog_id.get(), m->message_id.get(), m->edit_date,
get_reply_markup_object(m->reply_markup))); 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()); 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<telegram_api::InputChatPhoto> MessagesManager::get_input_chat_photo(FileId file_id) const { tl_object_ptr<telegram_api::InputChatPhoto> MessagesManager::get_input_chat_photo(FileId file_id) const {
if (!file_id.is_valid()) { if (!file_id.is_valid()) {
return make_tl_object<telegram_api::inputChatPhotoEmpty>(); return make_tl_object<telegram_api::inputChatPhotoEmpty>();
@ -21320,6 +21432,10 @@ MessagesManager::Message *MessagesManager::add_message_to_dialog(Dialog *d, uniq
message->reply_markup = nullptr; message->reply_markup = nullptr;
} }
if (from_update) {
on_user_dialog_action(dialog_id, message->sender_user_id, nullptr);
}
unique_ptr<Message> *v = &d->messages; unique_ptr<Message> *v = &d->messages;
while (*v != nullptr && (*v)->random_y >= message->random_y) { while (*v != nullptr && (*v)->random_y >= message->random_y) {
if ((*v)->message_id.get() < message_id.get()) { if ((*v)->message_id.get() < message_id.get()) {

View File

@ -1792,6 +1792,8 @@ class MessagesManager : public Actor {
static constexpr int32 MAX_PRELOADED_DIALOGS = 1000; 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 const char *DELETE_MESSAGE_USER_REQUEST_SOURCE = "user request";
static constexpr bool DROP_UPDATES = false; 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, 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; 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<int64> &&message_ids, bool is_permanent, void send_update_delete_messages(DialogId dialog_id, vector<int64> &&message_ids, bool is_permanent,
bool from_cache) const; bool from_cache) const;
@ -2156,6 +2158,8 @@ class MessagesManager : public Actor {
void on_send_dialog_action_timeout(DialogId dialog_id); 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); Dialog *get_dialog_by_message_id(MessageId message_id);
MessageId get_message_id_by_random_id(Dialog *d, int64 random_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_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); void load_secret_thumbnail(FileId thumbnail_file_id);
static tl_object_ptr<telegram_api::channelAdminLogEventsFilter> get_channel_admin_log_events_filter( static tl_object_ptr<telegram_api::channelAdminLogEventsFilter> get_channel_admin_log_events_filter(
@ -2628,6 +2634,19 @@ class MessagesManager : public Actor {
std::unordered_set<FullMessageId, FullMessageIdHash> waiting_for_web_page_messages_; std::unordered_set<FullMessageId, FullMessageIdHash> 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<DialogId, std::vector<ActiveDialogAction>, DialogIdHash> active_dialog_actions_;
NotificationSettings users_notification_settings_; NotificationSettings users_notification_settings_;
NotificationSettings chats_notification_settings_; NotificationSettings chats_notification_settings_;
NotificationSettings dialogs_notification_settings_; NotificationSettings dialogs_notification_settings_;
@ -2668,6 +2687,7 @@ class MessagesManager : public Actor {
MultiTimeout pending_unload_dialog_timeout_; MultiTimeout pending_unload_dialog_timeout_;
MultiTimeout dialog_unmute_timeout_; MultiTimeout dialog_unmute_timeout_;
MultiTimeout pending_send_dialog_action_timeout_; MultiTimeout pending_send_dialog_action_timeout_;
MultiTimeout active_dialog_action_timeout_;
Hints dialogs_hints_; // search dialogs by title and username Hints dialogs_hints_; // search dialogs by title and username

View File

@ -193,7 +193,7 @@ class Td final : public NetQueryCallback {
static td_api::object_ptr<td_api::Object> static_request(td_api::object_ptr<td_api::Function> function); static td_api::object_ptr<td_api::Object> static_request(td_api::object_ptr<td_api::Function> function);
private: 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 int64 ONLINE_ALARM_ID = 0;
static constexpr int32 ONLINE_TIMEOUT = 240; static constexpr int32 ONLINE_TIMEOUT = 240;
static constexpr int64 PING_SERVER_ALARM_ID = -1; static constexpr int64 PING_SERVER_ALARM_ID = -1;

View File

@ -1540,6 +1540,7 @@ tl_object_ptr<td_api::ChatAction> UpdatesManager::convert_send_message_action(
} }
default: default:
UNREACHABLE(); UNREACHABLE();
return make_tl_object<td_api::chatActionTyping>();
} }
} }