192 lines
6.3 KiB
Bash
Executable File
192 lines
6.3 KiB
Bash
Executable File
#!/usr/bin/env bash
|
|
# scripts/install/server.sh - install and setup all server related apps and environments
|
|
set -euo pipefail
|
|
ORIG_USER=${SUDO_USER:-$(id -un)}
|
|
|
|
REF=${LESAVKA_REF:-master} # fallback
|
|
|
|
while [[ $# -gt 0 ]]; do
|
|
case $1 in
|
|
-r|--ref) REF="$2"; shift 2 ;;
|
|
-h|--help)
|
|
echo "Usage: $0 [--ref <branch|commit>]"; exit 0 ;;
|
|
*) echo "Unknown option: $1"; exit 1 ;;
|
|
esac
|
|
done
|
|
echo "==> Using git ref: $REF"
|
|
|
|
echo "==> 1a. Base packages"
|
|
sudo pacman -Syq --needed --noconfirm git \
|
|
rustup \
|
|
protobuf \
|
|
gcc \
|
|
alsa-utils \
|
|
pipewire \
|
|
pipewire-pulse \
|
|
tailscale \
|
|
base-devel \
|
|
v4l-utils \
|
|
gstreamer \
|
|
gst-plugins-base \
|
|
gst-plugins-base-libs \
|
|
gst-plugins-good \
|
|
gst-plugins-bad \
|
|
gst-plugins-bad-libs \
|
|
gst-plugins-ugly \
|
|
gst-libav \
|
|
tcpdump \
|
|
lsof
|
|
if ! command -v yay >/dev/null 2>&1; then
|
|
echo "==> 1b. installing yay from AUR ..."
|
|
sudo -u "$ORIG_USER" bash -c '
|
|
cd /tmp && git clone --depth 1 https://aur.archlinux.org/yay.git &&
|
|
cd yay && makepkg -si --noconfirm'
|
|
fi
|
|
# yay -S --noconfirm grpcurl-bin
|
|
|
|
echo "==> 1c. GPIO permissions for relay"
|
|
echo 'z /dev/gpiochip* 0660 root gpio -' | sudo tee /etc/tmpfiles.d/gpiochip.conf >/dev/null
|
|
sudo systemd-tmpfiles --create /etc/tmpfiles.d/gpiochip.conf || true
|
|
|
|
echo "==> 2a. Kernel-driver tweaks"
|
|
cat <<'EOF' | sudo tee /etc/modprobe.d/gc311-stream.conf >/dev/null
|
|
options uvcvideo quirks=0x200 timeout=10000
|
|
EOF
|
|
|
|
echo "==> 2b. Predictable /dev names for each capture card"
|
|
# ensure relay (GPIO power) is on if present
|
|
if systemctl list-unit-files | grep -q '^relay.service'; then
|
|
sudo systemctl enable --now relay.service
|
|
sleep 2
|
|
fi
|
|
|
|
# probe v4l2 devices for GC311s (07ca:3311)
|
|
mapfile -t GC_VIDEOS < <(
|
|
sudo v4l2-ctl --list-devices 2>/dev/null |
|
|
awk '/Live Gamer MINI/{getline; print $1}'
|
|
)
|
|
|
|
# fallback via udev if v4l2-ctl output is empty/partial
|
|
if [ "${#GC_VIDEOS[@]}" -ne 2 ]; then
|
|
mapfile -t GC_VIDEOS < <(
|
|
for dev in /dev/video*; do
|
|
props=$(sudo udevadm info -q property -n "$dev" 2>/dev/null || true)
|
|
if echo "$props" | grep -q 'ID_VENDOR_ID=07ca' && echo "$props" | grep -q 'ID_MODEL_ID=3311'; then
|
|
echo "$dev"
|
|
fi
|
|
done | sort -u
|
|
)
|
|
fi
|
|
|
|
if [ "${#GC_VIDEOS[@]}" -ne 2 ]; then
|
|
echo "❌ Exactly two GC311 capture cards (index0) must be attached!" >&2
|
|
printf ' Detected: %s\n' "${GC_VIDEOS[@]}"
|
|
exit 1
|
|
fi
|
|
|
|
mapfile -t TAGS < <(
|
|
for v in "${GC_VIDEOS[@]}"; do
|
|
sudo udevadm info -q property -n "$v" |
|
|
awk -F= '/^ID_PATH_TAG=/{print $2}'
|
|
done
|
|
)
|
|
|
|
printf ' ↪ Left card: %s (%s)\n' "${GC_VIDEOS[0]}" "${TAGS[0]}"
|
|
printf ' ↪ Right card: %s (%s)\n' "${GC_VIDEOS[1]}" "${TAGS[1]}"
|
|
|
|
LEFT_TAG=${TAGS[0]}
|
|
RIGHT_TAG=${TAGS[1]}
|
|
|
|
sudo tee /etc/udev/rules.d/85-gc311.rules >/dev/null <<EOF
|
|
# auto-generated by lesavka/scripts/daemon/install-server.sh - DO NOT EDIT
|
|
SUBSYSTEM=="video4linux", ATTR{index}=="0", ENV{ID_PATH_TAG}=="$LEFT_TAG", SYMLINK+="lesavka_l_eye"
|
|
SUBSYSTEM=="video4linux", ATTR{index}=="0", ENV{ID_PATH_TAG}=="$RIGHT_TAG", SYMLINK+="lesavka_r_eye"
|
|
EOF
|
|
|
|
sudo udevadm control --reload
|
|
sudo udevadm trigger --subsystem-match=video4linux
|
|
sudo udevadm settle
|
|
|
|
echo "==> 3. Rust toolchain"
|
|
sudo rustup default stable
|
|
sudo -u "$ORIG_USER" rustup default stable
|
|
|
|
echo "==> 4a. Source checkout"
|
|
SRC_DIR=/var/src/lesavka
|
|
REPO_URL=ssh://git@scm.bstein.dev:2242/bstein/lesavka.git
|
|
if [[ ! -d $SRC_DIR ]]; then
|
|
sudo mkdir -p /var/src
|
|
sudo chown "$ORIG_USER":"$ORIG_USER" /var/src
|
|
fi
|
|
if [[ -d $SRC_DIR/.git ]]; then
|
|
sudo -u "$ORIG_USER" git -C "$SRC_DIR" fetch --all --tags --prune
|
|
else
|
|
sudo -u "$ORIG_USER" git clone "$REPO_URL" "$SRC_DIR"
|
|
fi
|
|
|
|
if sudo -u "$ORIG_USER" git -C "$SRC_DIR" rev-parse --verify --quiet "origin/$REF" >/dev/null; then
|
|
sudo -u "$ORIG_USER" git -C "$SRC_DIR" checkout -B "$REF" "origin/$REF"
|
|
else
|
|
sudo -u "$ORIG_USER" git -C "$SRC_DIR" checkout --force "$REF"
|
|
fi
|
|
|
|
echo "==> 4b. Source build"
|
|
sudo -u "$ORIG_USER" bash -c "cd '$SRC_DIR/server' && cargo clean && cargo build --release"
|
|
|
|
echo "==> 5. Install binaries"
|
|
sudo install -Dm755 "$SRC_DIR/server/target/release/lesavka-server" /usr/local/bin/lesavka-server
|
|
sudo install -Dm755 "$SRC_DIR/scripts/daemon/lesavka-core.sh" /usr/local/bin/lesavka-core.sh
|
|
|
|
echo "==> 6a. Systemd units - lesavka-core"
|
|
cat <<'UNIT' | sudo tee /etc/systemd/system/lesavka-core.service >/dev/null
|
|
[Unit]
|
|
Description=lesavka USB gadget bring-up
|
|
After=sys-kernel-config.mount
|
|
Requires=sys-kernel-config.mount
|
|
|
|
[Service]
|
|
Type=oneshot
|
|
ExecStart=/usr/local/bin/lesavka-core.sh
|
|
RemainAfterExit=yes
|
|
CapabilityBoundingSet=CAP_SYS_ADMIN CAP_SYS_MODULE
|
|
AmbientCapabilities=CAP_SYS_MODULE
|
|
MountFlags=slave
|
|
|
|
[Install]
|
|
WantedBy=multi-user.target
|
|
UNIT
|
|
|
|
echo "==> 6b. Systemd units - lesavka-server"
|
|
cat <<'UNIT' | sudo tee /etc/systemd/system/lesavka-server.service >/dev/null
|
|
[Unit]
|
|
Description=lesavka gRPC relay
|
|
After=network.target lesavka-core.service
|
|
|
|
[Service]
|
|
ExecStart=/usr/local/bin/lesavka-server
|
|
Restart=always
|
|
Environment=RUST_LOG=lesavka_server=info,lesavka_server::audio=info,lesavka_server::video=debug,lesavka_server::gadget=info
|
|
Environment=RUST_BACKTRACE=1
|
|
Environment=GST_DEBUG="*:2,alsasink:6,alsasrc:6"
|
|
Restart=always
|
|
RestartSec=5
|
|
StandardError=append:/tmp/lesavka-server.stderr
|
|
StartLimitIntervalSec=30
|
|
StartLimitBurst=10
|
|
User=root
|
|
|
|
[Install]
|
|
WantedBy=multi-user.target
|
|
UNIT
|
|
|
|
echo "==> 6c. Systemd units - initialization"
|
|
sudo truncate -s 0 /tmp/lesavka-server.log
|
|
sudo systemctl daemon-reload
|
|
sudo systemctl enable --now lesavka-core
|
|
sudo systemctl restart lesavka-core
|
|
echo "✅ lesavka-core installed and restarted..."
|
|
|
|
sudo systemctl enable --now lesavka-server
|
|
sudo systemctl restart lesavka-server
|
|
echo "✅ lesavka-server installed and restarted..."
|