aappeekk commited on
Commit
d558b55
·
verified ·
1 Parent(s): 293953c

Update sync_data.sh

Browse files
Files changed (1) hide show
  1. sync_data.sh +98 -121
sync_data.sh CHANGED
@@ -1,143 +1,120 @@
1
  #!/bin/bash
2
- set -e
3
 
4
- #################################
5
- # 1. WebDAV 参数检查
6
- #################################
 
 
 
 
7
  if [ -z "$WEBDAV_URL" ] || [ -z "$WEBDAV_USERNAME" ] || [ -z "$WEBDAV_PASSWORD" ]; then
8
- echo "[WARN] WebDAV not configured, starting Koishi without restore."
9
- exec yarn start
 
10
  fi
11
 
12
- WEBDAV_BACKUP_PATH=${WEBDAV_BACKUP_PATH:-""}
13
- FULL_WEBDAV_URL="$WEBDAV_URL"
14
- [ -n "$WEBDAV_BACKUP_PATH" ] && FULL_WEBDAV_URL="$WEBDAV_URL/$WEBDAV_BACKUP_PATH"
15
 
16
- #################################
17
- # 2. 启动前恢复备份(只此一次)
18
- #################################
19
- echo "[INFO] Restoring backup from WebDAV before Koishi startup..."
20
-
21
- # 检查并恢复备份
22
- python3 <<EOF
23
- import tarfile, sys, requests
24
  from webdav3.client import Client
25
 
26
  options = {
27
- "webdav_hostname": "${FULL_WEBDAV_URL}",
28
- "webdav_login": "${WEBDAV_USERNAME}",
29
- "webdav_password": "${WEBDAV_PASSWORD}",
30
  }
31
  client = Client(options)
32
-
33
  try:
34
- backups = [f for f in client.list()
35
- if f.startswith("koishi_backup_") and f.endswith(".tar.gz")]
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
36
  except Exception as e:
37
- print(f"[WARN] WebDAV error: {e}")
38
- sys.exit(0)
39
-
40
- if not backups:
41
- print("[INFO] No backup found, skipping restore.")
42
- sys.exit(0)
43
-
44
- latest = sorted(backups)[-1]
45
- print(f"[INFO] Latest backup: {latest}")
46
-
47
- r = requests.get(
48
- f"${FULL_WEBDAV_URL}/{latest}",
49
- auth=("${WEBDAV_USERNAME}", "${WEBDAV_PASSWORD}"),
50
- stream=True,
51
- )
52
- if r.status_code != 200:
53
- print("[WARN] Failed to download backup")
54
- sys.exit(0)
55
-
56
- tmp = f"/tmp/{latest}"
57
- with open(tmp, "wb") as f:
58
- for chunk in r.iter_content(8192):
59
- f.write(chunk)
60
-
61
- with tarfile.open(tmp, "r:gz") as tar:
62
- tar.extractall("/app")
63
-
64
- print("[INFO] Restore completed.")
65
- EOF
66
-
67
- #################################
68
- # 3. 启动 Koishi 服务
69
- #################################
70
- echo "[INFO] Starting Koishi..."
71
- exec yarn start &
72
 
