LCOV - code coverage report
Current view: top level - src/jamidht - presence_manager.cpp (source / functions) Coverage Total Hit
Test: jami-coverage-filtered.info Lines: 90.2 % 133 120
Test Date: 2026-06-13 09:18:46 Functions: 75.0 % 20 15

            Line data    Source code
       1              : /*
       2              :  * Copyright (C) 2004-2026 Savoir-faire Linux Inc.
       3              :  *
       4              :  * This program is free software: you can redistribute it and/or modify
       5              :  * it under the terms of the GNU General Public License as published by
       6              :  * the Free Software Foundation, either version 3 of the License, or
       7              :  * (at your option) any later version.
       8              :  *
       9              :  * This program is distributed in the hope that it will be useful,
      10              :  * but WITHOUT ANY WARRANTY; without even the implied warranty of
      11              :  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
      12              :  * GNU General Public License for more details.
      13              :  *
      14              :  * You should have received a copy of the GNU General Public License
      15              :  * along with this program. If not, see <https://www.gnu.org/licenses/>.
      16              :  */
      17              : 
      18              : #include "presence_manager.h"
      19              : #include "jami_contact.h" // For DeviceAnnouncement
      20              : #include "logger.h"
      21              : 
      22              : namespace jami {
      23              : 
      24          778 : PresenceManager::PresenceManager(const std::shared_ptr<dht::DhtRunner>& dht)
      25          778 :     : dht_(dht)
      26          778 : {}
      27              : 
      28          778 : PresenceManager::~PresenceManager()
      29              : {
      30          778 :     std::lock_guard lock(mutex_);
      31         1071 :     for (auto& [h, buddy] : trackedBuddies_) {
      32          293 :         if (dht_ && dht_->isRunning()) {
      33            0 :             dht_->cancelListen(h, std::move(buddy.listenToken));
      34              :         }
      35              :     }
      36          778 : }
      37              : 
      38              : void
      39          831 : PresenceManager::trackBuddy(const std::string& uri)
      40              : {
      41          831 :     dht::InfoHash h(uri);
      42          831 :     if (!h)
      43            0 :         return;
      44              : 
      45          831 :     std::lock_guard lock(mutex_);
      46          831 :     auto it = trackedBuddies_.find(h);
      47          831 :     if (it == trackedBuddies_.end()) {
      48          803 :         it = trackedBuddies_.emplace(h, TrackedBuddy {h}).first;
      49              :     }
      50              : 
      51          831 :     it->second.refCount++;
      52          831 :     if (it->second.refCount == 1) {
      53          803 :         trackPresence(h, it->second);
      54              :     }
      55          831 : }
      56              : 
      57              : void
      58          524 : PresenceManager::untrackBuddy(const std::string& uri)
      59              : {
      60          524 :     dht::InfoHash h(uri);
      61          524 :     if (!h)
      62            0 :         return;
      63              : 
      64          523 :     std::lock_guard lock(mutex_);
      65          524 :     auto it = trackedBuddies_.find(h);
      66          524 :     if (it != trackedBuddies_.end()) {
      67          523 :         it->second.refCount--;
      68          523 :         if (it->second.refCount <= 0) {
      69          509 :             if (dht_ && dht_->isRunning()) {
      70          503 :                 dht_->cancelListen(h, std::move(it->second.listenToken));
      71              :             }
      72          510 :             trackedBuddies_.erase(it);
      73              :         }
      74              :     }
      75          525 : }
      76              : 
      77              : bool
      78         2456 : PresenceManager::isOnline(const std::string& uri) const
      79              : {
      80         2456 :     dht::InfoHash h(uri);
      81         2456 :     if (!h)
      82            0 :         return false;
      83         2456 :     std::lock_guard lock(mutex_);
      84         2456 :     auto it = trackedBuddies_.find(h);
      85         2456 :     return it != trackedBuddies_.end() && !it->second.devices.empty();
      86         2456 : }
      87              : 
      88              : std::map<std::string, bool>
      89            2 : PresenceManager::getTrackedBuddyPresence() const
      90              : {
      91            2 :     std::lock_guard lock(mutex_);
      92            2 :     std::map<std::string, bool> presence_info;
      93            4 :     for (const auto& [h, buddy] : trackedBuddies_) {
      94            2 :         presence_info.emplace(h.toString(), !buddy.devices.empty());
      95              :     }
      96            4 :     return presence_info;
      97            2 : }
      98              : 
      99              : std::vector<dht::PkId>
     100         1021 : PresenceManager::getDevices(const std::string& uri) const
     101              : {
     102         1021 :     dht::InfoHash h(uri);
     103         1021 :     if (!h)
     104            0 :         return {};
     105         1021 :     std::lock_guard lock(mutex_);
     106         1021 :     auto it = trackedBuddies_.find(h);
     107         1021 :     if (it == trackedBuddies_.end())
     108          223 :         return {};
     109         2394 :     return {it->second.devices.begin(), it->second.devices.end()};
     110         1021 : }
     111              : 
     112              : uint64_t
     113          793 : PresenceManager::addListener(PresenceCallback cb)
     114              : {
     115          793 :     std::lock_guard lock(listenersMutex_);
     116          793 :     auto id = nextListenerId_++;
     117          793 :     listeners_.emplace(id, std::move(cb));
     118          793 :     return id;
     119          793 : }
     120              : 
     121              : void
     122            0 : PresenceManager::removeListener(uint64_t token)
     123              : {
     124            0 :     std::lock_guard lock(listenersMutex_);
     125            0 :     listeners_.erase(token);
     126            0 : }
     127              : 
     128              : uint64_t
     129         1179 : PresenceManager::addDeviceListener(DevicePresenceCallback cb)
     130              : {
     131         1179 :     std::lock_guard lock(listenersMutex_);
     132         1179 :     auto id = nextListenerId_++;
     133         1179 :     deviceListeners_.emplace(id, std::move(cb));
     134         1179 :     return id;
     135         1179 : }
     136              : 
     137              : void
     138          220 : PresenceManager::removeDeviceListener(uint64_t token)
     139              : {
     140          220 :     std::lock_guard lock(listenersMutex_);
     141          220 :     deviceListeners_.erase(token);
     142          220 : }
     143              : 
     144              : void
     145          694 : PresenceManager::refresh()
     146              : {
     147          694 :     std::lock_guard lock(mutex_);
     148          706 :     for (auto& [h, buddy] : trackedBuddies_) {
     149           12 :         buddy.listenToken = {};
     150           12 :         buddy.devices.clear();
     151           12 :         trackPresence(h, buddy);
     152              :     }
     153          694 : }
     154              : 
     155              : void
     156          815 : PresenceManager::trackPresence(const dht::InfoHash& h, TrackedBuddy& buddy)
     157              : {
     158          815 :     if (!dht_ || !dht_->isRunning())
     159           17 :         return;
     160              : 
     161          798 :     if (buddy.listenToken.valid()) {
     162            0 :         JAMI_ERROR("PresenceManager: Already tracking presence for {}", h.toString());
     163            0 :         return;
     164              :     }
     165              : 
     166         1596 :     buddy.listenToken = dht_->listen<DeviceAnnouncement>(h, [this, h](DeviceAnnouncement&& dev, bool expired) {
     167          721 :         if (!dev.pk) {
     168            0 :             JAMI_WARNING("PresenceManager: Received DeviceAnnouncement without public key for {}", h.toString());
     169            0 :             return true;
     170              :         }
     171              :         bool wasConnected, isConnected;
     172          721 :         auto deviceId = dev.pk->getLongId();
     173          721 :         bool deviceOnline = !expired;
     174              :         {
     175          721 :             std::lock_guard lock(mutex_);
     176          721 :             auto it = trackedBuddies_.find(h);
     177          721 :             if (it == trackedBuddies_.end())
     178           11 :                 return true;
     179              : 
     180          710 :             wasConnected = !it->second.devices.empty();
     181          710 :             if (expired) {
     182           77 :                 it->second.devices.erase(deviceId);
     183              :             } else {
     184          633 :                 it->second.devices.insert(deviceId);
     185              :             }
     186          710 :             isConnected = !it->second.devices.empty();
     187          721 :         }
     188              : 
     189          710 :         notifyDeviceListeners(h.toString(), deviceId, deviceOnline);
     190              : 
     191          710 :         if (isConnected != wasConnected) {
     192          627 :             notifyListeners(h.toString(), isConnected);
     193              :         }
     194          710 :         return true;
     195          798 :     });
     196              : }
     197              : 
     198              : void
     199          627 : PresenceManager::notifyListeners(const std::string& uri, bool online)
     200              : {
     201          627 :     std::vector<PresenceCallback> cbs;
     202              :     {
     203          627 :         std::lock_guard lock(listenersMutex_);
     204          627 :         cbs.reserve(listeners_.size());
     205         1259 :         for (const auto& [id, cb] : listeners_) {
     206          632 :             cbs.emplace_back(cb);
     207              :         }
     208          627 :     }
     209         1259 :     for (const auto& cb : cbs) {
     210          632 :         cb(uri, online);
     211              :     }
     212          627 : }
     213              : 
     214              : void
     215          710 : PresenceManager::notifyDeviceListeners(const std::string& uri, const dht::PkId& deviceId, bool online)
     216              : {
     217          710 :     std::vector<DevicePresenceCallback> cbs;
     218              :     {
     219          710 :         std::lock_guard lock(listenersMutex_);
     220          710 :         cbs.reserve(deviceListeners_.size());
     221         2114 :         for (const auto& [id, cb] : deviceListeners_) {
     222         1404 :             cbs.emplace_back(cb);
     223              :         }
     224          710 :     }
     225         2114 :     for (const auto& cb : cbs) {
     226         1404 :         cb(uri, deviceId, online);
     227              :     }
     228          710 : }
     229              : 
     230              : } // namespace jami
        

Generated by: LCOV version 2.0-1