From eedf7ca599b799b11f4997f327f6e081430e16ec Mon Sep 17 00:00:00 2001 From: Stephen Shelton Date: Mon, 20 Jul 2020 13:48:57 -0600 Subject: [PATCH] Add implementation of get_peer_stats API --- llarp/peerstats/peer_db.cpp | 16 ++++++++++++++++ llarp/peerstats/peer_db.hpp | 8 ++++++++ llarp/peerstats/types.cpp | 20 +++++++++++++++++++- llarp/peerstats/types.hpp | 5 ++++- llarp/rpc/lokid_rpc_client.cpp | 30 +++++++++++++++++++++++++++++- 5 files changed, 76 insertions(+), 3 deletions(-) diff --git a/llarp/peerstats/peer_db.cpp b/llarp/peerstats/peer_db.cpp index 045839d43..9d4fe50d2 100644 --- a/llarp/peerstats/peer_db.cpp +++ b/llarp/peerstats/peer_db.cpp @@ -140,6 +140,22 @@ namespace llarp return itr->second; } + std::vector + PeerDb::listAllPeerStats() const + { + std::lock_guard guard(m_statsLock); + + std::vector statsList; + statsList.reserve(m_peerStats.size()); + + for (const auto& [routerId, stats] : m_peerStats) + { + statsList.push_back(stats); + } + + return statsList; + } + /// Assume we receive an RC at some point `R` in time which was signed at some point `S` in time /// and expires at some point `E` in time, as depicted below: /// diff --git a/llarp/peerstats/peer_db.hpp b/llarp/peerstats/peer_db.hpp index c61fb3716..d7985e1bd 100644 --- a/llarp/peerstats/peer_db.hpp +++ b/llarp/peerstats/peer_db.hpp @@ -82,6 +82,14 @@ namespace llarp std::optional getCurrentPeerStats(const RouterID& routerId) const; + /// Lists all peer stats. This essentially dumps the database into a list of PeerStats objects. + /// + /// Note that this avoids disk I/O by copying from our cached map of peers. + /// + /// @return a list of all PeerStats we have maintained + std::vector + listAllPeerStats() const; + /// Handles a new gossiped RC, updating stats as needed. The database tracks the last /// advertised update time, so it knows whether this is a new RC or not. /// diff --git a/llarp/peerstats/types.cpp b/llarp/peerstats/types.cpp index 4a0900760..af78d70c0 100644 --- a/llarp/peerstats/types.cpp +++ b/llarp/peerstats/types.cpp @@ -101,7 +101,7 @@ namespace llarp } void - PeerStats::BEncode(llarp_buffer_t* buf) + PeerStats::BEncode(llarp_buffer_t* buf) const { if (not buf) throw std::runtime_error("PeerStats: Can't use null buf"); @@ -138,4 +138,22 @@ namespace llarp } + void + PeerStats::BEncodeList(const std::vector& statsList, llarp_buffer_t* buf) + { + if (not buf) + throw std::runtime_error("PeerStats: Can't use null buf"); + + if (not bencode_start_list(buf)) + throw std::runtime_error("PeerStats: Could not create bencode dict"); + + for (const auto& stats : statsList) + { + stats.BEncode(buf); + } + + if (not bencode_end(buf)) + throw std::runtime_error("PeerStats: Could not end bencode dict"); + } + }; // namespace llarp diff --git a/llarp/peerstats/types.hpp b/llarp/peerstats/types.hpp index d705d99db..78684a61a 100644 --- a/llarp/peerstats/types.hpp +++ b/llarp/peerstats/types.hpp @@ -50,7 +50,10 @@ namespace llarp toJson() const; void - BEncode(llarp_buffer_t* buf); + BEncode(llarp_buffer_t* buf) const; + + static void + BEncodeList(const std::vector& statsList, llarp_buffer_t* buf); }; } // namespace llarp diff --git a/llarp/rpc/lokid_rpc_client.cpp b/llarp/rpc/lokid_rpc_client.cpp index 640131167..aef954844 100644 --- a/llarp/rpc/lokid_rpc_client.cpp +++ b/llarp/rpc/lokid_rpc_client.cpp @@ -220,12 +220,40 @@ namespace llarp void LokidRpcClient::HandleGetPeerStats(lokimq::Message& msg) { - // TODO: construct response LogInfo("Got request for peer stats (size: ", msg.data.size(), ")"); for (auto str : msg.data) { LogInfo(" :", str); } + + assert(m_Router != nullptr); + + if (not m_Router->peerDb()) + { + LogWarn("HandleGetPeerStats called when router has no peerDb set up."); + throw std::runtime_error("Cannot handle get_peer_stats request when no peer db available"); + } + + try + { + // TODO: parse input, expect list of peers to query for + + auto statsList = m_Router->peerDb()->listAllPeerStats(); + + int32_t bufSize = + 256 + (statsList.size() * 1024); // TODO: tune this or allow to grow dynamically + auto buf = std::unique_ptr(new uint8_t[bufSize]); + llarp_buffer_t llarpBuf(buf.get(), bufSize); + + PeerStats::BEncodeList(statsList, &llarpBuf); + + msg.send_reply(std::string_view((const char*)llarpBuf.base, llarpBuf.cur - llarpBuf.base)); + } + catch (const std::exception& e) + { + LogError("Failed to handle get_peer_stats request: ", e.what()); + // TODO: reply with explicit rejection to make lokid's life easier + } } } // namespace rpc