- Статус
- Оффлайн
- Регистрация
- 10 Окт 2020
- Сообщения
- 536
- Реакции
- 529
Репозиторий:
Пожалуйста, авторизуйтесь для просмотра ссылки.
Всем привет. Aero это TLS-optional, async-first библиотека для современных клиентских приложений которые не хотят тащить в проект тяжелый boost-beast который требует ~50 различных boost модулей, или устаревший websocketpp который не обновлялся уже более 5 лет и имеет не самый приятный API. Так же в пользу относительной легкости, библиотека из коробки поддерживает wolfssl, билды которого в десятки раз меньше по размеру чем билды OpenSSL. Имплементация не является универсально максимально легкой по размеру генерируемого кода, речь скорее об "относительной" легкости, - aero не является сильно тяжелее оригинального standalone-asio на котором aero написан, и в сравнении с тем же boost-beast, количество зависимостей, размер артефакта после билда и скорость компиляции гораздо лучше.
Библиотека собирается и проходит 300+ юнит тестов на MSVC (Debug/Release & x64/x86, так как
Пожалуйста, авторизуйтесь для просмотра ссылки.
), Clang, Clang-cl, GCC и MacOS AppleClang компиляторах. Имплементация WebSocket так же протестирована
Пожалуйста, авторизуйтесь для просмотра ссылки.
, который используют крупнейшие имплементации WebSocket протокола (Google Chrome, Mozilla Firefox, Internet Explorer и т.д.).Из зависимостей у Aero сейчас: Asio, utfcpp, опционально TLS библиотека (openssl или wolfssl).
Aero старается объединять в себе лучшее из всех миров: простоту, детальность и производительность. Библиотека не отбирает у вас возможность детального контроля над транспортным слоем, кастомными заголовками, опциями и прочими надстройками, при этом не переходя к сильным компромиссам с производительностью, а для простоты - оборачивает привычные операции и дефолты таким образом, что самые частые юзкейсы становится использовать крайне просто и очевидно любому программисту понимающему C++.
Async слой построен на asio completion tokens, что позволяет вам использовать любой вид перегрузок который только возможен: callbacks,
use_awaitable, use_future, redirect_error, as_tuple, cancel_after и так далее, список большой. Те, кто знаком с asio уже поняли что такой дизайн упрощает жизнь и вариативность кода в различных сценариях в разы.Aero так же не использует mutexы для синхронизации (только в одном очень редком случае внутри переиспользуемого пула подключений для HTTP 1.1), используя механизм
asio::strand во избежание лока всего потока ради синхронизации доступа к чему-либо.Ниже 2 максимально простых примера использующие синхронные методы.
Больше примеров (в том числе и асинхронных) вы найдёте тут:
Пожалуйста, авторизуйтесь для просмотра ссылки.
HTTP synchronous example:
#include <print>
#include "aero/http.hpp"
namespace http = aero::http;
int main() {
std::expected<http::response, std::error_code> response = http::get("https://example.com/");
if (!response) {
std::println("Request failed: {}", response.error().message());
return 1;
}
std::println("Received response from example.com:");
std::println("Response Headers:");
for (const auto& [name, value] : response->headers) {
std::println("{}: {}", name, value);
}
std::println("Status: {} ({})", response->status_line.reason_phrase, response->status_code());
if (response->content_type() == "text/html") {
std::println("Body (first 100 bytes): {}", response->text().substr(0, 100));
} else {
std::println("Body: {}", response->text());
}
}
WebSocket TLS Binance Stream:
#include <print>
#include "aero/deadline.hpp"
#include "aero/error.hpp"
#include "aero/tls/system_context.hpp"
#include "aero/tls/version.hpp"
#include "aero/websocket/close_code.hpp"
#include "aero/websocket/tls/client.hpp"
namespace websocket = aero::websocket;
namespace tls = aero::tls;
namespace http = aero::http;
void print_error(std::string_view message, const std::error_code& ec) {
std::println("{}: {} ({} - {})", message, ec.message(), ec.value(), ec.category().name());
}
void print_headers(const http::headers& headers) {
std::println("[HEADERS] Printing:");
for (const auto& [name, value] : headers) {
std::println("{}: {}", name, value);
}
std::println("[HEADERS] Done");
}
int main() {
using namespace std::chrono_literals;
// System context simply wraps asio::ssl::context and implements
// AIA fetching for Win32, otherwise sets default verify paths
tls::system_context tls_ctx{tls::version::tlsv1_2};
tls_ctx.disable_deprecated_versions();
websocket::tls::client client{tls_ctx.context()};
auto handshake_headers = client.connect("wss://stream.binance.com:9443/ws/btcusdt@trade", 5s);
if (!handshake_headers) {
print_error("Connect to binance stream failed", handshake_headers.error());
return 1;
}
std::println("Succesfully connected");
print_headers(*handshake_headers);
aero::deadline deadline{5min};
for (;;) {
if (deadline.expired()) {
break;
}
auto message = client.read(deadline.remaining());
if (!message) {
if (message.error() == aero::error::errc::timeout && deadline.expired()) {
std::println("Read deadline expired, breaking from read-loop");
break;
}
print_error("Failed to receive message from binance stream", message.error());
break;
}
if (!message->is_text()) {
std::println("Received non-text message type ({}), skipping", message->kind);
continue;
}
std::println("Received message from binance stream: {}", message->text());
}
auto close_ec = client.close(websocket::close_code::normal, "thank you, we are leaving.");
if (close_ec) {
print_error("Close handshake failed", close_ec);
std::ignore = client.force_close();
}
return 0;
}
Библиотека написана в header-only стиле для упрощения интеграции в проекты, возможно в будущем так же добавлю single-header вариант.
Так же имплементирован TLS слой как отдельный модуль внутри библиотеки, внутри которого имплементирован
aero::tls::system_context который использует кастомный verify-callback с AIA фетчингом для Windows билдов (через WinCrypt API), который при возможности и необходимости подтянет недостающие промежуточные сертификаты (в случае если peer отдал неполную цепочку сертификатов). Для справки: никто не заставляет вас использовать TLS слой из aero, основной способ передачи внешнего tls-context это передавать asio::ssl::context.Синхронные обёртки сейчас имплементированы объективно говоря не лучшим образом, они используют блокирующий future с async вариантом соответствующей функции, что не даст вам использовать синхронные обёртки в контексте того же потока на котором запущен io_context (при попытке вам вернёт ошибку
aero::basic_error::deadlock_would_occur), поэтому это "не настоящая синхронность".В отличии от boost-beast, aero имеет не настолько сильные требования к контролю записи как это делает beast. Beast требует синхронизации всех
asio::async_write в websocket соединение, по вполне очевидной причине того что asio::async_write это composed операция, объединяющая в себе N вызовов к asio::async_write_some, из-за чего вполне возможен интерливинг между записями из разных потоков, то есть часть сообщения из потока A может "вклиниться" в сообщение, которое пишет поток B.Aero решает эту проблему
Пожалуйста, авторизуйтесь для просмотра ссылки.
которая естественным образом упорядочивает все записи в негоПодробнее о библиотеке и API можно прочитать в README репозитория.
Спасибо всем тем кто использует библиотеку и ставит звёзды. Если у вас появятся какие-либо проблемы при её использовании, создавайте Issue на Github. Буду рад каждому контрибьютору.
Последнее редактирование: