5#ifndef MP_PROXY_TYPES_H
6#define MP_PROXY_TYPES_H
18template <
typename Value>
29 bool has()
const {
return true; }
32template <
typename Accessor,
typename Struct>
41 decltype(
auto)
get()
const {
return Accessor::get(this->m_struct); }
61 template <
typename... Args>
decltype(
auto)
set(Args &&...
args)
const {
62 return Accessor::set(this->m_struct, std::forward<Args>(
args)...);
65 template <
typename... Args>
decltype(
auto)
init(Args &&...
args)
const {
66 return Accessor::init(this->m_struct, std::forward<Args>(
args)...);
93template <
typename LocalType,
typename EmplaceFn>
100 template <
typename... Args>
110 template <
typename UpdateFn>
113 if constexpr (std::is_const_v<std::remove_reference_t<std::invoke_result_t<EmplaceFn>>>) {
117 std::remove_cv_t<LocalType>
temp;
132template <
typename LocalType>
144template <
typename Value>
150 template <
typename UpdateFn>
159 template <
typename... Args>
218template <
typename LocalType,
typename Input>
229template <
typename Input>
232 auto data = input.get();
233 throw std::runtime_error(std::string(
CharCast(data.begin()), data.size()));
243template <
typename...
Values>
254 std::forward<Output>(output));
263template <
typename ListType>
266template <
typename T, ::capnp::Kind kind>
269 using Builder = typename ::capnp::List<T, kind>::Builder;
276 decltype(
auto)
get()
const {
return this->m_builder[this->m_index]; }
277 decltype(
auto)
init()
const {
return this->m_builder[this->m_index]; }
278 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)); }
279 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)); }
283template <
typename LocalType,
typename Value,
typename Output>
302 using Interface =
typename Decay<
decltype(input.get())>
::Calls;
303 auto param = std::make_unique<ProxyClient<Interface>>(input.get(),
server_context.proxy_server.m_context.connection,
false);
307template <
typename... Args>
312template <
typename... Args>
316template <
typename... Args>
321template <
typename... Args>
326template <
typename LocalType,
typename Value,
typename Output>
334template <
typename LocalTypes,
typename... Args>
345 std::optional<ArgType> param;
349 param.emplace(std::forward<
decltype(
args)>(
args)...);
355 if (!param) param.emplace();
364template <
typename Accessor,
typename ServerContext,
typename Fn,
typename... Args>
375template <
typename Derived,
size_t N = 0>
387 template <
typename Arg1,
typename Arg2,
typename ParamList>
399 template <
typename Arg1,
typename Arg2,
typename ParamList>
405template <
typename Exception,
typename Accessor>
410 template <
typename Params,
typename ParamList>
421 template <
typename Results,
typename ParamList>
435template <
typename Accessor,
typename... Types>
442 template <
typename Params,
typename ParamList>
468 template <
typename Results,
typename...
Params>
486template <
typename Accessor,
typename... Types>
489 return {std::forward<Types>(
values)...};
507 [&]() ->
decltype(
auto) {
540template <
typename Accessor,
typename Parent>
552 std::forward<
decltype(result)>(result));
556template <
typename Exception,
typename Accessor,
typename Parent>
566 }
catch (
const Exception& exception) {
575template <
typename Accessor,
typename Message>
576decltype(
auto)
MaybeGet(Message&& message,
decltype(Accessor::get(message))*
enable =
nullptr)
578 return Accessor::get(message);
581template <
typename Accessor>
587template <
class Accessor>
600template <
typename Accessor,
typename... Args>
606template <
int argc,
typename Accessor,
typename Parent>
611 const Parent&
parent()
const {
return *
this; }
621 std::forward<Args>(
args)...);
625template <
int argc,
typename Accessor,
typename Parent>
631template <
typename Request>
634template <
typename _Params,
typename _Results>
644template <
typename Client>
647 if (client.m_context.connection) {
650 KJ_LOG(INFO,
"IPC interrupted client destroy",
typeid(client).
name());
654template <
typename Server>
687 <<
"} IPC client first request from current thread, constructing waiter";
691 std::exception_ptr exception;
694 const char* disconnected =
nullptr;
697 const Lock lock(thread_context.waiter->m_mutex);
699 disconnected =
"IPC client method called after disconnect.";
700 thread_context.waiter->m_cv.notify_all();
710 <<
"{" << thread_context.thread_name <<
"} IPC client send "
713 <<
"send data: " <<
LogEscape(request.toString(),
proxy_client.m_context.loop->m_log_opts.max_chars);
715 proxy_client.m_context.loop->m_task_set->add(request.send().then(
716 [&](::capnp::Response<typename Request::Results>&&
response) {
717 MP_LOGPLAIN(*proxy_client.m_context.loop, Log::Debug)
718 <<
"{" << thread_context.thread_name <<
"} IPC client recv "
719 << TypeName<typename Request::Results>();
720 MP_LOGPLAIN(*proxy_client.m_context.loop, Log::Trace)
721 <<
"recv data: " << LogEscape(response.toString(), proxy_client.m_context.loop->m_log_opts.max_chars);
723 IterateFields().handleChain(
724 *invoke_context, response, FieldList(), typename FieldObjs::ReadResults{&fields}...);
726 exception = std::current_exception();
728 const Lock lock(thread_context.waiter->m_mutex);
730 thread_context.waiter->m_cv.notify_all();
732 [&](const ::kj::Exception&
e) {
733 if (
e.getType() == ::kj::Exception::Type::DISCONNECTED) {
734 disconnected =
"IPC client method call interrupted by disconnect.";
738 <<
"{" << thread_context.thread_name <<
"} IPC client exception " <<
kj_exception;
740 const Lock lock(thread_context.waiter->m_mutex);
742 thread_context.waiter->m_cv.notify_all();
746 Lock lock(thread_context.waiter->m_mutex);
747 thread_context.waiter->wait(lock, [&done]() {
return done; });
748 if (exception) std::rethrow_exception(exception);
756template <
typename Fn,
typename Ret>
759 if constexpr (std::is_same_v<
decltype(fn()),
void>) {
767extern std::atomic<int> server_reqs;
776template <
typename Server,
typename CallContext,
typename Fn>
777kj::Promise<void>
serverInvoke(Server& server, CallContext& call_context, Fn fn)
779 auto params = call_context.getParams();
780 using Params =
decltype(params);
781 using Results =
typename decltype(call_context.getResults())
::Builds;
784 MP_LOG(*server.m_context.loop, Log::Debug) <<
"IPC server recv request #" << req <<
" "
786 MP_LOG(*server.m_context.loop, Log::Trace) <<
"request data: "
787 <<
LogEscape(params.toString(), server.m_context.loop->m_log_opts.max_chars);
801 [&]() {
return kj::Promise<CallContext>(kj::mv(call_context)); })
802 .
then([&server, req](CallContext call_context) {
803 MP_LOG(*server.m_context.loop, Log::Debug) <<
"IPC server send response #" << req <<
" " <<
TypeName<Results>();
804 MP_LOG(*server.m_context.loop, Log::Trace) <<
"response data: "
805 <<
LogEscape(call_context.getResults().toString(), server.m_context.loop->m_log_opts.max_chars);
807 }
catch (
const std::exception&
e) {
808 MP_LOG(*server.m_context.loop, Log::Error) <<
"IPC server unhandled exception: " <<
e.what();
811 MP_LOG(*server.m_context.loop, Log::Error) <<
"IPC server unhandled exception";
819 template<
typename Interface>
catch(const std::exception &e)
const CChainParams & Params()
Return the currently selected parameters.
const Value & get() const
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:
bool CustomHasField(TypeList< LocalTypes... >, InvokeContext &invoke_context, const Input &input)
Return whether to read a C++ value from a Cap'n Proto field.
ClientParam< Accessor, Types... > MakeClientParam(Types &&... values)
void MaybeReadField(std::true_type, Args &&... args)
decltype(auto) TryFinally(Fn &&fn, After &&after)
Invoke a function and run a follow-up action before returning the original result.
kj::Promise< void > serverInvoke(Server &server, CallContext &call_context, Fn fn)
Entry point called by generated server code that looks like:
std::decay_t< T > Decay
Type helper abbreviating std::decay.
void BuildField(TypeList< LocalTypes... >, Context &context, Output &&output, Values &&... values)
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...
bool CustomHasValue(InvokeContext &invoke_context, const Values &... value)
Return whether to write a C++ value into a Cap'n Proto field.
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)
std::atomic< int > server_reqs
void ThrowField(TypeList< LocalType >, InvokeContext &invoke_context, Input &&input)
void MaybeSetWant(TypeList< LocalType * >, Priority< 1 >, const Value &value, Output &&output)
void serverDestroy(Server &server)
thread_local ThreadContext g_thread_context
std::remove_cv_t< std::remove_reference_t< T > > RemoveCvRef
Substitutue for std::remove_cvref_t.
auto ReadDestTemp()
Helper function to create a ReadDestEmplace object that constructs a temporary, ReadField can return.
decltype(auto) ReadField(TypeList< LocalTypes... >, InvokeContext &invoke_context, Input &&input, Args &&... args)
decltype(auto) MaybeGet(Message &&message, decltype(Accessor::get(message)) *enable=nullptr)
Helper for CustomPassField below.
ServerInvokeContext< ProxyServer< Interface >, ::capnp::CallContext< Params, Results > > ServerContext
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)
std::string LogEscape(const kj::StringTree &string, size_t max_size)
Escape binary string for use in log so it doesn't trigger unicode decode errors in python unit tests.
#define S(a, b, c, d, e, f, g, h, i, j, k, l, m, n, o, p)
#define MP_LOGPLAIN(loop,...)
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
Exception thrown from code executing an IPC call that is interrupted.
void handleChain(Arg1 &arg1, Arg2 &arg2, ParamList)
void handleChain(Arg1 &arg1, Arg2 &arg2, ParamList, NextFn &&next_fn, NextFnArgs &&... next_fn_args)
IterateFieldsHelper()=default
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)
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
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
The thread_local ThreadContext g_thread_context struct provides information about individual threads ...
std::unique_ptr< Waiter > waiter
Waiter object used to allow remote clients to execute code on this thread.
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.
constexpr auto Ticks(Dur2 d)
Helper to count the seconds of a duration/time_point.