aboutsummaryrefslogtreecommitdiff
path: root/libcmix-network/protobufclient.hpp
diff options
context:
space:
mode:
Diffstat (limited to 'libcmix-network/protobufclient.hpp')
-rw-r--r--libcmix-network/protobufclient.hpp148
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));
+}