diff --git a/td/generate/scheme/td_api.tl b/td/generate/scheme/td_api.tl index a6fd0d4da..73d6ec1c4 100644 --- a/td/generate/scheme/td_api.tl +++ b/td/generate/scheme/td_api.tl @@ -7409,7 +7409,7 @@ readChatList chat_list:ChatList = Ok; //@only_local Pass true to get only locally available information without sending network requests getStory story_sender_chat_id:int53 story_id:int32 only_local:Bool = Story; -//@description Sends a new story. Returns a temporary story with identifier 0 +//@description Sends a new story. Returns a temporary story //@content Content of the story //@areas Clickable rectangle areas to be shown on the story media; pass null if none //@caption Story caption; pass null to use an empty caption; 0-getOption("story_caption_length_max") characters diff --git a/td/telegram/StoryId.h b/td/telegram/StoryId.h index c9555459a..ceeacbd39 100644 --- a/td/telegram/StoryId.h +++ b/td/telegram/StoryId.h @@ -19,6 +19,8 @@ class StoryId { int32 id = 0; public: + static constexpr int32 MAX_SERVER_STORY_ID = 1999999999; + StoryId() = default; explicit constexpr StoryId(int32 story_id) : id(story_id) { @@ -48,11 +50,11 @@ class StoryId { } bool is_valid() const { - return id != 0; + return id > 0; } bool is_server() const { - return id > 0; + return id > 0 && id <= MAX_SERVER_STORY_ID; } template diff --git a/td/telegram/StoryManager.cpp b/td/telegram/StoryManager.cpp index 9358cee8f..caa6c3ca0 100644 --- a/td/telegram/StoryManager.cpp +++ b/td/telegram/StoryManager.cpp @@ -2729,6 +2729,17 @@ StoryId StoryManager::on_get_new_story(DialogId owner_dialog_id, update_story_ids_.erase(updates_story_ids_it); LOG(INFO) << "Receive sent " << old_story_id << " as " << story_full_id; + + auto old_story_full_id = StoryFullId(owner_dialog_id, old_story_id); + const Story *old_story = get_story_force(old_story_full_id, "on_get_new_story"); + if (old_story != nullptr) { + send_closure( + G()->td(), &Td::send_update, + td_api::make_object( + td_->messages_manager_->get_chat_id_object(owner_dialog_id, "updateStoryDeleted"), old_story_id.get())); + delete_story_files(old_story); + stories_.erase(old_story_full_id); + } } bool is_bot = td_->auth_manager_->is_bot(); @@ -3746,6 +3757,16 @@ void StoryManager::do_get_story(StoryFullId story_full_id, Result &&result promise.set_value(get_story_object(story_full_id, story)); } +Result StoryManager::get_next_yet_unsent_story_id(DialogId dialog_id) { + auto &story_id = current_yet_unsent_story_ids_[dialog_id]; + if (story_id == 0) { + story_id = StoryId::MAX_SERVER_STORY_ID; + } else if (story_id == std::numeric_limits::max()) { + return Status::Error(400, "Tried to send too many stories above daily limit"); + } + return StoryId(++story_id); +} + void StoryManager::send_story(td_api::object_ptr &&input_story_content, td_api::object_ptr &&input_areas, td_api::object_ptr &&input_caption, @@ -3765,6 +3786,7 @@ void StoryManager::send_story(td_api::object_ptr &&in return promise.set_error(Status::Error(400, "Invalid story active period specified")); } } + TRY_RESULT_PROMISE(promise, story_id, get_next_yet_unsent_story_id(dialog_id)); vector areas; if (input_areas != nullptr) { for (auto &input_area : input_areas->areas_) { @@ -3795,12 +3817,12 @@ void StoryManager::send_story(td_api::object_ptr &&in auto story_ptr = story.get(); auto pending_story = - td::make_unique(dialog_id, StoryId(), ++send_story_count_, random_id, std::move(story)); + td::make_unique(dialog_id, story_id, ++send_story_count_, random_id, std::move(story)); pending_story->log_event_id_ = save_send_story_log_event(pending_story.get()); do_send_story(std::move(pending_story), {}); - promise.set_value(get_story_object({dialog_id, StoryId()}, story_ptr)); + promise.set_value(get_story_object({dialog_id, story_id}, story_ptr)); } class StoryManager::SendStoryLogEvent { @@ -3836,15 +3858,30 @@ int64 StoryManager::save_send_story_log_event(const PendingStory *pending_story) void StoryManager::do_send_story(unique_ptr &&pending_story, vector bad_parts) { CHECK(pending_story != nullptr); + CHECK(pending_story->story_id_.is_valid()); CHECK(pending_story->story_ != nullptr); CHECK(pending_story->story_->content_ != nullptr); if (bad_parts.empty()) { - pending_story->story_->content_ = dup_story_content(td_, pending_story->story_->content_.get()); - if (!pending_story->story_id_.is_server()) { + auto story_full_id = StoryFullId(pending_story->dialog_id_, pending_story->story_id_); + auto story = make_unique(); + story->date_ = pending_story->story_->date_; + story->expire_date_ = pending_story->story_->expire_date_; + story->is_pinned_ = pending_story->story_->is_pinned_; + story->noforwards_ = pending_story->story_->noforwards_; + story->privacy_rules_ = pending_story->story_->privacy_rules_; + story->content_ = std::move(pending_story->story_->content_); + pending_story->story_->content_ = dup_story_content(td_, story->content_.get()); + story->areas_ = pending_story->story_->areas_; + story->caption_ = pending_story->story_->caption_; + send_update_story(story_full_id, story.get()); + stories_.set(story_full_id, std::move(story)); + yet_unsent_stories_[pending_story->dialog_id_].insert(pending_story->send_story_num_); - being_sent_stories_[pending_story->random_id_] = StoryFullId(pending_story->dialog_id_, pending_story->story_id_); + being_sent_stories_[pending_story->random_id_] = story_full_id; + } else { + pending_story->story_->content_ = dup_story_content(td_, pending_story->story_->content_.get()); } } @@ -4428,6 +4465,7 @@ void StoryManager::on_binlog_events(vector &&events) { ++send_story_count_; CHECK(!pending_story->story_id_.is_server()); + pending_story->story_id_ = get_next_yet_unsent_story_id(pending_story->dialog_id_).move_as_ok(); pending_story->send_story_num_ = send_story_count_; do_send_story(std::move(pending_story), {}); break; diff --git a/td/telegram/StoryManager.h b/td/telegram/StoryManager.h index a913a07df..5601df33a 100644 --- a/td/telegram/StoryManager.h +++ b/td/telegram/StoryManager.h @@ -472,6 +472,8 @@ class StoryManager final : public Actor { void delete_pending_story(FileId file_id, unique_ptr &&pending_story, Status status); + Result get_next_yet_unsent_story_id(DialogId dialog_id); + void do_send_story(unique_ptr &&pending_story, vector bad_parts); void on_upload_story(FileId file_id, telegram_api::object_ptr input_file); @@ -599,6 +601,8 @@ class StoryManager final : public Actor { int64 max_story_global_id_ = 0; + FlatHashMap current_yet_unsent_story_ids_; + bool has_active_synchronize_archive_all_stories_query_ = false; Timeout stealth_mode_update_timeout_;