summaryrefslogtreecommitdiff
path: root/modules/remote
diff options
context:
space:
mode:
authorClaudius 'keldu' Holeksa <mail@keldu.de>2024-07-15 15:29:12 +0200
committerClaudius 'keldu' Holeksa <mail@keldu.de>2024-07-15 15:29:12 +0200
commit816760c8480e8e76c7f4021a845161eb697e215c (patch)
treef18ef0578dab81e1f00798e9c897210236340b90 /modules/remote
parent5d92d62caa68473e67022debe45bf8038c6c3b60 (diff)
Moving remote definitions from codec to remote module
Diffstat (limited to 'modules/remote')
-rw-r--r--modules/remote/c++/remote.hpp116
-rw-r--r--modules/remote/c++/remote_loopback.hpp99
-rw-r--r--modules/remote/c++/remote_loopback_base.hpp7
-rw-r--r--modules/remote/c++/transfer.hpp21
-rw-r--r--modules/remote/c++/transfer_loopback.hpp152
5 files changed, 395 insertions, 0 deletions
diff --git a/modules/remote/c++/remote.hpp b/modules/remote/c++/remote.hpp
new file mode 100644
index 0000000..5803154
--- /dev/null
+++ b/modules/remote/c++/remote.hpp
@@ -0,0 +1,116 @@
+#pragma once
+
+#include <forstio/id.hpp>
+#include <forstio/async/async.hpp>
+
+#include "data.hpp"
+#include "interface.hpp"
+
+#include <variant>
+
+namespace saw {
+/**
+ * This class acts as a helper for rpc calls and representing data on the remote.
+ */
+template<typename T, typename Encoding, typename Storage>
+class data_or_id {
+private:
+ /**
+ * Variant representing the either id or data class.
+ */
+ std::variant<id<T>, data<T,Encoding, Storage>> doi_;
+public:
+ /**
+ * Constructor for instantiating.
+ */
+ data_or_id(const id<T>& val):
+ doi_{val}
+ {}
+
+ /**
+ * Constructor for instantiating.
+ */
+ data_or_id(data<T,Encoding, Storage> val):
+ doi_{std::move(val)}
+ {}
+
+ /**
+ * Check if this class holds an id.
+ */
+ bool is_id() const {
+ return std::holds_alternative<id<T>>(doi_);
+ }
+
+ /**
+ * Check if this class holds data.
+ */
+ bool is_data() const {
+ return std::holds_alternative<data<T,Encoding,Storage>>(doi_);
+ }
+
+ /**
+ * Returns the id.
+ */
+ id<T> get_id() const {
+ return std::get<id<T>>(doi_);
+ }
+
+ /**
+ * Return a data reference.
+ */
+ data<T,Encoding, Storage>& get_data(){
+ return std::get<data<T,Encoding, Storage>>(doi_);
+ }
+
+ /**
+ * Return a data reference.
+ */
+ const data<T,Encoding,Storage>& get_data() const {
+ return std::get<data<T,Encoding,Storage>>(doi_);
+ }
+};
+
+
+/**
+ * Representing data on the remote
+ */
+template<typename T, typename Encoding, typename Storage, typename Remote>
+class remote_data;
+
+template<typename Iface, typename Encoding, typename Storage, typename Remote>
+class rpc_client;
+
+/**
+ * Implementation of a remote server on the backend
+ */
+template<typename Iface, typename Encoding, typename Storage, typename Remote>
+class rpc_server {
+private:
+ interface<Iface, Encoding, Storage> iface_;
+public:
+ rpc_server(interface<Iface, Encoding, Storage> iface):
+ iface_{std::move(iface)}
+ {}
+};
+
+/**
+ * Representation of a remote.
+ * Partially similar to a network address
+ */
+template<typename Remote>
+class remote_address {
+ static_assert(always_false<Remote>, "Type of remote not supported");
+
+ /**
+ *
+ */
+};
+
+/**
+ * Reference Backend structure
+ */
+template<typename Remote>
+class remote {
+ static_assert(always_false<Remote>, "Type of backend not supported");
+};
+}
diff --git a/modules/remote/c++/remote_loopback.hpp b/modules/remote/c++/remote_loopback.hpp
new file mode 100644
index 0000000..2949243
--- /dev/null
+++ b/modules/remote/c++/remote_loopback.hpp
@@ -0,0 +1,99 @@
+#pragma once
+
+#include <variant>
+
+#include "interface.hpp"
+#include "remote.hpp"
+#include "transfer_loopback.hpp"
+
+namespace saw {
+
+template<typename T, typename Encoding, typename Storage>
+class remote_data<T, Encoding, Storage, rmt::Loopback> {
+private:
+ id<T> id_;
+public:
+ remote_data(const id<T>& id):
+ id_{id}
+ {}
+
+ /**
+ * Wait until data arrives
+ */
+ error_or<data<T, Encoding, Storage>> wait(wait_scope& wait);
+
+ /**
+ * Asynchronously wait for a result
+ */
+ conveyor<data<T, Encoding, Storage>> on_receive();
+};
+
+/**
+ * Client RPC reference structure
+ */
+template<typename Iface, typename Encoding, typename Storage>
+class rpc_client<Iface, Encoding, Storage, rmt::Loopback> {
+ /**
+ * request the data from the remote
+ */
+ template<typename IdT>
+ remote_data<IdT, Encoding, Storage, rmt::Loopback> request_data(id<IdT> data);
+
+ /** @todo
+ * Determine type based on Name
+ */
+ /*
+ template<string_literal Name>
+ error_or<
+ id<
+ typename schema_member_type<Name, Iface>::type
+ >
+ > call(data_or_id<Input> inp);
+ */
+};
+
+template<>
+class remote_address<rmt::Loopback> {
+};
+
+template<typename Iface, typename Encode, typename Storage>
+class rpc_server<Iface, Encode, Storage, rmt::Loopback> {
+public:
+ using InterfaceT = interface<Iface, Encode, Storage>;
+private:
+ const remote_address<rmt::Loopback>* addr_;
+ InterfaceT iface_;
+public:
+ rpc_server(const remote_address<rmt::Loopback>& addr__, InterfaceT iface__):
+ addr_{&addr__},
+ iface_{std::move(iface__)}
+ {}
+
+ // error_or<id<>>
+};
+
+template<>
+class remote<rmt::Loopback> {
+public:
+ /**
+ * Resolves an address for the remote
+ */
+ error_or<own<remote_address<rmt::Loopback>>> parse_address(){
+ return heap<remote_address<rmt::Loopback>>();
+ }
+
+ /**
+ * Connect to a remote
+ */
+ template<typename Iface, typename Encode, typename Storage>
+ conveyor<rpc_client<Iface, Encode, Storage, rmt::Loopback>> connect(const remote_address<rmt::Loopback>& addr);
+
+ /**
+ * Start listening
+ */
+ template<typename Iface, typename Encode, typename Storage>
+ rpc_server<Iface, Encode, Storage, rmt::Loopback> listen(const remote_address<rmt::Loopback>& addr, typename rpc_server<Iface,Encode,Storage,rmt::Loopback>::InterfaceT iface){
+ return {addr, std::move(iface)};
+ }
+};
+}
diff --git a/modules/remote/c++/remote_loopback_base.hpp b/modules/remote/c++/remote_loopback_base.hpp
new file mode 100644
index 0000000..823c516
--- /dev/null
+++ b/modules/remote/c++/remote_loopback_base.hpp
@@ -0,0 +1,7 @@
+#pragma once
+
+namespace saw {
+namespace rmt {
+struct Loopback {};
+}
+}
diff --git a/modules/remote/c++/transfer.hpp b/modules/remote/c++/transfer.hpp
new file mode 100644
index 0000000..2fdd0b9
--- /dev/null
+++ b/modules/remote/c++/transfer.hpp
@@ -0,0 +1,21 @@
+#pragma once
+
+namespace saw {
+template<typename Schema, typename Encoding, typename Remote>
+class data_server;
+
+template<typename Schema, typename Encoding, typename Remote>
+class data_client;
+
+namespace impl {
+template<typename Encoding, typename Storage, typename T>
+struct data_server_redux {
+ using type = std::tuple<>;
+};
+
+template<typename Encoding, typename Storage, typename... Schema>
+struct data_server_redux<Encoding, Storage, tmpl_group<Schema...>> {
+ using type = std::tuple<std::unordered_map<uint64_t, data<Schema, Encoding, Storage>>...>;
+};
+}
+}
diff --git a/modules/remote/c++/transfer_loopback.hpp b/modules/remote/c++/transfer_loopback.hpp
new file mode 100644
index 0000000..6c81c9c
--- /dev/null
+++ b/modules/remote/c++/transfer_loopback.hpp
@@ -0,0 +1,152 @@
+#pragma once
+
+#include <forstio/reduce_templates.hpp>
+
+#include "transfer.hpp"
+
+namespace saw {
+namespace rmt {
+struct Loopback {};
+}
+
+template<typename... Schema, typename Encoding>
+class data_server<tmpl_group<Schema...>, Encoding, rmt::Loopback> {
+private:
+ typename impl::data_server_redux<Encoding, storage::Default, typename tmpl_reduce<tmpl_group<Schema...>>::type>::type values_;
+public:
+ /**
+ * Get data from client
+ */
+ template<typename Sch>
+ error_or<void> send(const data<Sch, Encoding, storage::Default>& dat, id<Sch> store_id){
+ auto& vals = std::get<std::unordered_map<uint64_t, data<Sch,Encoding>>>(values_);
+
+ try {
+ auto insert_res = vals.emplace(std::make_pair(store_id.get_value(), std::move(dat)));
+ if(!insert_res.second){
+ return make_error<err::already_exists>();
+ }
+ }catch(std::exception& ){
+ return make_error<err::out_of_memory>();
+ }
+ return void_t{};
+ }
+
+ template<typename Sch>
+ error_or<data<Sch, Encoding, storage::Default>> receive(id<Sch> store_id){
+ auto& vals = std::get<std::unordered_map<uint64_t, data<Sch,Encoding>>>(values_);
+
+ auto find_res = vals.find(store_id.get_value());
+ if(find_res == vals.end()){
+ return make_error<err::not_found>();
+ }
+
+ auto& dat = find_res->second;
+ return dat;
+ }
+
+ template<typename Sch>
+ error_or<void> erase(id<Sch> store_id){
+ auto& vals = std::get<std::unordered_map<uint64_t, data<Sch,Encoding>>>(values_);
+ auto erase_op = vals.erase(store_id.get_value());
+ if(erase_op == 0u){
+ return make_error<err::not_found>();
+ }
+ return void_t{};
+ }
+
+ template<typename Sch>
+ error_or<data<Sch, Encoding, storage::Default>*> find(id<Sch> store_id){
+ auto& vals = std::get<std::unordered_map<uint64_t, data<Sch,Encoding>>>(values_);
+ auto find_res = vals.find(store_id.get_value());
+ if(find_res == vals.end()){
+ return make_error<err::not_found>();
+ }
+
+ auto& dat = find_res->second;
+ return &dat;
+ }
+};
+
+/**
+ * Client for transporting data to remote and receiving data back
+ */
+template<typename... Schema, typename Encoding>
+class data_client<tmpl_group<Schema...>, Encoding, rmt::Loopback> {
+private:
+ /**
+ * Corresponding server for this client
+ */
+ data_server<tmpl_group<Schema...>, Encoding, rmt::Loopback>* srv_;
+
+ /**
+ * The next id for identifying issues on the remote side.
+ */
+ uint64_t next_id_;
+public:
+ /**
+ * Main constructor
+ */
+ data_client(data_server<tmpl_group<Schema...>, Encoding, rmt::Loopback>& srv__):
+ srv_{&srv__},
+ next_id_{0u}
+ {}
+
+ /**
+ * Send data to the remote.
+ */
+ template<typename Sch>
+ error_or<id<Sch>> send(const data<Sch, Encoding, storage::Default>& dat){
+ id<Sch> dat_id{next_id_};
+ auto eov = srv_->send(dat, dat_id);
+ if(eov.is_error()){
+ auto& err = eov.get_error();
+ return std::move(err);
+ }
+
+ ++next_id_;
+ return dat_id;
+ }
+
+ /**
+ * Receive data
+ */
+ template<typename Sch>
+ conveyor<data<Sch, Encoding, storage::Default>> receive(id<Sch> dat_id){
+ auto eov = srv_->receive(dat_id);
+ if(eov.is_error()){
+ auto& err = eov.get_error();
+ return std::move(err);
+ }
+
+ auto& val = eov.get_value();
+ return std::move(val);
+ }
+
+ /**
+ * Erase data
+ */
+ template<typename Sch>
+ error_or<void> erase(id<Sch> dat_id){
+ return srv_->erase(dat_id);
+ }
+
+ /**
+ * An exception for the Loopback backend. Here we can safely use find from
+ * the client side.
+ */
+ template<typename Sch>
+ error_or<data<Sch, Encoding>*> find(id<Sch> dat_id){
+ auto eov = srv_->find(dat_id);
+ if(eov.is_error()){
+ auto& err = eov.get_error();
+ return std::move(err);
+ }
+
+ auto val = eov.get_value();
+ return val;
+ }
+
+};
+
+}