@abtnode/core 1.16.15-beta-78ad21d3 → 1.16.15-beta-d464647a
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/blocklet/manager/config-synchronizer.js +108 -0
- package/lib/blocklet/manager/disk.js +44 -13
- package/lib/blocklet/manager/helper/install-application-from-dev.js +2 -0
- package/lib/blocklet/manager/helper/install-component-from-url.js +5 -1
- package/lib/blocklet/storage/backup/spaces.js +34 -1
- package/lib/blocklet/storage/utils/disk.js +39 -0
- package/lib/index.js +1 -0
- package/lib/locales/en.js +3 -0
- package/lib/locales/zh.js +2 -0
- package/lib/util/blocklet.js +7 -1
- package/package.json +23 -21
|
@@ -0,0 +1,108 @@
|
|
|
1
|
+
const path = require('path');
|
|
2
|
+
const throttle = require('lodash/throttle');
|
|
3
|
+
const fs = require('fs-extra');
|
|
4
|
+
const logger = require('@abtnode/logger')('@abtnode/core:config-synchronizer');
|
|
5
|
+
const { encrypt } = require('@blocklet/sdk/lib/security');
|
|
6
|
+
const { APP_CONFIG_FILE_PATH, APP_CONFIG_DIR, COMPONENT_ENV_FILE_NAME } = require('@blocklet/constant');
|
|
7
|
+
|
|
8
|
+
const { findComponentByIdV2, getSharedConfigObj, getBlockletAppIdList } = require('@blocklet/meta/lib/util');
|
|
9
|
+
const { getBlockletLanguages, getBlockletPreferences } = require('@blocklet/env/lib/util');
|
|
10
|
+
const { getComponentsInternalInfo } = require('@blocklet/meta/lib/blocklet');
|
|
11
|
+
const { getComponentApiKey } = require('@abtnode/util/lib/blocklet');
|
|
12
|
+
|
|
13
|
+
const getValueFromEnvironments = (environments, key) => {
|
|
14
|
+
const env = (environments || []).find((x) => x.key === key);
|
|
15
|
+
return env ? env.value : undefined;
|
|
16
|
+
};
|
|
17
|
+
|
|
18
|
+
const isAppObj = (x) => typeof x === 'object' && x !== null && !!x.meta;
|
|
19
|
+
|
|
20
|
+
class ConfigSynchronizer {
|
|
21
|
+
constructor({ manager, states, wait = 5000 }) {
|
|
22
|
+
this.manager = manager;
|
|
23
|
+
this.wait = wait;
|
|
24
|
+
this.throttles = new Map();
|
|
25
|
+
this.states = states;
|
|
26
|
+
}
|
|
27
|
+
|
|
28
|
+
async syncAppConfig(did, { serverVersion: inputServerVersion } = {}) {
|
|
29
|
+
try {
|
|
30
|
+
const app = isAppObj(did) ? did : await this.manager.getBlocklet(did);
|
|
31
|
+
const serverVersion = inputServerVersion || (await this.states.node.read()).version;
|
|
32
|
+
const env = {
|
|
33
|
+
appId: app.appDid,
|
|
34
|
+
appPid: app.appPid,
|
|
35
|
+
appIds: getBlockletAppIdList(app),
|
|
36
|
+
appName: app.meta.title,
|
|
37
|
+
appDescription: app.meta.description,
|
|
38
|
+
appUrl: getValueFromEnvironments(app.environments, 'BLOCKLET_APP_URL'),
|
|
39
|
+
appStorageEndpoint: getValueFromEnvironments(app.environments, 'BLOCKLET_APP_SPACE_ENDPOINT'),
|
|
40
|
+
languages: getBlockletLanguages(getValueFromEnvironments(app.environments, 'BLOCKLET_APP_LANGUAGES')),
|
|
41
|
+
preferences: getBlockletPreferences(
|
|
42
|
+
(app.configs || []).reduce((acc, x) => {
|
|
43
|
+
acc[x.key] = x.value;
|
|
44
|
+
return acc;
|
|
45
|
+
}, {})
|
|
46
|
+
),
|
|
47
|
+
serverVersion,
|
|
48
|
+
};
|
|
49
|
+
const components = getComponentsInternalInfo(app);
|
|
50
|
+
|
|
51
|
+
const config = { env, components };
|
|
52
|
+
|
|
53
|
+
const dataDir = getValueFromEnvironments(app.environments, 'BLOCKLET_DATA_DIR');
|
|
54
|
+
|
|
55
|
+
await fs.outputFile(path.join(dataDir, APP_CONFIG_FILE_PATH), JSON.stringify(config));
|
|
56
|
+
} catch (error) {
|
|
57
|
+
logger.error('sync app config failed', { error });
|
|
58
|
+
}
|
|
59
|
+
}
|
|
60
|
+
|
|
61
|
+
async syncComponentConfig(did, rootDid, { serverSk }) {
|
|
62
|
+
try {
|
|
63
|
+
const app = await this.manager.getBlocklet(rootDid);
|
|
64
|
+
const component = findComponentByIdV2(app, did);
|
|
65
|
+
const env = {
|
|
66
|
+
...component.configObj,
|
|
67
|
+
...getSharedConfigObj(component, [app]),
|
|
68
|
+
};
|
|
69
|
+
|
|
70
|
+
const componentApiKey = getComponentApiKey({
|
|
71
|
+
serverSk,
|
|
72
|
+
app,
|
|
73
|
+
component,
|
|
74
|
+
});
|
|
75
|
+
|
|
76
|
+
const dataDir = getValueFromEnvironments(app.environments, 'BLOCKLET_DATA_DIR');
|
|
77
|
+
|
|
78
|
+
const envString = JSON.stringify(env);
|
|
79
|
+
|
|
80
|
+
await fs.outputFile(
|
|
81
|
+
path.join(dataDir, APP_CONFIG_DIR, component.meta.did, COMPONENT_ENV_FILE_NAME),
|
|
82
|
+
encrypt(envString, componentApiKey, component.meta.did)
|
|
83
|
+
);
|
|
84
|
+
} catch (error) {
|
|
85
|
+
logger.error('sync component config failed', { error });
|
|
86
|
+
}
|
|
87
|
+
}
|
|
88
|
+
|
|
89
|
+
async throttledSyncAppConfig(did) {
|
|
90
|
+
if (!this.throttles.has(did)) {
|
|
91
|
+
this.throttles.set(
|
|
92
|
+
did,
|
|
93
|
+
throttle(
|
|
94
|
+
async () => {
|
|
95
|
+
await this.syncAppConfig(did);
|
|
96
|
+
this.throttles.get(did).cancel();
|
|
97
|
+
this.throttles.delete(did);
|
|
98
|
+
},
|
|
99
|
+
this.wait,
|
|
100
|
+
{ leading: false }
|
|
101
|
+
)
|
|
102
|
+
);
|
|
103
|
+
}
|
|
104
|
+
await this.throttles.get(did)();
|
|
105
|
+
}
|
|
106
|
+
}
|
|
107
|
+
|
|
108
|
+
module.exports = ConfigSynchronizer;
|
|
@@ -51,7 +51,9 @@ const { getComponentsInternalInfo } = require('@blocklet/meta/lib/blocklet');
|
|
|
51
51
|
const { update: updateMetaFile } = require('@blocklet/meta/lib/file');
|
|
52
52
|
const { titleSchema, updateMountPointSchema, environmentNameSchema } = require('@blocklet/meta/lib/schema');
|
|
53
53
|
const { emailConfigSchema } = require('@blocklet/sdk/lib/validators/email');
|
|
54
|
+
const { encrypt } = require('@blocklet/sdk/lib/security');
|
|
54
55
|
const Lock = require('@abtnode/util/lib/lock');
|
|
56
|
+
const { getComponentApiKey } = require('@abtnode/util/lib/blocklet');
|
|
55
57
|
const defaults = require('lodash/defaults');
|
|
56
58
|
|
|
57
59
|
const {
|
|
@@ -77,6 +79,8 @@ const {
|
|
|
77
79
|
CHAIN_PROP_MAP_REVERSE,
|
|
78
80
|
BLOCKLET_CONTROLLER_STATUS,
|
|
79
81
|
SUSPENDED_REASON,
|
|
82
|
+
APP_CONFIG_DIR,
|
|
83
|
+
COMPONENT_ENV_FILE_NAME,
|
|
80
84
|
} = require('@blocklet/constant');
|
|
81
85
|
const isUndefined = require('lodash/isUndefined');
|
|
82
86
|
const { WELLKNOWN_SERVICE_PATH_PREFIX, WELLKNOWN_BLOCKLET_ADMIN_PATH } = require('@abtnode/constant');
|
|
@@ -159,6 +163,7 @@ const { validateAddSpaceGateway, validateUpdateSpaceGateway } = require('../../v
|
|
|
159
163
|
const { sessionConfigSchema } = require('../../validators/util');
|
|
160
164
|
|
|
161
165
|
const request = require('../../util/request');
|
|
166
|
+
const ConfigSynchronizer = require('./config-synchronizer');
|
|
162
167
|
|
|
163
168
|
const { formatEnvironments, getBlockletMeta, validateOwner, isCLI } = util;
|
|
164
169
|
|
|
@@ -210,6 +215,8 @@ class DiskBlockletManager extends BaseBlockletManager {
|
|
|
210
215
|
|
|
211
216
|
this._rollbackCache = new RollbackCache({ dir: this.dataDirs.tmp });
|
|
212
217
|
|
|
218
|
+
this.configSynchronizer = new ConfigSynchronizer({ manager: this, states });
|
|
219
|
+
|
|
213
220
|
if (daemon) {
|
|
214
221
|
blockletPm2Events.on('online', (data) => this._syncPm2Status('online', data.blockletDid, data.componentDid));
|
|
215
222
|
blockletPm2Events.on('stop', (data) => this._syncPm2Status('stop', data.blockletDid, data.componentDid));
|
|
@@ -501,6 +508,8 @@ class DiskBlockletManager extends BaseBlockletManager {
|
|
|
501
508
|
// start process
|
|
502
509
|
const nodeEnvironments = await states.node.getEnvironments();
|
|
503
510
|
|
|
511
|
+
await this.configSynchronizer.syncAppConfig(blocklet);
|
|
512
|
+
|
|
504
513
|
await startBlockletProcess(blocklet, {
|
|
505
514
|
...context,
|
|
506
515
|
preStart: getHookFn('preStart'),
|
|
@@ -509,6 +518,7 @@ class DiskBlockletManager extends BaseBlockletManager {
|
|
|
509
518
|
nodeInfo: await states.node.read(),
|
|
510
519
|
e2eMode,
|
|
511
520
|
componentDids,
|
|
521
|
+
configSynchronizer: this.configSynchronizer,
|
|
512
522
|
});
|
|
513
523
|
|
|
514
524
|
// check blocklet healthy
|
|
@@ -626,6 +636,7 @@ class DiskBlockletManager extends BaseBlockletManager {
|
|
|
626
636
|
appDid: blocklet.appDid,
|
|
627
637
|
components: getComponentsInternalInfo(res),
|
|
628
638
|
});
|
|
639
|
+
this.configSynchronizer.throttledSyncAppConfig(blocklet.meta.did);
|
|
629
640
|
|
|
630
641
|
this._createNotification(did, {
|
|
631
642
|
title: '',
|
|
@@ -876,9 +887,9 @@ class DiskBlockletManager extends BaseBlockletManager {
|
|
|
876
887
|
async deleteComponent({ did, rootDid, keepData, keepState }, context) {
|
|
877
888
|
logger.info('delete blocklet component', { did, rootDid, keepData });
|
|
878
889
|
|
|
879
|
-
const
|
|
890
|
+
const app = await this.getBlocklet(rootDid);
|
|
880
891
|
|
|
881
|
-
const child =
|
|
892
|
+
const child = app.children.find((x) => x.meta.did === did);
|
|
882
893
|
if (!child) {
|
|
883
894
|
throw new Error('Component does not exist');
|
|
884
895
|
}
|
|
@@ -902,25 +913,25 @@ class DiskBlockletManager extends BaseBlockletManager {
|
|
|
902
913
|
// delete process
|
|
903
914
|
try {
|
|
904
915
|
const skippedProcessIds = [];
|
|
905
|
-
forEachBlockletSync(
|
|
916
|
+
forEachBlockletSync(app, (b) => {
|
|
906
917
|
if (!b.env.id.startsWith(child.env.id)) {
|
|
907
918
|
skippedProcessIds.push(b.env.processId);
|
|
908
919
|
}
|
|
909
920
|
});
|
|
910
|
-
await deleteBlockletProcess(
|
|
921
|
+
await deleteBlockletProcess(app, { skippedProcessIds });
|
|
911
922
|
logger.info('delete blocklet process for deleting component', { did, rootDid });
|
|
912
923
|
} catch (err) {
|
|
913
924
|
logger.error('delete blocklet process for deleting component', { did, rootDid, error: err });
|
|
914
925
|
}
|
|
915
926
|
|
|
916
927
|
// delete storage
|
|
917
|
-
const
|
|
918
|
-
const { cacheDir, logsDir, dataDir } = childBlocklet.env;
|
|
928
|
+
const { cacheDir, logsDir, dataDir } = child.env;
|
|
919
929
|
fs.removeSync(cacheDir);
|
|
920
930
|
fs.removeSync(logsDir);
|
|
931
|
+
fs.removeSync(path.join(app.env.dataDir, APP_CONFIG_DIR, child.meta.did, COMPONENT_ENV_FILE_NAME));
|
|
921
932
|
if (keepData === false) {
|
|
922
933
|
fs.removeSync(dataDir);
|
|
923
|
-
await states.blockletExtras.delConfigs([
|
|
934
|
+
await states.blockletExtras.delConfigs([app.meta.did, child.meta.did]);
|
|
924
935
|
}
|
|
925
936
|
|
|
926
937
|
const newBlocklet = await this.getBlocklet(rootDid);
|
|
@@ -944,19 +955,20 @@ class DiskBlockletManager extends BaseBlockletManager {
|
|
|
944
955
|
});
|
|
945
956
|
|
|
946
957
|
this.emit(BlockletEvents.componentRemoved, {
|
|
947
|
-
...
|
|
958
|
+
...app,
|
|
948
959
|
componentDids: [child.meta.did],
|
|
949
960
|
});
|
|
950
961
|
|
|
951
962
|
this.emit(BlockletInternalEvents.componentRemoved, {
|
|
952
|
-
appDid:
|
|
963
|
+
appDid: app.appDid,
|
|
953
964
|
components: [{ did: child.meta.did }],
|
|
954
965
|
});
|
|
955
966
|
// for backward compatibility
|
|
956
967
|
this.emit(BlockletInternalEvents.componentsUpdated, {
|
|
957
|
-
appDid:
|
|
968
|
+
appDid: app.appDid,
|
|
958
969
|
components: getComponentsInternalInfo(newBlocklet),
|
|
959
970
|
});
|
|
971
|
+
this.configSynchronizer.throttledSyncAppConfig(app.meta.did);
|
|
960
972
|
|
|
961
973
|
return { ...newBlocklet, deletedComponent: child };
|
|
962
974
|
}
|
|
@@ -1225,9 +1237,21 @@ class DiskBlockletManager extends BaseBlockletManager {
|
|
|
1225
1237
|
appDid: rootDid,
|
|
1226
1238
|
configs: newConfigs.map((x) => ({ key: x.key, value: x.value })),
|
|
1227
1239
|
});
|
|
1240
|
+
this.configSynchronizer.throttledSyncAppConfig(blocklet.meta.did);
|
|
1228
1241
|
}
|
|
1229
1242
|
|
|
1230
1243
|
this.emit(BlockletEvents.updated, newState);
|
|
1244
|
+
const serverSk = (await states.node.read()).sk;
|
|
1245
|
+
if (childDid) {
|
|
1246
|
+
const configs = JSON.stringify(newConfigs.map((x) => ({ key: x.key, value: x.value })));
|
|
1247
|
+
this.emit(BlockletInternalEvents.componentConfigChanged, {
|
|
1248
|
+
appDid: rootDid,
|
|
1249
|
+
componentDid: childDid,
|
|
1250
|
+
configs: encrypt(configs, getComponentApiKey({ serverSk, app: ancestors[0], component: blocklet }), childDid),
|
|
1251
|
+
});
|
|
1252
|
+
|
|
1253
|
+
this.configSynchronizer.syncComponentConfig(childDid, rootDid, { serverSk });
|
|
1254
|
+
}
|
|
1231
1255
|
|
|
1232
1256
|
return newState;
|
|
1233
1257
|
}
|
|
@@ -1418,6 +1442,7 @@ class DiskBlockletManager extends BaseBlockletManager {
|
|
|
1418
1442
|
appDid: blocklet.appDid,
|
|
1419
1443
|
components: getComponentsInternalInfo(blocklet),
|
|
1420
1444
|
});
|
|
1445
|
+
this.configSynchronizer.throttledSyncAppConfig(blocklet.meta.did);
|
|
1421
1446
|
|
|
1422
1447
|
return this.getBlocklet(rootDid);
|
|
1423
1448
|
}
|
|
@@ -1818,6 +1843,10 @@ class DiskBlockletManager extends BaseBlockletManager {
|
|
|
1818
1843
|
}
|
|
1819
1844
|
}
|
|
1820
1845
|
|
|
1846
|
+
syncAppConfig(did, { serverVersion } = {}) {
|
|
1847
|
+
return this.configSynchronizer.syncAppConfig(did, { serverVersion });
|
|
1848
|
+
}
|
|
1849
|
+
|
|
1821
1850
|
// ============================================================================================
|
|
1822
1851
|
// Private API that are used by self of helper function
|
|
1823
1852
|
// ============================================================================================
|
|
@@ -2076,6 +2105,7 @@ class DiskBlockletManager extends BaseBlockletManager {
|
|
|
2076
2105
|
appDid: blocklet.appDid,
|
|
2077
2106
|
components: getComponentsInternalInfo(res),
|
|
2078
2107
|
});
|
|
2108
|
+
this.configSynchronizer.throttledSyncAppConfig(res);
|
|
2079
2109
|
|
|
2080
2110
|
this.emit(BlockletEvents.statusChange, res);
|
|
2081
2111
|
this.emit(BlockletEvents.started, { ...res, componentDids });
|
|
@@ -2142,7 +2172,7 @@ class DiskBlockletManager extends BaseBlockletManager {
|
|
|
2142
2172
|
async _onBackupToSpaces({ blocklet, context, backup }) {
|
|
2143
2173
|
const {
|
|
2144
2174
|
referrer,
|
|
2145
|
-
user: { did: userDid },
|
|
2175
|
+
user: { did: userDid, locale },
|
|
2146
2176
|
} = context;
|
|
2147
2177
|
const {
|
|
2148
2178
|
appDid,
|
|
@@ -2150,7 +2180,7 @@ class DiskBlockletManager extends BaseBlockletManager {
|
|
|
2150
2180
|
} = blocklet;
|
|
2151
2181
|
|
|
2152
2182
|
try {
|
|
2153
|
-
const spacesBackup = new SpacesBackup({ appDid, appPid, event: this, userDid, referrer, locale
|
|
2183
|
+
const spacesBackup = new SpacesBackup({ appDid, appPid, event: this, userDid, referrer, locale, backup });
|
|
2154
2184
|
this.emit(BlockletEvents.backupProgress, {
|
|
2155
2185
|
appDid,
|
|
2156
2186
|
meta: { did: appPid },
|
|
@@ -2274,7 +2304,7 @@ class DiskBlockletManager extends BaseBlockletManager {
|
|
|
2274
2304
|
const nodeInfo = await states.node.read();
|
|
2275
2305
|
|
|
2276
2306
|
const appSystemEnvironments = {
|
|
2277
|
-
...getAppSystemEnvironments(blockletWithEnv, nodeInfo),
|
|
2307
|
+
...getAppSystemEnvironments(blockletWithEnv, nodeInfo, this.dataDirs),
|
|
2278
2308
|
...getAppOverwrittenEnvironments(blockletWithEnv, nodeInfo),
|
|
2279
2309
|
};
|
|
2280
2310
|
|
|
@@ -2770,6 +2800,7 @@ class DiskBlockletManager extends BaseBlockletManager {
|
|
|
2770
2800
|
appDid: blocklet.appDid,
|
|
2771
2801
|
components: getComponentsInternalInfo(blocklet),
|
|
2772
2802
|
});
|
|
2803
|
+
this.configSynchronizer.throttledSyncAppConfig(blocklet);
|
|
2773
2804
|
|
|
2774
2805
|
return blocklet;
|
|
2775
2806
|
} catch (err) {
|
|
@@ -94,12 +94,16 @@ const installComponentFromUrl = async ({
|
|
|
94
94
|
// if upgrade, do not update mountPoint and title
|
|
95
95
|
newChild.mountPoint = blocklet.children[index].mountPoint;
|
|
96
96
|
newChild.meta.title = blocklet.children[index].meta.title;
|
|
97
|
+
newChild.installedAt = blocklet.children[index].installedAt;
|
|
97
98
|
blocklet.children.splice(index, 1, newChild);
|
|
98
99
|
} else {
|
|
99
100
|
dynamicComponents.unshift(newChild);
|
|
100
101
|
}
|
|
101
102
|
|
|
102
|
-
const newChildren = filterDuplicateComponents(dynamicComponents, blocklet.children)
|
|
103
|
+
const newChildren = filterDuplicateComponents(dynamicComponents, blocklet.children).map((x) => ({
|
|
104
|
+
...x,
|
|
105
|
+
installedAt: new Date(),
|
|
106
|
+
}));
|
|
103
107
|
|
|
104
108
|
blocklet.children.push(...newChildren);
|
|
105
109
|
|
|
@@ -27,6 +27,8 @@ const { getAppName, getAppDescription } = require('@blocklet/meta/lib/util');
|
|
|
27
27
|
|
|
28
28
|
const logger = require('@abtnode/logger')('@abtnode/core:storage:backup');
|
|
29
29
|
|
|
30
|
+
const { default: axios } = require('axios');
|
|
31
|
+
const xbytes = require('xbytes');
|
|
30
32
|
const states = require('../../../states');
|
|
31
33
|
const { BaseBackup } = require('./base');
|
|
32
34
|
const { AuditLogBackup } = require('./audit-log');
|
|
@@ -36,6 +38,7 @@ const { BlockletsBackup } = require('./blocklets');
|
|
|
36
38
|
const { DataBackup } = require('./data');
|
|
37
39
|
const { RoutingRuleBackup } = require('./routing-rule');
|
|
38
40
|
const { translate } = require('../../../locales');
|
|
41
|
+
const { getFolderSize } = require('../utils/disk');
|
|
39
42
|
|
|
40
43
|
class SpacesBackup extends BaseBackup {
|
|
41
44
|
/**
|
|
@@ -126,6 +129,7 @@ class SpacesBackup extends BaseBackup {
|
|
|
126
129
|
try {
|
|
127
130
|
await this.initialize();
|
|
128
131
|
await this.export();
|
|
132
|
+
await this.verifySpace();
|
|
129
133
|
await this.syncToSpaces();
|
|
130
134
|
} catch (error) {
|
|
131
135
|
console.error(error);
|
|
@@ -183,6 +187,35 @@ class SpacesBackup extends BaseBackup {
|
|
|
183
187
|
});
|
|
184
188
|
}
|
|
185
189
|
|
|
190
|
+
/**
|
|
191
|
+
* @description 验证 Space 的空间是否足够备份所需
|
|
192
|
+
* @memberof SpacesBackup
|
|
193
|
+
*/
|
|
194
|
+
async verifySpace() {
|
|
195
|
+
const { headers } = await axios.head(`${this.spaceBackupEndpoint}?withExtras=true`, {
|
|
196
|
+
// @FIXME: 等到 space 的存储优化专项完成后,这里可以给出更小的超时时间
|
|
197
|
+
timeout: 1000 * 120,
|
|
198
|
+
});
|
|
199
|
+
|
|
200
|
+
const [spaceIsFull, spaceFreeCapacity] = [headers['x-space-is-full'] === 'true', +headers['x-space-free-capacity']];
|
|
201
|
+
const backupFolderSize = getFolderSize(this.backupDir);
|
|
202
|
+
|
|
203
|
+
logger.info('verifySpace', {
|
|
204
|
+
spaceIsFull,
|
|
205
|
+
spaceFreeCapacity: xbytes(spaceFreeCapacity),
|
|
206
|
+
backupFolderSize: xbytes(backupFolderSize),
|
|
207
|
+
backupDir: this.backupDir,
|
|
208
|
+
});
|
|
209
|
+
|
|
210
|
+
if (spaceIsFull) {
|
|
211
|
+
throw new Error(translate(this.input.locale, 'backup.space.isFull'));
|
|
212
|
+
}
|
|
213
|
+
|
|
214
|
+
if (spaceFreeCapacity <= backupFolderSize) {
|
|
215
|
+
throw new Error(translate(this.input.locale, 'backup.space.lackOfSpace'));
|
|
216
|
+
}
|
|
217
|
+
}
|
|
218
|
+
|
|
186
219
|
async syncToSpaces() {
|
|
187
220
|
/**
|
|
188
221
|
* @type {import('@abtnode/client').NodeState}
|
|
@@ -225,7 +258,7 @@ class SpacesBackup extends BaseBackup {
|
|
|
225
258
|
const percent = (data.completed * 100) / data.total;
|
|
226
259
|
// 0.8 是因为上传文件到 spaces 占进度的 80%,+ 20 是因为需要累加之前的进度
|
|
227
260
|
const progress = +Math.floor(percent * 0.8).toFixed(2) + 20;
|
|
228
|
-
const progressMessage = `
|
|
261
|
+
const progressMessage = `(${data.completed}/${data.total}) Uploading file ${basename(data.key)}`;
|
|
229
262
|
|
|
230
263
|
await states.backup.progress(this.input.backup.id, {
|
|
231
264
|
progress,
|
|
@@ -6,6 +6,11 @@ const logger = require('@abtnode/logger')('@abtnode/core:storage:utils:disk');
|
|
|
6
6
|
const backupDirName = '_abtnode/backup';
|
|
7
7
|
const restoreDirName = 'tmp/restore-disk';
|
|
8
8
|
|
|
9
|
+
/**
|
|
10
|
+
* @description
|
|
11
|
+
* @param {string} dataDir
|
|
12
|
+
* @return {any[]}
|
|
13
|
+
*/
|
|
9
14
|
const getBackupList = (dataDir) => {
|
|
10
15
|
const baseBackupDir = path.join(dataDir, backupDirName);
|
|
11
16
|
const backupList = [];
|
|
@@ -28,6 +33,12 @@ const getBackupList = (dataDir) => {
|
|
|
28
33
|
return backupList;
|
|
29
34
|
};
|
|
30
35
|
|
|
36
|
+
/**
|
|
37
|
+
*
|
|
38
|
+
* @param {string} dataDir
|
|
39
|
+
* @param {string} appDid
|
|
40
|
+
* @returns {Promise<boolean>}
|
|
41
|
+
*/
|
|
31
42
|
const removeBackup = async (dataDir, appDid) => {
|
|
32
43
|
try {
|
|
33
44
|
const baseBackupDir = path.join(dataDir, backupDirName);
|
|
@@ -54,8 +65,36 @@ const getBackupDirs = (serverDir, appDid) => {
|
|
|
54
65
|
};
|
|
55
66
|
};
|
|
56
67
|
|
|
68
|
+
/**
|
|
69
|
+
* @description
|
|
70
|
+
* @param {string} folderPath
|
|
71
|
+
* @return {number}
|
|
72
|
+
*/
|
|
73
|
+
function getFolderSize(folderPath) {
|
|
74
|
+
let totalSize = 0;
|
|
75
|
+
const stack = [folderPath];
|
|
76
|
+
|
|
77
|
+
while (stack.length) {
|
|
78
|
+
const currentPath = stack.pop();
|
|
79
|
+
const stats = fs.statSync(currentPath);
|
|
80
|
+
|
|
81
|
+
if (stats.isFile()) {
|
|
82
|
+
totalSize += stats.size;
|
|
83
|
+
} else if (stats.isDirectory()) {
|
|
84
|
+
const files = fs.readdirSync(currentPath);
|
|
85
|
+
files.forEach((file) => {
|
|
86
|
+
const filePath = path.join(currentPath, file);
|
|
87
|
+
stack.push(filePath);
|
|
88
|
+
});
|
|
89
|
+
}
|
|
90
|
+
}
|
|
91
|
+
|
|
92
|
+
return totalSize;
|
|
93
|
+
}
|
|
94
|
+
|
|
57
95
|
module.exports = {
|
|
58
96
|
getBackupList,
|
|
59
97
|
removeBackup,
|
|
60
98
|
getBackupDirs,
|
|
99
|
+
getFolderSize,
|
|
61
100
|
};
|
package/lib/index.js
CHANGED
|
@@ -273,6 +273,7 @@ function ABTNode(options) {
|
|
|
273
273
|
backupBlocklet: blockletManager.backup.bind(blockletManager),
|
|
274
274
|
restoreBlocklet: blockletManager.restoreBlocklet.bind(blockletManager),
|
|
275
275
|
migrateApplicationToStructV2: blockletManager.migrateApplicationToStructV2.bind(blockletManager),
|
|
276
|
+
syncAppConfig: blockletManager.syncAppConfig.bind(blockletManager),
|
|
276
277
|
|
|
277
278
|
// For diagnose purpose
|
|
278
279
|
syncBlockletStatus: blockletManager.status.bind(blockletManager),
|
package/lib/locales/en.js
CHANGED
|
@@ -11,6 +11,9 @@ module.exports = flat({
|
|
|
11
11
|
forbidden:
|
|
12
12
|
'You do not have permission to perform the backup, try restoring the application license on DID Spaces or reconnect to DID Spaces and try again',
|
|
13
13
|
},
|
|
14
|
+
isFull: 'The current Space storage space is full, please expand the space and back up again',
|
|
15
|
+
lackOfSpace:
|
|
16
|
+
'The current available space in the storage is insufficient. Please expand the space and perform the backup again',
|
|
14
17
|
},
|
|
15
18
|
},
|
|
16
19
|
});
|
package/lib/locales/zh.js
CHANGED
package/lib/util/blocklet.js
CHANGED
|
@@ -263,7 +263,7 @@ const ensureBlockletExpanded = async (meta, appDir) => {
|
|
|
263
263
|
}
|
|
264
264
|
};
|
|
265
265
|
|
|
266
|
-
const getAppSystemEnvironments = (blocklet, nodeInfo) => {
|
|
266
|
+
const getAppSystemEnvironments = (blocklet, nodeInfo, dataDirs) => {
|
|
267
267
|
const { did, name, title, description } = blocklet.meta;
|
|
268
268
|
const keys = Object.keys(BLOCKLET_CONFIGURABLE_KEY);
|
|
269
269
|
const result = getBlockletInfo(
|
|
@@ -311,6 +311,7 @@ const getAppSystemEnvironments = (blocklet, nodeInfo) => {
|
|
|
311
311
|
BLOCKLET_APP_NAME: appName,
|
|
312
312
|
BLOCKLET_APP_DESCRIPTION: appDescription,
|
|
313
313
|
BLOCKLET_APP_URL: appUrl,
|
|
314
|
+
BLOCKLET_APP_DATA_DIR: path.join(dataDirs.data, blocklet.meta.name),
|
|
314
315
|
};
|
|
315
316
|
};
|
|
316
317
|
|
|
@@ -491,6 +492,7 @@ const startBlockletProcess = async (
|
|
|
491
492
|
e2eMode,
|
|
492
493
|
skippedProcessIds = [],
|
|
493
494
|
componentDids,
|
|
495
|
+
configSynchronizer,
|
|
494
496
|
} = {}
|
|
495
497
|
) => {
|
|
496
498
|
if (!blocklet) {
|
|
@@ -604,6 +606,10 @@ const startBlockletProcess = async (
|
|
|
604
606
|
}
|
|
605
607
|
}
|
|
606
608
|
|
|
609
|
+
await configSynchronizer.syncComponentConfig(b.meta.did, blocklet.meta.did, {
|
|
610
|
+
serverSk: nodeEnvironments.ABT_NODE_SK,
|
|
611
|
+
});
|
|
612
|
+
|
|
607
613
|
await pm2.startAsync(options);
|
|
608
614
|
|
|
609
615
|
const status = await getProcessState(processId);
|
package/package.json
CHANGED
|
@@ -3,7 +3,7 @@
|
|
|
3
3
|
"publishConfig": {
|
|
4
4
|
"access": "public"
|
|
5
5
|
},
|
|
6
|
-
"version": "1.16.15-beta-
|
|
6
|
+
"version": "1.16.15-beta-d464647a",
|
|
7
7
|
"description": "",
|
|
8
8
|
"main": "lib/index.js",
|
|
9
9
|
"files": [
|
|
@@ -19,19 +19,19 @@
|
|
|
19
19
|
"author": "wangshijun <wangshijun2010@gmail.com> (http://github.com/wangshijun)",
|
|
20
20
|
"license": "Apache-2.0",
|
|
21
21
|
"dependencies": {
|
|
22
|
-
"@abtnode/analytics": "1.16.15-beta-
|
|
23
|
-
"@abtnode/auth": "1.16.15-beta-
|
|
24
|
-
"@abtnode/certificate-manager": "1.16.15-beta-
|
|
25
|
-
"@abtnode/constant": "1.16.15-beta-
|
|
26
|
-
"@abtnode/cron": "1.16.15-beta-
|
|
27
|
-
"@abtnode/logger": "1.16.15-beta-
|
|
28
|
-
"@abtnode/models": "1.16.15-beta-
|
|
29
|
-
"@abtnode/queue": "1.16.15-beta-
|
|
30
|
-
"@abtnode/rbac": "1.16.15-beta-
|
|
31
|
-
"@abtnode/router-provider": "1.16.15-beta-
|
|
32
|
-
"@abtnode/static-server": "1.16.15-beta-
|
|
33
|
-
"@abtnode/timemachine": "1.16.15-beta-
|
|
34
|
-
"@abtnode/util": "1.16.15-beta-
|
|
22
|
+
"@abtnode/analytics": "1.16.15-beta-d464647a",
|
|
23
|
+
"@abtnode/auth": "1.16.15-beta-d464647a",
|
|
24
|
+
"@abtnode/certificate-manager": "1.16.15-beta-d464647a",
|
|
25
|
+
"@abtnode/constant": "1.16.15-beta-d464647a",
|
|
26
|
+
"@abtnode/cron": "1.16.15-beta-d464647a",
|
|
27
|
+
"@abtnode/logger": "1.16.15-beta-d464647a",
|
|
28
|
+
"@abtnode/models": "1.16.15-beta-d464647a",
|
|
29
|
+
"@abtnode/queue": "1.16.15-beta-d464647a",
|
|
30
|
+
"@abtnode/rbac": "1.16.15-beta-d464647a",
|
|
31
|
+
"@abtnode/router-provider": "1.16.15-beta-d464647a",
|
|
32
|
+
"@abtnode/static-server": "1.16.15-beta-d464647a",
|
|
33
|
+
"@abtnode/timemachine": "1.16.15-beta-d464647a",
|
|
34
|
+
"@abtnode/util": "1.16.15-beta-d464647a",
|
|
35
35
|
"@arcblock/did": "1.18.89",
|
|
36
36
|
"@arcblock/did-auth": "1.18.89",
|
|
37
37
|
"@arcblock/did-ext": "^1.18.89",
|
|
@@ -42,11 +42,12 @@
|
|
|
42
42
|
"@arcblock/pm2-events": "^0.0.5",
|
|
43
43
|
"@arcblock/validator": "^1.18.89",
|
|
44
44
|
"@arcblock/vc": "1.18.89",
|
|
45
|
-
"@blocklet/constant": "1.16.15-beta-
|
|
46
|
-
"@blocklet/
|
|
47
|
-
"@blocklet/
|
|
48
|
-
"@blocklet/
|
|
49
|
-
"@
|
|
45
|
+
"@blocklet/constant": "1.16.15-beta-d464647a",
|
|
46
|
+
"@blocklet/env": "1.16.15-beta-d464647a",
|
|
47
|
+
"@blocklet/meta": "1.16.15-beta-d464647a",
|
|
48
|
+
"@blocklet/resolver": "1.16.15-beta-d464647a",
|
|
49
|
+
"@blocklet/sdk": "1.16.15-beta-d464647a",
|
|
50
|
+
"@did-space/client": "^0.2.165",
|
|
50
51
|
"@fidm/x509": "^1.2.1",
|
|
51
52
|
"@ocap/mcrypto": "1.18.89",
|
|
52
53
|
"@ocap/util": "1.18.89",
|
|
@@ -90,7 +91,8 @@
|
|
|
90
91
|
"ua-parser-js": "^1.0.2",
|
|
91
92
|
"url-join": "^4.0.1",
|
|
92
93
|
"uuid": "^8.3.2",
|
|
93
|
-
"valid-url": "^1.0.9"
|
|
94
|
+
"valid-url": "^1.0.9",
|
|
95
|
+
"xbytes": "^1.8.0"
|
|
94
96
|
},
|
|
95
97
|
"devDependencies": {
|
|
96
98
|
"expand-tilde": "^2.0.2",
|
|
@@ -98,5 +100,5 @@
|
|
|
98
100
|
"jest": "^27.5.1",
|
|
99
101
|
"unzipper": "^0.10.11"
|
|
100
102
|
},
|
|
101
|
-
"gitHead": "
|
|
103
|
+
"gitHead": "117b29484cbc36434ebdd635f100eb02a5cf7732"
|
|
102
104
|
}
|