[feat](trx-rs): add build/install script and systemd user services
CI / lint (pull_request) Canceled after 0s
CI / test (pull_request) Canceled after 0s
CI / frontend (pull_request) Canceled after 0s
CI / reuse (pull_request) Canceled after 0s
CI / lint (push) Canceled after 0s
CI / test (push) Canceled after 0s
CI / frontend (push) Canceled after 0s
CI / reuse (push) Canceled after 0s
CI / lint (pull_request) Canceled after 0s
CI / test (pull_request) Canceled after 0s
CI / frontend (pull_request) Canceled after 0s
CI / reuse (pull_request) Canceled after 0s
CI / lint (push) Canceled after 0s
CI / test (push) Canceled after 0s
CI / frontend (push) Canceled after 0s
CI / reuse (push) Canceled after 0s
Provide a one-shot installer and matching systemd *user* units so the
server and client can be built, installed system-wide, and run in the
background without hand-rolled steps.
- script/install.sh: builds all three binaries (trx-server, trx-client,
trx-configurator) in release mode and installs them to /usr/local/bin
(configurable via --prefix/--bindir/PREFIX, sudo only when the target
is not writable). Seeds ~/.config/trx-rs/trx-rs.toml from the example
without ever overwriting existing config, then installs the user units
with @BINDIR@ substituted to the real path and runs daemon-reload.
Flags: --no-sdr, --no-build, --no-systemd, --enable-now.
- script/uninstall.sh: stops/disables the units, removes them and the
binaries; keeps config unless --purge.
- packaging/systemd/{trx-server,trx-client}.service: user units reading
the combined config at ~/.config/trx-rs/trx-rs.toml. The client softly
depends on the server (Wants/After). KillSignal=SIGINT matches how the
binaries shut down cleanly (SIGTERM is not handled).
- README: new "Install (optional, Linux + systemd)" section.
The web UI assets are embedded in the binary, so an install needs only
the binaries plus a config file — no data directory to ship.
Signed-off-by: Stan Grams <sjg@haxx.space>
This commit was merged in pull request #67.
This commit is contained in:
@@ -116,6 +116,39 @@ section and the client reads `[trx-client]`.
|
|||||||
|
|
||||||
Open the configured HTTP frontend address in a browser (default `http://localhost:8080`).
|
Open the configured HTTP frontend address in a browser (default `http://localhost:8080`).
|
||||||
|
|
||||||
|
### 5. Install (optional, Linux + systemd)
|
||||||
|
|
||||||
|
To build, install the binaries system-wide, and set up systemd **user** services
|
||||||
|
that run the server and client in the background:
|
||||||
|
|
||||||
|
```bash
|
||||||
|
script/install.sh
|
||||||
|
```
|
||||||
|
|
||||||
|
This builds in release mode, installs `trx-server`, `trx-client`, and
|
||||||
|
`trx-configurator` to `/usr/local/bin` (using `sudo` only if needed), seeds
|
||||||
|
`~/.config/trx-rs/trx-rs.toml` from the example (existing config is never
|
||||||
|
overwritten), and installs `~/.config/systemd/user/{trx-server,trx-client}.service`.
|
||||||
|
|
||||||
|
```bash
|
||||||
|
script/install.sh --prefix ~/.local # install to ~/.local/bin instead
|
||||||
|
script/install.sh --no-sdr # build without SoapySDR support
|
||||||
|
script/install.sh --enable-now # also enable + start the services now
|
||||||
|
script/install.sh --help # all options
|
||||||
|
```
|
||||||
|
|
||||||
|
After editing your config, manage the services with:
|
||||||
|
|
||||||
|
```bash
|
||||||
|
systemctl --user enable --now trx-server trx-client # start now + on login
|
||||||
|
journalctl --user -u trx-server -u trx-client -f # follow logs
|
||||||
|
loginctl enable-linger "$USER" # keep running after logout
|
||||||
|
```
|
||||||
|
|
||||||
|
Serial (`/dev/ttyUSB*`) and audio access require your user to be in the
|
||||||
|
`dialout` and `audio` groups. Remove everything with `script/uninstall.sh`
|
||||||
|
(add `--purge` to also delete the config).
|
||||||
|
|
||||||
## How It Works
|
## How It Works
|
||||||
|
|
||||||
```mermaid
|
```mermaid
|
||||||
|
|||||||
@@ -0,0 +1,37 @@
|
|||||||
|
# SPDX-FileCopyrightText: 2026 Stan Grams <sjg@haxx.space>
|
||||||
|
#
|
||||||
|
# SPDX-License-Identifier: GPL-2.0-or-later
|
||||||
|
#
|
||||||
|
# systemd *user* unit for the trx-rs radio client and web frontend.
|
||||||
|
#
|
||||||
|
# Install with `script/install.sh` (which substitutes @BINDIR@ and copies this
|
||||||
|
# into ~/.config/systemd/user/), or by hand:
|
||||||
|
# sed 's|@BINDIR@|/usr/local/bin|' trx-client.service \
|
||||||
|
# > ~/.config/systemd/user/trx-client.service
|
||||||
|
# systemctl --user daemon-reload
|
||||||
|
# systemctl --user enable --now trx-client.service
|
||||||
|
#
|
||||||
|
# Reads the combined config at ~/.config/trx-rs/trx-rs.toml ([trx-client]
|
||||||
|
# section) and connects to the server (default 127.0.0.1:4530). The web UI
|
||||||
|
# defaults to http://127.0.0.1:8080.
|
||||||
|
|
||||||
|
[Unit]
|
||||||
|
Description=trx-rs radio client and web frontend
|
||||||
|
Documentation=https://github.com/stanislawgrams/trx-rs
|
||||||
|
# Prefer the server to be up first; it is a soft dependency so the client still
|
||||||
|
# starts (and retries) if the server is managed separately.
|
||||||
|
Wants=trx-server.service
|
||||||
|
After=trx-server.service
|
||||||
|
|
||||||
|
[Service]
|
||||||
|
Type=simple
|
||||||
|
ExecStart=@BINDIR@/trx-client --config %h/.config/trx-rs/trx-rs.toml
|
||||||
|
Restart=on-failure
|
||||||
|
RestartSec=2
|
||||||
|
# Shuts down cleanly on SIGINT (see trx-server.service for the rationale).
|
||||||
|
KillSignal=SIGINT
|
||||||
|
TimeoutStopSec=15
|
||||||
|
NoNewPrivileges=true
|
||||||
|
|
||||||
|
[Install]
|
||||||
|
WantedBy=default.target
|
||||||
@@ -0,0 +1,34 @@
|
|||||||
|
# SPDX-FileCopyrightText: 2026 Stan Grams <sjg@haxx.space>
|
||||||
|
#
|
||||||
|
# SPDX-License-Identifier: GPL-2.0-or-later
|
||||||
|
#
|
||||||
|
# systemd *user* unit for the trx-rs radio server.
|
||||||
|
#
|
||||||
|
# Install with `script/install.sh` (which substitutes @BINDIR@ and copies this
|
||||||
|
# into ~/.config/systemd/user/), or by hand:
|
||||||
|
# sed 's|@BINDIR@|/usr/local/bin|' trx-server.service \
|
||||||
|
# > ~/.config/systemd/user/trx-server.service
|
||||||
|
# systemctl --user daemon-reload
|
||||||
|
# systemctl --user enable --now trx-server.service
|
||||||
|
#
|
||||||
|
# Reads the combined config at ~/.config/trx-rs/trx-rs.toml ([trx-server]
|
||||||
|
# section). Serial (/dev/ttyUSB*) and audio access require your user to be in
|
||||||
|
# the `dialout` and `audio` groups — a user unit cannot grant them itself.
|
||||||
|
|
||||||
|
[Unit]
|
||||||
|
Description=trx-rs radio server (CAT/SDR backend)
|
||||||
|
Documentation=https://github.com/stanislawgrams/trx-rs
|
||||||
|
|
||||||
|
[Service]
|
||||||
|
Type=simple
|
||||||
|
ExecStart=@BINDIR@/trx-server --config %h/.config/trx-rs/trx-rs.toml
|
||||||
|
Restart=on-failure
|
||||||
|
RestartSec=2
|
||||||
|
# Both binaries shut down cleanly on SIGINT (the server drains audio and exits
|
||||||
|
# 0); systemd's default SIGTERM is not handled, so signal SIGINT instead.
|
||||||
|
KillSignal=SIGINT
|
||||||
|
TimeoutStopSec=15
|
||||||
|
NoNewPrivileges=true
|
||||||
|
|
||||||
|
[Install]
|
||||||
|
WantedBy=default.target
|
||||||
Executable
+156
@@ -0,0 +1,156 @@
|
|||||||
|
#!/usr/bin/env bash
|
||||||
|
# SPDX-FileCopyrightText: 2026 Stan Grams <sjg@haxx.space>
|
||||||
|
#
|
||||||
|
# SPDX-License-Identifier: GPL-2.0-or-later
|
||||||
|
#
|
||||||
|
# Build trx-rs in release mode and install the binaries system-wide, seed a
|
||||||
|
# per-user config, and install systemd *user* services to run the server and
|
||||||
|
# client. Idempotent: existing config is never overwritten.
|
||||||
|
|
||||||
|
set -euo pipefail
|
||||||
|
|
||||||
|
SCRIPT_DIR="$(cd "$(dirname "$0")" && pwd)"
|
||||||
|
PROJECT_ROOT="$(cd "$SCRIPT_DIR/.." && pwd)"
|
||||||
|
|
||||||
|
BINARIES=(trx-server trx-client trx-configurator)
|
||||||
|
|
||||||
|
# --- Defaults (override via flags or environment) ---------------------------
|
||||||
|
PREFIX="${PREFIX:-/usr/local}"
|
||||||
|
BINDIR="${BINDIR:-}" # derived from PREFIX unless set explicitly
|
||||||
|
NO_SDR=0
|
||||||
|
DO_BUILD=1
|
||||||
|
DO_SYSTEMD=1
|
||||||
|
ENABLE_NOW=0
|
||||||
|
|
||||||
|
CONFIG_DIR="${XDG_CONFIG_HOME:-$HOME/.config}/trx-rs"
|
||||||
|
CONFIG_FILE="$CONFIG_DIR/trx-rs.toml"
|
||||||
|
UNIT_DIR="${XDG_CONFIG_HOME:-$HOME/.config}/systemd/user"
|
||||||
|
|
||||||
|
usage() {
|
||||||
|
cat <<EOF
|
||||||
|
Usage: script/install.sh [options]
|
||||||
|
|
||||||
|
Build trx-rs (release) and install it.
|
||||||
|
|
||||||
|
Options:
|
||||||
|
--prefix DIR Install prefix; binaries go to DIR/bin (default: /usr/local)
|
||||||
|
--bindir DIR Install binaries directly to DIR (overrides --prefix)
|
||||||
|
--no-sdr Build without SoapySDR support (--no-default-features)
|
||||||
|
--no-build Skip cargo build; install existing target/release binaries
|
||||||
|
--no-systemd Do not install the systemd user services
|
||||||
|
--enable-now Enable and start the user services immediately after install
|
||||||
|
-h, --help Show this help
|
||||||
|
|
||||||
|
Environment:
|
||||||
|
PREFIX, BINDIR Same as the matching flags.
|
||||||
|
|
||||||
|
Installs:
|
||||||
|
binaries -> ${BINDIR:-$PREFIX/bin} (uses sudo if not writable)
|
||||||
|
config -> $CONFIG_FILE (from trx-rs.toml.example, only if absent)
|
||||||
|
services -> $UNIT_DIR/{trx-server,trx-client}.service
|
||||||
|
EOF
|
||||||
|
}
|
||||||
|
|
||||||
|
# --- Parse args -------------------------------------------------------------
|
||||||
|
while [ $# -gt 0 ]; do
|
||||||
|
case "$1" in
|
||||||
|
--prefix) PREFIX="$2"; shift 2 ;;
|
||||||
|
--bindir) BINDIR="$2"; shift 2 ;;
|
||||||
|
--no-sdr) NO_SDR=1; shift ;;
|
||||||
|
--no-build) DO_BUILD=0; shift ;;
|
||||||
|
--no-systemd) DO_SYSTEMD=0; shift ;;
|
||||||
|
--enable-now) ENABLE_NOW=1; shift ;;
|
||||||
|
-h|--help) usage; exit 0 ;;
|
||||||
|
*) echo "error: unknown option '$1'" >&2; usage >&2; exit 2 ;;
|
||||||
|
esac
|
||||||
|
done
|
||||||
|
|
||||||
|
[ -n "$BINDIR" ] || BINDIR="$PREFIX/bin"
|
||||||
|
|
||||||
|
log() { printf '\033[1;32m==>\033[0m %s\n' "$*"; }
|
||||||
|
warn() { printf '\033[1;33mwarning:\033[0m %s\n' "$*" >&2; }
|
||||||
|
|
||||||
|
# Return 0 (true) if writing into $1 needs elevated privileges.
|
||||||
|
need_sudo() {
|
||||||
|
local dir="$1"
|
||||||
|
while [ ! -e "$dir" ]; do dir="$(dirname "$dir")"; done
|
||||||
|
[ -w "$dir" ] && return 1 || return 0
|
||||||
|
}
|
||||||
|
|
||||||
|
# --- Build ------------------------------------------------------------------
|
||||||
|
if [ "$DO_BUILD" -eq 1 ]; then
|
||||||
|
build_args=(build --release --manifest-path "$PROJECT_ROOT/Cargo.toml")
|
||||||
|
for b in "${BINARIES[@]}"; do build_args+=(-p "$b"); done
|
||||||
|
if [ "$NO_SDR" -eq 1 ]; then
|
||||||
|
# --no-default-features only affects trx-server; harmless elsewhere.
|
||||||
|
build_args+=(-p trx-server --no-default-features)
|
||||||
|
log "Building (release, no SDR)…"
|
||||||
|
else
|
||||||
|
log "Building (release, with SDR)…"
|
||||||
|
fi
|
||||||
|
cargo "${build_args[@]}"
|
||||||
|
fi
|
||||||
|
|
||||||
|
# --- Install binaries -------------------------------------------------------
|
||||||
|
SUDO=""
|
||||||
|
if need_sudo "$BINDIR"; then
|
||||||
|
SUDO="sudo"
|
||||||
|
log "Installing binaries to $BINDIR (using sudo)…"
|
||||||
|
else
|
||||||
|
log "Installing binaries to $BINDIR…"
|
||||||
|
fi
|
||||||
|
|
||||||
|
for b in "${BINARIES[@]}"; do
|
||||||
|
src="$PROJECT_ROOT/target/release/$b"
|
||||||
|
if [ ! -x "$src" ]; then
|
||||||
|
echo "error: $src not found (build failed or --no-build with no prior build?)" >&2
|
||||||
|
exit 1
|
||||||
|
fi
|
||||||
|
$SUDO install -Dm755 "$src" "$BINDIR/$b"
|
||||||
|
log "installed $BINDIR/$b"
|
||||||
|
done
|
||||||
|
|
||||||
|
# --- Seed per-user config ---------------------------------------------------
|
||||||
|
if [ -e "$CONFIG_FILE" ]; then
|
||||||
|
log "Config already present, leaving it untouched: $CONFIG_FILE"
|
||||||
|
else
|
||||||
|
mkdir -p "$CONFIG_DIR"
|
||||||
|
install -m600 "$PROJECT_ROOT/trx-rs.toml.example" "$CONFIG_FILE"
|
||||||
|
log "Seeded config from example: $CONFIG_FILE"
|
||||||
|
warn "Edit $CONFIG_FILE for your rig before starting the services."
|
||||||
|
fi
|
||||||
|
|
||||||
|
# --- systemd user services --------------------------------------------------
|
||||||
|
if [ "$DO_SYSTEMD" -eq 1 ]; then
|
||||||
|
mkdir -p "$UNIT_DIR"
|
||||||
|
for unit in trx-server trx-client; do
|
||||||
|
sed "s|@BINDIR@|$BINDIR|g" \
|
||||||
|
"$PROJECT_ROOT/packaging/systemd/$unit.service" \
|
||||||
|
> "$UNIT_DIR/$unit.service"
|
||||||
|
log "installed $UNIT_DIR/$unit.service"
|
||||||
|
done
|
||||||
|
|
||||||
|
if command -v systemctl >/dev/null 2>&1; then
|
||||||
|
systemctl --user daemon-reload || warn "systemctl --user daemon-reload failed"
|
||||||
|
if [ "$ENABLE_NOW" -eq 1 ]; then
|
||||||
|
log "Enabling and starting user services…"
|
||||||
|
systemctl --user enable --now trx-server.service trx-client.service
|
||||||
|
warn "Run 'loginctl enable-linger $USER' to keep services running after logout."
|
||||||
|
else
|
||||||
|
cat <<EOF
|
||||||
|
|
||||||
|
Next steps:
|
||||||
|
1. Edit your config: \$EDITOR $CONFIG_FILE
|
||||||
|
2. Start the services: systemctl --user enable --now trx-server trx-client
|
||||||
|
3. Watch the logs: journalctl --user -u trx-server -u trx-client -f
|
||||||
|
4. Run after logout: loginctl enable-linger $USER
|
||||||
|
|
||||||
|
Web UI (default): http://127.0.0.1:8080
|
||||||
|
EOF
|
||||||
|
fi
|
||||||
|
else
|
||||||
|
warn "systemctl not found; units copied but not reloaded."
|
||||||
|
fi
|
||||||
|
fi
|
||||||
|
|
||||||
|
log "Done."
|
||||||
Executable
+86
@@ -0,0 +1,86 @@
|
|||||||
|
#!/usr/bin/env bash
|
||||||
|
# SPDX-FileCopyrightText: 2026 Stan Grams <sjg@haxx.space>
|
||||||
|
#
|
||||||
|
# SPDX-License-Identifier: GPL-2.0-or-later
|
||||||
|
#
|
||||||
|
# Reverse script/install.sh: stop and remove the systemd user services and the
|
||||||
|
# installed binaries. User config (~/.config/trx-rs) is left in place unless
|
||||||
|
# --purge is given.
|
||||||
|
|
||||||
|
set -euo pipefail
|
||||||
|
|
||||||
|
BINARIES=(trx-server trx-client trx-configurator)
|
||||||
|
|
||||||
|
PREFIX="${PREFIX:-/usr/local}"
|
||||||
|
BINDIR="${BINDIR:-}"
|
||||||
|
PURGE=0
|
||||||
|
|
||||||
|
CONFIG_DIR="${XDG_CONFIG_HOME:-$HOME/.config}/trx-rs"
|
||||||
|
UNIT_DIR="${XDG_CONFIG_HOME:-$HOME/.config}/systemd/user"
|
||||||
|
|
||||||
|
usage() {
|
||||||
|
cat <<EOF
|
||||||
|
Usage: script/uninstall.sh [options]
|
||||||
|
|
||||||
|
Options:
|
||||||
|
--prefix DIR Install prefix binaries were installed under (default: /usr/local)
|
||||||
|
--bindir DIR Directory binaries were installed to (overrides --prefix)
|
||||||
|
--purge Also delete the user config directory ($CONFIG_DIR)
|
||||||
|
-h, --help Show this help
|
||||||
|
EOF
|
||||||
|
}
|
||||||
|
|
||||||
|
while [ $# -gt 0 ]; do
|
||||||
|
case "$1" in
|
||||||
|
--prefix) PREFIX="$2"; shift 2 ;;
|
||||||
|
--bindir) BINDIR="$2"; shift 2 ;;
|
||||||
|
--purge) PURGE=1; shift ;;
|
||||||
|
-h|--help) usage; exit 0 ;;
|
||||||
|
*) echo "error: unknown option '$1'" >&2; usage >&2; exit 2 ;;
|
||||||
|
esac
|
||||||
|
done
|
||||||
|
|
||||||
|
[ -n "$BINDIR" ] || BINDIR="$PREFIX/bin"
|
||||||
|
|
||||||
|
log() { printf '\033[1;32m==>\033[0m %s\n' "$*"; }
|
||||||
|
|
||||||
|
need_sudo() {
|
||||||
|
local dir="$1"
|
||||||
|
while [ ! -e "$dir" ]; do dir="$(dirname "$dir")"; done
|
||||||
|
[ -w "$dir" ] && return 1 || return 0
|
||||||
|
}
|
||||||
|
|
||||||
|
# --- Stop and remove user services -----------------------------------------
|
||||||
|
if command -v systemctl >/dev/null 2>&1; then
|
||||||
|
log "Stopping and disabling user services…"
|
||||||
|
systemctl --user disable --now trx-client.service trx-server.service 2>/dev/null || true
|
||||||
|
fi
|
||||||
|
for unit in trx-client trx-server; do
|
||||||
|
if [ -e "$UNIT_DIR/$unit.service" ]; then
|
||||||
|
rm -f "$UNIT_DIR/$unit.service"
|
||||||
|
log "removed $UNIT_DIR/$unit.service"
|
||||||
|
fi
|
||||||
|
done
|
||||||
|
if command -v systemctl >/dev/null 2>&1; then
|
||||||
|
systemctl --user daemon-reload || true
|
||||||
|
fi
|
||||||
|
|
||||||
|
# --- Remove binaries --------------------------------------------------------
|
||||||
|
SUDO=""
|
||||||
|
if need_sudo "$BINDIR"; then SUDO="sudo"; fi
|
||||||
|
for b in "${BINARIES[@]}"; do
|
||||||
|
if [ -e "$BINDIR/$b" ]; then
|
||||||
|
$SUDO rm -f "$BINDIR/$b"
|
||||||
|
log "removed $BINDIR/$b"
|
||||||
|
fi
|
||||||
|
done
|
||||||
|
|
||||||
|
# --- Optionally purge config ------------------------------------------------
|
||||||
|
if [ "$PURGE" -eq 1 ]; then
|
||||||
|
rm -rf "$CONFIG_DIR"
|
||||||
|
log "purged $CONFIG_DIR"
|
||||||
|
else
|
||||||
|
log "Left config in place: $CONFIG_DIR (use --purge to delete)"
|
||||||
|
fi
|
||||||
|
|
||||||
|
log "Done."
|
||||||
Reference in New Issue
Block a user