From 5de9d9eee338fd1c5fbfe137662118ffee875dae Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Adrien=20B=C3=A9raud?= <adrien.beraud@savoirfairelinux.com> Date: Thu, 15 Feb 2024 14:51:12 -0500 Subject: [PATCH] conversation: cache account config A Conversation is now initialized for a specific userId and deviceId and is less dependent from the account. GitLab: #952 Change-Id: I0a0e14f6b1877c04a7853a36a3b08fbc1c2aba42 --- src/jamidht/conversation.cpp | 199 +++++++++++++++-------------------- 1 file changed, 87 insertions(+), 112 deletions(-) diff --git a/src/jamidht/conversation.cpp b/src/jamidht/conversation.cpp index 7f176a4dec..47469580c3 100644 --- a/src/jamidht/conversation.cpp +++ b/src/jamidht/conversation.cpp @@ -139,27 +139,36 @@ public: const std::string& otherMember = "") : repository_(ConversationRepository::createConversation(account, mode, otherMember)) , account_(account) + , accountId_(account->getAccountID()) + , userId_(account->getUsername()) + , deviceId_(account->currentDeviceId()) { if (!repository_) { throw std::logic_error("Couldn't create repository"); } - init(); + init(*account); } Impl(const std::shared_ptr<JamiAccount>& account, const std::string& conversationId) : account_(account) + , accountId_(account->getAccountID()) + , userId_(account->getUsername()) + , deviceId_(account->currentDeviceId()) { repository_ = std::make_unique<ConversationRepository>(account, conversationId); if (!repository_) { throw std::logic_error("Couldn't create repository"); } - init(); + init(*account); } Impl(const std::shared_ptr<JamiAccount>& account, const std::string& remoteDevice, const std::string& conversationId) : account_(account) + , accountId_(account->getAccountID()) + , userId_(account->getUsername()) + , deviceId_(account->currentDeviceId()) { std::vector<ConversationCommit> commits; repository_ = ConversationRepository::cloneConversation(account, @@ -170,66 +179,60 @@ public: }); if (!repository_) { emitSignal<libjami::ConversationSignal::OnConversationError>( - account->getAccountID(), conversationId, EFETCH, "Couldn't clone repository"); + accountId_, conversationId, EFETCH, "Couldn't clone repository"); throw std::logic_error("Couldn't clone repository"); } // To detect current active calls, we need to check history - conversationDataPath_ = fileutils::get_data_dir() / account->getAccountID() + conversationDataPath_ = fileutils::get_data_dir() / accountId_ / "conversation_data" / conversationId; activeCallsPath_ = conversationDataPath_ / ConversationMapKeys::ACTIVE_CALLS; for (const auto& c : repository_->convCommitsToMap(commits)) updateActiveCalls(c); - init(); - } - - void init() - { - if (auto shared = account_.lock()) { - ioContext_ = Manager::instance().ioContext(); - fallbackTimer_ = std::make_unique<asio::steady_timer>(*ioContext_); - swarmManager_ - = std::make_shared<SwarmManager>(NodeId(shared->currentDeviceId()), - Manager::instance().getSeededRandomEngine(), - [account = account_](const DeviceId& deviceId) { - if (auto acc = account.lock()) { - return acc->isConnectedWith(deviceId); - } - return false; - }); - swarmManager_->setMobility(shared->isMobile()); - accountId_ = shared->getAccountID(); - transferManager_ - = std::make_shared<TransferManager>(shared->getAccountID(), - "", - repository_->id(), - Manager::instance().getSeededRandomEngine()); - conversationDataPath_ = fileutils::get_data_dir() / shared->getAccountID() - / "conversation_data" / repository_->id(); - fetchedPath_ = conversationDataPath_ / "fetched"; - statusPath_ = conversationDataPath_ / "status"; - sendingPath_ = conversationDataPath_ / "sending"; - preferencesPath_ = conversationDataPath_ / ConversationMapKeys::PREFERENCES; - activeCallsPath_ = conversationDataPath_ / ConversationMapKeys::ACTIVE_CALLS; - hostedCallsPath_ = conversationDataPath_ / ConversationMapKeys::HOSTED_CALLS; - loadActiveCalls(); - loadStatus(); - typers_ = std::make_shared<Typers>(shared, repository_->id()); - } + init(*account); + } + + void init(JamiAccount& account) { + ioContext_ = Manager::instance().ioContext(); + fallbackTimer_ = std::make_unique<asio::steady_timer>(*ioContext_); + swarmManager_ + = std::make_shared<SwarmManager>(NodeId(deviceId_), + Manager::instance().getSeededRandomEngine(), + [account = account_](const DeviceId& deviceId) { + if (auto acc = account.lock()) { + return acc->isConnectedWith(deviceId); + } + return false; + }); + swarmManager_->setMobility(account.isMobile()); + transferManager_ + = std::make_shared<TransferManager>(accountId_, + "", + repository_->id(), + Manager::instance().getSeededRandomEngine()); + conversationDataPath_ = fileutils::get_data_dir() / accountId_ + / "conversation_data" / repository_->id(); + fetchedPath_ = conversationDataPath_ / "fetched"; + statusPath_ = conversationDataPath_ / "status"; + sendingPath_ = conversationDataPath_ / "sending"; + preferencesPath_ = conversationDataPath_ / ConversationMapKeys::PREFERENCES; + activeCallsPath_ = conversationDataPath_ / ConversationMapKeys::ACTIVE_CALLS; + hostedCallsPath_ = conversationDataPath_ / ConversationMapKeys::HOSTED_CALLS; + loadActiveCalls(); + loadStatus(); + typers_ = std::make_shared<Typers>(shared, repository_->id()); } const std::string& toString() const { if (fmtStr_.empty()) { if (repository_->mode() == ConversationMode::ONE_TO_ONE) { - if (auto acc = account_.lock()) { - auto peer = acc->getUsername(); - for (const auto& member : repository_->getInitialMembers()) { - if (member != acc->getUsername()) { - peer = member; - } + auto peer = userId_; + for (const auto& member : repository_->getInitialMembers()) { + if (member != userId_) { + peer = member; } - fmtStr_ = fmt::format("[Conversation (1:1) {}]", peer); } + fmtStr_ = fmt::format("[Conversation (1:1) {}]", peer); } else { fmtStr_ = fmt::format("[Conversation {}]", repository_->id()); } @@ -392,8 +395,7 @@ public: void announce(const std::vector<std::map<std::string, std::string>>& commits, bool commitFromSelf = false) const { - auto shared = account_.lock(); - if (!shared or !repository_) + if (!repository_) return; auto convId = repository_->id(); auto ok = !commits.empty(); @@ -438,7 +440,7 @@ public: if (pluginChatManager.hasHandlers()) { auto cm = std::make_shared<JamiMessage>(accountId_, convId, - c.at("author") != shared->getUsername(), + c.at("author") != userId_, c, false); cm->isSwarm = true; @@ -521,17 +523,18 @@ public: std::string_view bannedType(const std::string& uri) const { + auto repo = repoPath(); auto crt = fmt::format("{}.crt", uri); - auto bannedMember = repoPath() / "banned" / "members" / crt; + auto bannedMember = repo / "banned" / "members" / crt; if (std::filesystem::is_regular_file(bannedMember)) return "members"sv; - auto bannedAdmin = repoPath() / "banned" / "admins" / crt; + auto bannedAdmin = repo / "banned" / "admins" / crt; if (std::filesystem::is_regular_file(bannedAdmin)) return "admins"sv; - auto bannedInvited = repoPath() / "banned" / "invited" / uri; + auto bannedInvited = repo / "banned" / "invited" / uri; if (std::filesystem::is_regular_file(bannedInvited)) return "invited"sv; - auto bannedDevice = repoPath() / "banned" / "devices" / crt; + auto bannedDevice = repo / "banned" / "devices" / crt; if (std::filesystem::is_regular_file(bannedDevice)) return "devices"sv; return {}; @@ -567,6 +570,9 @@ public: std::unique_ptr<ConversationRepository> repository_; std::shared_ptr<SwarmManager> swarmManager_; std::weak_ptr<JamiAccount> account_; + std::string accountId_ {}; + std::string userId_; + std::string deviceId_; std::atomic_bool isRemoving_ {false}; std::vector<std::map<std::string, std::string>> loadMessages(const LogOptions& options); std::vector<libjami::SwarmMessage> loadMessages2(const LogOptions& options, @@ -584,8 +590,6 @@ public: // Manage last message displayed and status std::filesystem::path sendingPath_ {}; - // Manage last message displayed - std::string accountId_ {}; std::filesystem::path preferencesPath_ {}; OnMembersChanged onMembersChanged_ {}; @@ -603,7 +607,6 @@ public: std::shared_ptr<asio::io_context> ioContext_; std::unique_ptr<asio::steady_timer> fallbackTimer_; - bool isMobile {false}; /** * Loaded history represents the linearized history to show for clients @@ -667,16 +670,8 @@ public: bool Conversation::Impl::isAdmin() const { - auto shared = account_.lock(); - if (!shared) - return false; - auto adminsPath = repoPath() / "admins"; - auto cert = shared->identity().second; - if (!cert->issuer) - return false; - auto uri = cert->issuer->getId().toString(); - return std::filesystem::is_regular_file(fileutils::getFullPath(adminsPath, uri + ".crt")); + return std::filesystem::is_regular_file(fileutils::getFullPath(adminsPath, userId_ + ".crt")); } std::vector<std::map<std::string, std::string>> @@ -703,7 +698,6 @@ Conversation::Impl::getMembers(bool includeInvited, bool includeLeft, bool inclu std::vector<std::string> Conversation::Impl::commitsEndedCalls() { - auto shared = account_.lock(); // Handle current calls std::vector<std::string> commits {}; std::unique_lock lk(writeMtx_); @@ -714,10 +708,8 @@ Conversation::Impl::commitsEndedCalls() // will not be correctly updated // We don't need to send notifications there, as peers will sync with presence Json::Value value; - auto uri = shared->getUsername(); - auto device = std::string(shared->currentDeviceId()); - value["uri"] = uri; - value["device"] = device; + value["uri"] = userId_; + value["device"] = deviceId_; value["confId"] = hostedCall.first; value["type"] = "application/call-history+json"; auto now = std::chrono::system_clock::now(); @@ -726,9 +718,9 @@ Conversation::Impl::commitsEndedCalls() value["duration"] = std::to_string((nowConverted - hostedCall.second) * 1000); auto itActive = std::find_if(activeCalls_.begin(), activeCalls_.end(), - [confId = hostedCall.first, uri, device](auto value) { - return value.at("id") == confId && value.at("uri") == uri - && value.at("device") == device; + [this, confId = hostedCall.first](auto value) { + return value.at("id") == confId && value.at("uri") == userId_ + && value.at("device") == deviceId_; }); if (itActive != activeCalls_.end()) activeCalls_.erase(itActive); @@ -1526,9 +1518,6 @@ Conversation::sendMessage(Json::Value&& value, dht::ThreadPool::io().run( [w = weak(), value = std::move(value), onCommit = std::move(onCommit), cb = std::move(cb)] { if (auto sthis = w.lock()) { - auto acc = sthis->pimpl_->account_.lock(); - if (!acc) - return; std::unique_lock lk(sthis->pimpl_->writeMtx_); auto commit = sthis->pimpl_->repository_->commitMessage( Json::writeString(jsonBuilder, value)); @@ -1777,9 +1766,8 @@ Conversation::Impl::pull() auto changedFiles = repo->changedFiles(diffStats); if (find(changedFiles.begin(), changedFiles.end(), "profile.vcf") != changedFiles.end()) { - if (auto account = account_.lock()) - emitSignal<libjami::ConversationSignal::ConversationProfileUpdated>( - account->getAccountID(), repo->id(), repo->infos()); + emitSignal<libjami::ConversationSignal::ConversationProfileUpdated>( + accountId_, repo->id(), repo->infos()); } } } @@ -1791,20 +1779,17 @@ Conversation::sync(const std::string& member, OnPullCb&& cb, std::string commitId) { - if (!pull(deviceId, std::move(cb), commitId)) - return; - dht::ThreadPool::io().run([member, deviceId, a = pimpl_->account_, w = weak_from_this()] { + pull(deviceId, std::move(cb), commitId); + dht::ThreadPool::io().run([member, deviceId, w = weak_from_this()] { auto sthis = w.lock(); - if (auto account = a.lock()) { - // For waiting request, downloadFile - for (const auto& wr : sthis->dataTransfer()->waitingRequests()) { - auto path = fileutils::get_data_dir() / account->getAccountID() - / "conversation_data" / sthis->id() / wr.fileId; - auto start = fileutils::size(path.string()); - if (start < 0) - start = 0; - sthis->downloadFile(wr.interactionId, wr.fileId, wr.path, member, deviceId, start); - } + // For waiting request, downloadFile + for (const auto& wr : sthis->dataTransfer()->waitingRequests()) { + auto path = fileutils::get_data_dir() / sthis->pimpl_->accountId_ + / "conversation_data" / sthis->id() / wr.fileId; + auto start = fileutils::size(path); + if (start < 0) + start = 0; + sthis->downloadFile(wr.interactionId, wr.fileId, wr.path, member, deviceId, start); } }); } @@ -1888,9 +1873,8 @@ Conversation::updateInfos(const std::map<std::string, std::string>& map, const O lk.unlock(); if (cb) cb(!commit.empty(), commit); - if (auto account = sthis->pimpl_->account_.lock()) - emitSignal<libjami::ConversationSignal::ConversationProfileUpdated>( - account->getAccountID(), repo->id(), repo->infos()); + emitSignal<libjami::ConversationSignal::ConversationProfileUpdated>( + sthis->pimpl_->accountId_, repo->id(), repo->infos()); } }); } @@ -2065,10 +2049,9 @@ Conversation::hasFetched(const std::string& deviceId, const std::string& commitI auto sthis = w.lock(); if (!sthis) return; - auto acc = sthis->pimpl_->account_.lock(); // Update fetched for Uri auto uri = sthis->uriFromDevice(deviceId); - if (uri.empty() || !acc || uri == acc->getUsername()) + if (uri.empty() || uri == sthis->pimpl_->userId_) return; // When a user fetches a commit, the message is sent for this person sthis->pimpl_->updateStatus(uri, libjami::Account::MessageStates::SENT, commitId, std::to_string(std::time(nullptr)), true); @@ -2158,7 +2141,6 @@ Conversation::messageStatus() const void Conversation::updateMessageStatus(const std::map<std::string, std::map<std::string, std::string>>& messageStatus) { - auto acc = pimpl_->account_.lock(); std::unique_lock lk(pimpl_->messageStatusMtx_); std::vector<std::tuple<libjami::Account::MessageStates, std::string, std::string, std::string>> stVec; for (const auto& [uri, status] : messageStatus) { @@ -2213,7 +2195,7 @@ Conversation::checkBootstrapMember(const asio::error_code& ec, auto member = members.back(); members.pop_back(); uri = member.at("uri"); - if (uri != acc->getUsername() + if (uri != pimpl_->userId_ && pimpl_->checkedMembers_.find(uri) == pimpl_->checkedMembers_.end()) break; } @@ -2256,7 +2238,7 @@ Conversation::checkBootstrapMember(const asio::error_code& ec, #endif JAMI_WARNING("{}[SwarmManager {}] Bootstrap: Fallback with member: {}", sthis->pimpl_->toString(), - fmt::ptr(sthis->pimpl_->swarmManager_.get()), + fmt::ptr(sthis->pimpl_->swarmManager_), uri); if (sthis->pimpl_->swarmManager_->setKnownNodes(*devices)) checkNext = false; @@ -2291,7 +2273,7 @@ Conversation::bootstrap(std::function<void()> onBootstraped, devices.insert(devices.end(), m.second.begin(), m.second.end()); JAMI_DEBUG("{}[SwarmManager {}] Bootstrap with {} devices", pimpl_->toString(), - fmt::ptr(pimpl_->swarmManager_.get()), + fmt::ptr(pimpl_->swarmManager_), devices.size()); // set callback auto fallback = [](auto sthis, bool now = false) { @@ -2426,10 +2408,6 @@ Conversation::search(uint32_t req, // do it asynchronously dht::ThreadPool::io().run([w = weak(), req, filter, flag] { if (auto sthis = w.lock()) { - auto acc = sthis->pimpl_->account_.lock(); - if (!acc) - return; - History history; std::vector<std::map<std::string, std::string>> commits {}; // std::regex_constants::ECMAScript is the default flag. @@ -2502,14 +2480,14 @@ Conversation::search(uint32_t req, if (commits.size() > 0) emitSignal<libjami::ConversationSignal::MessagesFound>(req, - acc->getAccountID(), + sthis->pimpl_->accountId_, sthis->id(), std::move(commits)); // If we're the latest thread, inform client that the search is finished if ((*flag)-- == 1 /* decrement return the old value */) { emitSignal<libjami::ConversationSignal::MessagesFound>( req, - acc->getAccountID(), + sthis->pimpl_->accountId_, std::string {}, std::vector<std::map<std::string, std::string>> {}); } @@ -2539,11 +2517,8 @@ Conversation::hostConference(Json::Value&& message, OnDoneCb&& cb) bool Conversation::isHosting(const std::string& confId) const { - auto shared = pimpl_->account_.lock(); - if (!shared) - return false; auto info = infos(); - if (info["rdvDevice"] == shared->currentDeviceId() && info["rdvHost"] == shared->getUsername()) + if (info["rdvDevice"] == pimpl_->deviceId_ && info["rdvHost"] == pimpl_->userId_) return true; // We are the current device Host std::lock_guard lk(pimpl_->activeCallsMtx_); return pimpl_->hostedCalls_.find(confId) != pimpl_->hostedCalls_.end(); -- GitLab