VLink  2.0.0
A high-performance communication middleware
publisher-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 "../impl/url.h"
33 #include "../publisher.h"
34 #include "../serializer.h"
35 
36 namespace vlink {
37 
38 template <typename MsgT, SecurityType SecT>
40  InitType type) {
41  return std::make_unique<Publisher<MsgT, SecT>>(url_str, type);
42 }
43 
44 template <typename MsgT, SecurityType SecT>
46  InitType type) {
47  return std::make_shared<Publisher<MsgT, SecT>>(url_str, type);
48 }
49 
50 template <typename MsgT, SecurityType SecT>
51 template <typename ConfT, typename>
52 inline Publisher<MsgT, SecT>::Publisher(const ConfT& conf, InitType type) {
53  static_assert(ConfT::get_allow_impl_type() & kImplType, "Conf does not support publisher mode.");
54 
55  if VUNLIKELY (!conf.parse(kImplType) || !conf.is_valid()) {
56  VLOG_F(conf, " publisher configuration is invalid or could not be parsed.");
57  return;
58  }
59 
60  this->impl_ = conf.create_publisher();
61 
62  if VUNLIKELY (!this->impl_) {
63  VLOG_F(conf, " publisher 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<kMsgType, MsgT>();
69  this->impl_->schema_type = Serializer::get_schema_type<kMsgType, MsgT>();
70  this->impl_->is_cdr_type = Serializer::is_cdr_type<MsgT>();
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 MsgT, SecurityType SecT>
86 inline Publisher<MsgT, SecT>::Publisher(const std::string& url_str, InitType type)
87  : Publisher<MsgT, SecT>(Url(url_str), type) {}
88 
89 template <typename MsgT, SecurityType SecT>
91  return this->impl_->detect_subscribers(std::move(callback));
92 }
93 
94 template <typename MsgT, SecurityType SecT>
95 inline bool Publisher<MsgT, SecT>::wait_for_subscribers(std::chrono::milliseconds timeout) {
96  if VUNLIKELY (timeout.count() == 0) {
97  VLOG_W("Publisher: Timeout value is 0, using infinite wait instead.");
98  timeout = Timeout::kInfinite;
99  }
100 
101  return this->impl_->wait_for_subscribers(timeout);
102 }
103 
104 template <typename MsgT, SecurityType SecT>
106  return this->impl_->has_subscribers();
107 }
108 
109 template <typename MsgT, SecurityType SecT>
110 inline bool Publisher<MsgT, SecT>::publish(const MsgT& msg, bool force) {
111 #ifndef VLINK_DISABLE_PROFILER
112  CpuProfilerGuard profiler_guard(this->impl_->profiler.get());
113 #endif
114 
115  if (!force) {
116  if (!this->impl_->has_subscribers()) {
117  return false;
118  }
119  }
120 
121  if constexpr (Traits::IsSharedPtr<MsgT>()) {
122  if constexpr (std::is_base_of_v<IntraDataType, typename MsgT::element_type>) {
123  static_assert(SecT != SecurityType::kWithSecurity, "IntraData must without security.");
124 
125  if (this->impl_->transport_type == TransportType::kIntra) {
126  return write_intra(msg);
127  }
128  }
129  }
130 
131  if constexpr (std::is_same_v<MsgT, Bytes>) {
132  return write_bytes(msg);
133  } else {
134  Bytes msg_data;
135 
136  if constexpr (SecT != SecurityType::kWithSecurity) {
137  if (this->is_support_loan_) {
138  size_t ser_size = Serializer::get_serialized_size<kMsgType>(msg);
139 
140  msg_data = this->impl_->loan(ser_size);
141 
142  if VUNLIKELY (ser_size != 0 && msg_data.empty()) {
143  return false;
144  }
145  }
146  }
147 
148  if VUNLIKELY (!Serializer::serialize<kMsgType>(msg, msg_data, this->impl_->transport_type)) {
149  VLOG_T("Publisher serialize failed, url: ", this->impl_->url, ".");
150 
151  if constexpr (SecT != SecurityType::kWithSecurity) {
152  if (this->is_support_loan_) {
153  this->impl_->return_loan(msg_data);
154  }
155  }
156 
157  return false;
158  }
159 
160  bool ret = write_bytes(msg_data);
161 
162  return ret;
163  }
164 }
165 
166 template <typename MsgT, SecurityType SecT>
167 bool Publisher<MsgT, SecT>::publish_fbb(const void* fbb, bool force) {
168  const auto* fbb_ptr = static_cast<const flatbuffers::FlatBufferBuilder*>(fbb);
169 
170 #ifndef VLINK_DISABLE_PROFILER
171  CpuProfilerGuard profiler_guard(this->impl_->profiler.get());
172 #endif
173 
174  if (!force) {
175  if (!this->impl_->has_subscribers()) {
176  return false;
177  }
178  }
179 
180  return write_bytes(Bytes::shallow_copy(fbb_ptr->GetBufferPointer(), fbb_ptr->GetSize()));
181 }
182 
183 template <typename MsgT, SecurityType SecT>
185  if VUNLIKELY (this->has_inited_.load(std::memory_order_acquire)) {
186  this->impl_->deinit_ext();
187  this->impl_->impl_type = kSetter;
188  this->impl_->init_ext();
189  } else {
190  this->impl_->impl_type = kSetter;
191  }
192 }
193 
194 template <typename MsgT, SecurityType SecT>
195 inline bool Publisher<MsgT, SecT>::write_bytes(const Bytes& data) {
196  if constexpr (SecT == SecurityType::kWithSecurity) {
197  Bytes sec_data;
198 
199  if VUNLIKELY (!this->impl_->security || !this->impl_->security->encrypt(data, sec_data)) {
200  VLOG_T("Publisher encrypt failed, url: ", this->impl_->url, ".");
201  return false;
202  }
203 
204  return this->impl_->write(sec_data);
205  } else {
206  this->impl_->try_record(ActionType::kPublish, data);
207 
208  return this->impl_->write(data);
209  }
210 }
211 
212 template <typename MsgT, SecurityType SecT>
213 inline bool Publisher<MsgT, SecT>::write_intra(const IntraData& intra_data) {
214  return this->impl_->write(intra_data);
215 }
216 
217 template <typename MsgT>
218 template <typename SecurityConfigT>
220  SecurityConfigT&& sec_cfg,
221  InitType type) {
222  static_assert(std::is_same_v<std::decay_t<SecurityConfigT>, Security::Config>,
223  "SecurityConfigT must be Security::Config.");
224 
225  return std::make_unique<SecurityPublisher<MsgT>>(url_str, std::forward<SecurityConfigT>(sec_cfg), type);
226 }
227 
228 template <typename MsgT>
229 template <typename SecurityConfigT>
231  SecurityConfigT&& sec_cfg,
232  InitType type) {
233  static_assert(std::is_same_v<std::decay_t<SecurityConfigT>, Security::Config>,
234  "SecurityConfigT must be Security::Config.");
235 
236  return std::make_shared<SecurityPublisher<MsgT>>(url_str, std::forward<SecurityConfigT>(sec_cfg), type);
237 }
238 
239 template <typename MsgT>
240 template <typename ConfT, typename SecurityConfigT, typename>
241 inline SecurityPublisher<MsgT>::SecurityPublisher(const ConfT& conf, SecurityConfigT&& sec_cfg, InitType type)
243  static_assert(std::is_same_v<std::decay_t<SecurityConfigT>, Security::Config>,
244  "SecurityConfigT must be Security::Config.");
245 
246  this->enable_security(std::forward<SecurityConfigT>(sec_cfg));
247 
248  if VLIKELY (type == InitType::kWithInit) {
249  this->init(); // NOLINT(clang-analyzer-optin.cplusplus.VirtualCall)
250  }
251 }
252 
253 template <typename MsgT>
254 template <typename SecurityConfigT>
255 inline SecurityPublisher<MsgT>::SecurityPublisher(const std::string& url_str, SecurityConfigT&& sec_cfg, InitType type)
257  static_assert(std::is_same_v<std::decay_t<SecurityConfigT>, Security::Config>,
258  "SecurityConfigT must be Security::Config.");
259 
260  this->enable_security(std::forward<SecurityConfigT>(sec_cfg));
261 
262  if VLIKELY (type == InitType::kWithInit) {
263  this->init(); // NOLINT(clang-analyzer-optin.cplusplus.VirtualCall)
264  }
265 }
266 
267 } // namespace vlink
#define VLOG_F(...)
Definition: logger.h:791
#define VLOG_W(...)
Definition: logger.h:787
#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
Definition: serializer-inl.h:126