8 stream_mgr.set_daemon_start_hook(opencv_daemon_start);
9 stream_mgr.set_frame_processor(opencv_motion_processor);
16 std::cout <<
"yodau> " << std::flush;
17 if (!std::getline(std::cin, line)) {
20 auto tokens = tokenize(line);
24 const auto& cmd = tokens[0];
25 std::vector args(tokens.begin() + 1, tokens.end());
26 if (cmd ==
"quit" || cmd ==
"q" || cmd ==
"exit") {
29 dispatch_command(cmd, args);
34std::vector<std::string>
36 std::vector<std::string> tokens;
37 std::istringstream stream(line);
39 while (stream >> token) {
40 tokens.push_back(token);
46 const std::string& cmd,
const std::vector<std::string>& args
48 static const std::unordered_map<
50 void (cli_client::*)(
const std::vector<std::string>& args)
const>
51 command_map = { {
"list-streams", &cli_client::cmd_list_streams },
52 {
"add-stream", &cli_client::cmd_add_stream },
53 {
"start-stream", &cli_client::cmd_start_stream },
54 {
"stop-stream", &cli_client::cmd_stop_stream },
55 {
"list-lines", &cli_client::cmd_list_lines },
56 {
"add-line", &cli_client::cmd_add_line },
57 {
"set-line", &cli_client::cmd_set_line } };
58 const auto it = command_map.find(cmd);
59 if (it == command_map.end()) {
60 std::cerr <<
"unknown command: " << cmd << std::endl;
64 const auto method = it->second;
65 (
this->*method)(args);
66 }
catch (
const std::exception& e) {
67 std::cerr <<
"error executing command '" << cmd <<
"': " << e.what()
73 const std::string& cmd,
const std::vector<std::string>& args,
74 cxxopts::Options& options
76 std::vector<
char*> argv;
77 argv.reserve(args.size() + 1);
78 argv.push_back(
const_cast<
char*>(cmd.data()));
79 for (
const auto& arg : args) {
80 argv.push_back(
const_cast<
char*>(arg.data()));
82 const int argc =
static_cast<
int>(argv.size());
83 char** argv_ptr = argv.data();
84 return options.parse(argc, argv_ptr);
88 const std::vector<std::string>& args
90 const std::string cmd =
"list-streams";
91 cxxopts::Options options(cmd,
"List all streams");
92 options.allow_unrecognised_options();
93 options.add_options()(
"h,help",
"Print help")(
94 "c,connections",
"Show connected lines",
95 cxxopts::value<
bool>()->default_value(
"false")
98 const auto result = parse_with_cxxopts(cmd, args, options);
99 if (result.count(
"help")) {
100 std::cout << options.help() << std::endl;
103 const bool show_connections = result[
"connections"].as<
bool>();
104 stream_mgr.dump_stream(std::cout, show_connections);
105 std::cout << std::endl;
106 }
catch (
const cxxopts::exceptions::exception& e) {
107 std::cerr <<
"Error parsing command '" << cmd <<
"': " << e.what()
109 std::cout << options.help() << std::endl;
114 const std::vector<std::string>& args
116 const std::string cmd =
"add-stream";
117 cxxopts::Options options(cmd,
"Add a new stream");
118 options.allow_unrecognised_options();
119 options.positional_help(
"<path> [<name>] [<type>] [<loop>]");
120 options.add_options()
121 (
"h,help",
"Print help")
122 (
"path",
"Path to the device, media file or stream URL", cxxopts::value<std::string>())
123 (
"name",
"Name of the stream", cxxopts::value<std::string>()->default_value(
""))
124 (
"type",
"Type of the stream (local/file/rtsp/http)", cxxopts::value<std::string>()->default_value(
""))
125 (
"loop",
"Whether to loop the stream (true/false)", cxxopts::value<
bool>()->default_value(
"true"));
126 options.parse_positional({
"path",
"name",
"type",
"loop" });
128 const auto result = parse_with_cxxopts(cmd, args, options);
129 if (result.count(
"help")) {
130 std::cout << options.help() << std::endl;
133 if (!result.count(
"path")) {
134 std::cerr <<
"Error: 'path' argument is required." << std::endl;
137 const std::string path = result[
"path"].as<std::string>();
138 const std::string name = result[
"name"].as<std::string>();
139 const std::string type = result[
"type"].as<std::string>();
140 const bool loop = result[
"loop"].as<
bool>();
141 const auto& stream =
stream_mgr.add_stream(path, name, type, loop);
142 stream.dump(std::cout,
true);
143 std::cout << std::endl;
144 }
catch (
const cxxopts::exceptions::exception& e) {
145 std::cerr <<
"Error parsing command '" << cmd <<
"': " << e.what()
147 std::cout << options.help() << std::endl;
152 const std::vector<std::string>& args
154 const std::string cmd =
"start-stream";
155 cxxopts::Options options(
"start-stream",
"Start a stream");
156 options.allow_unrecognised_options();
157 options.add_options()(
"h,help",
"Print help")(
158 "name",
"Name of the stream to start", cxxopts::value<std::string>()
160 options.parse_positional({
"name" });
162 const auto result = parse_with_cxxopts(
"start-stream", args, options);
163 if (result.count(
"help")) {
164 std::cout << options.help() << std::endl;
167 if (!result.count(
"name")) {
168 std::cerr <<
"Error: 'name' argument is required." << std::endl;
171 const std::string name = result[
"name"].as<std::string>();
173 }
catch (
const cxxopts::exceptions::exception& e) {
174 std::cerr <<
"Error parsing command '" << cmd <<
"': " << e.what()
176 std::cout << options.help() << std::endl;
181 const std::vector<std::string>& args
183 const std::string cmd =
"stop-stream";
184 cxxopts::Options options(
"stop-stream",
"Stop a stream");
185 options.allow_unrecognised_options();
186 options.add_options()(
"h,help",
"Print help")(
187 "name",
"Name of the stream to stop", cxxopts::value<std::string>()
189 options.parse_positional({
"name" });
191 const auto result = parse_with_cxxopts(
"stop-stream", args, options);
192 if (result.count(
"help")) {
193 std::cout << options.help() << std::endl;
196 if (!result.count(
"name")) {
197 std::cerr <<
"Error: 'name' argument is required." << std::endl;
200 const std::string name = result[
"name"].as<std::string>();
202 }
catch (
const cxxopts::exceptions::exception& e) {
203 std::cerr <<
"Error parsing command '" << cmd <<
"': " << e.what()
205 std::cout << options.help() << std::endl;
210 const std::vector<std::string>& args
212 const std::string cmd =
"list-lines";
213 cxxopts::Options options(
"list-lines",
"List all lines in a stream");
214 options.allow_unrecognised_options();
215 options.add_options()(
"h,help",
"Print help");
217 const auto result = parse_with_cxxopts(
"list-lines", args, options);
218 if (result.count(
"help")) {
219 std::cout << options.help() << std::endl;
223 std::cout << std::endl;
224 }
catch (
const cxxopts::exceptions::exception& e) {
225 std::cerr <<
"Error parsing command '" << cmd <<
"': " << e.what()
227 std::cout << options.help() << std::endl;
232 if (s ==
"neg_to_pos") {
235 if (s ==
"pos_to_neg") {
241 throw std::runtime_error(
"unknown dir: " + s);
245 const std::vector<std::string>& args
247 const std::string cmd =
"add-line";
248 cxxopts::Options options(
"add-line",
"Add a new line to a stream");
249 options.allow_unrecognised_options();
250 options.positional_help(
"<path> [<name>] [<close>]");
251 options.add_options()
252 (
"h,help",
"Print help")
253 (
"path",
"Line coordinates, e.g. 0,0;100,100", cxxopts::value<std::string>())
254 (
"name",
"Name of the line", cxxopts::value<std::string>()->default_value(
""))
255 (
"close",
"Whether the line is closed (true/false)", cxxopts::value<
bool>()->default_value(
"false"))
256 (
"d,dir",
"Tripwire direction (any/neg_to_pos/pos_to_neg)",
257 cxxopts::value<std::string>()->default_value(
"any"));
258 options.parse_positional({
"path",
"name",
"close" });
260 const auto result = parse_with_cxxopts(
"add-line", args, options);
261 if (result.count(
"help")) {
262 std::cout << options.help() << std::endl;
265 if (!result.count(
"path")) {
266 std::cerr <<
"Error: 'path' argument is required." << std::endl;
269 const std::string path = result[
"path"].as<std::string>();
270 const std::string name = result[
"name"].as<std::string>();
271 const bool close = result[
"close"].as<
bool>();
272 const std::string dir_str = result[
"dir"].as<std::string>();
274 const auto& line =
stream_mgr.add_line(path, close, name);
279 }
catch (
const std::exception& e) {
280 std::cerr <<
"bad dir: " << e.what() << std::endl;
283 line->dump(std::cout);
284 std::cout << std::endl;
286 }
catch (
const cxxopts::exceptions::exception& e) {
287 std::cerr <<
"Error parsing command '" << cmd <<
"': " << e.what()
289 std::cout << options.help() << std::endl;
294 const std::vector<std::string>& args
296 const std::string cmd =
"set-line";
297 cxxopts::Options options(
"set-line",
"Set a new line to a stream");
298 options.allow_unrecognised_options();
300 .add_options()(
"h,help",
"Print help")(
"stream",
"Stream name", cxxopts::value<std::string>())(
301 "line",
"Line name", cxxopts::value<std::string>()
303 options.parse_positional({
"stream",
"line" });
305 const auto result = parse_with_cxxopts(
"set-line", args, options);
306 if (result.count(
"help")) {
307 std::cout << options.help() << std::endl;
310 if (!result.count(
"stream") || !result.count(
"line")) {
311 std::cerr <<
"Error: 'stream' and 'line' arguments are required."
315 const std::string stream_name = result[
"stream"].as<std::string>();
316 const std::string line_name = result[
"line"].as<std::string>();
317 const auto& stream =
stream_mgr.set_line(stream_name, line_name);
318 stream.dump(std::cout,
true);
319 std::cout << std::endl;
320 }
catch (
const cxxopts::exceptions::exception& e) {
321 std::cerr <<
"Error parsing command '" << cmd <<
"': " << e.what()
323 std::cout << options.help() << std::endl;
Simple interactive CLI (REPL) for controlling a stream_manager.
void cmd_start_stream(const std::vector< std::string > &args) const
Handler for start-stream.
void dispatch_command(const std::string &cmd, const std::vector< std::string > &args) const
Dispatch a command to its handler.
void cmd_set_line(const std::vector< std::string > &args) const
Handler for set-line.
int run() const
Run the interactive command loop.
void cmd_add_line(const std::vector< std::string > &args) const
Handler for add-line.
backend::stream_manager & stream_mgr
Stream manager controlled by this CLI.
void cmd_stop_stream(const std::vector< std::string > &args) const
Handler for stop-stream.
void cmd_list_streams(const std::vector< std::string > &args) const
Handler for list-streams.
void cmd_add_stream(const std::vector< std::string > &args) const
Handler for add-stream.
void cmd_list_lines(const std::vector< std::string > &args) const
Handler for list-lines.
cli_client(backend::stream_manager &mgr)
Construct a CLI client operating on an existing manager.
Central coordinator for streams, geometry, frame processing and events.
static yodau::backend::tripwire_dir parse_tripwire_dir(const std::string &s)
tripwire_dir
Allowed crossing direction for a tripwire.