236 lines
9.2 KiB
Bash
Executable File
236 lines
9.2 KiB
Bash
Executable File
#!/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 ""
|