<?xml version='1.0' standalone='yes'?>
<!DOCTYPE PLUGIN [
<!ENTITY name    "varaverk">
<!ENTITY author  "gmer4lfe">
<!ENTITY version "2026.05.31">
<!ENTITY sha256  "d588470d6cc7f284601cb56039d5dfea6fb5bb1ee2c800657438a8edacafbd01">
<!ENTITY launch  "varaverk/monitor">
<!ENTITY github  "https://github.com/FailedProxy/Varaverk">
<!ENTITY branch  "main">
<!ENTITY cfgdir  "/boot/config/plugins/varaverk">
<!ENTITY plugdir "/usr/local/emhttp/plugins/varaverk">
<!ENTITY pkg     "varaverk-&version;-noarch-1.txz">
]>
<PLUGIN name="&name;" author="&author;" version="&version;" launch="&launch;"
        support="https://github.com/FailedProxy/Varaverk/issues"
        icon="/plugins/varaverk/icons/varaverk.png">

<CHANGES>
###2026.05.31
- Install via raw .plg URL (Gitea or GitHub) — same install script either way, Gitea → Tailscale peer → GITEA_DOMAIN → GitHub fallback chain
- Web files served via symlink to Plugin/unraid/ on flash, recreated every boot — survives reboots, no array dependency
- Scripts git-cloned to flash on first install only; updates handled in-UI (git pull) or the daily orchestrator, not by re-cloning on every boot
- build.sh packages a .txz for a possible future Community Apps release — not yet wired into install; current distribution is git-clone + symlink only

###2026.05.30
- First-run setup wizard: auto-detects hostname, creates master.conf + host conf from templates
- Scheduler setup mode: after wizard, master.conf and host conf open sequentially with forced save flow
- Partnership tab: Onboard button highlighted on arrival from wizard; disabled until partner is configured
- HOST2 install paths: state-file pull, master.conf push detection, conf-only flow
- Onboard Step 9: master.conf automatically pushed to all listed hosts on onboard completion
- Graceful pre-onboard state: neutral banners instead of error warnings before SSH is configured
- GitHub link in tab bar and Settings page; Community Apps support URL

###2026.05.28
- Initial release: Monitor, Scheduler, Docker, Watchdog, Partnership, Fallback, Arrs tabs
- Mutual container fallback with tiered escalation and strike-confirmed handback
- Partnership lifecycle: onboard, offboard, transfer
- Rsync profile system with per-share container stops and writeback
- Watchdog: Tier 1 (explicit) + Tier 2 (global scan) container monitoring
- master.conf push-on-save to all configured partners via SSH
</CHANGES>

<!--
  ── 1. Web files symlink (runs on every boot) ──────────────────────────────────
  Instead of extracting a .txz, we symlink the installed plugin web dir directly
  to the workspace on flash. Changes to Plugin/unraid/ are live instantly — no
  package build, no sync step. /boot is always mounted before this runs.
  ────────────────────────────────────────────────────────────────────────────────
-->
<FILE Run="/bin/bash">
<INLINE>
<![CDATA[
#!/bin/bash
WEB_DIR="/usr/local/emhttp/plugins/varaverk"
SRC="/boot/config/plugins/varaverk/Plugin/unraid"
[[ -L "$WEB_DIR" ]] && rm -f "$WEB_DIR"
[[ -d "$WEB_DIR" ]] && rm -rf "$WEB_DIR"
ln -sf "$SRC" "$WEB_DIR"
echo "[Varaverk] web dir symlinked → $SRC"
]]>
</INLINE>
</FILE>

<!--
  ── 2. Scripts bootstrap (first install only) ──────────────────────────────────
  Clones the repo directly into the plugin config dir on flash (/boot/config/plugins/varaverk).
  No array dependency — scripts live on flash (64GB NVMe) and are available at boot.
  Uses git init+fetch+reset so the clone works into the non-empty cfgdir (varaverk.cfg,
  varaverk-*.txz etc. are already there). Never auto-pulls — updates via the UI git pull.

  Clone source priority:
    1. Gitea (local container, then Tailscale peer probe) — reads settings from varaverk.cfg
    2. Gitea (GITEA_DOMAIN) — public domain fallback if local/Tailscale lookup fails
    3. GitHub (public)  — HTTPS fallback if Gitea is unreachable by any path
  ────────────────────────────────────────────────────────────────────────────────
