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>
111 decltype(
auto)
update(UpdateFn&& update_fn)
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>
136 return LocalType{std::forward<decltype(args)>(
args)...};
144template <
typename Value>
150 template <
typename UpdateFn>
159 template <
typename... Args>
206template <
typename... LocalTypes,
typename Input>
212template <
typename... LocalTypes,
typename Input,
typename... Args>
218template <
typename LocalType,
typename Input>
223 [](
auto&& ...
args) ->
const LocalType& {
throw LocalType{std::forward<decltype(args)>(
args)...}; }));
229template <
typename Input>
232 auto data = input.get();
233 throw std::runtime_error(std::string(
CharCast(data.begin()), data.size()));
243template <
typename... Values>
249template <
typename... LocalTypes,
typename Context,
typename... Values,
typename Output>
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>
286 auto list = output.init(value.size());
288 for (
const auto& elem : value) {
294template <
typename LocalType,
typename Input,
typename ReadDest,
typename InitFn,
typename EmplaceFn>
297 return read_dest.update([&](
auto& value) {
298 auto data = input.get();
299 init(value, data.size());
300 for (
auto item : data) {
303 return emplace(value, std::forward<
decltype(
args)>(
args)...);
309template <
typename LocalType,
typename Value,
typename Output>
312 output.set(
BuildPrimitive(invoke_context, std::forward<Value>(value),
TypeList<
decltype(output.get())>()));
316template <
typename Accessor,
typename LocalType,
typename ServerContext,
typename Fn,
typename... Args>
318 ->
Require<
typename decltype(Accessor::get(server_context.call_context.getParams()))::Calls>
326 const auto& params = server_context.call_context.getParams();
328 using Interface =
typename Decay<
decltype(input.get())>::Calls;
329 auto param = std::make_unique<ProxyClient<Interface>>(input.get(), server_context.proxy_server.m_context.connection,
false);
330 fn.invoke(server_context, std::forward<Args>(
args)..., *param);
333template <
typename... Args>
338template <
typename... Args>
342template <
typename... Args>
347template <
typename... Args>
352template <
typename LocalType,
typename Value,
typename Output>
360template <
typename LocalTypes,
typename... Args>
366template <
typename Accessor,
typename LocalType,
typename ServerContext,
typename Fn,
typename... Args>
371 std::optional<ArgType> param;
372 const auto& params = server_context.
call_context.getParams();
375 param.emplace(std::forward<
decltype(
args)>(
args)...);
381 if (!param) param.emplace();
383 fn.invoke(server_context, std::forward<Args>(
args)...,
static_cast<LocalType&&
>(*param));
384 auto&& results = server_context.
call_context.getResults();
390template <
typename Accessor,
typename ServerContext,
typename Fn,
typename... Args>
393 const auto& params = server_context.
call_context.getParams();
396 fn.invoke(server_context, std::forward<Args>(
args)...);
397 auto&& results = server_context.
call_context.getResults();
401template <
typename Derived,
size_t N = 0>
404 template <
typename Arg1,
typename Arg2,
typename ParamList,
typename NextFn,
typename... NextFnArgs>
405 void handleChain(Arg1& arg1, Arg2& arg2, ParamList, NextFn&& next_fn, NextFnArgs&&... next_fn_args)
409 next_fn.handleChain(arg1, arg2,
typename S::Second(),
410 std::forward<NextFnArgs>(next_fn_args)...);
413 template <
typename Arg1,
typename Arg2,
typename ParamList>
416 static_cast<Derived*
>(
this)->handleField(arg1, arg2, ParamList());
425 template <
typename Arg1,
typename Arg2,
typename ParamList>
431template <
typename Exception,
typename Accessor>
436 template <
typename Params,
typename ParamList>
447 template <
typename Results,
typename ParamList>
461template <
typename Accessor,
typename... Types>
468 template <
typename Params,
typename ParamList>
471 auto const fun = [&]<
typename... Values>(Values&&... values) {
474 MaybeBuildField(std::integral_constant<bool, Accessor::in>(), ParamList(), invoke_context,
494 template <
typename Results,
typename...
Params>
497 auto const fun = [&]<
typename... Values>(Values&&... values) {
512template <
typename Accessor,
typename... Types>
515 return {std::forward<Types>(values)...};
533 [&]() ->
decltype(
auto) {
535 typename decltype(server_context.
call_context.getParams())::Reads
566template <
typename Accessor,
typename Parent>
574 auto&& result = Parent::invoke(server_context,
TypeList<>(), std::forward<Args>(
args)...);
575 auto&& results = server_context.
call_context.getResults();
578 std::forward<
decltype(result)>(result));
582template <
typename Exception,
typename Accessor,
typename Parent>
591 return Parent::invoke(server_context,
TypeList<>(), std::forward<Args>(
args)...);
592 }
catch (
const Exception& exception) {
593 auto&& results = server_context.
call_context.getResults();
601template <
typename Accessor,
typename Message>
602decltype(
auto)
MaybeGet(Message&& message,
decltype(Accessor::get(message))* enable =
nullptr)
604 return Accessor::get(message);
607template <
typename Accessor>
613template <
class Accessor>
626template <
typename Accessor,
typename... Args>
632template <
int argc,
typename Accessor,
typename Parent>
637 const Parent&
parent()
const {
return *
this; }
639 template <
typename ServerContext,
typename ArgTypes,
typename... Args>
647 std::forward<Args>(
args)...);
651template <
int argc,
typename Accessor,
typename Parent>
657template <
typename Request>
660template <
typename _Params,
typename _Results>
670template <
typename Client>
676template <
typename Server>
691template <
typename ProxyClient,
typename GetRequest,
typename... FieldObjs>
709 <<
"} IPC client first request from current thread, constructing waiter";
712 std::optional<ClientInvokeContext> invoke_context;
713 std::exception_ptr exception;
714 std::string kj_exception;
716 const char* disconnected =
nullptr;
717 proxy_client.m_context.loop->sync([&]() {
718 if (!proxy_client.m_context.connection) {
719 const Lock lock(thread_context.
waiter->m_mutex);
721 disconnected =
"IPC client method called after disconnect.";
722 thread_context.
waiter->m_cv.notify_all();
726 auto request = (proxy_client.m_client.*get_request)(
nullptr);
729 invoke_context.emplace(*proxy_client.m_context.connection, thread_context);
732 <<
"{" << thread_context.
thread_name <<
"} IPC client send "
735 <<
"send data: " <<
LogEscape(
request.toString(), proxy_client.m_context.loop->m_log_opts.max_chars);
737 proxy_client.m_context.loop->m_task_set->add(
request.send().then(
738 [&](::capnp::Response<typename Request::Results>&& response) {
739 MP_LOGPLAIN(*proxy_client.m_context.loop, Log::Debug)
740 <<
"{" << thread_context.thread_name <<
"} IPC client recv "
741 << TypeName<typename Request::Results>();
742 MP_LOGPLAIN(*proxy_client.m_context.loop, Log::Trace)
743 <<
"recv data: " << LogEscape(response.toString(), proxy_client.m_context.loop->m_log_opts.max_chars);
745 IterateFields().handleChain(
746 *invoke_context, response, FieldList(), typename FieldObjs::ReadResults{&fields}...);
748 exception = std::current_exception();
750 const Lock lock(thread_context.
waiter->m_mutex);
752 thread_context.
waiter->m_cv.notify_all();
754 [&](const ::kj::Exception& e) {
755 if (e.getType() == ::kj::Exception::Type::DISCONNECTED) {
756 disconnected =
"IPC client method call interrupted by disconnect.";
758 kj_exception = kj::str(
"kj::Exception: ", e).cStr();
760 <<
"{" << thread_context.
thread_name <<
"} IPC client exception " << kj_exception;
762 const Lock lock(thread_context.
waiter->m_mutex);
764 thread_context.
waiter->m_cv.notify_all();
768 Lock lock(thread_context.waiter->m_mutex);
769 thread_context.waiter->wait(lock, [&done]() {
return done; });
770 if (exception) std::rethrow_exception(exception);
778template <
typename Fn,
typename Ret>
781 if constexpr (std::is_same_v<
decltype(fn()),
void>) {
789extern std::atomic<int> server_reqs;
798template <
typename Server,
typename CallContext,
typename Fn>
799kj::Promise<void>
serverInvoke(Server& server, CallContext& call_context, Fn fn)
801 auto params = call_context.getParams();
802 using Params =
decltype(params);
803 using Results =
typename decltype(call_context.getResults())::Builds;
805 EventLoop& loop = *server.m_context.loop;
810 <<
LogEscape(params.toString(), server.m_context.loop->m_log_opts.max_chars);
823 return ReplaceVoid([&]() {
return fn.invoke(server_context, ArgList()); },
824 [&]() {
return kj::Promise<CallContext>(kj::mv(call_context)); })
825 .then([&loop,
req](CallContext call_context) {
829 }).catch_([&loop,
req](::kj::Exception&& e) -> kj::Promise<void> {
834 <<
" " << kj::str(
"kj::Exception: ", e.getDescription()).cStr();
837 }
catch (
const std::exception& e) {
849 template<
typename Interface>
catch(const std::exception &e)
const CChainParams & Params()
Return the currently selected parameters.
LogOptions m_log_opts
Logging options.
std::unique_lock< std::mutex > m_lock
const Value & get() const
ValueField(Value &&value)
const std::string request
Functions to serialize / deserialize common bitcoin types.
void MaybeBuildField(std::true_type, Args &&... args)
void clientDestroy(Client &client)
std::string CxxTypeName(const T &)
void clientInvoke(ProxyClient &proxy_client, const GetRequest &get_request, FieldObjs &&... fields)
const char * TypeName()
Return capnp type name with filename prefix removed.
void BuildList(TypeList< LocalType >, InvokeContext &invoke_context, Output &&output, Value &&value)
ClientParam< Accessor, Types... > MakeClientParam(Types &&... values)
void MaybeReadField(std::true_type, Args &&... args)
decltype(auto) TryFinally(Fn &&fn, After &&after)
kj::Promise< void > serverInvoke(Server &server, CallContext &call_context, Fn fn)
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)
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)
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)
Class< Types..., std::remove_reference_t< Args >... > Make(Args &&... args)
std::remove_cv_t< std::remove_reference_t< T > > RemoveCvRef
Substitutue for std::remove_cvref_t.
ThreadContext g_thread_context
decltype(auto) ReadField(TypeList< LocalTypes... >, InvokeContext &invoke_context, Input &&input, Args &&... args)
decltype(auto) MaybeGet(Message &&message, decltype(Accessor::get(message)) *enable=nullptr)
ServerInvokeContext< ProxyServer< Interface >, ::capnp::CallContext< Params, Results > > ServerContext
auto ReplaceVoid(Fn &&fn, Ret &&ret)
decltype(auto) ReadList(TypeList< LocalType >, InvokeContext &invoke_context, Input &&input, ReadDest &&read_dest, InitFn &&init, EmplaceFn &&emplace)
void CustomBuildField(TypeList< LocalType >, Priority< 1 >, InvokeContext &invoke_context, Value &&value, Output &&output)
ServerField< argc, Accessor, Parent > MakeServerField(Parent parent)
std::string LogEscape(const kj::StringTree &string, size_t max_size)
bool CustomHasField(TypeList< CTransaction >, InvokeContext &invoke_context, const Input &input)
#define S(a, b, c, d, e, f, g, h, i, j, k, l, m, n, o, p)
#define MP_LOGPLAIN(loop,...)
Accessor type holding flags that determine how to access a message field.
static const bool optional
static const bool requested
static const bool in
Field is present from the Cap'n Proto Params struct (client -> server).
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)
Context data associated with proxy client and server classes.
Mapping from local c++ type to capnp type and traits (specializations are generated by proxy-codegen....
ProxyTypeRegister(TypeList< Interface >)
std::map< std::type_index, ProxyContext &(*)(void *)> Types
decltype(auto) construct(Args &&... args)
ReadDestEmplace(TypeList< LocalType >, EmplaceFn emplace_fn)
decltype(auto) update(UpdateFn &&update_fn)
Value & update(UpdateFn &&update_fn)
Simple case. If ReadField works by calling update() just forward arguments to update_fn.
Value & construct(Args &&... args)
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
decltype(auto) set(Args &&...args) const
decltype(auto) init(Args &&...args) const
decltype(auto) get() const
std::unique_ptr< Waiter > waiter
std::string thread_name
Identifying string for debug.
Generic utility functions used by capnp code.