PMFlow/scripts/start_legacy_local.sh

164 lines
5.4 KiB
Bash
Executable File
Raw Blame History

This file contains invisible Unicode characters

This file contains invisible Unicode characters that are indistinguishable to humans but may be processed differently by a computer. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

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.

#!/bin/bash
# PMFlow 启动器:后端 + 前端 + Cloudflare Quick Tunnel(自动输出临时公网地址)
set -euo pipefail
PROJECT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)"
cd "$PROJECT_DIR"
GREEN='\033[0;32m'
YELLOW='\033[1;33m'
RED='\033[0;31m'
NC='\033[0m'
die() {
echo -e "${RED}❌ $1${NC}"
exit 1
}
kill_port() {
local port="$1"
lsof -tiTCP:"$port" -sTCP:LISTEN 2>/dev/null | xargs kill -9 2>/dev/null || true
}
wait_http_ok() {
local url="$1"
local max_retry="$2"
local retry=1
while [ "$retry" -le "$max_retry" ]; do
if curl -fsS "$url" >/dev/null 2>&1; then
return 0
fi
sleep 1
retry=$((retry + 1))
done
return 1
}
wait_remote_ok() {
local url="$1"
local max_retry="$2"
local retry=1
while [ "$retry" -le "$max_retry" ]; do
if curl -kfsS --max-time 8 "$url" >/dev/null 2>&1; then
return 0
fi
sleep 2
retry=$((retry + 1))
done
return 1
}
echo "🚀 PMFlow 启动器"
echo "===================="
[ -d "venv" ] || die "虚拟环境不存在,请先创建: python -m venv venv"
[ -d "backend" ] || die "缺少 backend 目录"
[ -d "frontend" ] || die "缺少 frontend 目录"
command -v cloudflared >/dev/null 2>&1 || die "未安装 cloudflared"
command -v npm >/dev/null 2>&1 || die "未安装 npm"
mkdir -p logs
rm -f logs/backend.pid logs/frontend.pid logs/tunnel.pid logs/tunnel-frontend.pid logs/tunnel-backend.pid logs/public_url.txt
rm -f logs/tunnel.log logs/tunnel-backend.log logs/tunnel-frontend.log
echo "🧹 清理旧进程与端口..."
pkill -f "cloudflared tunnel --url http://127.0.0.1:5174" >/dev/null 2>&1 || true
pkill -f "cloudflared tunnel --url http://localhost:5174" >/dev/null 2>&1 || true
pkill -f "cloudflared tunnel --url http://127.0.0.1:8000" >/dev/null 2>&1 || true
pkill -f "cloudflared tunnel --url http://localhost:8000" >/dev/null 2>&1 || true
kill_port 8000
kill_port 5173
kill_port 5174
sleep 1
echo -e "${GREEN}▶️ 启动后端 (8000)...${NC}"
(
cd backend
nohup "$PROJECT_DIR/venv/bin/uvicorn" app.main:app --host 0.0.0.0 --port 8000 --reload --reload-dir app > "$PROJECT_DIR/logs/backend.log" 2>&1 &
echo $! > "$PROJECT_DIR/logs/backend.pid"
)
BACKEND_PID="$(cat logs/backend.pid)"
wait_http_ok "http://127.0.0.1:8000/healthz" 15 || die "后端启动失败,查看 logs/backend.log"
echo -e "${GREEN}✅ 后端已启动 (PID: ${BACKEND_PID})${NC}"
echo -e "${GREEN}▶️ 启动前端 (5174)...${NC}"
(
cd frontend
nohup npm run dev -- --host 0.0.0.0 --port 5174 > "$PROJECT_DIR/logs/frontend.log" 2>&1 &
echo $! > "$PROJECT_DIR/logs/frontend.pid"
)
FRONTEND_PID="$(cat logs/frontend.pid)"
wait_http_ok "http://127.0.0.1:5174/login" 20 || wait_http_ok "http://127.0.0.1:5174" 10 || die "前端启动失败,查看 logs/frontend.log"
echo -e "${GREEN}✅ 前端已启动 (PID: ${FRONTEND_PID})${NC}"
echo -e "${GREEN}▶️ 启动 Cloudflare Quick Tunnels...${NC}"
# Start frontend tunnel
nohup cloudflared tunnel --url http://127.0.0.1:5174 > logs/tunnel-frontend.log 2>&1 &
TUNNEL_FRONT_PID=$!
echo "$TUNNEL_FRONT_PID" > logs/tunnel-frontend.pid
# Start backend tunnel
nohup cloudflared tunnel --url http://127.0.0.1:8000 > logs/tunnel-backend.log 2>&1 &
TUNNEL_BACK_PID=$!
echo "$TUNNEL_BACK_PID" > logs/tunnel-backend.pid
TEMP_URL_FRONT=""
TEMP_URL_BACK=""
for _ in {1..25}; do
if [ -z "$TEMP_URL_FRONT" ]; then
TEMP_URL_FRONT="$(grep -aEo 'https://[a-z0-9-]+\.trycloudflare\.com' logs/tunnel-frontend.log | head -n 1 || true)"
fi
if [ -z "$TEMP_URL_BACK" ]; then
TEMP_URL_BACK="$(grep -aEo 'https://[a-z0-9-]+\.trycloudflare\.com' logs/tunnel-backend.log | head -n 1 || true)"
fi
if [ -n "$TEMP_URL_FRONT" ] && [ -n "$TEMP_URL_BACK" ]; then
break
fi
sleep 1
done
if [ -n "$TEMP_URL_FRONT" ] && [ -n "$TEMP_URL_BACK" ]; then
FRONT_OK=false
BACK_OK=false
if wait_remote_ok "${TEMP_URL_FRONT}/login" 25 || wait_remote_ok "${TEMP_URL_FRONT}" 25; then
FRONT_OK=true
fi
if wait_remote_ok "${TEMP_URL_BACK}/healthz" 25; then
BACK_OK=true
fi
echo "$TEMP_URL_FRONT" > logs/public_url.txt
echo "$TEMP_URL_BACK" >> logs/public_url.txt
if [ "$FRONT_OK" = true ] && [ "$BACK_OK" = true ]; then
echo -e "${GREEN}✅ Tunnels 已启动且公网可访问${NC}"
else
echo -e "${YELLOW}⚠️ Tunnel 已启动,但公网健康检查未全部通过(请稍后再试)${NC}"
fi
echo -e "🌐 前端公网地址(临时): ${YELLOW}${TEMP_URL_FRONT}${NC}"
echo -e "🌐 后端公网地址(临时): ${YELLOW}${TEMP_URL_BACK}${NC}"
echo -e "${YELLOW}ℹ️ 前端公网默认通过 /api 代理访问本地后端,无需手动修改 VITE_API_BASE_URL。${NC}"
else
echo -e "${YELLOW}⚠️ Tunnel 已启动但部分地址未解析,请查看 logs/tunnel-*.log${NC}"
fi
LAN_IP="$(ipconfig getifaddr en0 2>/dev/null || echo '本机IP')"
echo
echo -e "${GREEN}🎉 启动完成${NC}"
echo "===================="
echo "本地前端: http://127.0.0.1:5174"
echo "本地后端: http://127.0.0.1:8000"
echo "局域网前端: http://${LAN_IP}:5174"
echo "API 文档: http://127.0.0.1:8000/docs"
if [ -n "$TEMP_URL_FRONT" ]; then
echo "前端公网: ${TEMP_URL_FRONT}"
fi
if [ -n "$TEMP_URL_BACK" ]; then
echo "后端公网: ${TEMP_URL_BACK}"
fi
echo "日志: logs/backend.log | logs/frontend.log | logs/tunnel-*.log"
echo "停止: ./stop.sh"