2
0
mirror of https://github.com/ars3niy/tdlib-purple synced 2025-08-22 01:49:29 +00:00

Finished fetching message history when tdlib skips messages

This commit is contained in:
Arseniy Lartsev 2021-01-03 13:18:33 +01:00
parent 67962619d4
commit 41b514634b
9 changed files with 212 additions and 40 deletions

View File

@ -434,14 +434,18 @@ void removeGroupChat(PurpleAccount *purpleAccount, const td::td_api::chat &chat)
if (purpleChat)
purple_blist_remove_chat(purpleChat);
std::string setting = lastMessageSetting(getId(chat));
purple_account_remove_setting(purpleAccount, setting.c_str());
// TODO: uncomment when updateNewChat(chat_list=NULL) + updateChatChatList(non-NULL) at login
// no longer removes chat
//std::string setting = lastMessageSetting(getId(chat));
//purple_account_remove_setting(purpleAccount, setting.c_str());
}
void removePrivateChat(TdAccountData &account, const td::td_api::chat &chat)
{
std::string setting = lastMessageSetting(getId(chat));
purple_account_remove_setting(account.purpleAccount, setting.c_str());
// TODO: uncomment when updateNewChat(chat_list=NULL) + updateChatChatList(non-NULL) at login
// no longer removes chat
//std::string setting = lastMessageSetting(getId(chat));
//purple_account_remove_setting(account.purpleAccount, setting.c_str());
}
void saveChatLastMessage(TdAccountData &account, ChatId chatId, MessageId messageId)

View File

