{"id":15136945,"url":"https://github.com/qchateau/packio","last_synced_at":"2025-04-05T02:11:24.452Z","repository":{"id":54493274,"uuid":"177233692","full_name":"qchateau/packio","owner":"qchateau","description":"An asynchronous msgpack-RPC and JSON-RPC library built on top of Boost.Asio.","archived":false,"fork":false,"pushed_at":"2025-03-13T07:25:55.000Z","size":1282,"stargazers_count":144,"open_issues_count":6,"forks_count":22,"subscribers_count":8,"default_branch":"master","last_synced_at":"2025-03-29T01:15:21.587Z","etag":null,"topics":["asio","async","asynchronous","boost","boost-asio","conan","coroutines","cpp17","cpp20","json","json-rpc","msgpack","msgpack-rpc","rpc","ssl","websockets"],"latest_commit_sha":null,"homepage":"https://qchateau.github.io/packio/","language":"C++","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":"mpl-2.0","status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/qchateau.png","metadata":{"files":{"readme":"README.md","changelog":null,"contributing":null,"funding":null,"license":"LICENSE.md","code_of_conduct":null,"threat_model":null,"audit":null,"citation":null,"codeowners":null,"security":null,"support":null,"governance":null,"roadmap":null,"authors":null,"dei":null,"publiccode":null,"codemeta":null}},"created_at":"2019-03-23T02:16:16.000Z","updated_at":"2025-03-13T14:00:10.000Z","dependencies_parsed_at":"2024-09-21T11:01:42.603Z","dependency_job_id":"6b9b6054-4520-46cc-a00c-b5ba03237d54","html_url":"https://github.com/qchateau/packio","commit_stats":null,"previous_names":[],"tags_count":24,"template":false,"template_full_name":null,"repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/qchateau%2Fpackio","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/qchateau%2Fpackio/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/qchateau%2Fpackio/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/qchateau%2Fpackio/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/qchateau","download_url":"https://codeload.github.com/qchateau/packio/tar.gz/refs/heads/master","host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":247276189,"owners_count":20912288,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2022-07-04T15:15:14.044Z","host_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub","repositories_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories","repository_names_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repository_names","owners_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners"}},"keywords":["asio","async","asynchronous","boost","boost-asio","conan","coroutines","cpp17","cpp20","json","json-rpc","msgpack","msgpack-rpc","rpc","ssl","websockets"],"created_at":"2024-09-26T06:42:02.287Z","updated_at":"2025-04-05T02:11:24.429Z","avatar_url":"https://github.com/qchateau.png","language":"C++","funding_links":[],"categories":["C++"],"sub_categories":[],"readme":"## Header-only | JSON-RPC | msgpack-RPC | asio | coroutines\n\nThis 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.\n\nThe 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/).\n\n## Overview\n\n```cpp\n#include \u003ciostream\u003e\n\n#include \u003cpackio/packio.h\u003e\n\nusing packio::allow_extra_arguments;\nusing packio::arg;\nusing packio::nl_json_rpc::completion_handler;\nusing packio::nl_json_rpc::make_client;\nusing packio::nl_json_rpc::make_server;\nusing packio::nl_json_rpc::rpc;\nusing namespace packio::arg_literals;\n\nint main(int, char**)\n{\n    using namespace packio::arg_literals;\n\n    // Declare a server and a client, sharing the same io_context\n    packio::net::io_context io;\n    packio::net::ip::tcp::endpoint bind_ep{\n        packio::net::ip::make_address(\"127.0.0.1\"), 0};\n    auto server = make_server(packio::net::ip::tcp::acceptor{io, bind_ep});\n    auto client = make_client(packio::net::ip::tcp::socket{io});\n\n    // Declare a synchronous callback with named arguments\n    server-\u003edispatcher()-\u003eadd(\n        \"add\", {\"a\", \"b\"}, [](int a, int b) { return a + b; });\n    // Declare an asynchronous callback with named arguments,\n    // an argument with a default value and an option to\n    // accept and discard extra arguments\n    server-\u003edispatcher()-\u003eadd_async(\n        \"multiply\",\n        {allow_extra_arguments, \"a\", \"b\"_arg = 2},\n        [\u0026io](completion_handler complete, int a, int b) {\n            // Call the completion handler later\n            packio::net::post(\n                io, [a, b, complete = std::move(complete)]() mutable {\n                    complete(a * b);\n                });\n        });\n    // Declare a coroutine with unnamed arguments\n    server-\u003edispatcher()-\u003eadd_coro(\n        \"pow\", io, [](int a, int b) -\u003e packio::net::awaitable\u003cint\u003e {\n            co_return std::pow(a, b);\n        });\n\n    // Connect the client\n    client-\u003esocket().connect(server-\u003eacceptor().local_endpoint());\n    // Accept connections\n    server-\u003easync_serve_forever();\n    // Run the io_context\n    std::thread thread{[\u0026] { io.run(); }};\n\n    // Make an asynchronous call with named arguments\n    // using either `packio::arg` or `packio::arg_literals`\n    std::promise\u003cint\u003e add1_result, multiply_result;\n    client-\u003easync_call(\n        \"add\",\n        std::tuple{arg(\"a\") = 42, \"b\"_arg = 24},\n        [\u0026](packio::error_code, const rpc::response_type\u0026 r) {\n            add1_result.set_value(r.result.get\u003cint\u003e());\n        });\n    std::cout \u003c\u003c \"42 + 24 = \" \u003c\u003c add1_result.get_future().get() \u003c\u003c std::endl;\n\n    // Use packio::net::use_future with named arguments and literals\n    auto add_future = client-\u003easync_call(\n        \"multiply\",\n        std::tuple{\"a\"_arg = 12, \"b\"_arg = 23},\n        packio::net::use_future);\n    std::cout \u003c\u003c \"12 * 23 = \" \u003c\u003c add_future.get().result.get\u003cint\u003e() \u003c\u003c std::endl;\n\n    // Spawn the coroutine and wait for its completion\n    std::promise\u003cint\u003e pow_result;\n    packio::net::co_spawn(\n        io,\n        [\u0026]() -\u003e packio::net::awaitable\u003cvoid\u003e {\n            // Call using an awaitable and positional arguments\n            auto res = co_await client-\u003easync_call(\n                \"pow\", std::tuple{2, 8}, packio::net::use_awaitable);\n            pow_result.set_value(res.result.get\u003cint\u003e());\n        },\n        packio::net::detached);\n    std::cout \u003c\u003c \"2 ** 8 = \" \u003c\u003c pow_result.get_future().get() \u003c\u003c std::endl;\n\n    io.stop();\n    thread.join();\n\n    return 0;\n}\n```\n\n## Requirements\n\n- C++17 or C++20\n- msgpack \u003e= 3.2.1\n- nlohmann_json \u003e= 3.9.1\n- boost.asio \u003e= 1.70.0 or asio \u003e= 1.13.0\n\nOlder versions of `msgpack` and `nlohmann_json` are probably compatible but they are not tested on the CI.\n\n## Configurations\n\n### Standalone or Boost.Asio\n\nBy 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.\n\nIf you are using the conan package, you can use the option `standalone_asio=True`.\n\nDepending on your choice, the namespace `packio::net` will be an alias for either `boost::asio` or `asio`.\n\n### RPC components\n\nYou can define the following preprocessor macros to either 0 or 1 to force-disable or force-enable components of `packio`:\n\n- `PACKIO_HAS_MSGPACK`\n- `PACKIO_HAS_NLOHMANN_JSON`\n- `PACKIO_HAS_BOOST_JSON`\n\nIf you're using the conan package, use the associated options instead, conan will define these macros accordingly.\n\nIf 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.\n\n### Boost before 1.75\n\nIf 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`.\n`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.\n\n## Tested compilers\n\n- gcc-9\n- gcc-10\n- gcc-11\n- gcc-12\n- clang-11\n- clang-12\n- clang-13\n- clang-14\n- Apple clang-13\n- Visual Studio 2019 Version 16\n- Visual Studio 2022 Version 17\n\nOlder compilers may be compatible but are not tested.\n\n## Install with conan\n\n```bash\nconan install packio/x.x.x\n```\n\n## Coroutines\n\n`packio` is compatible with C++20 coroutines:\n\n- calls can use the `packio::asio::use_awaitable` completion token\n- coroutines can be registered in the server\n\nCoroutines are tested for the following compilers:\n\n- gcc-11\n- gcc-12\n- clang-14\n- Apple clang-12\n\n## Samples\n\nYou will find some samples in `test_package/samples/` to help you get a hand on `packio`.\n\n## Bonus\n\nLet's compute fibonacci's numbers recursively over websockets with coroutines on a single thread ... in 65 lines of code.\n\n```cpp\n#include \u003ciostream\u003e\n\n#include \u003cpackio/extra/websocket.h\u003e\n#include \u003cpackio/packio.h\u003e\n\nusing packio::msgpack_rpc::make_client;\nusing packio::msgpack_rpc::make_server;\nusing packio::net::ip::make_address;\n\nusing awaitable_tcp_stream = decltype(packio::net::use_awaitable_t\u003c\u003e::as_default_on(\n    std::declval\u003cboost::beast::tcp_stream\u003e()));\nusing websocket = packio::extra::\n    websocket_adapter\u003cboost::beast::websocket::stream\u003cawaitable_tcp_stream\u003e, true\u003e;\nusing ws_acceptor =\n    packio::extra::websocket_acceptor_adapter\u003cpackio::net::ip::tcp::acceptor, websocket\u003e;\n\nint main(int argc, char** argv)\n{\n    if (argc \u003c 2) {\n        std::cerr \u003c\u003c \"I require one argument\" \u003c\u003c std::endl;\n        return 1;\n    }\n    const int n = std::atoi(argv[1]);\n\n    packio::net::io_context io;\n    packio::net::ip::tcp::endpoint bind_ep{make_address(\"127.0.0.1\"), 0};\n\n    auto server = make_server(ws_acceptor{io, bind_ep});\n    auto client = make_client(websocket{io});\n\n    server-\u003edispatcher()-\u003eadd_coro(\n        \"fibonacci\", io, [\u0026](int n) -\u003e packio::net::awaitable\u003cint\u003e {\n            if (n \u003c= 1) {\n                co_return n;\n            }\n\n            auto r1 = co_await client-\u003easync_call(\"fibonacci\", std::tuple{n - 1});\n            auto r2 = co_await client-\u003easync_call(\"fibonacci\", std::tuple{n - 2});\n\n            co_return r1.result.as\u003cint\u003e() + r2.result.as\u003cint\u003e();\n        });\n\n    int result = 0;\n    packio::net::co_spawn(\n        io,\n        [\u0026]() -\u003e packio::net::awaitable\u003cvoid\u003e {\n            auto ep = server-\u003eacceptor().local_endpoint();\n            co_await client-\u003esocket().next_layer().async_connect(ep);\n            co_await client-\u003esocket().async_handshake(\n                \"127.0.0.1:\" + std::to_string(ep.port()), \"/\");\n            auto ret = co_await client-\u003easync_call(\"fibonacci\", std::tuple{n});\n            result = ret.result.template as\u003cint\u003e();\n            io.stop();\n        },\n        packio::net::detached);\n\n    server-\u003easync_serve_forever();\n    io.run();\n\n    std::cout \u003c\u003c \"F{\" \u003c\u003c n \u003c\u003c \"} = \" \u003c\u003c result \u003c\u003c std::endl;\n\n    return 0;\n}\n```\n","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fqchateau%2Fpackio","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Fqchateau%2Fpackio","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fqchateau%2Fpackio/lists"}