-->
<FILE Run="/bin/bash" Method="install">
<INLINE>
<![CDATA[
#!/bin/bash
PLUGIN="varaverk"
CFG_DIR="/boot/config/plugins/$PLUGIN"
CFG_FILE="$CFG_DIR/varaverk.cfg"
GITHUB="https://github.com/FailedProxy/Varaverk"
BRANCH="main"
LOG="$CFG_DIR/install.log"

mkdir -p "$CFG_DIR"
log() { echo "[$(date '+%H:%M:%S')] $*" | tee -a "$LOG"; }

# Scripts live in the plugin dir on flash — no array needed.
SCRIPTS_DIR="$CFG_DIR"
CONF_DIR="$SCRIPTS_DIR/Configurations"
DEPLOY_DIR="$SCRIPTS_DIR/Deployment"

# ── Boot device check ─────────────────────────────────────────────────────────
# Warn if /boot is on a USB/removable device. Varaverk is designed for internal
# NVMe/SSD boot — git repo + state files + data writes on USB will wear it out
# fast and may run out of space. Install proceeds but user is warned.
_boot_dev=$(df /boot --output=source 2>/dev/null | tail -1)
_boot_base=$(lsblk -no pkname "$_boot_dev" 2>/dev/null || basename "${_boot_dev%[0-9p]*}")
_removable=$(cat "/sys/block/${_boot_base}/removable" 2>/dev/null || echo "0")
if [[ "$_removable" == "1" ]]; then
    log "WARNING: /boot is on a removable/USB device ($_boot_dev)"
    log "WARNING: Varaverk is designed for internal NVMe/SSD boot."
    log "WARNING: Running from USB risks drive wear and space exhaustion."
    log "WARNING: Strongly recommend migrating boot to an internal NVMe/SSD drive."
fi
unset _boot_dev _boot_base _removable

# Seed varaverk.cfg with defaults (SCRIPTS_DIR + Gitea settings) if not present.
# Requires internal NVMe/SSD boot — scripts live on flash, available before array mounts.
if [[ ! -f "$CFG_FILE" ]]; then
    cat > "$CFG_FILE" <<'CFGEOF'
SCRIPTS_DIR="/boot/config/plugins/varaverk"
GITEA_CONTAINER="Gitea"
GITEA_REPO_PATH="FailedProxy/Varaverk.git"
GITEA_SSH_KEY="/root/.ssh/unraid_gitea"
GITEA_DOMAIN=""
SSH_PORT="221"
CFGEOF
    log "seeded varaverk.cfg"
fi

# Read Gitea settings from varaverk.cfg (allows override without editing .plg).
_read_cfg() { grep -oP "(?<=^${1}=\")[^\"]*" "$CFG_FILE" 2>/dev/null || echo "${2}"; }
GITEA_CONTAINER=$(_read_cfg GITEA_CONTAINER "Gitea")
GITEA_REPO_PATH=$(_read_cfg GITEA_REPO_PATH "FailedProxy/Varaverk.git")
GITEA_SSH_KEY=$(_read_cfg   GITEA_SSH_KEY   "/root/.ssh/unraid_gitea")
GITEA_DOMAIN=$(_read_cfg    GITEA_DOMAIN    "")
SSH_PORT=$(_read_cfg        SSH_PORT        "221")

# Clone on first install only; never auto-pull (updates via the UI git pull).
if [[ ! -d "$SCRIPTS_DIR/.git" ]]; then
    log "initialising repo in $SCRIPTS_DIR ($BRANCH)..."

    # Locate Gitea: local container → Tailscale → GITEA_DOMAIN → GitHub.
    GITEA_IP=""
    if command -v docker >/dev/null 2>&1 && \
       docker ps --format "{{.Names}}" 2>/dev/null | grep -q "^${GITEA_CONTAINER}$"; then
        GITEA_IP=$(hostname -I | awk '{print $1}')
        log "Gitea running locally — using $GITEA_IP"
    elif command -v tailscale >/dev/null 2>&1; then
        # Try each known peer until we find one hosting Gitea
        while IFS= read -r peer_ip; do
            if ssh -i "$GITEA_SSH_KEY" -p "$SSH_PORT" \
                   -o ConnectTimeout=3 -o StrictHostKeyChecking=no \
                   -o BatchMode=yes "git@${peer_ip}" 2>&1 | grep -q "varaverk\|Gitea\|gitea"; then
                GITEA_IP="$peer_ip"
                log "Gitea found on Tailscale peer $GITEA_IP"
                break
            fi
        done < <(tailscale status 2>/dev/null | \
                 awk '{print $1}' | grep -E '^[0-9]+\.[0-9]+\.[0-9]+\.[0-9]+$')
    fi

    if [[ -z "$GITEA_IP" && -n "$GITEA_DOMAIN" ]]; then
        log "local/Tailscale lookup failed — falling back to domain: $GITEA_DOMAIN"
        GITEA_IP="$GITEA_DOMAIN"
    fi

    # init-in-place — git clone would fail because the dir already has files.
    git -C "$SCRIPTS_DIR" init >> "$LOG" 2>&1

    CLONED=false
    if [[ -n "$GITEA_IP" && -f "$GITEA_SSH_KEY" ]]; then
        GITEA_URL="ssh://git@${GITEA_IP}:${SSH_PORT}/${GITEA_REPO_PATH}"
        log "trying Gitea: $GITEA_URL"
        git -C "$SCRIPTS_DIR" remote add origin "$GITEA_URL" >> "$LOG" 2>&1
        if GIT_SSH_COMMAND="ssh -i $GITEA_SSH_KEY -p $SSH_PORT -o StrictHostKeyChecking=no" \
           GIT_TERMINAL_PROMPT=0 \
           git -C "$SCRIPTS_DIR" fetch --depth=1 origin "$BRANCH" >> "$LOG" 2>&1; then
            git -C "$SCRIPTS_DIR" reset --hard FETCH_HEAD >> "$LOG" 2>&1
            git -C "$SCRIPTS_DIR" branch -M "$BRANCH" >> "$LOG" 2>&1
            git -C "$SCRIPTS_DIR" branch --set-upstream-to=origin/"$BRANCH" "$BRANCH" >> "$LOG" 2>&1
            log "scripts installed from Gitea ($GITEA_IP)"
            CLONED=true
        else
            log "Gitea fetch failed — falling back to GitHub"
            git -C "$SCRIPTS_DIR" remote remove origin >> "$LOG" 2>&1 || true
        fi
    fi

    if [[ "$CLONED" == false ]]; then
        log "trying GitHub: $GITHUB"
        git -C "$SCRIPTS_DIR" remote add origin "$GITHUB" >> "$LOG" 2>&1
        if GIT_TERMINAL_PROMPT=0 \
           git -C "$SCRIPTS_DIR" fetch --depth=1 origin "$BRANCH" >> "$LOG" 2>&1; then
            git -C "$SCRIPTS_DIR" reset --hard FETCH_HEAD >> "$LOG" 2>&1
            git -C "$SCRIPTS_DIR" branch -M "$BRANCH" >> "$LOG" 2>&1
            git -C "$SCRIPTS_DIR" branch --set-upstream-to=origin/"$BRANCH" "$BRANCH" >> "$LOG" 2>&1
            log "scripts installed from GitHub"
            CLONED=true
        else
            log "WARNING: both Gitea and GitHub failed — scripts not installed, retry when network is up"
            exit 0
        fi
    fi
else
    log "repo present — leaving scripts untouched (update from the UI)"
fi

# Seed master.conf from template if absent.
mkdir -p "$CONF_DIR"
if [[ ! -f "$CONF_DIR/master.conf" && -f "$DEPLOY_DIR/master.conf.template" ]]; then
    cp "$DEPLOY_DIR/master.conf.template" "$CONF_DIR/master.conf"
    log "seeded master.conf from template"
fi
log "install step complete"
]]>
</INLINE>
</FILE>

