Merge branch 'master' into auth

This commit is contained in:
Scott Lamb 2018-12-01 15:27:54 -08:00
commit 4f87c16c31
13 changed files with 319 additions and 235 deletions

451
Cargo.lock generated

File diff suppressed because it is too large Load Diff

View File

@ -38,11 +38,11 @@ moonfire-db = { path = "db" }
moonfire-ffmpeg = { path = "ffmpeg" } moonfire-ffmpeg = { path = "ffmpeg" }
mylog = { git = "https://github.com/scottlamb/mylog" } mylog = { git = "https://github.com/scottlamb/mylog" }
openssl = "0.10" openssl = "0.10"
parking_lot = { version = "0.6", features = [] } parking_lot = { version = "0.7", features = [] }
reffers = "0.5.1" reffers = "0.5.1"
regex = "1.0" regex = "1.0"
ring = "0.12.1" ring = "0.12.1"
rusqlite = "0.14" rusqlite = "0.15"
serde = "1.0" serde = "1.0"
serde_derive = "1.0" serde_derive = "1.0"
serde_json = "1.0" serde_json = "1.0"
@ -51,14 +51,14 @@ time = "0.1"
tokio = "0.1.8" tokio = "0.1.8"
tokio-signal = "0.2" tokio-signal = "0.2"
url = "1.4" url = "1.4"
uuid = { version = "0.6", features = ["serde", "std", "v4"] } uuid = { version = "0.7", features = ["serde", "std", "v4"] }
[dev-dependencies] [dev-dependencies]
reqwest = "0.9.5" reqwest = "0.9.5"
tempdir = "0.3" tempdir = "0.3"
[dependencies.cursive] [dependencies.cursive]
version = "0.9" version = "0.10"
#default-features = false #default-features = false
#features = ["termion-backend"] #features = ["termion-backend"]

View File

@ -14,5 +14,5 @@ path = "lib.rs"
failure = "0.1.1" failure = "0.1.1"
libc = "0.2" libc = "0.2"
log = "0.4" log = "0.4"
parking_lot = { version = "0.6", features = [] } parking_lot = { version = "0.7", features = [] }
time = "0.1" time = "0.1"

View File

@ -23,10 +23,10 @@ lru-cache = "0.1"
moonfire-base = { path = "../base" } moonfire-base = { path = "../base" }
mylog = { git = "https://github.com/scottlamb/mylog" } mylog = { git = "https://github.com/scottlamb/mylog" }
openssl = "0.10" openssl = "0.10"
parking_lot = { version = "0.6", features = [] } parking_lot = { version = "0.7", features = [] }
protobuf = "2.0" protobuf = "2.0"
regex = "1.0" regex = "1.0"
rusqlite = "0.14" rusqlite = "0.15"
tempdir = "0.3" tempdir = "0.3"
time = "0.1" time = "0.1"
uuid = { version = "0.6", features = ["std", "v4"] } uuid = { version = "0.7", features = ["std", "v4"] }

View File

