qchateau / packio Goto Github PK
View Code? Open in Web Editor NEWAn asynchronous msgpack-RPC and JSON-RPC library built on top of Boost.Asio.
Home Page: https://qchateau.github.io/packio/
License: Mozilla Public License 2.0
An asynchronous msgpack-RPC and JSON-RPC library built on top of Boost.Asio.
Home Page: https://qchateau.github.io/packio/
License: Mozilla Public License 2.0
Support completion tokens to prepare for coroutines support
Hi!
I'm working with your library, and I'm trying to figure out how to get the session (or socket) from within a handler.
We'd like to send back notifications on the same websocket; the server may have several users connected.
The only example code I saw related to this, was capturing a session_ptr when adding the handler (from basic_test_server_crash.cpp)
std::shared_ptr<session_type> session_ptr;
this->server_->async_serve([&](auto ec, auto session) {
ASSERT_FALSE(ec);
session->start();
session_ptr = session;
});
this->server_->dispatcher()->add(
"close", [&]() { session_ptr->socket().close(); });
But, I'm not sure something like that would work with more than one connection.
I could capture the server itself, but I don't know how to go about finding the socket in the handler.
Thank you for any hints here!
Kyle
I am trying to use packio in my cmake project but I get a few compiler errors:
error 1
.conan/data/packio/2.2.0/_/_/package/0c0791061c9ce0b41dcaec85e4a8aeeb1bfa1a31/include/packio/json_rpc/hash.h:66:8: error: redefinition of ‘struct std::hash<boost::json::value>’
66 | struct hash<boost::json::value> {
...
.conan/data/boost/1.80.0/_/_/package/cb420f7a9d4f5344407adad933bfd4a05ab58ddd/include/boost/json/value.hpp:4030:8: note: previous definition of ‘struct std::hash<boost::json::value>’
4030 | struct hash< ::boost::json::value > {
error 2
error: ‘using element_type = class packio::dispatcher<packio::nl_json_rpc::rpc, packio::default_map, std::mutex>’ {aka ‘class packio::dispatcher<packio::nl_json_rpc::rpc, packio::default_map, std::mutex>’} has no member named ‘add_coro’
108 | server->dispatcher()->add_coro(
error 3
error: ‘awaitable’ in namespace ‘packio::net’ does not name a template type
109 | "pow", io, [](int a, int b) -> packio::net::awaitable<int> {
It seems that boost asio is not correctly linked somehow?
My cmake code for including packio:
include("${CMAKE_MODULE_PATH}/conan.cmake")
conan_cmake_configure(REQUIRES packio/2.2.0
GENERATORS cmake_find_package)
conan_cmake_autodetect(settings)
message("external: settings = ${settings}")
conan_cmake_install(PATH_OR_REFERENCE .
BUILD missing
REMOTE conancenter
SETTINGS ${settings})
Any help would be very much appreciated.
UPDATE:
I am getting this error even when running test_package:
packio$ conan test test_package/ packio/2.2.0
.conan/data/packio/2.2.0/_/_/package/0c0791061c9ce0b41dcaec85e4a8aeeb1bfa1a31/include/packio/json_rpc/hash.h:66:8: error: redefinition of ‘struct std::hash<boost::json::value>’
66 | struct hash<boost::json::value> {
...
.conan/data/boost/1.80.0/_/_/package/cb420f7a9d4f5344407adad933bfd4a05ab58ddd/include/boost/json/value.hpp:4030:8: note: previous definition of ‘struct std::hash<boost::json::value>’
4030 | struct hash< ::boost::json::value > {
I have no experience with conan so please forgive me if I am missing something obvious.
The optional
header isn't included in traits.h
. It causes some errors with MSVC:
E:\Users\Yoann\.conan\data\packio\1.3.0\_\_\package\5ab84d6acfe1f23c4fae0ab88f26e3a396351ac9\include\packio\traits.h(88): error C2065: 'optional': undeclared identifier
E:\Users\Yoann\.conan\data\packio\1.3.0\_\_\package\5ab84d6acfe1f23c4fae0ab88f26e3a396351ac9\include\packio\traits.h(89): note: see reference to class template instantiation 'packio::traits::AsCallHandler<T,Result>' being compiled
E:\Users\Yoann\.conan\data\packio\1.3.0\_\_\package\5ab84d6acfe1f23c4fae0ab88f26e3a396351ac9\include\packio\traits.h(88): error C3544: '_Args': parameter pack expects a type template argument
E:\Users\Yoann\.conan\data\packio\1.3.0\_\_\package\5ab84d6acfe1f23c4fae0ab88f26e3a396351ac9\include\packio\traits.h(88): error C2993: 'unknown-type': is not a valid type for non-type template parameter 'condition'
E:\Users\Yoann\.conan\data\packio\1.3.0\_\_\package\5ab84d6acfe1f23c4fae0ab88f26e3a396351ac9\include\packio\traits.h(88): error C2955: 'packio::traits::Trait': use of class template requires template argument list
E:\Users\Yoann\.conan\data\packio\1.3.0\_\_\package\5ab84d6acfe1f23c4fae0ab88f26e3a396351ac9\include\packio\traits.h(62): note: see declaration of 'packio::traits::Trait'
E:\Users\Yoann\.conan\data\packio\1.3.0\_\_\package\5ab84d6acfe1f23c4fae0ab88f26e3a396351ac9\include\packio\traits.h(88): error C2143: syntax error: missing ',' before '>'
E:\Users\Yoann\.conan\data\packio\1.3.0\_\_\package\5ab84d6acfe1f23c4fae0ab88f26e3a396351ac9\include\packio\client.h(166): error C2061: syntax error: identifier 'optional'
E:\Users\Yoann\.conan\data\packio\1.3.0\_\_\package\5ab84d6acfe1f23c4fae0ab88f26e3a396351ac9\include\packio\client.h(483): note: see reference to class template instantiation 'packio::client<Socket,Map>' being compiled
E:\Users\Yoann\.conan\data\packio\1.3.0\_\_\package\5ab84d6acfe1f23c4fae0ab88f26e3a396351ac9\include\packio\client.h(182): error C2061: syntax error: identifier 'optional'
E:\Users\Yoann\.conan\data\packio\1.3.0\_\_\package\5ab84d6acfe1f23c4fae0ab88f26e3a396351ac9\include\packio\client.h(414): error C2061: syntax error: identifier 'optional'
E:\Users\Yoann\.conan\data\packio\1.3.0\_\_\package\5ab84d6acfe1f23c4fae0ab88f26e3a396351ac9\include\packio\client.h(472): note: see reference to class template instantiation 'packio::client<Socket,Map>::initiate_async_call<Buffer>' being compiled
Hi,
I would like to use the library with Boost::Beast websockets. How can I do that?
Here, if handler invocation throws, you'll leave the handler in the queue. If a higher layer (in user code) attempts to recover from the exception, you may end up calling the same handler again (possibly in a different async operation on the same I/O object).
Hello library developer! I ask you to please add a synchronous call for the client. Asynchrony is not possible in all environments, so this will be very useful and I think not only for me.
When the dispatcher encounters a missing parameter (using the nlohmann::json
implementation), it throws the request away as the request fails to parse in rpc::convert_named_args
, due to the use of the json::at
method which throws due to the parameter key not being present.
We have a use-case where the other end omits optional parameters (instead of setting them to null
), which we cannot change. Currently, I have hacked a workaround in, which is to attempt to return a default constructed object if the parameter is not found:
template <typename T, typename NamesContainer, std::size_t... Idxs>
static T convert_named_args(
const nlohmann::json& args,
const NamesContainer& names,
std::index_sequence<Idxs...>)
{
return T{(args.template value<std::tuple_element_t<Idxs, T>>(names.at(Idxs), {}))...};
}
It's not particularly elegant, and requires a suitably friendly type with a sensible default constructor to be passed into dispatcher::add
(e.g. nlohmann::json
, which can be explicitly tested for is_null()
in the dispatcher callback).
Do you think this change is appropriate for general inclusion in a PR? I'm not sure how well it would work for the Boost JSON or MessagePack variants. Alternatively, do you have a better solution?
C4702 is disabled in Debug because MSVC detects unreachable code in nl_json_rpc/rpc.h
for an unknown reason...
Is there any way to get the response to omit the data field? For the most part, it's sort of redundant information for me. If I use set_error()
with no arguments, it gets set to unknown error
which is extra redundant since that's already what's in the message
field of the response.
Based on my previous request Closed Issue #65 i have a further question. I'm using the nl_json_rpc client
and I tried to separate the client and server in two different programs (executable). From the client i can connect to the server socket (in the code below i get "The connection has been established!")
packio::net::io_context io_context;
packio::net::ip::tcp::socket socket{io_context};
packio::net::ip::tcp::resolver resolver{io_context};
auto endpoints = resolver.resolve("localhost", std::to_string(6543));
packio::error_code error;
auto client = make_client(std::move(socket));
client->socket().connect(endpoints->endpoint(), error);
if(not error)
{
std::cout << "The connection has been established!";
}
else
{
std::cerr << "Something went wrong :(";
}
But for some reason the following RPC async_call does not work anymore, e.g. it seems it waits forever for the add_result.get_future().get()
std::promise<int> add_result, multiply_result;
client->async_call(
"add",
std::tuple{arg("a") = 42, arg("b") = 24},
[&](packio::error_code, const rpc::response_type& r) {
add_result.set_value(r.result.get<int>());
});
std::cout << "42 + 24 = " << add_result.get_future().get() << std::endl;
May i ask you if you know what the problem is or you can add an example with separated client & server?
Should work from asio 1.25
Depending on the type of the argument of the handler
Is there a way to handle each connection by a separate thread?
Background: clients keep the connections alive (connection pool) for long period of the time to send many requests to one connection (one after another). Processing of a request, including reading it and writing it to the socket, is quite heavy (consumes a lot of CPU).
How can I start a new thread for each connection, right after accept()
? The new thread suppose to be created once for entire connection, not for each request.
Thank you in advance.
Client calls should be compatible, verify that
See how we can use coroutines as server procedures
ATM, C++20 and coroutines usage is differenciated in tests because compilers do not properly support coroutines. In a (close?) future, C++20 and coroutines usage should go hand in hand.
Compiler status:
We should wrap the result in a move-only version of std::function
to avoid copies ... as weird as it sounds
Boost 1.75 has support for it but the tests do not pass
And remove -fcoroutines
How do i define the rpc client as a class member variable? I cannot use auto. I have to setup a rpc connection to serveral devices and i thought the best to do this is to instantiate a device object from a device class, each holding the rpc client as a member variable.
I am able to connect and call_async works until I make a call that passes arguments. It completes on the servers side but then I get this crash on my client:
Exception thrown at 0x00007FFDA474543C in SiameseKat.exe: Microsoft C++ exception: msgpack::v1::type_error at memory location 0x000000EE2CDFF9E0.
server side:
dispatcher->add("ThermalSetSV", [bld](int thermalDeviceID, float newSV) {
std::lock_guard g(bld->getDeviceMutex());
auto thermalDevices = bld->getThermalDevices();
auto ret = thermalDevices.at(thermalDeviceID)->setSV(newSV);
return ret;
});
client:
int ThermalDeviceRemoteClient::setSV(float sv) {
std::promise<int> p;
_client->async_call("ThermalSetSV", std::tuple{_idx, sv},
[&](packio::error_code, const rpc::response_type &r) { p.set_value(r.result.as<int>()); });
return p.get_future().get();
}
any help greatly appreciated...I am so close but no idea where to go from here
Currently it does for ==20
Error details:
ERROR: packio/2.5.0: Error in configure() method, line 89
self.output.warn("packio requires C++17. Your compiler is unknown. Assuming it supports C++17.")
AttributeError: 'ConanOutput' object has no attribute 'warn'
cause analysis:
warn() in https://github.com/conan-io/conan-center-index/blob/master/recipes/packio/all/conanfile.py#L89C18-L89C24 doesn't exist in conan 2.0 api https://docs.conan.io/2/reference/conanfile/running_and_output.html
Hello,
first of all a big thanks for this library!
I'm currently working on a HTTPS stream adapter to use packio to talk to OpenWRT's ubus system bus. ubus exposes its API via jsonrpc2.0 over HTTP. Since I don't want to send login credentials over the plain wire, HTTPS is used.
This works quite well, except for some issues that stem from the HTTP/HTTPS session management. The webserver (which is uhttpd) which is running on the OpenWRT device does not enable HTTP keepalive by default, so it immediately kills the session (down to the TCP layers) once a request/response cycle is through. But even with HTTP keepalive enabled, it only waits for a few seconds before doing the same.
In my adapters async_read_some()
this results in a boost::asio::ssl::error::stream_truncated
. Because why should one gracefully shutdown the SSL layer, if you can just shutdown the TCP layer? sigh
Anyway, the problem I'm trying to solve is that once this happens, and the error code is propagated up into packio code, the packio code is calling its client::close()
. This then calls my handler with net::error::operation_aborted
. Which is the same error code that client::cancel()
uses. So there is currently no way to differentiate between cancellation and the situation where the remote host (the OpenWRT) closes the session.
I currently hotfix this locally by letting client::close()
return net::error::not_connected
, so that I can detect this in my handler and re-open my HTTPS session.
I'm not sure if this really the best approach, so I wanted to ask for feedback here.
Thanks in advance!
With best wishes,
Tobias
Conan version of boost 1.75 is most likely bugged at the moment
I am currently using packio as a JSON RPC client in a commercial project. The server is a custom JSON RPC implementation that sends unsolicited notifications. This behaviour is outside the JSON RPC specification, but we have no control over the server. Other libraries have implemented this extension - see https://github.com/joncol/jcon-cpp as an example.
I have implemented the client-side support for this, extending the client class using the existing dispatcher class used by the server. We have been using this successfully over the last couple of months. What we have not done:
Before I do any further work - would you be interested in a PR for this feature?
I have WebSocket server over JSON-RPC (MR #60), that can do long (from 1 to 30 minutes) the API call and can generate progress (%) with extra data (remaining time, sec).
Can I do progress somehow?
We should run CI for macOS and windows, also, list supported compilers and boost versions
A declarative, efficient, and flexible JavaScript library for building user interfaces.
🖖 Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.
TypeScript is a superset of JavaScript that compiles to clean JavaScript output.
An Open Source Machine Learning Framework for Everyone
The Web framework for perfectionists with deadlines.
A PHP framework for web artisans
Bring data to life with SVG, Canvas and HTML. 📊📈🎉
JavaScript (JS) is a lightweight interpreted programming language with first-class functions.
Some thing interesting about web. New door for the world.
A server is a program made to process requests and deliver data to clients.
Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.
Some thing interesting about visualization, use data art
Some thing interesting about game, make everyone happy.
We are working to build community through open source technology. NB: members must have two-factor auth.
Open source projects and samples from Microsoft.
Google ❤️ Open Source for everyone.
Alibaba Open Source for everyone
Data-Driven Documents codes.
China tencent open source team.