VLink  2.1.0
A high-performance communication middleware
server-inl.h
浏览该文件的文档.
1 /*
2  * Copyright (C) 2026 by Thun Lu. All rights reserved.
3  * Author: Thun Lu <thun.lu@zohomail.cn>
4  * Repo: https://github.com/thun-res/vlink
5  * _ __ __ _ __
6  * | | / / / / (_) ____ / /__
7  * | | / / / / / / / __ \ / //_/
8  * | |/ / / /___ / / / / / / / ,<
9  * |___/ /_____/ /_/ /_/ /_/ /_/|_|
10  *
11  * Licensed under the Apache License, Version 2.0 (the "License");
12  * you may not use this file except in compliance with the License.
13  * You may obtain a copy of the License at
14  *
15  * http://www.apache.org/licenses/LICENSE-2.0
16  *
17  * Unless required by applicable law or agreed to in writing, software
18  * distributed under the License is distributed on an "AS IS" BASIS,
19  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
20  * See the License for the specific language governing permissions and
21  * limitations under the License.
22  */
23 
24 #pragma once
25 
26 #include <memory>
27 #include <string>
28 #include <utility>
29 
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"
35 
36 namespace vlink {
37 
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);
42 }
43 
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);
48 }
49 
50 template <typename ReqT, typename RespT, SecurityType SecT>
51 template <typename ConfT, typename>
52 inline Server<ReqT, RespT, SecT>::Server(const ConfT& conf, InitType type) {
53  static_assert(ConfT::get_allow_impl_type() & kImplType, "Conf does not support server mode.");
54 
55  if VUNLIKELY (!conf.parse(kImplType) || !conf.is_valid()) {
56  VLOG_F(conf, " server configuration is invalid or could not be parsed.");
57  return;
58  }
59 
60  this->impl_ = conf.create_server();
61 
62  if VUNLIKELY (!this->impl_) {
63  VLOG_F(conf, " server implementation not available for this transport.");
64  return;
65  }
66 
67  this->impl_->transport_type = conf.get_transport_type();
68  this->impl_->ser_type = Serializer::get_serialized_type<kReqType, ReqT>();
69 
70  if constexpr (kHasResp) {
71  const auto resp_ser_type = Serializer::get_serialized_type<kRespType, RespT>();
72 
73  if (!this->impl_->ser_type.empty() || !resp_ser_type.empty()) {
74  this->impl_->ser_type += "|" + resp_ser_type;
75  }
76  }
77 
78  {
79  constexpr auto kReqSchemaType = Serializer::get_schema_type<kReqType, ReqT>();
80  constexpr auto kRespSchemaType = Serializer::get_schema_type<kRespType, RespT>();
81 
82  if constexpr (kHasResp && kReqSchemaType != kRespSchemaType) {
83  this->impl_->schema_type = SchemaType::kUnknown;
84  } else {
85  this->impl_->schema_type = kReqSchemaType;
86  }
87  }
88 
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>();
93  }
94 
95  if constexpr (std::is_same_v<ConfT, Url>) {
96  this->impl_->url = conf.get_str();
97  }
98 
99  if constexpr (SecT == SecurityType::kWithSecurity) {
100  this->impl_->is_security_type = true;
101  }
102 
103  if VLIKELY (type == InitType::kWithInit) {
104  this->init(); // NOLINT(clang-analyzer-optin.cplusplus.VirtualCall)
105  }
106 }
107 
108 template <typename ReqT, typename RespT, SecurityType SecT>
109 inline Server<ReqT, RespT, SecT>::Server(const std::string& url_str, InitType type)
110  : Server<ReqT, RespT, SecT>(Url(url_str), type) {}
111 
112 template <typename ReqT, typename RespT, SecurityType SecT>
114  static_assert(!kHasResp, "Reply not supported; use listen(ReqRespCallback&&) instead.");
115 
116  this->impl_->is_sync_type = true;
117 
118  return listen_bytes([this, callback = std::move(callback)](uint64_t, const Bytes& req_data, Bytes*) {
119 #ifndef VLINK_DISABLE_PROFILER
120  CpuProfilerGuard profiler_guard(this->impl_->profiler.get());
121 #endif
122 
123  if constexpr (std::is_same_v<ReqT, Bytes>) {
124  (void)this;
125 
126  callback(req_data);
127  } else {
128  auto req = this->template get_default_value<ReqT>();
129 
130  if VUNLIKELY (!Serializer::deserialize<kReqType>(req_data, req, this->impl_->transport_type)) {
131  VLOG_T("Server deserialize failed, url: ", this->impl_->url, ".");
132  return;
133  }
134 
135  callback(req);
136  }
137  });
138 }
139 
140 template <typename ReqT, typename RespT, SecurityType SecT>
142  static_assert(kHasResp, "Must have reply.");
143 
144  this->impl_->is_sync_type = true;
145 
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
148  CpuProfilerGuard profiler_guard(this->impl_->profiler.get());
149 #endif
150 
151  if VUNLIKELY (!resp_data) {
152  VLOG_E("Server resp_data pointer is null.");
153  return;
154  }
155 
156  if constexpr (std::is_same_v<ReqT, Bytes> && std::is_same_v<RespT, Bytes>) {
157  (void)this;
158 
159  callback(req_data, *resp_data);
160 
161  reply_bytes<true>(req_id, *resp_data, true, resp_data);
162  } else {
163  auto req = this->template get_default_value<ReqT>();
164  auto resp = this->template get_default_value<RespT>();
165 
166  if VUNLIKELY (!Serializer::deserialize<kReqType>(req_data, req, this->impl_->transport_type)) {
167  VLOG_T("Server deserialize failed, url: ", this->impl_->url, ".");
168  return;
169  }
170 
171  callback(req, resp);
172  const bool use_loan = SecT != SecurityType::kWithSecurity && this->is_support_loan_;
173 
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, ".");
178 
179  if constexpr (SecT != SecurityType::kWithSecurity) {
180  if (this->is_support_loan_) {
181  this->impl_->return_loan(*resp_data);
182  }
183  }
184 
185  return;
186  }
187 
188  reply_bytes<true>(req_id, *resp_data, true, resp_data);
189  }
190  });
191 }
192 
193 template <typename ReqT, typename RespT, SecurityType SecT>
195  static_assert(kHasResp, "Must have reply.");
196 
197  this->impl_->is_sync_type = false;
198 
199  return listen_bytes([this, callback = std::move(callback)](uint64_t req_id, const Bytes& req_data, Bytes*) {
200 #ifndef VLINK_DISABLE_PROFILER
201  CpuProfilerGuard profiler_guard(this->impl_->profiler.get());
202 #endif
203 
204  if constexpr (std::is_same_v<ReqT, Bytes>) {
205  (void)this;
206 
207  callback(req_id, req_data);
208  } else {
209  auto req = this->template get_default_value<ReqT>();
210 
211  if VUNLIKELY (!Serializer::deserialize<kReqType>(req_data, req, this->impl_->transport_type)) {
212  VLOG_T("Server deserialize failed, url: ", this->impl_->url, ".");
213  return;
214  }
215 
216  callback(req_id, req);
217  }
218  });
219 }
220 
221 template <typename ReqT, typename RespT, SecurityType SecT>
222 inline bool Server<ReqT, RespT, SecT>::reply(uint64_t req_id, const RespT& resp) {
223  static_assert(kHasResp, "Reply requires a response type.");
224 
225  if VUNLIKELY (!this->impl_->is_listened) {
226  VLOG_F("Server::reply() requires listen() to be called first.");
227  return false;
228  }
229 
230  if VUNLIKELY (this->impl_->is_sync_type) {
231  VLOG_F("Server::reply() is not available in synchronous listen mode.");
232  return false;
233  }
234 
235  if constexpr (std::is_same_v<RespT, Bytes>) {
236  return reply_bytes<false>(req_id, resp, false);
237  } else {
238  Bytes resp_data;
239  const bool use_loan = SecT != SecurityType::kWithSecurity && this->is_support_loan_;
240 
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, ".");
245 
246  if constexpr (SecT != SecurityType::kWithSecurity) {
247  if (this->is_support_loan_) {
248  this->impl_->return_loan(resp_data);
249  }
250  }
251 
252  return false;
253  }
254 
255  bool ret = reply_bytes<false>(req_id, resp_data, false);
256 
257  return ret;
258  }
259 }
260 
261 template <typename ReqT, typename RespT, SecurityType SecT>
262 inline bool Server<ReqT, RespT, SecT>::has_clients() const {
263  return this->impl_->has_clients();
264 }
265 
266 template <typename ReqT, typename RespT, SecurityType SecT>
267 inline bool Server<ReqT, RespT, SecT>::listen_bytes(NodeImpl::ReqRespCallback&& callback) {
268  if VUNLIKELY (!this->has_inited_.load(std::memory_order_acquire)) {
269  VLOG_F("Server::listen_bytes() called before init().");
270  return false;
271  }
272 
273  if VUNLIKELY (this->impl_->is_listened) {
274  VLOG_F("Server has already been listened, url: ", this->impl_->url, ".");
275  return false;
276  }
277 
278  bool ret = this->impl_->listen(
279  [this, callback = std::move(callback)](uint64_t req_id, const Bytes& req_data, Bytes* resp_data) {
280  if constexpr (SecT == SecurityType::kWithSecurity) {
281  Bytes sec_req_data;
282 
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, ".");
285  return;
286  }
287 
288  this->invoke_callback(callback, req_id, sec_req_data, resp_data);
289  } else {
290  this->impl_->try_record(ActionType::kServerRequest, req_data);
291 
292  this->invoke_callback(callback, req_id, req_data, resp_data);
293  }
294  });
295 
296  this->impl_->is_listened = ret;
297 
298  return ret;
299 }
300 
301 template <typename ReqT, typename RespT, SecurityType SecT>
302 template <bool HasPtrT>
303 inline bool Server<ReqT, RespT, SecT>::reply_bytes(uint64_t req_id, const Bytes& resp_data, bool is_sync,
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().");
307  }
308 
309  if constexpr (SecT == SecurityType::kWithSecurity) {
310  Bytes sec_resp_data;
311 
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, ".");
314  return false;
315  }
316 
317  if constexpr (HasPtrT) {
318  *resp_data_ptr = sec_resp_data;
319  }
320 
321  return this->impl_->reply(req_id, sec_resp_data, is_sync);
322  } else {
323  if constexpr (HasPtrT) {
324  *resp_data_ptr = resp_data;
325  }
326 
327  this->impl_->try_record(ActionType::kServerResponse, resp_data);
328 
329  return this->impl_->reply(req_id, resp_data, is_sync);
330  }
331 }
332 
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.");
339 
340  return std::make_unique<SecurityServer<ReqT, RespT>>(url_str, std::forward<SecurityConfigT>(sec_cfg), type);
341 }
342 
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.");
349 
350  return std::make_shared<SecurityServer<ReqT, RespT>>(url_str, std::forward<SecurityConfigT>(sec_cfg), type);
351 }
352 
353 template <typename ReqT, typename RespT>
354 template <typename ConfT, typename SecurityConfigT, typename>
355 inline SecurityServer<ReqT, RespT>::SecurityServer(const ConfT& conf, SecurityConfigT&& sec_cfg, InitType type)
356  : Server<ReqT, RespT, SecurityType::kWithSecurity>(conf, InitType::kWithoutInit) {
357  static_assert(std::is_same_v<std::decay_t<SecurityConfigT>, Security::Config>,
358  "SecurityConfigT must be Security::Config.");
359 
360  this->enable_security(std::forward<SecurityConfigT>(sec_cfg));
361 
362  if VLIKELY (type == InitType::kWithInit) {
363  this->init(); // NOLINT(clang-analyzer-optin.cplusplus.VirtualCall)
364  }
365 }
366 
367 template <typename ReqT, typename RespT>
368 template <typename SecurityConfigT>
369 inline SecurityServer<ReqT, RespT>::SecurityServer(const std::string& url_str, SecurityConfigT&& sec_cfg, InitType type)
370  : Server<ReqT, RespT, SecurityType::kWithSecurity>(url_str, InitType::kWithoutInit) {
371  static_assert(std::is_same_v<std::decay_t<SecurityConfigT>, Security::Config>,
372  "SecurityConfigT must be Security::Config.");
373 
374  this->enable_security(std::forward<SecurityConfigT>(sec_cfg));
375 
376  if VLIKELY (type == InitType::kWithInit) {
377  this->init(); // NOLINT(clang-analyzer-optin.cplusplus.VirtualCall)
378  }
379 }
380 
381 } // namespace vlink
#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