#!/usr/bin/env bash set -euo pipefail echo "===== Application Startup at $(date '+%Y-%m-%d %H:%M:%S') =====" export APP_HOME="${APP_HOME:-/app}" export SUB2API_DATA_DIR="${SUB2API_DATA_DIR:-/app/data}" export PGDATA="${PGDATA:-/app/pgdata}" export REDIS_DIR="${REDIS_DIR:-/app/redis}" export VENV_PATH="${VENV_PATH:-/app/venv}" mkdir -p "$APP_HOME" "$SUB2API_DATA_DIR" "$PGDATA" "$REDIS_DIR" /var/log/supervisor # ========================================== # 可选:重置本地状态(仅调试/首次重新初始化时使用) # ========================================== if [[ "${RESET_APP_STATE:-false}" == "true" ]]; then echo "[reset] wiping local app state..." rm -rf "$PGDATA"/* || true rm -rf "$SUB2API_DATA_DIR"/* || true fi # ============================= # 基础运行参数 # ============================= export AUTO_SETUP="${AUTO_SETUP:-true}" export SERVER_HOST="${SERVER_HOST:-0.0.0.0}" export SERVER_PORT="${SERVER_PORT:-8080}" export SERVER_MODE="${SERVER_MODE:-release}" export RUN_MODE="${RUN_MODE:-standard}" export TZ="${TZ:-Asia/Singapore}" # ============================= # PostgreSQL(本地) # ============================= export POSTGRES_USER="${POSTGRES_USER:-sub2api}" export POSTGRES_PASSWORD="${POSTGRES_PASSWORD:-change_me_please}" export POSTGRES_DB="${POSTGRES_DB:-sub2api}" # 强制 sub2api 使用本地 PostgreSQL export DATABASE_HOST="127.0.0.1" export DATABASE_PORT="5432" export DATABASE_USER="${POSTGRES_USER}" export DATABASE_PASSWORD="${POSTGRES_PASSWORD}" export DATABASE_DBNAME="${POSTGRES_DB}" export DATABASE_SSLMODE="disable" export DATABASE_MAX_OPEN_CONNS="${DATABASE_MAX_OPEN_CONNS:-50}" export DATABASE_MAX_IDLE_CONNS="${DATABASE_MAX_IDLE_CONNS:-10}" # bootstrap 阶段走 /tmp socket export PGHOST="/tmp" # ============================= # Redis(本地) # ============================= export REDIS_HOST="127.0.0.1" export REDIS_PORT="6379" export REDIS_PASSWORD="${REDIS_PASSWORD:-}" export REDIS_DB="${REDIS_DB:-0}" # ============================= # 管理员和密钥 # ============================= export ADMIN_EMAIL="${ADMIN_EMAIL:-admin@example.com}" export ADMIN_PASSWORD="${ADMIN_PASSWORD:-change_me_please}" export JWT_SECRET="${JWT_SECRET:-}" export TOTP_ENCRYPTION_KEY="${TOTP_ENCRYPTION_KEY:-}" echo "[debug] ADMIN_EMAIL=${ADMIN_EMAIL}" echo "[debug] ADMIN_PASSWORD_LEN=$(printf %s "$ADMIN_PASSWORD" | wc -c | tr -d ' ')" # ============================= # 备份 / 恢复控制 # ============================= export AUTO_RESTORE_FROM_DATASET="${AUTO_RESTORE_FROM_DATASET:-true}" export APPLY_CONFIG_OVERRIDE="${APPLY_CONFIG_OVERRIDE:-false}" # ============================= # 启动前校验密钥格式 # ============================= validate_hex_even() { local name="$1" local value="$2" if [[ -z "$value" ]]; then echo "[fatal] ${name} is empty" exit 1 fi if ! echo -n "$value" | grep -Eq '^[0-9a-fA-F]+$'; then echo "[fatal] ${name} must be hex only" exit 1 fi local len len=$(echo -n "$value" | wc -c | tr -d ' ') if (( len % 2 != 0 )); then echo "[fatal] ${name} must be even-length hex, got length=${len}" exit 1 fi } validate_hex_even "JWT_SECRET" "$JWT_SECRET" validate_hex_even "TOTP_ENCRYPTION_KEY" "$TOTP_ENCRYPTION_KEY" if [[ ! -x "$VENV_PATH/bin/python" ]]; then echo "[fatal] Python venv not found at $VENV_PATH" exit 1 fi # ============================= # PostgreSQL 二进制目录 # ============================= PGBIN="/usr/lib/postgresql/15/bin" if [[ ! -x "$PGBIN/postgres" ]]; then echo "[fatal] PostgreSQL binary not found at $PGBIN/postgres" ls -lah /usr/lib/postgresql || true exit 1 fi # ============================= # 目录权限 # ============================= mkdir -p "$PGDATA" chown -R "$(whoami)":"$(whoami)" "$PGDATA" chmod 700 "$PGDATA" fresh_db=false if [[ ! -s "$PGDATA/PG_VERSION" ]]; then fresh_db=true fi # 如果是损坏的半初始化目录,先清理 if [[ -d "$PGDATA" && ! -s "$PGDATA/PG_VERSION" ]]; then echo "[init] Cleaning incomplete PGDATA..." rm -rf "$PGDATA"/* fi # ============================= # 初始化 PostgreSQL # ============================= if [[ ! -s "$PGDATA/PG_VERSION" ]]; then echo "[init] Initializing PostgreSQL data directory..." "$PGBIN/initdb" -D "$PGDATA" > /tmp/initdb.log 2>&1 || { echo "[fatal] initdb failed" echo "===== /tmp/initdb.log =====" cat /tmp/initdb.log || true exit 1 } chmod 700 "$PGDATA" cat >> "$PGDATA/postgresql.conf" < "$PGDATA/pg_hba.conf" </dev/null 2>&1; then break fi sleep 1 done echo "[init] Creating/updating application role..." psql -h /tmp -U "$(whoami)" -d postgres -v ON_ERROR_STOP=1 < /app/data/config.yaml" else echo "[config] /app/config.override.yaml not found, skipping" fi fi # ============================= # 生成本地 Redis 配置 # ============================= mkdir -p "$REDIS_DIR" cat > "$REDIS_DIR/redis.conf" <> "$REDIS_DIR/redis.conf" fi # ============================= # 调试:启动完成后查看 users 表 # ============================= ( sleep 25 echo "[debug] current users in DB:" psql -h /tmp -U "$(whoami)" -d "${POSTGRES_DB}" -c "select id, email, role, status, created_at from users order by id;" || true ) & echo "[start] Launching supervisord..." exec /usr/bin/supervisord -c /etc/supervisor/conf.d/supervisord.conf -n