From f9c0ddae062b629a0f32abc3850bce33fd2bcd7f Mon Sep 17 00:00:00 2001 From: levlam Date: Fri, 21 Aug 2020 14:47:43 +0300 Subject: [PATCH] Add getMessagePublicForwards method. GitOrigin-RevId: a0b16c241bcf3276c245423f7fff3f41751883b6 --- td/generate/scheme/td_api.tl | 14 ++- td/generate/scheme/td_api.tlo | Bin 179480 -> 179680 bytes td/telegram/MessagesManager.cpp | 185 +++++++++++++++++++++++++++++++- td/telegram/MessagesManager.h | 24 ++++- td/telegram/Td.cpp | 54 +++++++--- td/telegram/Td.h | 2 + td/telegram/cli.cpp | 12 +++ 7 files changed, 266 insertions(+), 25 deletions(-) diff --git a/td/generate/scheme/td_api.tl b/td/generate/scheme/td_api.tl index ea0458d96..0b1d48f3f 100644 --- a/td/generate/scheme/td_api.tl +++ b/td/generate/scheme/td_api.tl @@ -3590,12 +3590,13 @@ searchChatMessages chat_id:int53 query:string sender_user_id:int32 from_message_ //@offset_date The date of the message starting from which the results should be fetched. Use 0 or any date in the future to get results from the last message //@offset_chat_id The chat identifier of the last found message, or 0 for the first request //@offset_message_id The message identifier of the last found message, or 0 for the first request -//@limit The maximum number of messages to be returned, up to 100. Fewer messages may be returned than specified by the limit, even if the end of the message history has not been reached +//@limit The maximum number of messages to be returned; up to 100. Fewer messages may be returned than specified by the limit, even if the end of the message history has not been reached searchMessages chat_list:ChatList query:string offset_date:int32 offset_chat_id:int53 offset_message_id:int53 limit:int32 = Messages; //@description Searches for messages in secret chats. Returns the results in reverse chronological order. For optimal performance the number of returned messages is chosen by the library -//@chat_id Identifier of the chat in which to search. Specify 0 to search in all secret chats @query Query to search for. If empty, searchChatMessages should be used instead -//@offset Offset of the first entry to return; use empty string to get results from the last message +//@chat_id Identifier of the chat in which to search. Specify 0 to search in all secret chats +//@query Query to search for. If empty, searchChatMessages should be used instead +//@offset Offset of the first entry to return as received from the previous request; use empty string to get first chunk of results //@limit The maximum number of messages to be returned; up to 100. Fewer messages may be returned than specified by the limit, even if the end of the message history has not been reached //@filter A filter for the content of messages in the search results searchSecretMessages chat_id:int53 query:string offset:string limit:int32 filter:SearchMessagesFilter = FoundMessages; @@ -3620,6 +3621,13 @@ getChatMessageCount chat_id:int53 filter:SearchMessagesFilter return_local:Bool //@description Returns all scheduled messages in a chat. The messages are returned in a reverse chronological order (i.e., in order of decreasing message_id) @chat_id Chat identifier getChatScheduledMessages chat_id:int53 = Messages; +//@description Returns forwarded copies of a channel message to another public channels. For optimal performance the number of returned messages is chosen by the library +//@chat_id Chat identifier of the message +//@message_id Message identifier +//@offset Offset of the first entry to return as received from the previous request; use empty string to get first chunk of results +//@limit The maximum number of messages to be returned; must be positive and can't be greater than 100. Fewer messages may be returned than specified by the limit, even if the end of the list has not been reached +getMessagePublicForwards chat_id:int53 message_id:int53 offset:string limit:int32 = FoundMessages; + //@description Removes an active notification from notification list. Needs to be called only if the notification is removed by the current user @notification_group_id Identifier of notification group to which the notification belongs @notification_id Identifier of removed notification removeNotification notification_group_id:int32 notification_id:int32 = Ok; diff --git a/td/generate/scheme/td_api.tlo b/td/generate/scheme/td_api.tlo index 66c70304dfa45d0bd87b09b3333957b13717126c..051116aefffa6866b8541a5ecc8699d234de41b2 100644 GIT binary patch delta 88 zcmV-e0H^<$`U>Ft3V?(Gv;vd?0f4ua0RkgZBuS|TU>Ij*bWLS*b75y?P<3K#X=6rj ua(7{JWOD!j05~Dhp_f3s0Z^ALCjt promise_; + DialogId dialog_id_; + int32 limit_; + int64 random_id_; + + public: + explicit GetMessagePublicForwardsQuery(Promise &&promise) : promise_(std::move(promise)) { + } + + void send(FullMessageId full_message_id, int32 offset_date, DialogId offset_dialog_id, + ServerMessageId offset_message_id, int32 limit, int64 random_id) { + dialog_id_ = full_message_id.get_dialog_id(); + limit_ = limit; + random_id_ = random_id; + + auto input_peer = MessagesManager::get_input_peer_force(offset_dialog_id); + CHECK(input_peer != nullptr); + + send_query(G()->net_query_creator().create(telegram_api::stats_getMessagePublicForwards( + td->contacts_manager_->get_input_channel(dialog_id_.get_channel_id()), + full_message_id.get_message_id().get_server_message_id().get(), offset_date, std::move(input_peer), + offset_message_id.get(), limit))); + } + + void on_result(uint64 id, BufferSlice packet) override { + auto result_ptr = fetch_result(packet); + if (result_ptr.is_error()) { + return on_error(id, result_ptr.move_as_error()); + } + + auto info = td->messages_manager_->on_get_messages(result_ptr.move_as_ok(), "GetMessagePublicForwardsQuery"); + LOG_IF(ERROR, !info.is_channel_messages) << "Receive ordinary messages in GetMessagePublicForwardsQuery"; + td->messages_manager_->on_get_message_public_forwards_result(random_id_, info.total_count, + std::move(info.messages)); + + promise_.set_value(Unit()); + } + + void on_error(uint64 id, Status status) override { + td->messages_manager_->on_get_dialog_error(dialog_id_, status, "GetMessagePublicForwardsQuery"); + td->messages_manager_->on_failed_get_message_public_forwards(random_id_); + promise_.set_error(std::move(status)); + } +}; + class HidePromoDataQuery : public Td::ResultHandler { DialogId dialog_id_; @@ -8838,6 +8884,48 @@ void MessagesManager::on_get_recent_locations_failed(int64 random_id) { found_dialog_recent_location_messages_.erase(it); } +void MessagesManager::on_get_message_public_forwards_result(int64 random_id, int32 total_count, + vector> &&messages) { + LOG(INFO) << "Receive " << messages.size() << " forwarded messages"; + auto it = found_message_public_forwards_.find(random_id); + CHECK(it != found_message_public_forwards_.end()); + + auto &result = it->second.full_message_ids; + CHECK(result.empty()); + FullMessageId last_full_message_id; + for (auto &message : messages) { + auto dialog_id = get_message_dialog_id(message); + auto new_full_message_id = on_get_message(std::move(message), false, dialog_id.get_type() == DialogType::Channel, + false, false, false, "get message public forwards"); + if (new_full_message_id != FullMessageId()) { + CHECK(dialog_id == new_full_message_id.get_dialog_id()); + result.push_back(new_full_message_id); + last_full_message_id = new_full_message_id; + } else { + total_count--; + } + } + if (total_count < static_cast(result.size())) { + LOG(ERROR) << "Receive " << result.size() << " valid messages out of " << total_count << " in " << messages.size() + << " messages"; + total_count = static_cast(result.size()); + } + if (!result.empty()) { + auto m = get_message(last_full_message_id); + CHECK(m != nullptr); + it->second.next_offset = PSTRING() << m->date << "," << last_full_message_id.get_dialog_id().get() << "," + << m->message_id.get_server_message_id().get(); + } + + // it->second.total_count = total_count; +} + +void MessagesManager::on_failed_get_message_public_forwards(int64 random_id) { + auto it = found_message_public_forwards_.find(random_id); + CHECK(it != found_message_public_forwards_.end()); + found_message_public_forwards_.erase(it); +} + void MessagesManager::delete_messages_from_updates(const vector &message_ids) { std::unordered_map, DialogIdHash> deleted_message_ids; std::unordered_map need_update_dialog_pos; @@ -18994,7 +19082,21 @@ void MessagesManager::on_search_dialog_messages_db_result(int64 random_id, Dialo promise.set_value(Unit()); } -std::pair> MessagesManager::offline_search_messages( +td_api::object_ptr MessagesManager::get_found_messages_object( + const FoundMessages &found_messages) { + vector> result; + result.reserve(found_messages.full_message_ids.size()); + for (auto full_message_id : found_messages.full_message_ids) { + auto message = get_message_object(full_message_id); + if (message != nullptr) { + result.push_back(std::move(message)); + } + } + + return td_api::make_object(std::move(result), found_messages.next_offset); +} + +MessagesManager::FoundMessages MessagesManager::offline_search_messages( DialogId dialog_id, const string &query, const string &offset, int32 limit, const tl_object_ptr &filter, int64 &random_id, Promise<> &&promise) { if (!G()->parameters().use_message_db) { @@ -19070,7 +19172,7 @@ void MessagesManager::on_messages_db_fts_result(Result resu auto it = found_fts_messages_.find(random_id); CHECK(it != found_fts_messages_.end()); - auto &res = it->second.second; + auto &res = it->second.full_message_ids; res.reserve(fts_result.messages.size()); for (auto &message : fts_result.messages) { @@ -19081,7 +19183,7 @@ void MessagesManager::on_messages_db_fts_result(Result resu } } - it->second.first = fts_result.next_search_id <= 1 ? string() : to_string(fts_result.next_search_id); + it->second.next_offset = fts_result.next_search_id <= 1 ? string() : to_string(fts_result.next_search_id); promise.set_value(Unit()); } @@ -19930,6 +20032,83 @@ void MessagesManager::on_get_scheduled_messages_from_database(DialogId dialog_id } } +MessagesManager::FoundMessages MessagesManager::get_message_public_forwards(FullMessageId full_message_id, + const string &offset, int32 limit, + int64 &random_id, Promise &&promise) { + if (random_id != 0) { + // request has already been sent before + auto it = found_message_public_forwards_.find(random_id); + CHECK(it != found_message_public_forwards_.end()); + auto result = std::move(it->second); + found_message_public_forwards_.erase(it); + promise.set_value(Unit()); + return result; + } + + auto dialog_id = full_message_id.get_dialog_id(); + Dialog *d = get_dialog_force(dialog_id); + if (d == nullptr) { + promise.set_error(Status::Error(5, "Chat not found")); + return {}; + } + + const Message *m = get_message_force(d, full_message_id.get_message_id(), "get_message_public_forwards"); + if (m == nullptr) { + promise.set_error(Status::Error(5, "Message not found")); + return {}; + } + + if (m->view_count == 0 || m->forward_info != nullptr || m->had_forward_info || m->message_id.is_scheduled() || + !m->message_id.is_server()) { + promise.set_error(Status::Error(5, "Message forwards are inaccessible")); + return {}; + } + + FoundMessages result; + if (limit <= 0) { + promise.set_error(Status::Error(3, "Parameter limit must be positive")); + return {}; + } + if (limit > MAX_SEARCH_MESSAGES) { + limit = MAX_SEARCH_MESSAGES; + } + + int32 offset_date = std::numeric_limits::max(); + DialogId offset_dialog_id; + ServerMessageId offset_message_id; + + if (!offset.empty()) { + auto parts = full_split(offset, ','); + if (parts.size() != 3) { + promise.set_error(Status::Error(3, "Wrong offset specified")); + return {}; + } + auto r_offset_date = to_integer_safe(parts[0]); + auto r_offset_dialog_id = to_integer_safe(parts[1]); + auto r_offset_message_id = to_integer_safe(parts[2]); + if (r_offset_date.is_error() || r_offset_dialog_id.is_error() || r_offset_message_id.is_error()) { + promise.set_error(Status::Error(3, "Wrong offset specified")); + return {}; + } + + offset_date = r_offset_date.ok(); + offset_dialog_id = DialogId(r_offset_dialog_id.ok()); + offset_message_id = ServerMessageId(r_offset_message_id.ok()); + } + + do { + random_id = Random::secure_int64(); + } while (random_id == 0 || found_message_public_forwards_.find(random_id) != found_message_public_forwards_.end()); + found_message_public_forwards_[random_id]; // reserve place for result + + LOG(DEBUG) << "Get public message forwards from date " << offset_date << ", " << offset_dialog_id + << ", server message " << offset_message_id.get() << " and with limit " << limit; + + td_->create_handler(std::move(promise)) + ->send(full_message_id, offset_date, offset_dialog_id, offset_message_id, limit, random_id); + return {}; +} + Result MessagesManager::get_message_schedule_date( td_api::object_ptr &&scheduling_state) { if (scheduling_state == nullptr) { diff --git a/td/telegram/MessagesManager.h b/td/telegram/MessagesManager.h index 52a03bf55..196bd9df0 100644 --- a/td/telegram/MessagesManager.h +++ b/td/telegram/MessagesManager.h @@ -246,6 +246,10 @@ class MessagesManager : public Actor { vector> &&messages); void on_get_recent_locations_failed(int64 random_id); + void on_get_message_public_forwards_result(int64 random_id, int32 total_count, + vector> &&messages); + void on_failed_get_message_public_forwards(int64 random_id); + // if message is from_update, flags have_previous and have_next are ignored and should be both true FullMessageId on_get_message(tl_object_ptr message_ptr, bool from_update, bool is_channel_message, bool is_scheduled, bool have_previous, bool have_next, @@ -653,9 +657,16 @@ class MessagesManager : public Actor { const tl_object_ptr &filter, int64 &random_id, bool use_db, Promise &&promise); - std::pair> offline_search_messages( - DialogId dialog_id, const string &query, const string &offset, int32 limit, - const tl_object_ptr &filter, int64 &random_id, Promise<> &&promise); + struct FoundMessages { + vector full_message_ids; + string next_offset; + }; + + td_api::object_ptr get_found_messages_object(const FoundMessages &found_messages); + + FoundMessages offline_search_messages(DialogId dialog_id, const string &query, const string &offset, int32 limit, + const tl_object_ptr &filter, int64 &random_id, + Promise<> &&promise); std::pair> search_messages(FolderId folder_id, bool ignore_folder_id, const string &query, int32 offset_date, @@ -683,6 +694,9 @@ class MessagesManager : public Actor { vector get_dialog_scheduled_messages(DialogId dialog_id, bool force, bool ignore_result, Promise &&promise); + FoundMessages get_message_public_forwards(FullMessageId full_message_id, const string &offset, int32 limit, + int64 &random_id, Promise &&promise); + tl_object_ptr get_dialog_message_by_date_object(int64 random_id); tl_object_ptr get_message_object(FullMessageId full_message_id); @@ -2931,8 +2945,8 @@ class MessagesManager : public Actor { std::unordered_map>> found_dialog_recent_location_messages_; // random_id -> [total_count, [message_id]...] - std::unordered_map>> - found_fts_messages_; // random_id -> [next_offset, [full_message_id]...] + std::unordered_map found_fts_messages_; // random_id -> FoundMessages + std::unordered_map found_message_public_forwards_; // random_id -> FoundMessages std::unordered_map, FullMessageIdHash> public_message_links_[2]; diff --git a/td/telegram/Td.cpp b/td/telegram/Td.cpp index 730da7a58..f0887f540 100644 --- a/td/telegram/Td.cpp +++ b/td/telegram/Td.cpp @@ -1473,21 +1473,15 @@ class SearchSecretMessagesRequest : public RequestActor<> { tl_object_ptr filter_; int64 random_id_; - std::pair> messages_; + MessagesManager::FoundMessages found_messages_; void do_run(Promise &&promise) override { - messages_ = td->messages_manager_->offline_search_messages(dialog_id_, query_, offset_, limit_, filter_, random_id_, - std::move(promise)); + found_messages_ = td->messages_manager_->offline_search_messages(dialog_id_, query_, offset_, limit_, filter_, + random_id_, std::move(promise)); } void do_send_result() override { - vector> result; - result.reserve(messages_.second.size()); - for (auto full_message_id : messages_.second) { - result.push_back(td->messages_manager_->get_message_object(full_message_id)); - } - - send_result(make_tl_object(std::move(result), std::move(messages_.first))); + send_result(td->messages_manager_->get_found_messages_object(found_messages_)); } public: @@ -1685,6 +1679,34 @@ class GetChatScheduledMessagesRequest : public RequestActor<> { } }; +class GetMessagePublicForwardsRequest : public RequestActor<> { + FullMessageId full_message_id_; + string offset_; + int32 limit_; + int64 random_id_; + + MessagesManager::FoundMessages messages_; + + void do_run(Promise &&promise) override { + messages_ = td->messages_manager_->get_message_public_forwards(full_message_id_, offset_, limit_, random_id_, + std::move(promise)); + } + + void do_send_result() override { + send_result(td->messages_manager_->get_found_messages_object(messages_)); + } + + public: + GetMessagePublicForwardsRequest(ActorShared td, uint64 request_id, int64 dialog_id, int64 message_id, + string offset, int32 limit) + : RequestActor(std::move(td), request_id) + , full_message_id_(DialogId(dialog_id), MessageId(message_id)) + , offset_(std::move(offset)) + , limit_(limit) + , random_id_(0) { + } +}; + class GetWebPagePreviewRequest : public RequestOnceActor { td_api::object_ptr text_; @@ -1875,10 +1897,6 @@ class GetChatMemberRequest : public RequestActor<> { send_result(td->contacts_manager_->get_chat_member_object(dialog_participant_)); } - void do_send_error(Status &&status) override { - send_error(std::move(status)); - } - public: GetChatMemberRequest(ActorShared td, uint64 request_id, int64 dialog_id, int32 user_id) : RequestActor(std::move(td), request_id), dialog_id_(dialog_id), user_id_(user_id), random_id_(0) { @@ -5463,6 +5481,7 @@ void Td::on_request(uint64 id, td_api::searchChatMessages &request) { void Td::on_request(uint64 id, td_api::searchSecretMessages &request) { CHECK_IS_USER(); CLEAN_INPUT_STRING(request.query_); + CLEAN_INPUT_STRING(request.offset_); CREATE_REQUEST(SearchSecretMessagesRequest, request.chat_id_, std::move(request.query_), std::move(request.offset_), request.limit_, std::move(request.filter_)); } @@ -5508,6 +5527,13 @@ void Td::on_request(uint64 id, const td_api::getChatScheduledMessages &request) CREATE_REQUEST(GetChatScheduledMessagesRequest, request.chat_id_); } +void Td::on_request(uint64 id, td_api::getMessagePublicForwards &request) { + CHECK_IS_USER(); + CLEAN_INPUT_STRING(request.offset_); + CREATE_REQUEST(GetMessagePublicForwardsRequest, request.chat_id_, request.message_id_, request.offset_, + request.limit_); +} + void Td::on_request(uint64 id, const td_api::removeNotification &request) { CHECK_IS_USER(); CREATE_OK_REQUEST_PROMISE(); diff --git a/td/telegram/Td.h b/td/telegram/Td.h index f736e1e19..208c02933 100644 --- a/td/telegram/Td.h +++ b/td/telegram/Td.h @@ -585,6 +585,8 @@ class Td final : public NetQueryCallback { void on_request(uint64 id, const td_api::getChatScheduledMessages &request); + void on_request(uint64 id, td_api::getMessagePublicForwards &request); + void on_request(uint64 id, const td_api::removeNotification &request); void on_request(uint64 id, const td_api::removeNotificationGroup &request); diff --git a/td/telegram/cli.cpp b/td/telegram/cli.cpp index 5300c31e0..fc32b541f 100644 --- a/td/telegram/cli.cpp +++ b/td/telegram/cli.cpp @@ -1843,6 +1843,18 @@ class CliClient final : public Actor { } else if (op == "gcsm") { string chat_id = args; send_request(td_api::make_object(as_chat_id(chat_id))); + } else if (op == "gmpf") { + string chat_id; + string message_id; + string offset; + string limit; + + std::tie(chat_id, args) = split(args); + std::tie(message_id, args) = split(args); + std::tie(offset, limit) = split(args); + + send_request(td_api::make_object(as_chat_id(chat_id), as_message_id(message_id), + offset, to_integer(limit))); } else if (op == "ghf") { get_history_chat_id_ = as_chat_id(args);