diff --git a/CHANGELOG.md b/CHANGELOG.md index 8fc7e6e..e5531cb 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -40,6 +40,8 @@ even on minor releases, e.g. `0.7.5` -> `0.7.6`. * get rid of live view's dreaded `ws close: 1006` error altogether. The live view WebSocket protocol now conveys errors in a way that allows the Javscript UI to see them. +* fix [#282](https://github.com/scottlamb/moonfire-nvr/issues/282): + sessions' last use information wasn't getting persisted. ## 0.7.5 (2022-05-09) diff --git a/server/Cargo.lock b/server/Cargo.lock index 820a477..a3048c1 100644 --- a/server/Cargo.lock +++ b/server/Cargo.lock @@ -1081,6 +1081,7 @@ dependencies = [ name = "moonfire-base" version = "0.0.1" dependencies = [ + "chrono", "failure", "futures", "libc", @@ -1090,6 +1091,9 @@ dependencies = [ "slab", "time 0.1.45", "tracing", + "tracing-core", + "tracing-log", + "tracing-subscriber", ] [[package]] diff --git a/server/base/Cargo.toml b/server/base/Cargo.toml index 90c5ae0..c93763f 100644 --- a/server/base/Cargo.toml +++ b/server/base/Cargo.toml @@ -13,6 +13,7 @@ nightly = [] path = "lib.rs" [dependencies] +chrono = "0.4.23" failure = "0.1.1" futures = "0.3" libc = "0.2" @@ -22,3 +23,6 @@ serde_json = "1.0" slab = "0.4" time = "0.1" tracing = "0.1.37" +tracing-core = "0.1.30" +tracing-log = "0.1.3" +tracing-subscriber = { version = "0.3.16", features = ["env-filter", "json"] } diff --git a/server/base/lib.rs b/server/base/lib.rs index 40ab9b2..577feba 100644 --- a/server/base/lib.rs +++ b/server/base/lib.rs @@ -7,5 +7,6 @@ mod error; pub mod shutdown; pub mod strutil; pub mod time; +pub mod tracing_setup; pub use crate::error::{prettify_failure, Error, ErrorKind, ResultExt}; diff --git a/server/src/tracing_setup.rs b/server/base/tracing_setup.rs similarity index 100% rename from server/src/tracing_setup.rs rename to server/base/tracing_setup.rs diff --git a/server/db/auth.rs b/server/db/auth.rs index 9023a2c..1843a40 100644 --- a/server/db/auth.rs +++ b/server/db/auth.rs @@ -831,18 +831,20 @@ impl State { ":id": &id, })?; } - for s in self.sessions.values() { + for (sh, s) in &self.sessions { if !s.dirty { continue; } let addr = s.last_use.addr_buf(); let addr: Option<&[u8]> = addr.as_ref().map(|a| a.as_ref()); - s_stmt.execute(named_params! { + let cnt = s_stmt.execute(named_params! { ":last_use_time_sec": &s.last_use.when_sec, ":last_use_user_agent": &s.last_use.user_agent, ":last_use_peer_addr": &addr, ":use_count": &s.use_count, + ":hash": &sh.0[..], })?; + debug_assert_eq!(cnt, 1); } Ok(()) } @@ -1049,6 +1051,53 @@ mod tests { ); } + /// Tests that flush works, including updating dirty sessions. + #[test] + fn flush() { + testutil::init(); + let mut conn = Connection::open_in_memory().unwrap(); + db::init(&mut conn).unwrap(); + let mut state = State::init(&conn).unwrap(); + let req = Request { + when_sec: Some(42), + addr: Some(::std::net::IpAddr::V4(::std::net::Ipv4Addr::new( + 127, 0, 0, 1, + ))), + user_agent: Some(b"some ua".to_vec()), + }; + { + let mut c = UserChange::add_user("slamb".to_owned()); + c.set_password("hunter2".to_owned()); + state.apply(&conn, c).unwrap(); + } + let (sid, _) = state + .login_by_password( + &conn, + req.clone(), + "slamb", + "hunter2".to_owned(), + Some(b"nvr.example.com".to_vec()), + 0, + ) + .unwrap(); + + let (s, _u) = state + .authenticate_session(&conn, req.clone(), &sid.hash()) + .unwrap(); + assert_eq!(s.use_count, 1); + + let mut tx = conn.transaction().unwrap(); + state.flush(&mut tx).unwrap(); + tx.commit().unwrap(); + state.post_flush(); + + // Everything should persist across reload. + drop(state); + let mut state = State::init(&conn).unwrap(); + let (s, _u) = state.authenticate_session(&conn, req, &sid.hash()).unwrap(); + assert_eq!(s.use_count, 2); + } + #[test] fn revoke_not_in_cache() { testutil::init(); diff --git a/server/db/testutil.rs b/server/db/testutil.rs index 154ffb0..eb193df 100644 --- a/server/db/testutil.rs +++ b/server/db/testutil.rs @@ -38,7 +38,7 @@ pub const TEST_VIDEO_SAMPLE_ENTRY_DATA: &[u8] = /// * use a fast but insecure password hashing format. pub fn init() { INIT.call_once(|| { - // TODO: tracing setup. + base::tracing_setup::install(); env::set_var("TZ", "America/Los_Angeles"); time::tzset(); crate::auth::set_test_config(); diff --git a/server/src/main.rs b/server/src/main.rs index f326e28..916ed0e 100644 --- a/server/src/main.rs +++ b/server/src/main.rs @@ -17,7 +17,6 @@ mod mp4; mod slices; mod stream; mod streamer; -mod tracing_setup; mod web; const DEFAULT_DB_DIR: &str = "/var/lib/moonfire-nvr/db"; @@ -71,7 +70,7 @@ fn main() { std::process::exit(1); } - tracing_setup::install(); + base::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.