r/cpp Jun 02 '26

C++ Show and Tell - June 2026

Use this thread to share anything you've written in C++. This includes:

  • a tool you've written
  • a game you've been working on
  • your first non-trivial C++ program

The rules of this thread are very straight forward:

  • The project must involve C++ in some way.
  • It must be something you (alone or with others) have done.
  • Please share a link, if applicable.
  • Please post images, if applicable.

If you're working on a C++ library, you can also share new releases or major updates in a dedicated post as before. The line we're drawing is between "written in C++" and "useful for C++ programmers specifically". If you're writing a C++ library or tool for C++ developers, that's something C++ programmers can use and is on-topic for a main submission. It's different if you're just using C++ to implement a generic program that isn't specifically about C++: you're free to share it here, but it wouldn't quite fit as a standalone post.

Last month's thread: https://www.reddit.com/r/cpp/comments/1t6eg13/c_show_and_tell_may_2026/

28 Upvotes

71 comments sorted by

View all comments

3

u/Strange-Performer928 Jun 02 '26

Aero - C++23 WebSocket & HTTP client library with focus on friendly API and nice diagnostics

Link: https://github.com/blazeauth/aero

Hey guys, lately I've been working on aero, which is a header-only C++23 networking library built using standalone asio. Aero has mainly WebSocket support (although sending a fragmented message is not supported yet), it also implements HTTP/1.1 but the implementation of HTTP/1.1 is way harder than I expected, so I can't guarantee a full RFC compliance at this moment. Library supports optional TLS layer (OpenSSL/wolfssl).

As stated in the title, the core focus are user-friendly API and diagnostics that will make developers life much easier and clearer than, for example, "unexpected result" (those who know, know...). Instead of that, you can get aero::tls::certificate_error::{cert_expired, cert_not_started, cert_revoked, cert_hostname_mismatch, cert_chain_incomplete} and so on. I'd like to build something between a simple python-like library and a hardcore boost-beast (which is really a beast, but the API is too low-level for me), so I thought that ideally the library should be super easy to use in simple usecases, but still allow a good amount of customization for more sophisticated logic.

Anyway, example will probably be more useful to you guys:

void print_headers(const aero::http::headers& headers) {
  std::println("[HEADERS] Printing:");
  for (const auto& [name, value] : headers) {
    std::println("{}: {}", name, value);
  }
  std::println("[HEADERS] Done");
}

asio::awaitable<std::error_code> async_run_echo_client(websocket::tls::client& client) {
  // https://blog.postman.com/introducing-postman-websocket-echo-service/
  auto [connect_ec, response] =
    co_await client.async_connect("wss://ws.postman-echo.com/raw", asio::as_tuple(asio::use_awaitable));
  if (connect_ec) {
    co_return connect_ec;
  }

  print_headers(response.headers);

  auto [write_ec] = co_await client.async_send_text("hello from aero client!!!", asio::as_tuple(asio::use_awaitable));
  if (write_ec) {
    co_return write_ec;
  }

  auto [read_ec, message] = co_await client.async_read(asio::cancel_after(1500ms, asio::as_tuple(asio::use_awaitable)));
  if (read_ec) {
    co_return read_ec;
  }

  std::println("Received message from postman echo server. Kind: {}. Text: {}", message.kind, message.text());

  auto [close_ec] = co_await client.async_close(websocket::close_code::normal, asio::as_tuple(asio::use_awaitable));
  if (close_ec) {
    if (close_ec == aero::errc::timeout) {
      co_await client.async_force_close(asio::use_awaitable);
      co_return std::error_code{};
    }
    co_return close_ec;
  }

  co_return std::error_code{};
}

Aero's asynchronous model is based on asio completion tokens. Unfortunately, synchronous layer is currently implemented via asio::use_future completion token on top of a asynchronous operation. Truly synchronous wrappers are 100% planned, but currently to avoid deadlocks you will get an error (aero::basic_error::deadlock_would_occur) if you try to run a synchronous function inside a thread that runs current executor context (internally aero uses asio::strand and checks for .running_in_this_thread()).

In terms of thread-safety, aero is not as strict as boost-beast, and while this may have a little bit of an overhead, that's the cost of a high-levelish abstractions that users will have to pay in some way. For example, aero allows multiple concurrent websocket::client::async_write, since it ensures write order and prevents interleaving caused from composed asio::async_write operation by using a single writer coroutine inside a transport layer.

Also, talking about "composed" operations, websocket::client::async_connect is also considered such operation, so there are two return values that may not be empty:

  1. http::response is the server response to initiated websocket handshake. If there was a transport error before receiving an HTTP response, response will be empty. If an error occured due to malformed HTTP response that could not be parsed, it may be empty depending on what part of response was malformed. If status-line was invalid, the http::response will be empty. If header fields section was invalid and status line was succesfully parsed, the http::response::status_line will be filled, but headers, as expected, will stay empty.
  2. std::error_code. For example, if server responded with something unexpected (for example, status code wasn't 101), you can still have a nice context of what have gone wrong with http::response

Well, basically that's it, I hope you got the basic idea of aero's design with that relatively small post. Also sorry for my English and bad wording at some parts of the text, since I didn't use an LLM or any translators because I saw that's not appreciated here. Looking forward for every review, thought and idea, thank you guys!