Compare commits
16 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
| 4a40c38686 | |||
| 9955c1986c | |||
| 15fb311c66 | |||
| 5c5b886360 | |||
| 1eea074051 | |||
| 626cfa64f2 | |||
| 00da1c9f32 | |||
| c5ede14eaf | |||
| 981568f104 | |||
| 638c565702 | |||
| 81f8f709a2 | |||
| 6fea0e2450 | |||
| e881b6b699 | |||
| 2157b25a95 | |||
| f2dfee7a38 | |||
| 5afbf771ca |
1
.gitignore
vendored
1
.gitignore
vendored
@ -6,5 +6,4 @@ subprojects/googletest-*
|
||||
subprojects/nlohmann_json/
|
||||
subprojects/packagecache/
|
||||
subprojects/yaml-cpp-0.8.0
|
||||
subprojects/base64-0.5.2/
|
||||
.venv/
|
||||
|
||||
@ -4,7 +4,7 @@ Communication JSON RPC protocol and implementation with Unity Scene.
|
||||
|
||||
## TODO
|
||||
|
||||
- [x] Server implementation with C-API for Unity
|
||||
- [ ] Server implementation with C-API for Unity
|
||||
- [ ] Client correct implementation with OpenCV
|
||||
|
||||
## API Documentation
|
||||
|
||||
@ -3,7 +3,7 @@
|
||||
#include <iostream>
|
||||
#include <string>
|
||||
#include "export.h"
|
||||
namespace score {
|
||||
namespace cloud_point_rpc {
|
||||
|
||||
/**
|
||||
* @brief Runs the CLI client.
|
||||
|
||||
@ -6,11 +6,11 @@
|
||||
#include <vector>
|
||||
#include <yaml-cpp/yaml.h>
|
||||
|
||||
namespace score {
|
||||
namespace cloud_point_rpc {
|
||||
|
||||
struct ServerConfig {
|
||||
std::string ip;
|
||||
int port{0};
|
||||
int port;
|
||||
};
|
||||
|
||||
struct TestData {
|
||||
|
||||
@ -6,7 +6,7 @@
|
||||
#include <jsonrpccxx/client.hpp>
|
||||
#include <nlohmann/json.hpp>
|
||||
#include <vector>
|
||||
namespace score {
|
||||
namespace cloud_point_rpc {
|
||||
|
||||
class RpcClient : public jsonrpccxx::JsonRpcClient {
|
||||
public:
|
||||
|
||||
@ -1,27 +0,0 @@
|
||||
//
|
||||
// Created by vptyp on 11.03.2026.
|
||||
//
|
||||
|
||||
#pragma once
|
||||
|
||||
#include <string>
|
||||
#include <vector>
|
||||
namespace score {
|
||||
|
||||
class IRPCCoder {
|
||||
public:
|
||||
virtual ~IRPCCoder() = default;
|
||||
virtual std::vector<char> decode(const std::string& encoded) = 0;
|
||||
virtual std::string encode(const std::vector<char>& data) = 0;
|
||||
};
|
||||
|
||||
class Base64RPCCoder final : public IRPCCoder {
|
||||
public:
|
||||
Base64RPCCoder();
|
||||
~Base64RPCCoder() override;
|
||||
|
||||
std::vector<char> decode(const std::string& encoded) override;
|
||||
std::string encode(const std::vector<char>& data) override;
|
||||
};
|
||||
|
||||
}
|
||||
@ -16,7 +16,7 @@ struct rpc_string {
|
||||
};
|
||||
}
|
||||
|
||||
namespace score {
|
||||
namespace cloud_point_rpc {
|
||||
|
||||
class CRPC_EXPORT RpcServer {
|
||||
public:
|
||||
|
||||
@ -5,7 +5,7 @@
|
||||
#include <type_traits>
|
||||
#include <vector>
|
||||
|
||||
namespace score {
|
||||
namespace cloud_point_rpc {
|
||||
|
||||
template <typename T>
|
||||
concept NumericType = requires(T param) {
|
||||
|
||||
@ -3,7 +3,7 @@
|
||||
#include "cloud_point_rpc/config.hpp"
|
||||
#include <vector>
|
||||
#include "export.h"
|
||||
namespace score {
|
||||
namespace cloud_point_rpc {
|
||||
|
||||
class CRPC_EXPORT Service {
|
||||
public:
|
||||
|
||||
@ -6,7 +6,7 @@
|
||||
#include <glog/logging.h>
|
||||
#include <string>
|
||||
#include "export.h"
|
||||
namespace score {
|
||||
namespace cloud_point_rpc {
|
||||
/**
|
||||
* TCPConnector main purpose is to implement jsonrpccxx::IClientConnector Send
|
||||
* method As an internal implementation, TCPConnector adds to the beginning of
|
||||
|
||||
@ -3,7 +3,7 @@
|
||||
#include <asio.hpp>
|
||||
#include <cloud_point_rpc/serialize.hpp>
|
||||
#include <glog/logging.h>
|
||||
namespace score {
|
||||
namespace cloud_point_rpc {
|
||||
|
||||
static inline std::string tcp_read(asio::ip::tcp::socket &socket,
|
||||
std::string_view prefix) {
|
||||
|
||||
@ -10,7 +10,7 @@
|
||||
#include "export.h"
|
||||
#include <list>
|
||||
#include <ranges>
|
||||
namespace score {
|
||||
namespace cloud_point_rpc {
|
||||
|
||||
class CRPC_EXPORT TcpServer {
|
||||
public:
|
||||
|
||||
@ -6,7 +6,7 @@ project('cloud_point_rpc', 'cpp',
|
||||
json_dep = dependency('nlohmann_json', fallback : ['nlohmann_json', 'nlohmann_json_dep'])
|
||||
thread_dep = dependency('threads')
|
||||
asio_dep = dependency('asio', fallback : ['asio', 'asio_dep'])
|
||||
base64_dep = dependency('base64', fallback: ['aklomp-base64', 'base64'])
|
||||
|
||||
# GLog via CMake fallback
|
||||
cmake = import('cmake')
|
||||
glog_opt = cmake.subproject_options()
|
||||
|
||||
@ -3,7 +3,7 @@
|
||||
#include <glog/logging.h>
|
||||
#include <string>
|
||||
|
||||
namespace score {
|
||||
namespace cloud_point_rpc {
|
||||
|
||||
void print_menu(std::ostream &output) {
|
||||
output << "\n=== Cloud Point RPC CLI ===" << std::endl;
|
||||
|
||||
@ -24,8 +24,8 @@ int main(int argc, char *argv[]) {
|
||||
f.close();
|
||||
|
||||
try {
|
||||
auto config = score::ConfigLoader::load(config_path);
|
||||
return score::run_cli(std::cin, std::cout, config.server.ip,
|
||||
auto config = cloud_point_rpc::ConfigLoader::load(config_path);
|
||||
return cloud_point_rpc::run_cli(std::cin, std::cout, config.server.ip,
|
||||
config.server.port);
|
||||
} catch (const std::exception &e) {
|
||||
std::cerr << "Failed to start CLI: " << e.what() << std::endl;
|
||||
|
||||
@ -3,20 +3,19 @@ add_project_arguments('-DCRPC_SERVER_API_EXPORT -pthread', language: 'cpp')
|
||||
cloud_point_rpc_sources = files(
|
||||
'rpc_server.cpp',
|
||||
'service.cpp',
|
||||
'server_api.cpp',
|
||||
'rpc_coder.cpp'
|
||||
'server_api.cpp'
|
||||
)
|
||||
|
||||
libcloud_point_rpc = shared_library('cloud_point_rpc',
|
||||
cloud_point_rpc_sources,
|
||||
include_directories : inc,
|
||||
dependencies : [json_dep, thread_dep, glog_dep, yaml_dep, asio_dep, base64_dep],
|
||||
dependencies : [json_dep, thread_dep, glog_dep, yaml_dep, asio_dep],
|
||||
install : true)
|
||||
|
||||
cloud_point_rpc_dep = declare_dependency(
|
||||
include_directories : inc,
|
||||
link_with : libcloud_point_rpc,
|
||||
dependencies : [json_dep, glog_dep, yaml_dep, asio_dep, base64_dep])
|
||||
dependencies : [json_dep, glog_dep, yaml_dep, asio_dep])
|
||||
|
||||
# Test lib
|
||||
libcloud_point_rpc_test = shared_library('test_cloud_point',
|
||||
@ -33,7 +32,7 @@ cloud_point_rpc_test_dep = declare_dependency(
|
||||
libcloud_point_rpc_cli = shared_library('libcloud_point_rpc_cli',
|
||||
'cli.cpp',
|
||||
include_directories : inc,
|
||||
dependencies : [cloud_point_rpc_dep],
|
||||
dependencies : [json_dep, thread_dep, glog_dep, yaml_dep, asio_dep, cloud_point_rpc_dep],
|
||||
install : true)
|
||||
|
||||
cloud_point_rpc_cli_dep = declare_dependency(
|
||||
|
||||
@ -1,42 +0,0 @@
|
||||
//
|
||||
// Created by vptyp on 11.03.2026.
|
||||
//
|
||||
#include "cloud_point_rpc/rpc_coder.h"
|
||||
|
||||
#include "libbase64.h"
|
||||
#include <glog/logging.h>
|
||||
namespace score {
|
||||
|
||||
Base64RPCCoder::Base64RPCCoder() = default;
|
||||
Base64RPCCoder::~Base64RPCCoder() = default;
|
||||
|
||||
/**
|
||||
* Tries to decode ASCII complained string to the
|
||||
* @param encoded ASCII complained base64 encoded string
|
||||
* @return vector of raw bytes << allocated on encoded.size() / 4 * 3 + 1 size
|
||||
*/
|
||||
std::vector<char> Base64RPCCoder::decode(const std::string& encoded) {
|
||||
DLOG(INFO) << "Base64RPCCoder::decode";
|
||||
std::vector<char> result((encoded.length() >> 2) * 3 + 1);
|
||||
size_t result_len = 0;
|
||||
base64_decode(encoded.data(), encoded.size(),
|
||||
result.data(), &result_len, 0);
|
||||
DLOG(INFO) << "result_len: " << result_len;
|
||||
return result;
|
||||
}
|
||||
/**
|
||||
*
|
||||
* @param data raw byte stream
|
||||
* @return encoded base64 string
|
||||
*/
|
||||
std::string Base64RPCCoder::encode(const std::vector<char>& data) {
|
||||
DLOG(INFO) << "Base64RPCCoder::encode";
|
||||
size_t result_len = 0;
|
||||
std::string result(data.size() / 3 * 4 + 1, 0);
|
||||
base64_encode(data.data(), data.size(),
|
||||
result.data(), &result_len, 0
|
||||
);
|
||||
DLOG(INFO) << "result_len: " << result_len;
|
||||
return result;
|
||||
}
|
||||
}
|
||||
@ -2,7 +2,7 @@
|
||||
#include <glog/logging.h>
|
||||
using json = nlohmann::json;
|
||||
|
||||
namespace score {
|
||||
namespace cloud_point_rpc {
|
||||
|
||||
namespace {
|
||||
json create_error(int code, const std::string &message,
|
||||
|
||||
@ -9,8 +9,8 @@
|
||||
#include <list>
|
||||
|
||||
static std::list<std::unique_ptr<rpc_string>> gc;
|
||||
score::RpcServer rpc_server;
|
||||
std::unique_ptr<score::TcpServer> server = nullptr;
|
||||
cloud_point_rpc::RpcServer rpc_server;
|
||||
std::unique_ptr<cloud_point_rpc::TcpServer> server = nullptr;
|
||||
|
||||
extern "C" {
|
||||
|
||||
@ -40,10 +40,10 @@ void crpc_init(const char* config_path) {
|
||||
LOG(INFO) << "config_path was not provided";
|
||||
}
|
||||
try {
|
||||
auto config = score::ConfigLoader::load(config_path);
|
||||
auto config = cloud_point_rpc::ConfigLoader::load(config_path);
|
||||
LOG(INFO) << "Loaded config from " << config_path;
|
||||
|
||||
server = std::make_unique<score::TcpServer>(config.server.ip, config.server.port,
|
||||
server = std::make_unique<cloud_point_rpc::TcpServer>(config.server.ip, config.server.port,
|
||||
[&](const std::string &request) {
|
||||
return rpc_server.process(
|
||||
request);
|
||||
|
||||
@ -20,12 +20,12 @@ int main(int argc, char *argv[]) {
|
||||
LOG(INFO) << "Starting Cloud Point RPC Server (Test Mock)...";
|
||||
|
||||
try {
|
||||
auto config = score::ConfigLoader::load(config_path);
|
||||
auto config = cloud_point_rpc::ConfigLoader::load(config_path);
|
||||
LOG(INFO) << "Loaded config from " << config_path;
|
||||
|
||||
// Inject test data into service
|
||||
score::Service service(config.test_data);
|
||||
score::RpcServer rpc_server;
|
||||
cloud_point_rpc::Service service(config.test_data);
|
||||
cloud_point_rpc::RpcServer rpc_server;
|
||||
|
||||
rpc_server.register_method("get-intrinsic-params", [&](const json &) {
|
||||
return service.get_intrinsic_params();
|
||||
@ -39,7 +39,7 @@ int main(int argc, char *argv[]) {
|
||||
return service.get_cloud_point();
|
||||
});
|
||||
|
||||
score::TcpServer server(config.server.ip, config.server.port,
|
||||
cloud_point_rpc::TcpServer server(config.server.ip, config.server.port,
|
||||
[&](const std::string &request) {
|
||||
return rpc_server.process(
|
||||
request);
|
||||
|
||||
@ -1,6 +1,6 @@
|
||||
#include "cloud_point_rpc/service.hpp"
|
||||
|
||||
namespace score {
|
||||
namespace cloud_point_rpc {
|
||||
|
||||
Service::Service(const TestData &data) : data_(data) {}
|
||||
|
||||
|
||||
@ -121,7 +121,7 @@ class TestThread {
|
||||
calls_queue = std::queue<std::string>();
|
||||
methods.clear();
|
||||
state.store(true, std::memory_order_relaxed);
|
||||
server = score::RpcServer();
|
||||
server = cloud_point_rpc::RpcServer();
|
||||
}
|
||||
|
||||
private:
|
||||
@ -131,7 +131,7 @@ class TestThread {
|
||||
std::set<std::string> methods{};
|
||||
std::jthread thr;
|
||||
std::mutex mtx;
|
||||
score::RpcServer server;
|
||||
cloud_point_rpc::RpcServer server;
|
||||
std::chrono::duration<int64_t, std::milli> thr_sleep{50};
|
||||
} test;
|
||||
|
||||
|
||||
@ -1,14 +0,0 @@
|
||||
[wrap-file]
|
||||
directory = base64-0.5.2
|
||||
source_url = https://github.com/aklomp/base64/archive/refs/tags/v0.5.2.tar.gz
|
||||
source_filename = base64-0.5.2.tar.gz
|
||||
source_hash = 723a0f9f4cf44cf79e97bcc315ec8f85e52eb104c8882942c3f2fba95acc080d
|
||||
source_fallback_url = https://wrapdb.mesonbuild.com/v2/aklomp-base64_0.5.2-1/get_source/base64-0.5.2.tar.gz
|
||||
patch_filename = aklomp-base64_0.5.2-1_patch.zip
|
||||
patch_url = https://wrapdb.mesonbuild.com/v2/aklomp-base64_0.5.2-1/get_patch
|
||||
patch_fallback_url = https://github.com/mesonbuild/wrapdb/releases/download/aklomp-base64_0.5.2-1/aklomp-base64_0.5.2-1_patch.zip
|
||||
patch_hash = 9805354b8c0333fe0123c10d8c62356ef1d0d67a2689a348d18f73bddc1e2b10
|
||||
wrapdb_version = 0.5.2-1
|
||||
|
||||
[provide]
|
||||
dependency_names = base64
|
||||
@ -3,8 +3,7 @@ test_sources = files(
|
||||
'test_integration.cpp',
|
||||
'test_tcp.cpp',
|
||||
'test_cli.cpp',
|
||||
'test_c_api.cpp',
|
||||
'test_base64.cpp'
|
||||
'test_c_api.cpp'
|
||||
)
|
||||
|
||||
test_exe = executable('unit_tests',
|
||||
|
||||
@ -1,31 +0,0 @@
|
||||
//
|
||||
// Created by vptyp on 11.03.2026.
|
||||
//
|
||||
#include <chrono>
|
||||
#include <gmock/gmock.h>
|
||||
#include <gtest/gtest.h>
|
||||
#include <thread>
|
||||
|
||||
#include "cloud_point_rpc/config.hpp"
|
||||
#include "cloud_point_rpc/rpc_coder.h"
|
||||
|
||||
|
||||
class Base64Test : public ::testing::Test {
|
||||
protected:
|
||||
void SetUp() override {
|
||||
|
||||
}
|
||||
void TearDown() override {
|
||||
|
||||
}
|
||||
};
|
||||
|
||||
TEST_F(Base64Test, EncodeDecode) {
|
||||
std::vector raw{'H', 'e', 'l', 'l', 'o', 'w', '\0'};
|
||||
score::Base64RPCCoder coder;
|
||||
auto encoded = coder.encode(raw);
|
||||
LOG(INFO) << "encoded: " << encoded;
|
||||
auto decoded = coder.decode(encoded);
|
||||
EXPECT_EQ(std::ranges::equal(decoded, raw), true);
|
||||
LOG(INFO) << "done";
|
||||
}
|
||||
@ -9,7 +9,7 @@
|
||||
#include "cloud_point_rpc/rpc_server.hpp"
|
||||
#include "cloud_point_rpc/tcp_server.hpp"
|
||||
|
||||
using namespace score;
|
||||
using namespace cloud_point_rpc;
|
||||
|
||||
class CliTest : public ::testing::Test {
|
||||
public:
|
||||
|
||||
@ -11,7 +11,7 @@
|
||||
|
||||
#include <fstream>
|
||||
|
||||
using namespace score;
|
||||
using namespace cloud_point_rpc;
|
||||
|
||||
class IntegrationTest : public ::testing::Test {
|
||||
protected:
|
||||
@ -69,7 +69,7 @@ class IntegrationTest : public ::testing::Test {
|
||||
std::remove("config.yaml");
|
||||
}
|
||||
|
||||
Config config_{};
|
||||
Config config_;
|
||||
std::unique_ptr<Service> service_;
|
||||
std::unique_ptr<RpcServer> rpc_server_;
|
||||
std::unique_ptr<TcpServer> tcp_server_;
|
||||
|
||||
@ -7,7 +7,7 @@
|
||||
#include <vector>
|
||||
|
||||
using json = nlohmann::json;
|
||||
using namespace score;
|
||||
using namespace cloud_point_rpc;
|
||||
|
||||
class RpcServerTest : public ::testing::Test {
|
||||
protected:
|
||||
|
||||
@ -15,11 +15,11 @@ class TcpTest : public ::testing::Test {
|
||||
|
||||
protected:
|
||||
void SetUp() override {
|
||||
server_ = std::make_unique<score::TcpServer>(
|
||||
server_ = std::make_unique<cloud_point_rpc::TcpServer>(
|
||||
"127.0.0.1", 12345, [this](const std::string &request) {
|
||||
EXPECT_EQ(request, expected_);
|
||||
std::string msg = "Echo: " + request;
|
||||
auto v = score::serialize(msg.length());
|
||||
auto v = cloud_point_rpc::serialize(msg.length());
|
||||
std::string res(v.begin(), v.end());
|
||||
res += msg;
|
||||
return res;
|
||||
@ -33,19 +33,19 @@ class TcpTest : public ::testing::Test {
|
||||
}
|
||||
|
||||
std::string expected_;
|
||||
std::unique_ptr<score::TcpServer> server_;
|
||||
std::unique_ptr<cloud_point_rpc::TcpServer> server_;
|
||||
};
|
||||
|
||||
TEST(SerializeTest, Base) {
|
||||
uint64_t value{123};
|
||||
auto res = score::serialize(value);
|
||||
EXPECT_EQ(value, score::deserialize<uint64_t>(res));
|
||||
auto res = cloud_point_rpc::serialize(value);
|
||||
EXPECT_EQ(value, cloud_point_rpc::deserialize<uint64_t>(res));
|
||||
}
|
||||
|
||||
TEST_F(TcpTest, EchoTest) {
|
||||
constexpr std::string_view msg = "Hello, TCP Server!";
|
||||
ExpectedResponse(msg.data());
|
||||
score::TCPConnector connector("127.0.0.1", 12345);
|
||||
cloud_point_rpc::TCPConnector connector("127.0.0.1", 12345);
|
||||
auto res = connector.Send(msg.data());
|
||||
}
|
||||
|
||||
@ -53,6 +53,6 @@ TEST_F(TcpTest, HugeBuffer) {
|
||||
static constexpr uint64_t w = 1280, h = 720, c = 3;
|
||||
std::string data(w * h * c, 77);
|
||||
ExpectedResponse(data);
|
||||
score::TCPConnector connector("127.0.0.1", 12345);
|
||||
cloud_point_rpc::TCPConnector connector("127.0.0.1", 12345);
|
||||
auto res = connector.Send(data);
|
||||
}
|
||||
Loading…
x
Reference in New Issue
Block a user