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>
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> { }
67template <
typename LocalType,
typename EmplaceFn>
74 template <
typename... Args>
84 template <
typename UpdateFn>
85 decltype(
auto)
update(UpdateFn&& update_fn)
87 if constexpr (std::is_const_v<std::remove_reference_t<std::invoke_result_t<EmplaceFn>>>) {
91 std::remove_cv_t<LocalType> temp;
106template <
typename LocalType>
110 return LocalType{std::forward<decltype(args)>(
args)...};
118template <
typename Value>
124 template <
typename UpdateFn>
133 template <
typename... Args>
144template <
typename... LocalTypes,
typename... Args>
150template <
typename LocalType,
typename Input>
155 [](
auto&& ...
args) ->
const LocalType& {
throw LocalType{std::forward<decltype(args)>(
args)...}; }));
161template <
typename Input>
164 auto data = input.get();
168template <
typename... Values>
174template <
typename... LocalTypes,
typename Context,
typename... Values,
typename Output>
179 std::forward<Output>(output));
188template <
typename ListType>
191template <
typename T, ::capnp::Kind kind>
194 using Builder = typename ::capnp::List<T, kind>::Builder;
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)); }
208template <
typename LocalType,
typename Value,
typename Output>
211 output.set(
BuildPrimitive(invoke_context, std::forward<Value>(value),
TypeList<
decltype(output.get())>()));
215template <
typename Accessor,
typename LocalType,
typename ServerContext,
typename Fn,
typename... Args>
217 ->
Require<
typename decltype(Accessor::get(server_context.call_context.getParams()))::Calls>
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);
232template <
typename... Args>
237template <
typename... Args>
241template <
typename... Args>
246template <
typename... Args>
251template <
typename LocalType,
typename Value,
typename Output>
259template <
typename LocalTypes,
typename... Args>
265template <
typename Accessor,
typename LocalType,
typename ServerContext,
typename Fn,
typename... Args>
270 std::optional<ArgType> param;
271 const auto& params = server_context.
call_context.getParams();
274 param.emplace(std::forward<
decltype(
args)>(
args)...);
280 if (!param) param.emplace();
282 fn.invoke(server_context, std::forward<Args>(
args)...,
static_cast<LocalType&&
>(*param));
283 auto&& results = server_context.
call_context.getResults();
285 Make<StructField, Accessor>(results), *param);
289template <
typename Accessor,
typename ServerContext,
typename Fn,
typename... Args>
292 const auto& params = server_context.
call_context.getParams();
293 const auto& input = Make<StructField, Accessor>(params);
295 fn.invoke(server_context, std::forward<Args>(
args)...);
296 auto&& results = server_context.
call_context.getResults();
300template <
typename Derived,
size_t N = 0>
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)
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)...);
312 template <
typename Arg1,
typename Arg2,
typename ParamList>
315 static_cast<Derived*
>(
this)->handleField(std::forward<Arg1>(arg1), std::forward<Arg2>(arg2), ParamList());
324 template <
typename Arg1,
typename Arg2,
typename ParamList>
330template <
typename Exception,
typename Accessor>
335 template <
typename Params,
typename ParamList>
346 template <
typename Results,
typename ParamList>
360template <
typename Accessor,
typename... Types>
367 template <
typename... Args>
370 callBuild<0>(std::forward<Args>(
args)...);
377 template <
size_t I,
typename... Args>
383 template <
size_t I,
typename Params,
typename ParamList,
typename... Values>
385 std::enable_if_t<(I ==
sizeof...(Types))>
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));
399 template <
typename... Args>
402 callRead<0>(std::forward<Args>(
args)...);
405 template <
int I,
typename... Args>
406 auto callRead(Args&&...
args) -> std::enable_if_t<(I <
sizeof...(Types))>
411 template <
int I,
typename Results,
typename...
Params,
typename... Values>
413 -> std::enable_if_t<I ==
sizeof...(Types)>
426template <
typename Accessor,
typename... Types>
429 return {std::forward<Types>(
values)...};
440 std::forward<Args>(
args)...);
453template <
typename Accessor,
typename Parent>
461 auto&& result = Parent::invoke(server_context,
TypeList<>(), std::forward<Args>(
args)...);
462 auto&& results = server_context.
call_context.getResults();
464 BuildField(
TypeList<
decltype(result)>(), invoke_context, Make<StructField, Accessor>(results),
465 std::forward<
decltype(result)>(result));
469template <
typename Exception,
typename Accessor,
typename Parent>
478 return Parent::invoke(server_context,
TypeList<>(), std::forward<Args>(
args)...);
479 }
catch (
const Exception& exception) {
480 auto&& results = server_context.
call_context.getResults();
488template <
typename Accessor,
typename Message>
489decltype(
auto)
MaybeGet(Message&& message,
decltype(Accessor::get(message))* enable =
nullptr)
491 return Accessor::get(message);
494template <
typename Accessor>
500template <
class Accessor>
513template <
typename Accessor,
typename... Args>
516 return CustomPassField<Accessor>(std::forward<Args>(
args)...);
519template <
int argc,
typename Accessor,
typename Parent>
524 const Parent&
parent()
const {
return *
this; }
526 template <
typename ServerContext,
typename ArgTypes,
typename... Args>
534 std::forward<Args>(
args)...);
538template <
int argc,
typename Accessor,
typename Parent>
544template <
typename Request>
547template <
typename _Params,
typename _Results>
557template <
typename Client>
560 if (client.m_context.connection) {
561 client.m_context.connection->m_loop.log() <<
"IPC client destroy " <<
typeid(client).
name();
563 KJ_LOG(INFO,
"IPC interrupted client destroy",
typeid(client).
name());
567template <
typename Server>
570 server.m_context.connection->m_loop.log() <<
"IPC server destroy " <<
typeid(server).
name();
582template <
typename ProxyClient,
typename GetRequest,
typename... FieldObjs>
585 if (!proxy_client.m_context.connection) {
586 throw std::logic_error(
"clientInvoke call made after disconnect");
601 proxy_client.m_context.connection->m_loop.logPlain()
603 <<
"} IPC client first request from current thread, constructing waiter";
606 std::exception_ptr exception;
607 std::string kj_exception;
609 proxy_client.m_context.connection->m_loop.sync([&]() {
610 auto request = (proxy_client.m_client.*get_request)(
nullptr);
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());
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());
624 IterateFields().handleChain(
625 invoke_context, response, FieldList(), typename FieldObjs::ReadResults{&fields}...);
627 exception = std::current_exception();
629 const std::unique_lock<std::mutex> lock(invoke_context.thread_context.waiter->m_mutex);
631 invoke_context.thread_context.waiter->m_cv.notify_all();
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);
639 invoke_context.thread_context.waiter->m_cv.notify_all();
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;
652template <
typename Fn,
typename Ret>
654 std::enable_if_t<std::is_same_v<void,
decltype(fn())>,
decltype(
ret())>
661template <
typename Fn,
typename Ret>
663 std::enable_if_t<!std::is_same_v<void,
decltype(fn())>,
decltype(fn())>
677template <
typename Server,
typename CallContext,
typename Fn>
678kj::Promise<void>
serverInvoke(Server& server, CallContext& call_context, Fn fn)
680 auto params = call_context.getParams();
681 using Params =
decltype(params);
682 using Results =
typename decltype(call_context.getResults())::Builds;
685 server.m_context.connection->m_loop.log() <<
"IPC server recv request #" << req <<
" "
686 << TypeName<typename Params::Reads>() <<
" " <<
LogEscape(params.toString());
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());
705 }
catch (
const std::exception& e) {
706 server.m_context.connection->m_loop.log() <<
"IPC server unhandled exception: " << e.what();
709 server.m_context.connection->m_loop.log() <<
"IPC server unhandled exception";
717 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:
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.
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.
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.
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(Args &&... args)
BuildParams(ClientParam *client_param)
auto callBuild(Args &&... args) -> std::enable_if_t<(I< sizeof...(Types))>
auto callBuild(ClientInvokeContext &invoke_context, Params ¶ms, ParamList, Values &&... values) -> std::enable_if_t<(I==sizeof...(Types))>
ClientParam * m_client_param
auto callRead(Args &&... args) -> std::enable_if_t<(I< sizeof...(Types))>
auto callRead(ClientInvokeContext &invoke_context, Results &results, TypeList< Params... >, Values &&... values) -> std::enable_if_t< I==sizeof...(Types)>
ClientParam * m_client_param
ReadResults(ClientParam *client_param)
void handleField(Args &&... args)
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.
auto has() const -> std::enable_if_t<!A::optional &&A::boxed, bool >
decltype(auto) set(Args &&... args) const
auto setWant() const -> std::enable_if_t< A::requested >
auto setWant() const -> std::enable_if_t<!A::requested >
decltype(auto) init(Args &&... args) const
auto has() const -> std::enable_if_t< A::optional, bool >
auto setHas() const -> std::enable_if_t< A::optional >
auto want() const -> std::enable_if_t<!A::requested, bool >
auto want() const -> std::enable_if_t< A::requested, bool >
auto has() const -> std::enable_if_t<!A::optional &&!A::boxed, bool >
auto setHas() const -> std::enable_if_t<!A::optional >
auto get() const -> decltype(A::get(this->m_struct))
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.