From 90bd600c5025ede4db99122f13dfb07b27de46ae Mon Sep 17 00:00:00 2001 From: Egor Tensin Date: Sat, 30 Nov 2019 01:38:08 +0300 Subject: initial commit --- client/transport.hpp | 104 +++++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 104 insertions(+) create mode 100644 client/transport.hpp (limited to 'client/transport.hpp') diff --git a/client/transport.hpp b/client/transport.hpp new file mode 100644 index 0000000..ae56f73 --- /dev/null +++ b/client/transport.hpp @@ -0,0 +1,104 @@ +#pragma once + +#include "error.hpp" + +#include +#include + +#include +#include +#include + +namespace math::client { +namespace transport { + +class Error : public client::Error { +public: + explicit Error(const std::string& msg) + : client::Error{"transport error: " + msg} + { } +}; + +} + +class Transport { +public: + virtual ~Transport() = default; + + using ProcessResult = std::function; + + virtual void send_query(const std::string&, const ProcessResult&) = 0; +}; + +using TransportPtr = std::unique_ptr; + +class NetworkTransport : public Transport { +public: + static constexpr auto DEFAULT_PORT = "18000"; + + NetworkTransport(const std::string& host, const std::string& port) + : m_host{host}, m_port{port} + { } + +protected: + const std::string m_host; + const std::string m_port; +}; + +class BlockingNetworkTransport : public NetworkTransport { +public: + BlockingNetworkTransport(const std::string &host, const std::string& port) + : NetworkTransport{host, port}, m_socket{m_io_context} { + try { + connect(); + } catch (const boost::system::system_error& e) { + throw transport::Error{e.what()}; + } + } + + void send_query(const std::string& query, const ProcessResult& on_reply) override { + std::string reply; + try { + reply = send_query(query); + } catch (const boost::system::system_error& e) { + throw transport::Error{e.what()}; + } + on_reply(reply); + } + +private: + void connect() { + boost::asio::ip::tcp::resolver resolver{m_io_context}; + boost::asio::connect(m_socket, resolver.resolve(m_host, m_port)); + } + + std::string send_query(const std::string& query) { + write(query); + return read_line(); + } + + void write(std::string input) { + input += '\n'; + boost::asio::write(m_socket, boost::asio::const_buffer{input.c_str(), input.size()}); + } + + std::string read_line() { + const auto bytes = boost::asio::read_until(m_socket, m_buffer, '\n'); + const auto data = boost::asio::buffer_cast(m_buffer.data()); + const std::string result{data, bytes - 1}; + m_buffer.consume(bytes); + return result; + } + + boost::asio::io_context m_io_context; + boost::asio::ip::tcp::socket m_socket; + boost::asio::streambuf m_buffer; +}; + +inline TransportPtr make_blocking_network_transport( + const std::string& host, const std::string& port) { + + return std::make_unique(host, port); +} + +} -- cgit v1.2.3