VLink  2.0.0
A high-performance communication middleware
setter.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 setter.h
26  * @brief Write-side primitive of the VLink field communication model.
27  *
28  * @details
29  * @c Setter<ValueT, SecT> publishes the latest value for a field topic.
30  * Every call to @c set() updates the locally cached value and emits the new
31  * serialised payload over the transport. When a late @c Getter joins after
32  * the setter has already written, an internally registered @c sync()
33  * callback resends the cached value so the late peer receives the current
34  * state immediately.
35  *
36  * The class is a thin, header-only template wrapper around @c SetterImpl.
37  *
38  * @par Field-model Data Flow
39  * @verbatim
40  * Setter<ValueT> Transport Back-end Getter<ValueT>
41  * -------------- ------------------ ---------------
42  * | set(v) | |
43  * | cache value | |
44  * | Serializer::serialize | |
45  * |----------------------------->|--- latest-value frame ------>|
46  * | | (overwrites any previous) |
47  * | | |--> callback(v)
48  * | | |--> get() => v
49  * | <-- late joiner sync ------- | <-- sync() fired by impl --- |
50  * | re-emit cached value | |
51  * |----------------------------->|----------------------------->|
52  * @endverbatim
53  *
54  * @par Setter vs Publisher
55  * | Feature | @c Setter<T> | @c Publisher<T> |
56  * | ------------------------ | --------------------------------------- | ------------------------------ |
57  * | Transport role tag | @c kSetter | @c kPublisher |
58  * | Latest-value retention | Re-sent to late-joining getters | No re-send to late subscribers |
59  * | Sync-on-connect callback | Yes (registered inside @c init()) | No |
60  * | Cross-role bridge | @c mark_as_publisher() | @c mark_as_setter() |
61  *
62  * @par Durability and Persistence Modes
63  * @c Setter inherits durability behaviour from the transport's effective
64  * @c Qos profile. Common configurations:
65  *
66  * | Durability mode | Behaviour |
67  * | -------------------- | ---------------------------------------------------------- |
68  * | @c kVolatile | Cached in-process only; re-sent on local @c sync() hook. |
69  * | @c kTransientLocal | Cached inside the transport writer for late subscribers. |
70  * | @c kTransient | Persisted in an external durability service (DDS only). |
71  * | @c kPersistent | Persisted to stable storage (DDS only). |
72  *
73  * @par Usage Example
74  * @code
75  * vlink::Setter<MyStruct> setter("dds://vehicle/gear");
76  * setter.set(MyStruct{3, "Drive"});
77  *
78  * // A Getter that connects afterwards still receives the cached value:
79  * vlink::Getter<MyStruct> getter("dds://vehicle/gear");
80  * if (auto v = getter.get()) { use(*v); }
81  * @endcode
82  *
83  * @see getter.h, publisher.h, node.h, extension/qos.h
84  */
85 
86 #pragma once
87 
88 #include <memory>
89 #include <mutex>
90 #include <optional>
91 #include <string>
92 #include <type_traits>
93 
94 #include "./impl/setter_impl.h"
95 #include "./node.h"
96 
97 namespace vlink {
98 
99 /**
100  * @class Setter
101  * @brief Type-safe latest-value writer for the VLink field communication model.
102  *
103  * @details
104  * Inherits the full @c Node API and adds field-specific operations: cached
105  * @c set(), automatic late-joiner sync via an internally registered
106  * @c sync() callback, and bridging hooks to behave as a plain publisher
107  * on transports that do not natively differentiate the two roles.
108  *
109  * @tparam ValueT C++ value type. Must satisfy @c Serializer::is_supported().
110  * @tparam SecT Security mode; defaults to @c SecurityType::kWithoutSecurity.
111  */
112 template <typename ValueT, SecurityType SecT = SecurityType::kWithoutSecurity>
113 class Setter : public Node<SetterImpl, SecT> {
114  public:
115  using UniquePtr = std::unique_ptr<Setter<ValueT, SecT>>; ///< Owning unique-pointer alias.
116  using SharedPtr = std::shared_ptr<Setter<ValueT, SecT>>; ///< Owning shared-pointer alias.
117 
118  static constexpr ImplType kImplType = kSetter; ///< Node role tag (@c kSetter).
119  static constexpr Serializer::Type kValueType = Serializer::get_type_of<ValueT>(); ///< Codec resolved from @c ValueT.
120 
121  static_assert(Serializer::is_supported(kValueType), "<ValueT> is not a supported Serializer type.");
122 
123  /**
124  * @brief Heap-allocates a @c Setter and wraps it in a @c std::unique_ptr.
125  *
126  * @param url_str Field URL such as @c "shm://vehicle/gear".
127  * @param type Whether to call @c init() inline; default is @c InitType::kWithInit.
128  * @return Owning @c UniquePtr to the new setter.
129  */
130  [[nodiscard]] static UniquePtr create_unique(const std::string& url_str, InitType type = InitType::kWithInit);
131 
132  /**
133  * @brief Heap-allocates a @c Setter and wraps it in a @c std::shared_ptr.
134  *
135  * @param url_str Field URL string.
136  * @param type Whether to call @c init() inline; default is @c InitType::kWithInit.
137  * @return Owning @c SharedPtr to the new setter.
138  */
139  [[nodiscard]] static SharedPtr create_shared(const std::string& url_str, InitType type = InitType::kWithInit);
140 
141  /**
142  * @brief Constructs a setter from a typed transport configuration object.
143  *
144  * @details
145  * Accepts any @c Conf-derived configuration. Following @c init() the
146  * setter registers a transport-level @c sync() callback that re-emits the
147  * cached value whenever a late @c Getter connects.
148  *
149  * @tparam ConfT Concrete configuration type derived from @c Conf.
150  * @param conf Populated configuration aggregate.
151  * @param type Whether to call @c init() inline; default is @c InitType::kWithInit.
152  */
153  // NOLINTNEXTLINE(modernize-use-constraints)
154  template <typename ConfT, typename = std::enable_if_t<std::is_base_of_v<Conf, ConfT>>>
155  explicit Setter(const ConfT& conf, InitType type = InitType::kWithInit);
156 
157  /**
158  * @brief Constructs a setter from a URL string.
159  *
160  * @param url_str Field URL such as @c "dds://vehicle/gear".
161  * @param type Whether to call @c init() inline; default is @c InitType::kWithInit.
162  */
163  explicit Setter(const std::string& url_str, InitType type = InitType::kWithInit);
164 
165  /**
166  * @brief Destroys the setter and drains in-flight transport callbacks.
167  *
168  * @details
169  * Required so the @c sync() callback installed by @c init() cannot fire on
170  * the transport thread after this setter's mutex and cached value have
171  * already been destroyed. Mirrors the lifecycle contract of @c Client and
172  * @c Getter.
173  */
174  ~Setter() override;
175 
176  /**
177  * @brief Initialises the setter and registers the late-getter @c sync() hook.
178  *
179  * @details
180  * Calls the base @c Node initialisation, then installs a transport-level
181  * callback that resends the cached value whenever a new @c Getter joins
182  * after this setter has already been written.
183  *
184  * @return @c true on first successful initialisation; @c false otherwise.
185  */
186  bool init() override;
187 
188  /**
189  * @brief Deinitialises the setter and releases the underlying transport resources.
190  *
191  * @details
192  * Delegates to the base @c Node teardown path. After deinitialisation the
193  * setter no longer participates in @c sync() or writes until @c init() is
194  * called again.
195  *
196  * @return @c true on first successful deinitialisation; @c false if not initialised.
197  */
198  bool deinit() override;
199 
200  /**
201  * @brief Writes a new field value and emits it to every connected @c Getter.
202  *
203  * @details
204  * Caches @p value under @c mtx_, then serialises and writes it via the
205  * transport. When security is enabled the serialised payload is encrypted
206  * before transmission. The cached value is automatically re-emitted when
207  * a late @c Getter joins (see @c init()).
208  *
209  * @param value New field value to publish.
210  */
211  void set(const ValueT& value);
212 
213  /**
214  * @brief Promotes this setter to behave as a @c Publisher at the transport layer.
215  *
216  * @details
217  * Switches @c impl_type from @c kSetter to @c kPublisher so that
218  * event-mode semantics are applied (no latest-value retention).
219  * Reinitialises the transport extension if called post-@c init(). Useful
220  * on transports that do not natively distinguish the two roles.
221  */
222  void mark_as_publisher();
223 
224  private:
225  void write(const ValueT& value);
226 
227  void write_bytes(const Bytes& data);
228 
229  std::optional<ValueT> value_;
230  std::mutex mtx_;
231 };
232 
233 /**
234  * @class SecuritySetter
235  * @brief Convenience alias of @c Setter with per-message encryption enabled.
236  *
237  * @details
238  * Equivalent to @c Setter<ValueT, SecurityType::kWithSecurity>. Each
239  * outgoing payload is encrypted before transmission.
240  *
241  * @tparam ValueT Value type to write.
242  */
243 template <typename ValueT>
244 class SecuritySetter : public Setter<ValueT, SecurityType::kWithSecurity> {
245  public:
246  using UniquePtr = std::unique_ptr<SecuritySetter<ValueT>>; ///< Owning unique-pointer alias.
247  using SharedPtr = std::shared_ptr<SecuritySetter<ValueT>>; ///< Owning shared-pointer alias.
248 
249  /**
250  * @brief Heap-allocates a @c SecuritySetter and wraps it in a @c std::unique_ptr.
251  *
252  * @tparam SecurityConfigT Forwardable @c Security::Config compatible type.
253  * @param url_str Field URL string.
254  * @param sec_cfg Security configuration; empty uses the default symmetric slot.
255  * @param type Whether to call @c init() inline; default is @c InitType::kWithInit.
256  * @return Owning @c UniquePtr to the new secure setter.
257  */
258  // NOLINTNEXTLINE(modernize-use-constraints)
259  template <typename SecurityConfigT = Security::Config>
260  [[nodiscard]] static UniquePtr create_unique(const std::string& url_str, SecurityConfigT&& sec_cfg = {},
262 
263  /**
264  * @brief Heap-allocates a @c SecuritySetter and wraps it in a @c std::shared_ptr.
265  *
266  * @tparam SecurityConfigT Forwardable @c Security::Config compatible type.
267  * @param url_str Field URL string.
268  * @param sec_cfg Security configuration; empty uses the default symmetric slot.
269  * @param type Whether to call @c init() inline; default is @c InitType::kWithInit.
270  * @return Owning @c SharedPtr to the new secure setter.
271  */
272  // NOLINTNEXTLINE(modernize-use-constraints)
273  template <typename SecurityConfigT = Security::Config>
274  [[nodiscard]] static SharedPtr create_shared(const std::string& url_str, SecurityConfigT&& sec_cfg = {},
276 
277  /**
278  * @brief Constructs a @c SecuritySetter from a typed configuration object.
279  *
280  * @tparam ConfT Configuration type derived from @c Conf.
281  * @tparam SecurityConfigT Forwardable @c Security::Config compatible type.
282  * @param conf Populated configuration aggregate.
283  * @param sec_cfg Security configuration; empty uses the default symmetric slot.
284  * @param type Whether to call @c init() inline; default is @c InitType::kWithInit.
285  */
286  // NOLINTNEXTLINE(modernize-use-constraints)
287  template <typename ConfT, typename SecurityConfigT = Security::Config,
288  typename = std::enable_if_t<std::is_base_of_v<Conf, ConfT>>>
289  explicit SecuritySetter(const ConfT& conf, SecurityConfigT&& sec_cfg = {}, InitType type = InitType::kWithInit);
290 
291  /**
292  * @brief Constructs a @c SecuritySetter from a URL string and installs the security configuration.
293  *
294  * @details
295  * Builds the base @c Setter in @c kWithoutInit mode, installs @p sec_cfg
296  * via @c enable_security(), then calls @c init() unless deferred. When
297  * @c enable_security() fails to produce a usable @c NodeImpl::security the
298  * subsequent @c init() will fail.
299  *
300  * @tparam SecurityConfigT Forwardable @c Security::Config compatible type.
301  * @param url_str Field URL string.
302  * @param sec_cfg Security configuration; empty uses the default symmetric slot.
303  * @param type Whether to call @c init() inline; default is @c InitType::kWithInit.
304  */
305  // NOLINTNEXTLINE(modernize-use-constraints)
306  template <typename SecurityConfigT = Security::Config>
307  explicit SecuritySetter(const std::string& url_str, SecurityConfigT&& sec_cfg = {},
309 };
310 
311 } // namespace vlink
312 
313 #include "./internal/setter-inl.h"
Common CRTP base for every VLink communication primitive.
Transport-neutral base class for every field-model setter (latest-value writer).