#!/bin/sh # Jay 9router HF Space — bucket-sync wrapper entrypoint. # # Persists 9router SQLite config through HF Bucket. On boot, restore the latest # SQLite snapshot from the bucket. While running, backup frequently so manual # restarts do not lose freshly edited config. On shutdown, run one final # best-effort backup before exiting. set -eu DATA_DIR="${DATA_DIR:-/app/data}" HF_BUCKET_ID="${HF_BUCKET_ID:-hank-jay/9router-storage}" HF_BUCKET_PREFIX="${HF_BUCKET_PREFIX:-}" # Keep this short: config edits followed by quick restarts should not be lost. SYNC_INTERVAL="${SYNC_INTERVAL:-60}" INITIAL_SYNC_DELAY="${INITIAL_SYNC_DELAY:-10}" RESTORE_DIR="$DATA_DIR/.bucket-restore" mkdir -p "$DATA_DIR/db/backups" APP_PID="" SYNC_PID="" bucket_uri() { if [ -n "$HF_BUCKET_PREFIX" ]; then printf 'hf://buckets/%s/%s' "$HF_BUCKET_ID" "$HF_BUCKET_PREFIX" else printf 'hf://buckets/%s' "$HF_BUCKET_ID" fi } run_backup() { if [ -z "${HF_TOKEN:-}" ]; then echo "[sync] HF_TOKEN missing — skip backup" >&2 return 0 fi if /opt/9router-sync/backup.sh; then echo "[sync] backup ok" else echo "[sync] backup failed (will retry next interval)" >&2 return 1 fi } restore_from_bucket() { if [ -z "${HF_TOKEN:-}" ]; then return 0 fi BUCKET_URI="$(bucket_uri)" echo "[start] Pulling SQLite snapshot from bucket: $BUCKET_URI" rm -rf "$RESTORE_DIR" mkdir -p "$RESTORE_DIR" "$DATA_DIR/db" # hf buckets sync is directory-oriented. Sync bucket root/prefix to a temp # directory, then copy only the SQLite DB we need at runtime. if hf buckets sync "$BUCKET_URI" "$RESTORE_DIR" >/dev/null 2>&1; then if [ -s "$RESTORE_DIR/db/data.sqlite" ]; then cp "$RESTORE_DIR/db/data.sqlite" "$DATA_DIR/db/data.sqlite" echo "[start] Snapshot restored: $DATA_DIR/db/data.sqlite" else echo "[start] Bucket sync succeeded but db/data.sqlite missing — starting clean" >&2 fi else echo "[start] No prior snapshot in bucket (or restore failed) — starting clean" fi rm -rf "$RESTORE_DIR" } shutdown() { echo "[start] shutdown signal received — final backup" if [ -n "$SYNC_PID" ]; then kill "$SYNC_PID" 2>/dev/null || true fi run_backup || true if [ -n "$APP_PID" ]; then kill "$APP_PID" 2>/dev/null || true wait "$APP_PID" 2>/dev/null || true fi exit 0 } trap shutdown INT TERM if [ -z "${HF_TOKEN:-}" ]; then echo "[start] WARNING: HF_TOKEN not set — running with EPHEMERAL data." >&2 echo "[start] Set HF_TOKEN as a Space secret to enable persistence." >&2 else restore_from_bucket ( sleep "$INITIAL_SYNC_DELAY" run_backup || true while true; do sleep "$SYNC_INTERVAL" run_backup || true done ) & SYNC_PID="$!" fi npm run start & APP_PID="$!" set +e wait "$APP_PID" APP_STATUS="$?" set -e if [ -n "$SYNC_PID" ]; then kill "$SYNC_PID" 2>/dev/null || true fi run_backup || true exit "$APP_STATUS"