From 1e4d7d5ad95e4b61bf8de1e0ea15f6ab0424b8e0 Mon Sep 17 00:00:00 2001 From: Scott Lamb Date: Mon, 9 Oct 2017 21:58:44 -0700 Subject: [PATCH] make json api more idiomatic * camelCase * lose the "days":null in the overall cameras dict --- design/api.md | 102 +++++++++++++++++++++++++------------------------- src/json.rs | 4 ++ src/web.rs | 10 ++--- 3 files changed, 60 insertions(+), 56 deletions(-) diff --git a/design/api.md b/design/api.md index a221374..2a68d09 100644 --- a/design/api.md +++ b/design/api.md @@ -29,18 +29,18 @@ A `GET` request on this URL returns basic information about all cameras. The attributes about each camera: * `uuid`: in text format -* `short_name`: a short name (typically one or two words) +* `shortName`: a short name (typically one or two words) * `description`: a longer description (typically a phrase or paragraph) -* `retain_bytes`: the configured total number of bytes of completed +* `retainBytes`: the configured total number of bytes of completed recordings to retain. -* `min_start_time_90k`: the start time of the earliest recording for this +* `minStartTime90k`: the start time of the earliest recording for this camera, in 90kHz units since 1970-01-01 00:00:00 UTC. -* `max_end_time_90k`: the end time of the latest recording for this +* `maxEndTime90k`: the end time of the latest recording for this camera, in 90kHz units since 1970-01-01 00:00:00 UTC. -* `total_duration_90k`: the total duration recorded, in 90 kHz units. - This is no greater than `max_end_time_90k - max_start_time_90k`; it +* `totalDuration90k`: the total duration recorded, in 90 kHz units. + This is no greater than `maxEndTime90k - maxStartTime90k`; it will be lesser if there are gaps in the recorded data. -* `total_sample_file_bytes`: the total number of bytes of sample data (the +* `totalSampleFileBytes`: the total number of bytes of sample data (the `mdat` portion of a `.mp4` file). Example response: @@ -50,13 +50,13 @@ Example response: "cameras": [ { "uuid": "fd20f7a2-9d69-4cb3-94ed-d51a20c3edfe", - "short_name": "driveway", + "shortName": "driveway", "description": "Hikvision DS-2CD2032 overlooking the driveway from east", - "retain_bytes": 536870912000, - "min_start_time_90k": 130888729442361, - "max_end_time_90k": 130985466591817, - "total_duration_90k": 96736169725, - "total_sample_file_bytes": 446774393937, + "retainBytes": 536870912000, + "minStartTime90k": 130888729442361, + "maxEndTime90k": 130985466591817, + "totalDuration90k": 96736169725, + "totalSampleFileBytes": 446774393937, }, ... ], @@ -71,12 +71,12 @@ list of calendar days (in the server's time zone) with data in the server's time zone. The `days` entry is a object mapping `YYYY-mm-dd` to a day object with the following attributes: -* `total_duration_90k` is the total duration recorded during that day. +* `totalDuration90k` is the total duration recorded during that day. If a recording spans a day boundary, some portion of it is accounted to each day. -* `start_time_90k` is the start of that calendar day in the server's time +* `startTime90k` is the start of that calendar day in the server's time zone. -* `end_time_90k` is the end of that calendar day in the server's time zone. +* `endTime90k` is the end of that calendar day in the server's time zone. It is usually 24 hours after the start time. It might be 23 hours or 25 hours during spring forward or fall back, respectively. @@ -89,23 +89,23 @@ Example response: { "days": { "2016-05-01": { - "end_time_90k": 131595516000000, - "start_time_90k": 131587740000000, - "total_duration_90k": 52617609 + "endTime90k": 131595516000000, + "startTime90k": 131587740000000, + "totalDuration90k": 52617609 }, "2016-05-02": { - "end_time_90k": 131603292000000, - "start_time_90k": 131595516000000, - "total_duration_90k": 20946022 + "endTime90k": 131603292000000, + "startTime90k": 131595516000000, + "totalDuration90k": 20946022 } }, "description":"", - "max_end_time_90k": 131598273666690, - "min_start_time_90k": 131590386129355, - "retain_bytes": 104857600, - "short_name": "driveway", - "total_duration_90k": 73563631, - "total_sample_file_bytes": 98901406, + "maxEndTime90k": 131598273666690, + "minStartTime90k": 131590386129355, + "retainBytes": 104857600, + "shortName": "driveway", + "totalDuration90k": 73563631, + "totalSampleFileBytes": 98901406, } ``` @@ -115,7 +115,7 @@ A GET returns information about recordings, in descending order. Valid request parameters: -* `start_time_90k` and and `end_time_90k` limit the data returned to only +* `startTime90k` and and `endTime90k` limit the data returned to only recordings which overlap with the given half-open interval. Either or both may be absent; they default to the beginning and end of time, respectively. * TODO(slamb): `continue` to support paging. (If data is too large, the @@ -128,32 +128,32 @@ URI or as a separate `/annotations`? In the property `recordings`, returns a list of recordings in arbitrary order. Each recording object has the following properties: -* `start_id`. The id of this recording, which can be used with `/view.mp4` +* `startId`. The id of this recording, which can be used with `/view.mp4` to retrieve its content. -* `end_id` (optional). If absent, this object describes a single recording. - If present, this indicates that recordings `start_id-end_id` (inclusive) +* `endId` (optional). If absent, this object describes a single recording. + If present, this indicates that recordings `startId-endId` (inclusive) together are as described. Adjacent recordings from the same RTSP session may be coalesced in this fashion to reduce the amount of redundant data transferred. -* `start_time_90k`: the start time of the given recording. Note this may be - less than the requested `start_time_90k` if this recording was ongoing +* `startTime90k`: the start time of the given recording. Note this may be + less than the requested `startTime90k` if this recording was ongoing at the requested time. -* `end_time_90k`: the end time of the given recording. Note this may be - greater than the requested `end_time_90k` if this recording was ongoing at +* `endTime90k`: the end time of the given recording. Note this may be + greater than the requested `endTime90k` if this recording was ongoing at the requested time. -* `sample_file_bytes` -* `video_sample_entry_sha1` -* `video_sample_entry_width` -* `video_sample_entry_height` -* `video_samples`: the number of samples (aka frames) of video in this +* `sampleFileBytes` +* `videoSampleEntrySha1` +* `videoSampleEntryWidth` +* `videoSampleEntryHeight` +* `videoSamples`: the number of samples (aka frames) of video in this recording. Example request URI (with added whitespace between parameters): ``` /camera/fd20f7a2-9d69-4cb3-94ed-d51a20c3edfe/recordings - ?start_time_90k=130888729442361 - &end_time_90k=130985466591817 + ?startTime90k=130888729442361 + &endTime90k=130985466591817 ``` Example response: @@ -162,16 +162,16 @@ Example response: { "recordings": [ { - "start_id": 1, - "start_time_90k": 130985461191810, - "end_time_90k": 130985466591817, - "sample_file_bytes": 8405564, - "video_sample_entry_sha1": "81710c9c51a02cc95439caa8dd3bc12b77ffe767", - "video_sample_entry_width": 1280, - "video_sample_entry_height": 720, + "startId": 1, + "startTime90k": 130985461191810, + "endTime90k": 130985466591817, + "sampleFileBytes": 8405564, + "videoSampleEntrySha1": "81710c9c51a02cc95439caa8dd3bc12b77ffe767", + "videoSampleEntryWidth": 1280, + "videoSampleEntryHeight": 720, }, { - "end_time_90k": 130985461191810, + "endTime90k": 130985461191810, ... }, ... diff --git a/src/json.rs b/src/json.rs index 9357242..8263ca9 100644 --- a/src/json.rs +++ b/src/json.rs @@ -43,6 +43,7 @@ pub struct ListCameras<'a> { /// JSON serialization wrapper for a single camera when processing `/cameras/` and /// `/cameras//`. See `design/api.md` for details. #[derive(Debug, Serialize)] +#[serde(rename_all="camelCase")] pub struct Camera<'a> { pub uuid: Uuid, pub short_name: &'a str, @@ -53,6 +54,7 @@ pub struct Camera<'a> { pub total_duration_90k: i64, pub total_sample_file_bytes: i64, + #[serde(skip_serializing_if = "Option::is_none")] #[serde(serialize_with = "Camera::serialize_days")] pub days: Option<&'a BTreeMap>, } @@ -94,6 +96,7 @@ impl<'a> Camera<'a> { } #[derive(Debug, Serialize)] +#[serde(rename_all="camelCase")] struct CameraDayValue { pub start_time_90k: i64, pub end_time_90k: i64, @@ -120,6 +123,7 @@ pub struct ListRecordings { } #[derive(Debug, Serialize)] +#[serde(rename_all="camelCase")] pub struct Recording { pub start_time_90k: i64, pub end_time_90k: i64, diff --git a/src/web.rs b/src/web.rs index 07a956b..11b0a94 100644 --- a/src/web.rs +++ b/src/web.rs @@ -326,8 +326,8 @@ impl Service { for (key, value) in form_urlencoded::parse(q.as_bytes()) { let (key, value) = (key.borrow(), value.borrow()); match key { - "start_time" => time.start = recording::Time::parse(value)?, - "end_time" => time.end = recording::Time::parse(value)?, + "startTime" => time.start = recording::Time::parse(value)?, + "endTime" => time.end = recording::Time::parse(value)?, "trim" if value == "true" => trim = true, _ => {}, } @@ -556,7 +556,7 @@ impl Service { Ok(http_entity::serve(mp4, req)) } - /// Parses optional `start_time_90k` and `end_time_90k` query parameters, defaulting to the + /// Parses optional `startTime90k` and `endTime90k` query parameters, defaulting to the /// full range of possible values. fn get_optional_range(query: Option<&str>) -> Result, Error> { let mut start = i64::min_value(); @@ -565,8 +565,8 @@ impl Service { for (key, value) in form_urlencoded::parse(q.as_bytes()) { let (key, value) = (key.borrow(), value.borrow()); match key { - "start_time_90k" => start = i64::from_str(value)?, - "end_time_90k" => end = i64::from_str(value)?, + "startTime90k" => start = i64::from_str(value)?, + "endTime90k" => end = i64::from_str(value)?, _ => {}, } };