stale
This commit is contained in:
parent
4ddaea91a7
commit
19d21ec47d
@ -1,11 +1,8 @@
|
|||||||
server:
|
server:
|
||||||
ip: "127.0.0.1"
|
ip: "127.0.0.1"
|
||||||
port: 8085
|
port: 9095
|
||||||
|
|
||||||
test_data:
|
test_data:
|
||||||
intrinsic_params: [1.1, 0.0, 0.0, 0.0, 1.1, 0.0, 0.0, 0.0, 1.0]
|
intrinsic_params: [1.0, 2.0, 3.0, 4.0, 5.0, 6.0, 7.0, 8.0, 9.0]
|
||||||
extrinsic_params: [1.0, 0.0, 0.0, 0.5, 0.0, 1.0, 0.0, 0.5, 0.0, 0.0, 1.0, 0.0, 0.0, 0.0, 0.0, 1.0]
|
extrinsic_params: [1,0,0,0, 0,1,0,0, 0,0,1,0, 0,0,0,1]
|
||||||
cloud_point:
|
cloud_point:
|
||||||
- [0.1, 0.2, 0.3]
|
- [0.1, 0.2, 0.3]
|
||||||
- [1.1, 1.2, 1.3]
|
|
||||||
- [5.5, 6.6, 7.7]
|
|
||||||
|
|||||||
@ -1,19 +1,21 @@
|
|||||||
#pragma once
|
#pragma once
|
||||||
|
|
||||||
|
#include "jsonrpccxx/iclientconnector.hpp"
|
||||||
|
#include <asio.hpp>
|
||||||
|
#include <cstddef>
|
||||||
#include <glog/logging.h>
|
#include <glog/logging.h>
|
||||||
|
#include <jsonrpccxx/client.hpp>
|
||||||
|
#include <nlohmann/json.hpp>
|
||||||
|
#include <stdexcept>
|
||||||
#include <string>
|
#include <string>
|
||||||
#include <vector>
|
#include <vector>
|
||||||
#include <nlohmann/json.hpp>
|
|
||||||
#include <asio.hpp>
|
|
||||||
#include <stdexcept>
|
|
||||||
|
|
||||||
namespace cloud_point_rpc {
|
namespace cloud_point_rpc {
|
||||||
|
|
||||||
class RpcClient {
|
class TCPConnector : public jsonrpccxx::IClientConnector {
|
||||||
public:
|
public:
|
||||||
RpcClient() : socket_(io_context_) {}
|
TCPConnector(const std::string &ip, size_t port) noexcept(false)
|
||||||
|
: io_context_(), socket_(io_context_) {
|
||||||
void connect(const std::string& ip, int port) {
|
|
||||||
try {
|
try {
|
||||||
LOG(INFO) << "Client connecting to " << ip << ":" << port;
|
LOG(INFO) << "Client connecting to " << ip << ":" << port;
|
||||||
asio::ip::tcp::endpoint endpoint(asio::ip::make_address(ip), port);
|
asio::ip::tcp::endpoint endpoint(asio::ip::make_address(ip), port);
|
||||||
@ -24,59 +26,63 @@ class RpcClient {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
[[nodiscard]] std::vector<double> get_intrinsic_params() {
|
std::string Send(const std::string &request) override {
|
||||||
return call("get-intrinsic-params")["result"].get<std::vector<double>>();
|
|
||||||
}
|
|
||||||
|
|
||||||
[[nodiscard]] std::vector<double> get_extrinsic_params() {
|
|
||||||
return call("get-extrinsic-params")["result"].get<std::vector<double>>();
|
|
||||||
}
|
|
||||||
|
|
||||||
[[nodiscard]] std::vector<std::vector<double>> get_cloud_point() {
|
|
||||||
return call("get-cloud-point")["result"].get<std::vector<std::vector<double>>>();
|
|
||||||
}
|
|
||||||
|
|
||||||
[[nodiscard]] nlohmann::json call(const std::string& method, const nlohmann::json& params = nlohmann::json::object()) {
|
|
||||||
using json = nlohmann::json;
|
|
||||||
|
|
||||||
// Create Request
|
|
||||||
json request = {
|
|
||||||
{"jsonrpc", "2.0"},
|
|
||||||
{"method", method},
|
|
||||||
{"params", params},
|
|
||||||
{"id", ++id_counter_}
|
|
||||||
};
|
|
||||||
std::string request_str = request.dump();
|
|
||||||
|
|
||||||
// Send
|
// Send
|
||||||
LOG(INFO) << "Client sending: " << request_str;
|
LOG(INFO) << "Client sending: " << request;
|
||||||
asio::write(socket_, asio::buffer(request_str));
|
asio::write(socket_, asio::buffer(request));
|
||||||
|
return read();
|
||||||
// Read Response
|
|
||||||
LOG(INFO) << "Client reading response...";
|
|
||||||
std::vector<char> buffer(65536);
|
|
||||||
asio::error_code ec;
|
|
||||||
size_t len = socket_.read_some(asio::buffer(buffer), ec);
|
|
||||||
if (ec) throw std::system_error(ec);
|
|
||||||
|
|
||||||
LOG(INFO) << "Client read " << len << " bytes";
|
|
||||||
json response = json::parse(std::string(buffer.data(), len));
|
|
||||||
|
|
||||||
if (response.contains("error")) {
|
|
||||||
throw std::runtime_error(response["error"]["message"].get<std::string>());
|
|
||||||
}
|
}
|
||||||
|
|
||||||
return response;
|
protected:
|
||||||
|
std::string read() {
|
||||||
|
std::string result;
|
||||||
|
std::array<char, 8> header;
|
||||||
|
LOG(INFO) << "trying to read";
|
||||||
|
|
||||||
|
size_t len = asio::read(socket_, asio::buffer(header));
|
||||||
|
if (len != sizeof(uint64_t)) {
|
||||||
|
LOG(ERROR) << "failed to read header";
|
||||||
|
return result;
|
||||||
}
|
}
|
||||||
|
|
||||||
~RpcClient() {
|
uint64_t packet_size = reinterpret_cast<uint64_t>(header.data());
|
||||||
// Socket closes automatically
|
|
||||||
|
std::vector<char> payload(packet_size);
|
||||||
|
len = asio::read(socket_, asio::buffer(payload));
|
||||||
|
|
||||||
|
LOG(INFO) << std::format("read len={}", len);
|
||||||
|
|
||||||
|
result = payload.data();
|
||||||
|
return result;
|
||||||
}
|
}
|
||||||
|
|
||||||
private:
|
private:
|
||||||
asio::io_context io_context_;
|
asio::io_context io_context_;
|
||||||
asio::ip::tcp::socket socket_;
|
asio::ip::tcp::socket socket_;
|
||||||
int id_counter_ = 0;
|
};
|
||||||
|
|
||||||
|
class RpcClient : public jsonrpccxx::JsonRpcClient {
|
||||||
|
public:
|
||||||
|
RpcClient(TCPConnector &connector)
|
||||||
|
: jsonrpccxx::JsonRpcClient(connector, jsonrpccxx::version::v2) {}
|
||||||
|
|
||||||
|
[[nodiscard]] std::vector<double> get_intrinsic_params() {
|
||||||
|
return this->CallMethod<std::vector<double>>(id++, "get-intrinsic-params");
|
||||||
|
}
|
||||||
|
|
||||||
|
[[nodiscard]] std::vector<double> get_extrinsic_params() {
|
||||||
|
return this->CallMethod<std::vector<double>>(id++, "get-extrinsic-params");
|
||||||
|
}
|
||||||
|
|
||||||
|
[[nodiscard]] std::vector<std::vector<double>> get_cloud_point() {
|
||||||
|
return this->CallMethod<std::vector<std::vector<double>>>(
|
||||||
|
id++, "get-cloud-point");
|
||||||
|
}
|
||||||
|
|
||||||
|
~RpcClient() = default;
|
||||||
|
|
||||||
|
private:
|
||||||
|
int id{0};
|
||||||
};
|
};
|
||||||
|
|
||||||
} // namespace cloud_point_rpc
|
} // namespace cloud_point_rpc
|
||||||
|
|||||||
46
src/cli.cpp
46
src/cli.cpp
@ -2,6 +2,7 @@
|
|||||||
#include "cloud_point_rpc/rpc_client.hpp"
|
#include "cloud_point_rpc/rpc_client.hpp"
|
||||||
#include <glog/logging.h>
|
#include <glog/logging.h>
|
||||||
#include <iomanip>
|
#include <iomanip>
|
||||||
|
#include <string>
|
||||||
|
|
||||||
namespace cloud_point_rpc {
|
namespace cloud_point_rpc {
|
||||||
|
|
||||||
@ -14,19 +15,39 @@ void print_menu(std::ostream& output) {
|
|||||||
output << "Select an option: ";
|
output << "Select an option: ";
|
||||||
}
|
}
|
||||||
|
|
||||||
int run_cli(std::istream& input, std::ostream& output, const std::string& ip, int port) {
|
template <typename T> std::string vector_to_string(const std::vector<T> &v) {
|
||||||
|
std::string result;
|
||||||
|
for (auto &el : v) {
|
||||||
|
result += std::to_string(el) + " ";
|
||||||
|
}
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
|
||||||
|
template <typename T>
|
||||||
|
std::string vector_to_string(const std::vector<std::vector<T>> &v) {
|
||||||
|
std::string result;
|
||||||
|
for (auto &el : v) {
|
||||||
|
result += vector_to_string(el) + "\n";
|
||||||
|
}
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
|
||||||
|
int run_cli(std::istream &input, std::ostream &output, const std::string &ip,
|
||||||
|
int port) {
|
||||||
try {
|
try {
|
||||||
RpcClient client;
|
TCPConnector connector(ip, port);
|
||||||
client.connect(ip, port);
|
RpcClient client(connector);
|
||||||
|
|
||||||
output << "Connected to " << ip << ":" << port << std::endl;
|
output << "Connected to " << ip << ":" << port << std::endl;
|
||||||
|
|
||||||
std::string choice;
|
std::string choice;
|
||||||
while (true) {
|
while (true) {
|
||||||
print_menu(output);
|
print_menu(output);
|
||||||
if (!(input >> choice)) break;
|
if (!(input >> choice))
|
||||||
|
break;
|
||||||
|
|
||||||
if (choice == "0") break;
|
if (choice == "0")
|
||||||
|
break;
|
||||||
|
|
||||||
std::string method;
|
std::string method;
|
||||||
if (choice == "1") {
|
if (choice == "1") {
|
||||||
@ -41,8 +62,19 @@ int run_cli(std::istream& input, std::ostream& output, const std::string& ip, in
|
|||||||
}
|
}
|
||||||
|
|
||||||
try {
|
try {
|
||||||
auto response = client.call(method);
|
|
||||||
output << "\nResponse:\n" << response.dump(4) << std::endl;
|
if (method == "get-intrinsic-params") {
|
||||||
|
auto response = client.get_intrinsic_params();
|
||||||
|
LOG(INFO) << vector_to_string(response);
|
||||||
|
}
|
||||||
|
if (method == "get-extrinsic-params") {
|
||||||
|
auto response = client.get_extrinsic_params();
|
||||||
|
LOG(INFO) << vector_to_string(response);
|
||||||
|
}
|
||||||
|
if (method == "get-cloud-point") {
|
||||||
|
auto response = client.get_cloud_point();
|
||||||
|
LOG(INFO) << vector_to_string(response);
|
||||||
|
}
|
||||||
} catch (const std::exception &e) {
|
} catch (const std::exception &e) {
|
||||||
output << "\nRPC Error: " << e.what() << std::endl;
|
output << "\nRPC Error: " << e.what() << std::endl;
|
||||||
}
|
}
|
||||||
|
|||||||
@ -1,13 +1,13 @@
|
|||||||
#include <gtest/gtest.h>
|
|
||||||
#include <gmock/gmock.h>
|
|
||||||
#include <thread>
|
|
||||||
#include <chrono>
|
#include <chrono>
|
||||||
|
#include <gmock/gmock.h>
|
||||||
|
#include <gtest/gtest.h>
|
||||||
|
#include <thread>
|
||||||
|
|
||||||
#include "cloud_point_rpc/config.hpp"
|
#include "cloud_point_rpc/config.hpp"
|
||||||
|
#include "cloud_point_rpc/rpc_client.hpp"
|
||||||
#include "cloud_point_rpc/rpc_server.hpp"
|
#include "cloud_point_rpc/rpc_server.hpp"
|
||||||
#include "cloud_point_rpc/service.hpp"
|
#include "cloud_point_rpc/service.hpp"
|
||||||
#include "cloud_point_rpc/tcp_server.hpp"
|
#include "cloud_point_rpc/tcp_server.hpp"
|
||||||
#include "cloud_point_rpc/rpc_client.hpp"
|
|
||||||
|
|
||||||
#include <fstream>
|
#include <fstream>
|
||||||
|
|
||||||
@ -18,7 +18,8 @@ class IntegrationTest : public ::testing::Test {
|
|||||||
void SetUp() override {
|
void SetUp() override {
|
||||||
// Create a temporary config file for testing
|
// Create a temporary config file for testing
|
||||||
std::ofstream config_file("config.yaml");
|
std::ofstream config_file("config.yaml");
|
||||||
config_file << "server:\n"
|
config_file
|
||||||
|
<< "server:\n"
|
||||||
<< " ip: \"127.0.0.1\"\n"
|
<< " ip: \"127.0.0.1\"\n"
|
||||||
<< " port: 9095\n"
|
<< " port: 9095\n"
|
||||||
<< "test_data:\n"
|
<< "test_data:\n"
|
||||||
@ -32,27 +33,25 @@ class IntegrationTest : public ::testing::Test {
|
|||||||
try {
|
try {
|
||||||
config_ = ConfigLoader::load("config.yaml");
|
config_ = ConfigLoader::load("config.yaml");
|
||||||
} catch (...) {
|
} catch (...) {
|
||||||
// If config fails, we can't proceed, but we should avoid crashing in TearDown
|
// If config fails, we can't proceed, but we should avoid crashing in
|
||||||
|
// TearDown
|
||||||
throw;
|
throw;
|
||||||
}
|
}
|
||||||
|
|
||||||
service_ = std::make_unique<Service>(config_.test_data);
|
service_ = std::make_unique<Service>(config_.test_data);
|
||||||
rpc_server_ = std::make_unique<RpcServer>();
|
rpc_server_ = std::make_unique<RpcServer>();
|
||||||
|
|
||||||
rpc_server_->register_method("get-intrinsic-params", [&](const nlohmann::json&) {
|
rpc_server_->register_method("get-intrinsic-params",
|
||||||
|
[&](const nlohmann::json &) {
|
||||||
return service_->get_intrinsic_params();
|
return service_->get_intrinsic_params();
|
||||||
});
|
});
|
||||||
|
|
||||||
// Start Server Thread
|
// Start Server Thread
|
||||||
tcp_server_ = std::make_unique<TcpServer>(config_.server.ip, config_.server.port,
|
tcp_server_ = std::make_unique<TcpServer>(
|
||||||
[&](const std::string& req) {
|
config_.server.ip, config_.server.port,
|
||||||
return rpc_server_->process(req);
|
[&](const std::string &req) { return rpc_server_->process(req); });
|
||||||
}
|
|
||||||
);
|
|
||||||
|
|
||||||
server_thread_ = std::thread([&]() {
|
server_thread_ = std::thread([&]() { tcp_server_->start(); });
|
||||||
tcp_server_->start();
|
|
||||||
});
|
|
||||||
|
|
||||||
// Give server time to start
|
// Give server time to start
|
||||||
std::this_thread::sleep_for(std::chrono::milliseconds(200));
|
std::this_thread::sleep_for(std::chrono::milliseconds(200));
|
||||||
@ -77,13 +76,12 @@ class IntegrationTest : public ::testing::Test {
|
|||||||
};
|
};
|
||||||
|
|
||||||
TEST_F(IntegrationTest, ClientCanConnectAndRetrieveValues) {
|
TEST_F(IntegrationTest, ClientCanConnectAndRetrieveValues) {
|
||||||
RpcClient client;
|
TCPConnector connector(config_.server.ip, config_.server.port);
|
||||||
|
RpcClient client(connector);
|
||||||
// Act: Connect
|
|
||||||
ASSERT_NO_THROW(client.connect(config_.server.ip, config_.server.port));
|
|
||||||
|
|
||||||
// Act: Call Method
|
// Act: Call Method
|
||||||
auto params = client.get_intrinsic_params();
|
std::vector<double> params;
|
||||||
|
EXPECT_NO_THROW(params = client.get_intrinsic_params());
|
||||||
|
|
||||||
// Assert: Values match config
|
// Assert: Values match config
|
||||||
const auto &expected = config_.test_data.intrinsic_params;
|
const auto &expected = config_.test_data.intrinsic_params;
|
||||||
@ -94,7 +92,5 @@ TEST_F(IntegrationTest, ClientCanConnectAndRetrieveValues) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
TEST_F(IntegrationTest, ClientHandlesConnectionError) {
|
TEST_F(IntegrationTest, ClientHandlesConnectionError) {
|
||||||
RpcClient client;
|
EXPECT_THROW(TCPConnector connector("127.0.0.1", 9999), std::runtime_error);
|
||||||
// Try connecting to a closed port
|
|
||||||
EXPECT_THROW(client.connect("127.0.0.1", 9999), std::runtime_error);
|
|
||||||
}
|
}
|
||||||
|
|||||||
@ -1,10 +1,10 @@
|
|||||||
#include <gtest/gtest.h>
|
|
||||||
#include <gmock/gmock.h>
|
|
||||||
#include <string>
|
|
||||||
#include <vector>
|
|
||||||
#include "cloud_point_rpc/rpc_server.hpp"
|
#include "cloud_point_rpc/rpc_server.hpp"
|
||||||
#include "cloud_point_rpc/service.hpp"
|
#include "cloud_point_rpc/service.hpp"
|
||||||
|
#include <gmock/gmock.h>
|
||||||
|
#include <gtest/gtest.h>
|
||||||
#include <nlohmann/json.hpp>
|
#include <nlohmann/json.hpp>
|
||||||
|
#include <string>
|
||||||
|
#include <vector>
|
||||||
|
|
||||||
using json = nlohmann::json;
|
using json = nlohmann::json;
|
||||||
using namespace cloud_point_rpc;
|
using namespace cloud_point_rpc;
|
||||||
@ -22,7 +22,8 @@ class RpcServerTest : public ::testing::Test {
|
|||||||
};
|
};
|
||||||
|
|
||||||
TEST_F(RpcServerTest, GetIntrinsicParamsReturnsMatrix) {
|
TEST_F(RpcServerTest, GetIntrinsicParamsReturnsMatrix) {
|
||||||
std::string request = R"({"jsonrpc": "2.0", "method": "get-intrinsic-params", "id": 1})";
|
std::string request =
|
||||||
|
R"({"jsonrpc": "2.0", "method": "get-intrinsic-params", "id": 1})";
|
||||||
std::string response_str = server.process(request);
|
std::string response_str = server.process(request);
|
||||||
|
|
||||||
json response = json::parse(response_str);
|
json response = json::parse(response_str);
|
||||||
@ -40,7 +41,8 @@ TEST_F(RpcServerTest, GetIntrinsicParamsReturnsMatrix) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
TEST_F(RpcServerTest, MethodNotFoundReturnsError) {
|
TEST_F(RpcServerTest, MethodNotFoundReturnsError) {
|
||||||
std::string request = R"({"jsonrpc": "2.0", "method": "unknown-method", "id": 99})";
|
std::string request =
|
||||||
|
R"({"jsonrpc": "2.0", "method": "unknown-method", "id": 99})";
|
||||||
std::string response_str = server.process(request);
|
std::string response_str = server.process(request);
|
||||||
|
|
||||||
json response = json::parse(response_str);
|
json response = json::parse(response_str);
|
||||||
|
|||||||
Loading…
x
Reference in New Issue
Block a user