tdlight/td/telegram/RecentDialogList.cpp

278 lines
8.0 KiB
C++
Raw Normal View History

2021-09-13 19:34:57 +02:00
//
// Copyright Aliaksei Levin (levlam@telegram.org), Arseny Smirnov (arseny30@gmail.com) 2014-2021
//
// 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)
//
#include "td/telegram/RecentDialogList.h"
2021-09-18 23:47:05 +02:00
#include "td/telegram/AccessRights.h"
2021-09-13 19:34:57 +02:00
#include "td/telegram/ContactsManager.h"
2021-09-18 23:47:05 +02:00
#include "td/telegram/DialogListId.h"
#include "td/telegram/FolderId.h"
2021-09-13 19:34:57 +02:00
#include "td/telegram/Global.h"
#include "td/telegram/MessagesManager.h"
#include "td/telegram/Td.h"
2021-09-18 23:47:05 +02:00
#include "td/telegram/td_api.h"
2021-09-13 19:34:57 +02:00
#include "td/telegram/TdDb.h"
#include "td/telegram/TdParameters.h"
2021-09-18 23:47:05 +02:00
#include "td/actor/MultiPromise.h"
2021-09-13 19:34:57 +02:00
#include "td/utils/algorithm.h"
#include "td/utils/misc.h"
2021-09-18 23:47:05 +02:00
#include "td/utils/Slice.h"
2021-09-13 19:34:57 +02:00
#include "td/utils/SliceBuilder.h"
2021-09-15 16:16:23 +02:00
#include <algorithm>
2021-09-13 19:34:57 +02:00
namespace td {
RecentDialogList::RecentDialogList(Td *td, const char *name, size_t max_size)
: td_(td), name_(name), max_size_(max_size) {
register_actor(PSLICE() << name << "_chats", this).release();
2021-09-13 19:34:57 +02:00
}
string RecentDialogList::get_binlog_key() const {
return PSTRING() << name_ << "_dialog_usernames_and_ids";
}
void RecentDialogList::save_dialogs() const {
2021-09-14 10:31:21 +02:00
if (!is_loaded_) {
2021-09-13 19:34:57 +02:00
return;
}
CHECK(removed_dialog_ids_.empty());
2021-09-13 19:34:57 +02:00
SliceBuilder sb;
2021-09-13 19:34:57 +02:00
for (auto &dialog_id : dialog_ids_) {
sb << ',';
if (!G()->parameters().use_chat_info_db) {
// if there is no dialog info database, prefer to save dialogs by username
2021-09-13 19:34:57 +02:00
string username;
switch (dialog_id.get_type()) {
case DialogType::User:
if (!td_->contacts_manager_->is_user_contact(dialog_id.get_user_id())) {
username = td_->contacts_manager_->get_user_username(dialog_id.get_user_id());
}
2021-09-13 19:34:57 +02:00
break;
case DialogType::Chat:
break;
case DialogType::Channel:
username = td_->contacts_manager_->get_channel_username(dialog_id.get_channel_id());
break;
case DialogType::SecretChat:
break;
case DialogType::None:
default:
UNREACHABLE();
}
2021-09-14 10:31:21 +02:00
if (!username.empty() && username.find(',') == string::npos) {
sb << '@' << username;
2021-09-13 19:34:57 +02:00
continue;
}
}
sb << dialog_id.get();
}
auto result = sb.as_cslice();
if (!result.empty()) {
result.remove_prefix(1);
2021-09-13 19:34:57 +02:00
}
G()->td_db()->get_binlog_pmc()->set(get_binlog_key(), result.str());
2021-09-13 19:34:57 +02:00
}
void RecentDialogList::load_dialogs(Promise<Unit> &&promise) {
2021-09-14 10:31:21 +02:00
if (is_loaded_) {
return promise.set_value(Unit());
2021-09-13 19:34:57 +02:00
}
2021-09-14 10:31:21 +02:00
load_list_queries_.push_back(std::move(promise));
if (load_list_queries_.size() != 1) {
return;
2021-09-13 19:34:57 +02:00
}
2021-09-14 10:31:21 +02:00
auto found_dialogs = full_split(G()->td_db()->get_binlog_pmc()->get(get_binlog_key()), ',');
MultiPromiseActorSafe mpas{"LoadRecentDialogListMultiPromiseActor"};
mpas.add_promise(PromiseCreator::lambda([actor_id = actor_id(this), found_dialogs](Unit) mutable {
send_closure(actor_id, &RecentDialogList::on_load_dialogs, std::move(found_dialogs));
}));
mpas.set_ignore_errors(true);
auto lock = mpas.get_promise();
2021-09-13 19:34:57 +02:00
2021-09-14 10:31:21 +02:00
vector<DialogId> dialog_ids;
for (auto &found_dialog : found_dialogs) {
if (found_dialog[0] == '@') {
td_->messages_manager_->search_public_dialog(found_dialog, false, mpas.get_promise());
} else {
dialog_ids.push_back(DialogId(to_integer<int64>(found_dialog)));
2021-09-13 19:34:57 +02:00
}
2021-09-14 10:31:21 +02:00
}
2021-10-05 09:44:13 +02:00
if (!dialog_ids.empty()) {
if (G()->parameters().use_chat_info_db) {
td_->messages_manager_->load_dialogs(
std::move(dialog_ids),
PromiseCreator::lambda(
[promise = mpas.get_promise()](vector<DialogId> dialog_ids) mutable { promise.set_value(Unit()); }));
} else {
td_->messages_manager_->get_dialogs_from_list(
DialogListId(FolderId::main()), 102,
PromiseCreator::lambda([promise = mpas.get_promise()](td_api::object_ptr<td_api::chats> &&chats) mutable {
promise.set_value(Unit());
}));
td_->contacts_manager_->search_contacts("", 1, mpas.get_promise());
}
2021-09-13 19:34:57 +02:00
}
2021-09-14 10:31:21 +02:00
lock.set_value(Unit());
}
2021-09-13 19:34:57 +02:00
2021-09-14 10:31:21 +02:00
void RecentDialogList::on_load_dialogs(vector<string> &&found_dialogs) {
auto promises = std::move(load_list_queries_);
CHECK(!promises.empty());
2021-09-13 19:34:57 +02:00
2021-10-07 14:28:52 +02:00
if (G()->close_flag()) {
for (auto &promise : promises) {
2021-10-07 15:36:21 +02:00
promise.set_error(Global::request_aborted_error());
2021-10-07 14:28:52 +02:00
}
return;
}
2021-09-14 10:31:21 +02:00
auto newly_found_dialogs = std::move(dialog_ids_);
reset_to_empty(dialog_ids_);
for (auto it = found_dialogs.rbegin(); it != found_dialogs.rend(); ++it) {
DialogId dialog_id;
if ((*it)[0] == '@') {
dialog_id = td_->messages_manager_->resolve_dialog_username(it->substr(1));
} else {
dialog_id = DialogId(to_integer<int64>(*it));
2021-09-13 19:34:57 +02:00
}
2021-09-14 10:31:21 +02:00
if (dialog_id.is_valid() && removed_dialog_ids_.count(dialog_id) == 0 &&
td_->messages_manager_->have_dialog_info(dialog_id) &&
2021-09-14 10:31:21 +02:00
td_->messages_manager_->have_input_peer(dialog_id, AccessRights::Read)) {
td_->messages_manager_->force_create_dialog(dialog_id, "recent dialog");
do_add_dialog(dialog_id);
2021-09-13 19:34:57 +02:00
}
2021-09-14 10:31:21 +02:00
}
for (auto it = newly_found_dialogs.rbegin(); it != newly_found_dialogs.rend(); ++it) {
do_add_dialog(*it);
}
is_loaded_ = true;
removed_dialog_ids_.clear();
if (!newly_found_dialogs.empty()) {
save_dialogs();
}
2021-09-13 19:34:57 +02:00
2021-09-14 10:31:21 +02:00
for (auto &promise : promises) {
promise.set_value(Unit());
2021-09-13 19:34:57 +02:00
}
}
void RecentDialogList::add_dialog(DialogId dialog_id) {
2021-09-14 10:31:21 +02:00
if (!is_loaded_) {
load_dialogs(Promise<Unit>());
}
2021-09-13 19:34:57 +02:00
if (do_add_dialog(dialog_id)) {
save_dialogs();
}
}
bool RecentDialogList::do_add_dialog(DialogId dialog_id) {
if (!dialog_ids_.empty() && dialog_ids_[0] == dialog_id) {
return false;
}
// TODO create function
auto it = std::find(dialog_ids_.begin(), dialog_ids_.end(), dialog_id);
if (it == dialog_ids_.end()) {
if (dialog_ids_.size() == max_size_) {
CHECK(!dialog_ids_.empty());
dialog_ids_.back() = dialog_id;
} else {
dialog_ids_.push_back(dialog_id);
}
it = dialog_ids_.end() - 1;
}
std::rotate(dialog_ids_.begin(), it, it + 1);
removed_dialog_ids_.erase(dialog_id);
2021-09-13 19:34:57 +02:00
return true;
}
void RecentDialogList::remove_dialog(DialogId dialog_id) {
2021-09-14 10:31:21 +02:00
if (!is_loaded_) {
load_dialogs(Promise<Unit>());
}
2021-09-13 19:34:57 +02:00
if (td::remove(dialog_ids_, dialog_id)) {
save_dialogs();
2021-09-14 10:31:21 +02:00
} else if (!is_loaded_) {
removed_dialog_ids_.insert(dialog_id);
2021-09-13 19:34:57 +02:00
}
}
void RecentDialogList::update_dialogs() {
2021-09-14 10:31:21 +02:00
CHECK(is_loaded_);
2021-09-13 19:34:57 +02:00
vector<DialogId> dialog_ids;
for (auto dialog_id : dialog_ids_) {
if (!td_->messages_manager_->have_dialog(dialog_id)) {
continue;
}
switch (dialog_id.get_type()) {
case DialogType::User:
// always keep
break;
case DialogType::Chat: {
auto channel_id = td_->contacts_manager_->get_chat_migrated_to_channel_id(dialog_id.get_chat_id());
if (channel_id.is_valid() && td_->messages_manager_->have_dialog(DialogId(channel_id))) {
dialog_id = DialogId(channel_id);
}
break;
}
case DialogType::Channel:
// always keep
break;
case DialogType::SecretChat:
if (td_->messages_manager_->is_deleted_secret_chat(dialog_id)) {
dialog_id = DialogId();
}
break;
case DialogType::None:
default:
UNREACHABLE();
break;
}
if (dialog_id.is_valid()) {
dialog_ids.push_back(dialog_id);
}
}
if (dialog_ids != dialog_ids_) {
dialog_ids_ = std::move(dialog_ids);
save_dialogs();
}
}
std::pair<int32, vector<DialogId>> RecentDialogList::get_dialogs(int32 limit, Promise<Unit> &&promise) {
load_dialogs(std::move(promise));
2021-09-14 10:31:21 +02:00
if (!is_loaded_) {
return {};
}
2021-09-13 19:34:57 +02:00
update_dialogs();
2021-09-14 10:31:21 +02:00
CHECK(limit >= 0);
int32 total_count = narrow_cast<int32>(dialog_ids_.size());
return {total_count, vector<DialogId>(dialog_ids_.begin(), dialog_ids_.begin() + min(limit, total_count))};
2021-09-13 19:34:57 +02:00
}
void RecentDialogList::clear_dialogs() {
2021-09-14 10:31:21 +02:00
if (dialog_ids_.empty() && is_loaded_) {
2021-09-13 19:34:57 +02:00
return;
}
2021-09-14 10:31:21 +02:00
is_loaded_ = true;
2021-09-13 19:34:57 +02:00
dialog_ids_.clear();
removed_dialog_ids_.clear();
2021-09-13 19:34:57 +02:00
save_dialogs();
}
} // namespace td