mirror of
https://github.com/scottlamb/moonfire-nvr.git
synced 2025-04-30 15:11:20 -04:00
tweak bpaf usage message
As discussed here: https://github.com/pacak/bpaf/discussions/165#discussioncomment-4967176 I also snuck in a conversion from `lazy_static` to `once_cell`, rather than adding another usage of the former.
This commit is contained in:
parent
015dfef9c9
commit
2b27797f42
13
server/Cargo.lock
generated
13
server/Cargo.lock
generated
@ -146,8 +146,8 @@ dependencies = [
|
|||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "bpaf"
|
name = "bpaf"
|
||||||
version = "0.7.8"
|
version = "0.7.9"
|
||||||
source = "git+https://github.com/pacak/bpaf.git?branch=exit_code#77b8efc5d33adcf57901a03514a3ce6183144f8d"
|
source = "git+https://github.com/pacak/bpaf.git?branch=exit_code#5238a6069abca0d61cf1c000e56bbac946e7ee18"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"bpaf_derive",
|
"bpaf_derive",
|
||||||
"owo-colors",
|
"owo-colors",
|
||||||
@ -155,8 +155,8 @@ dependencies = [
|
|||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "bpaf_derive"
|
name = "bpaf_derive"
|
||||||
version = "0.3.3"
|
version = "0.3.4"
|
||||||
source = "git+https://github.com/pacak/bpaf.git?branch=exit_code#77b8efc5d33adcf57901a03514a3ce6183144f8d"
|
source = "git+https://github.com/pacak/bpaf.git?branch=exit_code#5238a6069abca0d61cf1c000e56bbac946e7ee18"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"proc-macro2",
|
"proc-macro2",
|
||||||
"quote",
|
"quote",
|
||||||
@ -1101,7 +1101,6 @@ version = "0.0.1"
|
|||||||
dependencies = [
|
dependencies = [
|
||||||
"failure",
|
"failure",
|
||||||
"futures",
|
"futures",
|
||||||
"lazy_static",
|
|
||||||
"libc",
|
"libc",
|
||||||
"log",
|
"log",
|
||||||
"nom",
|
"nom",
|
||||||
@ -1126,7 +1125,6 @@ dependencies = [
|
|||||||
"h264-reader",
|
"h264-reader",
|
||||||
"hashlink",
|
"hashlink",
|
||||||
"itertools",
|
"itertools",
|
||||||
"lazy_static",
|
|
||||||
"libc",
|
"libc",
|
||||||
"log",
|
"log",
|
||||||
"moonfire-base",
|
"moonfire-base",
|
||||||
@ -1134,6 +1132,7 @@ dependencies = [
|
|||||||
"nix",
|
"nix",
|
||||||
"num-rational",
|
"num-rational",
|
||||||
"odds",
|
"odds",
|
||||||
|
"once_cell",
|
||||||
"pretty-hex",
|
"pretty-hex",
|
||||||
"protobuf",
|
"protobuf",
|
||||||
"protobuf-codegen",
|
"protobuf-codegen",
|
||||||
@ -1168,7 +1167,6 @@ dependencies = [
|
|||||||
"http-serve",
|
"http-serve",
|
||||||
"hyper",
|
"hyper",
|
||||||
"itertools",
|
"itertools",
|
||||||
"lazy_static",
|
|
||||||
"libc",
|
"libc",
|
||||||
"log",
|
"log",
|
||||||
"memchr",
|
"memchr",
|
||||||
@ -1179,6 +1177,7 @@ dependencies = [
|
|||||||
"nix",
|
"nix",
|
||||||
"nom",
|
"nom",
|
||||||
"num-rational",
|
"num-rational",
|
||||||
|
"once_cell",
|
||||||
"password-hash",
|
"password-hash",
|
||||||
"protobuf",
|
"protobuf",
|
||||||
"reffers",
|
"reffers",
|
||||||
|
@ -37,7 +37,6 @@ http = "0.2.3"
|
|||||||
http-serve = { version = "0.3.1", features = ["dir"] }
|
http-serve = { version = "0.3.1", features = ["dir"] }
|
||||||
hyper = { version = "0.14.2", features = ["http1", "server", "stream", "tcp"] }
|
hyper = { version = "0.14.2", features = ["http1", "server", "stream", "tcp"] }
|
||||||
itertools = "0.10.0"
|
itertools = "0.10.0"
|
||||||
lazy_static = "1.0"
|
|
||||||
libc = "0.2"
|
libc = "0.2"
|
||||||
log = { version = "0.4" }
|
log = { version = "0.4" }
|
||||||
memchr = "2.0.2"
|
memchr = "2.0.2"
|
||||||
@ -62,6 +61,7 @@ toml = "0.5"
|
|||||||
tracing = { version = "0.1", features = ["log"] }
|
tracing = { version = "0.1", features = ["log"] }
|
||||||
url = "2.1.1"
|
url = "2.1.1"
|
||||||
uuid = { version = "1.1.2", features = ["serde", "std", "v4"] }
|
uuid = { version = "1.1.2", features = ["serde", "std", "v4"] }
|
||||||
|
once_cell = "1.17.0"
|
||||||
|
|
||||||
[dev-dependencies]
|
[dev-dependencies]
|
||||||
mp4 = { git = "https://github.com/scottlamb/mp4-rust", branch = "moonfire" }
|
mp4 = { git = "https://github.com/scottlamb/mp4-rust", branch = "moonfire" }
|
||||||
|
@ -15,7 +15,6 @@ path = "lib.rs"
|
|||||||
[dependencies]
|
[dependencies]
|
||||||
failure = "0.1.1"
|
failure = "0.1.1"
|
||||||
futures = "0.3"
|
futures = "0.3"
|
||||||
lazy_static = "1.0"
|
|
||||||
libc = "0.2"
|
libc = "0.2"
|
||||||
log = "0.4"
|
log = "0.4"
|
||||||
nom = "7.0.0"
|
nom = "7.0.0"
|
||||||
|
@ -24,7 +24,6 @@ fnv = "1.0"
|
|||||||
futures = "0.3"
|
futures = "0.3"
|
||||||
h264-reader = "0.6.0"
|
h264-reader = "0.6.0"
|
||||||
hashlink = "0.8.1"
|
hashlink = "0.8.1"
|
||||||
lazy_static = "1.0"
|
|
||||||
libc = "0.2"
|
libc = "0.2"
|
||||||
log = "0.4"
|
log = "0.4"
|
||||||
mylog = { git = "https://github.com/scottlamb/mylog" }
|
mylog = { git = "https://github.com/scottlamb/mylog" }
|
||||||
@ -46,6 +45,7 @@ tokio = { version = "1.24", features = ["macros", "rt-multi-thread", "sync"] }
|
|||||||
url = { version = "2.1.1", features = ["serde"] }
|
url = { version = "2.1.1", features = ["serde"] }
|
||||||
uuid = { version = "1.1.2", features = ["serde", "std", "v4"] }
|
uuid = { version = "1.1.2", features = ["serde", "std", "v4"] }
|
||||||
itertools = "0.10.0"
|
itertools = "0.10.0"
|
||||||
|
once_cell = "1.17.0"
|
||||||
|
|
||||||
[build-dependencies]
|
[build-dependencies]
|
||||||
protobuf-codegen = "3.0"
|
protobuf-codegen = "3.0"
|
||||||
|
@ -9,7 +9,6 @@ use crate::schema::Permissions;
|
|||||||
use base::{bail_t, format_err_t, strutil, ErrorKind, ResultExt as _};
|
use base::{bail_t, format_err_t, strutil, ErrorKind, ResultExt as _};
|
||||||
use failure::{bail, format_err, Error, Fail, ResultExt as _};
|
use failure::{bail, format_err, Error, Fail, ResultExt as _};
|
||||||
use fnv::FnvHashMap;
|
use fnv::FnvHashMap;
|
||||||
use lazy_static::lazy_static;
|
|
||||||
use log::info;
|
use log::info;
|
||||||
use protobuf::Message;
|
use protobuf::Message;
|
||||||
use ring::rand::{SecureRandom, SystemRandom};
|
use ring::rand::{SecureRandom, SystemRandom};
|
||||||
@ -21,9 +20,8 @@ use std::net::IpAddr;
|
|||||||
use std::str::FromStr;
|
use std::str::FromStr;
|
||||||
use std::sync::Mutex;
|
use std::sync::Mutex;
|
||||||
|
|
||||||
lazy_static! {
|
static PARAMS: once_cell::sync::Lazy<Mutex<scrypt::Params>> =
|
||||||
static ref PARAMS: Mutex<scrypt::Params> = Mutex::new(scrypt::Params::recommended());
|
once_cell::sync::Lazy::new(|| Mutex::new(scrypt::Params::recommended()));
|
||||||
}
|
|
||||||
|
|
||||||
/// For testing only: use fast but insecure hashes.
|
/// For testing only: use fast but insecure hashes.
|
||||||
/// Call via `testutil::init()`.
|
/// Call via `testutil::init()`.
|
||||||
|
@ -9,7 +9,9 @@ use db::check;
|
|||||||
use failure::Error;
|
use failure::Error;
|
||||||
use std::path::PathBuf;
|
use std::path::PathBuf;
|
||||||
|
|
||||||
|
/// Checks database integrity (like fsck).
|
||||||
#[derive(Bpaf, Debug)]
|
#[derive(Bpaf, Debug)]
|
||||||
|
#[bpaf(options)]
|
||||||
pub struct Args {
|
pub struct Args {
|
||||||
/// Directory holding the SQLite3 index database.
|
/// Directory holding the SQLite3 index database.
|
||||||
///
|
///
|
||||||
@ -40,6 +42,10 @@ pub struct Args {
|
|||||||
trash_corrupt_rows: bool,
|
trash_corrupt_rows: bool,
|
||||||
}
|
}
|
||||||
|
|
||||||
|
pub fn subcommand() -> impl bpaf::Parser<Args> {
|
||||||
|
crate::subcommand(args(), "check")
|
||||||
|
}
|
||||||
|
|
||||||
pub fn run(args: Args) -> Result<i32, Error> {
|
pub fn run(args: Args) -> Result<i32, Error> {
|
||||||
let (_db_dir, mut conn) = super::open_conn(&args.db_dir, super::OpenMode::ReadWrite)?;
|
let (_db_dir, mut conn) = super::open_conn(&args.db_dir, super::OpenMode::ReadWrite)?;
|
||||||
check::run(
|
check::run(
|
||||||
|
@ -19,7 +19,9 @@ mod cameras;
|
|||||||
mod dirs;
|
mod dirs;
|
||||||
mod users;
|
mod users;
|
||||||
|
|
||||||
|
/// Interactively edits configuration.
|
||||||
#[derive(Bpaf, Debug)]
|
#[derive(Bpaf, Debug)]
|
||||||
|
#[bpaf(options)]
|
||||||
pub struct Args {
|
pub struct Args {
|
||||||
/// Directory holding the SQLite3 index database.
|
/// Directory holding the SQLite3 index database.
|
||||||
///
|
///
|
||||||
@ -28,6 +30,10 @@ pub struct Args {
|
|||||||
db_dir: PathBuf,
|
db_dir: PathBuf,
|
||||||
}
|
}
|
||||||
|
|
||||||
|
pub fn subcommand() -> impl bpaf::Parser<Args> {
|
||||||
|
crate::subcommand(args(), "config")
|
||||||
|
}
|
||||||
|
|
||||||
pub fn run(args: Args) -> Result<i32, Error> {
|
pub fn run(args: Args) -> Result<i32, Error> {
|
||||||
let (_db_dir, conn) = super::open_conn(&args.db_dir, super::OpenMode::ReadWrite)?;
|
let (_db_dir, conn) = super::open_conn(&args.db_dir, super::OpenMode::ReadWrite)?;
|
||||||
let clocks = clock::RealClocks {};
|
let clocks = clock::RealClocks {};
|
||||||
|
@ -7,7 +7,9 @@ use failure::Error;
|
|||||||
use log::info;
|
use log::info;
|
||||||
use std::path::PathBuf;
|
use std::path::PathBuf;
|
||||||
|
|
||||||
|
/// Initializes a database.
|
||||||
#[derive(Bpaf, Debug)]
|
#[derive(Bpaf, Debug)]
|
||||||
|
#[bpaf(options)]
|
||||||
pub struct Args {
|
pub struct Args {
|
||||||
/// Directory holding the SQLite3 index database.
|
/// Directory holding the SQLite3 index database.
|
||||||
///
|
///
|
||||||
@ -16,6 +18,10 @@ pub struct Args {
|
|||||||
db_dir: PathBuf,
|
db_dir: PathBuf,
|
||||||
}
|
}
|
||||||
|
|
||||||
|
pub fn subcommand() -> impl bpaf::Parser<Args> {
|
||||||
|
crate::subcommand(args(), "init")
|
||||||
|
}
|
||||||
|
|
||||||
pub fn run(args: Args) -> Result<i32, Error> {
|
pub fn run(args: Args) -> Result<i32, Error> {
|
||||||
let (_db_dir, mut conn) = super::open_conn(&args.db_dir, super::OpenMode::Create)?;
|
let (_db_dir, mut conn) = super::open_conn(&args.db_dir, super::OpenMode::Create)?;
|
||||||
|
|
||||||
|
@ -24,7 +24,14 @@ fn parse_flags(flags: String) -> Result<Vec<SessionFlag>, Error> {
|
|||||||
.collect()
|
.collect()
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Logs in a user, returning the session cookie.
|
||||||
|
///
|
||||||
|
///
|
||||||
|
/// This is a privileged command that directly accesses the database. It doesn't check the
|
||||||
|
/// user's password and even can be used to create sessions with permissions the user doesn't
|
||||||
|
/// have.
|
||||||
#[derive(Bpaf, Debug, PartialEq, Eq)]
|
#[derive(Bpaf, Debug, PartialEq, Eq)]
|
||||||
|
#[bpaf(options)]
|
||||||
pub struct Args {
|
pub struct Args {
|
||||||
/// Directory holding the SQLite3 index database.
|
/// Directory holding the SQLite3 index database.
|
||||||
///
|
///
|
||||||
@ -64,6 +71,10 @@ pub struct Args {
|
|||||||
username: String,
|
username: String,
|
||||||
}
|
}
|
||||||
|
|
||||||
|
pub fn subcommand() -> impl bpaf::Parser<Args> {
|
||||||
|
crate::subcommand(args(), "login")
|
||||||
|
}
|
||||||
|
|
||||||
pub fn run(args: Args) -> Result<i32, Error> {
|
pub fn run(args: Args) -> Result<i32, Error> {
|
||||||
let clocks = clock::RealClocks {};
|
let clocks = clock::RealClocks {};
|
||||||
let (_db_dir, conn) = super::open_conn(&args.db_dir, super::OpenMode::ReadWrite)?;
|
let (_db_dir, conn) = super::open_conn(&args.db_dir, super::OpenMode::ReadWrite)?;
|
||||||
@ -148,12 +159,9 @@ fn curl_cookie(cookie: &str, flags: i32, domain: &str) -> String {
|
|||||||
mod tests {
|
mod tests {
|
||||||
use super::*;
|
use super::*;
|
||||||
|
|
||||||
use bpaf::Parser;
|
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
fn parse_args() {
|
fn parse_args() {
|
||||||
let args = args()
|
let args = args()
|
||||||
.to_options()
|
|
||||||
.run_inner(bpaf::Args::from(&[
|
.run_inner(bpaf::Args::from(&[
|
||||||
"--permissions",
|
"--permissions",
|
||||||
"{\"viewVideo\": true}",
|
"{\"viewVideo\": true}",
|
||||||
|
@ -25,7 +25,9 @@ use self::config::ConfigFile;
|
|||||||
|
|
||||||
mod config;
|
mod config;
|
||||||
|
|
||||||
|
/// Runs the server, saving recordings and allowing web access.
|
||||||
#[derive(Bpaf, Debug)]
|
#[derive(Bpaf, Debug)]
|
||||||
|
#[bpaf(options)]
|
||||||
pub struct Args {
|
pub struct Args {
|
||||||
/// Path to configuration file.
|
/// Path to configuration file.
|
||||||
///
|
///
|
||||||
@ -40,6 +42,10 @@ pub struct Args {
|
|||||||
read_only: bool,
|
read_only: bool,
|
||||||
}
|
}
|
||||||
|
|
||||||
|
pub fn subcommand() -> impl bpaf::Parser<Args> {
|
||||||
|
crate::subcommand(args(), "run")
|
||||||
|
}
|
||||||
|
|
||||||
// These are used in a hack to get the name of the current time zone (e.g. America/Los_Angeles).
|
// These are used in a hack to get the name of the current time zone (e.g. America/Los_Angeles).
|
||||||
// They seem to be correct for Linux and macOS at least.
|
// They seem to be correct for Linux and macOS at least.
|
||||||
const LOCALTIME_PATH: &str = "/etc/localtime";
|
const LOCALTIME_PATH: &str = "/etc/localtime";
|
||||||
|
@ -12,7 +12,13 @@ use std::os::unix::process::CommandExt;
|
|||||||
use std::path::PathBuf;
|
use std::path::PathBuf;
|
||||||
use std::process::Command;
|
use std::process::Command;
|
||||||
|
|
||||||
|
/// Runs a SQLite3 shell on Moonfire NVR's index database.
|
||||||
|
///
|
||||||
|
///
|
||||||
|
/// Note this locks the database to prevent simultaneous access with a running server. The
|
||||||
|
/// server maintains cached state which could be invalidated otherwise.
|
||||||
#[derive(Bpaf, Debug, PartialEq, Eq)]
|
#[derive(Bpaf, Debug, PartialEq, Eq)]
|
||||||
|
#[bpaf(options)]
|
||||||
pub struct Args {
|
pub struct Args {
|
||||||
/// Directory holding the SQLite3 index database.
|
/// Directory holding the SQLite3 index database.
|
||||||
///
|
///
|
||||||
@ -33,6 +39,10 @@ pub struct Args {
|
|||||||
arg: Vec<OsString>,
|
arg: Vec<OsString>,
|
||||||
}
|
}
|
||||||
|
|
||||||
|
pub fn subcommand() -> impl bpaf::Parser<Args> {
|
||||||
|
crate::subcommand(args(), "sql")
|
||||||
|
}
|
||||||
|
|
||||||
pub fn run(args: Args) -> Result<i32, Error> {
|
pub fn run(args: Args) -> Result<i32, Error> {
|
||||||
let mode = if args.read_only {
|
let mode = if args.read_only {
|
||||||
OpenMode::ReadOnly
|
OpenMode::ReadOnly
|
||||||
@ -59,12 +69,9 @@ pub fn run(args: Args) -> Result<i32, Error> {
|
|||||||
mod tests {
|
mod tests {
|
||||||
use super::*;
|
use super::*;
|
||||||
|
|
||||||
use bpaf::Parser;
|
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
fn parse_args() {
|
fn parse_args() {
|
||||||
let args = args()
|
let args = args()
|
||||||
.to_options()
|
|
||||||
.run_inner(bpaf::Args::from(&[
|
.run_inner(bpaf::Args::from(&[
|
||||||
"--db-dir",
|
"--db-dir",
|
||||||
"/foo/bar",
|
"/foo/bar",
|
||||||
|
@ -5,7 +5,9 @@
|
|||||||
use bpaf::Bpaf;
|
use bpaf::Bpaf;
|
||||||
use failure::Error;
|
use failure::Error;
|
||||||
|
|
||||||
|
/// Translates between integer and human-readable timestamps.
|
||||||
#[derive(Bpaf, Debug)]
|
#[derive(Bpaf, Debug)]
|
||||||
|
#[bpaf(options)]
|
||||||
pub struct Args {
|
pub struct Args {
|
||||||
/// Timestamp(s) to translate.
|
/// Timestamp(s) to translate.
|
||||||
///
|
///
|
||||||
@ -17,6 +19,10 @@ pub struct Args {
|
|||||||
timestamps: Vec<String>,
|
timestamps: Vec<String>,
|
||||||
}
|
}
|
||||||
|
|
||||||
|
pub fn subcommand() -> impl bpaf::Parser<Args> {
|
||||||
|
crate::subcommand(args(), "ts")
|
||||||
|
}
|
||||||
|
|
||||||
pub fn run(args: Args) -> Result<i32, Error> {
|
pub fn run(args: Args) -> Result<i32, Error> {
|
||||||
for timestamp in &args.timestamps {
|
for timestamp in &args.timestamps {
|
||||||
let t = db::recording::Time::parse(timestamp)?;
|
let t = db::recording::Time::parse(timestamp)?;
|
||||||
|
@ -8,7 +8,9 @@ use bpaf::Bpaf;
|
|||||||
/// See `guide/schema.md` for more information.
|
/// See `guide/schema.md` for more information.
|
||||||
use failure::Error;
|
use failure::Error;
|
||||||
|
|
||||||
|
/// Upgrades to the latest database schema.
|
||||||
#[derive(Bpaf, Debug)]
|
#[derive(Bpaf, Debug)]
|
||||||
|
#[bpaf(options)]
|
||||||
pub struct Args {
|
pub struct Args {
|
||||||
/// Directory holding the SQLite3 index database.
|
/// Directory holding the SQLite3 index database.
|
||||||
///
|
///
|
||||||
@ -35,6 +37,10 @@ pub struct Args {
|
|||||||
no_vacuum: bool,
|
no_vacuum: bool,
|
||||||
}
|
}
|
||||||
|
|
||||||
|
pub fn subcommand() -> impl bpaf::Parser<Args> {
|
||||||
|
crate::subcommand(args(), "upgrade")
|
||||||
|
}
|
||||||
|
|
||||||
pub fn run(args: Args) -> Result<i32, Error> {
|
pub fn run(args: Args) -> Result<i32, Error> {
|
||||||
let (_db_dir, mut conn) = super::open_conn(&args.db_dir, super::OpenMode::ReadWrite)?;
|
let (_db_dir, mut conn) = super::open_conn(&args.db_dir, super::OpenMode::ReadWrite)?;
|
||||||
|
|
||||||
|
@ -19,50 +19,43 @@ mod stream;
|
|||||||
mod streamer;
|
mod streamer;
|
||||||
mod web;
|
mod web;
|
||||||
|
|
||||||
|
/// The program name, taken from the OS-provided arguments if available.
|
||||||
|
///
|
||||||
|
/// E.g. if invoked as `target/debug/nvr`, should return `nvr`.
|
||||||
|
static PROGNAME: once_cell::sync::Lazy<&'static str> = once_cell::sync::Lazy::new(|| {
|
||||||
|
std::env::args_os()
|
||||||
|
.next()
|
||||||
|
.and_then(|p| {
|
||||||
|
let p = std::path::PathBuf::from(p);
|
||||||
|
p.file_name().and_then(|f| {
|
||||||
|
f.to_str()
|
||||||
|
.map(|s| &*Box::leak(s.to_owned().into_boxed_str()))
|
||||||
|
})
|
||||||
|
})
|
||||||
|
.unwrap_or(env!("CARGO_PKG_NAME"))
|
||||||
|
});
|
||||||
|
|
||||||
|
fn subcommand<T: 'static>(
|
||||||
|
parser: bpaf::OptionParser<T>,
|
||||||
|
cmd: &'static str,
|
||||||
|
) -> impl bpaf::Parser<T> {
|
||||||
|
let usage = format!("Usage: {progname} {cmd} {{usage}}", progname = *PROGNAME);
|
||||||
|
parser.usage(Box::leak(usage.into_boxed_str())).command(cmd)
|
||||||
|
}
|
||||||
|
|
||||||
/// Moonfire NVR: security camera network video recorder.
|
/// Moonfire NVR: security camera network video recorder.
|
||||||
#[derive(Bpaf, Debug)]
|
#[derive(Bpaf, Debug)]
|
||||||
#[bpaf(options, version)]
|
#[bpaf(options, version)]
|
||||||
enum Args {
|
enum Args {
|
||||||
/// Checks database integrity (like fsck).
|
// See docstrings of `cmds::*::Args` structs for a description of the respective subcommands.
|
||||||
#[bpaf(command)]
|
Check(#[bpaf(external(cmds::check::subcommand))] cmds::check::Args),
|
||||||
Check(#[bpaf(external(cmds::check::args))] cmds::check::Args),
|
Config(#[bpaf(external(cmds::config::subcommand))] cmds::config::Args),
|
||||||
|
Init(#[bpaf(external(cmds::init::subcommand))] cmds::init::Args),
|
||||||
/// Interactively edits configuration.
|
Login(#[bpaf(external(cmds::login::subcommand))] cmds::login::Args),
|
||||||
#[bpaf(command)]
|
Run(#[bpaf(external(cmds::run::subcommand))] cmds::run::Args),
|
||||||
Config(#[bpaf(external(cmds::config::args))] cmds::config::Args),
|
Sql(#[bpaf(external(cmds::sql::subcommand))] cmds::sql::Args),
|
||||||
|
Ts(#[bpaf(external(cmds::ts::subcommand))] cmds::ts::Args),
|
||||||
/// Initializes a database.
|
Upgrade(#[bpaf(external(cmds::upgrade::subcommand))] cmds::upgrade::Args),
|
||||||
#[bpaf(command)]
|
|
||||||
Init(#[bpaf(external(cmds::init::args))] cmds::init::Args),
|
|
||||||
|
|
||||||
/// Logs in a user, returning the session cookie.
|
|
||||||
///
|
|
||||||
///
|
|
||||||
/// This is a privileged command that directly accesses the database. It doesn't check the
|
|
||||||
/// user's password and even can be used to create sessions with permissions the user doesn't
|
|
||||||
/// have.
|
|
||||||
#[bpaf(command)]
|
|
||||||
Login(#[bpaf(external(cmds::login::args))] cmds::login::Args),
|
|
||||||
|
|
||||||
/// Runs the server, saving recordings and allowing web access.
|
|
||||||
#[bpaf(command)]
|
|
||||||
Run(#[bpaf(external(cmds::run::args))] cmds::run::Args),
|
|
||||||
|
|
||||||
/// Runs a SQLite3 shell on Moonfire NVR's index database.
|
|
||||||
///
|
|
||||||
///
|
|
||||||
/// Note this locks the database to prevent simultaneous access with a running server. The
|
|
||||||
/// server maintains cached state which could be invalidated otherwise.
|
|
||||||
#[bpaf(command)]
|
|
||||||
Sql(#[bpaf(external(cmds::sql::args))] cmds::sql::Args),
|
|
||||||
|
|
||||||
/// Translates between integer and human-readable timestamps.
|
|
||||||
#[bpaf(command)]
|
|
||||||
Ts(#[bpaf(external(cmds::ts::args))] cmds::ts::Args),
|
|
||||||
|
|
||||||
/// Upgrades to the latest database schema.
|
|
||||||
#[bpaf(command)]
|
|
||||||
Upgrade(#[bpaf(external(cmds::upgrade::args))] cmds::upgrade::Args),
|
|
||||||
}
|
}
|
||||||
|
|
||||||
impl Args {
|
impl Args {
|
||||||
@ -141,12 +134,15 @@ fn main() {
|
|||||||
.build();
|
.build();
|
||||||
h.clone().install().unwrap();
|
h.clone().install().unwrap();
|
||||||
|
|
||||||
|
let args = args().usage(Box::leak(
|
||||||
|
format!("Usage: {progname} {{usage}}", progname = *PROGNAME).into_boxed_str(),
|
||||||
|
));
|
||||||
|
|
||||||
// TODO: remove this when bpaf adds more direct support for defaulting to `--help`.
|
// TODO: remove this when bpaf adds more direct support for defaulting to `--help`.
|
||||||
// See discussion: <https://github.com/pacak/bpaf/discussions/165>.
|
// See discussion: <https://github.com/pacak/bpaf/discussions/165>.
|
||||||
if std::env::args_os().len() < 2 {
|
if std::env::args_os().len() < 2 {
|
||||||
std::process::exit(
|
std::process::exit(
|
||||||
args()
|
args.run_inner(bpaf::Args::from(&["--help"]))
|
||||||
.run_inner(bpaf::Args::from(&["--help"]))
|
|
||||||
.unwrap_err()
|
.unwrap_err()
|
||||||
.exit_code(),
|
.exit_code(),
|
||||||
);
|
);
|
||||||
@ -159,7 +155,7 @@ fn main() {
|
|||||||
std::panic::set_hook(Box::new(&panic_hook));
|
std::panic::set_hook(Box::new(&panic_hook));
|
||||||
}
|
}
|
||||||
|
|
||||||
let args = args().run();
|
let args = args.run();
|
||||||
log::trace!("Parsed command-line arguments: {args:#?}");
|
log::trace!("Parsed command-line arguments: {args:#?}");
|
||||||
|
|
||||||
let r = {
|
let r = {
|
||||||
|
@ -2979,11 +2979,10 @@ mod bench {
|
|||||||
use futures::future;
|
use futures::future;
|
||||||
use http_serve;
|
use http_serve;
|
||||||
use hyper;
|
use hyper;
|
||||||
use lazy_static::lazy_static;
|
|
||||||
use url::Url;
|
use url::Url;
|
||||||
|
|
||||||
/// An HTTP server for benchmarking.
|
/// An HTTP server for benchmarking.
|
||||||
/// It's used as a singleton via `lazy_static!` so that when getting a CPU profile of the
|
/// It's used as a singleton so that when getting a CPU profile of the
|
||||||
/// benchmark, more of the profile focuses on the HTTP serving rather than the setup.
|
/// benchmark, more of the profile focuses on the HTTP serving rather than the setup.
|
||||||
///
|
///
|
||||||
/// Currently this only serves a single `.mp4` file but we could set up variations to benchmark
|
/// Currently this only serves a single `.mp4` file but we could set up variations to benchmark
|
||||||
@ -3029,9 +3028,8 @@ mod bench {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
lazy_static! {
|
static SERVER: once_cell::sync::Lazy<BenchServer> =
|
||||||
static ref SERVER: BenchServer = BenchServer::new();
|
once_cell::sync::Lazy::new(BenchServer::new);
|
||||||
}
|
|
||||||
|
|
||||||
#[bench]
|
#[bench]
|
||||||
fn build_index(b: &mut test::Bencher) {
|
fn build_index(b: &mut test::Bencher) {
|
||||||
|
@ -183,7 +183,6 @@ mod tests {
|
|||||||
use crate::body::BoxedError;
|
use crate::body::BoxedError;
|
||||||
use db::testutil;
|
use db::testutil;
|
||||||
use futures::stream::{self, Stream, TryStreamExt};
|
use futures::stream::{self, Stream, TryStreamExt};
|
||||||
use lazy_static::lazy_static;
|
|
||||||
use std::ops::Range;
|
use std::ops::Range;
|
||||||
use std::pin::Pin;
|
use std::pin::Pin;
|
||||||
|
|
||||||
@ -224,18 +223,16 @@ mod tests {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
lazy_static! {
|
#[rustfmt::skip]
|
||||||
#[rustfmt::skip]
|
static SLICES: once_cell::sync::Lazy<Slices<FakeSlice>> = once_cell::sync::Lazy::new(|| {
|
||||||
static ref SLICES: Slices<FakeSlice> = {
|
let mut s = Slices::new();
|
||||||
let mut s = Slices::new();
|
s.append(FakeSlice { end: 5, name: "a" }).unwrap();
|
||||||
s.append(FakeSlice { end: 5, name: "a" }).unwrap();
|
s.append(FakeSlice { end: 5 + 13, name: "b" }).unwrap();
|
||||||
s.append(FakeSlice { end: 5 + 13, name: "b" }).unwrap();
|
s.append(FakeSlice { end: 5 + 13 + 7, name: "c" }).unwrap();
|
||||||
s.append(FakeSlice { end: 5 + 13 + 7, name: "c" }).unwrap();
|
s.append(FakeSlice { end: 5 + 13 + 7 + 17, name: "d" }).unwrap();
|
||||||
s.append(FakeSlice { end: 5 + 13 + 7 + 17, name: "d" }).unwrap();
|
s.append(FakeSlice { end: 5 + 13 + 7 + 17 + 19, name: "e" }).unwrap();
|
||||||
s.append(FakeSlice { end: 5 + 13 + 7 + 17 + 19, name: "e" }).unwrap();
|
s
|
||||||
s
|
});
|
||||||
};
|
|
||||||
}
|
|
||||||
|
|
||||||
async fn get_range(r: Range<u64>) -> Vec<FakeChunk> {
|
async fn get_range(r: Range<u64>) -> Vec<FakeChunk> {
|
||||||
Pin::from(SLICES.get_range(&&*SLICES, r))
|
Pin::from(SLICES.get_range(&&*SLICES, r))
|
||||||
|
@ -728,7 +728,6 @@ mod bench {
|
|||||||
|
|
||||||
use db::testutil::{self, TestDb};
|
use db::testutil::{self, TestDb};
|
||||||
use hyper;
|
use hyper;
|
||||||
use lazy_static::lazy_static;
|
|
||||||
use std::sync::Arc;
|
use std::sync::Arc;
|
||||||
use uuid::Uuid;
|
use uuid::Uuid;
|
||||||
|
|
||||||
@ -786,9 +785,7 @@ mod bench {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
lazy_static! {
|
static SERVER: once_cell::sync::Lazy<Server> = once_cell::sync::Lazy::new(Server::new);
|
||||||
static ref SERVER: Server = Server::new();
|
|
||||||
}
|
|
||||||
|
|
||||||
#[bench]
|
#[bench]
|
||||||
fn serve_stream_recordings(b: &mut test::Bencher) {
|
fn serve_stream_recordings(b: &mut test::Bencher) {
|
||||||
|
Loading…
x
Reference in New Issue
Block a user