Connector Open-Source Code

Browse connector files locally. Exchange API keys stay on your device.

update.sh

#!/usr/bin/env bash
set -euo pipefail

APP_DIR="/opt/nuxvision_connector"
BACKUP_ROOT="/opt/nuxvision_connector_backups"
TMP_DIR="$(mktemp -d)"
BASE_URL="https://nuxvision.com/nuxvision_connector"

cleanup() { rm -rf "$TMP_DIR"; }
trap cleanup EXIT

REMOTE_VERSION="$(curl -fsSL "$BASE_URL/version.txt" | tr -d '\r\n')"
LOCAL_VERSION="$(cat "$APP_DIR/VERSION" 2>/dev/null | tr -d '\r\n' || echo "0")"

if [[ -z "$REMOTE_VERSION" ]]; then
  echo "remote version is empty"
  exit 1
fi

version_gt() {
  local a="$1" b="$2"
  [[ "$a" != "$b" && "$(printf '%s\n%s\n' "$a" "$b" | sort -V | tail -n1)" == "$a" ]]
}

if [[ "$REMOTE_VERSION" == "$LOCAL_VERSION" ]]; then
  echo "No update available ($LOCAL_VERSION)"
  exit 0
fi

if version_gt "$LOCAL_VERSION" "$REMOTE_VERSION"; then
  echo "Local version ($LOCAL_VERSION) is newer than remote ($REMOTE_VERSION). Skipping."
  exit 0
fi

echo "Updating $LOCAL_VERSION -> $REMOTE_VERSION"

STAMP="$(date +%Y%m%d_%H%M%S)"
BACKUP_DIR="$BACKUP_ROOT/$STAMP"
mkdir -p "$BACKUP_DIR"

# Full backup (including instances/)
rsync -a --delete "$APP_DIR/" "$BACKUP_DIR/"

# Download package
curl -fsSL "$BASE_URL/package.tar.gz" -o "$TMP_DIR/package.tar.gz"

# Verify SHA256
REMOTE_SHA="$(curl -fsSL "$BASE_URL/package.tar.gz.sha256" | tr -d '\r' | awk 'NR==1{print $1}')"
LOCAL_SHA="$(sha256sum "$TMP_DIR/package.tar.gz" | awk '{print $1}')"

if [[ ! "$REMOTE_SHA" =~ ^[A-Fa-f0-9]{64}$ ]]; then
  echo "Invalid remote checksum: $REMOTE_SHA"
  exit 1
fi

if [[ "${LOCAL_SHA,,}" != "${REMOTE_SHA,,}" ]]; then
  echo "Checksum mismatch (local=$LOCAL_SHA remote=$REMOTE_SHA)"
  exit 1
fi

mkdir -p "$TMP_DIR/new"
TAR_ERR="$TMP_DIR/tar_extract.stderr"
if ! tar --no-same-owner -xzf "$TMP_DIR/package.tar.gz" -C "$TMP_DIR/new" 2>"$TAR_ERR"; then
  cat "$TAR_ERR" >&2
  exit 1
fi
# Hide noisy metadata warnings from macOS-built archives, keep all other warnings.
grep -Fv "Ignoring unknown extended header keyword" "$TAR_ERR" >&2 || true

# Update except instances/
rsync -a --delete \
  --exclude 'instances/' \
  --exclude 'build_package.sh' \
  --exclude 'version.txt' \
  "$TMP_DIR/new/" "$APP_DIR/"

# Ensure build-only files are not kept on client
rm -f "$APP_DIR/build_package.sh" "$APP_DIR/version.txt"

echo "$REMOTE_VERSION" > "$APP_DIR/VERSION"

# Enforce safe ownership/permissions after update
chown root:root "$APP_DIR/update.sh" "$APP_DIR/uninstall.sh" "$APP_DIR/VERSION" || true
chmod 750 "$APP_DIR/update.sh" "$APP_DIR/uninstall.sh" || true
chmod 644 "$APP_DIR/VERSION" || true

# Restart only active services
mapfile -t RUNNERS < <(systemctl list-units --type=service --state=active 'nuxvision-runner@*.service' --no-legend | awk '{print $1}')
mapfile -t TRACKERS < <(systemctl list-units --type=service --state=active 'nuxvision-tracker@*.service' --no-legend | awk '{print $1}')

if ((${#RUNNERS[@]})); then
  echo "Restarting runner services: ${RUNNERS[*]}"
  systemctl restart "${RUNNERS[@]}"
else
  echo "No active runner service to restart"
fi
if ((${#TRACKERS[@]})); then
  echo "Restarting tracker services: ${TRACKERS[*]}"
  systemctl restart "${TRACKERS[@]}"
else
  echo "No active tracker service to restart"
fi

# Post-restart verification
for svc in "${RUNNERS[@]:-}" "${TRACKERS[@]:-}"; do
  [[ -z "${svc:-}" ]] && continue
  systemctl is-active --quiet "$svc" || {
    echo "Service failed after update: $svc. Rolling back..."
    rsync -a --delete "$BACKUP_DIR/" "$APP_DIR/"
    if ((${#RUNNERS[@]})); then systemctl restart "${RUNNERS[@]}"; fi
    if ((${#TRACKERS[@]})); then systemctl restart "${TRACKERS[@]}"; fi
    exit 1
  }
done

echo "Update successful to version $REMOTE_VERSION"