// This file is part of Moonfire NVR, a security camera network video recorder. // Copyright (C) 2021 The Moonfire NVR Authors; see AUTHORS and LICENSE.txt. // SPDX-License-Identifier: GPL-v3.0-or-later WITH GPL-3.0-linking-exception. #![cfg_attr(all(feature = "nightly", test), feature(test))] use bpaf::{Bpaf, Parser}; use std::ffi::OsStr; use std::path::{Path, PathBuf}; use tracing::{debug, error}; mod body; mod cmds; mod h264; mod json; mod mp4; mod slices; mod stream; mod streamer; mod tracing_setup; mod web; const DEFAULT_DB_DIR: &str = "/var/lib/moonfire-nvr/db"; /// Moonfire NVR: security camera network video recorder. #[derive(Bpaf, Debug)] #[bpaf(options, version)] enum Args { // See docstrings of `cmds::*::Args` structs for a description of the respective subcommands. Check(#[bpaf(external(cmds::check::args))] cmds::check::Args), Config(#[bpaf(external(cmds::config::args))] cmds::config::Args), Init(#[bpaf(external(cmds::init::args))] cmds::init::Args), Login(#[bpaf(external(cmds::login::args))] cmds::login::Args), Run(#[bpaf(external(cmds::run::args))] cmds::run::Args), Sql(#[bpaf(external(cmds::sql::args))] cmds::sql::Args), Ts(#[bpaf(external(cmds::ts::args))] cmds::ts::Args), Upgrade(#[bpaf(external(cmds::upgrade::args))] cmds::upgrade::Args), } impl Args { fn run(self) -> Result { match self { Args::Check(a) => cmds::check::run(a), Args::Config(a) => cmds::config::run(a), Args::Init(a) => cmds::init::run(a), Args::Login(a) => cmds::login::run(a), Args::Run(a) => cmds::run::run(a), Args::Sql(a) => cmds::sql::run(a), Args::Ts(a) => cmds::ts::run(a), Args::Upgrade(a) => cmds::upgrade::run(a), } } } fn parse_db_dir() -> impl Parser { bpaf::long("db-dir") .help("Directory holding the SQLite3 index database.") .argument::("PATH") .fallback(DEFAULT_DB_DIR.into()) .debug_fallback() } fn main() { // If using the clock will fail, find out now *before* trying to log // anything (with timestamps...) so we can print a helpful error. if let Err(e) = nix::time::clock_gettime(nix::time::ClockId::CLOCK_MONOTONIC) { eprintln!( "clock_gettime failed: {e}\n\n\ This indicates a broken environment. See the troubleshooting guide." ); std::process::exit(1); } tracing_setup::install(); // Get the program name from the OS (e.g. if invoked as `target/debug/nvr`: `nvr`), // falling back to the crate name if conversion to a path/UTF-8 string fails. // `bpaf`'s default logic is similar but doesn't have the fallback. let progname = std::env::args_os().next().map(PathBuf::from); let progname = progname .as_deref() .and_then(Path::file_name) .and_then(OsStr::to_str) .unwrap_or(env!("CARGO_PKG_NAME")); let args = match args() .fallback_to_usage() .run_inner(bpaf::Args::current_args().set_name(progname)) { Ok(a) => a, Err(e) => std::process::exit(e.exit_code()), }; tracing::trace!("Parsed command-line arguments: {args:#?}"); match args.run() { Err(e) => { error!("Exiting due to error: {}", base::prettify_failure(&e)); ::std::process::exit(1); } Ok(rv) => { debug!("Exiting with status {}", rv); std::process::exit(rv) } } } #[cfg(test)] mod tests { #[test] fn bpaf_invariants() { super::args().check_invariants(false); } }