This repository has been archived by the owner on Jan 3, 2022. It is now read-only.
-
Notifications
You must be signed in to change notification settings - Fork 0
/
import.js
135 lines (120 loc) · 5.05 KB
/
import.js
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
/*
Exports all databases and tables. Stores in folders according to to "date" in a similar format to npm logs
Dates are UTC but do not contain the timezone offset.
Uses streams to try and avoid storing massive tables in memory, but the way this is done is a bit "Hacky" so be aware of that.
(I manually write commas and array [] parts)
By default ignores the "test" db.
Dependencies:
* rethinkdbdash
*/
// At a later date I'll make it read these in from passed values
const blacklist = ["rethinkdb"];
const r = require("rethinkdbdash")();
const { join } = require("path");
const { stat, mkdir, createWriteStream, readdir, readFile} = require("fs");
const backupBase = join(__dirname, "backup");
async function findBase () {
const files = await toPromise(readdir, backupBase, {
withFileTypes: true
});
let mostRecent = "";
for (let file of files) {
if (file.isDirectory()) {
// "" doesn't eval to greater than
if (mostRecent < file.name) {
// Update most recent
mostRecent = file.name;
}
}
}
if (mostRecent === "") {
console.error("Failed to find suitable folder for restore - No folders found!");
process.exit(1);
return false;
}
return join(backupBase, mostRecent);
}
async function restore () {
const path = await findBase();
if (!path) return;
const files = await toPromise(readdir, path, {
withFileTypes: true
});
const databases = await r.dbList();
for (let file of files) {
if (file.isDirectory()) {
// Check DB exists
// ATM we **will** create the database but in future this something I would want to make configurable
// Given it's pretty "dangerous"
const dbName = file.name;
if (!databases.includes(dbName)) {
console.log(`No DB exists for ${dbName}, creating one.`);
await r.dbCreate(dbName);
}
// Restore tables
const tableFiles = await toPromise(readdir, join(path, dbName), {
withFileTypes: true
});
const tables = await r.db(dbName).tableList();
for (let tableFile of tableFiles) {
try {
if (tableFile.isFile()) {
const tableName = tableFile.name.split(".")[0];
console.log(`Backing up ${dbName}: ${tableName}`);
if (!tables.includes(tableName)) {
console.log(`No table exists for ${dbName}: ${tableName}, creating one.`);
await r.db(dbName).tableCreate(tableName, {
primaryKey: tableName.toLowerCase() === "users" && dbName.toLowerCase() === "main" ? "discordId" : "id"
});
}
let raw = await toPromise(readFile, join(path, dbName, tableFile.name), {
encoding: "utf8"
});
if (typeof raw !== "string") {
throw new Error("File contents are not a string!");
}
const parsed = JSON.parse(raw);
// Potentially big files, so save memory by removing it
raw = "";
const promises = [];
for (let item of parsed) {
// Actual import logic
const id = item.id ? item.id : item.discordId;
const prom = r.db(dbName).table(tableName).get(id)
.then(function (res){
if (res) {
return r.db(dbName).table(tableName).update(item);
} else {
return r.db(dbName).table(tableName).insert(item);
}
})
.catch(function (e) {
console.error(`${dbName}: ${tableName} Failed to restore row. Error: ${e.message}\n${e.stack}`)
});
promises.push(prom);
}
await Promise.all(promises);
console.log(`Restored table ${tableName}`);
}
} catch (e) {
console.error(`Failed to restore table. Error: ${e.message}\n\n${e.stack}`);
}
}
}
}
}
function toPromise(func, ...args) {
return new Promise(function (resolve, reject) {
func(...args, function (error, ...resp) {
if (error) {
return reject(error);
}
resolve(...resp);
})
});
}
// Main
restore()
.catch(function (e) {
console.log(`Failed to back up and error was not handled.\nError: ${e.message}\n${e.stack}`);
})