From 76fceef7d1f431d510e92dd7e2067e802dee89c3 Mon Sep 17 00:00:00 2001
From: Mingrui Zhang <mingrui.zhang@savoirfairelinux.com>
Date: Mon, 3 Jun 2019 11:36:38 -0400
Subject: [PATCH] peerdiscovery: add peerdiscoverymodel

-used to reveive peer discovery map change signal
-get peer discovery map directly by knowing accountId

Change-Id: I35faf9360200d86a68b64d17969797bfcaa3695e
---
 CMakeLists.txt                            |   2 +
 src/api/account.h                         |   2 +
 src/api/peerdiscoverymodel.h              |  81 ++++++++++++++++
 src/callbackshandler.cpp                  |  15 +++
 src/callbackshandler.h                    |  18 ++++
 src/newaccountmodel.cpp                   |   2 +
 src/peerdiscoverymodel.cpp                | 107 ++++++++++++++++++++++
 src/qtwrapper/configurationmanager_wrap.h |   4 +
 src/qtwrapper/presencemanager_wrap.h      |   5 +
 test/mocks/presencemanager_mock.h         |   5 +
 10 files changed, 241 insertions(+)
 create mode 100644 src/api/peerdiscoverymodel.h
 create mode 100644 src/peerdiscoverymodel.cpp

