From 7e74098cbea45a2ed7fc9e85950f25b437f33796 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?S=C3=A9bastien=20Blin?= <sebastien.blin@savoirfairelinux.com> Date: Mon, 25 Jul 2022 16:14:55 -0400 Subject: [PATCH] swarm: announce all messages updated when merging This will facilitate the work of the client in order to order messages as linearized parents for all commits until the merge base can be updated. Change-Id: I95266174d58913fbfb2ca665da18b08475aa9c93 --- src/jamidht/conversation.cpp | 34 +++++++++++++++++------- src/jamidht/conversationrepository.cpp | 36 +++++++++++++++++++++----- src/jamidht/conversationrepository.h | 8 ++++++ 3 files changed, 62 insertions(+), 16 deletions(-) diff --git a/src/jamidht/conversation.cpp b/src/jamidht/conversation.cpp index ef03874bfa..f4cc6c8654 100644 --- a/src/jamidht/conversation.cpp +++ b/src/jamidht/conversation.cpp @@ -993,17 +993,35 @@ Conversation::Impl::pull() cb(false); continue; } - auto oldId = repo->getHead(); + auto oldHead = repo->getHead(); + std::string newHead = oldHead; std::unique_lock<std::mutex> lk(writeMtx_); - auto newCommits = mergeHistory(deviceId); - announce(newCommits); + auto commits = mergeHistory(deviceId); + if (!commits.empty()) { + newHead = commits.rbegin()->at("id"); + // Note: Because clients needs to linearize the history, they need to know all commits + // that can be updated. + // In this case, all commits until the common merge base should be announced. + // The client ill need to update it's model after this. + std::string mergeBase = oldHead; // If fast-forward, the merge base is the previous head + auto newHeadCommit = repo->getCommit(newHead); + if (newHeadCommit != std::nullopt && newHeadCommit->parents.size() > 1) { + mergeBase = repo->mergeBase(newHeadCommit->parents[0], newHeadCommit->parents[1]); + auto updatedCommits = loadMessages("", mergeBase); + // We announce commits from oldest to update to newest. This generally avoid + // to get detached commits until they are all announced. + std::reverse(std::begin(updatedCommits), std::end(updatedCommits)); + announce(updatedCommits); + } else { + announce(commits); + } + } lk.unlock(); if (cb) cb(true); // Announce if profile changed - auto newId = repo->getHead(); - if (oldId != newId) { - auto diffStats = repo->diffStats(newId, oldId); + if (oldHead != newHead) { + auto diffStats = repo->diffStats(newHead, oldHead); auto changedFiles = repo->changedFiles(diffStats); if (find(changedFiles.begin(), changedFiles.end(), "profile.vcf") != changedFiles.end()) { @@ -1050,9 +1068,7 @@ Conversation::generateInvitation() const Json::StreamWriterBuilder wbuilder; wbuilder["commentStyle"] = "None"; wbuilder["indentation"] = ""; - return { - {"application/invite+json", Json::writeString(wbuilder, root)} - }; + return {{"application/invite+json", Json::writeString(wbuilder, root)}}; } std::string diff --git a/src/jamidht/conversationrepository.cpp b/src/jamidht/conversationrepository.cpp index 61c9d48e3f..129420ddd2 100644 --- a/src/jamidht/conversationrepository.cpp +++ b/src/jamidht/conversationrepository.cpp @@ -42,11 +42,15 @@ constexpr size_t MAX_FETCH_SIZE {256 * 1024 * 1024}; // 256Mb namespace jami { -inline std::string_view as_view(const git_blob* blob) { +inline std::string_view +as_view(const git_blob* blob) +{ return std::string_view(static_cast<const char*>(git_blob_rawcontent(blob)), - git_blob_rawsize(blob)); + git_blob_rawsize(blob)); } -inline std::string_view as_view(const GitObject& blob) { +inline std::string_view +as_view(const GitObject& blob) +{ return as_view(reinterpret_cast<git_blob*>(blob.get())); } @@ -228,7 +232,8 @@ public: const std::string& userUri, std::string_view oldCert = ""sv) const { - auto cert = dht::crypto::Certificate((const uint8_t*)certContent.data(), certContent.size()); + auto cert = dht::crypto::Certificate((const uint8_t*) certContent.data(), + certContent.size()); auto isDeviceCertificate = cert.getId().toString() != userUri; auto issuerUid = cert.getIssuerUID(); if (isDeviceCertificate && issuerUid.empty()) { @@ -236,7 +241,8 @@ public: JAMI_ERR("Empty issuer for %s", cert.getId().to_c_str()); } if (!oldCert.empty()) { - auto deviceCert = dht::crypto::Certificate((const uint8_t*)oldCert.data(), oldCert.size()); + auto deviceCert = dht::crypto::Certificate((const uint8_t*) oldCert.data(), + oldCert.size()); if (isDeviceCertificate) { if (issuerUid != deviceCert.getIssuerUID()) { // NOTE: Here, because JAMS certificate can be incorrectly formatted, there is @@ -495,7 +501,8 @@ initial_commit(GitRepository& repo, return {}; } - std::string signed_str = base64::encode(account->identity().first->sign((const uint8_t*)to_sign.ptr, to_sign.size)); + std::string signed_str = base64::encode( + account->identity().first->sign((const uint8_t*) to_sign.ptr, to_sign.size)); // git commit -S if (git_commit_create_with_signature(&commit_id, @@ -898,7 +905,8 @@ ConversationRepository::Impl::checkVote(const std::string& userDevice, } // Check votedFile path - static const std::regex regex_votes("votes.(\\w+).(members|devices|admins|invited).(\\w+).(\\w+)"); + static const std::regex regex_votes( + "votes.(\\w+).(members|devices|admins|invited).(\\w+).(\\w+)"); std::svmatch base_match; if (!std::regex_match(votedFile, base_match, regex_votes) or base_match.size() != 5) { JAMI_WARN("Invalid votes path: %s", votedFile.c_str()); @@ -2910,6 +2918,20 @@ ConversationRepository::merge(const std::string& merge_id, bool force) return {!result.empty(), result}; } +std::string +ConversationRepository::mergeBase(const std::string& from, const std::string& to) const +{ + if (auto repo = pimpl_->repository()) { + git_oid oid, oidFrom, oidMerge; + git_oid_fromstr(&oidFrom, from.c_str()); + git_oid_fromstr(&oid, to.c_str()); + git_merge_base(&oidMerge, repo.get(), &oid, &oidFrom); + if (auto* commit_str = git_oid_tostr_s(&oidMerge)) + return commit_str; + } + return {}; +} + std::string ConversationRepository::diffStats(const std::string& newId, const std::string& oldId) const { diff --git a/src/jamidht/conversationrepository.h b/src/jamidht/conversationrepository.h index ec1420d215..7d66e9b290 100644 --- a/src/jamidht/conversationrepository.h +++ b/src/jamidht/conversationrepository.h @@ -220,6 +220,14 @@ public: */ std::pair<bool, std::string> merge(const std::string& merge_id, bool force = false); + /** + * Get the common parent between two branches + * @param from The first branch + * @param to The second branch + * @return the common parent + */ + std::string mergeBase(const std::string& from, const std::string& to) const; + /** * Get current diff stats between two commits * @param oldId Old commit -- GitLab