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 // clang-format off
41 template<typename A = Accessor> auto get() const -> decltype(A::get(this->m_struct)) { return A::get(this->m_struct); }
42 template<typename A = Accessor> auto has() const -> std::enable_if_t<A::optional, bool> { return A::getHas(m_struct); }
43 template<typename A = Accessor> auto has() const -> std::enable_if_t<!A::optional && A::boxed, bool> { return A::has(m_struct); }
44 template<typename A = Accessor> auto has() const -> std::enable_if_t<!A::optional && !A::boxed, bool> { return true; }
45 template<typename A = Accessor> auto want() const -> std::enable_if_t<A::requested, bool> { return A::getWant(m_struct); }
46 template<typename A = Accessor> auto want() const -> std::enable_if_t<!A::requested, bool> { return true; }
47 template<typename A = Accessor, typename... Args> decltype(auto) set(Args&&... args) const { return A::set(this->m_struct, std::forward<Args>(args)...); }
48 template<typename A = Accessor, typename... Args> decltype(auto) init(Args&&... args) const { return A::init(this->m_struct, std::forward<Args>(args)...); }
49 template<typename A = Accessor> auto setHas() const -> std::enable_if_t<A::optional> { return A::setHas(m_struct); }
50 template<typename A = Accessor> auto setHas() const -> std::enable_if_t<!A::optional> { }
51 template<typename A = Accessor> auto setWant() const -> std::enable_if_t<A::requested> { return A::setWant(m_struct); }
52 template<typename A = Accessor> auto setWant() const -> std::enable_if_t<!A::requested> { }
53 // clang-format on
54};
55
56
57
58// Destination parameter type that can be passed to ReadField function as an
59// alternative to ReadDestUpdate. It allows the ReadField implementation to call
60// the provided emplace_fn function with constructor arguments, so it only needs
61// to determine the arguments, and can let the emplace function decide how to
62// actually construct the read destination object. For example, if a std::string
63// is being read, the ReadField call will call the custom emplace_fn with char*
64// and size_t arguments, and the emplace function can decide whether to call the
65// constructor via the operator or make_shared or emplace or just return a
66// temporary string that is moved from.
67template <typename LocalType, typename EmplaceFn>
69{
70 ReadDestEmplace(TypeList<LocalType>, EmplaceFn&& emplace_fn) : m_emplace_fn(emplace_fn) {}
71
74 template <typename... Args>
75 decltype(auto) construct(Args&&... args)
76 {
77 return m_emplace_fn(std::forward<Args>(args)...);
78 }
79
84 template <typename UpdateFn>
85 decltype(auto) update(UpdateFn&& update_fn)
86 {
87 if constexpr (std::is_const_v<std::remove_reference_t<std::invoke_result_t<EmplaceFn>>>) {
88 // If destination type is const, default construct temporary
89 // to pass to update, then call move constructor via construct() to
90 // move from that temporary.
91 std::remove_cv_t<LocalType> temp;
92 update_fn(temp);
93 return construct(std::move(temp));
94 } else {
95 // Default construct object and pass it to update_fn.
96 decltype(auto) temp = construct();
97 update_fn(temp);
98 return temp;
99 }
100 }
101 EmplaceFn& m_emplace_fn;
102};
103
106template <typename LocalType>
108{
109 return ReadDestEmplace{TypeList<LocalType>(), [&](auto&&... args) -> decltype(auto) {
110 return LocalType{std::forward<decltype(args)>(args)...};
111 }};
112}
113
118template <typename Value>
120{
121 ReadDestUpdate(Value& value) : m_value(value) {}
122
124 template <typename UpdateFn>
125 Value& update(UpdateFn&& update_fn)
126 {
127 update_fn(m_value);
128 return m_value;
129 }
130
133 template <typename... Args>
134 Value& construct(Args&&... args)
135 {
136 m_value.~Value();
137 new (&m_value) Value(std::forward<Args>(args)...);
138 return m_value;
139 }
140
141 Value& m_value;
142};
143
144template <typename... LocalTypes, typename... Args>
145decltype(auto) ReadField(TypeList<LocalTypes...>, Args&&... args)
146{
147 return CustomReadField(TypeList<RemoveCvRef<LocalTypes>...>(), Priority<2>(), std::forward<Args>(args)...);
148}
149
150template <typename LocalType, typename Input>
151void ThrowField(TypeList<LocalType>, InvokeContext& invoke_context, Input&& input)
152{
153 ReadField(
154 TypeList<LocalType>(), invoke_context, input, ReadDestEmplace(TypeList<LocalType>(),
155 [](auto&& ...args) -> const LocalType& { throw LocalType{std::forward<decltype(args)>(args)...}; }));
156}
157
161template <typename Input>
162void ThrowField(TypeList<std::exception>, InvokeContext& invoke_context, Input&& input)
163{
164 auto data = input.get();
165 throw std::runtime_error(std::string(CharCast(data.begin()), data.size()));
166}
167
168template <typename... Values>
169bool CustomHasValue(InvokeContext& invoke_context, Values&&... value)
170{
171 return true;
172}
173
174template <typename... LocalTypes, typename Context, typename... Values, typename Output>
175void BuildField(TypeList<LocalTypes...>, Context& context, Output&& output, Values&&... values)
176{
177 if (CustomHasValue(context, std::forward<Values>(values)...)) {
178 CustomBuildField(TypeList<LocalTypes...>(), Priority<3>(), context, std::forward<Values>(values)...,
179 std::forward<Output>(output));
180 }
181}
182
183// Adapter to let BuildField overloads methods work set & init list elements as
184// if they were fields of a struct. If BuildField is changed to use some kind of
185// accessor class instead of calling method pointers, then then maybe this could
186// go away or be simplified, because would no longer be a need to return
187// ListOutput method pointers emulating capnp struct method pointers..
188template <typename ListType>
190
191template <typename T, ::capnp::Kind kind>
192struct ListOutput<::capnp::List<T, kind>>
193{
194 using Builder = typename ::capnp::List<T, kind>::Builder;
195
196 ListOutput(Builder& builder, size_t index) : m_builder(builder), m_index(index) {}
198 size_t m_index;
199
200 // clang-format off
201 decltype(auto) get() const { return this->m_builder[this->m_index]; }
202 decltype(auto) init() const { return this->m_builder[this->m_index]; }
203 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)); }
204 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)); }
205 // clang-format on
206};
207
208template <typename LocalType, typename Value, typename Output>
209void CustomBuildField(TypeList<LocalType>, Priority<0>, InvokeContext& invoke_context, Value&& value, Output&& output)
210{
211 output.set(BuildPrimitive(invoke_context, std::forward<Value>(value), TypeList<decltype(output.get())>()));
212}
213
215template <typename Accessor, typename LocalType, typename ServerContext, typename Fn, typename... Args>
216auto PassField(Priority<1>, TypeList<LocalType&>, ServerContext& server_context, Fn&& fn, Args&&... args)
217 -> Require<typename decltype(Accessor::get(server_context.call_context.getParams()))::Calls>
218{
219 // Just create a temporary ProxyClient if argument is a reference to an
220 // interface client. If argument needs to have a longer lifetime and not be
221 // destroyed after this call, a CustomPassField overload can be implemented
222 // to bypass this code, and a custom ProxyServerMethodTraits overload can be
223 // implemented in order to read the capability pointer out of params and
224 // construct a ProxyClient with a longer lifetime.
225 const auto& params = server_context.call_context.getParams();
226 const auto& input = Make<StructField, Accessor>(params);
227 using Interface = typename Decay<decltype(input.get())>::Calls;
228 auto param = std::make_unique<ProxyClient<Interface>>(input.get(), server_context.proxy_server.m_context.connection, false);
229 fn.invoke(server_context, std::forward<Args>(args)..., *param);
230}
231
232template <typename... Args>
233void MaybeBuildField(std::true_type, Args&&... args)
234{
235 BuildField(std::forward<Args>(args)...);
236}
237template <typename... Args>
238void MaybeBuildField(std::false_type, Args&&...)
239{
240}
241template <typename... Args>
242void MaybeReadField(std::true_type, Args&&... args)
243{
244 ReadField(std::forward<Args>(args)...);
245}
246template <typename... Args>
247void MaybeReadField(std::false_type, Args&&...)
248{
249}
250
251template <typename LocalType, typename Value, typename Output>
252void MaybeSetWant(TypeList<LocalType*>, Priority<1>, Value&& value, Output&& output)
253{
254 if (value) {
255 output.setWant();
256 }
257}
258
259template <typename LocalTypes, typename... Args>
260void MaybeSetWant(LocalTypes, Priority<0>, Args&&...)
261{
262}
263
265template <typename Accessor, typename LocalType, typename ServerContext, typename Fn, typename... Args>
266void PassField(Priority<0>, TypeList<LocalType>, ServerContext& server_context, Fn&& fn, Args&&... args)
267{
268 InvokeContext& invoke_context = server_context;
269 using ArgType = RemoveCvRef<LocalType>;
270 std::optional<ArgType> param;
271 const auto& params = server_context.call_context.getParams();
272 MaybeReadField(std::integral_constant<bool, Accessor::in>(), TypeList<ArgType>(), invoke_context,
273 Make<StructField, Accessor>(params), ReadDestEmplace(TypeList<ArgType>(), [&](auto&&... args) -> auto& {
274 param.emplace(std::forward<decltype(args)>(args)...);
275 return *param;
276 }));
277 if constexpr (Accessor::in) {
278 assert(param);
279 } else {
280 if (!param) param.emplace();
281 }
282 fn.invoke(server_context, std::forward<Args>(args)..., static_cast<LocalType&&>(*param));
283 auto&& results = server_context.call_context.getResults();
284 MaybeBuildField(std::integral_constant<bool, Accessor::out>(), TypeList<LocalType>(), invoke_context,
285 Make<StructField, Accessor>(results), *param);
286}
287
289template <typename Accessor, typename ServerContext, typename Fn, typename... Args>
290void PassField(Priority<0>, TypeList<>, ServerContext& server_context, const Fn& fn, Args&&... args)
291{
292 const auto& params = server_context.call_context.getParams();
293 const auto& input = Make<StructField, Accessor>(params);
294 ReadField(TypeList<>(), server_context, input);
295 fn.invoke(server_context, std::forward<Args>(args)...);
296 auto&& results = server_context.call_context.getResults();
297 BuildField(TypeList<>(), server_context, Make<StructField, Accessor>(results));
298}
299
300template <typename Derived, size_t N = 0>
302{
303 template <typename Arg1, typename Arg2, typename ParamList, typename NextFn, typename... NextFnArgs>
304 void handleChain(Arg1&& arg1, Arg2&& arg2, ParamList, NextFn&& next_fn, NextFnArgs&&... next_fn_args)
305 {
306 using S = Split<N, ParamList>;
307 handleChain(std::forward<Arg1>(arg1), std::forward<Arg2>(arg2), typename S::First());
308 next_fn.handleChain(std::forward<Arg1>(arg1), std::forward<Arg2>(arg2), typename S::Second(),
309 std::forward<NextFnArgs>(next_fn_args)...);
310 }
311
312 template <typename Arg1, typename Arg2, typename ParamList>
313 void handleChain(Arg1&& arg1, Arg2&& arg2, ParamList)
314 {
315 static_cast<Derived*>(this)->handleField(std::forward<Arg1>(arg1), std::forward<Arg2>(arg2), ParamList());
316 }
317private:
319 friend Derived;
320};
321
322struct IterateFields : IterateFieldsHelper<IterateFields, 0>
323{
324 template <typename Arg1, typename Arg2, typename ParamList>
325 void handleField(Arg1&&, Arg2&&, ParamList)
326 {
327 }
328};
329
330template <typename Exception, typename Accessor>
332{
333 struct BuildParams : IterateFieldsHelper<BuildParams, 0>
334 {
335 template <typename Params, typename ParamList>
336 void handleField(InvokeContext& invoke_context, Params& params, ParamList)
337 {
338 }
339
340 BuildParams(ClientException* client_exception) : m_client_exception(client_exception) {}
342 };
343
344 struct ReadResults : IterateFieldsHelper<ReadResults, 0>
345 {
346 template <typename Results, typename ParamList>
347 void handleField(InvokeContext& invoke_context, Results& results, ParamList)
348 {
349 StructField<Accessor, Results> input(results);
350 if (input.has()) {
351 ThrowField(TypeList<Exception>(), invoke_context, input);
352 }
353 }
354
355 ReadResults(ClientException* client_exception) : m_client_exception(client_exception) {}
357 };
358};
359
360template <typename Accessor, typename... Types>
362{
363 ClientParam(Types&&... values) : m_values(values...) {}
364
365 struct BuildParams : IterateFieldsHelper<BuildParams, sizeof...(Types)>
366 {
367 template <typename... Args>
368 void handleField(Args&&... args)
369 {
370 callBuild<0>(std::forward<Args>(args)...);
371 }
372
373 // TODO Possible optimization to speed up compile time:
374 // https://stackoverflow.com/a/7858971 Using enable_if below to check
375 // position when unpacking tuple might be slower than pattern matching
376 // approach in the stack overflow solution
377 template <size_t I, typename... Args>
378 auto callBuild(Args&&... args) -> std::enable_if_t<(I < sizeof...(Types))>
379 {
380 callBuild<I + 1>(std::forward<Args>(args)..., std::get<I>(m_client_param->m_values));
381 }
382
383 template <size_t I, typename Params, typename ParamList, typename... Values>
384 auto callBuild(ClientInvokeContext& invoke_context, Params& params, ParamList, Values&&... values) ->
385 std::enable_if_t<(I == sizeof...(Types))>
386 {
387 MaybeBuildField(std::integral_constant<bool, Accessor::in>(), ParamList(), invoke_context,
388 Make<StructField, Accessor>(params), std::forward<Values>(values)...);
390 ParamList(), Priority<1>(), std::forward<Values>(values)..., Make<StructField, Accessor>(params));
391 }
392
393 BuildParams(ClientParam* client_param) : m_client_param(client_param) {}
395 };
396
397 struct ReadResults : IterateFieldsHelper<ReadResults, sizeof...(Types)>
398 {
399 template <typename... Args>
400 void handleField(Args&&... args)
401 {
402 callRead<0>(std::forward<Args>(args)...);
403 }
404
405 template <int I, typename... Args>
406 auto callRead(Args&&... args) -> std::enable_if_t<(I < sizeof...(Types))>
407 {
408 callRead<I + 1>(std::forward<Args>(args)..., std::get<I>(m_client_param->m_values));
409 }
410
411 template <int I, typename Results, typename... Params, typename... Values>
412 auto callRead(ClientInvokeContext& invoke_context, Results& results, TypeList<Params...>, Values&&... values)
413 -> std::enable_if_t<I == sizeof...(Types)>
414 {
415 MaybeReadField(std::integral_constant<bool, Accessor::out>(), TypeList<Decay<Params>...>(), invoke_context,
416 Make<StructField, Accessor>(results), ReadDestUpdate(values)...);
417 }
418
419 ReadResults(ClientParam* client_param) : m_client_param(client_param) {}
421 };
422
423 std::tuple<Types&&...> m_values;
424};
425
426template <typename Accessor, typename... Types>
428{
429 return {std::forward<Types>(values)...};
430}
431
433{
434 // FIXME: maybe call call_context.releaseParams()
435 template <typename ServerContext, typename... Args>
436 decltype(auto) invoke(ServerContext& server_context, TypeList<>, Args&&... args) const
437 {
438 return ProxyServerMethodTraits<typename decltype(server_context.call_context.getParams())::Reads>::invoke(
439 server_context,
440 std::forward<Args>(args)...);
441 }
442};
443
445{
446 template <typename ServerContext, typename... Args>
447 void invoke(ServerContext& server_context, TypeList<>, Args&&... args) const
448 {
449 server_context.proxy_server.invokeDestroy(std::forward<Args>(args)...);
450 }
451};
452
453template <typename Accessor, typename Parent>
454struct ServerRet : Parent
455{
456 ServerRet(Parent parent) : Parent(parent) {}
457
458 template <typename ServerContext, typename... Args>
459 void invoke(ServerContext& server_context, TypeList<>, Args&&... args) const
460 {
461 auto&& result = Parent::invoke(server_context, TypeList<>(), std::forward<Args>(args)...);
462 auto&& results = server_context.call_context.getResults();
463 InvokeContext& invoke_context = server_context;
464 BuildField(TypeList<decltype(result)>(), invoke_context, Make<StructField, Accessor>(results),
465 std::forward<decltype(result)>(result));
466 }
467};
468
469template <typename Exception, typename Accessor, typename Parent>
470struct ServerExcept : Parent
471{
472 ServerExcept(Parent parent) : Parent(parent) {}
473
474 template <typename ServerContext, typename... Args>
475 void invoke(ServerContext& server_context, TypeList<>, Args&&... args) const
476 {
477 try {
478 return Parent::invoke(server_context, TypeList<>(), std::forward<Args>(args)...);
479 } catch (const Exception& exception) {
480 auto&& results = server_context.call_context.getResults();
481 BuildField(TypeList<Exception>(), server_context, Make<StructField, Accessor>(results), exception);
482 }
483 }
484};
485
488template <typename Accessor, typename Message>
489decltype(auto) MaybeGet(Message&& message, decltype(Accessor::get(message))* enable = nullptr)
490{
491 return Accessor::get(message);
492}
493
494template <typename Accessor>
495::capnp::Void MaybeGet(...)
496{
497 return {};
498}
499
500template <class Accessor>
502
513template <typename Accessor, typename... Args>
514auto PassField(Priority<2>, Args&&... args) -> decltype(CustomPassField<Accessor>(std::forward<Args>(args)...))
515{
516 return CustomPassField<Accessor>(std::forward<Args>(args)...);
517};
518
519template <int argc, typename Accessor, typename Parent>
520struct ServerField : Parent
521{
522 ServerField(Parent parent) : Parent(parent) {}
523
524 const Parent& parent() const { return *this; }
525
526 template <typename ServerContext, typename ArgTypes, typename... Args>
527 decltype(auto) invoke(ServerContext& server_context, ArgTypes, Args&&... args) const
528 {
529 return PassField<Accessor>(Priority<2>(),
531 server_context,
532 this->parent(),
534 std::forward<Args>(args)...);
535 }
536};
537
538template <int argc, typename Accessor, typename Parent>
540{
541 return {parent};
542}
543
544template <typename Request>
546
547template <typename _Params, typename _Results>
548struct CapRequestTraits<::capnp::Request<_Params, _Results>>
549{
550 using Params = _Params;
551 using Results = _Results;
552};
553
557template <typename Client>
558void clientDestroy(Client& client)
559{
560 if (client.m_context.connection) {
561 client.m_context.connection->m_loop.log() << "IPC client destroy " << typeid(client).name();
562 } else {
563 KJ_LOG(INFO, "IPC interrupted client destroy", typeid(client).name());
564 }
565}
566
567template <typename Server>
568void serverDestroy(Server& server)
569{
570 server.m_context.connection->m_loop.log() << "IPC server destroy " << typeid(server).name();
571}
572
582template <typename ProxyClient, typename GetRequest, typename... FieldObjs>
583void clientInvoke(ProxyClient& proxy_client, const GetRequest& get_request, FieldObjs&&... fields)
584{
585 if (!proxy_client.m_context.connection) {
586 throw std::logic_error("clientInvoke call made after disconnect");
587 }
590 g_thread_context.thread_name = ThreadName(proxy_client.m_context.connection->m_loop.m_exe_name);
591 // If next assert triggers, it means clientInvoke is being called from
592 // the capnp event loop thread. This can happen when a ProxyServer
593 // method implementation that runs synchronously on the event loop
594 // thread tries to make a blocking callback to the client. Any server
595 // method that makes a blocking callback or blocks in general needs to
596 // run asynchronously off the event loop thread. This is easy to fix by
597 // just adding a 'context :Proxy.Context' argument to the capnp method
598 // declaration so the server method runs in a dedicated thread.
600 g_thread_context.waiter = std::make_unique<Waiter>();
601 proxy_client.m_context.connection->m_loop.logPlain()
603 << "} IPC client first request from current thread, constructing waiter";
604 }
605 ClientInvokeContext invoke_context{*proxy_client.m_context.connection, g_thread_context};
606 std::exception_ptr exception;
607 std::string kj_exception;
608 bool done = false;
609 proxy_client.m_context.connection->m_loop.sync([&]() {
610 auto request = (proxy_client.m_client.*get_request)(nullptr);
611 using Request = CapRequestTraits<decltype(request)>;
613 IterateFields().handleChain(invoke_context, request, FieldList(), typename FieldObjs::BuildParams{&fields}...);
614 proxy_client.m_context.connection->m_loop.logPlain()
615 << "{" << invoke_context.thread_context.thread_name << "} IPC client send "
616 << TypeName<typename Request::Params>() << " " << LogEscape(request.toString());
617
618 proxy_client.m_context.connection->m_loop.m_task_set->add(request.send().then(
619 [&](::capnp::Response<typename Request::Results>&& response) {
620 proxy_client.m_context.connection->m_loop.logPlain()
621 << "{" << invoke_context.thread_context.thread_name << "} IPC client recv "
622 << TypeName<typename Request::Results>() << " " << LogEscape(response.toString());
623 try {
624 IterateFields().handleChain(
625 invoke_context, response, FieldList(), typename FieldObjs::ReadResults{&fields}...);
626 } catch (...) {
627 exception = std::current_exception();
628 }
629 const std::unique_lock<std::mutex> lock(invoke_context.thread_context.waiter->m_mutex);
630 done = true;
631 invoke_context.thread_context.waiter->m_cv.notify_all();
632 },
633 [&](const ::kj::Exception& e) {
634 kj_exception = kj::str("kj::Exception: ", e).cStr();
635 proxy_client.m_context.connection->m_loop.logPlain()
636 << "{" << invoke_context.thread_context.thread_name << "} IPC client exception " << kj_exception;
637 const std::unique_lock<std::mutex> lock(invoke_context.thread_context.waiter->m_mutex);
638 done = true;
639 invoke_context.thread_context.waiter->m_cv.notify_all();
640 }));
641 });
642
643 std::unique_lock<std::mutex> lock(invoke_context.thread_context.waiter->m_mutex);
644 invoke_context.thread_context.waiter->wait(lock, [&done]() { return done; });
645 if (exception) std::rethrow_exception(exception);
646 if (!kj_exception.empty()) proxy_client.m_context.connection->m_loop.raise() << kj_exception;
647}
648
652template <typename Fn, typename Ret>
653auto ReplaceVoid(Fn&& fn, Ret&& ret) ->
654 std::enable_if_t<std::is_same_v<void, decltype(fn())>, decltype(ret())>
655{
656 fn();
657 return ret();
658}
659
661template <typename Fn, typename Ret>
662auto ReplaceVoid(Fn&& fn, Ret&& ret) ->
663 std::enable_if_t<!std::is_same_v<void, decltype(fn())>, decltype(fn())>
664{
665 return fn();
666}
667
668extern std::atomic<int> server_reqs;
669
677template <typename Server, typename CallContext, typename Fn>
678kj::Promise<void> serverInvoke(Server& server, CallContext& call_context, Fn fn)
679{
680 auto params = call_context.getParams();
681 using Params = decltype(params);
682 using Results = typename decltype(call_context.getResults())::Builds;
683
684 int req = ++server_reqs;
685 server.m_context.connection->m_loop.log() << "IPC server recv request #" << req << " "
686 << TypeName<typename Params::Reads>() << " " << LogEscape(params.toString());
687
688 try {
691 ServerContext server_context{server, call_context, req};
692 // ReplaceVoid is used to support fn.invoke implementations that
693 // execute asynchronously and return promises, as well as
694 // implementations that execute synchronously and return void. The
695 // invoke function will be synchronous by default, but asynchronous if
696 // an mp.Context argument is passed, and the mp.Context PassField
697 // overload returns a promise executing the request in a worker thread
698 // and waiting for it to complete.
699 return ReplaceVoid([&]() { return fn.invoke(server_context, ArgList()); },
700 [&]() { return kj::Promise<CallContext>(kj::mv(call_context)); })
701 .then([&server, req](CallContext call_context) {
702 server.m_context.connection->m_loop.log() << "IPC server send response #" << req << " " << TypeName<Results>()
703 << " " << LogEscape(call_context.getResults().toString());
704 });
705 } catch (const std::exception& e) {
706 server.m_context.connection->m_loop.log() << "IPC server unhandled exception: " << e.what();
707 throw;
708 } catch (...) {
709 server.m_context.connection->m_loop.log() << "IPC server unhandled exception";
710 throw;
711 }
712}
713
717 template<typename Interface>
719 types().emplace(typeid(Interface), [](void* iface) -> ProxyContext& { return static_cast<typename mp::ProxyType<Interface>::Client&>(*static_cast<Interface*>(iface)).m_context; });
720 }
721 using Types = std::map<std::type_index, ProxyContext&(*)(void*)>;
722 static Types& types() { static Types types; return types; }
723};
724
725} // namespace mp
726
727#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:233
void clientDestroy(Client &client)
Entry point called by all generated ProxyClient destructors.
Definition: proxy-types.h:558
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:583
auto ReplaceVoid(Fn &&fn, Ret &&ret) -> std::enable_if_t< std::is_same_v< void, decltype(fn())>, decltype(ret())>
Invoke callable fn() that may return void.
Definition: proxy-types.h:653
void CustomPassField()
ClientParam< Accessor, Types... > MakeClientParam(Types &&... values)
Definition: proxy-types.h:427
bool CustomHasValue(InvokeContext &invoke_context, Values &&... value)
Definition: proxy-types.h:169
void MaybeReadField(std::true_type, Args &&... args)
Definition: proxy-types.h:242
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:678
void BuildField(TypeList< LocalTypes... >, Context &context, Output &&output, Values &&... values)
Definition: proxy-types.h:175
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:216
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:151
ServerInvokeContext< ProxyServer< Interface >, ::capnp::CallContext< Params, Results > > ServerContext
Definition: proxy-io.h:56
void serverDestroy(Server &server)
Definition: proxy-types.h:568
thread_local ThreadContext g_thread_context
Definition: proxy.cpp:43
void MaybeSetWant(TypeList< LocalType * >, Priority< 1 >, Value &&value, Output &&output)
Definition: proxy-types.h:252
decltype(auto) ReadField(TypeList< LocalTypes... >, Args &&... args)
Definition: proxy-types.h:145
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:107
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:489
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:539
#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:277
static const bool in
Definition: proxy.h:278
void handleField(InvokeContext &invoke_context, Params &params, ParamList)
Definition: proxy-types.h:336
ClientException * m_client_exception
Definition: proxy-types.h:341
BuildParams(ClientException *client_exception)
Definition: proxy-types.h:340
void handleField(InvokeContext &invoke_context, Results &results, ParamList)
Definition: proxy-types.h:347
ReadResults(ClientException *client_exception)
Definition: proxy-types.h:355
ClientException * m_client_exception
Definition: proxy-types.h:356
void handleField(Args &&... args)
Definition: proxy-types.h:368
BuildParams(ClientParam *client_param)
Definition: proxy-types.h:393
auto callBuild(Args &&... args) -> std::enable_if_t<(I< sizeof...(Types))>
Definition: proxy-types.h:378
auto callBuild(ClientInvokeContext &invoke_context, Params &params, ParamList, Values &&... values) -> std::enable_if_t<(I==sizeof...(Types))>
Definition: proxy-types.h:384
auto callRead(Args &&... args) -> std::enable_if_t<(I< sizeof...(Types))>
Definition: proxy-types.h:406
auto callRead(ClientInvokeContext &invoke_context, Results &results, TypeList< Params... >, Values &&... values) -> std::enable_if_t< I==sizeof...(Types)>
Definition: proxy-types.h:412
ReadResults(ClientParam *client_param)
Definition: proxy-types.h:419
void handleField(Args &&... args)
Definition: proxy-types.h:400
ClientParam(Types &&... values)
Definition: proxy-types.h:363
std::tuple< Types &&... > m_values
Definition: proxy-types.h:423
void handleChain(Arg1 &&arg1, Arg2 &&arg2, ParamList, NextFn &&next_fn, NextFnArgs &&... next_fn_args)
Definition: proxy-types.h:304
void handleChain(Arg1 &&arg1, Arg2 &&arg2, ParamList)
Definition: proxy-types.h:313
void handleField(Arg1 &&, Arg2 &&, ParamList)
Definition: proxy-types.h:325
decltype(auto) set(Arg &&arg) const
Definition: proxy-types.h:203
decltype(auto) init(Arg &&arg) const
Definition: proxy-types.h:204
typename ::capnp::List< T, kind >::Builder Builder
Definition: proxy-types.h:194
ListOutput(Builder &builder, size_t index)
Definition: proxy-types.h:196
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:265
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:716
static Types & types()
Definition: proxy-types.h:722
ProxyTypeRegister(TypeList< Interface >)
Definition: proxy-types.h:718
std::map< std::type_index, ProxyContext &(*)(void *)> Types
Definition: proxy-types.h:721
EmplaceFn & m_emplace_fn
Definition: proxy-types.h:101
decltype(auto) construct(Args &&... args)
Simple case.
Definition: proxy-types.h:75
ReadDestEmplace(TypeList< LocalType >, EmplaceFn &&emplace_fn)
Definition: proxy-types.h:70
decltype(auto) update(UpdateFn &&update_fn)
More complicated case.
Definition: proxy-types.h:85
Destination parameter type that can be passed to ReadField function as an alternative to ReadDestEmpl...
Definition: proxy-types.h:120
Value & update(UpdateFn &&update_fn)
Simple case. If ReadField works by calling update() just forward arguments to update_fn.
Definition: proxy-types.h:125
Value & construct(Args &&... args)
More complicated case.
Definition: proxy-types.h:134
ReadDestUpdate(Value &value)
Definition: proxy-types.h:121
decltype(auto) invoke(ServerContext &server_context, TypeList<>, Args &&... args) const
Definition: proxy-types.h:436
void invoke(ServerContext &server_context, TypeList<>, Args &&... args) const
Definition: proxy-types.h:447
ServerExcept(Parent parent)
Definition: proxy-types.h:472
void invoke(ServerContext &server_context, TypeList<>, Args &&... args) const
Definition: proxy-types.h:475
ServerField(Parent parent)
Definition: proxy-types.h:522
decltype(auto) invoke(ServerContext &server_context, ArgTypes, Args &&... args) const
Definition: proxy-types.h:527
const Parent & parent() const
Definition: proxy-types.h:524
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:459
ServerRet(Parent parent)
Definition: proxy-types.h:456
Type helper splitting a TypeList into two halves at position index.
Definition: util.h:57
StructField(S &struct_)
Definition: proxy-types.h:35
auto has() const -> std::enable_if_t<!A::optional &&A::boxed, bool >
Definition: proxy-types.h:43
decltype(auto) set(Args &&... args) const
Definition: proxy-types.h:47
auto setWant() const -> std::enable_if_t< A::requested >
Definition: proxy-types.h:51
auto setWant() const -> std::enable_if_t<!A::requested >
Definition: proxy-types.h:52
decltype(auto) init(Args &&... args) const
Definition: proxy-types.h:48
auto has() const -> std::enable_if_t< A::optional, bool >
Definition: proxy-types.h:42
auto setHas() const -> std::enable_if_t< A::optional >
Definition: proxy-types.h:49
auto want() const -> std::enable_if_t<!A::requested, bool >
Definition: proxy-types.h:46
auto want() const -> std::enable_if_t< A::requested, bool >
Definition: proxy-types.h:45
auto has() const -> std::enable_if_t<!A::optional &&!A::boxed, bool >
Definition: proxy-types.h:44
Struct & m_struct
Definition: proxy-types.h:38
auto setHas() const -> std::enable_if_t<!A::optional >
Definition: proxy-types.h:50
auto get() const -> decltype(A::get(this->m_struct))
Definition: proxy-types.h:41
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())