VLink  2.1.0
A high-performance communication middleware
trigger_plugin_interface.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 trigger_plugin_interface.h
26  * @brief Plugin contract for reacting to trigger-recorder events -- above all, deciding what happens
27  * to a dumped bag @e after it is written (network upload, archival, notification, cleanup).
28  *
29  * @details
30  * @c TriggerPluginInterface is a dynamic plugin loaded through the VLink @c Plugin framework and
31  * attached to a @c TriggerRecorder via @c TriggerRecorder::bind_trigger_interface(). Unlike
32  * @c BagPluginInterface -- a frame-forwarding pipeline that rewrites traffic in flight -- this
33  * interface is an @b observer over the recorder's life cycle: the recorder owns the ring buffer and
34  * the disk write, and the plugin is notified at each stage so it can drive the @e next step. The
35  * primary lifecycle hook is @c on_dump_finished(), invoked once the bag file is fully
36  * written and closed -- the natural place to upload the file to a backend, move it to long-term
37  * storage, enqueue it for transfer, or fire an alert.
38  *
39  * A broad set of hooks is provided so an implementation can instrument the whole flow. Implementations supply
40  * @c init() and @c on_dump_finished(); the remaining hooks have default no-op implementations.
41  *
42  * Plugin contract:
43  *
44  * | Hook | Stage / thread | Purpose |
45  * | ------------------- | --------------------------------- | ------------------------------------------- |
46  * | init() | plugin load (daemon thread) | Parse the host-supplied configuration |
47  * | on_start() | engine start (recorder loop) | Acquire resources (open an upload session) |
48  * | on_stop() | engine stop (recorder loop) | Release resources |
49  * | on_trigger() | window captured (recorder loop) | A dump is about to run for this request |
50  * | on_dump_started() | writer opened (recorder loop) | The output file is being written |
51  * | on_frame() | frame submitted (recorder loop) | Inspect / count each writer-accepted frame |
52  * | on_dump_finished() | file closed (recorder loop) | Upload / archive / notify -- the next step |
53  * | on_dump_failed() | dump aborted (recorder loop) | React to a failed dump |
54  * | on_file_rotated() | file removed (recorder loop) | A rotated-out file was deleted |
55  * | flush() | before unbind / teardown | Drain plugin-internal async work |
56  *
57  * @note Dump hooks and normal recorder start/stop hooks run on the recorder loop. Bind the plugin while the
58  * recorder is stopped. A slow hook blocks later recorder work, so offload it to a plugin-owned worker and
59  * drain it in @c flush(). @c on_frame() can be hot -- keep it cheap.
60  * @note Hooks must not re-enter the owning recorder.
61  *
62  * @par Example (upload every dumped bag to a backend)
63  * @code
64  * class UploadPlugin : public vlink::TriggerPluginInterface {
65  * public:
66  * bool init(const std::string& config) override { return queue_.configure(config); }
67  *
68  * void on_dump_finished(const DumpResult& result) override {
69  * if (result.success) {
70  * queue_.push(result.path); // hand off to a background uploader; drain it in flush()
71  * }
72  * }
73  *
74  * void flush() override { queue_.drain(); }
75  *
76  * private:
77  * UploadQueue queue_;
78  * };
79  * VLINK_PLUGIN_DECLARE(UploadPlugin, 2, 0)
80  * @endcode
81  */
82 
83 #pragma once
84 
85 #include <cstdint>
86 #include <string>
87 
88 #include "../base/plugin.h"
89 #include "../impl/types.h"
90 
91 namespace vlink {
92 
93 /**
94  * @class TriggerPluginInterface
95  * @brief Abstract plugin base notified across a @c TriggerRecorder's life cycle and dump pipeline.
96  *
97  * @details
98  * The host binds an instance through @c TriggerRecorder::bind_trigger_interface() and calls each
99  * hook at the corresponding stage. Implementations provide @c init() and @c on_dump_finished(); the remaining
100  * hooks have default no-op implementations. Implementations must follow the threading contract documented
101  * above.
102  */
105 
106  protected:
108 
109  virtual ~TriggerPluginInterface() = default;
110 
111  public:
112  /**
113  * @struct TriggerContext
114  * @brief Describes an accepted trigger request, delivered to @c on_trigger().
115  */
116  struct TriggerContext final {
117  std::string reason; ///< Trigger reason (also written as the bag tag).
118  std::string name_hint; ///< Requested output file-name hint (may be empty).
119  std::string out_file; ///< Explicit output path requested (empty => auto-named).
120  int64_t pre_ms{-1}; ///< Per-trigger pre window override in ms (<0 => configured default).
121  int64_t post_ms{-1}; ///< Per-trigger post window override in ms (<0 => configured default).
122  int64_t trigger_timestamp{0}; ///< Wall-clock time of the trigger instant, in microseconds.
123  };
124 
125  /**
126  * @struct DumpContext
127  * @brief Describes the dump currently being written, delivered to @c on_dump_started() / @c on_frame().
128  */
129  struct DumpContext final {
130  std::string reason; ///< Trigger reason for this dump.
131  std::string path; ///< Output bag file path.
132  int64_t start_timestamp{0}; ///< Wall-clock time of the window's first frame, in milliseconds.
133  int64_t url_count{0}; ///< Number of URLs snapshotted into this dump (some may contribute 0 frames).
134  };
135 
136  /**
137  * @struct DumpResult
138  * @brief Final outcome of a dump, delivered to @c on_dump_finished() / @c on_dump_failed().
139  */
140  struct DumpResult final {
141  std::string reason; ///< Trigger reason for this dump.
142  std::string path; ///< Output bag file path.
143  int64_t frame_count{0}; ///< Snapshot frames accepted by the writer; a bag plugin may alter final output count.
144  int64_t dropped_count{0}; ///< Retained for compatibility; a synchronous dump aborts on failure, so this stays 0.
145  int64_t byte_count{0}; ///< Total payload bytes accepted by the writer.
146  int64_t url_count{0}; ///< Number of URLs snapshotted into this dump.
147  int64_t start_timestamp{0}; ///< Wall-clock time of the window's first frame, in milliseconds.
148  int64_t duration_us{0}; ///< Wall-clock time spent writing the dump, in microseconds.
149  bool success{false}; ///< @c true when the dump completed and the file was closed.
150  std::string error; ///< Human-readable failure reason when @c success is @c false.
151  };
152 
153  /**
154  * @brief Initialises the plugin with an opaque configuration string.
155  *
156  * @details
157  * Called once by a plugin-loading host before the plugin is bound to a recorder. The string may be a file
158  * path, JSON document or any other format defined by the plugin. Programmatically constructed plugins call
159  * this method themselves when configuration is required.
160  *
161  * @param config Plugin-defined configuration; may be empty.
162  * @return @c true on success; @c false makes the host reject the plugin.
163  */
164  virtual bool init(const std::string& config) = 0;
165 
166  /**
167  * @brief Notifies the plugin that the recorder has started.
168  *
169  * @details
170  * Invoked on the recorder's loop thread during @c TriggerRecorder::async_run(), after discovery is running.
171  * A place to acquire long-lived resources such as an upload session. Default: no-op.
172  */
173  virtual void on_start();
174 
175  /**
176  * @brief Notifies the plugin that the recorder is stopping.
177  *
178  * @details
179  * Invoked on the recorder's loop thread during shutdown. A place to release resources acquired in
180  * @c on_start(). Default: no-op.
181  */
182  virtual void on_stop();
183 
184  /**
185  * @brief Notifies the plugin that a trigger was accepted and a dump is about to run.
186  *
187  * @details
188  * Invoked on the recorder's loop thread after the requested window has been snapshotted and before the bag
189  * writer is opened. Slow work delays persistence but does not change the captured window. Default: no-op.
190  *
191  * @param context Accepted trigger request details.
192  */
193  virtual void on_trigger(const TriggerContext& context);
194 
195  /**
196  * @brief Notifies the plugin that the output file has been opened and writing is beginning.
197  *
198  * @details
199  * Invoked on the recorder's loop thread after the bag writer is created, before frames are written.
200  * Default: no-op.
201  *
202  * @param context Dump-in-progress details.
203  */
204  virtual void on_dump_started(const DumpContext& context);
205 
206  /**
207  * @brief Inspects each frame as it is submitted to the writer (hot path).
208  *
209  * @details
210  * Invoked on the recorder's loop thread once per frame successfully handed to the writer, in ascending
211  * capture-time order. A frame the writer fails to persist aborts the dump and is @b not reported here.
212  * This observes @e submission, not final persistence: a bound bag reorder
213  * plugin may still reorder or drop the frame downstream before it reaches disk. Runs for potentially many
214  * frames, so keep the implementation cheap; it cannot alter or drop the frame. Default: no-op.
215  *
216  * @param frame Submitted frame (payload is a shallow view valid for the call).
217  * @param context Dump-in-progress details.
218  */
219  virtual void on_frame(const Frame& frame, const DumpContext& context);
220 
221  /**
222  * @brief Notifies the plugin that the dump file has been fully written and closed.
223  *
224  * @details
225  * The primary lifecycle hook: invoked on the recorder's loop thread once the bag is finalised.
226  * The place to upload, archive, or notify. Slow work here blocks the next dump -- offload to a worker and
227  * drain it in @c flush().
228  *
229  * @param result Final dump outcome, with @c success set to @c true.
230  */
231  virtual void on_dump_finished(const DumpResult& result) = 0;
232 
233  /**
234  * @brief Notifies the plugin that a dump was aborted before completion.
235  *
236  * @details
237  * Invoked on the recorder's loop thread when the writer could not be created, the write failed, or an accepted
238  * delayed dump was abandoned during shutdown. Default: no-op.
239  *
240  * @param result Dump outcome, with @c success set to @c false and @c error describing the failure.
241  */
242  virtual void on_dump_failed(const DumpResult& result);
243 
244  /**
245  * @brief Notifies the plugin that an old dump file was removed by rotation.
246  *
247  * @details
248  * Invoked on the recorder's loop thread each time file rotation deletes an aged-out dump, so a plugin
249  * mirroring files to a backend can mirror the deletion. Default: no-op.
250  *
251  * @param path Path of the file that was deleted.
252  */
253  virtual void on_file_rotated(const std::string& path);
254 
255  /**
256  * @brief Drains any plugin-internal asynchronous work before the host unbinds or tears down.
257  *
258  * @details
259  * Invoked by the host while the plugin is still valid, right before it detaches this plugin (at recorder stop /
260  * teardown). A plugin that offloads work to a background worker (e.g. an upload queue) must override this to
261  * finish or checkpoint that work synchronously, so pending uploads are not lost. Default: no-op.
262  */
263  virtual void flush();
264 
265  private:
267 };
268 
269 ////////////////////////////////////////////////////////////////
270 /// Details
271 ////////////////////////////////////////////////////////////////
272 
274 
276 
277 inline void TriggerPluginInterface::on_trigger(const TriggerContext& context) { (void)context; }
278 
279 inline void TriggerPluginInterface::on_dump_started(const DumpContext& context) { (void)context; }
280 
281 inline void TriggerPluginInterface::on_frame(const Frame& frame, const DumpContext& context) {
282  (void)frame;
283  (void)context;
284 }
285 
286 inline void TriggerPluginInterface::on_dump_failed(const DumpResult& result) { (void)result; }
287 
288 inline void TriggerPluginInterface::on_file_rotated(const std::string& path) { (void)path; }
289 
291 
292 } // namespace vlink
#define VLINK_DISALLOW_COPY_AND_ASSIGN(classname)
Deletes the copy constructor and copy-assignment operator of classname.
Definition: macros.h:174
#define VLINK_PLUGIN_REGISTER(InterfaceType)
Declares a plugin's identity from the demangled name of its abstract interface.
Definition: plugin.h:347