@abtnode/core 1.6.17 → 1.6.21
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 +1 -1
- package/lib/blocklet/hooks.js +16 -63
- package/lib/blocklet/manager/disk.js +85 -76
- package/lib/blocklet/migration.js +16 -52
- package/lib/event.js +3 -2
- package/lib/index.js +2 -3
- package/lib/migrations/1.6.21-rename-ip-echo-domain.js +27 -0
- package/lib/router/helper.js +80 -59
- package/lib/router/index.js +6 -6
- package/lib/router/manager.js +4 -4
- package/lib/states/blocklet.js +80 -4
- package/lib/states/node.js +4 -3
- package/lib/util/blocklet.js +50 -3
- package/lib/util/get-domain-for-blocklet.js +2 -2
- package/lib/util/index.js +5 -5
- package/lib/util/upgrade.js +8 -4
- package/package.json +22 -22
package/lib/api/node.js
CHANGED
|
@@ -93,7 +93,7 @@ class NodeAPI {
|
|
|
93
93
|
async updateNodeInfo(entity = {}, context) {
|
|
94
94
|
await validateNodeInfo(entity, context);
|
|
95
95
|
|
|
96
|
-
if (entity.autoUpgrade) {
|
|
96
|
+
if (entity.autoUpgrade && process.env.NODE_ENV !== 'development') {
|
|
97
97
|
try {
|
|
98
98
|
canPackageReadWrite(process.env.ABT_NODE_BINARY_NAME, process.env.ABT_NODE_PACKAGE_NAME);
|
|
99
99
|
} catch (err) {
|
package/lib/blocklet/hooks.js
CHANGED
|
@@ -1,68 +1,23 @@
|
|
|
1
|
-
const childProcess = require('child_process');
|
|
2
1
|
const get = require('lodash/get');
|
|
3
2
|
const camelCase = require('lodash/camelCase');
|
|
3
|
+
const runScript = require('@abtnode/util/lib/run-script');
|
|
4
4
|
|
|
5
5
|
// eslint-disable-next-line global-require
|
|
6
6
|
const logger = require('@abtnode/logger')(`${require('../../package.json').name}:blocklet:hooks`);
|
|
7
7
|
|
|
8
8
|
const { getSafeEnv } = require('../util');
|
|
9
9
|
|
|
10
|
-
const
|
|
11
|
-
const
|
|
12
|
-
const
|
|
13
|
-
cwd: appDir,
|
|
14
|
-
env: safeEnv,
|
|
15
|
-
stdio: 'inherit',
|
|
16
|
-
});
|
|
17
|
-
|
|
18
|
-
if (progress) {
|
|
19
|
-
child.stdout.pipe(process.stdout);
|
|
20
|
-
child.stderr.pipe(process.stderr);
|
|
21
|
-
}
|
|
22
|
-
|
|
23
|
-
return new Promise((resolve, reject) => {
|
|
24
|
-
const errorMessages = [];
|
|
25
|
-
let hasUnhandledRejection = false;
|
|
26
|
-
|
|
27
|
-
child.stderr.on('data', (err) => {
|
|
28
|
-
// Check if has unhandledRejection in childProcess
|
|
29
|
-
// https://stackoverflow.com/questions/32784649/gracefully-handle-errors-in-child-processes-in-nodejs
|
|
30
|
-
if (err.includes('UnhandledPromiseRejectionWarning')) {
|
|
31
|
-
hasUnhandledRejection = true;
|
|
32
|
-
}
|
|
33
|
-
errorMessages.push(err);
|
|
34
|
-
});
|
|
35
|
-
|
|
36
|
-
child.on('exit', (code) => {
|
|
37
|
-
if (errorMessages.length > 0) {
|
|
38
|
-
if (code !== 0 || hasUnhandledRejection) {
|
|
39
|
-
return reject(new Error(errorMessages.join('\r\n')));
|
|
40
|
-
}
|
|
41
|
-
|
|
42
|
-
if (!progress) {
|
|
43
|
-
errorMessages.forEach((message) => process.stderr.write(message));
|
|
44
|
-
}
|
|
45
|
-
}
|
|
46
|
-
|
|
47
|
-
return resolve();
|
|
48
|
-
});
|
|
49
|
-
});
|
|
50
|
-
};
|
|
51
|
-
|
|
52
|
-
/**
|
|
53
|
-
* @param {*} args.did root blocklet did
|
|
54
|
-
*/
|
|
55
|
-
const runUserHook = async (name, args) => {
|
|
56
|
-
const { appDir, hooks, env, exitOnError = true, progress = false, notification, did } = args;
|
|
57
|
-
const hook = get(hooks, `[${name}]`) || get(hooks, `[${camelCase(name)}]`);
|
|
10
|
+
const runUserHook = async (appId, hookName, args) => {
|
|
11
|
+
const { appDir, hooks, env, exitOnError = true, silent = false, notification, did } = args;
|
|
12
|
+
const hook = get(hooks, `[${hookName}]`) || get(hooks, `[${camelCase(hookName)}]`);
|
|
58
13
|
|
|
59
14
|
try {
|
|
60
15
|
if (!hook) {
|
|
61
16
|
return;
|
|
62
17
|
}
|
|
63
18
|
|
|
64
|
-
logger.info(`run hook:${
|
|
65
|
-
await
|
|
19
|
+
logger.info(`run hook:${hookName}:`, { hook });
|
|
20
|
+
await runScript(hook, [appId, hookName].join(':'), { cwd: appDir, env: getSafeEnv(env), silent });
|
|
66
21
|
} catch (error) {
|
|
67
22
|
logger.error(`run ${hook} error:`, { error });
|
|
68
23
|
|
|
@@ -77,33 +32,31 @@ const runUserHook = async (name, args) => {
|
|
|
77
32
|
}
|
|
78
33
|
|
|
79
34
|
if (exitOnError) {
|
|
80
|
-
throw new Error(`Run [${
|
|
35
|
+
throw new Error(`Run [${hookName}] failed: ${error.message}`);
|
|
81
36
|
}
|
|
82
37
|
}
|
|
83
38
|
};
|
|
84
39
|
|
|
85
|
-
const preDeploy = (...args) => runUserHook('pre-deploy', ...args);
|
|
86
|
-
const preInstall = (...args) => runUserHook('pre-install', ...args);
|
|
87
|
-
const postInstall = (...args) => runUserHook('post-install', ...args);
|
|
88
|
-
|
|
89
|
-
const preStart = async (blocklet,
|
|
40
|
+
const preDeploy = (appId, ...args) => runUserHook(appId, 'pre-deploy', ...args);
|
|
41
|
+
const preInstall = (appId, ...args) => runUserHook(appId, 'pre-install', ...args);
|
|
42
|
+
const postInstall = (appId, ...args) => runUserHook(appId, 'post-install', ...args);
|
|
43
|
+
const preConfig = (appId, ...args) => runUserHook(appId, 'pre-config', ...args);
|
|
44
|
+
const preStart = async (blocklet, options) => {
|
|
90
45
|
// check required environments
|
|
91
46
|
let environments = get(blocklet, 'meta.environments', []);
|
|
92
47
|
if (!Array.isArray(environments)) {
|
|
93
48
|
environments = [environments];
|
|
94
49
|
}
|
|
95
50
|
|
|
96
|
-
const tmp = environments.filter((e) => e.required &&
|
|
51
|
+
const tmp = environments.filter((e) => e.required && options.env[e.name] === undefined).map((e) => e.name);
|
|
97
52
|
if (tmp.length > 0) {
|
|
98
53
|
throw new Error(`Required environments is not set: ${tmp.join(',')}`);
|
|
99
54
|
}
|
|
100
55
|
|
|
101
|
-
return runUserHook('pre-start',
|
|
56
|
+
return runUserHook(blocklet.env.appId, 'pre-start', options);
|
|
102
57
|
};
|
|
103
58
|
|
|
104
|
-
const preUninstall = (...args) => runUserHook('pre-uninstall', ...args);
|
|
105
|
-
const preStop = (...args) => runUserHook('pre-stop', ...args);
|
|
106
|
-
|
|
107
|
-
const preConfig = (...args) => runUserHook('pre-config', ...args);
|
|
59
|
+
const preUninstall = (appId, ...args) => runUserHook(appId, 'pre-uninstall', ...args);
|
|
60
|
+
const preStop = (appId, ...args) => runUserHook(appId, 'pre-stop', ...args);
|
|
108
61
|
|
|
109
62
|
module.exports = { preDeploy, preInstall, postInstall, preStart, preUninstall, preStop, preConfig };
|
|
@@ -20,18 +20,17 @@ const logger = require('@abtnode/logger')('@abtnode/core:blocklet:manager');
|
|
|
20
20
|
const downloadFile = require('@abtnode/util/lib/download-file');
|
|
21
21
|
const Lock = require('@abtnode/util/lib/lock');
|
|
22
22
|
const { getVcFromPresentation } = require('@abtnode/util/lib/vc');
|
|
23
|
-
const {
|
|
24
|
-
const { BLOCKLET_PURCHASE_NFT_TYPE } = require('@abtnode/constant');
|
|
23
|
+
const { VC_TYPE_BLOCKLET_PURCHASE } = require('@abtnode/constant');
|
|
25
24
|
|
|
26
25
|
const getBlockletEngine = require('@blocklet/meta/lib/engine');
|
|
27
26
|
const {
|
|
28
27
|
isFreeBlocklet,
|
|
28
|
+
isComponentBlocklet,
|
|
29
29
|
isDeletableBlocklet,
|
|
30
30
|
getRequiredMissingConfigs,
|
|
31
31
|
hasRunnableComponent,
|
|
32
32
|
} = require('@blocklet/meta/lib/util');
|
|
33
33
|
const validateBlockletEntry = require('@blocklet/meta/lib/entry');
|
|
34
|
-
const { getBlockletInfo } = require('@blocklet/meta/lib');
|
|
35
34
|
const toBlockletDid = require('@blocklet/meta/lib/did');
|
|
36
35
|
const { validateMeta } = require('@blocklet/meta/lib/validate');
|
|
37
36
|
const { update: updateMetaFile } = require('@blocklet/meta/lib/file');
|
|
@@ -90,6 +89,8 @@ const {
|
|
|
90
89
|
checkDuplicateComponents,
|
|
91
90
|
getDiffFiles,
|
|
92
91
|
getBundleDir,
|
|
92
|
+
needBlockletDownload,
|
|
93
|
+
verifyPurchase,
|
|
93
94
|
} = require('../../util/blocklet');
|
|
94
95
|
const states = require('../../states');
|
|
95
96
|
const BlockletRegistry = require('../registry');
|
|
@@ -197,6 +198,20 @@ class BlockletManager extends BaseBlockletManager {
|
|
|
197
198
|
throw new Error('Unknown source');
|
|
198
199
|
}
|
|
199
200
|
|
|
201
|
+
/**
|
|
202
|
+
* @param {String} rootDid
|
|
203
|
+
* @param {String} mountPoint
|
|
204
|
+
* @param {Boolean} context.blockletPurchaseVerified
|
|
205
|
+
*
|
|
206
|
+
* installFromUrl
|
|
207
|
+
* @param {String} url
|
|
208
|
+
*
|
|
209
|
+
* InstallFromUpload
|
|
210
|
+
* @param {Object} file
|
|
211
|
+
* @param {String} did for diff upload
|
|
212
|
+
* @param {String} diffVersion for diff upload
|
|
213
|
+
* @param {Array} deleteSet for diff upload
|
|
214
|
+
*/
|
|
200
215
|
async installComponent({ rootDid, mountPoint, url, file, did, diffVersion, deleteSet }, context = {}) {
|
|
201
216
|
logger.debug('start install component', { rootDid, mountPoint, url });
|
|
202
217
|
|
|
@@ -244,8 +259,8 @@ class BlockletManager extends BaseBlockletManager {
|
|
|
244
259
|
// FIXME: 这里的 trustedIssuers 相当于相信任何 VC,需要想更安全的方法
|
|
245
260
|
verifyPresentation({ presentation: vcPresentation, trustedIssuers: [get(vc, 'issuer.id')], challenge });
|
|
246
261
|
|
|
247
|
-
if (!vc.type.includes(
|
|
248
|
-
throw new Error(`Expect ${
|
|
262
|
+
if (!vc.type.includes(VC_TYPE_BLOCKLET_PURCHASE)) {
|
|
263
|
+
throw new Error(`Expect ${VC_TYPE_BLOCKLET_PURCHASE} VC type`);
|
|
249
264
|
}
|
|
250
265
|
|
|
251
266
|
const blockletUrl = get(vc, 'credentialSubject.purchased.blocklet.url');
|
|
@@ -293,7 +308,6 @@ class BlockletManager extends BaseBlockletManager {
|
|
|
293
308
|
hooks: Object.assign(b.meta.hooks || {}, b.meta.scripts || {}),
|
|
294
309
|
env: getRuntimeEnvironments(b, nodeEnvironments, blocklet),
|
|
295
310
|
did, // root blocklet did,
|
|
296
|
-
progress: blocklet.mode === BLOCKLET_MODES.DEVELOPMENT,
|
|
297
311
|
}),
|
|
298
312
|
nodeEnvironments,
|
|
299
313
|
nodeInfo: await states.node.read(),
|
|
@@ -344,7 +358,7 @@ class BlockletManager extends BaseBlockletManager {
|
|
|
344
358
|
}
|
|
345
359
|
}
|
|
346
360
|
|
|
347
|
-
async stop({ did, updateStatus = true }, context) {
|
|
361
|
+
async stop({ did, updateStatus = true, silent = false }, context) {
|
|
348
362
|
logger.info('stop blocklet', { did });
|
|
349
363
|
|
|
350
364
|
const blocklet = await this.ensureBlocklet(did);
|
|
@@ -360,7 +374,7 @@ class BlockletManager extends BaseBlockletManager {
|
|
|
360
374
|
|
|
361
375
|
await stopBlockletProcess(blocklet, {
|
|
362
376
|
preStop: (b) =>
|
|
363
|
-
hooks.preStop({
|
|
377
|
+
hooks.preStop(b.env.appId, {
|
|
364
378
|
appDir: b.env.appDir,
|
|
365
379
|
hooks: Object.assign(b.meta.hooks || {}, b.meta.scripts || {}),
|
|
366
380
|
env: getRuntimeEnvironments(b, nodeEnvironments, blocklet),
|
|
@@ -368,7 +382,7 @@ class BlockletManager extends BaseBlockletManager {
|
|
|
368
382
|
notification: states.notification,
|
|
369
383
|
context,
|
|
370
384
|
exitOnError: false,
|
|
371
|
-
|
|
385
|
+
silent,
|
|
372
386
|
}),
|
|
373
387
|
});
|
|
374
388
|
|
|
@@ -436,7 +450,7 @@ class BlockletManager extends BaseBlockletManager {
|
|
|
436
450
|
|
|
437
451
|
await deleteBlockletProcess(blocklet, {
|
|
438
452
|
preDelete: (b) =>
|
|
439
|
-
hooks.preUninstall({
|
|
453
|
+
hooks.preUninstall(b.env.appId, {
|
|
440
454
|
appDir: b.env.appDir,
|
|
441
455
|
hooks: Object.assign(b.meta.hooks || {}, b.meta.scripts || {}),
|
|
442
456
|
env: getRuntimeEnvironments(b, nodeEnvironments, blocklet),
|
|
@@ -512,12 +526,14 @@ class BlockletManager extends BaseBlockletManager {
|
|
|
512
526
|
return result;
|
|
513
527
|
}
|
|
514
528
|
|
|
515
|
-
async detail({ did, attachRuntimeInfo = true }, context) {
|
|
529
|
+
async detail({ did, attachConfig = true, attachRuntimeInfo = true }, context) {
|
|
516
530
|
if (!did) {
|
|
517
531
|
throw new Error('did should not be empty');
|
|
518
532
|
}
|
|
519
533
|
|
|
520
|
-
|
|
534
|
+
if (!attachConfig) {
|
|
535
|
+
return states.blocklet.getBlocklet(did);
|
|
536
|
+
}
|
|
521
537
|
|
|
522
538
|
if (!attachRuntimeInfo) {
|
|
523
539
|
try {
|
|
@@ -528,6 +544,8 @@ class BlockletManager extends BaseBlockletManager {
|
|
|
528
544
|
}
|
|
529
545
|
}
|
|
530
546
|
|
|
547
|
+
const nodeInfo = await states.node.read();
|
|
548
|
+
|
|
531
549
|
return this.attachRuntimeInfo({ did, nodeInfo, diskInfo: true, context });
|
|
532
550
|
}
|
|
533
551
|
|
|
@@ -624,14 +642,13 @@ class BlockletManager extends BaseBlockletManager {
|
|
|
624
642
|
}
|
|
625
643
|
|
|
626
644
|
// FIXME: we should also call preConfig for child blocklets
|
|
627
|
-
await hooks.preConfig({
|
|
645
|
+
await hooks.preConfig(blocklet.env.appId, {
|
|
628
646
|
appDir: blocklet.env.appDir,
|
|
629
647
|
hooks: Object.assign(blocklet.meta.hooks || {}, blocklet.meta.scripts || {}),
|
|
630
648
|
exitOnError: true,
|
|
631
649
|
env: { ...getRuntimeEnvironments(blocklet, nodeEnvironments), ...blocklet.configObj },
|
|
632
650
|
did,
|
|
633
651
|
context,
|
|
634
|
-
progress: blocklet.mode === BLOCKLET_MODES.DEVELOPMENT,
|
|
635
652
|
});
|
|
636
653
|
|
|
637
654
|
// update db
|
|
@@ -819,21 +836,23 @@ class BlockletManager extends BaseBlockletManager {
|
|
|
819
836
|
};
|
|
820
837
|
}
|
|
821
838
|
|
|
822
|
-
async updateChildren({ updateId, did: inputDid, children: inputChildren }, context) {
|
|
839
|
+
async updateChildren({ updateId, did: inputDid, children: inputChildren, oldBlocklet: inputOldBlocklet }, context) {
|
|
823
840
|
let did;
|
|
824
841
|
let children;
|
|
842
|
+
let oldBlocklet;
|
|
825
843
|
if (!updateId && inputDid && inputChildren) {
|
|
826
844
|
did = inputDid;
|
|
827
845
|
children = inputChildren;
|
|
846
|
+
oldBlocklet = inputOldBlocklet;
|
|
828
847
|
} else {
|
|
829
848
|
const sessionData = await states.session.end(updateId);
|
|
830
849
|
did = sessionData.did;
|
|
831
850
|
const { staticChildren = [], dynamicChildren = [] } = sessionData;
|
|
832
851
|
children = [...staticChildren, ...dynamicChildren.map((x) => ({ ...x, dynamic: true }))];
|
|
852
|
+
oldBlocklet = await states.blocklet.getBlocklet(did);
|
|
833
853
|
}
|
|
834
854
|
|
|
835
855
|
// get old blocklet
|
|
836
|
-
const oldBlocklet = await states.blocklet.getBlocklet(did);
|
|
837
856
|
const { meta } = oldBlocklet;
|
|
838
857
|
const { name, version } = meta;
|
|
839
858
|
|
|
@@ -887,6 +906,11 @@ class BlockletManager extends BaseBlockletManager {
|
|
|
887
906
|
// ============================================================================================
|
|
888
907
|
// Internal API that are used by public APIs and called from CLI
|
|
889
908
|
// ============================================================================================
|
|
909
|
+
|
|
910
|
+
/**
|
|
911
|
+
* After the dev function finished, the caller should send a BlockletEvents.deployed event to the daemon
|
|
912
|
+
* @returns {Object} blocklet
|
|
913
|
+
*/
|
|
890
914
|
async dev(folder) {
|
|
891
915
|
logger.info('dev blocklet', { folder });
|
|
892
916
|
|
|
@@ -919,11 +943,13 @@ class BlockletManager extends BaseBlockletManager {
|
|
|
919
943
|
await this.deleteProcess({ did });
|
|
920
944
|
logger.info('delete blocklet precess for dev', { did, version });
|
|
921
945
|
} catch (err) {
|
|
922
|
-
|
|
946
|
+
if (process.env.NODE_ENV !== 'development') {
|
|
947
|
+
logger.error('failed to delete blocklet process for dev', { error: err });
|
|
948
|
+
}
|
|
923
949
|
}
|
|
924
950
|
|
|
925
951
|
const children = await this._getChildren(meta);
|
|
926
|
-
const
|
|
952
|
+
const added = await states.blocklet.addBlocklet({
|
|
927
953
|
did,
|
|
928
954
|
meta,
|
|
929
955
|
source: BlockletSource.local,
|
|
@@ -934,15 +960,16 @@ class BlockletManager extends BaseBlockletManager {
|
|
|
934
960
|
logger.info('add blocklet for dev', { did, version, meta });
|
|
935
961
|
|
|
936
962
|
const oldBlocklet = { children: children.filter((x) => x.dynamic) }; // let downloader skip re-downloading dynamic blocklet
|
|
937
|
-
await this._downloadBlocklet(
|
|
963
|
+
await this._downloadBlocklet(added, oldBlocklet);
|
|
938
964
|
await states.blocklet.setBlockletStatus(did, BlockletStatus.installed);
|
|
939
965
|
|
|
940
966
|
// Add environments
|
|
941
967
|
await this._setConfigs(did);
|
|
942
968
|
await this.updateBlockletEnvironment(did);
|
|
943
969
|
|
|
944
|
-
|
|
945
|
-
|
|
970
|
+
const blocklet = await this.ensureBlocklet(did);
|
|
971
|
+
|
|
972
|
+
return blocklet;
|
|
946
973
|
}
|
|
947
974
|
|
|
948
975
|
async ensureBlocklet(did) {
|
|
@@ -1171,9 +1198,6 @@ class BlockletManager extends BaseBlockletManager {
|
|
|
1171
1198
|
return;
|
|
1172
1199
|
}
|
|
1173
1200
|
|
|
1174
|
-
const blocklet1 = await states.blocklet.setBlockletStatus(did, BlockletStatus.downloading);
|
|
1175
|
-
this.emit(BlockletEvents.statusChange, blocklet1);
|
|
1176
|
-
|
|
1177
1201
|
preDownloadLock.release();
|
|
1178
1202
|
|
|
1179
1203
|
const { isCancelled } = await this._downloadBlocklet(blocklet, oldBlocklet);
|
|
@@ -1319,14 +1343,15 @@ class BlockletManager extends BaseBlockletManager {
|
|
|
1319
1343
|
const blocklet = await states.blocklet.getBlocklet(did);
|
|
1320
1344
|
const nodeInfo = await states.node.read();
|
|
1321
1345
|
|
|
1322
|
-
const rootSystemEnvironments =
|
|
1323
|
-
|
|
1346
|
+
const rootSystemEnvironments = {
|
|
1347
|
+
...getRootSystemEnvironments(blockletWithEnv, nodeInfo),
|
|
1348
|
+
...getOverwrittenEnvironments(blockletWithEnv, nodeInfo),
|
|
1349
|
+
};
|
|
1324
1350
|
|
|
1325
1351
|
// fill environments to blocklet and blocklet.children
|
|
1326
1352
|
blocklet.environments = formatEnvironments({
|
|
1327
1353
|
...getSystemEnvironments(blockletWithEnv),
|
|
1328
1354
|
...rootSystemEnvironments,
|
|
1329
|
-
...overwrittenEnvironments,
|
|
1330
1355
|
});
|
|
1331
1356
|
|
|
1332
1357
|
for (const child of blocklet.children) {
|
|
@@ -1335,11 +1360,13 @@ class BlockletManager extends BaseBlockletManager {
|
|
|
1335
1360
|
child.environments = formatEnvironments({
|
|
1336
1361
|
...getSystemEnvironments(childWithEnv), // system env of child blocklet
|
|
1337
1362
|
...rootSystemEnvironments, // system env of root blocklet
|
|
1338
|
-
...overwrittenEnvironments,
|
|
1339
1363
|
});
|
|
1340
1364
|
}
|
|
1341
1365
|
}
|
|
1342
1366
|
|
|
1367
|
+
// put BLOCKLET_APP_ID at root level for indexing
|
|
1368
|
+
blocklet.appDid = rootSystemEnvironments.BLOCKLET_APP_ID;
|
|
1369
|
+
|
|
1343
1370
|
// update state to db
|
|
1344
1371
|
return states.blocklet.updateBlocklet(did, blocklet);
|
|
1345
1372
|
}
|
|
@@ -1360,23 +1387,21 @@ class BlockletManager extends BaseBlockletManager {
|
|
|
1360
1387
|
|
|
1361
1388
|
const registryUrl = registry || (await states.node.getBlockletRegistry());
|
|
1362
1389
|
const info = await BlockletRegistry.getRegistryMeta(registryUrl);
|
|
1363
|
-
const
|
|
1364
|
-
if (!
|
|
1390
|
+
const meta = await this.registry.getBlocklet(did, registryUrl);
|
|
1391
|
+
if (!meta) {
|
|
1365
1392
|
throw new Error('Can not install blocklet that not found in registry');
|
|
1366
1393
|
}
|
|
1367
1394
|
|
|
1368
|
-
const state = await states.blocklet.getBlocklet(
|
|
1395
|
+
const state = await states.blocklet.getBlocklet(meta.did);
|
|
1369
1396
|
if (state) {
|
|
1370
1397
|
throw new Error('Can not install an already installed blocklet');
|
|
1371
1398
|
}
|
|
1372
1399
|
|
|
1373
|
-
|
|
1374
|
-
throw new Error('Can not install a non-free blocklet directly');
|
|
1375
|
-
}
|
|
1400
|
+
verifyPurchase(meta, context);
|
|
1376
1401
|
|
|
1377
1402
|
// install
|
|
1378
1403
|
return this._install({
|
|
1379
|
-
meta
|
|
1404
|
+
meta,
|
|
1380
1405
|
source: BlockletSource.registry,
|
|
1381
1406
|
deployedFrom: info.cdnUrl || registryUrl,
|
|
1382
1407
|
context,
|
|
@@ -1426,6 +1451,12 @@ class BlockletManager extends BaseBlockletManager {
|
|
|
1426
1451
|
throw new Error('Cannot add self as a component');
|
|
1427
1452
|
}
|
|
1428
1453
|
|
|
1454
|
+
if (!isComponentBlocklet(meta)) {
|
|
1455
|
+
throw new Error('The blocklet cannot be a component');
|
|
1456
|
+
}
|
|
1457
|
+
|
|
1458
|
+
verifyPurchase(meta, context);
|
|
1459
|
+
|
|
1429
1460
|
const newChildren = await parseChildren(blocklet.meta, {
|
|
1430
1461
|
children: [
|
|
1431
1462
|
{
|
|
@@ -1439,10 +1470,14 @@ class BlockletManager extends BaseBlockletManager {
|
|
|
1439
1470
|
|
|
1440
1471
|
checkDuplicateComponents(blocklet.children, newChildren);
|
|
1441
1472
|
|
|
1473
|
+
// add component to db
|
|
1474
|
+
await states.blocklet.addChildren(rootDid, newChildren);
|
|
1475
|
+
|
|
1442
1476
|
return this.updateChildren(
|
|
1443
1477
|
{
|
|
1444
1478
|
did: rootDid,
|
|
1445
1479
|
children: [...blocklet.children, ...newChildren],
|
|
1480
|
+
oldBlocklet: blocklet,
|
|
1446
1481
|
},
|
|
1447
1482
|
context
|
|
1448
1483
|
);
|
|
@@ -1705,19 +1740,6 @@ class BlockletManager extends BaseBlockletManager {
|
|
|
1705
1740
|
);
|
|
1706
1741
|
}
|
|
1707
1742
|
|
|
1708
|
-
async getStatus(did) {
|
|
1709
|
-
if (!did) {
|
|
1710
|
-
throw new Error('did is required');
|
|
1711
|
-
}
|
|
1712
|
-
|
|
1713
|
-
const blocklet = await states.blocklet.getBlocklet(did);
|
|
1714
|
-
if (!blocklet) {
|
|
1715
|
-
return null;
|
|
1716
|
-
}
|
|
1717
|
-
|
|
1718
|
-
return { name: blocklet.meta.name, did: blocklet.meta.did, status: blocklet.status };
|
|
1719
|
-
}
|
|
1720
|
-
|
|
1721
1743
|
async prune() {
|
|
1722
1744
|
const blocklets = await states.blocklet.getBlocklets();
|
|
1723
1745
|
const settings = await states.blockletExtras.listSettings();
|
|
@@ -2126,7 +2148,7 @@ class BlockletManager extends BaseBlockletManager {
|
|
|
2126
2148
|
// pre install
|
|
2127
2149
|
const nodeEnvironments = await states.node.getEnvironments();
|
|
2128
2150
|
const preInstall = (b) =>
|
|
2129
|
-
hooks.preInstall({
|
|
2151
|
+
hooks.preInstall(b.env.appId, {
|
|
2130
2152
|
hooks: Object.assign(b.meta.hooks || {}, b.meta.scripts || {}),
|
|
2131
2153
|
env: { ...nodeEnvironments },
|
|
2132
2154
|
appDir: b.env.appDir,
|
|
@@ -2142,7 +2164,7 @@ class BlockletManager extends BaseBlockletManager {
|
|
|
2142
2164
|
|
|
2143
2165
|
// post install
|
|
2144
2166
|
const postInstall = (b) =>
|
|
2145
|
-
hooks.postInstall({
|
|
2167
|
+
hooks.postInstall(b.env.appId, {
|
|
2146
2168
|
hooks: Object.assign(b.meta.hooks || {}, b.meta.scripts || {}),
|
|
2147
2169
|
env: getRuntimeEnvironments(b, nodeEnvironments, blocklet),
|
|
2148
2170
|
appDir: b.env.appDir,
|
|
@@ -2155,17 +2177,6 @@ class BlockletManager extends BaseBlockletManager {
|
|
|
2155
2177
|
await states.blocklet.setBlockletStatus(did, BlockletStatus.installed);
|
|
2156
2178
|
blocklet = await this.ensureBlocklet(did);
|
|
2157
2179
|
logger.info('blocklet installed', { source, did: meta.did });
|
|
2158
|
-
if (process.env.NODE_ENV !== 'test') {
|
|
2159
|
-
const nodeInfo = await states.node.read();
|
|
2160
|
-
const blockletInfo = getBlockletInfo(blocklet, nodeInfo.sk);
|
|
2161
|
-
const updateDidDnsResult = await updateDidDocument({
|
|
2162
|
-
wallet: blockletInfo.wallet,
|
|
2163
|
-
domain: nodeInfo.didDomain,
|
|
2164
|
-
nodeDid: nodeInfo.did,
|
|
2165
|
-
didRegistryUrl: nodeInfo.didRegistry,
|
|
2166
|
-
});
|
|
2167
|
-
logger.info('updated did document', { updateDidDnsResult, blockletId: blocklet.meta.did });
|
|
2168
|
-
}
|
|
2169
2180
|
|
|
2170
2181
|
this.emit(BlockletEvents.installed, { blocklet, context });
|
|
2171
2182
|
|
|
@@ -2226,7 +2237,7 @@ class BlockletManager extends BaseBlockletManager {
|
|
|
2226
2237
|
// pre install
|
|
2227
2238
|
const nodeEnvironments = await states.node.getEnvironments();
|
|
2228
2239
|
const preInstall = (b) =>
|
|
2229
|
-
hooks.preInstall({
|
|
2240
|
+
hooks.preInstall(b.env.appId, {
|
|
2230
2241
|
hooks: Object.assign(b.meta.hooks || {}, b.meta.scripts || {}),
|
|
2231
2242
|
env: { ...nodeEnvironments },
|
|
2232
2243
|
appDir: b.env.appDir,
|
|
@@ -2242,7 +2253,7 @@ class BlockletManager extends BaseBlockletManager {
|
|
|
2242
2253
|
|
|
2243
2254
|
// post install
|
|
2244
2255
|
const postInstall = (b) =>
|
|
2245
|
-
hooks.postInstall({
|
|
2256
|
+
hooks.postInstall(b.env.appId, {
|
|
2246
2257
|
hooks: Object.assign(b.meta.hooks || {}, b.meta.scripts || {}),
|
|
2247
2258
|
env: getRuntimeEnvironments(b, nodeEnvironments, blocklet),
|
|
2248
2259
|
appDir: b.env.appDir,
|
|
@@ -2258,10 +2269,10 @@ class BlockletManager extends BaseBlockletManager {
|
|
|
2258
2269
|
if (b.meta.did === did) {
|
|
2259
2270
|
return runMigrationScripts({
|
|
2260
2271
|
blocklet: b,
|
|
2272
|
+
appDir: b.env.appDir,
|
|
2273
|
+
env: getRuntimeEnvironments(b, nodeEnvironments, blocklet),
|
|
2261
2274
|
oldVersion,
|
|
2262
2275
|
newVersion: version,
|
|
2263
|
-
env: getRuntimeEnvironments(b, nodeEnvironments, blocklet),
|
|
2264
|
-
appDir: b.env.appDir,
|
|
2265
2276
|
did: b.meta.did,
|
|
2266
2277
|
notification: states.notification,
|
|
2267
2278
|
context,
|
|
@@ -2288,7 +2299,7 @@ class BlockletManager extends BaseBlockletManager {
|
|
|
2288
2299
|
} else {
|
|
2289
2300
|
const status =
|
|
2290
2301
|
oldBlocklet.status === BlockletStatus.installed ? BlockletStatus.installed : BlockletStatus.stopped;
|
|
2291
|
-
await states.blocklet.setBlockletStatus(did, status);
|
|
2302
|
+
await states.blocklet.setBlockletStatus(did, status, { children: 'all' });
|
|
2292
2303
|
}
|
|
2293
2304
|
|
|
2294
2305
|
blocklet = await this.ensureBlocklet(did, context);
|
|
@@ -2512,10 +2523,7 @@ class BlockletManager extends BaseBlockletManager {
|
|
|
2512
2523
|
} = blocklet;
|
|
2513
2524
|
|
|
2514
2525
|
const metas = [];
|
|
2515
|
-
if (
|
|
2516
|
-
![BlockletSource.upload, BlockletSource.local].includes(blocklet.source) &&
|
|
2517
|
-
get(oldBlocklet, 'meta.dist.integrity') !== get(blocklet, 'meta.dist.integrity')
|
|
2518
|
-
) {
|
|
2526
|
+
if (needBlockletDownload(blocklet)) {
|
|
2519
2527
|
metas.push(blocklet.meta);
|
|
2520
2528
|
}
|
|
2521
2529
|
|
|
@@ -2526,16 +2534,17 @@ class BlockletManager extends BaseBlockletManager {
|
|
|
2526
2534
|
|
|
2527
2535
|
for (const child of blocklet.children) {
|
|
2528
2536
|
const oldChild = oldChildren[child.meta.did];
|
|
2529
|
-
if (
|
|
2530
|
-
!oldChild ||
|
|
2531
|
-
(![BlockletSource.upload, BlockletSource.local].includes(child.source) &&
|
|
2532
|
-
child.sourceUrl &&
|
|
2533
|
-
get(oldChild, 'meta.dist.integrity') !== get(child, 'meta.dist.integrity'))
|
|
2534
|
-
) {
|
|
2537
|
+
if (needBlockletDownload(child, oldChild)) {
|
|
2535
2538
|
metas.push(child.meta);
|
|
2536
2539
|
}
|
|
2537
2540
|
}
|
|
2538
2541
|
|
|
2542
|
+
// update children status
|
|
2543
|
+
const blocklet1 = await states.blocklet.setBlockletStatus(did, BlockletStatus.downloading, {
|
|
2544
|
+
children: metas.map((x) => ({ did: x.did })),
|
|
2545
|
+
});
|
|
2546
|
+
this.emit(BlockletEvents.statusChange, blocklet1);
|
|
2547
|
+
|
|
2539
2548
|
try {
|
|
2540
2549
|
logger.info('Download Blocklet', { name, did, bundles: metas.map((x) => get(x, 'dist.tarball')) });
|
|
2541
2550
|
const tasks = [];
|
|
@@ -1,67 +1,25 @@
|
|
|
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
|
}) {
|
|
66
24
|
let scripts = [];
|
|
67
25
|
try {
|
|
@@ -90,7 +48,11 @@ async function runScripts({
|
|
|
90
48
|
const { script: scriptPath } = pendingScripts[i];
|
|
91
49
|
try {
|
|
92
50
|
printInfo(`Migration script started: ${scriptPath}`);
|
|
93
|
-
await
|
|
51
|
+
await runScript(`node ${path.join(scriptsDir, scriptPath)}`, [blocklet.env.appId, 'migration'].join(':'), {
|
|
52
|
+
cwd: appDir,
|
|
53
|
+
env: getSafeEnv(env),
|
|
54
|
+
silent: false,
|
|
55
|
+
});
|
|
94
56
|
printInfo(`Migration script executed: ${scriptPath}`);
|
|
95
57
|
} catch (migrationErr) {
|
|
96
58
|
printError(`Failed to execute migration script: ${scriptPath}, error: ${migrationErr.message}`);
|
|
@@ -123,6 +85,7 @@ async function doRestore({ dbDir, backupDir, printInfo, printSuccess }) {
|
|
|
123
85
|
}
|
|
124
86
|
|
|
125
87
|
module.exports = async ({
|
|
88
|
+
blocklet,
|
|
126
89
|
appDir,
|
|
127
90
|
env,
|
|
128
91
|
oldVersion,
|
|
@@ -142,15 +105,16 @@ module.exports = async ({
|
|
|
142
105
|
fs.ensureDirSync(backupDir);
|
|
143
106
|
|
|
144
107
|
await runScripts({
|
|
108
|
+
blocklet,
|
|
109
|
+
appDir,
|
|
110
|
+
env,
|
|
111
|
+
oldVersion,
|
|
112
|
+
newVersion,
|
|
145
113
|
dbDir,
|
|
146
114
|
backupDir,
|
|
147
115
|
scriptsDir,
|
|
148
116
|
printError,
|
|
149
117
|
printInfo,
|
|
150
118
|
printSuccess,
|
|
151
|
-
appDir,
|
|
152
|
-
env,
|
|
153
|
-
oldVersion,
|
|
154
|
-
newVersion,
|
|
155
119
|
});
|
|
156
120
|
};
|