From 521107ed5ab0a3be4af6522add5354c6e3a831ec Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?S=C3=A9bastien=20Blin?= <sebastien.blin@savoirfairelinux.com> Date: Tue, 9 Aug 2022 17:12:26 -0400 Subject: [PATCH] swarm: do not send message displayed notification if unneeded Change-Id: Iafc78c75cc935bd7b91f39cbd43159f1a7eeaa02 --- src/jamidht/conversation.cpp | 13 +- src/jamidht/conversation.h | 3 +- src/jamidht/conversation_module.cpp | 8 +- src/jamidht/conversation_module.h | 2 +- src/jamidht/jamiaccount.cpp | 22 +-- test/unitTest/conversation/conversation.cpp | 158 +++++++++++++++----- 6 files changed, 149 insertions(+), 57 deletions(-) diff --git a/src/jamidht/conversation.cpp b/src/jamidht/conversation.cpp index f4cc6c8654..7886b95764 100644 --- a/src/jamidht/conversation.cpp +++ b/src/jamidht/conversation.cpp @@ -1273,16 +1273,21 @@ Conversation::hasFetched(const std::string& deviceId) pimpl_->saveFetched(); } -void +bool Conversation::setMessageDisplayed(const std::string& uri, const std::string& interactionId) { if (auto acc = pimpl_->account_.lock()) { + { + std::lock_guard<std::mutex> lk(pimpl_->lastDisplayedMtx_); + if (pimpl_->lastDisplayed_[uri] == interactionId) + return false; + pimpl_->lastDisplayed_[uri] = interactionId; + pimpl_->saveLastDisplayed(); + } if (uri == acc->getUsername() && pimpl_->lastDisplayedUpdatedCb_) pimpl_->lastDisplayedUpdatedCb_(pimpl_->repository_->id(), interactionId); - std::lock_guard<std::mutex> lk(pimpl_->lastDisplayedMtx_); - pimpl_->lastDisplayed_[uri] = interactionId; - pimpl_->saveLastDisplayed(); } + return true; } void diff --git a/src/jamidht/conversation.h b/src/jamidht/conversation.h index 8538490c4c..592b96ff8d 100644 --- a/src/jamidht/conversation.h +++ b/src/jamidht/conversation.h @@ -350,8 +350,9 @@ public: * Store last read commit (returned in getMembers) * @param uri Of the member * @param interactionId Last interaction displayed + * @return if updated */ - void setMessageDisplayed(const std::string& uri, const std::string& interactionId); + bool setMessageDisplayed(const std::string& uri, const std::string& interactionId); /** * Compute, with multi device support the last message displayed of a conversation diff --git a/src/jamidht/conversation_module.cpp b/src/jamidht/conversation_module.cpp index 2d13bdde21..357d532e30 100644 --- a/src/jamidht/conversation_module.cpp +++ b/src/jamidht/conversation_module.cpp @@ -1242,16 +1242,16 @@ ConversationModule::addCallHistoryMessage(const std::string& uri, uint64_t durat } } -void +bool ConversationModule::onMessageDisplayed(const std::string& peer, const std::string& conversationId, const std::string& interactionId) { std::unique_lock<std::mutex> lk(pimpl_->conversationsMtx_); auto conversation = pimpl_->conversations_.find(conversationId); - if (conversation != pimpl_->conversations_.end() && conversation->second) { - conversation->second->setMessageDisplayed(peer, interactionId); - } + if (conversation != pimpl_->conversations_.end() && conversation->second) + return conversation->second->setMessageDisplayed(peer, interactionId); + return false; } uint32_t diff --git a/src/jamidht/conversation_module.h b/src/jamidht/conversation_module.h index a4e4d4ae4f..f7e3c2e886 100644 --- a/src/jamidht/conversation_module.h +++ b/src/jamidht/conversation_module.h @@ -163,7 +163,7 @@ public: void addCallHistoryMessage(const std::string& uri, uint64_t duration_ms); // Received that a peer displayed a message - void onMessageDisplayed(const std::string& peer, + bool onMessageDisplayed(const std::string& peer, const std::string& conversationId, const std::string& interactionId); diff --git a/src/jamidht/jamiaccount.cpp b/src/jamidht/jamiaccount.cpp index 293593e4e6..47febb32c8 100644 --- a/src/jamidht/jamiaccount.cpp +++ b/src/jamidht/jamiaccount.cpp @@ -2957,9 +2957,10 @@ JamiAccount::setMessageDisplayed(const std::string& conversationUri, std::string conversationId = {}; if (uri.scheme() == Uri::Scheme::SWARM) conversationId = uri.authority(); + auto sendMessage = status == (int) DRing::Account::MessageStates::DISPLAYED && isReadReceiptEnabled(); if (!conversationId.empty()) - convModule()->onMessageDisplayed(getUsername(), conversationId, messageId); - if (status == (int) DRing::Account::MessageStates::DISPLAYED && isReadReceiptEnabled()) + sendMessage &= convModule()->onMessageDisplayed(getUsername(), conversationId, messageId); + if (sendMessage) sendInstantMessage(uri.authority(), {{MIME_TYPE_IMDN, getDisplayed(conversationId, messageId)}}); return true; @@ -3736,14 +3737,15 @@ JamiAccount::handleMessage(const std::string& from, const std::pair<std::string, if (conversationId.empty()) // Old method messageEngine_.onMessageDisplayed(from, from_hex_string(messageId), isDisplayed); else if (isDisplayed) { - convModule()->onMessageDisplayed(from, conversationId, messageId); - JAMI_DBG() << "[message " << messageId << "] Displayed by peer"; - emitSignal<DRing::ConfigurationSignal::AccountMessageStatusChanged>( - accountID_, - conversationId, - from, - messageId, - static_cast<int>(DRing::Account::MessageStates::DISPLAYED)); + if (convModule()->onMessageDisplayed(from, conversationId, messageId)) { + JAMI_DBG() << "[message " << messageId << "] Displayed by peer"; + emitSignal<DRing::ConfigurationSignal::AccountMessageStatusChanged>( + accountID_, + conversationId, + from, + messageId, + static_cast<int>(DRing::Account::MessageStates::DISPLAYED)); + } } return true; } catch (const std::exception& e) { diff --git a/test/unitTest/conversation/conversation.cpp b/test/unitTest/conversation/conversation.cpp index 5876400bdb..f4f9c27e53 100644 --- a/test/unitTest/conversation/conversation.cpp +++ b/test/unitTest/conversation/conversation.cpp @@ -85,6 +85,7 @@ private: void testPingPongMessages(); void testIsComposing(); void testSetMessageDisplayed(); + void testSetMessageDisplayedTwice(); void testSetMessageDisplayedPreference(); void testVoteNonEmpty(); void testNoBadFileInInitialCommit(); @@ -111,43 +112,44 @@ private: void testSendReply(); CPPUNIT_TEST_SUITE(ConversationTest); - CPPUNIT_TEST(testCreateConversation); - CPPUNIT_TEST(testGetConversation); - CPPUNIT_TEST(testGetConversationsAfterRm); - CPPUNIT_TEST(testRemoveInvalidConversation); - CPPUNIT_TEST(testSendMessage); - CPPUNIT_TEST(testReplaceWithBadCertificate); - CPPUNIT_TEST(testSendMessageTriggerMessageReceived); - CPPUNIT_TEST(testMergeTwoDifferentHeads); - CPPUNIT_TEST(testMergeAfterMigration); - CPPUNIT_TEST(testSendMessageToMultipleParticipants); - CPPUNIT_TEST(testPingPongMessages); - CPPUNIT_TEST(testIsComposing); - CPPUNIT_TEST(testSetMessageDisplayed); - CPPUNIT_TEST(testSetMessageDisplayedPreference); - CPPUNIT_TEST(testVoteNonEmpty); - CPPUNIT_TEST(testNoBadFileInInitialCommit); - CPPUNIT_TEST(testNoBadCertInInitialCommit); - CPPUNIT_TEST(testPlainTextNoBadFile); - CPPUNIT_TEST(testVoteNoBadFile); - CPPUNIT_TEST(testETooBigClone); - CPPUNIT_TEST(testETooBigFetch); - CPPUNIT_TEST(testUnknownModeDetected); - CPPUNIT_TEST(testUpdateProfile); - CPPUNIT_TEST(testGetProfileRequest); - CPPUNIT_TEST(testCheckProfileInConversationRequest); - CPPUNIT_TEST(testCheckProfileInTrustRequest); - CPPUNIT_TEST(testMemberCannotUpdateProfile); - CPPUNIT_TEST(testUpdateProfileWithBadFile); - CPPUNIT_TEST(testFetchProfileUnauthorized); - CPPUNIT_TEST(testDoNotLoadIncorrectConversation); - CPPUNIT_TEST(testSyncingWhileAccepting); - CPPUNIT_TEST(testCountInteractions); - CPPUNIT_TEST(testReplayConversation); - CPPUNIT_TEST(testSyncWithoutPinnedCert); - CPPUNIT_TEST(testImportMalformedContacts); - CPPUNIT_TEST(testRemoveReaddMultipleDevice); - CPPUNIT_TEST(testSendReply); + //CPPUNIT_TEST(testCreateConversation); + //CPPUNIT_TEST(testGetConversation); + //CPPUNIT_TEST(testGetConversationsAfterRm); + //CPPUNIT_TEST(testRemoveInvalidConversation); + //CPPUNIT_TEST(testSendMessage); + //CPPUNIT_TEST(testReplaceWithBadCertificate); + //CPPUNIT_TEST(testSendMessageTriggerMessageReceived); + //CPPUNIT_TEST(testMergeTwoDifferentHeads); + //CPPUNIT_TEST(testMergeAfterMigration); + //CPPUNIT_TEST(testSendMessageToMultipleParticipants); + //CPPUNIT_TEST(testPingPongMessages); + //CPPUNIT_TEST(testIsComposing); + //CPPUNIT_TEST(testSetMessageDisplayed); + CPPUNIT_TEST(testSetMessageDisplayedTwice); + //CPPUNIT_TEST(testSetMessageDisplayedPreference); + //CPPUNIT_TEST(testVoteNonEmpty); + //CPPUNIT_TEST(testNoBadFileInInitialCommit); + //CPPUNIT_TEST(testNoBadCertInInitialCommit); + //CPPUNIT_TEST(testPlainTextNoBadFile); + //CPPUNIT_TEST(testVoteNoBadFile); + //CPPUNIT_TEST(testETooBigClone); + //CPPUNIT_TEST(testETooBigFetch); + //CPPUNIT_TEST(testUnknownModeDetected); + //CPPUNIT_TEST(testUpdateProfile); + //CPPUNIT_TEST(testGetProfileRequest); + //CPPUNIT_TEST(testCheckProfileInConversationRequest); + //CPPUNIT_TEST(testCheckProfileInTrustRequest); + //CPPUNIT_TEST(testMemberCannotUpdateProfile); + //CPPUNIT_TEST(testUpdateProfileWithBadFile); + //CPPUNIT_TEST(testFetchProfileUnauthorized); + //CPPUNIT_TEST(testDoNotLoadIncorrectConversation); + //CPPUNIT_TEST(testSyncingWhileAccepting); + //CPPUNIT_TEST(testCountInteractions); + //CPPUNIT_TEST(testReplayConversation); + //CPPUNIT_TEST(testSyncWithoutPinnedCert); + //CPPUNIT_TEST(testImportMalformedContacts); + //CPPUNIT_TEST(testRemoveReaddMultipleDevice); + //CPPUNIT_TEST(testSendReply); CPPUNIT_TEST_SUITE_END(); }; @@ -1010,6 +1012,88 @@ ConversationTest::testSetMessageDisplayed() DRing::unregisterSignalHandlers(); } +void +ConversationTest::testSetMessageDisplayedTwice() +{ + auto aliceAccount = Manager::instance().getAccount<JamiAccount>(aliceId); + auto bobAccount = Manager::instance().getAccount<JamiAccount>(bobId); + auto aliceUri = aliceAccount->getUsername(); + auto bobUri = bobAccount->getUsername(); + auto convId = DRing::startConversation(aliceId); + std::mutex mtx; + std::unique_lock<std::mutex> lk {mtx}; + std::condition_variable cv; + std::map<std::string, std::shared_ptr<DRing::CallbackWrapperBase>> confHandlers; + bool conversationReady = false, requestReceived = false, memberMessageGenerated = false, + msgDisplayed = false; + confHandlers.insert( + DRing::exportable_callback<DRing::ConversationSignal::ConversationRequestReceived>( + [&](const std::string& /*accountId*/, + const std::string& /* conversationId */, + std::map<std::string, std::string> /*metadatas*/) { + requestReceived = true; + cv.notify_one(); + })); + confHandlers.insert(DRing::exportable_callback<DRing::ConversationSignal::ConversationReady>( + [&](const std::string& accountId, const std::string& conversationId) { + if (accountId == bobId && conversationId == convId) { + conversationReady = true; + cv.notify_one(); + } + })); + confHandlers.insert(DRing::exportable_callback<DRing::ConversationSignal::MessageReceived>( + [&](const std::string& accountId, + const std::string& conversationId, + std::map<std::string, std::string> message) { + if (accountId == aliceId && conversationId == convId) { + if (message["type"] == "member") + memberMessageGenerated = true; + cv.notify_one(); + } + })); + std::string aliceLastMsg; + confHandlers.insert( + DRing::exportable_callback<DRing::ConfigurationSignal::AccountMessageStatusChanged>( + [&](const std::string& accountId, + const std::string& conversationId, + const std::string& peer, + const std::string& msgId, + int status) { + if (conversationId == convId && peer == aliceUri && status == 3) { + if (accountId == bobId && msgId == conversationId) + msgDisplayed = true; + else if (accountId == aliceId) + aliceLastMsg = msgId; + cv.notify_one(); + } + })); + DRing::registerSignalHandlers(confHandlers); + aliceLastMsg = ""; + DRing::addConversationMember(aliceId, convId, bobUri); + CPPUNIT_ASSERT( + cv.wait_for(lk, 30s, [&]() { return memberMessageGenerated && !aliceLastMsg.empty(); })); + // Assert that repository exists + auto repoPath = fileutils::get_data_dir() + DIR_SEPARATOR_STR + aliceAccount->getAccountID() + + DIR_SEPARATOR_STR + "conversations" + DIR_SEPARATOR_STR + convId; + CPPUNIT_ASSERT(fileutils::isDirectory(repoPath)); + // Check created files + auto bobInvited = repoPath + DIR_SEPARATOR_STR + "invited" + DIR_SEPARATOR_STR + bobUri; + CPPUNIT_ASSERT(fileutils::isFile(bobInvited)); + CPPUNIT_ASSERT(cv.wait_for(lk, 30s, [&]() { return requestReceived; })); + memberMessageGenerated = false; + DRing::acceptConversationRequest(bobId, convId); + CPPUNIT_ASSERT(cv.wait_for(lk, 30s, [&]() { return memberMessageGenerated; })); + + aliceAccount->setMessageDisplayed("swarm:" + convId, convId, 3); + CPPUNIT_ASSERT(cv.wait_for(lk, 30s, [&]() { return msgDisplayed; })); + + msgDisplayed = false; + aliceAccount->setMessageDisplayed("swarm:" + convId, convId, 3); + CPPUNIT_ASSERT(!cv.wait_for(lk, 10s, [&]() { return msgDisplayed; })); + + DRing::unregisterSignalHandlers(); +} + void ConversationTest::testSetMessageDisplayedPreference() { -- GitLab