mirror of
https://github.com/scottlamb/moonfire-nvr.git
synced 2025-12-04 23:02:32 -05:00
massive error overhaul
* fully stop using ancient `failure` crate in favor of own error type * set an `ErrorKind` on everything
This commit is contained in:
@@ -6,8 +6,8 @@
|
||||
//!
|
||||
//! See `guide/schema.md` for more information.
|
||||
|
||||
use crate::db;
|
||||
use failure::{bail, Error};
|
||||
use crate::db::{self, EXPECTED_VERSION};
|
||||
use base::{bail, Error};
|
||||
use nix::NixPath;
|
||||
use rusqlite::params;
|
||||
use std::ffi::CStr;
|
||||
@@ -60,14 +60,16 @@ fn upgrade(args: &Args, target_ver: i32, conn: &mut rusqlite::Connection) -> Res
|
||||
{
|
||||
assert_eq!(upgraders.len(), db::EXPECTED_VERSION as usize);
|
||||
let old_ver = conn.query_row("select max(id) from version", params![], |row| row.get(0))?;
|
||||
if old_ver > db::EXPECTED_VERSION {
|
||||
if old_ver > EXPECTED_VERSION {
|
||||
bail!(
|
||||
"Database is at version {}, later than expected {}",
|
||||
old_ver,
|
||||
db::EXPECTED_VERSION
|
||||
FailedPrecondition,
|
||||
msg("database is at version {old_ver}, later than expected {EXPECTED_VERSION}"),
|
||||
);
|
||||
} else if old_ver < 0 {
|
||||
bail!("Database is at negative version {}!", old_ver);
|
||||
bail!(
|
||||
FailedPrecondition,
|
||||
msg("Database is at negative version {old_ver}!")
|
||||
);
|
||||
}
|
||||
info!(
|
||||
"Upgrading database from version {} to version {}...",
|
||||
@@ -95,7 +97,7 @@ pub fn run(args: &Args, conn: &mut rusqlite::Connection) -> Result<(), Error> {
|
||||
db::check_sqlite_version()?;
|
||||
db::set_integrity_pragmas(conn)?;
|
||||
set_journal_mode(conn, args.preset_journal)?;
|
||||
upgrade(args, db::EXPECTED_VERSION, conn)?;
|
||||
upgrade(args, EXPECTED_VERSION, conn)?;
|
||||
|
||||
// As in "moonfire-nvr init": try for page_size=16384 and wal for the reasons explained there.
|
||||
//
|
||||
@@ -154,7 +156,7 @@ mod tests {
|
||||
use super::*;
|
||||
use crate::compare;
|
||||
use crate::testutil;
|
||||
use failure::ResultExt;
|
||||
use base::err;
|
||||
use fnv::FnvHashMap;
|
||||
|
||||
const BAD_ANAMORPHIC_VIDEO_SAMPLE_ENTRY: &[u8] = b"\x00\x00\x00\x84\x61\x76\x63\x31\x00\x00\
|
||||
@@ -209,7 +211,7 @@ mod tests {
|
||||
let tmpdir = tempfile::Builder::new()
|
||||
.prefix("moonfire-nvr-test")
|
||||
.tempdir()?;
|
||||
//let path = tmpdir.path().to_str().ok_or_else(|| format_err!("invalid UTF-8"))?.to_owned();
|
||||
//let path = tmpdir.path().to_str().ok_or_else(|| err!("invalid UTF-8"))?.to_owned();
|
||||
let mut upgraded = new_conn()?;
|
||||
upgraded.execute_batch(include_str!("v0.sql"))?;
|
||||
upgraded.execute_batch(
|
||||
@@ -291,7 +293,7 @@ mod tests {
|
||||
*ver,
|
||||
&mut upgraded,
|
||||
)
|
||||
.context(format!("upgrading to version {ver}"))?;
|
||||
.map_err(|e| err!(e, msg("upgrade to version {ver} failed")))?;
|
||||
if let Some(f) = fresh_sql {
|
||||
compare(&upgraded, *ver, f)?;
|
||||
}
|
||||
|
||||
@@ -5,7 +5,7 @@
|
||||
/// Upgrades a version 0 schema to a version 1 schema.
|
||||
use crate::db;
|
||||
use crate::recording;
|
||||
use failure::Error;
|
||||
use base::Error;
|
||||
use rusqlite::{named_params, params};
|
||||
use std::collections::HashMap;
|
||||
use tracing::warn;
|
||||
|
||||
@@ -5,7 +5,7 @@
|
||||
/// Upgrades a version 1 schema to a version 2 schema.
|
||||
use crate::dir;
|
||||
use crate::schema::DirMeta;
|
||||
use failure::{bail, format_err, Error};
|
||||
use base::{bail, Error};
|
||||
use nix::fcntl::{FlockArg, OFlag};
|
||||
use nix::sys::stat::Mode;
|
||||
use rusqlite::{named_params, params};
|
||||
@@ -13,9 +13,12 @@ use std::os::unix::io::AsRawFd;
|
||||
use uuid::Uuid;
|
||||
|
||||
pub fn run(args: &super::Args, tx: &rusqlite::Transaction) -> Result<(), Error> {
|
||||
let sample_file_path = args.sample_file_dir.ok_or_else(|| {
|
||||
format_err!("--sample-file-dir required when upgrading from schema version 1 to 2.")
|
||||
})?;
|
||||
let Some(sample_file_path) = args.sample_file_dir else {
|
||||
bail!(
|
||||
InvalidArgument,
|
||||
msg("--sample-file-dir required when upgrading from schema version 1 to 2."),
|
||||
);
|
||||
};
|
||||
|
||||
let mut d = nix::dir::Dir::open(
|
||||
sample_file_path,
|
||||
@@ -101,12 +104,12 @@ pub fn run(args: &super::Args, tx: &rusqlite::Transaction) -> Result<(), Error>
|
||||
}
|
||||
dir::write_meta(d.as_raw_fd(), &meta)?;
|
||||
|
||||
let sample_file_path = sample_file_path.to_str().ok_or_else(|| {
|
||||
format_err!(
|
||||
"sample file dir {} is not a valid string",
|
||||
sample_file_path.display()
|
||||
)
|
||||
})?;
|
||||
let Some(sample_file_path) = sample_file_path.to_str() else {
|
||||
bail!(
|
||||
InvalidArgument,
|
||||
msg("sample file dir {} is not a valid string", sample_file_path.display()),
|
||||
);
|
||||
};
|
||||
tx.execute(
|
||||
r#"
|
||||
insert into sample_file_dir (path, uuid, last_complete_open_id)
|
||||
@@ -317,15 +320,24 @@ fn verify_dir_contents(
|
||||
};
|
||||
let s = match f.to_str() {
|
||||
Ok(s) => s,
|
||||
Err(_) => bail!("unexpected file {:?} in {:?}", f, sample_file_path),
|
||||
Err(_) => bail!(
|
||||
FailedPrecondition,
|
||||
msg("unexpected file {f:?} in {sample_file_path:?}")
|
||||
),
|
||||
};
|
||||
let uuid = match Uuid::parse_str(s) {
|
||||
Ok(u) => u,
|
||||
Err(_) => bail!("unexpected file {:?} in {:?}", f, sample_file_path),
|
||||
Err(_) => bail!(
|
||||
FailedPrecondition,
|
||||
msg("unexpected file {f:?} in {sample_file_path:?}")
|
||||
),
|
||||
};
|
||||
if s != uuid.as_hyphenated().to_string() {
|
||||
// non-canonical form.
|
||||
bail!("unexpected file {:?} in {:?}", f, sample_file_path);
|
||||
bail!(
|
||||
FailedPrecondition,
|
||||
msg("unexpected file {f:?} in {sample_file_path:?}")
|
||||
);
|
||||
}
|
||||
files.insert(uuid);
|
||||
}
|
||||
@@ -338,9 +350,12 @@ fn verify_dir_contents(
|
||||
let uuid: crate::db::SqlUuid = row.get(0)?;
|
||||
if !files.remove(&uuid.0) {
|
||||
bail!(
|
||||
"{} is missing from dir {}!",
|
||||
uuid.0,
|
||||
sample_file_path.display()
|
||||
FailedPrecondition,
|
||||
msg(
|
||||
"{} is missing from dir {}!",
|
||||
uuid.0,
|
||||
sample_file_path.display()
|
||||
),
|
||||
);
|
||||
}
|
||||
}
|
||||
@@ -367,10 +382,13 @@ fn verify_dir_contents(
|
||||
|
||||
if !files.is_empty() {
|
||||
bail!(
|
||||
"{} unexpected sample file uuids in dir {}: {:?}!",
|
||||
files.len(),
|
||||
sample_file_path.display(),
|
||||
files
|
||||
FailedPrecondition,
|
||||
msg(
|
||||
"{} unexpected sample file uuids in dir {}: {:?}!",
|
||||
files.len(),
|
||||
sample_file_path.display(),
|
||||
files,
|
||||
),
|
||||
);
|
||||
}
|
||||
Ok(())
|
||||
@@ -413,7 +431,7 @@ fn fix_video_sample_entry(tx: &rusqlite::Transaction) -> Result<(), Error> {
|
||||
fn rfc6381_codec_from_sample_entry(sample_entry: &[u8]) -> Result<String, Error> {
|
||||
if sample_entry.len() < 99 || &sample_entry[4..8] != b"avc1" || &sample_entry[90..94] != b"avcC"
|
||||
{
|
||||
bail!("not a valid AVCSampleEntry");
|
||||
bail!(InvalidArgument, msg("not a valid AVCSampleEntry"));
|
||||
}
|
||||
let profile_idc = sample_entry[103];
|
||||
let constraint_flags_byte = sample_entry[104];
|
||||
|
||||
@@ -8,9 +8,8 @@
|
||||
use crate::db::{self, SqlUuid};
|
||||
use crate::dir;
|
||||
use crate::schema;
|
||||
use failure::Error;
|
||||
use base::Error;
|
||||
use rusqlite::params;
|
||||
use std::convert::TryFrom;
|
||||
use std::os::unix::io::AsRawFd;
|
||||
use std::path::PathBuf;
|
||||
use std::sync::Arc;
|
||||
@@ -50,7 +49,7 @@ fn open_sample_file_dir(tx: &rusqlite::Transaction) -> Result<Arc<dir::SampleFil
|
||||
open.id = o_id as u32;
|
||||
open.uuid.extend_from_slice(&o_uuid.0.as_bytes()[..]);
|
||||
}
|
||||
let p = PathBuf::try_from(p)?;
|
||||
let p = PathBuf::from(p);
|
||||
dir::SampleFileDir::open(&p, &meta)
|
||||
}
|
||||
|
||||
|
||||
@@ -3,7 +3,7 @@
|
||||
// SPDX-License-Identifier: GPL-v3.0-or-later WITH GPL-3.0-linking-exception.
|
||||
|
||||
/// Upgrades a version 3 schema to a version 4 schema.
|
||||
use failure::Error;
|
||||
use base::Error;
|
||||
|
||||
pub fn run(_args: &super::Args, tx: &rusqlite::Transaction) -> Result<(), Error> {
|
||||
// These create statements match the schema.sql when version 4 was the latest.
|
||||
|
||||
@@ -8,8 +8,8 @@
|
||||
/// Otherwise, verify they are consistent with the database then upgrade them.
|
||||
use crate::db::SqlUuid;
|
||||
use crate::{dir, schema};
|
||||
use base::{bail, err, Error};
|
||||
use cstr::cstr;
|
||||
use failure::{bail, Error, Fail};
|
||||
use nix::fcntl::{FlockArg, OFlag};
|
||||
use nix::sys::stat::Mode;
|
||||
use protobuf::Message;
|
||||
@@ -34,15 +34,17 @@ fn maybe_upgrade_meta(dir: &dir::Fd, db_meta: &schema::DirMeta) -> Result<bool,
|
||||
|
||||
let mut s = protobuf::CodedInputStream::from_bytes(&data);
|
||||
let mut dir_meta = schema::DirMeta::new();
|
||||
dir_meta
|
||||
.merge_from(&mut s)
|
||||
.map_err(|e| e.context("Unable to parse metadata proto: {}"))?;
|
||||
dir_meta.merge_from(&mut s).map_err(|e| {
|
||||
err!(
|
||||
FailedPrecondition,
|
||||
msg("unable to parse metadata proto"),
|
||||
source(e)
|
||||
)
|
||||
})?;
|
||||
if let Err(e) = dir::SampleFileDir::check_consistent(db_meta, &dir_meta) {
|
||||
bail!(
|
||||
"Inconsistent db_meta={:?} dir_meta={:?}: {}",
|
||||
&db_meta,
|
||||
&dir_meta,
|
||||
e
|
||||
FailedPrecondition,
|
||||
msg("inconsistent db_meta={db_meta:?} dir_meta={dir_meta:?}: {e}"),
|
||||
);
|
||||
}
|
||||
let mut f = crate::fs::openat(
|
||||
@@ -56,9 +58,12 @@ fn maybe_upgrade_meta(dir: &dir::Fd, db_meta: &schema::DirMeta) -> Result<bool,
|
||||
.expect("proto3->vec is infallible");
|
||||
if data.len() > FIXED_DIR_META_LEN {
|
||||
bail!(
|
||||
"Length-delimited DirMeta message requires {} bytes, over limit of {}",
|
||||
data.len(),
|
||||
FIXED_DIR_META_LEN
|
||||
Internal,
|
||||
msg(
|
||||
"length-delimited DirMeta message requires {} bytes, over limit of {}",
|
||||
data.len(),
|
||||
FIXED_DIR_META_LEN,
|
||||
),
|
||||
);
|
||||
}
|
||||
data.resize(FIXED_DIR_META_LEN, 0); // pad to required length.
|
||||
@@ -144,12 +149,12 @@ pub fn run(_args: &super::Args, tx: &rusqlite::Transaction) -> Result<(), Error>
|
||||
o.uuid.extend_from_slice(&uuid.0.as_bytes()[..]);
|
||||
}
|
||||
(None, None) => {}
|
||||
_ => bail!("open table missing id"),
|
||||
_ => bail!(Internal, msg("open table missing id")),
|
||||
}
|
||||
|
||||
let dir = dir::Fd::open(path, false)?;
|
||||
dir.lock(FlockArg::LockExclusiveNonblock)
|
||||
.map_err(|e| e.context(format!("unable to lock dir {path}")))?;
|
||||
.map_err(|e| err!(e, msg("unable to lock dir {path}")))?;
|
||||
|
||||
let mut need_sync = maybe_upgrade_meta(&dir, &db_meta)?;
|
||||
if maybe_cleanup_garbage_uuids(&dir)? {
|
||||
|
||||
@@ -2,9 +2,9 @@
|
||||
// Copyright (C) 2020 The Moonfire NVR Authors; see AUTHORS and LICENSE.txt.
|
||||
// SPDX-License-Identifier: GPL-v3.0-or-later WITH GPL-3.0-linking-exception.
|
||||
|
||||
use base::{bail, err, Error};
|
||||
/// Upgrades a version 4 schema to a version 5 schema.
|
||||
use byteorder::{BigEndian, ByteOrder, WriteBytesExt};
|
||||
use failure::{bail, format_err, Error, ResultExt};
|
||||
use h264_reader::avcc::AvcDecoderConfigurationRecord;
|
||||
use rusqlite::{named_params, params};
|
||||
use std::convert::{TryFrom, TryInto};
|
||||
@@ -29,22 +29,31 @@ fn default_pixel_aspect_ratio(width: u16, height: u16) -> (u16, u16) {
|
||||
|
||||
fn parse(data: &[u8]) -> Result<AvcDecoderConfigurationRecord, Error> {
|
||||
if data.len() < 94 || &data[4..8] != b"avc1" || &data[90..94] != b"avcC" {
|
||||
bail!("data of len {} doesn't have an avcC", data.len());
|
||||
bail!(
|
||||
DataLoss,
|
||||
msg("data of len {} doesn't have an avcC", data.len())
|
||||
);
|
||||
}
|
||||
let avcc_len = BigEndian::read_u32(&data[86..90]);
|
||||
if avcc_len < 8 {
|
||||
// length and type.
|
||||
bail!("invalid avcc len {}", avcc_len);
|
||||
bail!(DataLoss, msg("invalid avcc len {avcc_len}"));
|
||||
}
|
||||
let end_pos = 86 + usize::try_from(avcc_len)?;
|
||||
if end_pos != data.len() {
|
||||
let end_pos = usize::try_from(avcc_len)
|
||||
.ok()
|
||||
.and_then(|l| l.checked_add(86));
|
||||
if end_pos != Some(data.len()) {
|
||||
bail!(
|
||||
"expected avcC to be end of extradata; there are {} more bytes.",
|
||||
data.len() - end_pos
|
||||
DataLoss,
|
||||
msg(
|
||||
"avcC end pos {:?} and total data len {} should match",
|
||||
end_pos,
|
||||
data.len(),
|
||||
),
|
||||
);
|
||||
}
|
||||
AvcDecoderConfigurationRecord::try_from(&data[94..end_pos])
|
||||
.map_err(|e| format_err!("Bad AvcDecoderConfigurationRecord: {:?}", e))
|
||||
AvcDecoderConfigurationRecord::try_from(&data[94..])
|
||||
.map_err(|e| err!(DataLoss, msg("Bad AvcDecoderConfigurationRecord: {:?}", e)))
|
||||
}
|
||||
|
||||
pub fn run(_args: &super::Args, tx: &rusqlite::Transaction) -> Result<(), Error> {
|
||||
@@ -100,24 +109,37 @@ pub fn run(_args: &super::Args, tx: &rusqlite::Transaction) -> Result<(), Error>
|
||||
let mut rows = stmt.query(params![])?;
|
||||
while let Some(row) = rows.next()? {
|
||||
let id: i32 = row.get(0)?;
|
||||
let width: u16 = row.get::<_, i32>(1)?.try_into()?;
|
||||
let height: u16 = row.get::<_, i32>(2)?.try_into()?;
|
||||
let rfc6381_codec: &str = row.get_ref(3)?.as_str()?;
|
||||
let width: u16 = row
|
||||
.get::<_, i32>(1)?
|
||||
.try_into()
|
||||
.map_err(|_| err!(OutOfRange))?;
|
||||
let height: u16 = row
|
||||
.get::<_, i32>(2)?
|
||||
.try_into()
|
||||
.map_err(|_| err!(OutOfRange))?;
|
||||
let rfc6381_codec: &str = row
|
||||
.get_ref(3)?
|
||||
.as_str()
|
||||
.map_err(|_| err!(InvalidArgument))?;
|
||||
let mut data: Vec<u8> = row.get(4)?;
|
||||
let avcc = parse(&data)?;
|
||||
if avcc.num_of_sequence_parameter_sets() != 1 {
|
||||
bail!("Multiple SPSs!");
|
||||
bail!(Unimplemented, msg("multiple SPSs!"));
|
||||
}
|
||||
let ctx = avcc.create_context().map_err(|e| {
|
||||
format_err!(
|
||||
"Can't load SPS+PPS for video_sample_entry_id {}: {:?}",
|
||||
id,
|
||||
e
|
||||
err!(
|
||||
Unknown,
|
||||
msg("can't load SPS+PPS for video_sample_entry_id {id}: {e:?}"),
|
||||
)
|
||||
})?;
|
||||
let sps = ctx
|
||||
.sps_by_id(h264_reader::nal::pps::ParamSetId::from_u32(0).unwrap())
|
||||
.ok_or_else(|| format_err!("No SPS 0 for video_sample_entry_id {}", id))?;
|
||||
.ok_or_else(|| {
|
||||
err!(
|
||||
Unimplemented,
|
||||
msg("no SPS 0 for video_sample_entry_id {id}")
|
||||
)
|
||||
})?;
|
||||
let pasp = sps
|
||||
.vui_parameters
|
||||
.as_ref()
|
||||
@@ -129,7 +151,10 @@ pub fn run(_args: &super::Args, tx: &rusqlite::Transaction) -> Result<(), Error>
|
||||
data.write_u32::<BigEndian>(pasp.0.into())?;
|
||||
data.write_u32::<BigEndian>(pasp.1.into())?;
|
||||
let len = data.len();
|
||||
BigEndian::write_u32(&mut data[0..4], u32::try_from(len)?);
|
||||
BigEndian::write_u32(
|
||||
&mut data[0..4],
|
||||
u32::try_from(len).map_err(|_| err!(OutOfRange))?,
|
||||
);
|
||||
}
|
||||
|
||||
insert.execute(named_params! {
|
||||
@@ -268,7 +293,7 @@ pub fn run(_args: &super::Args, tx: &rusqlite::Transaction) -> Result<(), Error>
|
||||
":video_sync_samples": video_sync_samples,
|
||||
":video_sample_entry_id": video_sample_entry_id,
|
||||
})
|
||||
.with_context(|_| format!("Unable to insert composite_id {composite_id}"))?;
|
||||
.map_err(|e| err!(e, msg("unable to insert composite_id {composite_id}")))?;
|
||||
cum_duration_90k += i64::from(wall_duration_90k);
|
||||
cum_runs += if run_offset == 0 { 1 } else { 0 };
|
||||
}
|
||||
|
||||
@@ -3,7 +3,7 @@
|
||||
// SPDX-License-Identifier: GPL-v3.0-or-later WITH GPL-3.0-linking-exception
|
||||
|
||||
/// Upgrades a version 6 schema to a version 7 schema.
|
||||
use failure::{format_err, Error, ResultExt};
|
||||
use base::{err, Error};
|
||||
use fnv::FnvHashMap;
|
||||
use rusqlite::{named_params, params};
|
||||
use std::{convert::TryFrom, path::PathBuf};
|
||||
@@ -28,7 +28,13 @@ fn copy_meta(tx: &rusqlite::Transaction) -> Result<(), Error> {
|
||||
let config = GlobalConfig {
|
||||
max_signal_changes: max_signal_changes
|
||||
.map(|s| {
|
||||
u32::try_from(s).map_err(|_| format_err!("max_signal_changes out of range"))
|
||||
u32::try_from(s).map_err(|e| {
|
||||
err!(
|
||||
OutOfRange,
|
||||
msg("max_signal_changes out of range"),
|
||||
source(e)
|
||||
)
|
||||
})
|
||||
})
|
||||
.transpose()?,
|
||||
..Default::default()
|
||||
@@ -57,7 +63,7 @@ fn copy_sample_file_dir(tx: &rusqlite::Transaction) -> Result<(), Error> {
|
||||
let path: String = row.get(2)?;
|
||||
let uuid: SqlUuid = row.get(1)?;
|
||||
let config = SampleFileDirConfig {
|
||||
path: PathBuf::try_from(path)?,
|
||||
path: PathBuf::from(path),
|
||||
..Default::default()
|
||||
};
|
||||
let last_complete_open_id: Option<i64> = row.get(3)?;
|
||||
@@ -107,7 +113,10 @@ fn copy_users(tx: &rusqlite::Transaction) -> Result<(), Error> {
|
||||
let permissions: Vec<u8> = row.get(7)?;
|
||||
let config = UserConfig {
|
||||
disabled: (flags & 1) != 0,
|
||||
unix_uid: unix_uid.map(u64::try_from).transpose()?,
|
||||
unix_uid: unix_uid
|
||||
.map(u64::try_from)
|
||||
.transpose()
|
||||
.map_err(|_| err!(OutOfRange, msg("bad unix_uid")))?,
|
||||
..Default::default()
|
||||
};
|
||||
insert.execute(named_params! {
|
||||
@@ -134,7 +143,8 @@ fn copy_signal_types(tx: &rusqlite::Transaction) -> Result<(), Error> {
|
||||
let type_ = types_
|
||||
.entry(type_uuid.0)
|
||||
.or_insert_with(SignalTypeConfig::default);
|
||||
let value = u8::try_from(value).map_err(|_| format_err!("bad signal type value"))?;
|
||||
let value =
|
||||
u8::try_from(value).map_err(|_| err!(OutOfRange, msg("bad signal type value")))?;
|
||||
let value_config = type_.values.entry(value).or_insert_with(Default::default);
|
||||
if let Some(n) = name {
|
||||
value_config.name = n;
|
||||
@@ -163,7 +173,8 @@ fn copy_signals(tx: &rusqlite::Transaction) -> Result<(), Error> {
|
||||
let mut rows = stmt.query(params![])?;
|
||||
while let Some(row) = rows.next()? {
|
||||
let id: i32 = row.get(0)?;
|
||||
let id = u32::try_from(id)?;
|
||||
let id =
|
||||
u32::try_from(id).map_err(|e| err!(OutOfRange, msg("bad signal id"), source(e)))?;
|
||||
let source_uuid: SqlUuid = row.get(1)?;
|
||||
let type_uuid: SqlUuid = row.get(2)?;
|
||||
let short_name: String = row.get(3)?;
|
||||
@@ -187,7 +198,8 @@ fn copy_signals(tx: &rusqlite::Transaction) -> Result<(), Error> {
|
||||
let mut rows = stmt.query(params![])?;
|
||||
while let Some(row) = rows.next()? {
|
||||
let signal_id: i32 = row.get(0)?;
|
||||
let signal_id = u32::try_from(signal_id)?;
|
||||
let signal_id = u32::try_from(signal_id)
|
||||
.map_err(|e| err!(OutOfRange, msg("bad signal_id"), source(e)))?;
|
||||
let camera_id: i32 = row.get(1)?;
|
||||
let type_: i32 = row.get(2)?;
|
||||
let signal = signals.get_mut(&signal_id).unwrap();
|
||||
@@ -261,7 +273,13 @@ fn copy_cameras(tx: &rusqlite::Transaction) -> Result<(), Error> {
|
||||
.filter(|h| !h.is_empty())
|
||||
.map(|h| Url::parse(&format!("http://{h}/")))
|
||||
.transpose()
|
||||
.with_context(|_| "bad onvif_host")?,
|
||||
.map_err(|e| {
|
||||
err!(
|
||||
InvalidArgument,
|
||||
msg("bad onvif_host for camera id {id}"),
|
||||
source(e)
|
||||
)
|
||||
})?,
|
||||
username: username.take().unwrap_or_default(),
|
||||
password: password.take().unwrap_or_default(),
|
||||
..Default::default()
|
||||
@@ -324,7 +342,13 @@ fn copy_streams(tx: &rusqlite::Transaction) -> Result<(), Error> {
|
||||
""
|
||||
})
|
||||
.to_owned(),
|
||||
url: Some(Url::parse(&rtsp_url)?),
|
||||
url: Some(Url::parse(&rtsp_url).map_err(|e| {
|
||||
err!(
|
||||
InvalidArgument,
|
||||
msg("bad rtsp_url for stream id {id}"),
|
||||
source(e)
|
||||
)
|
||||
})?),
|
||||
retain_bytes,
|
||||
flush_if_sec,
|
||||
..Default::default()
|
||||
|
||||
Reference in New Issue
Block a user