aboutsummaryrefslogtreecommitdiffstatshomepage
path: root/client/transport.hpp
diff options
context:
space:
mode:
Diffstat (limited to '')
-rw-r--r--client/transport.hpp104
1 files changed, 104 insertions, 0 deletions
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 <boost/asio.hpp>
+#include <boost/system/system_error.hpp>
+
+#include <functional>
+#include <memory>
+#include <string>
+
+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<void (const std::string&)>;
+
+ virtual void send_query(const std::string&, const ProcessResult&) = 0;
+};
+
+using TransportPtr = std::unique_ptr<Transport>;
+
+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<const char*>(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<BlockingNetworkTransport>(host, port);
+}
+
+}