@ -8,6 +8,10 @@
#include "call.h"
#include <algorithm>
enum {
HISTORY_MESSAGES_ABSOLUTE_LIMIT = 10000
};
std::string makeNoticeWithSender(const td::td_api::chat &chat, const TgMessageInfo &message,
const char *noticeText, PurpleAccount *account)
{
@ -1057,35 +1061,43 @@ static void fetchHistoryResponse(TdAccountData &account, ChatId chatId, MessageI
td::td_api::object_ptr<td::td_api::Object> response)
{
MessageId requestMoreFrom = MessageId::invalid;
const td::td_api::chat *chat = account.getChat(chatId);
if (response && (response->get_id() == td::td_api::messages::ID)) {
td::td_api::messages &messages = static_cast<td::td_api::messages &>(*response);
if (!messages.messages_.empty()) {
const td::td_api::chat *chat = account.getChat(chatId);
auto stop = messages.messages_.begin();
MessageId lastMessageId = MessageId::invalid;
for (; stop != messages.messages_.end(); ++stop) {
td::td_api::object_ptr<td::td_api::message> message = std::move(*stop);
if (!message ||
(lastReceivedMessage.valid() && (getId(*message) == lastReceivedMessage)) ||
(!lastReceivedMessage.valid() && (messagesFetched == 100)))
{
break;
}
messagesFetched++;
lastMessageId = getId(*message);
if (chat)
handleIncomingMessage(account, *chat, std::move(message), PendingMessageQueue::Prepend);
purple_debug_misc(config::pluginId, "Fetched %zu messages for chat %" G_GINT64_FORMAT "\n",
messages.messages_.size(), chatId.value());
auto stop = messages.messages_.begin();
MessageId lastMessageId = MessageId::invalid;
for (; stop != messages.messages_.end(); ++stop) {
td::td_api::object_ptr<td::td_api::message> message = std::move(*stop);
if (!message) {
purple_debug_warning(config::pluginId, "Erroneous message in history, stopping\n");
break;
}
if (stop == messages.messages_.end())
requestMoreFrom = lastMessageId;
if (lastReceivedMessage.valid() && (getId(*message) == lastReceivedMessage)) {
purple_debug_misc(config::pluginId, "Found message %" G_GINT64_FORMAT ", stopping\n",
lastReceivedMessage.value());
break;
}
if ((!lastReceivedMessage.valid() && (messagesFetched == 100)) ||
(messagesFetched == HISTORY_MESSAGES_ABSOLUTE_LIMIT))
{
purple_debug_misc(config::pluginId, "Reached history limit, stopping\n");
break;
}
messagesFetched++;
lastMessageId = getId(*message);
if (chat)
handleIncomingMessage(account, *chat, std::move(message), PendingMessageQueue::Prepend);
}
if (stop == messages.messages_.end())
requestMoreFrom = lastMessageId;
} else {
std::string message = formatMessage(_("Failed to fetch earlier messages: {}"),
getDisplayedError(response));
purple_debug_warning(config::pluginId, "%s\n", message.c_str());
const td::td_api::chat *chat = account.getChat(chatId);
if (chat)
showChatNotification(account, *chat, message.c_str(), PURPLE_MESSAGE_ERROR);
}
@ -1093,6 +1105,8 @@ static void fetchHistoryResponse(TdAccountData &account, ChatId chatId, MessageI
if (requestMoreFrom.valid())
fetchHistoryRequest(account, chatId, messagesFetched, requestMoreFrom, lastReceivedMessage);
else {
purple_debug_misc(config::pluginId, "Done fetching history for chat %" G_GINT64_FORMAT "\n",
chatId.value());
std::vector<IncomingMessage> readyMessages;
account.pendingMessages.setChatReady(chatId, readyMessages);
showMessages(readyMessages, account);
@ -1108,6 +1122,8 @@ static void fetchHistoryRequest(TdAccountData &account, ChatId chatId, unsigned
request->limit_ = 30;
request->offset_ = 0;
request->only_local_ = false;
purple_debug_misc(config::pluginId, "Requesting history for chat %" G_GINT64_FORMAT
" starting from %" G_GINT64_FORMAT "\n", chatId.value(), fetchBackFrom.value());
account.transceiver.sendQuery(std::move(request),
[&account, chatId, messagesFetched, lastReceivedMessage](uint64_t requestId, td::td_api::object_ptr<td::td_api::Object> response) {
fetchHistoryResponse(account, chatId, lastReceivedMessage, messagesFetched, std::move(response));

View File

@ -176,11 +176,15 @@ void PurpleTdClient::processUpdate(td::td_api::Object &update)
ChatId chatId = getChatId(lastMessage);
m_data.updateChatOrder(chatId, lastMessage.order_);
if (lastMessage.last_message_)
saveChatLastMessage(m_data, getChatId(lastMessage), getId(*lastMessage.last_message_));
saveChatLastMessage(m_data, chatId, getId(*lastMessage.last_message_));
else {
MessageId lastMessageId = getChatLastMessage(m_data, chatId);
if (lastMessageId.valid())
{}//fetchHistory(m_data, chatId, lastMessageId);
if (lastMessageId.valid()) {
purple_debug_misc(config::pluginId, "Skipped messages detected for chat %" G_GINT64_FORMAT
", fetching history until %" G_GINT64_FORMAT "\n",
chatId.value(), lastMessageId.value());
fetchHistory(m_data, chatId, lastMessageId);
}
}
break;
}

View File

@ -15,6 +15,7 @@ add_executable(tests EXCLUDE_FROM_ALL
secret-chat-test.cpp
message-split-test.cpp
message-order-test.cpp
message-history-test.cpp
test-transceiver.cpp
libpurple-mock.cpp
printout.cpp

View File

@ -17,6 +17,7 @@ void CommTest::SetUp()
connection = new PurpleConnection;
connection->state = PURPLE_DISCONNECTED;
connection->account = account;
purple_connection_set_protocol_data(connection, NULL);
account->gc = connection;
prpl.discardEvents();
setUiName("Pidgin");

View File

@ -0,0 +1,130 @@
#include "supergroup-test.h"
class MessageHistoryTest: public SupergroupTest {
protected:
const std::string userNameInChat = userFirstNames[0] + " " + userLastNames[0];
};
TEST_F(MessageHistoryTest, TdlibSkipMessages_LastMessageUnknown)
{
loginWithSupergroup();
tgl.update(make_object<updateChatLastMessage>(
groupChatId, nullptr, 0
));
tgl.verifyNoRequests();
}
TEST_F(MessageHistoryTest, TdlibSkipMessages)
{
const int purpleChatId = 1;
purple_account_set_string(account, ("last-message-chat" + std::to_string(groupChatId)).c_str(), "1");
loginWithSupergroup();
tgl.update(make_object<updateChatLastMessage>(
groupChatId, nullptr, 0
));
tgl.verifyRequest(getChatHistory(groupChatId, 0, 0, 30, false));
tgl.update(make_object<updateNewMessage>(
makeMessage(6, userIds[0], groupChatId, false, 6, makeTextMessage("6"))
));
tgl.update(make_object<updateChatLastMessage>(
groupChatId,
makeMessage(6, userIds[0], groupChatId, false, 6, makeTextMessage("6")),
0
));
tgl.update(make_object<updateNewMessage>(
makeMessage(7, userIds[0], groupChatId, false, 7, makeTextMessage("7"))
));
tgl.update(make_object<updateChatLastMessage>(
groupChatId,
makeMessage(7, userIds[0], groupChatId, false, 7, makeTextMessage("7")),
0
));
prpl.verifyNoEvents();
tgl.verifyNoRequests();
std::vector<object_ptr<message>> history;
history.push_back(makeMessage(5, userIds[0], groupChatId, false, 5, makeTextMessage("5")));
history.push_back(makeMessage(4, userIds[0], groupChatId, false, 4, makeTextMessage("4")));
tgl.reply(make_object<messages>(history.size(), std::move(history)));
prpl.verifyNoEvents();
tgl.verifyRequest(getChatHistory(groupChatId, 4, 0, 30, false));
history.clear();
history.push_back(makeMessage(3, userIds[0], groupChatId, false, 3, makeTextMessage("3")));
history.push_back(makeMessage(2, userIds[0], groupChatId, false, 2, makeTextMessage("2")));
history.push_back(makeMessage(1, userIds[0], groupChatId, false, 1, makeTextMessage("1")));
tgl.reply(make_object<messages>(history.size(), std::move(history)));
prpl.verifyEvents(
ServGotJoinedChatEvent(connection, purpleChatId, groupChatPurpleName, groupChatTitle),
ChatSetTopicEvent(groupChatPurpleName, "", ""),
ChatClearUsersEvent(groupChatPurpleName),
ServGotChatEvent(connection, purpleChatId, userNameInChat, "2", PURPLE_MESSAGE_RECV, 2),
ServGotChatEvent(connection, purpleChatId, userNameInChat, "3", PURPLE_MESSAGE_RECV, 3),
ServGotChatEvent(connection, purpleChatId, userNameInChat, "4", PURPLE_MESSAGE_RECV, 4),
ServGotChatEvent(connection, purpleChatId, userNameInChat, "5", PURPLE_MESSAGE_RECV, 5),
ServGotChatEvent(connection, purpleChatId, userNameInChat, "6", PURPLE_MESSAGE_RECV, 6),
ServGotChatEvent(connection, purpleChatId, userNameInChat, "7", PURPLE_MESSAGE_RECV, 7)
);
tgl.verifyRequest(viewMessages(groupChatId, {6, 7, 5, 4, 3, 2}, true));
ASSERT_EQ(std::string("7"), std::string(purple_account_get_string(
account, ("last-message-chat" + std::to_string(groupChatId)).c_str(), "")));
}
TEST_F(MessageHistoryTest, TdlibSkipMessages_FlushAtLogout)
{
const int purpleChatId = 1;
purple_account_set_string(account, ("last-message-chat" + std::to_string(groupChatId)).c_str(), "1");
loginWithSupergroup();
tgl.update(make_object<updateChatLastMessage>(
groupChatId, nullptr, 0
));
tgl.verifyRequest(getChatHistory(groupChatId, 0, 0, 30, false));
tgl.update(make_object<updateNewMessage>(
makeMessage(6, userIds[0], groupChatId, false, 6, makeTextMessage("6"))
));
tgl.update(make_object<updateChatLastMessage>(
groupChatId,
makeMessage(6, userIds[0], groupChatId, false, 6, makeTextMessage("6")),
0
));
prpl.verifyNoEvents();
tgl.verifyNoRequests();
std::vector<object_ptr<message>> history;
history.push_back(makeMessage(5, userIds[0], groupChatId, false, 5, makeTextMessage("5")));
history.push_back(makeMessage(4, userIds[0], groupChatId, false, 4, makeTextMessage("4")));
tgl.reply(make_object<messages>(history.size(), std::move(history)));
prpl.verifyNoEvents();
tgl.verifyRequest(getChatHistory(groupChatId, 4, 0, 30, false));
history.clear();
history.push_back(makeMessage(3, userIds[0], groupChatId, false, 3, makeTextMessage("3")));
history.push_back(makeMessage(2, userIds[0], groupChatId, false, 2, makeTextMessage("2")));
tgl.reply(make_object<messages>(history.size(), std::move(history)));
prpl.verifyNoEvents();
tgl.verifyRequest(getChatHistory(groupChatId, 2, 0, 30, false));
pluginInfo().close(connection);
prpl.verifyEvents(
ServGotJoinedChatEvent(connection, purpleChatId, groupChatPurpleName, groupChatTitle),
ChatSetTopicEvent(groupChatPurpleName, "", ""),
ChatClearUsersEvent(groupChatPurpleName),
ServGotChatEvent(connection, purpleChatId, userNameInChat, "2", PURPLE_MESSAGE_RECV, 2),
ServGotChatEvent(connection, purpleChatId, userNameInChat, "3", PURPLE_MESSAGE_RECV, 3),
ServGotChatEvent(connection, purpleChatId, userNameInChat, "4", PURPLE_MESSAGE_RECV, 4),
ServGotChatEvent(connection, purpleChatId, userNameInChat, "5", PURPLE_MESSAGE_RECV, 5),
ServGotChatEvent(connection, purpleChatId, userNameInChat, "6", PURPLE_MESSAGE_RECV, 6)
);
tgl.verifyRequest(viewMessages(groupChatId, {6, 5, 4, 3, 2}, true));
ASSERT_EQ(std::string("6"), std::string(purple_account_get_string(
account, ("last-message-chat" + std::to_string(groupChatId)).c_str(), "")));
}

View File

@ -1,20 +1,8 @@
#include "fixture.h"
#include "supergroup-test.h"
#include <glib/gstrfuncs.h>
static const char *NotificationWho = " ";
class SupergroupTest: public CommTest {
protected:
const int32_t groupId = 700;
const int64_t groupChatId = -7000;
const std::string groupChatTitle = "Title";
const std::string groupChatPurpleName = "chat" + std::to_string(groupChatId);
void loginWithSupergroup(object_ptr<supergroupFullInfo> fullInfo = nullptr,
object_ptr<chatMembers> recentMembers = nullptr,
object_ptr<chatMembers> administrators = nullptr);
};
void SupergroupTest::loginWithSupergroup(object_ptr<supergroupFullInfo> fullInfo,
object_ptr<chatMembers> recentMembers,
object_ptr<chatMembers> administrators)

18
test/supergroup-test.h Normal file
View File

@ -0,0 +1,18 @@
#ifndef _SUPERGROUP_TEST_H
#define _SUPERGROUP_TEST_H
#include "fixture.h"
class SupergroupTest: public CommTest {
protected:
const int32_t groupId = 700;
const int64_t groupChatId = -7000;
const std::string groupChatTitle = "Title";
const std::string groupChatPurpleName = "chat" + std::to_string(groupChatId);
void loginWithSupergroup(object_ptr<supergroupFullInfo> fullInfo = nullptr,
object_ptr<chatMembers> recentMembers = nullptr,
object_ptr<chatMembers> administrators = nullptr);
};
#endif

View File

@ -457,6 +457,15 @@ static void compare(const createNewSecretChat &actual, const createNewSecretChat
COMPARE(user_id_);
}
static void compare(const getChatHistory &actual, const getChatHistory &expected)
{
COMPARE(chat_id_);
COMPARE(from_message_id_);
COMPARE(offset_);
COMPARE(limit_);
COMPARE(only_local_);
}
static void compareRequests(const Function &actual, const Function &expected,
std::vector<std::string> &m_inputPhotoPaths)
{
@ -508,6 +517,7 @@ static void compareRequests(const Function &actual, const Function &expected,
C(searchPublicChat)
C(joinChat)
C(createNewSecretChat)
C(getChatHistory)
default: ASSERT_TRUE(false) << "Unsupported request " << requestToString(actual);
}
}