Support viewing messages in message threads.

GitOrigin-RevId: 5bde413f4192993e12b8e89ff5cb569421b90d78
This commit is contained in:
levlam 2020-09-22 01:13:06 +03:00
parent 3b97a0944d
commit 08ff725767
8 changed files with 303 additions and 53 deletions

View File

@ -3916,9 +3916,12 @@ openChat chat_id:int53 = Ok;
//@description Informs TDLib that the chat is closed by the user. Many useful activities depend on the chat being opened or closed @chat_id Chat identifier //@description Informs TDLib that the chat is closed by the user. Many useful activities depend on the chat being opened or closed @chat_id Chat identifier
closeChat chat_id:int53 = Ok; closeChat chat_id:int53 = Ok;
//@description Informs TDLib that messages are being viewed by the user. Many useful activities depend on whether the messages are currently being viewed or not (e.g., marking messages as read, incrementing a view counter, updating a view counter, removing deleted messages in supergroups and channels) @chat_id Chat identifier @message_ids The identifiers of the messages being viewed //@description Informs TDLib that messages are being viewed by the user. Many useful activities depend on whether the messages are currently being viewed or not (e.g., marking messages as read, incrementing a view counter, updating a view counter, removing deleted messages in supergroups and channels)
//@force_read True, if messages in closed chats should be marked as read //@chat_id Chat identifier
viewMessages chat_id:int53 message_ids:vector<int53> force_read:Bool = Ok; //@message_thread_id If not 0, a message thread identifier in which the messages are being viewed
//@message_ids The identifiers of the messages being viewed
//@force_read True, if messages in closed chats should be marked as read by the request
viewMessages chat_id:int53 message_thread_id:int53 message_ids:vector<int53> force_read:Bool = Ok;
//@description Informs TDLib that the message content has been opened (e.g., the user has opened a photo, video, document, location or venue, or has listened to an audio file or voice note message). An updateMessageContentOpened update will be generated if something has changed @chat_id Chat identifier of the message @message_id Identifier of the message with the opened content //@description Informs TDLib that the message content has been opened (e.g., the user has opened a photo, video, document, location or venue, or has listened to an audio file or voice note message). An updateMessageContentOpened update will be generated if something has changed @chat_id Chat identifier of the message @message_id Identifier of the message with the opened content
openMessageContent chat_id:int53 message_id:int53 = Ok; openMessageContent chat_id:int53 message_id:int53 = Ok;

Binary file not shown.

View File

