From 2a805d24fe5af11da527ed68086c093e6daf008a Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?Fran=C3=A7ois-Simon=20Fauteux-Chapleau?=
 <francois-simon.fauteux-chapleau@savoirfairelinux.com>
Date: Mon, 15 Jul 2024 14:36:12 -0400
Subject: [PATCH] jamiaccount: fix deadlock

This patch moves the updateConvForContact function from JamiAccount to
ConversationModule. This fixes a deadlock that sometimes occurred when
starting Jami.

GitLab: #1033
Change-Id: I441426fa339e5cfb327566df6132bfecb206bd1e
---
 src/jamidht/conversation_module.cpp         | 50 +++++++++++++++------
 src/jamidht/conversation_module.h           | 13 +++++-
 src/jamidht/jamiaccount.cpp                 | 31 +------------
 src/jamidht/jamiaccount.h                   | 11 -----
 test/unitTest/conversation/conversation.cpp |  2 +-
 5 files changed, 50 insertions(+), 57 deletions(-)

diff --git a/src/jamidht/conversation_module.cpp b/src/jamidht/conversation_module.cpp
index 1a9076ea1c..c5c39115d3 100644
--- a/src/jamidht/conversation_module.cpp
+++ b/src/jamidht/conversation_module.cpp
@@ -128,7 +128,6 @@ public:
          SengMsgCb&& sendMsgCb,
          NeedSocketCb&& onNeedSocket,
          NeedSocketCb&& onNeedSwarmSocket,
-         UpdateConvReq&& updateConvReqCb,
          OneToOneRecvCb&& oneToOneRecvCb);
 
     template<typename S, typename T>
@@ -248,6 +247,11 @@ public:
 
     std::string getOneToOneConversation(const std::string& uri) const noexcept;
 
