Move get_channel_participants to DialogParticipantManager.
This commit is contained in:
parent
6399c64252
commit
22d9c86b57
@ -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) {
|
||||
|
@ -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);
|
||||
|
@ -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: {
|
||||
|
@ -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);
|
||||
|
||||
|
@ -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 {
|
||||
|
@ -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) {
|
||||
|
Loading…
Reference in New Issue
Block a user