#!/bin/bash # ================= 配置 ================= WEBDAV_URL=${WEBDAV_URL%/} WEBDAV_BACKUP_PATH=${WEBDAV_BACKUP_PATH:-""} # 处理子路径 WEBDAV_BACKUP_PATH=${WEBDAV_BACKUP_PATH#/} WEBDAV_BACKUP_PATH=${WEBDAV_BACKUP_PATH%/} if [ -n "$WEBDAV_BACKUP_PATH" ]; then FULL_WEBDAV_URL="${WEBDAV_URL}/${WEBDAV_BACKUP_PATH}" else FULL_WEBDAV_URL="${WEBDAV_URL}" fi SYNC_INTERVAL=${SYNC_INTERVAL:-60} TARGET_FILENAME="accounts.json" REMOTE_FILENAME="antigravity_accounts.json" TEMP_DIR="/tmp/backup_temp" # ======================================= log() { echo "[Backup] [$(date '+%H:%M:%S')] $1"; } mkdir -p "$TEMP_DIR" # 检查环境 if [[ -z "$WEBDAV_URL" ]]; then log "未设置 WEBDAV_URL,跳过备份" exit 0 fi if ! command -v curl &> /dev/null; then apk add --no-cache curl || (apt-get update && apt-get install -y curl) fi # === 核心修复:智能寻找真正活跃的文件 === find_active_file() { FILE_ROOT="/app/$TARGET_FILENAME" FILE_DATA="/app/data/$TARGET_FILENAME" # 获取文件修改时间戳 (如果文件不存在则为0) TIME_ROOT=$(stat -c %Y "$FILE_ROOT" 2>/dev/null || echo 0) TIME_DATA=$(stat -c %Y "$FILE_DATA" 2>/dev/null || echo 0) # 比较哪个文件更新 if [ "$TIME_ROOT" -gt "$TIME_DATA" ]; then echo "$FILE_ROOT" elif [ "$TIME_DATA" -gt 0 ]; then echo "$FILE_DATA" else # 如果都没有,尝试用 find 找 (兼容性兜底) find /app -name "$TARGET_FILENAME" -type f -not -path "*/node_modules/*" | head -n 1 fi } # === 恢复功能 === restore() { log "正在从 WebDAV 恢复备份..." REMOTE_FILE="$FULL_WEBDAV_URL/$REMOTE_FILENAME" TEMP_FILE="$TEMP_DIR/restored.json" HTTP_CODE=$(curl -s -o "$TEMP_FILE" -w "%{http_code}" -u "$WEBDAV_USERNAME:$WEBDAV_PASSWORD" "$REMOTE_FILE") if [[ "$HTTP_CODE" == "200" ]] && [ -s "$TEMP_FILE" ]; then # 恢复策略:只恢复到 /app 根目录 # 为什么?因为我们确定程序会优先读取根目录,或者在根目录生成 # 如果程序之前在 data 目录,它找不到 data 里的文件通常会自动回落或重建 DEST_PATH="/app/$TARGET_FILENAME" cp "$TEMP_FILE" "$DEST_PATH" log "✅ 备份已恢复到: $DEST_PATH" # 只有当 data 目录已经存在时,才顺便放一份进去,但不强求 if [ -d "/app/data" ]; then cp "$TEMP_FILE" "/app/data/$TARGET_FILENAME" fi else log "📭 未找到远程备份或文件为空,将以新状态启动" fi } # === 循环备份功能 === loop() { log "启动智能增量备份 (间隔: ${SYNC_INTERVAL}秒)" # 尝试创建远程目录 if [ -n "$WEBDAV_BACKUP_PATH" ]; then curl -s -o /dev/null -u "$WEBDAV_USERNAME:$WEBDAV_PASSWORD" -X MKCOL "$FULL_WEBDAV_URL/" fi while true; do sleep $SYNC_INTERVAL # 每次都重新判断哪个文件是最新的 CURRENT_PATH=$(find_active_file) if [ -n "$CURRENT_PATH" ] && [ -f "$CURRENT_PATH" ]; then FILE_SIZE=$(wc -c < "$CURRENT_PATH") # 只有大于 10 字节才备份 (避免备份空的 []) if [ "$FILE_SIZE" -gt 10 ]; then # log "正在备份活跃文件: $CURRENT_PATH (大小: $FILE_SIZE)" HTTP_CODE=$(curl -s -o /dev/null -w "%{http_code}" -u "$WEBDAV_USERNAME:$WEBDAV_PASSWORD" -T "$CURRENT_PATH" "$FULL_WEBDAV_URL/$REMOTE_FILENAME") if [[ "$HTTP_CODE" != "201" ]] && [[ "$HTTP_CODE" != "204" ]] && [[ "$HTTP_CODE" != "200" ]]; then log "❌ 上传失败: HTTP $HTTP_CODE" else # 成功时不刷屏,静默成功 : fi else log "⚠️ 文件过小 ($FILE_SIZE bytes),跳过备份以免覆盖数据" fi else log "等待 accounts.json 生成..." fi done } case "$1" in "restore") restore ;; "loop") loop ;; *) restore; loop ;; esac