refactor: 认证系统重构 + DevTools CLI 重写 + 文档全面更新
- auth: Login 简化为管理员始终通过 .env 验证,GetProfile 修正 admin DB 查询 - devtools: .sh/.bat 同步重写为完整 CLI (start/stop/status/logs/build/db:*) - docs: 新增 devtools.md,重写 Deploy.md (三种方式+Windows说明),更新 README/gateway-api - voice-service: DashScope 实时流式 STT 支持 - gateway: Phase 6 多模型配置 + 多端客户端管理 + WebSocket 增强 Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
This commit is contained in:
+447
-90
@@ -1,110 +1,467 @@
|
||||
#!/bin/bash
|
||||
# ========================================
|
||||
# Cyrene DevTools 启动脚本
|
||||
# 自动处理端口冲突、依赖安装和服务管理
|
||||
# 管理开发环境: 数据库 / 服务编译 / DevTools 控制台
|
||||
# ========================================
|
||||
set -e
|
||||
|
||||
SCRIPT_DIR="$(cd "$(dirname "$0")" && pwd)"
|
||||
DEVTOOLS_DIR="$SCRIPT_DIR/devtools"
|
||||
ROOT="$SCRIPT_DIR"
|
||||
PORT="${DEVTOOLS_PORT:-9090}"
|
||||
LOG_DIR="$SCRIPT_DIR/logs"
|
||||
LOG_DIR="$DEVTOOLS_DIR/logs"
|
||||
LOG_FILE="$LOG_DIR/sh.log"
|
||||
|
||||
# 颜色输出
|
||||
# 颜色
|
||||
RED='\033[0;31m'
|
||||
GREEN='\033[0;32m'
|
||||
YELLOW='\033[1;33m'
|
||||
CYAN='\033[0;36m'
|
||||
NC='\033[0m' # No Color
|
||||
BOLD='\033[1m'
|
||||
NC='\033[0m'
|
||||
|
||||
echo -e "${CYAN}━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━${NC}"
|
||||
echo -e "${CYAN} 🛠️ Cyrene DevTools${NC}"
|
||||
echo -e "${CYAN}━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━${NC}"
|
||||
# ========== 平台检测 ==========
|
||||
IS_WIN=false
|
||||
case "$(uname -s)" in
|
||||
MINGW*|MSYS*|CYGWIN*) IS_WIN=true ;;
|
||||
esac
|
||||
|
||||
# 切换到 devtools 目录
|
||||
cd "$DEVTOOLS_DIR"
|
||||
# ========== 帮助 ==========
|
||||
show_help() {
|
||||
echo -e "${CYAN}Cyrene DevTools${NC} — 开发环境管理工具"
|
||||
echo ""
|
||||
echo -e "${BOLD}用法:${NC} ./devtools.sh [命令] [选项]"
|
||||
echo ""
|
||||
echo -e "${BOLD}命令:${NC}"
|
||||
echo " (无参数) 启动 DevTools 控制台 (默认)"
|
||||
echo " start 启动 DevTools 控制台"
|
||||
echo " start --fresh 强制重启全部后端服务后启动"
|
||||
echo " start --build 编译全部服务后启动"
|
||||
echo " stop 停止 DevTools 控制台"
|
||||
echo " status 查看所有服务状态"
|
||||
echo " logs [服务ID] 查看服务日志 (默认显示最近 20 行)"
|
||||
echo " build [服务ID] 编译服务 (不指定则编译全部)"
|
||||
echo " db:start 启动数据库容器 (Docker Compose)"
|
||||
echo " db:stop 停止数据库容器"
|
||||
echo " db:status 检查数据库连接状态"
|
||||
echo " help 显示此帮助"
|
||||
echo ""
|
||||
echo -e "${BOLD}选项:${NC}"
|
||||
echo " --port, -p <端口> 指定 DevTools 端口 (默认: 9090)"
|
||||
echo " --fresh 启动前强制重启全部后端服务"
|
||||
echo " --build 启动前编译全部服务"
|
||||
echo ""
|
||||
echo -e "${BOLD}示例:${NC}"
|
||||
echo " ./devtools.sh # 快速启动"
|
||||
echo " ./devtools.sh start --build # 编译后启动"
|
||||
echo " ./devtools.sh start --fresh # 全新重启"
|
||||
echo " ./devtools.sh logs gateway # 查看 Gateway 日志"
|
||||
echo " ./devtools.sh build ai-core # 仅编译 AI-Core"
|
||||
echo " ./devtools.sh db:status # 检查数据库"
|
||||
echo ""
|
||||
echo -e "${BOLD}Web 控制台:${NC} http://localhost:$PORT"
|
||||
}
|
||||
|
||||
# 确保 Node.js 可用
|
||||
if ! command -v node &> /dev/null; then
|
||||
if [ -x /usr/local/node/bin/node ]; then
|
||||
export PATH="/usr/local/node/bin:$PATH"
|
||||
# ========== 依赖检查 ==========
|
||||
check_deps() {
|
||||
local missing=0
|
||||
|
||||
# Node.js
|
||||
if ! command -v node &>/dev/null; then
|
||||
if [ -x /usr/local/node/bin/node ]; then
|
||||
export PATH="/usr/local/node/bin:$PATH"
|
||||
else
|
||||
echo -e "${RED}✗ Node.js 未安装${NC}"
|
||||
missing=1
|
||||
fi
|
||||
fi
|
||||
|
||||
# Docker (用于数据库)
|
||||
if ! command -v docker &>/dev/null; then
|
||||
echo -e "${YELLOW}⚠ Docker 未安装 (数据库容器功能不可用)${NC}"
|
||||
fi
|
||||
|
||||
# Go (用于编译后端服务)
|
||||
if ! command -v go &>/dev/null; then
|
||||
if $IS_WIN && [ -f "/c/Program Files/Go/bin/go.exe" ]; then
|
||||
export PATH="$PATH:/c/Program Files/Go/bin"
|
||||
else
|
||||
echo -e "${YELLOW}⚠ Go 未安装 (服务编译功能不可用)${NC}"
|
||||
fi
|
||||
fi
|
||||
|
||||
return $missing
|
||||
}
|
||||
|
||||
# ========== 加载 .env ==========
|
||||
load_env() {
|
||||
local env_file="$ROOT/backend/.env"
|
||||
if [ -f "$env_file" ]; then
|
||||
echo -e "${GREEN}✓ 加载环境变量: backend/.env${NC}"
|
||||
set -a
|
||||
source "$env_file"
|
||||
set +a
|
||||
else
|
||||
echo -e "${RED}❌ 未找到 Node.js,请先安装 Node.js${NC}"
|
||||
echo -e "${YELLOW}⚠ 未找到 backend/.env,使用默认值${NC}"
|
||||
fi
|
||||
}
|
||||
|
||||
# ========== 端口工具 (跨平台) ==========
|
||||
port_in_use() {
|
||||
local port=$1
|
||||
if $IS_WIN; then
|
||||
netstat -ano 2>/dev/null | grep -q ":$port " | grep -q "LISTENING"
|
||||
else
|
||||
ss -tlnp 2>/dev/null | grep -q ":$port " || netstat -tlnp 2>/dev/null | grep -q ":$port "
|
||||
fi
|
||||
}
|
||||
|
||||
kill_port() {
|
||||
local port=$1
|
||||
if $IS_WIN; then
|
||||
local pid=$(netstat -ano 2>/dev/null | grep ":$port " | grep "LISTENING" | awk '{print $NF}' | head -1)
|
||||
if [ -n "$pid" ] && [ "$pid" != "0" ]; then
|
||||
powershell -Command "Stop-Process -Id $pid -Force" 2>/dev/null || true
|
||||
fi
|
||||
else
|
||||
fuser -k "$port/tcp" 2>/dev/null || true
|
||||
fi
|
||||
sleep 1
|
||||
}
|
||||
|
||||
# ========== 健康检查 ==========
|
||||
health_check() {
|
||||
local url=$1
|
||||
local max_wait=${2:-30}
|
||||
local waited=0
|
||||
while [ $waited -lt $max_wait ]; do
|
||||
if curl -s -o /dev/null -w "%{http_code}" "$url" 2>/dev/null | grep -q "200"; then
|
||||
return 0
|
||||
fi
|
||||
sleep 1
|
||||
waited=$((waited + 1))
|
||||
done
|
||||
return 1
|
||||
}
|
||||
|
||||
# ========== 数据库管理 ==========
|
||||
DB_COMPOSE_FILE="$ROOT/docker-compose.dev.db.yml"
|
||||
|
||||
db_status() {
|
||||
if port_in_use 5432; then
|
||||
echo -e "${GREEN}✓ PostgreSQL 在线 (端口 5432)${NC}"
|
||||
return 0
|
||||
else
|
||||
echo -e "${RED}✗ PostgreSQL 离线${NC}"
|
||||
return 1
|
||||
fi
|
||||
}
|
||||
|
||||
db_start() {
|
||||
echo -e "${CYAN}启动数据库容器...${NC}"
|
||||
if [ ! -f "$DB_COMPOSE_FILE" ]; then
|
||||
echo -e "${RED}✗ 未找到 $DB_COMPOSE_FILE${NC}"
|
||||
return 1
|
||||
fi
|
||||
docker compose -f "$DB_COMPOSE_FILE" up -d
|
||||
echo -e "${YELLOW}等待数据库就绪...${NC}"
|
||||
if health_check "http://localhost:5432" 30; then
|
||||
echo -e "${GREEN}✓ 数据库已就绪${NC}"
|
||||
else
|
||||
echo -e "${YELLOW}⚠ 数据库可能仍在启动中,请稍后检查${NC}"
|
||||
fi
|
||||
}
|
||||
|
||||
db_stop() {
|
||||
echo -e "${CYAN}停止数据库容器...${NC}"
|
||||
if [ ! -f "$DB_COMPOSE_FILE" ]; then
|
||||
echo -e "${RED}✗ 未找到 $DB_COMPOSE_FILE${NC}"
|
||||
return 1
|
||||
fi
|
||||
docker compose -f "$DB_COMPOSE_FILE" down
|
||||
echo -e "${GREEN}✓ 数据库已停止${NC}"
|
||||
}
|
||||
|
||||
# ========== 服务编译 ==========
|
||||
SERVICES=(
|
||||
"memory-service:backend/memory-service"
|
||||
"tool-engine:backend/tool-engine"
|
||||
"iot-debug-service:backend/iot-debug-service"
|
||||
"voice-service:backend/voice-service"
|
||||
"ai-core:backend/ai-core"
|
||||
"plugin-manager:backend/plugin-manager"
|
||||
"platform-bridge:backend/platform-bridge"
|
||||
"gateway:backend/gateway"
|
||||
)
|
||||
|
||||
build_service() {
|
||||
local id=$1
|
||||
local dir=$2
|
||||
local label=${3:-$id}
|
||||
|
||||
echo -e "${CYAN}[编译] $label...${NC}"
|
||||
local binary="main"
|
||||
$IS_WIN && binary="main.exe"
|
||||
|
||||
cd "$ROOT/$dir"
|
||||
if GOWORK=off go build -o "$binary" ./cmd/main.go 2>&1; then
|
||||
echo -e "${GREEN} ✓ $label 编译完成${NC}"
|
||||
return 0
|
||||
else
|
||||
echo -e "${RED} ✗ $label 编译失败${NC}"
|
||||
return 1
|
||||
fi
|
||||
}
|
||||
|
||||
build_all() {
|
||||
echo -e "${BOLD}编译全部后端服务...${NC}"
|
||||
local failed=0
|
||||
for entry in "${SERVICES[@]}"; do
|
||||
IFS=':' read -r id dir <<< "$entry"
|
||||
# 检查目录是否存在
|
||||
if [ -d "$ROOT/$dir" ]; then
|
||||
build_service "$id" "$dir" "$id" || failed=$((failed + 1))
|
||||
fi
|
||||
done
|
||||
|
||||
if [ $failed -eq 0 ]; then
|
||||
echo -e "${GREEN}✓ 全部编译完成${NC}"
|
||||
else
|
||||
echo -e "${YELLOW}⚠ $failed 个服务编译失败${NC}"
|
||||
fi
|
||||
cd "$ROOT"
|
||||
return $failed
|
||||
}
|
||||
|
||||
# ========== 查看日志 ==========
|
||||
show_logs() {
|
||||
local service_id=$1
|
||||
local lines=${2:-20}
|
||||
local log_path="$LOG_DIR/${service_id}.log"
|
||||
|
||||
if [ ! -f "$log_path" ]; then
|
||||
echo -e "${YELLOW}日志文件不存在: $log_path${NC}"
|
||||
return 1
|
||||
fi
|
||||
|
||||
echo -e "${BOLD}=== $service_id 日志 (最近 $lines 行) ===${NC}"
|
||||
tail -n "$lines" "$log_path"
|
||||
}
|
||||
|
||||
# ========== 启动 DevTools ==========
|
||||
start_devtools() {
|
||||
local do_build=false
|
||||
local do_fresh=false
|
||||
|
||||
# 解析参数
|
||||
for arg in "$@"; do
|
||||
case $arg in
|
||||
--build) do_build=true ;;
|
||||
--fresh) do_fresh=true ;;
|
||||
--port=*) PORT="${arg#*=}" ;;
|
||||
-p) shift; PORT="$1" ;;
|
||||
esac
|
||||
done
|
||||
|
||||
echo ""
|
||||
echo -e "${CYAN}━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━${NC}"
|
||||
echo -e "${CYAN} Cyrene DevTools${NC}"
|
||||
echo -e "${CYAN}━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━${NC}"
|
||||
|
||||
# 依赖检查
|
||||
check_deps || exit 1
|
||||
|
||||
echo -e "${YELLOW}Node.js:${NC} $(node --version)"
|
||||
command -v go &>/dev/null && echo -e "${YELLOW}Go:${NC} $(go version | cut -d' ' -f3)"
|
||||
command -v docker &>/dev/null && echo -e "${YELLOW}Docker:${NC} $(docker --version | cut -d' ' -f3 | tr -d ',')"
|
||||
|
||||
# 加载环境变量
|
||||
load_env
|
||||
|
||||
# 编译 (如果指定)
|
||||
if $do_build; then
|
||||
build_all
|
||||
fi
|
||||
|
||||
# 全新重启 (如果指定)
|
||||
if $do_fresh; then
|
||||
echo -e "${YELLOW}强制重启全部后端服务...${NC}"
|
||||
curl -s -X POST "http://localhost:$PORT/api/services/start-all-fresh" 2>/dev/null || true
|
||||
fi
|
||||
|
||||
# 检查并释放端口
|
||||
if port_in_use "$PORT"; then
|
||||
# 检查是否是已有 DevTools 实例
|
||||
if curl -s -o /dev/null "http://localhost:$PORT/api/health" 2>/dev/null; then
|
||||
echo -e "${GREEN}✓ DevTools 已在运行: http://localhost:$PORT${NC}"
|
||||
echo -e "${CYAN} API: http://localhost:$PORT/api/health${NC}"
|
||||
return 0
|
||||
fi
|
||||
echo -e "${YELLOW}⚠ 端口 $PORT 被占用,正在释放...${NC}"
|
||||
kill_port "$PORT"
|
||||
fi
|
||||
|
||||
# 切换到 devtools 目录
|
||||
cd "$DEVTOOLS_DIR"
|
||||
|
||||
# 安装依赖
|
||||
if [ ! -d "node_modules" ] || [ ! -f "node_modules/.package-lock.json" ]; then
|
||||
echo -e "${YELLOW}安装依赖...${NC}"
|
||||
npm install --silent
|
||||
fi
|
||||
|
||||
# 确保日志目录存在
|
||||
mkdir -p "$LOG_DIR"
|
||||
|
||||
echo ""
|
||||
echo -e "${GREEN}启动 DevTools 服务器 (端口: $PORT)...${NC}"
|
||||
echo -e "${CYAN} Web 控制台: http://localhost:$PORT${NC}"
|
||||
echo -e "${CYAN} API: http://localhost:$PORT/api/health${NC}"
|
||||
echo -e "${CYAN} WebSocket: ws://localhost:$PORT/ws${NC}"
|
||||
echo ""
|
||||
echo -e "${YELLOW}正在后台启动...${NC}"
|
||||
|
||||
# 后台启动 DevTools
|
||||
nohup node src/index.js > "$LOG_FILE" 2>&1 &
|
||||
local pid=$!
|
||||
cd "$ROOT"
|
||||
|
||||
# 等待健康检查
|
||||
echo -e "${YELLOW}等待服务就绪...${NC}"
|
||||
if health_check "http://localhost:$PORT/api/health" 30; then
|
||||
echo ""
|
||||
echo -e "${GREEN}━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━${NC}"
|
||||
echo -e "${GREEN} DevTools 已启动!${NC}"
|
||||
echo -e "${GREEN} PID: ${pid}${NC}"
|
||||
echo -e "${GREEN} 控制台: http://localhost:$PORT${NC}"
|
||||
echo -e "${GREEN} 日志: ${LOG_FILE}${NC}"
|
||||
echo -e "${GREEN}━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━${NC}"
|
||||
echo ""
|
||||
|
||||
# 检查数据库状态
|
||||
db_status
|
||||
|
||||
return 0
|
||||
fi
|
||||
|
||||
# 超时
|
||||
if kill -0 "$pid" 2>/dev/null; then
|
||||
echo ""
|
||||
echo -e "${YELLOW}⚠ 服务可能仍在启动中 (已等待 30 秒)${NC}"
|
||||
echo -e "${CYAN} 请稍后检查 http://localhost:$PORT/api/health${NC}"
|
||||
else
|
||||
echo ""
|
||||
echo -e "${RED}✗ 服务启动失败,请检查日志: ${LOG_FILE}${NC}"
|
||||
return 1
|
||||
fi
|
||||
}
|
||||
|
||||
# ========== 停止 DevTools ==========
|
||||
stop_devtools() {
|
||||
if port_in_use "$PORT"; then
|
||||
echo -e "${CYAN}停止 DevTools...${NC}"
|
||||
if $IS_WIN; then
|
||||
kill_port "$PORT"
|
||||
else
|
||||
fuser -k "$PORT/tcp" 2>/dev/null || true
|
||||
fi
|
||||
echo -e "${GREEN}✓ DevTools 已停止${NC}"
|
||||
else
|
||||
echo -e "${YELLOW}DevTools 未在运行${NC}"
|
||||
fi
|
||||
}
|
||||
|
||||
# ========== 查看状态 ==========
|
||||
show_status() {
|
||||
if curl -s -o /dev/null "http://localhost:$PORT/api/health" 2>/dev/null; then
|
||||
echo -e "${GREEN}✓ DevTools 在线${NC}"
|
||||
|
||||
# 获取服务状态
|
||||
local status_json=$(curl -s "http://localhost:$PORT/api/services" 2>/dev/null)
|
||||
if [ -n "$status_json" ]; then
|
||||
echo ""
|
||||
echo -e "${BOLD}服务状态:${NC}"
|
||||
local tmpfile="$(mktemp)"
|
||||
echo "$status_json" > "$tmpfile"
|
||||
node -e "
|
||||
const fs = require('fs');
|
||||
const data = JSON.parse(fs.readFileSync(process.argv[1], 'utf-8'));
|
||||
for (const [id, svc] of Object.entries(data)) {
|
||||
const icon = svc.status === 'running' ? '✓' : svc.status === 'stopped' ? '✗' : '○';
|
||||
const color = svc.status === 'running' ? '\x1b[32m' : '\x1b[31m';
|
||||
const pid = svc.pid ? ' (PID: ' + svc.pid + ')' : '';
|
||||
const uptime = svc.uptime ? ' | uptime: ' + Math.round(svc.uptime / 1000) + 's' : '';
|
||||
console.log(' ' + color + icon + '\x1b[0m ' + svc.name.padEnd(16) + ' [' + svc.status + ']' + pid + uptime);
|
||||
}
|
||||
" "$tmpfile"
|
||||
rm -f "$tmpfile"
|
||||
fi
|
||||
|
||||
# 数据库状态
|
||||
echo ""
|
||||
db_status
|
||||
else
|
||||
echo -e "${RED}✗ DevTools 离线${NC}"
|
||||
fi
|
||||
}
|
||||
|
||||
# ========== 主入口 ==========
|
||||
CMD="${1:-start}"
|
||||
shift 2>/dev/null || true
|
||||
|
||||
case "$CMD" in
|
||||
help|--help|-h)
|
||||
show_help
|
||||
;;
|
||||
start|"")
|
||||
start_devtools "$@"
|
||||
;;
|
||||
stop)
|
||||
stop_devtools
|
||||
;;
|
||||
status)
|
||||
show_status
|
||||
;;
|
||||
logs)
|
||||
if [ -z "$1" ]; then
|
||||
echo -e "${YELLOW}用法: ./devtools.sh logs <服务ID>${NC}"
|
||||
echo "可用服务: gateway, ai-core, memory-service, tool-engine, voice-service, iot-debug-service, plugin-manager, platform-bridge, frontend"
|
||||
exit 1
|
||||
fi
|
||||
show_logs "$1" "${2:-20}"
|
||||
;;
|
||||
build)
|
||||
check_deps || exit 1
|
||||
load_env
|
||||
if [ -n "$1" ]; then
|
||||
# 查找服务目录
|
||||
for entry in "${SERVICES[@]}"; do
|
||||
IFS=':' read -r id dir <<< "$entry"
|
||||
if [ "$id" = "$1" ]; then
|
||||
build_service "$id" "$dir" "$id"
|
||||
exit $?
|
||||
fi
|
||||
done
|
||||
echo -e "${RED}未知服务: $1${NC}"
|
||||
echo "可用服务: ${SERVICES[*]}"
|
||||
exit 1
|
||||
else
|
||||
build_all
|
||||
fi
|
||||
;;
|
||||
db:start)
|
||||
db_start
|
||||
;;
|
||||
db:stop)
|
||||
db_stop
|
||||
;;
|
||||
db:status)
|
||||
db_status
|
||||
;;
|
||||
*)
|
||||
echo -e "${RED}未知命令: $CMD${NC}"
|
||||
echo ""
|
||||
show_help
|
||||
exit 1
|
||||
fi
|
||||
fi
|
||||
|
||||
echo -e "${YELLOW}Node.js:${NC} $(node --version)"
|
||||
echo -e "${YELLOW}npm:${NC} $(npm --version)"
|
||||
|
||||
# 加载 backend/.env 环境变量
|
||||
ENV_FILE="$SCRIPT_DIR/backend/.env"
|
||||
if [ -f "$ENV_FILE" ]; then
|
||||
echo -e "${GREEN}✅ 加载环境变量: $ENV_FILE${NC}"
|
||||
set -a
|
||||
# shellcheck disable=SC1090
|
||||
source "$ENV_FILE"
|
||||
set +a
|
||||
else
|
||||
echo -e "${YELLOW}⚠ 未找到 .env 文件,使用默认值${NC}"
|
||||
fi
|
||||
|
||||
# 检查并释放端口
|
||||
if ss -tlnp 2>/dev/null | grep -q ":$PORT "; then
|
||||
echo -e "${YELLOW}⚠ 端口 $PORT 已被占用,正在释放...${NC}"
|
||||
fuser -k "$PORT/tcp" 2>/dev/null || true
|
||||
sleep 1
|
||||
echo -e "${GREEN}✅ 端口 $PORT 已释放${NC}"
|
||||
fi
|
||||
|
||||
# 安装依赖 (如有需要)
|
||||
if [ ! -d "node_modules" ] || [ ! -f "node_modules/.package-lock.json" ]; then
|
||||
echo -e "${YELLOW}📦 安装依赖...${NC}"
|
||||
npm install --silent
|
||||
fi
|
||||
|
||||
# 确保日志目录存在
|
||||
mkdir -p "$LOG_DIR"
|
||||
|
||||
echo ""
|
||||
echo -e "${GREEN}🚀 启动 DevTools 服务器 (端口: $PORT)...${NC}"
|
||||
echo -e "${CYAN} Web 控制台: http://localhost:$PORT${NC}"
|
||||
echo -e "${CYAN} API: http://localhost:$PORT/api/health${NC}"
|
||||
echo -e "${CYAN} WebSocket: ws://localhost:$PORT/ws${NC}"
|
||||
echo ""
|
||||
echo -e "${YELLOW}⏳ 正在后台启动所有服务...${NC}"
|
||||
|
||||
# 后台启动 DevTools,日志写入 ./logs/sh.log
|
||||
nohup node src/index.js > "$LOG_FILE" 2>&1 &
|
||||
DEVTOOLS_PID=$!
|
||||
|
||||
# 健康检查(最多等待 30 秒)
|
||||
MAX_WAIT=30
|
||||
WAITED=0
|
||||
while [ $WAITED -lt $MAX_WAIT ]; do
|
||||
HTTP_CODE=$(curl -s -o /dev/null -w "%{http_code}" "http://localhost:$PORT/api/health" 2>/dev/null || true)
|
||||
if [ "$HTTP_CODE" = "200" ]; then
|
||||
echo ""
|
||||
echo -e "${GREEN}✅ 所有服务启动完成!${NC}"
|
||||
echo -e "${CYAN} PID: ${DEVTOOLS_PID}${NC}"
|
||||
echo -e "${CYAN} 日志文件: ${LOG_FILE}${NC}"
|
||||
echo ""
|
||||
exit 0
|
||||
fi
|
||||
sleep 1
|
||||
WAITED=$((WAITED + 1))
|
||||
done
|
||||
|
||||
# 超时处理
|
||||
if kill -0 "$DEVTOOLS_PID" 2>/dev/null; then
|
||||
echo ""
|
||||
echo -e "${YELLOW}⚠ 服务可能仍在启动中(已等待 ${MAX_WAIT} 秒)${NC}"
|
||||
echo -e "${CYAN} PID: ${DEVTOOLS_PID}${NC}"
|
||||
echo -e "${CYAN} 日志文件: ${LOG_FILE}${NC}"
|
||||
echo -e "${YELLOW} 请稍后检查 http://localhost:$PORT/api/health${NC}"
|
||||
else
|
||||
echo ""
|
||||
echo -e "${RED}❌ 服务启动失败,请检查日志: ${LOG_FILE}${NC}"
|
||||
exit 1
|
||||
fi
|
||||
;;
|
||||
esac
|
||||
|
||||
Reference in New Issue
Block a user