Files
ligo/include/ligo/tcp.hpp
T
khodowany 4170d3a003
publish / publish (push) Successful in 27m34s
Formatting
2026-09-14 23:54:56 -05:00

130 lines
6.3 KiB
C++
Executable File

#pragma once
#include <expected>
#include <chrono>
#include <cstdint>
#include <functional>
#include <memory>
#include <string>
#include <utility>
#include <boost/asio/any_io_executor.hpp>
#include <boost/asio/awaitable.hpp>
#include <boost/asio/io_context.hpp>
#include <boost/asio/ip/tcp.hpp>
#include <boost/asio/ssl/context.hpp>
#include <boost/asio/ssl/stream.hpp>
#include <boost/json/value.hpp>
#include <boost/system/error_code.hpp>
#include <modulus.hpp>
#include <ligo/detail/state.hpp>
#include <ligo/config.hpp>
#include <ligo/security.hpp>
#include <ligo/service.hpp>
namespace ligo::tcp {
struct endpoint {
std::string host{"127.0.0.1"};
std::uint16_t port{0};
};
struct socket_handle {
socket_handle() = default;
socket_handle(ligo::tcp::socket_handle const &) = delete;
socket_handle(ligo::tcp::socket_handle &&) noexcept = default;
explicit socket_handle(boost::asio::ip::tcp::socket socket);
explicit socket_handle(std::shared_ptr<boost::asio::ip::tcp::socket> socket);
auto operator=(ligo::tcp::socket_handle const &) -> ligo::tcp::socket_handle & = delete;
auto operator=(ligo::tcp::socket_handle &&) noexcept -> ligo::tcp::socket_handle & = default;
auto socket() -> std::expected<std::reference_wrapper<boost::asio::ip::tcp::socket>, modulus::error>;
auto socket() const -> std::expected<std::reference_wrapper<boost::asio::ip::tcp::socket const>, modulus::error>;
auto is_open() const -> std::bool_t;
auto close(boost::system::error_code &error) -> void;
auto release_socket() -> std::expected<boost::asio::ip::tcp::socket, modulus::error>;
private:
std::shared_ptr<boost::asio::ip::tcp::socket> socket_{};
};
struct tls_socket {
struct released_stream {
released_stream(std::shared_ptr<boost::asio::ssl::context> context, boost::asio::ssl::stream<boost::asio::ip::tcp::socket> stream);
std::shared_ptr<boost::asio::ssl::context> context{};
boost::asio::ssl::stream<boost::asio::ip::tcp::socket> stream;
};
tls_socket() = default;
tls_socket(ligo::tcp::tls_socket const &) = delete;
tls_socket(ligo::tcp::tls_socket &&) noexcept = default;
tls_socket(std::shared_ptr<boost::asio::ssl::context> context, boost::asio::ip::tcp::socket socket);
auto operator=(ligo::tcp::tls_socket const &) -> ligo::tcp::tls_socket & = delete;
auto operator=(ligo::tcp::tls_socket &&) noexcept -> ligo::tcp::tls_socket & = default;
auto stream() -> std::expected<std::reference_wrapper<boost::asio::ssl::stream<boost::asio::ip::tcp::socket>>, modulus::error>;
auto stream() const -> std::expected<std::reference_wrapper<boost::asio::ssl::stream<boost::asio::ip::tcp::socket> const>, modulus::error>;
auto context() -> std::expected<std::reference_wrapper<boost::asio::ssl::context>, modulus::error>;
auto context() const -> std::expected<std::reference_wrapper<boost::asio::ssl::context const>, modulus::error>;
auto is_open() const -> std::bool_t;
auto close(boost::system::error_code &error) -> void;
auto release_stream() -> std::expected<ligo::tcp::tls_socket::released_stream, modulus::error>;
private:
std::shared_ptr<boost::asio::ssl::context> context_{};
std::unique_ptr<boost::asio::ssl::stream<boost::asio::ip::tcp::socket>> stream_{};
};
struct request {
std::string route{};
boost::json::value payload{};
};
struct client_options {
std::chrono::milliseconds timeout{5000};
ligo::security_config security{};
};
struct server_options {
std::chrono::milliseconds timeout{5000};
std::function<void(modulus::error)> on_error{};
ligo::security_config security{};
};
class client {
public:
explicit client(ligo::tcp::endpoint endpoint, ligo::tcp::client_options options = {});
auto call(ligo::tcp::request const &request) const -> boost::asio::awaitable<std::expected<boost::json::value, modulus::error>>;
private:
ligo::tcp::endpoint endpoint_{};
ligo::tcp::client_options options_{};
};
class server {
public:
server(boost::asio::io_context &io, ligo::tcp::endpoint endpoint, ligo::service_router router, ligo::tcp::server_options options = {});
server(boost::asio::any_io_executor executor, ligo::tcp::endpoint endpoint, ligo::service_router router, ligo::tcp::server_options options = {});
server(ligo::tcp::server const &) = delete;
server(ligo::tcp::server &&) noexcept = default;
~server();
auto operator=(ligo::tcp::server const &) -> ligo::tcp::server & = delete;
auto operator=(ligo::tcp::server &&) noexcept -> ligo::tcp::server &;
auto start() -> std::expected<void, modulus::error>;
auto stop() -> void;
auto async_stop(std::chrono::milliseconds timeout = std::chrono::milliseconds{5000}) -> boost::asio::awaitable<std::expected<void, modulus::error>>;
auto selected_port() const -> std::uint16_t;
private:
ligo::detail::state_handle state_{};
};
auto client_endpoint_from_config(ligo::endpoint_config const &config) -> std::expected<ligo::tcp::endpoint, modulus::error>;
auto server_endpoint_from_config(ligo::endpoint_config const &config) -> std::expected<ligo::tcp::endpoint, modulus::error>;
auto client_options_from_config(ligo::endpoint_config const &config) -> ligo::tcp::client_options;
auto server_options_from_config(ligo::endpoint_config const &config) -> ligo::tcp::server_options;
auto connect(boost::asio::any_io_executor executor, ligo::tcp::endpoint endpoint, ligo::tcp::client_options options = {}) -> boost::asio::awaitable<std::expected<ligo::tcp::socket_handle, modulus::error>>;
auto connect(boost::asio::any_io_executor executor, ligo::endpoint_config const &config) -> boost::asio::awaitable<std::expected<ligo::tcp::socket_handle, modulus::error>>;
auto connect_tls_configured(boost::asio::any_io_executor executor, ligo::tcp::endpoint endpoint, ligo::tcp::client_options options = {}, ligo::security_config security = {.mode = ligo::security_mode::TLS}) -> boost::asio::awaitable<std::expected<ligo::tcp::tls_socket, modulus::error>>;
auto connect_tls_handshaken(boost::asio::any_io_executor executor, ligo::tcp::endpoint endpoint, ligo::tcp::client_options options = {}, ligo::security_config security = {.mode = ligo::security_mode::TLS}) -> boost::asio::awaitable<std::expected<ligo::tcp::tls_socket, modulus::error>>;
inline tls_socket::released_stream::released_stream(std::shared_ptr<boost::asio::ssl::context> context, boost::asio::ssl::stream<boost::asio::ip::tcp::socket> stream)
: context{std::move(context)}, stream{std::move(stream)} {}
}