Add td_api::getMessageThreadHistory.

GitOrigin-RevId: c5aaa396b1fcdd6704302296e407989ff19be0a0
This commit is contained in:
levlam 2020-09-30 04:26:39 +03:00
parent b2c52ede12
commit b751acc3ae
8 changed files with 267 additions and 3 deletions

View File

@ -156,6 +156,7 @@ function split_file($file, $chunks, $undo) {
'(?<name>[A-Z][A-Za-z]*) : public (Td::ResultHandler|NetActor|Request)|'.
'(CREATE_REQUEST|CREATE_NO_ARGS_REQUEST)[(](?<name>[A-Z][A-Za-z]*)|'.
'(?<name>complete_pending_preauthentication_requests)|'.
'(?<name>get_message_history_slice)|'.
'(Up|Down)load[a-zA-Z]*C(?<name>allback)|(up|down)load_[a-z_]*_c(?<name>allback)_|'.
'(?<name>lazy_to_json)|'.
'(?<name>LogEvent)[^sA]|'.

View File

@ -3624,10 +3624,19 @@ getGroupsInCommon user_id:int32 offset_chat_id:int53 limit:int32 = Chats;
//@chat_id Chat identifier
//@from_message_id Identifier of the message starting from which history must be fetched; use 0 to get results from the last message
//@offset Specify 0 to get results from exactly the from_message_id or a negative offset up to 99 to get additionally some newer messages
//@limit The maximum number of messages to be returned; must be positive and can't be greater than 100. If the offset is negative, the limit must be greater or equal to -offset. 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; must be positive and can't be greater than 100. If the offset is negative, the limit must be greater than or equal to -offset. Fewer messages may be returned than specified by the limit, even if the end of the message history has not been reached
//@only_local If true, returns only messages that are available locally without sending network requests
getChatHistory chat_id:int53 from_message_id:int53 offset:int32 limit:int32 only_local:Bool = Messages;
//@description Returns messages in a message thread of a message. Can be used only if message.can_get_message_thread == true. Message thread of a channel message is in the channel's linked supergroup.
//-The messages are returned in a reverse chronological order (i.e., in order of decreasing message_id). For optimal performance the number of returned messages is chosen by the library
//@chat_id Chat identifier
//@message_id Message identifier, which thread history needs to be returned
//@from_message_id Identifier of the message starting from which history must be fetched; use 0 to get results from the last message
//@offset Specify 0 to get results from exactly the from_message_id or a negative offset up to 99 to get additionally some newer messages
//@limit The maximum number of messages to be returned; must be positive and can't be greater than 100. If the offset is negative, the limit must be greater than or equal to -offset. Fewer messages may be returned than specified by the limit, even if the end of the message thread history has not been reached
getMessageThreadHistory chat_id:int53 message_id:int53 from_message_id:int53 offset:int32 limit:int32 = Messages;
//@description Deletes all messages in the chat. Use Chat.can_be_deleted_only_for_self and Chat.can_be_deleted_for_all_users fields to find whether and how the method can be applied to the chat
//@chat_id Chat identifier @remove_from_chat_list Pass true if the chat should be removed from the chat list @revoke Pass true to try to delete chat history for all users
deleteChatHistory chat_id:int53 remove_from_chat_list:Bool revoke:Bool = Ok;

Binary file not shown.

View File

@ -19330,7 +19330,7 @@ tl_object_ptr<td_api::messages> MessagesManager::get_dialog_history(DialogId dia
return nullptr;
}
if (offset < -limit) {
promise.set_error(Status::Error(5, "Parameter offset must not be less than -limit"));
promise.set_error(Status::Error(5, "Parameter offset must be greater than or equal to -limit"));
return nullptr;
}
bool is_limit_increased = false;
@ -19728,6 +19728,202 @@ void MessagesManager::on_read_history_finished(DialogId dialog_id, MessageId top
}
}
template <class T, class It>
vector<MessageId> MessagesManager::get_message_history_slice(const T &begin, It it, const T &end,
MessageId from_message_id, int32 offset, int32 limit) {
int32 left_offset = -offset;
int32 left_limit = limit + offset;
while (left_offset > 0 && it != end) {
++it;
left_offset--;
left_limit++;
}
vector<MessageId> message_ids;
while (left_limit > 0 && it != begin) {
--it;
left_limit--;
message_ids.push_back(*it);
}
return message_ids;
}
std::pair<DialogId, vector<MessageId>> MessagesManager::get_message_thread_history(
DialogId dialog_id, MessageId message_id, MessageId from_message_id, int32 offset, int32 limit, int64 &random_id,
Promise<Unit> &&promise) {
if (limit <= 0) {
promise.set_error(Status::Error(3, "Parameter limit must be positive"));
return {};
}
if (limit > MAX_GET_HISTORY) {
limit = MAX_GET_HISTORY;
}
if (offset > 0) {
promise.set_error(Status::Error(5, "Parameter offset must be non-positive"));
return {};
}
if (offset <= -MAX_GET_HISTORY) {
promise.set_error(Status::Error(5, "Parameter offset must be greater than -100"));
return {};
}
if (offset < -limit) {
promise.set_error(Status::Error(5, "Parameter offset must be greater than or equal to -limit"));
return {};
}
bool is_limit_increased = false;
if (limit == -offset) {
limit++;
is_limit_increased = true;
}
CHECK(0 < limit && limit <= MAX_GET_HISTORY);
CHECK(-limit < offset && offset <= 0);
Dialog *d = get_dialog_force(dialog_id);
if (d == nullptr) {
promise.set_error(Status::Error(6, "Chat not found"));
return {};
}
if (!have_input_peer(dialog_id, AccessRights::Read)) {
promise.set_error(Status::Error(5, "Can't access the chat"));
return {};
}
if (dialog_id.get_type() != DialogType::Channel) {
promise.set_error(Status::Error(400, "Can't get message thread history in the chat"));
return {};
}
if (from_message_id == MessageId() || from_message_id.get() > MessageId::max().get()) {
from_message_id = MessageId::max();
}
if (!from_message_id.is_valid()) {
promise.set_error(Status::Error(3, "Parameter from_message_id must be identifier of the chat message or 0"));
return {};
}
DialogId message_thread_dialog_id;
MessageId top_thread_message_id;
{
Message *m = get_message_force(d, message_id, "get_message_thread_history 1");
if (m == nullptr) {
promise.set_error(Status::Error(400, "Message not found"));
return {};
}
if (m->reply_info.is_comment) {
if (!is_active_message_reply_info(dialog_id, m->reply_info)) {
promise.set_error(Status::Error(400, "Message has no comments"));
return {};
}
if (!m->linked_top_thread_message_id.is_valid()) {
get_message_thread(
dialog_id, message_id,
PromiseCreator::lambda([promise = std::move(promise)](Result<MessageThreadInfo> &&result) mutable {
if (result.is_error()) {
promise.set_error(result.move_as_error());
} else {
promise.set_value(Unit());
}
}));
return {};
}
message_thread_dialog_id = DialogId(m->reply_info.channel_id);
top_thread_message_id = m->linked_top_thread_message_id;
} else {
if (!m->top_thread_message_id.is_valid()) {
promise.set_error(Status::Error(400, "Message has no thread"));
return {};
}
message_thread_dialog_id = dialog_id;
top_thread_message_id = m->top_thread_message_id;
}
}
CHECK(top_thread_message_id.is_valid());
if (random_id != 0) {
// request has already been sent before
auto it = found_dialog_messages_.find(random_id);
CHECK(it != found_dialog_messages_.end());
auto result = std::move(it->second.second);
found_dialog_messages_.erase(it);
auto dialog_id_it = found_dialog_messages_dialog_id_.find(random_id);
if (dialog_id_it != found_dialog_messages_dialog_id_.end()) {
dialog_id = dialog_id_it->second;
found_dialog_messages_dialog_id_.erase(dialog_id_it);
d = get_dialog(dialog_id);
CHECK(d != nullptr);
}
if (dialog_id != message_thread_dialog_id) {
promise.set_error(Status::Error(500, "Receive messages in an unexpected chat"));
return {};
}
auto yet_unsent_it = d->yet_unsent_thread_message_ids.find(top_thread_message_id);
if (yet_unsent_it != d->yet_unsent_thread_message_ids.end()) {
const std::set<MessageId> &message_ids = yet_unsent_it->second;
auto merge_message_ids = get_message_history_slice(message_ids.begin(), message_ids.lower_bound(from_message_id),
message_ids.end(), from_message_id, offset, limit);
vector<MessageId> new_result(result.size() + merge_message_ids.size());
std::merge(result.begin(), result.end(), merge_message_ids.begin(), merge_message_ids.end(), new_result.begin(),
std::greater<>());
result = std::move(new_result);
}
Message *top_m = get_message_force(d, top_thread_message_id, "get_message_thread_history 2");
if (top_m != nullptr && !top_m->local_thread_message_ids.empty()) {
vector<MessageId> &message_ids = top_m->local_thread_message_ids;
vector<MessageId> merge_message_ids;
while (true) {
merge_message_ids = get_message_history_slice(
message_ids.begin(), std::lower_bound(message_ids.begin(), message_ids.end(), from_message_id),
message_ids.end(), from_message_id, offset, limit);
bool found_deleted = false;
for (auto local_message_id : merge_message_ids) {
Message *local_m = get_message_force(d, local_message_id, "get_message_thread_history 3");
if (local_m == nullptr) {
auto local_it = std::lower_bound(message_ids.begin(), message_ids.end(), local_message_id);
CHECK(local_it != message_ids.end() && *local_it == local_message_id);
message_ids.erase(local_it);
found_deleted = true;
}
}
if (!found_deleted) {
break;
}
on_message_changed(d, top_m, false, "get_message_thread_history");
}
vector<MessageId> new_result(result.size() + merge_message_ids.size());
std::merge(result.begin(), result.end(), merge_message_ids.begin(), merge_message_ids.end(), new_result.begin(),
std::greater<>());
result = std::move(new_result);
}
if (is_limit_increased) {
limit--;
}
std::reverse(result.begin(), result.end());
result = get_message_history_slice(result.begin(), std::lower_bound(result.begin(), result.end(), from_message_id),
result.end(), from_message_id, offset, limit);
LOG(INFO) << "Return " << result.size() << " messages in result to getMessageThreadHistory";
promise.set_value(Unit());
return {dialog_id, std::move(result)};
}
do {
random_id = Random::secure_int64();
} while (random_id == 0 || found_dialog_messages_.find(random_id) != found_dialog_messages_.end());
found_dialog_messages_[random_id]; // reserve place for result
td_->create_handler<SearchMessagesQuery>(std::move(promise))
->send(dialog_id, string(), UserId(), nullptr, from_message_id.get_next_server_message_id(), offset, limit,
MessageSearchFilter::Empty, message_id, random_id);
return {};
}
std::pair<int32, vector<MessageId>> MessagesManager::search_dialog_messages(
DialogId dialog_id, const string &query, UserId sender_user_id, MessageId from_message_id, int32 offset,
int32 limit, MessageSearchFilter filter, MessageId top_thread_message_id, int64 &random_id, bool use_db,

View File

@ -701,6 +701,11 @@ class MessagesManager : public Actor {
int32 limit, int left_tries, bool only_local,
Promise<Unit> &&promise);
std::pair<DialogId, vector<MessageId>> get_message_thread_history(DialogId dialog_id, MessageId message_id,
MessageId from_message_id, int32 offset,
int32 limit, int64 &random_id,
Promise<Unit> &&promise);
std::pair<int32, vector<MessageId>> search_dialog_messages(DialogId dialog_id, const string &query,
UserId sender_user_id, MessageId from_message_id,
int32 offset, int32 limit, MessageSearchFilter filter,
@ -1987,6 +1992,10 @@ class MessagesManager : public Actor {
void on_update_dialog_online_member_count_timeout(DialogId dialog_id);
template <class T, class It>
vector<MessageId> get_message_history_slice(const T &begin, It it, const T &end, MessageId from_message_id,
int32 offset, int32 limit);
void preload_newer_messages(const Dialog *d, MessageId max_message_id);
void preload_older_messages(const Dialog *d, MessageId min_message_id);

View File

@ -1398,6 +1398,39 @@ class GetChatHistoryRequest : public RequestActor<> {
}
};
class GetMessageThreadHistoryRequest : public RequestActor<> {
DialogId dialog_id_;
MessageId message_id_;
MessageId from_message_id_;
int32 offset_;
int32 limit_;
int64 random_id_;
std::pair<DialogId, vector<MessageId>> messages_;
void do_run(Promise<Unit> &&promise) override {
messages_ = td->messages_manager_->get_message_thread_history(dialog_id_, message_id_, from_message_id_, offset_,
limit_, random_id_, std::move(promise));
}
void do_send_result() override {
send_result(td->messages_manager_->get_messages_object(-1, messages_.first, messages_.second));
}
public:
GetMessageThreadHistoryRequest(ActorShared<Td> td, uint64 request_id, int64 dialog_id, int64 message_id,
int64 from_message_id, int32 offset, int32 limit)
: RequestActor(std::move(td), request_id)
, dialog_id_(dialog_id)
, message_id_(message_id)
, from_message_id_(from_message_id)
, offset_(offset)
, limit_(limit)
, random_id_(0) {
set_tries(3);
}
};
class SearchChatMessagesRequest : public RequestActor<> {
DialogId dialog_id_;
string query_;
@ -5488,6 +5521,12 @@ void Td::on_request(uint64 id, const td_api::deleteChatHistory &request) {
std::move(promise));
}
void Td::on_request(uint64 id, const td_api::getMessageThreadHistory &request) {
CHECK_IS_USER();
CREATE_REQUEST(GetMessageThreadHistoryRequest, request.chat_id_, request.message_id_, request.from_message_id_,
request.offset_, request.limit_);
}
void Td::on_request(uint64 id, td_api::searchChatMessages &request) {
CHECK_IS_USER();
CLEAN_INPUT_STRING(request.query_);

View File

@ -572,6 +572,8 @@ class Td final : public NetQueryCallback {
void on_request(uint64 id, const td_api::deleteChatHistory &request);
void on_request(uint64 id, const td_api::getMessageThreadHistory &request);
void on_request(uint64 id, td_api::searchChatMessages &request);
void on_request(uint64 id, td_api::searchSecretMessages &request);

View File

@ -1816,13 +1816,17 @@ class CliClient final : public Actor {
}
send_request(td_api::make_object<td_api::getGroupsInCommon>(as_user_id(user_id), as_chat_id(offset_chat_id),
to_integer<int32>(limit)));
} else if (op == "gh" || op == "GetHistory" || op == "ghl") {
} else if (op == "gh" || op == "GetHistory" || op == "ghl" || op == "gmth") {
string chat_id;
string thread_message_id;
string from_message_id;
string offset;
string limit;
std::tie(chat_id, args) = split(args);
if (op == "gmth") {
std::tie(thread_message_id, args) = split(args);
}
std::tie(from_message_id, args) = split(args);
if (from_message_id.empty()) {
from_message_id = "0";
@ -1837,6 +1841,10 @@ class CliClient final : public Actor {
}
if (!args.empty()) {
LOG(ERROR) << "Wrong parameters to function getChatHistory specified";
} else if (op == "gmth") {
send_request(td_api::make_object<td_api::getMessageThreadHistory>(
as_chat_id(chat_id), as_message_id(thread_message_id), as_message_id(from_message_id),
to_integer<int32>(offset), to_integer<int32>(limit)));
} else {
send_request(td_api::make_object<td_api::getChatHistory>(as_chat_id(chat_id), as_message_id(from_message_id),
to_integer<int32>(offset), to_integer<int32>(limit),