VLink 2.0.0
A high-performance communication middleware
载入中...
搜索中...
未找到
publisher.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/**
25 * @file publisher.h
26 * @brief Type-safe event-model publisher for VLink topics.
27 *
28 * @details
29 * @c Publisher<MsgT, SecT> is the write side of the VLink event model.
30 * It serialises a @c MsgT object and delivers it to all @c Subscriber nodes
31 * that share the same URL.
32 *
33 * @par Event Model Data Flow
34 * @code
35 * Publisher<T> Transport Back-end Subscriber<T>
36 * | | |
37 * |-- publish(msg) --------> | |
38 * | serialize(msg) | |
39 * | [loan if shm://] |-- bytes delivery ---------> |
40 * | | |--> callback(msg)
41 * | | | deserialize(bytes)
42 * @endcode
43 *
44 * @par Supported Message Types
45 * | Category | Type | Serializer |
46 * | --------------- | ------------------------------ | ---------------- |
47 * | Raw bytes | @c Bytes | kBytesType |
48 * | Protobuf | @c MyProto (MessageLite) | kProtoType |
49 * | Protobuf ptr | @c MyProto* (Arena-managed) | kProtoPtrType |
50 * | FlatBuffers | @c MyTableT (NativeTable) | kFlatTableType |
51 * | FlatBuffers | @c MyBuilder (has fbb_+Finish) | kFlatBuilderType |
52 * | CDR (DDS only) | @c MyCdrType (serialize/des.) | kCdrType |
53 * | Standard layout | POD struct / trivial type | kStandardType |
54 * | String | @c std::string | kStringType |
55 * | Custom | @c T (has operator>>/<<) | kCustomType |
56 *
57 * @par Subscriber Detection
58 * @code
59 * Publisher<MyMsg> pub("dds://topic");
60 * pub.detect_subscribers([](bool has) { // async notification
61 * if (has) pub.publish(MyMsg{});
62 * });
63 * pub.wait_for_subscribers(); // blocking until subscriber appears
64 * if (pub.has_subscribers()) { ... } // non-blocking query
65 * @endcode
66 *
67 * @par Zero-copy on shm://
68 * @code
69 * Publisher<MyStruct> pub("shm://topic");
70 * if (pub.is_support_loan()) {
71 * Bytes buf = pub.loan(sizeof(MyStruct));
72 * new (buf.data()) MyStruct{...};
73 * pub.publish(buf); // no copy; loan returned automatically
74 * }
75 * @endcode
76 *
77 * @note Pass @p force = @c true to @c publish() to send even when no subscribers
78 * are present (e.g. for guaranteed-delivery or field-mode semantics).
79 *
80 * @tparam MsgT Message type. Must satisfy @c Serializer::is_supported().
81 * @tparam SecT Security mode; defaults to @c SecurityType::kWithoutSecurity.
82 */
83
84#pragma once
85
86#include <memory>
87#include <string>
88
90#include "./node.h"
91
92namespace vlink {
93
94/**
95 * @class Publisher
96 * @brief Type-safe publisher for the VLink event communication model.
97 *
98 * @tparam MsgT Message type.
99 * @tparam SecT Security mode.
100 */
101template <typename MsgT, SecurityType SecT = SecurityType::kWithoutSecurity>
102class Publisher : public Node<PublisherImpl, SecT> {
103 public:
104 /** @brief Unique-pointer alias for heap allocation. */
105 using UniquePtr = std::unique_ptr<Publisher<MsgT, SecT>>;
106
107 /** @brief Shared-pointer alias for heap allocation. */
108 using SharedPtr = std::shared_ptr<Publisher<MsgT, SecT>>;
109
110 /** @brief Callback type fired when subscriber presence changes. */
112
113 /** @brief Node role identifier (@c kPublisher). */
114 static constexpr ImplType kImplType = kPublisher;
115
116 /** @brief Serializer type resolved at compile time from @c MsgT. */
118
119 static_assert(Serializer::is_supported(kMsgType), "<MsgT> is not a supported Serializer type.");
120
121 /**
122 * @brief Creates a @c Publisher on the heap wrapped in a @c unique_ptr.
123 *
124 * @param url_str Topic URL string (e.g. @c "dds://vehicle/speed").
125 * @param type @c kWithInit to call @c init() immediately (default).
126 * @return @c UniquePtr owning the new publisher instance.
127 */
128 [[nodiscard]] static UniquePtr create_unique(const std::string& url_str, InitType type = InitType::kWithInit);
129
130 /**
131 * @brief Creates a @c Publisher on the heap wrapped in a @c shared_ptr.
132 *
133 * @param url_str Topic URL string.
134 * @param type @c kWithInit to call @c init() immediately (default).
135 * @return @c SharedPtr owning the new publisher instance.
136 */
137 [[nodiscard]] static SharedPtr create_shared(const std::string& url_str, InitType type = InitType::kWithInit);
138
139 /**
140 * @brief Constructs a publisher from a typed transport configuration object.
141 *
142 * @details
143 * Accepts any @c Conf-derived configuration (e.g. @c DdsConf, @c ShmConf).
144 * A compile-time @c static_assert checks that the @c Conf supports the
145 * publisher role. Parses and validates the conf; logs a fatal error if the
146 * conf is invalid or if the transport factory returns @c nullptr.
147 *
148 * @tparam ConfT @c Conf-derived configuration type.
149 * @param conf Populated configuration object.
150 * @param type @c kWithInit to call @c init() immediately (default).
151 */
152 // NOLINTNEXTLINE(modernize-use-constraints)
153 template <typename ConfT, typename = std::enable_if_t<std::is_base_of_v<Conf, ConfT>>>
154 explicit Publisher(const ConfT& conf, InitType type = InitType::kWithInit);
155
156 /**
157 * @brief Constructs a publisher from a URL string.
158 *
159 * @details
160 * The transport prefix in the URL selects the transport back-end automatically (e.g.
161 * @c "shm://" => Iceoryx, @c "dds://" => FastDDS). Internally wraps the
162 * string in a @c Url object and delegates to the @c ConfT constructor.
163 *
164 * @param url_str Topic URL (e.g. @c "shm://vehicle/speed").
165 * @param type @c kWithInit to call @c init() immediately (default).
166 */
167 explicit Publisher(const std::string& url_str, InitType type = InitType::kWithInit);
168
169 /**
170 * @brief Registers a callback invoked when subscriber presence changes.
171 *
172 * @details
173 * Fires immediately (synchronously) if a subscriber is already present at
174 * registration time. Otherwise fires asynchronously the first time a
175 * subscriber appears. The callback receives @c true when at least one
176 * subscriber is present and @c false when the last subscriber disconnects.
177 *
178 * @param callback @c void(bool) callable -- @c true = subscriber(s) present.
179 */
180 void detect_subscribers(ConnectCallback&& callback);
181
182 /**
183 * @brief Blocks until at least one subscriber is present or the timeout expires.
184 *
185 * @details
186 * A timeout of @c 0 is treated as infinite (a warning is logged). A
187 * negative timeout also waits indefinitely. Can be interrupted by calling
188 * @c interrupt(), which causes this method to return @c false.
189 *
190 * @param timeout Maximum wait duration. Default: @c Timeout::kDefaultInterval.
191 * @return @c true if a subscriber appeared; @c false on timeout or interrupt.
192 */
193 bool wait_for_subscribers(std::chrono::milliseconds timeout = Timeout::kDefaultInterval);
194
195 /**
196 * @brief Returns @c true if at least one subscriber is currently present.
197 *
198 * @details
199 * Non-blocking poll; reflects the transport's last known peer state.
200 *
201 * @return @c true when one or more subscribers are known to exist.
202 */
203 [[nodiscard]] bool has_subscribers() const;
204
205 /**
206 * @brief Serialises and publishes @p msg to all current subscribers.
207 *
208 * @details
209 * Serialization is performed according to @c kMsgType. On loan-capable
210 * transports (e.g. @c shm://) the output buffer is a loaned segment to
211 * avoid an extra copy. Loaned buffers are not used when security is
212 * enabled (@c kWithSecurity) because the encrypted payload size differs
213 * from the serialized size.
214 *
215 * By default (@p force = @c false) the call is a no-op when no subscribers
216 * are present; pass @c true to force-write regardless (useful for field-mode
217 * or recording-only scenarios).
218 *
219 * For @c intra:// with a message type whose @c element_type derives from
220 * @c IntraDataType (generated via @c VLINK_INTRA_DATA_DECLARE), the pointer
221 * is forwarded zero-copy and no serialization occurs.
222 *
223 * @param msg Message value to publish.
224 * @param force @c true to publish even with no subscribers.
225 * @return @c true if the transport accepted the message; @c false on error.
226 */
227 bool publish(const MsgT& msg, bool force = false);
228
229 /**
230 * @brief Publishes a pre-finished @c FlatBufferBuilder buffer directly.
231 *
232 * @details
233 * Accepts a pointer to a @c flatbuffers::FlatBufferBuilder whose @c Finish()
234 * has already been called. The raw bytes are shallow-copied and sent without
235 * re-serialisation. Useful in pipeline scenarios where the FlatBuffers object
236 * is constructed externally.
237 *
238 * @param fbb Pointer to a finished @c flatbuffers::FlatBufferBuilder.
239 * @param force @c true to publish even with no subscribers.
240 * @return @c true on success; @c false on error.
241 */
242 bool publish_fbb(const void* fbb, bool force = false);
243
244 /**
245 * @brief Changes this publisher's role to @c kSetter (field-writer).
246 *
247 * @details
248 * Updates @c impl_->impl_type from @c kPublisher to @c kSetter so that
249 * transport-specific field semantics are applied (e.g. last-value retention
250 * for late-joining getters). If called after @c init() the extension is
251 * automatically reinitialised. Used internally by @c Setter.
252 */
253 void mark_as_setter();
254
255 private:
256 bool write_bytes(const Bytes& data);
257
258 bool write_intra(const IntraData& intra_data);
259};
260
261/**
262 * @class SecurityPublisher
263 * @brief Convenience alias for @c Publisher with message security enabled.
264 *
265 * @details
266 * Equivalent to @c Publisher<MsgT, SecurityType::kWithSecurity>. Encrypts
267 * every outgoing message using the key or callbacks configured via
268 * @c set_security_key() or @c set_security_callbacks().
269 *
270 * @note Not supported on @c intra:// or @c dds:// CDR transport.
271 *
272 * @tparam MsgT Message type to publish.
273 */
274template <typename MsgT>
275class SecurityPublisher : public Publisher<MsgT, SecurityType::kWithSecurity> {
276 public:
278};
279
280} // namespace vlink
281
Base CRTP template for all VLink communication nodes.
Abstract base class for all transport-specific publisher implementations.