Commit Graph

494 Commits

Author SHA1 Message Date
Scott Lamb
04ab8cdc7d more readable async web code
This uses "async fn" throughout rather than a mix of async and the older
futures style. And it takes advantage of the "self: Arc<Self>" syntax
to avoid having a ServiceInner. It was confusing to have some methods
on Service and some on ServiceInner; now that distinction is gone.

One downside is there's a little more atomic reference-counting. Before,
service_fn essentially took an &Arc<Self>, which means it could call
Arc::clone where its use of self actually outlived the future (see
stream_live_m4s) but didn't need to otherwise. After, it calls
an async fn that takes Arc<Self>. Using &Arc<Self> is apparently
possible (as of Rust 1.41) but using that with "async fn" means the
returned future is tied to its lifetime. The workaround is to use
async blocks as described here:
<https://rust-lang.github.io/async-book/03_async_await/01_chapter.html>
but that's really ugly: it brings back the explicit Future reference,
requires futures::future::Either in some cases, and introduces another
level of indenting. I think it's better to just pay the arc costs which
are probably negligible, or at least cheaper than the boxing was before.

Oh, and I make this compile on Rust 1.40 again as it claimed to.
http-serve accidentally used the &Arc<Self> thing which broke this.
Update to a freshly-pushed commit which doesn't do that.
2020-05-30 21:34:37 -07:00
Scott Lamb
45abeb22de overhaul HTTP serving and caching
* use content-hashed paths for static resources (except the top-level
  request), with immutable Cache-Control headers. This should improve
  cache behavior in both directions: avoid preventable HTTP requests and
  cause immediate refresh when needed. I had some staleness when
  browsing with my phone.

* set up the favicons properly while I'm at it (closes #50). I used the
  convenient favicons-webpack-plugin to build everything from a .svg.
  I've hit an error similar to lovell/sharp#1593 at least once though so
  I might change my mind about that part if it continues to be
  problematic.

* use http-serve's new directory traversal code for static file serving.
  This removes the odd behavior where files that weren't present at
  server startup couldn't be served. (I wasn't comfortable switching to
  the content-hashed paths before doing this.) It also means the static
  files can be served compressed. JSON API responses were already served
  compressed, so this closes #25.

* for a given API URL, decide if we want it to be cached or not
  server-side. Stop using jQuery's kludgy cache-defeating _=<timestamp>
  URL parameter. I might start setting etags on some of these things
  and could serve 304 Not Modified responses if it's genuinely
  unmodified.
2020-05-29 21:20:15 -07:00
Scott Lamb
88fe6e5135 fix description of MOONFIRE_DEV_HOST 2020-05-08 19:29:47 -07:00
Scott Lamb
ae5b840fae update all js deps
This addresses this error travis-ci builds have been hitting:

