Add cache of channel participants for bots-administrators.
This commit is contained in:
parent
6f51690275
commit
1e8724127a
@ -3453,6 +3453,9 @@ ContactsManager::ContactsManager(Td *td, ActorShared<> parent) : td_(td), parent
|
|||||||
|
|
||||||
invite_link_info_expire_timeout_.set_callback(on_invite_link_info_expire_timeout_callback);
|
invite_link_info_expire_timeout_.set_callback(on_invite_link_info_expire_timeout_callback);
|
||||||
invite_link_info_expire_timeout_.set_callback_data(static_cast<void *>(this));
|
invite_link_info_expire_timeout_.set_callback_data(static_cast<void *>(this));
|
||||||
|
|
||||||
|
channel_participant_cache_timeout_.set_callback(on_channel_participant_cache_timeout_callback);
|
||||||
|
channel_participant_cache_timeout_.set_callback_data(static_cast<void *>(this));
|
||||||
}
|
}
|
||||||
|
|
||||||
ContactsManager::~ContactsManager() = default;
|
ContactsManager::~ContactsManager() = default;
|
||||||
@ -3614,6 +3617,44 @@ void ContactsManager::on_invite_link_info_expire_timeout(DialogId dialog_id) {
|
|||||||
remove_dialog_access_by_invite_link(dialog_id);
|
remove_dialog_access_by_invite_link(dialog_id);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void ContactsManager::on_channel_participant_cache_timeout_callback(void *contacts_manager_ptr, int64 channel_id_long) {
|
||||||
|
if (G()->close_flag()) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
auto contacts_manager = static_cast<ContactsManager *>(contacts_manager_ptr);
|
||||||
|
send_closure_later(contacts_manager->actor_id(contacts_manager),
|
||||||
|
&ContactsManager::on_channel_participant_cache_timeout,
|
||||||
|
ChannelId(narrow_cast<int32>(channel_id_long)));
|
||||||
|
}
|
||||||
|
|
||||||
|
void ContactsManager::on_channel_participant_cache_timeout(ChannelId channel_id) {
|
||||||
|
if (G()->close_flag()) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
auto channel_participants_it = channel_participants_.find(channel_id);
|
||||||
|
if (channel_participants_it == channel_participants_.end()) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
auto &participants = channel_participants_it->second.participants_;
|
||||||
|
auto min_access_date = G()->unix_time() - CHANNEL_PARTICIPANT_CACHE_TIME;
|
||||||
|
for (auto it = participants.begin(); it != participants.end();) {
|
||||||
|
if (it->second.last_access_date_ < min_access_date) {
|
||||||
|
it = participants.erase(it);
|
||||||
|
} else {
|
||||||
|
++it;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (participants.empty()) {
|
||||||
|
channel_participants_.erase(channel_participants_it);
|
||||||
|
} else {
|
||||||
|
channel_participant_cache_timeout_.set_timeout_in(channel_id.get(), CHANNEL_PARTICIPANT_CACHE_TIME);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
template <class StorerT>
|
template <class StorerT>
|
||||||
void ContactsManager::BotInfo::store(StorerT &storer) const {
|
void ContactsManager::BotInfo::store(StorerT &storer) const {
|
||||||
using td::store;
|
using td::store;
|
||||||
@ -11749,6 +11790,11 @@ void ContactsManager::on_get_channel_participants(
|
|||||||
on_update_channel_bot_user_ids(channel_id, std::move(bot_user_ids));
|
on_update_channel_bot_user_ids(channel_id, std::move(bot_user_ids));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
if (have_channel_participant_cache(channel_id)) {
|
||||||
|
for (const auto &participant : result) {
|
||||||
|
add_channel_participant_to_cache(channel_id, participant, false);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
if (participant_count != -1 || administrator_count != -1) {
|
if (participant_count != -1 || administrator_count != -1) {
|
||||||
auto channel_full = get_channel_full_force(channel_id, "on_get_channel_participants_success");
|
auto channel_full = get_channel_full_force(channel_id, "on_get_channel_participants_success");
|
||||||
@ -11803,6 +11849,46 @@ void ContactsManager::on_get_channel_participants(
|
|||||||
promise.set_value(DialogParticipants{total_count, std::move(result)});
|
promise.set_value(DialogParticipants{total_count, std::move(result)});
|
||||||
}
|
}
|
||||||
|
|
||||||
|
bool ContactsManager::have_channel_participant_cache(ChannelId channel_id) const {
|
||||||
|
if (!td_->auth_manager_->is_bot()) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
auto c = get_channel(channel_id);
|
||||||
|
return c != nullptr && c->status.is_administrator();
|
||||||
|
}
|
||||||
|
|
||||||
|
void ContactsManager::add_channel_participant_to_cache(ChannelId channel_id,
|
||||||
|
const DialogParticipant &dialog_participant,
|
||||||
|
bool allow_replace) {
|
||||||
|
auto &participants = channel_participants_[channel_id];
|
||||||
|
if (participants.participants_.empty()) {
|
||||||
|
channel_participant_cache_timeout_.set_timeout_in(channel_id.get(), CHANNEL_PARTICIPANT_CACHE_TIME);
|
||||||
|
}
|
||||||
|
auto &participant_info = participants.participants_[dialog_participant.dialog_id];
|
||||||
|
if (participant_info.last_access_date_ > 0 && !allow_replace) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
participant_info.participant_ = dialog_participant;
|
||||||
|
participant_info.last_access_date_ = G()->unix_time();
|
||||||
|
}
|
||||||
|
|
||||||
|
const DialogParticipant *ContactsManager::get_channel_participant_from_cache(ChannelId channel_id,
|
||||||
|
DialogId participant_dialog_id) const {
|
||||||
|
auto channel_participants_it = channel_participants_.find(channel_id);
|
||||||
|
if (channel_participants_it == channel_participants_.end()) {
|
||||||
|
return nullptr;
|
||||||
|
}
|
||||||
|
|
||||||
|
auto &participants = channel_participants_it->second.participants_;
|
||||||
|
CHECK(!participants.empty());
|
||||||
|
auto it = participants.find(participant_dialog_id);
|
||||||
|
if (it != participants.end()) {
|
||||||
|
it->second.last_access_date_ = G()->unix_time();
|
||||||
|
return &it->second.participant_;
|
||||||
|
}
|
||||||
|
return nullptr;
|
||||||
|
}
|
||||||
|
|
||||||
bool ContactsManager::speculative_add_count(int32 &count, int32 delta_count, int32 min_count) {
|
bool ContactsManager::speculative_add_count(int32 &count, int32 delta_count, int32 min_count) {
|
||||||
auto new_count = count + delta_count;
|
auto new_count = count + delta_count;
|
||||||
if (new_count < min_count) {
|
if (new_count < min_count) {
|
||||||
@ -13103,6 +13189,9 @@ void ContactsManager::on_channel_status_changed(const Channel *c, ChannelId chan
|
|||||||
send_closure_later(G()->messages_manager(), &MessagesManager::on_update_dialog_group_call_rights,
|
send_closure_later(G()->messages_manager(), &MessagesManager::on_update_dialog_group_call_rights,
|
||||||
DialogId(channel_id));
|
DialogId(channel_id));
|
||||||
}
|
}
|
||||||
|
if (td_->auth_manager_->is_bot() && old_status.is_administrator() && !new_status.is_administrator()) {
|
||||||
|
channel_participants_.erase(channel_id);
|
||||||
|
}
|
||||||
|
|
||||||
// must not load ChannelFull, because must not change the Channel
|
// must not load ChannelFull, because must not change the Channel
|
||||||
CHECK(have_channel_full == (get_channel_full(channel_id) != nullptr));
|
CHECK(have_channel_full == (get_channel_full(channel_id) != nullptr));
|
||||||
@ -13408,6 +13497,13 @@ void ContactsManager::on_update_channel_participant(ChannelId channel_id, UserId
|
|||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (old_dialog_participant.dialog_id == DialogId(get_my_id()) && old_dialog_participant.status.is_administrator() &&
|
||||||
|
!new_dialog_participant.status.is_administrator()) {
|
||||||
|
channel_participants_.erase(channel_id);
|
||||||
|
} else if (have_channel_participant_cache(channel_id)) {
|
||||||
|
add_channel_participant_to_cache(channel_id, new_dialog_participant, true);
|
||||||
|
}
|
||||||
|
|
||||||
send_update_chat_member(DialogId(channel_id), user_id, date, invite_link, old_dialog_participant,
|
send_update_chat_member(DialogId(channel_id), user_id, date, invite_link, old_dialog_participant,
|
||||||
new_dialog_participant);
|
new_dialog_participant);
|
||||||
}
|
}
|
||||||
@ -14930,6 +15026,14 @@ DialogParticipant ContactsManager::get_channel_participant(ChannelId channel_id,
|
|||||||
return DialogParticipant();
|
return DialogParticipant();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (have_channel_participant_cache(channel_id)) {
|
||||||
|
auto *participant = get_channel_participant_from_cache(channel_id, participant_dialog_id);
|
||||||
|
if (participant != nullptr) {
|
||||||
|
promise.set_value(Unit());
|
||||||
|
return *participant;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
if (!td_->auth_manager_->is_bot() && participant_dialog_id.get_type() == DialogType::User &&
|
if (!td_->auth_manager_->is_bot() && participant_dialog_id.get_type() == DialogType::User &&
|
||||||
is_user_bot(participant_dialog_id.get_user_id())) {
|
is_user_bot(participant_dialog_id.get_user_id())) {
|
||||||
auto user_id = participant_dialog_id.get_user_id();
|
auto user_id = participant_dialog_id.get_user_id();
|
||||||
@ -14953,10 +15057,11 @@ DialogParticipant ContactsManager::get_channel_participant(ChannelId channel_id,
|
|||||||
LOG(DEBUG) << "Get info about " << participant_dialog_id << " membership in the " << channel_id << " with random_id "
|
LOG(DEBUG) << "Get info about " << participant_dialog_id << " membership in the " << channel_id << " with random_id "
|
||||||
<< random_id;
|
<< random_id;
|
||||||
|
|
||||||
auto on_result_promise = PromiseCreator::lambda([actor_id = actor_id(this), random_id, promise = std::move(promise)](
|
auto on_result_promise =
|
||||||
Result<DialogParticipant> r_dialog_participant) mutable {
|
PromiseCreator::lambda([actor_id = actor_id(this), channel_id, random_id,
|
||||||
send_closure(actor_id, &ContactsManager::on_get_channel_participant, random_id, std::move(r_dialog_participant),
|
promise = std::move(promise)](Result<DialogParticipant> r_dialog_participant) mutable {
|
||||||
std::move(promise));
|
send_closure(actor_id, &ContactsManager::on_get_channel_participant, channel_id, random_id,
|
||||||
|
std::move(r_dialog_participant), std::move(promise));
|
||||||
});
|
});
|
||||||
|
|
||||||
td_->create_handler<GetChannelParticipantQuery>(std::move(on_result_promise))
|
td_->create_handler<GetChannelParticipantQuery>(std::move(on_result_promise))
|
||||||
@ -14964,13 +15069,14 @@ DialogParticipant ContactsManager::get_channel_participant(ChannelId channel_id,
|
|||||||
return DialogParticipant();
|
return DialogParticipant();
|
||||||
}
|
}
|
||||||
|
|
||||||
void ContactsManager::on_get_channel_participant(int64 random_id, Result<DialogParticipant> r_dialog_participant,
|
void ContactsManager::on_get_channel_participant(ChannelId channel_id, int64 random_id,
|
||||||
|
Result<DialogParticipant> r_dialog_participant,
|
||||||
Promise<Unit> &&promise) {
|
Promise<Unit> &&promise) {
|
||||||
if (G()->close_flag()) {
|
if (G()->close_flag()) {
|
||||||
return promise.set_error(Status::Error(500, "Request aborted"));
|
return promise.set_error(Status::Error(500, "Request aborted"));
|
||||||
}
|
}
|
||||||
|
|
||||||
LOG(INFO) << "Receive a member of a channel with random_id " << random_id;
|
LOG(INFO) << "Receive a member of a channel " << channel_id << " with random_id " << random_id;
|
||||||
|
|
||||||
auto it = received_channel_participant_.find(random_id);
|
auto it = received_channel_participant_.find(random_id);
|
||||||
CHECK(it != received_channel_participant_.end());
|
CHECK(it != received_channel_participant_.end());
|
||||||
@ -14980,6 +15086,9 @@ void ContactsManager::on_get_channel_participant(int64 random_id, Result<DialogP
|
|||||||
promise.set_error(r_dialog_participant.move_as_error());
|
promise.set_error(r_dialog_participant.move_as_error());
|
||||||
} else {
|
} else {
|
||||||
it->second = r_dialog_participant.move_as_ok();
|
it->second = r_dialog_participant.move_as_ok();
|
||||||
|
if (have_channel_participant_cache(channel_id)) {
|
||||||
|
add_channel_participant_to_cache(channel_id, it->second, false);
|
||||||
|
}
|
||||||
promise.set_value(Unit());
|
promise.set_value(Unit());
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -979,6 +979,8 @@ class ContactsManager : public Actor {
|
|||||||
static constexpr size_t MAX_BIO_LENGTH = 70; // server side limit
|
static constexpr size_t MAX_BIO_LENGTH = 70; // server side limit
|
||||||
static constexpr int32 MAX_GET_CHANNEL_PARTICIPANTS = 200; // server side limit
|
static constexpr int32 MAX_GET_CHANNEL_PARTICIPANTS = 200; // server side limit
|
||||||
|
|
||||||
|
static constexpr int32 CHANNEL_PARTICIPANT_CACHE_TIME = 1800; // some reasonable limit
|
||||||
|
|
||||||
static constexpr int32 USER_FLAG_HAS_ACCESS_HASH = 1 << 0;
|
static constexpr int32 USER_FLAG_HAS_ACCESS_HASH = 1 << 0;
|
||||||
static constexpr int32 USER_FLAG_HAS_FIRST_NAME = 1 << 1;
|
static constexpr int32 USER_FLAG_HAS_FIRST_NAME = 1 << 1;
|
||||||
static constexpr int32 USER_FLAG_HAS_LAST_NAME = 1 << 2;
|
static constexpr int32 USER_FLAG_HAS_LAST_NAME = 1 << 2;
|
||||||
@ -1493,7 +1495,7 @@ class ContactsManager : public Actor {
|
|||||||
|
|
||||||
void delete_chat_participant(ChatId chat_id, UserId user_id, bool revoke_messages, Promise<Unit> &&promise);
|
void delete_chat_participant(ChatId chat_id, UserId user_id, bool revoke_messages, Promise<Unit> &&promise);
|
||||||
|
|
||||||
void on_get_channel_participant(int64 random_id, Result<DialogParticipant> r_dialog_participant,
|
void on_get_channel_participant(ChannelId channel_id, int64 random_id, Result<DialogParticipant> r_dialog_participant,
|
||||||
Promise<Unit> &&promise);
|
Promise<Unit> &&promise);
|
||||||
|
|
||||||
void search_chat_participants(ChatId chat_id, const string &query, int32 limit, DialogParticipantsFilter filter,
|
void search_chat_participants(ChatId chat_id, const string &query, int32 limit, DialogParticipantsFilter filter,
|
||||||
@ -1511,6 +1513,14 @@ class ContactsManager : public Actor {
|
|||||||
tl_object_ptr<telegram_api::channels_channelParticipants> &&channel_participants,
|
tl_object_ptr<telegram_api::channels_channelParticipants> &&channel_participants,
|
||||||
Promise<DialogParticipants> &&promise);
|
Promise<DialogParticipants> &&promise);
|
||||||
|
|
||||||
|
bool have_channel_participant_cache(ChannelId channel_id) const;
|
||||||
|
|
||||||
|
void add_channel_participant_to_cache(ChannelId channel_id, const DialogParticipant &dialog_participant,
|
||||||
|
bool allow_replace);
|
||||||
|
|
||||||
|
const DialogParticipant *get_channel_participant_from_cache(ChannelId channel_id,
|
||||||
|
DialogId participant_dialog_id) const;
|
||||||
|
|
||||||
void change_channel_participant_status_impl(ChannelId channel_id, DialogId participant_dialog_id,
|
void change_channel_participant_status_impl(ChannelId channel_id, DialogId participant_dialog_id,
|
||||||
DialogParticipantStatus status, DialogParticipantStatus old_status,
|
DialogParticipantStatus status, DialogParticipantStatus old_status,
|
||||||
Promise<Unit> &&promise);
|
Promise<Unit> &&promise);
|
||||||
@ -1553,6 +1563,8 @@ class ContactsManager : public Actor {
|
|||||||
|
|
||||||
static void on_invite_link_info_expire_timeout_callback(void *contacts_manager_ptr, int64 dialog_id_long);
|
static void on_invite_link_info_expire_timeout_callback(void *contacts_manager_ptr, int64 dialog_id_long);
|
||||||
|
|
||||||
|
static void on_channel_participant_cache_timeout_callback(void *contacts_manager_ptr, int64 channel_id_long);
|
||||||
|
|
||||||
void on_user_online_timeout(UserId user_id);
|
void on_user_online_timeout(UserId user_id);
|
||||||
|
|
||||||
void on_channel_unban_timeout(ChannelId channel_id);
|
void on_channel_unban_timeout(ChannelId channel_id);
|
||||||
@ -1563,6 +1575,8 @@ class ContactsManager : public Actor {
|
|||||||
|
|
||||||
void on_invite_link_info_expire_timeout(DialogId dialog_id);
|
void on_invite_link_info_expire_timeout(DialogId dialog_id);
|
||||||
|
|
||||||
|
void on_channel_participant_cache_timeout(ChannelId channel_id);
|
||||||
|
|
||||||
void tear_down() override;
|
void tear_down() override;
|
||||||
|
|
||||||
Td *td_;
|
Td *td_;
|
||||||
@ -1667,6 +1681,17 @@ class ContactsManager : public Actor {
|
|||||||
|
|
||||||
std::unordered_map<ChannelId, vector<DialogParticipant>, ChannelIdHash> cached_channel_participants_;
|
std::unordered_map<ChannelId, vector<DialogParticipant>, ChannelIdHash> cached_channel_participants_;
|
||||||
|
|
||||||
|
// bot-administrators only
|
||||||
|
struct ChannelParticipantInfo {
|
||||||
|
DialogParticipant participant_;
|
||||||
|
|
||||||
|
mutable int32 last_access_date_ = 0;
|
||||||
|
};
|
||||||
|
struct ChannelParticipants {
|
||||||
|
std::unordered_map<DialogId, ChannelParticipantInfo, DialogIdHash> participants_;
|
||||||
|
};
|
||||||
|
std::unordered_map<ChannelId, ChannelParticipants, ChannelIdHash> channel_participants_;
|
||||||
|
|
||||||
bool are_contacts_loaded_ = false;
|
bool are_contacts_loaded_ = false;
|
||||||
int32 next_contacts_sync_date_ = 0;
|
int32 next_contacts_sync_date_ = 0;
|
||||||
Hints contacts_hints_; // search contacts by first name, last name and username
|
Hints contacts_hints_; // search contacts by first name, last name and username
|
||||||
@ -1710,6 +1735,7 @@ class ContactsManager : public Actor {
|
|||||||
MultiTimeout user_nearby_timeout_{"UserNearbyTimeout"};
|
MultiTimeout user_nearby_timeout_{"UserNearbyTimeout"};
|
||||||
MultiTimeout slow_mode_delay_timeout_{"SlowModeDelayTimeout"};
|
MultiTimeout slow_mode_delay_timeout_{"SlowModeDelayTimeout"};
|
||||||
MultiTimeout invite_link_info_expire_timeout_{"InviteLinkInfoExpireTimeout"};
|
MultiTimeout invite_link_info_expire_timeout_{"InviteLinkInfoExpireTimeout"};
|
||||||
|
MultiTimeout channel_participant_cache_timeout_{"ChannelParticipantCacheTimeout"};
|
||||||
};
|
};
|
||||||
|
|
||||||
} // namespace td
|
} // namespace td
|
||||||
|
Loading…
Reference in New Issue
Block a user