This library requires C++17 and is designed as an extension to boost.asio
. It will let you build asynchronous servers or client for JSON-RPC or msgpack-RPC.
The project is hosted on GitHub and available on Conan Center. Documentation is available on GitHub Pages.
Overview
#include <iostream>
using namespace packio::arg_literals;
int main(int, char**)
{
using namespace packio::arg_literals;
packio::net::io_context io;
packio::net::ip::tcp::endpoint bind_ep{
packio::net::ip::make_address("127.0.0.1"), 0};
"add", {"a", "b"}, [](int a, int b) { return a + b; });
server->dispatcher()->add_async(
"multiply",
packio::net::post(
io, [a, b, complete = std::move(complete)]() mutable {
complete(a * b);
});
});
server->dispatcher()->add_coro(
"pow", io, [](int a, int b) -> packio::net::awaitable<int> {
co_return std::pow(a, b);
});
client->socket().connect(
server->acceptor().local_endpoint());
server->async_serve_forever();
std::thread thread{[&] { io.run(); }};
std::promise<int> add1_result, multiply_result;
"add",
std::tuple{arg("a") = 42, "b"_arg = 24},
[&](packio::error_code, const rpc::response_type& r) {
add1_result.set_value(r.result.get<int>());
});
std::cout << "42 + 24 = " << add1_result.get_future().get() << std::endl;
auto add_future =
client->async_call(
"multiply",
std::tuple{"a"_arg = 12, "b"_arg = 23},
packio::net::use_future);
std::cout << "12 * 23 = " << add_future.get().result.get<int>() << std::endl;
std::promise<int> pow_result;
packio::net::co_spawn(
io,
[&]() -> packio::net::awaitable<void> {
auto res = co_await
client->async_call(
"pow", std::tuple{2, 8}, packio::net::use_awaitable);
pow_result.set_value(res.result.get<int>());
},
packio::net::detached);
std::cout << "2 ** 8 = " << pow_result.get_future().get() << std::endl;
io.stop();
thread.join();
return 0;
}
A named argument.
Definition: arg.h:17
The JSON-RPC protocol implementation.
Definition: rpc.h:174
::packio::client< rpc, Socket, Map > client
The client for JSON-RPC.
Definition: json_rpc.h:31
::packio::server< rpc, Acceptor, Dispatcher > server
The server for JSON-RPC.
Definition: json_rpc.h:42
completion_handler< rpc > completion_handler
The completion_handler for JSON-RPC.
Definition: json_rpc.h:23
completion_handler< rpc > completion_handler
The completion_handler for JSON-RPC.
Definition: nl_json_rpc.h:23
auto make_server(Acceptor &&acceptor)
The make_server function for JSON-RPC.
Definition: nl_json_rpc.h:46
auto make_client(Socket &&socket)
The make_client function for JSON-RPC.
Definition: nl_json_rpc.h:35
auto make_server(Acceptor &&acceptor)
Create a server from an acceptor.
Definition: server.h:150
auto make_client(Socket &&socket)
Create a client from a socket.
Definition: client.h:474
constexpr auto allow_extra_arguments
Option to allo extra arguments, ignoring them.
Definition: args_specs.h:181
Requirements
- C++17 or C++20
- msgpack >= 3.2.1
- nlohmann_json >= 3.9.1
- boost.asio >= 1.70.0 or asio >= 1.13.0
Older versions of msgpack
and nlohmann_json
are probably compatible but they are not tested on the CI.
Configurations
Standalone or Boost.Asio
By default, packio
uses boost::asio
. It is also compatible with standalone asio
. To use the standalone version, the preprocessor macro PACKIO_STANDALONE_ASIO=1
must be defined.
If you are using the conan package, you can use the option standalone_asio=True
.
Depending on your choice, the namespace packio::net
will be an alias for either boost::asio
or asio
.
RPC components
You can define the following preprocessor macros to either 0 or 1 to force-disable or force-enable components of packio
:
PACKIO_HAS_MSGPACK
PACKIO_HAS_NLOHMANN_JSON
PACKIO_HAS_BOOST_JSON
If you're using the conan package, use the associated options instead, conan will define these macros accordingly.
If you're not using the conan package, packio
will try to auto-detect whether these components are available on your system. Define the macros to the appropriate value if you encounter any issue.
Boost before 1.75
If you're using the conan package with a boost version older than 1.75, you need to manually disable Boost.Json
with the options boost_json=False
. Boost.Json
version 1.75 contains some bugs when using C-strings as arguments so I'd recommend at using at least version 1.76.
Tested compilers
- gcc-9
- gcc-10
- gcc-11
- gcc-12
- clang-11
- clang-12
- clang-13
- clang-14
- Apple clang-13
- Visual Studio 2019 Version 16
- Visual Studio 2022 Version 17
Older compilers may be compatible but are not tested.
Install with conan
conan install packio/x.x.x
Coroutines
packio
is compatible with C++20 coroutines:
- calls can use the
packio::asio::use_awaitable
completion token
- coroutines can be registered in the server
Coroutines are tested for the following compilers:
- gcc-11
- gcc-12
- clang-14
- Apple clang-12
Samples
You will find some samples in test_package/samples/
to help you get a hand on packio
.
Bonus
Let's compute fibonacci's numbers recursively over websockets with coroutines on a single thread ... in 65 lines of code.
#include <iostream>
using packio::net::ip::make_address;
using awaitable_tcp_stream = decltype(packio::net::use_awaitable_t<>::as_default_on(
std::declval<boost::beast::tcp_stream>()));
using websocket = packio::extra::
websocket_adapter<boost::beast::websocket::stream<awaitable_tcp_stream>, true>;
using ws_acceptor =
int main(int argc, char** argv)
{
if (argc < 2) {
std::cerr << "I require one argument" << std::endl;
return 1;
}
const int n = std::atoi(argv[1]);
packio::net::io_context io;
packio::net::ip::tcp::endpoint bind_ep{make_address("127.0.0.1"), 0};
server->dispatcher()->add_coro(
"fibonacci", io, [&](int n) -> packio::net::awaitable<int> {
if (n <= 1) {
co_return n;
}
auto r1 = co_await
client->async_call(
"fibonacci", std::tuple{n - 1});
auto r2 = co_await
client->async_call(
"fibonacci", std::tuple{n - 2});
co_return r1.result.as<int>() + r2.result.as<int>();
});
int result = 0;
packio::net::co_spawn(
io,
[&]() -> packio::net::awaitable<void> {
auto ep =
server->acceptor().local_endpoint();
co_await
client->socket().next_layer().async_connect(ep);
co_await
client->socket().async_handshake(
"127.0.0.1:" + std::to_string(ep.port()), "/");
auto ret = co_await
client->async_call(
"fibonacci", std::tuple{n});
result = ret.result.template as<int>();
io.stop();
},
packio::net::detached);
server->async_serve_forever();
io.run();
std::cout << "F{" << n << "} = " << result << std::endl;
return 0;
}
auto make_server(Acceptor &&acceptor)
The make_server function for JSON-RPC.
Definition: json_rpc.h:46
auto make_client(Socket &&socket)
The make_client function for msgpack-RPC.
Definition: msgpack_rpc.h:33
auto make_server(Acceptor &&acceptor)
The make_server function for msgpack-RPC.
Definition: msgpack_rpc.h:44