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

Prevent message duplication after fetching skipped messages

This commit is contained in:
Arseniy Lartsev 2021-01-03 14:20:23 +01:00
parent 41b514634b
commit 92fa3f314f
5 changed files with 73 additions and 30 deletions

View File

@ -1056,7 +1056,7 @@ void handleIncomingMessage(TdAccountData &account, const td::td_api::chat &chat,
static void fetchHistoryRequest(TdAccountData &account, ChatId chatId, unsigned messagesFetched,
MessageId fetchBackFrom, MessageId lastReceivedMessage);
static void fetchHistoryResponse(TdAccountData &account, ChatId chatId, MessageId lastReceivedMessage,
static void fetchHistoryResponse(TdAccountData &account, ChatId chatId, MessageId stopAt,
unsigned messagesFetched,
td::td_api::object_ptr<td::td_api::Object> response)
{
@ -1075,12 +1075,12 @@ static void fetchHistoryResponse(TdAccountData &account, ChatId chatId, MessageI
purple_debug_warning(config::pluginId, "Erroneous message in history, stopping\n");
break;
}
if (lastReceivedMessage.valid() && (getId(*message) == lastReceivedMessage)) {
if (stopAt.valid() && (getId(*message) == stopAt)) {
purple_debug_misc(config::pluginId, "Found message %" G_GINT64_FORMAT ", stopping\n",
lastReceivedMessage.value());
stopAt.value());
break;
}
if ((!lastReceivedMessage.valid() && (messagesFetched == 100)) ||
if ((!stopAt.valid() && (messagesFetched == 100)) ||
(messagesFetched == HISTORY_MESSAGES_ABSOLUTE_LIMIT))
{
purple_debug_misc(config::pluginId, "Reached history limit, stopping\n");
@ -1103,7 +1103,7 @@ static void fetchHistoryResponse(TdAccountData &account, ChatId chatId, MessageI
}
if (requestMoreFrom.valid())
fetchHistoryRequest(account, chatId, messagesFetched, requestMoreFrom, lastReceivedMessage);
fetchHistoryRequest(account, chatId, messagesFetched, requestMoreFrom, stopAt);
else {
purple_debug_misc(config::pluginId, "Done fetching history for chat %" G_GINT64_FORMAT "\n",
chatId.value());
@ -1114,7 +1114,7 @@ static void fetchHistoryResponse(TdAccountData &account, ChatId chatId, MessageI
}
static void fetchHistoryRequest(TdAccountData &account, ChatId chatId, unsigned messagesFetched,
MessageId fetchBackFrom, MessageId lastReceivedMessage)
MessageId fetchBackFrom, MessageId stopAt)
{
auto request = td::td_api::make_object<td::td_api::getChatHistory>();
request->chat_id_ = chatId.value();
@ -1125,16 +1125,16 @@ static void fetchHistoryRequest(TdAccountData &account, ChatId chatId, unsigned
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));
[&account, chatId, messagesFetched, stopAt](uint64_t requestId, td::td_api::object_ptr<td::td_api::Object> response) {
fetchHistoryResponse(account, chatId, stopAt, messagesFetched, std::move(response));
});
}
void fetchHistory(TdAccountData &account, ChatId chatId, MessageId lastReceivedMessage)
void fetchHistory(TdAccountData &account, ChatId chatId, MessageId fetchFrom, MessageId stopAt)
{
if (!account.pendingMessages.isChatReady(chatId))
return;
account.pendingMessages.setChatNotReady(chatId);
fetchHistoryRequest(account, chatId, 0, MessageId::invalid, lastReceivedMessage);
fetchHistoryRequest(account, chatId, 0, fetchFrom, stopAt);
}

View File

@ -53,7 +53,7 @@ void checkMessageReady(const IncomingMessage *message, TdTransceiver &transceive
void handleIncomingMessage(TdAccountData &account, const td::td_api::chat &chat,
td::td_api::object_ptr<td::td_api::message> message,
PendingMessageQueue::MessageAction action);
void fetchHistory(TdAccountData &account, ChatId chatId, MessageId lastReceivedMessage);
void fetchHistory(TdAccountData &account, ChatId chatId, MessageId fetchFrom, MessageId stopAt);
#endif

View File

@ -173,19 +173,7 @@ void PurpleTdClient::processUpdate(td::td_api::Object &update)
case td::td_api::updateChatLastMessage::ID: {
auto &lastMessage = static_cast<td::td_api::updateChatLastMessage &>(update);
ChatId chatId = getChatId(lastMessage);
m_data.updateChatOrder(chatId, lastMessage.order_);
if (lastMessage.last_message_)
saveChatLastMessage(m_data, chatId, getId(*lastMessage.last_message_));
else {
MessageId lastMessageId = getChatLastMessage(m_data, chatId);
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);
}
}
updateChatLastMessage(lastMessage);
break;
}
@ -943,8 +931,20 @@ void PurpleTdClient::onIncomingMessage(td::td_api::object_ptr<td::td_api::messag
{
if (!message)
return;
ChatId chatId = getChatId(*message);
auto pGap = std::find_if(m_chatGaps.begin(), m_chatGaps.end(),
[chatId](const ChatGap &gap) { return (gap.chatId == chatId); });
if (pGap != m_chatGaps.end()) {
MessageId lastMessageId = pGap->lastMessage;
m_chatGaps.erase(pGap);
purple_debug_misc(config::pluginId,
"Fetching skipped messages for chat %" G_GINT64_FORMAT
" between %" G_GINT64_FORMAT " and %" G_GINT64_FORMAT "\n",
chatId.value(), lastMessageId.value(), getId(*message).value());
fetchHistory(m_data, chatId, getId(*message), lastMessageId);
}
const td::td_api::chat *chat = m_data.getChat(chatId);
if (!chat) {
purple_debug_warning(config::pluginId, "Received message with unknown chat id %" G_GINT64_FORMAT "\n",
@ -955,6 +955,31 @@ void PurpleTdClient::onIncomingMessage(td::td_api::object_ptr<td::td_api::messag
handleIncomingMessage(m_data, *chat, std::move(message), PendingMessageQueue::Append);
}
void PurpleTdClient::updateChatLastMessage(const td::td_api::updateChatLastMessage &lastMessage)
{
ChatId chatId = getChatId(lastMessage);
m_data.updateChatOrder(chatId, lastMessage.order_);
if (lastMessage.last_message_)
saveChatLastMessage(m_data, chatId, getId(*lastMessage.last_message_));
else {
MessageId lastMessageId = getChatLastMessage(m_data, chatId);
if (lastMessageId.valid()) {
purple_debug_misc(config::pluginId,
"Skipped messages detected for chat %" G_GINT64_FORMAT
", last seen message %" G_GINT64_FORMAT "\n",
chatId.value(), lastMessageId.value());
if (std::find_if(m_chatGaps.begin(), m_chatGaps.end(),
[chatId](const ChatGap &gap) {
return (gap.chatId == chatId);
}) == m_chatGaps.end()) {
m_chatGaps.emplace_back();
m_chatGaps.back().chatId = chatId;
m_chatGaps.back().lastMessage = lastMessageId;
}
}
}
}
int PurpleTdClient::sendMessage(const char *buddyName, const char *message)
{
SecretChatId secretChatId = purpleBuddyNameToSecretChatId(buddyName);

View File

@ -90,8 +90,7 @@ private:
// Login sequence end
void onIncomingMessage(td::td_api::object_ptr<td::td_api::message> message);
void findMessageResponse(ChatId chatId, MessageId pendingMessageId,
td::td_api::object_ptr<td::td_api::Object> object);
void updateChatLastMessage(const td::td_api::updateChatLastMessage &lastMessage);
void updateUserStatus(UserId userId, td::td_api::object_ptr<td::td_api::UserStatus> status);
void updateUser(td::td_api::object_ptr<td::td_api::user> user);
@ -150,6 +149,12 @@ private:
std::vector<PurpleRoomlist *> m_pendingRoomLists;
td::td_api::object_ptr<td::td_api::proxy> m_addedProxy;
td::td_api::object_ptr<td::td_api::proxies> m_proxies;
struct ChatGap {
ChatId chatId;
MessageId lastMessage;
};
std::vector<ChatGap> m_chatGaps;
};
#endif

View File

@ -24,11 +24,11 @@ TEST_F(MessageHistoryTest, TdlibSkipMessages)
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.verifyRequest(getChatHistory(groupChatId, 6, 0, 30, false));
tgl.update(make_object<updateChatLastMessage>(
groupChatId,
makeMessage(6, userIds[0], groupChatId, false, 6, makeTextMessage("6")),
@ -72,7 +72,20 @@ TEST_F(MessageHistoryTest, TdlibSkipMessages)
);
tgl.verifyRequest(viewMessages(groupChatId, {6, 7, 5, 4, 3, 2}, true));
ASSERT_EQ(std::string("7"), std::string(purple_account_get_string(
tgl.update(make_object<updateNewMessage>(
makeMessage(8, userIds[0], groupChatId, false, 8, makeTextMessage("8"))
));
tgl.update(make_object<updateChatLastMessage>(
groupChatId,
makeMessage(8, userIds[0], groupChatId, false, 8, makeTextMessage("8")),
0
));
prpl.verifyEvents(
ServGotChatEvent(connection, purpleChatId, userNameInChat, "8", PURPLE_MESSAGE_RECV, 8)
);
tgl.verifyRequest(viewMessages(groupChatId, {8}, true));
ASSERT_EQ(std::string("8"), std::string(purple_account_get_string(
account, ("last-message-chat" + std::to_string(groupChatId)).c_str(), "")));
}
@ -85,11 +98,11 @@ TEST_F(MessageHistoryTest, TdlibSkipMessages_FlushAtLogout)
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.verifyRequest(getChatHistory(groupChatId, 6, 0, 30, false));
tgl.update(make_object<updateChatLastMessage>(
groupChatId,
makeMessage(6, userIds[0], groupChatId, false, 6, makeTextMessage("6")),