File size: 10,000 Bytes
13ad5f7
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
636a8bc
 
 
 
 
 
b10884e
 
636a8bc
 
 
 
 
 
b10884e
 
636a8bc
b10884e
 
 
 
 
13ad5f7
636a8bc
 
 
 
b10884e
636a8bc
b10884e
 
 
 
 
 
 
 
 
 
 
636a8bc
 
 
 
 
b10884e
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
636a8bc
 
 
 
 
 
b10884e
13ad5f7
 
 
 
 
 
 
 
 
 
 
 
 
b10884e
13ad5f7
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
636a8bc
 
13ad5f7
 
636a8bc
13ad5f7
 
 
636a8bc
 
 
13ad5f7
 
 
 
 
 
 
636a8bc
 
13ad5f7
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
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
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
#!/bin/bash

# 检查必要的环境变量
if [ -z "$WEBDAV_URL" ] || [ -z "$WEBDAV_USERNAME" ] || [ -z "$WEBDAV_PASSWORD" ]; then
    echo "缺少必要的环境变量 WEBDAV_URL、WEBDAV_USERNAME 或 WEBDAV_PASSWORD"
    exit 1
fi

if [ -z "$HF_TOKEN" ] || [ -z "$DATASET_ID" ]; then
    echo "缺少必要的环境变量 HF_TOKEN 或 DATASET_ID"
    exit 1
fi

# 创建数据目录
mkdir -p ./data

# 创建 HuggingFace 同步脚本
cat > /tmp/hf_sync.py << 'EOL'
from huggingface_hub import HfApi
import sys
import os

def manage_backups(api, repo_id, max_files=50):
    files = api.list_repo_files(repo_id=repo_id, repo_type="dataset")
    backup_files = [f for f in files if f.startswith('webui_backup_') and f.endswith('.db')]
    backup_files.sort()
    
    if len(backup_files) >= max_files:
        files_to_delete = backup_files[:(len(backup_files) - max_files + 1)]
        for file_to_delete in files_to_delete:
            try:
                api.delete_file(path_in_repo=file_to_delete, repo_id=repo_id, repo_type="dataset")
                print(f'已删除旧备份: {file_to_delete}')
            except Exception as e:
                print(f'删除 {file_to_delete} 时出错: {str(e)}')

def upload_backup(file_path, file_name, token, repo_id):
    api = HfApi(token=token)
    try:
        api.upload_file(
            path_or_fileobj=file_path,
            path_in_repo=file_name,
            repo_id=repo_id,
            repo_type="dataset"
        )
        print(f"成功上传 {file_name}")
        
        manage_backups(api, repo_id)
    except Exception as e:
        print(f"文件上传出错: {str(e)}")

# 下载最新备份
def download_latest_backup(token, repo_id):
    try:
        api = HfApi(token=token)
        files = api.list_repo_files(repo_id=repo_id, repo_type="dataset")
        backup_files = [f for f in files if f.startswith('webui_backup_') and f.endswith('.db')]
        
        if not backup_files:
            print("未找到备份文件")
            return False
            
        latest_backup = sorted(backup_files)[-1]
        
        filepath = api.hf_hub_download(
            repo_id=repo_id,
            filename=latest_backup,
            repo_type="dataset"
        )
        
        if filepath and os.path.exists(filepath):
            os.makedirs('./data', exist_ok=True)
            os.system(f'cp "{filepath}" ./data/webui.db')
            print(f"成功从 {latest_backup} 恢复备份")
            return True
        return False
                
    except Exception as e:
        print(f"下载备份时出错: {str(e)}")
        return False

if __name__ == "__main__":
    action = sys.argv[1]
    token = sys.argv[2]
    repo_id = sys.argv[3]
    
    if action == "upload":
        file_path = sys.argv[4]
        file_name = sys.argv[5]
        upload_backup(file_path, file_name, token, repo_id)
    elif action == "download":
        download_latest_backup(token, repo_id)
EOL

# 首次启动时的数据恢复策略
echo "开始初始化数据恢复..."

