30 #include "../base/cpu_profiler_guard.h"
31 #include "../base/logger.h"
32 #include "../impl/url.h"
33 #include "../serializer.h"
34 #include "../server.h"
38 template <
typename ReqT,
typename RespT, SecurityType SecT>
40 const std::string& url_str,
InitType type) {
41 return std::make_unique<Server<ReqT, RespT, SecT>>(url_str, type);
44 template <
typename ReqT,
typename RespT, SecurityType SecT>
46 const std::string& url_str,
InitType type) {
47 return std::make_shared<Server<ReqT, RespT, SecT>>(url_str, type);
50 template <
typename ReqT,
typename RespT, SecurityType SecT>
51 template <
typename ConfT,
typename>
53 static_assert(ConfT::get_allow_impl_type() & kImplType,
"Conf does not support server mode.");
55 if VUNLIKELY (!conf.parse(kImplType) || !conf.is_valid()) {
56 VLOG_F(conf,
" server configuration is invalid or could not be parsed.");
60 this->impl_ = conf.create_server();
63 VLOG_F(conf,
" server implementation not available for this transport.");
67 this->impl_->transport_type = conf.get_transport_type();
68 this->impl_->ser_type = Serializer::get_serialized_type<kReqType, ReqT>();
70 if constexpr (kHasResp) {
71 const auto resp_ser_type = Serializer::get_serialized_type<kRespType, RespT>();
73 if (!this->impl_->ser_type.empty() || !resp_ser_type.empty()) {
74 this->impl_->ser_type +=
"|" + resp_ser_type;
79 constexpr
auto kReqSchemaType = Serializer::get_schema_type<kReqType, ReqT>();
80 constexpr
auto kRespSchemaType = Serializer::get_schema_type<kRespType, RespT>();
82 if constexpr (kHasResp && kReqSchemaType != kRespSchemaType) {
85 this->impl_->schema_type = kReqSchemaType;
89 this->impl_->is_cdr_type = Serializer::is_cdr_type<ReqT>();
90 this->impl_->is_resp_type = kHasResp;
92 if constexpr (std::is_same_v<ConfT, Url>) {
93 this->impl_->url = conf.get_str();
97 this->impl_->is_security_type =
true;
105 template <
typename ReqT,
typename RespT, SecurityType SecT>
107 :
Server<ReqT, RespT, SecT>(
Url(url_str), type) {}
109 template <
typename ReqT,
typename RespT, SecurityType SecT>
111 static_assert(!kHasResp,
"Reply not supported; use listen(ReqRespCallback&&) instead.");
113 this->impl_->is_sync_type =
true;
115 return listen_bytes([
this, callback = std::move(callback)](uint64_t,
const Bytes& req_data,
Bytes*) {
116 #ifndef VLINK_DISABLE_PROFILER
120 if constexpr (std::is_same_v<ReqT, Bytes>) {
125 thread_local
auto req = this->
template get_default_value<ReqT>();
127 if VUNLIKELY (!Serializer::deserialize<kReqType>(req_data, req, this->impl_->transport_type)) {
128 VLOG_T(
"Server deserialize failed, url: ", this->impl_->url,
".");
137 template <
typename ReqT,
typename RespT, SecurityType SecT>
139 static_assert(kHasResp,
"Must have reply.");
141 this->impl_->is_sync_type =
true;
143 return listen_bytes([
this, callback = std::move(callback)](uint64_t req_id,
const Bytes& req_data,
Bytes* resp_data) {
144 #ifndef VLINK_DISABLE_PROFILER
149 VLOG_E(
"Server resp_data pointer is null.");
153 if constexpr (std::is_same_v<ReqT, Bytes> && std::is_same_v<RespT, Bytes>) {
156 callback(req_data, *resp_data);
158 reply_bytes<true>(req_id, *resp_data,
true, resp_data);
160 thread_local
auto req = this->
template get_default_value<ReqT>();
161 auto resp = this->
template get_default_value<RespT>();
163 if VUNLIKELY (!Serializer::deserialize<kReqType>(req_data, req, this->impl_->transport_type)) {
164 VLOG_T(
"Server deserialize failed, url: ", this->impl_->url,
".");
171 if (this->is_support_loan_) {
172 size_t ser_size = Serializer::get_serialized_size<kRespType>(resp);
174 *resp_data = this->impl_->loan(ser_size);
182 if VUNLIKELY (!Serializer::serialize<kRespType>(resp, *resp_data, this->impl_->transport_type)) {
183 VLOG_T(
"Server serialize failed, url: ", this->impl_->url,
".");
186 if (this->is_support_loan_) {
187 this->impl_->return_loan(*resp_data);
194 reply_bytes<true>(req_id, *resp_data,
true, resp_data);
199 template <
typename ReqT,
typename RespT, SecurityType SecT>
201 static_assert(kHasResp,
"Must have reply.");
203 this->impl_->is_sync_type =
false;
205 return listen_bytes([
this, callback = std::move(callback)](uint64_t req_id,
const Bytes& req_data,
Bytes*) {
206 #ifndef VLINK_DISABLE_PROFILER
210 if constexpr (std::is_same_v<ReqT, Bytes>) {
213 callback(req_id, req_data);
215 thread_local
auto req = this->
template get_default_value<ReqT>();
217 if VUNLIKELY (!Serializer::deserialize<kReqType>(req_data, req, this->impl_->transport_type)) {
218 VLOG_T(
"Server deserialize failed, url: ", this->impl_->url,
".");
222 callback(req_id, req);
227 template <
typename ReqT,
typename RespT, SecurityType SecT>
229 static_assert(kHasResp,
"Reply requires a response type.");
231 if VUNLIKELY (!this->impl_->is_listened) {
232 VLOG_F(
"Server::reply() requires listen() to be called first.");
236 if VUNLIKELY (this->impl_->is_sync_type) {
237 VLOG_F(
"Server::reply() is not available in synchronous listen mode.");
241 if constexpr (std::is_same_v<RespT, Bytes>) {
242 return reply_bytes<false>(req_id, resp,
false);
247 if (this->is_support_loan_) {
248 size_t ser_size = Serializer::get_serialized_size<kRespType>(resp);
250 resp_data = this->impl_->loan(ser_size);
252 if VUNLIKELY (ser_size != 0 && resp_data.empty()) {
258 if VUNLIKELY (!Serializer::serialize<kRespType>(resp, resp_data, this->impl_->transport_type)) {
259 VLOG_T(
"Server serialize failed, url: ", this->impl_->url,
".");
262 if (this->is_support_loan_) {
263 this->impl_->return_loan(resp_data);
270 bool ret = reply_bytes<false>(req_id, resp_data,
false);
276 template <
typename ReqT,
typename RespT, SecurityType SecT>
277 inline bool Server<ReqT, RespT, SecT>::has_clients()
const {
278 return this->impl_->has_clients();
281 template <
typename ReqT,
typename RespT, SecurityType SecT>
283 if VUNLIKELY (!this->has_inited_.load(std::memory_order_acquire)) {
284 VLOG_F(
"Server::listen_bytes() called before init().");
288 if VUNLIKELY (this->impl_->is_listened) {
289 VLOG_F(
"Server has already been listened, url: ", this->impl_->url,
".");
293 bool ret = this->impl_->listen(
294 [
this, callback = std::move(callback)](uint64_t req_id,
const Bytes& req_data, Bytes* resp_data) {
298 if VUNLIKELY (!this->impl_->security || !this->impl_->security->decrypt(req_data, sec_req_data)) {
299 VLOG_T(
"Server decrypt failed, url: ", this->impl_->url,
".");
303 this->invoke_callback(callback, req_id, sec_req_data, resp_data);
307 this->invoke_callback(callback, req_id, req_data, resp_data);
311 this->impl_->is_listened = ret;
316 template <
typename ReqT,
typename RespT, SecurityType SecT>
317 template <
bool HasPtrT>
319 [[maybe_unused]]
Bytes* resp_data_ptr) {
320 if VUNLIKELY (!this->has_inited_.load(std::memory_order_acquire)) {
321 VLOG_F(
"Server::reply_bytes() called before init().");
327 if VUNLIKELY (!this->impl_->security || !this->impl_->security->encrypt(resp_data, sec_resp_data)) {
328 VLOG_T(
"Server encrypt failed, url: ", this->impl_->url,
".");
332 if constexpr (HasPtrT) {
333 *resp_data_ptr = sec_resp_data;
336 return this->impl_->reply(req_id, sec_resp_data, is_sync);
338 if constexpr (HasPtrT) {
339 *resp_data_ptr = resp_data;
344 return this->impl_->reply(req_id, resp_data, is_sync);
348 template <
typename ReqT,
typename RespT>
349 template <
typename SecurityConfigT>
351 const std::string& url_str, SecurityConfigT&& sec_cfg,
InitType type) {
352 static_assert(std::is_same_v<std::decay_t<SecurityConfigT>,
Security::Config>,
353 "SecurityConfigT must be Security::Config.");
355 return std::make_unique<SecurityServer<ReqT, RespT>>(url_str, std::forward<SecurityConfigT>(sec_cfg), type);
358 template <
typename ReqT,
typename RespT>
359 template <
typename SecurityConfigT>
361 const std::string& url_str, SecurityConfigT&& sec_cfg,
InitType type) {
362 static_assert(std::is_same_v<std::decay_t<SecurityConfigT>,
Security::Config>,
363 "SecurityConfigT must be Security::Config.");
365 return std::make_shared<SecurityServer<ReqT, RespT>>(url_str, std::forward<SecurityConfigT>(sec_cfg), type);
368 template <
typename ReqT,
typename RespT>
369 template <
typename ConfT,
typename SecurityConfigT,
typename>
372 static_assert(std::is_same_v<std::decay_t<SecurityConfigT>,
Security::Config>,
373 "SecurityConfigT must be Security::Config.");
382 template <
typename ReqT,
typename RespT>
383 template <
typename SecurityConfigT>
386 static_assert(std::is_same_v<std::decay_t<SecurityConfigT>,
Security::Config>,
387 "SecurityConfigT must be Security::Config.");
Fixed-size 128-byte buffer holder with SBO, five ownership modes and integrated codecs.
Definition: bytes.h:120
bool empty() const noexcept
Reports whether the buffer is logically empty.
Definition: bytes.h:861
Scope guard that opens and closes a CpuProfiler active interval.
Definition: cpu_profiler_guard.h:80
Copyable type-erased callable analogue of std::function with a tunable SBO and pool spill.
Definition: functional.h:131
Function< void(uint64_t, const Bytes &, Bytes *)> ReqRespCallback
Request / response handler installed by ServerImpl::listen().
Definition: node_impl.h:193
bool enable_security(const Security::Config &cfg)
Installs a Security configuration before transport initialisation.
Definition: node-inl.h:321
virtual bool init()
Initialises the node and its transport back-end.
Definition: node-inl.h:39
std::shared_ptr< SecurityServer< ReqT, RespT > > SharedPtr
Owning shared-pointer alias.
Definition: server.h:272
std::unique_ptr< SecurityServer< ReqT, RespT > > UniquePtr
Owning unique-pointer alias.
Definition: server.h:271
static UniquePtr create_unique(const std::string &url_str, SecurityConfigT &&sec_cfg={}, InitType type=InitType::kWithInit)
Heap-allocates a SecurityServer and wraps it in a std::unique_ptr.
Definition: server-inl.h:350
static SharedPtr create_shared(const std::string &url_str, SecurityConfigT &&sec_cfg={}, InitType type=InitType::kWithInit)
Heap-allocates a SecurityServer and wraps it in a std::shared_ptr.
Definition: server-inl.h:360
SecurityServer(const ConfT &conf, SecurityConfigT &&sec_cfg={}, InitType type=InitType::kWithInit)
Constructs a SecurityServer from a typed configuration object.
Definition: server-inl.h:370
Type-safe RPC handler for the VLink method communication model.
Definition: server.h:126
bool reply(uint64_t req_id, const RespT &resp)
Emits the asynchronous response for a previously received request.
Definition: server-inl.h:228
static SharedPtr create_shared(const std::string &url_str, InitType type=InitType::kWithInit)
Heap-allocates a Server and wraps it in a std::shared_ptr.
Definition: server-inl.h:45
static UniquePtr create_unique(const std::string &url_str, InitType type=InitType::kWithInit)
Heap-allocates a Server and wraps it in a std::unique_ptr.
Definition: server-inl.h:39
Server(const ConfT &conf, InitType type=InitType::kWithInit)
Constructs a server from a typed transport configuration object.
Definition: server-inl.h:52
std::shared_ptr< Server< ReqT, RespT, SecT > > SharedPtr
Owning shared-pointer alias.
Definition: server.h:129
bool listen(ReqCallback &&callback)
Installs a fire-and-forget request handler.
Definition: server-inl.h:110
bool listen_for_reply(ReqAsyncRespCallback &&callback)
Installs a handler that defers the reply via reply().
Definition: server-inl.h:200
std::unique_ptr< Server< ReqT, RespT, SecT > > UniquePtr
Owning unique-pointer alias.
Definition: server.h:128
#define VLOG_E(...)
Definition: logger.h:789
#define VLOG_F(...)
Definition: logger.h:791
#define VLOG_T(...)
Definition: logger.h:781
#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:154
@ kWithoutInit
Defer initialisation; call init() manually.
@ kWithInit
Initialise immediately in the constructor.
@ kUnknown
Decoding family unknown.
@ kServerRequest
RPC request observed by a Server node.
@ kServerResponse
RPC response emitted by a Server node.
SecurityType
Compile-time selector for the per-node message security variant.
Definition: types.h:172
@ kWithSecurity
Encrypted and authenticated transport.
Aggregate of every parameter accepted by the Security constructor.
Definition: security.h:164
Conf subclass that routes virtual calls to the transport selected by a URL string.
Definition: url.h:213