#!/bin/bash # # sync-accounts.sh - 账号配置增量同步脚本 # # 用途:从本地机器增量同步 accounts.json 到远程无头服务器 # # 使用方式: # ./sync-accounts.sh # 使用默认配置 # ./sync-accounts.sh user@server.com # 指定服务器 # ./sync-accounts.sh user@server.com /path/to/droid2api # 指定路径 # # 前置要求: # 1. 配置 SSH 免密登录:ssh-copy-id user@server.com # 2. 远程服务器安装 jq:apt install jq 或 yum install jq # set -e # ========== 配置区域 ========== # 优先从 .env 文件读取,可通过环境变量或命令行参数覆盖 # 加载 .env 文件(如果存在) SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)" if [[ -f "$SCRIPT_DIR/.env" ]]; then set -a # 自动导出变量 source "$SCRIPT_DIR/.env" set +a fi # 配置项(优先级:命令行参数 > 环境变量 > 默认值) DEFAULT_SERVER="${SYNC_SERVER:-user@your-server.com}" DEFAULT_REMOTE_PATH="${SYNC_REMOTE_PATH:-/opt/droid2api}" LOCAL_FILE="accounts.json" # 部署方式: pm2 | docker | docker-compose | none DEPLOY_TYPE="${DEPLOY_TYPE:-docker-compose}" DOCKER_SERVICE_NAME="${DOCKER_SERVICE_NAME:-droid2api}" PM2_APP_NAME="${PM2_APP_NAME:-droid2api}" # ============================== # 颜色输出 RED='\033[0;31m' GREEN='\033[0;32m' YELLOW='\033[1;33m' BLUE='\033[0;34m' NC='\033[0m' # No Color log_info() { echo -e "${BLUE}[INFO]${NC} $1"; } log_success() { echo -e "${GREEN}[OK]${NC} $1"; } log_warn() { echo -e "${YELLOW}[WARN]${NC} $1"; } log_error() { echo -e "${RED}[ERROR]${NC} $1"; } # 解析命令行参数 SERVER="${1:-$DEFAULT_SERVER}" REMOTE_PATH="${2:-$DEFAULT_REMOTE_PATH}" REMOTE_FILE="$REMOTE_PATH/accounts.json" # 显示帮助 if [[ "$1" == "-h" || "$1" == "--help" ]]; then echo "用法: $0 [user@server] [remote_path]" echo "" echo "环境变量:" echo " DEPLOY_TYPE 部署方式: pm2 | docker | docker-compose | none (默认: docker-compose)" echo " DOCKER_SERVICE_NAME Docker 服务名 (默认: droid2api)" echo " PM2_APP_NAME PM2 应用名 (默认: droid2api)" echo "" echo "示例:" echo " $0 root@192.168.1.100 /opt/droid2api" echo " DEPLOY_TYPE=pm2 $0 user@server.com" exit 0 fi echo "" echo "═══════════════════════════════════════════════════════════════" echo " 📦 账号配置增量同步工具" echo "═══════════════════════════════════════════════════════════════" echo "" # 检查本地文件是否存在 if [[ ! -f "$LOCAL_FILE" ]]; then log_error "本地文件 $LOCAL_FILE 不存在" log_info "请先运行 'node add-account.js' 添加账号" exit 1 fi # 显示连接信息 log_info "目标服务器: $SERVER" log_info "远程路径: $REMOTE_FILE" log_info "部署方式: $DEPLOY_TYPE" echo "" # 创建临时目录 TEMP_DIR=$(mktemp -d) trap "rm -rf $TEMP_DIR" EXIT # Step 1: 下载远程现有配置 log_info "正在获取远程现有配置..." if ssh "$SERVER" "test -f $REMOTE_FILE" 2>/dev/null; then scp -q "$SERVER:$REMOTE_FILE" "$TEMP_DIR/remote_accounts.json" REMOTE_COUNT=$(jq '.accounts | length' "$TEMP_DIR/remote_accounts.json" 2>/dev/null || echo 0) log_success "远程现有 $REMOTE_COUNT 个账号" else log_warn "远程配置不存在,将创建新文件" echo '{"accounts":[],"settings":{}}' > "$TEMP_DIR/remote_accounts.json" REMOTE_COUNT=0 fi # Step 1.5: 检测 Docker 镜像版本(仅 docker-compose 模式) if [[ "$DEPLOY_TYPE" == "docker-compose" ]]; then log_info "正在检测远程镜像版本..." # 检查远程 auth.js 是否包含多账号检测逻辑 MULTI_ACCOUNT_SUPPORT=$(ssh "$SERVER" "docker exec $DOCKER_SERVICE_NAME cat /app/auth.js 2>/dev/null | grep -c 'accounts.json' || echo 0" 2>/dev/null || echo "error") if [[ "$MULTI_ACCOUNT_SUPPORT" == "error" || "$MULTI_ACCOUNT_SUPPORT" == "" ]]; then log_warn "无法检测镜像版本(容器可能未运行)" elif [[ "$MULTI_ACCOUNT_SUPPORT" == "0" ]]; then echo "" echo "══════════════════════════════════════════════════════════════" log_error "⚠️ 远程镜像版本过旧,不支持多账号功能!" echo "══════════════════════════════════════════════════════════════" echo "" log_info "请在服务器上执行以下命令更新镜像:" echo "" echo " cd $REMOTE_PATH" echo " git pull origin main" echo " docker compose build --no-cache" echo " docker compose up -d" echo "" log_info "更新完成后,重新运行本脚本同步配置。" echo "" read -p "是否继续同步配置?(不推荐) (y/N) " -n 1 -r echo "" if [[ ! $REPLY =~ ^[Yy]$ ]]; then log_warn "已取消同步" exit 0 fi else log_success "远程镜像支持多账号功能" fi fi # Step 2: 显示本地账号数量 LOCAL_COUNT=$(jq '.accounts | length' "$LOCAL_FILE") log_info "本地现有 $LOCAL_COUNT 个账号" # Step 3: 合并配置(按 email 去重,本地优先) log_info "正在合并配置..." jq -s ' # 使用第一个文件(远程)的 accounts 作为基础 (.[0].accounts // []) as $remote | # 使用第二个文件(本地)的 accounts (.[1].accounts // []) as $local | # 获取远程账号的 email 列表 ($remote | map(.email)) as $remote_emails | # 过滤出本地新增的账号(email 不在远程列表中的) ($local | map(select(.email as $e | $remote_emails | index($e) | not))) as $new_local | # 更新远程已存在的账号(用本地数据覆盖同 email 的远程账号) ($remote | map( . as $r | ($local | map(select(.email == $r.email)) | .[0]) as $l | if $l then $l else $r end )) as $updated_remote | # 合并:更新后的远程 + 本地新增 { accounts: ($updated_remote + $new_local), settings: (.[1].settings // .[0].settings // {}), last_updated: (now | strftime("%Y-%m-%dT%H:%M:%SZ")) } ' "$TEMP_DIR/remote_accounts.json" "$LOCAL_FILE" > "$TEMP_DIR/merged_accounts.json" MERGED_COUNT=$(jq '.accounts | length' "$TEMP_DIR/merged_accounts.json") NEW_COUNT=$((MERGED_COUNT - REMOTE_COUNT)) if [[ $NEW_COUNT -gt 0 ]]; then log_success "新增 $NEW_COUNT 个账号,合并后共 $MERGED_COUNT 个账号" else log_info "无新增账号,共 $MERGED_COUNT 个账号" fi # Step 4: 显示账号列表 echo "" log_info "合并后的账号列表:" echo "──────────────────────────────────────────────────────────────" jq -r '.accounts[] | " \(.status == "active" | if . then "🟢" else "🔴" end) \(.email // .name) [\(.id)]"' "$TEMP_DIR/merged_accounts.json" echo "──────────────────────────────────────────────────────────────" echo "" # Step 5: 确认上传 read -p "确认上传到服务器? (y/N) " -n 1 -r echo "" if [[ ! $REPLY =~ ^[Yy]$ ]]; then log_warn "已取消" exit 0 fi # Step 6: 上传合并后的配置 log_info "正在上传配置..." scp -q "$TEMP_DIR/merged_accounts.json" "$SERVER:$REMOTE_FILE" log_success "配置已上传" # Step 7: 重启服务(根据部署方式) echo "" case "$DEPLOY_TYPE" in pm2) log_info "正在重启 PM2 服务..." ssh "$SERVER" "pm2 restart $PM2_APP_NAME" 2>/dev/null && \ log_success "PM2 服务已重启" || \ log_warn "PM2 重启失败,请手动重启" ;; docker) log_info "正在重启 Docker 容器..." ssh "$SERVER" "docker restart $DOCKER_SERVICE_NAME" 2>/dev/null && \ log_success "Docker 容器已重启" || \ log_warn "Docker 重启失败,请手动重启" ;; docker-compose) log_info "正在重启 Docker Compose 服务..." ssh "$SERVER" "cd $REMOTE_PATH && docker compose restart" 2>/dev/null && \ log_success "Docker Compose 服务已重启" || \ log_warn "Docker Compose 重启失败,请手动重启" ;; none) log_warn "已跳过服务重启,请手动重启服务以生效" ;; *) log_warn "未知的部署方式: $DEPLOY_TYPE,请手动重启服务" ;; esac echo "" echo "═══════════════════════════════════════════════════════════════" log_success "同步完成!" echo "═══════════════════════════════════════════════════════════════" echo ""