Bitcoin Core 29.99.0
P2P Digital Currency
proxy-types.h
Go to the documentation of this file.
1// Copyright (c) 2019 The Bitcoin Core developers
2// Distributed under the MIT software license, see the accompanying
3// file COPYING or http://www.opensource.org/licenses/mit-license.php.
4
5#ifndef MP_PROXY_TYPES_H
6#define MP_PROXY_TYPES_H
7
8#include <mp/proxy-io.h>
9
10#include <exception>
11#include <optional>
12#include <set>
13#include <typeindex>
14#include <vector>
15
16namespace mp {
17
18template <typename Value>
20{
21public:
22 ValueField(Value& value) : m_value(value) {}
23 ValueField(Value&& value) : m_value(value) {}
24 Value& m_value;
25
26 Value& get() { return m_value; }
27 Value& init() { return m_value; }
28 bool has() { return true; }
29};
30
31template <typename Accessor, typename Struct>
33{
34 template <typename S>
35 StructField(S& struct_) : m_struct(struct_)
36 {
37 }
38 Struct& m_struct;
39
40 decltype(auto) get() const { return Accessor::get(this->m_struct); }
41
42 bool has() const {
43 if constexpr (Accessor::optional) {
44 return Accessor::getHas(m_struct);
45 } else if constexpr (Accessor::boxed) {
46 return Accessor::has(m_struct);
47 } else {
48 return true;
49 }
50 }
51
52 bool want() const {
53 if constexpr (Accessor::requested) {
54 return Accessor::getWant(m_struct);
55 } else {
56 return true;
57 }
58 }
59
60 template <typename... Args> decltype(auto) set(Args &&...args) const {
61 return Accessor::set(this->m_struct, std::forward<Args>(args)...);
62 }
63
64 template <typename... Args> decltype(auto) init(Args &&...args) const {
65 return Accessor::init(this->m_struct, std::forward<Args>(args)...);
66 }
67
68 void setHas() const {
69 if constexpr (Accessor::optional) {
70 Accessor::setHas(m_struct);
71 }
72 }
73
74 void setWant() const {
75 if constexpr (Accessor::requested) {
76 Accessor::setWant(m_struct);
77 }
78 }
79};
80
81
82
83// Destination parameter type that can be passed to ReadField function as an
84// alternative to ReadDestUpdate. It allows the ReadField implementation to call
85// the provided emplace_fn function with constructor arguments, so it only needs
86// to determine the arguments, and can let the emplace function decide how to
87// actually construct the read destination object. For example, if a std::string
88// is being read, the ReadField call will call the custom emplace_fn with char*
89// and size_t arguments, and the emplace function can decide whether to call the
90// constructor via the operator or make_shared or emplace or just return a
91// temporary string that is moved from.
92template <typename LocalType, typename EmplaceFn>
94{
95 ReadDestEmplace(TypeList<LocalType>, EmplaceFn&& emplace_fn) : m_emplace_fn(emplace_fn) {}
96
99 template <typename... Args>
100 decltype(auto) construct(Args&&... args)
101 {
102 return m_emplace_fn(std::forward<Args>(args)...);
103 }
104
109 template <typename UpdateFn>
110 decltype(auto) update(UpdateFn&& update_fn)
111 {
112 if constexpr (std::is_const_v<std::remove_reference_t<std::invoke_result_t<EmplaceFn>>>) {
113 // If destination type is const, default construct temporary
114 // to pass to update, then call move constructor via construct() to
115 // move from that temporary.
116 std::remove_cv_t<LocalType> temp;
117 update_fn(temp);
118 return construct(std::move(temp));
119 } else {
120 // Default construct object and pass it to update_fn.
121 decltype(auto) temp = construct();
122 update_fn(temp);
123 return temp;
124 }
125 }
126 EmplaceFn& m_emplace_fn;
127};
128
131template <typename LocalType>
133{
134 return ReadDestEmplace{TypeList<LocalType>(), [&](auto&&... args) -> decltype(auto) {
135 return LocalType{std::forward<decltype(args)>(args)...};
136 }};
137}
138
143template <typename Value>
145{
146 ReadDestUpdate(Value& value) : m_value(value) {}
147
149 template <typename UpdateFn>
150 Value& update(UpdateFn&& update_fn)
151 {
152 update_fn(m_value);
153 return m_value;
154 }
155
158 template <typename... Args>
159 Value& construct(Args&&... args)
160 {
161 m_value.~Value();
162 new (&m_value) Value(std::forward<Args>(args)...);
163 return m_value;
164 }
165
166 Value& m_value;
167};
168
169template <typename... LocalTypes, typename... Args>
170decltype(auto) ReadField(TypeList<LocalTypes...>, Args&&... args)
171{
172 return CustomReadField(TypeList<RemoveCvRef<LocalTypes>...>(), Priority<2>(), std::forward<Args>(args)...);
173}
174
175template <typename LocalType, typename Input>
176void ThrowField(TypeList<LocalType>, InvokeContext& invoke_context, Input&& input)
177{
178 ReadField(
179 TypeList<LocalType>(), invoke_context, input, ReadDestEmplace(TypeList<LocalType>(),
180 [](auto&& ...args) -> const LocalType& { throw LocalType{std::forward<decltype(args)>(args)...}; }));
181}
182
186template <typename Input>
187void ThrowField(TypeList<std::exception>, InvokeContext& invoke_context, Input&& input)
188{
189 auto data = input.get();
190 throw std::runtime_error(std::string(CharCast(data.begin()), data.size()));
191}
192
193template <typename... Values>
194bool CustomHasValue(InvokeContext& invoke_context, Values&&... value)
195{
196 return true;
197}
198
199template <typename... LocalTypes, typename Context, typename... Values, typename Output>
200void BuildField(TypeList<LocalTypes...>, Context& context, Output&& output, Values&&... values)
201{
202 if (CustomHasValue(context, std::forward<Values>(values)...)) {
203 CustomBuildField(TypeList<LocalTypes...>(), Priority<3>(), context, std::forward<Values>(values)...,
204 std::forward<Output>(output));
205 }
206}
207
208// Adapter to let BuildField overloads methods work set & init list elements as
209// if they were fields of a struct. If BuildField is changed to use some kind of
210// accessor class instead of calling method pointers, then then maybe this could
211// go away or be simplified, because would no longer be a need to return
212// ListOutput method pointers emulating capnp struct method pointers..
213template <typename ListType>
215
216template <typename T, ::capnp::Kind kind>
217struct ListOutput<::capnp::List<T, kind>>
218{
219 using Builder = typename ::capnp::List<T, kind>::Builder;
220
221 ListOutput(Builder& builder, size_t index) : m_builder(builder), m_index(index) {}
223 size_t m_index;
224
225 // clang-format off
226 decltype(auto) get() const { return this->m_builder[this->m_index]; }
227 decltype(auto) init() const { return this->m_builder[this->m_index]; }
228 template<typename B = Builder, typename Arg> decltype(auto) set(Arg&& arg) const { return static_cast<B&>(this->m_builder).set(m_index, std::forward<Arg>(arg)); }
229 template<typename B = Builder, typename Arg> decltype(auto) init(Arg&& arg) const { return static_cast<B&>(this->m_builder).init(m_index, std::forward<Arg>(arg)); }
230 // clang-format on
231};
232
233template <typename LocalType, typename Value, typename Output>
234void CustomBuildField(TypeList<LocalType>, Priority<0>, InvokeContext& invoke_context, Value&& value, Output&& output)
235{
236 output.set(BuildPrimitive(invoke_context, std::forward<Value>(value), TypeList<decltype(output.get())>()));
237}
238
240template <typename Accessor, typename LocalType, typename ServerContext, typename Fn, typename... Args>
241auto PassField(Priority<1>, TypeList<LocalType&>, ServerContext& server_context, Fn&& fn, Args&&... args)
242 -> Require<typename decltype(Accessor::get(server_context.call_context.getParams()))::Calls>
243{
244 // Just create a temporary ProxyClient if argument is a reference to an
245 // interface client. If argument needs to have a longer lifetime and not be
246 // destroyed after this call, a CustomPassField overload can be implemented
247 // to bypass this code, and a custom ProxyServerMethodTraits overload can be
248 // implemented in order to read the capability pointer out of params and
249 // construct a ProxyClient with a longer lifetime.
250 const auto& params = server_context.call_context.getParams();
251 const auto& input = Make<StructField, Accessor>(params);
252 using Interface = typename Decay<decltype(input.get())>::Calls;
253 auto param = std::make_unique<ProxyClient<Interface>>(input.get(), server_context.proxy_server.m_context.connection, false);
254 fn.invoke(server_context, std::forward<Args>(args)..., *param);
255}
256
257template <typename... Args>
258void MaybeBuildField(std::true_type, Args&&... args)
259{
260 BuildField(std::forward<Args>(args)...);
261}
262template <typename... Args>
263void MaybeBuildField(std::false_type, Args&&...)
264{
265}
266template <typename... Args>
267void MaybeReadField(std::true_type, Args&&... args)
268{
269 ReadField(std::forward<Args>(args)...);
270}
271template <typename... Args>
272void MaybeReadField(std::false_type, Args&&...)
273{
274}
275
276template <typename LocalType, typename Value, typename Output>
277void MaybeSetWant(TypeList<LocalType*>, Priority<1>, Value&& value, Output&& output)
278{
279 if (value) {
280 output.setWant();
281 }
282}
283
284template <typename LocalTypes, typename... Args>
285void MaybeSetWant(LocalTypes, Priority<0>, Args&&...)
286{
287}
288
290template <typename Accessor, typename LocalType, typename ServerContext, typename Fn, typename... Args>
291void PassField(Priority<0>, TypeList<LocalType>, ServerContext& server_context, Fn&& fn, Args&&... args)
292{
293 InvokeContext& invoke_context = server_context;
294 using ArgType = RemoveCvRef<LocalType>;
295 std::optional<ArgType> param;
296 const auto& params = server_context.call_context.getParams();
297 MaybeReadField(std::integral_constant<bool, Accessor::in>(), TypeList<ArgType>(), invoke_context,
298 Make<StructField, Accessor>(params), ReadDestEmplace(TypeList<ArgType>(), [&](auto&&... args) -> auto& {
299 param.emplace(std::forward<decltype(args)>(args)...);
300 return *param;
301 }));
302 if constexpr (Accessor::in) {
303 assert(param);
304 } else {
305 if (!param) param.emplace();
306 }
307 fn.invoke(server_context, std::forward<Args>(args)..., static_cast<LocalType&&>(*param));
308 auto&& results = server_context.call_context.getResults();
309 MaybeBuildField(std::integral_constant<bool, Accessor::out>(), TypeList<LocalType>(), invoke_context,
310 Make<StructField, Accessor>(results), *param);
311}
312
314template <typename Accessor, typename ServerContext, typename Fn, typename... Args>
315void PassField(Priority<0>, TypeList<>, ServerContext& server_context, const Fn& fn, Args&&... args)
316{
317 const auto& params = server_context.call_context.getParams();
318 const auto& input = Make<StructField, Accessor>(params);
319 ReadField(TypeList<>(), server_context, input);
320 fn.invoke(server_context, std::forward<Args>(args)...);
321 auto&& results = server_context.call_context.getResults();
322 BuildField(TypeList<>(), server_context, Make<StructField, Accessor>(results));
323}
324
325template <typename Derived, size_t N = 0>
327{
328 template <typename Arg1, typename Arg2, typename ParamList, typename NextFn, typename... NextFnArgs>
329 void handleChain(Arg1&& arg1, Arg2&& arg2, ParamList, NextFn&& next_fn, NextFnArgs&&... next_fn_args)
330 {
331 using S = Split<N, ParamList>;
332 handleChain(std::forward<Arg1>(arg1), std::forward<Arg2>(arg2), typename S::First());
333 next_fn.handleChain(std::forward<Arg1>(arg1), std::forward<Arg2>(arg2), typename S::Second(),
334 std::forward<NextFnArgs>(next_fn_args)...);
335 }
336
337 template <typename Arg1, typename Arg2, typename ParamList>
338 void handleChain(Arg1&& arg1, Arg2&& arg2, ParamList)
339 {
340 static_cast<Derived*>(this)->handleField(std::forward<Arg1>(arg1), std::forward<Arg2>(arg2), ParamList());
341 }
342private:
344 friend Derived;
345};
346
347struct IterateFields : IterateFieldsHelper<IterateFields, 0>
348{
349 template <typename Arg1, typename Arg2, typename ParamList>
350 void handleField(Arg1&&, Arg2&&, ParamList)
351 {
352 }
353};
354
355template <typename Exception, typename Accessor>
357{
358 struct BuildParams : IterateFieldsHelper<BuildParams, 0>
359 {
360 template <typename Params, typename ParamList>
361 void handleField(InvokeContext& invoke_context, Params& params, ParamList)
362 {
363 }
364
365 BuildParams(ClientException* client_exception) : m_client_exception(client_exception) {}
367 };
368
369 struct ReadResults : IterateFieldsHelper<ReadResults, 0>
370 {
371 template <typename Results, typename ParamList>
372 void handleField(InvokeContext& invoke_context, Results& results, ParamList)
373 {
374 StructField<Accessor, Results> input(results);
375 if (input.has()) {
376 ThrowField(TypeList<Exception>(), invoke_context, input);
377 }
378 }
379
380 ReadResults(ClientException* client_exception) : m_client_exception(client_exception) {}
382 };
383};
384
385template <typename Accessor, typename... Types>
387{
388 ClientParam(Types&&... values) : m_values{std::forward<Types>(values)...} {}
389
390 struct BuildParams : IterateFieldsHelper<BuildParams, sizeof...(Types)>
391 {
392 template <typename Params, typename ParamList>
393 void handleField(ClientInvokeContext& invoke_context, Params& params, ParamList)
394 {
395 auto const fun = [&]<typename... Values>(Values&&... values) {
396 MaybeBuildField(std::integral_constant<bool, Accessor::in>(), ParamList(), invoke_context,
397 Make<StructField, Accessor>(params), std::forward<Values>(values)...);
399 ParamList(), Priority<1>(), std::forward<Values>(values)..., Make<StructField, Accessor>(params));
400 };
401
402 // Note: The m_values tuple just consists of lvalue and rvalue
403 // references, so calling std::move doesn't change the tuple, it
404 // just causes std::apply to call the std::get overload that returns
405 // && instead of &, so rvalue references are preserved and not
406 // turned into lvalue references. This allows the BuildField call to
407 // move from the argument if it is an rvalue reference or was passed
408 // by value.
409 std::apply(fun, std::move(m_client_param->m_values));
410 }
411
412 BuildParams(ClientParam* client_param) : m_client_param(client_param) {}
414 };
415
416 struct ReadResults : IterateFieldsHelper<ReadResults, sizeof...(Types)>
417 {
418 template <typename Results, typename... Params>
419 void handleField(ClientInvokeContext& invoke_context, Results& results, TypeList<Params...>)
420 {
421 auto const fun = [&]<typename... Values>(Values&&... values) {
422 MaybeReadField(std::integral_constant<bool, Accessor::out>(), TypeList<Decay<Params>...>(), invoke_context,
423 Make<StructField, Accessor>(results), ReadDestUpdate(values)...);
424 };
425
426 std::apply(fun, m_client_param->m_values);
427 }
428
429 ReadResults(ClientParam* client_param) : m_client_param(client_param) {}
431 };
432
433 std::tuple<Types&&...> m_values;
434};
435
436template <typename Accessor, typename... Types>
438{
439 return {std::forward<Types>(values)...};
440}
441
443{
444 // FIXME: maybe call call_context.releaseParams()
445 template <typename ServerContext, typename... Args>
446 decltype(auto) invoke(ServerContext& server_context, TypeList<>, Args&&... args) const
447 {
448 return ProxyServerMethodTraits<typename decltype(server_context.call_context.getParams())::Reads>::invoke(
449 server_context,
450 std::forward<Args>(args)...);
451 }
452};
453
455{
456 template <typename ServerContext, typename... Args>
457 void invoke(ServerContext& server_context, TypeList<>, Args&&... args) const
458 {
459 server_context.proxy_server.invokeDestroy(std::forward<Args>(args)...);
460 }
461};
462
463template <typename Accessor, typename Parent>
464struct ServerRet : Parent
465{
466 ServerRet(Parent parent) : Parent(parent) {}
467
468 template <typename ServerContext, typename... Args>
469 void invoke(ServerContext& server_context, TypeList<>, Args&&... args) const
470 {
471 auto&& result = Parent::invoke(server_context, TypeList<>(), std::forward<Args>(args)...);
472 auto&& results = server_context.call_context.getResults();
473 InvokeContext& invoke_context = server_context;
474 BuildField(TypeList<decltype(result)>(), invoke_context, Make<StructField, Accessor>(results),
475 std::forward<decltype(result)>(result));
476 }
477};
478
479template <typename Exception, typename Accessor, typename Parent>
480struct ServerExcept : Parent
481{
482 ServerExcept(Parent parent) : Parent(parent) {}
483
484 template <typename ServerContext, typename... Args>
485 void invoke(ServerContext& server_context, TypeList<>, Args&&... args) const
486 {
487 try {
488 return Parent::invoke(server_context, TypeList<>(), std::forward<Args>(args)...);
489 } catch (const Exception& exception) {
490 auto&& results = server_context.call_context.getResults();
491 BuildField(TypeList<Exception>(), server_context, Make<StructField, Accessor>(results), exception);
492 }
493 }
494};
495
498template <typename Accessor, typename Message>
499decltype(auto) MaybeGet(Message&& message, decltype(Accessor::get(message))* enable = nullptr)
500{
501 return Accessor::get(message);
502}
503
504template <typename Accessor>
505::capnp::Void MaybeGet(...)
506{
507 return {};
508}
509
510template <class Accessor>
512
523template <typename Accessor, typename... Args>
524auto PassField(Priority<2>, Args&&... args) -> decltype(CustomPassField<Accessor>(std::forward<Args>(args)...))
525{
526 return CustomPassField<Accessor>(std::forward<Args>(args)...);
527};
528
529template <int argc, typename Accessor, typename Parent>
530struct ServerField : Parent
531{
532 ServerField(Parent parent) : Parent(parent) {}
533
534 const Parent& parent() const { return *this; }
535
536 template <typename ServerContext, typename ArgTypes, typename... Args>
537 decltype(auto) invoke(ServerContext& server_context, ArgTypes, Args&&... args) const
538 {
539 return PassField<Accessor>(Priority<2>(),
541 server_context,
542 this->parent(),
544 std::forward<Args>(args)...);
545 }
546};
547
548template <int argc, typename Accessor, typename Parent>
550{
551 return {parent};
552}
553
554template <typename Request>
556
557template <typename _Params, typename _Results>
558struct CapRequestTraits<::capnp::Request<_Params, _Results>>
559{
560 using Params = _Params;
561 using Results = _Results;
562};
563
567template <typename Client>
568void clientDestroy(Client& client)
569{
570 if (client.m_context.connection) {
571 client.m_context.connection->m_loop.log() << "IPC client destroy " << typeid(client).name();
572 } else {
573 KJ_LOG(INFO, "IPC interrupted client destroy", typeid(client).name());
574 }
575}
576
577template <typename Server>
578void serverDestroy(Server& server)
579{
580 server.m_context.connection->m_loop.log() << "IPC server destroy " << typeid(server).name();
581}
582
592template <typename ProxyClient, typename GetRequest, typename... FieldObjs>
593void clientInvoke(ProxyClient& proxy_client, const GetRequest& get_request, FieldObjs&&... fields)
594{
595 if (!proxy_client.m_context.connection) {
596 throw std::logic_error("clientInvoke call made after disconnect");
597 }
600 g_thread_context.thread_name = ThreadName(proxy_client.m_context.connection->m_loop.m_exe_name);
601 // If next assert triggers, it means clientInvoke is being called from
602 // the capnp event loop thread. This can happen when a ProxyServer
603 // method implementation that runs synchronously on the event loop
604 // thread tries to make a blocking callback to the client. Any server
605 // method that makes a blocking callback or blocks in general needs to
606 // run asynchronously off the event loop thread. This is easy to fix by
607 // just adding a 'context :Proxy.Context' argument to the capnp method
608 // declaration so the server method runs in a dedicated thread.
610 g_thread_context.waiter = std::make_unique<Waiter>();
611 proxy_client.m_context.connection->m_loop.logPlain()
613 << "} IPC client first request from current thread, constructing waiter";
614 }
615 ClientInvokeContext invoke_context{*proxy_client.m_context.connection, g_thread_context};
616 std::exception_ptr exception;
617 std::string kj_exception;
618 bool done = false;
619 proxy_client.m_context.connection->m_loop.sync([&]() {
620 auto request = (proxy_client.m_client.*get_request)(nullptr);
621 using Request = CapRequestTraits<decltype(request)>;
623 IterateFields().handleChain(invoke_context, request, FieldList(), typename FieldObjs::BuildParams{&fields}...);
624 proxy_client.m_context.connection->m_loop.logPlain()
625 << "{" << invoke_context.thread_context.thread_name << "} IPC client send "
626 << TypeName<typename Request::Params>() << " " << LogEscape(request.toString());
627
628 proxy_client.m_context.connection->m_loop.m_task_set->add(request.send().then(
629 [&](::capnp::Response<typename Request::Results>&& response) {
630 proxy_client.m_context.connection->m_loop.logPlain()
631 << "{" << invoke_context.thread_context.thread_name << "} IPC client recv "
632 << TypeName<typename Request::Results>() << " " << LogEscape(response.toString());
633 try {
634 IterateFields().handleChain(
635 invoke_context, response, FieldList(), typename FieldObjs::ReadResults{&fields}...);
636 } catch (...) {
637 exception = std::current_exception();
638 }
639 const std::unique_lock<std::mutex> lock(invoke_context.thread_context.waiter->m_mutex);
640 done = true;
641 invoke_context.thread_context.waiter->m_cv.notify_all();
642 },
643 [&](const ::kj::Exception& e) {
644 kj_exception = kj::str("kj::Exception: ", e).cStr();
645 proxy_client.m_context.connection->m_loop.logPlain()
646 << "{" << invoke_context.thread_context.thread_name << "} IPC client exception " << kj_exception;
647 const std::unique_lock<std::mutex> lock(invoke_context.thread_context.waiter->m_mutex);
648 done = true;
649 invoke_context.thread_context.waiter->m_cv.notify_all();
650 }));
651 });
652
653 std::unique_lock<std::mutex> lock(invoke_context.thread_context.waiter->m_mutex);
654 invoke_context.thread_context.waiter->wait(lock, [&done]() { return done; });
655 if (exception) std::rethrow_exception(exception);
656 if (!kj_exception.empty()) proxy_client.m_context.connection->m_loop.raise() << kj_exception;
657}
658
662template <typename Fn, typename Ret>
663auto ReplaceVoid(Fn&& fn, Ret&& ret)
664{
665 if constexpr (std::is_same_v<decltype(fn()), void>) {
666 fn();
667 return ret();
668 } else {
669 return fn();
670 }
671}
672
673extern std::atomic<int> server_reqs;
674
682template <typename Server, typename CallContext, typename Fn>
683kj::Promise<void> serverInvoke(Server& server, CallContext& call_context, Fn fn)
684{
685 auto params = call_context.getParams();
686 using Params = decltype(params);
687 using Results = typename decltype(call_context.getResults())::Builds;
688
689 int req = ++server_reqs;
690 server.m_context.connection->m_loop.log() << "IPC server recv request #" << req << " "
691 << TypeName<typename Params::Reads>() << " " << LogEscape(params.toString());
692
693 try {
696 ServerContext server_context{server, call_context, req};
697 // ReplaceVoid is used to support fn.invoke implementations that
698 // execute asynchronously and return promises, as well as
699 // implementations that execute synchronously and return void. The
700 // invoke function will be synchronous by default, but asynchronous if
701 // an mp.Context argument is passed, and the mp.Context PassField
702 // overload returns a promise executing the request in a worker thread
703 // and waiting for it to complete.
704 return ReplaceVoid([&]() { return fn.invoke(server_context, ArgList()); },
705 [&]() { return kj::Promise<CallContext>(kj::mv(call_context)); })
706 .then([&server, req](CallContext call_context) {
707 server.m_context.connection->m_loop.log() << "IPC server send response #" << req << " " << TypeName<Results>()
708 << " " << LogEscape(call_context.getResults().toString());
709 });
710 } catch (const std::exception& e) {
711 server.m_context.connection->m_loop.log() << "IPC server unhandled exception: " << e.what();
712 throw;
713 } catch (...) {
714 server.m_context.connection->m_loop.log() << "IPC server unhandled exception";
715 throw;
716 }
717}
718
722 template<typename Interface>
724 types().emplace(typeid(Interface), [](void* iface) -> ProxyContext& { return static_cast<typename mp::ProxyType<Interface>::Client&>(*static_cast<Interface*>(iface)).m_context; });
725 }
726 using Types = std::map<std::type_index, ProxyContext&(*)(void*)>;
727 static Types& types() { static Types types; return types; }
728};
729
730} // namespace mp
731
732#endif // MP_PROXY_TYPES_H
int ret
catch(const std::exception &e)
std::unique_ptr< interfaces::Init > init
ArgsManager & args
Definition: bitcoind.cpp:277
const CChainParams & Params()
Return the currently selected parameters.
Value & get()
Definition: proxy-types.h:26
Value & init()
Definition: proxy-types.h:27
ValueField(Value &&value)
Definition: proxy-types.h:23
ValueField(Value &value)
Definition: proxy-types.h:22
Value & m_value
Definition: proxy-types.h:24
Functions to serialize / deserialize common bitcoin types.
Definition: common-types.h:57
void MaybeBuildField(std::true_type, Args &&... args)
Definition: proxy-types.h:258
void clientDestroy(Client &client)
Entry point called by all generated ProxyClient destructors.
Definition: proxy-types.h:568
void clientInvoke(ProxyClient &proxy_client, const GetRequest &get_request, FieldObjs &&... fields)
Entry point called by generated client code that looks like:
Definition: proxy-types.h:593
void CustomPassField()
ClientParam< Accessor, Types... > MakeClientParam(Types &&... values)
Definition: proxy-types.h:437
bool CustomHasValue(InvokeContext &invoke_context, Values &&... value)
Definition: proxy-types.h:194
void MaybeReadField(std::true_type, Args &&... args)
Definition: proxy-types.h:267
kj::Promise< void > serverInvoke(Server &server, CallContext &call_context, Fn fn)
Entry point called by generated server code that looks like:
Definition: proxy-types.h:683
void BuildField(TypeList< LocalTypes... >, Context &context, Output &&output, Values &&... values)
Definition: proxy-types.h:200
auto PassField(Priority< 1 >, TypeList< LocalType & >, ServerContext &server_context, Fn &&fn, Args &&... args) -> Require< typename decltype(Accessor::get(server_context.call_context.getParams()))::Calls >
PassField override for callable interface reference arguments.
Definition: proxy-types.h:241
std::string ThreadName(const char *exe_name)
Format current thread name as "{exe_name}-{$pid}/{thread_name}-{$tid}".
Definition: util.cpp:47
decltype(auto) CustomReadField(TypeList< LocalType >, Priority< 1 >, InvokeContext &invoke_context, Input &&input, ReadDest &&read_dest)
Overload multiprocess library's CustomReadField hook to allow any object with an Unserialize method t...
Definition: common-types.h:83
LocalType BuildPrimitive(InvokeContext &invoke_context, const Value &value, TypeList< LocalType >, typename std::enable_if< std::is_enum< Value >::value >::type *enable=nullptr)
Definition: type-number.h:12
typename _Require< SfinaeExpr, Result >::Result Require
SFINAE helper, basically the same as to C++17's void_t, but allowing types other than void to be retu...
Definition: util.h:97
std::atomic< int > server_reqs
Definition: proxy.cpp:392
void ThrowField(TypeList< LocalType >, InvokeContext &invoke_context, Input &&input)
Definition: proxy-types.h:176
ServerInvokeContext< ProxyServer< Interface >, ::capnp::CallContext< Params, Results > > ServerContext
Definition: proxy-io.h:56
void serverDestroy(Server &server)
Definition: proxy-types.h:578
thread_local ThreadContext g_thread_context
Definition: proxy.cpp:43
void MaybeSetWant(TypeList< LocalType * >, Priority< 1 >, Value &&value, Output &&output)
Definition: proxy-types.h:277
decltype(auto) ReadField(TypeList< LocalTypes... >, Args &&... args)
Definition: proxy-types.h:170
std::decay_t< T > Decay
Type helper abbreviating std::decay.
Definition: util.h:86
auto ReadDestTemp()
Helper function to create a ReadDestEmplace object that constructs a temporary, ReadField can return.
Definition: proxy-types.h:132
std::remove_cv_t< std::remove_reference_t< T > > RemoveCvRef
Substitutue for std::remove_cvref_t.
Definition: util.h:82
std::string LogEscape(const kj::StringTree &string)
Escape binary string for use in log so it doesn't trigger unicode decode errors in python unit tests.
Definition: util.cpp:78
char * CharCast(char *c)
Definition: util.h:213
decltype(auto) MaybeGet(Message &&message, decltype(Accessor::get(message)) *enable=nullptr)
Helper for CustomPassField below.
Definition: proxy-types.h:499
auto ReplaceVoid(Fn &&fn, Ret &&ret)
Invoke callable fn() that may return void.
Definition: proxy-types.h:663
void CustomBuildField(TypeList< LocalType >, Priority< 1 >, InvokeContext &invoke_context, Value &&value, Output &&output)
Overload multiprocess library's CustomBuildField hook to allow any serializable object to be stored i...
Definition: common-types.h:63
ServerField< argc, Accessor, Parent > MakeServerField(Parent parent)
Definition: proxy-types.h:549
#define S(a, b, c, d, e, f, g, h, i, j, k, l, m, n, o, p)
const char * name
Definition: rest.cpp:49
static const int64_t values[]
A selection of numbers that do not trigger int64_t overflow when added/subtracted.
Accessor type holding flags that determine how to access a message field.
Definition: proxy.h:288
static const bool boxed
Definition: proxy.h:293
static const bool optional
Definition: proxy.h:291
static const bool requested
Definition: proxy.h:292
static const bool in
Definition: proxy.h:289
void handleField(InvokeContext &invoke_context, Params &params, ParamList)
Definition: proxy-types.h:361
ClientException * m_client_exception
Definition: proxy-types.h:366
BuildParams(ClientException *client_exception)
Definition: proxy-types.h:365
void handleField(InvokeContext &invoke_context, Results &results, ParamList)
Definition: proxy-types.h:372
ReadResults(ClientException *client_exception)
Definition: proxy-types.h:380
ClientException * m_client_exception
Definition: proxy-types.h:381
void handleField(ClientInvokeContext &invoke_context, Params &params, ParamList)
Definition: proxy-types.h:393
BuildParams(ClientParam *client_param)
Definition: proxy-types.h:412
ReadResults(ClientParam *client_param)
Definition: proxy-types.h:429
void handleField(ClientInvokeContext &invoke_context, Results &results, TypeList< Params... >)
Definition: proxy-types.h:419
ClientParam(Types &&... values)
Definition: proxy-types.h:388
std::tuple< Types &&... > m_values
Definition: proxy-types.h:433
void handleChain(Arg1 &&arg1, Arg2 &&arg2, ParamList, NextFn &&next_fn, NextFnArgs &&... next_fn_args)
Definition: proxy-types.h:329
void handleChain(Arg1 &&arg1, Arg2 &&arg2, ParamList)
Definition: proxy-types.h:338
void handleField(Arg1 &&, Arg2 &&, ParamList)
Definition: proxy-types.h:350
decltype(auto) set(Arg &&arg) const
Definition: proxy-types.h:228
decltype(auto) init(Arg &&arg) const
Definition: proxy-types.h:229
typename ::capnp::List< T, kind >::Builder Builder
Definition: proxy-types.h:219
ListOutput(Builder &builder, size_t index)
Definition: proxy-types.h:221
Specialization of above (base case)
Definition: util.h:115
Function parameter type for prioritizing overloaded function calls that would otherwise be ambiguous.
Definition: util.h:109
Mapping from capnp interface type to proxy client implementation (specializations are generated by pr...
Definition: proxy.h:24
Context data associated with proxy client and server classes.
Definition: proxy.h:52
Customizable (through template specialization) traits class used in generated ProxyServer implementat...
Definition: proxy.h:276
Mapping from local c++ type to capnp type and traits (specializations are generated by proxy-codegen....
Definition: proxy.h:37
Map to convert client interface pointers to ProxyContext struct references at runtime using typeids.
Definition: proxy-types.h:721
static Types & types()
Definition: proxy-types.h:727
ProxyTypeRegister(TypeList< Interface >)
Definition: proxy-types.h:723
std::map< std::type_index, ProxyContext &(*)(void *)> Types
Definition: proxy-types.h:726
EmplaceFn & m_emplace_fn
Definition: proxy-types.h:126
decltype(auto) construct(Args &&... args)
Simple case.
Definition: proxy-types.h:100
ReadDestEmplace(TypeList< LocalType >, EmplaceFn &&emplace_fn)
Definition: proxy-types.h:95
decltype(auto) update(UpdateFn &&update_fn)
More complicated case.
Definition: proxy-types.h:110
Destination parameter type that can be passed to ReadField function as an alternative to ReadDestEmpl...
Definition: proxy-types.h:145
Value & update(UpdateFn &&update_fn)
Simple case. If ReadField works by calling update() just forward arguments to update_fn.
Definition: proxy-types.h:150
Value & construct(Args &&... args)
More complicated case.
Definition: proxy-types.h:159
ReadDestUpdate(Value &value)
Definition: proxy-types.h:146
decltype(auto) invoke(ServerContext &server_context, TypeList<>, Args &&... args) const
Definition: proxy-types.h:446
void invoke(ServerContext &server_context, TypeList<>, Args &&... args) const
Definition: proxy-types.h:457
ServerExcept(Parent parent)
Definition: proxy-types.h:482
void invoke(ServerContext &server_context, TypeList<>, Args &&... args) const
Definition: proxy-types.h:485
ServerField(Parent parent)
Definition: proxy-types.h:532
decltype(auto) invoke(ServerContext &server_context, ArgTypes, Args &&... args) const
Definition: proxy-types.h:537
const Parent & parent() const
Definition: proxy-types.h:534
CallContext & call_context
Definition: proxy-io.h:46
ProxyServer & proxy_server
Definition: proxy-io.h:45
void invoke(ServerContext &server_context, TypeList<>, Args &&... args) const
Definition: proxy-types.h:469
ServerRet(Parent parent)
Definition: proxy-types.h:466
Type helper splitting a TypeList into two halves at position index.
Definition: util.h:57
StructField(S &struct_)
Definition: proxy-types.h:35
void setWant() const
Definition: proxy-types.h:74
decltype(auto) set(Args &&...args) const
Definition: proxy-types.h:60
decltype(auto) init(Args &&...args) const
Definition: proxy-types.h:64
bool want() const
Definition: proxy-types.h:52
Struct & m_struct
Definition: proxy-types.h:38
decltype(auto) get() const
Definition: proxy-types.h:40
bool has() const
Definition: proxy-types.h:42
void setHas() const
Definition: proxy-types.h:68
std::unique_ptr< Waiter > waiter
Waiter object used to allow client threads blocked waiting for a server response to execute callbacks...
Definition: proxy-io.h:536
bool loop_thread
Whether this thread is a capnp event loop thread.
Definition: proxy-io.h:556
std::string thread_name
Identifying string for debug.
Definition: proxy-io.h:531
Generic utility functions used by capnp code.
Definition: util.h:33
#define B
Definition: util_tests.cpp:545
assert(!tx.IsCoinBase())