From 2facb494d3ee689ebf1a7660463d7aeef32691f1 Mon Sep 17 00:00:00 2001 From: levlam Date: Fri, 29 Mar 2019 00:08:57 +0300 Subject: [PATCH] Add new notification type for push notifications. GitOrigin-RevId: 47c4527806cab7a43bf4375dc2a2aeeab02fc7c1 --- td/generate/scheme/td_api.tl | 2 +- td/telegram/ContactsManager.cpp | 2 +- td/telegram/MessagesManager.cpp | 64 ++++-- td/telegram/MessagesManager.h | 10 +- td/telegram/NotificationManager.cpp | 295 ++++++++++++++++++++++++++-- td/telegram/NotificationManager.h | 8 +- td/telegram/NotificationType.cpp | 58 +++++- td/telegram/NotificationType.h | 8 +- 8 files changed, 395 insertions(+), 52 deletions(-) diff --git a/td/generate/scheme/td_api.tl b/td/generate/scheme/td_api.tl index 123b6dfe..e73417b2 100644 --- a/td/generate/scheme/td_api.tl +++ b/td/generate/scheme/td_api.tl @@ -3446,7 +3446,7 @@ deleteLanguagePack language_pack_id:string = Ok; //@description Registers the currently used device for receiving push notifications. Returns a globally unique identifier of the push notification subscription @device_token Device token @other_user_ids List of at most 100 user identifiers of other users currently using the client registerDevice device_token:DeviceToken other_user_ids:vector = PushReceiverId; -//@description Handles a push notification. Can be called before authorization @payload JSON-encoded push notification payload +//@description Handles a push notification. Can be called before authorization @payload JSON-encoded push notification payload with all fields sent by the server, and "google.sent_time" and "google.notification.sound" fields added processPushNotification payload:string = Ok; //@description Returns a globally unique push notification subscription identifier for identification of an account, which has received a push notification. This is an offline method. Can be called before authorization. Can be called synchronously @payload JSON-encoded push notification payload diff --git a/td/telegram/ContactsManager.cpp b/td/telegram/ContactsManager.cpp index 9a9ea3c5..396880b0 100644 --- a/td/telegram/ContactsManager.cpp +++ b/td/telegram/ContactsManager.cpp @@ -2945,7 +2945,7 @@ tl_object_ptr ContactsManager::get_input_encry } const DialogPhoto *ContactsManager::get_user_dialog_photo(UserId user_id) { - auto u = get_user(user_id); + auto u = get_user_force(user_id); if (u == nullptr) { return nullptr; } diff --git a/td/telegram/MessagesManager.cpp b/td/telegram/MessagesManager.cpp index 83cec210..fd2bdc31 100644 --- a/td/telegram/MessagesManager.cpp +++ b/td/telegram/MessagesManager.cpp @@ -18189,39 +18189,69 @@ NotificationGroupId MessagesManager::get_dialog_notification_group_id(DialogId d return group_info.group_id; } -bool MessagesManager::need_message_push_notification(DialogId dialog_id, MessageId message_id, int64 random_id, - bool &contains_mention, bool is_pinned) { +MessagesManager::MessagePushNotificationInfo MessagesManager::get_message_push_notification_info( + DialogId dialog_id, MessageId message_id, int64 random_id, UserId sender_user_id, int32 date, bool contains_mention, + bool is_pinned) { init(); + if (dialog_id == get_my_dialog_id() || td_->auth_manager_->is_bot()) { + return {}; + } + + if (sender_user_id.is_valid() && !td_->contacts_manager_->have_user(sender_user_id)) { + // allow messages from unknown sender, we will use only sender's name and photo + // return {}; + } + Dialog *d = get_dialog_force(dialog_id); if (d == nullptr) { - return false; + return {}; } if (message_id.is_valid() && message_id.get() <= d->last_new_message_id.get()) { - return false; + return {}; } if (random_id != 0) { CHECK(dialog_id.get_type() == DialogType::SecretChat); if (get_message_id_by_random_id(d, random_id, "need_message_push_notification").is_valid()) { - return false; + return {}; } } - if (dialog_id == get_my_dialog_id() || td_->auth_manager_->is_bot()) { - return false; - } - if (is_dialog_message_notification_disabled(dialog_id, G()->unix_time())) { - return false; - } - - if (is_pinned && is_dialog_pinned_message_notifications_disabled(d)) { - contains_mention = false; - } - if (contains_mention && is_dialog_mention_notifications_disabled(d)) { + if (is_pinned) { + contains_mention = !is_dialog_pinned_message_notifications_disabled(d); + } else if (contains_mention && is_dialog_mention_notifications_disabled(d)) { contains_mention = false; } - return true; + DialogId settings_dialog_id = dialog_id; + Dialog *settings_dialog = d; + if (contains_mention && sender_user_id.is_valid()) { + settings_dialog_id = DialogId(sender_user_id); + settings_dialog = get_dialog_force(settings_dialog_id); + } + + bool have_settings; + int32 mute_until; + std::tie(have_settings, mute_until) = get_dialog_mute_until(settings_dialog_id, settings_dialog); + if (have_settings && mute_until <= date) { + return {}; + } + + if (is_dialog_message_notification_disabled(settings_dialog_id, date)) { + return {}; + } + + auto group_id = get_dialog_notification_group_id( + dialog_id, contains_mention ? d->mention_notification_group : d->message_notification_group); + if (!group_id.is_valid()) { + return {}; + } + + MessagePushNotificationInfo result; + result.group_id = group_id; + result.group_type = contains_mention ? NotificationGroupType::Mentions : NotificationGroupType::Messages; + result.settings_dialog_id = settings_dialog_id; + return result; } NotificationId MessagesManager::get_next_notification_id(Dialog *d, NotificationGroupId notification_group_id, diff --git a/td/telegram/MessagesManager.h b/td/telegram/MessagesManager.h index 1579be13..cb76e32a 100644 --- a/td/telegram/MessagesManager.h +++ b/td/telegram/MessagesManager.h @@ -691,8 +691,14 @@ class MessagesManager : public Actor { FileSourceId get_message_file_source_id(FullMessageId full_message_id); - bool need_message_push_notification(DialogId dialog_id, MessageId message_id, int64 random_id, bool &contains_mention, - bool is_pinned); + struct MessagePushNotificationInfo { + NotificationGroupId group_id; + NotificationGroupType group_type = NotificationGroupType::Calls; + DialogId settings_dialog_id; + }; + MessagePushNotificationInfo get_message_push_notification_info(DialogId dialog_id, MessageId message_id, + int64 random_id, UserId sender_user_id, int32 date, + bool contains_mention, bool is_pinned); struct MessageNotificationGroup { DialogId dialog_id; diff --git a/td/telegram/NotificationManager.cpp b/td/telegram/NotificationManager.cpp index d97d1197..f9605596 100644 --- a/td/telegram/NotificationManager.cpp +++ b/td/telegram/NotificationManager.cpp @@ -10,6 +10,7 @@ #include "td/telegram/ConfigShared.h" #include "td/telegram/ContactsManager.h" #include "td/telegram/DeviceTokenManager.h" +#include "td/telegram/files/FileManager.h" #include "td/telegram/Global.h" #include "td/telegram/MessagesManager.h" #include "td/telegram/misc.h" @@ -2329,6 +2330,191 @@ void NotificationManager::process_push_notification(string payload, Promise loc_args; + string sender_name; + int32 sent_date = G()->unix_time(); + bool is_silent = false; for (auto &field_value : json_value.get_object()) { if (field_value.first == "loc_key") { if (field_value.second.type() != JsonValue::Type::String) { @@ -2372,6 +2561,17 @@ Status NotificationManager::process_push_notification_payload(string payload) { return Status::Error("Expected announcement message text as a String"); } announcement_message_text = field_value.second.get_string().str(); + } else if (field_value.first == "google.sent_time") { + TRY_RESULT(google_sent_time, get_json_object_long_field(json_value.get_object(), "google.sent_time")); + google_sent_time /= 1000; + if (sent_date - 86400 <= google_sent_time && google_sent_time <= sent_date + 5) { + sent_date = narrow_cast(google_sent_time); + } + } else if (field_value.first == "google.notification.sound" && field_value.second.type() != JsonValue::Type::Null) { + if (field_value.second.type() != JsonValue::Type::String) { + return Status::Error("Expected notification sound as a String"); + } + is_silent = field_value.second.get_string().empty(); } } if (!clean_input_string(loc_key)) { @@ -2510,17 +2710,20 @@ Status NotificationManager::process_push_notification_payload(string payload) { } loc_key = loc_key.substr(8); } - if (begins_with(loc_key, "CHAT_MESSAGE")) { - if (dialog_id.get_type() != DialogType::Chat) { - return Status::Error("Receive wrong chat type"); - } - loc_key = loc_key.substr(5); - } if (begins_with(loc_key, "CHAT_")) { auto dialog_type = dialog_id.get_type(); if (dialog_type != DialogType::Chat && dialog_type != DialogType::Channel) { return Status::Error("Receive wrong chat type"); } + + if (begins_with(loc_key, "CHAT_MESSAGE")) { + loc_key = loc_key.substr(5); + } + if (loc_args.empty()) { + return Status::Error("Expect sender name as first argument"); + } + sender_name = std::move(loc_args[0]); + loc_args.erase(loc_args.begin()); } if (begins_with(loc_key, "MESSAGE") && !server_message_id.is_valid()) { return Status::Error("Receive no message ID"); @@ -2535,7 +2738,7 @@ Status NotificationManager::process_push_notification_payload(string payload) { } if (begins_with(loc_key, "ENCRYPTION_")) { - // TODO new secret chat notification + // TODO new secret chat notifications return Status::OK(); } @@ -2544,27 +2747,81 @@ Status NotificationManager::process_push_notification_payload(string payload) { return Status::OK(); } - return process_message_push_notification(dialog_id, sender_user_id, MessageId(server_message_id), random_id, - contains_mention, std::move(loc_key), std::move(loc_args)); + loc_key = convert_loc_key(loc_key); + if (loc_key.empty()) { + return Status::Error("Push type is unknown"); + } + + if (loc_args.empty()) { + return Status::Error("Expected chat name as next argument"); + } + if (dialog_id.get_type() == DialogType::User) { + sender_name = std::move(loc_args[0]); + } + loc_args.erase( + loc_args + .begin()); // chat title for CHAT_*, CHANNEL_*, ENCRYPTED_MESSAGE and PINNED_*, sender name for MESSAGE_* and CONTACT_JOINED + + return process_message_push_notification(dialog_id, MessageId(server_message_id), random_id, sender_user_id, + std::move(sender_name), sent_date, contains_mention, is_silent, + std::move(loc_key), std::move(loc_args)); } -Status NotificationManager::process_message_push_notification(DialogId dialog_id, UserId sender_user_id, - MessageId message_id, int64 random_id, - bool contains_mention, string loc_key, +Status NotificationManager::process_message_push_notification(DialogId dialog_id, MessageId message_id, int64 random_id, + UserId sender_user_id, string sender_name, int32 date, + bool contains_mention, bool is_silent, string loc_key, vector loc_args) { - auto is_pinned = begins_with(loc_key, "PINNED_"); - if (is_pinned) { - contains_mention = true; + if (loc_args.size() > 1) { + return Status::Error("Receive too much arguments"); } - if (!td_->messages_manager_->need_message_push_notification(dialog_id, message_id, random_id, contains_mention, - is_pinned)) { + + string arg; + if (loc_args.size() == 1) { + arg = std::move(loc_args[0]); + } + + auto is_pinned = begins_with(loc_key, "PINNED_"); + auto info = td_->messages_manager_->get_message_push_notification_info( + dialog_id, message_id, random_id, sender_user_id, date, contains_mention, is_pinned); + if (!info.group_id.is_valid()) { VLOG(notifications) << "Don't need message push notification for " << message_id << "/" << random_id << " from " << dialog_id; return Status::OK(); } - VLOG(notifications) << "Process message push notification " << loc_key << " for " << message_id << "/" << random_id - << " from " << dialog_id << ", sent by " << sender_user_id << " with args " << loc_args; + if (dialog_id.get_type() == DialogType::SecretChat) { + VLOG(notifications) << "Skep notification in secret " << dialog_id; + // TODO support secret chat notifications + // main problem: there is no message_id yet + return Status::OK(); + } + CHECK(random_id == 0); + + auto notification_id = get_next_notification_id(); + if (!notification_id.is_valid()) { + return Status::OK(); + } + + auto sender_photo = td_->contacts_manager_->get_user_dialog_photo(sender_user_id); + string sender_photo_path; + if (sender_photo != nullptr) { + FileView file_view = td_->file_manager_->get_file_view(sender_photo->small_file_id); + if (file_view.has_local_location()) { + sender_photo_path = file_view.path(); + } + } + + auto group_id = info.group_id; + auto group_type = info.group_type; + auto settings_dialog_id = info.settings_dialog_id; + VLOG(notifications) << "Add message push notification of type " << loc_key << " for " << message_id << "/" + << random_id << " in " << dialog_id << ", sent by " << sender_user_id << " at " << date + << " with args " << loc_args << " to " << group_id << " of type " << group_type + << " with settings from " << settings_dialog_id; + + add_notification(group_id, group_type, dialog_id, date, settings_dialog_id, is_silent, 0, notification_id, + create_new_push_message_notification(std::move(sender_name), std::move(sender_photo_path), + message_id, std::move(loc_key), std::move(arg))); return Status::OK(); } diff --git a/td/telegram/NotificationManager.h b/td/telegram/NotificationManager.h index c964b950..96913326 100644 --- a/td/telegram/NotificationManager.h +++ b/td/telegram/NotificationManager.h @@ -256,11 +256,13 @@ class NotificationManager : public Actor { static Result decrypt_push_payload(int64 encryption_key_id, string encryption_key, string payload); + static string convert_loc_key(const string &loc_key); + Status process_push_notification_payload(string payload); - Status process_message_push_notification(DialogId dialog_id, UserId sender_user_id, MessageId message_id, - int64 random_id, bool contains_mention, string loc_key, - vector loc_args); + Status process_message_push_notification(DialogId dialog_id, MessageId message_id, int64 random_id, + UserId sender_user_id, string sender_name, int32 date, bool contains_mention, + bool is_silent, string loc_key, vector loc_args); void after_get_difference_impl(); diff --git a/td/telegram/NotificationType.cpp b/td/telegram/NotificationType.cpp index 04932510..a14eaf40 100644 --- a/td/telegram/NotificationType.cpp +++ b/td/telegram/NotificationType.cpp @@ -32,11 +32,11 @@ class NotificationTypeMessage : public NotificationType { StringBuilder &to_string_builder(StringBuilder &string_builder) const override { return string_builder << "NewMessageNotification[" << message_id_ << ']'; } - + /* Type get_type() const override { return Type::Message; } - + */ MessageId message_id_; public: @@ -60,11 +60,11 @@ class NotificationTypeSecretChat : public NotificationType { StringBuilder &to_string_builder(StringBuilder &string_builder) const override { return string_builder << "NewSecretChatNotification[]"; } - + /* Type get_type() const override { return Type::SecretChat; } - + */ public: NotificationTypeSecretChat() { } @@ -86,11 +86,11 @@ class NotificationTypeCall : public NotificationType { StringBuilder &to_string_builder(StringBuilder &string_builder) const override { return string_builder << "NewCallNotification[" << call_id_ << ']'; } - + /* Type get_type() const override { return Type::Call; } - + */ CallId call_id_; public: @@ -98,6 +98,46 @@ class NotificationTypeCall : public NotificationType { } }; +class NotificationTypePushMessage : public NotificationType { + bool can_be_delayed() const override { + return false; + } + + MessageId get_message_id() const override { + return message_id_; + } + + td_api::object_ptr get_notification_type_object(DialogId dialog_id) const override { + return nullptr; + // return td_api::make_object(sender_name_, sender_photo_path_, message_id_.get(), key_, arg_); + } + + StringBuilder &to_string_builder(StringBuilder &string_builder) const override { + return string_builder << "NewPushMessageNotification[" << sender_name_ << ", " << message_id_ << ", " << key_ + << ", " << arg_ << ']'; + } + /* + Type get_type() const override { + return Type::PushMessage; + } + */ + string sender_name_; + string sender_photo_path_; + MessageId message_id_; + string key_; + string arg_; + + public: + NotificationTypePushMessage(string sender_name, string sender_photo_path, MessageId message_id, string key, + string arg) + : sender_name_(std::move(sender_name)) + , sender_photo_path_(std::move(sender_photo_path)) + , message_id_(message_id) + , key_(std::move(key)) + , arg_(std::move(arg)) { + } +}; + unique_ptr create_new_message_notification(MessageId message_id) { return make_unique(message_id); } @@ -110,4 +150,10 @@ unique_ptr create_new_call_notification(CallId call_id) { return make_unique(call_id); } +unique_ptr create_new_push_message_notification(string sender_name, string sender_photo_path, + MessageId message_id, string key, string arg) { + return td::make_unique(std::move(sender_name), std::move(sender_photo_path), message_id, + std::move(key), std::move(arg)); +} + } // namespace td diff --git a/td/telegram/NotificationType.h b/td/telegram/NotificationType.h index 9a62e31e..b6524d11 100644 --- a/td/telegram/NotificationType.h +++ b/td/telegram/NotificationType.h @@ -36,10 +36,9 @@ class NotificationType { virtual StringBuilder &to_string_builder(StringBuilder &string_builder) const = 0; protected: - // append only - enum class Type : int32 { Message, SecretChat, Call }; + // enum class Type : int32 { Message, SecretChat, Call, PushMessage }; - virtual Type get_type() const = 0; + // virtual Type get_type() const = 0; }; inline StringBuilder &operator<<(StringBuilder &string_builder, const NotificationType ¬ification_type) { @@ -59,4 +58,7 @@ unique_ptr create_new_secret_chat_notification(); unique_ptr create_new_call_notification(CallId call_id); +unique_ptr create_new_push_message_notification(string sender_name, string sender_photo_path, + MessageId message_id, string key, string arg); + } // namespace td