Files
affiliate_dash/start.sh
T
2026-07-31 12:57:17 +08:00

194 lines
5.6 KiB
Bash
Executable File
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
#!/usr/bin/env bash
# 一键启动前后端开发服务
set -euo pipefail
ROOT="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)"
PIDS=()
log() { echo ">>> $*"; }
# 加载仓库根目录 .envsource 后可供 PORT / FRONTEND_PORT 使用)
if [[ -f "$ROOT/.env" ]]; then
set -a
# shellcheck disable=SC1091
source "$ROOT/.env"
set +a
log "已加载 $ROOT/.env"
elif [[ -f "$ROOT/.env.example" ]]; then
log "未找到 .env,可执行: cp .env.example .env"
fi
BACKEND_PORT="${PORT:-8080}"
FRONTEND_PORT="${FRONTEND_PORT:-5173}"
POSTGRES_USER="${POSTGRES_USER:-affiliate}"
POSTGRES_PASSWORD="${POSTGRES_PASSWORD:-affiliate_dev_password}"
POSTGRES_DB="${POSTGRES_DB:-affiliate_dash}"
POSTGRES_PORT="${POSTGRES_PORT:-5432}"
POSTGRES_IMAGE="${POSTGRES_IMAGE:-docker.m.daocloud.io/library/postgres:16-alpine}"
DEV_DB_CONTAINER="${DEV_DB_CONTAINER:-affiliate_dash_postgres_dev}"
TZ="${TZ:-Asia/Shanghai}"
DATABASE_URL="${DATABASE_URL:-postgres://${POSTGRES_USER}:${POSTGRES_PASSWORD}@127.0.0.1:${POSTGRES_PORT}/${POSTGRES_DB}?sslmode=disable&TimeZone=${TZ}}"
export DATABASE_URL
export TZ
# 结束指定端口上的进程(避免残留占用)
free_port() {
local port=$1
local pids
pids=$(lsof -tiTCP:"$port" -sTCP:LISTEN 2>/dev/null || true)
if [[ -n "${pids}" ]]; then
log "端口 ${port} 已被占用,正在释放: ${pids}"
# shellcheck disable=SC2086
kill ${pids} 2>/dev/null || true
sleep 0.5
pids=$(lsof -tiTCP:"$port" -sTCP:LISTEN 2>/dev/null || true)
if [[ -n "${pids}" ]]; then
# shellcheck disable=SC2086
kill -9 ${pids} 2>/dev/null || true
fi
fi
}
postgres_container_exists() {
docker ps -a --format '{{.Names}}' | grep -qx "$DEV_DB_CONTAINER"
}
postgres_container_running() {
docker ps --format '{{.Names}}' | grep -qx "$DEV_DB_CONTAINER"
}
postgres_container_timezone_ready() {
local env cmd
env="$(docker inspect -f '{{range .Config.Env}}{{println .}}{{end}}' "$DEV_DB_CONTAINER" 2>/dev/null || true)"
cmd="$(docker inspect -f '{{json .Config.Cmd}}' "$DEV_DB_CONTAINER" 2>/dev/null || true)"
grep -qx "TZ=${TZ}" <<<"$env" && grep -qx "PGTZ=${TZ}" <<<"$env" && [[ "$cmd" == *"timezone=${TZ}"* ]]
}
ensure_postgres() {
if command -v docker >/dev/null 2>&1 && postgres_container_exists; then
if ! postgres_container_timezone_ready; then
log "检测到旧 PostgreSQL 开发容器缺少时区配置,重建容器并保留数据卷: ${DEV_DB_CONTAINER}"
docker rm -f "$DEV_DB_CONTAINER" >/dev/null
fi
elif (echo >"/dev/tcp/127.0.0.1/${POSTGRES_PORT}") >/dev/null 2>&1; then
log "检测到本机 PostgreSQL 端口已可访问: ${POSTGRES_PORT}"
return 0
fi
if ! command -v docker >/dev/null 2>&1; then
log "未找到 Docker,请确认本机 PostgreSQL 已可通过 DATABASE_URL 访问"
return 0
fi
if postgres_container_running; then
log "PostgreSQL 开发容器已运行: ${DEV_DB_CONTAINER}"
elif postgres_container_exists; then
log "启动 PostgreSQL 开发容器: ${DEV_DB_CONTAINER}"
docker start "$DEV_DB_CONTAINER" >/dev/null
else
log "创建 PostgreSQL 开发容器: ${DEV_DB_CONTAINER}"
docker run -d \
--name "$DEV_DB_CONTAINER" \
-p "${POSTGRES_PORT}:5432" \
-e POSTGRES_USER="$POSTGRES_USER" \
-e POSTGRES_PASSWORD="$POSTGRES_PASSWORD" \
-e POSTGRES_DB="$POSTGRES_DB" \
-e TZ="$TZ" \
-e PGTZ="$TZ" \
-v "${DEV_DB_CONTAINER}-data:/var/lib/postgresql/data" \
"$POSTGRES_IMAGE" \
-c timezone="$TZ" >/dev/null
fi
for i in $(seq 1 40); do
if docker exec "$DEV_DB_CONTAINER" pg_isready -U "$POSTGRES_USER" -d "$POSTGRES_DB" >/dev/null 2>&1; then
log "PostgreSQL 已就绪"
return 0
fi
sleep 0.5
done
echo "错误: PostgreSQL 启动超时"
docker logs "$DEV_DB_CONTAINER" 2>/dev/null || true
exit 1
}
cleanup() {
trap - INT TERM EXIT
echo ""
log "正在停止前后端..."
for pid in "${PIDS[@]:-}"; do
if kill -0 "$pid" 2>/dev/null; then
# 结束子进程树
pkill -P "$pid" 2>/dev/null || true
kill "$pid" 2>/dev/null || true
fi
done
free_port "$BACKEND_PORT"
free_port "$FRONTEND_PORT"
wait 2>/dev/null || true
log "已全部停止"
exit 0
}
trap cleanup INT TERM
# 检查依赖
if ! command -v go >/dev/null 2>&1; then
echo "错误: 未找到 go,请先安装 Go"
exit 1
fi
if ! command -v npm >/dev/null 2>&1; then
echo "错误: 未找到 npm,请先安装 Node.js"
exit 1
fi
# 首次安装前端依赖
if [[ ! -d "$ROOT/frontend/node_modules" ]]; then
log "安装前端依赖..."
(cd "$ROOT/frontend" && npm install)
fi
free_port "$BACKEND_PORT"
free_port "$FRONTEND_PORT"
ensure_postgres
log "启动后端 http://localhost:${BACKEND_PORT}"
(
cd "$ROOT/backend"
export PORT="$BACKEND_PORT"
go run ./cmd/server
) &
PIDS+=($!)
# 等后端健康检查就绪(最多约 15 秒)
for i in $(seq 1 30); do
if curl -sf "http://127.0.0.1:${BACKEND_PORT}/health" >/dev/null 2>&1; then
log "后端已就绪"
break
fi
if ! kill -0 "${PIDS[0]}" 2>/dev/null; then
echo "错误: 后端启动失败"
cleanup
fi
sleep 0.5
done
log "启动前端 http://localhost:${FRONTEND_PORT}"
(
cd "$ROOT/frontend"
npm run dev -- --host --port "$FRONTEND_PORT"
) &
PIDS+=($!)
echo ""
log "========================================"
log " 游戏皮肤分销系统 已启动"
log " 前端: http://localhost:${FRONTEND_PORT}"
log " 后端: http://localhost:${BACKEND_PORT}"
log " 账号: admin / admin123"
log " 按 Ctrl+C 停止全部服务"
log "========================================"
echo ""
# 任一子进程退出则整体清理
wait -n 2>/dev/null || wait
cleanup