VLink  2.1.0
A high-performance communication middleware
bag_plugin_interface.h File Reference

Unified plugin contract for rewriting bag traffic on both playback (read) and recording (write). More...

#include <cstdint>
#include <string>
#include <utility>
#include "../base/plugin.h"
#include "../impl/types.h"
Include dependency graph for bag_plugin_interface.h:

Go to the source code of this file.

Classes

class  vlink::BagPluginInterface
 Abstract plugin base shared by bag playback and bag recording. More...
 

Namespaces

 

Detailed Description

Unified plugin contract for rewriting bag traffic on both playback (read) and recording (write).

BagPluginInterface is a dynamic plugin loaded through the VLink Plugin framework and attached either to a BagReader (via BagReader::bind_bag_interface()) or to a BagWriter (via BagWriter::bind_bag_interface()). A single class serves both directions; an implementation discovers which side it is bound to through get_direction() and overrides only the hooks for that side.

The two directions are symmetric: each is a frame-forwarding pipeline. The host supplies a downstream sink at bind time and the plugin re-emits every Frame – optionally transformed, dropped, fanned out, or reordered – through that sink. Plugins never touch the raw sink member directly; they emit by calling the single do_callback() helper. Read and write share one callable type (Callback, a const Frame& sink); a plugin overrides the on_read() or on_write() hook for its bound direction.

  • Read (playback). Frames originate inside the reader and flow out to the user. on_read() receives each frame and re-emits it via do_callback(). URL/type remapping is a separate, once-per-URL hook, convert_url_meta(), applied when the bag is opened. The effective Frame::ser_type / schema_type metadata is populated before on_read() runs.
  • Write (recording). Frames originate from the caller and flow into the bag. on_write() receives each frame – fully populated with ser_type / schema_type because recording persists them – and re-emits it via do_callback().

Both hooks may forward unchanged, transcode (e.g. record a raw image as compressed JPEG by emitting new Frame::data plus a new ser_type / schema_type), drop a frame (by not emitting), fan a frame out into several, or buffer frames and emit them reordered by their true data-plane time – a sliding-window reorder, identical on both sides, typically built on a BagProcessor.

Plugin contract:

Hook Dir Purpose
bind_direction() both At bind time: stored, observable via get_direction()
register_callback() both At bind time: store the forwarding sink
convert_url_meta() read Once per URL at open: true = keep, false = drop
on_reset() read Before a playback session: discard retained session state
on_read() read Every replayed frame: re-emit via do_callback()
on_write() write Every frame before persist: re-emit via do_callback()
flush() both At a completed boundary or detach: drain buffered tail
do_callback() both Forward one frame to the sink (drop = not call)

on_read() and on_write() are both pure: an implementation defines both even when it serves a single direction, leaving the unused one as a trivial pass-through (do_callback(frame)) or an empty body.

Lifecycle:

*   read  : load .so -> bind_direction(kRead) -> register_callback -> convert_url_meta (per URL)
*                    -> on_reset -> [on_read -> do_callback -> callback_ -> user] (per frame) -> flush
*   write : load .so -> bind_direction(kWrite) -> register_callback
*                    -> on_write (per frame) -> do_callback -> callback_ -> writer persists
* 

A read pass calls flush() only after natural completion. If the reader observes stop() or jump() before the boundary drain begins, it skips flush(); the next top-level session calls on_reset() to discard that retained tail.

Read-side example (rename a topic on replay)
class MyReadPlugin : public vlink::BagPluginInterface {
public:
bool convert_url_meta(std::string& url, std::string& ser_type,
vlink::SchemaType& schema_type) override {
if (url.rfind("dds://legacy/", 0) == 0) { url.replace(0, 13, "dds://v2/"); }
(void)ser_type;
(void)schema_type;
return true;
}
void on_read(const vlink::Frame& frame) override {
do_callback(frame); // forward downstream (drop by not calling)
}
void on_write(const vlink::Frame& frame) override { do_callback(frame); } // unused on the read side
};
VLINK_PLUGIN_DECLARE(MyReadPlugin, 2, 0)
#define VLINK_PLUGIN_DECLARE(ImplementType, VersionMajor, VersionMinor)
Emits the extern "C" construction and destruction entry points exported by a plugin module.
Definition: plugin.h:389
Write-side example (sliding-window reorder by true data-plane time before persist)
class MyWritePlugin : public vlink::BagPluginInterface {
public:
MyWritePlugin() {
processor_.register_output_callback([this](const vlink::Frame& frame) { do_callback(frame); });
}
void on_read(const vlink::Frame& frame) override { do_callback(frame); } // unused on the write side
void on_write(const vlink::Frame& frame) override {
const int64_t data_timestamp = parse_header_time(frame.data); // plugin extracts the data-plane time
processor_.push(data_timestamp, frame); // reorder by data_timestamp; emit via
}
void flush() override { processor_.flush(); } // drain the buffered tail at teardown
private:
vlink::BagProcessor processor_;
};
VLINK_PLUGIN_DECLARE(MyWritePlugin, 2, 0)