Cache received story viewers.

This commit is contained in:
levlam 2023-06-20 15:54:47 +03:00
parent c885e3f5fa
commit 4e2e6f6e61
6 changed files with 81 additions and 10 deletions

View File

@ -7284,10 +7284,12 @@ openStory story_sender_user_id:int53 story_id:int32 = Ok;
//@story_id The identifier of the story
closeStory story_sender_user_id:int53 story_id:int32 = Ok;
//@description Returns viewers of a recent outgoing story. The method can be called if story.can_get_viewers == true
//@description Returns viewers of a recent outgoing story. The method can be called if story.can_get_viewers == true. The views are returned in a reverse chronological order (i.e., in order of decreasing view_date)
//-For optimal performance, the number of returned stories is chosen by TDLib
//@story_id Story identifier
//@offset_viewer A viewer from which to return next viewers; pass null to get results from the beginning
//@limit The maximum number of story viewers to return
//-For optimal performance, the number of returned stories is chosen by TDLib and can be smaller than the specified limit
getStoryViewers story_id:int32 offset_viewer:messageViewer limit:int32 = MessageViewers;

View File

@ -53,7 +53,7 @@ MessageViewers::MessageViewers(vector<telegram_api::object_ptr<telegram_api::rea
}
MessageViewers MessageViewers::get_sublist(const MessageViewer &offset, int32 limit) const {
MessageViewers result{vector<telegram_api::object_ptr<telegram_api::storyView>>()};
MessageViewers result;
bool found = offset.is_empty();
for (auto &message_viewer : message_viewers_) {
if (found) {
@ -68,6 +68,25 @@ MessageViewers MessageViewers::get_sublist(const MessageViewer &offset, int32 li
return result;
}
void MessageViewers::add_sublist(const MessageViewer &offset, const MessageViewers &sublist) {
if (offset.is_empty()) {
if (message_viewers_.empty()) {
message_viewers_ = sublist.message_viewers_;
} else {
auto old_viewers = std::move(message_viewers_);
for (auto &viewer : sublist.message_viewers_) {
if (viewer == old_viewers[0]) {
append(message_viewers_, old_viewers);
return;
}
message_viewers_.push_back(viewer);
}
}
} else if (!message_viewers_.empty() && message_viewers_.back() == offset) {
append(message_viewers_, sublist.message_viewers_);
}
}
td_api::object_ptr<td_api::messageViewers> MessageViewers::get_message_viewers_object(
ContactsManager *contacts_manager) const {
return td_api::make_object<td_api::messageViewers>(

View File

@ -51,12 +51,20 @@ StringBuilder &operator<<(StringBuilder &string_builder, const MessageViewer &vi
struct MessageViewers {
vector<MessageViewer> message_viewers_;
MessageViewers() = default;
explicit MessageViewers(vector<telegram_api::object_ptr<telegram_api::storyView>> &&story_views);
explicit MessageViewers(vector<telegram_api::object_ptr<telegram_api::readParticipantDate>> &&read_dates);
bool is_empty() const {
return message_viewers_.empty();
}
MessageViewers get_sublist(const MessageViewer &offset, int32 limit) const;
void add_sublist(const MessageViewer &offset, const MessageViewers &sublist);
td_api::object_ptr<td_api::messageViewers> get_message_viewers_object(ContactsManager *contacts_manager) const;
};

View File

@ -44,6 +44,10 @@ class StoryInteractionInfo {
return false;
}
int32 get_view_count() const {
return view_count_;
}
td_api::object_ptr<td_api::storyInteractionInfo> get_story_interaction_info_object(Td *td) const;
};

View File

@ -16,7 +16,6 @@
#include "td/telegram/logevent/LogEventHelper.h"
#include "td/telegram/MessageEntity.h"
#include "td/telegram/MessagesManager.h"
#include "td/telegram/MessageViewer.h"
#include "td/telegram/OptionManager.h"
#include "td/telegram/StoryContent.h"
#include "td/telegram/StoryContentType.h"
@ -695,6 +694,7 @@ void StoryManager::on_story_can_get_viewers_timeout(int64 story_global_id) {
send_closure(G()->td(), &Td::send_update,
td_api::make_object<td_api::updateStory>(get_story_object(story_full_id, story)));
}
cached_story_viewers_.erase(story_full_id);
}
bool StoryManager::is_story_owned(DialogId owner_dialog_id) const {
@ -1100,7 +1100,7 @@ void StoryManager::get_story_viewers(StoryId story_id, const td_api::messageView
if (limit <= 0) {
return promise.set_error(Status::Error(400, "Parameter limit must be positive"));
}
if (can_get_story_viewers(story_full_id, story).is_error()) {
if (can_get_story_viewers(story_full_id, story).is_error() || story->interaction_info_.get_view_count() == 0) {
return promise.set_value(td_api::object_ptr<td_api::messageViewers>());
}
@ -1110,11 +1110,22 @@ void StoryManager::get_story_viewers(StoryId story_id, const td_api::messageView
offset_date = offset->view_date_;
offset_user_id = offset->user_id_;
}
MessageViewer offset_viewer{UserId(offset_user_id), offset_date};
auto &cached_viewers = cached_story_viewers_[story_full_id];
if (cached_viewers != nullptr && story->content_ != nullptr &&
(cached_viewers->total_count_ == story->interaction_info_.get_view_count() || !offset_viewer.is_empty())) {
auto result = cached_viewers->viewers_.get_sublist(offset_viewer, limit);
if (!result.is_empty()) {
return promise.set_value(result.get_message_viewers_object(td_->contacts_manager_.get()));
}
}
auto query_promise = PromiseCreator::lambda(
[actor_id = actor_id(this), story_id, promise = std::move(promise)](
[actor_id = actor_id(this), story_id, offset_viewer, promise = std::move(promise)](
Result<telegram_api::object_ptr<telegram_api::stories_storyViewsList>> result) mutable {
send_closure(actor_id, &StoryManager::on_get_story_viewers, story_id, std::move(result), std::move(promise));
send_closure(actor_id, &StoryManager::on_get_story_viewers, story_id, offset_viewer, std::move(result),
std::move(promise));
});
td_->create_handler<GetStoryViewsListQuery>(std::move(query_promise))
@ -1122,7 +1133,8 @@ void StoryManager::get_story_viewers(StoryId story_id, const td_api::messageView
}
void StoryManager::on_get_story_viewers(
StoryId story_id, Result<telegram_api::object_ptr<telegram_api::stories_storyViewsList>> r_view_list,
StoryId story_id, MessageViewer offset,
Result<telegram_api::object_ptr<telegram_api::stories_storyViewsList>> r_view_list,
Promise<td_api::object_ptr<td_api::messageViewers>> &&promise) {
G()->ignore_result_if_closing(r_view_list);
if (r_view_list.is_error()) {
@ -1140,11 +1152,29 @@ void StoryManager::on_get_story_viewers(
td_->contacts_manager_->on_get_users(std::move(view_list->users_), "on_get_story_viewers");
if (story->content_ != nullptr && story->interaction_info_.set_view_count(view_list->count_)) {
on_story_changed(story_full_id, story, true, true);
auto total_count = view_list->count_;
if (total_count < 0 || static_cast<size_t>(total_count) < view_list->views_.size()) {
LOG(ERROR) << "Receive total_count = " << total_count << " and " << view_list->views_.size() << " story viewers";
total_count = static_cast<int32>(view_list->views_.size());
}
MessageViewers story_viewers(std::move(view_list->views_));
if (story->content_ != nullptr) {
if (story->interaction_info_.set_view_count(view_list->count_)) {
on_story_changed(story_full_id, story, true, true);
}
auto &cached_viewers = cached_story_viewers_[story_full_id];
if (cached_viewers == nullptr) {
cached_viewers = make_unique<CachedStoryViewers>();
}
if (total_count < cached_viewers->total_count_) {
LOG(ERROR) << "Total viewer count decreased from " << cached_viewers->total_count_ << " to " << total_count;
} else {
cached_viewers->total_count_ = total_count;
}
cached_viewers->viewers_.add_sublist(offset, story_viewers);
}
promise.set_value(story_viewers.get_message_viewers_object(td_->contacts_manager_.get()));
}

View File

@ -11,6 +11,7 @@
#include "td/telegram/files/FileSourceId.h"
#include "td/telegram/FullMessageId.h"
#include "td/telegram/MessageEntity.h"
#include "td/telegram/MessageViewer.h"
#include "td/telegram/StoryFullId.h"
#include "td/telegram/StoryId.h"
#include "td/telegram/StoryInteractionInfo.h"
@ -82,6 +83,11 @@ class StoryManager final : public Actor {
vector<StoryId> story_ids_;
};
struct CachedStoryViewers {
int32 total_count_ = -1;
MessageViewers viewers_;
};
public:
StoryManager(Td *td, ActorShared<> parent);
StoryManager(const StoryManager &) = delete;
@ -284,7 +290,7 @@ class StoryManager final : public Actor {
void on_synchronized_archive_all_stories(bool set_archive_all_stories, Result<Unit> result);
void on_get_story_viewers(StoryId story_id,
void on_get_story_viewers(StoryId story_id, MessageViewer offset,
Result<telegram_api::object_ptr<telegram_api::stories_storyViewsList>> r_view_list,
Promise<td_api::object_ptr<td_api::messageViewers>> &&promise);
@ -312,6 +318,8 @@ class StoryManager final : public Actor {
FlatHashMap<StoryFullId, uint32, StoryFullIdHash> opened_owned_stories_;
FlatHashMap<StoryFullId, unique_ptr<CachedStoryViewers>, StoryFullIdHash> cached_story_viewers_;
uint32 send_story_count_ = 0;
int64 max_story_global_id_ = 0;