#!/bin/sh set -eu echo "" echo " Oden Installer" echo " Voysys AB (2026)" echo "" echo " https://voysys.se" echo "" TMPDIR=$(mktemp -d) chmod o+rx "$TMPDIR" BASE_URL="https://releases.voysys.dev" usage() { cat >&2 <] [options] Installs the latest Oden release from ${BASE_URL}. Arguments: fleet-streamer, streamer, or vr. Options: --application Same as the positional argument. --install-service fleet-streamer only: whether to install, enable, and start the systemd service. If omitted, the script prompts interactively. --activate Activate the installed binary with the given key. --release Install a specific release version (e.g. 2.48.1) instead of the latest. --nightly Install a nightly build instead of a release. is either "latest" or an ISO 8601 date (e.g. 2026-05-18). -h, --help Show this help and exit. Examples: $0 fleet-streamer --install-service true $0 --application vr --activate ABC123 $0 streamer --release 2.48.1 $0 streamer --nightly latest $0 streamer --nightly 2026-05-18 curl -fsSL ${BASE_URL}/install.sh | sh -s -- fleet-streamer --install-service true EOF } APPLICATION="" INSTALL_SERVICE="false" INSTALL_SERVICE_SET="false" ACTIVATE_KEY="" NIGHTLY="" NIGHTLY_SET="false" RELEASE="" RELEASE_SET="false" case "${1:-}" in -*|"") ;; *) APPLICATION="$1"; shift ;; esac while [ $# -gt 0 ]; do case "$1" in --application) APPLICATION="${2:-}"; shift 2 ;; --application=*) APPLICATION="${1#--application=}"; shift ;; --install-service) INSTALL_SERVICE="${2:-}"; INSTALL_SERVICE_SET="true"; shift 2 ;; --install-service=*) INSTALL_SERVICE="${1#--install-service=}"; INSTALL_SERVICE_SET="true"; shift ;; --activate) ACTIVATE_KEY="${2:-}"; shift 2 ;; --activate=*) ACTIVATE_KEY="${1#--activate=}"; shift ;; --nightly) NIGHTLY="${2:-}"; NIGHTLY_SET="true"; shift 2 ;; --nightly=*) NIGHTLY="${1#--nightly=}"; NIGHTLY_SET="true"; shift ;; --release) RELEASE="${2:-}"; RELEASE_SET="true"; shift 2 ;; --release=*) RELEASE="${1#--release=}"; RELEASE_SET="true"; shift ;; -h|--help) usage; exit 0 ;; *) echo "[ERROR] Unknown argument: $1" >&2; usage; exit 1 ;; esac done if [ "$NIGHTLY_SET" = "true" ] && [ "$RELEASE_SET" = "true" ]; then echo "[ERROR] --nightly and --release are mutually exclusive." >&2 exit 1 fi if [ "$INSTALL_SERVICE_SET" = "true" ] \ && [ "$INSTALL_SERVICE" != "true" ] \ && [ "$INSTALL_SERVICE" != "false" ]; then echo "[ERROR] --install-service value must be 'true' or 'false', got: '$INSTALL_SERVICE'" >&2 exit 1 fi if [ "$(id -u)" -eq 0 ]; then SUDO="" else SUDO="sudo" fi if [ -z "$APPLICATION" ]; then echo "What do you want to install?" echo " 1) Oden Fleet Streamer" echo " 2) OdenVR" printf "Enter your choice: " read choice < /dev/tty case "$choice" in 1) APPLICATION="fleet-streamer" ;; 2) APPLICATION="vr" ;; *) echo "[ERROR] Invalid selection. Exiting." >&2; exit 1 ;; esac fi if [ "$APPLICATION" != "fleet-streamer" ] && [ "$APPLICATION" != "streamer" ] && [ "$APPLICATION" != "vr" ]; then echo "[ERROR] Unknown application: $APPLICATION" >&2 exit 1 fi if [ "$APPLICATION" = "fleet-streamer" ] && [ "$INSTALL_SERVICE_SET" = "false" ]; then printf "Install, enable and start the systemd service? [Y/n]: " read service_choice < /dev/tty case "$service_choice" in [Nn]*) INSTALL_SERVICE="false" ;; *) INSTALL_SERVICE="true" ;; esac fi if [ "$NIGHTLY_SET" = "true" ]; then if [ "$NIGHTLY" = "latest" ]; then echo "[INFO] Fetching latest nightly from ${BASE_URL}/nightly/" HTML=$(curl -fsSL "${BASE_URL}/nightly/") NIGHTLY_DIR=$(echo "$HTML" | grep -o 'href="/nightly/[0-9]\{8\}' | sed 's|.*nightly/||' | sort -r | head -n1) if [ -z "$NIGHTLY_DIR" ]; then echo "[ERROR] Failed to find the latest nightly." >&2 exit 1 fi else NIGHTLY_DIR=$(echo "$NIGHTLY" | tr -d '-') case "$NIGHTLY_DIR" in [0-9][0-9][0-9][0-9][0-9][0-9][0-9][0-9]) ;; *) echo "[ERROR] Invalid --nightly value: '$NIGHTLY'. Use 'latest' or an ISO 8601 date (e.g. 2026-05-18)." >&2 exit 1 ;; esac fi LATEST_VERSION="$NIGHTLY_DIR" VERSION_URL="${BASE_URL}/nightly/${NIGHTLY_DIR}" NIGHTLY_DISPLAY=$(echo "$NIGHTLY_DIR" | sed 's|\(....\)\(..\)\(..\)|\1-\2-\3|') echo "[INFO] Nightly: $NIGHTLY_DISPLAY" elif [ "$RELEASE_SET" = "true" ]; then case "$RELEASE" in [0-9]*.[0-9]*.[0-9]*) ;; *) echo "[ERROR] Invalid --release value: '$RELEASE'. Expected a version like 2.48.1." >&2 exit 1 ;; esac LATEST_VERSION="$RELEASE" VERSION_URL="${BASE_URL}/${LATEST_VERSION}" echo "[INFO] Release: $LATEST_VERSION" else echo "[INFO] Fetching latest version from ${BASE_URL}/" HTML=$(curl -fsSL "$BASE_URL") LATEST_VERSION=$(echo "$HTML" | grep 'href="/[0-9]\+\.[0-9]\+\.[0-9]\+/' | sed 's|.*href="/\([0-9]\+\.[0-9]\+\.[0-9]\+\)/.*|\1|' | sort -Vr | head -n1) if [ -z "$LATEST_VERSION" ]; then echo "[ERROR] Failed to parse the latest version." >&2 exit 1 fi echo "[INFO] Latest version: $LATEST_VERSION" VERSION_URL="${BASE_URL}/${LATEST_VERSION}" fi OS=$(uname -s) ARCH=$(uname -m) case "$OS" in Linux) if ! grep -qi "ubuntu" /etc/os-release; then echo "[ERROR] Only Ubuntu is supported on Linux." >&2 exit 1 fi case "$ARCH" in x86_64) FILE="oden-${APPLICATION}_${LATEST_VERSION}_amd64.deb" ;; aarch64|arm64) OS_ID=$(grep '^VERSION_ID=' /etc/os-release | cut -d '"' -f2) if [ -z "$OS_ID" ]; then echo "[ERROR] Unable to determine Ubuntu version." >&2 exit 1 fi case "$OS_ID" in 18*) JETPACK="jetpack_4.6" ;; 20*) JETPACK="jetpack_5.1" ;; 22*) JETPACK="jetpack_6.1" ;; 24*) JETPACK="jetpack_7.1" ;; *) echo "[ERROR] Unsupported Ubuntu version for Jetson: $OS_ID" >&2; exit 1 ;; esac FILE="oden-${APPLICATION}_${LATEST_VERSION}_arm64_${OS_ID}_${JETPACK}.deb" ;; *) echo "[ERROR] Unsupported architecture: $ARCH" >&2 exit 1 ;; esac ;; *) echo "[ERROR] Unsupported OS: $OS" >&2 exit 1 ;; esac case "$APPLICATION" in fleet-streamer|streamer) BIN="oden-streamer" ;; vr) BIN="oden-vr" ;; esac INSTALLER_URL="${VERSION_URL}/${FILE}" SHA_URL="${INSTALLER_URL}.sha256" echo "" echo " This script will:" if [ "$NIGHTLY_SET" = "true" ]; then echo " - Install ${BIN} nightly ${NIGHTLY_DISPLAY} (${FILE})" else echo " - Install ${BIN} ${LATEST_VERSION} (${FILE})" fi if [ "$APPLICATION" = "fleet-streamer" ] && [ "$INSTALL_SERVICE" = "true" ]; then echo " - Install, enable, and start the ${BIN} systemd service" fi if [ -n "$ACTIVATE_KEY" ]; then echo " - Activate ${BIN} with the provided key" if [ "$INSTALL_SERVICE" = "true" ]; then echo " - Restart the ${BIN} systemd service" fi fi echo "" cd "$TMPDIR" echo "[INFO] Downloading..." curl -fsSLO "$INSTALLER_URL" curl -fsSLO "$SHA_URL" echo "[INFO] Verifying SHA256..." if ! sha256sum -c "$(basename "$SHA_URL")" >/dev/null 2>&1; then echo "[ERROR] SHA256 checksum failed!" >&2 exit 1 fi case "$FILE" in *.deb) echo "[INFO] Installing .deb..." if [ "$APPLICATION" = "fleet-streamer" ]; then echo "oden-streamer oden-streamer/install-services boolean $INSTALL_SERVICE" \ | $SUDO debconf-set-selections fi $SUDO env DEBIAN_FRONTEND=noninteractive apt-get install -y --reinstall "./$FILE" if [ "$NIGHTLY_SET" = "true" ]; then echo "[SUCCESS] Installed Oden nightly $NIGHTLY_DISPLAY" else echo "[SUCCESS] Installed Oden version $LATEST_VERSION" fi if [ -n "$ACTIVATE_KEY" ]; then echo "[INFO] Activating..." if [ -n "$SUDO" ]; then $SUDO -H "$BIN" --activate "$ACTIVATE_KEY" fi "$BIN" --activate "$ACTIVATE_KEY" if [ "$INSTALL_SERVICE" = "true" ]; then echo "[INFO] Restarting $BIN service..." $SUDO systemctl restart "$BIN" fi fi ;; *) echo "[ERROR] Unknown file type: $FILE" >&2 exit 1 ;; esac