New API for connection monitoring

Change-Id: If63c8121351f81b869b5b48b3df64eb412dd6f79
diff --git a/include/connectionmanager.h b/include/connectionmanager.h
index 17300dc..ae08212 100644
--- a/include/connectionmanager.h
+++ b/include/connectionmanager.h
@@ -42,6 +42,7 @@
 namespace tls {
 class CertificateStore;
 }
+enum class ConnectionStatus : int { Connected, TLS, ICE, Connecting, Waiting };
 
 /**
  * A PeerConnectionRequest is a request which ask for an initial connection
@@ -211,6 +212,46 @@
      */
     void storeActiveIpAddress(std::function<void()>&& cb = {});
 
+    /**
+     * Retrieve the list of connections.
+     *
+     * @param device The device ID to filter the connections (optional).
+     * @return The list of connections as a vector of maps, where each map represents a connection.
+     *
+     * Note: The connections are represented as maps with string keys and string values. The map
+     *       contains the following key-value pairs:
+     *       - "id": The unique identifier of the connection.
+     *       - "userUri": The user URI associated with the connection (if available).
+     *       - "status": The status of the connection, represented as an integer:
+     *                   - 0: ConnectionStatus::Connected
+     *                   - 1: ConnectionStatus::TLS
+     *                   - 2: ConnectionStatus::ICE
+     *                   - 3: ConnectionStatus::Connecting (for pending operations)
+     *                   - 4: ConnectionStatus::Waiting (for pending operations)
+     *       - "remoteAddress": The remote IP address of the connection (if available).
+     *       - "remotePort": The remote port of the connection (if available).
+     *
+     *       If a specific device ID is provided, the returned list will only include connections
+     *       associated with that device. Otherwise, connections from all devices will be included.
+    */
+    std::vector<std::map<std::string, std::string>> getConnectionList(
+        const DeviceId& device = {}) const;
+
+    /**
+      * Retrieve the list of channels associated with a connection.
+    *
+    * @param connectionId The ID of the connection to fetch the channels from.
+    * @return The list of channels as a vector of maps, where each map represents a channel
+    *         and contains key-value pairs of channel ID and channel name.
+    *
+    *       If the specified connection ID is valid and associated with a connection,
+    *       the method returns the list of channels associated with that connection.
+    *       Otherwise, an empty vector is returned.
+    */
+    std::vector<std::map<std::string, std::string>> getChannelList(
+        const std::string& connectionId) const;
+
+
     std::shared_ptr<Config> getConfig();
 
 private:
@@ -273,6 +314,7 @@
      * ie: if it is able to make port mappings
      */
     bool getUPnPActive() const;
+
 };
 
 } // namespace dhtnet
\ No newline at end of file
diff --git a/include/multiplexed_socket.h b/include/multiplexed_socket.h
index b440891..1d37166 100644
--- a/include/multiplexed_socket.h
+++ b/include/multiplexed_socket.h
@@ -142,6 +142,11 @@
     const std::shared_ptr<Logger>& logger();
 
     /**
+     * Get the list of channels
+     */
+    std::vector<std::map<std::string, std::string>> getChannelList() const;
+
+    /**
      * Send a beacon on the socket and close if no response come
      * @param timeout
      */
diff --git a/src/connectionmanager.cpp b/src/connectionmanager.cpp
index b3d8b79..9fda75c 100644
--- a/src/connectionmanager.cpp
+++ b/src/connectionmanager.cpp
@@ -41,7 +41,23 @@
 
 using ValueIdDist = std::uniform_int_distribution<dht::Value::Id>;
 using CallbackId = std::pair<dhtnet::DeviceId, dht::Value::Id>;
+std::string
+callbackIdToString(const dhtnet::DeviceId& did, const dht::Value::Id& vid)
+{
+    return fmt::format("{} {}", did.to_view(), vid);
+}
 
+CallbackId parseCallbackId(std::string_view ci)
+{
+    auto sep = ci.find(' ');
+    std::string_view deviceIdString = ci.substr(0, sep);
+    std::string_view vidString = ci.substr(sep + 1);
+
+    dhtnet::DeviceId deviceId(deviceIdString);
+    dht::Value::Id vid = std::stoul(std::string(vidString), nullptr, 10);
+
+    return CallbackId(deviceId, vid);
+}
 struct ConnectionInfo
 {
     ~ConnectionInfo()
@@ -1756,4 +1772,92 @@
     return pimpl_->config_;
 }
 
