30 #include "../base/cpu_profiler_guard.h"
31 #include "../base/logger.h"
32 #include "../base/memory_resource.h"
33 #include "../client.h"
34 #include "../impl/url.h"
35 #include "../serializer.h"
39 template <
typename ReqT,
typename RespT, SecurityType SecT>
41 const std::string& url_str,
InitType type) {
42 return std::make_unique<Client<ReqT, RespT, SecT>>(url_str, type);
45 template <
typename ReqT,
typename RespT, SecurityType SecT>
47 const std::string& url_str,
InitType type) {
48 return std::make_shared<Client<ReqT, RespT, SecT>>(url_str, type);
51 template <
typename ReqT,
typename RespT, SecurityType SecT>
52 template <
typename ConfT,
typename>
54 static_assert(ConfT::get_allow_impl_type() & kImplType,
"Conf does not support client mode.");
56 if VUNLIKELY (!conf.parse(kImplType) || !conf.is_valid()) {
57 VLOG_F(conf,
" client configuration is invalid or could not be parsed.");
61 this->impl_ = conf.create_client();
64 VLOG_F(conf,
" client implementation not available for this transport.");
68 this->impl_->transport_type = conf.get_transport_type();
69 this->impl_->ser_type = Serializer::get_serialized_type<kReqType, ReqT>();
71 if constexpr (kHasResp) {
72 const auto resp_ser_type = Serializer::get_serialized_type<kRespType, RespT>();
74 if (!this->impl_->ser_type.empty() || !resp_ser_type.empty()) {
75 this->impl_->ser_type +=
"|" + resp_ser_type;
80 constexpr
auto kReqSchemaType = Serializer::get_schema_type<kReqType, ReqT>();
81 constexpr
auto kRespSchemaType = Serializer::get_schema_type<kRespType, RespT>();
83 if constexpr (kHasResp && kReqSchemaType != kRespSchemaType) {
86 this->impl_->schema_type = kReqSchemaType;
90 this->impl_->is_cdr_type = Serializer::is_cdr_type<ReqT>();
91 this->impl_->is_resp_type = kHasResp;
93 if constexpr (kHasResp) {
94 this->impl_->is_resp_cdr_type = Serializer::is_cdr_type<RespT>();
97 if constexpr (std::is_same_v<ConfT, Url>) {
98 this->impl_->url = conf.get_str();
102 this->impl_->is_security_type =
true;
110 template <
typename ReqT,
typename RespT, SecurityType SecT>
112 :
Client<ReqT, RespT, SecT>(
Url(url_str), type) {}
114 template <
typename ReqT,
typename RespT, SecurityType SecT>
117 std::lock_guard lock(future_mtx_);
125 template <
typename ReqT,
typename RespT, SecurityType SecT>
127 this->impl_->detect_connected(std::move(callback));
130 template <
typename ReqT,
typename RespT, SecurityType SecT>
133 VLOG_W(
"Client: Timeout value is 0, using infinite wait instead.");
137 return this->impl_->wait_for_connected(timeout);
140 template <
typename ReqT,
typename RespT, SecurityType SecT>
142 return this->impl_->is_connected();
145 template <
typename ReqT,
typename RespT, SecurityType SecT>
148 VLOG_W(
"Client: Timeout value is 0, using infinite wait instead.");
152 #ifndef VLINK_DISABLE_PROFILER
156 static_assert(kHasResp,
"Invoke requires a response type.");
160 if constexpr (std::is_same_v<ReqT, Bytes> && std::is_same_v<RespT, Bytes>) {
161 ret = call_bytes(req, [&resp](
const Bytes& resp_data) { resp = resp_data; }, timeout);
166 if VUNLIKELY (!Serializer::serialize_to_transport<kReqType>(
167 req, req_data, this->impl_->transport_type, use_loan,
168 [
this](
size_t size) { return this->impl_->loan(size); })) {
169 VLOG_T(
"Client serialize failed, url: ", this->impl_->url,
".");
172 if (this->is_support_loan_) {
173 this->impl_->return_loan(req_data);
180 bool deserialize_success =
false;
184 [
this, &resp, &deserialize_success](
const Bytes& resp_data) {
185 if VLIKELY (Serializer::deserialize<kRespType>(resp_data, resp, this->impl_->transport_type)) {
186 deserialize_success =
true;
188 VLOG_T(
"Client deserialize failed, url: ", this->impl_->url,
".");
193 ret = ret && deserialize_success;
199 template <
typename ReqT,
typename RespT, SecurityType SecT>
202 VLOG_W(
"Client: Timeout value is 0, using infinite wait instead.");
206 #ifndef VLINK_DISABLE_PROFILER
210 auto resp = this->
template get_default_value<RespT>();
212 if VLIKELY (invoke(req, resp, timeout)) {
213 return std::make_optional<RespT>(std::move(resp));
219 template <
typename ReqT,
typename RespT, SecurityType SecT>
221 #ifndef VLINK_DISABLE_PROFILER
225 static_assert(kHasResp,
"Invoke requires a response type.");
229 if constexpr (std::is_same_v<ReqT, Bytes> && std::is_same_v<RespT, Bytes>) {
230 ret = call_bytes(req, [callback = std::move(callback)](
const Bytes& resp_data) { callback(resp_data); });
235 if VUNLIKELY (!Serializer::serialize_to_transport<kReqType>(
236 req, req_data, this->impl_->transport_type, use_loan,
237 [
this](
size_t size) { return this->impl_->loan(size); })) {
238 VLOG_T(
"Client serialize failed, url: ", this->impl_->url,
".");
241 if (this->is_support_loan_) {
242 this->impl_->return_loan(req_data);
249 ret = call_bytes(req_data, [
this, callback = std::move(callback)](
const Bytes& resp_data) {
250 auto resp = this->
template get_default_value<RespT>();
252 if VUNLIKELY (!Serializer::deserialize<kRespType>(resp_data, resp, this->impl_->transport_type)) {
253 VLOG_T(
"Client deserialize failed, url: ", this->impl_->url,
".");
264 template <
typename ReqT,
typename RespT, SecurityType SecT>
266 #ifndef VLINK_DISABLE_PROFILER
270 static_assert(kHasResp,
"async_invoke requires a response type.");
272 auto pro = MemoryResource::make_shared<std::promise<RespT>>();
273 auto future = pro->get_future();
276 int64_t target_seq = 0;
279 std::lock_guard lock(future_mtx_);
280 target_seq = future_seq_++;
281 future_map_.emplace(target_seq, pro);
284 auto cleanup_on_error = [
this, target_seq, pro](
const std::string& error_str) {
285 std::lock_guard lock(future_mtx_);
286 future_map_.erase(target_seq);
290 }
catch (std::exception&) {
291 pro->set_exception(std::current_exception());
295 if constexpr (std::is_same_v<ReqT, Bytes> && std::is_same_v<RespT, Bytes>) {
296 ret = call_bytes(req, [
this, target_seq](
const Bytes& resp_data) {
297 std::lock_guard lock(future_mtx_);
298 auto it = future_map_.find(target_seq);
300 if VLIKELY (it != future_map_.end()) {
301 it->second->set_value(resp_data);
302 future_map_.erase(it);
309 if VUNLIKELY (!Serializer::serialize_to_transport<kReqType>(
310 req, req_data, this->impl_->transport_type, use_loan,
311 [
this](
size_t size) { return this->impl_->loan(size); })) {
312 VLOG_T(
"Client serialize failed, url: ", this->impl_->url,
".");
315 if (this->is_support_loan_) {
316 this->impl_->return_loan(req_data);
320 cleanup_on_error(
"Client async_invoke error (Failed to serialize req)");
324 ret = call_bytes(req_data, [
this, target_seq](
const Bytes& resp_data) {
325 bool convert_success =
false;
327 auto resp = this->
template get_default_value<RespT>();
329 if VLIKELY (Serializer::deserialize<kRespType>(resp_data, resp, this->impl_->transport_type)) {
330 convert_success =
true;
332 VLOG_T(
"Client deserialize failed, url: ", this->impl_->url,
".");
335 std::lock_guard lock(future_mtx_);
337 auto it = future_map_.find(target_seq);
339 if VLIKELY (it != future_map_.end()) {
341 it->second->set_value(std::move(resp));
344 throw Exception::RuntimeError(
"Client async_invoke error (Failed to deserialize resp)");
345 }
catch (std::exception&) {
346 it->second->set_exception(std::current_exception());
350 future_map_.erase(it);
356 cleanup_on_error(
"Client async_invoke error (Failed to call)");
362 template <
typename ReqT,
typename RespT, SecurityType SecT>
364 #ifndef VLINK_DISABLE_PROFILER
368 static_assert(!kHasResp,
"Send not supported; use invoke() for request-response.");
372 if constexpr (std::is_same_v<ReqT, Bytes>) {
373 ret = call_bytes(req);
378 if VUNLIKELY (!Serializer::serialize_to_transport<kReqType>(
379 req, req_data, this->impl_->transport_type, use_loan,
380 [
this](
size_t size) { return this->impl_->loan(size); })) {
381 VLOG_T(
"Client serialize failed, url: ", this->impl_->url,
".");
384 if (this->is_support_loan_) {
385 this->impl_->return_loan(req_data);
392 ret = call_bytes(req_data);
398 template <
typename ReqT,
typename RespT, SecurityType SecT>
400 std::chrono::milliseconds timeout) {
404 if VUNLIKELY (!this->impl_->security || !this->impl_->security->encrypt(req_data, req_sec_data)) {
405 VLOG_T(
"Client encrypt failed, url: ", this->impl_->url,
".");
410 return this->impl_->call(req_sec_data,
nullptr, timeout);
413 return this->impl_->call(
415 [
this, callback = std::move(callback)](
const Bytes& resp_data) {
418 if VUNLIKELY (!this->impl_->security || !this->impl_->security->decrypt(resp_data, resp_sec_data)) {
419 VLOG_T(
"Client decrypt failed, url: ", this->impl_->url,
".");
423 this->invoke_callback(callback, resp_sec_data);
430 return this->impl_->call(req_data,
nullptr, timeout);
433 return this->impl_->call(
435 [
this, callback = std::move(callback)](
const Bytes& resp_data) {
438 this->invoke_callback(callback, resp_data);
444 template <
typename ReqT,
typename RespT>
445 template <
typename SecurityConfigT>
447 const std::string& url_str, SecurityConfigT&& sec_cfg,
InitType type) {
448 static_assert(std::is_same_v<std::decay_t<SecurityConfigT>,
Security::Config>,
449 "SecurityConfigT must be Security::Config.");
451 return std::make_unique<SecurityClient<ReqT, RespT>>(url_str, std::forward<SecurityConfigT>(sec_cfg), type);
454 template <
typename ReqT,
typename RespT>
455 template <
typename SecurityConfigT>
457 const std::string& url_str, SecurityConfigT&& sec_cfg,
InitType type) {
458 static_assert(std::is_same_v<std::decay_t<SecurityConfigT>,
Security::Config>,
459 "SecurityConfigT must be Security::Config.");
461 return std::make_shared<SecurityClient<ReqT, RespT>>(url_str, std::forward<SecurityConfigT>(sec_cfg), type);
464 template <
typename ReqT,
typename RespT>
465 template <
typename ConfT,
typename SecurityConfigT,
typename>
468 static_assert(std::is_same_v<std::decay_t<SecurityConfigT>,
Security::Config>,
469 "SecurityConfigT must be Security::Config.");
478 template <
typename ReqT,
typename RespT>
479 template <
typename SecurityConfigT>
482 static_assert(std::is_same_v<std::decay_t<SecurityConfigT>,
Security::Config>,
483 "SecurityConfigT must be Security::Config.");
Fixed-size 128-byte buffer holder with SBO, five ownership modes and integrated codecs.
Definition: bytes.h:120
Type-safe RPC caller for the VLink method communication model.
Definition: client.h:132
void detect_connected(ConnectCallback &&callback)
Registers a callback invoked when the server-presence state changes.
Definition: client-inl.h:126
std::unique_ptr< Client< ReqT, RespT, SecT > > UniquePtr
Owning unique-pointer alias.
Definition: client.h:134
static SharedPtr create_shared(const std::string &url_str, InitType type=InitType::kWithInit)
Heap-allocates a Client and wraps it in a std::shared_ptr.
Definition: client-inl.h:46
bool wait_for_connected(std::chrono::milliseconds timeout=Timeout::kDefaultInterval)
Blocks until a server is discovered or timeout expires.
Definition: client-inl.h:131
Client(const ConfT &conf, InitType type=InitType::kWithInit)
Constructs a client from a typed transport configuration object.
Definition: client-inl.h:53
static UniquePtr create_unique(const std::string &url_str, InitType type=InitType::kWithInit)
Heap-allocates a Client and wraps it in a std::unique_ptr.
Definition: client-inl.h:40
bool invoke(const ReqT &req, RespT &resp, std::chrono::milliseconds timeout=Timeout::kDefaultInterval)
Synchronous request/response invocation with an output parameter.
Definition: client-inl.h:146
std::future< RespT > async_invoke(const ReqT &req)
Asynchronous future-based invocation.
Definition: client-inl.h:265
~Client() override
Destroys the client and tears down outstanding promises.
Definition: client-inl.h:115
std::shared_ptr< Client< ReqT, RespT, SecT > > SharedPtr
Owning shared-pointer alias.
Definition: client.h:135
bool is_connected() const
Non-blocking query of server presence.
Definition: client-inl.h:141
bool send(const ReqT &req)
Fire-and-forget request emission.
Definition: client-inl.h:363
Scope guard that opens and closes a CpuProfiler active interval.
Definition: cpu_profiler_guard.h:80
Generic runtime failure; thrown by the logger on kFatal messages.
Definition: exception.h:90
Copyable type-erased callable analogue of std::function with a tunable SBO and pool spill.
Definition: functional.h:132
bool enable_security(const Security::Config &cfg)
Installs a Security configuration before transport initialisation.
Definition: node-inl.h:327
virtual bool init()
Initialises the node and its transport back-end.
Definition: node-inl.h:39
std::unique_ptr< SecurityClient< ReqT, RespT > > UniquePtr
Owning unique-pointer alias.
Definition: client.h:323
static UniquePtr create_unique(const std::string &url_str, SecurityConfigT &&sec_cfg={}, InitType type=InitType::kWithInit)
Heap-allocates a SecurityClient and wraps it in a std::unique_ptr.
Definition: client-inl.h:446
std::shared_ptr< SecurityClient< ReqT, RespT > > SharedPtr
Owning shared-pointer alias.
Definition: client.h:324
static SharedPtr create_shared(const std::string &url_str, SecurityConfigT &&sec_cfg={}, InitType type=InitType::kWithInit)
Heap-allocates a SecurityClient and wraps it in a std::shared_ptr.
Definition: client-inl.h:456
SecurityClient(const ConfT &conf, SecurityConfigT &&sec_cfg={}, InitType type=InitType::kWithInit)
Constructs a SecurityClient from a typed configuration object.
Definition: client-inl.h:466
#define VLOG_F(...)
Definition: logger.h:843
#define VLOG_W(...)
Definition: logger.h:839
#define VLOG_T(...)
Definition: logger.h:833
#define VUNLIKELY(...)
Short alias for VLINK_UNLIKELY.
Definition: macros.h:289
#define VLIKELY(...)
Short alias for VLINK_LIKELY.
Definition: macros.h:284
InitType
Selects between immediate and deferred node initialisation.
Definition: types.h:150
@ kWithoutInit
Defer initialisation; call init() manually.
@ kWithInit
Initialise immediately in the constructor.
@ kUnknown
Decoding family unknown.
@ kClientResponse
RPC response observed by a Client node.
@ kClientRequest
RPC request emitted by a Client node.
SecurityType
Compile-time selector for the per-node message security variant.
Definition: types.h:168
@ kWithSecurity
Encrypted and authenticated transport.
Aggregate of every parameter accepted by the Security constructor.
Definition: security.h:164
static constexpr std::chrono::milliseconds kInfinite
Wait indefinitely (negative timeout).
Definition: types.h:256
Conf subclass that routes virtual calls to the transport selected by a URL string.
Definition: url.h:216