@abtnode/core 1.6.14 → 1.6.18
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/hooks.js +16 -63
- package/lib/blocklet/manager/disk.js +426 -144
- package/lib/blocklet/migration.js +16 -52
- package/lib/event.js +1 -1
- package/lib/index.js +3 -11
- package/lib/migrations/1.6.17-blocklet-children.js +48 -0
- package/lib/router/helper.js +33 -19
- package/lib/router/manager.js +64 -42
- package/lib/states/blocklet-extras.js +39 -3
- package/lib/states/blocklet.js +18 -20
- package/lib/states/node.js +17 -2
- package/lib/util/blocklet.js +276 -67
- package/lib/util/default-node-config.js +1 -1
- package/lib/util/get-domain-for-blocklet.js +2 -2
- package/lib/util/router.js +13 -0
- package/lib/validators/node.js +11 -12
- package/lib/validators/permission.js +16 -1
- package/package.json +21 -21
|
@@ -3,30 +3,36 @@
|
|
|
3
3
|
const fs = require('fs-extra');
|
|
4
4
|
const path = require('path');
|
|
5
5
|
const get = require('lodash/get');
|
|
6
|
+
const pick = require('lodash/pick');
|
|
6
7
|
const cloneDeep = require('lodash/cloneDeep');
|
|
7
8
|
const semver = require('semver');
|
|
8
9
|
const capitalize = require('lodash/capitalize');
|
|
9
|
-
const diff = require('deep-diff');
|
|
10
10
|
const { Throttle } = require('stream-throttle');
|
|
11
11
|
const LRU = require('lru-cache');
|
|
12
|
+
const joi = require('joi');
|
|
12
13
|
|
|
13
14
|
const { isValid: isValidDid } = require('@arcblock/did');
|
|
14
15
|
const { verifyPresentation } = require('@arcblock/vc');
|
|
15
|
-
const { toBase58 } = require('@ocap/util');
|
|
16
|
+
const { toBase58, isHex } = require('@ocap/util');
|
|
16
17
|
const { fromSecretKey } = require('@ocap/wallet');
|
|
17
18
|
|
|
18
19
|
const logger = require('@abtnode/logger')('@abtnode/core:blocklet:manager');
|
|
19
|
-
const hashFiles = require('@abtnode/util/lib/hash-files');
|
|
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 { updateBlocklet: updateDidDocument } = require('@abtnode/util/lib/did-document');
|
|
24
23
|
const { BLOCKLET_PURCHASE_NFT_TYPE } = require('@abtnode/constant');
|
|
25
24
|
|
|
26
25
|
const getBlockletEngine = require('@blocklet/meta/lib/engine');
|
|
27
|
-
const {
|
|
26
|
+
const {
|
|
27
|
+
isFreeBlocklet,
|
|
28
|
+
isDeletableBlocklet,
|
|
29
|
+
getRequiredMissingConfigs,
|
|
30
|
+
hasRunnableComponent,
|
|
31
|
+
} = require('@blocklet/meta/lib/util');
|
|
28
32
|
const validateBlockletEntry = require('@blocklet/meta/lib/entry');
|
|
29
|
-
const
|
|
33
|
+
const toBlockletDid = require('@blocklet/meta/lib/did');
|
|
34
|
+
const { validateMeta } = require('@blocklet/meta/lib/validate');
|
|
35
|
+
const { update: updateMetaFile } = require('@blocklet/meta/lib/file');
|
|
30
36
|
|
|
31
37
|
const {
|
|
32
38
|
BlockletStatus,
|
|
@@ -37,6 +43,15 @@ const {
|
|
|
37
43
|
BlockletGroup,
|
|
38
44
|
fromBlockletStatus,
|
|
39
45
|
fromBlockletSource,
|
|
46
|
+
BLOCKLET_DEFAULT_PORT_NAME,
|
|
47
|
+
BLOCKLET_INTERFACE_TYPE_WEB,
|
|
48
|
+
BLOCKLET_INTERFACE_PUBLIC,
|
|
49
|
+
BLOCKLET_DYNAMIC_PATH_PREFIX,
|
|
50
|
+
BLOCKLET_INTERFACE_PROTOCOL_HTTP,
|
|
51
|
+
BLOCKLET_DEFAULT_PATH_REWRITE,
|
|
52
|
+
BLOCKLET_DEFAULT_VERSION,
|
|
53
|
+
BLOCKLET_LATEST_SPEC_VERSION,
|
|
54
|
+
BLOCKLET_META_FILE,
|
|
40
55
|
} = require('@blocklet/meta/lib/constants');
|
|
41
56
|
const util = require('../../util');
|
|
42
57
|
const {
|
|
@@ -60,16 +75,19 @@ const {
|
|
|
60
75
|
getBlockletStatusFromProcess,
|
|
61
76
|
checkBlockletProcessHealthy,
|
|
62
77
|
validateBlocklet,
|
|
63
|
-
getChildrenMeta,
|
|
64
78
|
statusMap,
|
|
65
79
|
expandTarball,
|
|
66
80
|
verifyIntegrity,
|
|
67
81
|
pruneBlockletBundle,
|
|
68
82
|
getDiskInfo,
|
|
69
83
|
getRuntimeInfo,
|
|
70
|
-
mergeMeta,
|
|
71
84
|
getUpdateMetaList,
|
|
72
85
|
getRuntimeEnvironments,
|
|
86
|
+
getSourceFromInstallParams,
|
|
87
|
+
parseChildren,
|
|
88
|
+
checkDuplicateComponents,
|
|
89
|
+
getDiffFiles,
|
|
90
|
+
getBundleDir,
|
|
73
91
|
} = require('../../util/blocklet');
|
|
74
92
|
const states = require('../../states');
|
|
75
93
|
const BlockletRegistry = require('../registry');
|
|
@@ -153,20 +171,43 @@ class BlockletManager extends BaseBlockletManager {
|
|
|
153
171
|
*/
|
|
154
172
|
async install(params, context) {
|
|
155
173
|
logger.debug('install blocklet', { params, context });
|
|
156
|
-
|
|
174
|
+
|
|
175
|
+
const source = getSourceFromInstallParams(params);
|
|
176
|
+
|
|
177
|
+
if (source === BlockletSource.url) {
|
|
157
178
|
return this._installFromUrl({ url: params.url, sync: params.sync }, context);
|
|
158
179
|
}
|
|
159
180
|
|
|
160
|
-
if (
|
|
181
|
+
if (source === BlockletSource.upload) {
|
|
161
182
|
const { file, did, diffVersion, deleteSet } = params;
|
|
162
183
|
return this._installFromUpload({ file, did, diffVersion, deleteSet, context });
|
|
163
184
|
}
|
|
164
185
|
|
|
165
|
-
if (
|
|
166
|
-
return this.
|
|
186
|
+
if (source === BlockletSource.registry) {
|
|
187
|
+
return this._installFromStore({ did: params.did }, context);
|
|
188
|
+
}
|
|
189
|
+
|
|
190
|
+
if (source === BlockletSource.custom) {
|
|
191
|
+
return this._installFromCreate({ title: params.title, description: params.description }, context);
|
|
192
|
+
}
|
|
193
|
+
|
|
194
|
+
// should not be here
|
|
195
|
+
throw new Error('Unknown source');
|
|
196
|
+
}
|
|
197
|
+
|
|
198
|
+
async installComponent({ rootDid, mountPoint, url, file, did, diffVersion, deleteSet }, context = {}) {
|
|
199
|
+
logger.debug('start install component', { rootDid, mountPoint, url });
|
|
200
|
+
|
|
201
|
+
if (file) {
|
|
202
|
+
return this._installComponentFromUpload({ rootDid, mountPoint, file, did, diffVersion, deleteSet, context });
|
|
203
|
+
}
|
|
204
|
+
|
|
205
|
+
if (url) {
|
|
206
|
+
return this._installComponentFromUrl({ rootDid, mountPoint, url, context });
|
|
167
207
|
}
|
|
168
208
|
|
|
169
|
-
|
|
209
|
+
// should not be here
|
|
210
|
+
throw new Error('Unknown source');
|
|
170
211
|
}
|
|
171
212
|
|
|
172
213
|
// eslint-disable-next-line no-unused-vars
|
|
@@ -189,9 +230,9 @@ class BlockletManager extends BaseBlockletManager {
|
|
|
189
230
|
}
|
|
190
231
|
}
|
|
191
232
|
|
|
192
|
-
|
|
233
|
+
const blocklet = await states.blocklet.getBlocklet(meta.did);
|
|
193
234
|
|
|
194
|
-
return meta;
|
|
235
|
+
return { meta, isFree, isInstalled: !!blocklet };
|
|
195
236
|
}
|
|
196
237
|
|
|
197
238
|
async installBlockletFromVc({ vcPresentation, challenge }, context) {
|
|
@@ -210,7 +251,7 @@ class BlockletManager extends BaseBlockletManager {
|
|
|
210
251
|
const did = get(vc, 'credentialSubject.purchased.blocklet.id');
|
|
211
252
|
const registry = urlObject.origin;
|
|
212
253
|
|
|
213
|
-
return this.
|
|
254
|
+
return this._installFromStore({ did, registry }, { ...context, blockletPurchaseVerified: true });
|
|
214
255
|
}
|
|
215
256
|
|
|
216
257
|
async start({ did, checkHealthImmediately = false, throwOnError }, context) {
|
|
@@ -218,6 +259,10 @@ class BlockletManager extends BaseBlockletManager {
|
|
|
218
259
|
const blocklet = await this.ensureBlocklet(did);
|
|
219
260
|
|
|
220
261
|
try {
|
|
262
|
+
if (!hasRunnableComponent(blocklet)) {
|
|
263
|
+
throw new Error('No runnable component found');
|
|
264
|
+
}
|
|
265
|
+
|
|
221
266
|
// check required config
|
|
222
267
|
const missingProps = getRequiredMissingConfigs(blocklet);
|
|
223
268
|
if (missingProps.length) {
|
|
@@ -246,7 +291,6 @@ class BlockletManager extends BaseBlockletManager {
|
|
|
246
291
|
hooks: Object.assign(b.meta.hooks || {}, b.meta.scripts || {}),
|
|
247
292
|
env: getRuntimeEnvironments(b, nodeEnvironments, blocklet),
|
|
248
293
|
did, // root blocklet did,
|
|
249
|
-
progress: blocklet.mode === BLOCKLET_MODES.DEVELOPMENT,
|
|
250
294
|
}),
|
|
251
295
|
nodeEnvironments,
|
|
252
296
|
nodeInfo: await states.node.read(),
|
|
@@ -297,7 +341,7 @@ class BlockletManager extends BaseBlockletManager {
|
|
|
297
341
|
}
|
|
298
342
|
}
|
|
299
343
|
|
|
300
|
-
async stop({ did, updateStatus = true }, context) {
|
|
344
|
+
async stop({ did, updateStatus = true, silent = false }, context) {
|
|
301
345
|
logger.info('stop blocklet', { did });
|
|
302
346
|
|
|
303
347
|
const blocklet = await this.ensureBlocklet(did);
|
|
@@ -313,7 +357,7 @@ class BlockletManager extends BaseBlockletManager {
|
|
|
313
357
|
|
|
314
358
|
await stopBlockletProcess(blocklet, {
|
|
315
359
|
preStop: (b) =>
|
|
316
|
-
hooks.preStop({
|
|
360
|
+
hooks.preStop(b.env.appId, {
|
|
317
361
|
appDir: b.env.appDir,
|
|
318
362
|
hooks: Object.assign(b.meta.hooks || {}, b.meta.scripts || {}),
|
|
319
363
|
env: getRuntimeEnvironments(b, nodeEnvironments, blocklet),
|
|
@@ -321,7 +365,7 @@ class BlockletManager extends BaseBlockletManager {
|
|
|
321
365
|
notification: states.notification,
|
|
322
366
|
context,
|
|
323
367
|
exitOnError: false,
|
|
324
|
-
|
|
368
|
+
silent,
|
|
325
369
|
}),
|
|
326
370
|
});
|
|
327
371
|
|
|
@@ -389,7 +433,7 @@ class BlockletManager extends BaseBlockletManager {
|
|
|
389
433
|
|
|
390
434
|
await deleteBlockletProcess(blocklet, {
|
|
391
435
|
preDelete: (b) =>
|
|
392
|
-
hooks.preUninstall({
|
|
436
|
+
hooks.preUninstall(b.env.appId, {
|
|
393
437
|
appDir: b.env.appDir,
|
|
394
438
|
hooks: Object.assign(b.meta.hooks || {}, b.meta.scripts || {}),
|
|
395
439
|
env: getRuntimeEnvironments(b, nodeEnvironments, blocklet),
|
|
@@ -412,6 +456,22 @@ class BlockletManager extends BaseBlockletManager {
|
|
|
412
456
|
}
|
|
413
457
|
}
|
|
414
458
|
|
|
459
|
+
async deleteComponent({ did, rootDid }, context) {
|
|
460
|
+
logger.info('delete blocklet component', { did, rootDid });
|
|
461
|
+
|
|
462
|
+
const doc = await states.blocklet.getBlocklet(rootDid);
|
|
463
|
+
|
|
464
|
+
doc.children = doc.children.filter((x) => x.meta.did !== did);
|
|
465
|
+
const children = (await this._getDynamicChildrenFromSettings(rootDid)).filter((x) => x.meta.did !== did);
|
|
466
|
+
|
|
467
|
+
await states.blocklet.updateBlocklet(rootDid, doc);
|
|
468
|
+
states.blockletExtras.setSettings(rootDid, { children });
|
|
469
|
+
|
|
470
|
+
const newBlocklet = await this.ensureBlocklet(rootDid);
|
|
471
|
+
this.emit(BlockletEvents.upgraded, { blocklet: newBlocklet, context }); // trigger router refresh
|
|
472
|
+
return newBlocklet;
|
|
473
|
+
}
|
|
474
|
+
|
|
415
475
|
async cancelDownload({ did }, context) {
|
|
416
476
|
await preDownloadLock.acquire();
|
|
417
477
|
try {
|
|
@@ -449,12 +509,14 @@ class BlockletManager extends BaseBlockletManager {
|
|
|
449
509
|
return result;
|
|
450
510
|
}
|
|
451
511
|
|
|
452
|
-
async detail({ did, attachRuntimeInfo = true }, context) {
|
|
512
|
+
async detail({ did, attachConfig = true, attachRuntimeInfo = true }, context) {
|
|
453
513
|
if (!did) {
|
|
454
514
|
throw new Error('did should not be empty');
|
|
455
515
|
}
|
|
456
516
|
|
|
457
|
-
|
|
517
|
+
if (!attachConfig) {
|
|
518
|
+
return states.blocklet.getBlocklet(did);
|
|
519
|
+
}
|
|
458
520
|
|
|
459
521
|
if (!attachRuntimeInfo) {
|
|
460
522
|
try {
|
|
@@ -465,6 +527,8 @@ class BlockletManager extends BaseBlockletManager {
|
|
|
465
527
|
}
|
|
466
528
|
}
|
|
467
529
|
|
|
530
|
+
const nodeInfo = await states.node.read();
|
|
531
|
+
|
|
468
532
|
return this.attachRuntimeInfo({ did, nodeInfo, diskInfo: true, context });
|
|
469
533
|
}
|
|
470
534
|
|
|
@@ -549,19 +613,25 @@ class BlockletManager extends BaseBlockletManager {
|
|
|
549
613
|
}
|
|
550
614
|
}
|
|
551
615
|
|
|
616
|
+
if (x.key === 'BLOCKLET_PASSPORT_COLOR') {
|
|
617
|
+
if (x.value && x.value !== 'auto') {
|
|
618
|
+
if (x.value.length !== 7 || !isHex(x.value.slice(-6))) {
|
|
619
|
+
throw new Error('BLOCKLET_PASSPORT_COLOR must be a hex encoded color, eg. #ffeeaa');
|
|
620
|
+
}
|
|
621
|
+
}
|
|
622
|
+
}
|
|
623
|
+
|
|
552
624
|
blocklet.configObj[x.key] = x.value;
|
|
553
625
|
}
|
|
554
626
|
|
|
555
627
|
// FIXME: we should also call preConfig for child blocklets
|
|
556
|
-
await hooks.preConfig({
|
|
628
|
+
await hooks.preConfig(blocklet.env.appId, {
|
|
557
629
|
appDir: blocklet.env.appDir,
|
|
558
630
|
hooks: Object.assign(blocklet.meta.hooks || {}, blocklet.meta.scripts || {}),
|
|
559
631
|
exitOnError: true,
|
|
560
632
|
env: { ...getRuntimeEnvironments(blocklet, nodeEnvironments), ...blocklet.configObj },
|
|
561
|
-
notification: states.notification,
|
|
562
633
|
did,
|
|
563
634
|
context,
|
|
564
|
-
progress: blocklet.mode === BLOCKLET_MODES.DEVELOPMENT,
|
|
565
635
|
});
|
|
566
636
|
|
|
567
637
|
// update db
|
|
@@ -657,56 +727,45 @@ class BlockletManager extends BaseBlockletManager {
|
|
|
657
727
|
}
|
|
658
728
|
|
|
659
729
|
// eslint-disable-next-line no-unused-vars
|
|
660
|
-
async diff({ did, hashFiles: clientFiles }, context) {
|
|
730
|
+
async diff({ did, hashFiles: clientFiles, rootDid: inputRootDid }, context) {
|
|
661
731
|
if (!did) {
|
|
662
732
|
throw new Error('did is empty');
|
|
663
733
|
}
|
|
734
|
+
|
|
664
735
|
if (!clientFiles || !clientFiles.length) {
|
|
665
736
|
throw new Error('hashFiles is empty');
|
|
666
737
|
}
|
|
667
738
|
|
|
668
|
-
|
|
739
|
+
const rootDid = inputRootDid || did;
|
|
740
|
+
const childDid = inputRootDid ? did : '';
|
|
741
|
+
|
|
742
|
+
if (childDid === rootDid) {
|
|
743
|
+
throw new Error('Cannot add self as a component');
|
|
744
|
+
}
|
|
745
|
+
|
|
746
|
+
logger.info('Get blocklet diff', { rootDid, childDid, clientFilesNumber: clientFiles.length });
|
|
747
|
+
|
|
748
|
+
const rootBlocklet = await states.blocklet.getBlocklet(rootDid);
|
|
749
|
+
if (childDid && !rootBlocklet) {
|
|
750
|
+
throw new Error('Root blocklet does not exist');
|
|
751
|
+
}
|
|
752
|
+
|
|
753
|
+
const state = childDid ? await (rootBlocklet.children || []).find((x) => x.meta.did === childDid) : rootBlocklet;
|
|
669
754
|
|
|
670
|
-
const state = await states.blocklet.getBlocklet(did);
|
|
671
755
|
if (!state) {
|
|
672
756
|
return {
|
|
673
757
|
hasBlocklet: false,
|
|
674
758
|
};
|
|
675
759
|
}
|
|
760
|
+
|
|
676
761
|
if (state.source === BlockletSource.local) {
|
|
677
762
|
throw new Error(`Blocklet ${state.meta.name} is already deployed from local, can not deployed from remote.`);
|
|
678
763
|
}
|
|
679
|
-
const { name, version } = state.meta;
|
|
680
|
-
const installDir = path.join(this.installDir, name, version);
|
|
681
|
-
// eslint-disable-next-line no-param-reassign
|
|
682
|
-
clientFiles = clientFiles.reduce((obj, item) => {
|
|
683
|
-
obj[item.file] = item.hash;
|
|
684
|
-
return obj;
|
|
685
|
-
}, {});
|
|
686
764
|
|
|
687
|
-
const {
|
|
688
|
-
|
|
689
|
-
|
|
690
|
-
|
|
691
|
-
logger.info('Get files hash', { filesNum: Object.keys(files).length });
|
|
692
|
-
|
|
693
|
-
const addSet = [];
|
|
694
|
-
const changeSet = [];
|
|
695
|
-
const deleteSet = [];
|
|
696
|
-
const diffFiles = diff(files, clientFiles);
|
|
697
|
-
if (diffFiles) {
|
|
698
|
-
diffFiles.forEach((item) => {
|
|
699
|
-
if (item.kind === 'D') {
|
|
700
|
-
deleteSet.push(item.path[0]);
|
|
701
|
-
}
|
|
702
|
-
if (item.kind === 'E') {
|
|
703
|
-
changeSet.push(item.path[0]);
|
|
704
|
-
}
|
|
705
|
-
if (item.kind === 'N') {
|
|
706
|
-
addSet.push(item.path[0]);
|
|
707
|
-
}
|
|
708
|
-
});
|
|
709
|
-
}
|
|
765
|
+
const { version } = state.meta;
|
|
766
|
+
const bundleDir = getBundleDir(this.installDir, state.meta);
|
|
767
|
+
const { addSet, changeSet, deleteSet } = await getDiffFiles(clientFiles, bundleDir);
|
|
768
|
+
|
|
710
769
|
logger.info('Diff files', {
|
|
711
770
|
name: state.meta.name,
|
|
712
771
|
did: state.meta.did,
|
|
@@ -715,6 +774,7 @@ class BlockletManager extends BaseBlockletManager {
|
|
|
715
774
|
changeNum: changeSet.length,
|
|
716
775
|
deleteNum: deleteSet.length,
|
|
717
776
|
});
|
|
777
|
+
|
|
718
778
|
return {
|
|
719
779
|
hasBlocklet: true,
|
|
720
780
|
version,
|
|
@@ -726,10 +786,20 @@ class BlockletManager extends BaseBlockletManager {
|
|
|
726
786
|
|
|
727
787
|
async checkChildrenForUpdates({ did }) {
|
|
728
788
|
const blocklet = await states.blocklet.getBlocklet(did);
|
|
729
|
-
const
|
|
789
|
+
const newStaticChildren = await parseChildren(blocklet.meta);
|
|
790
|
+
|
|
791
|
+
const oldDynamicChildren = await this._getDynamicChildrenFromSettings(did);
|
|
792
|
+
const noneSourceUrlChildren = oldDynamicChildren.filter((x) => !x.sourceUrl);
|
|
793
|
+
const dynamicConfig = oldDynamicChildren
|
|
794
|
+
.filter((x) => x.sourceUrl)
|
|
795
|
+
.map((x) => ({ resolved: x.sourceUrl, name: x.meta.name, mountPoint: x.mountPoint }));
|
|
796
|
+
const newDynamicChildren = [...noneSourceUrlChildren, ...(await parseChildren(dynamicConfig, { dynamic: true }))];
|
|
797
|
+
|
|
798
|
+
checkDuplicateComponents(newDynamicChildren, newStaticChildren);
|
|
799
|
+
|
|
730
800
|
const updateList = getUpdateMetaList(
|
|
731
|
-
blocklet.children.map((x) => x.meta),
|
|
732
|
-
|
|
801
|
+
[...blocklet.children.map((x) => x.meta), ...oldDynamicChildren.map((x) => x.meta)],
|
|
802
|
+
[...newStaticChildren.map((x) => x.meta), ...newDynamicChildren.map((x) => x.meta)]
|
|
733
803
|
);
|
|
734
804
|
|
|
735
805
|
if (!updateList.length) {
|
|
@@ -739,7 +809,8 @@ class BlockletManager extends BaseBlockletManager {
|
|
|
739
809
|
// start session
|
|
740
810
|
const { id: updateId } = await states.session.start({
|
|
741
811
|
did,
|
|
742
|
-
|
|
812
|
+
staticChildren: newStaticChildren,
|
|
813
|
+
dynamicChildren: newDynamicChildren,
|
|
743
814
|
});
|
|
744
815
|
|
|
745
816
|
return {
|
|
@@ -748,8 +819,18 @@ class BlockletManager extends BaseBlockletManager {
|
|
|
748
819
|
};
|
|
749
820
|
}
|
|
750
821
|
|
|
751
|
-
async updateChildren({ updateId }, context) {
|
|
752
|
-
|
|
822
|
+
async updateChildren({ updateId, did: inputDid, children: inputChildren }, context) {
|
|
823
|
+
let did;
|
|
824
|
+
let children;
|
|
825
|
+
if (!updateId && inputDid && inputChildren) {
|
|
826
|
+
did = inputDid;
|
|
827
|
+
children = inputChildren;
|
|
828
|
+
} else {
|
|
829
|
+
const sessionData = await states.session.end(updateId);
|
|
830
|
+
did = sessionData.did;
|
|
831
|
+
const { staticChildren = [], dynamicChildren = [] } = sessionData;
|
|
832
|
+
children = [...staticChildren, ...dynamicChildren.map((x) => ({ ...x, dynamic: true }))];
|
|
833
|
+
}
|
|
753
834
|
|
|
754
835
|
// get old blocklet
|
|
755
836
|
const oldBlocklet = await states.blocklet.getBlocklet(did);
|
|
@@ -762,14 +843,13 @@ class BlockletManager extends BaseBlockletManager {
|
|
|
762
843
|
did,
|
|
763
844
|
name,
|
|
764
845
|
version,
|
|
765
|
-
children:
|
|
846
|
+
children: children.map((x) => ({ name: x.meta.name, version: x.meta.version })),
|
|
766
847
|
});
|
|
767
848
|
|
|
768
849
|
// new blocklet
|
|
769
850
|
const newBlocklet = await states.blocklet.setBlockletStatus(did, BlockletStatus.waiting);
|
|
770
|
-
|
|
771
|
-
newBlocklet.
|
|
772
|
-
newBlocklet.children = await states.blocklet.getChildrenFromMetas(childrenMeta);
|
|
851
|
+
|
|
852
|
+
newBlocklet.children = children;
|
|
773
853
|
await validateBlocklet(newBlocklet);
|
|
774
854
|
|
|
775
855
|
this.emit(BlockletEvents.statusChange, newBlocklet);
|
|
@@ -807,6 +887,11 @@ class BlockletManager extends BaseBlockletManager {
|
|
|
807
887
|
// ============================================================================================
|
|
808
888
|
// Internal API that are used by public APIs and called from CLI
|
|
809
889
|
// ============================================================================================
|
|
890
|
+
|
|
891
|
+
/**
|
|
892
|
+
* After the dev function finished, the caller should send a BlockletEvents.deployed event to the daemon
|
|
893
|
+
* @returns {Object} blocklet
|
|
894
|
+
*/
|
|
810
895
|
async dev(folder) {
|
|
811
896
|
logger.info('dev blocklet', { folder });
|
|
812
897
|
|
|
@@ -839,30 +924,33 @@ class BlockletManager extends BaseBlockletManager {
|
|
|
839
924
|
await this.deleteProcess({ did });
|
|
840
925
|
logger.info('delete blocklet precess for dev', { did, version });
|
|
841
926
|
} catch (err) {
|
|
842
|
-
|
|
927
|
+
if (process.env.NODE_ENV !== 'development') {
|
|
928
|
+
logger.error('failed to delete blocklet process for dev', { error: err });
|
|
929
|
+
}
|
|
843
930
|
}
|
|
844
931
|
|
|
845
|
-
const
|
|
846
|
-
|
|
847
|
-
const blocklet = await states.blocklet.addBlocklet({
|
|
932
|
+
const children = await this._getChildren(meta);
|
|
933
|
+
const added = await states.blocklet.addBlocklet({
|
|
848
934
|
did,
|
|
849
935
|
meta,
|
|
850
936
|
source: BlockletSource.local,
|
|
851
937
|
deployedFrom: folder,
|
|
852
938
|
mode: BLOCKLET_MODES.DEVELOPMENT,
|
|
853
|
-
|
|
939
|
+
children,
|
|
854
940
|
});
|
|
855
941
|
logger.info('add blocklet for dev', { did, version, meta });
|
|
856
942
|
|
|
857
|
-
|
|
943
|
+
const oldBlocklet = { children: children.filter((x) => x.dynamic) }; // let downloader skip re-downloading dynamic blocklet
|
|
944
|
+
await this._downloadBlocklet(added, oldBlocklet);
|
|
858
945
|
await states.blocklet.setBlockletStatus(did, BlockletStatus.installed);
|
|
859
946
|
|
|
860
947
|
// Add environments
|
|
861
948
|
await this._setConfigs(did);
|
|
862
949
|
await this.updateBlockletEnvironment(did);
|
|
863
950
|
|
|
864
|
-
|
|
865
|
-
|
|
951
|
+
const blocklet = await this.ensureBlocklet(did);
|
|
952
|
+
|
|
953
|
+
return blocklet;
|
|
866
954
|
}
|
|
867
955
|
|
|
868
956
|
async ensureBlocklet(did) {
|
|
@@ -997,7 +1085,8 @@ class BlockletManager extends BaseBlockletManager {
|
|
|
997
1085
|
blocklet.diskInfo = await getDiskInfo(blocklet, { useFakeDiskInfo: !diskInfo });
|
|
998
1086
|
|
|
999
1087
|
try {
|
|
1000
|
-
const
|
|
1088
|
+
const app = blocklet.meta.group === BlockletGroup.gateway ? blocklet.children[0].env : blocklet.env;
|
|
1089
|
+
const { appId } = app;
|
|
1001
1090
|
blocklet.runtimeInfo = await getRuntimeInfo(appId);
|
|
1002
1091
|
if (blocklet.runtimeInfo.status && shouldUpdateBlockletStatus(blocklet.status)) {
|
|
1003
1092
|
blocklet.status = statusMap[blocklet.runtimeInfo.status];
|
|
@@ -1271,7 +1360,7 @@ class BlockletManager extends BaseBlockletManager {
|
|
|
1271
1360
|
}
|
|
1272
1361
|
}
|
|
1273
1362
|
|
|
1274
|
-
async
|
|
1363
|
+
async _installFromStore({ did, registry }, context) {
|
|
1275
1364
|
logger.debug('start install blocklet', { did });
|
|
1276
1365
|
if (!isValidDid(did)) {
|
|
1277
1366
|
throw new Error('Blocklet did is invalid');
|
|
@@ -1333,9 +1422,84 @@ class BlockletManager extends BaseBlockletManager {
|
|
|
1333
1422
|
});
|
|
1334
1423
|
}
|
|
1335
1424
|
|
|
1336
|
-
async
|
|
1337
|
-
|
|
1338
|
-
|
|
1425
|
+
async _installComponentFromUrl({ rootDid, mountPoint, url, context }) {
|
|
1426
|
+
const blocklet = await states.blocklet.getBlocklet(rootDid);
|
|
1427
|
+
if (!blocklet) {
|
|
1428
|
+
throw new Error('Root blocklet does not exist');
|
|
1429
|
+
}
|
|
1430
|
+
|
|
1431
|
+
const meta = await getBlockletMetaFromUrl(url);
|
|
1432
|
+
|
|
1433
|
+
if (meta.did === rootDid) {
|
|
1434
|
+
throw new Error('Cannot add self as a component');
|
|
1435
|
+
}
|
|
1436
|
+
|
|
1437
|
+
const newChildren = await parseChildren(blocklet.meta, {
|
|
1438
|
+
children: [
|
|
1439
|
+
{
|
|
1440
|
+
meta,
|
|
1441
|
+
mountPoint,
|
|
1442
|
+
sourceUrl: url,
|
|
1443
|
+
},
|
|
1444
|
+
],
|
|
1445
|
+
dynamic: true,
|
|
1446
|
+
});
|
|
1447
|
+
|
|
1448
|
+
checkDuplicateComponents(blocklet.children, newChildren);
|
|
1449
|
+
|
|
1450
|
+
return this.updateChildren(
|
|
1451
|
+
{
|
|
1452
|
+
did: rootDid,
|
|
1453
|
+
children: [...blocklet.children, ...newChildren],
|
|
1454
|
+
},
|
|
1455
|
+
context
|
|
1456
|
+
);
|
|
1457
|
+
}
|
|
1458
|
+
|
|
1459
|
+
async _installFromCreate({ title, description }, context = {}) {
|
|
1460
|
+
logger.debug('create blocklet', { title, description });
|
|
1461
|
+
|
|
1462
|
+
await joi.string().label('title').max(20).required().validateAsync(title);
|
|
1463
|
+
await joi.string().label('description').max(80).required().validateAsync(description);
|
|
1464
|
+
|
|
1465
|
+
const { did, name } = await this._findNextCustomBlockletName();
|
|
1466
|
+
const rawMeta = {
|
|
1467
|
+
name,
|
|
1468
|
+
did,
|
|
1469
|
+
title,
|
|
1470
|
+
description,
|
|
1471
|
+
version: BLOCKLET_DEFAULT_VERSION,
|
|
1472
|
+
group: BlockletGroup.gateway,
|
|
1473
|
+
interfaces: [
|
|
1474
|
+
{
|
|
1475
|
+
type: BLOCKLET_INTERFACE_TYPE_WEB,
|
|
1476
|
+
name: BLOCKLET_INTERFACE_PUBLIC,
|
|
1477
|
+
path: BLOCKLET_DEFAULT_PATH_REWRITE,
|
|
1478
|
+
prefix: BLOCKLET_DYNAMIC_PATH_PREFIX,
|
|
1479
|
+
port: BLOCKLET_DEFAULT_PORT_NAME,
|
|
1480
|
+
protocol: BLOCKLET_INTERFACE_PROTOCOL_HTTP,
|
|
1481
|
+
},
|
|
1482
|
+
],
|
|
1483
|
+
specVersion: BLOCKLET_LATEST_SPEC_VERSION,
|
|
1484
|
+
};
|
|
1485
|
+
const meta = validateMeta(rawMeta);
|
|
1486
|
+
|
|
1487
|
+
await states.blocklet.addBlocklet({
|
|
1488
|
+
did: meta.did,
|
|
1489
|
+
meta,
|
|
1490
|
+
source: BlockletSource.custom,
|
|
1491
|
+
});
|
|
1492
|
+
await this._setConfigs(did);
|
|
1493
|
+
|
|
1494
|
+
// fake install bundle
|
|
1495
|
+
const bundleDir = getBundleDir(this.installDir, meta);
|
|
1496
|
+
fs.mkdirSync(bundleDir, { recursive: true });
|
|
1497
|
+
updateMetaFile(path.join(bundleDir, BLOCKLET_META_FILE), meta);
|
|
1498
|
+
|
|
1499
|
+
return this._installBlocklet({ did, context });
|
|
1500
|
+
}
|
|
1501
|
+
|
|
1502
|
+
async _downloadFromUpload(file) {
|
|
1339
1503
|
// const { filename, mimetype, encoding, createReadStream } = await file;
|
|
1340
1504
|
const { filename, createReadStream } = await file;
|
|
1341
1505
|
const cwd = path.join(this.dataDirs.tmp, 'download');
|
|
@@ -1359,6 +1523,13 @@ class BlockletManager extends BaseBlockletManager {
|
|
|
1359
1523
|
writeStream.on('finish', resolve);
|
|
1360
1524
|
});
|
|
1361
1525
|
|
|
1526
|
+
return { cwd, tarFile };
|
|
1527
|
+
}
|
|
1528
|
+
|
|
1529
|
+
async _installFromUpload({ file, did, diffVersion, deleteSet, context }) {
|
|
1530
|
+
logger.info('install blocklet', { from: 'upload file' });
|
|
1531
|
+
const { cwd, tarFile } = await this._downloadFromUpload(file);
|
|
1532
|
+
|
|
1362
1533
|
// diff deploy
|
|
1363
1534
|
if (did && diffVersion) {
|
|
1364
1535
|
const oldBlocklet = await states.blocklet.getBlocklet(did);
|
|
@@ -1379,14 +1550,12 @@ class BlockletManager extends BaseBlockletManager {
|
|
|
1379
1550
|
throw new Error(`Can not deploy blocklet when it is ${fromBlockletStatus(oldBlocklet.status)}`);
|
|
1380
1551
|
}
|
|
1381
1552
|
|
|
1382
|
-
const { meta } = await this._resolveDiffDownload(cwd, tarFile, deleteSet, oldBlocklet);
|
|
1383
|
-
const childrenMeta = await getChildrenMeta(meta);
|
|
1384
|
-
mergeMeta(meta, childrenMeta);
|
|
1553
|
+
const { meta } = await this._resolveDiffDownload(cwd, tarFile, deleteSet, oldBlocklet.meta);
|
|
1385
1554
|
const newBlocklet = await states.blocklet.getBlocklet(did);
|
|
1386
1555
|
newBlocklet.meta = meta;
|
|
1387
1556
|
newBlocklet.source = BlockletSource.upload;
|
|
1388
1557
|
newBlocklet.deployedFrom = `Upload by ${context.user.did}`;
|
|
1389
|
-
newBlocklet.children = await
|
|
1558
|
+
newBlocklet.children = await this._getChildren(meta);
|
|
1390
1559
|
await validateBlocklet(newBlocklet);
|
|
1391
1560
|
await this._downloadBlocklet(newBlocklet, oldBlocklet);
|
|
1392
1561
|
|
|
@@ -1401,19 +1570,18 @@ class BlockletManager extends BaseBlockletManager {
|
|
|
1401
1570
|
const { meta } = await this._resolveDownload(cwd, tarFile);
|
|
1402
1571
|
const oldBlocklet = await states.blocklet.getBlocklet(meta.did);
|
|
1403
1572
|
|
|
1573
|
+
// full deploy - upgrade
|
|
1404
1574
|
if (oldBlocklet) {
|
|
1405
1575
|
if (isInProgress(oldBlocklet.status)) {
|
|
1406
1576
|
logger.error(`Can not deploy blocklet when it is ${fromBlockletStatus(oldBlocklet.status)}`);
|
|
1407
1577
|
throw new Error(`Can not deploy blocklet when it is ${fromBlockletStatus(oldBlocklet.status)}`);
|
|
1408
1578
|
}
|
|
1409
1579
|
|
|
1410
|
-
const childrenMeta = await getChildrenMeta(meta);
|
|
1411
|
-
mergeMeta(meta, childrenMeta);
|
|
1412
1580
|
const newBlocklet = await states.blocklet.getBlocklet(meta.did);
|
|
1413
1581
|
newBlocklet.meta = meta;
|
|
1414
1582
|
newBlocklet.source = BlockletSource.upload;
|
|
1415
1583
|
newBlocklet.deployedFrom = `Upload by ${context.user.did}`;
|
|
1416
|
-
newBlocklet.children = await
|
|
1584
|
+
newBlocklet.children = await this._getChildren(meta);
|
|
1417
1585
|
|
|
1418
1586
|
await validateBlocklet(newBlocklet);
|
|
1419
1587
|
await this._downloadBlocklet(newBlocklet, oldBlocklet);
|
|
@@ -1425,14 +1593,14 @@ class BlockletManager extends BaseBlockletManager {
|
|
|
1425
1593
|
});
|
|
1426
1594
|
}
|
|
1427
1595
|
|
|
1428
|
-
|
|
1429
|
-
|
|
1596
|
+
// full deploy - install
|
|
1597
|
+
const children = await this._getChildren(meta);
|
|
1430
1598
|
const blocklet = await states.blocklet.addBlocklet({
|
|
1431
1599
|
did: meta.did,
|
|
1432
1600
|
meta,
|
|
1433
1601
|
source: BlockletSource.upload,
|
|
1434
1602
|
deployedFrom: `Upload by ${context.user.did}`,
|
|
1435
|
-
|
|
1603
|
+
children,
|
|
1436
1604
|
});
|
|
1437
1605
|
|
|
1438
1606
|
await validateBlocklet(blocklet);
|
|
@@ -1440,13 +1608,92 @@ class BlockletManager extends BaseBlockletManager {
|
|
|
1440
1608
|
await this._setConfigs(meta.did);
|
|
1441
1609
|
|
|
1442
1610
|
// download
|
|
1443
|
-
await this._downloadBlocklet(
|
|
1611
|
+
await this._downloadBlocklet(
|
|
1612
|
+
blocklet,
|
|
1613
|
+
// let downloader skip re-downloading dynamic blocklet
|
|
1614
|
+
{ children: children.filter((x) => x.dynamic) }
|
|
1615
|
+
);
|
|
1444
1616
|
return this._installBlocklet({
|
|
1445
1617
|
did: meta.did,
|
|
1446
1618
|
context,
|
|
1447
1619
|
});
|
|
1448
1620
|
}
|
|
1449
1621
|
|
|
1622
|
+
async _installComponentFromUpload({ rootDid, mountPoint, file, did, diffVersion, deleteSet, context }) {
|
|
1623
|
+
logger.info('install blocklet', { from: 'upload file' });
|
|
1624
|
+
// download
|
|
1625
|
+
const { cwd, tarFile } = await this._downloadFromUpload(file);
|
|
1626
|
+
|
|
1627
|
+
const oldBlocklet = await states.blocklet.getBlocklet(rootDid);
|
|
1628
|
+
if (!oldBlocklet) {
|
|
1629
|
+
throw new Error('Root blocklet does not exist');
|
|
1630
|
+
}
|
|
1631
|
+
|
|
1632
|
+
if (isInProgress(oldBlocklet.status)) {
|
|
1633
|
+
logger.error(`Can not deploy blocklet when it is ${fromBlockletStatus(oldBlocklet.status)}`);
|
|
1634
|
+
throw new Error(`Can not deploy blocklet when it is ${fromBlockletStatus(oldBlocklet.status)}`);
|
|
1635
|
+
}
|
|
1636
|
+
|
|
1637
|
+
let meta;
|
|
1638
|
+
// diff upload
|
|
1639
|
+
if (did && diffVersion) {
|
|
1640
|
+
const oldChild = oldBlocklet.children.find((x) => x.meta.did === did);
|
|
1641
|
+
if (!oldChild) {
|
|
1642
|
+
throw new Error(`Blocklet ${did} not found when diff deploying`);
|
|
1643
|
+
}
|
|
1644
|
+
if (oldChild.meta.version !== diffVersion) {
|
|
1645
|
+
logger.error('Diff deploy: Blocklet version changed', {
|
|
1646
|
+
preVersion: diffVersion,
|
|
1647
|
+
changedVersion: oldChild.meta.version,
|
|
1648
|
+
name: oldChild.meta.name,
|
|
1649
|
+
did: oldChild.meta.did,
|
|
1650
|
+
});
|
|
1651
|
+
throw new Error('Blocklet version changed when diff deploying');
|
|
1652
|
+
}
|
|
1653
|
+
|
|
1654
|
+
meta = (await this._resolveDiffDownload(cwd, tarFile, deleteSet, oldChild.meta)).meta;
|
|
1655
|
+
} else {
|
|
1656
|
+
// full deploy
|
|
1657
|
+
meta = (await this._resolveDownload(cwd, tarFile)).meta;
|
|
1658
|
+
}
|
|
1659
|
+
|
|
1660
|
+
if (meta.did === rootDid) {
|
|
1661
|
+
// should not be here
|
|
1662
|
+
throw new Error('Cannot add self as a component');
|
|
1663
|
+
}
|
|
1664
|
+
|
|
1665
|
+
const newBlocklet = await states.blocklet.getBlocklet(rootDid);
|
|
1666
|
+
const dynamicChildren = await this._getDynamicChildrenFromSettings(rootDid);
|
|
1667
|
+
|
|
1668
|
+
const newChild = {
|
|
1669
|
+
meta,
|
|
1670
|
+
mountPoint,
|
|
1671
|
+
source: BlockletSource.upload,
|
|
1672
|
+
deployedFrom: `Upload by ${context.user.did}`,
|
|
1673
|
+
sourceUrl: '',
|
|
1674
|
+
dynamic: true,
|
|
1675
|
+
};
|
|
1676
|
+
const index = dynamicChildren.findIndex((child) => child.meta.did === meta.did);
|
|
1677
|
+
if (index >= 0) {
|
|
1678
|
+
dynamicChildren.splice(index, 1, newChild);
|
|
1679
|
+
} else {
|
|
1680
|
+
dynamicChildren.push(newChild);
|
|
1681
|
+
}
|
|
1682
|
+
|
|
1683
|
+
const staticChildren = newBlocklet.children.filter((x) => !x.dynamic);
|
|
1684
|
+
checkDuplicateComponents(dynamicChildren, staticChildren);
|
|
1685
|
+
|
|
1686
|
+
newBlocklet.children = [...staticChildren, ...dynamicChildren.map((x) => ({ ...x, dynamic: true }))];
|
|
1687
|
+
|
|
1688
|
+
await validateBlocklet(newBlocklet);
|
|
1689
|
+
|
|
1690
|
+
return this._upgradeBlocklet({
|
|
1691
|
+
oldBlocklet,
|
|
1692
|
+
newBlocklet,
|
|
1693
|
+
context,
|
|
1694
|
+
});
|
|
1695
|
+
}
|
|
1696
|
+
|
|
1450
1697
|
/**
|
|
1451
1698
|
* add to download job queue
|
|
1452
1699
|
* @param {string} did blocklet did
|
|
@@ -1466,22 +1713,16 @@ class BlockletManager extends BaseBlockletManager {
|
|
|
1466
1713
|
);
|
|
1467
1714
|
}
|
|
1468
1715
|
|
|
1469
|
-
async getStatus(did) {
|
|
1470
|
-
if (!did) {
|
|
1471
|
-
throw new Error('did is required');
|
|
1472
|
-
}
|
|
1473
|
-
|
|
1474
|
-
const blocklet = await states.blocklet.getBlocklet(did);
|
|
1475
|
-
if (!blocklet) {
|
|
1476
|
-
return null;
|
|
1477
|
-
}
|
|
1478
|
-
|
|
1479
|
-
return { name: blocklet.meta.name, did: blocklet.meta.did, status: blocklet.status };
|
|
1480
|
-
}
|
|
1481
|
-
|
|
1482
1716
|
async prune() {
|
|
1483
1717
|
const blocklets = await states.blocklet.getBlocklets();
|
|
1484
|
-
await
|
|
1718
|
+
const settings = await states.blockletExtras.listSettings();
|
|
1719
|
+
await pruneBlockletBundle({
|
|
1720
|
+
installDir: this.dataDirs.blocklets,
|
|
1721
|
+
blocklets,
|
|
1722
|
+
blockletSettings: settings
|
|
1723
|
+
.filter((x) => x.settings.children && x.settings.children.length)
|
|
1724
|
+
.map((x) => x.settings),
|
|
1725
|
+
});
|
|
1485
1726
|
}
|
|
1486
1727
|
|
|
1487
1728
|
async getLatestBlockletVersion({ did, version }) {
|
|
@@ -1569,20 +1810,35 @@ class BlockletManager extends BaseBlockletManager {
|
|
|
1569
1810
|
blocklets.forEach(run);
|
|
1570
1811
|
}
|
|
1571
1812
|
|
|
1813
|
+
async _getChildren(meta) {
|
|
1814
|
+
const staticChildren = await parseChildren(meta);
|
|
1815
|
+
const dynamicChildren = await parseChildren(meta, {
|
|
1816
|
+
children: await states.blockletExtras.getSettings(meta.did, 'children', []),
|
|
1817
|
+
dynamic: true,
|
|
1818
|
+
});
|
|
1819
|
+
checkDuplicateComponents(dynamicChildren, staticChildren);
|
|
1820
|
+
|
|
1821
|
+
return [...staticChildren, ...dynamicChildren];
|
|
1822
|
+
}
|
|
1823
|
+
|
|
1824
|
+
async _getDynamicChildrenFromSettings(did) {
|
|
1825
|
+
const children = await states.blockletExtras.getSettings(did, 'children', []);
|
|
1826
|
+
return children.map((x) => ({ ...x, dynamic: true }));
|
|
1827
|
+
}
|
|
1828
|
+
|
|
1572
1829
|
async _install({ meta, source, deployedFrom, context, sync }) {
|
|
1573
1830
|
validateBlockletMeta(meta, { ensureDist: true });
|
|
1574
1831
|
|
|
1575
1832
|
const { name, did, version } = meta;
|
|
1576
1833
|
|
|
1577
|
-
const
|
|
1578
|
-
mergeMeta(meta, childrenMeta);
|
|
1834
|
+
const children = await this._getChildren(meta);
|
|
1579
1835
|
try {
|
|
1580
1836
|
const blocklet = await states.blocklet.addBlocklet({
|
|
1581
1837
|
did: meta.did,
|
|
1582
1838
|
meta,
|
|
1583
1839
|
source,
|
|
1584
1840
|
deployedFrom,
|
|
1585
|
-
|
|
1841
|
+
children,
|
|
1586
1842
|
});
|
|
1587
1843
|
|
|
1588
1844
|
await validateBlocklet(blocklet);
|
|
@@ -1597,6 +1853,7 @@ class BlockletManager extends BaseBlockletManager {
|
|
|
1597
1853
|
// download
|
|
1598
1854
|
const downloadParams = {
|
|
1599
1855
|
blocklet: { ...blocklet1 },
|
|
1856
|
+
oldBlocklet: { children: children.filter((x) => x.dynamic) }, // let downloader skip re-downloading dynamic blocklet
|
|
1600
1857
|
context,
|
|
1601
1858
|
postAction: 'install',
|
|
1602
1859
|
};
|
|
@@ -1655,7 +1912,7 @@ class BlockletManager extends BaseBlockletManager {
|
|
|
1655
1912
|
}
|
|
1656
1913
|
|
|
1657
1914
|
async _upgrade({ meta, source, deployedFrom, context, sync }) {
|
|
1658
|
-
validateBlockletMeta(meta, { ensureDist:
|
|
1915
|
+
validateBlockletMeta(meta, { ensureDist: meta.group !== BlockletGroup.gateway });
|
|
1659
1916
|
|
|
1660
1917
|
const { name, version, did } = meta;
|
|
1661
1918
|
|
|
@@ -1666,12 +1923,11 @@ class BlockletManager extends BaseBlockletManager {
|
|
|
1666
1923
|
logger.info(`${action} blocklet`, { did, version });
|
|
1667
1924
|
|
|
1668
1925
|
const newBlocklet = await states.blocklet.setBlockletStatus(did, BlockletStatus.waiting);
|
|
1669
|
-
|
|
1670
|
-
mergeMeta(meta, childrenMeta);
|
|
1926
|
+
|
|
1671
1927
|
newBlocklet.meta = meta;
|
|
1672
1928
|
newBlocklet.source = source;
|
|
1673
1929
|
newBlocklet.deployedFrom = deployedFrom;
|
|
1674
|
-
newBlocklet.children = await
|
|
1930
|
+
newBlocklet.children = await this._getChildren(meta);
|
|
1675
1931
|
|
|
1676
1932
|
await validateBlocklet(newBlocklet);
|
|
1677
1933
|
|
|
@@ -1774,7 +2030,7 @@ class BlockletManager extends BaseBlockletManager {
|
|
|
1774
2030
|
|
|
1775
2031
|
await ensureBlockletExpanded(meta, downloadDir);
|
|
1776
2032
|
|
|
1777
|
-
installDir =
|
|
2033
|
+
installDir = getBundleDir(this.installDir, meta);
|
|
1778
2034
|
if (fs.existsSync(installDir)) {
|
|
1779
2035
|
fs.removeSync(installDir);
|
|
1780
2036
|
logger.info('cleanup blocklet upgrade dir', { name, version, installDir });
|
|
@@ -1791,7 +2047,7 @@ class BlockletManager extends BaseBlockletManager {
|
|
|
1791
2047
|
return { meta, installDir };
|
|
1792
2048
|
}
|
|
1793
2049
|
|
|
1794
|
-
async _resolveDiffDownload(cwd, tarFile, deleteSet,
|
|
2050
|
+
async _resolveDiffDownload(cwd, tarFile, deleteSet, bundle) {
|
|
1795
2051
|
logger.info('Resolve diff download', { tarFile, cwd });
|
|
1796
2052
|
const downloadDir = path.join(cwd, `${path.basename(tarFile, path.extname(tarFile))}`);
|
|
1797
2053
|
const diffDir = `${downloadDir}-diff`;
|
|
@@ -1804,7 +2060,7 @@ class BlockletManager extends BaseBlockletManager {
|
|
|
1804
2060
|
throw error;
|
|
1805
2061
|
}
|
|
1806
2062
|
logger.info('Copy installDir to downloadDir', { installDir: this.installDir, downloadDir });
|
|
1807
|
-
await fs.copy(
|
|
2063
|
+
await fs.copy(getBundleDir(this.installDir, bundle), downloadDir);
|
|
1808
2064
|
try {
|
|
1809
2065
|
// delete
|
|
1810
2066
|
logger.info('Delete files from downloadDir', { fileNum: deleteSet.length });
|
|
@@ -1833,11 +2089,11 @@ class BlockletManager extends BaseBlockletManager {
|
|
|
1833
2089
|
|
|
1834
2090
|
await ensureBlockletExpanded(meta, downloadDir);
|
|
1835
2091
|
|
|
1836
|
-
const
|
|
1837
|
-
logger.info('Move downloadDir to installDir', { downloadDir,
|
|
1838
|
-
await fs.move(downloadDir,
|
|
2092
|
+
const bundleDir = getBundleDir(this.installDir, meta);
|
|
2093
|
+
logger.info('Move downloadDir to installDir', { downloadDir, bundleDir });
|
|
2094
|
+
await fs.move(downloadDir, bundleDir, { overwrite: true });
|
|
1839
2095
|
|
|
1840
|
-
return { meta, installDir };
|
|
2096
|
+
return { meta, installDir: bundleDir };
|
|
1841
2097
|
} catch (error) {
|
|
1842
2098
|
fs.removeSync(downloadDir);
|
|
1843
2099
|
fs.removeSync(diffDir);
|
|
@@ -1865,10 +2121,10 @@ class BlockletManager extends BaseBlockletManager {
|
|
|
1865
2121
|
// pre install
|
|
1866
2122
|
const nodeEnvironments = await states.node.getEnvironments();
|
|
1867
2123
|
const preInstall = (b) =>
|
|
1868
|
-
hooks.preInstall({
|
|
2124
|
+
hooks.preInstall(b.env.appId, {
|
|
1869
2125
|
hooks: Object.assign(b.meta.hooks || {}, b.meta.scripts || {}),
|
|
1870
2126
|
env: { ...nodeEnvironments },
|
|
1871
|
-
appDir:
|
|
2127
|
+
appDir: b.env.appDir,
|
|
1872
2128
|
did, // root blocklet did
|
|
1873
2129
|
notification: states.notification,
|
|
1874
2130
|
context,
|
|
@@ -1881,10 +2137,10 @@ class BlockletManager extends BaseBlockletManager {
|
|
|
1881
2137
|
|
|
1882
2138
|
// post install
|
|
1883
2139
|
const postInstall = (b) =>
|
|
1884
|
-
hooks.postInstall({
|
|
2140
|
+
hooks.postInstall(b.env.appId, {
|
|
1885
2141
|
hooks: Object.assign(b.meta.hooks || {}, b.meta.scripts || {}),
|
|
1886
2142
|
env: getRuntimeEnvironments(b, nodeEnvironments, blocklet),
|
|
1887
|
-
appDir:
|
|
2143
|
+
appDir: b.env.appDir,
|
|
1888
2144
|
did, // root blocklet did
|
|
1889
2145
|
notification: states.notification,
|
|
1890
2146
|
context,
|
|
@@ -1894,17 +2150,6 @@ class BlockletManager extends BaseBlockletManager {
|
|
|
1894
2150
|
await states.blocklet.setBlockletStatus(did, BlockletStatus.installed);
|
|
1895
2151
|
blocklet = await this.ensureBlocklet(did);
|
|
1896
2152
|
logger.info('blocklet installed', { source, did: meta.did });
|
|
1897
|
-
if (process.env.NODE_ENV !== 'test') {
|
|
1898
|
-
const nodeInfo = await states.node.read();
|
|
1899
|
-
const blockletInfo = getBlockletInfo(blocklet, nodeInfo.sk);
|
|
1900
|
-
const updateDidDnsResult = await updateDidDocument({
|
|
1901
|
-
wallet: blockletInfo.wallet,
|
|
1902
|
-
domain: nodeInfo.didDomain,
|
|
1903
|
-
nodeDid: nodeInfo.did,
|
|
1904
|
-
didRegistryUrl: nodeInfo.didRegistry,
|
|
1905
|
-
});
|
|
1906
|
-
logger.info('updated did document', { updateDidDnsResult, blockletId: blocklet.meta.did });
|
|
1907
|
-
}
|
|
1908
2153
|
|
|
1909
2154
|
this.emit(BlockletEvents.installed, { blocklet, context });
|
|
1910
2155
|
|
|
@@ -1965,10 +2210,10 @@ class BlockletManager extends BaseBlockletManager {
|
|
|
1965
2210
|
// pre install
|
|
1966
2211
|
const nodeEnvironments = await states.node.getEnvironments();
|
|
1967
2212
|
const preInstall = (b) =>
|
|
1968
|
-
hooks.preInstall({
|
|
2213
|
+
hooks.preInstall(b.env.appId, {
|
|
1969
2214
|
hooks: Object.assign(b.meta.hooks || {}, b.meta.scripts || {}),
|
|
1970
2215
|
env: { ...nodeEnvironments },
|
|
1971
|
-
appDir:
|
|
2216
|
+
appDir: b.env.appDir,
|
|
1972
2217
|
did, // root blocklet did
|
|
1973
2218
|
notification: states.notification,
|
|
1974
2219
|
context,
|
|
@@ -1981,7 +2226,7 @@ class BlockletManager extends BaseBlockletManager {
|
|
|
1981
2226
|
|
|
1982
2227
|
// post install
|
|
1983
2228
|
const postInstall = (b) =>
|
|
1984
|
-
hooks.postInstall({
|
|
2229
|
+
hooks.postInstall(b.env.appId, {
|
|
1985
2230
|
hooks: Object.assign(b.meta.hooks || {}, b.meta.scripts || {}),
|
|
1986
2231
|
env: getRuntimeEnvironments(b, nodeEnvironments, blocklet),
|
|
1987
2232
|
appDir: b.env.appDir,
|
|
@@ -1997,10 +2242,10 @@ class BlockletManager extends BaseBlockletManager {
|
|
|
1997
2242
|
if (b.meta.did === did) {
|
|
1998
2243
|
return runMigrationScripts({
|
|
1999
2244
|
blocklet: b,
|
|
2245
|
+
appDir: b.env.appDir,
|
|
2246
|
+
env: getRuntimeEnvironments(b, nodeEnvironments, blocklet),
|
|
2000
2247
|
oldVersion,
|
|
2001
2248
|
newVersion: version,
|
|
2002
|
-
env: getRuntimeEnvironments(b, nodeEnvironments, blocklet),
|
|
2003
|
-
appDir: b.env.appDir,
|
|
2004
2249
|
did: b.meta.did,
|
|
2005
2250
|
notification: states.notification,
|
|
2006
2251
|
context,
|
|
@@ -2053,6 +2298,12 @@ class BlockletManager extends BaseBlockletManager {
|
|
|
2053
2298
|
logger.error('emit upgrade notification failed', { name, version, error });
|
|
2054
2299
|
}
|
|
2055
2300
|
|
|
2301
|
+
// Update dynamic component meta in blocklet settings
|
|
2302
|
+
const dynamicChildren = blocklet.children
|
|
2303
|
+
.filter((x) => x.dynamic)
|
|
2304
|
+
.map((x) => pick(x, ['meta', 'mountPoint', 'sourceUrl', 'source']));
|
|
2305
|
+
await states.blockletExtras.setSettings(did, { children: dynamicChildren });
|
|
2306
|
+
|
|
2056
2307
|
return blocklet;
|
|
2057
2308
|
} catch (err) {
|
|
2058
2309
|
const b = await this._rollback(action, did, oldBlocklet);
|
|
@@ -2259,12 +2510,18 @@ class BlockletManager extends BaseBlockletManager {
|
|
|
2259
2510
|
|
|
2260
2511
|
for (const child of blocklet.children) {
|
|
2261
2512
|
const oldChild = oldChildren[child.meta.did];
|
|
2262
|
-
if (
|
|
2513
|
+
if (
|
|
2514
|
+
!oldChild ||
|
|
2515
|
+
(![BlockletSource.upload, BlockletSource.local].includes(child.source) &&
|
|
2516
|
+
child.sourceUrl &&
|
|
2517
|
+
get(oldChild, 'meta.dist.integrity') !== get(child, 'meta.dist.integrity'))
|
|
2518
|
+
) {
|
|
2263
2519
|
metas.push(child.meta);
|
|
2264
2520
|
}
|
|
2265
2521
|
}
|
|
2266
2522
|
|
|
2267
2523
|
try {
|
|
2524
|
+
logger.info('Download Blocklet', { name, did, bundles: metas.map((x) => get(x, 'dist.tarball')) });
|
|
2268
2525
|
const tasks = [];
|
|
2269
2526
|
for (const meta of metas) {
|
|
2270
2527
|
const url = await this.registry.resolveTarballURL({
|
|
@@ -2332,7 +2589,7 @@ class BlockletManager extends BaseBlockletManager {
|
|
|
2332
2589
|
async _rollback(action, did, oldBlocklet) {
|
|
2333
2590
|
if (action === 'install') {
|
|
2334
2591
|
// remove blocklet
|
|
2335
|
-
return this._deleteBlocklet({ did, keepData:
|
|
2592
|
+
return this._deleteBlocklet({ did, keepData: true });
|
|
2336
2593
|
}
|
|
2337
2594
|
|
|
2338
2595
|
if (['upgrade', 'downgrade'].includes(action)) {
|
|
@@ -2374,7 +2631,18 @@ class BlockletManager extends BaseBlockletManager {
|
|
|
2374
2631
|
const result = await states.blocklet.deleteBlocklet(did);
|
|
2375
2632
|
logger.info('blocklet removed successfully', { did });
|
|
2376
2633
|
|
|
2377
|
-
|
|
2634
|
+
let keepRouting = true;
|
|
2635
|
+
if (keepData === false || keepConfigs === false) {
|
|
2636
|
+
keepRouting = false;
|
|
2637
|
+
}
|
|
2638
|
+
|
|
2639
|
+
this.emit(BlockletEvents.removed, {
|
|
2640
|
+
blocklet: result,
|
|
2641
|
+
context: {
|
|
2642
|
+
...context,
|
|
2643
|
+
keepRouting,
|
|
2644
|
+
},
|
|
2645
|
+
});
|
|
2378
2646
|
return blocklet;
|
|
2379
2647
|
}
|
|
2380
2648
|
|
|
@@ -2395,6 +2663,20 @@ class BlockletManager extends BaseBlockletManager {
|
|
|
2395
2663
|
await states.blockletExtras.delChildConfigs(did, child.meta.did);
|
|
2396
2664
|
}
|
|
2397
2665
|
}
|
|
2666
|
+
|
|
2667
|
+
async _findNextCustomBlockletName(leftTimes = 10) {
|
|
2668
|
+
if (leftTimes <= 0) {
|
|
2669
|
+
throw new Error('Generate custom blocklet did too many times');
|
|
2670
|
+
}
|
|
2671
|
+
const number = await states.node.increaseCustomBlockletNumber();
|
|
2672
|
+
const name = `custom-${number}`;
|
|
2673
|
+
const did = toBlockletDid(name);
|
|
2674
|
+
const blocklet = await states.blocklet.getBlocklet(did);
|
|
2675
|
+
if (blocklet) {
|
|
2676
|
+
return this._findNextCustomBlockletName(leftTimes - 1);
|
|
2677
|
+
}
|
|
2678
|
+
return { did, name };
|
|
2679
|
+
}
|
|
2398
2680
|
}
|
|
2399
2681
|
|
|
2400
2682
|
module.exports = BlockletManager;
|