From abcd650304740c67c20d3222af0f0381494f5210 Mon Sep 17 00:00:00 2001 From: Scott Lamb Date: Tue, 23 Mar 2021 20:22:29 -0700 Subject: [PATCH] present signal days in API requests I also enforced some invariants in the signals code, fixing a couple bugs. The signals code is more complex than I'd like, but hopefully is working now. --- design/api.md | 14 +-- server/base/time.rs | 7 ++ server/db/days.rs | 21 +++-- server/db/schema.sql | 5 +- server/db/signal.rs | 218 +++++++++++++++++++++++++++++++++++++------ server/src/json.rs | 39 +++++++- 6 files changed, 257 insertions(+), 47 deletions(-) diff --git a/design/api.md b/design/api.md index 52fbf94..dd61a80 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] } } } @@ -577,8 +580,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/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 index fc46989..f013cf8 100644 --- a/server/db/days.rs +++ b/server/db/days.rs @@ -16,8 +16,8 @@ use std::ops::Range; use std::str; /// A calendar day in `YYYY-mm-dd` format. -#[derive(Copy, Clone, Debug, Eq, Ord, PartialEq, PartialOrd)] -pub struct Key([u8; 10]); +#[derive(Copy, Clone, Eq, Ord, PartialEq, PartialOrd)] +pub struct Key(pub(crate) [u8; 10]); impl Key { fn new(tm: time::Tm) -> Result { @@ -46,6 +46,12 @@ impl AsRef for Key { } } +impl std::fmt::Debug for Key { + fn fmt(&self, f: &mut std::fmt::Formatter) -> std::fmt::Result { + write!(f, "{:?}", self.as_ref()) + } +} + pub trait Value: std::fmt::Debug + Default { type Change: std::fmt::Debug; @@ -140,14 +146,14 @@ pub struct SignalChange { duration: Duration, /// The state of the given range before this change. - old_state: i16, + old_state: u16, /// The state of the given range after this change. - new_state: i16, + new_state: u16, } -#[derive(Clone, Debug)] -pub struct Map(BTreeMap); +#[derive(Clone, Debug, Eq, PartialEq)] +pub struct Map(pub(crate) BTreeMap); impl Map { pub fn new() -> Self { @@ -253,14 +259,13 @@ impl Map { } } -#[cfg(test)] impl Map { /// Adjusts `self` to reflect the range of the given recording. /// Note that the specified range may span several days (unlike StreamValue). /// /// This function swallows/logs date formatting errors because they shouldn't happen and there's /// not much that can be done about them. (The database operation has already gone through.) - pub(crate) fn adjust(&mut self, mut r: Range