Spaces:
Runtime error
Runtime error
| # 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" | |