From 1e17a532803402f7495ff603e39f1bddb28ce4d7 Mon Sep 17 00:00:00 2001 From: Scott Lamb Date: Thu, 28 Oct 2021 14:09:30 -0700 Subject: [PATCH] separate out signals API to own file --- server/src/web/mod.rs | 65 +--------------------------- server/src/web/signals.rs | 89 +++++++++++++++++++++++++++++++++++++++ 2 files changed, 90 insertions(+), 64 deletions(-) create mode 100644 server/src/web/signals.rs diff --git a/server/src/web/mod.rs b/server/src/web/mod.rs index 2e36f05..1ca9df9 100644 --- a/server/src/web/mod.rs +++ b/server/src/web/mod.rs @@ -5,6 +5,7 @@ mod live; mod path; mod session; +mod signals; mod static_file; mod view; @@ -224,18 +225,6 @@ impl Service { }) } - async fn signals(&self, req: Request, caller: Caller) -> ResponseResult { - match *req.method() { - Method::POST => self.post_signals(req, caller).await, - Method::GET | Method::HEAD => self.get_signals(&req), - _ => Err(plain_response( - StatusCode::METHOD_NOT_ALLOWED, - "POST, GET, or HEAD expected", - ) - .into()), - } - } - /// Serves an HTTP request. /// Note that the `serve` wrapper handles responses the same whether they /// are `Ok` or `Err`. But returning `Err` here with the `?` operator is @@ -564,58 +553,6 @@ impl Service { .unwrap_or(false) } - async fn post_signals(&self, mut req: Request, caller: Caller) -> ResponseResult { - if !caller.permissions.update_signals { - bail_t!(PermissionDenied, "update_signals required"); - } - let r = extract_json_body(&mut req).await?; - let r: json::PostSignalsRequest = - serde_json::from_slice(&r).map_err(|e| bad_req(e.to_string()))?; - let now = recording::Time::new(self.db.clocks().realtime()); - let mut l = self.db.lock(); - let start = match r.start { - json::PostSignalsTimeBase::Epoch(t) => t, - json::PostSignalsTimeBase::Now(d) => now + d, - }; - let end = match r.end { - json::PostSignalsTimeBase::Epoch(t) => t, - json::PostSignalsTimeBase::Now(d) => now + d, - }; - l.update_signals(start..end, &r.signal_ids, &r.states) - .map_err(from_base_error)?; - serve_json(&req, &json::PostSignalsResponse { time_90k: now }) - } - - fn get_signals(&self, req: &Request) -> ResponseResult { - let mut time = recording::Time::min_value()..recording::Time::max_value(); - if let Some(q) = req.uri().query() { - for (key, value) in form_urlencoded::parse(q.as_bytes()) { - let (key, value) = (key.borrow(), value.borrow()); - match key { - "startTime90k" => { - time.start = recording::Time::parse(value) - .map_err(|_| bad_req("unparseable startTime90k"))? - } - "endTime90k" => { - time.end = recording::Time::parse(value) - .map_err(|_| bad_req("unparseable endTime90k"))? - } - _ => {} - } - } - } - - let mut signals = json::Signals::default(); - self.db - .lock() - .list_changes_by_time(time, &mut |c: &db::signal::ListStateChangesRow| { - signals.times_90k.push(c.when); - signals.signal_ids.push(c.signal); - signals.states.push(c.state); - }); - serve_json(req, &signals) - } - /// Authenticates the session (if any) and returns a Caller. /// /// If there's no session, diff --git a/server/src/web/signals.rs b/server/src/web/signals.rs new file mode 100644 index 0000000..b631454 --- /dev/null +++ b/server/src/web/signals.rs @@ -0,0 +1,89 @@ +// 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. + +//! `/api/signals` handling. + +use base::{bail_t, clock::Clocks}; +use db::recording; +use http::{Method, Request, StatusCode}; +use url::form_urlencoded; + +use crate::json; + +use super::{ + bad_req, extract_json_body, from_base_error, plain_response, serve_json, Caller, + ResponseResult, Service, +}; + +use std::borrow::Borrow; + +impl Service { + pub(super) async fn signals( + &self, + req: Request, + caller: Caller, + ) -> ResponseResult { + match *req.method() { + Method::POST => self.post_signals(req, caller).await, + Method::GET | Method::HEAD => self.get_signals(&req), + _ => Err(plain_response( + StatusCode::METHOD_NOT_ALLOWED, + "POST, GET, or HEAD expected", + ) + .into()), + } + } + + async fn post_signals(&self, mut req: Request, caller: Caller) -> ResponseResult { + if !caller.permissions.update_signals { + bail_t!(PermissionDenied, "update_signals required"); + } + let r = extract_json_body(&mut req).await?; + let r: json::PostSignalsRequest = + serde_json::from_slice(&r).map_err(|e| bad_req(e.to_string()))?; + let now = recording::Time::new(self.db.clocks().realtime()); + let mut l = self.db.lock(); + let start = match r.start { + json::PostSignalsTimeBase::Epoch(t) => t, + json::PostSignalsTimeBase::Now(d) => now + d, + }; + let end = match r.end { + json::PostSignalsTimeBase::Epoch(t) => t, + json::PostSignalsTimeBase::Now(d) => now + d, + }; + l.update_signals(start..end, &r.signal_ids, &r.states) + .map_err(from_base_error)?; + serve_json(&req, &json::PostSignalsResponse { time_90k: now }) + } + + fn get_signals(&self, req: &Request) -> ResponseResult { + let mut time = recording::Time::min_value()..recording::Time::max_value(); + if let Some(q) = req.uri().query() { + for (key, value) in form_urlencoded::parse(q.as_bytes()) { + let (key, value) = (key.borrow(), value.borrow()); + match key { + "startTime90k" => { + time.start = recording::Time::parse(value) + .map_err(|_| bad_req("unparseable startTime90k"))? + } + "endTime90k" => { + time.end = recording::Time::parse(value) + .map_err(|_| bad_req("unparseable endTime90k"))? + } + _ => {} + } + } + } + + let mut signals = json::Signals::default(); + self.db + .lock() + .list_changes_by_time(time, &mut |c: &db::signal::ListStateChangesRow| { + signals.times_90k.push(c.when); + signals.signal_ids.push(c.signal); + signals.states.push(c.state); + }); + serve_json(req, &signals) + } +}