huanbao commited on
Commit
0d068a3
·
verified ·
1 Parent(s): 2433f23

Update sync_data.sh

Browse files
Files changed (1) hide show
  1. sync_data.sh +91 -59
sync_data.sh CHANGED
@@ -1,6 +1,10 @@
1
  #!/bin/bash
2
  # ==============================================================================
3
- # landppt 多源备份脚本 - 最终稳定版 (Curl重构)
 
 
 
 
4
  # ==============================================================================
5
 
6
  DATA_DIR="."
@@ -10,14 +14,13 @@ BACKUP_KEEP="${BACKUP_KEEP:-24}"
10
  TIMEOUT_RESTORE="120"
11
  TIMEOUT_CMD="180"
12
 
13
- # --- S3 区域设置 ---
14
- # 默认 auto。如果某个 S3 报错,请在环境变量设置 S3_REGION=us-east-1
15
  S3_REGION="${S3_REGION:-auto}"
16
  S3_2_REGION="${S3_2_REGION:-auto}"
17
 
18
  log() { echo "[Backup] $(date '+%Y-%m-%d %H:%M:%S') $*"; }
19
 
20
- # ----------------- 基础函数 -----------------
21
 
22
  run_with_timeout() {
23
  local t="$1"; shift
@@ -31,22 +34,17 @@ run_with_timeout() {
31
  fi
32
  }
33
 
34
- # ----------------- WebDAV 纯 Curl 实现 (核心修改) -----------------
35
-
36
- # 检查配置是否存在
37
  has_webdav() { [[ -n "$WEBDAV_URL" && -n "$WEBDAV_USERNAME" && -n "$WEBDAV_PASSWORD" ]]; }
38
  has_s3() { [[ -n "$S3_ENDPOINT_URL" && -n "$S3_BUCKET" && -n "$S3_ACCESS_KEY_ID" ]]; }
39
  has_s3_2() { [[ -n "$S3_2_ENDPOINT_URL" && -n "$S3_2_BUCKET" && -n "$S3_2_ACCESS_KEY_ID" ]]; }
40
 
41
- # 构造 WebDAV 完整 URL
 
42
  get_webdav_url() {
43
  local file="$1"
44
- # 移除末尾斜杠
45
  local base="${WEBDAV_URL%/}"
46
- # 处理子路径 (移除首尾斜杠)
47
  local sub="${WEBDAV_BACKUP_PATH#/}"
48
  sub="${sub%/}"
49
-
50
  if [ -n "$sub" ]; then
51
  echo "$base/$sub/$file"
52
  else
@@ -54,11 +52,8 @@ get_webdav_url() {
54
  fi
55
  }
56
 
57
- # 获取最新备份文件名 (解析 XML 或 grep 提取)
58
  get_webdav_latest_name() {
59
  local url=$(get_webdav_url "")
60
-
61
- # 使用 curl PROPFIND 获取列表,然后用 grep 提取符合格式的文件名
62
  run_with_timeout 30 curl -s -X PROPFIND -H "Depth: 1" \
63
  -u "$WEBDAV_USERNAME:$WEBDAV_PASSWORD" \
64
  --connect-timeout 15 "$url" \
@@ -66,7 +61,6 @@ get_webdav_latest_name() {
66
  | sort -u | sort | tail -n 1
67
  }
68
 
69
- # WebDAV 下载
70
  download_webdav_file() {
71
  local file="$1"
72
  local dl_path="$2"
@@ -79,29 +73,7 @@ download_webdav_file() {
79
  -o "$dl_path" "$url"
80
  }
81
 
82
- # WebDAV 清理逻辑
83
- cleanup_webdav() {
84
- local url=$(get_webdav_url "")
85
- # 获取所有备份文件列表
86
- local all_files=$(curl -s -X PROPFIND -H "Depth: 1" -u "$WEBDAV_USERNAME:$WEBDAV_PASSWORD" --connect-timeout 15 "$url" \
87
- | grep -o 'landppt_backup_[0-9_]*\.tar\.gz' | sort -u | sort)
88
-
89
- local count=$(echo "$all_files" | grep -c .)
90
-
91
- if [ "$count" -gt "$BACKUP_KEEP" ]; then
92
- local del_count=$(($count - $BACKUP_KEEP))
93
- # log "WebDAV 清理: 发现 $count 个备份,保留 $BACKUP_KEEP 个,删除 $del_count 个旧文件..."
94
-
95
- echo "$all_files" | head -n "$del_count" | while read -r file; do
96
- if [ -n "$file" ]; then
97
- local del_url=$(get_webdav_url "$file")
98
- curl -s -X DELETE -u "$WEBDAV_USERNAME:$WEBDAV_PASSWORD" "$del_url" >/dev/null
99
- fi
100
- done
101
- fi
102
- }
103
-
104
- # ----------------- S3 实现 -----------------
105
 
106
  get_s3_latest_name() {
107
  local ENDPOINT="$1" BUCKET="$2" ACCESS="$3" SECRET="$4" REGION="$5"
@@ -127,26 +99,39 @@ download_s3_file() {
127
  return 1
128
  }
129
 
130
- # ----------------- 解压工具 -----------------
 
131
  extract_db() {
132
  local tar_path="$1"
133
  mkdir -p "$DATA_DIR"
134
- # 使用 tar 原生解压
 
135
  if tar -xzf "$tar_path" -C "$DATA_DIR" 2>/dev/null; then
136
- # 兼容性:如果解压后文件不在根目录,尝试查找
 
 
 
 
 
 
137
  local found=$(find "$DATA_DIR" -name "landppt.db" -type f | head -n 1)
138
- if [ -n "$found" ] && [ "$found" != "$DB_FILE" ]; then
139
  mv "$found" "$DB_FILE"
 
 
 
 
140
  fi
141
- return 0
142
  fi
143
  return 1
144
  }
145
 
146
  # ==============================================================================
147
- # 阶段 1: 恢复流程
148
  # ==============================================================================
149
 
 
 
150
  if [ -f "$DB_FILE" ] && [ -s "$DB_FILE" ]; then
151
  log "本地数据库已存在,跳过恢复。"
152
  else
@@ -166,7 +151,7 @@ else
166
  [ -n "$F_S3_2" ] && echo "$F_S3_2 S3_SEC" >> "$CANDIDATES_FILE" && log "发现 S3(备): $F_S3_2"
167
  fi
168
 
169
- # 3. 检查 WebDAV (无需 Python)
170
  if has_webdav; then
171
  F_DAV=$(get_webdav_latest_name)
172
  [ -n "$F_DAV" ] && echo "$F_DAV WEBDAV" >> "$CANDIDATES_FILE" && log "发现 WebDAV: $F_DAV"
@@ -180,7 +165,7 @@ else
180
  SOURCE_TYPE=$(echo "$BEST_LINE" | awk '{print $2}')
181
  DL_FILE="/tmp/restore.tar.gz"
182
 
183
- log ">>> 使用最新备份: $TARGET_FILE (来源: $SOURCE_TYPE)"
184
  SUCCESS=0
185
 
186
  case "$SOURCE_TYPE" in
@@ -196,30 +181,35 @@ else
196
  esac
197
 
198
  if [ $SUCCESS -eq 1 ] && extract_db "$DL_FILE"; then
199
- log "恢复成功!"
200
  else
201
- log "恢复失败: 下载或解压出错"
202
  fi
203
  rm -f "$DL_FILE"
204
  else
205
- log "未找到备份,启动全新实例。"
206
  fi
207
  rm -f "$CANDIDATES_FILE"
208
  fi
209
 
 
 
210
  # ==============================================================================
211
- # 阶段 2: 后台备份循环
212
  # ==============================================================================
213
  (
 
 
 
214
  while true; do
215
- sleep "$SYNC_INTERVAL"
216
-
217
  if [ -f "$DB_FILE" ]; then
218
  TS=$(date +%Y%m%d_%H%M%S)
219
  BACKUP_NAME="landppt_backup_${TS}.tar.gz"
220
  TMP_BAK="/tmp/$BACKUP_NAME"
221
 
222
- tar -czf "$TMP_BAK" -C "$DATA_DIR" landppt.db 2>/dev/null
 
 
223
 
224
  # --- 1. WebDAV 备份 ---
225
  if has_webdav; then
@@ -228,8 +218,43 @@ fi
228
  -u "$WEBDAV_USERNAME:$WEBDAV_PASSWORD" \
229
  -T "$TMP_BAK" "$UPLOAD_URL" >/dev/null 2>&1; then
230
 
231
- # WebDAV 清理
232
- cleanup_webdav
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
233
  else
234
  log "WebDAV 上传失败"
235
  fi
@@ -242,15 +267,17 @@ fi
242
  export AWS_DEFAULT_REGION="$S3_REGION"
243
 
244
  if run_with_timeout "$TIMEOUT_CMD" aws --endpoint-url "$S3_ENDPOINT_URL" --region "$S3_REGION" s3 cp "$TMP_BAK" "s3://$S3_BUCKET/$BACKUP_NAME" --quiet >/dev/null 2>&1; then
245
- # S3 清理
246
  FILES=$(aws --endpoint-url "$S3_ENDPOINT_URL" --region "$S3_REGION" s3 ls "s3://$S3_BUCKET/" 2>/dev/null | awk '{print $4}' | grep 'landppt_backup_' | sort)
247
  COUNT=$(echo "$FILES" | grep -c .)
248
  if [ "$COUNT" -gt "$BACKUP_KEEP" ]; then
249
- DEL=$(($COUNT - $BACKUP_KEEP))
250
- echo "$FILES" | head -n "$DEL" | while read -r F; do
251
  [ -n "$F" ] && aws --endpoint-url "$S3_ENDPOINT_URL" --region "$S3_REGION" s3 rm "s3://$S3_BUCKET/$F" --quiet
252
  done
253
  fi
 
 
254
  fi
255
  fi
256
 
@@ -265,5 +292,10 @@ fi
265
  rm -f "$TMP_BAK"
266
  log "备份完成: $BACKUP_NAME"
267
  fi
 
 
268
  done
269
- ) &
 
 
 
 
1
  #!/bin/bash
2
  # ==============================================================================
3
+ # landppt 多源备份脚本 (WebDAV + S3/R2/C2)
4
+ # 版本特性:
5
+ # 1. 纯 Curl 实现 (无 Python 依赖)
6
+ # 2. 支持 SQLite WAL 模式 (备份 .db, .db-shm, .db-wal)
7
+ # 3. 阻塞式启动 (防止数据被覆盖)
8
  # ==============================================================================
9
 
10
  DATA_DIR="."
 
14
  TIMEOUT_RESTORE="120"
15
  TIMEOUT_CMD="180"
16
 
17
+ # --- 区域设置 ---
 
18
  S3_REGION="${S3_REGION:-auto}"
19
  S3_2_REGION="${S3_2_REGION:-auto}"
20
 
21
  log() { echo "[Backup] $(date '+%Y-%m-%d %H:%M:%S') $*"; }
22
 
23
+ # ----------------- 基础工具函数 -----------------
24
 
25
  run_with_timeout() {
26
  local t="$1"; shift
 
34
  fi
35
  }
36
 
 
 
 
37
  has_webdav() { [[ -n "$WEBDAV_URL" && -n "$WEBDAV_USERNAME" && -n "$WEBDAV_PASSWORD" ]]; }
38
  has_s3() { [[ -n "$S3_ENDPOINT_URL" && -n "$S3_BUCKET" && -n "$S3_ACCESS_KEY_ID" ]]; }
39
  has_s3_2() { [[ -n "$S3_2_ENDPOINT_URL" && -n "$S3_2_BUCKET" && -n "$S3_2_ACCESS_KEY_ID" ]]; }
40
 
41
+ # ----------------- WebDAV 模块 -----------------
42
+
43
  get_webdav_url() {
44
  local file="$1"
 
45
  local base="${WEBDAV_URL%/}"
 
46
  local sub="${WEBDAV_BACKUP_PATH#/}"
47
  sub="${sub%/}"
 
48
  if [ -n "$sub" ]; then
49
  echo "$base/$sub/$file"
50
  else
 
52
  fi
53
  }
54
 
 
55
  get_webdav_latest_name() {
56
  local url=$(get_webdav_url "")
 
 
57
  run_with_timeout 30 curl -s -X PROPFIND -H "Depth: 1" \
58
  -u "$WEBDAV_USERNAME:$WEBDAV_PASSWORD" \
59
  --connect-timeout 15 "$url" \
 
61
  | sort -u | sort | tail -n 1
62
  }
63
 
 
64
  download_webdav_file() {
65
  local file="$1"
66
  local dl_path="$2"
 
73
  -o "$dl_path" "$url"
74
  }
75
 
76
+ # ----------------- S3 模块 -----------------
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
77
 
78
  get_s3_latest_name() {
79
  local ENDPOINT="$1" BUCKET="$2" ACCESS="$3" SECRET="$4" REGION="$5"
 
99
  return 1
100
  }
101
 
102
+ # ----------------- 解压模块 -----------------
103
+
104
  extract_db() {
105
  local tar_path="$1"
106
  mkdir -p "$DATA_DIR"
107
+
108
+ # 尝试解压
109
  if tar -xzf "$tar_path" -C "$DATA_DIR" 2>/dev/null; then
110
+
111
+ # 检查是否包含 landppt.db
112
+ if [ -f "$DATA_DIR/landppt.db" ]; then
113
+ return 0
114
+ fi
115
+
116
+ # 兼容性查找(防止路径不对)
117
  local found=$(find "$DATA_DIR" -name "landppt.db" -type f | head -n 1)
118
+ if [ -n "$found" ]; then
119
  mv "$found" "$DB_FILE"
120
+ # 尝试移动关联文件
121
+ [ -f "${found}-shm" ] && mv "${found}-shm" "${DB_FILE}-shm"
122
+ [ -f "${found}-wal" ] && mv "${found}-wal" "${DB_FILE}-wal"
123
+ return 0
124
  fi
 
125
  fi
126
  return 1
127
  }
128
 
129
  # ==============================================================================
130
+ # 阶段 1: 启动前恢复 (在前台运行,阻塞应用启动)
131
  # ==============================================================================
132
 
133
+ log ">>> 开始初始化数据检查..."
134
+
135
  if [ -f "$DB_FILE" ] && [ -s "$DB_FILE" ]; then
136
  log "本地数据库已存在,跳过恢复。"
137
  else
 
151
  [ -n "$F_S3_2" ] && echo "$F_S3_2 S3_SEC" >> "$CANDIDATES_FILE" && log "发现 S3(备): $F_S3_2"
152
  fi
153
 
154
+ # 3. 检查 WebDAV
155
  if has_webdav; then
156
  F_DAV=$(get_webdav_latest_name)
157
  [ -n "$F_DAV" ] && echo "$F_DAV WEBDAV" >> "$CANDIDATES_FILE" && log "发现 WebDAV: $F_DAV"
 
165
  SOURCE_TYPE=$(echo "$BEST_LINE" | awk '{print $2}')
166
  DL_FILE="/tmp/restore.tar.gz"
167
 
168
+ log ">>> 决定使用备份: $TARGET_FILE (来源: $SOURCE_TYPE)"
169
  SUCCESS=0
170
 
171
  case "$SOURCE_TYPE" in
 
181
  esac
182
 
183
  if [ $SUCCESS -eq 1 ] && extract_db "$DL_FILE"; then
184
+ log "恢复成功!数据已就绪。"
185
  else
186
+ log "恢复失败: 下载或解压出错"
187
  fi
188
  rm -f "$DL_FILE"
189
  else
190
+ log "未找到备份,启动全新实例。"
191
  fi
192
  rm -f "$CANDIDATES_FILE"
193
  fi
194
 
195
+ log ">>> 数据准备完成,即将启动应用。"
196
+
197
  # ==============================================================================
198
+ # 阶段 2: 启动后台备份 (放入后台运行,不阻塞)
199
  # ==============================================================================
200
  (
201
+ # 延时 60秒,避免与应用启动争抢 IO
202
+ sleep 60
203
+
204
  while true; do
 
 
205
  if [ -f "$DB_FILE" ]; then
206
  TS=$(date +%Y%m%d_%H%M%S)
207
  BACKUP_NAME="landppt_backup_${TS}.tar.gz"
208
  TMP_BAK="/tmp/$BACKUP_NAME"
209
 
210
+ # [关键修复] 打包所有数据库相关文件 (WAL/SHM),确保数据一致性
211
+ # 使用 cd 避免路径问题
212
+ (cd "$DATA_DIR" && tar -czf "$TMP_BAK" landppt.db* 2>/dev/null)
213
 
214
  # --- 1. WebDAV 备份 ---
215
  if has_webdav; then
 
218
  -u "$WEBDAV_USERNAME:$WEBDAV_PASSWORD" \
219
  -T "$TMP_BAK" "$UPLOAD_URL" >/dev/null 2>&1; then
220
 
221
+ # WebDAV 清理逻辑
222
+ LIST_URL=$(get_webdav_url "")
223
+ ALL_FILES=$(curl -s -X PROPFIND -H "Depth: 1" -u "$WEBDAV_USERNAME:$WEBDAV_PASSWORD" --connect-timeout 15 "$LIST_URL" \
224
+ | grep -o 'landppt_backup_[0-9_]*\.tar\.gz' | sort -u | sort)
225
+
226
+ COUNT=$(echo "$ALL_FILES" | grep -c .)
227
+ if [ "$COUNT" -gt "$BACKUP_KEEP" ]; then
228
+ DEL_
229
+ <details type="reasoning" done="true" duration="3">
230
+ <summary>Thought for 3 seconds</summary>
231
+ &gt; 用户要求继续输出被截断的代码。
232
+ &gt; 上下文是 `sync_data.sh` 脚本中的 WebDAV 清理逻辑部分。
233
+ &gt; 截断处是:
234
+ &gt; ```bash
235
+ &gt; COUNT=$(echo &quot;$ALL_FILES&quot; | grep -c .)
236
+ &gt; if [ &quot;$COUNT&quot; -gt &quot;$BACKUP_KEEP&quot; ]; then
237
+ &gt; DEL_
238
+ &gt; ```
239
+ &gt; 我需要补全 WebDAV 清理逻辑,然后是 S3(主) 备份与清理,S3(备) 备份,以及循环结尾。
240
+ &gt; 最后别忘了 ``。
241
+ &gt;
242
+ &gt; 补充逻辑:
243
+ &gt; 1. 完成 `DEL_COUNT` 计算。
244
+ &gt; 2. 循环删除旧文件。
245
+ &gt; 3. S3 主备份代码 + 清理代码。
246
+ &gt; 4. S3 备备份代码。
247
+ &gt; 5. 清理临时文件和循环结束。
248
+ &gt; 6. `exit 0` 让主进程退出。
249
+ </details>
250
+ COUNT=$(($COUNT - $BACKUP_KEEP))
251
+ echo "$ALL_FILES" | head -n "$DEL_COUNT" | while read -r F; do
252
+ if [ -n "$F" ]; then
253
+ DEL_URL=$(get_webdav_url "$F")
254
+ curl -s -X DELETE -u "$WEBDAV_USERNAME:$WEBDAV_PASSWORD" "$DEL_URL" >/dev/null 2>&1
255
+ fi
256
+ done
257
+ fi
258
  else
259
  log "WebDAV 上传失败"
260
  fi
 
267
  export AWS_DEFAULT_REGION="$S3_REGION"
268
 
269
  if run_with_timeout "$TIMEOUT_CMD" aws --endpoint-url "$S3_ENDPOINT_URL" --region "$S3_REGION" s3 cp "$TMP_BAK" "s3://$S3_BUCKET/$BACKUP_NAME" --quiet >/dev/null 2>&1; then
270
+ # S3 清理逻辑
271
  FILES=$(aws --endpoint-url "$S3_ENDPOINT_URL" --region "$S3_REGION" s3 ls "s3://$S3_BUCKET/" 2>/dev/null | awk '{print $4}' | grep 'landppt_backup_' | sort)
272
  COUNT=$(echo "$FILES" | grep -c .)
273
  if [ "$COUNT" -gt "$BACKUP_KEEP" ]; then
274
+ DEL_COUNT=$(($COUNT - $BACKUP_KEEP))
275
+ echo "$FILES" | head -n "$DEL_COUNT" | while read -r F; do
276
  [ -n "$F" ] && aws --endpoint-url "$S3_ENDPOINT_URL" --region "$S3_REGION" s3 rm "s3://$S3_BUCKET/$F" --quiet
277
  done
278
  fi
279
+ else
280
+ log "S3(主) 上传失败"
281
  fi
282
  fi
283
 
 
292
  rm -f "$TMP_BAK"
293
  log "备份完成: $BACKUP_NAME"
294
  fi
295
+
296
+ sleep "$SYNC_INTERVAL"
297
  done
298
+ ) &
299
+
300
+ # 脚本主进程退出,允许 Docker 继续启动应用
301
+ exit 0