File size: 7,470 Bytes
13ad5f7
51af98b
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
13ad5f7
51af98b
 
 
13ad5f7
51af98b
 
85c4208
 
 
 
 
51af98b
85c4208
 
 
51af98b
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
b10884e
51af98b
7d26d69
 
51af98b
 
 
 
 
 
 
 
 
 
b10884e
13ad5f7
51af98b
 
 
 
 
7d26d69
51af98b
7d26d69
51af98b
7d26d69
51af98b
85c4208
51af98b
 
7d26d69
85c4208
51af98b
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
#!/bin/bash
# sync_data.sh - 负责数据恢复和启动后台同步任务

# 遇到错误时立即退出(在恢复阶段)
set -e

# --- 配置 ---
# WebDAV 相关环境变量由 Hugging Face Secrets 提供:
# WEBDAV_URL, WEBDAV_USERNAME, WEBDAV_PASSWORD
# Hugging Face 相关环境变量由 Hugging Face Secrets 提供:
# HF_TOKEN, DATASET_ID
WEBDAV_BASE_PATH="openwebui" # WebDAV上的基础目录名
LOCAL_DATA_DIR="./data"      # 本地数据存储目录
DB_FILENAME="webui.db"       # 数据库文件名
WEBDAV_SYNC_INTERVAL=${WEBDAV_SYNC_INTERVAL:-7200} # WebDAV同步间隔(秒),默认2小时
HF_SYNC_INTERVAL=${HF_SYNC_INTERVAL:-7200}     # Hugging Face同步间隔(秒),默认2小时
WEBDAV_CLEANUP_DAYS=7        # WebDAV保留最近多少天的备份
HF_MAX_BACKUPS=50            # Hugging Face保留的最大备份数量 (通过hf_sync.py控制)

# --- 检查环境变量 ---
if [ -z "$WEBDAV_URL" ] || [ -z "$WEBDAV_USERNAME" ] || [ -z "$WEBDAV_PASSWORD" ]; then
    echo "错误:缺少必要的WebDAV环境变量 (WEBDAV_URL, WEBDAV_USERNAME, WEBDAV_PASSWORD)。"
    exit 1
fi
if [ -z "$HF_TOKEN" ] || [ -z "$DATASET_ID" ]; then
    echo "错误:缺少必要的Hugging Face环境变量 (HF_TOKEN, DATASET_ID)。"
    exit 1
fi

# 确保WebDAV URL末尾没有斜杠,方便拼接
WEBDAV_URL=$(echo "$WEBDAV_URL" | sed 's:/*$::')
WEBDAV_FULL_PATH="$WEBDAV_URL/$WEBDAV_BASE_PATH"

# --- 函数定义 ---
# 计算文件MD5哈希
get_file_hash() {
    local file_path="$1"
    if [ -f "$file_path" ]; then
        md5sum "$file_path" | awk '{print $1}'
    else
        echo "not_found" # 返回特殊值表示文件不存在
    fi
}

# --- 初始化和恢复 ---
echo "[恢复] 开始初始化数据恢复流程..."
mkdir -p "$LOCAL_DATA_DIR"
LOCAL_DB_PATH="$LOCAL_DATA_DIR/$DB_FILENAME"
recovered=false

# 1. 尝试从 WebDAV 恢复最新的日期文件
echo "[恢复] 尝试从 WebDAV 恢复 ($WEBDAV_FULL_PATH)..."
# 使用 curl 获取目录列表 (PROPFIND)。注意:解析 XML 可能不稳定
# curl -s -f: 静默模式,遇到HTTP错误时失败退出
webdav_list_output=$(curl -s -f --user "$WEBDAV_USERNAME:$WEBDAV_PASSWORD" -X PROPFIND -H "Depth: 1" "$WEBDAV_FULL_PATH/" || echo "WebDAV PROPFIND failed")

