#!/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