-
Notifications
You must be signed in to change notification settings - Fork 125
/
Copy pathbackup.ts
94 lines (76 loc) · 2.69 KB
/
backup.ts
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
"use strict";
import dateUtils from "./date_utils.js";
import optionService from "./options.js";
import fs from "fs-extra";
import dataDir from "./data_dir.js";
import log from "./log.js";
import syncMutexService from "./sync_mutex.js";
import cls from "./cls.js";
import sql from "./sql.js";
import path from "path";
import type { OptionNames } from "./options_interface.js";
type BackupType = "daily" | "weekly" | "monthly";
function getExistingBackups() {
if (!fs.existsSync(dataDir.BACKUP_DIR)) {
return [];
}
return fs
.readdirSync(dataDir.BACKUP_DIR)
.filter((fileName) => fileName.includes("backup"))
.map((fileName) => {
const filePath = path.resolve(dataDir.BACKUP_DIR, fileName);
const stat = fs.statSync(filePath);
return { fileName, filePath, mtime: stat.mtime };
});
}
function regularBackup() {
cls.init(() => {
periodBackup("lastDailyBackupDate", "daily", 24 * 3600);
periodBackup("lastWeeklyBackupDate", "weekly", 7 * 24 * 3600);
periodBackup("lastMonthlyBackupDate", "monthly", 30 * 24 * 3600);
});
}
function isBackupEnabled(backupType: BackupType) {
let optionName: OptionNames;
switch (backupType) {
case "daily":
optionName = "dailyBackupEnabled";
break;
case "weekly":
optionName = "weeklyBackupEnabled";
break;
case "monthly":
optionName = "monthlyBackupEnabled";
break;
}
return optionService.getOptionBool(optionName);
}
function periodBackup(optionName: "lastDailyBackupDate" | "lastWeeklyBackupDate" | "lastMonthlyBackupDate", backupType: BackupType, periodInSeconds: number) {
if (!isBackupEnabled(backupType)) {
return;
}
const now = new Date();
const lastBackupDate = dateUtils.parseDateTime(optionService.getOption(optionName));
if (now.getTime() - lastBackupDate.getTime() > periodInSeconds * 1000) {
backupNow(backupType);
optionService.setOption(optionName, dateUtils.utcNowDateTime());
}
}
async function backupNow(name: string) {
// we don't want to back up DB in the middle of sync with potentially inconsistent DB state
return await syncMutexService.doExclusively(async () => {
const backupFile = `${dataDir.BACKUP_DIR}/backup-${name}.db`;
if (!fs.existsSync(dataDir.BACKUP_DIR)) {
fs.mkdirSync(dataDir.BACKUP_DIR, 0o700);
}
log.info("Creating backup...");
await sql.copyDatabase(backupFile);
log.info(`Created backup at ${backupFile}`);
return backupFile;
});
}
export default {
getExistingBackups,
backupNow,
regularBackup
};