From 863ee6ac33dabd05f8eb5777dec40038471d9273 Mon Sep 17 00:00:00 2001 From: levlam Date: Wed, 14 Jun 2023 16:06:48 +0300 Subject: [PATCH] Send expired story views to the server. --- td/telegram/StoryManager.cpp | 74 +++++++++++++++++++++++++++++++++++- td/telegram/StoryManager.h | 11 ++++++ 2 files changed, 84 insertions(+), 1 deletion(-) diff --git a/td/telegram/StoryManager.cpp b/td/telegram/StoryManager.cpp index 32cf1e3e5..bae1c7235 100644 --- a/td/telegram/StoryManager.cpp +++ b/td/telegram/StoryManager.cpp @@ -72,6 +72,37 @@ class ToggleStoriesHiddenQuery final : public Td::ResultHandler { } }; +class IncrementStoryViewsQuery final : public Td::ResultHandler { + Promise promise_; + + public: + explicit IncrementStoryViewsQuery(Promise &&promise) : promise_(std::move(promise)) { + } + + void send(DialogId owner_dialog_id, vector input_story_ids) { + CHECK(owner_dialog_id.get_type() == DialogType::User); + auto r_input_user = td_->contacts_manager_->get_input_user(owner_dialog_id.get_user_id()); + if (r_input_user.is_error()) { + return on_error(r_input_user.move_as_error()); + } + send_query(G()->net_query_creator().create( + telegram_api::stories_incrementStoryViews(r_input_user.move_as_ok(), std::move(input_story_ids)))); + } + + void on_result(BufferSlice packet) final { + auto result_ptr = fetch_result(packet); + if (result_ptr.is_error()) { + return on_error(result_ptr.move_as_error()); + } + + promise_.set_value(Unit()); + } + + void on_error(Status status) final { + promise_.set_error(std::move(status)); + } +}; + class GetStoriesByIDQuery final : public Td::ResultHandler { Promise promise_; UserId user_id_; @@ -631,15 +662,56 @@ void StoryManager::open_story(DialogId owner_dialog_id, StoryId story_id, Promis td_->file_manager_->check_local_location_async(file_id, true); } + bool need_increment_story_views = G()->unix_time() >= story->expire_date_ && story->is_pinned_; + if (story_id.is_server() && need_increment_story_views) { + auto &story_views = pending_story_views_[owner_dialog_id]; + story_views.story_ids_.insert(story_id); + if (!story_views.has_query_) { + increment_story_views(owner_dialog_id, story_views); + } + } + promise.set_value(Unit()); } +void StoryManager::increment_story_views(DialogId owner_dialog_id, PendingStoryViews &story_views) { + CHECK(!story_views.has_query_); + vector viewed_story_ids; + const size_t MAX_VIEWED_STORIES = 200; // server-side limit + while (!story_views.story_ids_.empty() && viewed_story_ids.size() < MAX_VIEWED_STORIES) { + auto story_id_it = story_views.story_ids_.begin(); + viewed_story_ids.push_back(story_id_it->get()); + story_views.story_ids_.erase(story_id_it); + } + CHECK(!viewed_story_ids.empty()); + story_views.has_query_ = true; + auto promise = PromiseCreator::lambda([actor_id = actor_id(this), owner_dialog_id](Result) { + send_closure(actor_id, &StoryManager::on_increment_story_views, owner_dialog_id); + }); + td_->create_handler(std::move(promise))->send(owner_dialog_id, std::move(viewed_story_ids)); +} + +void StoryManager::on_increment_story_views(DialogId owner_dialog_id) { + if (G()->close_flag()) { + return; + } + + auto &story_views = pending_story_views_[owner_dialog_id]; + CHECK(story_views.has_query_); + story_views.has_query_ = false; + if (story_views.story_ids_.empty()) { + pending_story_views_.erase(owner_dialog_id); + return; + } + increment_story_views(owner_dialog_id, story_views); +} + bool StoryManager::have_story(StoryFullId story_full_id) const { return get_story(story_full_id) != nullptr; } bool StoryManager::have_story_force(StoryFullId story_full_id) const { - // TODO try load story + // TODO try load story from the database return have_story(story_full_id); } diff --git a/td/telegram/StoryManager.h b/td/telegram/StoryManager.h index a8a1e91ef..bf9f09dcf 100644 --- a/td/telegram/StoryManager.h +++ b/td/telegram/StoryManager.h @@ -68,6 +68,11 @@ class StoryManager final : public Actor { unique_ptr &&story); }; + struct PendingStoryViews { + FlatHashSet story_ids_; + bool has_query_ = false; + }; + public: StoryManager(Td *td, ActorShared<> parent); StoryManager(const StoryManager &) = delete; @@ -200,6 +205,10 @@ class StoryManager final : public Actor { void on_toggle_story_is_pinned(StoryId story_id, bool is_pinned, Promise &&promise); + void increment_story_views(DialogId owner_dialog_id, PendingStoryViews &story_views); + + void on_increment_story_views(DialogId owner_dialog_id); + std::shared_ptr upload_media_callback_; WaitFreeHashMap story_full_id_to_file_source_id_; @@ -214,6 +223,8 @@ class StoryManager final : public Actor { FlatHashMap, StoryFullIdHash> being_edited_stories_; + FlatHashMap pending_story_views_; + uint32 send_story_count_ = 0; FlatHashMap, FileIdHash> being_uploaded_files_;