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;
91 if constexpr (kHasResp) {
92 this->impl_->is_resp_cdr_type = Serializer::is_cdr_type<RespT>();
95 if constexpr (std::is_same_v<ConfT, Url>) {
96 this->impl_->url = conf.get_str();
100 this->impl_->is_security_type =
true;
108 template <
typename ReqT,
typename RespT, SecurityType SecT>
110 :
Server<ReqT, RespT, SecT>(
Url(url_str), type) {}
112 template <
typename ReqT,
typename RespT, SecurityType SecT>
114 static_assert(!kHasResp,
"Reply not supported; use listen(ReqRespCallback&&) instead.");
116 this->impl_->is_sync_type =
true;
118 return listen_bytes([
this, callback = std::move(callback)](uint64_t,
const Bytes& req_data,
Bytes*) {
119 #ifndef VLINK_DISABLE_PROFILER
123 if constexpr (std::is_same_v<ReqT, Bytes>) {
128 auto req = this->
template get_default_value<ReqT>();
130 if VUNLIKELY (!Serializer::deserialize<kReqType>(req_data, req, this->impl_->transport_type)) {
131 VLOG_T(
"Server deserialize failed, url: ", this->impl_->url,
".");
140 template <
typename ReqT,
typename RespT, SecurityType SecT>
142 static_assert(kHasResp,
"Must have reply.");
144 this->impl_->is_sync_type =
true;
146 return listen_bytes([
this, callback = std::move(callback)](uint64_t req_id,
const Bytes& req_data,
Bytes* resp_data) {
147 #ifndef VLINK_DISABLE_PROFILER
152 VLOG_E(
"Server resp_data pointer is null.");
156 if constexpr (std::is_same_v<ReqT, Bytes> && std::is_same_v<RespT, Bytes>) {
159 callback(req_data, *resp_data);
161 reply_bytes<true>(req_id, *resp_data,
true, resp_data);
163 auto req = this->
template get_default_value<ReqT>();
164 auto resp = this->
template get_default_value<RespT>();
166 if VUNLIKELY (!Serializer::deserialize<kReqType>(req_data, req, this->impl_->transport_type)) {
167 VLOG_T(
"Server deserialize failed, url: ", this->impl_->url,
".");
174 if VUNLIKELY (!Serializer::serialize_to_transport<kRespType>(
175 resp, *resp_data, this->impl_->transport_type, use_loan,
176 [
this](
size_t size) { return this->impl_->loan(size); })) {
177 VLOG_T(
"Server serialize failed, url: ", this->impl_->url,
".");
180 if (this->is_support_loan_) {
181 this->impl_->return_loan(*resp_data);
188 reply_bytes<true>(req_id, *resp_data,
true, resp_data);
193 template <
typename ReqT,
typename RespT, SecurityType SecT>
195 static_assert(kHasResp,
"Must have reply.");
197 this->impl_->is_sync_type =
false;
199 return listen_bytes([
this, callback = std::move(callback)](uint64_t req_id,
const Bytes& req_data,
Bytes*) {
200 #ifndef VLINK_DISABLE_PROFILER
204 if constexpr (std::is_same_v<ReqT, Bytes>) {
207 callback(req_id, req_data);
209 auto req = this->
template get_default_value<ReqT>();
211 if VUNLIKELY (!Serializer::deserialize<kReqType>(req_data, req, this->impl_->transport_type)) {
212 VLOG_T(
"Server deserialize failed, url: ", this->impl_->url,
".");
216 callback(req_id, req);
221 template <
typename ReqT,
typename RespT, SecurityType SecT>
223 static_assert(kHasResp,
"Reply requires a response type.");
225 if VUNLIKELY (!this->impl_->is_listened) {
226 VLOG_F(
"Server::reply() requires listen() to be called first.");
231 VLOG_F(
"Server::reply() is not available in synchronous listen mode.");
235 if constexpr (std::is_same_v<RespT, Bytes>) {
236 return reply_bytes<false>(req_id, resp,
false);
241 if VUNLIKELY (!Serializer::serialize_to_transport<kRespType>(
242 resp, resp_data, this->impl_->transport_type, use_loan,
243 [
this](
size_t size) { return this->impl_->loan(size); })) {
244 VLOG_T(
"Server serialize failed, url: ", this->impl_->url,
".");
247 if (this->is_support_loan_) {
248 this->impl_->return_loan(resp_data);
255 bool ret = reply_bytes<false>(req_id, resp_data,
false);
261 template <
typename ReqT,
typename RespT, SecurityType SecT>
262 inline bool Server<ReqT, RespT, SecT>::has_clients()
const {
263 return this->impl_->has_clients();
266 template <
typename ReqT,
typename RespT, SecurityType SecT>
268 if VUNLIKELY (!this->has_inited_.load(std::memory_order_acquire)) {
269 VLOG_F(
"Server::listen_bytes() called before init().");
273 if VUNLIKELY (this->impl_->is_listened) {
274 VLOG_F(
"Server has already been listened, url: ", this->impl_->url,
".");
278 bool ret = this->impl_->listen(
279 [
this, callback = std::move(callback)](uint64_t req_id,
const Bytes& req_data, Bytes* resp_data) {
283 if VUNLIKELY (!this->impl_->security || !this->impl_->security->decrypt(req_data, sec_req_data)) {
284 VLOG_T(
"Server decrypt failed, url: ", this->impl_->url,
".");
288 this->invoke_callback(callback, req_id, sec_req_data, resp_data);
292 this->invoke_callback(callback, req_id, req_data, resp_data);
296 this->impl_->is_listened = ret;
301 template <
typename ReqT,
typename RespT, SecurityType SecT>
302 template <
bool HasPtrT>
304 [[maybe_unused]]
Bytes* resp_data_ptr) {
305 if VUNLIKELY (!this->has_inited_.load(std::memory_order_acquire)) {
306 VLOG_F(
"Server::reply_bytes() called before init().");
312 if VUNLIKELY (!this->impl_->security || !this->impl_->security->encrypt(resp_data, sec_resp_data)) {
313 VLOG_T(
"Server encrypt failed, url: ", this->impl_->url,
".");
317 if constexpr (HasPtrT) {
318 *resp_data_ptr = sec_resp_data;
321 return this->impl_->reply(req_id, sec_resp_data, is_sync);
323 if constexpr (HasPtrT) {
324 *resp_data_ptr = resp_data;
329 return this->impl_->reply(req_id, resp_data, is_sync);
333 template <
typename ReqT,
typename RespT>
334 template <
typename SecurityConfigT>
336 const std::string& url_str, SecurityConfigT&& sec_cfg,
InitType type) {
337 static_assert(std::is_same_v<std::decay_t<SecurityConfigT>,
Security::Config>,
338 "SecurityConfigT must be Security::Config.");
340 return std::make_unique<SecurityServer<ReqT, RespT>>(url_str, std::forward<SecurityConfigT>(sec_cfg), type);
343 template <
typename ReqT,
typename RespT>
344 template <
typename SecurityConfigT>
346 const std::string& url_str, SecurityConfigT&& sec_cfg,
InitType type) {
347 static_assert(std::is_same_v<std::decay_t<SecurityConfigT>,
Security::Config>,
348 "SecurityConfigT must be Security::Config.");
350 return std::make_shared<SecurityServer<ReqT, RespT>>(url_str, std::forward<SecurityConfigT>(sec_cfg), type);
353 template <
typename ReqT,
typename RespT>
354 template <
typename ConfT,
typename SecurityConfigT,
typename>
357 static_assert(std::is_same_v<std::decay_t<SecurityConfigT>,
Security::Config>,
358 "SecurityConfigT must be Security::Config.");
367 template <
typename ReqT,
typename RespT>
368 template <
typename SecurityConfigT>
371 static_assert(std::is_same_v<std::decay_t<SecurityConfigT>,
Security::Config>,
372 "SecurityConfigT must be Security::Config.");
Fixed-size 128-byte buffer holder with SBO, five ownership modes and integrated codecs.
Definition: bytes.h:120
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:132
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:327
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:335
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:345
SecurityServer(const ConfT &conf, SecurityConfigT &&sec_cfg={}, InitType type=InitType::kWithInit)
Constructs a SecurityServer from a typed configuration object.
Definition: server-inl.h:355
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:222
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:113
bool listen_for_reply(ReqAsyncRespCallback &&callback)
Installs a handler that defers the reply via reply().
Definition: server-inl.h:194
std::unique_ptr< Server< ReqT, RespT, SecT > > UniquePtr
Owning unique-pointer alias.
Definition: server.h:128
#define VLOG_E(...)
Definition: logger.h:841
#define VLOG_F(...)
Definition: logger.h:843
#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.
@ 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:168
@ 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:216