# 打印 WebDAV 信息(隐藏密码)
echo "WebDAV URL: $WEBDAV_URL"
echo "WebDAV 用户名: $WEBDAV_USERNAME"
masked_password=$(echo $WEBDAV_PASSWORD | sed 's/./*/g')
echo "WebDAV 密码: $masked_password"

# 首先尝试从 WebDAV 恢复最新文件
echo "正在尝试从 WebDAV 获取文件列表..."
echo "PROPFIND 请求: $WEBDAV_URL/openwebui/"

# 获取并打印 WebDAV 目录内容
webdav_list_output=$(curl -v -X PROPFIND --user "$WEBDAV_USERNAME:$WEBDAV_PASSWORD" -H "Depth: 1" "$WEBDAV_URL/openwebui/" 2>&1)
echo "WebDAV 目录内容响应:"
echo "$webdav_list_output"

# 获取 WebDAV 目录中的文件列表并找出最新的备份文件
webdav_files=$(echo "$webdav_list_output" | grep -o '<d:href>[^<]*webui_[0-9][0-9]-[0-9][0-9]\.db</d:href>' | sed 's/<d:href>//g' | sed 's/<\/d:href>//g')

if [ -n "$webdav_files" ]; then
    # 找出最新的文件 (按文件名排序,取最后一个)
    latest_file=$(echo "$webdav_files" | sort | tail -n 1)
    echo "找到最新的 WebDAV 备份文件: $latest_file"
    
    # 构建并打印完整下载链接
    download_url="$WEBDAV_URL$latest_file"
    echo "下载 URL: $download_url"
    
    # 下载最新文件
    curl -v -L --fail --user "$WEBDAV_USERNAME:$WEBDAV_PASSWORD" "$download_url" -o "./data/webui.db" && {
        echo "成功从 WebDAV 下载最新数据库文件: $latest_file"
        # 上传到 HuggingFace
        timestamp=$(date +%Y%m%d_%H%M%S)
        backup_file="webui_backup_${timestamp}.db"
        cp ./data/webui.db "/tmp/${backup_file}"
        echo "正在上传初始备份到 HuggingFace..."
        python3 /tmp/hf_sync.py upload "${HF_TOKEN}" "${DATASET_ID}" "/tmp/${backup_file}" "${backup_file}"
        rm -f "/tmp/${backup_file}"
    } || {
        echo "从 WebDAV 下载最新文件失败,尝试下载 WebDAV 的 webui.db..."
        
        # 打印 webui.db 下载链接
        main_db_url="$WEBDAV_URL/openwebui/webui.db"
        echo "尝试下载主数据库文件 URL: $main_db_url"
        
        curl -v -L --fail --user "$WEBDAV_USERNAME:$WEBDAV_PASSWORD" "$main_db_url" -o "./data/webui.db" && {
            echo "成功从 WebDAV 下载主数据库文件"
            # 上传到 HuggingFace
            timestamp=$(date +%Y%m%d_%H%M%S)
            backup_file="webui_backup_${timestamp}.db"
            cp ./data/webui.db "/tmp/${backup_file}"
            echo "正在上传初始备份到 HuggingFace..."
            python3 /tmp/hf_sync.py upload "${HF_TOKEN}" "${DATASET_ID}" "/tmp/${backup_file}" "${backup_file}"
            rm -f "/tmp/${backup_file}"
        } || {
            echo "从 WebDAV 下载失败,尝试从 HuggingFace 恢复..."
            python3 /tmp/hf_sync.py download "${HF_TOKEN}" "${DATASET_ID}" || {
                echo "所有恢复方式均失败,将使用空数据库开始"
            }
        }
    }