+std::vector<std::map<std::string, std::string>>
+ConnectionManager::getConnectionList(const DeviceId& device) const
+{
+    std::vector<std::map<std::string, std::string>> connectionsList;
+    std::lock_guard<std::mutex> lk(pimpl_->infosMtx_);
+
+    for (const auto& [key, ci] : pimpl_->infos_) {
+        if (device && key.first != device)
+            continue;
+        std::map<std::string, std::string> connectionInfo;
+        connectionInfo["id"] = callbackIdToString(key.first, key.second);
+        if (ci->tls_ && ci->tls_->peerCertificate()) {
+            auto cert = ci->tls_->peerCertificate();
+            connectionInfo["userUri"] = cert->issuer->getId().toString();
+        }
+        if (ci->socket_) {
+            connectionInfo["status"] = std::to_string(static_cast<int>(ConnectionStatus::Connected));
+        } else if (ci->tls_) {
+            connectionInfo["status"] = std::to_string(static_cast<int>(ConnectionStatus::TLS));
+        } else if(ci->ice_)
+        {
+            connectionInfo["status"] = std::to_string(static_cast<int>(ConnectionStatus::ICE));
+        }
+        if (ci->tls_) {
+            std::string remoteAddress = ci->tls_->getRemoteAddress();
+            std::string remoteAddressIp = remoteAddress.substr(0, remoteAddress.find(':'));
+            std::string remoteAddressPort = remoteAddress.substr(remoteAddress.find(':') + 1);
+            connectionInfo["remoteAdress"] = remoteAddressIp;
+            connectionInfo["remotePort"] = remoteAddressPort;
+        }
+        connectionsList.emplace_back(std::move(connectionInfo));
+    }
+
+    if (device) {
+        auto it = pimpl_->pendingOperations_.find(device);
+        if (it != pimpl_->pendingOperations_.end()) {
+            const auto& po = it->second;
+            for (const auto& [vid, ci] : po.connecting) {
+                std::map<std::string, std::string> connectionInfo;
+                connectionInfo["id"] = callbackIdToString(device, vid);
+                connectionInfo["deviceId"] = vid;
+                connectionInfo["status"] = std::to_string(static_cast<int>(ConnectionStatus::Connecting));
+                connectionsList.emplace_back(std::move(connectionInfo));
+            }
+
+            for (const auto& [vid, ci] : po.waiting) {
+                std::map<std::string, std::string> connectionInfo;
+                connectionInfo["id"] = callbackIdToString(device, vid);
+                connectionInfo["deviceId"] = vid;
+                connectionInfo["status"] = std::to_string(static_cast<int>(ConnectionStatus::Waiting));
+                connectionsList.emplace_back(std::move(connectionInfo));
+            }
+        }
+    }
+    else {
+        for (const auto& [key, po] : pimpl_->pendingOperations_) {
+            for (const auto& [vid, ci] : po.connecting) {
+                std::map<std::string, std::string> connectionInfo;
+                connectionInfo["id"] = callbackIdToString(device, vid);
+                connectionInfo["deviceId"] = vid;
+                connectionInfo["status"] = std::to_string(static_cast<int>(ConnectionStatus::Connecting));
+                connectionsList.emplace_back(std::move(connectionInfo));
+            }
+
+            for (const auto& [vid, ci] : po.waiting) {
+               std::map<std::string, std::string> connectionInfo;
+                connectionInfo["id"] = callbackIdToString(device, vid);
+                connectionInfo["deviceId"] = vid;
+                connectionInfo["status"] = std::to_string(static_cast<int>(ConnectionStatus::Waiting));
+                connectionsList.emplace_back(std::move(connectionInfo));
+            }
+        }
+    }
+    return connectionsList;
+}
+
+std::vector<std::map<std::string, std::string>>
+ConnectionManager::getChannelList(const std::string& connectionId) const
+{
+    std::lock_guard<std::mutex> lk(pimpl_->infosMtx_);
+    CallbackId cbid = parseCallbackId(connectionId);
+    if (pimpl_->infos_.count(cbid) > 0) {
+        return pimpl_->infos_[cbid]->socket_->getChannelList();
+    } else {
+        return {};
+    }
+}
+
 } // namespace dhtnet
diff --git a/src/multiplexed_socket.cpp b/src/multiplexed_socket.cpp
index 7b58922..9c6d59d 100644
--- a/src/multiplexed_socket.cpp
+++ b/src/multiplexed_socket.cpp
@@ -1204,4 +1204,21 @@
     return {};
 }
 
+std::vector<std::map<std::string, std::string>>
+MultiplexedSocket::getChannelList() const
+{
+    std::vector<std::map<std::string, std::string>> channelsList;
+
+    for (const auto& [_, channel] : pimpl_->sockets) {
+        if (channel) {
+            std::map<std::string, std::string> channelMap;
+            channelMap["channel"] = std::to_string(channel->channel());
+            channelMap["channelName"]= channel->name();
+            channelsList.emplace_back(std::move(channelMap));
+        }
+    }
+
+    return channelsList;
+}
+
 } // namespace dhtnet