+    bool updateConvForContact(const std::string& uri,
+                              const std::string& oldConv,
+                              const std::string& newConv);
+
+
     std::shared_ptr<SyncedConversation> getConversation(std::string_view convId) const
     {
         std::lock_guard lk(conversationsMtx_);
@@ -373,7 +377,6 @@ public:
     SengMsgCb sendMsgCb_;
     NeedSocketCb onNeedSocket_;
     NeedSocketCb onNeedSwarmSocket_;
-    UpdateConvReq updateConvReqCb_;
     OneToOneRecvCb oneToOneRecvCb_;
 
     std::string accountId_ {};
@@ -457,7 +460,6 @@ ConversationModule::Impl::Impl(std::shared_ptr<JamiAccount>&& account,
                                SengMsgCb&& sendMsgCb,
                                NeedSocketCb&& onNeedSocket,
                                NeedSocketCb&& onNeedSwarmSocket,
-                               UpdateConvReq&& updateConvReqCb,
                                OneToOneRecvCb&& oneToOneRecvCb)
     : account_(account)
     , accountManager_(accountManager)
@@ -465,7 +467,6 @@ ConversationModule::Impl::Impl(std::shared_ptr<JamiAccount>&& account,
     , sendMsgCb_(sendMsgCb)
     , onNeedSocket_(onNeedSocket)
     , onNeedSwarmSocket_(onNeedSwarmSocket)
-    , updateConvReqCb_(updateConvReqCb)
     , oneToOneRecvCb_(oneToOneRecvCb)
     , accountId_(account->getAccountID())
 {
@@ -907,6 +908,25 @@ ConversationModule::Impl::getOneToOneConversation(const std::string& uri) const
     return {};
 }
 
+bool
+ConversationModule::Impl::updateConvForContact(const std::string& uri,
+                                               const std::string& oldConv,
+                                               const std::string& newConv)
+{
+    if (newConv != oldConv) {
+        auto conversation = getOneToOneConversation(uri);
+        if (conversation != oldConv) {
+            JAMI_DEBUG("Old conversation is not found in details {} - found: {}",
+                       oldConv,
+                       conversation);
+            return false;
+        }
+        accountManager_->updateContactConversation(uri, newConv);
+        return true;
+    }
+    return false;
+}
+
 void
 ConversationModule::Impl::declineOtherConversationWith(const std::string& uri) noexcept
 {
@@ -1027,8 +1047,8 @@ ConversationModule::Impl::removeConversationImpl(SyncedConversation& conv)
         }
     } else {
         for (const auto& m : members)
-            if (username_ != m.at("uri") && updateConvReqCb_)
-                updateConvReqCb_(conv.info.id, m.at("uri"), false);
+            if (username_ != m.at("uri"))
+                updateConvForContact(m.at("uri"), conv.info.id, "");
     }
     // Else we are the last member, so we can remove
     removeRepositoryImpl(conv, true);
@@ -1253,7 +1273,7 @@ ConversationModule::Impl::fixStructures(
     const std::set<std::string>& toRm)
 {
     for (const auto& [uri, oldConv, newConv] : updateContactConv) {
-        acc->updateConvForContact(uri, oldConv, newConv);
+        updateConvForContact(uri, oldConv, newConv);
     }
     ////////////////////////////////////////////////////////////////
     // Note: This is only to homogeneize trust and convRequests
@@ -1491,7 +1511,6 @@ ConversationModule::ConversationModule(std::shared_ptr<JamiAccount> account,
                                        SengMsgCb&& sendMsgCb,
                                        NeedSocketCb&& onNeedSocket,
                                        NeedSocketCb&& onNeedSwarmSocket,
-                                       UpdateConvReq&& updateConvReqCb,
                                        OneToOneRecvCb&& oneToOneRecvCb,
                                        bool autoLoadConversations)
     : pimpl_ {std::make_unique<Impl>(std::move(account),
@@ -1500,7 +1519,6 @@ ConversationModule::ConversationModule(std::shared_ptr<JamiAccount> account,
                                      std::move(sendMsgCb),
                                      std::move(onNeedSocket),
                                      std::move(onNeedSwarmSocket),
-                                     std::move(updateConvReqCb),
                                      std::move(oneToOneRecvCb))}
 {
     if (autoLoadConversations) {
@@ -1846,6 +1864,14 @@ ConversationModule::getOneToOneConversation(const std::string& uri) const noexce
     return pimpl_->getOneToOneConversation(uri);
 }
 
+bool
+ConversationModule::updateConvForContact(const std::string& uri,
+                                         const std::string& oldConv,
+                                         const std::string& newConv)
+{
+    return pimpl_->updateConvForContact(uri, oldConv, newConv);
+}
+
 std::vector<std::map<std::string, std::string>>
 ConversationModule::getConversationRequests() const
 {
@@ -2003,8 +2029,7 @@ ConversationModule::acceptConversationRequest(const std::string& conversationId,
     }
     pimpl_->rmConversationRequest(conversationId);
     lkCr.unlock();
-    if (pimpl_->updateConvReqCb_)
-        pimpl_->updateConvReqCb_(conversationId, request->from, true);
+    pimpl_->accountManager_->acceptTrustRequest(request->from, true);
     cloneConversationFrom(conversationId, request->from);
 }
 
@@ -2816,8 +2841,7 @@ ConversationModule::removeContact(const std::string& uri, bool banned)
     auto isSelf = uri == pimpl_->username_;
     std::vector<std::string> toRm;
     auto updateClient = [&](const auto& convId) {
-        if (pimpl_->updateConvReqCb_)
-            pimpl_->updateConvReqCb_(convId, uri, false);
+        pimpl_->updateConvForContact(uri, convId, "");
         emitSignal<libjami::ConversationSignal::ConversationRemoved>(pimpl_->accountId_, convId);
     };
     auto removeConvInfo = [&](const auto& conv, const auto& members) {
diff --git a/src/jamidht/conversation_module.h b/src/jamidht/conversation_module.h
index 3f89f1b30d..bfbd9462b9 100644
--- a/src/jamidht/conversation_module.h
+++ b/src/jamidht/conversation_module.h
@@ -66,7 +66,6 @@ using NeedSocketCb
 using SengMsgCb = std::function<
     uint64_t(const std::string&, const DeviceId&, std::map<std::string, std::string>, uint64_t)>;
 using NeedsSyncingCb = std::function<void(std::shared_ptr<SyncMsg>&&)>;
-using UpdateConvReq = std::function<void(const std::string&, const std::string&, bool)>;
 using OneToOneRecvCb = std::function<void(const std::string&, const std::string&)>;
 
 class ConversationModule
@@ -78,7 +77,6 @@ public:
                        SengMsgCb&& sendMsgCb,
                        NeedSocketCb&& onNeedSocket,
                        NeedSocketCb&& onNeedSwarmSocket,
-                       UpdateConvReq&& updateConvReqCb,
                        OneToOneRecvCb&& oneToOneRecvCb,
                        bool autoLoadConversations = true);
     ~ConversationModule() = default;
@@ -125,6 +123,17 @@ public:
      */
     std::string getOneToOneConversation(const std::string& uri) const noexcept;
 
+    /**
+     * Replace linked conversation in contact's details
+     * @param uri           Of the contact
+     * @param oldConv       Current conversation
+     * @param newConv
+     * @return if replaced
+     */
+    bool updateConvForContact(const std::string& uri,
+                              const std::string& oldConv,
+                              const std::string& newConv);
+
     /**
      * Return conversation's requests
      */
diff --git a/src/jamidht/jamiaccount.cpp b/src/jamidht/jamiaccount.cpp
index 5638828da0..0112f6738c 100644
--- a/src/jamidht/jamiaccount.cpp
+++ b/src/jamidht/jamiaccount.cpp
@@ -1208,7 +1208,7 @@ JamiAccount::loadAccount(const std::string& archive_password_scheme,
                         // TODO: In the future, we may want to re-commit the messages we
                         // may have send in the request we sent.
                         if (oldConv != convFromReq
-                            && shared->updateConvForContact(uri, oldConv, convFromReq)) {
+                            && cm->updateConvForContact(uri, oldConv, convFromReq)) {
                             cm->initReplay(oldConv, convFromReq);
                             cm->cloneConversationFrom(convFromReq, uri, oldConv);
                         }
@@ -2268,15 +2268,6 @@ JamiAccount::convModule(bool noCreation)
                     }
                 });
             },
-            [this](auto&& convId, auto&& contactUri, bool accept) {
-                // NOTE: do not reschedule as the conversation's requests
-                // should be synched with trust requests
-                if (accept) {
-                    accountManager_->acceptTrustRequest(contactUri, true);
-                } else {
-                    updateConvForContact(contactUri, convId, "");
-                }
-            },
             [this](auto&& convId, auto&& from) {
                 accountManager_
                     ->findCertificate(dht::InfoHash(from),
@@ -2815,26 +2806,6 @@ JamiAccount::removeContact(const std::string& uri, bool ban)
         JAMI_WARNING("[Account {}] removeContact: account not loaded", getAccountID());
 }
 
-bool
-JamiAccount::updateConvForContact(const std::string& uri,
-                                  const std::string& oldConv,
-                                  const std::string& newConv)
-{
-    auto cm = convModule(false);
-    if (newConv != oldConv && cm) {
-        auto conversation = cm->getOneToOneConversation(uri);
-        if (conversation != oldConv) {
-            JAMI_DEBUG("Old conversation is not found in details {} - found: {}",
-                       oldConv,
-                       conversation);
-            return false;
-        }
-        accountManager_->updateContactConversation(uri, newConv);
-        return true;
-    }
-    return false;
-}
-
 std::map<std::string, std::string>
 JamiAccount::getContactDetails(const std::string& uri) const
 {
diff --git a/src/jamidht/jamiaccount.h b/src/jamidht/jamiaccount.h
index e0b533ff90..347deb409a 100644
--- a/src/jamidht/jamiaccount.h
+++ b/src/jamidht/jamiaccount.h
@@ -303,17 +303,6 @@ public:
     void removeContact(const std::string& uri, bool banned = true);
     std::vector<std::map<std::string, std::string>> getContacts(bool includeRemoved = false) const;
 
-    /**
-     * Replace in contact's details related conversation
-     * @param uri           Of the contact
-     * @param oldConv       Current conversation
-     * @param newConv
-     * @return if replaced
-     */
-    bool updateConvForContact(const std::string& uri,
-                              const std::string& oldConv,
-                              const std::string& newConv);
-
     ///
     /// Obtain details about one account contact in serializable form.
     ///
diff --git a/test/unitTest/conversation/conversation.cpp b/test/unitTest/conversation/conversation.cpp
index 0979182f95..a9a0baef78 100644
--- a/test/unitTest/conversation/conversation.cpp
+++ b/test/unitTest/conversation/conversation.cpp
@@ -2145,7 +2145,7 @@ ConversationTest::testFixContactDetails()
     auto details = aliceAccount->getContactDetails(bobUri);
     CPPUNIT_ASSERT(details["conversationId"] == aliceData.conversationId);
     // Erase convId from contact details, this should be fixed by next reload.
-    CPPUNIT_ASSERT(aliceAccount->updateConvForContact(bobUri, aliceData.conversationId, ""));
+    CPPUNIT_ASSERT(aliceAccount->convModule()->updateConvForContact(bobUri, aliceData.conversationId, ""));
     details = aliceAccount->getContactDetails(bobUri);
     CPPUNIT_ASSERT(details["conversationId"].empty());
 
-- 
GitLab