VLink 2.0.0
A high-performance communication middleware
载入中...
搜索中...
未找到
getter.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 getter.h
26 * @brief Type-safe field-model reader for VLink topics.
27 *
28 * @details
29 * @c Getter<ValueT, SecT> is the read side of the VLink field model.
30 * It maintains the latest value published by any matching @c Setter on the
31 * same URL. Unlike @c Subscriber, it retains only the most recent value
32 * rather than queuing a history of updates.
33 *
34 * @par Field Model Overview
35 * @code
36 * Setter<T> Transport Back-end Getter<T>
37 * | | |
38 * |-- set(value) ----------> | |
39 * | serialize(value) |-- latest-value delivery ----> |
40 * | | (overwrites previous) |--> listen callback(value)
41 * | | | value_ updated
42 * | | |--> get() returns latest
43 * @endcode
44 *
45 * @par Key Differences: Getter vs Subscriber
46 * | Feature | @c Getter<T> | @c Subscriber<T> |
47 * | ----------------------- | -------------------------------------- | ------------------------------ |
48 * | Value retention | Latest value cached | No caching |
49 * | Transport role | @c kGetter | @c kSubscriber |
50 * | Blocking read | @c wait_for_value() | N/A |
51 * | Change-reporting filter | @c set_change_reporting(true) | No built-in filter |
52 * | Cross-transport use | As subscriber: @c mark_as_subscriber() | As getter: @c mark_as_getter() |
53 *
54 * @par Usage Patterns
55 * @code
56 * // Pattern 1: polling
57 * Getter<int> g("shm://my_field");
58 * if (auto v = g.get()) {
59 * std::cout << "value: " << *v << std::endl;
60 * }
61 *
62 * // Pattern 2: blocking wait
63 * if (g.wait_for_value()) {
64 * auto v = g.get();
65 * }
66 *
67 * // Pattern 3: value-change callback (fires when Setter writes a new value)
68 * g.listen([](const int& v) { std::cout << "updated: " << v << std::endl; });
69 *
70 * // Pattern 4: change-only reporting (suppress duplicate values)
71 * g.set_change_reporting(true);
72 * g.listen([](const int& v) { ... });
73 * @endcode
74 *
75 * @note @c get() and @c wait_for_value() both require a prior Setter write to
76 * return a value. Before any Setter has written, @c get() returns
77 * @c std::nullopt and @c wait_for_value() blocks until one does.
78 *
79 * @tparam ValueT Value type. Must satisfy @c Serializer::is_supported().
80 * @tparam SecT Security mode; defaults to @c SecurityType::kWithoutSecurity.
81 */
82
83#pragma once
84
85#include <functional>
86#include <memory>
87#include <mutex>
88#include <optional>
89#include <string>
90
92#include "./impl/getter_impl.h"
93#include "./node.h"
94
95namespace vlink {
96
97/**
98 * @class Getter
99 * @brief Type-safe field reader for the VLink field communication model.
100 *
101 * @tparam ValueT Value type to read.
102 * @tparam SecT Security mode.
103 */
104template <typename ValueT, SecurityType SecT = SecurityType::kWithoutSecurity>
105class Getter : public Node<GetterImpl, SecT> {
106 public:
107 /** @brief Unique-pointer alias. */
108 using UniquePtr = std::unique_ptr<Getter<ValueT, SecT>>;
109
110 /** @brief Shared-pointer alias. */
111 using SharedPtr = std::shared_ptr<Getter<ValueT, SecT>>;
112
113 /** @brief User-facing callback type for value-change notifications. */
114 using MsgCallback = std::function<void(const ValueT&)>;
115
116 /** @brief Node role identifier (@c kGetter). */
117 static constexpr ImplType kImplType = kGetter;
118
119 /** @brief Serializer type resolved at compile time from @c ValueT. */
121
122 static_assert(Serializer::is_supported(kValueType), "<ValueT> is not a supported Serializer type.");
123
124 /**
125 * @brief Creates a @c Getter on the heap wrapped in a @c unique_ptr.
126 *
127 * @param url_str Field URL string (e.g. @c "shm://vehicle/gear").
128 * @param type @c kWithInit to call @c init() immediately (default).
129 * @return @c UniquePtr owning the new getter.
130 */
131 [[nodiscard]] static UniquePtr create_unique(const std::string& url_str, InitType type = InitType::kWithInit);
132
133 /**
134 * @brief Creates a @c Getter on the heap wrapped in a @c shared_ptr.
135 *
136 * @param url_str Field URL string.
137 * @param type @c kWithInit to call @c init() immediately (default).
138 * @return @c SharedPtr owning the new getter.
139 */
140 [[nodiscard]] static SharedPtr create_shared(const std::string& url_str, InitType type = InitType::kWithInit);
141
142 /**
143 * @brief Constructs a getter from a typed transport configuration object.
144 *
145 * @tparam ConfT @c Conf-derived configuration type.
146 * @param conf Populated configuration object.
147 * @param type @c kWithInit to call @c init() immediately (default).
148 */
149 // NOLINTNEXTLINE(modernize-use-constraints)
150 template <typename ConfT, typename = std::enable_if_t<std::is_base_of_v<Conf, ConfT>>>
151 explicit Getter(const ConfT& conf, InitType type = InitType::kWithInit);
152
153 /**
154 * @brief Constructs a getter from a URL string.
155 *
156 * @param url_str Field URL (e.g. @c "shm://vehicle/gear").
157 * @param type @c kWithInit to call @c init() immediately (default).
158 */
159 explicit Getter(const std::string& url_str, InitType type = InitType::kWithInit);
160
161 /**
162 * @brief Returns the latest cached value, if one has been received.
163 *
164 * @details
165 * Thread-safe. Returns @c std::nullopt if no @c Setter has written a value
166 * yet since this getter was initialised.
167 *
168 * @return @c std::optional<ValueT> -- holds the latest value, or empty.
169 */
170 [[nodiscard]] std::optional<ValueT> get() const;
171
172 /**
173 * @brief Blocks until a value is received or the timeout expires.
174 *
175 * @details
176 * Returns immediately if a value is already available. A @p timeout of @c 0
177 * is treated as infinite (a warning is logged). Can be interrupted by
178 * @c interrupt(), which causes this method to return @c false.
179 *
180 * After returning @c true, call @c get() to retrieve the value.
181 *
182 * @param timeout Maximum wait duration. Default: @c Timeout::kDefaultInterval.
183 * @return @c true if a value was received; @c false on timeout or interrupt.
184 */
185 bool wait_for_value(std::chrono::milliseconds timeout = Timeout::kDefaultInterval);
186
187 /**
188 * @brief Registers a callback invoked whenever a new value arrives.
189 *
190 * @details
191 * The callback receives a pre-deserialized @c ValueT reference. It is
192 * invoked on every setter write unless @c set_change_reporting(true) is
193 * active, in which case duplicate values (same raw bytes as the last) are
194 * suppressed before the callback is called.
195 *
196 * Internally, @c Getter also maintains @c value_ and notifies @c wait_for_value().
197 * The listen callback is stored once; calling @c listen() more than once is
198 * a fatal error.
199 *
200 * @param callback @c void(const ValueT&) invoked on each new value.
201 * @return @c true always (registration is deferred to @c init()).
202 */
203 bool listen(MsgCallback&& callback);
204
205 /**
206 * @brief Enables or disables change-reporting (suppress duplicate values).
207 *
208 * @details
209 * When @c true, incoming values whose raw serialized bytes are identical to
210 * the previous delivery are silently dropped -- neither the callback nor
211 * @c wait_for_value() is notified. Useful for reducing CPU load when a
212 * @c Setter writes the same value repeatedly.
213 *
214 * @param enable @c true to enable change-only reporting; @c false to disable.
215 */
216 void set_change_reporting(bool enable);
217
218 /**
219 * @brief Enables or disables manual-unloan mode for zero-copy receives.
220 *
221 * @param manual_unloan @c true to enable; @c false for automatic (default).
222 */
223 void set_manual_unloan(bool manual_unloan) override;
224
225 /**
226 * @brief Enables or disables per-value latency and sample-loss tracking.
227 *
228 * @param enable @c true to start tracking; @c false to stop.
229 */
230 void set_latency_and_lost_enabled(bool enable);
231
232 /**
233 * @brief Returns @c true if latency and sample-loss tracking is active.
234 *
235 * @return @c true if @c set_latency_and_lost_enabled(true) was called.
236 */
237 [[nodiscard]] bool is_latency_and_lost_enabled() const;
238
239 /**
240 * @brief Returns the most recently measured end-to-end value latency.
241 *
242 * @return Latency in microseconds; @c 0 if tracking is disabled.
243 */
244 [[nodiscard]] int64_t get_latency() const;
245
246 /**
247 * @brief Returns cumulative sample delivery statistics.
248 *
249 * @return @c SampleLostInfo with @c total expected and @c lost value counts.
250 */
251 [[nodiscard]] SampleLostInfo get_lost() const;
252
253 /**
254 * @brief Returns @c true if change-reporting mode is currently active.
255 *
256 * @return @c true if duplicate suppression is enabled.
257 */
258 [[nodiscard]] bool get_change_reporting() const;
259
260 /**
261 * @brief Initialises the getter and registers the internal delivery callback.
262 *
263 * @details
264 * Overrides @c Node::init() to also set up the internal @c listen_bytes()
265 * callback that receives raw bytes, deserialises them into @c ValueT,
266 * stores the result in @c value_, and fires the user @c listen() callback.
267 *
268 * @return @c true on success; @c false if already initialised.
269 */
270 bool init() override;
271
272 /**
273 * @brief Interrupts any blocking @c wait_for_value() call.
274 *
275 * @details
276 * Overrides @c Node::interrupt() to additionally notify the getter's own
277 * condition variable, causing @c wait_for_value() to return @c false.
278 */
279 void interrupt() override;
280
281 /**
282 * @brief Changes this getter's role to @c kSubscriber (event-receiver).
283 *
284 * @details
285 * Updates @c impl_->impl_type from @c kGetter to @c kSubscriber so that
286 * transport-specific event semantics are applied. If called after @c init(),
287 * the extension is automatically reinitialised. Used internally when
288 * routing a @c Getter through an event-capable transport.
289 */
290 void mark_as_subscriber();
291
292 private:
293 void listen_bytes(NodeImpl::MsgCallback&& callback);
294
295 std::optional<ValueT> value_;
296 mutable std::mutex mtx_;
298 MsgCallback callback_;
299 Bytes last_cache_;
300 bool has_value_notification_{false};
301 bool change_reporting_{false};
302};
303
304/**
305 * @class SecurityGetter
306 * @brief Convenience alias for @c Getter with message security enabled.
307 *
308 * @details
309 * Equivalent to @c Getter<ValueT, SecurityType::kWithSecurity>. Decrypts
310 * each incoming value using the configured security key or callbacks.
311 *
312 * @tparam ValueT Value type to read.
313 */
314template <typename ValueT>
315class SecurityGetter : public Getter<ValueT, SecurityType::kWithSecurity> {
316 public:
318};
319
320} // namespace vlink
321
POSIX monotonic-clock condition variable replacing std::condition_variable.
Abstract base class for all transport-specific getter (field reader) implementations.
Base CRTP template for all VLink communication nodes.