mirror of
https://github.com/scottlamb/moonfire-nvr.git
synced 2025-04-16 09:08:01 -04:00
make json api more idiomatic
* camelCase * lose the "days":null in the overall cameras dict
This commit is contained in:
parent
5bb3dde74e
commit
1e4d7d5ad9
102
design/api.md
102
design/api.md
@ -29,18 +29,18 @@ A `GET` request on this URL returns basic information about all cameras. The
|
|||||||
attributes about each camera:
|
attributes about each camera:
|
||||||
|
|
||||||
* `uuid`: in text format
|
* `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)
|
* `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.
|
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.
|
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.
|
camera, in 90kHz units since 1970-01-01 00:00:00 UTC.
|
||||||
* `total_duration_90k`: the total duration recorded, in 90 kHz units.
|
* `totalDuration90k`: the total duration recorded, in 90 kHz units.
|
||||||
This is no greater than `max_end_time_90k - max_start_time_90k`; it
|
This is no greater than `maxEndTime90k - maxStartTime90k`; it
|
||||||
will be lesser if there are gaps in the recorded data.
|
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).
|
`mdat` portion of a `.mp4` file).
|
||||||
|
|
||||||
Example response:
|
Example response:
|
||||||
@ -50,13 +50,13 @@ Example response:
|
|||||||
"cameras": [
|
"cameras": [
|
||||||
{
|
{
|
||||||
"uuid": "fd20f7a2-9d69-4cb3-94ed-d51a20c3edfe",
|
"uuid": "fd20f7a2-9d69-4cb3-94ed-d51a20c3edfe",
|
||||||
"short_name": "driveway",
|
"shortName": "driveway",
|
||||||
"description": "Hikvision DS-2CD2032 overlooking the driveway from east",
|
"description": "Hikvision DS-2CD2032 overlooking the driveway from east",
|
||||||
"retain_bytes": 536870912000,
|
"retainBytes": 536870912000,
|
||||||
"min_start_time_90k": 130888729442361,
|
"minStartTime90k": 130888729442361,
|
||||||
"max_end_time_90k": 130985466591817,
|
"maxEndTime90k": 130985466591817,
|
||||||
"total_duration_90k": 96736169725,
|
"totalDuration90k": 96736169725,
|
||||||
"total_sample_file_bytes": 446774393937,
|
"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
|
time zone. The `days` entry is a object mapping `YYYY-mm-dd` to a day object
|
||||||
with the following attributes:
|
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
|
If a recording spans a day boundary, some portion of it is accounted to
|
||||||
each day.
|
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.
|
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
|
It is usually 24 hours after the start time. It might be 23 hours or 25
|
||||||
hours during spring forward or fall back, respectively.
|
hours during spring forward or fall back, respectively.
|
||||||
|
|
||||||
@ -89,23 +89,23 @@ Example response:
|
|||||||
{
|
{
|
||||||
"days": {
|
"days": {
|
||||||
"2016-05-01": {
|
"2016-05-01": {
|
||||||
"end_time_90k": 131595516000000,
|
"endTime90k": 131595516000000,
|
||||||
"start_time_90k": 131587740000000,
|
"startTime90k": 131587740000000,
|
||||||
"total_duration_90k": 52617609
|
"totalDuration90k": 52617609
|
||||||
},
|
},
|
||||||
"2016-05-02": {
|
"2016-05-02": {
|
||||||
"end_time_90k": 131603292000000,
|
"endTime90k": 131603292000000,
|
||||||
"start_time_90k": 131595516000000,
|
"startTime90k": 131595516000000,
|
||||||
"total_duration_90k": 20946022
|
"totalDuration90k": 20946022
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
"description":"",
|
"description":"",
|
||||||
"max_end_time_90k": 131598273666690,
|
"maxEndTime90k": 131598273666690,
|
||||||
"min_start_time_90k": 131590386129355,
|
"minStartTime90k": 131590386129355,
|
||||||
"retain_bytes": 104857600,
|
"retainBytes": 104857600,
|
||||||
"short_name": "driveway",
|
"shortName": "driveway",
|
||||||
"total_duration_90k": 73563631,
|
"totalDuration90k": 73563631,
|
||||||
"total_sample_file_bytes": 98901406,
|
"totalSampleFileBytes": 98901406,
|
||||||
}
|
}
|
||||||
```
|
```
|
||||||
|
|
||||||
@ -115,7 +115,7 @@ A GET returns information about recordings, in descending order.
|
|||||||
|
|
||||||
Valid request parameters:
|
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
|
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.
|
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
|
* 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.
|
In the property `recordings`, returns a list of recordings in arbitrary order.
|
||||||
Each recording object has the following properties:
|
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.
|
to retrieve its content.
|
||||||
* `end_id` (optional). If absent, this object describes a single recording.
|
* `endId` (optional). If absent, this object describes a single recording.
|
||||||
If present, this indicates that recordings `start_id-end_id` (inclusive)
|
If present, this indicates that recordings `startId-endId` (inclusive)
|
||||||
together are as described. Adjacent recordings from the same RTSP session
|
together are as described. Adjacent recordings from the same RTSP session
|
||||||
may be coalesced in this fashion to reduce the amount of redundant data
|
may be coalesced in this fashion to reduce the amount of redundant data
|
||||||
transferred.
|
transferred.
|
||||||
* `start_time_90k`: the start time of the given recording. Note this may be
|
* `startTime90k`: the start time of the given recording. Note this may be
|
||||||
less than the requested `start_time_90k` if this recording was ongoing
|
less than the requested `startTime90k` if this recording was ongoing
|
||||||
at the requested time.
|
at the requested time.
|
||||||
* `end_time_90k`: the end time of the given recording. Note this may be
|
* `endTime90k`: the end time of the given recording. Note this may be
|
||||||
greater than the requested `end_time_90k` if this recording was ongoing at
|
greater than the requested `endTime90k` if this recording was ongoing at
|
||||||
the requested time.
|
the requested time.
|
||||||
* `sample_file_bytes`
|
* `sampleFileBytes`
|
||||||
* `video_sample_entry_sha1`
|
* `videoSampleEntrySha1`
|
||||||
* `video_sample_entry_width`
|
* `videoSampleEntryWidth`
|
||||||
* `video_sample_entry_height`
|
* `videoSampleEntryHeight`
|
||||||
* `video_samples`: the number of samples (aka frames) of video in this
|
* `videoSamples`: the number of samples (aka frames) of video in this
|
||||||
recording.
|
recording.
|
||||||
|
|
||||||
Example request URI (with added whitespace between parameters):
|
Example request URI (with added whitespace between parameters):
|
||||||
|
|
||||||
```
|
```
|
||||||
/camera/fd20f7a2-9d69-4cb3-94ed-d51a20c3edfe/recordings
|
/camera/fd20f7a2-9d69-4cb3-94ed-d51a20c3edfe/recordings
|
||||||
?start_time_90k=130888729442361
|
?startTime90k=130888729442361
|
||||||
&end_time_90k=130985466591817
|
&endTime90k=130985466591817
|
||||||
```
|
```
|
||||||
|
|
||||||
Example response:
|
Example response:
|
||||||
@ -162,16 +162,16 @@ Example response:
|
|||||||
{
|
{
|
||||||
"recordings": [
|
"recordings": [
|
||||||
{
|
{
|
||||||
"start_id": 1,
|
"startId": 1,
|
||||||
"start_time_90k": 130985461191810,
|
"startTime90k": 130985461191810,
|
||||||
"end_time_90k": 130985466591817,
|
"endTime90k": 130985466591817,
|
||||||
"sample_file_bytes": 8405564,
|
"sampleFileBytes": 8405564,
|
||||||
"video_sample_entry_sha1": "81710c9c51a02cc95439caa8dd3bc12b77ffe767",
|
"videoSampleEntrySha1": "81710c9c51a02cc95439caa8dd3bc12b77ffe767",
|
||||||
"video_sample_entry_width": 1280,
|
"videoSampleEntryWidth": 1280,
|
||||||
"video_sample_entry_height": 720,
|
"videoSampleEntryHeight": 720,
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"end_time_90k": 130985461191810,
|
"endTime90k": 130985461191810,
|
||||||
...
|
...
|
||||||
},
|
},
|
||||||
...
|
...
|
||||||
|
@ -43,6 +43,7 @@ pub struct ListCameras<'a> {
|
|||||||
/// JSON serialization wrapper for a single camera when processing `/cameras/` and
|
/// JSON serialization wrapper for a single camera when processing `/cameras/` and
|
||||||
/// `/cameras/<uuid>/`. See `design/api.md` for details.
|
/// `/cameras/<uuid>/`. See `design/api.md` for details.
|
||||||
#[derive(Debug, Serialize)]
|
#[derive(Debug, Serialize)]
|
||||||
|
#[serde(rename_all="camelCase")]
|
||||||
pub struct Camera<'a> {
|
pub struct Camera<'a> {
|
||||||
pub uuid: Uuid,
|
pub uuid: Uuid,
|
||||||
pub short_name: &'a str,
|
pub short_name: &'a str,
|
||||||
@ -53,6 +54,7 @@ pub struct Camera<'a> {
|
|||||||
pub total_duration_90k: i64,
|
pub total_duration_90k: i64,
|
||||||
pub total_sample_file_bytes: i64,
|
pub total_sample_file_bytes: i64,
|
||||||
|
|
||||||
|
#[serde(skip_serializing_if = "Option::is_none")]
|
||||||
#[serde(serialize_with = "Camera::serialize_days")]
|
#[serde(serialize_with = "Camera::serialize_days")]
|
||||||
pub days: Option<&'a BTreeMap<db::CameraDayKey, db::CameraDayValue>>,
|
pub days: Option<&'a BTreeMap<db::CameraDayKey, db::CameraDayValue>>,
|
||||||
}
|
}
|
||||||
@ -94,6 +96,7 @@ impl<'a> Camera<'a> {
|
|||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Debug, Serialize)]
|
#[derive(Debug, Serialize)]
|
||||||
|
#[serde(rename_all="camelCase")]
|
||||||
struct CameraDayValue {
|
struct CameraDayValue {
|
||||||
pub start_time_90k: i64,
|
pub start_time_90k: i64,
|
||||||
pub end_time_90k: i64,
|
pub end_time_90k: i64,
|
||||||
@ -120,6 +123,7 @@ pub struct ListRecordings {
|
|||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Debug, Serialize)]
|
#[derive(Debug, Serialize)]
|
||||||
|
#[serde(rename_all="camelCase")]
|
||||||
pub struct Recording {
|
pub struct Recording {
|
||||||
pub start_time_90k: i64,
|
pub start_time_90k: i64,
|
||||||
pub end_time_90k: i64,
|
pub end_time_90k: i64,
|
||||||
|
10
src/web.rs
10
src/web.rs
@ -326,8 +326,8 @@ impl Service {
|
|||||||
for (key, value) in form_urlencoded::parse(q.as_bytes()) {
|
for (key, value) in form_urlencoded::parse(q.as_bytes()) {
|
||||||
let (key, value) = (key.borrow(), value.borrow());
|
let (key, value) = (key.borrow(), value.borrow());
|
||||||
match key {
|
match key {
|
||||||
"start_time" => time.start = recording::Time::parse(value)?,
|
"startTime" => time.start = recording::Time::parse(value)?,
|
||||||
"end_time" => time.end = recording::Time::parse(value)?,
|
"endTime" => time.end = recording::Time::parse(value)?,
|
||||||
"trim" if value == "true" => trim = true,
|
"trim" if value == "true" => trim = true,
|
||||||
_ => {},
|
_ => {},
|
||||||
}
|
}
|
||||||
@ -556,7 +556,7 @@ impl Service {
|
|||||||
Ok(http_entity::serve(mp4, req))
|
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.
|
/// full range of possible values.
|
||||||
fn get_optional_range(query: Option<&str>) -> Result<Range<recording::Time>, Error> {
|
fn get_optional_range(query: Option<&str>) -> Result<Range<recording::Time>, Error> {
|
||||||
let mut start = i64::min_value();
|
let mut start = i64::min_value();
|
||||||
@ -565,8 +565,8 @@ impl Service {
|
|||||||
for (key, value) in form_urlencoded::parse(q.as_bytes()) {
|
for (key, value) in form_urlencoded::parse(q.as_bytes()) {
|
||||||
let (key, value) = (key.borrow(), value.borrow());
|
let (key, value) = (key.borrow(), value.borrow());
|
||||||
match key {
|
match key {
|
||||||
"start_time_90k" => start = i64::from_str(value)?,
|
"startTime90k" => start = i64::from_str(value)?,
|
||||||
"end_time_90k" => end = i64::from_str(value)?,
|
"endTime90k" => end = i64::from_str(value)?,
|
||||||
_ => {},
|
_ => {},
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
Loading…
x
Reference in New Issue
Block a user