Support getChatSparseMessagePositions in secret chats when message database enabled.

This commit is contained in:
levlam 2021-11-01 16:30:03 +03:00
parent 5a82af3f7f
commit a3b71ca82c
4 changed files with 113 additions and 10 deletions

View File

@ -813,7 +813,7 @@ messages total_count:int32 messages:vector<message> = 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<message> 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
//@description Contains information about a message in a specific position @position 0-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
@ -4298,11 +4298,12 @@ 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)
//@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).
//-Cannot be used in secret chats or with searchMessagesFilterFailedToSend filter without an enabled message database
//@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
//@filter Filter for message content. Filters searchMessagesFilterEmpty, searchMessagesFilterCall, searchMessagesFilterMissedCall, searchMessagesFilterMention and searchMessagesFilterUnreadMention 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
//@limit The expected number of message positions to be returned; 50-2000. 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 information about the next messages of the specified type in the chat splitted by days. Returns the results in reverse chronological order. Can return partial result for the last returned day

View File

@ -230,6 +230,12 @@ class MessagesDbImpl final : public MessagesDbSyncInterface {
"ORDER BY rowid DESC LIMIT ?3) ORDER BY search_id DESC"));
for (int32 i = 0; i < MESSAGES_DB_INDEX_COUNT; i++) {
TRY_RESULT_ASSIGN(
get_message_ids_stmts_[i],
db_.get_statement(
PSLICE() << "SELECT message_id FROM messages WHERE dialog_id = ?1 AND message_id < ?2 AND (index_mask & "
<< (1 << i) << ") != 0 ORDER BY message_id DESC LIMIT 1000000"));
TRY_RESULT_ASSIGN(
get_messages_from_index_stmts_[i].desc_stmt_,
db_.get_statement(
@ -469,16 +475,16 @@ class MessagesDbImpl final : public MessagesDbSyncInterface {
return Status::Error("Not found");
}
MessageId received_message_id(stmt.view_int64(0));
MessagesDbDialogMessage result{received_message_id, BufferSlice(stmt.view_blob(1))};
Slice data = stmt.view_blob(1);
if (is_scheduled_server) {
CHECK(received_message_id.is_scheduled());
CHECK(received_message_id.is_scheduled_server());
CHECK(received_message_id.get_scheduled_server_message_id() == message_id.get_scheduled_server_message_id());
} else {
LOG_CHECK(received_message_id == message_id)
<< received_message_id << ' ' << message_id << ' ' << get_message_info(result, true).first;
<< received_message_id << ' ' << message_id << ' ' << get_message_info(received_message_id, data, true).first;
}
return std::move(result);
return MessagesDbDialogMessage{received_message_id, BufferSlice(data)};
}
Result<MessagesDbMessage> get_message_by_unique_message_id(ServerMessageId unique_message_id) final {
@ -643,6 +649,37 @@ class MessagesDbImpl final : public MessagesDbSyncInterface {
return MessagesDbCalendar{std::move(messages), std::move(total_counts)};
}
Result<MessagesDbMessagePositions> get_dialog_sparse_message_positions(
MessagesDbGetDialogSparseMessagePositionsQuery query) final {
auto &stmt = get_message_ids_stmts_[message_search_filter_index(query.filter)];
SCOPE_EXIT {
stmt.reset();
};
stmt.bind_int64(1, query.dialog_id.get()).ensure();
stmt.bind_int64(2, query.from_message_id.get()).ensure();
vector<MessageId> message_ids;
stmt.step().ensure();
while (stmt.has_row()) {
message_ids.push_back(MessageId(stmt.view_int64(0)));
stmt.step().ensure();
}
int32 limit = min(query.limit, static_cast<int32>(message_ids.size()));
double delta = static_cast<double>(message_ids.size()) / limit;
vector<MessagesDbMessagePosition> positions;
positions.reserve(limit);
for (int32 i = 0; i < limit; i++) {
auto position = static_cast<int32>((i + 0.5) * delta);
auto message_id = message_ids[position];
TRY_RESULT(message, get_message({query.dialog_id, message_id}));
auto date = get_message_info(message).second;
positions.push_back(MessagesDbMessagePosition{position, date, message_id});
}
return MessagesDbMessagePositions{static_cast<int32>(message_ids.size()), std::move(positions)};
}
Result<vector<MessagesDbDialogMessage>> get_messages(MessagesDbMessagesQuery query) final {
if (query.filter != MessageSearchFilter::Empty) {
return get_messages_from_index(query.dialog_id, query.from_message_id, query.filter, query.offset, query.limit);
@ -836,6 +873,7 @@ class MessagesDbImpl final : public MessagesDbSyncInterface {
SqliteStatement get_scheduled_messages_stmt_;
SqliteStatement get_messages_from_notification_id_stmt_;
std::array<SqliteStatement, MESSAGES_DB_INDEX_COUNT> get_message_ids_stmts_;
std::array<GetMessagesStmt, MESSAGES_DB_INDEX_COUNT> get_messages_from_index_stmts_;
std::array<SqliteStatement, 2> get_calls_stmts_;
@ -1020,6 +1058,11 @@ class MessagesDbAsync final : public MessagesDbAsyncInterface {
send_closure_later(impl_, &Impl::get_dialog_message_calendar, std::move(query), std::move(promise));
}
void get_dialog_sparse_message_positions(MessagesDbGetDialogSparseMessagePositionsQuery query,
Promise<MessagesDbMessagePositions> promise) final {
send_closure_later(impl_, &Impl::get_dialog_sparse_message_positions, std::move(query), std::move(promise));
}
void get_messages(MessagesDbMessagesQuery query, Promise<vector<MessagesDbDialogMessage>> promise) final {
send_closure_later(impl_, &Impl::get_messages, std::move(query), std::move(promise));
}
@ -1116,6 +1159,12 @@ class MessagesDbAsync final : public MessagesDbAsyncInterface {
promise.set_result(sync_db_->get_dialog_message_calendar(std::move(query)));
}
void get_dialog_sparse_message_positions(MessagesDbGetDialogSparseMessagePositionsQuery query,
Promise<MessagesDbMessagePositions> promise) {
add_read_query();
promise.set_result(sync_db_->get_dialog_sparse_message_positions(std::move(query)));
}
void get_messages(MessagesDbMessagesQuery query, Promise<vector<MessagesDbDialogMessage>> promise) {
add_read_query();
promise.set_result(sync_db_->get_messages(std::move(query)));

View File

@ -58,6 +58,24 @@ struct MessagesDbCalendar {
vector<int32> total_counts;
};
struct MessagesDbGetDialogSparseMessagePositionsQuery {
DialogId dialog_id;
MessageSearchFilter filter{MessageSearchFilter::Empty};
MessageId from_message_id;
int32 limit{0};
};
struct MessagesDbMessagePosition {
int32 position{0};
int32 date{0};
MessageId message_id;
};
struct MessagesDbMessagePositions {
int32 total_count{0};
vector<MessagesDbMessagePosition> positions;
};
struct MessagesDbFtsQuery {
string query;
DialogId dialog_id;
@ -104,6 +122,9 @@ class MessagesDbSyncInterface {
virtual Result<MessagesDbCalendar> get_dialog_message_calendar(MessagesDbDialogCalendarQuery query) = 0;
virtual Result<MessagesDbMessagePositions> get_dialog_sparse_message_positions(
MessagesDbGetDialogSparseMessagePositionsQuery query) = 0;
virtual Result<vector<MessagesDbDialogMessage>> get_messages(MessagesDbMessagesQuery query) = 0;
virtual Result<vector<MessagesDbDialogMessage>> get_scheduled_messages(DialogId dialog_id, int32 limit) = 0;
virtual Result<vector<MessagesDbDialogMessage>> get_messages_from_notification_id(DialogId dialog_id,
@ -158,6 +179,9 @@ class MessagesDbAsyncInterface {
virtual void get_dialog_message_calendar(MessagesDbDialogCalendarQuery query,
Promise<MessagesDbCalendar> promise) = 0;
virtual void get_dialog_sparse_message_positions(MessagesDbGetDialogSparseMessagePositionsQuery query,
Promise<MessagesDbMessagePositions> promise) = 0;
virtual void get_messages(MessagesDbMessagesQuery query, Promise<vector<MessagesDbDialogMessage>> promise) = 0;
virtual void get_scheduled_messages(DialogId dialog_id, int32 limit,
Promise<vector<MessagesDbDialogMessage>> promise) = 0;

View File

@ -22763,11 +22763,13 @@ void MessagesManager::get_dialog_sparse_message_positions(
if (d == nullptr) {
return promise.set_error(Status::Error(400, "Chat not found"));
}
if (limit < 50 || limit > 2000) { // server-side limits
return promise.set_error(Status::Error(400, "Invalid limit specified"));
}
if (filter == MessageSearchFilter::Empty || filter == MessageSearchFilter::Call ||
filter == MessageSearchFilter::MissedCall || filter == MessageSearchFilter::Mention ||
filter == MessageSearchFilter::UnreadMention || filter == MessageSearchFilter::FailedToSend ||
filter == MessageSearchFilter::Pinned) {
filter == MessageSearchFilter::UnreadMention || filter == MessageSearchFilter::Pinned) {
return promise.set_error(Status::Error(400, "The filter is not supported"));
}
@ -22784,6 +22786,34 @@ void MessagesManager::get_dialog_sparse_message_positions(
from_message_id = from_message_id.get_next_server_message_id();
}
if (filter == MessageSearchFilter::FailedToSend || dialog_id.get_type() == DialogType::SecretChat) {
if (!G()->parameters().use_message_db) {
return promise.set_error(Status::Error(400, "Unsupported without message database"));
}
LOG(INFO) << "Get sparse message positions from database";
auto new_promise =
PromiseCreator::lambda([promise = std::move(promise)](Result<MessagesDbMessagePositions> result) mutable {
if (result.is_error()) {
return promise.set_error(result.move_as_error());
}
auto positions = result.move_as_ok();
promise.set_value(td_api::make_object<td_api::messagePositions>(
positions.total_count, transform(positions.positions, [](const MessagesDbMessagePosition &position) {
return td_api::make_object<td_api::messagePosition>(position.position, position.message_id.get(),
position.date);
})));
});
MessagesDbGetDialogSparseMessagePositionsQuery db_query;
db_query.dialog_id = dialog_id;
db_query.filter = filter;
db_query.from_message_id = from_message_id;
db_query.limit = limit;
G()->td_db()->get_messages_db_async()->get_dialog_sparse_message_positions(db_query, std::move(new_promise));
return;
}
switch (dialog_id.get_type()) {
case DialogType::User:
case DialogType::Chat:
@ -22792,7 +22822,6 @@ void MessagesManager::get_dialog_sparse_message_positions(
->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();