diff options
Diffstat (limited to 'libcmix-network/protobufclient.hpp')
| -rw-r--r-- | libcmix-network/protobufclient.hpp | 148 |
1 files changed, 148 insertions, 0 deletions
diff --git a/libcmix-network/protobufclient.hpp b/libcmix-network/protobufclient.hpp new file mode 100644 index 0000000..1c97cfa --- /dev/null +++ b/libcmix-network/protobufclient.hpp @@ -0,0 +1,148 @@ +#pragma once + +#include "client.hpp" + +#include "logging.hpp" +#include "cmix.pb.h" + +#include <type_traits> + +struct Send; +struct Receive; +struct SendReceive; + +template<typename T> +class ProtobufClient; + +typedef ProtobufClient<Receive> Receiver; +typedef ProtobufClient<Send> Sender; +typedef ProtobufClient<SendReceive> SenderReceiver; + +template<typename T = SendReceive> +class ProtobufClient +{ + Client client; + + + #define MESSAGE_SETTER(TYPE, NAME) \ + void message_setter(cmix_proto::CMixMessage& m, cmix_proto::TYPE const& v) { \ + *m.mutable_##NAME() = v; \ + } \ + + MESSAGE_SETTER(Initialization, initialization) + MESSAGE_SETTER(ImANode, imanode) + MESSAGE_SETTER(ImAClient, imaclient) + MESSAGE_SETTER(Bye, bye) + MESSAGE_SETTER(KeyExchange, keyexchange) + + #undef MESSAGE_SETTER + +public: + /*! + * \brief ProtobufClient + * \param socket An rvalue reference to a socket it will now own and receive from. + */ + ProtobufClient(boost::asio::ip::tcp::socket&& socket) + : client(std::move(socket)) + {} + + /*! + * \brief Move constructor for ProtobufClient. + */ + ProtobufClient(ProtobufClient&& c) = default; + + ProtobufClient(Client&& c) + : client(std::move(c)) + {} + + template<typename Ty> + ProtobufClient(ProtobufClient<Ty>&& r) + : client(std::move(r.client)) + {} + + /*! + * \brief Move assignment for ProtobufClient. + */ + ProtobufClient& operator=(ProtobufClient&&) = 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. + */ + template<typename F> + void async_connect(std::string next_host, std::string next_port, F on_connect) { + client.async_connect(next_host, next_port, on_connect); + } + + + template<typename V, typename F, typename std::enable_if<(sizeof(V), std::is_same<T, Send>::value || std::is_same<T, SendReceive>::value), void>::type* = nullptr> + void async_send(V value, F on_sent) { + cmix_proto::CMixMessage m; + message_setter(m, value); + client.async_send(m.SerializeAsString(), on_sent); + } + + /*! + * \brief send sends the string prefixed with it's length over the socket asynchronously. + * \param message The string to be sent. + */ + template<typename V, typename std::enable_if<(sizeof(V), std::is_same<T, Send>::value || std::is_same<T, SendReceive>::value)>::type* = nullptr> + void async_send(V value) { + cmix_proto::CMixMessage m; + message_setter(m, value); + client.async_send(m.SerializeAsString(), []{}); + } + + /*! + * \brief receive + * \param message_handler The function to call when a message has been received. + */ + template <typename F, typename std::enable_if<(sizeof(F), std::is_same<T, Receive>::value || std::is_same<T, SendReceive>::value)>::type* = nullptr> + void receive(F message_handler) { + auto f = [message_handler](std::vector<uint8_t> const& buffer) { + cmix_proto::CMixMessage message; + if(!message.ParseFromArray(buffer.data(), buffer.size())) { + BOOST_LOG_TRIVIAL(error) << "Received something which was not a CMixMessage"; + throw std::runtime_error("Network communication was disrupted in a unrecoverable way."); + } + message_handler(message); + }; + client.receive(f); + } + + /*! + * \brief close Closes the underlying socket. + */ + void close(){ + client.close(); + } + + /*! + * \brief on_done sets the done callback. + * \param f The new done callback function. + */ + template <typename F> + void on_done(F f) { + client.on_done(f); + } + + friend Receiver make_receiver(Receiver&& r); + + friend SenderReceiver make_sender_receiver(SenderReceiver&& r); + friend SenderReceiver make_sender_receiver(Receiver&& r); +}; + +inline Receiver make_receiver(Receiver&& r) { + return Receiver(std::move(r.client)); +} + +inline SenderReceiver make_sender_receiver(SenderReceiver&& r) { + return SenderReceiver(std::move(r.client)); +} + +inline SenderReceiver make_sender_receiver(Receiver&& r) +{ + return SenderReceiver(std::move(r.client)); +} |
