{"id":37302541,"url":"https://github.com/slickquant/slick-net","last_synced_at":"2026-05-04T09:01:06.246Z","repository":{"id":316429915,"uuid":"1063338029","full_name":"SlickQuant/slick-net","owner":"SlickQuant","description":"C++ HTTP/WebSocket client library built on Boost.Beast with SSL/TLS support","archived":false,"fork":false,"pushed_at":"2026-04-27T12:27:42.000Z","size":175,"stargazers_count":3,"open_issues_count":0,"forks_count":0,"subscribers_count":1,"default_branch":"main","last_synced_at":"2026-04-27T14:24:21.059Z","etag":null,"topics":[],"latest_commit_sha":null,"homepage":"","language":"C++","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":"mit","status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/SlickQuant.png","metadata":{"files":{"readme":"README.md","changelog":"CHANGELOG.md","contributing":null,"funding":".github/FUNDING.yml","license":"LICENSE","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,"zenodo":null,"notice":null,"maintainers":null,"copyright":null,"agents":null,"dco":null,"cla":null},"funding":{"github":"SlickQuant","patreon":null,"open_collective":null,"ko_fi":null,"tidelift":null,"community_bridge":null,"liberapay":null,"issuehunt":null,"lfx_crowdfunding":null,"polar":null,"buy_me_a_coffee":null,"thanks_dev":null,"custom":null}},"created_at":"2025-09-24T13:42:54.000Z","updated_at":"2026-04-27T12:27:45.000Z","dependencies_parsed_at":"2026-05-04T09:00:49.758Z","dependency_job_id":null,"html_url":"https://github.com/SlickQuant/slick-net","commit_stats":null,"previous_names":["slickquant/slick_net","slickquant/slick-net"],"tags_count":13,"template":false,"template_full_name":null,"purl":"pkg:github/SlickQuant/slick-net","repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/SlickQuant%2Fslick-net","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/SlickQuant%2Fslick-net/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/SlickQuant%2Fslick-net/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/SlickQuant%2Fslick-net/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/SlickQuant","download_url":"https://codeload.github.com/SlickQuant/slick-net/tar.gz/refs/heads/main","sbom_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/SlickQuant%2Fslick-net/sbom","scorecard":null,"host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":286080680,"owners_count":32600968,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2026-05-03T22:12:39.696Z","status":"online","status_checked_at":"2026-05-04T02:00:06.625Z","response_time":58,"last_error":null,"robots_txt_status":"success","robots_txt_updated_at":"2025-07-24T06:49:26.215Z","robots_txt_url":"https://github.com/robots.txt","online":true,"can_crawl_api":true,"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":[],"created_at":"2026-01-16T02:50:22.423Z","updated_at":"2026-05-04T09:01:06.198Z","avatar_url":"https://github.com/SlickQuant.png","language":"C++","funding_links":["https://github.com/sponsors/SlickQuant"],"categories":[],"sub_categories":[],"readme":"# slick-net\n\n[![C++20](https://img.shields.io/badge/C%2B%2B-20-blue.svg)](https://en.cppreference.com/w/cpp/20)\n[![License: MIT](https://img.shields.io/badge/License-MIT-yellow.svg)](https://opensource.org/licenses/MIT)\n[![CI](https://github.com/SlickQuant/slick-net/actions/workflows/ci.yml/badge.svg)](https://github.com/SlickQuant/slick-net/actions/workflows/ci.yml)\n[![GitHub release](https://img.shields.io/github/v/release/SlickQuant/slick-net)](https://github.com/SlickQuant/slick-net/releases)\n\nA high-performance C++ HTTP/WebSocket client library built on Boost.Beast with full SSL/TLS support. Designed for asynchronous, non-blocking HTTP/WebSocket communication in modern C++ applications.\n\n## Features\n\n- **HTTP/HTTPS Client**: Full support for GET, POST, PUT, PATCH, and DELETE methods\n- **HTTP Streaming**: Support for Server-Sent Events (SSE) and chunked response streaming\n- **Asynchronous WebSocket Client**: Built on Boost.Asio coroutines for high-performance async operations\n- **SSL/TLS Support**: Native support for secure `https://` and `wss://` connections\n- **Multiple Async APIs**: Synchronous, callback-based, and C++20 coroutine awaitable interfaces\n- **Cross-Platform**: Works on Windows, Linux, and macOS\n- **Static Library by Default**: Heavy networking implementation compiles once in `slick-net`\n- **Callback-Based API**: Clean event-driven interface for connection lifecycle management\n- **Thread-Safe**: Proper strand management for concurrent operations\n- **Modern C++20**: Leverages coroutines and modern C++ features\n\n## Dependencies\n\n- **Boost** (1.75+): beast, asio, context components\n- **OpenSSL**: For SSL/TLS support\n- **C++20 Compiler**: Required for coroutine support\n  - GCC 14+ (GCC 13 has a known bug with coroutine lambdas in test code)\n  - Clang 14+\n  - MSVC 2022+\n\n## Installation\n\n### CMake Integration\n\nAdd slick-net as a subdirectory in your CMake project:\n\n```cmake\nadd_subdirectory(path/to/slick-net)\ntarget_link_libraries(your_target PRIVATE slick::net)\n```\n\n`slick::net` is the default static-library target.\n\nOr use FetchContent:\n\n```cmake\ninclude(FetchContent)\nFetchContent_Declare(\n    slick-net\n    GIT_REPOSITORY https://github.com/SlickQuant/slick-net.git\n    GIT_TAG main\n)\nFetchContent_MakeAvailable(slick-net)\ntarget_link_libraries(your_target PRIVATE slick::net)\n```\n\n### Runtime Logging Hooks\n\nInternal slick-net logs are routed via runtime hooks:\n\n```cpp\n#include \u003cslick/net/logging.hpp\u003e\n\nslick::net::set_log_handler([](slick::net::LogLevel level, const char* format_text, std::format_args args) {\n    // Route to your logger\n});\n\n// Optional cleanup\nslick::net::clear_log_handler();\n```\n\n## Usage\n\n### Basic WebSocket Client\n\n```cpp\n#include \u003cslick/net/websocket.hpp\u003e\n\nusing namespace slick::net;\n\nint main() {\n    Websocket ws(\n        \"wss://ws.postman-echo.com/raw\",           // WebSocket URL\n        []() {                                // onConnected\n            std::cout \u003c\u003c \"Connected!\\n\";\n        },\n        []() {                                // onDisconnected\n            std::cout \u003c\u003c \"Disconnected!\\n\";\n        },\n        [](const char* data, size_t size) {   // onData\n            std::cout \u003c\u003c \"Received: \" \u003c\u003c std::string(data, size) \u003c\u003c \"\\n\";\n        },\n        [](std::string err) {                 // onError\n            std::cerr \u003c\u003c \"Error: \" \u003c\u003c err \u003c\u003c \"\\n\";\n        }\n    );\n    \n    ws.open();\n    \n    // Send a message\n    std::string message = \"Hello, WebSocket!\";\n    ws.send(message.data(), message.size());\n    \n    // Keep the application running\n    while(Websocket::is_running()) {\n        std::this_thread::sleep_for(std::chrono::seconds(1));\n    }\n    \n    return 0;\n}\n```\n\n### Advanced Usage with JSON\n\n```cpp\n#include \u003cslick/net/websocket.hpp\u003e\n#include \u003cnlohmann/json.hpp\u003e\n\nusing namespace slick::net;\nusing json = nlohmann::json;\n\nint main() {\n    std::shared_ptr\u003cWebsocket\u003e ws;\n    ws = std::make_shared\u003cWebsocket\u003e(\n        \"wss://advanced-trade-ws.coinbase.com\",\n        [\u0026]() { \n            std::cout \u003c\u003c \"Connected to Coinbase\\n\";\n            // Subscribe to market data\n            json subscribe_msg = {\n                {\"type\", \"subscribe\"},\n                {\"channel\", \"level2\"},\n                {\"product_ids\", {\"BTC-USD\"}}\n            };\n            auto msg_str = subscribe_msg.dump();\n            ws-\u003esend(msg_str.data(), msg_str.size());\n        },\n        []() {\n            std::cout \u003c\u003c \"Disconnected from Coinbase\\n\";\n        },\n        [](const char* data, size_t size) {\n            std::cout \u003c\u003c \"Market data: \" \u003c\u003c std::string(data, size) \u003c\u003c \"\\n\";\n        },\n        [](std::string err) {\n            std::cerr \u003c\u003c \"Error: \" \u003c\u003c err \u003c\u003c \"\\n\";\n        }\n    );\n    \n    ws-\u003eopen();\n    \n    // Ctrl + C to exit\n    // Keep running\n    while(Websocket::is_running()) {\n        std::this_thread::sleep_for(std::chrono::seconds(1));\n    }\n    \n    return 0;\n}\n```\n\n## Build Examples\n\nThe repository includes working examples. To build them:\n\n```bash\nmkdir build\ncd build\ncmake ..\ncmake --build .\n```\n\nRun examples:\n```bash\n./examples/websocket_client_example\n./examples/http_client_example\n./examples/http_stream_client_example\n./examples/http_awaitable_client_example\n```\n\n## API Reference\n\n### Http Class\n\n**Synchronous Methods:**\n```cpp\nHttp::Response get(std::string_view url, std::vector\u003cstd::pair\u003cstd::string, std::string\u003e\u003e\u0026\u0026 headers = {});\nHttp::Response post(std::string_view url, std::string_view data, std::vector\u003cstd::pair\u003cstd::string, std::string\u003e\u003e\u0026\u0026 headers = {});\nHttp::Response put(std::string_view url, std::string_view data, std::vector\u003cstd::pair\u003cstd::string, std::string\u003e\u003e\u0026\u0026 headers = {});\nHttp::Response patch(std::string_view url, std::string_view data, std::vector\u003cstd::pair\u003cstd::string, std::string\u003e\u003e\u0026\u0026 headers = {});\nHttp::Response del(std::string_view url, std::string_view data, std::vector\u003cstd::pair\u003cstd::string, std::string\u003e\u003e\u0026\u0026 headers = {});\n```\n\n**Asynchronous Callback-Based Methods:**\n```cpp\nvoid async_get(std::function\u003cvoid(Response\u0026\u0026)\u003e on_response, std::string_view url, std::vector\u003cstd::pair\u003cstd::string, std::string\u003e\u003e\u0026\u0026 headers = {});\nvoid async_post(std::function\u003cvoid(Response\u0026\u0026)\u003e on_response, std::string_view url, std::string_view data, std::vector\u003cstd::pair\u003cstd::string, std::string\u003e\u003e\u0026\u0026 headers = {});\nvoid async_put(std::function\u003cvoid(Response\u0026\u0026)\u003e on_response, std::string_view url, std::string_view data, std::vector\u003cstd::pair\u003cstd::string, std::string\u003e\u003e\u0026\u0026 headers = {});\nvoid async_patch(std::function\u003cvoid(Response\u0026\u0026)\u003e on_response, std::string_view url, std::string_view data, std::vector\u003cstd::pair\u003cstd::string, std::string\u003e\u003e\u0026\u0026 headers = {});\nvoid async_del(std::function\u003cvoid(Response\u0026\u0026)\u003e on_response, std::string_view url, std::string_view data, std::vector\u003cstd::pair\u003cstd::string, std::string\u003e\u003e\u0026\u0026 headers = {});\n```\n\n**Asynchronous Awaitable Methods (C++20 Coroutines):**\n```cpp\nasio::awaitable\u003cResponse\u003e async_get(std::string_view url, std::vector\u003cstd::pair\u003cstd::string, std::string\u003e\u003e\u0026\u0026 headers = {});\nasio::awaitable\u003cResponse\u003e async_post(std::string_view url, std::string_view data, std::vector\u003cstd::pair\u003cstd::string, std::string\u003e\u003e\u0026\u0026 headers = {});\nasio::awaitable\u003cResponse\u003e async_put(std::string_view url, std::string_view data, std::vector\u003cstd::pair\u003cstd::string, std::string\u003e\u003e\u0026\u0026 headers = {});\nasio::awaitable\u003cResponse\u003e async_patch(std::string_view url, std::string_view data, std::vector\u003cstd::pair\u003cstd::string, std::string\u003e\u003e\u0026\u0026 headers = {});\nasio::awaitable\u003cResponse\u003e async_del(std::string_view url, std::string_view data = \"\", std::vector\u003cstd::pair\u003cstd::string, std::string\u003e\u003e\u0026\u0026 headers = {});\n```\n\n**Response Structure:**\n```cpp\nstruct Response {\n    uint32_t result_code;     // HTTP status code\n    std::string result_text;  // Response body or error message\n    bool is_ok() const;       // Returns true if status code is 2xx\n};\n```\n\n**Example Usage - Synchronous:**\n```cpp\n#include \u003cslick/net/http.hpp\u003e\n\n// Synchronous GET\nauto response = Http::get(\"https://api.example.com/data\");\nif (response.is_ok()) {\n    std::cout \u003c\u003c response.result_text \u003c\u003c std::endl;\n}\n```\n\n**Example Usage - Asynchronous Callback-Based:**\n```cpp\n#include \u003cslick/net/http.hpp\u003e\n\n// Asynchronous POST with JSON\nnlohmann::json data = {{\"key\", \"value\"}};\nHttp::async_post([](Http::Response\u0026\u0026 rsp) {\n    if (rsp.is_ok()) {\n        std::cout \u003c\u003c \"Success: \" \u003c\u003c rsp.result_text \u003c\u003c std::endl;\n    }\n}, \"https://api.example.com/resource\", data.dump(), {{\"Content-Type\", \"application/json\"}});\n```\n\n**Example Usage - Asynchronous Awaitable (C++20 Coroutines):**\n```cpp\n#include \u003cslick/net/http.hpp\u003e\n#include \u003cboost/asio.hpp\u003e\n\nasio::awaitable\u003cvoid\u003e fetch_data() {\n    // Awaitable GET - clean async/await syntax\n    auto response = co_await Http::async_get(\"https://api.example.com/data\");\n    if (response.is_ok()) {\n        std::cout \u003c\u003c \"Response: \" \u003c\u003c response.result_text \u003c\u003c std::endl;\n    }\n\n    // Sequential requests\n    nlohmann::json post_data = {{\"key\", \"value\"}};\n    auto post_response = co_await Http::async_post(\n        \"https://api.example.com/resource\",\n        post_data.dump(),\n        {{\"Content-Type\", \"application/json\"}}\n    );\n\n    if (post_response.is_ok()) {\n        std::cout \u003c\u003c \"Created: \" \u003c\u003c post_response.result_text \u003c\u003c std::endl;\n    }\n}\n\nint main() {\n    asio::io_context ioc;\n\n    asio::co_spawn(ioc, fetch_data(), asio::detached);\n\n    ioc.run();\n    return 0;\n}\n```\n\n### Websocket Class\n\n**Constructor:**\n```cpp\nWebsocket(\n    std::string url,\n    std::function\u003cvoid()\u003e onConnected,\n    std::function\u003cvoid()\u003e onDisconnected,\n    std::function\u003cvoid(const char*, std::size_t)\u003e onData,\n    std::function\u003cvoid(std::string\u0026\u0026)\u003e onError\n)\n```\n\n**Methods:**\n- `void open()` - Start the WebSocket connection\n- `void close()` - Close the WebSocket connection\n- `void send(const char* buffer, size_t len)` - Send data through the WebSocket\n- `Status status() const` - Get current connection status\n- `static void shutdown()` - Shutdown all WebSocket services\n\n**Status Enum:**\n- `CONNECTING` - Connection in progress\n- `CONNECTED` - Connected and ready\n- `DISCONNECTING` - Disconnection in progress\n- `DISCONNECTED` - Disconnected\n\n### HttpStream Class\n\nThe `HttpStream` class provides support for HTTP streaming, including Server-Sent Events (SSE) and chunked responses.\n\n**Constructor:**\n```cpp\nHttpStream(\n    std::string url,\n    std::function\u003cvoid()\u003e onConnected,\n    std::function\u003cvoid()\u003e onDisconnected,\n    std::function\u003cvoid(const char*, std::size_t)\u003e onData,\n    std::function\u003cvoid(std::string\u0026\u0026)\u003e onError,\n    std::vector\u003cstd::pair\u003cstd::string, std::string\u003e\u003e\u0026\u0026 headers = {}\n)\n```\n\n**Methods:**\n- `void open()` - Start the HTTP stream connection\n- `void close()` - Close the stream connection\n- `Status status() const` - Get current connection status\n- `static bool is_running()` - Check if any streams are running\n- `static void shutdown()` - Shutdown all HTTP stream services\n\n**Status Enum:**\n- `CONNECTING` - Connection in progress\n- `CONNECTED` - Connected and receiving data\n- `DISCONNECTED` - Disconnected\n\n**Example Usage - Server-Sent Events (SSE):**\n```cpp\n#include \u003cslick/net/http.hpp\u003e\n\nauto stream = std::make_shared\u003cHttpStream\u003e(\n    \"https://api.example.com/events\",\n    []() {\n        std::cout \u003c\u003c \"Stream connected\\n\";\n    },\n    []() {\n        std::cout \u003c\u003c \"Stream disconnected\\n\";\n    },\n    [](const char* data, size_t size) {\n        std::string event(data, size);\n        std::cout \u003c\u003c \"Event: \" \u003c\u003c event \u003c\u003c \"\\n\";\n    },\n    [](std::string err) {\n        std::cerr \u003c\u003c \"Error: \" \u003c\u003c err \u003c\u003c \"\\n\";\n    }\n);\n\nstream-\u003eopen();\n\n// Stream will receive events via the onData callback\n// Close when done\nstream-\u003eclose();\n```\n\n**Example Usage - OpenAI Streaming API:**\n```cpp\n#include \u003cslick/net/http.hpp\u003e\n#include \u003cnlohmann/json.hpp\u003e\n\nauto stream = std::make_shared\u003cHttpStream\u003e(\n    \"https://api.openai.com/v1/chat/completions\",\n    []() {\n        std::cout \u003c\u003c \"Connected to OpenAI\\n\";\n    },\n    []() {\n        std::cout \u003c\u003c \"Stream ended\\n\";\n    },\n    [](const char* data, size_t size) {\n        // Parse streaming JSON chunks\n        std::string chunk(data, size);\n        try {\n            auto json = nlohmann::json::parse(chunk);\n            if (json.contains(\"choices\")) {\n                auto delta = json[\"choices\"][0][\"delta\"];\n                if (delta.contains(\"content\")) {\n                    std::cout \u003c\u003c delta[\"content\"].get\u003cstd::string\u003e();\n                }\n            }\n        } catch (...) {}\n    },\n    [](std::string err) {\n        std::cerr \u003c\u003c \"Error: \" \u003c\u003c err \u003c\u003c \"\\n\";\n    },\n    {\n        {\"Authorization\", \"Bearer YOUR_API_KEY\"},\n        {\"Content-Type\", \"application/json\"}\n    }\n);\n\nstream-\u003eopen();\n```\n\n## License\n\nThis project is licensed under the MIT License - see the [LICENSE](LICENSE) file for details.\n\n## Author\n\nPart of the [SlickQuant](https://github.com/SlickQuant) ecosystem.\n\n**Made with ⚡ by [SlickQuant](https://github.com/SlickQuant)**\n","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fslickquant%2Fslick-net","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Fslickquant%2Fslick-net","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fslickquant%2Fslick-net/lists"}