73
- #################################
74
- # 4. 启动周期性备份任务(启动 Koishi 后)
75
- #################################
76
  sync_data() {
77
  while true; do
78
- echo "[INFO] Backup started at $(date)"
79
- ts=$(date +%Y%m%d_%H%M%S)
80
- file="koishi_backup_${ts}.tar.gz"
81
-
82
- # 使用文件锁确保压缩期间不被其他进程干扰
83
- exec 200>/tmp/koishi_backup.lock
84
- flock -n 200 || { echo "[ERROR] Could not lock backup process, skipping this cycle."; return 1; }
85
-
86
- # 执行备份操作
87
- tar -czf "/tmp/$file" -C /app .
88
-
89
- # 释放锁
90
- flock -u 200
91
-
92
- # 使用 Python WebDAV 客户端上传文件
93
- python3 <<EOF
94
- import os
 
 
 
 
 
 
 
 
 
 
 
 
 
 
95
  from webdav3.client import Client
96
-
97
- options = {
98
- "webdav_hostname": "${FULL_WEBDAV_URL}",
99
- "webdav_login": "${WEBDAV_USERNAME}",
100
- "webdav_password": "${WEBDAV_PASSWORD}",
101
- }
102
- client = Client(options)
103
-
104
- # 上传备份文件
105
- try:
106
- with open("/tmp/$file", "rb") as f:
107
- client.upload(os.path.join("${FULL_WEBDAV_URL}", "$file"), f)
108
- print(f"[INFO] Backup uploaded successfully: {file}")
109
- except Exception as e:
110
- print(f"[ERROR] Failed to upload backup: {e}")
111
- EOF
112
-
113
- # 清理 WebDAV 上的旧备份(只保留最近 5 个)
114
- python3 <<EOF
115
- from webdav3.client import Client
116
-
117
- options = {
118
- "webdav_hostname": "${FULL_WEBDAV_URL}",
119
- "webdav_login": "${WEBDAV_USERNAME}",
120
- "webdav_password": "${WEBDAV_PASSWORD}",
121
- }
122
  client = Client(options)
123
-
124
- # 获取备份文件并排序
125
- files = sorted(f for f in client.list() if f.startswith("koishi_backup_") and f.endswith(".tar.gz"))
126
- # 删除旧的备份文件
127
- for f in files[:-5]:
128
- client.clean(f)
129
- print(f"[INFO] Deleted old backup: {f}")
130
- EOF
131
-
132
- # 删除本地临时文件
133
- rm -f "/tmp/$file"
134
-
135
- sleep ${SYNC_INTERVAL:-7200} # 默认每两小时备份一次
 
136
  done
137
  }
138
 
139
- # 启动周期性备份任务
 
140
  sync_data &
141
-
142
- # 确保后台进程正常退出
143
- wait
 
1
  #!/bin/bash
 
2
 
3
+ # 路径修正
4
+ PYTHON_BIN="python3"
5
+ LOG_PREFIX="[Backup-System]"
6
+
7
+ echo "$LOG_PREFIX 脚本启动 - 正在初始化..."
8
+
9
+ # 1. 检查环境变量
10
  if [ -z "$WEBDAV_URL" ] || [ -z "$WEBDAV_USERNAME" ] || [ -z "$WEBDAV_PASSWORD" ]; then
11
+ echo "$LOG_PREFIX [ERROR] 缺少 WebDAV 配置变量,将直接启动 Koishi"
12
+ yarn start
13
+ exit 0
14
  fi
15
 
16
+ FULL_WEBDAV_URL="${WEBDAV_URL}${WEBDAV_BACKUP_PATH:+/$WEBDAV_BACKUP_PATH}"
17
+ echo "$LOG_PREFIX 目标地址: $FULL_WEBDAV_URL"
 
18
 
19
+ # 2. 恢复备份逻辑
20
+ restore_backup() {
21
+ echo "$LOG_PREFIX [Restore] 正在连接 WebDAV 检索最新备份..."
22
+ $PYTHON_BIN -c "
23
+ import sys, os, tarfile, requests, subprocess
 
 
 
24
  from webdav3.client import Client
25
 
26
  options = {
27
+ 'webdav_hostname': '${FULL_WEBDAV_URL}',
28
+ 'webdav_login': '${WEBDAV_USERNAME}',
29
+ 'webdav_password': '${WEBDAV_PASSWORD}'
30
  }
31
  client = Client(options)
 
32
  try:
33
+ files = client.list()
34
+ backups = [f for f in files if f.endswith('.tar.gz') and f.startswith('komari_backup_')]
35
+ if not backups:
36
+ print('$LOG_PREFIX [Restore] 未发现备份文件,跳过恢复过程。')
37
+ sys.exit(0)
38
+
39
+ latest_backup = sorted(backups)[-1]
40
+ print(f'$LOG_PREFIX [Restore] 发现最新备份: {latest_backup}')
41
+
42
+ local_path = f'/tmp/{latest_backup}'
43
+ print(f'$LOG_PREFIX [Restore] 开始下载到 {local_path}...')
44
+
45
+ r = requests.get(f'${FULL_WEBDAV_URL}/{latest_backup}', auth=('${WEBDAV_USERNAME}', '${WEBDAV_PASSWORD}'), stream=True)
46
+ if r.status_code == 200:
47
+ with open(local_path, 'wb') as f:
48
+ for chunk in r.iter_content(chunk_size=1024*1024): # 1MB chunk
49
+ if chunk: f.write(chunk)
50
+
51
+ print(f'$LOG_PREFIX [Restore] 下载完成。正在解压整个 /app 目录...')
52
+ with tarfile.open(local_path, 'r:gz') as tar:
53
+ tar.extractall('/app')
54
+ print(f'$LOG_PREFIX [Restore] 恢复成功!数据已更新。')
55
+ else:
56
+ print(f'$LOG_PREFIX [Restore] 下载失败,状态码: {r.status_code}')
57
  except Exception as e:
58
+ print(f'$LOG_PREFIX [Restore] 异常发生: {str(e)}')
59
+ "
60
+ }
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
61
 
