VLink  2.1.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  const bool use_loan = SecT != SecurityType::kWithSecurity && this->is_support_loan_;
136 
137  if VUNLIKELY (!Serializer::serialize_to_transport<kMsgType>(
138  msg, msg_data, this->impl_->transport_type, use_loan,
139  [this](size_t size) { return this->impl_->loan(size); })) {
140  VLOG_T("Publisher serialize failed, url: ", this->impl_->url, ".");
141 
142  if constexpr (SecT != SecurityType::kWithSecurity) {
143  if (this->is_support_loan_) {
144  this->impl_->return_loan(msg_data);
145  }
146  }
147 
148  return false;
149  }
150 
151  bool ret = write_bytes(msg_data);
152 
153  return ret;
154  }
155 }
156 
157 template <typename MsgT, SecurityType SecT>
158 bool Publisher<MsgT, SecT>::publish_fbb(const void* fbb, bool force) {
159 #ifdef VLINK_HAS_FLATBUFFERS
160  const auto* fbb_ptr = static_cast<const flatbuffers::FlatBufferBuilder*>(fbb);
161 
162 #ifndef VLINK_DISABLE_PROFILER
163  CpuProfilerGuard profiler_guard(this->impl_->profiler.get());
164 #endif
165 
166  if (!force) {
167  if (!this->impl_->has_subscribers()) {
168  return false;
169  }
170  }
171 
172  return write_bytes(Bytes::shallow_copy(fbb_ptr->GetBufferPointer(), fbb_ptr->GetSize()));
173 #else
174  (void)fbb;
175  (void)force;
176  return false;
177 #endif
178 }
179 
180 template <typename MsgT, SecurityType SecT>
182  if VUNLIKELY (this->has_inited_.load(std::memory_order_acquire)) {
183  this->impl_->deinit_ext();
184  this->impl_->impl_type = kSetter;
185  this->impl_->init_ext();
186  } else {
187  this->impl_->impl_type = kSetter;
188  }
189 }
190 
191 template <typename MsgT, SecurityType SecT>
192 inline bool Publisher<MsgT, SecT>::write_bytes(const Bytes& data) {
193  if constexpr (SecT == SecurityType::kWithSecurity) {
194  Bytes sec_data;
195 
196  if VUNLIKELY (!this->impl_->security || !this->impl_->security->encrypt(data, sec_data)) {
197  VLOG_T("Publisher encrypt failed, url: ", this->impl_->url, ".");
198  return false;
199  }
200 
201  return this->impl_->write(sec_data);
202  } else {
203  this->impl_->try_record(ActionType::kPublish, data);
204 
205  return this->impl_->write(data);
206  }
207 }
208 
209 template <typename MsgT, SecurityType SecT>
210 inline bool Publisher<MsgT, SecT>::write_intra(const IntraData& intra_data) {
211  return this->impl_->write(intra_data);
212 }
213 
214 template <typename MsgT>
215 template <typename SecurityConfigT>
217  SecurityConfigT&& sec_cfg,
218  InitType type) {
219  static_assert(std::is_same_v<std::decay_t<SecurityConfigT>, Security::Config>,
220  "SecurityConfigT must be Security::Config.");
221 
222  return std::make_unique<SecurityPublisher<MsgT>>(url_str, std::forward<SecurityConfigT>(sec_cfg), type);
223 }
224 
225 template <typename MsgT>
226 template <typename SecurityConfigT>
228  SecurityConfigT&& sec_cfg,
229  InitType type) {
230  static_assert(std::is_same_v<std::decay_t<SecurityConfigT>, Security::Config>,
231  "SecurityConfigT must be Security::Config.");
232 
233  return std::make_shared<SecurityPublisher<MsgT>>(url_str, std::forward<SecurityConfigT>(sec_cfg), type);
234 }
235 
236 template <typename MsgT>
237 template <typename ConfT, typename SecurityConfigT, typename>
238 inline SecurityPublisher<MsgT>::SecurityPublisher(const ConfT& conf, SecurityConfigT&& sec_cfg, InitType type)
240  static_assert(std::is_same_v<std::decay_t<SecurityConfigT>, Security::Config>,
241  "SecurityConfigT must be Security::Config.");
242 
243  this->enable_security(std::forward<SecurityConfigT>(sec_cfg));
244 
245  if VLIKELY (type == InitType::kWithInit) {
246  this->init(); // NOLINT(clang-analyzer-optin.cplusplus.VirtualCall)
247  }
248 }
249 
250 template <typename MsgT>
251 template <typename SecurityConfigT>
252 inline SecurityPublisher<MsgT>::SecurityPublisher(const std::string& url_str, SecurityConfigT&& sec_cfg, InitType type)
254  static_assert(std::is_same_v<std::decay_t<SecurityConfigT>, Security::Config>,
255  "SecurityConfigT must be Security::Config.");
256 
257  this->enable_security(std::forward<SecurityConfigT>(sec_cfg));
258 
259  if VLIKELY (type == InitType::kWithInit) {
260  this->init(); // NOLINT(clang-analyzer-optin.cplusplus.VirtualCall)
261  }
262 }
263 
264 } // 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