diff --git a/CHANGELOG.md b/CHANGELOG.md index 6e49053..9a94f2c 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -6,6 +6,14 @@ changes, see Git history. Each release is tagged in Git and on the Docker repository [`scottlamb/moonfire-nvr`](https://hub.docker.com/r/scottlamb/moonfire-nvr). +## `v0.6.3` (in progress) + +* Compile fix for nightly rust 2021-03-14 and beyond. +* Fix incorrect `prev_media_duration_90k` calculation. No current impact. + This field is intended to be used in an upcoming scrub bar UI, and when + not calculated properly there might be unexpected gaps or overlaps in + playback. + ## `v0.6.2` * Fix panics when a stream's PTS has extreme jumps diff --git a/design/api.md b/design/api.md index 39bbd70..922bb9d 100644 --- a/design/api.md +++ b/design/api.md @@ -91,7 +91,7 @@ The `application/json` response will have a dict as follows: this stream. This is slightly more than `totalSampleFileBytes` because it also includes the wasted portion of the final filesystem block allocated to each file. - * `days`: (only included if request pararameter `days` is true) + * `days`: (only included if request parameter `days` is true) dictionary representing calendar days (in the server's time zone) with non-zero total duration of recordings for that day. Currently this includes uncommitted and growing recordings. This is likely @@ -118,8 +118,11 @@ The `application/json` response will have a dict as follows: * `cameras`: a map of associated cameras' UUIDs to the type of association: `direct` or `indirect`. See `db/schema.sql` for more description. * `type`: a UUID, expected to match one of `signalTypes`. - * `days`: as in `cameras.streams.days` above. - **status: unimplemented** + * `days`: (only included if request parameter `days` is true) similar to + `cameras.days` above. Values are objects with the following attributes: + * `states`: an array of the time the signal is in each state, starting + from 1. These may not sum to the entire day; if so, the rest of the + day is in state 0 (`unknown`). * `signalTypes`: a list of all known signal types. * `uuid`: in text format. * `states`: a map of all possible states of the enumeration to more @@ -183,7 +186,7 @@ Example response: "2016-05-01": { "endTime90k": 131595516000000, "startTime90k": 131587740000000, - "totalDuration90k": 5400000 + "states": [5400000] } } } @@ -487,6 +490,8 @@ followed by by a `.mp4` media segment. The following headers will be included: * `X-Media-Time-Range`: the relative media start and end times of these frames within the recording, as a half-open interval. +The server will also send pings, currently at 30-second intervals. + The WebSocket will always open immediately but will receive messages only while the backing RTSP stream is connected. @@ -577,8 +582,7 @@ Valid request parameters: This will return the current state as of the latest change (to any signal) before the start time (if any), then all changes in the interval. This allows the caller to determine the state at every moment during the - selected timespan, as well as observe all events (even instantaneous - ones). + selected timespan, as well as observe all events. Responses are several parallel arrays for each observation: diff --git a/server/Cargo.lock b/server/Cargo.lock index 173fd40..4dd584d 100644 --- a/server/Cargo.lock +++ b/server/Cargo.lock @@ -1016,13 +1016,13 @@ checksum = "e2abad23fbc42b3700f2f279844dc832adb2b2eb069b2df918f455c4e18cc646" [[package]] name = "lexical-core" -version = "0.7.4" +version = "0.7.5" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "db65c6da02e61f55dae90a0ae427b2a5f6b3e8db09f58d10efab23af92592616" +checksum = "21f866863575d0e1d654fbeeabdc927292fdf862873dc3c96c6f753357e13374" dependencies = [ "arrayvec 0.5.2", "bitflags", - "cfg-if 0.1.10", + "cfg-if 1.0.0", "ryu", "static_assertions", ] @@ -1256,6 +1256,7 @@ dependencies = [ "tempdir", "time", "tokio", + "tokio-stream", "tokio-tungstenite", "url", "uuid", @@ -1629,12 +1630,12 @@ dependencies = [ [[package]] name = "protobuf" version = "3.0.0-pre" -source = "git+https://github.com/stepancheg/rust-protobuf#5f3ed259acf9ae42014e4e49f7c4d62917685584" +source = "git+https://github.com/stepancheg/rust-protobuf#c27743ae4ce421f5d9a61ef0d1885eface278d6c" [[package]] name = "protobuf-codegen" version = "3.0.0-pre" -source = "git+https://github.com/stepancheg/rust-protobuf#5f3ed259acf9ae42014e4e49f7c4d62917685584" +source = "git+https://github.com/stepancheg/rust-protobuf#c27743ae4ce421f5d9a61ef0d1885eface278d6c" dependencies = [ "protobuf", ] @@ -1642,7 +1643,7 @@ dependencies = [ [[package]] name = "protobuf-codegen-pure" version = "3.0.0-pre" -source = "git+https://github.com/stepancheg/rust-protobuf#5f3ed259acf9ae42014e4e49f7c4d62917685584" +source = "git+https://github.com/stepancheg/rust-protobuf#c27743ae4ce421f5d9a61ef0d1885eface278d6c" dependencies = [ "protobuf", "protobuf-codegen", @@ -2354,9 +2355,9 @@ checksum = "cda74da7e1a664f795bb1f8a87ec406fb89a02522cf6e50620d016add6dbbf5c" [[package]] name = "tokio" -version = "1.1.0" +version = "1.4.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8efab2086f17abcddb8f756117665c958feee6b2e39974c2f1600592ab3a4195" +checksum = "134af885d758d645f0f0505c9a8b3f9bf8a348fd822e112ab5248138348f1722" dependencies = [ "autocfg", "bytes", @@ -2374,9 +2375,9 @@ dependencies = [ [[package]] name = "tokio-macros" -version = "1.0.0" +version = "1.1.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "42517d2975ca3114b22a16192634e8241dc5cc1f130be194645970cc1c371494" +checksum = "caf7b11a536f46a809a8a9f0bb4237020f70ecbf115b842360afb127ea2fda57" dependencies = [ "proc-macro2 1.0.24", "quote 1.0.8", @@ -2385,9 +2386,9 @@ dependencies = [ [[package]] name = "tokio-stream" -version = "0.1.2" +version = "0.1.5" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "76066865172052eb8796c686f0b441a93df8b08d40a950b062ffb9a426f00edd" +checksum = "e177a5d8c3bf36de9ebe6d58537d8879e964332f93fb3339e43f618c81361af0" dependencies = [ "futures-core", "pin-project-lite", diff --git a/server/Cargo.toml b/server/Cargo.toml index b0ee0e8..3bcdf6c 100644 --- a/server/Cargo.toml +++ b/server/Cargo.toml @@ -57,7 +57,8 @@ smallvec = "1.0" structopt = { version = "0.3.13", features = ["default", "wrap_help"] } sync_wrapper = "0.1.0" time = "0.1" -tokio = { version = "1.0", features = ["macros", "parking_lot", "rt-multi-thread", "signal"] } +tokio = { version = "1.0", features = ["macros", "parking_lot", "rt-multi-thread", "signal", "time"] } +tokio-stream = "0.1.5" tokio-tungstenite = "0.13.0" url = "2.1.1" uuid = { version = "0.8", features = ["serde", "std", "v4"] } diff --git a/server/base/time.rs b/server/base/time.rs index 75c8fa5..e6e6cd8 100644 --- a/server/base/time.rs +++ b/server/base/time.rs @@ -281,6 +281,13 @@ impl fmt::Display for Duration { } } +impl ops::Mul for Duration { + type Output = Self; + fn mul(self, rhs: i64) -> Self::Output { + Duration(self.0 * rhs) + } +} + impl ops::Add for Duration { type Output = Duration; fn add(self, rhs: Duration) -> Duration { diff --git a/server/db/days.rs b/server/db/days.rs new file mode 100644 index 0000000..f013cf8 --- /dev/null +++ b/server/db/days.rs @@ -0,0 +1,530 @@ +// 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. + +//! In-memory indexes by calendar day. + +use base::time::{Duration, Time, TIME_UNITS_PER_SEC}; +use failure::Error; +use log::{error, trace}; +use smallvec::SmallVec; +use std::cmp; +use std::collections::BTreeMap; +use std::convert::TryFrom; +use std::io::Write; +use std::ops::Range; +use std::str; + +/// A calendar day in `YYYY-mm-dd` format. +#[derive(Copy, Clone, Eq, Ord, PartialEq, PartialOrd)] +pub struct Key(pub(crate) [u8; 10]); + +impl Key { + fn new(tm: time::Tm) -> Result { + let mut s = Key([0u8; 10]); + write!(&mut s.0[..], "{}", tm.strftime("%Y-%m-%d")?)?; + Ok(s) + } + + pub fn bounds(&self) -> Range