VLink  2.0.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 
92  if constexpr (std::is_same_v<ConfT, Url>) {
93  this->impl_->url = conf.get_str();
94  }
95 
96  if constexpr (SecT == SecurityType::kWithSecurity) {
97  this->impl_->is_security_type = true;
98  }
99 
100  if VLIKELY (type == InitType::kWithInit) {
101  this->init(); // NOLINT(clang-analyzer-optin.cplusplus.VirtualCall)
102  }
103 }
104 
105 template <typename ReqT, typename RespT, SecurityType SecT>
106 inline Server<ReqT, RespT, SecT>::Server(const std::string& url_str, InitType type)
107  : Server<ReqT, RespT, SecT>(Url(url_str), type) {}
108 
109 template <typename ReqT, typename RespT, SecurityType SecT>
111  static_assert(!kHasResp, "Reply not supported; use listen(ReqRespCallback&&) instead.");
112 
113  this->impl_->is_sync_type = true;
114 
115  return listen_bytes([this, callback = std::move(callback)](uint64_t, const Bytes& req_data, Bytes*) {
116 #ifndef VLINK_DISABLE_PROFILER
117  CpuProfilerGuard profiler_guard(this->impl_->profiler.get());
118 #endif
119 
120  if constexpr (std::is_same_v<ReqT, Bytes>) {
121  (void)this;
122 
123  callback(req_data);
124  } else {
125  thread_local auto req = this->template get_default_value<ReqT>();
126 
127  if VUNLIKELY (!Serializer::deserialize<kReqType>(req_data, req, this->impl_->transport_type)) {
128  VLOG_T("Server deserialize failed, url: ", this->impl_->url, ".");
129  return;
130  }
131 
132  callback(req);
133  }
134  });
135 }
136 
137 template <typename ReqT, typename RespT, SecurityType SecT>
139  static_assert(kHasResp, "Must have reply.");
140 
141  this->impl_->is_sync_type = true;
142 
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
145  CpuProfilerGuard profiler_guard(this->impl_->profiler.get());
146 #endif
147 
148  if VUNLIKELY (!resp_data) {
149  VLOG_E("Server resp_data pointer is null.");
150  return;
151  }
152 
153  if constexpr (std::is_same_v<ReqT, Bytes> && std::is_same_v<RespT, Bytes>) {
154  (void)this;
155 
156  callback(req_data, *resp_data);
157 
158  reply_bytes<true>(req_id, *resp_data, true, resp_data);
159  } else {
160  thread_local auto req = this->template get_default_value<ReqT>();
161  auto resp = this->template get_default_value<RespT>();
162 
163  if VUNLIKELY (!Serializer::deserialize<kReqType>(req_data, req, this->impl_->transport_type)) {
164  VLOG_T("Server deserialize failed, url: ", this->impl_->url, ".");
165  return;
166  }
167 
168  callback(req, resp);
169 
170  if constexpr (SecT != SecurityType::kWithSecurity) {
171  if (this->is_support_loan_) {
172  size_t ser_size = Serializer::get_serialized_size<kRespType>(resp);
173 
174  *resp_data = this->impl_->loan(ser_size);
175 
176  if VUNLIKELY (ser_size != 0 && resp_data->empty()) {
177  return;
178  }
179  }
180  }
181 
182  if VUNLIKELY (!Serializer::serialize<kRespType>(resp, *resp_data, this->impl_->transport_type)) {
183  VLOG_T("Server serialize failed, url: ", this->impl_->url, ".");
184 
185  if constexpr (SecT != SecurityType::kWithSecurity) {
186  if (this->is_support_loan_) {
187  this->impl_->return_loan(*resp_data);
188  }
189  }
190 
191  return;
192  }
193 
194  reply_bytes<true>(req_id, *resp_data, true, resp_data);
195  }
196  });
197 }
198 
199 template <typename ReqT, typename RespT, SecurityType SecT>
201  static_assert(kHasResp, "Must have reply.");
202 
203  this->impl_->is_sync_type = false;
204 
205  return listen_bytes([this, callback = std::move(callback)](uint64_t req_id, const Bytes& req_data, Bytes*) {
206 #ifndef VLINK_DISABLE_PROFILER
207  CpuProfilerGuard profiler_guard(this->impl_->profiler.get());
208 #endif
209 
210  if constexpr (std::is_same_v<ReqT, Bytes>) {
211  (void)this;
212 
213  callback(req_id, req_data);
214  } else {
215  thread_local auto req = this->template get_default_value<ReqT>();
216 
217  if VUNLIKELY (!Serializer::deserialize<kReqType>(req_data, req, this->impl_->transport_type)) {
218  VLOG_T("Server deserialize failed, url: ", this->impl_->url, ".");
219  return;
220  }
221 
222  callback(req_id, req);
223  }
224  });
225 }
226 
227 template <typename ReqT, typename RespT, SecurityType SecT>
228 inline bool Server<ReqT, RespT, SecT>::reply(uint64_t req_id, const RespT& resp) {
229  static_assert(kHasResp, "Reply requires a response type.");
230 
231  if VUNLIKELY (!this->impl_->is_listened) {
232  VLOG_F("Server::reply() requires listen() to be called first.");
233  return false;
234  }
235 
236  if VUNLIKELY (this->impl_->is_sync_type) {
237  VLOG_F("Server::reply() is not available in synchronous listen mode.");
238  return false;
239  }
240 
241  if constexpr (std::is_same_v<RespT, Bytes>) {
242  return reply_bytes<false>(req_id, resp, false);
243  } else {
244  Bytes resp_data;
245 
246  if constexpr (SecT != SecurityType::kWithSecurity) {
247  if (this->is_support_loan_) {
248  size_t ser_size = Serializer::get_serialized_size<kRespType>(resp);
249 
250  resp_data = this->impl_->loan(ser_size);
251 
252  if VUNLIKELY (ser_size != 0 && resp_data.empty()) {
253  return false;
254  }
255  }
256  }
257 
258  if VUNLIKELY (!Serializer::serialize<kRespType>(resp, resp_data, this->impl_->transport_type)) {
259  VLOG_T("Server serialize failed, url: ", this->impl_->url, ".");
260 
261  if constexpr (SecT != SecurityType::kWithSecurity) {
262  if (this->is_support_loan_) {
263  this->impl_->return_loan(resp_data);
264  }
265  }
266 
267  return false;
268  }
269 
270  bool ret = reply_bytes<false>(req_id, resp_data, false);
271 
272  return ret;
273  }
274 }
275 
276 template <typename ReqT, typename RespT, SecurityType SecT>
277 inline bool Server<ReqT, RespT, SecT>::has_clients() const {
278  return this->impl_->has_clients();
279 }
280 
281 template <typename ReqT, typename RespT, SecurityType SecT>
282 inline bool Server<ReqT, RespT, SecT>::listen_bytes(NodeImpl::ReqRespCallback&& callback) {
283  if VUNLIKELY (!this->has_inited_.load(std::memory_order_acquire)) {
284  VLOG_F("Server::listen_bytes() called before init().");
285  return false;
286  }
287 
288  if VUNLIKELY (this->impl_->is_listened) {
289  VLOG_F("Server has already been listened, url: ", this->impl_->url, ".");
290  return false;
291  }
292 
293  bool ret = this->impl_->listen(
294  [this, callback = std::move(callback)](uint64_t req_id, const Bytes& req_data, Bytes* resp_data) {
295  if constexpr (SecT == SecurityType::kWithSecurity) {
296  Bytes sec_req_data;
297 
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, ".");
300  return;
301  }
302 
303  this->invoke_callback(callback, req_id, sec_req_data, resp_data);
304  } else {
305  this->impl_->try_record(ActionType::kServerRequest, req_data);
306 
307  this->invoke_callback(callback, req_id, req_data, resp_data);
308  }
309  });
310 
311  this->impl_->is_listened = ret;
312 
313  return ret;
314 }
315 
316 template <typename ReqT, typename RespT, SecurityType SecT>
317 template <bool HasPtrT>
318 inline bool Server<ReqT, RespT, SecT>::reply_bytes(uint64_t req_id, const Bytes& resp_data, bool is_sync,
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().");
322  }
323 
324  if constexpr (SecT == SecurityType::kWithSecurity) {
325  Bytes sec_resp_data;
326 
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, ".");
329  return false;
330  }
331 
332  if constexpr (HasPtrT) {
333  *resp_data_ptr = sec_resp_data;
334  }
335 
336  return this->impl_->reply(req_id, sec_resp_data, is_sync);
337  } else {
338  if constexpr (HasPtrT) {
339  *resp_data_ptr = resp_data;
340  }
341 
342  this->impl_->try_record(ActionType::kServerResponse, resp_data);
343 
344  return this->impl_->reply(req_id, resp_data, is_sync);
345  }
346 }
347 
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.");
354 
355  return std::make_unique<SecurityServer<ReqT, RespT>>(url_str, std::forward<SecurityConfigT>(sec_cfg), type);
356 }
357 
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.");
364 
365  return std::make_shared<SecurityServer<ReqT, RespT>>(url_str, std::forward<SecurityConfigT>(sec_cfg), type);
366 }
367 
368 template <typename ReqT, typename RespT>
369 template <typename ConfT, typename SecurityConfigT, typename>
370 inline SecurityServer<ReqT, RespT>::SecurityServer(const ConfT& conf, SecurityConfigT&& sec_cfg, InitType type)
371  : Server<ReqT, RespT, SecurityType::kWithSecurity>(conf, InitType::kWithoutInit) {
372  static_assert(std::is_same_v<std::decay_t<SecurityConfigT>, Security::Config>,
373  "SecurityConfigT must be Security::Config.");
374 
375  this->enable_security(std::forward<SecurityConfigT>(sec_cfg));
376 
377  if VLIKELY (type == InitType::kWithInit) {
378  this->init(); // NOLINT(clang-analyzer-optin.cplusplus.VirtualCall)
379  }
380 }
381 
382 template <typename ReqT, typename RespT>
383 template <typename SecurityConfigT>
384 inline SecurityServer<ReqT, RespT>::SecurityServer(const std::string& url_str, SecurityConfigT&& sec_cfg, InitType type)
385  : Server<ReqT, RespT, SecurityType::kWithSecurity>(url_str, InitType::kWithoutInit) {
386  static_assert(std::is_same_v<std::decay_t<SecurityConfigT>, Security::Config>,
387  "SecurityConfigT must be Security::Config.");
388 
389  this->enable_security(std::forward<SecurityConfigT>(sec_cfg));
390 
391  if VLIKELY (type == InitType::kWithInit) {
392  this->init(); // NOLINT(clang-analyzer-optin.cplusplus.VirtualCall)
393  }
394 }
395 
396 } // namespace vlink
#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