diff --git a/CMakeLists.txt b/CMakeLists.txt
index 0d7c51ca..40437fd5 100644
--- a/CMakeLists.txt
+++ b/CMakeLists.txt
@@ -343,6 +343,7 @@ SET( libringclient_LIB_SRCS
   src/authority/databasehelper.cpp
   src/lrc.cpp
   src/newaccountmodel.cpp
+  src/peerdiscoverymodel.cpp
   src/callbackshandler.cpp
   src/behaviorcontroller.cpp
   src/datatransfermodel.cpp
@@ -483,6 +484,7 @@ SET(libringclient_api_LIB_HDRS
   src/api/lrc.h
   src/api/avmodel.h
   src/api/newaccountmodel.h
+  src/api/peerdiscoverymodel.h
   src/api/newcallmodel.h
   src/api/newcodecmodel.h
   src/api/newdevicemodel.h
diff --git a/src/api/account.h b/src/api/account.h
index 8d353d19..6f9ecfe3 100644
--- a/src/api/account.h
+++ b/src/api/account.h
@@ -40,6 +40,7 @@ class NewCallModel;
 class NewAccountModel;
 class NewDeviceModel;
 class NewCodecModel;
+class PeerDiscoveryModel;
 
 namespace account
 {
@@ -225,6 +226,7 @@ struct Info
     std::unique_ptr<lrc::api::NewCallModel> callModel;
     std::unique_ptr<lrc::api::NewDeviceModel> deviceModel;
     std::unique_ptr<lrc::api::NewCodecModel> codecModel;
+    std::unique_ptr<lrc::api::PeerDiscoveryModel> peerDiscoveryModel;
     NewAccountModel* accountModel {nullptr};
 
     // daemon config
diff --git a/src/api/peerdiscoverymodel.h b/src/api/peerdiscoverymodel.h
new file mode 100644
index 00000000..5112629e
--- /dev/null
+++ b/src/api/peerdiscoverymodel.h
@@ -0,0 +1,81 @@
+/****************************************************************************
+ *    Copyright (C) 2019 Savoir-faire Linux Inc.                            *
+ *   Author: Mingrui Zhang <mingrui.zhang@savoirfairelinux.com>             *
+ *                                                                          *
+ *   This library is free software; you can redistribute it and/or          *
+ *   modify it under the terms of the GNU Lesser General Public             *
+ *   License as published by the Free Software Foundation; either           *
+ *   version 2.1 of the License, or (at your option) any later version.     *
+ *                                                                          *
+ *   This library is distributed in the hope that it will be useful,        *
+ *   but WITHOUT ANY WARRANTY; without even the implied warranty of         *
+ *   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU      *
+ *   Lesser General Public License for more details.                        *
+ *                                                                          *
+ *   You should have received a copy of the GNU General Public License      *
+ *   along with this program.  If not, see <http://www.gnu.org/licenses/>.  *
+ ***************************************************************************/
+
+#pragma once
+
+// std
+#include <vector>
+#include <map>
+#include <memory>
+#include <string>
+
+// Qt
+#include <qobject.h>
+
+// Lrc
+#include "typedefs.h"
+
+namespace lrc
+{
+
+class CallbacksHandler;
+class PeerDiscoveryModelPimpl;
+
+namespace api
+{
+
+struct PeerContact
+{
+    std::string uri;
+    std::string displayName;
+};
+
+enum class PeerModelChanged
+{
+    INSERT,
+    REMOVE
+};
+
+
+/**
+  *  @brief Class that manages local peer discovery info
+  */
+class LIB_EXPORT PeerDiscoveryModel : public QObject {
+    Q_OBJECT
+public:
+
+    PeerDiscoveryModel(const CallbacksHandler& callbackHandler, const std::string& accountID);
+    ~PeerDiscoveryModel();
+    /**
+     * get a map of discovered peers account
+     * @return a std::vector<PeerContact>
+     */
+    std::vector<PeerContact> getNearbyPeers() const;
+
+Q_SIGNALS:
+    /**
+     * Connect this signal to know when the status of local peer discovery map changed.
+     */
+    void modelChanged(const std::string& contactUri, PeerModelChanged state, const std::string& displayname);
+
+private:
+    std::unique_ptr<PeerDiscoveryModelPimpl> pimpl_;
+};
+
+} // namespace api
+} // namespace lrc
diff --git a/src/callbackshandler.cpp b/src/callbackshandler.cpp
index dad2607e..283d54e3 100644
--- a/src/callbackshandler.cpp
+++ b/src/callbackshandler.cpp
@@ -64,6 +64,12 @@ CallbacksHandler::CallbacksHandler(const Lrc& parent)
             &CallbacksHandler::slotNewBuddySubscription,
             Qt::QueuedConnection);
 
+    connect(&PresenceManager::instance(),
+            &PresenceManagerInterface::nearbyPeerNotification,
+            this,
+            &CallbacksHandler::slotNearbyPeerSubscription,
+            Qt::QueuedConnection);
+
     connect(&ConfigurationManager::instance(),
             &ConfigurationManagerInterface::contactAdded,
             this,
@@ -248,6 +254,15 @@ CallbacksHandler::slotNewBuddySubscription(const QString& accountId,
     emit newBuddySubscription(uri.toStdString(), status);
 }
 
+void
+CallbacksHandler::slotNearbyPeerSubscription(const QString& accountId,
+                                             const QString& contactUri,
+                                             int state,
+                                             const QString& displayname)
+{
+    emit newPeerSubscription(accountId.toStdString(), contactUri.toStdString(), state, displayname.toStdString());
+}
+
 void
 CallbacksHandler::slotContactAdded(const QString& accountId,
                                    const QString& contactUri,
diff --git a/src/callbackshandler.h b/src/callbackshandler.h
index 098e7b9a..31409cf1 100644
--- a/src/callbackshandler.h
+++ b/src/callbackshandler.h
@@ -68,6 +68,12 @@ Q_SIGNALS:
      * @param present if the peer is online.
      */
     void newBuddySubscription(const std::string& contactUri, bool present);
+    /**
+     * Connect this signal to get information when peer discovery changes.
+     * @param contactUri the peer.
+     * @param state is 0 if the peer is added.
+     */
+    void newPeerSubscription(const std::string& accountId, const std::string& contactUri, int state, const std::string& displayname);
     /**
      * Connect this signal to know when a contact is removed by the daemon.
      * @param accountId the one who lost a contact.
@@ -467,6 +473,18 @@ private Q_SLOTS:
      */
     void slotAudioMeterReceived(const QString& id, float level);
 
+    /**
+     * Emit newPeerSubscription
+     * @param accountId
+     * @param contactUri
+     * @param status if the peer is added or removed
+     * @param displayname is the account display name
+     */
+    void slotNearbyPeerSubscription(const QString& accountId,
+                                    const QString& contactUri,
+                                    int state,
+                                    const QString& displayname);
+
 private:
     const api::Lrc& parent;
 };
diff --git a/src/newaccountmodel.cpp b/src/newaccountmodel.cpp
index c12703f5..887d613b 100644
--- a/src/newaccountmodel.cpp
+++ b/src/newaccountmodel.cpp
@@ -31,6 +31,7 @@
 #include "api/lrc.h"
 #include "api/contactmodel.h"
 #include "api/conversationmodel.h"
+#include "api/peerdiscoverymodel.h"
 #include "api/newcallmodel.h"
 #include "api/newcodecmodel.h"
 #include "api/newdevicemodel.h"
@@ -582,6 +583,7 @@ NewAccountModelPimpl::addToAccounts(const std::string& accountId)
     newAcc.callModel = std::make_unique<NewCallModel>(newAcc, callbacksHandler);
     newAcc.contactModel = std::make_unique<ContactModel>(newAcc, database, callbacksHandler, behaviorController);
     newAcc.conversationModel = std::make_unique<ConversationModel>(newAcc, lrc, database, callbacksHandler, behaviorController);
+    newAcc.peerDiscoveryModel = std::make_unique<PeerDiscoveryModel>(callbacksHandler, accountId);
     newAcc.deviceModel = std::make_unique<NewDeviceModel>(newAcc, callbacksHandler);
     newAcc.codecModel = std::make_unique<NewCodecModel>(newAcc, callbacksHandler);
     newAcc.accountModel = &linked;
diff --git a/src/peerdiscoverymodel.cpp b/src/peerdiscoverymodel.cpp
new file mode 100644
index 00000000..759edc89
--- /dev/null
+++ b/src/peerdiscoverymodel.cpp
@@ -0,0 +1,107 @@
+/****************************************************************************
+ *    Copyright (C) 2019 Savoir-faire Linux Inc.                            *
+ *   Author: Mingrui Zhang <mingrui.zhang@savoirfairelinux.com>             *
+ *                                                                          *
+ *   This library is free software; you can redistribute it and/or          *
+ *   modify it under the terms of the GNU Lesser General Public             *
+ *   License as published by the Free Software Foundation; either           *
+ *   version 2.1 of the License, or (at your option) any later version.     *
+ *                                                                          *
+ *   This library is distributed in the hope that it will be useful,        *
+ *   but WITHOUT ANY WARRANTY; without even the implied warranty of         *
+ *   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU      *
+ *   Lesser General Public License for more details.                        *
+ *                                                                          *
+ *   You should have received a copy of the GNU General Public License      *
+ *   along with this program.  If not, see <http://www.gnu.org/licenses/>.  *
+ ***************************************************************************/
+#include "api/peerdiscoverymodel.h"
+
+// new LRC
+#include "callbackshandler.h"
+
+// Dbus
+#include "dbus/configurationmanager.h"
+
+namespace lrc
+{
+
+using namespace api;
+
+class PeerDiscoveryModelPimpl: public QObject
+{
+    Q_OBJECT
+public:
+    PeerDiscoveryModelPimpl(PeerDiscoveryModel& linked,
+                            const CallbacksHandler& callbackHandler,
+                            const std::string& accountID);
+    ~PeerDiscoveryModelPimpl();
+
+    PeerDiscoveryModel& linked_;
+    const CallbacksHandler& callbacksHandler_;
+    const std::string accountID_;
+
+public Q_SLOTS:
+
+    /**
+     * Emit peerMapStatusChanged.
+     * @param accountId
+     * @param status
+     */
+    void slotPeerMapStatusChanged(const std::string& accountID, const std::string& contactUri, int state, const std::string& displayname);
+};
+
+PeerDiscoveryModel::PeerDiscoveryModel(const CallbacksHandler& callbacksHandler, const std::string& accountID)
+: QObject()
+, pimpl_(std::make_unique<PeerDiscoveryModelPimpl>(*this, callbacksHandler, accountID))
+{
+}
+
+PeerDiscoveryModel::~PeerDiscoveryModel()
+{
+}
+
+PeerDiscoveryModelPimpl::PeerDiscoveryModelPimpl(PeerDiscoveryModel& linked,
+                                                 const CallbacksHandler& callbacksHandler,
+                                                 const std::string& accountID)
+: linked_(linked)
+, callbacksHandler_(callbacksHandler)
+, accountID_(accountID)
+{
+    connect(&callbacksHandler_, &CallbacksHandler::newPeerSubscription, this, &PeerDiscoveryModelPimpl::slotPeerMapStatusChanged);
+}
+
+PeerDiscoveryModelPimpl::~PeerDiscoveryModelPimpl()
+{
+    disconnect(&callbacksHandler_, &CallbacksHandler::newPeerSubscription, this, &PeerDiscoveryModelPimpl::slotPeerMapStatusChanged);
+}
+
+void
+PeerDiscoveryModelPimpl::slotPeerMapStatusChanged(const std::string& accountID, const std::string& contactUri, int state, const std::string& displayname)
+{
+    if(accountID != accountID_){
+        return;
+    } 
+    emit linked_.modelChanged(contactUri,state == 0 ? PeerModelChanged::INSERT : PeerModelChanged::REMOVE,displayname);
+
+}
+
+std::vector<PeerContact>
+PeerDiscoveryModel::getNearbyPeers() const
+{
+    std::vector<PeerContact> result;
+    const MapStringString nearbyPeers = ConfigurationManager::instance().getNearbyPeers(QString::fromStdString(pimpl_->accountID_));
+    result.reserve(nearbyPeers.size());
+
+    QMap<QString, QString>::const_iterator i = nearbyPeers.constBegin();
+    while (i != nearbyPeers.constEnd()) {
+        result.emplace_back(PeerContact{i.key().toStdString(), i.value().toStdString()});
+        ++i;
+    }
+    return result;
+}
+
+} // namespace lrc
+
+#include "api/moc_peerdiscoverymodel.cpp"
+#include "peerdiscoverymodel.moc"
diff --git a/src/qtwrapper/configurationmanager_wrap.h b/src/qtwrapper/configurationmanager_wrap.h
index 703bc068..49bfb046 100644
--- a/src/qtwrapper/configurationmanager_wrap.h
+++ b/src/qtwrapper/configurationmanager_wrap.h
@@ -621,6 +621,10 @@ public Q_SLOTS: // METHODS
         return DRing::getMessageStatus(id);
     }
 
+    MapStringString getNearbyPeers(const QString &accountID){
+        return convertMap(DRing::getNearbyPeers(accountID.toStdString()));
+    }
+
     void connectivityChanged() {
         DRing::connectivityChanged();
     }
diff --git a/src/qtwrapper/presencemanager_wrap.h b/src/qtwrapper/presencemanager_wrap.h
index f1019a74..1ca89e73 100644
--- a/src/qtwrapper/presencemanager_wrap.h
+++ b/src/qtwrapper/presencemanager_wrap.h
@@ -63,6 +63,10 @@ public:
             exportable_callback<PresenceSignal::SubscriptionStateChanged>(
                 [this] (const std::string &accountID, const std::string &buddyUri, bool state) {
                     Q_EMIT this->subscriptionStateChanged(QString(accountID.c_str()), QString(buddyUri.c_str()), state);
+                }),
+            exportable_callback<PresenceSignal::NearbyPeerNotification>(
+                [this] (const std::string &accountID, const std::string &buddyUri, int status, const std::string &displayname) {
+                    Q_EMIT this->nearbyPeerNotification(QString(accountID.c_str()), QString(buddyUri.c_str()), status, QString(displayname.c_str()));
                 })
          };
     }
