mirror of
https://github.com/oxen-io/lokinet.git
synced 2024-11-02 03:40:12 +00:00
Make new header for json type conversions
This commit is contained in:
parent
02b392881b
commit
0632e88de0
@ -225,7 +225,7 @@ main(int argc, char* argv[])
|
||||
{
|
||||
nlohmann::json opts{{"address", options.exitAddress}, {"token", options.token}};
|
||||
if (options.range)
|
||||
opts["IP_range"] = *options.range;
|
||||
opts["ip_range"] = *options.range;
|
||||
|
||||
auto maybe_result = OMQ_Request(omq, connectionID, "llarp.map_exit", std::move(opts));
|
||||
|
||||
@ -240,10 +240,10 @@ main(int argc, char* argv[])
|
||||
}
|
||||
if (options.vpnDown)
|
||||
{
|
||||
nlohmann::json opts{{"unmap", true}};
|
||||
nlohmann::json opts{{"unmap_exit", true}};
|
||||
if (options.range)
|
||||
opts["range"] = *options.range;
|
||||
if (not OMQ_Request(omq, connectionID, "llarp.exit", std::move(opts)))
|
||||
opts["ip_range"] = *options.range;
|
||||
if (not OMQ_Request(omq, connectionID, "llarp.unmap_exit", std::move(opts)))
|
||||
return exit_error("failed to unmap exit");
|
||||
}
|
||||
|
||||
|
@ -247,6 +247,7 @@ add_library(lokinet-context
|
||||
add_library(lokinet-rpc
|
||||
STATIC
|
||||
rpc/json_binary_proxy.cpp
|
||||
rpc/json_conversions.cpp
|
||||
rpc/lokid_rpc_client.cpp
|
||||
rpc/rpc_request_parser.cpp
|
||||
rpc/rpc_server.cpp
|
||||
|
@ -8,6 +8,7 @@
|
||||
|
||||
#include <list>
|
||||
#include <optional>
|
||||
#include <stdexcept>
|
||||
#include <string>
|
||||
|
||||
namespace llarp
|
||||
@ -24,6 +25,12 @@ namespace llarp
|
||||
: addr{std::move(address)}, netmask_bits{std::move(netmask)}
|
||||
{}
|
||||
|
||||
explicit IPRange(std::string _range)
|
||||
{
|
||||
if (not FromString(_range))
|
||||
throw std::invalid_argument{"IP string '{}' cannot be parsed as IP range"_format(_range)};
|
||||
}
|
||||
|
||||
static IPRange
|
||||
StringInit(std::string _range)
|
||||
{
|
||||
@ -32,6 +39,13 @@ namespace llarp
|
||||
return range;
|
||||
}
|
||||
|
||||
static bool
|
||||
IsValidString(std::string _range)
|
||||
{
|
||||
IPRange range;
|
||||
return (range.FromString(_range));
|
||||
}
|
||||
|
||||
static constexpr IPRange
|
||||
V4MappedRange()
|
||||
{
|
||||
|
@ -156,26 +156,3 @@ namespace llarp::rpc
|
||||
};
|
||||
|
||||
} // namespace llarp::rpc
|
||||
|
||||
// Specializations of binary types for deserialization; when receiving these from json we expect
|
||||
// them encoded in hex or base64. These may *not* be used for serialization, and will throw if so
|
||||
// invoked; for serialization you need to use RPC_COMMAND::response_hex (or _b64) instead.
|
||||
namespace nlohmann
|
||||
{
|
||||
template <typename T>
|
||||
struct adl_serializer<T, std::enable_if_t<llarp::rpc::json_is_binary<T>>>
|
||||
{
|
||||
static_assert(std::is_trivially_copyable_v<T> && std::has_unique_object_representations_v<T>);
|
||||
|
||||
static void
|
||||
to_json(const T&)
|
||||
{
|
||||
throw std::logic_error{"Internal error: binary types are not directly serializable"};
|
||||
}
|
||||
static void
|
||||
from_json(const json& j, T& val)
|
||||
{
|
||||
llarp::rpc::load_binary_parameter(j.get<std::string_view>(), false /*no raw*/, val);
|
||||
}
|
||||
};
|
||||
} // namespace nlohmann
|
||||
|
18
llarp/rpc/json_conversions.cpp
Normal file
18
llarp/rpc/json_conversions.cpp
Normal file
@ -0,0 +1,18 @@
|
||||
#include "json_conversions.hpp"
|
||||
#include <nlohmann/json.hpp>
|
||||
|
||||
namespace llarp
|
||||
{
|
||||
void
|
||||
to_json(nlohmann::json& j, const IPRange& ipr)
|
||||
{
|
||||
j = ipr.ToString();
|
||||
}
|
||||
|
||||
void
|
||||
from_json(const nlohmann::json& j, IPRange& ipr)
|
||||
{
|
||||
ipr = IPRange{j.get<std::string>()};
|
||||
}
|
||||
|
||||
} // namespace llarp
|
37
llarp/rpc/json_conversions.hpp
Normal file
37
llarp/rpc/json_conversions.hpp
Normal file
@ -0,0 +1,37 @@
|
||||
#pragma once
|
||||
|
||||
#include <llarp/net/ip_range.hpp>
|
||||
#include <nlohmann/json_fwd.hpp>
|
||||
#include "json_binary_proxy.hpp"
|
||||
|
||||
namespace llarp
|
||||
{
|
||||
void
|
||||
to_json(nlohmann::json& j, const IPRange& ipr);
|
||||
void
|
||||
from_json(const nlohmann::json& j, IPRange& ipr);
|
||||
} // namespace llarp
|
||||
|
||||
namespace nlohmann
|
||||
{
|
||||
// Specializations of binary types for deserialization; when receiving these from json we expect
|
||||
// them encoded in hex or base64. These may *not* be used for serialization, and will throw if so
|
||||
// invoked; for serialization you need to use RPC_COMMAND::response_hex (or _b64) instead.
|
||||
template <typename T>
|
||||
struct adl_serializer<T, std::enable_if_t<llarp::rpc::json_is_binary<T>>>
|
||||
{
|
||||
static_assert(std::is_trivially_copyable_v<T> && std::has_unique_object_representations_v<T>);
|
||||
|
||||
static void
|
||||
to_json(json&, const T&)
|
||||
{
|
||||
throw std::logic_error{"Internal error: binary types are not directly serializable"};
|
||||
}
|
||||
static void
|
||||
from_json(const json& j, T& val)
|
||||
{
|
||||
llarp::rpc::load_binary_parameter(j.get<std::string_view>(), false /*no raw*/, val);
|
||||
}
|
||||
};
|
||||
|
||||
} // namespace nlohmann
|
@ -1,14 +1,17 @@
|
||||
#pragma once
|
||||
|
||||
#include "json_binary_proxy.hpp"
|
||||
#include "json_bt.hpp"
|
||||
#include "json_conversions.hpp"
|
||||
#include <oxenc/bt_serialize.h>
|
||||
#include <nlohmann/json.hpp>
|
||||
#include <stdexcept>
|
||||
#include <string>
|
||||
#include <unordered_map>
|
||||
#include <optional>
|
||||
|
||||
namespace llarp::rpc
|
||||
{
|
||||
|
||||
using json_range = std::pair<nlohmann::json::const_iterator, nlohmann::json::const_iterator>;
|
||||
using rpc_input = std::variant<std::monostate, nlohmann::json, oxenc::bt_dict_consumer>;
|
||||
|
||||
@ -116,6 +119,12 @@ namespace llarp::rpc
|
||||
template <typename T>
|
||||
constexpr bool is_expandable_list<std::vector<T>> = true;
|
||||
|
||||
// Types that are constructible from string
|
||||
template <typename T>
|
||||
constexpr bool is_string_constructible = false;
|
||||
template <>
|
||||
inline constexpr bool is_string_constructible<IPRange> = true;
|
||||
|
||||
// Fixed size elements: tuples, pairs, and std::array's; we accept list input as long as the
|
||||
// list length matches exactly.
|
||||
template <typename T>
|
||||
@ -147,32 +156,34 @@ namespace llarp::rpc
|
||||
oxenc::bt_dict_consumer> || std::is_same_v<BTConsumer, oxenc::bt_list_consumer>,
|
||||
int> = 0>
|
||||
void
|
||||
load_value(BTConsumer& c, T& val)
|
||||
load_value(BTConsumer& c, T& target)
|
||||
{
|
||||
if constexpr (std::is_integral_v<T>)
|
||||
val = c.template consume_integer<T>();
|
||||
target = c.template consume_integer<T>();
|
||||
else if constexpr (std::is_same_v<T, std::string> || std::is_same_v<T, std::string_view>)
|
||||
val = c.consume_string_view();
|
||||
target = c.consume_string_view();
|
||||
else if constexpr (is_string_constructible<T>)
|
||||
target = T{c.consume_string()};
|
||||
else if constexpr (llarp::rpc::json_is_binary<T>)
|
||||
llarp::rpc::load_binary_parameter(c.consume_string_view(), true /*allow raw*/, val);
|
||||
llarp::rpc::load_binary_parameter(c.consume_string_view(), true /*allow raw*/, target);
|
||||
else if constexpr (is_expandable_list<T>)
|
||||
{
|
||||
auto lc = c.consume_list_consumer();
|
||||
val.clear();
|
||||
target.clear();
|
||||
while (!lc.is_finished())
|
||||
load_value(lc, val.emplace_back());
|
||||
load_value(lc, target.emplace_back());
|
||||
}
|
||||
else if constexpr (is_tuple_like<T>)
|
||||
{
|
||||
auto lc = c.consume_list_consumer();
|
||||
load_tuple_values(lc, val, std::make_index_sequence<std::tuple_size_v<T>>{});
|
||||
load_tuple_values(lc, target, std::make_index_sequence<std::tuple_size_v<T>>{});
|
||||
}
|
||||
else if constexpr (is_unordered_string_map<T>)
|
||||
{
|
||||
auto dc = c.consume_dict_consumer();
|
||||
val.clear();
|
||||
target.clear();
|
||||
while (!dc.is_finished())
|
||||
load_value(dc, val[std::string{dc.key()}]);
|
||||
load_value(dc, target[std::string{dc.key()}]);
|
||||
}
|
||||
else
|
||||
static_assert(std::is_same_v<T, void>, "Unsupported load_value type");
|
||||
@ -182,21 +193,21 @@ namespace llarp::rpc
|
||||
// on unconvertible values.
|
||||
template <typename T>
|
||||
void
|
||||
load_value(json_range& r, T& val)
|
||||
load_value(json_range& range_itr, T& target)
|
||||
{
|
||||
auto& key = r.first.key();
|
||||
auto& e = *r.first;
|
||||
auto& key = range_itr.first.key();
|
||||
auto& current = *range_itr.first; // value currently pointed to by range_itr.first
|
||||
if constexpr (std::is_same_v<T, bool>)
|
||||
{
|
||||
if (e.is_boolean())
|
||||
val = e.get<bool>();
|
||||
else if (e.is_number_unsigned())
|
||||
if (current.is_boolean())
|
||||
target = current.get<bool>();
|
||||
else if (current.is_number_unsigned())
|
||||
{
|
||||
// Also accept 0 or 1 for bools (mainly to be compatible with bt-encoding which doesn't
|
||||
// have a distinct bool type).
|
||||
auto b = e.get<uint64_t>();
|
||||
auto b = current.get<uint64_t>();
|
||||
if (b <= 1)
|
||||
val = b;
|
||||
target = b;
|
||||
else
|
||||
throw std::domain_error{"Invalid value for '" + key + "': expected boolean"};
|
||||
}
|
||||
@ -207,18 +218,18 @@ namespace llarp::rpc
|
||||
}
|
||||
else if constexpr (std::is_unsigned_v<T>)
|
||||
{
|
||||
if (!e.is_number_unsigned())
|
||||
if (!current.is_number_unsigned())
|
||||
throw std::domain_error{"Invalid value for '" + key + "': non-negative value required"};
|
||||
auto i = e.get<uint64_t>();
|
||||
auto i = current.get<uint64_t>();
|
||||
if (sizeof(T) < sizeof(uint64_t) && i > std::numeric_limits<T>::max())
|
||||
throw std::domain_error{"Invalid value for '" + key + "': value too large"};
|
||||
val = i;
|
||||
target = i;
|
||||
}
|
||||
else if constexpr (std::is_integral_v<T>)
|
||||
{
|
||||
if (!e.is_number_integer())
|
||||
if (!current.is_number_integer())
|
||||
throw std::domain_error{"Invalid value for '" + key + "': value is not an integer"};
|
||||
auto i = e.get<int64_t>();
|
||||
auto i = current.get<int64_t>();
|
||||
if (sizeof(T) < sizeof(int64_t))
|
||||
{
|
||||
if (i < std::numeric_limits<T>::lowest())
|
||||
@ -227,11 +238,11 @@ namespace llarp::rpc
|
||||
if (i > std::numeric_limits<T>::max())
|
||||
throw std::domain_error{"Invalid value for '" + key + "': value is too large"};
|
||||
}
|
||||
val = i;
|
||||
target = i;
|
||||
}
|
||||
else if constexpr (std::is_same_v<T, std::string> || std::is_same_v<T, std::string_view>)
|
||||
{
|
||||
val = e.get<std::string_view>();
|
||||
target = current.get<std::string_view>();
|
||||
}
|
||||
else if constexpr (
|
||||
llarp::rpc::json_is_binary<
|
||||
@ -239,7 +250,7 @@ namespace llarp::rpc
|
||||
{
|
||||
try
|
||||
{
|
||||
e.get_to(val);
|
||||
current.get_to(target);
|
||||
}
|
||||
catch (const std::exception& e)
|
||||
{
|
||||
@ -250,7 +261,7 @@ namespace llarp::rpc
|
||||
{
|
||||
static_assert(std::is_same_v<T, void>, "Unsupported load type");
|
||||
}
|
||||
++r.first;
|
||||
++range_itr.first;
|
||||
}
|
||||
|
||||
template <typename TupleLike, size_t... Is>
|
||||
@ -355,5 +366,4 @@ namespace llarp::rpc
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
} // namespace llarp::rpc
|
@ -14,7 +14,6 @@
|
||||
|
||||
namespace llarp::rpc
|
||||
{
|
||||
|
||||
using nlohmann::json;
|
||||
|
||||
template <typename RPC>
|
||||
|
@ -176,78 +176,16 @@ namespace llarp::rpc
|
||||
struct request_parameters
|
||||
{
|
||||
std::string address;
|
||||
std::vector<std::string> ip_range;
|
||||
std::vector<IPRange> ip_range;
|
||||
std::string token;
|
||||
} request;
|
||||
|
||||
void
|
||||
onGoodResult(std::string reason, bool hasClient)
|
||||
{
|
||||
response = (hasClient) ? nlohmann::json{{"result", reason}}.dump()
|
||||
: nlohmann::json{{"error", "We don't have an exit?"}}.dump();
|
||||
}
|
||||
|
||||
void
|
||||
onBadResult(
|
||||
std::string reason, AbstractRouter& abs, llarp::service::Endpoint_ptr eptr, IPRange range)
|
||||
{
|
||||
abs.routePoker()->Down();
|
||||
eptr->UnmapExitRange(range);
|
||||
response = nlohmann::json{{"result", reason}}.dump();
|
||||
}
|
||||
|
||||
void
|
||||
mapExit(
|
||||
service::Address addr,
|
||||
AbstractRouter& router,
|
||||
llarp::service::Endpoint_ptr eptr,
|
||||
IPRange range,
|
||||
service::Address exitAddr)
|
||||
{
|
||||
eptr->MapExitRange(range, addr);
|
||||
|
||||
bool sendAuth = (request.token.empty()) ? false : true;
|
||||
if (sendAuth)
|
||||
eptr->SetAuthInfoForEndpoint(exitAddr, service::AuthInfo{request.token});
|
||||
|
||||
if (addr.IsZero())
|
||||
{
|
||||
onGoodResult("Null exit added", router.HasClientExit());
|
||||
return;
|
||||
}
|
||||
|
||||
eptr->MarkAddressOutbound(addr);
|
||||
|
||||
eptr->EnsurePathToService(addr, [&](auto, service::OutboundContext* ctx) {
|
||||
if (ctx == nullptr)
|
||||
{
|
||||
onBadResult("Could not find exit", router, eptr, range);
|
||||
return;
|
||||
}
|
||||
if (not sendAuth)
|
||||
{
|
||||
onGoodResult("OK: connected to " + addr.ToString(), router.HasClientExit());
|
||||
return;
|
||||
}
|
||||
// only lambda that we will keep
|
||||
ctx->AsyncSendAuth([&](service::AuthResult result) {
|
||||
if (result.code != service::AuthResultCode::eAuthAccepted)
|
||||
{
|
||||
onBadResult(result.reason, router, eptr, range);
|
||||
return;
|
||||
}
|
||||
onGoodResult(result.reason, router.HasClientExit());
|
||||
return;
|
||||
});
|
||||
});
|
||||
}
|
||||
};
|
||||
|
||||
// RPC: list_exits
|
||||
// List all currently mapped exit node connections
|
||||
//
|
||||
// Inputs: none
|
||||
//
|
||||
//
|
||||
// Returns:
|
||||
//
|
||||
struct ListExits : NoArgs
|
||||
@ -271,15 +209,13 @@ namespace llarp::rpc
|
||||
|
||||
struct request_parameters
|
||||
{
|
||||
std::vector<std::string> ip_range;
|
||||
std::vector<IPRange> ip_range;
|
||||
} request;
|
||||
};
|
||||
|
||||
// RPC: dns_query
|
||||
// Attempts to query endpoint by domain name
|
||||
//
|
||||
// Note: ask Jason about the internals of this
|
||||
//
|
||||
// Inputs:
|
||||
// "endpoint" : endpoint ID to query (string)
|
||||
// "qname" : query name (string)
|
||||
|
@ -58,7 +58,7 @@ namespace llarp::rpc
|
||||
input,
|
||||
"address",
|
||||
mapexit.request.address,
|
||||
"IP_range",
|
||||
"ip_range",
|
||||
mapexit.request.ip_range,
|
||||
"token",
|
||||
mapexit.request.token);
|
||||
@ -67,10 +67,7 @@ namespace llarp::rpc
|
||||
void
|
||||
parse_request(UnmapExit& unmapexit, rpc_input input)
|
||||
{
|
||||
get_values(
|
||||
input,
|
||||
"IP_range",
|
||||
unmapexit.request.ip_range);
|
||||
get_values(input, "ip_range", unmapexit.request.ip_range);
|
||||
}
|
||||
|
||||
void
|
||||
|
@ -91,11 +91,11 @@ namespace llarp::rpc
|
||||
register_rpc_command(std::unordered_map<std::string, rpc_callback>& regs)
|
||||
{
|
||||
static_assert(std::is_base_of_v<RPCRequest, RPC>);
|
||||
auto cback = std::make_shared<rpc_callback>();
|
||||
rpc_callback cback{};
|
||||
|
||||
cback->invoke = make_invoke<RPC>();
|
||||
cback.invoke = make_invoke<RPC>();
|
||||
|
||||
regs.emplace(RPC::name, cback);
|
||||
regs.emplace(RPC::name, std::move(cback));
|
||||
}
|
||||
|
||||
RPCServer::RPCServer(LMQ_ptr lmq, AbstractRouter& r)
|
||||
@ -355,12 +355,17 @@ namespace llarp::rpc
|
||||
MapExit exit_request;
|
||||
// steal replier from exit RPC endpoint
|
||||
exit_request.replier.emplace(std::move(*mapexit.replier));
|
||||
|
||||
//
|
||||
//
|
||||
//
|
||||
//
|
||||
//
|
||||
|
||||
m_Router.hiddenServiceContext().GetDefault()->map_exit(
|
||||
mapexit.request.address,
|
||||
mapexit.request.token,
|
||||
mapexit.request.ip_range,
|
||||
[exit = std::move(exit_request)](bool success, std::string result) mutable {
|
||||
if (success)
|
||||
exit.send_response({{"result"}, std::move(result)});
|
||||
else
|
||||
exit.send_response({{"error"}, std::move(result)});
|
||||
});
|
||||
}
|
||||
|
||||
void
|
||||
@ -369,8 +374,10 @@ namespace llarp::rpc
|
||||
if (not m_Router.hiddenServiceContext().hasEndpoints())
|
||||
listexits.response = CreateJSONError("No mapped endpoints found");
|
||||
else
|
||||
listexits.response = CreateJSONResponse(
|
||||
m_Router.hiddenServiceContext().GetDefault()->ExtractStatus()["m_ExitMap"]);
|
||||
listexits.response =
|
||||
CreateJSONResponse(m_Router.hiddenServiceContext().GetDefault()->ExtractStatus()["m_"
|
||||
"ExitMa"
|
||||
"p"]);
|
||||
}
|
||||
|
||||
void
|
||||
@ -382,22 +389,14 @@ namespace llarp::rpc
|
||||
return;
|
||||
}
|
||||
|
||||
std::vector<IPRange> range{};
|
||||
|
||||
for (auto& ip : unmapexit.request.ip_range)
|
||||
try
|
||||
{
|
||||
try {
|
||||
range.push_back(IPRange::StringInit(ip));
|
||||
} catch (std::exception& e) {
|
||||
unmapexit.response = CreateJSONError(e.what());
|
||||
}
|
||||
}
|
||||
|
||||
try {
|
||||
m_Router.routePoker()->Down();
|
||||
for (auto& ip : range)
|
||||
for (auto& ip : unmapexit.request.ip_range)
|
||||
m_Router.hiddenServiceContext().GetDefault()->UnmapExitRange(ip);
|
||||
} catch (std::exception& e) {
|
||||
}
|
||||
catch (std::exception& e)
|
||||
{
|
||||
unmapexit.response = CreateJSONError("Unable to unmap to given range");
|
||||
}
|
||||
|
||||
@ -439,16 +438,6 @@ namespace llarp::rpc
|
||||
return;
|
||||
}
|
||||
|
||||
/*
|
||||
only have simple filename ex: "persist_key.ini"
|
||||
create .ini files inside conf.d
|
||||
|
||||
add delete functionality
|
||||
delete parameter (bool)
|
||||
use same filename parameter
|
||||
|
||||
*/
|
||||
|
||||
void
|
||||
RPCServer::invoke(Config& config)
|
||||
{
|
||||
|
@ -150,10 +150,6 @@ namespace llarp::rpc
|
||||
fmt::format("RPC request 'rpc.{}' raised an exception: {}", rpc.name, e.what()));
|
||||
}
|
||||
|
||||
// check if std::optional in rpc is present
|
||||
// then rpc.send_response
|
||||
// else
|
||||
// do nothing because invoke stole RPC
|
||||
if (rpc.replier.has_value())
|
||||
rpc.send_response();
|
||||
}
|
||||
|
Loading…
Reference in New Issue
Block a user