populate timeZoneName as expected by UI

This works by a nasty hack, but it seems to work well enough for now.
Fingers crossed.
This commit is contained in:
Scott Lamb 2017-10-21 23:57:13 -07:00
parent 2966cf59b0
commit 8de7e391f8
3 changed files with 30 additions and 8 deletions

View File

@ -42,6 +42,11 @@ use tokio_core::reactor;
use tokio_signal::unix::{Signal, SIGINT, SIGTERM};
use web;
// These are used in a hack to get the name of the current time zone (e.g. America/Los_Angeles).
// They seem to be correct for Linux and OS X at least.
const LOCALTIME_PATH: &'static str = "/etc/localtime";
const ZONEINFO_PATH: &'static str = "/usr/share/zoneinfo/";
const USAGE: &'static str = r#"
Usage: moonfire-nvr run [options]
@ -77,6 +82,16 @@ fn setup_shutdown_future(h: &reactor::Handle) -> Box<Future<Item = (), Error = (
.map_err(|_| ()))
}
fn resolve_zone() -> String {
let p = ::std::fs::read_link(LOCALTIME_PATH).expect("unable to read localtime symlink");
let p = p.to_str().expect("localtime symlink destination must be valid UTF-8");
if !p.starts_with(ZONEINFO_PATH) {
panic!("Expected {} to point to a path within {}; actually points to {}",
LOCALTIME_PATH, ZONEINFO_PATH, p);
}
p[ZONEINFO_PATH.len()..].into()
}
pub fn run() -> Result<(), Error> {
let args: Args = super::parse_args(USAGE)?;
let (_db_dir, conn) = super::open_conn(
@ -86,7 +101,7 @@ pub fn run() -> Result<(), Error> {
let dir = dir::SampleFileDir::new(&args.flag_sample_file_dir, db.clone()).unwrap();
info!("Database is loaded.");
let s = web::Service::new(db.clone(), dir.clone(), Some(&args.flag_ui_dir))?;
let s = web::Service::new(db.clone(), dir.clone(), Some(&args.flag_ui_dir), resolve_zone())?;
// Start a streamer for each camera.
let shutdown_streamers = Arc::new(AtomicBool::new(false));

View File

@ -34,10 +34,13 @@ use std::collections::BTreeMap;
use uuid::Uuid;
#[derive(Debug, Serialize)]
pub struct ListCameras<'a> {
#[serde(rename_all="camelCase")]
pub struct TopLevel<'a> {
pub time_zone_name: &'a str,
// Use a custom serializer which presents the map's values as a sequence and includes the
// "days" attribute or not, according to the bool in the tuple.
#[serde(serialize_with = "ListCameras::serialize_cameras")]
#[serde(serialize_with = "TopLevel::serialize_cameras")]
pub cameras: (&'a BTreeMap<i32, db::Camera>, bool),
}
@ -104,9 +107,8 @@ struct CameraDayValue {
pub total_duration_90k: i64,
}
impl<'a> ListCameras<'a> {
/// Serializes cameras as a list (rather than a map), wrapping each camera in the
/// `ListCamerasCamera` type to tweak the data returned.
impl<'a> TopLevel<'a> {
/// Serializes cameras as a list (rather than a map), optionally including the `days` field.
fn serialize_cameras<S>(cameras: &(&BTreeMap<i32, db::Camera>, bool),
serializer: S) -> Result<S::Ok, S::Error>
where S: Serializer {

View File

@ -172,6 +172,7 @@ struct ServiceInner {
dir: Arc<SampleFileDir>,
ui_files: HashMap<String, UiFile>,
pool: futures_cpupool::CpuPool,
time_zone_name: String,
}
impl ServiceInner {
@ -197,7 +198,10 @@ impl ServiceInner {
let buf = {
let db = self.db.lock();
serde_json::to_vec(&json::ListCameras{cameras: (db.cameras_by_id(), days)})?
serde_json::to_vec(&json::TopLevel {
time_zone_name: &self.time_zone_name,
cameras: (db.cameras_by_id(), days),
})?
};
let len = buf.len();
let body: slices::Body = Box::new(stream::once(Ok(ARefs::new(buf))));
@ -390,7 +394,7 @@ impl ServiceInner {
pub struct Service(Arc<ServiceInner>);
impl Service {
pub fn new(db: Arc<db::Database>, dir: Arc<SampleFileDir>, ui_dir: Option<&str>)
pub fn new(db: Arc<db::Database>, dir: Arc<SampleFileDir>, ui_dir: Option<&str>, zone: String)
-> Result<Self, Error> {
let mut ui_files = HashMap::new();
if let Some(d) = ui_dir {
@ -402,6 +406,7 @@ impl Service {
dir,
ui_files,
pool: futures_cpupool::Builder::new().pool_size(1).name_prefix("static").create(),
time_zone_name: zone,
})))
}