130 lines
6.3 KiB
C++
Executable File
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)} {}
|
|
|
|
}
|