VLink  2.0.0
A high-performance communication middleware
discovery_viewer.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 /**
25  * @file discovery_viewer.h
26  * @brief Live aggregator of VLink endpoint announcements emitted by @c DiscoveryReporter.
27  *
28  * @details
29  * @c DiscoveryViewer is the listening counterpart of @c DiscoveryReporter. It joins the
30  * discovery UDP multicast group, decodes incoming announcements, and maintains an
31  * in-memory snapshot of every URL/process currently advertised on the host or network.
32  * It powers @c vlink-cli, dashboards and any custom monitoring tool that needs a live
33  * topology view.
34  *
35  * Filter modes select which announcements survive into the snapshot:
36  *
37  * | Value | Description |
38  * | ------------------- | ---------------------------------------------------------------------------- |
39  * | @c kFilterNone | Keep every announcement regardless of origin |
40  * | @c kFilterAvailable | Drop remote announcements for local-only URL schemes (@c intra, @c shm, ...) |
41  * | @c kFilterNative | Keep only announcements emitted by the same host as the viewer |
42  *
43  * Viewer interaction:
44  *
45  * @verbatim
46  * DiscoveryReporter --(UDP multicast)--> +----------------+ Callback(info_list)
47  * | Viewer | ---------------------> user code
48  * Heartbeat timeout ----+---> | (MessageLoop) | <--- get_info_list()
49  * process_offline() ----+---> +----------------+
50  * @endverbatim
51  *
52  * @par Example
53  * @code
54  * vlink::DiscoveryViewer viewer(vlink::DiscoveryViewer::kFilterAvailable);
55  * viewer.register_callback([](const std::vector<vlink::DiscoveryViewer::Info>& list) {
56  * for (const auto& entry : list) {
57  * VLOG_I("url=", entry.url, " ser=", entry.ser_type,
58  * " hosts=", entry.process_list.size());
59  * }
60  * });
61  * viewer.async_run();
62  * @endcode
63  *
64  * @note The callback runs on the viewer's @c MessageLoop thread; copy the snapshot if it
65  * needs to outlive the call. Endpoints whose heartbeat lapses are pruned automatically.
66  */
67 
68 #pragma once
69 
70 #include <cstdint>
71 #include <memory>
72 #include <string>
73 #include <vector>
74 
75 #include "../base/functional.h"
76 #include "../base/macros.h"
77 #include "../base/message_loop.h"
78 #include "../impl/types.h"
79 
80 namespace vlink {
81 
82 /**
83  * @class DiscoveryViewer
84  * @brief @c MessageLoop-based aggregator of live VLink endpoint announcements.
85  *
86  * @details
87  * Construct with the desired filter and start with @c async_run(). Each viewer is
88  * explicitly owned by the caller; no process-global viewer is exposed. The viewer
89  * continuously rebuilds an @c Info list and notifies the registered callback every time
90  * the topology changes.
91  */
93  public:
94  /**
95  * @brief Selects which announcements contribute to the live snapshot.
96  *
97  * | Value | Effect |
98  * | ----------------- | --------------------------------------------------------------------- |
99  * | kFilterNone | All announcements visible |
100  * | kFilterAvailable | Drop remote announcements for local-only URL schemes |
101  * | kFilterNative | Keep only announcements from the same host |
102  */
103  enum FilterType : uint8_t {
104  kFilterNone = 0, ///< No filtering applied.
105  kFilterAvailable = 1, ///< Drop remote announcements for local-only URL schemes.
106  kFilterNative = 2, ///< Keep only same-host announcements.
107  };
108 
109  /**
110  * @struct Process
111  * @brief Identity of a process that hosts at least one endpoint for a URL.
112  */
113  struct VLINK_EXPORT Process final {
114  uint32_t type{0}; ///< Bitmask of @c ImplType kinds advertised by this process.
115  std::string host; ///< Host name of the process.
116  uint32_t pid{0}; ///< Process identifier.
117  std::string name; ///< Process or application name.
118  std::string ip; ///< IP address of the host.
119  double profiler{-1}; ///< Most recent CPU usage sample (-1 when unavailable).
120 
121  /**
122  * @brief Defines a stable ordering between two process descriptors.
123  *
124  * @details
125  * Sort key is type, then host, IP, name and finally PID.
126  *
127  * @param target Right-hand operand.
128  * @return @c true when @c *this should appear before @p target.
129  */
130  bool operator<(const Process& target) const noexcept;
131  };
132 
133  /**
134  * @struct Info
135  * @brief One row of the discovery snapshot, describing a URL and its publishers/subscribers.
136  *
137  * @details
138  * Each row aggregates the communication kinds, serialisation type, schema family and
139  * the list of processes that have announced a matching endpoint.
140  */
141  struct VLINK_EXPORT Info final {
142  int sort_index{-1}; ///< Stable sort key assigned internally by the viewer.
143  uint32_t type{0}; ///< Bitmask of @c ImplType kinds for this URL.
144  std::string url; ///< Fully-qualified VLink URL.
145  std::string ser_type; ///< Serialisation type name announced for this URL.
146  SchemaType schema_type{SchemaType::kUnknown}; ///< Coarse schema family derived from announcements.
147  std::vector<Process> process_list; ///< Processes currently hosting this URL.
148 
149  /**
150  * @brief Defines a stable ordering between two snapshot rows.
151  *
152  * @details
153  * Sort key is type, then sort_index, URL, schema family, serialisation type and
154  * finally the process list.
155  *
156  * @param target Right-hand operand.
157  * @return @c true when @c *this should appear before @p target.
158  */
159  bool operator<(const Info& target) const noexcept;
160  };
161 
162  /**
163  * @brief Callback signature delivered whenever the snapshot changes.
164  *
165  * @details
166  * Invoked on the viewer's @c MessageLoop thread with the freshly built list.
167  */
168  using Callback = Function<void(const std::vector<Info>& info_list)>;
169 
170  /**
171  * @brief Translates a discovery role token to the corresponding @c ImplType bit.
172  *
173  * @param str Role token: @c "Ser", @c "Cli", @c "Pub", @c "Sub", @c "Set" or @c "Get".
174  * @return Matching @c ImplType, or 0 when the token is not recognised.
175  */
176  [[nodiscard]] static ImplType convert_type(std::string_view str);
177 
178  /**
179  * @brief Formats an @c ImplType bitmask as a human-readable label.
180  *
181  * @param type ImplType bitmask.
182  * @return Display string suitable for tooling output.
183  */
184  [[nodiscard]] static std::string convert_type_to_view(uint32_t type);
185 
186  /**
187  * @brief Formats an @c ImplType bitmask together with its process list.
188  *
189  * @param type ImplType bitmask.
190  * @param process_list Processes to include in the display.
191  * @return Combined display string.
192  */
193  [[nodiscard]] static std::string convert_type_to_view(uint32_t type, const std::vector<Process>& process_list);
194 
195  /**
196  * @brief Returns the UDP multicast/broadcast address used by the discovery subsystem.
197  */
198  [[nodiscard]] static std::string get_listen_address();
199 
200  /**
201  * @brief Builds the viewer with the requested filter mode.
202  *
203  * @param type Filter selecting which announcements survive (default: @c kFilterNone).
204  */
205  explicit DiscoveryViewer(FilterType type = kFilterNone);
206 
207  /**
208  * @brief Stops the viewer loop and releases resources.
209  */
210  ~DiscoveryViewer() override;
211 
212  /**
213  * @brief Registers the callback notified on every snapshot change.
214  *
215  * @details
216  * Replaces any previously installed callback; only the most recent registration
217  * remains effective.
218  *
219  * @param callback Function invoked with the new @c Info list.
220  */
221  void register_callback(Callback&& callback);
222 
223  /**
224  * @brief Returns a copy of the live snapshot at the moment of the call.
225  *
226  * @return Vector of @c Info rows.
227  */
228  [[nodiscard]] std::vector<Info> get_info_list();
229 
230  /**
231  * @brief Resolves the announced serialisation type for @p url.
232  *
233  * @param url Topic URL.
234  * @return Announced serialisation type, or an empty string when unknown.
235  */
236  [[nodiscard]] std::string get_ser_type(const std::string& url) const;
237 
238  /**
239  * @brief Resolves the announced coarse schema family for @p url.
240  *
241  * @param url Topic URL.
242  * @return @c SchemaType, or @c SchemaType::kUnknown when unavailable.
243  */
244  [[nodiscard]] SchemaType get_schema_type(const std::string& url) const;
245 
246  protected:
247  size_t get_max_task_count() const override;
248 
249  uint32_t get_max_elapsed_time() const override;
250 
251  void on_begin() override;
252 
253  void on_end() override;
254 
255  private:
256  void process_timeout();
257 
258  void process_offline(std::string_view hostname, uint32_t pid, std::string_view process_name);
259 
260  void sort_url();
261 
262  void report_list();
263 
264  struct Impl;
265  std::unique_ptr<Impl> impl_;
266 
268 };
269 
270 } // namespace vlink
#define VLINK_EXPORT
Definition: macros.h:81
#define VLINK_DISALLOW_COPY_AND_ASSIGN(classname)
Deletes the copy constructor and copy-assignment operator of classname.
Definition: macros.h:174