diff --git a/td/generate/scheme/td_api.tl b/td/generate/scheme/td_api.tl index 288dff8f1..d5017dfef 100644 --- a/td/generate/scheme/td_api.tl +++ b/td/generate/scheme/td_api.tl @@ -801,6 +801,12 @@ messages total_count:int32 messages:vector = Messages; //@description Contains a list of messages found by a search @total_count Approximate total count of messages found; -1 if unknown @messages List of messages @next_offset The offset for the next request. If empty, there are no more results foundMessages total_count:int32 messages:vector next_offset:string = FoundMessages; +//@description Contains information about a message in a specific position @position 1-based message position in the full list of suitable messages @message_id Message identifier @date Point in time (Unix timestamp) when the message was sent +messagePosition position:int32 message_id:int53 date:int32 = MessagePosition; + +//@description Contains a list of message positions @total_count Total count of messages found @positions List of message positions +messagePositions total_count:int32 positions:vector = MessagePositions; + //@description Describes a sponsored message @id Unique sponsored message identifier @sponsor_chat_id Chat identifier //@link An internal link to be opened when the sponsored message is clicked; may be null. If null, the sponsor chat needs to be opened instead @content Content of the message @@ -4271,6 +4277,13 @@ getActiveLiveLocationMessages = Messages; //@description Returns the last message sent in a chat no later than the specified date @chat_id Chat identifier @date Point in time (Unix timestamp) relative to which to search for messages getChatMessageByDate chat_id:int53 date:int32 = Message; +//@description Returns sparse positions of messages of the specified type in the chat to be used for shared media scroll implementation. Returns the results in reverse chronological order (i.e., in order of decreasing message_id) +//@chat_id Identifier of the chat in which to return information about message positions +//@filter Filter for message content. Filters searchMessagesFilterEmpty, searchMessagesFilterCall, searchMessagesFilterMissedCall, searchMessagesFilterMention, searchMessagesFilterUnreadMention and searchMessagesFilterFailedToSend are unsupported in this function +//@from_message_id The message identifier from which to return information about message positions +//@limit The expected number of message positions to be returned. A smaller number of positions can be returned, if there are not enough appropriate messages +getChatSparseMessagePositions chat_id:int53 filter:SearchMessagesFilter from_message_id:int53 limit:int32 = MessagePositions; + //@description Returns approximate number of messages of the specified type in the chat @chat_id Identifier of the chat in which to count messages @filter Filter for message content; searchMessagesFilterEmpty is unsupported in this function @return_local If true, returns count that is available locally without sending network requests, returning -1 if the number of messages is unknown getChatMessageCount chat_id:int53 filter:SearchMessagesFilter return_local:Bool = Count; diff --git a/td/telegram/MessagesManager.cpp b/td/telegram/MessagesManager.cpp index 6e5797e85..bfd93b4be 100644 --- a/td/telegram/MessagesManager.cpp +++ b/td/telegram/MessagesManager.cpp @@ -2272,6 +2272,45 @@ class SearchMessagesQuery final : public Td::ResultHandler { } }; +class GetSearchResultPositionsQuery final : public Td::ResultHandler { + Promise> promise_; + DialogId dialog_id_; + MessageSearchFilter filter_; + + public: + explicit GetSearchResultPositionsQuery(Promise> &&promise) + : promise_(std::move(promise)) { + } + + void send(DialogId dialog_id, MessageSearchFilter filter, MessageId from_message_id, int32 limit) { + auto input_peer = td->messages_manager_->get_input_peer(dialog_id, AccessRights::Read); + if (input_peer == nullptr) { + return promise_.set_error(Status::Error(400, "Can't access the chat")); + } + dialog_id_ = dialog_id; + filter_ = filter; + + send_query(G()->net_query_creator().create( + telegram_api::messages_getSearchResultsPositions(std::move(input_peer), get_input_messages_filter(filter), + from_message_id.get_server_message_id().get(), limit))); + } + + void on_result(uint64 id, BufferSlice packet) final { + auto result_ptr = fetch_result(packet); + if (result_ptr.is_error()) { + return on_error(id, result_ptr.move_as_error()); + } + + td->messages_manager_->on_get_dialog_sparse_message_positions(dialog_id_, filter_, result_ptr.move_as_ok(), + std::move(promise_)); + } + + void on_error(uint64 id, Status status) final { + td->messages_manager_->on_get_dialog_error(dialog_id_, status, "GetSearchResultPositionsQuery"); + promise_.set_error(std::move(status)); + } +}; + class GetSearchCountersQuery final : public Td::ResultHandler { Promise promise_; DialogId dialog_id_; @@ -22215,6 +22254,61 @@ tl_object_ptr MessagesManager::get_dialog_message_by_date_objec return get_message_object(full_message_id, "get_dialog_message_by_date_object"); } +void MessagesManager::get_dialog_sparse_message_positions( + DialogId dialog_id, MessageSearchFilter filter, MessageId from_message_id, int32 limit, + Promise> &&promise) { + const Dialog *d = get_dialog_force(dialog_id, "get_dialog_sparse_message_positions"); + if (d == nullptr) { + return promise.set_error(Status::Error(400, "Chat not found")); + } + + if (filter == MessageSearchFilter::Empty || filter == MessageSearchFilter::Call || + filter == MessageSearchFilter::MissedCall || filter == MessageSearchFilter::Mention || + filter == MessageSearchFilter::UnreadMention || filter == MessageSearchFilter::FailedToSend || + filter == MessageSearchFilter::Pinned) { + return promise.set_error(Status::Error(400, "The filter is not supported")); + } + + if (from_message_id.is_scheduled()) { + return promise.set_error(Status::Error(400, "Invalid from_message_id specified")); + } + if (!from_message_id.is_valid() || from_message_id > d->last_new_message_id) { + if (d->last_new_message_id.is_valid()) { + from_message_id = d->last_new_message_id.get_next_message_id(MessageType::Server); + } else { + from_message_id = MessageId::max(); + } + } else { + from_message_id = from_message_id.get_next_server_message_id(); + } + + switch (dialog_id.get_type()) { + case DialogType::User: + case DialogType::Chat: + case DialogType::Channel: + td_->create_handler(std::move(promise)) + ->send(dialog_id, filter, from_message_id, limit); + break; + case DialogType::SecretChat: + return promise.set_error(Status::Error(400, "Secret chats aren't supported")); + case DialogType::None: + default: + UNREACHABLE(); + } +} + +void MessagesManager::on_get_dialog_sparse_message_positions( + DialogId dialog_id, MessageSearchFilter filter, + telegram_api::object_ptr positions, + Promise> &&promise) { + auto message_positions = transform( + positions->positions_, [](const telegram_api::object_ptr &position) { + return td_api::make_object( + position->offset_, MessageId(ServerMessageId(position->msg_id_)).get(), position->date_); + }); + promise.set_value(td_api::make_object(positions->count_, std::move(message_positions))); +} + void MessagesManager::get_dialog_message_count(DialogId dialog_id, MessageSearchFilter filter, bool return_local, Promise &&promise) { LOG(INFO) << "Get " << (return_local ? "local " : "") << "number of messages in " << dialog_id << " filtered by " @@ -22241,7 +22335,7 @@ void MessagesManager::get_dialog_message_count(DialogId dialog_id, MessageSearch LOG(INFO) << "Get number of messages in " << dialog_id << " filtered by " << filter << " from the server"; - switch (dialog_id.get_type()) { + switch (dialog_type) { case DialogType::User: case DialogType::Chat: case DialogType::Channel: diff --git a/td/telegram/MessagesManager.h b/td/telegram/MessagesManager.h index 56c5074f9..3a424370f 100644 --- a/td/telegram/MessagesManager.h +++ b/td/telegram/MessagesManager.h @@ -733,6 +733,15 @@ class MessagesManager final : public Actor { void on_get_dialog_message_by_date_fail(int64 random_id); + void get_dialog_sparse_message_positions(DialogId dialog_id, MessageSearchFilter filter, MessageId from_message_id, + int32 limit, + Promise> &&promise); + + void on_get_dialog_sparse_message_positions( + DialogId dialog_id, MessageSearchFilter filter, + telegram_api::object_ptr positions, + Promise> &&promise); + void get_dialog_message_count(DialogId dialog_id, MessageSearchFilter filter, bool return_local, Promise &&promise); diff --git a/td/telegram/Td.cpp b/td/telegram/Td.cpp index 1d76b82ce..c833a7352 100644 --- a/td/telegram/Td.cpp +++ b/td/telegram/Td.cpp @@ -5376,7 +5376,15 @@ void Td::on_request(uint64 id, const td_api::getChatMessageByDate &request) { CREATE_REQUEST(GetChatMessageByDateRequest, request.chat_id_, request.date_); } -void Td::on_request(uint64 id, td_api::getChatMessageCount &request) { +void Td::on_request(uint64 id, const td_api::getChatSparseMessagePositions &request) { + CHECK_IS_USER(); + CREATE_REQUEST_PROMISE(); + messages_manager_->get_dialog_sparse_message_positions( + DialogId(request.chat_id_), get_message_search_filter(request.filter_), MessageId(request.from_message_id_), + request.limit_, std::move(promise)); +} + +void Td::on_request(uint64 id, const td_api::getChatMessageCount &request) { CHECK_IS_USER(); CREATE_REQUEST_PROMISE(); auto query_promise = PromiseCreator::lambda([promise = std::move(promise)](Result result) mutable { diff --git a/td/telegram/Td.h b/td/telegram/Td.h index 63896f421..324eeb955 100644 --- a/td/telegram/Td.h +++ b/td/telegram/Td.h @@ -628,7 +628,9 @@ class Td final : public Actor { void on_request(uint64 id, const td_api::getChatMessageByDate &request); - void on_request(uint64 id, td_api::getChatMessageCount &request); + void on_request(uint64 id, const td_api::getChatSparseMessagePositions &request); + + void on_request(uint64 id, const td_api::getChatMessageCount &request); void on_request(uint64 id, const td_api::getChatScheduledMessages &request); diff --git a/td/telegram/cli.cpp b/td/telegram/cli.cpp index f15f984a4..2e046d3fc 100644 --- a/td/telegram/cli.cpp +++ b/td/telegram/cli.cpp @@ -2105,6 +2105,19 @@ class CliClient final : public Actor { send_request(td_api::make_object(as_chat_id(chat_id), query.query, nullptr, as_message_id(offset_message_id), 0, query.limit, as_search_messages_filter(op), 0)); + } else if (op == "gcmbd") { + string chat_id; + int32 date; + get_args(args, chat_id, date); + send_request(td_api::make_object(as_chat_id(chat_id), date)); + } else if (op == "gcsmp") { + string chat_id; + string filter; + string from_message_id; + string limit; + get_args(args, chat_id, filter, from_message_id, limit); + send_request(td_api::make_object( + as_chat_id(chat_id), as_search_messages_filter(filter), as_message_id(from_message_id), as_limit(limit))); } else if (op == "gcmc") { string chat_id; string filter; @@ -2640,11 +2653,6 @@ class CliClient final : public Actor { for_album)); } else if (op == "gmli") { send_request(td_api::make_object(args)); - } else if (op == "gcmbd") { - string chat_id; - int32 date; - get_args(args, chat_id, date); - send_request(td_api::make_object(as_chat_id(chat_id), date)); } else if (op == "gf" || op == "GetFile") { send_request(td_api::make_object(as_file_id(args))); } else if (op == "gfdps") {