Store server dialog filters separately.

GitOrigin-RevId: 30c0da52c254008ab17e3be0b6707cd0678a87ec
This commit is contained in:
levlam 2020-05-25 22:31:12 +03:00
parent 8bb76ff0e9
commit d85dd48101
2 changed files with 140 additions and 24 deletions

View File

@ -5011,18 +5011,22 @@ void MessagesManager::DialogFilter::parse(ParserT &parser) {
class MessagesManager::DialogFiltersLogEvent {
public:
int32 updated_date = 0;
const vector<unique_ptr<DialogFilter>> *server_dialog_filters_in;
const vector<unique_ptr<DialogFilter>> *dialog_filters_in;
vector<unique_ptr<DialogFilter>> server_dialog_filters_out;
vector<unique_ptr<DialogFilter>> dialog_filters_out;
template <class StorerT>
void store(StorerT &storer) const {
td::store(updated_date, storer);
td::store(*server_dialog_filters_in, storer);
td::store(*dialog_filters_in, storer);
}
template <class ParserT>
void parse(ParserT &parser) {
td::parse(updated_date, parser);
td::parse(server_dialog_filters_out, parser);
td::parse(dialog_filters_out, parser);
}
};
@ -10966,10 +10970,15 @@ void MessagesManager::init() {
auto dialog_filters = G()->td_db()->get_binlog_pmc()->get("dialog_filters");
if (!dialog_filters.empty()) {
DialogFiltersLogEvent log_event;
log_event_parse(log_event, dialog_filters).ensure();
if (log_event_parse(log_event, dialog_filters).is_ok()) {
dialog_filters_updated_date_ = log_event.updated_date;
dialog_filters_ = std::move(log_event.dialog_filters_out);
server_dialog_filters_ = std::move(log_event.server_dialog_filters_out);
for (auto &dialog_filter : log_event.dialog_filters_out) {
add_dialog_filter(std::move(dialog_filter), "binlog");
}
} else {
LOG(ERROR) << "Failed to parse chat filters from binlog";
}
}
send_update_chat_filters(true); // always send updateChatFilters
@ -14240,22 +14249,77 @@ void MessagesManager::on_get_dialog_filters(Result<vector<tl_object_ptr<telegram
}
auto filters = r_filters.move_as_ok();
vector<unique_ptr<DialogFilter>> dialog_filters;
vector<unique_ptr<DialogFilter>> new_server_dialog_filters;
LOG(INFO) << "Receive " << filters.size() << " chat filters";
std::unordered_set<DialogFilterId, DialogFilterIdHash> new_dialog_filter_ids;
for (auto &filter : filters) {
auto dialog_filter = DialogFilter::get_dialog_filter(std::move(filter), true);
if (dialog_filter == nullptr) {
continue;
}
if (!new_dialog_filter_ids.insert(dialog_filter->dialog_filter_id).second) {
LOG(ERROR) << "Receive duplicate " << dialog_filter->dialog_filter_id;
continue;
}
// TODO add secret chats to the filter
dialog_filters.push_back(std::move(dialog_filter));
new_server_dialog_filters.push_back(std::move(dialog_filter));
}
dialog_filters_updated_date_ = G()->unix_time();
if (dialog_filters_ != dialog_filters) {
// TODO update all changed chat lists and their unread counts
dialog_filters_ = std::move(dialog_filters);
if (server_dialog_filters_ != new_server_dialog_filters) {
std::unordered_map<DialogFilterId, const DialogFilter *, DialogFilterIdHash> old_server_dialog_filters;
for (auto &filter : server_dialog_filters_) {
old_server_dialog_filters.emplace(filter->dialog_filter_id, filter.get());
}
for (auto &new_server_filter : new_server_dialog_filters) {
auto dialog_filter_id = new_server_filter->dialog_filter_id;
auto old_filter = get_dialog_filter(dialog_filter_id);
auto it = old_server_dialog_filters.find(dialog_filter_id);
if (it != old_server_dialog_filters.end()) {
auto old_server_filter = it->second;
if (*new_server_filter != *old_server_filter) {
if (old_filter == nullptr) {
// the filter was deleted, don't need to edit it
} else if (*old_filter == *new_server_filter) {
// the filter was edited from this client, nothing to do
} else if (*old_filter == *old_server_filter) {
// the filter was edited only from another client
edit_dialog_filter(make_unique<DialogFilter>(*new_server_filter), "on_get_dialog_filters 1");
} else {
// the filter was edited both locally and remotely
// TODO merge local and remote changes
edit_dialog_filter(make_unique<DialogFilter>(*new_server_filter), "on_get_dialog_filters 2");
}
}
old_server_dialog_filters.erase(it);
} else {
if (old_filter == nullptr) {
// the filter was added from another client
add_dialog_filter(make_unique<DialogFilter>(*new_server_filter), "on_get_dialog_filters");
} else if (*old_filter == *new_server_filter) {
// the filter was added from that client, nothing to do
} else {
// the filter was added from two different client simultaneously,
// or it was added and edited from that client
// prefer local value, so do nothing
}
}
}
for (auto &old_server_filter : old_server_dialog_filters) {
auto dialog_filter_id = old_server_filter.first;
// deleted filter
auto old_filter = get_dialog_filter(dialog_filter_id);
if (old_filter == nullptr) {
// the filter was deleted from this client, nothing to do
} else {
// the filter was deleted from another client
// ignore edits done from the current client and just delete the filter
delete_dialog_filter(dialog_filter_id, "on_get_dialog_filters");
}
}
// TODO update dialog filter order
server_dialog_filters_ = std::move(new_server_dialog_filters);
send_update_chat_filters(false);
}
schedule_dialog_filters_reload(DIALOG_FILTERS_CACHE_TIME * 0.0001 * Random::fast(9000, 11000));
@ -15262,7 +15326,7 @@ void MessagesManager::create_dialog_filter(td_api::object_ptr<td_api::chatFilter
auto min_id = static_cast<int>(DialogFilterId::min().get());
auto max_id = static_cast<int>(DialogFilterId::max().get());
dialog_filter_id = DialogFilterId(static_cast<int32>(Random::fast(min_id, max_id)));
} while (get_dialog_filter(dialog_filter_id) != nullptr);
} while (get_dialog_filter(dialog_filter_id) != nullptr || get_server_dialog_filter(dialog_filter_id) != nullptr);
auto r_dialog_filter = create_dialog_filter(dialog_filter_id, std::move(filter));
if (r_dialog_filter.is_error()) {
@ -15272,8 +15336,9 @@ void MessagesManager::create_dialog_filter(td_api::object_ptr<td_api::chatFilter
CHECK(dialog_filter != nullptr);
auto input_dialog_filter = dialog_filter->get_input_dialog_filter();
// TODO logevent
// TODO add dialog filter locally
add_dialog_filter(make_unique<DialogFilter>(*dialog_filter), "create_dialog_filter");
send_update_chat_filters(false);
// TODO SequenceDispatcher
auto query_promise = PromiseCreator::lambda([actor_id = actor_id(this), dialog_filter = std::move(dialog_filter),
promise = std::move(promise)](Result<Unit> result) mutable {
@ -15305,8 +15370,9 @@ void MessagesManager::edit_dialog_filter(DialogFilterId dialog_filter_id, td_api
auto input_dialog_filter = new_dialog_filter->get_input_dialog_filter();
// TODO logevent
// TODO edit dialog filter locally
edit_dialog_filter(make_unique<DialogFilter>(*new_dialog_filter), "edit_dialog_filter");
send_update_chat_filters(false);
// TODO SequenceDispatcher
auto query_promise = PromiseCreator::lambda([actor_id = actor_id(this), dialog_filter = std::move(new_dialog_filter),
promise = std::move(promise)](Result<Unit> result) mutable {
@ -15320,11 +15386,11 @@ void MessagesManager::edit_dialog_filter(DialogFilterId dialog_filter_id, td_api
void MessagesManager::on_update_dialog_filter(unique_ptr<DialogFilter> dialog_filter, Status result,
Promise<Unit> &&promise) {
if (result.is_error()) {
// TODO rollback dialog_filters_ changes
return promise.set_error(result.move_as_error());
}
// TODO update all changed chat lists and their unread counts
for (auto &filter : dialog_filters_) {
for (auto &filter : server_dialog_filters_) {
if (filter->dialog_filter_id == dialog_filter->dialog_filter_id) {
if (*filter != *dialog_filter) {
filter = std::move(dialog_filter);
@ -15335,7 +15401,7 @@ void MessagesManager::on_update_dialog_filter(unique_ptr<DialogFilter> dialog_fi
}
}
dialog_filters_.push_back(std::move(dialog_filter));
server_dialog_filters_.push_back(std::move(dialog_filter));
send_update_chat_filters(false);
promise.set_value(Unit());
}
@ -15347,8 +15413,9 @@ void MessagesManager::delete_dialog_filter(DialogFilterId dialog_filter_id, Prom
return promise.set_value(Unit());
}
// TODO logevent
// TODO delete dialog filter locally
delete_dialog_filter(dialog_filter_id, "delete_dialog_filter");
send_update_chat_filters(false);
// TODO SequenceDispatcher
auto query_promise = PromiseCreator::lambda(
[actor_id = actor_id(this), dialog_filter_id, promise = std::move(promise)](Result<Unit> result) mutable {
@ -15360,13 +15427,13 @@ void MessagesManager::delete_dialog_filter(DialogFilterId dialog_filter_id, Prom
void MessagesManager::on_delete_dialog_filter(DialogFilterId dialog_filter_id, Status result, Promise<Unit> &&promise) {
if (result.is_error()) {
// TODO rollback dialog_filters_ changes
return promise.set_error(result.move_as_error());
}
for (auto it = dialog_filters_.begin(); it != dialog_filters_.end(); ++it) {
for (auto it = server_dialog_filters_.begin(); it != server_dialog_filters_.end(); ++it) {
if ((*it)->dialog_filter_id == dialog_filter_id) {
// TODO delete chat list
dialog_filters_.erase(it);
server_dialog_filters_.erase(it);
send_update_chat_filters(false);
break;
}
@ -15422,12 +15489,42 @@ void MessagesManager::reorder_dialog_filters(vector<DialogFilterId> dialog_filte
}
send_update_chat_filters(false);
// TODO logevent
// TODO SequenceDispatcher
td_->create_handler<ReorderDialogFiltersQuery>(std::move(promise))->send(dialog_filter_ids);
return promise.set_value(Unit());
}
void MessagesManager::add_dialog_filter(unique_ptr<DialogFilter> dialog_filter, const char *source) {
CHECK(dialog_filter != nullptr);
LOG(INFO) << "Add " << dialog_filter->dialog_filter_id << " from " << source;
CHECK(get_dialog_filter(dialog_filter->dialog_filter_id) == nullptr);
dialog_filters_.push_back(std::move(dialog_filter));
}
void MessagesManager::edit_dialog_filter(unique_ptr<DialogFilter> dialog_filter, const char *source) {
CHECK(dialog_filter != nullptr);
LOG(INFO) << "Edit " << dialog_filter->dialog_filter_id << " from " << source;
for (auto &filter : dialog_filters_) {
if (filter->dialog_filter_id == dialog_filter->dialog_filter_id) {
CHECK(*filter != *dialog_filter);
filter = std::move(dialog_filter);
return;
}
}
UNREACHABLE();
}
void MessagesManager::delete_dialog_filter(DialogFilterId dialog_filter_id, const char *source) {
LOG(INFO) << "Delete " << dialog_filter_id << " from " << source;
for (auto it = dialog_filters_.begin(); it != server_dialog_filters_.end(); ++it) {
if ((*it)->dialog_filter_id == dialog_filter_id) {
dialog_filters_.erase(it);
return;
}
}
UNREACHABLE();
}
Status MessagesManager::delete_dialog_reply_markup(DialogId dialog_id, MessageId message_id) {
if (td_->auth_manager_->is_bot()) {
return Status::Error(6, "Bots can't delete chat reply markup");
@ -24075,6 +24172,7 @@ void MessagesManager::send_update_chat_filters(bool from_database) {
if (!from_database) {
DialogFiltersLogEvent log_event;
log_event.updated_date = dialog_filters_updated_date_;
log_event.server_dialog_filters_in = &server_dialog_filters_;
log_event.dialog_filters_in = &dialog_filters_;
G()->td_db()->get_binlog_pmc()->set("dialog_filters", log_event_store(log_event).as_slice().str());
@ -30161,6 +30259,15 @@ MessagesManager::Dialog *MessagesManager::on_load_dialog_from_database(DialogId
return add_new_dialog(parse_dialog(dialog_id, value), true);
}
const MessagesManager::DialogFilter *MessagesManager::get_server_dialog_filter(DialogFilterId dialog_filter_id) const {
for (auto &filter : server_dialog_filters_) {
if (filter->dialog_filter_id == dialog_filter_id) {
return filter.get();
}
}
return nullptr;
}
MessagesManager::DialogFilter *MessagesManager::get_dialog_filter(DialogFilterId dialog_filter_id) {
for (auto &filter : dialog_filters_) {
if (filter->dialog_filter_id == dialog_filter_id) {

View File

@ -2253,6 +2253,14 @@ class MessagesManager : public Actor {
void on_delete_dialog_filter(DialogFilterId dialog_filter_id, Status result, Promise<Unit> &&promise);
void add_dialog_filter(unique_ptr<DialogFilter> dialog_filter, const char *source);
void edit_dialog_filter(unique_ptr<DialogFilter> dialog_filter, const char *source);
void delete_dialog_filter(DialogFilterId dialog_filter_id, const char *source);
const DialogFilter *get_server_dialog_filter(DialogFilterId dialog_filter_id) const;
DialogFilter *get_dialog_filter(DialogFilterId dialog_filter_id);
const DialogFilter *get_dialog_filter(DialogFilterId dialog_filter_id) const;
@ -2854,6 +2862,7 @@ class MessagesManager : public Actor {
std::unordered_map<FolderId, DialogFolder, FolderIdHash> dialog_folders_;
int32 dialog_filters_updated_date_ = 0;
vector<unique_ptr<DialogFilter>> server_dialog_filters_;
vector<unique_ptr<DialogFilter>> dialog_filters_;
std::unordered_map<DialogId, string, DialogIdHash> active_get_channel_differencies_;