226 lines
6.4 KiB
Bash
Executable File
226 lines
6.4 KiB
Bash
Executable File
#!/usr/bin/env bash
|
||
# ═══════════════════════════════════════════
|
||
# 工作手机 SDK — 一键部署脚本
|
||
# 阿服负责 · 支持本地 / Docker / 远程服务器
|
||
# ═══════════════════════════════════════════
|
||
set -e
|
||
|
||
SCRIPT_DIR="$(cd "$(dirname "$0")" && pwd)"
|
||
cd "$SCRIPT_DIR"
|
||
|
||
RED='\033[0;31m'
|
||
GREEN='\033[0;32m'
|
||
BLUE='\033[0;34m'
|
||
YELLOW='\033[1;33m'
|
||
NC='\033[0m'
|
||
|
||
info() { echo -e "${BLUE}[INFO]${NC} $1"; }
|
||
ok() { echo -e "${GREEN}[OK]${NC} $1"; }
|
||
warn() { echo -e "${YELLOW}[WARN]${NC} $1"; }
|
||
err() { echo -e "${RED}[ERROR]${NC} $1"; }
|
||
|
||
usage() {
|
||
echo ""
|
||
echo "工作手机 SDK 一键部署"
|
||
echo ""
|
||
echo "用法: ./deploy.sh [命令]"
|
||
echo ""
|
||
echo "命令:"
|
||
echo " local 本地直接运行(开发模式)"
|
||
echo " docker Docker Compose 部署(生产模式)"
|
||
echo " stop 停止服务"
|
||
echo " status 查看服务状态"
|
||
echo " logs 查看日志"
|
||
echo " health 健康检查"
|
||
echo ""
|
||
}
|
||
|
||
deploy_local() {
|
||
info "本地模式启动..."
|
||
|
||
# 清理旧进程
|
||
lsof -ti :8899 2>/dev/null | xargs kill -9 2>/dev/null || true
|
||
sleep 1
|
||
|
||
# 检查 Python
|
||
if ! command -v python3 &>/dev/null; then
|
||
err "未找到 python3,请先安装"
|
||
exit 1
|
||
fi
|
||
|
||
# 安装依赖
|
||
if [ -f requirements.txt ]; then
|
||
info "检查依赖..."
|
||
pip3 install -q -r requirements.txt 2>/dev/null || warn "部分依赖安装失败,可能影响某些功能"
|
||
fi
|
||
|
||
# 设置 ADB 环境
|
||
export ADB_VENDOR_KEYS="${HOME}/.android/adbkey"
|
||
|
||
info "启动 SDK 服务端..."
|
||
cd app
|
||
nohup python3 -m uvicorn main:app --host 0.0.0.0 --port 8899 > ../sdk.log 2>&1 &
|
||
SDK_PID=$!
|
||
cd ..
|
||
|
||
sleep 3
|
||
|
||
if curl -sf http://localhost:8899/health > /dev/null 2>&1; then
|
||
ok "服务启动成功!PID: $SDK_PID"
|
||
echo ""
|
||
echo " 控制台: http://localhost:8899/hub"
|
||
echo " API 文档: http://localhost:8899/docs"
|
||
echo " 健康检查: http://localhost:8899/health"
|
||
echo " 外部对接: http://localhost:8899/api/v3/gateway/info"
|
||
echo ""
|
||
echo " 日志: tail -f sdk.log"
|
||
echo " 停止: ./deploy.sh stop"
|
||
else
|
||
err "服务启动失败,查看 sdk.log"
|
||
cat sdk.log | tail -20
|
||
fi
|
||
}
|
||
|
||
deploy_docker() {
|
||
info "Docker 模式部署..."
|
||
|
||
if ! command -v docker &>/dev/null; then
|
||
err "未找到 docker,请先安装"
|
||
exit 1
|
||
fi
|
||
|
||
if ! command -v docker-compose &>/dev/null && ! docker compose version &>/dev/null 2>&1; then
|
||
err "未找到 docker-compose,请先安装"
|
||
exit 1
|
||
fi
|
||
|
||
# 使用 docker compose(新版)或 docker-compose(旧版)
|
||
COMPOSE="docker compose"
|
||
if ! docker compose version &>/dev/null 2>&1; then
|
||
COMPOSE="docker-compose"
|
||
fi
|
||
|
||
info "构建并启动容器..."
|
||
$COMPOSE up -d --build
|
||
|
||
sleep 5
|
||
|
||
if curl -sf http://localhost:8899/health > /dev/null 2>&1; then
|
||
ok "Docker 部署成功!"
|
||
echo ""
|
||
echo " 控制台: http://localhost:8899/hub"
|
||
echo " Nginx 入口: http://localhost:8880"
|
||
echo " API 文档: http://localhost:8899/docs"
|
||
echo " 外部对接: http://localhost:8899/api/v3/gateway/info"
|
||
echo ""
|
||
echo " 日志: $COMPOSE logs -f workphone-sdk"
|
||
echo " 停止: ./deploy.sh stop"
|
||
else
|
||
warn "服务可能还在启动中,等待 10 秒..."
|
||
sleep 10
|
||
if curl -sf http://localhost:8899/health > /dev/null 2>&1; then
|
||
ok "Docker 部署成功!"
|
||
else
|
||
err "服务启动失败"
|
||
$COMPOSE logs --tail=30 workphone-sdk
|
||
fi
|
||
fi
|
||
}
|
||
|
||
stop_services() {
|
||
info "停止服务..."
|
||
|
||
# 停止本地进程
|
||
lsof -ti :8899 2>/dev/null | xargs kill -9 2>/dev/null || true
|
||
|
||
# 停止 Docker
|
||
COMPOSE="docker compose"
|
||
if ! docker compose version &>/dev/null 2>&1; then
|
||
COMPOSE="docker-compose"
|
||
fi
|
||
$COMPOSE down 2>/dev/null || true
|
||
|
||
ok "服务已停止"
|
||
}
|
||
|
||
check_status() {
|
||
echo ""
|
||
echo "═══ 工作手机 SDK 状态 ═══"
|
||
echo ""
|
||
|
||
if curl -sf http://localhost:8899/health > /dev/null 2>&1; then
|
||
HEALTH=$(curl -s http://localhost:8899/health)
|
||
ok "服务端: 运行中"
|
||
echo " $HEALTH" | python3 -c "import sys,json; d=json.load(sys.stdin); print(f' 版本: {d.get(\"version\",\"-\")}'); print(f' WS设备: {d.get(\"devices_online\",0)}'); print(f' ADB设备: {d.get(\"adb_devices\",0)}')" 2>/dev/null || echo " $HEALTH"
|
||
else
|
||
err "服务端: 未运行"
|
||
fi
|
||
|
||
echo ""
|
||
|
||
if command -v adb &>/dev/null; then
|
||
ADB_COUNT=$(adb devices 2>/dev/null | grep -c "device$" || echo 0)
|
||
info "ADB 设备: $ADB_COUNT 台"
|
||
fi
|
||
|
||
# Docker 状态
|
||
if command -v docker &>/dev/null; then
|
||
RUNNING=$(docker ps --filter "name=workphone" --format "{{.Names}}: {{.Status}}" 2>/dev/null)
|
||
if [ -n "$RUNNING" ]; then
|
||
info "Docker 容器:"
|
||
echo " $RUNNING"
|
||
fi
|
||
fi
|
||
echo ""
|
||
}
|
||
|
||
check_health() {
|
||
echo ""
|
||
info "健康检查..."
|
||
|
||
ENDPOINTS=(
|
||
"/health"
|
||
"/ready"
|
||
"/api/v3/workbench/overview"
|
||
"/api/v3/gateway/info"
|
||
"/api/v3/gateway/fleet/status"
|
||
"/api/v3/gateway/mcp/tools"
|
||
"/docs"
|
||
)
|
||
|
||
for ep in "${ENDPOINTS[@]}"; do
|
||
STATUS=$(curl -s -o /dev/null -w "%{http_code}" "http://localhost:8899${ep}" 2>/dev/null || echo "000")
|
||
if [ "$STATUS" = "200" ]; then
|
||
ok "$ep → $STATUS"
|
||
else
|
||
err "$ep → $STATUS"
|
||
fi
|
||
done
|
||
echo ""
|
||
}
|
||
|
||
show_logs() {
|
||
COMPOSE="docker compose"
|
||
if ! docker compose version &>/dev/null 2>&1; then
|
||
COMPOSE="docker-compose"
|
||
fi
|
||
|
||
if [ -f sdk.log ]; then
|
||
tail -f sdk.log
|
||
elif $COMPOSE ps 2>/dev/null | grep -q workphone; then
|
||
$COMPOSE logs -f workphone-sdk
|
||
else
|
||
err "未找到日志文件"
|
||
fi
|
||
}
|
||
|
||
case "${1:-}" in
|
||
local) deploy_local ;;
|
||
docker) deploy_docker ;;
|
||
stop) stop_services ;;
|
||
status) check_status ;;
|
||
health) check_health ;;
|
||
logs) show_logs ;;
|
||
*) usage ;;
|
||
esac
|