VLink  2.1.0
A high-performance communication middleware
getter-inl.h
Go to the documentation of this file.
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 "../getter.h"
33 #include "../impl/url.h"
34 #include "../serializer.h"
35 
36 namespace vlink {
37 
38 template <typename ValueT, SecurityType SecT>
39 inline typename Getter<ValueT, SecT>::UniquePtr Getter<ValueT, SecT>::create_unique(const std::string& url_str,
40  InitType type) {
41  return std::make_unique<Getter<ValueT, SecT>>(url_str, type);
42 }
43 
44 template <typename ValueT, SecurityType SecT>
45 inline typename Getter<ValueT, SecT>::SharedPtr Getter<ValueT, SecT>::create_shared(const std::string& url_str,
46  InitType type) {
47  return std::make_shared<Getter<ValueT, SecT>>(url_str, type);
48 }
49 
50 template <typename ValueT, SecurityType SecT>
51 template <typename ConfT, typename>
52 inline Getter<ValueT, SecT>::Getter(const ConfT& conf, InitType type) {
53  static_assert(ConfT::get_allow_impl_type() & kImplType, "Conf does not support getter mode.");
54 
55  if VUNLIKELY (!conf.parse(kImplType) || !conf.is_valid()) {
56  VLOG_F(conf, " getter configuration is invalid or could not be parsed.");
57  return;
58  }
59 
60  this->impl_ = conf.create_getter();
61 
62  if VUNLIKELY (!this->impl_) {
63  VLOG_F(conf, " getter 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<kValueType, ValueT>();
69  this->impl_->schema_type = Serializer::get_schema_type<kValueType, ValueT>();
70  this->impl_->is_cdr_type = Serializer::is_cdr_type<ValueT>();
71 
72  if constexpr (std::is_same_v<ConfT, Url>) {
73  this->impl_->url = conf.get_str();
74  }
75 
76  if constexpr (SecT == SecurityType::kWithSecurity) {
77  this->impl_->is_security_type = true;
78  }
79 
80  if VLIKELY (type == InitType::kWithInit) {
81  this->init(); // NOLINT(clang-analyzer-optin.cplusplus.VirtualCall)
82  }
83 }
84 
85 template <typename ValueT, SecurityType SecT>
86 inline Getter<ValueT, SecT>::Getter(const std::string& url_str, InitType type)
87  : Getter<ValueT, SecT>(Url(url_str), type) {}
88 
89 template <typename ValueT, SecurityType SecT>
91  // NOLINTNEXTLINE(clang-analyzer-optin.cplusplus.VirtualCall)
92  this->deinit();
93 }
94 
95 template <typename ValueT, SecurityType SecT>
96 inline std::optional<ValueT> Getter<ValueT, SecT>::get() const {
97  std::lock_guard lock(mtx_);
98  return value_;
99 }
100 
101 template <typename ValueT, SecurityType SecT>
102 inline bool Getter<ValueT, SecT>::wait_for_value(std::chrono::milliseconds timeout) {
103  if VUNLIKELY (timeout.count() == 0) {
104  VLOG_W("Getter: Timeout value is 0, using infinite wait instead.");
105  timeout = Timeout::kInfinite;
106  }
107 
108  std::unique_lock lock(mtx_);
109 
110  this->impl_->reset_interrupted();
111 
112  if (value_.has_value()) {
113  return true;
114  }
115 
116  has_value_notification_ = false;
117 
118  auto predicate = [this]() -> bool { return has_value_notification_ || this->impl_->is_interrupted(); };
119 
120  if (timeout.count() < 0) {
121  cv_.wait(lock, std::move(predicate));
122  return !this->impl_->is_interrupted();
123  } else {
124  return cv_.wait_for(lock, timeout, std::move(predicate)) && !this->impl_->is_interrupted();
125  }
126 }
127 
128 template <typename ValueT, SecurityType SecT>
129 inline bool Getter<ValueT, SecT>::listen(MsgCallback&& callback) {
130  std::lock_guard lock(mtx_);
131 
132  if VUNLIKELY (this->impl_->is_listened) {
133  VLOG_F("Getter has already been listened.");
134  return false;
135  }
136 
137  callback_ = std::move(callback);
138 
139  this->impl_->is_listened = true;
140 
141  return true;
142 }
143 
144 template <typename ValueT, SecurityType SecT>
146  std::lock_guard lock(mtx_);
147  change_reporting_ = enable;
148 }
149 
150 template <typename ValueT, SecurityType SecT>
152  this->impl_->set_latency_and_lost_enabled(enable);
153 }
154 
155 template <typename ValueT, SecurityType SecT>
157  return this->impl_->is_latency_and_lost_enabled();
158 }
159 
160 template <typename ValueT, SecurityType SecT>
161 inline int64_t Getter<ValueT, SecT>::get_latency() const {
162  return this->impl_->get_latency();
163 }
164 
165 template <typename ValueT, SecurityType SecT>
167  return this->impl_->get_lost();
168 }
169 
170 template <typename ValueT, SecurityType SecT>
172  std::lock_guard lock(mtx_);
173  return change_reporting_;
174 }
175 
176 template <typename ValueT, SecurityType SecT>
179  return false;
180  }
181 
182  listen_bytes([this](const Bytes& data) {
183 #ifndef VLINK_DISABLE_PROFILER
184  CpuProfilerGuard profiler_guard(this->impl_->profiler.get());
185 #endif
186 
187  bool has_callback = false;
188 
189  {
190  std::lock_guard lock(mtx_);
191 
192  if (change_reporting_) {
193  if (value_.has_value() && last_cache_ == data) {
194  return;
195  }
196 
197  last_cache_ = data;
198  }
199 
200  has_callback = static_cast<bool>(callback_);
201  }
202 
203  if constexpr (std::is_same_v<ValueT, Bytes>) {
204  if VLIKELY (has_callback) {
205  callback_(data);
206  }
207 
208  {
209  std::lock_guard lock(mtx_);
210 
211  has_value_notification_ = true;
212 
213  value_.emplace(data);
214  }
215 
216  cv_.notify_all();
217 
218  } else {
219  auto value = this->template get_default_value<ValueT>();
220 
221  if VUNLIKELY (!Serializer::deserialize<kValueType>(data, value, this->impl_->transport_type)) {
222  VLOG_T("Getter deserialize failed, url: ", this->impl_->url, ".");
223  return;
224  }
225 
226  if VLIKELY (has_callback) {
227  callback_(value);
228  }
229 
230  {
231  std::lock_guard lock(mtx_);
232 
233  has_value_notification_ = true;
234 
235  value_.emplace(std::move(value));
236  }
237 
238  cv_.notify_all();
239  }
240  });
241 
242  return true;
243 }
244 
245 template <typename ValueT, SecurityType SecT>
247  {
248  std::lock_guard lock(mtx_);
250  }
251 
252  cv_.notify_all();
253 }
254 
255 template <typename ValueT, SecurityType SecT>
257  if VUNLIKELY (this->has_inited_.load(std::memory_order_acquire)) {
258  this->impl_->deinit_ext();
259  this->impl_->impl_type = kSubscriber;
260  this->impl_->init_ext();
261  } else {
262  this->impl_->impl_type = kSubscriber;
263  }
264 }
265 
266 template <typename ValueT, SecurityType SecT>
267 inline void Getter<ValueT, SecT>::listen_bytes(NodeImpl::MsgCallback&& callback) {
268  if (!this->has_inited_.load(std::memory_order_acquire)) {
269  return;
270  }
271 
272  this->impl_->listen([this, callback = std::move(callback)](const Bytes& data) {
273  if constexpr (SecT == SecurityType::kWithSecurity) {
274  Bytes sec_data;
275 
276  if VUNLIKELY (!this->impl_->security || !this->impl_->security->decrypt(data, sec_data)) {
277  VLOG_T("Getter decrypt failed, url: ", this->impl_->url, ".");
278  return;
279  }
280 
281  this->invoke_callback(callback, sec_data);
282  } else {
283  this->impl_->try_record(ActionType::kGet, data);
284 
285  this->invoke_callback(callback, data);
286  }
287  });
288 }
289 
290 template <typename ValueT>
291 template <typename SecurityConfigT>
293  SecurityConfigT&& sec_cfg,
294  InitType type) {
295  static_assert(std::is_same_v<std::decay_t<SecurityConfigT>, Security::Config>,
296  "SecurityConfigT must be Security::Config.");
297 
298  return std::make_unique<SecurityGetter<ValueT>>(url_str, std::forward<SecurityConfigT>(sec_cfg), type);
299 }
300 
301 template <typename ValueT>
302 template <typename SecurityConfigT>
304  SecurityConfigT&& sec_cfg,
305  InitType type) {
306  static_assert(std::is_same_v<std::decay_t<SecurityConfigT>, Security::Config>,
307  "SecurityConfigT must be Security::Config.");
308 
309  return std::make_shared<SecurityGetter<ValueT>>(url_str, std::forward<SecurityConfigT>(sec_cfg), type);
310 }
311 
312 template <typename ValueT>
313 template <typename ConfT, typename SecurityConfigT, typename>
314 inline SecurityGetter<ValueT>::SecurityGetter(const ConfT& conf, SecurityConfigT&& sec_cfg, InitType type)
316  static_assert(std::is_same_v<std::decay_t<SecurityConfigT>, Security::Config>,
317  "SecurityConfigT must be Security::Config.");
318 
319  this->enable_security(std::forward<SecurityConfigT>(sec_cfg));
320 
321  if VLIKELY (type == InitType::kWithInit) {
322  this->init(); // NOLINT(clang-analyzer-optin.cplusplus.VirtualCall)
323  }
324 }
325 
326 template <typename ValueT>
327 template <typename SecurityConfigT>
328 inline SecurityGetter<ValueT>::SecurityGetter(const std::string& url_str, SecurityConfigT&& sec_cfg, InitType type)
329  : Getter<ValueT, SecurityType::kWithSecurity>(url_str, InitType::kWithoutInit) {
330  static_assert(std::is_same_v<std::decay_t<SecurityConfigT>, Security::Config>,
331  "SecurityConfigT must be Security::Config.");
332 
333  this->enable_security(std::forward<SecurityConfigT>(sec_cfg));
334 
335  if VLIKELY (type == InitType::kWithInit) {
336  this->init(); // NOLINT(clang-analyzer-optin.cplusplus.VirtualCall)
337  }
338 }
339 
340 } // namespace vlink
#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