Nui
rpc_client.hpp
Go to the documentation of this file.
1 #pragma once
2 
3 #include <nui/frontend/val.hpp>
4 
10 
11 #include <string>
12 #include <cstdint>
13 #include <tuple>
14 
15 namespace Nui
16 {
17  namespace Detail
18  {
19  template <typename ReturnType, typename ArgsTypes, typename IndexSeq>
20  struct FunctionWrapperImpl
21  {};
22 
23  template <typename ArgT>
24  constexpr static auto extractMember(Nui::val const& val) -> decltype(auto)
25  {
26  if constexpr (std::is_same_v<std::decay_t<ArgT>, Nui::val>)
27  return val;
28  else
29  {
30  std::decay_t<ArgT> value;
31  convertFromVal(val, value);
32  return value;
33  }
34  }
35 
36  template <typename ReturnType>
37  struct FunctionWrapperImpl<ReturnType, std::tuple<Nui::val>, std::index_sequence<0>>
38  {
39  template <typename FunctionT>
40  constexpr static auto wrapFunction(FunctionT&& func)
41  {
42  return [func = std::move(func)](Nui::val const& args) mutable {
43  func(args);
44  };
45  }
46  };
47 
48  template <typename ReturnType, typename ArgType>
49  struct FunctionWrapperImpl<ReturnType, std::tuple<ArgType>, std::index_sequence<0>>
50  {
51  template <typename FunctionT>
52  constexpr static auto wrapFunction(FunctionT&& func)
53  {
54  return [func = std::move(func)](Nui::val const& arg) mutable {
55  func(extractMember<ArgType>(arg));
56  };
57  }
58  };
59 
60  template <typename ReturnType, typename... ArgsTypes, std::size_t... Is>
61  struct FunctionWrapperImpl<ReturnType, std::tuple<ArgsTypes...>, std::index_sequence<Is...>>
62  {
63  template <typename FunctionT>
64  constexpr static auto wrapFunction(FunctionT&& func)
65  {
66  return [func = std::move(func)](Nui::val const& args) mutable {
67  func(extractMember<ArgsTypes>(args[Is])...);
68  };
69  }
70  };
71 
72  template <typename ReturnType, typename ArgsTypes>
73  struct FunctionWrapperImpl2
74  {};
75 
76  template <typename ReturnType, typename... ArgsTypes>
77  struct FunctionWrapperImpl2<ReturnType, std::tuple<ArgsTypes...>>
78  : public FunctionWrapperImpl<ReturnType, std::tuple<ArgsTypes...>, std::index_sequence_for<ArgsTypes...>>
79  {};
80 
81  template <typename FunctionT>
82  struct FunctionWrapper
83  : public FunctionWrapperImpl2<
84  FunctionReturnType_t<std::decay_t<FunctionT>>,
85  FunctionArgumentTypes_t<std::decay_t<FunctionT>>>
86  {};
87  }
88 
89  class RpcClient
90  {
91  public:
93  {
94  public:
95  template <typename... Args>
96  auto operator()(Args&&... args) const
97  {
98  using namespace std::string_literals;
99  if (!resolve())
100  {
101  Console::error("Remote callable with name '"s + name_ + "' is undefined");
102  return Nui::val::undefined();
103  }
104  if (backChannel_.empty())
105  return callable_(convertToVal(args)...);
106  else
107  return callable_(convertToVal(backChannel_), convertToVal(args)...);
108  }
109  auto operator()(Nui::val val) const
110  {
111  using namespace std::string_literals;
112  if (!resolve())
113  {
114  Console::error("Remote callable with name '"s + name_ + "' is undefined");
115  return Nui::val::undefined();
116  }
117  if (backChannel_.empty())
118  return callable_(val);
119  else
120  return callable_(convertToVal(backChannel_), val);
121  }
122 
123  bool isValid() const
124  {
125  return resolve();
126  }
127 
128  explicit operator bool() const
129  {
130  return isValid();
131  }
132 
133  RemoteCallable(std::string name)
134  : name_{std::move(name)}
135  , backChannel_{}
136  , callable_{Nui::val::undefined()}
137  , isSet_{false}
138  {}
139 
140  RemoteCallable(std::string name, std::string backChannel)
141  : name_{std::move(name)}
142  , backChannel_{std::move(backChannel)}
143  , callable_{Nui::val::undefined()}
144  , isSet_{false}
145  {}
146 
147  private:
148  bool resolve() const
149  {
150  using namespace std::string_literals;
151  if (isSet_)
152  return true;
153 
154  const auto rpcObject = Nui::val::global("nui_rpc");
155  if (rpcObject.isUndefined())
156  return false;
157 
158  callable_ = Nui::val::global("nui_rpc")["backend"][name_.c_str()];
159  isSet_ = !callable_.isUndefined();
160  return isSet_;
161  }
162 
163  private:
164  std::string name_;
165  std::string backChannel_;
166  mutable Nui::val callable_;
167  mutable bool isSet_;
168  };
169 
176  static auto getRemoteCallable(std::string name)
177  {
178  return RemoteCallable{std::move(name)};
179  }
180 
188  template <typename... ArgsT>
189  static auto call(std::string name, ArgsT&&... args)
190  {
191  return getRemoteCallable(std::move(name))(std::forward<ArgsT>(args)...);
192  }
193 
202  template <typename FunctionT, typename... ArgsT>
203  static auto callWithBackChannel(std::string name, FunctionT&& cb, ArgsT&&... args)
204  {
205  return getRemoteCallableWithBackChannel(std::move(name), std::forward<FunctionT>(cb))(
206  std::forward<ArgsT>(args)...);
207  }
208 
212  template <typename FunctionT>
213  static auto getRemoteCallableWithBackChannel(std::string name, FunctionT&& func)
214  {
215  return RemoteCallable{std::move(name), registerFunctionOnce(std::forward<FunctionT>(func))};
216  }
217 
224  template <typename FunctionT>
225  static std::string registerFunctionOnce(FunctionT&& func)
226  {
227  using namespace std::string_literals;
228  if (Nui::val::global("nui_rpc").isUndefined())
229  {
230  Console::error("rpc was not setup by backend"s);
231  return {};
232  }
233  auto tempId = Nui::val::global("nui_rpc")["tempId"].as<uint32_t>() + 1;
234  Nui::val::global("nui_rpc").set("tempId", tempId);
235  const auto tempIdString = "temp_"s + std::to_string(tempId);
236  Nui::val::global("nui_rpc")["frontend"].set(
237  tempIdString,
238  Nui::bind(
239  [func = Detail::FunctionWrapper<FunctionT>::wrapFunction(std::forward<FunctionT>(func)),
240  tempIdString](Nui::val param) mutable {
241  func(param);
242  Nui::val::global("nui_rpc")["frontend"].delete_(tempIdString);
243  },
244  std::placeholders::_1));
245  return tempIdString;
246  }
247 
254  template <typename FunctionT>
255  static void registerFunction(std::string const& name, FunctionT&& func)
256  {
257  using namespace std::string_literals;
258  if (Nui::val::global("nui_rpc").isUndefined())
259  {
260  Console::error("rpc was not setup by backend"s);
261  return;
262  }
263  Nui::val::global("nui_rpc")["frontend"].set(
264  name.c_str(),
265  Nui::bind(
266  [func = Detail::FunctionWrapper<FunctionT>::wrapFunction(std::forward<FunctionT>(func))](
267  Nui::val param) mutable {
268  func(param);
269  },
270  std::placeholders::_1));
271  }
272 
278  static void unregisterFunction(std::string const& name)
279  {
280  using namespace std::string_literals;
281  if (Nui::val::global("nui_rpc").isUndefined())
282  {
283  Console::error("rpc was not setup by backend"s);
284  return;
285  }
286  Nui::val::global("nui_rpc")["frontend"].delete_(name.c_str());
287  }
288 
289  struct AutoUnregister : public OnDestroy
290  {
292  : OnDestroy{[]() {}}
293  {}
294  AutoUnregister(std::string name)
295  : OnDestroy{[name = std::move(name)]() {
296  unregisterFunction(name);
297  }}
298  {}
299  ~AutoUnregister() = default;
300 
301  AutoUnregister(AutoUnregister const&) = delete;
303  : OnDestroy{std::move(other)}
304  {}
307  {
308  OnDestroy::operator=(std::move(other));
309  return *this;
310  }
311 
312  void reset()
313  {
314  trigger();
315  }
316  };
317 
318  template <typename FunctionT>
319  static AutoUnregister autoRegisterFunction(std::string const& name, FunctionT&& func)
320  {
321  registerFunction(name, std::forward<FunctionT>(func));
322  return AutoUnregister{name};
323  }
324  };
325 }
static void error(Args &&... args)
Definition: console.hpp:18
Definition: on_destroy.hpp:8
OnDestroy & operator=(OnDestroy const &)=delete
Definition: rpc_client.hpp:93
RemoteCallable(std::string name)
Definition: rpc_client.hpp:133
auto operator()(Args &&... args) const
Definition: rpc_client.hpp:96
RemoteCallable(std::string name, std::string backChannel)
Definition: rpc_client.hpp:140
bool isValid() const
Definition: rpc_client.hpp:123
auto operator()(Nui::val val) const
Definition: rpc_client.hpp:109
Definition: rpc_client.hpp:90
static void unregisterFunction(std::string const &name)
Unregister a function.
Definition: rpc_client.hpp:278
static void registerFunction(std::string const &name, FunctionT &&func)
Register a permanent function that is callable from the backend.
Definition: rpc_client.hpp:255
static auto call(std::string name, ArgsT &&... args)
Get a callable remote function and call it immediately.
Definition: rpc_client.hpp:189
static auto getRemoteCallableWithBackChannel(std::string name, FunctionT &&func)
Get a callable remote function and register a temporary callable for a response.
Definition: rpc_client.hpp:213
static AutoUnregister autoRegisterFunction(std::string const &name, FunctionT &&func)
Definition: rpc_client.hpp:319
static std::string registerFunctionOnce(FunctionT &&func)
Registers a single shot function that is removed after it was called.
Definition: rpc_client.hpp:225
static auto getRemoteCallable(std::string name)
Get a callable remote function.
Definition: rpc_client.hpp:176
static auto callWithBackChannel(std::string name, FunctionT &&cb, ArgsT &&... args)
Get a callable remote function and call it immediately with a callback.
Definition: rpc_client.hpp:203
constexpr static auto extractMember(Nui::val const &val) -> decltype(auto)
Definition: rpc_client.hpp:24
Definition: file_dialog.hpp:6
requires(!std::is_union_v< T >) void convertFromValObjImpl(Nui requires(!std::is_union_v< T >) void convertFromVal(Nui requires(!std::is_union_v< T > &&!boost::describe::has_describe_bases< T >::value) void convertFromVal(Nui requires Fundamental< T > void convertFromVal(Nui::val const &val, T &value)
Definition: val_conversion.hpp:262
emscripten::val bind(F &&f, Args &&... args)
Equivalent of std::bind returning a javascript functor.
Definition: functions.hpp:98
void convertToVal(Nui::val &val, T const &obj)
Definition: val_conversion.hpp:109
emscripten::val val
Definition: val.hpp:5
constexpr static auto wrapFunction(FunctionT &&func)
Definition: rpc_client.hpp:52
constexpr static auto wrapFunction(FunctionT &&func)
Definition: rpc_client.hpp:64
constexpr static auto wrapFunction(FunctionT &&func)
Definition: rpc_client.hpp:40
Definition: rpc_hub.hpp:26
Definition: rpc_hub.hpp:75
Definition: rpc_client.hpp:290
AutoUnregister(std::string name)
Definition: rpc_client.hpp:294
void reset()
Definition: rpc_client.hpp:312
AutoUnregister(AutoUnregister const &)=delete
AutoUnregister()
Definition: rpc_client.hpp:291
AutoUnregister(AutoUnregister &&other)
Definition: rpc_client.hpp:302
AutoUnregister & operator=(AutoUnregister const &)=delete
AutoUnregister & operator=(AutoUnregister &&other)
Definition: rpc_client.hpp:306