if [[ "$webdav_list_output" != "WebDAV PROPFIND failed" ]]; then
    # 提取日期格式的文件名 (webui_YYYYMMDD.db)
    webdav_files=$(echo "$webdav_list_output" | grep '<d:href>' | sed 's#<d:href>[^<]*/$[^<]*$</d:href>#\1#' | grep -E '^webui_[0-9]{8}\.db$')
    if [ -n "$webdav_files" ]; then
        latest_webdav_file=$(echo "$webdav_files" | sort -r | head -n 1)
        echo "[恢复] 在WebDAV找到最新的日期文件: $latest_webdav_file"
        download_url="$WEBDAV_FULL_PATH/$latest_webdav_file"
        temp_db_path="${LOCAL_DB_PATH}.webdav.tmp"
        echo "[恢复] 尝试下载: $download_url"
        if curl -L -f -s -o "$temp_db_path" --user "$WEBDAV_USERNAME:$WEBDAV_PASSWORD" "$download_url"; then
            # 验证下载的文件是否有效(至少非空)
            if [ -s "$temp_db_path" ]; then
                mv "$temp_db_path" "$LOCAL_DB_PATH"
                echo "[恢复] 成功从 WebDAV ($latest_webdav_file) 恢复数据库。"
                recovered=true
            else
                echo "[恢复] WebDAV下载的文件为空或无效,删除临时文件。"
                rm -f "$temp_db_path"
            fi
        else
            echo "[恢复] 从 WebDAV 下载 $latest_webdav_file 失败。"
            rm -f "$temp_db_path"
        fi
    else
        echo "[恢复] 在WebDAV路径 ($WEBDAV_FULL_PATH/) 未找到符合 'webui_YYYYMMDD.db' 格式的文件。"
        # 可选:尝试恢复主文件 webui.db (如果存在)
        main_db_url="$WEBDAV_FULL_PATH/$DB_FILENAME"
        echo "[恢复] 尝试从WebDAV恢复主文件: $main_db_url"
        temp_db_path="${LOCAL_DB_PATH}.webdav_main.tmp"
        if curl -L -f -s -o "$temp_db_path" --user "$WEBDAV_USERNAME:$WEBDAV_PASSWORD" "$main_db_url"; then
             if [ -s "$temp_db_path" ]; then
                mv "$temp_db_path" "$LOCAL_DB_PATH"
                echo "[恢复] 成功从 WebDAV (主文件 $DB_FILENAME) 恢复数据库。"
                recovered=true
             else
                echo "[恢复] WebDAV下载的主文件为空或无效,删除临时文件。"
                rm -f "$temp_db_path"
             fi
        else
            echo "[恢复] 从WebDAV下载主文件 $DB_FILENAME 失败。"
            rm -f "$temp_db_path"
        fi
    fi
else
    echo "[恢复] 无法访问WebDAV目录 ($WEBDAV_FULL_PATH/)。"
fi

# 2. 如果WebDAV恢复失败,尝试从 Hugging Face 恢复
if [ "$recovered" != true ]; then
    echo "[恢复] WebDAV恢复失败或未找到文件,尝试从 Hugging Face ($DATASET_ID) 恢复..."
    # 调用 Python 脚本进行下载,传递目标目录
    if python3 /app/hf_sync.py download "$HF_TOKEN" "$DATASET_ID" "$LOCAL_DATA_DIR"; then
        echo "[恢复] 成功从 Hugging Face 恢复。"
        recovered=true
    else
        echo "[恢复] 从 Hugging Face 恢复也失败了。"
    fi
fi

# 3. 如果所有恢复都失败,并且本地数据库文件不存在,则创建空文件
if [ "$recovered" != true ] && [ ! -f "$LOCAL_DB_PATH" ]; then
    echo "[恢复] 所有恢复方式均失败,创建空的数据库文件: $LOCAL_DB_PATH"
    touch "$LOCAL_DB_PATH"
fi

echo "[恢复] 数据恢复流程结束。"

# --- 后台同步任务 ---

# WebDAV 同步函数
webdav_sync() {
    echo "[WebDAV Sync] 后台任务启动,间隔: ${WEBDAV_SYNC_INTERVAL} 秒"
    local last_uploaded_hash=""

    while true; do
        timestamp=$(date '+%Y-%m-%d %H:%M:%S')
        echo "[WebDAV Sync @ $timestamp] 开始检查..."

        if [ -f "$LOCAL_DB_PATH" ]; then
            current_hash=$(get_file_hash "$LOCAL_DB_PATH")
            echo "[WebDAV Sync @ $timestamp] 本地文件哈希: $current_hash"

            if [ "$current_hash" == "$last_uploaded_hash" ]; then
                echo "[WebDAV Sync @ $timestamp] 文件未变化,跳过上传。"
            else
                echo "[WebDAV Sync @ $timestamp] 检测到文件变化或首次运行,准备上传到 WebDAV..."
                current_date=$(date +'%Y%m%d')
                dated_filename="webui_${current_date}.db"
                upload_dated_url="$WEBDAV_FULL_PATH/$dated_filename"
                upload_main_url="$WEBDAV_FULL_PATH/$DB_FILENAME"

                # 上传带日期的文件
                echo "[WebDAV Sync @ $timestamp] 上传日期文件: $upload_dated_url"
                if curl -L -f -T "$LOCAL_DB_PATH" --user "$WEBDAV_USERNAME:$WEBDAV_PASSWORD" "$upload_dated_url"; then
                    echo "[WebDAV Sync @ $timestamp] 日期文件上传成功: $dated_filename"

                    # 上传主文件 (覆盖)
                    echo "[WebDAV Sync @ $timestamp] 更新主文件: $upload_main_url"
                    if curl -L -f -T "$LOCAL_DB_PATH" --user "$WEBDAV_USERNAME:$WEBDAV_PASSWORD" "$upload_main_url"; then
                        echo "[WebDAV Sync @ $timestamp] 主文件更新成功。"
                        last_uploaded_hash=$current_hash # 只有主文件也成功才更新哈希
                    else
                        echo "[WebDAV Sync @ $timestamp] 错误:主文件更新失败!"
                        # 主文件失败,不更新哈希,下次会