@ -1713,9 +1713,10 @@ class ReadHistoryQuery : public Td::ResultHandler {
void send(DialogId dialog_id, MessageId max_message_id) { void send(DialogId dialog_id, MessageId max_message_id) {
dialog_id_ = dialog_id; dialog_id_ = dialog_id;
auto input_peer = td->messages_manager_->get_input_peer(dialog_id, AccessRights::Read);
CHECK(input_peer != nullptr);
send_query(G()->net_query_creator().create( send_query(G()->net_query_creator().create(
telegram_api::messages_readHistory(td->messages_manager_->get_input_peer(dialog_id, AccessRights::Read), telegram_api::messages_readHistory(std::move(input_peer), max_message_id.get_server_message_id().get())));
max_message_id.get_server_message_id().get())));
} }
void on_result(uint64 id, BufferSlice packet) override { void on_result(uint64 id, BufferSlice packet) override {
@ -1778,6 +1779,38 @@ class ReadChannelHistoryQuery : public Td::ResultHandler {
} }
}; };
class ReadDiscussionQuery : public Td::ResultHandler {
Promise<Unit> promise_;
DialogId dialog_id_;
public:
explicit ReadDiscussionQuery(Promise<Unit> &&promise) : promise_(std::move(promise)) {
}
void send(DialogId dialog_id, MessageId top_thread_message_id, MessageId max_message_id) {
dialog_id_ = dialog_id;
auto input_peer = td->messages_manager_->get_input_peer(dialog_id, AccessRights::Read);
CHECK(input_peer != nullptr);
send_query(G()->net_query_creator().create(telegram_api::messages_readDiscussion(
std::move(input_peer), top_thread_message_id.get_server_message_id().get(),
max_message_id.get_server_message_id().get())));
}
void on_result(uint64 id, BufferSlice packet) override {
auto result_ptr = fetch_result<telegram_api::messages_readDiscussion>(packet);
if (result_ptr.is_error()) {
return on_error(id, result_ptr.move_as_error());
}
promise_.set_value(Unit());
}
void on_error(uint64 id, Status status) override {
td->messages_manager_->on_get_dialog_error(dialog_id_, status, "ReadDiscussionQuery");
promise_.set_error(std::move(status));
}
};
class SearchMessagesQuery : public Td::ResultHandler { class SearchMessagesQuery : public Td::ResultHandler {
Promise<Unit> promise_; Promise<Unit> promise_;
DialogId dialog_id_; DialogId dialog_id_;
@ -5331,8 +5364,8 @@ void MessagesManager::on_pending_read_history_timeout_callback(void *messages_ma
} }
auto messages_manager = static_cast<MessagesManager *>(messages_manager_ptr); auto messages_manager = static_cast<MessagesManager *>(messages_manager_ptr);
send_closure_later(messages_manager->actor_id(messages_manager), &MessagesManager::read_history_on_server_impl, send_closure_later(messages_manager->actor_id(messages_manager), &MessagesManager::do_read_history_on_server,
DialogId(dialog_id_int), MessageId()); DialogId(dialog_id_int));
} }
void MessagesManager::on_pending_updated_dialog_timeout_callback(void *messages_manager_ptr, int64 dialog_id_int) { void MessagesManager::on_pending_updated_dialog_timeout_callback(void *messages_manager_ptr, int64 dialog_id_int) {
@ -16090,9 +16123,7 @@ Result<std::pair<string, bool>> MessagesManager::get_message_link(FullMessageId
auto t_me = G()->shared_config().get_option_string("t_me_url", "https://t.me/"); auto t_me = G()->shared_config().get_option_string("t_me_url", "https://t.me/");
if (for_comment) { if (for_comment) {
auto *top_m = get_message_force(d, m->top_reply_message_id, "get_public_message_link"); auto *top_m = get_message_force(d, m->top_reply_message_id, "get_public_message_link");
if (is_discussion_message(dialog_id, top_m) && if (is_discussion_message(dialog_id, top_m) && is_active_message_reply_info(dialog_id, top_m->reply_info)) {
top_m->forward_info->sender_dialog_id ==
DialogId(td_->contacts_manager_->get_channel_linked_channel_id(dialog_id.get_channel_id()))) {
auto linked_dialog_id = top_m->forward_info->sender_dialog_id; auto linked_dialog_id = top_m->forward_info->sender_dialog_id;
auto linked_message_id = top_m->forward_info->message_id; auto linked_message_id = top_m->forward_info->message_id;
auto linked_d = get_dialog(linked_dialog_id); auto linked_d = get_dialog(linked_dialog_id);
@ -16100,9 +16131,9 @@ Result<std::pair<string, bool>> MessagesManager::get_message_link(FullMessageId
CHECK(linked_dialog_id.get_type() == DialogType::Channel); CHECK(linked_dialog_id.get_type() == DialogType::Channel);
auto *linked_m = get_message_force(linked_d, linked_message_id, "get_public_message_link"); auto *linked_m = get_message_force(linked_d, linked_message_id, "get_public_message_link");
auto channel_username = td_->contacts_manager_->get_channel_username(linked_dialog_id.get_channel_id()); auto channel_username = td_->contacts_manager_->get_channel_username(linked_dialog_id.get_channel_id());
if (linked_m != nullptr && linked_message_id.is_server() && if (linked_m != nullptr && is_active_message_reply_info(linked_dialog_id, linked_m->reply_info) &&
have_input_peer(linked_dialog_id, AccessRights::Read) && !channel_username.empty() && linked_message_id.is_server() && have_input_peer(linked_dialog_id, AccessRights::Read) &&
linked_d->deleted_message_ids.count(linked_message_id) == 0) { !channel_username.empty()) {
return std::make_pair( return std::make_pair(
PSTRING() << t_me << channel_username << '/' << linked_message_id.get_server_message_id().get() PSTRING() << t_me << channel_username << '/' << linked_message_id.get_server_message_id().get()
<< "?comment=" << m->message_id.get_server_message_id().get() << (for_group ? "" : "&single"), << "?comment=" << m->message_id.get_server_message_id().get() << (for_group ? "" : "&single"),
@ -18079,7 +18110,8 @@ DialogId MessagesManager::get_my_dialog_id() const {
return DialogId(td_->contacts_manager_->get_my_id()); return DialogId(td_->contacts_manager_->get_my_id());
} }
Status MessagesManager::view_messages(DialogId dialog_id, const vector<MessageId> &message_ids, bool force_read) { Status MessagesManager::view_messages(DialogId dialog_id, MessageId top_thread_message_id,
const vector<MessageId> &message_ids, bool force_read) {
CHECK(!td_->auth_manager_->is_bot()); CHECK(!td_->auth_manager_->is_bot());
Dialog *d = get_dialog_force(dialog_id); Dialog *d = get_dialog_force(dialog_id);
@ -18095,6 +18127,15 @@ Status MessagesManager::view_messages(DialogId dialog_id, const vector<MessageId
return Status::Error(5, "Can't access the chat"); return Status::Error(5, "Can't access the chat");
} }
if (top_thread_message_id != MessageId()) {
if (!top_thread_message_id.is_valid() || !top_thread_message_id.is_server()) {
return Status::Error(400, "Invalid message thread ID specified");
}
if (dialog_id.get_type() != DialogType::Channel || is_broadcast_channel(dialog_id)) {
return Status::Error(400, "There is no message threads in the chat");
}
}
bool need_read = force_read || d->is_opened; bool need_read = force_read || d->is_opened;
MessageId max_message_id; // max server or local viewed message_id MessageId max_message_id; // max server or local viewed message_id
vector<MessageId> read_content_message_ids; vector<MessageId> read_content_message_ids;
@ -18138,9 +18179,55 @@ Status MessagesManager::view_messages(DialogId dialog_id, const vector<MessageId
read_message_contents_on_server(dialog_id, std::move(read_content_message_ids), 0, Auto()); read_message_contents_on_server(dialog_id, std::move(read_content_message_ids), 0, Auto());
} }
if (need_read && max_message_id > d->last_read_inbox_message_id) { if (!need_read) {
MessageId last_read_message_id = max_message_id; return Status::OK();
MessageId prev_last_read_inbox_message_id = d->last_read_inbox_message_id; }
if (top_thread_message_id.is_valid()) {
MessageId prev_last_read_inbox_message_id;
MessageId max_thread_message_id;
Message *top_m = get_message_force(d, top_thread_message_id, "view_messages 2");
if (top_m != nullptr && is_active_message_reply_info(dialog_id, top_m->reply_info)) {
prev_last_read_inbox_message_id = top_m->reply_info.last_read_inbox_message_id;
if (top_m->reply_info.update_max_message_ids(MessageId(), max_message_id, MessageId())) {
send_update_message_interaction_info(dialog_id, top_m);
on_message_changed(d, top_m, true, "view_messages 3");
}
max_thread_message_id = top_m->reply_info.max_message_id;
if (is_discussion_message(dialog_id, top_m)) {
auto linked_dialog_id = top_m->forward_info->sender_dialog_id;
auto linked_d = get_dialog(linked_dialog_id);
CHECK(linked_d != nullptr);
CHECK(linked_dialog_id.get_type() == DialogType::Channel);
auto *linked_m = get_message_force(linked_d, top_m->forward_info->message_id, "view_messages 4");
if (linked_m != nullptr && is_active_message_reply_info(linked_dialog_id, linked_m->reply_info)) {
if (linked_m->reply_info.last_read_inbox_message_id < prev_last_read_inbox_message_id) {
prev_last_read_inbox_message_id = linked_m->reply_info.last_read_inbox_message_id;
}
if (linked_m->reply_info.update_max_message_ids(MessageId(), max_message_id, MessageId())) {
send_update_message_interaction_info(linked_dialog_id, linked_m);
on_message_changed(linked_d, linked_m, true, "view_messages 5");
}
if (linked_m->reply_info.max_message_id > max_thread_message_id) {
max_thread_message_id = linked_m->reply_info.max_message_id;
}
}
}
}
if (max_message_id.get_prev_server_message_id().get() >
prev_last_read_inbox_message_id.get_prev_server_message_id().get()) {
read_message_thread_history_on_server(d, top_thread_message_id, max_message_id.get_prev_server_message_id(),
max_thread_message_id.get_prev_server_message_id());
}
return Status::OK();
}
if (max_message_id > d->last_read_inbox_message_id) {
const MessageId last_read_message_id = max_message_id;
const MessageId prev_last_read_inbox_message_id = d->last_read_inbox_message_id;
MessageId read_history_on_server_message_id; MessageId read_history_on_server_message_id;
if (dialog_id.get_type() != DialogType::SecretChat) { if (dialog_id.get_type() != DialogType::SecretChat) {
if (last_read_message_id.get_prev_server_message_id().get() > if (last_read_message_id.get_prev_server_message_id().get() >
@ -18164,7 +18251,7 @@ Status MessagesManager::view_messages(DialogId dialog_id, const vector<MessageId
read_history_on_server(d, read_history_on_server_message_id); read_history_on_server(d, read_history_on_server_message_id);
} }
} }
if (need_read && d->is_marked_as_unread) { if (d->is_marked_as_unread) {
set_dialog_is_marked_as_unread(d, false); set_dialog_is_marked_as_unread(d, false);
} }
@ -19106,6 +19193,27 @@ class MessagesManager::ReadHistoryInSecretChatLogEvent {
} }
}; };
class MessagesManager::ReadMessageThreadHistoryOnServerLogEvent {
public:
DialogId dialog_id_;
MessageId top_thread_message_id_;
MessageId max_message_id_;
template <class StorerT>
void store(StorerT &storer) const {
td::store(dialog_id_, storer);
td::store(top_thread_message_id_, storer);
td::store(max_message_id_, storer);
}
template <class ParserT>
void parse(ParserT &parser) {
td::parse(dialog_id_, parser);
td::parse(top_thread_message_id_, parser);
td::parse(max_message_id_, parser);
}
};
void MessagesManager::read_history_on_server(Dialog *d, MessageId max_message_id) { void MessagesManager::read_history_on_server(Dialog *d, MessageId max_message_id) {
if (td_->auth_manager_->is_bot()) { if (td_->auth_manager_->is_bot()) {
return; return;
@ -19128,7 +19236,7 @@ void MessagesManager::read_history_on_server(Dialog *d, MessageId max_message_id
ReadHistoryInSecretChatLogEvent logevent; ReadHistoryInSecretChatLogEvent logevent;
logevent.dialog_id_ = dialog_id; logevent.dialog_id_ = dialog_id;
logevent.max_date_ = m->date; logevent.max_date_ = m->date;
add_log_event(d->read_history_logevent_id, LogEventStorerImpl<ReadHistoryInSecretChatLogEvent>(logevent), add_log_event(d->read_history_logevent_ids[0], LogEventStorerImpl<ReadHistoryInSecretChatLogEvent>(logevent),
LogEvent::HandlerType::ReadHistoryInSecretChat, "read history"); LogEvent::HandlerType::ReadHistoryInSecretChat, "read history");
d->last_read_inbox_message_date = m->date; d->last_read_inbox_message_date = m->date;
@ -19136,37 +19244,87 @@ void MessagesManager::read_history_on_server(Dialog *d, MessageId max_message_id
ReadHistoryOnServerLogEvent logevent; ReadHistoryOnServerLogEvent logevent;
logevent.dialog_id_ = dialog_id; logevent.dialog_id_ = dialog_id;
logevent.max_message_id_ = max_message_id; logevent.max_message_id_ = max_message_id;
add_log_event(d->read_history_logevent_id, LogEventStorerImpl<ReadHistoryOnServerLogEvent>(logevent), add_log_event(d->read_history_logevent_ids[0], LogEventStorerImpl<ReadHistoryOnServerLogEvent>(logevent),
LogEvent::HandlerType::ReadHistoryOnServer, "read history"); LogEvent::HandlerType::ReadHistoryOnServer, "read history");
} }
d->updated_read_history_message_ids.insert(MessageId());
bool need_delay = d->is_opened && !is_secret && d->server_unread_count > 0; bool need_delay = d->is_opened && !is_secret && d->server_unread_count > 0;
pending_read_history_timeout_.set_timeout_in(dialog_id.get(), need_delay ? MIN_READ_HISTORY_DELAY : 0); pending_read_history_timeout_.set_timeout_in(dialog_id.get(), need_delay ? MIN_READ_HISTORY_DELAY : 0);
} }
void MessagesManager::read_history_on_server_impl(DialogId dialog_id, MessageId max_message_id) { void MessagesManager::read_message_thread_history_on_server(Dialog *d, MessageId top_thread_message_id,
MessageId max_message_id, MessageId last_message_id) {
if (td_->auth_manager_->is_bot()) {
return;
}
CHECK(d != nullptr);
CHECK(top_thread_message_id.is_valid());
CHECK(top_thread_message_id.is_server());
CHECK(max_message_id.is_server());
auto dialog_id = d->dialog_id;
LOG(INFO) << "Read history in thread of " << top_thread_message_id << " in " << dialog_id << " on server up to "
<< max_message_id;
if (G()->parameters().use_message_db) {
ReadMessageThreadHistoryOnServerLogEvent logevent;
logevent.dialog_id_ = dialog_id;
logevent.top_thread_message_id_ = top_thread_message_id;
logevent.max_message_id_ = max_message_id;
add_log_event(d->read_history_logevent_ids[top_thread_message_id.get()],
LogEventStorerImpl<ReadMessageThreadHistoryOnServerLogEvent>(logevent),
LogEvent::HandlerType::ReadMessageThreadHistoryOnServer, "read history");
}
d->updated_read_history_message_ids.insert(top_thread_message_id);
bool need_delay = d->is_opened && last_message_id.is_valid() && max_message_id != last_message_id;
pending_read_history_timeout_.set_timeout_in(dialog_id.get(), need_delay ? MIN_READ_HISTORY_DELAY : 0);
}
void MessagesManager::do_read_history_on_server(DialogId dialog_id) {
if (G()->close_flag()) { if (G()->close_flag()) {
return; return;
} }
Dialog *d = get_dialog(dialog_id); Dialog *d = get_dialog(dialog_id);
CHECK(d != nullptr); CHECK(d != nullptr);
CHECK(!d->updated_read_history_message_ids.empty());
auto message_id = d->last_read_inbox_message_id; for (auto top_thread_message_id : d->updated_read_history_message_ids) {
if (dialog_id.get_type() != DialogType::SecretChat) { if (!top_thread_message_id.is_valid()) {
message_id = message_id.get_prev_server_message_id(); read_history_on_server_impl(d, MessageId());
} else {
read_message_thread_history_on_server_impl(d, top_thread_message_id, MessageId());
}
} }
if (message_id > max_message_id) { reset_to_empty(d->updated_read_history_message_ids);
max_message_id = message_id; }
void MessagesManager::read_history_on_server_impl(Dialog *d, MessageId max_message_id) {
CHECK(d != nullptr);
auto dialog_id = d->dialog_id;
{
auto message_id = d->last_read_inbox_message_id;
if (dialog_id.get_type() != DialogType::SecretChat) {
message_id = message_id.get_prev_server_message_id();
}
if (message_id > max_message_id) {
max_message_id = message_id;
}
} }
Promise<> promise; Promise<> promise;
if (d->read_history_logevent_id.logevent_id != 0) { if (d->read_history_logevent_ids[0].logevent_id != 0) {
d->read_history_logevent_id.generation++; d->read_history_logevent_ids[0].generation++;
promise = PromiseCreator::lambda([actor_id = actor_id(this), dialog_id, promise = PromiseCreator::lambda([actor_id = actor_id(this), dialog_id,
generation = d->read_history_logevent_id.generation](Result<Unit> result) { generation = d->read_history_logevent_ids[0].generation](Result<Unit> result) {
if (!G()->close_flag()) { if (!G()->close_flag()) {
send_closure(actor_id, &MessagesManager::on_read_history_finished, dialog_id, generation); send_closure(actor_id, &MessagesManager::on_read_history_finished, dialog_id, MessageId(), generation);
} }
}); });
} }
@ -19174,7 +19332,7 @@ void MessagesManager::read_history_on_server_impl(DialogId dialog_id, MessageId
repair_server_unread_count(dialog_id, d->server_unread_count); repair_server_unread_count(dialog_id, d->server_unread_count);
} }
if (!max_message_id.is_valid()) { if (!max_message_id.is_valid() || !have_input_peer(dialog_id, AccessRights::Read)) {
return promise.set_value(Unit()); return promise.set_value(Unit());
} }
@ -19210,10 +19368,53 @@ void MessagesManager::read_history_on_server_impl(DialogId dialog_id, MessageId
} }
} }
void MessagesManager::on_read_history_finished(DialogId dialog_id, uint64 generation) { void MessagesManager::read_message_thread_history_on_server_impl(Dialog *d, MessageId top_thread_message_id,
MessageId max_message_id) {
CHECK(d != nullptr);
auto dialog_id = d->dialog_id;
CHECK(dialog_id.get_type() == DialogType::Channel);
const Message *m = get_message_force(d, top_thread_message_id, "read_message_thread_history_on_server_impl");
if (m != nullptr) {
auto message_id = m->reply_info.last_read_inbox_message_id.get_prev_server_message_id();
if (message_id > max_message_id) {
max_message_id = message_id;
}
}
Promise<> promise;
if (d->read_history_logevent_ids[top_thread_message_id.get()].logevent_id != 0) {
d->read_history_logevent_ids[top_thread_message_id.get()].generation++;
promise = PromiseCreator::lambda(
[actor_id = actor_id(this), dialog_id, top_thread_message_id,
generation = d->read_history_logevent_ids[top_thread_message_id.get()].generation](Result<Unit> result) {
if (!G()->close_flag()) {
send_closure(actor_id, &MessagesManager::on_read_history_finished, dialog_id, top_thread_message_id,
generation);
}
});
}
if (!max_message_id.is_valid() || !have_input_peer(dialog_id, AccessRights::Read)) {
return promise.set_value(Unit());
}
LOG(INFO) << "Send read history request in thread of " << top_thread_message_id << " in " << dialog_id << " up to "
<< max_message_id;
td_->create_handler<ReadDiscussionQuery>(std::move(promise))->send(dialog_id, top_thread_message_id, max_message_id);
}
void MessagesManager::on_read_history_finished(DialogId dialog_id, MessageId top_thread_message_id, uint64 generation) {
auto d = get_dialog(dialog_id); auto d = get_dialog(dialog_id);
CHECK(d != nullptr); CHECK(d != nullptr);
delete_log_event(d->read_history_logevent_id, generation, "read history"); auto it = d->read_history_logevent_ids.find(top_thread_message_id.get());
if (it == d->read_history_logevent_ids.end()) {
return;
}
delete_log_event(it->second, generation, "read history");
if (it->second.logevent_id == 0) {
d->read_history_logevent_ids.erase(it);
}
} }
std::pair<int32, vector<MessageId>> MessagesManager::search_dialog_messages( std::pair<int32, vector<MessageId>> MessagesManager::search_dialog_messages(
@ -23634,6 +23835,9 @@ bool MessagesManager::is_discussion_message(DialogId dialog_id, const Message *m
if (m->forward_info->sender_dialog_id == dialog_id) { if (m->forward_info->sender_dialog_id == dialog_id) {
return false; return false;
} }
if (m->forward_info->sender_dialog_id.get_type() != DialogType::Channel) {
return false;
}
return true; return true;
} }
@ -34162,13 +34366,13 @@ void MessagesManager::on_binlog_events(vector<BinlogEvent> &&events) {
binlog_erase(G()->td_db()->get_binlog(), event.id_); binlog_erase(G()->td_db()->get_binlog(), event.id_);
break; break;
} }
if (d->read_history_logevent_id.logevent_id != 0) { if (d->read_history_logevent_ids[0].logevent_id != 0) {
// we need only latest read history event // we need only latest read history event
binlog_erase(G()->td_db()->get_binlog(), d->read_history_logevent_id.logevent_id); binlog_erase(G()->td_db()->get_binlog(), d->read_history_logevent_ids[0].logevent_id);
} }
d->read_history_logevent_id.logevent_id = event.id_; d->read_history_logevent_ids[0].logevent_id = event.id_;
read_history_on_server_impl(dialog_id, log_event.max_message_id_); read_history_on_server_impl(d, log_event.max_message_id_);
break; break;
} }
case LogEvent::HandlerType::ReadHistoryInSecretChat: { case LogEvent::HandlerType::ReadHistoryInSecretChat: {
@ -34188,14 +34392,40 @@ void MessagesManager::on_binlog_events(vector<BinlogEvent> &&events) {
binlog_erase(G()->td_db()->get_binlog(), event.id_); binlog_erase(G()->td_db()->get_binlog(), event.id_);
break; break;
} }
if (d->read_history_logevent_id.logevent_id != 0) { if (d->read_history_logevent_ids[0].logevent_id != 0) {
// we need only latest read history event // we need only latest read history event
binlog_erase(G()->td_db()->get_binlog(), d->read_history_logevent_id.logevent_id); binlog_erase(G()->td_db()->get_binlog(), d->read_history_logevent_ids[0].logevent_id);
} }
d->read_history_logevent_id.logevent_id = event.id_; d->read_history_logevent_ids[0].logevent_id = event.id_;
d->last_read_inbox_message_date = log_event.max_date_; d->last_read_inbox_message_date = log_event.max_date_;
read_history_on_server_impl(dialog_id, MessageId()); read_history_on_server_impl(d, MessageId());
break;
}
case LogEvent::HandlerType::ReadMessageThreadHistoryOnServer: {
if (!G()->parameters().use_message_db) {
binlog_erase(G()->td_db()->get_binlog(), event.id_);
break;
}
ReadMessageThreadHistoryOnServerLogEvent log_event;
log_event_parse(log_event, event.data_).ensure();
auto dialog_id = log_event.dialog_id_;
Dialog *d = get_dialog_force(dialog_id);
if (d == nullptr || !have_input_peer(dialog_id, AccessRights::Read)) {
binlog_erase(G()->td_db()->get_binlog(), event.id_);
break;
}
auto top_thread_message_id = log_event.top_thread_message_id_;
if (d->read_history_logevent_ids[top_thread_message_id.get()].logevent_id != 0) {
// we need only latest read history event
binlog_erase(G()->td_db()->get_binlog(),
d->read_history_logevent_ids[top_thread_message_id.get()].logevent_id);
}
d->read_history_logevent_ids[top_thread_message_id.get()].logevent_id = event.id_;
read_message_thread_history_on_server_impl(d, top_thread_message_id, log_event.max_message_id_);
break; break;
} }
case LogEvent::HandlerType::ReadMessageContentsOnServer: { case LogEvent::HandlerType::ReadMessageContentsOnServer: {

View File

@ -654,7 +654,8 @@ class MessagesManager : public Actor {
Status close_dialog(DialogId dialog_id) TD_WARN_UNUSED_RESULT; Status close_dialog(DialogId dialog_id) TD_WARN_UNUSED_RESULT;
Status view_messages(DialogId dialog_id, const vector<MessageId> &message_ids, bool force_read) TD_WARN_UNUSED_RESULT; Status view_messages(DialogId dialog_id, MessageId top_thread_message_id, const vector<MessageId> &message_ids,
bool force_read) TD_WARN_UNUSED_RESULT;
Status open_message_content(FullMessageId full_message_id) TD_WARN_UNUSED_RESULT; Status open_message_content(FullMessageId full_message_id) TD_WARN_UNUSED_RESULT;
@ -1147,7 +1148,8 @@ class MessagesManager : public Actor {
unique_ptr<DraftMessage> draft_message; unique_ptr<DraftMessage> draft_message;
LogeventIdWithGeneration save_draft_message_logevent_id; LogeventIdWithGeneration save_draft_message_logevent_id;
LogeventIdWithGeneration save_notification_settings_logevent_id; LogeventIdWithGeneration save_notification_settings_logevent_id;
LogeventIdWithGeneration read_history_logevent_id; std::unordered_map<int64, LogeventIdWithGeneration> read_history_logevent_ids;
std::unordered_set<MessageId, MessageIdHash> updated_read_history_message_ids;
LogeventIdWithGeneration set_folder_id_logevent_id; LogeventIdWithGeneration set_folder_id_logevent_id;
FolderId folder_id; FolderId folder_id;
@ -1592,9 +1594,10 @@ class MessagesManager : public Actor {
class GetChannelDifferenceLogEvent; class GetChannelDifferenceLogEvent;
class GetDialogFromServerLogEvent; class GetDialogFromServerLogEvent;
class ReadAllDialogMentionsOnServerLogEvent; class ReadAllDialogMentionsOnServerLogEvent;
class ReadHistoryOnServerLogEvent;
class ReadHistoryInSecretChatLogEvent; class ReadHistoryInSecretChatLogEvent;
class ReadHistoryOnServerLogEvent;
class ReadMessageContentsOnServerLogEvent; class ReadMessageContentsOnServerLogEvent;
class ReadMessageThreadHistoryOnServerLogEvent;
class ReorderPinnedDialogsOnServerLogEvent; class ReorderPinnedDialogsOnServerLogEvent;
class ResetAllNotificationSettingsOnServerLogEvent; class ResetAllNotificationSettingsOnServerLogEvent;
class SaveDialogDraftMessageOnServerLogEvent; class SaveDialogDraftMessageOnServerLogEvent;
@ -1603,9 +1606,9 @@ class MessagesManager : public Actor {
class SendMessageLogEvent; class SendMessageLogEvent;
class SendScreenshotTakenNotificationMessageLogEvent; class SendScreenshotTakenNotificationMessageLogEvent;
class SetDialogFolderIdOnServerLogEvent; class SetDialogFolderIdOnServerLogEvent;
class ToggleDialogIsPinnedOnServerLogEvent;
class ToggleDialogIsMarkedAsUnreadOnServerLogEvent;
class ToggleDialogIsBlockedOnServerLogEvent; class ToggleDialogIsBlockedOnServerLogEvent;
class ToggleDialogIsMarkedAsUnreadOnServerLogEvent;
class ToggleDialogIsPinnedOnServerLogEvent;
class UpdateDialogNotificationSettingsOnServerLogEvent; class UpdateDialogNotificationSettingsOnServerLogEvent;
class UpdateScopeNotificationSettingsOnServerLogEvent; class UpdateScopeNotificationSettingsOnServerLogEvent;
@ -1935,9 +1938,16 @@ class MessagesManager : public Actor {
void read_history_on_server(Dialog *d, MessageId max_message_id); void read_history_on_server(Dialog *d, MessageId max_message_id);
void read_history_on_server_impl(DialogId dialog_id, MessageId max_message_id); void do_read_history_on_server(DialogId dialog_id);
void on_read_history_finished(DialogId dialog_id, uint64 generation); void read_history_on_server_impl(Dialog *d, MessageId max_message_id);
void read_message_thread_history_on_server_impl(Dialog *d, MessageId top_thread_message_id, MessageId max_message_id);
void on_read_history_finished(DialogId dialog_id, MessageId top_thread_message_id, uint64 generation);
void read_message_thread_history_on_server(Dialog *d, MessageId top_thread_message_id, MessageId max_message_id,
MessageId last_message_id);
void read_secret_chat_outbox_inner(DialogId dialog_id, int32 up_to_date, int32 read_date); void read_secret_chat_outbox_inner(DialogId dialog_id, int32 up_to_date, int32 read_date);

View File

@ -5454,9 +5454,9 @@ void Td::on_request(uint64 id, const td_api::closeChat &request) {
void Td::on_request(uint64 id, const td_api::viewMessages &request) { void Td::on_request(uint64 id, const td_api::viewMessages &request) {
CHECK_IS_USER(); CHECK_IS_USER();
answer_ok_query( answer_ok_query(id, messages_manager_->view_messages(
id, messages_manager_->view_messages( DialogId(request.chat_id_), MessageId(request.message_thread_id_),
DialogId(request.chat_id_), MessagesManager::get_message_ids(request.message_ids_), request.force_read_)); MessagesManager::get_message_ids(request.message_ids_), request.force_read_));
} }
void Td::on_request(uint64 id, const td_api::openMessageContent &request) { void Td::on_request(uint64 id, const td_api::openMessageContent &request) {

View File

@ -113,6 +113,7 @@ Status init_binlog(Binlog &binlog, string path, BinlogKeyValue<Binlog> &binlog_p
case LogEvent::HandlerType::SetDialogFolderIdOnServer: case LogEvent::HandlerType::SetDialogFolderIdOnServer:
case LogEvent::HandlerType::DeleteScheduledMessagesFromServer: case LogEvent::HandlerType::DeleteScheduledMessagesFromServer:
case LogEvent::HandlerType::ToggleDialogIsBlockedOnServer: case LogEvent::HandlerType::ToggleDialogIsBlockedOnServer:
case LogEvent::HandlerType::ReadMessageThreadHistoryOnServer:
events.to_messages_manager.push_back(event.clone()); events.to_messages_manager.push_back(event.clone());
break; break;
case LogEvent::HandlerType::AddMessagePushNotification: case LogEvent::HandlerType::AddMessagePushNotification:

View File

@ -3960,12 +3960,17 @@ class CliClient final : public Actor {
} else if (op == "rrh") { } else if (op == "rrh") {
auto hashtag = std::move(args); auto hashtag = std::move(args);
send_request(td_api::make_object<td_api::removeRecentHashtag>(hashtag)); send_request(td_api::make_object<td_api::removeRecentHashtag>(hashtag));
} else if (op == "view") { } else if (op == "view" || op == "viewt") {
string chat_id; string chat_id;
string message_thread_id;
string message_ids; string message_ids;
std::tie(chat_id, message_ids) = split(args); std::tie(chat_id, message_ids) = split(args);
if (op == "viewt") {
std::tie(message_thread_id, message_ids) = split(message_ids);
}
send_request(td_api::make_object<td_api::viewMessages>(as_chat_id(chat_id), as_message_ids(message_ids), true)); send_request(td_api::make_object<td_api::viewMessages>(
as_chat_id(chat_id), as_message_thread_id(message_thread_id), as_message_ids(message_ids), true));
} else if (op == "omc") { } else if (op == "omc") {
string chat_id; string chat_id;
string message_id; string message_id;

View File

@ -97,6 +97,7 @@ class LogEvent {
SetDialogFolderIdOnServer = 0x116, SetDialogFolderIdOnServer = 0x116,
DeleteScheduledMessagesFromServer = 0x117, DeleteScheduledMessagesFromServer = 0x117,
ToggleDialogIsBlockedOnServer = 0x118, ToggleDialogIsBlockedOnServer = 0x118,
ReadMessageThreadHistoryOnServer = 0x119,
GetChannelDifference = 0x140, GetChannelDifference = 0x140,
AddMessagePushNotification = 0x200, AddMessagePushNotification = 0x200,
EditMessagePushNotification = 0x201, EditMessagePushNotification = 0x201,