Add support for updateNotificationGroup and delaying of updates.
GitOrigin-RevId: 28974259dcaf97d2ddc7b303c7609bd99b846089
This commit is contained in:
parent
d82e9b1b2c
commit
a86a9d2a00
@ -2216,12 +2216,15 @@ updateChatReplyMarkup chat_id:int53 reply_markup_message_id:int53 = Update;
|
||||
//@description A chat draft has changed. Be aware that the update may come in the currently opened chat but with old content of the draft. If the user has changed the content of the draft, this update shouldn't be applied @chat_id Chat identifier @draft_message The new draft message; may be null @order New value of the chat order
|
||||
updateChatDraftMessage chat_id:int53 draft_message:draftMessage order:int64 = Update;
|
||||
|
||||
//@description A list of active notifications in a notification group has changed @notification_group_id Unique notification group identifier @chat_id Identifier of a chat to which all notifications in the group belong
|
||||
//@notification_settings_chat_id Chat identifier, which notification settings must be applied @silent True, if the notifications should be shown without sound
|
||||
//@total_count Total number of active notifications in the group @new_notifications List of new group notifications @edited_notifications List of edited group notifications @removed_notification_ids Identifiers of removed group notifications
|
||||
updateNotificationGroup notification_group_id:int32 chat_id:int53 notification_settings_chat_id:int53 silent:Bool total_count:int32 new_notifications:vector<notification> edited_notifications:vector<notification> removed_notification_ids:vector<int32> = Update;
|
||||
//@description A notification was changed @notification_group_id Unique notification group identifier @notification Changed notification
|
||||
updateNotification notification_group_id:int32 notification:notification = Update;
|
||||
|
||||
//@description Contains active notifications that was shown on previous application launches. This update is sent only if a message database is used. In that case it comes once before any updateNotificationGroup update @groups Lists of active notification groups
|
||||
//@description A list of active notifications in a notification group has changed @notification_group_id Unique notification group identifier @chat_id Identifier of a chat to which all notifications in the group belong
|
||||
//@notification_settings_chat_id Chat identifier, which notification settings must be applied @is_silent True, if the notifications should be shown without sound
|
||||
//@total_count Total number of active notifications in the group @new_notifications List of new group notifications @removed_notification_ids Identifiers of removed group notifications
|
||||
updateNotificationGroup notification_group_id:int32 chat_id:int53 notification_settings_chat_id:int53 is_silent:Bool total_count:int32 new_notifications:vector<notification> removed_notification_ids:vector<int32> = Update;
|
||||
|
||||
//@description Contains active notifications that was shown on previous application launches. This update is sent only if a message database is used. In that case it comes once before any updateNotification and updateNotificationGroup update @groups Lists of active notification groups
|
||||
updateActiveNotifications groups:vector<notificationGroup> = Update;
|
||||
|
||||
//@description Some messages were deleted @chat_id Chat identifier @message_ids Identifiers of the deleted messages
|
||||
|
Binary file not shown.
@ -3110,6 +3110,20 @@ void ContactsManager::set_my_online_status(bool is_online, bool send_update, boo
|
||||
}
|
||||
}
|
||||
|
||||
ContactsManager::MyOnlineStatusInfo ContactsManager::get_my_online_status() const {
|
||||
auto my_id = get_my_id();
|
||||
const User *u = get_user(my_id);
|
||||
int32 was_online = my_was_online_local_ != 0 ? my_was_online_local_ : (u == nullptr ? 0 : u->was_online);
|
||||
|
||||
MyOnlineStatusInfo status_info;
|
||||
status_info.is_online_local = td_->is_online();
|
||||
status_info.is_online_remote = false; // TODO
|
||||
status_info.was_online_local = was_online; // TODO
|
||||
status_info.was_online_remote = was_online; // TODO
|
||||
|
||||
return status_info;
|
||||
}
|
||||
|
||||
UserId ContactsManager::get_service_notifications_user_id() {
|
||||
UserId user_id(777000);
|
||||
if (!have_user_force(user_id)) {
|
||||
|
@ -213,6 +213,15 @@ class ContactsManager : public Actor {
|
||||
|
||||
void set_my_online_status(bool is_online, bool send_update, bool is_local);
|
||||
|
||||
struct MyOnlineStatusInfo {
|
||||
bool is_online_local = false;
|
||||
bool is_online_remote = false;
|
||||
int32 was_online_local = 0;
|
||||
int32 was_online_remote = 0;
|
||||
};
|
||||
|
||||
MyOnlineStatusInfo get_my_online_status() const;
|
||||
|
||||
UserId get_service_notifications_user_id();
|
||||
|
||||
void on_update_online_status_privacy();
|
||||
|
@ -17462,7 +17462,7 @@ void MessagesManager::add_new_message_notification(Dialog *d, Message *m, bool f
|
||||
set_dialog_last_notification_date(d, m->date);
|
||||
VLOG(notifications) << "Assign " << m->notification_id << " to " << m->message_id << " in " << d->dialog_id;
|
||||
send_closure_later(G()->notification_manager(), &NotificationManager::add_notification,
|
||||
get_dialog_message_notification_group_id(d), d->dialog_id, settings_dialog_id,
|
||||
get_dialog_message_notification_group_id(d), d->dialog_id, m->date, settings_dialog_id,
|
||||
m->disable_notification, m->notification_id, create_new_message_notification(m->message_id));
|
||||
}
|
||||
|
||||
|
@ -8,19 +8,35 @@
|
||||
|
||||
#include "td/telegram/AuthManager.h"
|
||||
#include "td/telegram/ConfigShared.h"
|
||||
#include "td/telegram/ContactsManager.h"
|
||||
#include "td/telegram/Global.h"
|
||||
#include "td/telegram/Td.h"
|
||||
#include "td/telegram/TdDb.h"
|
||||
|
||||
#include "td/utils/misc.h"
|
||||
|
||||
#include <tuple>
|
||||
|
||||
namespace td {
|
||||
|
||||
int VERBOSITY_NAME(notifications) = VERBOSITY_NAME(WARNING);
|
||||
|
||||
NotificationManager::NotificationManager(Td *td, ActorShared<> parent) : td_(td), parent_(std::move(parent)) {
|
||||
flush_pending_notifications_timeout_.set_callback(on_flush_pending_notifications_timeout_callback);
|
||||
flush_pending_notifications_timeout_.set_callback_data(static_cast<void *>(this));
|
||||
}
|
||||
|
||||
void NotificationManager::on_flush_pending_notifications_timeout_callback(void *notification_manager_ptr,
|
||||
int64 group_id_int) {
|
||||
if (G()->close_flag()) {
|
||||
return;
|
||||
}
|
||||
|
||||
auto notification_manager = static_cast<NotificationManager *>(notification_manager_ptr);
|
||||
notification_manager->flush_pending_notifications(NotificationGroupId(narrow_cast<int32>(group_id_int)));
|
||||
}
|
||||
|
||||
bool NotificationManager::is_disabled() const {
|
||||
LOG(ERROR) << "IS DISABLED";
|
||||
return td_->auth_manager_->is_bot();
|
||||
}
|
||||
|
||||
@ -34,10 +50,15 @@ void NotificationManager::start_up() {
|
||||
current_notification_group_id_ =
|
||||
NotificationGroupId(to_integer<int32>(G()->td_db()->get_binlog_pmc()->get("notification_group_id_current")));
|
||||
|
||||
max_notification_group_count_ =
|
||||
G()->shared_config().get_option_integer("notification_group_count_max", DEFAULT_NOTIFICATION_GROUP_COUNT_MAX);
|
||||
max_notification_group_size_ =
|
||||
G()->shared_config().get_option_integer("notification_group_size_max", DEFAULT_NOTIFICATION_GROUP_SIZE_MAX);
|
||||
on_notification_group_count_max_changed();
|
||||
on_notification_group_size_max_changed();
|
||||
|
||||
online_cloud_timeout_ms_ =
|
||||
G()->shared_config().get_option_integer("online_cloud_timeout_ms", DEFAULT_ONLINE_CLOUD_TIMEOUT_MS);
|
||||
notification_cloud_delay_ms_ =
|
||||
G()->shared_config().get_option_integer("notification_cloud_delay_ms", DEFAULT_ONLINE_CLOUD_DELAY_MS);
|
||||
notification_default_delay_ms_ =
|
||||
G()->shared_config().get_option_integer("notification_default_delay_ms", DEFAULT_DEFAULT_DELAY_MS);
|
||||
|
||||
// TODO load groups
|
||||
}
|
||||
@ -46,6 +67,16 @@ void NotificationManager::tear_down() {
|
||||
parent_.reset();
|
||||
}
|
||||
|
||||
NotificationManager::NotificationGroups::iterator NotificationManager::get_group(NotificationGroupId group_id) {
|
||||
// TODO optimize
|
||||
for (auto it = groups_.begin(); it != groups_.end(); ++it) {
|
||||
if (it->first.group_id == group_id) {
|
||||
return it;
|
||||
}
|
||||
}
|
||||
return groups_.end();
|
||||
}
|
||||
|
||||
NotificationId NotificationManager::get_next_notification_id() {
|
||||
if (is_disabled()) {
|
||||
return NotificationId();
|
||||
@ -66,18 +97,270 @@ NotificationGroupId NotificationManager::get_next_notification_group_id() {
|
||||
return current_notification_group_id_;
|
||||
}
|
||||
|
||||
void NotificationManager::add_notification(NotificationGroupId group_id, DialogId dialog_id,
|
||||
DialogId notification_settings_dialog_id, bool silent,
|
||||
NotificationManager::NotificationGroupKey NotificationManager::get_last_updated_group_key() const {
|
||||
int left = max_notification_group_count_;
|
||||
auto it = groups_.begin();
|
||||
while (it != groups_.end() && left > 1) {
|
||||
++it;
|
||||
left--;
|
||||
}
|
||||
if (it == groups_.end()) {
|
||||
return NotificationGroupKey();
|
||||
}
|
||||
return it->first;
|
||||
}
|
||||
|
||||
int32 NotificationManager::get_notification_delay_ms(DialogId dialog_id,
|
||||
const PendingNotification ¬ification) const {
|
||||
auto delay_ms = [&]() {
|
||||
if (dialog_id.get_type() == DialogType::SecretChat) {
|
||||
return 0; // there is no reason to delay notifications in secret chats
|
||||
}
|
||||
|
||||
auto online_info = td_->contacts_manager_->get_my_online_status();
|
||||
if (!online_info.is_online_local && online_info.is_online_remote) {
|
||||
// If we are offline, but online from some other client then delay notification
|
||||
// for 'notification_cloud_delay' seconds.
|
||||
return notification_cloud_delay_ms_;
|
||||
}
|
||||
|
||||
if (!online_info.is_online_local &&
|
||||
online_info.was_online_remote > max(static_cast<double>(online_info.was_online_local),
|
||||
G()->server_time_cached() - online_cloud_timeout_ms_ * 1e-3)) {
|
||||
// If we are offline, but was online from some other client in last 'online_cloud_timeout' seconds
|
||||
// after we had gone offline, then delay notification for 'notification_cloud_delay' seconds.
|
||||
return notification_cloud_delay_ms_;
|
||||
}
|
||||
|
||||
if (online_info.is_online_remote) {
|
||||
// If some other client is online, then delay notification for 'notification_default_delay' seconds.
|
||||
return notification_default_delay_ms_;
|
||||
}
|
||||
|
||||
// otherwise send update without additional delay
|
||||
return 0;
|
||||
}();
|
||||
|
||||
auto passed_time_ms = max(0, static_cast<int32>((G()->server_time_cached() - notification.date - 1) * 1000));
|
||||
return max(delay_ms - passed_time_ms, MIN_NOTIFICATION_DELAY_MS);
|
||||
}
|
||||
|
||||
void NotificationManager::add_notification(NotificationGroupId group_id, DialogId dialog_id, int32 date,
|
||||
DialogId notification_settings_dialog_id, bool is_silent,
|
||||
NotificationId notification_id, unique_ptr<NotificationType> type) {
|
||||
if (is_disabled()) {
|
||||
return;
|
||||
}
|
||||
|
||||
CHECK(group_id.is_valid());
|
||||
CHECK(dialog_id.is_valid());
|
||||
CHECK(notification_settings_dialog_id.is_valid());
|
||||
CHECK(notification_id.is_valid());
|
||||
CHECK(type != nullptr);
|
||||
VLOG(notifications) << "Add " << notification_id << " to " << group_id << " in " << dialog_id
|
||||
<< " with settings from " << notification_settings_dialog_id
|
||||
<< (silent ? " silent" : " with sound") << ": " << *type;
|
||||
// TODO total_count++;
|
||||
<< (is_silent ? " silent" : " with sound") << ": " << *type;
|
||||
|
||||
auto group_it = get_group(group_id);
|
||||
if (group_it == groups_.end()) {
|
||||
NotificationGroupKey group_key;
|
||||
group_key.group_id = group_id;
|
||||
group_key.dialog_id = dialog_id;
|
||||
group_key.last_notification_date = 0;
|
||||
group_it = std::move(groups_.emplace(group_key, NotificationGroup()).first);
|
||||
}
|
||||
|
||||
PendingNotification notification;
|
||||
notification.date = date;
|
||||
notification.settings_dialog_id = notification_settings_dialog_id;
|
||||
notification.is_silent = is_silent;
|
||||
notification.notification_id = notification_id;
|
||||
notification.type = std::move(type);
|
||||
|
||||
auto delay_ms = get_notification_delay_ms(dialog_id, notification);
|
||||
VLOG(notifications) << "Delay " << notification_id << " for " << delay_ms << " milliseconds";
|
||||
auto flush_time = delay_ms * 0.001 + Time::now_cached();
|
||||
|
||||
NotificationGroup &group = group_it->second;
|
||||
if (group.pending_notifications_flush_time == 0 || flush_time < group.pending_notifications_flush_time) {
|
||||
group.pending_notifications_flush_time = flush_time;
|
||||
flush_pending_notifications_timeout_.set_timeout_at(group_id.get(), group.pending_notifications_flush_time);
|
||||
}
|
||||
group.pending_notifications.push_back(std::move(notification));
|
||||
}
|
||||
|
||||
td_api::object_ptr<td_api::notification> NotificationManager::get_notification_object(
|
||||
DialogId dialog_id, const Notification ¬ification) {
|
||||
return td_api::make_object<td_api::notification>(notification.notification_id.get(),
|
||||
notification.type->get_notification_type_object(dialog_id));
|
||||
}
|
||||
|
||||
void NotificationManager::send_update_notification_group(td_api::object_ptr<td_api::updateNotificationGroup> update) {
|
||||
// TODO delay and combine updates while getDifference is running
|
||||
VLOG(notifications) << "Send " << to_string(update);
|
||||
send_closure(G()->td(), &Td::send_update, std::move(update));
|
||||
}
|
||||
|
||||
void NotificationManager::flush_pending_notifications(NotificationGroupKey &group_key, NotificationGroup &group,
|
||||
vector<PendingNotification> &pending_notifications) {
|
||||
if (pending_notifications.empty()) {
|
||||
return;
|
||||
}
|
||||
|
||||
VLOG(notifications) << "Flush " << pending_notifications.size() << " pending notifications in " << group_key
|
||||
<< " with available " << group.notifications.size() << " from " << group.total_count
|
||||
<< " notifications";
|
||||
|
||||
size_t old_notification_count = group.notifications.size();
|
||||
size_t shown_notification_count = min(old_notification_count, max_notification_group_size_);
|
||||
|
||||
vector<td_api::object_ptr<td_api::notification>> added_notifications;
|
||||
added_notifications.reserve(pending_notifications.size());
|
||||
for (auto &pending_notification : pending_notifications) {
|
||||
Notification notification{pending_notification.notification_id, std::move(pending_notification.type)};
|
||||
added_notifications.push_back(get_notification_object(group_key.dialog_id, notification));
|
||||
if (added_notifications.back()->type_ == nullptr) {
|
||||
added_notifications.pop_back();
|
||||
} else {
|
||||
group.notifications.push_back(std::move(notification));
|
||||
}
|
||||
}
|
||||
if (added_notifications.size() > max_notification_group_size_) {
|
||||
added_notifications.erase(
|
||||
added_notifications.begin(),
|
||||
added_notifications.begin() + (added_notifications.size() - max_notification_group_size_));
|
||||
}
|
||||
|
||||
vector<int32> removed_notification_ids;
|
||||
if (shown_notification_count + added_notifications.size() > max_notification_group_size_) {
|
||||
auto removed_notification_count =
|
||||
shown_notification_count + added_notifications.size() - max_notification_group_size_;
|
||||
removed_notification_ids.reserve(removed_notification_count);
|
||||
for (size_t i = 0; i < removed_notification_count; i++) {
|
||||
removed_notification_ids.push_back(
|
||||
group.notifications[old_notification_count - shown_notification_count + i].notification_id.get());
|
||||
}
|
||||
}
|
||||
|
||||
group.total_count += narrow_cast<int32>(added_notifications.size());
|
||||
if (!added_notifications.empty()) {
|
||||
send_update_notification_group(td_api::make_object<td_api::updateNotificationGroup>(
|
||||
group_key.group_id.get(), group_key.dialog_id.get(), pending_notifications[0].settings_dialog_id.get(),
|
||||
pending_notifications[0].is_silent, group.total_count, std::move(added_notifications),
|
||||
std::move(removed_notification_ids)));
|
||||
} else {
|
||||
CHECK(removed_notification_ids.empty());
|
||||
}
|
||||
pending_notifications.clear();
|
||||
}
|
||||
|
||||
void NotificationManager::send_remove_group_update(NotificationGroupId group_id) {
|
||||
CHECK(group_id.is_valid());
|
||||
auto group_it = get_group(group_id);
|
||||
CHECK(group_it != groups_.end());
|
||||
|
||||
auto total_size = group_it->second.notifications.size();
|
||||
auto removed_size = min(total_size, max_notification_group_size_);
|
||||
vector<int32> removed_notification_ids;
|
||||
removed_notification_ids.reserve(removed_size);
|
||||
for (size_t i = total_size - removed_size; i < total_size; i++) {
|
||||
removed_notification_ids.push_back(group_it->second.notifications[i].notification_id.get());
|
||||
}
|
||||
|
||||
if (!removed_notification_ids.empty()) {
|
||||
send_update_notification_group(td_api::make_object<td_api::updateNotificationGroup>(
|
||||
group_id.get(), group_it->first.dialog_id.get(), group_it->first.dialog_id.get(), true, 0,
|
||||
vector<td_api::object_ptr<td_api::notification>>(), std::move(removed_notification_ids)));
|
||||
}
|
||||
}
|
||||
|
||||
void NotificationManager::send_add_group_update(const NotificationGroupKey &group_key, const NotificationGroup &group) {
|
||||
auto total_size = group.notifications.size();
|
||||
auto added_size = min(total_size, max_notification_group_size_);
|
||||
vector<td_api::object_ptr<td_api::notification>> added_notifications;
|
||||
added_notifications.reserve(added_size);
|
||||
for (size_t i = total_size - added_size; i < total_size; i++) {
|
||||
added_notifications.push_back(get_notification_object(group_key.dialog_id, group.notifications[i]));
|
||||
if (added_notifications.back()->type_ == nullptr) {
|
||||
added_notifications.pop_back();
|
||||
}
|
||||
}
|
||||
|
||||
if (!added_notifications.empty()) {
|
||||
send_update_notification_group(
|
||||
td_api::make_object<td_api::updateNotificationGroup>(group_key.group_id.get(), group_key.dialog_id.get(), 0,
|
||||
true, 0, std::move(added_notifications), vector<int32>()));
|
||||
}
|
||||
}
|
||||
|
||||
void NotificationManager::flush_pending_notifications(NotificationGroupId group_id) {
|
||||
auto group_it = get_group(group_id);
|
||||
CHECK(group_it != groups_.end());
|
||||
auto group_key = group_it->first;
|
||||
auto group = std::move(group_it->second);
|
||||
|
||||
groups_.erase(group_it);
|
||||
|
||||
CHECK(!group.pending_notifications.empty());
|
||||
auto final_group_key = group_key;
|
||||
for (auto &pending_notification : group.pending_notifications) {
|
||||
if (pending_notification.date >= final_group_key.last_notification_date) {
|
||||
final_group_key.last_notification_date = pending_notification.date;
|
||||
}
|
||||
}
|
||||
CHECK(final_group_key.last_notification_date != 0);
|
||||
|
||||
VLOG(notifications) << "Flush pending notifications in " << group_key << " up to "
|
||||
<< final_group_key.last_notification_date;
|
||||
|
||||
auto last_group_key = get_last_updated_group_key();
|
||||
bool was_updated = group_key.last_notification_date != 0 && group_key < last_group_key;
|
||||
bool is_updated = final_group_key < last_group_key;
|
||||
|
||||
if (!is_updated) {
|
||||
CHECK(!was_updated);
|
||||
VLOG(notifications) << "There is no need to send updateNotificationGroup in " << group_key
|
||||
<< ", because of newer notification groups";
|
||||
for (auto &pending_notification : group.pending_notifications) {
|
||||
group.notifications.emplace_back(pending_notification.notification_id, std::move(pending_notification.type));
|
||||
}
|
||||
} else {
|
||||
if (!was_updated) {
|
||||
if (last_group_key.last_notification_date != 0) {
|
||||
// need to remove last notification group to not exceed max_notification_group_size_
|
||||
send_remove_group_update(last_group_key.group_id);
|
||||
}
|
||||
send_add_group_update(group_key, group);
|
||||
}
|
||||
|
||||
DialogId notification_settings_dialog_id;
|
||||
bool is_silent = false;
|
||||
|
||||
// split notifications by groups with common settings
|
||||
vector<PendingNotification> grouped_notifications;
|
||||
for (auto &pending_notification : group.pending_notifications) {
|
||||
if (notification_settings_dialog_id != pending_notification.settings_dialog_id ||
|
||||
is_silent != pending_notification.is_silent) {
|
||||
flush_pending_notifications(group_key, group, grouped_notifications);
|
||||
notification_settings_dialog_id = pending_notification.settings_dialog_id;
|
||||
is_silent = pending_notification.is_silent;
|
||||
}
|
||||
grouped_notifications.push_back(std::move(pending_notification));
|
||||
}
|
||||
flush_pending_notifications(group_key, group, grouped_notifications);
|
||||
}
|
||||
|
||||
group.pending_notifications_flush_time = 0;
|
||||
group.pending_notifications.clear();
|
||||
if (group.notifications.size() >
|
||||
keep_notification_group_size_ + EXTRA_GROUP_SIZE) { // ensure that we delete a lot of messages simultaneously
|
||||
// keep only keep_notification_group_size_ last notifications in memory
|
||||
group.notifications.erase(
|
||||
group.notifications.begin(),
|
||||
group.notifications.begin() + (group.notifications.size() - keep_notification_group_size_));
|
||||
}
|
||||
|
||||
groups_.emplace(std::move(final_group_key), std::move(group));
|
||||
}
|
||||
|
||||
void NotificationManager::edit_notification(NotificationId notification_id, unique_ptr<NotificationType> type) {
|
||||
@ -85,6 +368,8 @@ void NotificationManager::edit_notification(NotificationId notification_id, uniq
|
||||
return;
|
||||
}
|
||||
|
||||
CHECK(notification_id.is_valid());
|
||||
CHECK(type != nullptr);
|
||||
VLOG(notifications) << "Edit " << notification_id << ": " << *type;
|
||||
}
|
||||
|
||||
@ -92,6 +377,8 @@ void NotificationManager::delete_notification(NotificationId notification_id) {
|
||||
if (is_disabled()) {
|
||||
return;
|
||||
}
|
||||
|
||||
CHECK(notification_id.is_valid());
|
||||
}
|
||||
|
||||
void NotificationManager::remove_notification(NotificationId notification_id, Promise<Unit> &&promise) {
|
||||
@ -124,4 +411,48 @@ void NotificationManager::remove_notification_group(NotificationGroupId group_id
|
||||
promise.set_value(Unit());
|
||||
}
|
||||
|
||||
void NotificationManager::on_notification_group_count_max_changed() {
|
||||
if (is_disabled()) {
|
||||
return;
|
||||
}
|
||||
|
||||
auto new_max_notification_group_count =
|
||||
G()->shared_config().get_option_integer("notification_group_count_max", DEFAULT_GROUP_COUNT_MAX);
|
||||
CHECK(MIN_NOTIFICATION_GROUP_COUNT_MAX <= new_max_notification_group_count &&
|
||||
new_max_notification_group_count <= MAX_NOTIFICATION_GROUP_COUNT_MAX);
|
||||
|
||||
if (static_cast<size_t>(new_max_notification_group_count) == max_notification_group_count_) {
|
||||
return;
|
||||
}
|
||||
|
||||
if (max_notification_group_count_ != 0) {
|
||||
// TODO
|
||||
}
|
||||
|
||||
max_notification_group_count_ = static_cast<size_t>(new_max_notification_group_count);
|
||||
}
|
||||
|
||||
void NotificationManager::on_notification_group_size_max_changed() {
|
||||
if (is_disabled()) {
|
||||
return;
|
||||
}
|
||||
|
||||
auto new_max_notification_group_size =
|
||||
G()->shared_config().get_option_integer("notification_group_size_max", DEFAULT_GROUP_SIZE_MAX);
|
||||
CHECK(MIN_NOTIFICATION_GROUP_SIZE_MAX <= new_max_notification_group_size &&
|
||||
new_max_notification_group_size <= MAX_NOTIFICATION_GROUP_SIZE_MAX);
|
||||
|
||||
if (static_cast<size_t>(new_max_notification_group_size) == max_notification_group_size_) {
|
||||
return;
|
||||
}
|
||||
|
||||
if (max_notification_group_size_ != 0) {
|
||||
// TODO
|
||||
}
|
||||
|
||||
max_notification_group_size_ = static_cast<size_t>(new_max_notification_group_size);
|
||||
keep_notification_group_size_ =
|
||||
max_notification_group_size_ + max(EXTRA_GROUP_SIZE / 2, min(max_notification_group_size_, EXTRA_GROUP_SIZE));
|
||||
}
|
||||
|
||||
} // namespace td
|
||||
|
@ -10,11 +10,16 @@
|
||||
#include "td/telegram/NotificationGroupId.h"
|
||||
#include "td/telegram/NotificationId.h"
|
||||
#include "td/telegram/NotificationType.h"
|
||||
#include "td/telegram/td_api.h"
|
||||
|
||||
#include "td/actor/actor.h"
|
||||
#include "td/actor/PromiseFuture.h"
|
||||
#include "td/actor/Timeout.h"
|
||||
|
||||
#include "td/utils/common.h"
|
||||
#include "td/utils/StringBuilder.h"
|
||||
|
||||
#include <map>
|
||||
|
||||
namespace td {
|
||||
|
||||
@ -24,14 +29,20 @@ class Td;
|
||||
|
||||
class NotificationManager : public Actor {
|
||||
public:
|
||||
static constexpr int32 MIN_NOTIFICATION_GROUP_COUNT_MAX = 1;
|
||||
static constexpr int32 MAX_NOTIFICATION_GROUP_COUNT_MAX = 25;
|
||||
static constexpr int32 MIN_NOTIFICATION_GROUP_SIZE_MAX = 1;
|
||||
static constexpr int32 MAX_NOTIFICATION_GROUP_SIZE_MAX = 25;
|
||||
|
||||
NotificationManager(Td *td, ActorShared<> parent);
|
||||
|
||||
NotificationId get_next_notification_id();
|
||||
|
||||
NotificationGroupId get_next_notification_group_id();
|
||||
|
||||
void add_notification(NotificationGroupId group_id, DialogId dialog_id, DialogId notification_settings_dialog_id,
|
||||
bool silent, NotificationId notification_id, unique_ptr<NotificationType> type);
|
||||
void add_notification(NotificationGroupId group_id, DialogId dialog_id, int32 date,
|
||||
DialogId notification_settings_dialog_id, bool is_silent, NotificationId notification_id,
|
||||
unique_ptr<NotificationType> type);
|
||||
|
||||
void edit_notification(NotificationId notification_id, unique_ptr<NotificationType> type);
|
||||
|
||||
@ -42,40 +53,110 @@ class NotificationManager : public Actor {
|
||||
void remove_notification_group(NotificationGroupId group_id, NotificationId max_notification_id,
|
||||
Promise<Unit> &&promise);
|
||||
|
||||
void on_notification_group_count_max_changed();
|
||||
|
||||
void on_notification_group_size_max_changed();
|
||||
|
||||
private:
|
||||
static constexpr int32 DEFAULT_GROUP_COUNT_MAX = 10;
|
||||
static constexpr int32 DEFAULT_GROUP_SIZE_MAX = 10;
|
||||
static constexpr size_t EXTRA_GROUP_SIZE = 10;
|
||||
|
||||
static constexpr int32 DEFAULT_ONLINE_CLOUD_TIMEOUT_MS = 300000;
|
||||
static constexpr int32 DEFAULT_ONLINE_CLOUD_DELAY_MS = 30000;
|
||||
static constexpr int32 DEFAULT_DEFAULT_DELAY_MS = 1500;
|
||||
|
||||
static constexpr int32 MIN_NOTIFICATION_DELAY_MS = 1;
|
||||
|
||||
struct Notification {
|
||||
NotificationId notification_id;
|
||||
unique_ptr<NotificationType> type;
|
||||
|
||||
Notification(NotificationId notification_id, unique_ptr<NotificationType> type)
|
||||
: notification_id(notification_id), type(std::move(type)) {
|
||||
}
|
||||
};
|
||||
|
||||
struct PendingNotification {
|
||||
int32 date = 0;
|
||||
DialogId settings_dialog_id;
|
||||
bool silent = false;
|
||||
bool is_silent = false;
|
||||
NotificationId notification_id;
|
||||
unique_ptr<NotificationType> type;
|
||||
};
|
||||
|
||||
struct NotificationGroup {
|
||||
struct NotificationGroupKey {
|
||||
NotificationGroupId group_id;
|
||||
DialogId dialog_id;
|
||||
int32 last_notification_date = 0;
|
||||
|
||||
bool operator<(const NotificationGroupKey &other) const {
|
||||
if (last_notification_date != other.last_notification_date) {
|
||||
return last_notification_date > other.last_notification_date;
|
||||
}
|
||||
if (dialog_id != other.dialog_id) {
|
||||
return dialog_id.get() > other.dialog_id.get();
|
||||
}
|
||||
return group_id.get() > other.group_id.get();
|
||||
}
|
||||
|
||||
friend StringBuilder &operator<<(StringBuilder &string_builder, const NotificationGroupKey &group_key) {
|
||||
return string_builder << '[' << group_key.group_id << ',' << group_key.dialog_id << ','
|
||||
<< group_key.last_notification_date << ']';
|
||||
}
|
||||
};
|
||||
struct NotificationGroup {
|
||||
int32 total_count = 0;
|
||||
|
||||
vector<Notification> notifications;
|
||||
|
||||
double pending_notifications_flush_time = 0;
|
||||
vector<PendingNotification> pending_notifications;
|
||||
};
|
||||
|
||||
using NotificationGroups = std::map<NotificationGroupKey, NotificationGroup>;
|
||||
|
||||
static void on_flush_pending_notifications_timeout_callback(void *notification_manager_ptr, int64 group_id_int);
|
||||
|
||||
bool is_disabled() const;
|
||||
|
||||
void start_up() override;
|
||||
void tear_down() override;
|
||||
|
||||
static td_api::object_ptr<td_api::notification> get_notification_object(DialogId dialog_id,
|
||||
const Notification ¬ification);
|
||||
|
||||
void send_update_notification_group(td_api::object_ptr<td_api::updateNotificationGroup> update);
|
||||
|
||||
NotificationGroups::iterator get_group(NotificationGroupId group_id);
|
||||
|
||||
NotificationGroupKey get_last_updated_group_key() const;
|
||||
|
||||
void send_remove_group_update(NotificationGroupId group_id);
|
||||
|
||||
void send_add_group_update(const NotificationGroupKey &group_key, const NotificationGroup &group);
|
||||
|
||||
int32 get_notification_delay_ms(DialogId dialog_id, const PendingNotification ¬ification) const;
|
||||
|
||||
void flush_pending_notifications(NotificationGroupKey &group_key, NotificationGroup &group,
|
||||
vector<PendingNotification> &pending_notifications);
|
||||
|
||||
void flush_pending_notifications(NotificationGroupId group_id);
|
||||
|
||||
NotificationId current_notification_id_;
|
||||
NotificationGroupId current_notification_group_id_;
|
||||
|
||||
static constexpr int32 DEFAULT_NOTIFICATION_GROUP_COUNT_MAX = 10;
|
||||
static constexpr int32 DEFAULT_NOTIFICATION_GROUP_SIZE_MAX = 10;
|
||||
size_t max_notification_group_count_ = 0;
|
||||
size_t max_notification_group_size_ = 0;
|
||||
size_t keep_notification_group_size_ = 0;
|
||||
|
||||
int32 max_notification_group_count_;
|
||||
int32 max_notification_group_size_;
|
||||
int32 online_cloud_timeout_ms_ = DEFAULT_ONLINE_CLOUD_TIMEOUT_MS;
|
||||
int32 notification_cloud_delay_ms_ = DEFAULT_ONLINE_CLOUD_DELAY_MS;
|
||||
int32 notification_default_delay_ms_ = DEFAULT_DEFAULT_DELAY_MS;
|
||||
|
||||
NotificationGroups groups_;
|
||||
|
||||
MultiTimeout flush_pending_notifications_timeout_{"FlushPendingNotificationsTimeout"};
|
||||
|
||||
Td *td_;
|
||||
ActorShared<> parent_;
|
||||
|
@ -6,9 +6,20 @@
|
||||
//
|
||||
#include "td/telegram/NotificationType.h"
|
||||
|
||||
#include "td/telegram/MessagesManager.h"
|
||||
#include "td/telegram/Td.h"
|
||||
|
||||
namespace td {
|
||||
|
||||
class NotificationTypeMessage : public NotificationType {
|
||||
td_api::object_ptr<td_api::NotificationType> get_notification_type_object(DialogId dialog_id) const override {
|
||||
auto message_object = G()->td().get_actor_unsafe()->messages_manager_->get_message_object({dialog_id, message_id_});
|
||||
if (message_object == nullptr) {
|
||||
return nullptr;
|
||||
}
|
||||
return td_api::make_object<td_api::notificationTypeNewMessage>(std::move(message_object));
|
||||
}
|
||||
|
||||
StringBuilder &to_string_builder(StringBuilder &string_builder) const override {
|
||||
return string_builder << "NewMessageNotification[" << message_id_ << ']';
|
||||
}
|
||||
@ -25,6 +36,10 @@ class NotificationTypeMessage : public NotificationType {
|
||||
};
|
||||
|
||||
class NotificationTypeSecretChat : public NotificationType {
|
||||
td_api::object_ptr<td_api::NotificationType> get_notification_type_object(DialogId dialog_id) const override {
|
||||
return td_api::make_object<td_api::notificationTypeNewSecretChat>();
|
||||
}
|
||||
|
||||
StringBuilder &to_string_builder(StringBuilder &string_builder) const override {
|
||||
return string_builder << "NewSecretChatNotification[]";
|
||||
}
|
||||
@ -39,6 +54,10 @@ class NotificationTypeSecretChat : public NotificationType {
|
||||
};
|
||||
|
||||
class NotificationTypeCall : public NotificationType {
|
||||
td_api::object_ptr<td_api::NotificationType> get_notification_type_object(DialogId dialog_id) const override {
|
||||
return td_api::make_object<td_api::notificationTypeNewCall>(call_id_.get());
|
||||
}
|
||||
|
||||
StringBuilder &to_string_builder(StringBuilder &string_builder) const override {
|
||||
return string_builder << "NewCallNotification[" << call_id_ << ']';
|
||||
}
|
||||
|
@ -8,6 +8,7 @@
|
||||
|
||||
#include "td/telegram/CallId.h"
|
||||
#include "td/telegram/MessageId.h"
|
||||
#include "td/telegram/td_api.h"
|
||||
|
||||
#include "td/utils/common.h"
|
||||
#include "td/utils/StringBuilder.h"
|
||||
@ -25,6 +26,8 @@ class NotificationType {
|
||||
virtual ~NotificationType() {
|
||||
}
|
||||
|
||||
virtual td_api::object_ptr<td_api::NotificationType> get_notification_type_object(DialogId dialog_id) const = 0;
|
||||
|
||||
virtual StringBuilder &to_string_builder(StringBuilder &string_builder) const = 0;
|
||||
|
||||
protected:
|
||||
|
@ -3485,6 +3485,10 @@ void Td::on_config_option_updated(const string &name) {
|
||||
} else if (name == "language_pack_version") {
|
||||
send_closure(language_pack_manager_, &LanguagePackManager::on_language_pack_version_changed, -1);
|
||||
return;
|
||||
} else if (name == "notification_group_count_max") {
|
||||
send_closure(notification_manager_actor_, &NotificationManager::on_notification_group_count_max_changed);
|
||||
} else if (name == "notification_group_size_max") {
|
||||
send_closure(notification_manager_actor_, &NotificationManager::on_notification_group_size_max_changed);
|
||||
} else if (is_internal_config_option(name)) {
|
||||
return;
|
||||
}
|
||||
@ -6226,10 +6230,14 @@ void Td::on_request(uint64 id, td_api::setOption &request) {
|
||||
}
|
||||
break;
|
||||
case 'n':
|
||||
if (!is_bot && set_integer_option("notification_group_count_max", 1, 25)) {
|
||||
if (!is_bot &&
|
||||
set_integer_option("notification_group_count_max", NotificationManager::MIN_NOTIFICATION_GROUP_COUNT_MAX,
|
||||
NotificationManager::MAX_NOTIFICATION_GROUP_COUNT_MAX)) {
|
||||
return;
|
||||
}
|
||||
if (!is_bot && set_integer_option("notification_group_size_max", 1, 25)) {
|
||||
if (!is_bot &&
|
||||
set_integer_option("notification_group_size_max", NotificationManager::MIN_NOTIFICATION_GROUP_SIZE_MAX,
|
||||
NotificationManager::MAX_NOTIFICATION_GROUP_SIZE_MAX)) {
|
||||
return;
|
||||
}
|
||||
break;
|
||||
|
@ -4,9 +4,6 @@
|
||||
// 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)
|
||||
//
|
||||
// Just for testing.
|
||||
// Will be completly rewritten
|
||||
|
||||
#include "td/actor/actor.h"
|
||||
|
||||
#include "td/telegram/td_json_client.h"
|
||||
|
Loading…
Reference in New Issue
Block a user