moonfire-nvr/guide/build.md

145 lines
5.1 KiB
Markdown
Raw Normal View History

# Building Moonfire NVR <!-- omit in toc -->
This document has notes for software developers on building Moonfire NVR from
source code for development. If you just want to install precompiled
binaries, see the [installation instructions](install.md) instead.
This document doesn't spell out as many details as the installation
instructions. Please ask on Moonfire NVR's [issue
tracker](https://github.com/scottlamb/moonfire-nvr/issues) or
[mailing list](https://groups.google.com/d/forum/moonfire-nvr-users) when
stuck. Please also send pull requests to improve this doc.
* [Downloading](#downloading)
* [Building](#building)
* [Running interactively straight from the working copy](#running-interactively-straight-from-the-working-copy)
* [Release procedure](#release-procedure)
2021-03-12 15:18:24 -05:00
## Downloading
See the [github page](https://github.com/scottlamb/moonfire-nvr) (in case
you're not reading this text there already). You can download the
bleeding-edge version from the commandline via git:
```console
$ git clone https://github.com/scottlamb/moonfire-nvr.git
$ cd moonfire-nvr
```
## Building
Moonfire NVR should run natively on any Unix-like system. It's been tested on
Linux, macOS, and FreeBSD. (In theory [Windows Subsystem for
Linux](https://docs.microsoft.com/en-us/windows/wsl/about) should also work.
Please speak up if you try it.)
To build the server, you will need [SQLite3](https://www.sqlite.org/). You
can skip this if compiling with `--features=rusqlite/bundled` and don't
mind the `moonfire-nvr sql` command not working.
To build the UI, you'll need a [nodejs](https://nodejs.org/en/download/) release
in "Maintenance", "LTS", or "Current" status on the
[Release Schedule](https://github.com/nodejs/release#release-schedule):
currently v18, v20, or v21.
On recent Ubuntu or Raspbian Linux, the following command will install
most non-Rust dependencies:
```console
$ sudo apt-get install \
build-essential \
libsqlite3-dev \
pkgconf \
sqlite3 \
tzdata
```
Ubuntu 20.04 LTS (still popular, supported by Ubuntu until April 2025) bundles
node 10, which has reached end-of-life (see
[node.js: releases](https://nodejs.org/en/about/releases/)).
So rather than install the `nodejs` and `npm` packages from the built-in
repository, see [Installing Node.js via package
manager](https://nodejs.org/en/download/package-manager/#debian-and-ubuntu-based-linux-distributions).
On macOS with [Homebrew](https://brew.sh/) and Xcode installed, try the
following command:
```console
drop ffmpeg support * switch the config interface over to use Retina and make the test button honor rtsp_transport = udp. * adjust the threading model of the Retina streaming code. Before, it spawned a background future that read from the runtime and wrote to a channel. Other calls read from this channel. After, it does work directly from within the block_on calls (no channels). The immediate motivation was that the config interface didn't have another runtime handy. And passing in a current thread runtime deadlocked. I later learned this is a difference between Runtime::block_on and Handle::block_on. The former will drive IO and timers; the latter will not. But this is also more efficient to avoid so many thread hand-offs. Both the context switches and the extra spinning that tokio appears to do as mentioned here: https://github.com/scottlamb/retina/issues/5#issuecomment-871971550 This may not be the final word on the threading model. Eventually I may not have per-stream writing threads at all. But I think it will be easier to look at this after getting rid of the separate `moonfire-nvr config` subcommand in favor of a web interface. * in tests, read `.mp4` files via the `mp4` crate rather than ffmpeg. The annoying part is that this doesn't parse edit lists; oh well. * simplify the `Opener` interface. Formerly, it'd take either a RTSP URL or a path to a `.mp4` file, and they'd share some code because they both sometimes used ffmpeg. Now, they're totally different libraries (`retina` vs `mp4`). Pull the latter out to a `testutil` module with a different interface that exposes more of the `mp4` stuff. Now `Opener` is just for RTSP. * simplify the h264 module. It had a lot of logic to deal with Annex B. Retina doesn't use this encoding. Fixes #36 Fixes #126
2022-03-18 13:30:23 -04:00
$ brew install node
```
2023-07-04 17:59:10 -04:00
Next, you need Rust 1.65+ and Cargo. The easiest way to install them is by
following the instructions at [rustup.rs](https://www.rustup.rs/). Avoid
your Linux distribution's Rust packages, which tend to be too old.
(At least on Debian-based systems; Arch and Gentoo might be okay.)
Once prerequisites are installed, you can build the server and find it in
`target/release/moonfire-nvr`:
```console
$ cd server
$ cargo test
$ cargo build --release
$ sudo install -m 755 target/release/moonfire-nvr /usr/local/bin
$ cd ..
```
You can build the UI via `npm` and find it in the `ui/build` directory:
```console
$ cd ui
$ npm install
$ npm run build
$ sudo mkdir /usr/local/lib/moonfire-nvr
2021-09-14 23:28:21 -04:00
$ cd ..
$ sudo rsync --recursive --delete --chmod=D755,F644 ui/dist/ /usr/local/lib/moonfire-nvr/ui
```
If you wish to bundle the UI into the binary, you can build the UI first and then pass
`--features=bundled-ui` when building the server. See also the
[release workflow](../.github/workflows/release.yml) which statically links SQLite and
(musl-based) libc for a zero-dependencies binary.
### Running interactively straight from the working copy
The author finds it convenient for local development to set up symlinks so that
the binaries in the working copy will run via just `nvr`:
```console
$ sudo mkdir /usr/local/lib/moonfire-nvr
$ sudo ln -s `pwd`/ui/dist /usr/local/lib/moonfire-nvr/ui
$ sudo mkdir /var/lib/moonfire-nvr
$ sudo chown $USER: /var/lib/moonfire-nvr
$ ln -s `pwd`/server/target/release/moonfire-nvr $HOME/bin/moonfire-nvr
$ ln -s moonfire-nvr $HOME/bin/nvr
$ nvr init
$ nvr config
$ nvr run
```
(Alternatively, you could symlink to `target/debug/moonfire-nvr` and compile
with `cargo build` rather than `cargo build --release`, for a faster build
cycle and slower performance.)
## Release procedure
Releases are currently a bit manual. From a completely clean git work tree,
1. manually verify the current commit is pushed to github's master branch and
has a green checkmark indicating CI passed.
2. update versions:
* update `server/Cargo.toml` version by hand; run `cargo test --workspace`
to update `Cargo.lock`.
* ensure `README.md` and `CHANGELOG.md` refer to the new version.
3. run commands:
```bash
VERSION=x.y.z
git commit -am "prepare version ${VERSION}"
git tag -a "v${VERSION}" -m "version ${VERSION}"
git push origin "v${VERSION}"
```
The rest should happen automatically—the tag push will fire off a GitHub
Actions workflow which creates a release, cross-compiles statically compiled
binaries for three different platforms, and uploads them to the release.