@ -34,7 +34,7 @@ use failure::Error;
use fnv::FnvHashMap; use fnv::FnvHashMap;
use libpasta; use libpasta;
use parking_lot::Mutex; use parking_lot::Mutex;
use rusqlite::{self, Connection, Transaction}; use rusqlite::{self, Connection, Transaction, types::ToSql};
use std::collections::BTreeMap; use std::collections::BTreeMap;
use std::fmt; use std::fmt;
use std::net::IpAddr; use std::net::IpAddr;
@ -343,7 +343,7 @@ impl State {
from from
user user
"#)?; "#)?;
let mut rows = stmt.query(&[])?; let mut rows = stmt.query(&[] as &[&ToSql])?;
while let Some(row) = rows.next() { while let Some(row) = rows.next() {
let row = row?; let row = row?;
let id = row.get_checked(0)?; let id = row.get_checked(0)?;
@ -594,7 +594,7 @@ impl State {
let addr = req.addr_buf(); let addr = req.addr_buf();
let addr: Option<&[u8]> = addr.as_ref().map(|a| a.as_ref()); let addr: Option<&[u8]> = addr.as_ref().map(|a| a.as_ref());
stmt.execute(&[ stmt.execute(&[
&req.when_sec, &req.when_sec as &ToSql,
&req.user_agent, &req.user_agent,
&addr, &addr,
&(reason as i32), &(reason as i32),

View File

@ -36,7 +36,7 @@ use failure::Error;
use fnv::FnvHashMap; use fnv::FnvHashMap;
use raw; use raw;
use recording; use recording;
use rusqlite; use rusqlite::{self, types::ToSql};
use schema; use schema;
use std::os::unix::ffi::OsStrExt; use std::os::unix::ffi::OsStrExt;
use std::fs; use std::fs;
@ -57,7 +57,7 @@ pub fn run(conn: &rusqlite::Connection, opts: &Options) -> Result<(), Error> {
"#)?; "#)?;
let mut garbage_stmt = conn.prepare_cached( let mut garbage_stmt = conn.prepare_cached(
"select composite_id from garbage where sample_file_dir_id = ?")?; "select composite_id from garbage where sample_file_dir_id = ?")?;
let mut rows = dir_stmt.query(&[])?; let mut rows = dir_stmt.query(&[] as &[&ToSql])?;
while let Some(row) = rows.next() { while let Some(row) = rows.next() {
let row = row?; let row = row?;
let mut meta = schema::DirMeta::default(); let mut meta = schema::DirMeta::default();
@ -93,7 +93,7 @@ pub fn run(conn: &rusqlite::Connection, opts: &Options) -> Result<(), Error> {
let mut stmt = conn.prepare(r#" let mut stmt = conn.prepare(r#"
select id, sample_file_dir_id from stream where sample_file_dir_id is not null select id, sample_file_dir_id from stream where sample_file_dir_id is not null
"#)?; "#)?;
let mut rows = stmt.query(&[])?; let mut rows = stmt.query(&[] as &[&ToSql])?;
while let Some(row) = rows.next() { while let Some(row) = rows.next() {
let row = row?; let row = row?;
let stream_id = row.get_checked(0)?; let stream_id = row.get_checked(0)?;

View File

@ -62,7 +62,7 @@ use openssl::hash;
use parking_lot::{Mutex,MutexGuard}; use parking_lot::{Mutex,MutexGuard};
use raw; use raw;
use recording::{self, TIME_UNITS_PER_SEC}; use recording::{self, TIME_UNITS_PER_SEC};
use rusqlite; use rusqlite::{self, types::ToSql};
use schema; use schema;
use std::collections::{BTreeMap, VecDeque}; use std::collections::{BTreeMap, VecDeque};
use std::cell::RefCell; use std::cell::RefCell;
@ -101,7 +101,7 @@ pub struct FromSqlUuid(pub Uuid);
impl rusqlite::types::FromSql for FromSqlUuid { impl rusqlite::types::FromSql for FromSqlUuid {
fn column_result(value: rusqlite::types::ValueRef) -> rusqlite::types::FromSqlResult<Self> { fn column_result(value: rusqlite::types::ValueRef) -> rusqlite::types::FromSqlResult<Self> {
let uuid = Uuid::from_bytes(value.as_blob()?) let uuid = Uuid::from_slice(value.as_blob()?)
.map_err(|e| rusqlite::types::FromSqlError::Other(Box::new(e)))?; .map_err(|e| rusqlite::types::FromSqlError::Other(Box::new(e)))?;
Ok(FromSqlUuid(uuid)) Ok(FromSqlUuid(uuid))
} }
@ -881,7 +881,7 @@ impl LockedDatabase {
let mut stmt = tx.prepare_cached( let mut stmt = tx.prepare_cached(
r"update open set duration_90k = ?, end_time_90k = ? where id = ?")?; r"update open set duration_90k = ?, end_time_90k = ? where id = ?")?;
let rows = stmt.execute(&[ let rows = stmt.execute(&[
&(recording::Time::new(clocks.monotonic()) - self.open_monotonic).0, &(recording::Time::new(clocks.monotonic()) - self.open_monotonic).0 as &ToSql,
&recording::Time::new(clocks.realtime()).0, &recording::Time::new(clocks.realtime()).0,
&o.id, &o.id,
])?; ])?;
@ -1002,7 +1002,7 @@ impl LockedDatabase {
update sample_file_dir set last_complete_open_id = ? where id = ? update sample_file_dir set last_complete_open_id = ? where id = ?
"#)?; "#)?;
for &id in in_progress.keys() { for &id in in_progress.keys() {
if stmt.execute(&[&o.id, &id])? != 1 { if stmt.execute(&[&o.id as &ToSql, &id])? != 1 {
bail!("unable to update dir {}", id); bail!("unable to update dir {}", id);
} }
} }
@ -1260,7 +1260,7 @@ impl LockedDatabase {
from from
video_sample_entry video_sample_entry
"#)?; "#)?;
let mut rows = stmt.query(&[])?; let mut rows = stmt.query(&[] as &[&ToSql])?;
while let Some(row) = rows.next() { while let Some(row) = rows.next() {
let row = row?; let row = row?;
let id = row.get_checked(0)?; let id = row.get_checked(0)?;
@ -1300,7 +1300,7 @@ impl LockedDatabase {
from from
sample_file_dir d left join open o on (d.last_complete_open_id = o.id); sample_file_dir d left join open o on (d.last_complete_open_id = o.id);
"#)?; "#)?;
let mut rows = stmt.query(&[])?; let mut rows = stmt.query(&[] as &[&ToSql])?;
while let Some(row) = rows.next() { while let Some(row) = rows.next() {
let row = row?; let row = row?;
let id = row.get_checked(0)?; let id = row.get_checked(0)?;
@ -1342,7 +1342,7 @@ impl LockedDatabase {
from from
camera; camera;
"#)?; "#)?;
let mut rows = stmt.query(&[])?; let mut rows = stmt.query(&[] as &[&ToSql])?;
while let Some(row) = rows.next() { while let Some(row) = rows.next() {
let row = row?; let row = row?;
let id = row.get_checked(0)?; let id = row.get_checked(0)?;
@ -1381,7 +1381,7 @@ impl LockedDatabase {
from from
stream; stream;
"#)?; "#)?;
let mut rows = stmt.query(&[])?; let mut rows = stmt.query(&[] as &[&ToSql])?;
while let Some(row) = rows.next() { while let Some(row) = rows.next() {
let row = row?; let row = row?;
let id = row.get_checked(0)?; let id = row.get_checked(0)?;
@ -1486,7 +1486,7 @@ impl LockedDatabase {
self.conn.execute(r#" self.conn.execute(r#"
insert into sample_file_dir (path, uuid, last_complete_open_id) insert into sample_file_dir (path, uuid, last_complete_open_id)
values (?, ?, ?) values (?, ?, ?)
"#, &[&path, &uuid_bytes, &o.id])?; "#, &[&path as &ToSql, &uuid_bytes, &o.id])?;
let id = self.conn.last_insert_rowid() as i32; let id = self.conn.last_insert_rowid() as i32;
use ::std::collections::btree_map::Entry; use ::std::collections::btree_map::Entry;
let e = self.sample_file_dirs_by_id.entry(id); let e = self.sample_file_dirs_by_id.entry(id);
@ -1731,7 +1731,7 @@ impl LockedDatabase {
/// Note this doesn't set journal options, so that it can be used on in-memory databases for /// Note this doesn't set journal options, so that it can be used on in-memory databases for
/// test code. /// test code.
pub fn init(conn: &mut rusqlite::Connection) -> Result<(), Error> { pub fn init(conn: &mut rusqlite::Connection) -> Result<(), Error> {
conn.execute("pragma foreign_keys = on", &[])?; conn.execute("pragma foreign_keys = on", &[] as &[&ToSql])?;
let tx = conn.transaction()?; let tx = conn.transaction()?;
tx.execute_batch(include_str!("schema.sql"))?; tx.execute_batch(include_str!("schema.sql"))?;
{ {
@ -1750,11 +1750,12 @@ pub fn init(conn: &mut rusqlite::Connection) -> Result<(), Error> {
pub fn get_schema_version(conn: &rusqlite::Connection) -> Result<Option<i32>, Error> { pub fn get_schema_version(conn: &rusqlite::Connection) -> Result<Option<i32>, Error> {
let ver_tables: i32 = conn.query_row_and_then( let ver_tables: i32 = conn.query_row_and_then(
"select count(*) from sqlite_master where name = 'version'", "select count(*) from sqlite_master where name = 'version'",
&[], |row| row.get_checked(0))?; &[] as &[&ToSql], |row| row.get_checked(0))?;
if ver_tables == 0 { if ver_tables == 0 {
return Ok(None); return Ok(None);
} }
Ok(Some(conn.query_row_and_then("select max(id) from version", &[], |row| row.get_checked(0))?)) Ok(Some(conn.query_row_and_then("select max(id) from version", &[] as &[&ToSql],
|row| row.get_checked(0))?))
} }
/// The recording database. Abstracts away SQLite queries. Also maintains in-memory state /// The recording database. Abstracts away SQLite queries. Also maintains in-memory state
@ -1791,7 +1792,7 @@ impl<C: Clocks + Clone> Database<C> {
/// Creates the database from a caller-supplied SQLite connection. /// Creates the database from a caller-supplied SQLite connection.
pub fn new(clocks: C, conn: rusqlite::Connection, pub fn new(clocks: C, conn: rusqlite::Connection,
read_write: bool) -> Result<Database<C>, Error> { read_write: bool) -> Result<Database<C>, Error> {
conn.execute("pragma foreign_keys = on", &[])?; conn.execute("pragma foreign_keys = on", &[] as &[&ToSql])?;
{ {
let ver = get_schema_version(&conn)?.ok_or_else(|| format_err!( let ver = get_schema_version(&conn)?.ok_or_else(|| format_err!(
"no such table: version. \ "no such table: version. \
@ -1821,7 +1822,7 @@ impl<C: Clocks + Clone> Database<C> {
let mut stmt = conn.prepare(" insert into open (uuid, start_time_90k) values (?, ?)")?; let mut stmt = conn.prepare(" insert into open (uuid, start_time_90k) values (?, ?)")?;
let uuid = Uuid::new_v4(); let uuid = Uuid::new_v4();
let uuid_bytes = &uuid.as_bytes()[..]; let uuid_bytes = &uuid.as_bytes()[..];
stmt.execute(&[&uuid_bytes, &real.0])?; stmt.execute(&[&uuid_bytes as &ToSql, &real.0])?;
Some(Open { Some(Open {
id: conn.last_insert_rowid() as u32, id: conn.last_insert_rowid() as u32,
uuid, uuid,

View File

@ -34,7 +34,7 @@ use db::{self, CompositeId, FromSqlUuid};
use failure::{Error, ResultExt}; use failure::{Error, ResultExt};
use fnv::FnvHashSet; use fnv::FnvHashSet;
use recording; use recording;
use rusqlite; use rusqlite::{self, types::ToSql};
use std::ops::Range; use std::ops::Range;
use uuid::Uuid; use uuid::Uuid;
@ -166,7 +166,7 @@ fn list_recordings_inner(mut rows: rusqlite::Rows,
} }
pub(crate) fn get_db_uuid(conn: &rusqlite::Connection) -> Result<Uuid, Error> { pub(crate) fn get_db_uuid(conn: &rusqlite::Connection) -> Result<Uuid, Error> {
conn.query_row("select uuid from meta", &[], |row| -> Result<Uuid, Error> { conn.query_row("select uuid from meta", &[] as &[&ToSql], |row| -> Result<Uuid, Error> {
let uuid: FromSqlUuid = row.get_checked(0)?; let uuid: FromSqlUuid = row.get_checked(0)?;
Ok(uuid.0) Ok(uuid.0)
})? })?

View File

@ -34,7 +34,7 @@
use db; use db;
use failure::Error; use failure::Error;
use rusqlite; use rusqlite::{self, types::ToSql};
mod v0_to_v1; mod v0_to_v1;
mod v1_to_v2; mod v1_to_v2;
@ -52,7 +52,7 @@ pub struct Args<'a> {
fn set_journal_mode(conn: &rusqlite::Connection, requested: &str) -> Result<(), Error> { fn set_journal_mode(conn: &rusqlite::Connection, requested: &str) -> Result<(), Error> {
assert!(!requested.contains(';')); // quick check for accidental sql injection. assert!(!requested.contains(';')); // quick check for accidental sql injection.
let actual = conn.query_row(&format!("pragma journal_mode = {}", requested), &[], let actual = conn.query_row(&format!("pragma journal_mode = {}", requested), &[] as &[&ToSql],
|row| row.get_checked::<_, String>(0))??; |row| row.get_checked::<_, String>(0))??;
info!("...database now in journal_mode {} (requested {}).", actual, requested); info!("...database now in journal_mode {} (requested {}).", actual, requested);
Ok(()) Ok(())
@ -68,7 +68,8 @@ pub fn run(args: &Args, conn: &mut rusqlite::Connection) -> Result<(), Error> {
{ {
assert_eq!(upgraders.len(), db::EXPECTED_VERSION as usize); assert_eq!(upgraders.len(), db::EXPECTED_VERSION as usize);
let old_ver = let old_ver =
conn.query_row("select max(id) from version", &[], |row| row.get_checked(0))??; conn.query_row("select max(id) from version", &[] as &[&ToSql],
|row| row.get_checked(0))??;
if old_ver > db::EXPECTED_VERSION { if old_ver > db::EXPECTED_VERSION {
bail!("Database is at version {}, later than expected {}", bail!("Database is at version {}, later than expected {}",
old_ver, db::EXPECTED_VERSION); old_ver, db::EXPECTED_VERSION);
@ -84,7 +85,7 @@ pub fn run(args: &Args, conn: &mut rusqlite::Connection) -> Result<(), Error> {
tx.execute(r#" tx.execute(r#"
insert into version (id, unix_time, notes) insert into version (id, unix_time, notes)
values (?, cast(strftime('%s', 'now') as int32), ?) values (?, cast(strftime('%s', 'now') as int32), ?)
"#, &[&(ver + 1), &UPGRADE_NOTES])?; "#, &[&(ver + 1) as &ToSql, &UPGRADE_NOTES])?;
tx.commit()?; tx.commit()?;
} }
} }
@ -93,7 +94,7 @@ pub fn run(args: &Args, conn: &mut rusqlite::Connection) -> Result<(), Error> {
// compiles the SQLite3 amalgamation with -DSQLITE_DEFAULT_FOREIGN_KEYS=1). Ensure it's // compiles the SQLite3 amalgamation with -DSQLITE_DEFAULT_FOREIGN_KEYS=1). Ensure it's
// always on. Note that our foreign keys are immediate rather than deferred, so we have to // always on. Note that our foreign keys are immediate rather than deferred, so we have to
// be careful about the order of operations during the upgrade. // be careful about the order of operations during the upgrade.
conn.execute("pragma foreign_keys = on", &[])?; conn.execute("pragma foreign_keys = on", &[] as &[&ToSql])?;
// WAL is the preferred journal mode for normal operation; it reduces the number of syncs // WAL is the preferred journal mode for normal operation; it reduces the number of syncs
// without compromising safety. // without compromising safety.

View File

@ -33,7 +33,7 @@
use db; use db;
use failure::Error; use failure::Error;
use recording; use recording;
use rusqlite; use rusqlite::{self, types::ToSql};
use std::collections::HashMap; use std::collections::HashMap;
pub fn run(_args: &super::Args, tx: &rusqlite::Transaction) -> Result<(), Error> { pub fn run(_args: &super::Args, tx: &rusqlite::Transaction) -> Result<(), Error> {
@ -141,7 +141,7 @@ fn fill_recording(tx: &rusqlite::Transaction) -> Result<HashMap<i32, CameraState
insert into recording_playback values (:composite_id, :sample_file_uuid, :sample_file_sha1, insert into recording_playback values (:composite_id, :sample_file_uuid, :sample_file_sha1,
:video_index) :video_index)
"#)?; "#)?;
let mut rows = select.query(&[])?; let mut rows = select.query(&[] as &[&ToSql])?;
let mut camera_state: HashMap<i32, CameraState> = HashMap::new(); let mut camera_state: HashMap<i32, CameraState> = HashMap::new();
while let Some(row) = rows.next() { while let Some(row) = rows.next() {
let row = row?; let row = row?;
@ -216,7 +216,7 @@ fn fill_camera(tx: &rusqlite::Transaction, camera_state: HashMap<i32, CameraStat
insert into camera values (:id, :uuid, :short_name, :description, :host, :username, :password, insert into camera values (:id, :uuid, :short_name, :description, :host, :username, :password,
:main_rtsp_path, :sub_rtsp_path, :retain_bytes, :next_recording_id) :main_rtsp_path, :sub_rtsp_path, :retain_bytes, :next_recording_id)
"#)?; "#)?;
let mut rows = select.query(&[])?; let mut rows = select.query(&[] as &[&ToSql])?;
while let Some(row) = rows.next() { while let Some(row) = rows.next() {
let row = row?; let row = row?;
let id: i32 = row.get_checked(0)?; let id: i32 = row.get_checked(0)?;

View File

@ -33,7 +33,7 @@
use dir; use dir;
use failure::Error; use failure::Error;
use libc; use libc;
use rusqlite; use rusqlite::{self, types::ToSql};
use schema::DirMeta; use schema::DirMeta;
use std::fs; use std::fs;
use std::os::unix::ffi::OsStrExt; use std::os::unix::ffi::OsStrExt;
@ -122,7 +122,7 @@ pub fn run(args: &super::Args, tx: &rusqlite::Transaction) -> Result<(), Error>
tx.execute(r#" tx.execute(r#"
insert into sample_file_dir (path, uuid, last_complete_open_id) insert into sample_file_dir (path, uuid, last_complete_open_id)
values (?, ?, ?) values (?, ?, ?)
"#, &[&sample_file_path, &dir_uuid_bytes, &open_id])?; "#, &[&sample_file_path as &ToSql, &dir_uuid_bytes, &open_id])?;
tx.execute_batch(r#" tx.execute_batch(r#"
drop table reserved_sample_files; drop table reserved_sample_files;
@ -298,7 +298,7 @@ fn verify_dir_contents(sample_file_path: &str, tx: &rusqlite::Transaction) -> Re
from from
(select count(*) as c from recording) a, (select count(*) as c from recording) a,
(select count(*) as c from reserved_sample_files) b; (select count(*) as c from reserved_sample_files) b;
"#, &[], |r| r.get_checked(0))??; "#, &[] as &[&ToSql], |r| r.get_checked(0))??;
let mut files = ::fnv::FnvHashSet::with_capacity_and_hasher(n as usize, Default::default()); let mut files = ::fnv::FnvHashSet::with_capacity_and_hasher(n as usize, Default::default());
for e in fs::read_dir(sample_file_path)? { for e in fs::read_dir(sample_file_path)? {
let e = e?; let e = e?;
@ -320,7 +320,7 @@ fn verify_dir_contents(sample_file_path: &str, tx: &rusqlite::Transaction) -> Re
Ok(u) => u, Ok(u) => u,
Err(_) => bail!("unexpected file {:?} in {:?}", f, sample_file_path), Err(_) => bail!("unexpected file {:?} in {:?}", f, sample_file_path),
}; };
if s != uuid.hyphenated().to_string() { // non-canonical form. if s != uuid.to_hyphenated_ref().to_string() { // non-canonical form.
bail!("unexpected file {:?} in {:?}", f, sample_file_path); bail!("unexpected file {:?} in {:?}", f, sample_file_path);
} }
files.insert(uuid); files.insert(uuid);
@ -329,7 +329,7 @@ fn verify_dir_contents(sample_file_path: &str, tx: &rusqlite::Transaction) -> Re
// Iterate through the database and check that everything has a matching file. // Iterate through the database and check that everything has a matching file.
{ {
let mut stmt = tx.prepare(r"select sample_file_uuid from recording_playback")?; let mut stmt = tx.prepare(r"select sample_file_uuid from recording_playback")?;
let mut rows = stmt.query(&[])?; let mut rows = stmt.query(&[] as &[&ToSql])?;
while let Some(row) = rows.next() { while let Some(row) = rows.next() {
let row = row?; let row = row?;
let uuid: ::db::FromSqlUuid = row.get_checked(0)?; let uuid: ::db::FromSqlUuid = row.get_checked(0)?;
@ -340,7 +340,7 @@ fn verify_dir_contents(sample_file_path: &str, tx: &rusqlite::Transaction) -> Re
} }
let mut stmt = tx.prepare(r"select uuid from reserved_sample_files")?; let mut stmt = tx.prepare(r"select uuid from reserved_sample_files")?;
let mut rows = stmt.query(&[])?; let mut rows = stmt.query(&[] as &[&ToSql])?;
while let Some(row) = rows.next() { while let Some(row) = rows.next() {
let row = row?; let row = row?;
let uuid: ::db::FromSqlUuid = row.get_checked(0)?; let uuid: ::db::FromSqlUuid = row.get_checked(0)?;
@ -368,7 +368,7 @@ fn fix_video_sample_entry(tx: &rusqlite::Transaction) -> Result<(), Error> {
let mut insert = tx.prepare(r#" let mut insert = tx.prepare(r#"
insert into video_sample_entry values (:id, :sha1, :width, :height, :rfc6381_codec, :data) insert into video_sample_entry values (:id, :sha1, :width, :height, :rfc6381_codec, :data)
"#)?; "#)?;
let mut rows = select.query(&[])?; let mut rows = select.query(&[] as &[&ToSql])?;
while let Some(row) = rows.next() { while let Some(row) = rows.next() {
let row = row?; let row = row?;
let data: Vec<u8> = row.get_checked(4)?; let data: Vec<u8> = row.get_checked(4)?;

View File

@ -40,7 +40,7 @@ use schema;
use std::io::{self, Write}; use std::io::{self, Write};
use std::mem; use std::mem;
use std::sync::Arc; use std::sync::Arc;
use rusqlite; use rusqlite::{self, types::ToSql};
use uuid::Uuid; use uuid::Uuid;
/// Opens the sample file dir. /// Opens the sample file dir.
@ -57,7 +57,7 @@ fn open_sample_file_dir(tx: &rusqlite::Transaction) -> Result<Arc<dir::SampleFil
sample_file_dir s sample_file_dir s
join open o on (s.last_complete_open_id = o.id) join open o on (s.last_complete_open_id = o.id)
cross join meta m cross join meta m
"#, &[], |row| { "#, &[] as &[&ToSql], |row| {
(row.get_checked(0).unwrap(), (row.get_checked(0).unwrap(),
row.get_checked(1).unwrap(), row.get_checked(1).unwrap(),
row.get_checked(2).unwrap(), row.get_checked(2).unwrap(),
@ -84,7 +84,7 @@ pub fn run(_args: &super::Args, tx: &rusqlite::Transaction) -> Result<(), Error>
from from
recording_playback recording_playback
"#)?; "#)?;
let mut rows = stmt.query(&[])?; let mut rows = stmt.query(&[] as &[&ToSql])?;
while let Some(row) = rows.next() { while let Some(row) = rows.next() {
let row = row?; let row = row?;
let id = db::CompositeId(row.get_checked(0)?); let id = db::CompositeId(row.get_checked(0)?);
@ -124,7 +124,8 @@ pub fn run(_args: &super::Args, tx: &rusqlite::Transaction) -> Result<(), Error>
/// Gets a pathname for a sample file suitable for passing to open or unlink. /// Gets a pathname for a sample file suitable for passing to open or unlink.
fn get_uuid_pathname(uuid: Uuid) -> [libc::c_char; 37] { fn get_uuid_pathname(uuid: Uuid) -> [libc::c_char; 37] {
let mut buf = [0u8; 37]; let mut buf = [0u8; 37];
write!(&mut buf[..36], "{}", uuid.hyphenated()).expect("can't format uuid to pathname buf"); write!(&mut buf[..36], "{}", uuid.to_hyphenated_ref())
.expect("can't format uuid to pathname buf");
// libc::c_char seems to be i8 on some platforms (Linux/arm) and u8 on others (Linux/amd64). // libc::c_char seems to be i8 on some platforms (Linux/arm) and u8 on others (Linux/amd64).
unsafe { mem::transmute::<[u8; 37], [libc::c_char; 37]>(buf) } unsafe { mem::transmute::<[u8; 37], [libc::c_char; 37]>(buf) }

View File

@ -142,7 +142,7 @@ fn press_test(siv: &mut Cursive, t: db::StreamType) {
format!("{} stream at {}:\n\n{}", t.as_str(), url, description)) format!("{} stream at {}:\n\n{}", t.as_str(), url, description))
.title("Stream test succeeded") .title("Stream test succeeded")
.dismiss_button("Back")); .dismiss_button("Back"));
})); })).unwrap();
}); });
} }