Files
c-relay-pg/deploy_local.sh
T
Laan Tungir 50653dc86a v2.1.38 - Custom backfill feature: ad-hoc backfill jobs with arbitrary NIP-01 filters + admin UI isolation
- New caching_custom_backfill_jobs and caching_custom_backfill_batches tables
- Admin API (POST create/cancel, GET list) at admin/api/custom_backfill.php
- Admin UI form with preset buttons and job status table on Backfill page
- Caching daemon module (custom_backfill.c) processes jobs independently
- pg_inbox functions for job/batch claim, progress update, and cancel
- Three batch modes: author-batched, id-batched, time-window scan
- Fixed done_batches overcount on job completion
- Admin config now environment-variable driven (C_RELAY_DB_*)
- admin/serve.sh supports separate instances for different databases
- make_and_restart_relay.sh only kills relay on target port, not all relays
2026-08-07 14:49:13 -04:00

249 lines
9.4 KiB
Bash
Executable File

#!/bin/bash
#
# deploy_local.sh - Deploy the local production relay on port 7777.
#
# This is SEPARATE from the test relay run by make_and_restart_relay.sh:
# - Test relay: port 8888, database "crelay", run from build/ by make_and_restart_relay.sh
# - Local prod: port 7777, database "crelay_prod", systemd service c-relay-pg-local
#
# The two relays share one PostgreSQL server (localhost:5432) but use
# different databases, so they are fully isolated: separate config tables,
# separate keypairs, separate event stores, separate admin keys.
#
# Usage:
# ./deploy_local.sh # install (first time) or update (subsequent)
# ./deploy_local.sh --install # force full install steps
# ./deploy_local.sh --status # just show service status
#
# Prerequisites:
# - build/c_relay_pg_static_x86_64 exists (run ./build_static.sh first)
# - PostgreSQL running on localhost:5432 with role "crelay" (password "crelay")
# - Database "crelay_prod" exists (this script creates it if missing)
set -euo pipefail
# --- Configuration ---
LOCAL_BINARY="build/c_relay_pg_static_x86_64"
LOCAL_CACHING_BINARY="build/caching_relay"
DEPLOY_DIR="$HOME/Storage/c_relay_pg"
DEPLOYED_BINARY="$DEPLOY_DIR/crelay"
DEPLOYED_CACHING_BINARY="$DEPLOY_DIR/caching_relay"
SERVICE_NAME="c-relay-pg-local"
SERVICE_FILE="systemd/c-relay-pg-local.service"
INSTALLED_SERVICE_PATH="/etc/systemd/system/${SERVICE_NAME}.service"
# Admin dashboard paths
LOCAL_ADMIN_DIR="admin"
PROD_ADMIN_DIR="admin_prod"
PROD_ADMIN_PORT=7077
# Database config (must match the service file ExecStart)
DB_HOST="127.0.0.1"
DB_NAME="crelay_prod"
DB_USER="crelay"
DB_PASSWORD="crelay"
RELAY_PORT=7777
# --- Helpers ---
RED='\033[0;31m'
GREEN='\033[0;32m'
YELLOW='\033[1;33m'
BLUE='\033[0;34m'
NC='\033[0m'
info() { echo -e "${BLUE}[INFO]${NC} $1"; }
success() { echo -e "${GREEN}[OK]${NC} $1"; }
warn() { echo -e "${YELLOW}[WARN]${NC} $1"; }
error() { echo -e "${RED}[ERROR]${NC} $1"; }
# --- Parse args ---
ACTION="auto"
case "${1:-}" in
--install) ACTION="install" ;;
--status) ACTION="status" ;;
--help|-h)
echo "Usage: $0 [--install|--status]"
echo ""
echo " (no arg) Install if needed, then update binary and restart"
echo " --install Force full install steps (service file, database, dirs)"
echo " --status Just show service status and exit"
exit 0
;;
esac
# --- Status-only mode ---
if [ "$ACTION" = "status" ]; then
info "Service status for ${SERVICE_NAME}:"
sudo systemctl status "$SERVICE_NAME" --no-pager -l || true
info "Port ${RELAY_PORT} listeners:"
ss -tlnp 2>/dev/null | grep ":${RELAY_PORT}" || echo " (nothing listening on ${RELAY_PORT})"
exit 0
fi
# --- Check binary exists ---
if [ ! -f "$LOCAL_BINARY" ]; then
error "Binary not found: $LOCAL_BINARY"
echo "Build it first with: ./build_static.sh"
exit 1
fi
# --- Check service file exists ---
if [ ! -f "$SERVICE_FILE" ]; then
error "Service file not found: $SERVICE_FILE"
exit 1
fi
# --- Ensure crelay_prod database exists ---
info "Checking PostgreSQL database '${DB_NAME}'..."
if ! PGPASSWORD="$DB_PASSWORD" psql -U "$DB_USER" -d "$DB_NAME" -h "$DB_HOST" -c "SELECT 1" >/dev/null 2>&1; then
info "Database '${DB_NAME}' does not exist or is not accessible. Creating it..."
if ! sudo -u postgres psql -tAc "SELECT 1 FROM pg_roles WHERE rolname='${DB_USER}'" | grep -q 1; then
error "PostgreSQL role '${DB_USER}' does not exist. Create it first:"
echo " sudo -u postgres psql -c \"CREATE ROLE ${DB_USER} LOGIN PASSWORD '${DB_PASSWORD}'\""
exit 1
fi
sudo -u postgres createdb --owner="$DB_USER" "$DB_NAME"
success "Created database '${DB_NAME}' owned by '${DB_USER}'"
else
success "Database '${DB_NAME}' already exists"
fi
# --- Ensure deploy directory exists ---
info "Ensuring deploy directory exists: $DEPLOY_DIR"
mkdir -p "$DEPLOY_DIR"
success "Deploy directory ready: $DEPLOY_DIR"
# --- Install or update service file ---
SERVICE_NEEDS_INSTALL=0
if [ "$ACTION" = "install" ]; then
SERVICE_NEEDS_INSTALL=1
elif [ ! -f "$INSTALLED_SERVICE_PATH" ]; then
warn "Service file not installed at $INSTALLED_SERVICE_PATH"
SERVICE_NEEDS_INSTALL=1
elif ! diff -q "$SERVICE_FILE" "$INSTALLED_SERVICE_PATH" >/dev/null 2>&1; then
warn "Service file has changed, updating $INSTALLED_SERVICE_PATH"
SERVICE_NEEDS_INSTALL=1
fi
if [ "$SERVICE_NEEDS_INSTALL" -eq 1 ]; then
info "Installing service file to $INSTALLED_SERVICE_PATH"
sudo cp "$SERVICE_FILE" "$INSTALLED_SERVICE_PATH"
sudo chown root:root "$INSTALLED_SERVICE_PATH"
sudo chmod 644 "$INSTALLED_SERVICE_PATH"
sudo systemctl daemon-reload
success "Service file installed and daemon reloaded"
fi
# --- Stop service before swapping binary ---
info "Stopping ${SERVICE_NAME} (if running)..."
sudo systemctl stop "$SERVICE_NAME" 2>/dev/null || true
# --- Kill anything on port 7777 (safety) ---
PORT_PID=$(lsof -ti :"$RELAY_PORT" 2>/dev/null || true)
if [ -n "$PORT_PID" ]; then
warn "Port ${RELAY_PORT} in use by PID(s) $PORT_PID, killing..."
kill -9 $PORT_PID 2>/dev/null || true
sleep 1
fi
# --- Kill stale caching_relay processes from the prod deploy dir ---
CACHING_PIDS=$(pgrep -f "$DEPLOYED_CACHING_BINARY" || true)
if [ -n "$CACHING_PIDS" ]; then
warn "Killing stale caching_relay processes: $CACHING_PIDS"
kill -9 $CACHING_PIDS 2>/dev/null || true
sleep 1
fi
# --- Install relay binary ---
info "Installing relay binary: $LOCAL_BINARY -> $DEPLOYED_BINARY"
cp "$LOCAL_BINARY" "$DEPLOYED_BINARY"
chmod +x "$DEPLOYED_BINARY"
success "Relay binary installed"
# --- Install caching binary (static MUSL build) if present ---
if [ -f "$LOCAL_CACHING_BINARY" ]; then
info "Installing caching binary: $LOCAL_CACHING_BINARY -> $DEPLOYED_CACHING_BINARY"
cp "$LOCAL_CACHING_BINARY" "$DEPLOYED_CACHING_BINARY"
chmod +x "$DEPLOYED_CACHING_BINARY"
success "Caching binary installed (not auto-started; enable via config when ready)"
else
warn "Caching binary not found at $LOCAL_CACHING_BINARY — skipping"
warn "Build it with: cd caching && make"
fi
# --- Sync admin dashboard files to production admin directory ---
info "Syncing admin dashboard to ${PROD_ADMIN_DIR}/..."
rsync -a --delete \
--exclude='lib/config.php' \
--exclude='php_server.log' \
--exclude='cache/' \
"${LOCAL_ADMIN_DIR}/" "${PROD_ADMIN_DIR}/"
# Preserve the production-specific config (points to crelay_prod)
cp "${PROD_ADMIN_DIR}/lib/config.php" "${PROD_ADMIN_DIR}/lib/config.php.prod" 2>/dev/null || true
cp "${LOCAL_ADMIN_DIR}/lib/config.php" "${PROD_ADMIN_DIR}/lib/config.php"
# Restore the production config (it already points to crelay_prod after our fix)
if [ -f "${PROD_ADMIN_DIR}/lib/config.php.prod" ]; then
cp "${PROD_ADMIN_DIR}/lib/config.php.prod" "${PROD_ADMIN_DIR}/lib/config.php"
rm "${PROD_ADMIN_DIR}/lib/config.php.prod"
fi
success "Admin dashboard synced"
# --- Restart production admin PHP server ---
info "Restarting production admin PHP server on port ${PROD_ADMIN_PORT}..."
pkill -f "php -S 127.0.0.1:${PROD_ADMIN_PORT}" 2>/dev/null || true
sleep 1
setsid php -S 127.0.0.1:${PROD_ADMIN_PORT} -t "${PROD_ADMIN_DIR}" > "${PROD_ADMIN_DIR}/php_server.log" 2>&1 < /dev/null &
disown $! 2>/dev/null
sleep 1
success "Production admin PHP server restarted on http://127.0.0.1:${PROD_ADMIN_PORT}"
# --- Enable and start the service ---
info "Enabling and starting ${SERVICE_NAME}..."
sudo systemctl enable "$SERVICE_NAME"
sudo systemctl restart "$SERVICE_NAME"
# --- Wait and verify ---
sleep 3
info "Service status:"
sudo systemctl status "$SERVICE_NAME" --no-pager -l || true
# --- Health check ---
info "Health check on port ${RELAY_PORT}..."
HEALTH_CODE=$(curl -s -o /dev/null -w "%{http_code}" "http://127.0.0.1:${RELAY_PORT}" 2>/dev/null || echo "000")
if [ "$HEALTH_CODE" = "200" ]; then
success "Relay is responding on http://127.0.0.1:${RELAY_PORT} (HTTP $HEALTH_CODE)"
else
warn "Relay returned HTTP $HEALTH_CODE on port ${RELAY_PORT} (may still be starting up)"
echo " Check logs with: sudo journalctl -u ${SERVICE_NAME} -f"
fi
# --- Database verification ---
info "Verifying database connection..."
if PGPASSWORD="$DB_PASSWORD" psql -U "$DB_USER" -d "$DB_NAME" -h "$DB_HOST" -c "SELECT current_user, current_database();" >/dev/null 2>&1; then
success "Database connection OK: ${DB_USER}@${DB_NAME}"
else
error "Could not connect to database ${DB_NAME} as ${DB_USER}"
fi
echo ""
echo "=========================================="
success "Local production relay deployed"
echo "=========================================="
echo "WebSocket endpoint: ws://127.0.0.1:${RELAY_PORT}"
echo "HTTP endpoint: http://127.0.0.1:${RELAY_PORT}"
echo "Admin dashboard: http://127.0.0.1:${PROD_ADMIN_PORT}"
echo "Database: ${DB_NAME} (isolated from test relay's 'crelay' db)"
echo "Service: ${SERVICE_NAME}"
echo "Deploy dir: $DEPLOY_DIR"
echo ""
echo "Logs: sudo journalctl -u ${SERVICE_NAME} -f"
echo "Status: ./deploy_local.sh --status"
echo ""
warn "IMPORTANT: On first startup, the admin private key is printed ONCE in the logs."
echo " Retrieve it with:"
echo " sudo journalctl -u ${SERVICE_NAME} --since=\"5 min ago\" | grep -i \"admin.*key\""
echo ""
echo "Test relay (port 8888) is unaffected — run it separately with ./make_and_restart_relay.sh"
echo "Test admin UI: http://127.0.0.1:8088"