62
+ # 3. 同步备份逻辑
 
 
63
  sync_data() {
64
  while true; do
65
+ # 初始等待,防止启动瞬间就备份
66
+ SYNC_INTERVAL=${SYNC_INTERVAL:-600}
67
+ echo "$LOG_PREFIX [Sync] 计划在 $SYNC_INTERVAL 秒后执行下一次备份..."
68
+ sleep $SYNC_INTERVAL
69
+
70
+ echo "$LOG_PREFIX [Sync] ========================================"
71
+ echo "$LOG_PREFIX [Sync] 开始执行备份任务: $(date)"
72
+
73
+ timestamp=$(date +%Y%m%d_%H%M%S)
74
+ backup_file="komari_backup_${timestamp}.tar.gz"
75
+ start_time=$(date +%s)
76
+
77
+ # 打包整个 /app 目录(包含 node_modules)
78
+ echo "$LOG_PREFIX [Sync] 正在打包 /app (包含所有依赖)..."
79
+ tar -czf "/tmp/${backup_file}" -C /app .
80
+
81
+ file_size=$(du -h "/tmp/${backup_file}" | cut -f1)
82
+ echo "$LOG_PREFIX [Sync] 打包完成。文件大小: $file_size"
83
+
84
+ # 使用 curl 上传并显示进度 (仅在日志中显示简要)
85
+ echo "$LOG_PREFIX [Sync] 正在上传到 WebDAV..."
86
+ curl -u "$WEBDAV_USERNAME:$WEBDAV_PASSWORD" -T "/tmp/${backup_file}" "$FULL_WEBDAV_URL/${backup_file}" --fail --silent --show-error
87
+
88
+ if [ $? -eq 0 ]; then
89
+ end_time=$(date +%s)
90
+ duration=$((end_time - start_time))
91
+ echo "$LOG_PREFIX [Sync] 上传成功!耗时: ${duration}s"
92
+
93
+ # 清理旧备份逻辑
94
+ echo "$LOG_PREFIX [Clean] 正在清理 WebDAV 上的冗余备份 (保留最近 5 个)..."
95
+ $PYTHON_BIN -c "
96
  from webdav3.client import Client
97
+ options = {'webdav_hostname': '${FULL_WEBDAV_URL}', 'webdav_login': '${WEBDAV_USERNAME}', 'webdav_password': '${WEBDAV_PASSWORD}'}
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
98
  client = Client(options)
99
+ backups = sorted([f for f in client.list() if f.startswith('komari_backup_') and f.endswith('.tar.gz')])
100
+ if len(backups) > 5:
101
+ for f in backups[:-5]:
102
+ client.clean(f)
103
+ print(f'$LOG_PREFIX [Clean] 已删除旧备份: {f}')
104
+ else:
105
+ print(f'$LOG_PREFIX [Clean] 当前备份数量 ({len(backups)}), 无需清理。')
106
+ "
107
+ else
108
+ echo "$LOG_PREFIX [ERROR] 上传失败!请检查网络连接或 WebDAV 空间。"
109
+ fi
110
+
111
+ rm -f "/tmp/${backup_file}"
112
+ echo "$LOG_PREFIX [Sync] ========================================"
113
  done
114
  }
115
 
116
+ # 执行流程
117
+ restore_backup
118
  sync_data &
119
+ echo "$LOG_PREFIX 启动 Koishi 主程序..."
120
+ yarn start