diff --git a/td/generate/scheme/td_api.tl b/td/generate/scheme/td_api.tl index 86046cfcf..8527a2419 100644 --- a/td/generate/scheme/td_api.tl +++ b/td/generate/scheme/td_api.tl @@ -4923,6 +4923,15 @@ story id:int32 sender_user_id:int53 date:int32 is_pinned:Bool interaction_info:s //@description Represents a list of stories @total_count Approximate total number of stories found @stories The list of stories stories total_count:int32 stories:vector = Stories; +//@description Contains basic information about a story @story_id Unique story identifier among stories of the given sender @date Point in time (Unix timestamp) when the story was published +storyInfo story_id:int32 date:int32 = StoryInfo; + +//@description Describes active stories sent by the same sender +//@story_sender_user_id Identifier of the sender of the stories +//@max_read_story_id Identifier of the last read active story +//@stories Basic information about the stories; use getStory to get full information about the stories +activeStories story_sender_user_id:int53 max_read_story_id:int32 stories:vector = ActiveStories; + //@description Contains a part of a file @data File bytes filePart data:bytes = FilePart; @@ -7239,8 +7248,8 @@ deleteStory story_id:int32 = Ok; //@description Toggles whether stories of the user are available on the main chat list @user_id Identifier of the user @are_archived Pass true to make the story unavailable on the main chat list; pass false to make them available toggleUserStoriesAreArchived user_id:int53 are_archived:Bool = Ok; -//@description Returns the list of active stories of a given user. The stories are returned in a reverse chronological order (i.e., in order of decreasing story_id) @user_id User identifier -getUserActiveStories user_id:int53 = Stories; +//@description Returns the list of active stories of a given user. The stories are returned in a chronological order (i.e., in order of increasing story_id) @user_id User identifier +getUserActiveStories user_id:int53 = ActiveStories; //@description Returns the list of pinned stories of a given user. The stories are returned in a reverse chronological order (i.e., in order of decreasing story_id). //-For optimal performance, the number of returned stories is chosen by TDLib diff --git a/td/telegram/StoryManager.cpp b/td/telegram/StoryManager.cpp index 8ac634700..1950ca09f 100644 --- a/td/telegram/StoryManager.cpp +++ b/td/telegram/StoryManager.cpp @@ -605,7 +605,7 @@ void StoryManager::on_get_story_archive(telegram_api::object_ptr> &&promise) { + Promise> &&promise) { if (!td_->messages_manager_->have_dialog_info_force(owner_dialog_id)) { return promise.set_error(Status::Error(400, "Story sender not found")); } @@ -613,7 +613,7 @@ void StoryManager::get_dialog_expiring_stories(DialogId owner_dialog_id, return promise.set_error(Status::Error(400, "Can't access the story sender")); } if (owner_dialog_id.get_type() != DialogType::User) { - return promise.set_value(td_api::make_object()); + return promise.set_value(td_api::make_object(owner_dialog_id.get(), 0, Auto())); } auto query_promise = @@ -630,15 +630,11 @@ void StoryManager::get_dialog_expiring_stories(DialogId owner_dialog_id, void StoryManager::on_get_dialog_expiring_stories(DialogId owner_dialog_id, telegram_api::object_ptr &&stories, - Promise> &&promise) { + Promise> &&promise) { TRY_STATUS_PROMISE(promise, G()->close_status()); td_->contacts_manager_->on_get_users(std::move(stories->users_), "on_get_dialog_expiring_stories"); - auto story_ids = on_get_stories(owner_dialog_id, std::move(stories->stories_->stories_)); - CHECK(owner_dialog_id.get_type() == DialogType::User); - td_->contacts_manager_->on_update_user_has_stories(owner_dialog_id.get_user_id(), !story_ids.empty()); - promise.set_value(get_stories_object(-1, transform(story_ids, [owner_dialog_id](StoryId story_id) { - return StoryFullId(owner_dialog_id, story_id); - }))); + auto active_stories = on_get_user_stories(owner_dialog_id, std::move(stories->stories_)); + promise.set_value(get_active_stories_object(active_stories)); } void StoryManager::open_story(DialogId owner_dialog_id, StoryId story_id, Promise &&promise) { @@ -756,6 +752,19 @@ void StoryManager::unregister_story(StoryFullId story_full_id, FullMessageId ful } } +td_api::object_ptr StoryManager::get_story_info_object(StoryFullId story_full_id) const { + return get_story_info_object(story_full_id, get_story(story_full_id)); +} + +td_api::object_ptr StoryManager::get_story_info_object(StoryFullId story_full_id, + const Story *story) const { + if (story == nullptr || G()->unix_time() >= story->expire_date_) { + return nullptr; + } + + return td_api::make_object(story_full_id.get_story_id().get(), story->date_); +} + td_api::object_ptr StoryManager::get_story_object(StoryFullId story_full_id) const { return get_story_object(story_full_id, get_story(story_full_id)); } @@ -816,6 +825,22 @@ td_api::object_ptr StoryManager::get_stories_object(int32 total })); } +td_api::object_ptr StoryManager::get_active_stories_object( + const ActiveStories &active_stories) const { + auto owner_dialog_id = active_stories.dialog_id_; + vector> stories; + for (auto story_id : active_stories.story_ids_) { + auto story_info = get_story_info_object({owner_dialog_id, story_id}); + if (story_info != nullptr) { + stories.push_back(std::move(story_info)); + } + } + CHECK(owner_dialog_id.get_type() == DialogType::User); + return td_api::make_object( + td_->contacts_manager_->get_user_id_object(owner_dialog_id.get_user_id(), "get_active_stories_object"), + active_stories.max_read_story_id_.get(), std::move(stories)); +} + vector StoryManager::get_story_file_ids(const Story *story) const { if (story == nullptr || story->content_ == nullptr) { return {}; @@ -863,7 +888,7 @@ StoryId StoryManager::on_get_story(DialogId owner_dialog_id, return story_id; } case telegram_api::storyItemSkipped::ID: - LOG(ERROR) << "Receive storyItemSkipped"; + LOG(ERROR) << "Receive " << to_string(story_item_ptr); return {}; case telegram_api::storyItem::ID: { return on_get_story(owner_dialog_id, telegram_api::move_object_as(story_item_ptr)); @@ -1024,7 +1049,28 @@ std::pair> StoryManager::on_get_stories( DialogId owner_dialog_id, vector &&expected_story_ids, telegram_api::object_ptr &&stories) { td_->contacts_manager_->on_get_users(std::move(stories->users_), "on_get_stories"); - auto story_ids = on_get_stories(owner_dialog_id, std::move(stories->stories_)); + + vector story_ids; + for (auto &story : stories->stories_) { + switch (story->get_id()) { + case telegram_api::storyItemDeleted::ID: + LOG(ERROR) << "Receive " << to_string(story); + break; + case telegram_api::storyItemSkipped::ID: + LOG(ERROR) << "Receive " << to_string(story); + break; + case telegram_api::storyItem::ID: { + auto story_id = on_get_story(owner_dialog_id, telegram_api::move_object_as(story)); + if (story_id.is_valid()) { + story_ids.push_back(story_id); + } + break; + } + default: + UNREACHABLE(); + } + } + auto total_count = stories->count_; if (total_count < static_cast(story_ids.size())) { LOG(ERROR) << "Expected at most " << total_count << " stories, but receive " << story_ids.size(); @@ -1052,16 +1098,32 @@ std::pair> StoryManager::on_get_stories( return {total_count, std::move(story_ids)}; } -vector StoryManager::on_get_stories(DialogId owner_dialog_id, - vector> &&stories) { +StoryManager::ActiveStories StoryManager::on_get_user_stories( + DialogId owner_dialog_id, telegram_api::object_ptr &&user_stories) { + CHECK(user_stories != nullptr); + + DialogId story_dialog_id(UserId(user_stories->user_id_)); + if (owner_dialog_id.is_valid() && owner_dialog_id != story_dialog_id) { + LOG(ERROR) << "Receive stories from " << story_dialog_id << " instead of " << owner_dialog_id; + ActiveStories result; + result.dialog_id_ = owner_dialog_id; + return result; + } + + StoryId max_read_story_id(user_stories->max_read_id_); + if (!max_read_story_id.is_server() && max_read_story_id != StoryId()) { + LOG(ERROR) << "Receive max read " << max_read_story_id; + max_read_story_id = StoryId(); + } + vector story_ids; - for (auto &story : stories) { + for (auto &story : user_stories->stories_) { switch (story->get_id()) { case telegram_api::storyItemDeleted::ID: - LOG(ERROR) << "Receive storyItemDeleted"; + LOG(ERROR) << "Receive " << to_string(story); break; case telegram_api::storyItemSkipped::ID: - LOG(ERROR) << "Receive storyItemSkipped"; + // TODO break; case telegram_api::storyItem::ID: { auto story_id = on_get_story(owner_dialog_id, telegram_api::move_object_as(story)); @@ -1074,7 +1136,12 @@ vector StoryManager::on_get_stories(DialogId owner_dialog_id, UNREACHABLE(); } } - return story_ids; + + ActiveStories result; + result.dialog_id_ = story_dialog_id; + result.max_read_story_id_ = max_read_story_id; + result.story_ids_ = std::move(story_ids); + return result; } FileSourceId StoryManager::get_story_file_source_id(StoryFullId story_full_id) { diff --git a/td/telegram/StoryManager.h b/td/telegram/StoryManager.h index bf9f09dcf..d0701e3cd 100644 --- a/td/telegram/StoryManager.h +++ b/td/telegram/StoryManager.h @@ -73,6 +73,12 @@ class StoryManager final : public Actor { bool has_query_ = false; }; + struct ActiveStories { + DialogId dialog_id_; + StoryId max_read_story_id_; + vector story_ids_; + }; + public: StoryManager(Td *td, ActorShared<> parent); StoryManager(const StoryManager &) = delete; @@ -107,7 +113,8 @@ class StoryManager final : public Actor { void get_story_archive(StoryId from_story_id, int32 limit, Promise> &&promise); - void get_dialog_expiring_stories(DialogId owner_dialog_id, Promise> &&promise); + void get_dialog_expiring_stories(DialogId owner_dialog_id, + Promise> &&promise); void open_story(DialogId owner_dialog_id, StoryId story_id, Promise &&promise); @@ -159,14 +166,20 @@ class StoryManager final : public Actor { void on_story_changed(StoryFullId story_full_id, const Story *story, bool is_changed, bool need_save_to_database); + td_api::object_ptr get_story_info_object(StoryFullId story_full_id) const; + + td_api::object_ptr get_story_info_object(StoryFullId story_full_id, const Story *story) const; + td_api::object_ptr get_story_object(StoryFullId story_full_id, const Story *story) const; + td_api::object_ptr get_active_stories_object(const ActiveStories &active_stories) const; + StoryId on_get_story(DialogId owner_dialog_id, telegram_api::object_ptr &&story_item); void on_delete_story(DialogId owner_dialog_id, StoryId story_id); - vector on_get_stories(DialogId owner_dialog_id, - vector> &&stories); + ActiveStories on_get_user_stories(DialogId owner_dialog_id, + telegram_api::object_ptr &&user_stories); void on_get_dialog_pinned_stories(DialogId owner_dialog_id, telegram_api::object_ptr &&stories, @@ -177,7 +190,7 @@ class StoryManager final : public Actor { void on_get_dialog_expiring_stories(DialogId owner_dialog_id, telegram_api::object_ptr &&stories, - Promise> &&promise); + Promise> &&promise); vector get_story_file_ids(const Story *story) const;