1
1
Fork 0
mirror of https://github.com/oxen-io/lokinet synced 2023-12-14 06:53:00 +01:00
lokinet/llarp/rpc/lokid_rpc_client.cpp

203 lines
5.7 KiB
C++
Raw Normal View History

2020-05-18 18:06:52 +02:00
#include <rpc/lokid_rpc_client.hpp>
#include <util/logging/logger.hpp>
2020-05-19 20:53:03 +02:00
#include <router/abstractrouter.hpp>
#include <nlohmann/json.hpp>
#include <util/time.hpp>
#include <util/thread/logic.hpp>
2020-05-18 18:06:52 +02:00
namespace llarp
{
namespace rpc
{
static lokimq::LogLevel
2020-05-19 20:53:03 +02:00
toLokiMQLogLevel(llarp::LogLevel level)
2020-05-18 18:06:52 +02:00
{
switch (level)
{
case eLogError:
return lokimq::LogLevel::error;
case eLogWarn:
return lokimq::LogLevel::warn;
case eLogInfo:
return lokimq::LogLevel::info;
case eLogDebug:
return lokimq::LogLevel::debug;
case eLogNone:
default:
return lokimq::LogLevel::trace;
}
}
2020-05-19 20:53:03 +02:00
2020-05-19 20:53:03 +02:00
LokidRpcClient::LokidRpcClient(LMQ_ptr lmq, AbstractRouter* r)
: m_lokiMQ(std::move(lmq)), m_Router(r)
2020-05-18 18:06:52 +02:00
{
2020-05-19 20:53:03 +02:00
// m_lokiMQ->log_level(toLokiMQLogLevel(LogLevel::Instance().curLevel));
2020-05-18 18:06:52 +02:00
}
2020-05-19 20:53:03 +02:00
void
LokidRpcClient::ConnectAsync(lokimq::address url)
2020-05-18 18:06:52 +02:00
{
2020-05-19 20:53:03 +02:00
LogInfo("connecting to lokid via LMQ at ", url);
m_lokiMQ->connect_remote(
url.zmq_address(),
2020-05-19 20:53:03 +02:00
[self = shared_from_this()](lokimq::ConnectionID c) {
self->m_Connection = std::move(c);
self->Connected();
},
[self = shared_from_this(), url](lokimq::ConnectionID, std::string_view f) {
2020-05-19 20:53:03 +02:00
llarp::LogWarn("Failed to connect to lokid: ", f);
LogicCall(self->m_Router->logic(), [self, url]() { self->ConnectAsync(url); });
2020-05-19 20:53:03 +02:00
});
2020-05-18 18:06:52 +02:00
}
void
2020-05-19 20:53:03 +02:00
LokidRpcClient::Command(std::string_view cmd)
2020-05-18 18:06:52 +02:00
{
2020-05-19 20:53:03 +02:00
LogDebug("lokid command: ", cmd);
m_lokiMQ->send(*m_Connection, std::move(cmd));
2020-05-18 18:06:52 +02:00
}
2020-05-20 13:41:42 +02:00
void
LokidRpcClient::UpdateServiceNodeList()
{
nlohmann::json request;
request["pubkey_ed25519"] = true;
request["active_only"] = true;
if (not m_CurrentBlockHash.empty())
request["poll_block_hash"] = m_CurrentBlockHash;
Request(
"rpc.get_service_nodes",
[self = shared_from_this()](bool success, std::vector<std::string> data) {
if (not success)
{
LogWarn("failed to update service node list");
return;
}
if (data.size() < 2)
{
LogWarn("lokid gave empty reply for service node list");
return;
}
try
{
self->HandleGotServiceNodeList(std::move(data[1]));
}
catch (std::exception& ex)
{
LogError("failed to process service node list: ", ex.what());
}
},
request.dump());
}
2020-05-19 20:53:03 +02:00
void
LokidRpcClient::Connected()
2020-05-18 18:06:52 +02:00
{
2020-05-19 20:53:03 +02:00
constexpr auto PingInterval = 1min;
2020-05-20 13:41:42 +02:00
constexpr auto NodeListUpdateInterval = 30s;
2020-05-18 18:06:52 +02:00
2020-05-19 20:53:03 +02:00
LogInfo("we connected to lokid [", *m_Connection, "]");
2020-05-20 13:41:42 +02:00
Command("admin.lokinet_ping");
2020-05-19 20:53:03 +02:00
m_lokiMQ->add_timer(
2020-05-20 13:41:42 +02:00
[self = shared_from_this()]() { self->Command("admin.lokinet_ping"); }, PingInterval);
2020-05-19 20:53:03 +02:00
m_lokiMQ->add_timer(
2020-05-20 13:41:42 +02:00
[self = shared_from_this()]() { self->UpdateServiceNodeList(); }, NodeListUpdateInterval);
UpdateServiceNodeList();
2020-05-18 18:06:52 +02:00
}
void
2020-05-19 20:53:03 +02:00
LokidRpcClient::HandleGotServiceNodeList(std::string data)
2020-05-18 18:06:52 +02:00
{
2020-05-19 20:53:03 +02:00
auto j = nlohmann::json::parse(std::move(data));
{
const auto itr = j.find("block_hash");
if (itr != j.end())
{
m_CurrentBlockHash = itr->get<std::string>();
}
}
{
const auto itr = j.find("unchanged");
if (itr != j.end())
{
if (itr->get<bool>())
{
LogDebug("service node list unchanged");
return;
}
}
}
std::vector<RouterID> nodeList;
{
const auto itr = j.find("service_node_states");
if (itr != j.end() and itr->is_array())
{
for (auto j_itr = itr->begin(); j_itr != itr->end(); j_itr++)
{
const auto ed_itr = j_itr->find("pubkey_ed25519");
if (ed_itr == j_itr->end() or not ed_itr->is_string())
continue;
RouterID rid;
if (rid.FromHex(ed_itr->get<std::string>()))
nodeList.emplace_back(std::move(rid));
}
}
}
if (nodeList.empty())
{
LogWarn("got empty service node list from lokid");
return;
}
// inform router about the new list
LogicCall(m_Router->logic(), [r = m_Router, nodeList]() { r->SetRouterWhitelist(nodeList); });
2020-05-18 18:06:52 +02:00
}
2020-05-20 13:41:42 +02:00
std::optional<SecretKey>
LokidRpcClient::ObtainIdentityKey()
{
std::promise<std::optional<SecretKey>> promise;
Request(
"admin.get_service_privkeys",
[self = shared_from_this(), &promise](bool success, std::vector<std::string> data) {
if (not success)
{
LogError("failed to get private key");
promise.set_value(std::nullopt);
return;
}
if (data.empty())
2020-05-20 13:41:42 +02:00
{
LogError("failed to get private key, no response");
promise.set_value(std::nullopt);
return;
}
try
{
auto j = nlohmann::json::parse(data[0]);
2020-05-20 13:41:42 +02:00
SecretKey k;
if (not k.FromHex(j.at("service_node_ed25519_privkey").get<std::string>()))
{
promise.set_value(std::nullopt);
return;
}
promise.set_value(k);
}
catch (std::exception& ex)
{
LogError("failed to get private key: ", ex.what());
promise.set_value(std::nullopt);
}
});
return promise.get_future().get();
}
2020-05-18 18:06:52 +02:00
} // namespace rpc
} // namespace llarp