VLink  2.0.0
A high-performance communication middleware
vcap_writer.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 vcap_writer.h
26  * @brief Recorder that serialises VLink traffic into the MCAP container (@c .vcap / @c .vcapx).
27  *
28  * @details
29  * @c VCAPWriter materialises a @c BagWriter that emits Foxglove-compatible MCAP files. It
30  * inherits the cross-format split-recording machinery from @c BagWriter and produces files
31  * that any MCAP-aware tool can replay. Compression flips between no-compression and Zstd
32  * when the build links @c libzstd; other selectors degrade to plain chunks.
33  *
34  * @par File-format diagram
35  * @code
36  * push_schema() --> schema record
37  * push(frame) --> channel record (once per URL)
38  * --> message chunk (Zstd optional)
39  * on_end() --> attachments + summary section + footer (index of summary)
40  * @endcode
41  *
42  * @par Writer states
43  * @code
44  * +----------+ on_begin() +---------+ push()/push_schema() +-----------+
45  * | closed | ------------> | opening | -----------------------> | recording |
46  * +----------+ +---------+ +-----------+
47  * ^ |
48  * | v split triggered
49  * | +-------------+
50  * | | rotating |
51  * | | (new .vcap) |
52  * | +-------------+
53  * | |
54  * +-------------------- on_end() / dtor --------------------- finalising
55  * |
56  * v
57  * sealed
58  * @endcode
59  *
60  * @par Example
61  * @code
62  * auto writer = vlink::BagWriter::create("/data/recording.vcap");
63  *
64  * writer->async_run();
65  * writer->push_schema(my_schema);
66  *
67  * vlink::Frame frame;
68  * frame.timestamp = -1; // < 0 => writer auto-assigns from its clock (0 is recorded verbatim)
69  * frame.url = "dds://lidar/front";
70  * frame.ser_type = "demo.proto.PointCloud";
71  * frame.schema_type = vlink::SchemaType::kProtobuf;
72  * frame.action_type = vlink::ActionType::kPublish;
73  * frame.data = serialized_bytes;
74  * writer->push(frame);
75  * @endcode
76  *
77  * @see BagWriter, VDBWriter
78  */
79 
80 #pragma once
81 
82 #include <memory>
83 #include <string>
84 
85 #include "./bag_writer.h"
86 
87 namespace vlink {
88 
89 /**
90  * @class VCAPWriter
91  * @brief Concrete MCAP-format @c BagWriter implementation with optional Zstd compression.
92  *
93  * @details
94  * Prefer @c BagWriter::create() for format-agnostic instantiation; instantiate this class
95  * directly when an MCAP-specific feature is required.
96  */
97 class VLINK_EXPORT VCAPWriter final : public BagWriter {
98  public:
99  /**
100  * @brief Opens or creates an MCAP file for recording.
101  *
102  * @param path Filesystem path of the @c .vcap or @c .vcapx target.
103  * @param config Recording configuration (split policy, compression, etc.).
104  */
105  explicit VCAPWriter(const std::string& path, const Config& config = {});
106 
107  /**
108  * @brief Finalises the MCAP footer and flushes outstanding writes.
109  */
110  ~VCAPWriter() override;
111 
112  /**
113  * @brief Registers a callback invoked at each file-split boundary.
114  *
115  * @param callback Receives (split_index, filename) before or after the split.
116  * @param before @c true fires before the new file is opened; @c false fires after.
117  */
118  void register_split_callback(SplitCallback&& callback, bool before) override;
119 
120  /**
121  * @brief Registers a resolver that maps a serialisation-type string to @c SchemaData.
122  *
123  * @param callback Function consulted before writing a channel record.
124  */
125  void register_schema_callback(SchemaCallback&& callback) override;
126 
127  /**
128  * @brief Embeds @p schema_data in the MCAP file for offline introspection.
129  *
130  * @param schema_data Schema descriptor to embed.
131  * @param immediate @c true merges synchronously; @c false enqueues the write.
132  * @return @c false only when an immediate merge failed.
133  */
134  bool push_schema(const SchemaData& schema_data, bool immediate = false) override;
135 
136  /**
137  * @brief Returns the current value of the internal dumping flag.
138  *
139  * @return @c true while messages are actively being persisted.
140  */
141  [[nodiscard]] bool is_dumping() const override;
142 
143  /**
144  * @brief Reports whether split-file recording is active.
145  *
146  * @return @c true when emitting a @c .vcapx manifest with multiple parts.
147  */
148  [[nodiscard]] bool is_split_mode() const override;
149 
150  /**
151  * @brief Returns the index of the split part currently being written.
152  *
153  * @return Zero-based split index.
154  */
155  [[nodiscard]] int get_split_index() const override;
156 
157  protected:
158  int64_t record(const Frame& frame, bool immediate) override;
159 
160  int64_t get_record_timestamp() const override;
161 
162  size_t get_max_task_count() const override;
163 
164  void on_begin() override;
165 
166  void on_end() override;
167 
168  private:
169  void open(const std::string& path);
170 
171  void close();
172 
173  bool merge_schema(SchemaData& schema_data);
174 
175  bool load_schema(const std::string& ser_type, SchemaType& schema_type, SchemaData& schema_data);
176 
177  bool write(const std::string& url, const std::string& ser_type, SchemaType schema_type, ActionType action_type,
178  const Bytes& data, int64_t microseconds_timestamp);
179 
180  bool write_filex(bool complete = true);
181 
182  struct Impl;
183  std::unique_ptr<Impl> impl_;
184 
186 };
187 
188 } // namespace vlink
Abstract VLink bag recorder with split, compression, schema embedding and a global hook.
#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