web / sync_data.sh
nbugs's picture
Update sync_data.sh
51af98b verified
raw
history blame
7.47 kB
#!/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] 错误:主文件更新失败!"
# 主文件失败,不更新哈希,下次会