5#ifndef MP_PROXY_TYPES_H
6#define MP_PROXY_TYPES_H
18template <
typename Value>
28 bool has() {
return true; }
31template <
typename Accessor,
typename Struct>
40 decltype(
auto)
get()
const {
return Accessor::get(this->m_struct); }
60 template <
typename... Args>
decltype(
auto)
set(Args &&...
args)
const {
61 return Accessor::set(this->m_struct, std::forward<Args>(
args)...);
64 template <
typename... Args>
decltype(
auto)
init(Args &&...
args)
const {
92template <
typename LocalType,
typename EmplaceFn>
99 template <
typename... Args>
109 template <
typename UpdateFn>
110 decltype(
auto)
update(UpdateFn&& update_fn)
112 if constexpr (std::is_const_v<std::remove_reference_t<std::invoke_result_t<EmplaceFn>>>) {
116 std::remove_cv_t<LocalType> temp;
131template <
typename LocalType>
135 return LocalType{std::forward<decltype(args)>(
args)...};
143template <
typename Value>
149 template <
typename UpdateFn>
158 template <
typename... Args>
169template <
typename... LocalTypes,
typename... Args>
175template <
typename LocalType,
typename Input>
180 [](
auto&& ...
args) ->
const LocalType& {
throw LocalType{std::forward<decltype(args)>(
args)...}; }));
186template <
typename Input>
189 auto data = input.get();
193template <
typename... Values>
199template <
typename... LocalTypes,
typename Context,
typename... Values,
typename Output>
204 std::forward<Output>(output));
213template <
typename ListType>
216template <
typename T, ::capnp::Kind kind>
219 using Builder = typename ::capnp::List<T, kind>::Builder;
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)); }
233template <
typename LocalType,
typename Value,
typename Output>
236 output.set(
BuildPrimitive(invoke_context, std::forward<Value>(value),
TypeList<
decltype(output.get())>()));
240template <
typename Accessor,
typename LocalType,
typename ServerContext,
typename Fn,
typename... Args>
242 ->
Require<
typename decltype(Accessor::get(server_context.call_context.getParams()))::Calls>
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);
257template <
typename... Args>
262template <
typename... Args>
266template <
typename... Args>
271template <
typename... Args>
276template <
typename LocalType,
typename Value,
typename Output>
284template <
typename LocalTypes,
typename... Args>
290template <
typename Accessor,
typename LocalType,
typename ServerContext,
typename Fn,
typename... Args>
295 std::optional<ArgType> param;
296 const auto& params = server_context.
call_context.getParams();
299 param.emplace(std::forward<
decltype(
args)>(
args)...);
305 if (!param) param.emplace();
307 fn.invoke(server_context, std::forward<Args>(
args)...,
static_cast<LocalType&&
>(*param));
308 auto&& results = server_context.
call_context.getResults();
310 Make<StructField, Accessor>(results), *param);
314template <
typename Accessor,
typename ServerContext,
typename Fn,
typename... Args>
317 const auto& params = server_context.
call_context.getParams();
318 const auto& input = Make<StructField, Accessor>(params);
320 fn.invoke(server_context, std::forward<Args>(
args)...);
321 auto&& results = server_context.
call_context.getResults();
325template <
typename Derived,
size_t N = 0>
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)
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)...);
337 template <
typename Arg1,
typename Arg2,
typename ParamList>
340 static_cast<Derived*
>(
this)->handleField(std::forward<Arg1>(arg1), std::forward<Arg2>(arg2), ParamList());
349 template <
typename Arg1,
typename Arg2,
typename ParamList>
355template <
typename Exception,
typename Accessor>
360 template <
typename Params,
typename ParamList>
371 template <
typename Results,
typename ParamList>
385template <
typename Accessor,
typename... Types>
392 template <
typename Params,
typename ParamList>
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));
418 template <
typename Results,
typename...
Params>
421 auto const fun = [&]<
typename... Values>(Values&&...
values) {
436template <
typename Accessor,
typename... Types>
439 return {std::forward<Types>(
values)...};
450 std::forward<Args>(
args)...);
463template <
typename Accessor,
typename Parent>
471 auto&& result = Parent::invoke(server_context,
TypeList<>(), std::forward<Args>(
args)...);
472 auto&& results = server_context.
call_context.getResults();
474 BuildField(
TypeList<
decltype(result)>(), invoke_context, Make<StructField, Accessor>(results),
475 std::forward<
decltype(result)>(result));
479template <
typename Exception,
typename Accessor,
typename Parent>
488 return Parent::invoke(server_context,
TypeList<>(), std::forward<Args>(
args)...);
489 }
catch (
const Exception& exception) {
490 auto&& results = server_context.
call_context.getResults();
498template <
typename Accessor,
typename Message>
499decltype(
auto)
MaybeGet(Message&& message,
decltype(Accessor::get(message))* enable =
nullptr)
501 return Accessor::get(message);
504template <
typename Accessor>
510template <
class Accessor>
523template <
typename Accessor,
typename... Args>
526 return CustomPassField<Accessor>(std::forward<Args>(
args)...);
529template <
int argc,
typename Accessor,
typename Parent>
534 const Parent&
parent()
const {
return *
this; }
536 template <
typename ServerContext,
typename ArgTypes,
typename... Args>
544 std::forward<Args>(
args)...);
548template <
int argc,
typename Accessor,
typename Parent>
554template <
typename Request>
557template <
typename _Params,
typename _Results>
567template <
typename Client>
570 if (client.m_context.connection) {
571 client.m_context.connection->m_loop.log() <<
"IPC client destroy " <<
typeid(client).
name();
573 KJ_LOG(INFO,
"IPC interrupted client destroy",
typeid(client).
name());
577template <
typename Server>
580 server.m_context.connection->m_loop.log() <<
"IPC server destroy " <<
typeid(server).
name();
592template <
typename ProxyClient,
typename GetRequest,
typename... FieldObjs>
595 if (!proxy_client.m_context.connection) {
596 throw std::logic_error(
"clientInvoke call made after disconnect");
611 proxy_client.m_context.connection->m_loop.logPlain()
613 <<
"} IPC client first request from current thread, constructing waiter";
616 std::exception_ptr exception;
617 std::string kj_exception;
619 proxy_client.m_context.connection->m_loop.sync([&]() {
620 auto request = (proxy_client.m_client.*get_request)(
nullptr);
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());
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());
634 IterateFields().handleChain(
635 invoke_context, response, FieldList(), typename FieldObjs::ReadResults{&fields}...);
637 exception = std::current_exception();
639 const std::unique_lock<std::mutex> lock(invoke_context.thread_context.waiter->m_mutex);
641 invoke_context.thread_context.waiter->m_cv.notify_all();
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);
649 invoke_context.thread_context.waiter->m_cv.notify_all();
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;
662template <
typename Fn,
typename Ret>
665 if constexpr (std::is_same_v<
decltype(fn()),
void>) {
682template <
typename Server,
typename CallContext,
typename Fn>
683kj::Promise<void>
serverInvoke(Server& server, CallContext& call_context, Fn fn)
685 auto params = call_context.getParams();
686 using Params =
decltype(params);
687 using Results =
typename decltype(call_context.getResults())::Builds;
690 server.m_context.connection->m_loop.log() <<
"IPC server recv request #" << req <<
" "
691 << TypeName<typename Params::Reads>() <<
" " <<
LogEscape(params.toString());
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());
710 }
catch (
const std::exception& e) {
711 server.m_context.connection->m_loop.log() <<
"IPC server unhandled exception: " << e.what();
714 server.m_context.connection->m_loop.log() <<
"IPC server unhandled exception";
722 template<
typename Interface>
catch(const std::exception &e)
std::unique_ptr< interfaces::Init > init
const CChainParams & Params()
Return the currently selected parameters.
ValueField(Value &&value)
Functions to serialize / deserialize common bitcoin types.
void MaybeBuildField(std::true_type, Args &&... args)
void clientDestroy(Client &client)
Entry point called by all generated ProxyClient destructors.
void clientInvoke(ProxyClient &proxy_client, const GetRequest &get_request, FieldObjs &&... fields)
Entry point called by generated client code that looks like:
ClientParam< Accessor, Types... > MakeClientParam(Types &&... values)
bool CustomHasValue(InvokeContext &invoke_context, Values &&... value)
void MaybeReadField(std::true_type, Args &&... args)
kj::Promise< void > serverInvoke(Server &server, CallContext &call_context, Fn fn)
Entry point called by generated server code that looks like:
void BuildField(TypeList< LocalTypes... >, Context &context, Output &&output, Values &&... values)
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.
std::string ThreadName(const char *exe_name)
Format current thread name as "{exe_name}-{$pid}/{thread_name}-{$tid}".
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...
LocalType BuildPrimitive(InvokeContext &invoke_context, const Value &value, TypeList< LocalType >, typename std::enable_if< std::is_enum< Value >::value >::type *enable=nullptr)
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...
std::atomic< int > server_reqs
void ThrowField(TypeList< LocalType >, InvokeContext &invoke_context, Input &&input)
ServerInvokeContext< ProxyServer< Interface >, ::capnp::CallContext< Params, Results > > ServerContext
void serverDestroy(Server &server)
thread_local ThreadContext g_thread_context
void MaybeSetWant(TypeList< LocalType * >, Priority< 1 >, Value &&value, Output &&output)
decltype(auto) ReadField(TypeList< LocalTypes... >, Args &&... args)
std::decay_t< T > Decay
Type helper abbreviating std::decay.
auto ReadDestTemp()
Helper function to create a ReadDestEmplace object that constructs a temporary, ReadField can return.
std::remove_cv_t< std::remove_reference_t< T > > RemoveCvRef
Substitutue for std::remove_cvref_t.
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.
decltype(auto) MaybeGet(Message &&message, decltype(Accessor::get(message)) *enable=nullptr)
Helper for CustomPassField below.
auto ReplaceVoid(Fn &&fn, Ret &&ret)
Invoke callable fn() that may return void.
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...
ServerField< argc, Accessor, Parent > MakeServerField(Parent parent)
#define S(a, b, c, d, e, f, g, h, i, j, k, l, m, n, o, p)
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.
static const bool optional
static const bool requested
void handleField(InvokeContext &invoke_context, Params ¶ms, ParamList)
ClientException * m_client_exception
BuildParams(ClientException *client_exception)
void handleField(InvokeContext &invoke_context, Results &results, ParamList)
ReadResults(ClientException *client_exception)
ClientException * m_client_exception
void handleField(ClientInvokeContext &invoke_context, Params ¶ms, ParamList)
BuildParams(ClientParam *client_param)
ClientParam * m_client_param
ClientParam * m_client_param
ReadResults(ClientParam *client_param)
void handleField(ClientInvokeContext &invoke_context, Results &results, TypeList< Params... >)
ClientParam(Types &&... values)
std::tuple< Types &&... > m_values
void handleChain(Arg1 &&arg1, Arg2 &&arg2, ParamList, NextFn &&next_fn, NextFnArgs &&... next_fn_args)
IterateFieldsHelper()=default
void handleChain(Arg1 &&arg1, Arg2 &&arg2, ParamList)
void handleField(Arg1 &&, Arg2 &&, ParamList)
decltype(auto) set(Arg &&arg) const
decltype(auto) init(Arg &&arg) const
decltype(auto) get() const
decltype(auto) init() const
typename ::capnp::List< T, kind >::Builder Builder
ListOutput(Builder &builder, size_t index)
Specialization of above (base case)
Function parameter type for prioritizing overloaded function calls that would otherwise be ambiguous.
Mapping from capnp interface type to proxy client implementation (specializations are generated by pr...
Context data associated with proxy client and server classes.
Customizable (through template specialization) traits class used in generated ProxyServer implementat...
Mapping from local c++ type to capnp type and traits (specializations are generated by proxy-codegen....
Map to convert client interface pointers to ProxyContext struct references at runtime using typeids.
ProxyTypeRegister(TypeList< Interface >)
std::map< std::type_index, ProxyContext &(*)(void *)> Types
decltype(auto) construct(Args &&... args)
Simple case.
ReadDestEmplace(TypeList< LocalType >, EmplaceFn &&emplace_fn)
decltype(auto) update(UpdateFn &&update_fn)
More complicated case.
Destination parameter type that can be passed to ReadField function as an alternative to ReadDestEmpl...
Value & update(UpdateFn &&update_fn)
Simple case. If ReadField works by calling update() just forward arguments to update_fn.
Value & construct(Args &&... args)
More complicated case.
ReadDestUpdate(Value &value)
decltype(auto) invoke(ServerContext &server_context, TypeList<>, Args &&... args) const
void invoke(ServerContext &server_context, TypeList<>, Args &&... args) const
ServerExcept(Parent parent)
void invoke(ServerContext &server_context, TypeList<>, Args &&... args) const
ServerField(Parent parent)
decltype(auto) invoke(ServerContext &server_context, ArgTypes, Args &&... args) const
const Parent & parent() const
CallContext & call_context
ProxyServer & proxy_server
void invoke(ServerContext &server_context, TypeList<>, Args &&... args) const
Type helper splitting a TypeList into two halves at position index.
decltype(auto) set(Args &&...args) const
decltype(auto) init(Args &&...args) const
decltype(auto) get() const
std::unique_ptr< Waiter > waiter
Waiter object used to allow client threads blocked waiting for a server response to execute callbacks...
bool loop_thread
Whether this thread is a capnp event loop thread.
std::string thread_name
Identifying string for debug.
Generic utility functions used by capnp code.