Skip to content

Commit

Permalink
Merge pull request #37 from qchateau/v2
Browse files Browse the repository at this point in the history
V2
  • Loading branch information
qchateau authored Oct 3, 2020
2 parents 66e336c + b2876b2 commit c49d401
Show file tree
Hide file tree
Showing 224 changed files with 13,573 additions and 3,495 deletions.
8 changes: 5 additions & 3 deletions .ci/build.py
Original file line number Diff line number Diff line change
Expand Up @@ -47,7 +47,8 @@ def add(self, compiler, compiler_version, cppstd, build_type="Release", setting
options = options or {}
if "asio" not in options:
options.update(self._get_boost_options())
options["msgpack:header_only"] = True
options["msgpack:cpp_api"] = True
options["msgpack:c_api"] = False
options["cppstd"] = cppstd

env_vars = {}
Expand Down Expand Up @@ -75,7 +76,8 @@ def test_linux():
builder = Packager()

# Test coroutines
builder.add(compiler=CLANG, compiler_version="10", cppstd="17", settings={"compiler.libcxx": "libc++"}, options={"coroutines": True})
builder.add(compiler=CLANG, compiler_version="10", cppstd="20", settings={"compiler.libcxx": "libc++"}, options={"boost": "1.74.0", "coroutines": True})
builder.add(compiler=CLANG, compiler_version="10", cppstd="20", settings={"compiler.libcxx": "libc++"}, options={"asio": "1.17.0", "packio:standalone_asio": True, "coroutines": True})

# Test debug build
builder.add(compiler=GCC, compiler_version="10", cppstd="20", build_type="Debug")
Expand Down Expand Up @@ -105,6 +107,7 @@ def test_linux():
builder.add(compiler=GCC, compiler_version="10", cppstd="20", options={"asio": "1.13.0", "packio:standalone_asio": True})
builder.add(compiler=GCC, compiler_version="10", cppstd="20", options={"asio": "1.14.1", "packio:standalone_asio": True})
builder.add(compiler=GCC, compiler_version="10", cppstd="20", options={"asio": "1.16.1", "packio:standalone_asio": True})
builder.add(compiler=GCC, compiler_version="10", cppstd="20", options={"asio": "1.17.0", "packio:standalone_asio": True})

# Test logs
builder.add(compiler=GCC, compiler_version="10", cppstd="20", options={"loglevel": "trace"})
Expand All @@ -125,7 +128,6 @@ def test_windows():
builder.add(compiler=MSVC, compiler_version="16", cppstd="17")
builder.add(compiler=MSVC, compiler_version="16", cppstd="20")
builder.add(compiler=MSVC, compiler_version="16", cppstd="20", build_type="Debug")
builder.add(compiler=MSVC, compiler_version="16", cppstd="17", options={"coroutines": True})
builder.run()


Expand Down
6 changes: 3 additions & 3 deletions Doxyfile
Original file line number Diff line number Diff line change
Expand Up @@ -680,7 +680,7 @@ SHOW_FILES = YES
# Folder Tree View (if specified).
# The default value is: YES.

SHOW_NAMESPACES = NO
SHOW_NAMESPACES = YES

# The FILE_VERSION_FILTER tag can be used to specify a program or script that
# doxygen should invoke to get the current version for each file (typically from
Expand Down Expand Up @@ -762,7 +762,7 @@ WARN_NO_PARAMDOC = NO
# a warning is encountered.
# The default value is: NO.

WARN_AS_ERROR = NO
WARN_AS_ERROR = YES

# The WARN_FORMAT tag determines the format of the warning messages that doxygen
# can produce. The string should contain the $file, $line, and $text tags, which
Expand Down Expand Up @@ -2016,7 +2016,7 @@ ENABLE_PREPROCESSING = YES
# The default value is: NO.
# This tag requires that the tag ENABLE_PREPROCESSING is set to YES.

MACRO_EXPANSION = NO
MACRO_EXPANSION = YES

# If the EXPAND_ONLY_PREDEF and MACRO_EXPANSION tags are both set to YES then
# the macro expansion is limited to the macros specified with the PREDEFINED and
Expand Down
88 changes: 47 additions & 41 deletions README.md
Original file line number Diff line number Diff line change
@@ -1,7 +1,6 @@
## Header-only | JSON-RPC | msgpack-RPC | asio | coroutines

## Header-only | msgpack-RPC | asio | coroutines

This library requires C++17 and is designed as an extension to `boost.asio`. It will let you build asynchronous servers or client for msgpack-RPC.
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](https://github.com/qchateau/packio/) and available on [Conan Center](https://conan.io/center/). Documentation is available on [GitHub Pages](https://qchateau.github.io/packio/).

Expand All @@ -12,27 +11,36 @@ The project is hosted on [GitHub](https://github.com/qchateau/packio/) and avail

#include <packio/packio.h>

using packio::arg;
using packio::nl_json_rpc::completion_handler;
using packio::nl_json_rpc::make_client;
using packio::nl_json_rpc::make_server;
using packio::nl_json_rpc::rpc;

int main(int, char**)
{
using namespace packio::arg_literals;

// Declare a server and a client, sharing the same io_context
packio::net::io_context io;
packio::net::ip::tcp::endpoint bind_ep{
packio::net::ip::make_address("127.0.0.1"), 0};
auto server = packio::make_server(packio::net::ip::tcp::acceptor{io, bind_ep});
auto client = packio::make_client(packio::net::ip::tcp::socket{io});
auto server = make_server(packio::net::ip::tcp::acceptor{io, bind_ep});
auto client = make_client(packio::net::ip::tcp::socket{io});

// Declare a synchronous callback
server->dispatcher()->add("add", [](int a, int b) { return a + b; });
// Declare an asynchronous callback
// Declare a synchronous callback with named arguments
server->dispatcher()->add(
"add", {"a", "b"}, [](int a, int b) { return a + b; });
// Declare an asynchronous callback with named arguments
server->dispatcher()->add_async(
"multiply", [&io](packio::completion_handler complete, int a, int b) {
"multiply", {"a", "b"}, [&io](completion_handler complete, int a, int b) {
// Call the completion handler later
packio::net::post(
io, [a, b, complete = std::move(complete)]() mutable {
complete(a * b);
});
});
// Declare a coroutine
// Declare a coroutine with unnamed arguments
server->dispatcher()->add_coro(
"pow", io, [](int a, int b) -> packio::net::awaitable<int> {
co_return std::pow(a, b);
Expand All @@ -45,40 +53,32 @@ int main(int, char**)
// Run the io_context
std::thread thread{[&] { io.run(); }};

// Make an asynchronous call
// Make an asynchronous call with named arguments
std::promise<int> add1_result, multiply_result;
client->async_call(
"add",
std::tuple{42, 24},
[&](packio::error_code, msgpack::object_handle r) {
add1_result.set_value(r->as<int>());
std::tuple{arg("a") = 42, arg("b") = 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;

// Use auto result type conversion
std::promise<int> add2_result;
client->async_call(
"add",
std::tuple{11, 32},
packio::as<int>([&](packio::error_code, std::optional<int> r) {
add2_result.set_value(*r);
}));
std::cout << "11 + 32 = " << add2_result.get_future().get() << std::endl;

// Use packio::net::use_future
std::future<msgpack::object_handle> add_future = client->async_call(
"multiply", std::tuple{12, 23}, packio::net::use_future);
std::cout << "12 * 23 = " << add_future.get()->as<int>() << std::endl;
// Use packio::net::use_future with named arguments and literals
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;

// Spawn the coroutine and wait for its completion
std::promise<int> pow_result;
packio::net::co_spawn(
io,
[&]() -> packio::net::awaitable<void> {
// Call using an awaitable
msgpack::object_handle res = co_await client->async_call(
// Call using an awaitable and positional arguments
auto res = co_await client->async_call(
"pow", std::tuple{2, 8}, packio::net::use_awaitable);
pow_result.set_value(res->as<int>());
pow_result.set_value(res.result.get<int>());
},
packio::net::detached);
std::cout << "2 ** 8 = " << pow_result.get_future().get() << std::endl;
Expand All @@ -94,8 +94,12 @@ int main(int, char**)
- 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 version of `msgpack` and `nlohmann_json` are probably compatible
but they are not tested on the CI.
### 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.
Expand Down Expand Up @@ -126,12 +130,13 @@ 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:
- clang-9 with libc++
- Visual Studio 2019 Version 16

- clang-10 with libc++

## Bonus

Expand All @@ -142,6 +147,9 @@ Let's compute fibonacci's numbers recursively using `packio` and coroutines on a

#include <packio/packio.h>

using packio::msgpack_rpc::make_client;
using packio::msgpack_rpc::make_server;

int main(int argc, char** argv)
{
if (argc < 2) {
Expand All @@ -153,8 +161,8 @@ int main(int argc, char** argv)
packio::net::io_context io;
packio::net::ip::tcp::endpoint bind_ep{
packio::net::ip::make_address("127.0.0.1"), 0};
auto server = packio::make_server(packio::net::ip::tcp::acceptor{io, bind_ep});
auto client = packio::make_client(packio::net::use_awaitable_t<>::as_default_on(
auto server = make_server(packio::net::ip::tcp::acceptor{io, bind_ep});
auto client = make_client(packio::net::use_awaitable_t<>::as_default_on(
packio::net::ip::tcp::socket{io}));

server->dispatcher()->add_coro(
Expand All @@ -166,7 +174,7 @@ int main(int argc, char** argv)
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->as<int>() + r2->as<int>();
co_return r1.result.as<int>() + r2.result.as<int>();
});

client->socket().connect(server->acceptor().local_endpoint());
Expand All @@ -175,12 +183,10 @@ int main(int argc, char** argv)
int result = 0;

client->async_call(
"fibonacci",
std::tuple{n},
packio::as<int>([&](packio::error_code, std::optional<int> r) {
result = *r;
"fibonacci", std::tuple{n}, [&](packio::error_code, auto r) {
result = r.result.template as<int>();
io.stop();
}));
});

io.run();

Expand Down
55 changes: 35 additions & 20 deletions appveyor.yml
Original file line number Diff line number Diff line change
Expand Up @@ -5,48 +5,63 @@ environment:
CONAN_REQUEST_TIMEOUT: 300

matrix:
# Linux job
- job_name: Linux build
job_group: Build
appveyor_build_worker_image: Ubuntu2004
# Windows job
- job_name: Windows build
appveyor_build_worker_image: Visual Studio 2019

# Mac job
- job_name: MacOS build
job_group: Build
appveyor_build_worker_image: macos

# Windows job
- job_name: Windows build
job_group: Build
appveyor_build_worker_image: Visual Studio 2019
# Linux jobs
- job_name: Linux build 0
job_group: Linux build
appveyor_build_worker_image: Ubuntu2004

for:
- job_name: Linux build 1
job_group: Linux build
appveyor_build_worker_image: Ubuntu2004

-
matrix:
for:
- matrix:
only:
- job_name: Linux build
- job_group: Linux build

environment:
CONAN_TOTAL_PAGES: 2

install:
- source ~/venv3.7/bin/activate
- python -m pip install -U conan conan_package_tools
- sudo apt-get update
- sudo apt-get install -y
clang-6.0 clang-7 clang-8 clang-9 clang-10
g++-7 g++-8 g++-9 g++-10
libc++-10-dev libc++abi-10-dev
clang-6.0 clang-7 clang-8 clang-9 clang-10
g++-7 g++-8 g++-9 g++-10
libc++-10-dev libc++abi-10-dev

- matrix:
only:
- job_name: Linux build 0

environment:
CONAN_CURRENT_PAGE: 1

- matrix:
only:
- job_name: Linux build 1

environment:
CONAN_CURRENT_PAGE: 2

-
matrix:
- matrix:
only:
- job_name: MacOS build

install:
- source ~/venv3.7/bin/activate
- python -m pip install -U conan conan_package_tools

-
matrix:
- matrix:
only:
- job_name: Windows build

Expand Down
31 changes: 26 additions & 5 deletions conanfile.py
Original file line number Diff line number Diff line change
Expand Up @@ -7,15 +7,36 @@ class PackioConan(ConanFile):
license = "MPL-2.0"
author = "Quentin Chateau <[email protected]>"
url = "https://github.com/qchateau/packio"
description = "C++ implementation of msgpack-RPC"
topics = ("rpc", "msgpack", "cpp17", "cpp20", "coroutine")
description = "Asynchrnous msgpack-RPC and JSON-RPC server and client"
topics = (
"rpc",
"async",
"msgpack",
"json",
"msgpack-rpc",
"json-rpc",
"cpp17",
"cpp20",
"coroutine",
)
exports_sources = "include/*"
no_copy_source = True
options = {"standalone_asio": [True, False]}
default_options = {"standalone_asio": False}
options = {
"standalone_asio": [True, False],
"msgpack": [True, False],
"nlohmann_json": [True, False],
}
default_options = {
"standalone_asio": False,
"msgpack": True,
"nlohmann_json": True,
}

def requirements(self):
self.requires("msgpack/3.2.1")
if self.options.msgpack:
self.requires("msgpack/3.2.1")
if self.options.nlohmann_json:
self.requires("nlohmann_json/3.9.1")

if self.options.standalone_asio:
self.requires("asio/[>=1.13.0]")
Expand Down
Loading

0 comments on commit c49d401

Please sign in to comment.