Add supergroup.has_active_stories/has_unread_active_stories.

This commit is contained in:
levlam 2023-09-05 16:50:41 +03:00
parent 86d286fc7c
commit 8991ddf263
4 changed files with 173 additions and 11 deletions

View File

@ -987,7 +987,9 @@ basicGroupFullInfo photo:chatPhoto description:string creator_user_id:int53 memb
//@restriction_reason If non-empty, contains a human-readable description of the reason why access to this supergroup or channel must be restricted //@restriction_reason If non-empty, contains a human-readable description of the reason why access to this supergroup or channel must be restricted
//@is_scam True, if many users reported this supergroup or channel as a scam //@is_scam True, if many users reported this supergroup or channel as a scam
//@is_fake True, if many users reported this supergroup or channel as a fake account //@is_fake True, if many users reported this supergroup or channel as a fake account
supergroup id:int53 usernames:usernames date:int32 status:ChatMemberStatus member_count:int32 has_linked_chat:Bool has_location:Bool sign_messages:Bool join_to_send_messages:Bool join_by_request:Bool is_slow_mode_enabled:Bool is_channel:Bool is_broadcast_group:Bool is_forum:Bool is_verified:Bool restriction_reason:string is_scam:Bool is_fake:Bool = Supergroup; //@has_active_stories True, if the channel has non-expired stories available to the current user
//@has_unread_active_stories True, if the channel has unread non-expired stories available to the current user
supergroup id:int53 usernames:usernames date:int32 status:ChatMemberStatus member_count:int32 has_linked_chat:Bool has_location:Bool sign_messages:Bool join_to_send_messages:Bool join_by_request:Bool is_slow_mode_enabled:Bool is_channel:Bool is_broadcast_group:Bool is_forum:Bool is_verified:Bool restriction_reason:string is_scam:Bool is_fake:Bool has_active_stories:Bool has_unread_active_stories:Bool = Supergroup;
//@description Contains full information about a supergroup or channel //@description Contains full information about a supergroup or channel
//@photo Chat photo; may be null if empty or unknown. If non-null, then it is the same photo as in chat.photo //@photo Chat photo; may be null if empty or unknown. If non-null, then it is the same photo as in chat.photo

View File