else
    echo "WebDAV 中没有找到符合格式的备份文件,尝试下载 webui.db..."
    
    # 打印 webui.db 下载链接
    main_db_url="$WEBDAV_URL/openwebui/webui.db"
    echo "尝试下载主数据库文件 URL: $main_db_url"
    
    curl -v -L --fail --user "$WEBDAV_USERNAME:$WEBDAV_PASSWORD" "$main_db_url" -o "./data/webui.db" && {
        echo "成功从 WebDAV 下载主数据库文件"
        # 上传到 HuggingFace
        timestamp=$(date +%Y%m%d_%H%M%S)
        backup_file="webui_backup_${timestamp}.db"
        cp ./data/webui.db "/tmp/${backup_file}"
        echo "正在上传初始备份到 HuggingFace..."
        python3 /tmp/hf_sync.py upload "${HF_TOKEN}" "${DATASET_ID}" "/tmp/${backup_file}" "${backup_file}"
        rm -f "/tmp/${backup_file}"
    } || {
        echo "从 WebDAV 下载失败,尝试从 HuggingFace 恢复..."
        python3 /tmp/hf_sync.py download "${HF_TOKEN}" "${DATASET_ID}" || {
            echo "所有恢复方式均失败,将使用空数据库开始"
        }
    }
fi

# 定义 WebDAV 同步函数
webdav_sync() {
    SYNC_INTERVAL=${SYNC_INTERVAL:-7200}  # 默认间隔时间为 7200 秒
    echo "WebDAV 同步进程启动,等待 ${SYNC_INTERVAL} 秒后开始同步..."
    sleep $SYNC_INTERVAL

    while true; do
        echo "开始 WebDAV 同步 $(date)"
        
        # 检查数据库文件是否存在
        if [ -f "./data/webui.db" ]; then
            # 生成当前时间的文件名
            FILENAME="webui_$(date +'%m-%d_%H%M').db"
            
            echo "同步到 WebDAV..."
            upload_url="$WEBDAV_URL/openwebui/$FILENAME"
            echo "上传 URL: $upload_url"

            # 上传以日期命名的数据库文件
            curl -v -L -T "./data/webui.db" --user "$WEBDAV_USERNAME:$WEBDAV_PASSWORD" "$upload_url" && {
                echo "WebDAV 上传成功: $FILENAME"
                
                # 覆盖Webdav目录下默认的webui.db文件
                main_file_url="$WEBDAV_URL/openwebui/webui.db"
                echo "更新主文件 URL: $main_file_url"
                curl -v -L -T "./data/webui.db" --user "$WEBDAV_USERNAME:$WEBDAV_PASSWORD" "$main_file_url" && {
                    echo "WebDAV 更新主文件成功"
                } || {
                    echo "WebDAV 更新主文件失败"
                }
            } || {
                echo "WebDAV 上传失败,等待重试..."
                sleep 10
                echo "重试上传 URL: $upload_url"
                curl -v -L -T "./data/webui.db" --user "$WEBDAV_USERNAME:$WEBDAV_PASSWORD" "$upload_url" || {
                    echo "重试失败,放弃上传。"
                }
            }
        else
            echo "未找到 webui.db 文件,跳过 WebDAV 同步"
        fi

        # 等待下一次同步间隔
        echo "WebDAV 同步完成,下次同步将在 ${SYNC_INTERVAL} 秒后进行..."
        sleep $SYNC_INTERVAL
    done
}

# 定义 HuggingFace 同步函数
hf_sync() {
    SYNC_INTERVAL=${SYNC_INTERVAL:-7200}
    echo "HuggingFace 同步进程启动,等待 ${SYNC_INTERVAL} 秒后开始同步..."
    sleep $(($SYNC_INTERVAL / 2))  # 错开与 WebDAV 同步的时间

    while true; do
        echo "开始 HuggingFace 同步 $(date)"
        
        if [ -f "./data/webui.db" ]; then
            timestamp=$(date +%Y%m%d_%H%M%S)
            backup_file="webui_backup_${timestamp}.db"
            
            # 复制数据库文件
            cp ./data/webui.db "/tmp/${backup_file}"
            
            echo "正在上传备份到 HuggingFace..."
            python3 /tmp/hf_sync.py upload "${HF_TOKEN}" "${DATASET_ID}" "/tmp/${backup_file}" "${backup_file}"
            
            rm -f "/tmp/${backup_file}"
        else
            echo "数据库文件不存在,跳过 HuggingFace 同步"
        fi
        
        echo "HuggingFace 同步完成,下次同步将在 ${SYNC_INTERVAL} 秒后进行..."
        sleep $SYNC_INTERVAL
    done
}

# 后台启动同步进程
webdav_sync &
hf_sync &