@@ -100,6 +104,7 @@ public Q_SLOTS: // METHODS
     }
 
 Q_SIGNALS: // SIGNALS
+    void nearbyPeerNotification(const QString &accountID, const QString &buddyUri, int status, const QString &displayname);
     void newServerSubscriptionRequest(const QString &buddyUri);
     void serverError(const QString &accountID, const QString &error, const QString &msg);
     void newBuddyNotification(const QString &accountID, const QString &buddyUri, bool status, const QString &lineStatus);
diff --git a/test/mocks/presencemanager_mock.h b/test/mocks/presencemanager_mock.h
index facd0919..4d6e2c98 100644
--- a/test/mocks/presencemanager_mock.h
+++ b/test/mocks/presencemanager_mock.h
@@ -52,6 +52,10 @@ public:
     {
         emit newBuddyNotification(accountID, buddyUri, status, lineStatus);
     }
+    void emitNearbyPeerNotification(const QString &accountID, const QString &buddyUri, int status, const QString &displayname)
+    {
+        emit nearbyPeerNotification(accountID, buddyUri, status, displayname);
+    }
 
 public Q_SLOTS: // METHODS
     void answerServerRequest(const QString &uri, bool flag)
@@ -91,6 +95,7 @@ Q_SIGNALS: // SIGNALS
     void newServerSubscriptionRequest(const QString &buddyUri);
     void serverError(const QString &accountID, const QString &error, const QString &msg);
     void newBuddyNotification(const QString &accountID, const QString &buddyUri, bool status, const QString &lineStatus);
+    void nearbyPeerNotification(const QString &accountID, const QString &buddyUri, int status, const QString &displayname);
     void subscriptionStateChanged(const QString &accountID, const QString &buddyUri, bool state);
 };
 
-- 
GitLab