Mercurial > malikania
changeset 147:ba8642323700
Client: use handlers instead
author | David Demelier <markand@malikania.fr> |
---|---|
date | Thu, 26 Oct 2017 12:28:33 +0200 |
parents | 91e57baa2ede |
children | e21942f73ef6 |
files | libclient/malikania/client/connection.cpp libclient/malikania/client/connection.hpp |
diffstat | 2 files changed, 101 insertions(+), 73 deletions(-) [+] |
line wrap: on
line diff
--- a/libclient/malikania/client/connection.cpp Sat Sep 30 13:35:45 2017 +0200 +++ b/libclient/malikania/client/connection.cpp Thu Oct 26 12:28:33 2017 +0200 @@ -16,111 +16,115 @@ * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. */ -#include <functional> - -#include "client.hpp" #include "connection.hpp" namespace mlk { namespace client { +/* + * connection::connection + * ------------------------------------------------------------------ + */ connection::connection(boost::asio::io_service& service) : service_(service) , context_(boost::asio::ssl::context::sslv23) + , resolver_(service_) , socket_(service_, context_) { } -void connection::handshake(client& client) +/* + * connection::handshake + * ------------------------------------------------------------------ + */ +void connection::handshake(connect_t handler) { -#if 0 - socket_.async_handshake(boost::asio::ssl::stream_base::client, [this, &client] (auto code) { - if (code) { - client.handle_error(code); - } else { - client.handle_connect(code); - } - }); -#endif + socket_.async_handshake(boost::asio::ssl::stream_base::client, std::move(handler)); } -void connection::do_connect(client& client, std::string host, std::uint16_t port) +/* + * connection::flush + * ------------------------------------------------------------------ + */ +void connection::flush() { -#if 0 + if (output_.empty()) + return; + + auto buffer = boost::asio::buffer(std::get<1>(output_[0])); + + boost::asio::async_write(socket_, buffer, [this] (auto code, auto xfer) { + auto& handler = std::get<2>(output_[0]); + + if (handler) + handler(std::move(code), std::get<0>(output_[0])); + + if (!code && xfer != 0) + flush(); + }); +} + +/* + * connection::connect + * ------------------------------------------------------------------ + */ +void connection::connect(const std::string& host, std::uint16_t port, connect_t handler) +{ using tcp = boost::asio::ip::tcp; - auto resolver = std::make_shared<tcp::resolver>(service_); auto str = std::to_string(port); - resolver->async_resolve(tcp::resolver::query(host, str), [this, resolver, &client] (auto code, auto ep) { - if (code) { - client.handle_error(code); - } else { - boost::asio::async_connect(socket_.lowest_layer(), ep, [this, &client] (auto code, auto) { - if (code) { - client.handle_error(code); - } else { - this->handshake(client); - } + resolver_.async_resolve(tcp::resolver::query(host, str), [this, handler] (auto code, auto ep) { + if (code) + handler(std::move(code)); + else { + boost::asio::async_connect(socket_.lowest_layer(), ep, [this, handler] (auto code, auto) { + if (code) + handler(std::move(code)); + else + handshake(std::move(handler)); }); } }); -#endif } -void connection::flush(client& client) +/* + * connection::send + * ------------------------------------------------------------------ + */ +void connection::send(nlohmann::json message, send_t handler) { -#if 0 - auto buffer = boost::asio::buffer(output_.front().data(), output_.front().length()); - - boost::asio::async_write(socket_, buffer, [this, &client] (auto code, auto xfer) { - output_.pop_front(); - - if (xfer == 0) { - client.handle_disconnect(); - } else if (code) { - client.handle_error(code); - } else if (!output_.empty()) { - this->flush(client); - } - }); -#endif -} - -void connection::do_send(client& client, nlohmann::json message) -{ -#if 0 assert(message.is_object()); auto in_progress = !output_.empty(); - - output_.push_back(message.dump() + "\r\n\r\n"); + auto str = message.dump() + "\r\n\r\n"; - if (!in_progress) { - flush(client); - } -#endif + output_.push_back(std::make_tuple(std::move(message), std::move(str), std::move(handler))); + + if (!in_progress) + flush(); } -void connection::do_read(client& client) +/* + * connection::recv + * ------------------------------------------------------------------ + */ +void connection::read(recv_t handler) { -#if 0 #if !defined(NDEBUG) assert(!is_reading); is_reading = true; #endif - boost::asio::async_read_until(socket_, input_, "\r\n\r\n", [this, &client] (auto code, auto xfer) { + boost::asio::async_read_until(socket_, input_, "\r\n\r\n", [this, handler] (auto code, auto xfer) { #if !defined(NDEBUG) is_reading = false; #endif - if (xfer == 0) { - client.handle_disconnect(); - } else if (code) { - client.handle_error(code); - } else { + if (code || xfer == 0) + handler(std::move(code), nullptr); + else { std::string command{ boost::asio::buffers_begin(input_.data()), boost::asio::buffers_begin(input_.data()) + xfer - /* \r\n\r\n */ 4 @@ -129,13 +133,12 @@ input_.consume(xfer); try { - client.handle_read(std::move(code), nlohmann::json::parse(command)); - } catch (const std::exception& ex) { - std::cerr << "connection::do_read: " << ex.what() << std::endl; + handler(std::move(code), nlohmann::json::parse(command)); + } catch (const std::exception&) { + // TODO: add custom error code. } } }); -#endif } } // !client
--- a/libclient/malikania/client/connection.hpp Sat Sep 30 13:35:45 2017 +0200 +++ b/libclient/malikania/client/connection.hpp Thu Oct 26 12:28:33 2017 +0200 @@ -25,6 +25,8 @@ */ #include <deque> +#include <functional> +#include <utility> #include <boost/asio.hpp> #include <boost/asio/ssl.hpp> @@ -42,19 +44,40 @@ */ class connection { public: + /** + * Connection handler. + */ + using connect_t = std::function<void (boost::system::error_code)>; + + /** + * Receive handler. + */ + using recv_t = std::function<void (boost::system::error_code, nlohmann::json)>; + + /** + * Send handler. + */ + using send_t = std::function<void (boost::system::error_code, nlohmann::json)>; + private: + /** + * Wrap an handler, the JSON message and its dump string. + */ + using output_item_t = std::tuple<nlohmann::json, std::string, send_t>; + boost::asio::io_service& service_; boost::asio::ssl::context context_; + boost::asio::ip::tcp::resolver resolver_; boost::asio::ssl::stream<boost::asio::ip::tcp::socket> socket_; boost::asio::streambuf input_; - std::deque<std::string> output_; + std::deque<output_item_t> output_; #if !defined(NDEBUG) bool is_reading{false}; #endif - void handshake(client&); - void flush(client&); + void handshake(connect_t); + void flush(); public: /** @@ -70,23 +93,25 @@ * \param port the port number * \param handler the handler */ - virtual void do_connect(client& client, std::string host, std::uint16_t port); + virtual void connect(const std::string& host, std::uint16_t port, connect_t handler); /** * Send the given message to the server. * * \pre message.is_object() - * \pre handler != nullptr * \param message the message object + * \param handler the handler (may be null) */ - virtual void do_send(client& client, nlohmann::json message); + virtual void send(nlohmann::json message, send_t handler); /** * Request for a read operation. * * \pre no reading operation must be pending + * \pre handler != nullptr + * \param handler the handler */ - virtual void do_read(client& client); + virtual void read(recv_t handler); }; } // !client