Nui
Loading...
Searching...
No Matches
rpc_hub.hpp
Go to the documentation of this file.
1#pragma once
2
3#include <nui/window.hpp>
7
8#include <traits/functions.hpp>
9#include <nlohmann/json.hpp>
10#include <fmt/format.h>
11
12#include <memory>
13#include <string>
14#include <tuple>
15#include <utility>
16#include <functional>
17#include <unordered_map>
18#include <mutex>
19
20namespace 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::forward<FunctionT>(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::forward<FunctionT>(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 typename Traits::FunctionTraits<std::decay_t<FunctionT>>::ReturnType,
74 typename Traits::FunctionTraits<std::decay_t<FunctionT>>::ArgsTuple>
75 {};
76 }
77
78 class RpcHub
79 {
80 public:
81 explicit RpcHub(Window& window);
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 json = std::forward<Arg>(arg);
157 callRemoteImpl(name, json);
158 }
159 void callRemote(std::string const& name, nlohmann::json const& json) const
160 {
161 callRemoteImpl(name, json);
162 }
163 // I dont want to remove this overload in case there are some rvalue nlohmanns?
164 // NOLINTNEXTLINE(cppcoreguidelines-rvalue-reference-param-not-moved)
165 void callRemote(std::string const& name, nlohmann::json&& json) const
166 {
167 callRemoteImpl(name, json);
168 }
169 void callRemote(std::string const& name) const
170 {
171 callRemoteImpl(name);
172 }
173
174 // alias for callRemote
175 template <typename... Args>
176 void call(std::string const& name, Args&&... args) const
177 {
178 callRemote(name, std::forward<Args>(args)...);
179 }
180
184 void enableFileDialogs() const;
185
189 void enableFile();
190
194 void enableWindowFunctions() const;
195
199 void enableFetch() const;
200
204 void enableThrottle();
205
209 void enableTimer();
210
214 void enableScreen();
215
219 void enableEnvironmentVariables();
220
224 void enableAll();
225
226 template <typename ManagerT>
227 void* accessStateStore(std::string const& id)
228 {
229 std::scoped_lock lock{guard_};
230 auto iter = stateStores_.find(id);
231 if (iter == stateStores_.end())
232 {
233 return stateStores_
234 .insert(
235 {id,
236 std::unique_ptr<void, std::function<void(void*)>>{
237 ManagerT::create(),
238 [](void* ptr) {
239 ManagerT::destroy(ptr);
240 }}})
241 .first->second.get();
242 }
243 return iter->second.get();
244 }
245
246 private:
247 void callRemoteImpl(std::string const& name, nlohmann::json const& json) const
248 {
249 // window is threadsafe.
250 window_->eval(fmt::format(remoteCallScript, name, json.dump()));
251 }
252 void callRemoteImpl(std::string const& name) const
253 {
254 // window is threadsafe.
255 window_->eval(fmt::format(remoteCallScript, name, "undefined"));
256 }
257
258 private:
259 std::recursive_mutex guard_;
260 Window* window_;
261 std::unordered_map<std::string, std::unique_ptr<void, std::function<void(void*)>>> stateStores_;
262 };
263}
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:169
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:165
static constexpr char const * remoteCallScript
Definition rpc_hub.hpp:88
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
RpcHub & operator=(const RpcHub &)=delete
void registerFunction(std::string const &name, T &&func) const
Definition rpc_hub.hpp:120
void * accessStateStore(std::string const &id)
Definition rpc_hub.hpp:227
void call(std::string const &name, Args &&... args) const
Definition rpc_hub.hpp:176
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
Window & window() const
Returns the attached window.
Definition rpc_hub.hpp:136
RpcHub & operator=(RpcHub &&)=delete
This class encapsulates the webview.
Definition window.hpp:133
static constexpr auto extractJsonMember(nlohmann::json const &json) -> decltype(auto)
Definition rpc_hub.hpp:29
Definition file_dialog.hpp:6
Definition rpc_hub.hpp:63
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