aboutsummaryrefslogtreecommitdiff
path: root/apps/sample-tee.cpp
diff options
context:
space:
mode:
Diffstat (limited to 'apps/sample-tee.cpp')
-rw-r--r--apps/sample-tee.cpp111
1 files changed, 111 insertions, 0 deletions
diff --git a/apps/sample-tee.cpp b/apps/sample-tee.cpp
new file mode 100644
index 0000000..50c0c9b
--- /dev/null
+++ b/apps/sample-tee.cpp
@@ -0,0 +1,111 @@
+#include "apps.h"
+#include "trygvis/sensor/io.h"
+#include <boost/tokenizer.hpp>
+#include <fstream>
+
+namespace trygvis {
+namespace apps {
+
+using namespace std;
+using namespace trygvis::sensor;
+using namespace trygvis::sensor::io;
+using boost::tokenizer;
+namespace po = boost::program_options;
+
+class sample_tee final : public app, public SampleConsumer {
+private:
+ using clock = std::chrono::steady_clock;
+ using timestamp = std::chrono::time_point<clock>;
+
+ sample_format_type output_format = sample_format_type::KEY_VALUE;
+ sample_format_type file_output_format = sample_format_type::KEY_VALUE;
+ string file_name;
+ sample_output_stream_options options = {};
+ KeyDictionary dict;
+
+ shared_ptr<ostream> out;
+ unique_ptr<SampleConsumer> out_writer;
+ ofstream file;
+ timestamp next_flush;
+
+public:
+ sample_tee() : app("sample-to-file") {}
+
+ ~sample_tee() override = default;
+
+ void add_options(po::options_description_easy_init &options) override
+ {
+ options("output-format", po::value<sample_format_type>(&output_format)->default_value(output_format));
+ options("file-output-format",
+ po::value<sample_format_type>(&file_output_format)->default_value(file_output_format));
+ options("file", po::value<string>(&file_name));
+ }
+
+ int main(app_execution &execution) override
+ {
+ if (file_name.size() == 0) {
+ cerr << "Missing required argument --file" << endl;
+ return EXIT_FAILURE;
+ }
+
+ cerr << "Writing samples to " << file_name << endl;
+
+ const int buffer_size = 1024;
+ char buffer[buffer_size];
+
+ out = shared_ptr<ostream>(&cout, noop_deleter);
+ out_writer = std::move(open_sample_writer(out, dict, output_format, options));
+
+ next_flush = clock::now();
+
+ auto parser = open_sample_stream_parser(shared_ptr<SampleConsumer>(this, noop_deleter), dict);
+ auto in = shared_ptr<istream>(&cin, noop_deleter);
+ in->rdbuf(nullptr);
+ while (!in->eof()) {
+ in->read(buffer, buffer_size);
+ auto gcount = static_cast<size_t>(in->gcount());
+
+ out->write(buffer, gcount);
+
+ mutable_buffers_1 b = boost::asio::buffer(buffer, gcount);
+ parser->process(b);
+ }
+
+ file.flush();
+ file.close();
+
+ return EXIT_SUCCESS;
+ };
+
+protected:
+
+ void onSample(const SampleRecord &sample) override
+ {
+ out_writer->onSample(sample);
+
+ file.open(file_name, ios_base::out | ios_base::app);
+ if (file.good()) {
+ shared_ptr<ostream> output(&file, noop_deleter);
+ auto file_writer = std::move(open_sample_writer(output, dict, file_output_format, options));
+ file_writer->onSample(sample);
+ }
+
+ auto now = clock::now();
+
+ if(now >= next_flush) {
+ file.flush();
+ next_flush = now + chrono::seconds(3);
+
+ cerr << "flush" << endl;
+ }
+ }
+};
+}
+}
+
+int main(int argc, const char *argv[])
+{
+ using namespace trygvis::apps;
+
+ return real_main(new sample_tee(), argc, argv);
+}