#!/usr/bin/env bash # hf-entrypoint.sh - HF Spaces 容器入口 set -euo pipefail echo "[$(date -u +%Y-%m-%dT%H:%M:%SZ)] hf-entrypoint: starting..." # ============================================ # 0. 保存环境变量到 /etc/profile.d,供后续 bash 会话使用 # ============================================ if [[ -x /usr/local/bin/save-env.sh ]]; then /usr/local/bin/save-env.sh else echo "[$(date -u +%Y-%m-%dT%H:%M:%SZ)] hf-entrypoint: warning: save-env.sh not found, skipping env export" fi # 加载已保存的环境变量 if [[ -f /etc/profile.d/openclaw-env.sh ]]; then # shellcheck source=/dev/null source /etc/profile.d/openclaw-env.sh echo "[$(date -u +%Y-%m-%dT%H:%M:%SZ)] hf-entrypoint: loaded environment from /etc/profile.d/openclaw-env.sh" fi # ============================================ # 1. 启动 supervisord(管理 cron + openclaw-gateway) # ============================================ echo "[$(date -u +%Y-%m-%dT%H:%M:%SZ)] hf-entrypoint: starting supervisord..." mkdir -p /var/run /var/log/supervisor /var/log/hf-entrypoint /usr/bin/supervisord -c /etc/supervisor/supervisord.conf \ >> /var/log/hf-entrypoint/supervisord-stdout.log \ 2>> /var/log/hf-entrypoint/supervisord-stderr.log & SUPERVISORD_PID=$! echo "[$(date -u +%Y-%m-%dT%H:%M:%SZ)] hf-entrypoint: supervisord started (pid=$SUPERVISORD_PID)" while [[ ! -f /var/run/supervisord.pid ]]; do sleep 0.5 done echo "[$(date -u +%Y-%m-%dT%H:%M:%SZ)] hf-entrypoint: supervisord is ready" # 1.1 等待 openclaw-gateway 完成备份恢复 # ============================================ echo "[$(date -u +%Y-%m-%dT%H:%M:%SZ)] hf-entrypoint: waiting for openclaw-gateway to complete restore..." RESTORE_COMPLETED_FILE="/tmp/openclaw-restore-completed" OPENCLAW_LOG_FILE="/var/log/hf-entrypoint/openclaw-gateway-stdout.log" RESTORE_LOG_FILE="/var/log/openclaw/restore.log" WAITED=0 LAST_RESTORE_LINE=0 PROGRESS_CHECK_INTERVAL=20 mkdir -p "$(dirname "$RESTORE_LOG_FILE")" show_restore_progress() { if [[ -f "$RESTORE_LOG_FILE" ]]; then local current_lines current_lines=$(wc -l < "$RESTORE_LOG_FILE" 2>/dev/null || echo "0") if [[ -n "$current_lines" ]] && [[ "$current_lines" -gt "$LAST_RESTORE_LINE" ]]; then local new_lines=$((current_lines - LAST_RESTORE_LINE)) echo "[$(date -u +%Y-%m-%dT%H:%M:%SZ)] hf-entrypoint: --- Restore log ($new_lines new lines) ---" tail -n "$new_lines" "$RESTORE_LOG_FILE" | while IFS= read -r line; do echo "[$(date -u +%Y-%m-%dT%H:%M:%SZ)] $line" done LAST_RESTORE_LINE="$current_lines" fi fi } while true; do # 首次进入循环时显示诊断信息 if [[ $WAITED -eq 0 ]]; then echo "[$(date -u +%Y-%m-%dT%H:%M:%SZ)] hf-entrypoint: waiting for restore completion..." echo "[$(date -u +%Y-%m-%dT%H:%M:%SZ)] hf-entrypoint: RESTORE_LOG_FILE=$RESTORE_LOG_FILE" echo "[$(date -u +%Y-%m-%dT%H:%M:%SZ)] hf-entrypoint: RESTORE_COMPLETED_FILE=$RESTORE_COMPLETED_FILE" fi # 显示恢复日志进度 show_restore_progress # 只检查恢复完成标志文件 if [[ -f "$RESTORE_COMPLETED_FILE" ]]; then echo "[$(date -u +%Y-%m-%dT%H:%M:%SZ)] hf-entrypoint: ✓ Restore completed" # 显示恢复日志的最后几行 if [[ -f "$RESTORE_LOG_FILE" ]]; then echo "[$(date -u +%Y-%m-%dT%H:%M:%SZ)] hf-entrypoint: --- Final restore log ---" tail -n 5 "$RESTORE_LOG_FILE" | while IFS= read -r line; do echo "[$(date -u +%Y-%m-%dT%H:%M:%SZ)] $line" done fi rm -f "$RESTORE_COMPLETED_FILE" break fi sleep 2 WAITED=$((WAITED + 2)) # 每n秒输出一次等待进度 if [[ $((WAITED % PROGRESS_CHECK_INTERVAL)) -eq 0 ]]; then echo "[$(date -u +%Y-%m-%dT%H:%M:%SZ)] hf-entrypoint: still waiting for restore... (${WAITED}s)" show_restore_progress fi done echo "[$(date -u +%Y-%m-%dT%H:%M:%SZ)] hf-entrypoint: ✓ Restore wait completed (${WAITED}s), proceeding with PM2 startup" # 1.2 确保 cron daemon 运行 if ! pgrep -x cron >/dev/null 2>&1; then echo "[$(date -u +%Y-%m-%dT%H:%M:%SZ)] hf-entrypoint: starting cron daemon..." /usr/sbin/cron fi # ============================================ # 2. 启动 PM2 管理, 附加的 node 进程(如果需要) # ============================================ echo "[$(date -u +%Y-%m-%dT%H:%M:%SZ)] hf-entrypoint: starting PM2 for others..." mkdir -p /root/.pm2 /var/log/hf-entrypoint if grep -qE '"name"\s*:' /app/pm2/ecosystem.config.js 2>/dev/null; then /usr/bin/pm2-runtime /app/pm2/ecosystem.config.js \ >> /var/log/hf-entrypoint/pm2-stdout.log \ 2>> /var/log/hf-entrypoint/pm2-stderr.log & PM2_PID=$! echo "[$(date -u +%Y-%m-%dT%H:%M:%SZ)] hf-entrypoint: PM2 started (pid=$PM2_PID)" else echo "[$(date -u +%Y-%m-%dT%H:%M:%SZ)] hf-entrypoint: PM2: no applications defined in ecosystem.config.js, skipping..." PM2_PID="" fi # ============================================ # 3. 检查 BT Panel 状态并配置自定义首页 # ============================================ echo "[$(date -u +%Y-%m-%dT%H:%M:%SZ)] hf-entrypoint: checking BT Panel status..." if [[ -f "/www/server/panel/default.pl" ]]; then echo "[$(date -u +%Y-%m-%dT%H:%M:%SZ)] hf-entrypoint: BT Panel is installed..." # 启动宝塔面板 bt start bt default else echo "[$(date -u +%Y-%m-%dT%H:%M:%SZ)] hf-entrypoint: BT Panel not installed" fi # ============================================ # 4. 信号转发(确保 PID 1 的 SIGTERM 能传到 supervisord) # ============================================ signal_handler() { echo "[$(date -u +%Y-%m-%dT%H:%M:%SZ)] hf-entrypoint: received SIGTERM, forwarding to supervisord..." kill -TERM "$SUPERVISORD_PID" 2>/dev/null || true kill -TERM "$PM2_PID" 2>/dev/null || true } trap signal_handler TERM INT QUIT # ============================================ # 5. 启动 node hf-server.js 作为 PID 1 # ============================================ echo "[$(date -u +%Y-%m-%dT%H:%M:%SZ)] hf-entrypoint: starting node server.js..." cd /app exec node hf-server.js