Error: Cannot find module '@babel/compat-data/corejs3-shipped-proposals'
https://travis-ci.org/github/scottlamb/moonfire-nvr/jobs/684922930
https://github.com/nodejs/node/issues/32852#issuecomment-613655150
2020-05-08 19:25:45 -07:00
Scott Lamb
150556e105 fix js lint errors 2020-05-08 18:44:02 -07:00
Scott Lamb
c7c0d5a6c1 Merge branch 'master' into new-schema 2020-05-08 16:33:49 -07:00
Scott Lamb
e177cbd042 improve mobile-friendliness (#68)
nav div changes:
* make it togglable (on all devices) by hamburger button
* on narrow devices, make it closed by default and
  be at the top rather than on the left

open zoomed by default

trim some arguably less important columns on narrow displays,
and reduce some horizontal padding

always show videos full-screen on narrow displays
2020-05-04 23:36:24 -07:00
Scott Lamb
1b464fd555 nav div changes for narrow devices
* make it togglable (on all devices) by hamburger button
* on narrow devices, make it closed by default and
  be at the top rather than on the left

Improves #68 significantly
2020-05-04 18:06:12 -07:00
Scott Lamb
be479a1ffe consistently indent css by 2 spaces
matching the Google CSS style guide
2020-05-04 16:46:26 -07:00
Scott Lamb
482d8a3074 use mylog::Format::from_str 2020-04-21 22:19:17 -07:00
Scott Lamb
474d96803c Merge branch 'master' into new-schema 2020-04-19 22:53:42 -07:00
Scott Lamb
de56739571 upgrade deps
Both a "cargo update" and a bump of major versions of a few deps.
I left a few alone:

* base64 because some of the deps depend on 0.11 (and 0.9), so I don't
  want to pull in a third version (0.12).
* ring because libpasta depends on this version and I don't want to pull
  in two of them.
* time because it's not trivial. Last I checked, time 0.2 couldn't even
  do what I wanted at all.

I also made tokio use parking_lot, since I pull it in anyway.
2020-04-19 22:19:57 -07:00
Scott Lamb
618d0d71be Merge branch 'master' into new-schema 2020-04-17 23:33:46 -07:00
Scott Lamb
af9e568344 replace regex use with nom
This reduces the binary size noticeably on my macOS machine (#70):

                             unstripped  stripped
1  before switching to clap    11.1 MiB   6.7 MiB
2  after switching to clap     11.4 MiB   6.9 MiB
3  without regex               10.1 MiB   5.9 MiB
2020-04-17 21:53:52 -07:00
Scott Lamb
e8eb764b90 switch from docopt to structopt
A couple reasons for this:

* the docopt crate is "unlikely to see significant future evolution",
  and the wider docopt project is "mostly unmaintained at this point".
  clap/structopt is more full-featured, has more natural subcommand
  support, etc.

* it may allow me to shrink the binary (#70). This change alone seems
  to be a slight regression, but it's a step toward getting rid of
  regex, which is pretty large. And I feel less ridiculous now that I
  don't have two parsing crates anyway; prettydiff was pulling in
  structopt.

There are some behavior changes here:

* misc --help output changes and such as you'd expect from switching
  argument-parsing libraries

* I properly used PathBuf and OsString for stuff that theoretically
  could be non-UTF-8. I haven't tested that it actually made any
  difference. I'm also still storing the sample file dirname as "text"
  in the database to avoid causing a diff when not doing a schema
  change.
2020-04-17 21:53:37 -07:00
Scott Lamb
9d7cdc0954 cleanup: s/unflushed sample/unindexed sample/
db/writer.rs used the word "unflushed" in two ways:

* something which has been communicated to the LockedDatabase object but
  not yet committed to disk with SQLite.

* a video sample (aka video frame) which has been written to the sample
  file but not yet included in the video index. This happens because the
  duration of a frame isn't known until the following frame. These are
  always also unflushed in the other sense of the word (as unfinished
  recordings are never committed). But they can't be seen by clients at
  all, where indexed but uncommitted video frames can.

Replace the latter with "unindexed" to make things more clear. And a
couple minor other style cleanups.
2020-04-14 23:09:34 -07:00
Scott Lamb
3ed397bacd first step toward object detection (#30)
When compiled with cargo build --features=analytics and enabled via
moonfire-nvr run --object-detection, this runs object detection on every
sub stream frame through an Edge TPU (a Coral USB accelerator) and logs
the result.

This is a very small step toward a working system. It doesn't actually
record the result in the database or send it out on the live stream yet.
It doesn't support running object detection at a lower frame rate than
the sub streams come in at either. To address those problems, I need to
do some refactoring. Currently moonfire_db::writer::Writer::Write is the
only place that knows the duration of the frame it's about to flush,
before it gets added to the index or sent out on the live stream. I
don't want to do the detection from there; I'd prefer the moonfire_nvr
crate. So I either need to introduce an analytics callback or move a
bunch of that logic to the other crate.

Once I do that, I need to add database support (although I have some
experiments for that in moonfire-playground) and API support, then some
kind of useful frontend.

Note edgetpu.tflite is taken from the Apache 2.0-licensed
https://github.com/google-coral/edgetpu,
test_data/mobilenet_ssd_v2_coco_quant_postprocess_edgetpu.tflite. The
following page says it's fine to include Apache 2.0 stuff in GPLv3
projects:
https://www.apache.org/licenses/GPL-compatibility.html
2020-04-13 23:03:49 -07:00
Scott Lamb
ad13935ed6 use extracted ffmpeg library 2020-03-28 00:59:25 -07:00
Scott Lamb
c6fe1b66a1 add a preliminary schema for object detection (#30) 2020-03-25 18:10:37 -07:00
Scott Lamb
00991733f2 use Blake3 instead of SHA-1 or Blake2b
Benefits:

* Blake3 is faster. This is most noticeable for the hashing of the
  sample file data.
* we no longer need OpenSSL, which helps with shrinking the binary size
  (#70). sha1 basically forced OpenSSL usage; ring deliberately doesn't
  support this old algorithm, and the pure-Rust sha1 crate is painfully
  slow. OpenSSL might still be a better choice than ring/rustls for TLS
  but it's nice to have the option.

For the video sample entries, I decided we don't need to hash at all. I
think the id number is sufficiently stable, and it's okay---perhaps even
desirable---if an existing init segment changes for fixes like e5b83c2.
2020-03-20 21:46:53 -07:00
Scott Lamb
e5b83c21e1 schema version 6 with pixel aspect ratio
This makes anamorphic sub streams display correctly, even ones from old
Hikvision cameras that don't properly set the aspect ratio at the H.264
layer.
2020-03-19 21:40:59 -07:00
Scott Lamb
066c086050 style: use rusqlite's {named_,}params! everywhere 2020-03-19 20:46:25 -07:00
Scott Lamb
9d6dec2565 fix incorrect Javascript private variable style
It's supposed to be a trailing underscore, not a leading underscore, as
described here:

https://google.github.io/styleguide/jsguide.html#naming-method-names
https://google.github.io/styleguide/jsguide.html#naming-non-constant-field-names

and discussed in an earlier PR:

https://github.com/scottlamb/moonfire-nvr/pull/48#discussion_r175678736

I fixed these mechanically:

rg -l0 'this[.]_' | xargs -0 perl -pi -e 's/this[.]_(\w+)/this.$1_/g'
rg -l0 '\s_\w+\(' | xargs -0 perl -pi -e 's/_(\w+)\(/$1_(/g'
2020-03-14 15:20:18 -07:00
Scott Lamb
038aebe0fd javascript lint fix 2020-03-14 15:13:11 -07:00
Scott Lamb
3968bfe912 reorganize /recordings JSON response
I want to start returning the pixel aspect ratio of each video sample
entry. It's silly to duplicate it for each returned recording, so
let's instead return a videoSampleEntryId and then put all the
information about each VSE once.

This change doesn't actually handle pixel aspect ratio server-side yet.
Most likely I'll require a new schema version for that, to store it as a
new column in the database. Codec-specific logic in the database layer
is awkward and I'd like to avoid it. I did a similar schema change to
add the rfc6381_codec.

I also adjusted ui-src/lib/models/Recording.js in a few ways:

* fixed a couple mismatches between its field name and the key defined
  in the API. Consistency aids understanding.
* dropped all the getters in favor of just setting the fields (with
  type annotations) as described here:
  https://google.github.io/styleguide/jsguide.html#features-classes-fields
* where the wire format used undefined (to save space), translate it to
  a more natural null or false.
2020-03-13 21:41:02 -07:00
Scott Lamb
317a620e6e upgrade copyright notices
* As discussed in #48, say "The Moonfire NVR Authors" at the top of
  every file rather than whoever created that file. Have one AUTHORS
  file listing everyone.
* Consistently call it a "security camera network video recorder" rather
  than "security camera digital video recorder".
2020-03-01 22:53:41 -08:00
Scott Lamb
fc77db0fc9 add autocomplete attributes to login form
The Chrome console was nagging about this, linking to here:
https://www.chromium.org/developers/design-documents/create-amazing-password-forms
I'm not sure it makes any real difference (autocomplete already worked),
but it's easy enough to do.
2020-03-01 22:36:04 -08:00
Scott Lamb
aa25a85477 Fix a whole bunch of eslint errors
These apparently were silent until 92c532d mass-upgraded deps.
Apparently eslint returned status 0 despite errors before and now
returns 1.

Most of these were handled by its "--fix" option; I manually took care
of the remaining two:

/Users/slamb/git/moonfire-nvr/ui-src/lib/views/RecordingsView.js
  140:1  error  This line has a length of 82. Maximum allowed is 80  max-len

/Users/slamb/git/moonfire-nvr/ui-src/lib/views/StreamSelectorView.js
  72:1  error  This line has a length of 82. Maximum allowed is 80  max-len
2020-03-01 22:28:24 -08:00
Scott Lamb
92c532db3e upgrade minimum nodejs version, yarn dev deps
Looks like I basically had to do this to keep up. With nodejs version 12
(current LTS), the version of fsevents I installed wouldn't build. A
"yarn upgrade" by itself resulted in a new problem as described in #69.
Conversely, the new versions don't install with nodejs 8. So I bit the
bullet and upgraded all the dev dependency stuff and the nodejs at once.
nodejs 10 seems capable of running either the old or new, fwiw.

I'm a little sad that this seems to have made the UI bundle 5% larger.
Before, "yarn build" said 350 KiB. After, 369 KiB. A little bit in
several places. For example, jquery-ui.bundle.js went from 156 KiB (in
2 chunks) to 160 KiB (in 1 chunk) for some reason.
2020-03-01 21:57:51 -08:00
Scott Lamb
b298bd13f2 grab one minimizer rather than three
Apparently WebPack builds in "terser", which is what the cool kids use.
Just go with the default and simplify the configuration as well as
installing fewer node modules.

"babel-minify-webpack-plugin" wasn't actually being used, and
babel-minify is still in beta anyway.

uglifyjs, according to https://github.com/webpack/webpack/issues/7923,
doesn't support ES6 and depends on a package which is no longer
maintained.
2020-03-01 21:23:29 -08:00
Scott Lamb
4b397670a4 revamp webpack config
* simplify it. Go from six checked-in config files + one local one to
  three checked-in configs + commandline options. I find it less
  confusing to have the options plumbed through fewer layers.

* support developing against a https production server, as described in
  guide/developing-ui.md.

* fix the source map. The sourceMap parameter in prod.config.js as far
  as I can tell evaluated to false when run with production config, and
  anyway UglifyJS seems to be incompatible with the specified
  cheap-module-source-map. Use source-map instead.
2020-03-01 19:26:45 -08:00
Scott Lamb
92266612b5 switch to websocket for live stream (#59)
The multipart stream / hanging GET approach worked in a prototype for a
single stream, but Chrome has a per-host limit of six connections. If I
try streaming all my cameras at once, I hit that limit. I can't open all
the streams, much less additional connections to load init segments and
such. Websockets apparently has a much higher limit of 256.
2020-02-29 14:39:16 -08:00
Scott Lamb
3fa48ab0da remove the JsonWrapper class
Let's follow the Google Style Guide, in which private variables are
simply suffixed with "_". It's a sign, not a cop, but that's fine.
I'd rather keep things simple, and code review should suffice for
catching uses of a private variable outside the class.
2020-02-22 21:15:37 -08:00
Scott Lamb
a26c3d1649 fix some reqwest upgrade brokenness in benches 2020-02-21 11:58:38 -08:00
Scott Lamb
f7da085335 give downloaded .mp4s a useful filename
This is effective both for Chrome's "Save As" dialog and for curl -OJ.
It makes the filename like 20190717135519-driveway-main.mp4 rather than
view.mp4 (Chrome) or view.mp4?s=33-36&ts=true (Curl).
2020-02-21 11:25:12 -08:00
Scott Lamb
dd3c3f2f84 update some deps, including cursive
cursive renamed a few methods, so keep up with that. No functional
changes.
2020-01-21 08:58:11 -08:00
Scott Lamb
038fc574e9 upgrade some deps, including reqwest
The reqwest one is particularly notable because it means not having two
versions of hyper/http/tokio/futures/bytes. It also drops a number of
transitive deps; with some work I think I could stop depending on regex
now.
2020-01-09 20:06:30 -08:00
Scott Lamb
73f7cdd261 use application/json for login and logout 2020-01-09 16:24:03 -08:00
Scott Lamb
8af7bca6c2 upgrade to hyper 0.13 ecosystem
This doesn't take much advantage of async fns so far. For example, the
with_{form,json}_body functions are still designed to be used with
future combinators when it'd be more natural to call them from async
fns now. But it's a start.

Similarly, this still uses the old version of reqwest. Small steps.

Requires Rust 1.40 now. (1.39 is a requirement of async, and 1.40 is a
requirement of http-serve 0.2.0.)
2020-01-09 16:07:46 -08:00
Scott Lamb
fce0c5b014 use a released version of nix 2019-12-30 07:46:53 -06:00
Scott Lamb
79351eb84c run CI on bionic, not xenial
xenial is too old for 6fb346c to work. From comparing release dates, I
think it's reasonable to guess people won't have trouble running
something newer. In particular, there have been two major Raspbian
releases since then, so current Pi systems will be more bionic-like than
xenial-like.

https://wiki.ubuntu.com/Releases
* xenial (LTS) was relesed 2016-04-21
* bionic (LTS) was released 2018-04-26

https://en.wikipedia.org/wiki/Raspbian
* stretch was released 2017-08-17
* buster was released 2019-06-24

https://www.debian.org/releases/
* stretch was released 2017-06-17
* buster was released 2019-07-06
  (interesting that Raspbian buster was released before Debian buster)
2019-12-30 06:51:01 -06:00
Scott Lamb
6fb346cc8b address AVStream::codec deprecation
The codec -> codecpar move was sufficiently long ago (libavformat
57.5.0 on 2016-04-11) that I think we can just get away with requiring
the new version. Let's try it.

But if someone complains, AVCodecParameters and AVCodecContext look
sufficiently similar we could probably just use one or the other based on
the version we're compiling with.
2019-12-29 08:35:39 -06:00
Scott Lamb
7179ea04e3 address av_lockmgr_register deprecation 2019-12-29 08:20:25 -06:00
Scott Lamb
2ab7dbc9fb stop using deprecated try! 2019-12-28 08:07:33 -06:00
Scott Lamb
e8a00d4639 use parking_lot::Once in ffmpeg
I'm getting deprecation warnings for std::sync::ONCE_INIT, and I'm
not sure when std::sync::Once::new() became a const fn. Just as easy to
switch to parking_lot.
2019-12-28 08:03:05 -06:00
Scott Lamb
154d0c30c0 note caveat on signals schema 2019-12-28 08:00:38 -06:00
Scott Lamb
72d301af6e get rid of deprecated mem::uninitialized()
This requires a Rust version bump, as MaybeUninit was introduced in Rust
1.36.
2019-12-28 07:51:47 -06:00
Scott Lamb
2bd8963961 garbage collection for signals 2019-12-28 07:48:08 -06:00
Scott Lamb
1fdf6eb022 better logging for ffmpeg errors 2019-09-26 16:10:13 -07:00
Scott Lamb
0a29f62fd3 better logs during normal operation
* don't log every time we delete stuff; leave it for the flush
* when flushing, break apart counts by sample file dir and include
  human-readable sizes
2019-09-26 16:09:58 -07:00