#pragma once #include "logging.hpp" #include #include #include #include #include #include #include /*! * \file */ /*! * \brief The Client class */ class Client { public: /*! * \brief OnDoneFT Function type of the function being called when this instance is done operating. */ typedef std::function OnDoneFT; /*! * \brief MessageHandler Function type of the function handling incoming messages. */ typedef std::function)> MessageHandler; protected: /*! * \brief socket The socket connection this instance handles. */ boost::asio::ip::tcp::socket socket; private: std::unique_ptr buffer; OnDoneFT done; std::vector received_bytes_to_vector(size_t read_bytes); void handle_receive_size(MessageHandler message_handler, boost::system::error_code const& ec, size_t read_bytes); void handle_receive_message(MessageHandler message_handler, boost::system::error_code const& ec, size_t read_bytes); std::array prepare_length_prefix(uint32_t length); public: /*! * \brief Client * \param socket An rvalue reference to a socket it will now own and receive from. */ Client(boost::asio::ip::tcp::socket&& socket); ~Client(); /*! * \brief Move constructor for Client. */ Client(Client&&) = default; /*! * \brief Move assignment for Client. */ Client& operator=(Client&&) = default; /*! * \brief async_connect Asynchronously connects to next_host:port and calls on_connect * \param next_host The host to connect to * \param next_port The port to connect to * \param on_connect The callback to call on a succes. */ void async_connect(std::string next_host, std::string next_port, std::function on_connect); inline static void foo() {} /*! * \brief send sends the string prefixed with it's length over the socket. * \param message The string to be sent. */ template void async_send(std::string message, F on_sent) { auto length_buffer = prepare_length_prefix(message.size()); boost::array package = { boost::asio::buffer(length_buffer.data(), length_buffer.size()), boost::asio::buffer(message) }; auto handler = [on_sent](boost::system::error_code const& ec, std::size_t bytes_transferred) { if(ec) { BOOST_LOG_TRIVIAL(fatal) << ec; throw std::runtime_error("unable to send message"); } on_sent(); }; socket.async_send(package, 0, handler); } /*! * \brief receive * \param message_handler The function to call when a message has been received. */ void receive(MessageHandler message_handler) { using namespace boost::asio::placeholders; socket.async_receive( buffer->prepare(4), boost::bind(&Client::handle_receive_size, this, message_handler, error(), bytes_transferred()) ); } /*! * \brief close Closes the underlying socket. */ void close(); /*! * \brief on_done sets the done callback. * \param f The new done callback function. */ void on_done(OnDoneFT f); };