#!/usr/bin/env bash set -euo pipefail ROOT="$(CDPATH= cd -- "$(dirname "$0")/.." && pwd)" HOST="${STORYFORGE_PUBLIC_HOST:-111.231.132.51}" USER_NAME="${STORYFORGE_PUBLIC_USER:-ubuntu}" PORT="${STORYFORGE_PUBLIC_PORT:-22}" BASE_URL="${STORYFORGE_PUBLIC_BASE_URL:-https://storyforge.hyzq.net}" REMOTE_BASE="${STORYFORGE_PUBLIC_REMOTE_BASE:-/home/ubuntu/storyforge}" KEYCHAIN_SERVICE="${STORYFORGE_PUBLIC_KEYCHAIN_SERVICE:-ai-glasses-debug-ssh}" SYNC_COLLECTOR="${STORYFORGE_PUBLIC_SYNC_COLLECTOR:-1}" CURL_MAX_TIME="${STORYFORGE_PUBLIC_CURL_MAX_TIME:-60}" need_cmd() { if ! command -v "$1" >/dev/null 2>&1; then echo "missing required command: $1" >&2 exit 1 fi } need_cmd rsync need_cmd ssh need_cmd curl resolve_password() { if [ -n "${STORYFORGE_PUBLIC_PASSWORD:-}" ]; then printf '%s' "${STORYFORGE_PUBLIC_PASSWORD}" return 0 fi if [ -n "$KEYCHAIN_SERVICE" ] && command -v security >/dev/null 2>&1; then security find-generic-password -a "$USER_NAME" -s "$KEYCHAIN_SERVICE" -w 2>/dev/null || true return 0 fi return 0 } PASSWORD="$(resolve_password)" SSH_OPTS=(-p "$PORT" -o StrictHostKeyChecking=no -o UserKnownHostsFile=/dev/null) RSYNC_RSH=(ssh "${SSH_OPTS[@]}") run_ssh() { if [ -n "$PASSWORD" ]; then need_cmd sshpass SSHPASS="$PASSWORD" sshpass -e ssh "${SSH_OPTS[@]}" "$USER_NAME@$HOST" "$@" else ssh "${SSH_OPTS[@]}" "$USER_NAME@$HOST" "$@" fi } run_rsync() { if [ -n "$PASSWORD" ]; then need_cmd sshpass SSHPASS="$PASSWORD" sshpass -e rsync -az --delete -e "$(printf '%q ' "${RSYNC_RSH[@]}")" "$@" else rsync -az --delete -e "$(printf '%q ' "${RSYNC_RSH[@]}")" "$@" fi } echo "[1/6] backup remote web" run_ssh "mkdir -p '$REMOTE_BASE/backups'; ts=\$(date +%Y%m%d-%H%M%S); tar -czf '$REMOTE_BASE/backups/storyforge-web-v4-'\$ts'.tgz' -C '$REMOTE_BASE/web' storyforge-web-v4 && echo web-backup:'$REMOTE_BASE/backups/storyforge-web-v4-'\$ts'.tgz'" if [ "$SYNC_COLLECTOR" = "1" ]; then echo "[2/6] backup remote collector app" run_ssh "mkdir -p '$REMOTE_BASE/backups'; ts=\$(date +%Y%m%d-%H%M%S); tar -czf '$REMOTE_BASE/backups/storyforge-collector-app-'\$ts'.tgz' -C '$REMOTE_BASE/collector-service' app && echo collector-backup:'$REMOTE_BASE/backups/storyforge-collector-app-'\$ts'.tgz'" else echo "[2/6] skip collector backup" fi echo "[3/6] sync web/storyforge-web-v4" run_rsync "$ROOT/web/storyforge-web-v4/" "$USER_NAME@$HOST:$REMOTE_BASE/web/storyforge-web-v4/" if [ "$SYNC_COLLECTOR" = "1" ]; then echo "[4/6] sync collector-service/app" if [ -n "$PASSWORD" ]; then need_cmd sshpass SSHPASS="$PASSWORD" sshpass -e rsync -az --delete \ --exclude '__pycache__/' \ --exclude '*.pyc' \ -e "$(printf '%q ' "${RSYNC_RSH[@]}")" \ "$ROOT/collector-service/app/" \ "$USER_NAME@$HOST:$REMOTE_BASE/collector-service/app/" else rsync -az --delete \ --exclude '__pycache__/' \ --exclude '*.pyc' \ -e "$(printf '%q ' "${RSYNC_RSH[@]}")" \ "$ROOT/collector-service/app/" \ "$USER_NAME@$HOST:$REMOTE_BASE/collector-service/app/" fi else echo "[4/6] skip collector sync" fi echo "[5/6] restart remote services" if [ "$SYNC_COLLECTOR" = "1" ]; then run_ssh "sudo systemctl restart storyforge-collector storyforge-web-v4 && sleep 2 && systemctl is-active storyforge-collector storyforge-web-v4" else run_ssh "sudo systemctl restart storyforge-web-v4 && sleep 2 && systemctl is-active storyforge-web-v4" fi echo "[6/6] verify public health" curl -fsS --max-time "$CURL_MAX_TIME" "$BASE_URL/healthz" >/dev/null "$ROOT/scripts/smoke_public_storyforge.sh" echo "public deploy finished: $BASE_URL"