Nui
rpc_hub.hpp
Go to the documentation of this file.
1 #pragma once
2 
3 #include <nui/window.hpp>
8 #include <nlohmann/json.hpp>
9 #include <fmt/format.h>
10 
11 #include <memory>
12 #include <string>
13 #include <tuple>
14 #include <utility>
15 #include <thread>
16 #include <functional>
17 #include <unordered_map>
18 #include <mutex>
19 
20 namespace Nui
21 {
22  namespace Detail
23  {
24  template <typename ReturnType, typename ArgsTypes, typename IndexSeq>
26  {};
27 
28  template <typename ArgT>
29  constexpr static auto extractJsonMember(nlohmann::json const& json) -> decltype(auto)
30  {
31  if constexpr (std::is_same_v<std::decay_t<ArgT>, nlohmann::json>)
32  return json;
33  else
34  return json.get<std::decay_t<ArgT>>();
35  }
36 
37  template <typename ReturnType>
38  struct FunctionWrapperImpl<ReturnType, std::tuple<nlohmann::json>, std::index_sequence<0>>
39  {
40  template <typename FunctionT>
41  constexpr static auto wrapFunction(FunctionT&& func)
42  {
43  return [func = std::move(func)](nlohmann::json const& args) mutable {
44  func(args);
45  };
46  }
47  };
48 
49  template <typename ReturnType, typename... ArgsTypes, std::size_t... Is>
50  struct FunctionWrapperImpl<ReturnType, std::tuple<ArgsTypes...>, std::index_sequence<Is...>>
51  {
52  template <typename FunctionT>
53  constexpr static auto wrapFunction(FunctionT&& func)
54  {
55  return [func = std::move(func)](nlohmann::json const& args) mutable {
56  func(extractJsonMember<ArgsTypes>(args[Is])...);
57  };
58  }
59  };
60 
61  template <typename ReturnType, typename ArgsTypes>
63  {};
64 
65  template <typename ReturnType, typename... ArgsTypes>
66  struct FunctionWrapperImpl2<ReturnType, std::tuple<ArgsTypes...>>
67  : public FunctionWrapperImpl<ReturnType, std::tuple<ArgsTypes...>, std::index_sequence_for<ArgsTypes...>>
68  {};
69 
70  template <typename FunctionT>
72  : public FunctionWrapperImpl2<
73  FunctionReturnType_t<std::decay_t<FunctionT>>,
74  FunctionArgumentTypes_t<std::decay_t<FunctionT>>>
75  {};
76  }
77 
78  class RpcHub
79  {
80  public:
82  ~RpcHub() = default;
83  RpcHub(const RpcHub&) = delete;
84  RpcHub& operator=(const RpcHub&) = delete;
85  RpcHub(RpcHub&&) = delete;
86  RpcHub& operator=(RpcHub&&) = delete;
87 
88  constexpr static char const* remoteCallScript = R"(
89  (function() {{
90  if (globalThis.nui_rpc.frontend.hasOwnProperty("{0}")) {{
91  globalThis.nui_rpc.frontend["{0}"]({1});
92  return;
93  }}
94 
95  globalThis.nui_rpc.errors = globalThis.nui_rpc.errors || [];
96  globalThis.nui_rpc.errors.push("Function {0} does not exist.");
97  if (globalThis.nui_rpc.errors.length > 100) {{
98  globalThis.nui_rpc.errors.shift();
99  }}
100  }})();
101  )";
102 
103  struct AutoUnregister : public OnDestroy
104  {
105  AutoUnregister(RpcHub const* hub, std::string name)
106  : OnDestroy{[hub, name = std::move(name)]() {
107  hub->unregisterFunction(name);
108  }}
109  {}
110  };
111 
112  template <typename T>
113  AutoUnregister autoRegisterFunction(std::string const& name, T&& func) const
114  {
115  registerFunction(name, std::forward<T>(func));
116  return AutoUnregister{this, name};
117  }
118 
119  template <typename T>
120  void registerFunction(std::string const& name, T&& func) const
121  {
122  // window is threadsafe
123  window_->bind(name, Detail::FunctionWrapper<T>::wrapFunction(std::forward<T>(func)));
124  }
125  void unregisterFunction(std::string const& name) const
126  {
127  // window is threadsafe
128  window_->unbind(name);
129  }
130 
136  Window& window() const
137  {
138  return *window_;
139  }
140 
148  template <typename... Args>
149  void callRemote(std::string const& name, Args&&... args) const
150  {
151  callRemoteImpl(name, nlohmann::json{std::forward<Args>(args)...});
152  }
153  template <typename Arg>
154  void callRemote(std::string const& name, Arg&& arg) const
155  {
156  nlohmann::json j = arg;
157  callRemoteImpl(name, std::move(j));
158  }
159  void callRemote(std::string const& name, nlohmann::json const& json) const
160  {
161  callRemoteImpl(name, json);
162  }
163  void callRemote(std::string const& name, nlohmann::json&& json) const
164  {
165  callRemoteImpl(name, json);
166  }
167  void callRemote(std::string const& name) const
168  {
169  callRemoteImpl(name);
170  }
171 
172  // alias for callRemote
173  template <typename... Args>
174  void call(std::string const& name, Args&&... args) const
175  {
176  callRemote(name, std::forward<Args>(args)...);
177  }
178 
182  void enableFileDialogs() const;
183 
187  void enableFile();
188 
192  void enableWindowFunctions() const;
193 
197  void enableFetch() const;
198 
202  void enableThrottle();
203 
207  void enableTimer();
208 
212  void enableScreen();
213 
217  void enableEnvironmentVariables();
218 
222  void enableAll();
223 
224  template <typename ManagerT>
225  void* accessStateStore(std::string const& id)
226  {
227  std::scoped_lock lock{guard_};
228  auto iter = stateStores_.find(id);
229  if (iter == stateStores_.end())
230  {
231  return stateStores_
232  .insert(
233  {id,
234  std::unique_ptr<void, std::function<void(void*)>>{
235  ManagerT::create(),
236  [](void* ptr) {
237  ManagerT::destroy(ptr);
238  }}})
239  .first->second.get();
240  }
241  else
242  {
243  return iter->second.get();
244  }
245  }
246 
247  private:
248  void callRemoteImpl(std::string const& name, nlohmann::json const& json) const
249  {
250  // window is threadsafe.
251  window_->eval(fmt::format(remoteCallScript, name, json.dump()));
252  }
253  void callRemoteImpl(std::string const& name) const
254  {
255  // window is threadsafe.
256  window_->eval(fmt::format(remoteCallScript, name, "undefined"));
257  }
258 
259  private:
260  std::recursive_mutex guard_;
261  Window* window_;
262  std::unordered_map<std::string, std::unique_ptr<void, std::function<void(void*)>>> stateStores_;
263  };
264 }
Definition: on_destroy.hpp:8
Definition: rpc_hub.hpp:79
~RpcHub()=default
RpcHub(const RpcHub &)=delete
void callRemote(std::string const &name) const
Definition: rpc_hub.hpp:167
void callRemote(std::string const &name, Args &&... args) const
For technical reasons these cannot return a value currently.
Definition: rpc_hub.hpp:149
void callRemote(std::string const &name, nlohmann::json &&json) const
Definition: rpc_hub.hpp:163
RpcHub & operator=(const RpcHub &)=delete
void callRemote(std::string const &name, nlohmann::json const &json) const
Definition: rpc_hub.hpp:159
void callRemote(std::string const &name, Arg &&arg) const
Definition: rpc_hub.hpp:154
void * accessStateStore(std::string const &id)
Definition: rpc_hub.hpp:225
constexpr static char const * remoteCallScript
Definition: rpc_hub.hpp:88
RpcHub & operator=(RpcHub &&)=delete
void registerFunction(std::string const &name, T &&func) const
Definition: rpc_hub.hpp:120
void call(std::string const &name, Args &&... args) const
Definition: rpc_hub.hpp:174
AutoUnregister autoRegisterFunction(std::string const &name, T &&func) const
Definition: rpc_hub.hpp:113
RpcHub(RpcHub &&)=delete
void unregisterFunction(std::string const &name) const
Definition: rpc_hub.hpp:125
RpcHub(Window &window)
Definition: rpc_hub.cpp:14
Window & window() const
Returns the attached window.
Definition: rpc_hub.hpp:136
This class encapsulates the webview.
Definition: window.hpp:133
constexpr static auto extractJsonMember(nlohmann::json const &json) -> decltype(auto)
Definition: rpc_hub.hpp:29
Definition: file_dialog.hpp:6
Definition: rpc_hub.hpp:63
constexpr static auto wrapFunction(FunctionT &&func)
Definition: rpc_hub.hpp:41
Definition: rpc_hub.hpp:26
Definition: rpc_hub.hpp:75
Definition: rpc_hub.hpp:104
AutoUnregister(RpcHub const *hub, std::string name)
Definition: rpc_hub.hpp:105