Move get_channel_participants to DialogParticipantManager.

This commit is contained in:
levlam 2024-03-03 01:22:49 +03:00
parent 6399c64252
commit 22d9c86b57
6 changed files with 275 additions and 292 deletions

View File

@ -11,7 +11,6 @@
#include "td/telegram/AuthManager.h"
#include "td/telegram/BlockListId.h"
#include "td/telegram/BotMenuButton.h"
#include "td/telegram/ChannelParticipantFilter.h"
#include "td/telegram/CommonDialogManager.h"
#include "td/telegram/ConfigManager.h"
#include "td/telegram/Dependencies.h"
@ -2737,53 +2736,6 @@ class GetFullChannelQuery final : public Td::ResultHandler {
}
};
class GetChannelParticipantsQuery final : public Td::ResultHandler {
Promise<tl_object_ptr<telegram_api::channels_channelParticipants>> promise_;
ChannelId channel_id_;
public:
explicit GetChannelParticipantsQuery(Promise<tl_object_ptr<telegram_api::channels_channelParticipants>> &&promise)
: promise_(std::move(promise)) {
}
void send(ChannelId channel_id, const ChannelParticipantFilter &filter, int32 offset, int32 limit) {
auto input_channel = td_->contacts_manager_->get_input_channel(channel_id);
if (input_channel == nullptr) {
return promise_.set_error(Status::Error(400, "Supergroup not found"));
}
channel_id_ = channel_id;
send_query(G()->net_query_creator().create(telegram_api::channels_getParticipants(
std::move(input_channel), filter.get_input_channel_participants_filter(), offset, limit, 0)));
}
void on_result(BufferSlice packet) final {
auto result_ptr = fetch_result<telegram_api::channels_getParticipants>(packet);
if (result_ptr.is_error()) {
return on_error(result_ptr.move_as_error());
}
auto participants_ptr = result_ptr.move_as_ok();
LOG(INFO) << "Receive result for GetChannelParticipantsQuery: " << to_string(participants_ptr);
switch (participants_ptr->get_id()) {
case telegram_api::channels_channelParticipants::ID: {
promise_.set_value(telegram_api::move_object_as<telegram_api::channels_channelParticipants>(participants_ptr));
break;
}
case telegram_api::channels_channelParticipantsNotModified::ID:
LOG(ERROR) << "Receive channelParticipantsNotModified";
return on_error(Status::Error(500, "Receive channelParticipantsNotModified"));
default:
UNREACHABLE();
}
}
void on_error(Status status) final {
td_->contacts_manager_->on_get_channel_error(channel_id_, status, "GetChannelParticipantsQuery");
promise_.set_error(std::move(status));
}
};
class GetSupportUserQuery final : public Td::ResultHandler {
Promise<UserId> promise_;
@ -13124,6 +13076,10 @@ void ContactsManager::update_channel_online_member_count(ChannelId channel_id, b
td_->dialog_participant_manager_->update_dialog_online_member_count(it->second, DialogId(channel_id), is_from_server);
}
void ContactsManager::set_cached_channel_participants(ChannelId channel_id, vector<DialogParticipant> participants) {
cached_channel_participants_[channel_id] = std::move(participants);
}
void ContactsManager::drop_cached_channel_participants(ChannelId channel_id) {
cached_channel_participants_.erase(channel_id);
}
@ -13322,181 +13278,6 @@ bool ContactsManager::is_user_contact(const User *u, UserId user_id, bool is_mut
return u != nullptr && (is_mutual ? u->is_mutual_contact : u->is_contact) && user_id != get_my_id();
}
void ContactsManager::on_get_channel_participants(
ChannelId channel_id, ChannelParticipantFilter &&filter, int32 offset, int32 limit, string additional_query,
int32 additional_limit, tl_object_ptr<telegram_api::channels_channelParticipants> &&channel_participants,
Promise<DialogParticipants> &&promise) {
TRY_STATUS_PROMISE(promise, G()->close_status());
on_get_users(std::move(channel_participants->users_), "on_get_channel_participants");
on_get_chats(std::move(channel_participants->chats_), "on_get_channel_participants");
int32 total_count = channel_participants->count_;
auto participants = std::move(channel_participants->participants_);
LOG(INFO) << "Receive " << participants.size() << " " << filter << " members in " << channel_id;
bool is_full = offset == 0 && static_cast<int32>(participants.size()) < limit && total_count < limit;
bool has_hidden_participants =
get_channel_effective_has_hidden_participants(channel_id, "on_get_channel_participants");
bool is_full_recent = is_full && filter.is_recent() && !has_hidden_participants;
auto channel_type = get_channel_type(channel_id);
vector<DialogParticipant> result;
for (auto &participant_ptr : participants) {
auto debug_participant = to_string(participant_ptr);
result.emplace_back(std::move(participant_ptr), channel_type);
const auto &participant = result.back();
UserId participant_user_id;
if (participant.dialog_id_.get_type() == DialogType::User) {
participant_user_id = participant.dialog_id_.get_user_id();
}
if (!participant.is_valid() || (filter.is_bots() && !is_user_bot(participant_user_id)) ||
(filter.is_administrators() && !participant.status_.is_administrator()) ||
((filter.is_recent() || filter.is_contacts() || filter.is_search()) && !participant.status_.is_member()) ||
(filter.is_contacts() && !is_user_contact(participant_user_id)) ||
(filter.is_restricted() && !participant.status_.is_restricted()) ||
(filter.is_banned() && !participant.status_.is_banned())) {
bool skip_error = ((filter.is_administrators() || filter.is_bots()) && is_user_deleted(participant_user_id)) ||
(filter.is_contacts() && participant_user_id == get_my_id());
if (!skip_error) {
LOG(ERROR) << "Receive " << participant << ", while searching for " << filter << " in " << channel_id
<< " with offset " << offset << " and limit " << limit << ": " << oneline(debug_participant);
}
result.pop_back();
total_count--;
}
}
if (total_count < narrow_cast<int32>(result.size())) {
LOG(ERROR) << "Receive total_count = " << total_count << ", but have at least " << result.size() << " " << filter
<< " members in " << channel_id;
total_count = static_cast<int32>(result.size());
} else if (is_full && total_count > static_cast<int32>(result.size())) {
LOG(ERROR) << "Fix total number of " << filter << " members from " << total_count << " to " << result.size()
<< " in " << channel_id << " for request with limit " << limit << " and received " << participants.size()
<< " results";
total_count = static_cast<int32>(result.size());
}
const auto max_participant_count = is_megagroup_channel(channel_id) ? 975 : 195;
auto participant_count =
filter.is_recent() && !has_hidden_participants && total_count != 0 && total_count < max_participant_count
? total_count
: -1;
int32 administrator_count =
filter.is_administrators() || (filter.is_recent() && has_hidden_participants) ? total_count : -1;
if (is_full && (filter.is_administrators() || filter.is_bots() || filter.is_recent())) {
vector<DialogAdministrator> administrators;
vector<UserId> bot_user_ids;
{
if (filter.is_recent()) {
for (const auto &participant : result) {
if (participant.dialog_id_.get_type() == DialogType::User) {
auto participant_user_id = participant.dialog_id_.get_user_id();
if (participant.status_.is_administrator()) {
administrators.emplace_back(participant_user_id, participant.status_.get_rank(),
participant.status_.is_creator());
}
if (is_full_recent && is_user_bot(participant_user_id)) {
bot_user_ids.push_back(participant_user_id);
}
}
}
administrator_count = narrow_cast<int32>(administrators.size());
if (is_megagroup_channel(channel_id) && !td_->auth_manager_->is_bot() && is_full_recent) {
cached_channel_participants_[channel_id] = result;
update_channel_online_member_count(channel_id, true);
}
} else if (filter.is_administrators()) {
for (const auto &participant : result) {
if (participant.dialog_id_.get_type() == DialogType::User) {
administrators.emplace_back(participant.dialog_id_.get_user_id(), participant.status_.get_rank(),
participant.status_.is_creator());
}
}
} else if (filter.is_bots()) {
bot_user_ids = transform(result, [](const DialogParticipant &participant) {
CHECK(participant.dialog_id_.get_type() == DialogType::User);
return participant.dialog_id_.get_user_id();
});
}
}
if (filter.is_administrators() || filter.is_recent()) {
td_->dialog_participant_manager_->on_update_dialog_administrators(DialogId(channel_id), std::move(administrators),
true, false);
}
if (filter.is_bots() || is_full_recent) {
on_update_channel_bot_user_ids(channel_id, std::move(bot_user_ids));
}
}
if (td_->dialog_participant_manager_->have_channel_participant_cache(channel_id)) {
for (const auto &participant : result) {
td_->dialog_participant_manager_->add_channel_participant_to_cache(channel_id, participant, false);
}
}
if (participant_count != -1 || administrator_count != -1) {
auto channel_full = get_channel_full_force(channel_id, true, "on_get_channel_participants");
if (channel_full != nullptr) {
if (administrator_count == -1) {
administrator_count = channel_full->administrator_count;
}
if (participant_count == -1) {
participant_count = channel_full->participant_count;
}
if (participant_count < administrator_count) {
participant_count = administrator_count;
}
if (channel_full->participant_count != participant_count) {
channel_full->participant_count = participant_count;
channel_full->is_changed = true;
}
if (channel_full->administrator_count != administrator_count) {
channel_full->administrator_count = administrator_count;
channel_full->is_changed = true;
}
update_channel_full(channel_full, channel_id, "on_get_channel_participants");
}
if (participant_count != -1) {
auto c = get_channel(channel_id);
if (c != nullptr && c->participant_count != participant_count) {
c->participant_count = participant_count;
c->is_changed = true;
update_channel(c, channel_id);
}
}
}
if (!additional_query.empty()) {
auto dialog_ids = transform(result, [](const DialogParticipant &participant) { return participant.dialog_id_; });
std::pair<int32, vector<DialogId>> result_dialog_ids =
search_among_dialogs(dialog_ids, additional_query, additional_limit);
total_count = result_dialog_ids.first;
FlatHashSet<DialogId, DialogIdHash> result_dialog_ids_set;
for (auto result_dialog_id : result_dialog_ids.second) {
CHECK(result_dialog_id.is_valid());
result_dialog_ids_set.insert(result_dialog_id);
}
auto all_participants = std::move(result);
result.clear();
for (auto &participant : all_participants) {
if (result_dialog_ids_set.count(participant.dialog_id_)) {
result_dialog_ids_set.erase(participant.dialog_id_);
result.push_back(std::move(participant));
}
}
}
vector<DialogId> participant_dialog_ids;
for (const auto &participant : result) {
participant_dialog_ids.push_back(participant.dialog_id_);
}
on_view_dialog_active_stories(std::move(participant_dialog_ids));
promise.set_value(DialogParticipants{total_count, std::move(result)});
}
bool ContactsManager::speculative_add_count(int32 &count, int32 delta_count, int32 min_count) {
auto new_count = count + delta_count;
if (new_count < min_count) {
@ -16646,45 +16427,6 @@ void ContactsManager::finish_get_chat_participant(ChatId chat_id, UserId user_id
promise.set_value(DialogParticipant(*participant));
}
void ContactsManager::get_channel_participants(ChannelId channel_id,
tl_object_ptr<td_api::SupergroupMembersFilter> &&filter,
string additional_query, int32 offset, int32 limit,
int32 additional_limit, Promise<DialogParticipants> &&promise) {
if (limit <= 0) {
return promise.set_error(Status::Error(400, "Parameter limit must be positive"));
}
if (limit > MAX_GET_CHANNEL_PARTICIPANTS) {
limit = MAX_GET_CHANNEL_PARTICIPANTS;
}
if (offset < 0) {
return promise.set_error(Status::Error(400, "Parameter offset must be non-negative"));
}
auto channel_full = get_channel_full_force(channel_id, true, "get_channel_participants");
if (channel_full != nullptr && !channel_full->is_expired() && !channel_full->can_get_participants) {
return promise.set_error(Status::Error(400, "Member list is inaccessible"));
}
if (is_broadcast_channel(channel_id) && !get_channel_status(channel_id).is_administrator()) {
return promise.set_error(Status::Error(400, "Member list is inaccessible"));
}
ChannelParticipantFilter participant_filter(filter);
auto get_channel_participants_promise = PromiseCreator::lambda(
[actor_id = actor_id(this), channel_id, filter = participant_filter,
additional_query = std::move(additional_query), offset, limit, additional_limit, promise = std::move(promise)](
Result<tl_object_ptr<telegram_api::channels_channelParticipants>> &&result) mutable {
if (result.is_error()) {
promise.set_error(result.move_as_error());
} else {
send_closure(actor_id, &ContactsManager::on_get_channel_participants, channel_id, std::move(filter), offset,
limit, std::move(additional_query), additional_limit, result.move_as_ok(), std::move(promise));
}
});
td_->create_handler<GetChannelParticipantsQuery>(std::move(get_channel_participants_promise))
->send(channel_id, participant_filter, offset, limit);
}
void ContactsManager::on_update_channel_administrator_count(ChannelId channel_id, int32 administrator_count) {
auto channel_full = get_channel_full_force(channel_id, true, "on_update_channel_administrator_count");
if (channel_full != nullptr && channel_full->administrator_count != administrator_count) {

View File

@ -68,8 +68,6 @@ namespace td {
struct BinlogEvent;
class ChannelParticipantFilter;
struct MinChannel;
class Td;
@ -359,6 +357,10 @@ class ContactsManager final : public Actor {
void update_channel_online_member_count(ChannelId channel_id, bool is_from_server);
void on_update_channel_bot_user_ids(ChannelId channel_id, vector<UserId> &&bot_user_ids);
void set_cached_channel_participants(ChannelId channel_id, vector<DialogParticipant> participants);
void drop_cached_channel_participants(ChannelId channel_id);
void on_update_username_is_active(UserId user_id, string &&username, bool is_active, Promise<Unit> &&promise);
@ -667,10 +669,6 @@ class ContactsManager final : public Actor {
std::pair<int32, vector<DialogId>> search_among_dialogs(const vector<DialogId> &dialog_ids, const string &query,
int32 limit) const;
void get_channel_participants(ChannelId channel_id, tl_object_ptr<td_api::SupergroupMembersFilter> &&filter,
string additional_query, int32 offset, int32 limit, int32 additional_limit,
Promise<DialogParticipants> &&promise);
int64 get_user_id_object(UserId user_id, const char *source) const;
tl_object_ptr<td_api::user> get_user_object(UserId user_id) const;
@ -1177,11 +1175,10 @@ class ContactsManager final : public Actor {
class ChannelLogEvent;
class SecretChatLogEvent;
static constexpr int32 MAX_GET_PROFILE_PHOTOS = 100; // server side limit
static constexpr size_t MAX_NAME_LENGTH = 64; // server side limit for first/last name
static constexpr size_t MAX_TITLE_LENGTH = 128; // server side limit for chat title
static constexpr size_t MAX_DESCRIPTION_LENGTH = 255; // server side limit for chat/channel description
static constexpr int32 MAX_GET_CHANNEL_PARTICIPANTS = 200; // server side limit
static constexpr int32 MAX_GET_PROFILE_PHOTOS = 100; // server side limit
static constexpr size_t MAX_NAME_LENGTH = 64; // server side limit for first/last name
static constexpr size_t MAX_TITLE_LENGTH = 128; // server side limit for chat title
static constexpr size_t MAX_DESCRIPTION_LENGTH = 255; // server side limit for chat/channel description
static constexpr int32 MAX_ACTIVE_STORY_ID_RELOAD_TIME = 3600; // some reasonable limit
static constexpr int32 CHANNEL_RECOMMENDATIONS_CACHE_TIME = 86400; // some reasonable limit
@ -1503,8 +1500,6 @@ class ContactsManager final : public Actor {
StoryId max_read_story_id);
void on_update_channel_max_read_story_id(Channel *c, ChannelId channel_id, StoryId max_read_story_id);
void on_update_channel_bot_user_ids(ChannelId channel_id, vector<UserId> &&bot_user_ids);
void on_update_channel_full_photo(ChannelFull *channel_full, ChannelId channel_id, Photo photo);
void on_update_channel_full_invite_link(ChannelFull *channel_full,
tl_object_ptr<telegram_api::ExportedChatInvite> &&invite_link);
@ -1790,11 +1785,6 @@ class ContactsManager final : public Actor {
void update_dialogs_for_discussion(DialogId dialog_id, bool is_suitable);
void on_get_channel_participants(ChannelId channel_id, ChannelParticipantFilter &&filter, int32 offset, int32 limit,
string additional_query, int32 additional_limit,
tl_object_ptr<telegram_api::channels_channelParticipants> &&channel_participants,
Promise<DialogParticipants> &&promise);
void get_channel_statistics_dc_id_impl(ChannelId channel_id, bool for_full_statistics, Promise<DcId> &&promise);
void on_get_support_user(UserId user_id, Promise<td_api::object_ptr<td_api::user>> &&promise);

View File

@ -9,6 +9,7 @@
#include "td/telegram/AccessRights.h"
#include "td/telegram/AuthManager.h"
#include "td/telegram/ChannelId.h"
#include "td/telegram/ChannelParticipantFilter.h"
#include "td/telegram/ChannelType.h"
#include "td/telegram/ContactsManager.h"
#include "td/telegram/DialogManager.h"
@ -29,6 +30,7 @@
#include "td/utils/algorithm.h"
#include "td/utils/buffer.h"
#include "td/utils/FlatHashSet.h"
#include "td/utils/format.h"
#include "td/utils/logging.h"
#include "td/utils/misc.h"
@ -369,6 +371,54 @@ class GetChannelParticipantQuery final : public Td::ResultHandler {
}
};
class GetChannelParticipantsQuery final : public Td::ResultHandler {
Promise<telegram_api::object_ptr<telegram_api::channels_channelParticipants>> promise_;
ChannelId channel_id_;
public:
explicit GetChannelParticipantsQuery(
Promise<telegram_api::object_ptr<telegram_api::channels_channelParticipants>> &&promise)
: promise_(std::move(promise)) {
}
void send(ChannelId channel_id, const ChannelParticipantFilter &filter, int32 offset, int32 limit) {
auto input_channel = td_->contacts_manager_->get_input_channel(channel_id);
if (input_channel == nullptr) {
return promise_.set_error(Status::Error(400, "Supergroup not found"));
}
channel_id_ = channel_id;
send_query(G()->net_query_creator().create(telegram_api::channels_getParticipants(
std::move(input_channel), filter.get_input_channel_participants_filter(), offset, limit, 0)));
}
void on_result(BufferSlice packet) final {
auto result_ptr = fetch_result<telegram_api::channels_getParticipants>(packet);
if (result_ptr.is_error()) {
return on_error(result_ptr.move_as_error());
}
auto participants_ptr = result_ptr.move_as_ok();
LOG(INFO) << "Receive result for GetChannelParticipantsQuery: " << to_string(participants_ptr);
switch (participants_ptr->get_id()) {
case telegram_api::channels_channelParticipants::ID: {
promise_.set_value(telegram_api::move_object_as<telegram_api::channels_channelParticipants>(participants_ptr));
break;
}
case telegram_api::channels_channelParticipantsNotModified::ID:
LOG(ERROR) << "Receive channelParticipantsNotModified";
return on_error(Status::Error(500, "Receive channelParticipantsNotModified"));
default:
UNREACHABLE();
}
}
void on_error(Status status) final {
td_->contacts_manager_->on_get_channel_error(channel_id_, status, "GetChannelParticipantsQuery");
promise_.set_error(std::move(status));
}
};
class AddChatUserQuery final : public Td::ResultHandler {
Promise<Unit> promise_;
ChatId chat_id_;
@ -821,9 +871,8 @@ void DialogParticipantManager::on_update_dialog_online_member_count_timeout(Dial
if (participant_count == 0 || participant_count >= 195 || has_hidden_participants) {
td_->create_handler<GetOnlinesQuery>()->send(dialog_id);
} else {
td_->contacts_manager_->get_channel_participants(dialog_id.get_channel_id(),
td_api::make_object<td_api::supergroupMembersFilterRecent>(),
string(), 0, 200, 200, Auto());
get_channel_participants(dialog_id.get_channel_id(), td_api::make_object<td_api::supergroupMembersFilterRecent>(),
string(), 0, 200, 200, Auto());
}
return;
}
@ -1676,6 +1725,194 @@ void DialogParticipantManager::do_search_chat_participants(ChatId chat_id, const
promise.set_value(DialogParticipants{total_count, std::move(dialog_participants)});
}
void DialogParticipantManager::get_channel_participants(ChannelId channel_id,
td_api::object_ptr<td_api::SupergroupMembersFilter> &&filter,
string additional_query, int32 offset, int32 limit,
int32 additional_limit, Promise<DialogParticipants> &&promise) {
if (limit <= 0) {
return promise.set_error(Status::Error(400, "Parameter limit must be positive"));
}
if (limit > MAX_GET_CHANNEL_PARTICIPANTS) {
limit = MAX_GET_CHANNEL_PARTICIPANTS;
}
if (offset < 0) {
return promise.set_error(Status::Error(400, "Parameter offset must be non-negative"));
}
if (td_->contacts_manager_->is_broadcast_channel(channel_id) &&
!td_->contacts_manager_->get_channel_status(channel_id).is_administrator()) {
return promise.set_error(Status::Error(400, "Member list is inaccessible"));
}
ChannelParticipantFilter participant_filter(filter);
auto get_channel_participants_promise = PromiseCreator::lambda(
[actor_id = actor_id(this), channel_id, filter = participant_filter,
additional_query = std::move(additional_query), offset, limit, additional_limit, promise = std::move(promise)](
Result<telegram_api::object_ptr<telegram_api::channels_channelParticipants>> &&result) mutable {
if (result.is_error()) {
promise.set_error(result.move_as_error());
} else {
send_closure(actor_id, &DialogParticipantManager::on_get_channel_participants, channel_id, std::move(filter),
offset, limit, std::move(additional_query), additional_limit, result.move_as_ok(),
std::move(promise));
}
});
td_->create_handler<GetChannelParticipantsQuery>(std::move(get_channel_participants_promise))
->send(channel_id, participant_filter, offset, limit);
}
void DialogParticipantManager::on_get_channel_participants(
ChannelId channel_id, ChannelParticipantFilter &&filter, int32 offset, int32 limit, string additional_query,
int32 additional_limit, telegram_api::object_ptr<telegram_api::channels_channelParticipants> &&channel_participants,
Promise<DialogParticipants> &&promise) {
TRY_STATUS_PROMISE(promise, G()->close_status());
td_->contacts_manager_->on_get_users(std::move(channel_participants->users_), "on_get_channel_participants");
td_->contacts_manager_->on_get_chats(std::move(channel_participants->chats_), "on_get_channel_participants");
int32 total_count = channel_participants->count_;
auto participants = std::move(channel_participants->participants_);
LOG(INFO) << "Receive " << participants.size() << " " << filter << " members in " << channel_id;
bool is_full = offset == 0 && static_cast<int32>(participants.size()) < limit && total_count < limit;
bool has_hidden_participants =
td_->contacts_manager_->get_channel_effective_has_hidden_participants(channel_id, "on_get_channel_participants");
bool is_full_recent = is_full && filter.is_recent() && !has_hidden_participants;
auto channel_type = td_->contacts_manager_->get_channel_type(channel_id);
vector<DialogParticipant> result;
for (auto &participant_ptr : participants) {
auto debug_participant = to_string(participant_ptr);
result.emplace_back(std::move(participant_ptr), channel_type);
const auto &participant = result.back();
UserId participant_user_id;
if (participant.dialog_id_.get_type() == DialogType::User) {
participant_user_id = participant.dialog_id_.get_user_id();
}
if (!participant.is_valid() || (filter.is_bots() && !td_->contacts_manager_->is_user_bot(participant_user_id)) ||
(filter.is_administrators() && !participant.status_.is_administrator()) ||
((filter.is_recent() || filter.is_contacts() || filter.is_search()) && !participant.status_.is_member()) ||
(filter.is_contacts() && !td_->contacts_manager_->is_user_contact(participant_user_id)) ||
(filter.is_restricted() && !participant.status_.is_restricted()) ||
(filter.is_banned() && !participant.status_.is_banned())) {
bool skip_error = ((filter.is_administrators() || filter.is_bots()) &&
td_->contacts_manager_->is_user_deleted(participant_user_id)) ||
(filter.is_contacts() && participant_user_id == td_->contacts_manager_->get_my_id());
if (!skip_error) {
LOG(ERROR) << "Receive " << participant << ", while searching for " << filter << " in " << channel_id
<< " with offset " << offset << " and limit " << limit << ": " << oneline(debug_participant);
}
result.pop_back();
total_count--;
}
}
if (total_count < narrow_cast<int32>(result.size())) {
LOG(ERROR) << "Receive total_count = " << total_count << ", but have at least " << result.size() << " " << filter
<< " members in " << channel_id;
total_count = static_cast<int32>(result.size());
} else if (is_full && total_count > static_cast<int32>(result.size())) {
LOG(ERROR) << "Fix total number of " << filter << " members from " << total_count << " to " << result.size()
<< " in " << channel_id << " for request with limit " << limit << " and received " << participants.size()
<< " results";
total_count = static_cast<int32>(result.size());
}
auto is_megagroup = td_->contacts_manager_->is_megagroup_channel(channel_id);
const auto max_participant_count = is_megagroup ? 975 : 195;
auto participant_count =
filter.is_recent() && !has_hidden_participants && total_count != 0 && total_count < max_participant_count
? total_count
: -1;
int32 administrator_count =
filter.is_administrators() || (filter.is_recent() && has_hidden_participants) ? total_count : -1;
if (is_full && (filter.is_administrators() || filter.is_bots() || filter.is_recent())) {
vector<DialogAdministrator> administrators;
vector<UserId> bot_user_ids;
{
if (filter.is_recent()) {
for (const auto &participant : result) {
if (participant.dialog_id_.get_type() == DialogType::User) {
auto participant_user_id = participant.dialog_id_.get_user_id();
if (participant.status_.is_administrator()) {
administrators.emplace_back(participant_user_id, participant.status_.get_rank(),
participant.status_.is_creator());
}
if (is_full_recent && td_->contacts_manager_->is_user_bot(participant_user_id)) {
bot_user_ids.push_back(participant_user_id);
}
}
}
administrator_count = narrow_cast<int32>(administrators.size());
if (is_megagroup && !td_->auth_manager_->is_bot() && is_full_recent) {
td_->contacts_manager_->set_cached_channel_participants(channel_id, result);
td_->contacts_manager_->update_channel_online_member_count(channel_id, true);
}
} else if (filter.is_administrators()) {
for (const auto &participant : result) {
if (participant.dialog_id_.get_type() == DialogType::User) {
administrators.emplace_back(participant.dialog_id_.get_user_id(), participant.status_.get_rank(),
participant.status_.is_creator());
}
}
} else if (filter.is_bots()) {
bot_user_ids = transform(result, [](const DialogParticipant &participant) {
CHECK(participant.dialog_id_.get_type() == DialogType::User);
return participant.dialog_id_.get_user_id();
});
}
}
if (filter.is_administrators() || filter.is_recent()) {
on_update_dialog_administrators(DialogId(channel_id), std::move(administrators), true, false);
}
if (filter.is_bots() || is_full_recent) {
td_->contacts_manager_->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) {
td_->contacts_manager_->on_update_channel_participant_count(channel_id, participant_count);
}
if (administrator_count != -1) {
td_->contacts_manager_->on_update_channel_administrator_count(channel_id, administrator_count);
}
if (!additional_query.empty()) {
auto dialog_ids = transform(result, [](const DialogParticipant &participant) { return participant.dialog_id_; });
std::pair<int32, vector<DialogId>> result_dialog_ids =
td_->contacts_manager_->search_among_dialogs(dialog_ids, additional_query, additional_limit);
total_count = result_dialog_ids.first;
FlatHashSet<DialogId, DialogIdHash> result_dialog_ids_set;
for (auto result_dialog_id : result_dialog_ids.second) {
CHECK(result_dialog_id.is_valid());
result_dialog_ids_set.insert(result_dialog_id);
}
auto all_participants = std::move(result);
result.clear();
for (auto &participant : all_participants) {
if (result_dialog_ids_set.count(participant.dialog_id_)) {
result_dialog_ids_set.erase(participant.dialog_id_);
result.push_back(std::move(participant));
}
}
}
vector<DialogId> participant_dialog_ids;
for (const auto &participant : result) {
participant_dialog_ids.push_back(participant.dialog_id_);
}
td_->contacts_manager_->on_view_dialog_active_stories(std::move(participant_dialog_ids));
promise.set_value(DialogParticipants{total_count, std::move(result)});
}
void DialogParticipantManager::search_dialog_participants(DialogId dialog_id, const string &query, int32 limit,
DialogParticipantFilter filter,
Promise<DialogParticipants> &&promise) {
@ -1696,12 +1933,11 @@ void DialogParticipantManager::search_dialog_participants(DialogId dialog_id, co
case DialogType::Channel: {
auto channel_id = dialog_id.get_channel_id();
if (filter.has_query()) {
return td_->contacts_manager_->get_channel_participants(
channel_id, filter.get_supergroup_members_filter_object(query), string(), 0, limit, 0, std::move(promise));
return get_channel_participants(channel_id, filter.get_supergroup_members_filter_object(query), string(), 0,
limit, 0, std::move(promise));
} else {
return td_->contacts_manager_->get_channel_participants(channel_id,
filter.get_supergroup_members_filter_object(string()),
query, 0, 100, limit, std::move(promise));
return get_channel_participants(channel_id, filter.get_supergroup_members_filter_object(string()), query, 0,
100, limit, std::move(promise));
}
}
case DialogType::SecretChat: {

View File

@ -27,6 +27,8 @@
namespace td {
class ChannelParticipantFilter;
class Td;
class DialogParticipantManager final : public Actor {
@ -90,6 +92,10 @@ class DialogParticipantManager final : public Actor {
void get_channel_participant(ChannelId channel_id, DialogId participant_dialog_id,
Promise<DialogParticipant> &&promise);
void get_channel_participants(ChannelId channel_id, td_api::object_ptr<td_api::SupergroupMembersFilter> &&filter,
string additional_query, int32 offset, int32 limit, int32 additional_limit,
Promise<DialogParticipants> &&promise);
void search_dialog_participants(DialogId dialog_id, const string &query, int32 limit, DialogParticipantFilter filter,
Promise<DialogParticipants> &&promise);
@ -139,6 +145,8 @@ class DialogParticipantManager final : public Actor {
static constexpr int32 CHANNEL_PARTICIPANT_CACHE_TIME = 1800; // some reasonable limit
static constexpr int32 MAX_GET_CHANNEL_PARTICIPANTS = 200; // server side limit
void tear_down() final;
static void on_update_dialog_online_member_count_timeout_callback(void *dialog_participant_manager_ptr,
@ -191,6 +199,12 @@ class DialogParticipantManager final : public Actor {
void do_search_chat_participants(ChatId chat_id, const string &query, int32 limit, DialogParticipantFilter filter,
Promise<DialogParticipants> &&promise);
void on_get_channel_participants(
ChannelId channel_id, ChannelParticipantFilter &&filter, int32 offset, int32 limit, string additional_query,
int32 additional_limit,
telegram_api::object_ptr<telegram_api::channels_channelParticipants> &&channel_participants,
Promise<DialogParticipants> &&promise);
void set_chat_participant_status(ChatId chat_id, UserId user_id, DialogParticipantStatus status, bool is_recursive,
Promise<Unit> &&promise);

View File

@ -16790,7 +16790,7 @@ void MessagesManager::on_get_message_viewers(DialogId dialog_id, MessageViewers
return td_->contacts_manager_->reload_chat_full(dialog_id.get_chat_id(), std::move(query_promise),
"on_get_message_viewers");
case DialogType::Channel:
return td_->contacts_manager_->get_channel_participants(
return td_->dialog_participant_manager_->get_channel_participants(
dialog_id.get_channel_id(), td_api::make_object<td_api::supergroupMembersFilterRecent>(), string(), 0,
200, 200, PromiseCreator::lambda([query_promise = std::move(query_promise)](DialogParticipants) mutable {
query_promise.set_value(Unit());
@ -18940,7 +18940,7 @@ void MessagesManager::open_dialog(Dialog *d) {
auto has_hidden_participants = td_->contacts_manager_->get_channel_effective_has_hidden_participants(
dialog_id.get_channel_id(), "open_dialog");
if (participant_count < 195 && !has_hidden_participants) { // include unknown participant_count
td_->contacts_manager_->get_channel_participants(
td_->dialog_participant_manager_->get_channel_participants(
channel_id, td_api::make_object<td_api::supergroupMembersFilterRecent>(), string(), 0, 200, 200, Auto());
}
} else {

View File

@ -7887,8 +7887,9 @@ void Td::on_request(uint64 id, td_api::getSupergroupMembers &request) {
promise.set_value(result.ok().get_chat_members_object(td, "getSupergroupMembers"));
}
});
contacts_manager_->get_channel_participants(ChannelId(request.supergroup_id_), std::move(request.filter_), string(),
request.offset_, request.limit_, -1, std::move(query_promise));
dialog_participant_manager_->get_channel_participants(ChannelId(request.supergroup_id_), std::move(request.filter_),
string(), request.offset_, request.limit_, -1,
std::move(query_promise));
}
void Td::on_request(uint64 id, td_api::closeSecretChat &request) {