@abtnode/core 1.15.17 → 1.16.0-beta-8ee536d7
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/lib/api/node.js +67 -69
- package/lib/api/team.js +386 -55
- package/lib/blocklet/downloader/blocklet-downloader.js +226 -0
- package/lib/blocklet/downloader/bundle-downloader.js +272 -0
- package/lib/blocklet/downloader/constants.js +3 -0
- package/lib/blocklet/downloader/resolve-download.js +199 -0
- package/lib/blocklet/extras.js +83 -26
- package/lib/blocklet/hooks.js +18 -65
- package/lib/blocklet/manager/base.js +10 -16
- package/lib/blocklet/manager/disk.js +1680 -1566
- package/lib/blocklet/manager/helper/install-application-from-backup.js +177 -0
- package/lib/blocklet/manager/helper/install-application-from-dev.js +94 -0
- package/lib/blocklet/manager/helper/install-application-from-general.js +188 -0
- package/lib/blocklet/manager/helper/install-component-from-dev.js +84 -0
- package/lib/blocklet/manager/helper/install-component-from-upload.js +181 -0
- package/lib/blocklet/manager/helper/install-component-from-url.js +173 -0
- package/lib/blocklet/manager/helper/migrate-application-to-struct-v2.js +450 -0
- package/lib/blocklet/manager/helper/rollback-cache.js +41 -0
- package/lib/blocklet/manager/helper/upgrade-components.js +152 -0
- package/lib/blocklet/migration.js +30 -52
- package/lib/blocklet/storage/backup/audit-log.js +27 -0
- package/lib/blocklet/storage/backup/base.js +62 -0
- package/lib/blocklet/storage/backup/blocklet-extras.js +92 -0
- package/lib/blocklet/storage/backup/blocklet.js +70 -0
- package/lib/blocklet/storage/backup/blocklets.js +74 -0
- package/lib/blocklet/storage/backup/data.js +19 -0
- package/lib/blocklet/storage/backup/logs.js +24 -0
- package/lib/blocklet/storage/backup/routing-rule.js +19 -0
- package/lib/blocklet/storage/backup/spaces.js +240 -0
- package/lib/blocklet/storage/restore/base.js +67 -0
- package/lib/blocklet/storage/restore/blocklet-extras.js +86 -0
- package/lib/blocklet/storage/restore/blocklet.js +56 -0
- package/lib/blocklet/storage/restore/blocklets.js +43 -0
- package/lib/blocklet/storage/restore/logs.js +21 -0
- package/lib/blocklet/storage/restore/spaces.js +156 -0
- package/lib/blocklet/storage/utils/hash.js +51 -0
- package/lib/blocklet/storage/utils/zip.js +43 -0
- package/lib/cert.js +206 -0
- package/lib/event.js +237 -64
- package/lib/index.js +191 -83
- package/lib/migrations/1.0.21-update-config.js +1 -1
- package/lib/migrations/1.0.22-max-memory.js +1 -1
- package/lib/migrations/1.0.25.js +1 -1
- package/lib/migrations/1.0.32-update-config.js +1 -1
- package/lib/migrations/1.0.33-blocklets.js +1 -1
- package/lib/migrations/1.5.20-registry.js +15 -0
- package/lib/migrations/1.6.17-blocklet-children.js +48 -0
- package/lib/migrations/1.6.21-rename-ip-echo-domain.js +35 -0
- package/lib/migrations/1.6.4-security.js +59 -0
- package/lib/migrations/1.6.5-security.js +60 -0
- package/lib/migrations/1.6.9-update-node-info-and-certificate.js +38 -0
- package/lib/migrations/1.7.1-blocklet-setup.js +18 -0
- package/lib/migrations/1.7.12-blocklet-meta.js +51 -0
- package/lib/migrations/1.7.15-blocklet-bundle-source.js +42 -0
- package/lib/migrations/1.7.20-blocklet-component.js +41 -0
- package/lib/migrations/1.8.33-blocklet-mem-limit.js +20 -0
- package/lib/migrations/README.md +1 -1
- package/lib/migrations/index.js +6 -2
- package/lib/monitor/blocklet-runtime-monitor.js +200 -0
- package/lib/monitor/get-history-list.js +37 -0
- package/lib/monitor/node-runtime-monitor.js +228 -0
- package/lib/router/helper.js +576 -500
- package/lib/router/index.js +85 -21
- package/lib/router/manager.js +146 -187
- package/lib/states/README.md +36 -1
- package/lib/states/access-key.js +39 -17
- package/lib/states/audit-log.js +462 -0
- package/lib/states/base.js +4 -213
- package/lib/states/blocklet-extras.js +195 -138
- package/lib/states/blocklet.js +371 -110
- package/lib/states/cache.js +8 -6
- package/lib/states/challenge.js +5 -5
- package/lib/states/index.js +19 -36
- package/lib/states/migration.js +4 -4
- package/lib/states/node.js +135 -46
- package/lib/states/notification.js +22 -35
- package/lib/states/session.js +17 -9
- package/lib/states/site.js +50 -25
- package/lib/states/user.js +74 -20
- package/lib/states/webhook.js +10 -6
- package/lib/team/manager.js +124 -7
- package/lib/util/blocklet.js +1223 -246
- package/lib/util/chain.js +1 -1
- package/lib/util/default-node-config.js +5 -23
- package/lib/util/disk-monitor.js +13 -10
- package/lib/util/domain-status.js +84 -15
- package/lib/util/get-accessible-external-node-ip.js +2 -2
- package/lib/util/get-domain-for-blocklet.js +13 -0
- package/lib/util/get-meta-from-url.js +33 -0
- package/lib/util/index.js +207 -272
- package/lib/util/ip.js +6 -0
- package/lib/util/maintain.js +233 -0
- package/lib/util/public-to-store.js +85 -0
- package/lib/util/ready.js +1 -1
- package/lib/util/requirement.js +28 -9
- package/lib/util/reset-node.js +22 -7
- package/lib/util/router.js +13 -0
- package/lib/util/rpc.js +16 -0
- package/lib/util/store.js +179 -0
- package/lib/util/sysinfo.js +44 -0
- package/lib/util/ua.js +54 -0
- package/lib/validators/blocklet-extra.js +24 -0
- package/lib/validators/node.js +25 -12
- package/lib/validators/permission.js +16 -1
- package/lib/validators/role.js +17 -3
- package/lib/validators/router.js +40 -20
- package/lib/validators/trusted-passport.js +1 -0
- package/lib/validators/util.js +22 -5
- package/lib/webhook/index.js +45 -35
- package/lib/webhook/sender/index.js +5 -0
- package/lib/webhook/sender/slack/index.js +1 -1
- package/lib/webhook/sender/wallet/index.js +48 -0
- package/package.json +54 -36
- package/lib/blocklet/registry.js +0 -205
- package/lib/states/https-cert.js +0 -67
- package/lib/util/get-ip-dns-domain-for-blocklet.js +0 -19
- package/lib/util/service.js +0 -66
- package/lib/util/upgrade.js +0 -178
- /package/lib/{queue.js → util/queue.js} +0 -0
|
@@ -1,68 +1,27 @@
|
|
|
1
1
|
/* eslint-disable no-await-in-loop */
|
|
2
|
-
const childProcess = require('child_process');
|
|
3
2
|
const fs = require('fs-extra');
|
|
4
3
|
const path = require('path');
|
|
5
4
|
const semver = require('semver');
|
|
5
|
+
const runScript = require('@abtnode/util/lib/run-script');
|
|
6
6
|
|
|
7
7
|
const { getMigrationScripts: getScripts } = require('../migrations');
|
|
8
8
|
const { getSafeEnv } = require('../util');
|
|
9
9
|
const { name } = require('../../package.json');
|
|
10
10
|
const logger = require('@abtnode/logger')(`${name}:blocklet:migration`); // eslint-disable-line
|
|
11
11
|
|
|
12
|
-
const _runScript = ({ appDir, env, migrationScript, progress = false }) => {
|
|
13
|
-
const safeEnv = getSafeEnv(env);
|
|
14
|
-
|
|
15
|
-
const child = childProcess.exec(`node ${migrationScript}`, {
|
|
16
|
-
cwd: appDir,
|
|
17
|
-
env: safeEnv,
|
|
18
|
-
stdio: 'inherit',
|
|
19
|
-
});
|
|
20
|
-
let hasUnhandledRejection = false;
|
|
21
|
-
|
|
22
|
-
if (progress) {
|
|
23
|
-
child.stdout.pipe(process.stdout);
|
|
24
|
-
child.stderr.pipe(process.stderr);
|
|
25
|
-
}
|
|
26
|
-
|
|
27
|
-
return new Promise((resolve, reject) => {
|
|
28
|
-
const errorMessages = [];
|
|
29
|
-
|
|
30
|
-
child.stderr.on('data', (err) => {
|
|
31
|
-
// Check if has unhandledRejection in childProcess
|
|
32
|
-
// https://stackoverflow.com/questions/32784649/gracefully-handle-errors-in-child-processes-in-nodejs
|
|
33
|
-
if (err.includes('UnhandledPromiseRejectionWarning')) {
|
|
34
|
-
hasUnhandledRejection = true;
|
|
35
|
-
}
|
|
36
|
-
errorMessages.push(err);
|
|
37
|
-
});
|
|
38
|
-
|
|
39
|
-
child.on('exit', (code) => {
|
|
40
|
-
if (errorMessages.length > 0) {
|
|
41
|
-
if (code !== 0 || hasUnhandledRejection) {
|
|
42
|
-
return reject(new Error(errorMessages.join('\r\n')));
|
|
43
|
-
}
|
|
44
|
-
|
|
45
|
-
if (!progress) {
|
|
46
|
-
errorMessages.forEach((message) => process.stderr.write(message));
|
|
47
|
-
}
|
|
48
|
-
}
|
|
49
|
-
|
|
50
|
-
return resolve();
|
|
51
|
-
});
|
|
52
|
-
});
|
|
53
|
-
};
|
|
54
|
-
|
|
55
12
|
async function runScripts({
|
|
13
|
+
blocklet,
|
|
14
|
+
appDir,
|
|
15
|
+
env,
|
|
16
|
+
oldVersion,
|
|
56
17
|
dbDir,
|
|
57
18
|
backupDir,
|
|
58
19
|
scriptsDir,
|
|
59
20
|
printInfo,
|
|
60
21
|
printSuccess,
|
|
61
22
|
printError,
|
|
62
|
-
appDir,
|
|
63
|
-
env,
|
|
64
|
-
oldVersion,
|
|
65
23
|
}) {
|
|
24
|
+
// 获取所有待执行的脚本
|
|
66
25
|
let scripts = [];
|
|
67
26
|
try {
|
|
68
27
|
scripts = await getScripts(scriptsDir);
|
|
@@ -79,25 +38,36 @@ async function runScripts({
|
|
|
79
38
|
}
|
|
80
39
|
|
|
81
40
|
printInfo('pending scripts', pendingScripts);
|
|
41
|
+
// 执行脚本前需要对数据库文件做一次备份
|
|
82
42
|
try {
|
|
83
43
|
await doBackup({ dbDir, backupDir, printInfo, printSuccess, printError });
|
|
84
44
|
} catch (err) {
|
|
85
45
|
printError(`Failed to backup state db due to ${err.message}, abort!`);
|
|
46
|
+
// 备份失败时,需要移除备份目录
|
|
47
|
+
fs.removeSync(backupDir);
|
|
86
48
|
throw err;
|
|
87
49
|
}
|
|
88
50
|
|
|
51
|
+
// 按照顺序依次执行 migration 脚本
|
|
89
52
|
for (let i = 0; i < pendingScripts.length; i++) {
|
|
90
53
|
const { script: scriptPath } = pendingScripts[i];
|
|
91
54
|
try {
|
|
92
55
|
printInfo(`Migration script started: ${scriptPath}`);
|
|
93
|
-
await
|
|
56
|
+
await runScript(`node ${path.join(scriptsDir, scriptPath)}`, [blocklet.env.processId, 'migration'].join(':'), {
|
|
57
|
+
cwd: appDir,
|
|
58
|
+
env: getSafeEnv(env),
|
|
59
|
+
silent: false,
|
|
60
|
+
});
|
|
94
61
|
printInfo(`Migration script executed: ${scriptPath}`);
|
|
95
62
|
} catch (migrationErr) {
|
|
96
63
|
printError(`Failed to execute migration script: ${scriptPath}, error: ${migrationErr.message}`);
|
|
97
64
|
|
|
98
65
|
try {
|
|
99
66
|
await doRestore({ dbDir, backupDir, printInfo, printSuccess, printError });
|
|
67
|
+
// 恢复备份成功时,需要移除备份目录
|
|
68
|
+
fs.removeSync(backupDir);
|
|
100
69
|
} catch (restoreErr) {
|
|
70
|
+
// 如果恢复备份失败,则保留备份目录,恢复数据
|
|
101
71
|
printError(`Failed to restore state db due to: ${restoreErr.message}`);
|
|
102
72
|
}
|
|
103
73
|
|
|
@@ -123,6 +93,7 @@ async function doRestore({ dbDir, backupDir, printInfo, printSuccess }) {
|
|
|
123
93
|
}
|
|
124
94
|
|
|
125
95
|
module.exports = async ({
|
|
96
|
+
blocklet,
|
|
126
97
|
appDir,
|
|
127
98
|
env,
|
|
128
99
|
oldVersion,
|
|
@@ -131,6 +102,10 @@ module.exports = async ({
|
|
|
131
102
|
printSuccess = logger.info,
|
|
132
103
|
printError = logger.error,
|
|
133
104
|
}) => {
|
|
105
|
+
if (!oldVersion) {
|
|
106
|
+
return;
|
|
107
|
+
}
|
|
108
|
+
|
|
134
109
|
const baseDir = env.BLOCKLET_DATA_DIR;
|
|
135
110
|
|
|
136
111
|
const scriptsDir = path.join(appDir, 'migration');
|
|
@@ -142,15 +117,18 @@ module.exports = async ({
|
|
|
142
117
|
fs.ensureDirSync(backupDir);
|
|
143
118
|
|
|
144
119
|
await runScripts({
|
|
120
|
+
blocklet,
|
|
121
|
+
appDir,
|
|
122
|
+
env,
|
|
123
|
+
oldVersion,
|
|
124
|
+
newVersion,
|
|
145
125
|
dbDir,
|
|
146
126
|
backupDir,
|
|
147
127
|
scriptsDir,
|
|
148
128
|
printError,
|
|
149
129
|
printInfo,
|
|
150
130
|
printSuccess,
|
|
151
|
-
appDir,
|
|
152
|
-
env,
|
|
153
|
-
oldVersion,
|
|
154
|
-
newVersion,
|
|
155
131
|
});
|
|
132
|
+
|
|
133
|
+
fs.removeSync(backupDir);
|
|
156
134
|
};
|
|
@@ -0,0 +1,27 @@
|
|
|
1
|
+
const { removeSync, outputJsonSync } = require('fs-extra');
|
|
2
|
+
const { join } = require('path');
|
|
3
|
+
const states = require('../../../states');
|
|
4
|
+
const { BaseBackup } = require('./base');
|
|
5
|
+
|
|
6
|
+
/**
|
|
7
|
+
*
|
|
8
|
+
*
|
|
9
|
+
* @class AuditLogBackup
|
|
10
|
+
*/
|
|
11
|
+
class AuditLogBackup extends BaseBackup {
|
|
12
|
+
filename = 'audit-log.json';
|
|
13
|
+
|
|
14
|
+
async export() {
|
|
15
|
+
/**
|
|
16
|
+
* @type {import('@abtnode/client').AuditLog}
|
|
17
|
+
*/
|
|
18
|
+
const auditLogs = await states.auditLog.find({
|
|
19
|
+
scope: this.blocklet.meta.did,
|
|
20
|
+
});
|
|
21
|
+
|
|
22
|
+
removeSync(join(this.backupDir, this.filename));
|
|
23
|
+
outputJsonSync(join(this.backupDir, this.filename), auditLogs);
|
|
24
|
+
}
|
|
25
|
+
}
|
|
26
|
+
|
|
27
|
+
module.exports = { AuditLogBackup };
|
|
@@ -0,0 +1,62 @@
|
|
|
1
|
+
class BaseBackup {
|
|
2
|
+
/**
|
|
3
|
+
* @type {import('./spaces').SpaceBackupInput}
|
|
4
|
+
* @memberof BaseBackup
|
|
5
|
+
*/
|
|
6
|
+
input;
|
|
7
|
+
|
|
8
|
+
/**
|
|
9
|
+
* @description blocklet state 对象
|
|
10
|
+
* @type {import('@abtnode/client').BlockletState}
|
|
11
|
+
* @memberof BaseBackup
|
|
12
|
+
*/
|
|
13
|
+
blocklet;
|
|
14
|
+
|
|
15
|
+
/**
|
|
16
|
+
* @description 当前 blocklet 的数据目录
|
|
17
|
+
* @type {string}
|
|
18
|
+
* @memberof BaseBackup
|
|
19
|
+
*/
|
|
20
|
+
backupDir;
|
|
21
|
+
|
|
22
|
+
/**
|
|
23
|
+
*
|
|
24
|
+
* @description spaces 的 endpoint
|
|
25
|
+
* @type {import('./spaces').SecurityContext}
|
|
26
|
+
* @memberof BaseBackup
|
|
27
|
+
*/
|
|
28
|
+
securityContext;
|
|
29
|
+
|
|
30
|
+
/**
|
|
31
|
+
*
|
|
32
|
+
* @description server 的数据目录
|
|
33
|
+
* @type {string}
|
|
34
|
+
* @memberof BaseBackup
|
|
35
|
+
*/
|
|
36
|
+
serverDir;
|
|
37
|
+
|
|
38
|
+
constructor(input) {
|
|
39
|
+
this.input = input;
|
|
40
|
+
}
|
|
41
|
+
|
|
42
|
+
/**
|
|
43
|
+
*
|
|
44
|
+
*
|
|
45
|
+
* @param {import('./spaces').SpacesBackup} spacesBackup
|
|
46
|
+
* @memberof BaseBackup
|
|
47
|
+
*/
|
|
48
|
+
ensureParams(spacesBackup) {
|
|
49
|
+
this.blocklet = spacesBackup.blocklet;
|
|
50
|
+
this.serverDir = spacesBackup.serverDir;
|
|
51
|
+
this.backupDir = spacesBackup.backupDir;
|
|
52
|
+
this.securityContext = spacesBackup.securityContext;
|
|
53
|
+
}
|
|
54
|
+
|
|
55
|
+
async export() {
|
|
56
|
+
throw new Error('not implemented');
|
|
57
|
+
}
|
|
58
|
+
}
|
|
59
|
+
|
|
60
|
+
module.exports = {
|
|
61
|
+
BaseBackup,
|
|
62
|
+
};
|
|
@@ -0,0 +1,92 @@
|
|
|
1
|
+
const { removeSync, readFileSync, outputJsonSync } = require('fs-extra');
|
|
2
|
+
const { isEmpty, cloneDeep } = require('lodash');
|
|
3
|
+
const { join } = require('path');
|
|
4
|
+
const security = require('@abtnode/util/lib/security');
|
|
5
|
+
|
|
6
|
+
const states = require('../../../states');
|
|
7
|
+
const { BaseBackup } = require('./base');
|
|
8
|
+
|
|
9
|
+
class BlockletExtrasBackup extends BaseBackup {
|
|
10
|
+
filename = 'blocklet-extras.json';
|
|
11
|
+
|
|
12
|
+
async export() {
|
|
13
|
+
const blockletExtra = await this.getBlockletExtra();
|
|
14
|
+
removeSync(join(this.backupDir, this.filename));
|
|
15
|
+
outputJsonSync(join(this.backupDir, this.filename), blockletExtra);
|
|
16
|
+
}
|
|
17
|
+
|
|
18
|
+
/**
|
|
19
|
+
*
|
|
20
|
+
* @description
|
|
21
|
+
* @return {Promise<import('@abtnode/client').BlockletState>}
|
|
22
|
+
* @memberof BlockletExtrasBackup
|
|
23
|
+
*/
|
|
24
|
+
async getBlockletExtra() {
|
|
25
|
+
/**
|
|
26
|
+
* @type {import('@abtnode/client').BlockletState}
|
|
27
|
+
*/
|
|
28
|
+
const blockletExtra = await states.blockletExtras.findOne({
|
|
29
|
+
did: this.blocklet.meta.did,
|
|
30
|
+
});
|
|
31
|
+
if (isEmpty(blockletExtra)) {
|
|
32
|
+
throw new Error('blockletExtra cannot be empty');
|
|
33
|
+
}
|
|
34
|
+
|
|
35
|
+
return this.cleanData(blockletExtra);
|
|
36
|
+
}
|
|
37
|
+
|
|
38
|
+
/**
|
|
39
|
+
*
|
|
40
|
+
* @description 清理数据并加密
|
|
41
|
+
* @param {import('@abtnode/client').BlockletState} raw
|
|
42
|
+
* @return {Promise<any>}
|
|
43
|
+
* @memberof BlockletExtrasBackup
|
|
44
|
+
*/
|
|
45
|
+
async cleanData(raw) {
|
|
46
|
+
const blockletExtra = cloneDeep(raw);
|
|
47
|
+
|
|
48
|
+
const queue = [blockletExtra];
|
|
49
|
+
while (queue.length) {
|
|
50
|
+
const current = queue.pop();
|
|
51
|
+
|
|
52
|
+
// 删除父 blocklet 的某些数据
|
|
53
|
+
if (current._id) {
|
|
54
|
+
delete current._id;
|
|
55
|
+
delete current.createdAt;
|
|
56
|
+
delete current.updatedAt;
|
|
57
|
+
}
|
|
58
|
+
|
|
59
|
+
// 加解密
|
|
60
|
+
this.encrypt(current.configs);
|
|
61
|
+
|
|
62
|
+
if (current?.children) {
|
|
63
|
+
queue.push(...current.children);
|
|
64
|
+
}
|
|
65
|
+
}
|
|
66
|
+
|
|
67
|
+
return blockletExtra;
|
|
68
|
+
}
|
|
69
|
+
|
|
70
|
+
/**
|
|
71
|
+
*
|
|
72
|
+
* @description 清理数据并加密
|
|
73
|
+
* @param {import('@abtnode/client').ConfigEntry[]} configs
|
|
74
|
+
* @return {void}
|
|
75
|
+
* @memberof BlockletExtrasBackup
|
|
76
|
+
*/
|
|
77
|
+
encrypt(configs) {
|
|
78
|
+
if (isEmpty(configs)) {
|
|
79
|
+
return;
|
|
80
|
+
}
|
|
81
|
+
|
|
82
|
+
const dk = readFileSync(join(this.serverDir, '.sock'));
|
|
83
|
+
for (const config of configs) {
|
|
84
|
+
if (config.secure) {
|
|
85
|
+
const decrypted = security.decrypt(config.value, this.blocklet.meta.did, dk);
|
|
86
|
+
config.value = this.securityContext.encrypt(decrypted);
|
|
87
|
+
}
|
|
88
|
+
}
|
|
89
|
+
}
|
|
90
|
+
}
|
|
91
|
+
|
|
92
|
+
module.exports = { BlockletExtrasBackup };
|
|
@@ -0,0 +1,70 @@
|
|
|
1
|
+
const { removeSync, outputJsonSync } = require('fs-extra');
|
|
2
|
+
const { cloneDeep } = require('lodash');
|
|
3
|
+
const { join } = require('path');
|
|
4
|
+
const { BaseBackup } = require('./base');
|
|
5
|
+
|
|
6
|
+
class BlockletBackup extends BaseBackup {
|
|
7
|
+
filename = 'blocklet.json';
|
|
8
|
+
|
|
9
|
+
async export() {
|
|
10
|
+
const blocklet = await this.cleanData();
|
|
11
|
+
removeSync(join(this.backupDir, this.filename));
|
|
12
|
+
outputJsonSync(join(this.backupDir, this.filename), blocklet);
|
|
13
|
+
}
|
|
14
|
+
|
|
15
|
+
/**
|
|
16
|
+
* @description 清理数据
|
|
17
|
+
* @see blocklet.db 中需要删除哪些字段呢? https://github.com/ArcBlock/blocklet-server/issues/6120#issuecomment-1383798348
|
|
18
|
+
* @return {Promise<import('@abtnode/client').BlockletState>}
|
|
19
|
+
* @memberof BlockletBackup
|
|
20
|
+
*/
|
|
21
|
+
async cleanData() {
|
|
22
|
+
const clone = cloneDeep(this.blocklet);
|
|
23
|
+
|
|
24
|
+
/** @type {import('@abtnode/client').ComponentState[]} */
|
|
25
|
+
const queue = [clone];
|
|
26
|
+
|
|
27
|
+
// 广度优先遍历
|
|
28
|
+
while (queue.length) {
|
|
29
|
+
const current = queue.pop();
|
|
30
|
+
|
|
31
|
+
// 父组件才需要删除的属性
|
|
32
|
+
if (current._id) {
|
|
33
|
+
delete current._id;
|
|
34
|
+
delete current.createdAt;
|
|
35
|
+
delete current.startedAt;
|
|
36
|
+
delete current.installedAt;
|
|
37
|
+
}
|
|
38
|
+
|
|
39
|
+
// 子组件和父组件都需要删除的属性
|
|
40
|
+
delete current.status;
|
|
41
|
+
delete current.ports;
|
|
42
|
+
delete current.environments;
|
|
43
|
+
|
|
44
|
+
if (current.children) {
|
|
45
|
+
queue.push(...current.children);
|
|
46
|
+
}
|
|
47
|
+
}
|
|
48
|
+
|
|
49
|
+
return this.encrypt(clone);
|
|
50
|
+
}
|
|
51
|
+
|
|
52
|
+
/**
|
|
53
|
+
*
|
|
54
|
+
* @description 清理数据并加密
|
|
55
|
+
* @param {import('@abtnode/client').BlockletState} info
|
|
56
|
+
* @memberof BlockletExtrasBackup
|
|
57
|
+
*/
|
|
58
|
+
encrypt(info) {
|
|
59
|
+
if (Array.isArray(info.migratedFrom)) {
|
|
60
|
+
info.migratedFrom = info.migratedFrom.map((x) => {
|
|
61
|
+
x.appSk = this.securityContext.encrypt(x.appSk);
|
|
62
|
+
return x;
|
|
63
|
+
});
|
|
64
|
+
}
|
|
65
|
+
|
|
66
|
+
return info;
|
|
67
|
+
}
|
|
68
|
+
}
|
|
69
|
+
|
|
70
|
+
module.exports = { BlockletBackup };
|
|
@@ -0,0 +1,74 @@
|
|
|
1
|
+
const { join } = require('path');
|
|
2
|
+
const validUrl = require('valid-url');
|
|
3
|
+
const { BaseBackup } = require('./base');
|
|
4
|
+
const { dirToZip } = require('../utils/zip');
|
|
5
|
+
const { compareAndMove } = require('../utils/hash');
|
|
6
|
+
|
|
7
|
+
class BlockletsBackup extends BaseBackup {
|
|
8
|
+
/**
|
|
9
|
+
*
|
|
10
|
+
* @returns {Promise<void>}
|
|
11
|
+
* @memberof BlockletsBackup
|
|
12
|
+
*/
|
|
13
|
+
async export() {
|
|
14
|
+
const blockletMetas = this.getBlockletMetas(this.blocklet);
|
|
15
|
+
const serverBlockletsDir = join(this.serverDir, 'blocklets');
|
|
16
|
+
|
|
17
|
+
const blockletMetasFromLocal = blockletMetas.filter(
|
|
18
|
+
(b) => !validUrl.isHttpUri(b.tarball) && !validUrl.isHttpsUri(b.tarball)
|
|
19
|
+
);
|
|
20
|
+
|
|
21
|
+
const dirs = [];
|
|
22
|
+
for (const blockletMeta of blockletMetasFromLocal) {
|
|
23
|
+
const sourceDir = join(serverBlockletsDir, blockletMeta.name, blockletMeta.version);
|
|
24
|
+
const zipPath = join(this.backupDir, 'blocklets', blockletMeta.name, `${blockletMeta.version}.zip`);
|
|
25
|
+
dirs.push({ sourceDir, zipPath });
|
|
26
|
+
}
|
|
27
|
+
|
|
28
|
+
await this.dirsToZip(dirs);
|
|
29
|
+
}
|
|
30
|
+
|
|
31
|
+
/**
|
|
32
|
+
*
|
|
33
|
+
*
|
|
34
|
+
* @param {import('@abtnode/client').BlockletState} blocklet
|
|
35
|
+
* @returns {Array<{name: string, version: string, tarball: string}>}
|
|
36
|
+
* @memberof BlockletsBackup
|
|
37
|
+
*/
|
|
38
|
+
getBlockletMetas(blocklet) {
|
|
39
|
+
if (!blocklet?.meta?.bundleName || !blocklet?.meta?.version) {
|
|
40
|
+
return [];
|
|
41
|
+
}
|
|
42
|
+
|
|
43
|
+
const metas = [];
|
|
44
|
+
metas.push({
|
|
45
|
+
name: blocklet.meta.bundleName,
|
|
46
|
+
version: blocklet.meta.version,
|
|
47
|
+
tarball: blocklet?.meta?.dist?.tarball,
|
|
48
|
+
});
|
|
49
|
+
|
|
50
|
+
for (const child of blocklet.children) {
|
|
51
|
+
metas.push(...this.getBlockletMetas(child));
|
|
52
|
+
}
|
|
53
|
+
|
|
54
|
+
return metas;
|
|
55
|
+
}
|
|
56
|
+
|
|
57
|
+
/**
|
|
58
|
+
* @param {Array<{sourceDir: string, zipPath: string}>} dirs: /some/folder/to/compress
|
|
59
|
+
* @param {String} zipPath: /path/to/created.zip
|
|
60
|
+
* @returns {Promise}
|
|
61
|
+
* @memberof BlockletsBackup
|
|
62
|
+
*/
|
|
63
|
+
async dirsToZip(dirs) {
|
|
64
|
+
await Promise.all(
|
|
65
|
+
dirs.map(async (dir) => {
|
|
66
|
+
const tempZipPath = `${dir.zipPath}.bak`;
|
|
67
|
+
await dirToZip(dir.sourceDir, tempZipPath);
|
|
68
|
+
await compareAndMove(dir.zipPath, tempZipPath);
|
|
69
|
+
})
|
|
70
|
+
);
|
|
71
|
+
}
|
|
72
|
+
}
|
|
73
|
+
|
|
74
|
+
module.exports = { BlockletsBackup };
|
|
@@ -0,0 +1,19 @@
|
|
|
1
|
+
const { copy } = require('fs-extra');
|
|
2
|
+
const { join } = require('path');
|
|
3
|
+
const { BaseBackup } = require('./base');
|
|
4
|
+
|
|
5
|
+
class DataBackup extends BaseBackup {
|
|
6
|
+
/**
|
|
7
|
+
*
|
|
8
|
+
* @returns {Promise<void>}
|
|
9
|
+
* @memberof BlockletsBackup
|
|
10
|
+
*/
|
|
11
|
+
async export() {
|
|
12
|
+
const blockletDataDir = join(this.serverDir, 'data', this.blocklet.meta.name);
|
|
13
|
+
const blockletBackupDataDir = join(this.backupDir, 'data');
|
|
14
|
+
|
|
15
|
+
await copy(blockletDataDir, blockletBackupDataDir, { overwrite: true });
|
|
16
|
+
}
|
|
17
|
+
}
|
|
18
|
+
|
|
19
|
+
module.exports = { DataBackup };
|
|
@@ -0,0 +1,24 @@
|
|
|
1
|
+
const { ensureDirSync, copy, statSync } = require('fs-extra');
|
|
2
|
+
const { join } = require('path');
|
|
3
|
+
const { BaseBackup } = require('./base');
|
|
4
|
+
|
|
5
|
+
// note: 可以不需要备份
|
|
6
|
+
class LogsBackup extends BaseBackup {
|
|
7
|
+
async export() {
|
|
8
|
+
const sourceLogsDir = join(this.serverDir, 'logs', this.blocklet.meta.name);
|
|
9
|
+
ensureDirSync(sourceLogsDir);
|
|
10
|
+
|
|
11
|
+
const targetLogsDir = join(this.backupDir, 'logs');
|
|
12
|
+
|
|
13
|
+
await copy(sourceLogsDir, targetLogsDir, {
|
|
14
|
+
overwrite: true,
|
|
15
|
+
filter: (src) => {
|
|
16
|
+
return !statSync(src).isSymbolicLink();
|
|
17
|
+
},
|
|
18
|
+
});
|
|
19
|
+
}
|
|
20
|
+
}
|
|
21
|
+
|
|
22
|
+
module.exports = {
|
|
23
|
+
LogsBackup,
|
|
24
|
+
};
|
|
@@ -0,0 +1,19 @@
|
|
|
1
|
+
const { removeSync, outputJsonSync } = require('fs-extra');
|
|
2
|
+
const { join } = require('path');
|
|
3
|
+
const states = require('../../../states');
|
|
4
|
+
const { BaseBackup } = require('./base');
|
|
5
|
+
|
|
6
|
+
class RoutingRuleBackup extends BaseBackup {
|
|
7
|
+
filename = 'routing_rule.json';
|
|
8
|
+
|
|
9
|
+
async export() {
|
|
10
|
+
const routingRule = await states.site.findOne({
|
|
11
|
+
domain: `${this.blocklet.meta.did}.blocklet-domain-group`,
|
|
12
|
+
});
|
|
13
|
+
|
|
14
|
+
removeSync(join(this.backupDir, this.filename));
|
|
15
|
+
outputJsonSync(join(this.backupDir, this.filename), routingRule);
|
|
16
|
+
}
|
|
17
|
+
}
|
|
18
|
+
|
|
19
|
+
module.exports = { RoutingRuleBackup };
|