@ -5080,6 +5080,9 @@ void ContactsManager::Channel::store(StorerT &storer) const {
bool legacy_has_active_group_call = false; bool legacy_has_active_group_call = false;
bool has_usernames = !usernames.is_empty(); bool has_usernames = !usernames.is_empty();
bool has_flags2 = true; bool has_flags2 = true;
bool has_max_active_story_id = max_active_story_id.is_valid();
bool has_max_read_story_id = max_read_story_id.is_valid();
bool has_max_active_story_id_next_reload_time = max_active_story_id_next_reload_time > Time::now();
BEGIN_STORE_FLAGS(); BEGIN_STORE_FLAGS();
STORE_FLAG(false); STORE_FLAG(false);
STORE_FLAG(false); STORE_FLAG(false);
@ -5115,6 +5118,9 @@ void ContactsManager::Channel::store(StorerT &storer) const {
if (has_flags2) { if (has_flags2) {
BEGIN_STORE_FLAGS(); BEGIN_STORE_FLAGS();
STORE_FLAG(is_forum); STORE_FLAG(is_forum);
STORE_FLAG(has_max_active_story_id);
STORE_FLAG(has_max_read_story_id);
STORE_FLAG(has_max_active_story_id_next_reload_time);
END_STORE_FLAGS(); END_STORE_FLAGS();
} }
@ -5140,6 +5146,15 @@ void ContactsManager::Channel::store(StorerT &storer) const {
if (has_usernames) { if (has_usernames) {
store(usernames, storer); store(usernames, storer);
} }
if (has_max_active_story_id) {
store(max_active_story_id, storer);
}
if (has_max_read_story_id) {
store(max_read_story_id, storer);
}
if (has_max_active_story_id_next_reload_time) {
store_time(max_active_story_id_next_reload_time, storer);
}
} }
template <class ParserT> template <class ParserT>
@ -5162,6 +5177,9 @@ void ContactsManager::Channel::parse(ParserT &parser) {
bool legacy_has_active_group_call; bool legacy_has_active_group_call;
bool has_usernames; bool has_usernames;
bool has_flags2; bool has_flags2;
bool has_max_active_story_id = false;
bool has_max_read_story_id = false;
bool has_max_active_story_id_next_reload_time = false;
BEGIN_PARSE_FLAGS(); BEGIN_PARSE_FLAGS();
PARSE_FLAG(left); PARSE_FLAG(left);
PARSE_FLAG(kicked); PARSE_FLAG(kicked);
@ -5197,6 +5215,9 @@ void ContactsManager::Channel::parse(ParserT &parser) {
if (has_flags2) { if (has_flags2) {
BEGIN_PARSE_FLAGS(); BEGIN_PARSE_FLAGS();
PARSE_FLAG(is_forum); PARSE_FLAG(is_forum);
PARSE_FLAG(has_max_active_story_id);
PARSE_FLAG(has_max_read_story_id);
PARSE_FLAG(has_max_active_story_id_next_reload_time);
END_PARSE_FLAGS(); END_PARSE_FLAGS();
} }
@ -5252,6 +5273,15 @@ void ContactsManager::Channel::parse(ParserT &parser) {
CHECK(!legacy_has_username); CHECK(!legacy_has_username);
parse(usernames, parser); parse(usernames, parser);
} }
if (has_max_active_story_id) {
parse(max_active_story_id, parser);
}
if (has_max_read_story_id) {
parse(max_read_story_id, parser);
}
if (has_max_active_story_id_next_reload_time) {
parse_time(max_active_story_id_next_reload_time, parser);
}
if (!check_utf8(title)) { if (!check_utf8(title)) {
LOG(ERROR) << "Have invalid title \"" << title << '"'; LOG(ERROR) << "Have invalid title \"" << title << '"';
@ -10483,7 +10513,7 @@ void ContactsManager::on_get_user(tl_object_ptr<telegram_api::User> &&user_ptr,
} }
if (is_me_regular_user && (stories_available || stories_unavailable)) { if (is_me_regular_user && (stories_available || stories_unavailable)) {
// update at the end, because it calls need_poll_active_stories // update at the end, because it calls need_poll_user_active_stories
on_update_user_story_ids_impl(u, user_id, StoryId(user->stories_max_id_), StoryId()); on_update_user_story_ids_impl(u, user_id, StoryId(user->stories_max_id_), StoryId());
} }
@ -13638,7 +13668,7 @@ void ContactsManager::on_update_user_story_ids(UserId user_id, StoryId max_activ
on_update_user_story_ids_impl(u, user_id, max_active_story_id, max_read_story_id); on_update_user_story_ids_impl(u, user_id, max_active_story_id, max_read_story_id);
update_user(u, user_id); update_user(u, user_id);
} else { } else {
LOG(INFO) << "Ignore update user has stories about unknown " << user_id; LOG(INFO) << "Ignore update user story identifiers about unknown " << user_id;
} }
} }
@ -13663,7 +13693,7 @@ void ContactsManager::on_update_user_story_ids_impl(User *u, UserId user_id, Sto
u->max_active_story_id = max_active_story_id; u->max_active_story_id = max_active_story_id;
u->need_save_to_database = true; u->need_save_to_database = true;
} }
if (need_poll_active_stories(u, user_id)) { if (need_poll_user_active_stories(u, user_id)) {
auto max_active_story_id_next_reload_time = Time::now() + MAX_ACTIVE_STORY_ID_RELOAD_TIME; auto max_active_story_id_next_reload_time = Time::now() + MAX_ACTIVE_STORY_ID_RELOAD_TIME;
if (max_active_story_id_next_reload_time > if (max_active_story_id_next_reload_time >
u->max_active_story_id_next_reload_time + MAX_ACTIVE_STORY_ID_RELOAD_TIME / 5) { u->max_active_story_id_next_reload_time + MAX_ACTIVE_STORY_ID_RELOAD_TIME / 5) {
@ -15581,7 +15611,7 @@ void ContactsManager::invalidate_invite_link_info(const string &invite_link) {
invite_link_infos_.erase(invite_link); invite_link_infos_.erase(invite_link);
} }
bool ContactsManager::need_poll_active_stories(const User *u, UserId user_id) const { bool ContactsManager::need_poll_user_active_stories(const User *u, UserId user_id) const {
return u != nullptr && user_id != get_my_id() && !is_user_contact(u, user_id, false) && !is_user_bot(u) && return u != nullptr && user_id != get_my_id() && !is_user_contact(u, user_id, false) && !is_user_bot(u) &&
!is_user_support(u) && !is_user_deleted(u) && u->was_online != 0; !is_user_support(u) && !is_user_deleted(u) && u->was_online != 0;
} }
@ -15600,7 +15630,7 @@ void ContactsManager::on_view_user_active_stories(vector<UserId> user_ids) {
continue; continue;
} }
User *u = get_user(user_id); User *u = get_user(user_id);
if (!need_poll_active_stories(u, user_id) || Time::now() < u->max_active_story_id_next_reload_time || if (!need_poll_user_active_stories(u, user_id) || Time::now() < u->max_active_story_id_next_reload_time ||
u->is_max_active_story_id_being_reloaded) { u->is_max_active_story_id_being_reloaded) {
continue; continue;
} }
@ -16320,6 +16350,99 @@ void ContactsManager::on_update_channel_noforwards(Channel *c, ChannelId channel
} }
} }
void ContactsManager::on_update_channel_story_ids(ChannelId channel_id, StoryId max_active_story_id,
StoryId max_read_story_id) {
if (!channel_id.is_valid()) {
LOG(ERROR) << "Receive invalid " << channel_id;
return;
}
Channel *c = get_channel_force(channel_id);
if (c != nullptr) {
on_update_channel_story_ids_impl(c, channel_id, max_active_story_id, max_read_story_id);
update_channel(c, channel_id);
} else {
LOG(INFO) << "Ignore update channel story identifiers about unknown " << channel_id;
}
}
void ContactsManager::on_update_channel_story_ids_impl(Channel *c, ChannelId channel_id, StoryId max_active_story_id,
StoryId max_read_story_id) {
if (td_->auth_manager_->is_bot()) {
return;
}
if (max_active_story_id != StoryId() && !max_active_story_id.is_server()) {
LOG(ERROR) << "Receive max active " << max_active_story_id << " for " << channel_id;
return;
}
if (max_read_story_id != StoryId() && !max_read_story_id.is_server()) {
LOG(ERROR) << "Receive max read " << max_read_story_id << " for " << channel_id;
return;
}
auto has_unread_stories = get_channel_has_unread_stories(c);
if (c->max_active_story_id != max_active_story_id) {
LOG(DEBUG) << "Change last active story of " << channel_id << " from " << c->max_active_story_id << " to "
<< max_active_story_id;
c->max_active_story_id = max_active_story_id;
c->need_save_to_database = true;
}
if (need_poll_channel_active_stories(c, channel_id)) {
auto max_active_story_id_next_reload_time = Time::now() + MAX_ACTIVE_STORY_ID_RELOAD_TIME;
if (max_active_story_id_next_reload_time >
c->max_active_story_id_next_reload_time + MAX_ACTIVE_STORY_ID_RELOAD_TIME / 5) {
LOG(DEBUG) << "Change max_active_story_id_next_reload_time of " << channel_id;
c->max_active_story_id_next_reload_time = max_active_story_id_next_reload_time;
c->need_save_to_database = true;
}
}
if (!max_active_story_id.is_valid()) {
CHECK(max_read_story_id == StoryId());
if (c->max_read_story_id != StoryId()) {
LOG(DEBUG) << "Drop last read " << c->max_read_story_id << " of " << channel_id;
c->max_read_story_id = StoryId();
c->need_save_to_database = true;
}
} else if (max_read_story_id.get() > c->max_read_story_id.get()) {
LOG(DEBUG) << "Change last read story of " << channel_id << " from " << c->max_read_story_id << " to "
<< max_read_story_id;
c->max_read_story_id = max_read_story_id;
c->need_save_to_database = true;
}
if (has_unread_stories != get_channel_has_unread_stories(c)) {
LOG(DEBUG) << "Change has_unread_stories of " << channel_id;
c->is_changed = true;
}
}
void ContactsManager::on_update_channel_max_read_story_id(ChannelId channel_id, StoryId max_read_story_id) {
CHECK(channel_id.is_valid());
Channel *c = get_channel(channel_id);
if (c != nullptr) {
on_update_channel_max_read_story_id(c, channel_id, max_read_story_id);
update_channel(c, channel_id);
}
}
void ContactsManager::on_update_channel_max_read_story_id(Channel *c, ChannelId channel_id, StoryId max_read_story_id) {
if (td_->auth_manager_->is_bot()) {
return;
}
auto has_unread_stories = get_channel_has_unread_stories(c);
if (max_read_story_id.get() > c->max_read_story_id.get()) {
LOG(DEBUG) << "Change last read story of " << channel_id << " from " << c->max_read_story_id << " to "
<< max_read_story_id;
c->max_read_story_id = max_read_story_id;
c->need_save_to_database = true;
}
if (has_unread_stories != get_channel_has_unread_stories(c)) {
LOG(DEBUG) << "Change has_unread_stories of " << channel_id;
c->is_changed = true;
}
}
void ContactsManager::on_update_channel_editable_username(ChannelId channel_id, string &&username) { void ContactsManager::on_update_channel_editable_username(ChannelId channel_id, string &&username) {
Channel *c = get_channel(channel_id); Channel *c = get_channel(channel_id);
CHECK(c != nullptr); CHECK(c != nullptr);
@ -18747,6 +18870,8 @@ void ContactsManager::on_chat_update(telegram_api::channel &channel, const char
bool is_forum = (channel.flags_ & CHANNEL_FLAG_IS_FORUM) != 0; bool is_forum = (channel.flags_ & CHANNEL_FLAG_IS_FORUM) != 0;
bool have_participant_count = (channel.flags_ & CHANNEL_FLAG_HAS_PARTICIPANT_COUNT) != 0; bool have_participant_count = (channel.flags_ & CHANNEL_FLAG_HAS_PARTICIPANT_COUNT) != 0;
int32 participant_count = have_participant_count ? channel.participants_count_ : 0; int32 participant_count = have_participant_count ? channel.participants_count_ : 0;
bool stories_available = channel.stories_max_id_ > 0;
bool stories_unavailable = channel.stories_unavailable_;
if (have_participant_count) { if (have_participant_count) {
auto channel_full = get_channel_full_const(channel_id); auto channel_full = get_channel_full_const(channel_id);
@ -18931,6 +19056,10 @@ void ContactsManager::on_chat_update(telegram_api::channel &channel, const char
if (old_join_to_send != get_channel_join_to_send(c) || old_join_request != get_channel_join_request(c)) { if (old_join_to_send != get_channel_join_to_send(c) || old_join_request != get_channel_join_request(c)) {
c->is_changed = true; c->is_changed = true;
} }
if (!td_->auth_manager_->is_bot() && (stories_available || stories_unavailable)) {
// update at the end, because it calls need_poll_channel_active_stories
on_update_channel_story_ids_impl(c, channel_id, StoryId(channel.stories_max_id_), StoryId());
}
if (c->cache_version != Channel::CACHE_VERSION) { if (c->cache_version != Channel::CACHE_VERSION) {
c->cache_version = Channel::CACHE_VERSION; c->cache_version = Channel::CACHE_VERSION;
@ -19163,6 +19292,7 @@ td_api::object_ptr<td_api::UserStatus> ContactsManager::get_user_status_object(U
} }
bool ContactsManager::get_user_has_unread_stories(const User *u) { bool ContactsManager::get_user_has_unread_stories(const User *u) {
CHECK(u != nullptr);
return u->max_active_story_id.get() > u->max_read_story_id.get(); return u->max_active_story_id.get() > u->max_read_story_id.get();
} }
@ -19379,7 +19509,7 @@ td_api::object_ptr<td_api::updateSupergroup> ContactsManager::get_update_unknown
bool is_megagroup = min_channel == nullptr ? false : min_channel->is_megagroup_; bool is_megagroup = min_channel == nullptr ? false : min_channel->is_megagroup_;
return td_api::make_object<td_api::updateSupergroup>(td_api::make_object<td_api::supergroup>( return td_api::make_object<td_api::updateSupergroup>(td_api::make_object<td_api::supergroup>(
channel_id.get(), nullptr, 0, DialogParticipantStatus::Banned(0).get_chat_member_status_object(), 0, false, false, channel_id.get(), nullptr, 0, DialogParticipantStatus::Banned(0).get_chat_member_status_object(), 0, false, false,
false, !is_megagroup, false, false, !is_megagroup, false, false, false, string(), false, false)); false, !is_megagroup, false, false, !is_megagroup, false, false, false, string(), false, false, false, false));
} }
int64 ContactsManager::get_supergroup_id_object(ChannelId channel_id, const char *source) const { int64 ContactsManager::get_supergroup_id_object(ChannelId channel_id, const char *source) const {
@ -19395,6 +19525,16 @@ int64 ContactsManager::get_supergroup_id_object(ChannelId channel_id, const char
return channel_id.get(); return channel_id.get();
} }
bool ContactsManager::need_poll_channel_active_stories(const Channel *c, ChannelId channel_id) const {
return c != nullptr && !get_channel_status(c).is_member() &&
have_input_peer_channel(c, channel_id, AccessRights::Read);
}
bool ContactsManager::get_channel_has_unread_stories(const Channel *c) {
CHECK(c != nullptr);
return c->max_active_story_id.get() > c->max_read_story_id.get();
}
tl_object_ptr<td_api::supergroup> ContactsManager::get_supergroup_object(ChannelId channel_id) const { tl_object_ptr<td_api::supergroup> ContactsManager::get_supergroup_object(ChannelId channel_id) const {
return get_supergroup_object(channel_id, get_channel(channel_id)); return get_supergroup_object(channel_id, get_channel(channel_id));
} }
@ -19408,7 +19548,8 @@ tl_object_ptr<td_api::supergroup> ContactsManager::get_supergroup_object(Channel
get_channel_status(c).get_chat_member_status_object(), c->participant_count, c->has_linked_channel, get_channel_status(c).get_chat_member_status_object(), c->participant_count, c->has_linked_channel,
c->has_location, c->sign_messages, get_channel_join_to_send(c), get_channel_join_request(c), c->has_location, c->sign_messages, get_channel_join_to_send(c), get_channel_join_request(c),
c->is_slow_mode_enabled, !c->is_megagroup, c->is_gigagroup, c->is_forum, c->is_verified, c->is_slow_mode_enabled, !c->is_megagroup, c->is_gigagroup, c->is_forum, c->is_verified,
get_restriction_reason_description(c->restriction_reasons), c->is_scam, c->is_fake); get_restriction_reason_description(c->restriction_reasons), c->is_scam, c->is_fake,
c->max_active_story_id.is_valid(), get_channel_has_unread_stories(c));
} }
tl_object_ptr<td_api::supergroupFullInfo> ContactsManager::get_supergroup_full_info_object(ChannelId channel_id) const { tl_object_ptr<td_api::supergroupFullInfo> ContactsManager::get_supergroup_full_info_object(ChannelId channel_id) const {

View File

@ -213,6 +213,8 @@ class ContactsManager final : public Actor {
void on_update_channel_editable_username(ChannelId channel_id, string &&username); void on_update_channel_editable_username(ChannelId channel_id, string &&username);
void on_update_channel_usernames(ChannelId channel_id, Usernames &&usernames); void on_update_channel_usernames(ChannelId channel_id, Usernames &&usernames);
void on_update_channel_story_ids(ChannelId channel_id, StoryId max_active_story_id, StoryId max_read_story_id);
void on_update_channel_max_read_story_id(ChannelId channel_id, StoryId max_read_story_id);
void on_update_channel_description(ChannelId channel_id, string &&description); void on_update_channel_description(ChannelId channel_id, string &&description);
void on_update_channel_sticker_set(ChannelId channel_id, StickerSetId sticker_set_id); void on_update_channel_sticker_set(ChannelId channel_id, StickerSetId sticker_set_id);
void on_update_channel_linked_channel_id(ChannelId channel_id, ChannelId group_channel_id); void on_update_channel_linked_channel_id(ChannelId channel_id, ChannelId group_channel_id);
@ -977,6 +979,10 @@ class ContactsManager final : public Actor {
int32 date = 0; int32 date = 0;
int32 participant_count = 0; int32 participant_count = 0;
double max_active_story_id_next_reload_time = 0.0;
StoryId max_active_story_id;
StoryId max_read_story_id;
static constexpr uint32 CACHE_VERSION = 10; static constexpr uint32 CACHE_VERSION = 10;
uint32 cache_version = 0; uint32 cache_version = 0;
@ -1492,6 +1498,9 @@ class ContactsManager final : public Actor {
RestrictedRights default_permissions); RestrictedRights default_permissions);
static void on_update_channel_has_location(Channel *c, ChannelId channel_id, bool has_location); static void on_update_channel_has_location(Channel *c, ChannelId channel_id, bool has_location);
static void on_update_channel_noforwards(Channel *c, ChannelId channel_id, bool noforwards); static void on_update_channel_noforwards(Channel *c, ChannelId channel_id, bool noforwards);
void on_update_channel_story_ids_impl(Channel *c, ChannelId channel_id, StoryId max_active_story_id,
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_bot_user_ids(ChannelId channel_id, vector<UserId> &&bot_user_ids);
@ -1755,7 +1764,7 @@ class ContactsManager final : public Actor {
void on_dismiss_suggested_action(SuggestedAction action, Result<Unit> &&result); void on_dismiss_suggested_action(SuggestedAction action, Result<Unit> &&result);
bool need_poll_active_stories(const User *u, UserId user_id) const; bool need_poll_user_active_stories(const User *u, UserId user_id) const;
static bool get_user_has_unread_stories(const User *u); static bool get_user_has_unread_stories(const User *u);
@ -1780,6 +1789,10 @@ class ContactsManager final : public Actor {
tl_object_ptr<td_api::basicGroupFullInfo> get_basic_group_full_info_object(ChatId chat_id, tl_object_ptr<td_api::basicGroupFullInfo> get_basic_group_full_info_object(ChatId chat_id,
const ChatFull *chat_full) const; const ChatFull *chat_full) const;
bool need_poll_channel_active_stories(const Channel *c, ChannelId channel_id) const;
static bool get_channel_has_unread_stories(const Channel *c);
td_api::object_ptr<td_api::updateSupergroup> get_update_supergroup_object(ChannelId channel_id, td_api::object_ptr<td_api::updateSupergroup> get_update_supergroup_object(ChannelId channel_id,
const Channel *c) const; const Channel *c) const;

View File

@ -3501,8 +3501,12 @@ void StoryManager::on_update_dialog_max_story_ids(DialogId owner_dialog_id, Stor
send_closure_later(td_->contacts_manager_actor_, &ContactsManager::on_update_user_story_ids, send_closure_later(td_->contacts_manager_actor_, &ContactsManager::on_update_user_story_ids,
owner_dialog_id.get_user_id(), max_story_id, max_read_story_id); owner_dialog_id.get_user_id(), max_story_id, max_read_story_id);
break; break;
case DialogType::Chat:
case DialogType::Channel: case DialogType::Channel:
// use send_closure_later because story order can be updated from update_channel
send_closure_later(td_->contacts_manager_actor_, &ContactsManager::on_update_channel_story_ids,
owner_dialog_id.get_channel_id(), max_story_id, max_read_story_id);
break;
case DialogType::Chat:
case DialogType::SecretChat: case DialogType::SecretChat:
case DialogType::None: case DialogType::None:
default: default:
@ -3515,8 +3519,10 @@ void StoryManager::on_update_dialog_max_read_story_id(DialogId owner_dialog_id,
case DialogType::User: case DialogType::User:
td_->contacts_manager_->on_update_user_max_read_story_id(owner_dialog_id.get_user_id(), max_read_story_id); td_->contacts_manager_->on_update_user_max_read_story_id(owner_dialog_id.get_user_id(), max_read_story_id);
break; break;
case DialogType::Chat:
case DialogType::Channel: case DialogType::Channel:
td_->contacts_manager_->on_update_channel_max_read_story_id(owner_dialog_id.get_channel_id(), max_read_story_id);
break;
case DialogType::Chat:
case DialogType::SecretChat: case DialogType::SecretChat:
case DialogType::None: case DialogType::None:
default: default: