Nui
Loading...
Searching...
No Matches
rpc_client.hpp
Go to the documentation of this file.
1#pragma once
2
4
5#include <traits/functions.hpp>
10
11#include <string>
12#include <cstdint>
13#include <tuple>
14
15namespace 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::forward<FunctionT>(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::forward<FunctionT>(func)](Nui::val const& arg) mutable {
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::forward<FunctionT>(func)](Nui::val const& args) mutable {
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 typename Traits::FunctionTraits<std::decay_t<FunctionT>>::ReturnType,
85 typename Traits::FunctionTraits<std::decay_t<FunctionT>>::ArgsTuple>
86 {};
87 }
88
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 return callable_(convertToVal(backChannel_), convertToVal(args)...);
107 }
109 {
110 using namespace std::string_literals;
111 if (!resolve())
112 {
113 Console::error("Remote callable with name '"s + name_ + "' is undefined");
114 return Nui::val::undefined();
115 }
116 if (backChannel_.empty())
117 return callable_(val);
118 return callable_(convertToVal(backChannel_), val);
119 }
120
121 bool isValid() const
122 {
123 return resolve();
124 }
125
126 explicit operator bool() const
127 {
128 return isValid();
129 }
130
131 explicit RemoteCallable(std::string name)
132 : name_{std::move(name)}
133 , backChannel_{}
134 , callable_{Nui::val::undefined()}
135 , isSet_{false}
136 {}
137
138 RemoteCallable(std::string name, std::string backChannel)
139 : name_{std::move(name)}
140 , backChannel_{std::move(backChannel)}
141 , callable_{Nui::val::undefined()}
142 , isSet_{false}
143 {}
144
145 private:
146 bool resolve() const
147 {
148 using namespace std::string_literals;
149 if (isSet_)
150 return true;
151
152 const auto rpcObject = Nui::val::global("nui_rpc");
153 if (rpcObject.isUndefined())
154 return false;
155
156 callable_ = Nui::val::global("nui_rpc")["backend"][name_.c_str()];
157 isSet_ = !callable_.isUndefined();
158 return isSet_;
159 }
160
161 private:
162 std::string name_;
163 std::string backChannel_;
164 mutable Nui::val callable_;
165 mutable bool isSet_;
166 };
167
174 static auto getRemoteCallable(std::string name)
175 {
176 return RemoteCallable{std::move(name)};
177 }
178
186 template <typename... ArgsT>
187 static auto call(std::string name, ArgsT&&... args)
188 {
189 return getRemoteCallable(std::move(name))(std::forward<ArgsT>(args)...);
190 }
191
200 template <typename FunctionT, typename... ArgsT>
201 static auto callWithBackChannel(std::string name, FunctionT&& cb, ArgsT&&... args)
202 {
203 return getRemoteCallableWithBackChannel(std::move(name), std::forward<FunctionT>(cb))(
204 std::forward<ArgsT>(args)...);
205 }
206
210 template <typename FunctionT>
211 static auto getRemoteCallableWithBackChannel(std::string name, FunctionT&& func)
212 {
213 return RemoteCallable{std::move(name), registerFunctionOnce(std::forward<FunctionT>(func))};
214 }
215
222 template <typename FunctionT>
223 static std::string registerFunctionOnce(FunctionT&& func)
224 {
225 using namespace std::string_literals;
226 if (Nui::val::global("nui_rpc").isUndefined())
227 {
228 Console::error("rpc was not setup by backend"s);
229 return {};
230 }
231 auto tempId = Nui::val::global("nui_rpc")["tempId"].as<uint32_t>() + 1;
232 Nui::val::global("nui_rpc").set("tempId", tempId);
233 const auto tempIdString = "temp_"s + std::to_string(tempId);
234 Nui::val::global("nui_rpc")["frontend"].set(
235 tempIdString,
236 Nui::bind(
237 [funcInner = Detail::FunctionWrapper<FunctionT>::wrapFunction(std::forward<FunctionT>(func)),
238 tempIdString](Nui::val param) mutable {
239 funcInner(param);
240 Nui::val::global("nui_rpc")["frontend"].delete_(tempIdString);
241 },
242 std::placeholders::_1));
243 return tempIdString;
244 }
245
252 template <typename FunctionT>
253 static void registerFunction(std::string const& name, FunctionT&& func)
254 {
255 using namespace std::string_literals;
256 if (Nui::val::global("nui_rpc").isUndefined())
257 {
258 Console::error("rpc was not setup by backend"s);
259 return;
260 }
261 Nui::val::global("nui_rpc")["frontend"].set(
262 name.c_str(),
263 Nui::bind(
264 [funcInner = Detail::FunctionWrapper<FunctionT>::wrapFunction(std::forward<FunctionT>(func))](
265 Nui::val param) mutable {
266 funcInner(param);
267 },
268 std::placeholders::_1));
269 }
270
276 static void unregisterFunction(std::string const& name)
277 {
278 using namespace std::string_literals;
279 if (Nui::val::global("nui_rpc").isUndefined())
280 {
281 Console::error("rpc was not setup by backend"s);
282 return;
283 }
284 Nui::val::global("nui_rpc")["frontend"].delete_(name.c_str());
285 }
286
287 struct AutoUnregister : public OnDestroy
288 {
290 : OnDestroy{[]() {}}
291 {}
292 explicit AutoUnregister(std::string name)
293 : OnDestroy{[name = std::move(name)]() {
294 unregisterFunction(name);
295 }}
296 {}
297 ~AutoUnregister() = default;
298
301 : OnDestroy{std::move(other)}
302 {}
305 {
306 OnDestroy::operator=(std::move(other));
307 return *this;
308 }
309
310 void reset()
311 {
312 trigger();
313 }
314 };
315
316 template <typename FunctionT>
317 static AutoUnregister autoRegisterFunction(std::string const& name, FunctionT&& func)
318 {
319 registerFunction(name, std::forward<FunctionT>(func));
320 return AutoUnregister{name};
321 }
322 };
323}
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:131
auto operator()(Args &&... args) const
Definition rpc_client.hpp:96
RemoteCallable(std::string name, std::string backChannel)
Definition rpc_client.hpp:138
bool isValid() const
Definition rpc_client.hpp:121
auto operator()(Nui::val val) const
Definition rpc_client.hpp:108
Definition rpc_client.hpp:90
static void unregisterFunction(std::string const &name)
Unregister a function.
Definition rpc_client.hpp:276
static void registerFunction(std::string const &name, FunctionT &&func)
Register a permanent function that is callable from the backend.
Definition rpc_client.hpp:253
static auto call(std::string name, ArgsT &&... args)
Get a callable remote function and call it immediately.
Definition rpc_client.hpp:187
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:211
static AutoUnregister autoRegisterFunction(std::string const &name, FunctionT &&func)
Definition rpc_client.hpp:317
static std::string registerFunctionOnce(FunctionT &&func)
Registers a single shot function that is removed after it was called.
Definition rpc_client.hpp:223
static auto getRemoteCallable(std::string name)
Get a callable remote function.
Definition rpc_client.hpp:174
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:201
static constexpr auto extractJsonMember(nlohmann::json const &json) -> decltype(auto)
Definition rpc_hub.hpp:29
static constexpr auto extractMember(Nui::val const &val) -> decltype(auto)
Definition rpc_client.hpp:24
Definition file_dialog.hpp:6
emscripten::val bind(F &&f, Args &&... args)
Equivalent of std::bind returning a javascript functor.
Definition functions.hpp:98
void convertFromVal(Nui::val const &val, T &obj)
Definition val_conversion.hpp:229
void convertToVal(Nui::val &val, T const &obj)
Definition val_conversion.hpp:109
emscripten::val val
Definition val.hpp:5
static constexpr auto wrapFunction(FunctionT &&func)
Definition rpc_client.hpp:52
static constexpr auto wrapFunction(FunctionT &&func)
Definition rpc_client.hpp:64
static constexpr auto wrapFunction(FunctionT &&func)
Definition rpc_client.hpp:40
Definition rpc_hub.hpp:26
Definition rpc_hub.hpp:75
Definition rpc_client.hpp:288
AutoUnregister & operator=(AutoUnregister &&other) noexcept
Definition rpc_client.hpp:304
AutoUnregister & operator=(AutoUnregister const &)=delete
AutoUnregister(std::string name)
Definition rpc_client.hpp:292
void reset()
Definition rpc_client.hpp:310
AutoUnregister(AutoUnregister &&other) noexcept
Definition rpc_client.hpp:300
AutoUnregister(AutoUnregister const &)=delete
AutoUnregister()
Definition rpc_client.hpp:289