From b737ae27832859a136277549f4c1532bc1deac1f Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?S=C3=A9bastien=20Blin?=
 <sebastien.blin@savoirfairelinux.com>
Date: Wed, 21 Feb 2024 11:10:19 -0500
Subject: [PATCH] conversation: fix some bootstrap path

Sometimes, failed wasn't called

Change-Id: I7734518a5d186b45a6d82da14bd20948ec0976f9
---
 src/jamidht/conversation.cpp        | 76 +++++++++++++++++------------
 src/jamidht/conversation_module.cpp |  1 +
 2 files changed, 47 insertions(+), 30 deletions(-)

diff --git a/src/jamidht/conversation.cpp b/src/jamidht/conversation.cpp
index d181585748..3c5bf49484 100644
--- a/src/jamidht/conversation.cpp
+++ b/src/jamidht/conversation.cpp
@@ -2154,9 +2154,10 @@ void
 Conversation::checkBootstrapMember(const asio::error_code& ec,
                                    std::vector<std::map<std::string, std::string>> members)
 {
+    if (ec == asio::error::operation_aborted)
+        return;
     auto acc = pimpl_->account_.lock();
-    if (ec == asio::error::operation_aborted
-        or pimpl_->swarmManager_->getRoutingTable().getNodes().size() > 0 or not acc)
+    if (pimpl_->swarmManager_->getRoutingTable().getNodes().size() > 0 or not acc)
         return;
     // We bootstrap the DRT with devices who already wrote in the repository.
     // However, in a conversation, a large number of devices may just watch
@@ -2170,15 +2171,18 @@ Conversation::checkBootstrapMember(const asio::error_code& ec,
             && pimpl_->checkedMembers_.find(uri) == pimpl_->checkedMembers_.end())
             break;
     }
-    // If members is empty, we finished the fallback un-successfully
-    if (members.empty() && uri.empty()) {
+    auto fallbackFailed = [](auto sthis) {
         JAMI_WARNING("{}[SwarmManager {}] Bootstrap: Fallback failed. Wait for remote connections.",
-                     pimpl_->toString(),
-                     fmt::ptr(pimpl_->swarmManager_.get()));
+                    sthis->pimpl_->toString(),
+                    fmt::ptr(sthis->pimpl_->swarmManager_.get()));
 #ifdef LIBJAMI_TESTABLE
-        if (pimpl_->bootstrapCbTest_)
-            pimpl_->bootstrapCbTest_(id(), BootstrapStatus::FAILED);
+        if (sthis->pimpl_->bootstrapCbTest_)
+            sthis->pimpl_->bootstrapCbTest_(sthis->id(), BootstrapStatus::FAILED);
 #endif
+    };
+    // If members is empty, we finished the fallback un-successfully
+    if (members.empty() && uri.empty()) {
+        fallbackFailed(this);
         return;
     }
 
@@ -2194,7 +2198,7 @@ Conversation::checkBootstrapMember(const asio::error_code& ec,
                     devices->emplace_back(dev->getLongId());
             }
         },
-        [w = weak(), devices, members = std::move(members), uri](bool ok) {
+        [w = weak(), devices, members = std::move(members), uri, fallbackFailed=std::move(fallbackFailed)](bool ok) {
             auto sthis = w.lock();
             if (!sthis)
                 return;
@@ -2219,6 +2223,9 @@ Conversation::checkBootstrapMember(const asio::error_code& ec,
                               sthis,
                               std::placeholders::_1,
                               std::move(members)));
+            } else {
+                // In this case, all members are checked. Fallback failed
+                fallbackFailed(sthis);
             }
         });
 }
@@ -2241,9 +2248,33 @@ Conversation::bootstrap(std::function<void()> onBootstraped,
                fmt::ptr(pimpl_->swarmManager_.get()),
                devices.size());
     // set callback
-    pimpl_->swarmManager_->onConnectionChanged([w = weak()](bool ok) {
+    auto fallback = [](auto sthis, bool now = false) {
+        // Fallback
+        auto acc = sthis->pimpl_->account_.lock();
+        if (!acc)
+            return;
+        auto members = sthis->getMembers(false, false);
+        std::shuffle(members.begin(), members.end(), acc->rand);
+        if (now) {
+            sthis->pimpl_->fallbackTimer_->expires_at(std::chrono::steady_clock::now());
+        } else {
+            auto timeForBootstrap = std::min(static_cast<size_t>(8), members.size());
+            sthis->pimpl_->fallbackTimer_->expires_at(std::chrono::steady_clock::now() + 20s
+                                                        - std::chrono::seconds(timeForBootstrap));
+            JAMI_DEBUG("{}[SwarmManager {}] Fallback in {} seconds",
+                        sthis->pimpl_->toString(),
+                        fmt::ptr(sthis->pimpl_->swarmManager_.get()),
+                        (20 - timeForBootstrap));
+        }
+        sthis->pimpl_->fallbackTimer_->async_wait(std::bind(&Conversation::checkBootstrapMember,
+                                                            sthis,
+                                                            std::placeholders::_1,
+                                                            std::move(members)));
+    };
+
+    pimpl_->swarmManager_->onConnectionChanged([w = weak(), fallback](bool ok) {
         // This will call methods from accounts, so trigger on another thread.
-        dht::ThreadPool::io().run([w, ok] {
+        dht::ThreadPool::io().run([w, ok, fallback=std::move(fallback)] {
             auto sthis = w.lock();
             if (!sthis)
                 return;
@@ -2258,28 +2289,13 @@ Conversation::bootstrap(std::function<void()> onBootstraped,
 #endif
                 return;
             }
-            // Fallback
-            auto acc = sthis->pimpl_->account_.lock();
-            if (!acc)
-                return;
-            auto members = sthis->getMembers(false, false);
-            std::shuffle(members.begin(), members.end(), acc->rand);
-            // TODO decide a formula
-            auto timeForBootstrap = std::min(static_cast<size_t>(8), members.size());
-            JAMI_DEBUG("{}[SwarmManager {}] Fallback in {} seconds",
-                       sthis->pimpl_->toString(),
-                       fmt::ptr(sthis->pimpl_->swarmManager_.get()),
-                       (20 - timeForBootstrap));
-            sthis->pimpl_->fallbackTimer_->expires_at(std::chrono::steady_clock::now() + 20s
-                                                      - std::chrono::seconds(timeForBootstrap));
-            sthis->pimpl_->fallbackTimer_->async_wait(std::bind(&Conversation::checkBootstrapMember,
-                                                                sthis,
-                                                                std::placeholders::_1,
-                                                                std::move(members)));
+            fallback(sthis);
         });
     });
     pimpl_->checkedMembers_.clear();
-    pimpl_->swarmManager_->setKnownNodes(devices);
+    if (!pimpl_->swarmManager_->setKnownNodes(devices)) {
+        fallback(this, true);
+    }
 }
 
 std::vector<std::string>
diff --git a/src/jamidht/conversation_module.cpp b/src/jamidht/conversation_module.cpp
index c18d47c40a..b915ff0d20 100644
--- a/src/jamidht/conversation_module.cpp
+++ b/src/jamidht/conversation_module.cpp
@@ -1240,6 +1240,7 @@ ConversationModule::Impl::bootstrap(const std::string& convId)
     if (auto acc = account_.lock())
         for (const auto& [id, _] : acc->getKnownDevices())
             kd.emplace_back(id);
+
     auto bootstrap = [&](auto& conv) {
         if (conv) {
 #ifdef LIBJAMI_TESTABLE
-- 
GitLab