<!--
  ── 3. Remove ───────────────────────────────────────────────────────────────────
  Stops background scripts, removes cron, the installed package, and flash config.
  Scripts/conf in appdata are left intact (delete manually for a full wipe).
  ────────────────────────────────────────────────────────────────────────────────
-->
<FILE Run="/bin/bash" Method="remove">
<INLINE>
<![CDATA[
#!/bin/bash
PLUGIN="varaverk"
CFG_DIR="/boot/config/plugins/$PLUGIN"
CFG_FILE="$CFG_DIR/varaverk.cfg"
CRON_FILE="$CFG_DIR/varaverk.cron"
WEB_DIR="/usr/local/emhttp/plugins/$PLUGIN"
log() { echo "[Varaverk remove] $*"; }

[[ -f "$CFG_FILE" ]] && _sd=$(grep -oP '(?<=SCRIPTS_DIR=")[^"]+' "$CFG_FILE" 2>/dev/null)
SCRIPTS_DIR="${_sd:-$CFG_DIR}"

# Stop continuous background scripts.
if [[ -f "$SCRIPTS_DIR/Fallback/fallback.sh" ]]; then
    bash "$SCRIPTS_DIR/Fallback/fallback.sh" --stop 2>/dev/null && log "fallback.sh stopped" || true
fi
pkill -f "run_job.sh" 2>/dev/null || true
pkill -f "watchdog_orchestrator.sh" 2>/dev/null || true

# Remove cron entries.
if [[ -f "$CRON_FILE" ]]; then
    rm -f "$CRON_FILE"
    /usr/local/sbin/update_cron 2>/dev/null || true
    log "cron removed"
fi
rm -f /etc/cron.d/varaverk

# Remove the installed package (and its RAM files).
removepkg "$PLUGIN" 2>/dev/null || true
[[ -L "$WEB_DIR" ]] && rm -f "$WEB_DIR"
[[ -d "$WEB_DIR" ]] && rm -rf "$WEB_DIR"
log "web files removed"

# Remove flash config (incl. cached .txz).
rm -rf "$CFG_DIR"
log "flash config removed"
log "done — scripts/conf in $SCRIPTS_DIR preserved (delete manually for full wipe)"
]]>
</INLINE>
</FILE>

</PLUGIN>
