@abtnode/core 1.6.15 → 1.6.19
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 +429 -151
- package/lib/blocklet/migration.js +16 -52
- package/lib/event.js +1 -1
- package/lib/index.js +3 -1
- package/lib/migrations/1.6.17-blocklet-children.js +48 -0
- package/lib/router/helper.js +18 -12
- package/lib/router/manager.js +45 -41
- package/lib/states/blocklet-extras.js +39 -3
- package/lib/states/blocklet.js +89 -20
- package/lib/states/node.js +17 -2
- package/lib/util/blocklet.js +288 -67
- package/lib/util/default-node-config.js +1 -1
- package/lib/util/get-domain-for-blocklet.js +2 -2
- package/lib/util/upgrade.js +8 -4
- package/lib/validators/node.js +11 -12
- package/package.json +23 -23
|
@@ -3,30 +3,37 @@
|
|
|
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
|
+
isComponentBlocklet,
|
|
29
|
+
isDeletableBlocklet,
|
|
30
|
+
getRequiredMissingConfigs,
|
|
31
|
+
hasRunnableComponent,
|
|
32
|
+
} = require('@blocklet/meta/lib/util');
|
|
28
33
|
const validateBlockletEntry = require('@blocklet/meta/lib/entry');
|
|
29
|
-
const
|
|
34
|
+
const toBlockletDid = require('@blocklet/meta/lib/did');
|
|
35
|
+
const { validateMeta } = require('@blocklet/meta/lib/validate');
|
|
36
|
+
const { update: updateMetaFile } = require('@blocklet/meta/lib/file');
|
|
30
37
|
|
|
31
38
|
const {
|
|
32
39
|
BlockletStatus,
|
|
@@ -37,6 +44,15 @@ const {
|
|
|
37
44
|
BlockletGroup,
|
|
38
45
|
fromBlockletStatus,
|
|
39
46
|
fromBlockletSource,
|
|
47
|
+
BLOCKLET_DEFAULT_PORT_NAME,
|
|
48
|
+
BLOCKLET_INTERFACE_TYPE_WEB,
|
|
49
|
+
BLOCKLET_INTERFACE_PUBLIC,
|
|
50
|
+
BLOCKLET_DYNAMIC_PATH_PREFIX,
|
|
51
|
+
BLOCKLET_INTERFACE_PROTOCOL_HTTP,
|
|
52
|
+
BLOCKLET_DEFAULT_PATH_REWRITE,
|
|
53
|
+
BLOCKLET_DEFAULT_VERSION,
|
|
54
|
+
BLOCKLET_LATEST_SPEC_VERSION,
|
|
55
|
+
BLOCKLET_META_FILE,
|
|
40
56
|
} = require('@blocklet/meta/lib/constants');
|
|
41
57
|
const util = require('../../util');
|
|
42
58
|
const {
|
|
@@ -60,16 +76,20 @@ const {
|
|
|
60
76
|
getBlockletStatusFromProcess,
|
|
61
77
|
checkBlockletProcessHealthy,
|
|
62
78
|
validateBlocklet,
|
|
63
|
-
getChildrenMeta,
|
|
64
79
|
statusMap,
|
|
65
80
|
expandTarball,
|
|
66
81
|
verifyIntegrity,
|
|
67
82
|
pruneBlockletBundle,
|
|
68
83
|
getDiskInfo,
|
|
69
84
|
getRuntimeInfo,
|
|
70
|
-
mergeMeta,
|
|
71
85
|
getUpdateMetaList,
|
|
72
86
|
getRuntimeEnvironments,
|
|
87
|
+
getSourceFromInstallParams,
|
|
88
|
+
parseChildren,
|
|
89
|
+
checkDuplicateComponents,
|
|
90
|
+
getDiffFiles,
|
|
91
|
+
getBundleDir,
|
|
92
|
+
needBlockletDownload,
|
|
73
93
|
} = require('../../util/blocklet');
|
|
74
94
|
const states = require('../../states');
|
|
75
95
|
const BlockletRegistry = require('../registry');
|
|
@@ -153,20 +173,43 @@ class BlockletManager extends BaseBlockletManager {
|
|
|
153
173
|
*/
|
|
154
174
|
async install(params, context) {
|
|
155
175
|
logger.debug('install blocklet', { params, context });
|
|
156
|
-
|
|
176
|
+
|
|
177
|
+
const source = getSourceFromInstallParams(params);
|
|
178
|
+
|
|
179
|
+
if (source === BlockletSource.url) {
|
|
157
180
|
return this._installFromUrl({ url: params.url, sync: params.sync }, context);
|
|
158
181
|
}
|
|
159
182
|
|
|
160
|
-
if (
|
|
183
|
+
if (source === BlockletSource.upload) {
|
|
161
184
|
const { file, did, diffVersion, deleteSet } = params;
|
|
162
185
|
return this._installFromUpload({ file, did, diffVersion, deleteSet, context });
|
|
163
186
|
}
|
|
164
187
|
|
|
165
|
-
if (
|
|
166
|
-
return this.
|
|
188
|
+
if (source === BlockletSource.registry) {
|
|
189
|
+
return this._installFromStore({ did: params.did }, context);
|
|
190
|
+
}
|
|
191
|
+
|
|
192
|
+
if (source === BlockletSource.custom) {
|
|
193
|
+
return this._installFromCreate({ title: params.title, description: params.description }, context);
|
|
194
|
+
}
|
|
195
|
+
|
|
196
|
+
// should not be here
|
|
197
|
+
throw new Error('Unknown source');
|
|
198
|
+
}
|
|
199
|
+
|
|
200
|
+
async installComponent({ rootDid, mountPoint, url, file, did, diffVersion, deleteSet }, context = {}) {
|
|
201
|
+
logger.debug('start install component', { rootDid, mountPoint, url });
|
|
202
|
+
|
|
203
|
+
if (file) {
|
|
204
|
+
return this._installComponentFromUpload({ rootDid, mountPoint, file, did, diffVersion, deleteSet, context });
|
|
205
|
+
}
|
|
206
|
+
|
|
207
|
+
if (url) {
|
|
208
|
+
return this._installComponentFromUrl({ rootDid, mountPoint, url, context });
|
|
167
209
|
}
|
|
168
210
|
|
|
169
|
-
|
|
211
|
+
// should not be here
|
|
212
|
+
throw new Error('Unknown source');
|
|
170
213
|
}
|
|
171
214
|
|
|
172
215
|
// eslint-disable-next-line no-unused-vars
|
|
@@ -189,9 +232,9 @@ class BlockletManager extends BaseBlockletManager {
|
|
|
189
232
|
}
|
|
190
233
|
}
|
|
191
234
|
|
|
192
|
-
|
|
235
|
+
const blocklet = await states.blocklet.getBlocklet(meta.did);
|
|
193
236
|
|
|
194
|
-
return meta;
|
|
237
|
+
return { meta, isFree, isInstalled: !!blocklet };
|
|
195
238
|
}
|
|
196
239
|
|
|
197
240
|
async installBlockletFromVc({ vcPresentation, challenge }, context) {
|
|
@@ -210,7 +253,7 @@ class BlockletManager extends BaseBlockletManager {
|
|
|
210
253
|
const did = get(vc, 'credentialSubject.purchased.blocklet.id');
|
|
211
254
|
const registry = urlObject.origin;
|
|
212
255
|
|
|
213
|
-
return this.
|
|
256
|
+
return this._installFromStore({ did, registry }, { ...context, blockletPurchaseVerified: true });
|
|
214
257
|
}
|
|
215
258
|
|
|
216
259
|
async start({ did, checkHealthImmediately = false, throwOnError }, context) {
|
|
@@ -218,6 +261,10 @@ class BlockletManager extends BaseBlockletManager {
|
|
|
218
261
|
const blocklet = await this.ensureBlocklet(did);
|
|
219
262
|
|
|
220
263
|
try {
|
|
264
|
+
if (!hasRunnableComponent(blocklet)) {
|
|
265
|
+
throw new Error('No runnable component found');
|
|
266
|
+
}
|
|
267
|
+
|
|
221
268
|
// check required config
|
|
222
269
|
const missingProps = getRequiredMissingConfigs(blocklet);
|
|
223
270
|
if (missingProps.length) {
|
|
@@ -246,7 +293,6 @@ class BlockletManager extends BaseBlockletManager {
|
|
|
246
293
|
hooks: Object.assign(b.meta.hooks || {}, b.meta.scripts || {}),
|
|
247
294
|
env: getRuntimeEnvironments(b, nodeEnvironments, blocklet),
|
|
248
295
|
did, // root blocklet did,
|
|
249
|
-
progress: blocklet.mode === BLOCKLET_MODES.DEVELOPMENT,
|
|
250
296
|
}),
|
|
251
297
|
nodeEnvironments,
|
|
252
298
|
nodeInfo: await states.node.read(),
|
|
@@ -297,7 +343,7 @@ class BlockletManager extends BaseBlockletManager {
|
|
|
297
343
|
}
|
|
298
344
|
}
|
|
299
345
|
|
|
300
|
-
async stop({ did, updateStatus = true }, context) {
|
|
346
|
+
async stop({ did, updateStatus = true, silent = false }, context) {
|
|
301
347
|
logger.info('stop blocklet', { did });
|
|
302
348
|
|
|
303
349
|
const blocklet = await this.ensureBlocklet(did);
|
|
@@ -313,7 +359,7 @@ class BlockletManager extends BaseBlockletManager {
|
|
|
313
359
|
|
|
314
360
|
await stopBlockletProcess(blocklet, {
|
|
315
361
|
preStop: (b) =>
|
|
316
|
-
hooks.preStop({
|
|
362
|
+
hooks.preStop(b.env.appId, {
|
|
317
363
|
appDir: b.env.appDir,
|
|
318
364
|
hooks: Object.assign(b.meta.hooks || {}, b.meta.scripts || {}),
|
|
319
365
|
env: getRuntimeEnvironments(b, nodeEnvironments, blocklet),
|
|
@@ -321,7 +367,7 @@ class BlockletManager extends BaseBlockletManager {
|
|
|
321
367
|
notification: states.notification,
|
|
322
368
|
context,
|
|
323
369
|
exitOnError: false,
|
|
324
|
-
|
|
370
|
+
silent,
|
|
325
371
|
}),
|
|
326
372
|
});
|
|
327
373
|
|
|
@@ -389,7 +435,7 @@ class BlockletManager extends BaseBlockletManager {
|
|
|
389
435
|
|
|
390
436
|
await deleteBlockletProcess(blocklet, {
|
|
391
437
|
preDelete: (b) =>
|
|
392
|
-
hooks.preUninstall({
|
|
438
|
+
hooks.preUninstall(b.env.appId, {
|
|
393
439
|
appDir: b.env.appDir,
|
|
394
440
|
hooks: Object.assign(b.meta.hooks || {}, b.meta.scripts || {}),
|
|
395
441
|
env: getRuntimeEnvironments(b, nodeEnvironments, blocklet),
|
|
@@ -412,6 +458,22 @@ class BlockletManager extends BaseBlockletManager {
|
|
|
412
458
|
}
|
|
413
459
|
}
|
|
414
460
|
|
|
461
|
+
async deleteComponent({ did, rootDid }, context) {
|
|
462
|
+
logger.info('delete blocklet component', { did, rootDid });
|
|
463
|
+
|
|
464
|
+
const doc = await states.blocklet.getBlocklet(rootDid);
|
|
465
|
+
|
|
466
|
+
doc.children = doc.children.filter((x) => x.meta.did !== did);
|
|
467
|
+
const children = (await this._getDynamicChildrenFromSettings(rootDid)).filter((x) => x.meta.did !== did);
|
|
468
|
+
|
|
469
|
+
await states.blocklet.updateBlocklet(rootDid, doc);
|
|
470
|
+
states.blockletExtras.setSettings(rootDid, { children });
|
|
471
|
+
|
|
472
|
+
const newBlocklet = await this.ensureBlocklet(rootDid);
|
|
473
|
+
this.emit(BlockletEvents.upgraded, { blocklet: newBlocklet, context }); // trigger router refresh
|
|
474
|
+
return newBlocklet;
|
|
475
|
+
}
|
|
476
|
+
|
|
415
477
|
async cancelDownload({ did }, context) {
|
|
416
478
|
await preDownloadLock.acquire();
|
|
417
479
|
try {
|
|
@@ -449,12 +511,14 @@ class BlockletManager extends BaseBlockletManager {
|
|
|
449
511
|
return result;
|
|
450
512
|
}
|
|
451
513
|
|
|
452
|
-
async detail({ did, attachRuntimeInfo = true }, context) {
|
|
514
|
+
async detail({ did, attachConfig = true, attachRuntimeInfo = true }, context) {
|
|
453
515
|
if (!did) {
|
|
454
516
|
throw new Error('did should not be empty');
|
|
455
517
|
}
|
|
456
518
|
|
|
457
|
-
|
|
519
|
+
if (!attachConfig) {
|
|
520
|
+
return states.blocklet.getBlocklet(did);
|
|
521
|
+
}
|
|
458
522
|
|
|
459
523
|
if (!attachRuntimeInfo) {
|
|
460
524
|
try {
|
|
@@ -465,6 +529,8 @@ class BlockletManager extends BaseBlockletManager {
|
|
|
465
529
|
}
|
|
466
530
|
}
|
|
467
531
|
|
|
532
|
+
const nodeInfo = await states.node.read();
|
|
533
|
+
|
|
468
534
|
return this.attachRuntimeInfo({ did, nodeInfo, diskInfo: true, context });
|
|
469
535
|
}
|
|
470
536
|
|
|
@@ -549,19 +615,25 @@ class BlockletManager extends BaseBlockletManager {
|
|
|
549
615
|
}
|
|
550
616
|
}
|
|
551
617
|
|
|
618
|
+
if (x.key === 'BLOCKLET_PASSPORT_COLOR') {
|
|
619
|
+
if (x.value && x.value !== 'auto') {
|
|
620
|
+
if (x.value.length !== 7 || !isHex(x.value.slice(-6))) {
|
|
621
|
+
throw new Error('BLOCKLET_PASSPORT_COLOR must be a hex encoded color, eg. #ffeeaa');
|
|
622
|
+
}
|
|
623
|
+
}
|
|
624
|
+
}
|
|
625
|
+
|
|
552
626
|
blocklet.configObj[x.key] = x.value;
|
|
553
627
|
}
|
|
554
628
|
|
|
555
629
|
// FIXME: we should also call preConfig for child blocklets
|
|
556
|
-
await hooks.preConfig({
|
|
630
|
+
await hooks.preConfig(blocklet.env.appId, {
|
|
557
631
|
appDir: blocklet.env.appDir,
|
|
558
632
|
hooks: Object.assign(blocklet.meta.hooks || {}, blocklet.meta.scripts || {}),
|
|
559
633
|
exitOnError: true,
|
|
560
634
|
env: { ...getRuntimeEnvironments(blocklet, nodeEnvironments), ...blocklet.configObj },
|
|
561
|
-
notification: states.notification,
|
|
562
635
|
did,
|
|
563
636
|
context,
|
|
564
|
-
progress: blocklet.mode === BLOCKLET_MODES.DEVELOPMENT,
|
|
565
637
|
});
|
|
566
638
|
|
|
567
639
|
// update db
|
|
@@ -657,56 +729,45 @@ class BlockletManager extends BaseBlockletManager {
|
|
|
657
729
|
}
|
|
658
730
|
|
|
659
731
|
// eslint-disable-next-line no-unused-vars
|
|
660
|
-
async diff({ did, hashFiles: clientFiles }, context) {
|
|
732
|
+
async diff({ did, hashFiles: clientFiles, rootDid: inputRootDid }, context) {
|
|
661
733
|
if (!did) {
|
|
662
734
|
throw new Error('did is empty');
|
|
663
735
|
}
|
|
736
|
+
|
|
664
737
|
if (!clientFiles || !clientFiles.length) {
|
|
665
738
|
throw new Error('hashFiles is empty');
|
|
666
739
|
}
|
|
667
740
|
|
|
668
|
-
|
|
741
|
+
const rootDid = inputRootDid || did;
|
|
742
|
+
const childDid = inputRootDid ? did : '';
|
|
743
|
+
|
|
744
|
+
if (childDid === rootDid) {
|
|
745
|
+
throw new Error('Cannot add self as a component');
|
|
746
|
+
}
|
|
747
|
+
|
|
748
|
+
logger.info('Get blocklet diff', { rootDid, childDid, clientFilesNumber: clientFiles.length });
|
|
749
|
+
|
|
750
|
+
const rootBlocklet = await states.blocklet.getBlocklet(rootDid);
|
|
751
|
+
if (childDid && !rootBlocklet) {
|
|
752
|
+
throw new Error('Root blocklet does not exist');
|
|
753
|
+
}
|
|
754
|
+
|
|
755
|
+
const state = childDid ? await (rootBlocklet.children || []).find((x) => x.meta.did === childDid) : rootBlocklet;
|
|
669
756
|
|
|
670
|
-
const state = await states.blocklet.getBlocklet(did);
|
|
671
757
|
if (!state) {
|
|
672
758
|
return {
|
|
673
759
|
hasBlocklet: false,
|
|
674
760
|
};
|
|
675
761
|
}
|
|
762
|
+
|
|
676
763
|
if (state.source === BlockletSource.local) {
|
|
677
764
|
throw new Error(`Blocklet ${state.meta.name} is already deployed from local, can not deployed from remote.`);
|
|
678
765
|
}
|
|
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
766
|
|
|
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
|
-
}
|
|
767
|
+
const { version } = state.meta;
|
|
768
|
+
const bundleDir = getBundleDir(this.installDir, state.meta);
|
|
769
|
+
const { addSet, changeSet, deleteSet } = await getDiffFiles(clientFiles, bundleDir);
|
|
770
|
+
|
|
710
771
|
logger.info('Diff files', {
|
|
711
772
|
name: state.meta.name,
|
|
712
773
|
did: state.meta.did,
|
|
@@ -715,6 +776,7 @@ class BlockletManager extends BaseBlockletManager {
|
|
|
715
776
|
changeNum: changeSet.length,
|
|
716
777
|
deleteNum: deleteSet.length,
|
|
717
778
|
});
|
|
779
|
+
|
|
718
780
|
return {
|
|
719
781
|
hasBlocklet: true,
|
|
720
782
|
version,
|
|
@@ -726,10 +788,20 @@ class BlockletManager extends BaseBlockletManager {
|
|
|
726
788
|
|
|
727
789
|
async checkChildrenForUpdates({ did }) {
|
|
728
790
|
const blocklet = await states.blocklet.getBlocklet(did);
|
|
729
|
-
const
|
|
791
|
+
const newStaticChildren = await parseChildren(blocklet.meta);
|
|
792
|
+
|
|
793
|
+
const oldDynamicChildren = await this._getDynamicChildrenFromSettings(did);
|
|
794
|
+
const noneSourceUrlChildren = oldDynamicChildren.filter((x) => !x.sourceUrl);
|
|
795
|
+
const dynamicConfig = oldDynamicChildren
|
|
796
|
+
.filter((x) => x.sourceUrl)
|
|
797
|
+
.map((x) => ({ resolved: x.sourceUrl, name: x.meta.name, mountPoint: x.mountPoint }));
|
|
798
|
+
const newDynamicChildren = [...noneSourceUrlChildren, ...(await parseChildren(dynamicConfig, { dynamic: true }))];
|
|
799
|
+
|
|
800
|
+
checkDuplicateComponents(newDynamicChildren, newStaticChildren);
|
|
801
|
+
|
|
730
802
|
const updateList = getUpdateMetaList(
|
|
731
|
-
blocklet.children.map((x) => x.meta),
|
|
732
|
-
|
|
803
|
+
[...blocklet.children.map((x) => x.meta), ...oldDynamicChildren.map((x) => x.meta)],
|
|
804
|
+
[...newStaticChildren.map((x) => x.meta), ...newDynamicChildren.map((x) => x.meta)]
|
|
733
805
|
);
|
|
734
806
|
|
|
735
807
|
if (!updateList.length) {
|
|
@@ -739,7 +811,8 @@ class BlockletManager extends BaseBlockletManager {
|
|
|
739
811
|
// start session
|
|
740
812
|
const { id: updateId } = await states.session.start({
|
|
741
813
|
did,
|
|
742
|
-
|
|
814
|
+
staticChildren: newStaticChildren,
|
|
815
|
+
dynamicChildren: newDynamicChildren,
|
|
743
816
|
});
|
|
744
817
|
|
|
745
818
|
return {
|
|
@@ -748,11 +821,23 @@ class BlockletManager extends BaseBlockletManager {
|
|
|
748
821
|
};
|
|
749
822
|
}
|
|
750
823
|
|
|
751
|
-
async updateChildren({ updateId }, context) {
|
|
752
|
-
|
|
824
|
+
async updateChildren({ updateId, did: inputDid, children: inputChildren, oldBlocklet: inputOldBlocklet }, context) {
|
|
825
|
+
let did;
|
|
826
|
+
let children;
|
|
827
|
+
let oldBlocklet;
|
|
828
|
+
if (!updateId && inputDid && inputChildren) {
|
|
829
|
+
did = inputDid;
|
|
830
|
+
children = inputChildren;
|
|
831
|
+
oldBlocklet = inputOldBlocklet;
|
|
832
|
+
} else {
|
|
833
|
+
const sessionData = await states.session.end(updateId);
|
|
834
|
+
did = sessionData.did;
|
|
835
|
+
const { staticChildren = [], dynamicChildren = [] } = sessionData;
|
|
836
|
+
children = [...staticChildren, ...dynamicChildren.map((x) => ({ ...x, dynamic: true }))];
|
|
837
|
+
oldBlocklet = await states.blocklet.getBlocklet(did);
|
|
838
|
+
}
|
|
753
839
|
|
|
754
840
|
// get old blocklet
|
|
755
|
-
const oldBlocklet = await states.blocklet.getBlocklet(did);
|
|
756
841
|
const { meta } = oldBlocklet;
|
|
757
842
|
const { name, version } = meta;
|
|
758
843
|
|
|
@@ -762,14 +847,13 @@ class BlockletManager extends BaseBlockletManager {
|
|
|
762
847
|
did,
|
|
763
848
|
name,
|
|
764
849
|
version,
|
|
765
|
-
children:
|
|
850
|
+
children: children.map((x) => ({ name: x.meta.name, version: x.meta.version })),
|
|
766
851
|
});
|
|
767
852
|
|
|
768
853
|
// new blocklet
|
|
769
854
|
const newBlocklet = await states.blocklet.setBlockletStatus(did, BlockletStatus.waiting);
|
|
770
|
-
|
|
771
|
-
newBlocklet.
|
|
772
|
-
newBlocklet.children = await states.blocklet.getChildrenFromMetas(childrenMeta);
|
|
855
|
+
|
|
856
|
+
newBlocklet.children = children;
|
|
773
857
|
await validateBlocklet(newBlocklet);
|
|
774
858
|
|
|
775
859
|
this.emit(BlockletEvents.statusChange, newBlocklet);
|
|
@@ -807,6 +891,11 @@ class BlockletManager extends BaseBlockletManager {
|
|
|
807
891
|
// ============================================================================================
|
|
808
892
|
// Internal API that are used by public APIs and called from CLI
|
|
809
893
|
// ============================================================================================
|
|
894
|
+
|
|
895
|
+
/**
|
|
896
|
+
* After the dev function finished, the caller should send a BlockletEvents.deployed event to the daemon
|
|
897
|
+
* @returns {Object} blocklet
|
|
898
|
+
*/
|
|
810
899
|
async dev(folder) {
|
|
811
900
|
logger.info('dev blocklet', { folder });
|
|
812
901
|
|
|
@@ -839,30 +928,33 @@ class BlockletManager extends BaseBlockletManager {
|
|
|
839
928
|
await this.deleteProcess({ did });
|
|
840
929
|
logger.info('delete blocklet precess for dev', { did, version });
|
|
841
930
|
} catch (err) {
|
|
842
|
-
|
|
931
|
+
if (process.env.NODE_ENV !== 'development') {
|
|
932
|
+
logger.error('failed to delete blocklet process for dev', { error: err });
|
|
933
|
+
}
|
|
843
934
|
}
|
|
844
935
|
|
|
845
|
-
const
|
|
846
|
-
|
|
847
|
-
const blocklet = await states.blocklet.addBlocklet({
|
|
936
|
+
const children = await this._getChildren(meta);
|
|
937
|
+
const added = await states.blocklet.addBlocklet({
|
|
848
938
|
did,
|
|
849
939
|
meta,
|
|
850
940
|
source: BlockletSource.local,
|
|
851
941
|
deployedFrom: folder,
|
|
852
942
|
mode: BLOCKLET_MODES.DEVELOPMENT,
|
|
853
|
-
|
|
943
|
+
children,
|
|
854
944
|
});
|
|
855
945
|
logger.info('add blocklet for dev', { did, version, meta });
|
|
856
946
|
|
|
857
|
-
|
|
947
|
+
const oldBlocklet = { children: children.filter((x) => x.dynamic) }; // let downloader skip re-downloading dynamic blocklet
|
|
948
|
+
await this._downloadBlocklet(added, oldBlocklet);
|
|
858
949
|
await states.blocklet.setBlockletStatus(did, BlockletStatus.installed);
|
|
859
950
|
|
|
860
951
|
// Add environments
|
|
861
952
|
await this._setConfigs(did);
|
|
862
953
|
await this.updateBlockletEnvironment(did);
|
|
863
954
|
|
|
864
|
-
|
|
865
|
-
|
|
955
|
+
const blocklet = await this.ensureBlocklet(did);
|
|
956
|
+
|
|
957
|
+
return blocklet;
|
|
866
958
|
}
|
|
867
959
|
|
|
868
960
|
async ensureBlocklet(did) {
|
|
@@ -997,7 +1089,8 @@ class BlockletManager extends BaseBlockletManager {
|
|
|
997
1089
|
blocklet.diskInfo = await getDiskInfo(blocklet, { useFakeDiskInfo: !diskInfo });
|
|
998
1090
|
|
|
999
1091
|
try {
|
|
1000
|
-
const
|
|
1092
|
+
const app = blocklet.meta.group === BlockletGroup.gateway ? blocklet.children[0].env : blocklet.env;
|
|
1093
|
+
const { appId } = app;
|
|
1001
1094
|
blocklet.runtimeInfo = await getRuntimeInfo(appId);
|
|
1002
1095
|
if (blocklet.runtimeInfo.status && shouldUpdateBlockletStatus(blocklet.status)) {
|
|
1003
1096
|
blocklet.status = statusMap[blocklet.runtimeInfo.status];
|
|
@@ -1090,9 +1183,6 @@ class BlockletManager extends BaseBlockletManager {
|
|
|
1090
1183
|
return;
|
|
1091
1184
|
}
|
|
1092
1185
|
|
|
1093
|
-
const blocklet1 = await states.blocklet.setBlockletStatus(did, BlockletStatus.downloading);
|
|
1094
|
-
this.emit(BlockletEvents.statusChange, blocklet1);
|
|
1095
|
-
|
|
1096
1186
|
preDownloadLock.release();
|
|
1097
1187
|
|
|
1098
1188
|
const { isCancelled } = await this._downloadBlocklet(blocklet, oldBlocklet);
|
|
@@ -1271,7 +1361,7 @@ class BlockletManager extends BaseBlockletManager {
|
|
|
1271
1361
|
}
|
|
1272
1362
|
}
|
|
1273
1363
|
|
|
1274
|
-
async
|
|
1364
|
+
async _installFromStore({ did, registry }, context) {
|
|
1275
1365
|
logger.debug('start install blocklet', { did });
|
|
1276
1366
|
if (!isValidDid(did)) {
|
|
1277
1367
|
throw new Error('Blocklet did is invalid');
|
|
@@ -1333,9 +1423,92 @@ class BlockletManager extends BaseBlockletManager {
|
|
|
1333
1423
|
});
|
|
1334
1424
|
}
|
|
1335
1425
|
|
|
1336
|
-
async
|
|
1337
|
-
|
|
1338
|
-
|
|
1426
|
+
async _installComponentFromUrl({ rootDid, mountPoint, url, context }) {
|
|
1427
|
+
const blocklet = await states.blocklet.getBlocklet(rootDid);
|
|
1428
|
+
if (!blocklet) {
|
|
1429
|
+
throw new Error('Root blocklet does not exist');
|
|
1430
|
+
}
|
|
1431
|
+
|
|
1432
|
+
const meta = await getBlockletMetaFromUrl(url);
|
|
1433
|
+
|
|
1434
|
+
if (meta.did === rootDid) {
|
|
1435
|
+
throw new Error('Cannot add self as a component');
|
|
1436
|
+
}
|
|
1437
|
+
|
|
1438
|
+
if (!isComponentBlocklet(meta)) {
|
|
1439
|
+
throw new Error('The blocklet cannot be a component');
|
|
1440
|
+
}
|
|
1441
|
+
|
|
1442
|
+
const newChildren = await parseChildren(blocklet.meta, {
|
|
1443
|
+
children: [
|
|
1444
|
+
{
|
|
1445
|
+
meta,
|
|
1446
|
+
mountPoint,
|
|
1447
|
+
sourceUrl: url,
|
|
1448
|
+
},
|
|
1449
|
+
],
|
|
1450
|
+
dynamic: true,
|
|
1451
|
+
});
|
|
1452
|
+
|
|
1453
|
+
checkDuplicateComponents(blocklet.children, newChildren);
|
|
1454
|
+
|
|
1455
|
+
// add component to db
|
|
1456
|
+
await states.blocklet.addChildren(rootDid, newChildren);
|
|
1457
|
+
|
|
1458
|
+
return this.updateChildren(
|
|
1459
|
+
{
|
|
1460
|
+
did: rootDid,
|
|
1461
|
+
children: [...blocklet.children, ...newChildren],
|
|
1462
|
+
oldBlocklet: blocklet,
|
|
1463
|
+
},
|
|
1464
|
+
context
|
|
1465
|
+
);
|
|
1466
|
+
}
|
|
1467
|
+
|
|
1468
|
+
async _installFromCreate({ title, description }, context = {}) {
|
|
1469
|
+
logger.debug('create blocklet', { title, description });
|
|
1470
|
+
|
|
1471
|
+
await joi.string().label('title').max(20).required().validateAsync(title);
|
|
1472
|
+
await joi.string().label('description').max(80).required().validateAsync(description);
|
|
1473
|
+
|
|
1474
|
+
const { did, name } = await this._findNextCustomBlockletName();
|
|
1475
|
+
const rawMeta = {
|
|
1476
|
+
name,
|
|
1477
|
+
did,
|
|
1478
|
+
title,
|
|
1479
|
+
description,
|
|
1480
|
+
version: BLOCKLET_DEFAULT_VERSION,
|
|
1481
|
+
group: BlockletGroup.gateway,
|
|
1482
|
+
interfaces: [
|
|
1483
|
+
{
|
|
1484
|
+
type: BLOCKLET_INTERFACE_TYPE_WEB,
|
|
1485
|
+
name: BLOCKLET_INTERFACE_PUBLIC,
|
|
1486
|
+
path: BLOCKLET_DEFAULT_PATH_REWRITE,
|
|
1487
|
+
prefix: BLOCKLET_DYNAMIC_PATH_PREFIX,
|
|
1488
|
+
port: BLOCKLET_DEFAULT_PORT_NAME,
|
|
1489
|
+
protocol: BLOCKLET_INTERFACE_PROTOCOL_HTTP,
|
|
1490
|
+
},
|
|
1491
|
+
],
|
|
1492
|
+
specVersion: BLOCKLET_LATEST_SPEC_VERSION,
|
|
1493
|
+
};
|
|
1494
|
+
const meta = validateMeta(rawMeta);
|
|
1495
|
+
|
|
1496
|
+
await states.blocklet.addBlocklet({
|
|
1497
|
+
did: meta.did,
|
|
1498
|
+
meta,
|
|
1499
|
+
source: BlockletSource.custom,
|
|
1500
|
+
});
|
|
1501
|
+
await this._setConfigs(did);
|
|
1502
|
+
|
|
1503
|
+
// fake install bundle
|
|
1504
|
+
const bundleDir = getBundleDir(this.installDir, meta);
|
|
1505
|
+
fs.mkdirSync(bundleDir, { recursive: true });
|
|
1506
|
+
updateMetaFile(path.join(bundleDir, BLOCKLET_META_FILE), meta);
|
|
1507
|
+
|
|
1508
|
+
return this._installBlocklet({ did, context });
|
|
1509
|
+
}
|
|
1510
|
+
|
|
1511
|
+
async _downloadFromUpload(file) {
|
|
1339
1512
|
// const { filename, mimetype, encoding, createReadStream } = await file;
|
|
1340
1513
|
const { filename, createReadStream } = await file;
|
|
1341
1514
|
const cwd = path.join(this.dataDirs.tmp, 'download');
|
|
@@ -1359,6 +1532,13 @@ class BlockletManager extends BaseBlockletManager {
|
|
|
1359
1532
|
writeStream.on('finish', resolve);
|
|
1360
1533
|
});
|
|
1361
1534
|
|
|
1535
|
+
return { cwd, tarFile };
|
|
1536
|
+
}
|
|
1537
|
+
|
|
1538
|
+
async _installFromUpload({ file, did, diffVersion, deleteSet, context }) {
|
|
1539
|
+
logger.info('install blocklet', { from: 'upload file' });
|
|
1540
|
+
const { cwd, tarFile } = await this._downloadFromUpload(file);
|
|
1541
|
+
|
|
1362
1542
|
// diff deploy
|
|
1363
1543
|
if (did && diffVersion) {
|
|
1364
1544
|
const oldBlocklet = await states.blocklet.getBlocklet(did);
|
|
@@ -1379,14 +1559,12 @@ class BlockletManager extends BaseBlockletManager {
|
|
|
1379
1559
|
throw new Error(`Can not deploy blocklet when it is ${fromBlockletStatus(oldBlocklet.status)}`);
|
|
1380
1560
|
}
|
|
1381
1561
|
|
|
1382
|
-
const { meta } = await this._resolveDiffDownload(cwd, tarFile, deleteSet, oldBlocklet);
|
|
1383
|
-
const childrenMeta = await getChildrenMeta(meta);
|
|
1384
|
-
mergeMeta(meta, childrenMeta);
|
|
1562
|
+
const { meta } = await this._resolveDiffDownload(cwd, tarFile, deleteSet, oldBlocklet.meta);
|
|
1385
1563
|
const newBlocklet = await states.blocklet.getBlocklet(did);
|
|
1386
1564
|
newBlocklet.meta = meta;
|
|
1387
1565
|
newBlocklet.source = BlockletSource.upload;
|
|
1388
1566
|
newBlocklet.deployedFrom = `Upload by ${context.user.did}`;
|
|
1389
|
-
newBlocklet.children = await
|
|
1567
|
+
newBlocklet.children = await this._getChildren(meta);
|
|
1390
1568
|
await validateBlocklet(newBlocklet);
|
|
1391
1569
|
await this._downloadBlocklet(newBlocklet, oldBlocklet);
|
|
1392
1570
|
|
|
@@ -1401,19 +1579,18 @@ class BlockletManager extends BaseBlockletManager {
|
|
|
1401
1579
|
const { meta } = await this._resolveDownload(cwd, tarFile);
|
|
1402
1580
|
const oldBlocklet = await states.blocklet.getBlocklet(meta.did);
|
|
1403
1581
|
|
|
1582
|
+
// full deploy - upgrade
|
|
1404
1583
|
if (oldBlocklet) {
|
|
1405
1584
|
if (isInProgress(oldBlocklet.status)) {
|
|
1406
1585
|
logger.error(`Can not deploy blocklet when it is ${fromBlockletStatus(oldBlocklet.status)}`);
|
|
1407
1586
|
throw new Error(`Can not deploy blocklet when it is ${fromBlockletStatus(oldBlocklet.status)}`);
|
|
1408
1587
|
}
|
|
1409
1588
|
|
|
1410
|
-
const childrenMeta = await getChildrenMeta(meta);
|
|
1411
|
-
mergeMeta(meta, childrenMeta);
|
|
1412
1589
|
const newBlocklet = await states.blocklet.getBlocklet(meta.did);
|
|
1413
1590
|
newBlocklet.meta = meta;
|
|
1414
1591
|
newBlocklet.source = BlockletSource.upload;
|
|
1415
1592
|
newBlocklet.deployedFrom = `Upload by ${context.user.did}`;
|
|
1416
|
-
newBlocklet.children = await
|
|
1593
|
+
newBlocklet.children = await this._getChildren(meta);
|
|
1417
1594
|
|
|
1418
1595
|
await validateBlocklet(newBlocklet);
|
|
1419
1596
|
await this._downloadBlocklet(newBlocklet, oldBlocklet);
|
|
@@ -1425,14 +1602,14 @@ class BlockletManager extends BaseBlockletManager {
|
|
|
1425
1602
|
});
|
|
1426
1603
|
}
|
|
1427
1604
|
|
|
1428
|
-
|
|
1429
|
-
|
|
1605
|
+
// full deploy - install
|
|
1606
|
+
const children = await this._getChildren(meta);
|
|
1430
1607
|
const blocklet = await states.blocklet.addBlocklet({
|
|
1431
1608
|
did: meta.did,
|
|
1432
1609
|
meta,
|
|
1433
1610
|
source: BlockletSource.upload,
|
|
1434
1611
|
deployedFrom: `Upload by ${context.user.did}`,
|
|
1435
|
-
|
|
1612
|
+
children,
|
|
1436
1613
|
});
|
|
1437
1614
|
|
|
1438
1615
|
await validateBlocklet(blocklet);
|
|
@@ -1440,13 +1617,92 @@ class BlockletManager extends BaseBlockletManager {
|
|
|
1440
1617
|
await this._setConfigs(meta.did);
|
|
1441
1618
|
|
|
1442
1619
|
// download
|
|
1443
|
-
await this._downloadBlocklet(
|
|
1620
|
+
await this._downloadBlocklet(
|
|
1621
|
+
blocklet,
|
|
1622
|
+
// let downloader skip re-downloading dynamic blocklet
|
|
1623
|
+
{ children: children.filter((x) => x.dynamic) }
|
|
1624
|
+
);
|
|
1444
1625
|
return this._installBlocklet({
|
|
1445
1626
|
did: meta.did,
|
|
1446
1627
|
context,
|
|
1447
1628
|
});
|
|
1448
1629
|
}
|
|
1449
1630
|
|
|
1631
|
+
async _installComponentFromUpload({ rootDid, mountPoint, file, did, diffVersion, deleteSet, context }) {
|
|
1632
|
+
logger.info('install blocklet', { from: 'upload file' });
|
|
1633
|
+
// download
|
|
1634
|
+
const { cwd, tarFile } = await this._downloadFromUpload(file);
|
|
1635
|
+
|
|
1636
|
+
const oldBlocklet = await states.blocklet.getBlocklet(rootDid);
|
|
1637
|
+
if (!oldBlocklet) {
|
|
1638
|
+
throw new Error('Root blocklet does not exist');
|
|
1639
|
+
}
|
|
1640
|
+
|
|
1641
|
+
if (isInProgress(oldBlocklet.status)) {
|
|
1642
|
+
logger.error(`Can not deploy blocklet when it is ${fromBlockletStatus(oldBlocklet.status)}`);
|
|
1643
|
+
throw new Error(`Can not deploy blocklet when it is ${fromBlockletStatus(oldBlocklet.status)}`);
|
|
1644
|
+
}
|
|
1645
|
+
|
|
1646
|
+
let meta;
|
|
1647
|
+
// diff upload
|
|
1648
|
+
if (did && diffVersion) {
|
|
1649
|
+
const oldChild = oldBlocklet.children.find((x) => x.meta.did === did);
|
|
1650
|
+
if (!oldChild) {
|
|
1651
|
+
throw new Error(`Blocklet ${did} not found when diff deploying`);
|
|
1652
|
+
}
|
|
1653
|
+
if (oldChild.meta.version !== diffVersion) {
|
|
1654
|
+
logger.error('Diff deploy: Blocklet version changed', {
|
|
1655
|
+
preVersion: diffVersion,
|
|
1656
|
+
changedVersion: oldChild.meta.version,
|
|
1657
|
+
name: oldChild.meta.name,
|
|
1658
|
+
did: oldChild.meta.did,
|
|
1659
|
+
});
|
|
1660
|
+
throw new Error('Blocklet version changed when diff deploying');
|
|
1661
|
+
}
|
|
1662
|
+
|
|
1663
|
+
meta = (await this._resolveDiffDownload(cwd, tarFile, deleteSet, oldChild.meta)).meta;
|
|
1664
|
+
} else {
|
|
1665
|
+
// full deploy
|
|
1666
|
+
meta = (await this._resolveDownload(cwd, tarFile)).meta;
|
|
1667
|
+
}
|
|
1668
|
+
|
|
1669
|
+
if (meta.did === rootDid) {
|
|
1670
|
+
// should not be here
|
|
1671
|
+
throw new Error('Cannot add self as a component');
|
|
1672
|
+
}
|
|
1673
|
+
|
|
1674
|
+
const newBlocklet = await states.blocklet.getBlocklet(rootDid);
|
|
1675
|
+
const dynamicChildren = await this._getDynamicChildrenFromSettings(rootDid);
|
|
1676
|
+
|
|
1677
|
+
const newChild = {
|
|
1678
|
+
meta,
|
|
1679
|
+
mountPoint,
|
|
1680
|
+
source: BlockletSource.upload,
|
|
1681
|
+
deployedFrom: `Upload by ${context.user.did}`,
|
|
1682
|
+
sourceUrl: '',
|
|
1683
|
+
dynamic: true,
|
|
1684
|
+
};
|
|
1685
|
+
const index = dynamicChildren.findIndex((child) => child.meta.did === meta.did);
|
|
1686
|
+
if (index >= 0) {
|
|
1687
|
+
dynamicChildren.splice(index, 1, newChild);
|
|
1688
|
+
} else {
|
|
1689
|
+
dynamicChildren.push(newChild);
|
|
1690
|
+
}
|
|
1691
|
+
|
|
1692
|
+
const staticChildren = newBlocklet.children.filter((x) => !x.dynamic);
|
|
1693
|
+
checkDuplicateComponents(dynamicChildren, staticChildren);
|
|
1694
|
+
|
|
1695
|
+
newBlocklet.children = [...staticChildren, ...dynamicChildren.map((x) => ({ ...x, dynamic: true }))];
|
|
1696
|
+
|
|
1697
|
+
await validateBlocklet(newBlocklet);
|
|
1698
|
+
|
|
1699
|
+
return this._upgradeBlocklet({
|
|
1700
|
+
oldBlocklet,
|
|
1701
|
+
newBlocklet,
|
|
1702
|
+
context,
|
|
1703
|
+
});
|
|
1704
|
+
}
|
|
1705
|
+
|
|
1450
1706
|
/**
|
|
1451
1707
|
* add to download job queue
|
|
1452
1708
|
* @param {string} did blocklet did
|
|
@@ -1466,22 +1722,16 @@ class BlockletManager extends BaseBlockletManager {
|
|
|
1466
1722
|
);
|
|
1467
1723
|
}
|
|
1468
1724
|
|
|
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
1725
|
async prune() {
|
|
1483
1726
|
const blocklets = await states.blocklet.getBlocklets();
|
|
1484
|
-
await
|
|
1727
|
+
const settings = await states.blockletExtras.listSettings();
|
|
1728
|
+
await pruneBlockletBundle({
|
|
1729
|
+
installDir: this.dataDirs.blocklets,
|
|
1730
|
+
blocklets,
|
|
1731
|
+
blockletSettings: settings
|
|
1732
|
+
.filter((x) => x.settings.children && x.settings.children.length)
|
|
1733
|
+
.map((x) => x.settings),
|
|
1734
|
+
});
|
|
1485
1735
|
}
|
|
1486
1736
|
|
|
1487
1737
|
async getLatestBlockletVersion({ did, version }) {
|
|
@@ -1569,20 +1819,35 @@ class BlockletManager extends BaseBlockletManager {
|
|
|
1569
1819
|
blocklets.forEach(run);
|
|
1570
1820
|
}
|
|
1571
1821
|
|
|
1822
|
+
async _getChildren(meta) {
|
|
1823
|
+
const staticChildren = await parseChildren(meta);
|
|
1824
|
+
const dynamicChildren = await parseChildren(meta, {
|
|
1825
|
+
children: await states.blockletExtras.getSettings(meta.did, 'children', []),
|
|
1826
|
+
dynamic: true,
|
|
1827
|
+
});
|
|
1828
|
+
checkDuplicateComponents(dynamicChildren, staticChildren);
|
|
1829
|
+
|
|
1830
|
+
return [...staticChildren, ...dynamicChildren];
|
|
1831
|
+
}
|
|
1832
|
+
|
|
1833
|
+
async _getDynamicChildrenFromSettings(did) {
|
|
1834
|
+
const children = await states.blockletExtras.getSettings(did, 'children', []);
|
|
1835
|
+
return children.map((x) => ({ ...x, dynamic: true }));
|
|
1836
|
+
}
|
|
1837
|
+
|
|
1572
1838
|
async _install({ meta, source, deployedFrom, context, sync }) {
|
|
1573
1839
|
validateBlockletMeta(meta, { ensureDist: true });
|
|
1574
1840
|
|
|
1575
1841
|
const { name, did, version } = meta;
|
|
1576
1842
|
|
|
1577
|
-
const
|
|
1578
|
-
mergeMeta(meta, childrenMeta);
|
|
1843
|
+
const children = await this._getChildren(meta);
|
|
1579
1844
|
try {
|
|
1580
1845
|
const blocklet = await states.blocklet.addBlocklet({
|
|
1581
1846
|
did: meta.did,
|
|
1582
1847
|
meta,
|
|
1583
1848
|
source,
|
|
1584
1849
|
deployedFrom,
|
|
1585
|
-
|
|
1850
|
+
children,
|
|
1586
1851
|
});
|
|
1587
1852
|
|
|
1588
1853
|
await validateBlocklet(blocklet);
|
|
@@ -1597,6 +1862,7 @@ class BlockletManager extends BaseBlockletManager {
|
|
|
1597
1862
|
// download
|
|
1598
1863
|
const downloadParams = {
|
|
1599
1864
|
blocklet: { ...blocklet1 },
|
|
1865
|
+
oldBlocklet: { children: children.filter((x) => x.dynamic) }, // let downloader skip re-downloading dynamic blocklet
|
|
1600
1866
|
context,
|
|
1601
1867
|
postAction: 'install',
|
|
1602
1868
|
};
|
|
@@ -1655,7 +1921,7 @@ class BlockletManager extends BaseBlockletManager {
|
|
|
1655
1921
|
}
|
|
1656
1922
|
|
|
1657
1923
|
async _upgrade({ meta, source, deployedFrom, context, sync }) {
|
|
1658
|
-
validateBlockletMeta(meta, { ensureDist:
|
|
1924
|
+
validateBlockletMeta(meta, { ensureDist: meta.group !== BlockletGroup.gateway });
|
|
1659
1925
|
|
|
1660
1926
|
const { name, version, did } = meta;
|
|
1661
1927
|
|
|
@@ -1666,12 +1932,11 @@ class BlockletManager extends BaseBlockletManager {
|
|
|
1666
1932
|
logger.info(`${action} blocklet`, { did, version });
|
|
1667
1933
|
|
|
1668
1934
|
const newBlocklet = await states.blocklet.setBlockletStatus(did, BlockletStatus.waiting);
|
|
1669
|
-
|
|
1670
|
-
mergeMeta(meta, childrenMeta);
|
|
1935
|
+
|
|
1671
1936
|
newBlocklet.meta = meta;
|
|
1672
1937
|
newBlocklet.source = source;
|
|
1673
1938
|
newBlocklet.deployedFrom = deployedFrom;
|
|
1674
|
-
newBlocklet.children = await
|
|
1939
|
+
newBlocklet.children = await this._getChildren(meta);
|
|
1675
1940
|
|
|
1676
1941
|
await validateBlocklet(newBlocklet);
|
|
1677
1942
|
|
|
@@ -1774,7 +2039,7 @@ class BlockletManager extends BaseBlockletManager {
|
|
|
1774
2039
|
|
|
1775
2040
|
await ensureBlockletExpanded(meta, downloadDir);
|
|
1776
2041
|
|
|
1777
|
-
installDir =
|
|
2042
|
+
installDir = getBundleDir(this.installDir, meta);
|
|
1778
2043
|
if (fs.existsSync(installDir)) {
|
|
1779
2044
|
fs.removeSync(installDir);
|
|
1780
2045
|
logger.info('cleanup blocklet upgrade dir', { name, version, installDir });
|
|
@@ -1791,7 +2056,7 @@ class BlockletManager extends BaseBlockletManager {
|
|
|
1791
2056
|
return { meta, installDir };
|
|
1792
2057
|
}
|
|
1793
2058
|
|
|
1794
|
-
async _resolveDiffDownload(cwd, tarFile, deleteSet,
|
|
2059
|
+
async _resolveDiffDownload(cwd, tarFile, deleteSet, bundle) {
|
|
1795
2060
|
logger.info('Resolve diff download', { tarFile, cwd });
|
|
1796
2061
|
const downloadDir = path.join(cwd, `${path.basename(tarFile, path.extname(tarFile))}`);
|
|
1797
2062
|
const diffDir = `${downloadDir}-diff`;
|
|
@@ -1804,7 +2069,7 @@ class BlockletManager extends BaseBlockletManager {
|
|
|
1804
2069
|
throw error;
|
|
1805
2070
|
}
|
|
1806
2071
|
logger.info('Copy installDir to downloadDir', { installDir: this.installDir, downloadDir });
|
|
1807
|
-
await fs.copy(
|
|
2072
|
+
await fs.copy(getBundleDir(this.installDir, bundle), downloadDir);
|
|
1808
2073
|
try {
|
|
1809
2074
|
// delete
|
|
1810
2075
|
logger.info('Delete files from downloadDir', { fileNum: deleteSet.length });
|
|
@@ -1833,11 +2098,11 @@ class BlockletManager extends BaseBlockletManager {
|
|
|
1833
2098
|
|
|
1834
2099
|
await ensureBlockletExpanded(meta, downloadDir);
|
|
1835
2100
|
|
|
1836
|
-
const
|
|
1837
|
-
logger.info('Move downloadDir to installDir', { downloadDir,
|
|
1838
|
-
await fs.move(downloadDir,
|
|
2101
|
+
const bundleDir = getBundleDir(this.installDir, meta);
|
|
2102
|
+
logger.info('Move downloadDir to installDir', { downloadDir, bundleDir });
|
|
2103
|
+
await fs.move(downloadDir, bundleDir, { overwrite: true });
|
|
1839
2104
|
|
|
1840
|
-
return { meta, installDir };
|
|
2105
|
+
return { meta, installDir: bundleDir };
|
|
1841
2106
|
} catch (error) {
|
|
1842
2107
|
fs.removeSync(downloadDir);
|
|
1843
2108
|
fs.removeSync(diffDir);
|
|
@@ -1865,10 +2130,10 @@ class BlockletManager extends BaseBlockletManager {
|
|
|
1865
2130
|
// pre install
|
|
1866
2131
|
const nodeEnvironments = await states.node.getEnvironments();
|
|
1867
2132
|
const preInstall = (b) =>
|
|
1868
|
-
hooks.preInstall({
|
|
2133
|
+
hooks.preInstall(b.env.appId, {
|
|
1869
2134
|
hooks: Object.assign(b.meta.hooks || {}, b.meta.scripts || {}),
|
|
1870
2135
|
env: { ...nodeEnvironments },
|
|
1871
|
-
appDir:
|
|
2136
|
+
appDir: b.env.appDir,
|
|
1872
2137
|
did, // root blocklet did
|
|
1873
2138
|
notification: states.notification,
|
|
1874
2139
|
context,
|
|
@@ -1881,10 +2146,10 @@ class BlockletManager extends BaseBlockletManager {
|
|
|
1881
2146
|
|
|
1882
2147
|
// post install
|
|
1883
2148
|
const postInstall = (b) =>
|
|
1884
|
-
hooks.postInstall({
|
|
2149
|
+
hooks.postInstall(b.env.appId, {
|
|
1885
2150
|
hooks: Object.assign(b.meta.hooks || {}, b.meta.scripts || {}),
|
|
1886
2151
|
env: getRuntimeEnvironments(b, nodeEnvironments, blocklet),
|
|
1887
|
-
appDir:
|
|
2152
|
+
appDir: b.env.appDir,
|
|
1888
2153
|
did, // root blocklet did
|
|
1889
2154
|
notification: states.notification,
|
|
1890
2155
|
context,
|
|
@@ -1894,17 +2159,6 @@ class BlockletManager extends BaseBlockletManager {
|
|
|
1894
2159
|
await states.blocklet.setBlockletStatus(did, BlockletStatus.installed);
|
|
1895
2160
|
blocklet = await this.ensureBlocklet(did);
|
|
1896
2161
|
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
2162
|
|
|
1909
2163
|
this.emit(BlockletEvents.installed, { blocklet, context });
|
|
1910
2164
|
|
|
@@ -1965,10 +2219,10 @@ class BlockletManager extends BaseBlockletManager {
|
|
|
1965
2219
|
// pre install
|
|
1966
2220
|
const nodeEnvironments = await states.node.getEnvironments();
|
|
1967
2221
|
const preInstall = (b) =>
|
|
1968
|
-
hooks.preInstall({
|
|
2222
|
+
hooks.preInstall(b.env.appId, {
|
|
1969
2223
|
hooks: Object.assign(b.meta.hooks || {}, b.meta.scripts || {}),
|
|
1970
2224
|
env: { ...nodeEnvironments },
|
|
1971
|
-
appDir:
|
|
2225
|
+
appDir: b.env.appDir,
|
|
1972
2226
|
did, // root blocklet did
|
|
1973
2227
|
notification: states.notification,
|
|
1974
2228
|
context,
|
|
@@ -1981,7 +2235,7 @@ class BlockletManager extends BaseBlockletManager {
|
|
|
1981
2235
|
|
|
1982
2236
|
// post install
|
|
1983
2237
|
const postInstall = (b) =>
|
|
1984
|
-
hooks.postInstall({
|
|
2238
|
+
hooks.postInstall(b.env.appId, {
|
|
1985
2239
|
hooks: Object.assign(b.meta.hooks || {}, b.meta.scripts || {}),
|
|
1986
2240
|
env: getRuntimeEnvironments(b, nodeEnvironments, blocklet),
|
|
1987
2241
|
appDir: b.env.appDir,
|
|
@@ -1997,10 +2251,10 @@ class BlockletManager extends BaseBlockletManager {
|
|
|
1997
2251
|
if (b.meta.did === did) {
|
|
1998
2252
|
return runMigrationScripts({
|
|
1999
2253
|
blocklet: b,
|
|
2254
|
+
appDir: b.env.appDir,
|
|
2255
|
+
env: getRuntimeEnvironments(b, nodeEnvironments, blocklet),
|
|
2000
2256
|
oldVersion,
|
|
2001
2257
|
newVersion: version,
|
|
2002
|
-
env: getRuntimeEnvironments(b, nodeEnvironments, blocklet),
|
|
2003
|
-
appDir: b.env.appDir,
|
|
2004
2258
|
did: b.meta.did,
|
|
2005
2259
|
notification: states.notification,
|
|
2006
2260
|
context,
|
|
@@ -2027,7 +2281,7 @@ class BlockletManager extends BaseBlockletManager {
|
|
|
2027
2281
|
} else {
|
|
2028
2282
|
const status =
|
|
2029
2283
|
oldBlocklet.status === BlockletStatus.installed ? BlockletStatus.installed : BlockletStatus.stopped;
|
|
2030
|
-
await states.blocklet.setBlockletStatus(did, status);
|
|
2284
|
+
await states.blocklet.setBlockletStatus(did, status, { children: 'all' });
|
|
2031
2285
|
}
|
|
2032
2286
|
|
|
2033
2287
|
blocklet = await this.ensureBlocklet(did, context);
|
|
@@ -2053,6 +2307,12 @@ class BlockletManager extends BaseBlockletManager {
|
|
|
2053
2307
|
logger.error('emit upgrade notification failed', { name, version, error });
|
|
2054
2308
|
}
|
|
2055
2309
|
|
|
2310
|
+
// Update dynamic component meta in blocklet settings
|
|
2311
|
+
const dynamicChildren = blocklet.children
|
|
2312
|
+
.filter((x) => x.dynamic)
|
|
2313
|
+
.map((x) => pick(x, ['meta', 'mountPoint', 'sourceUrl', 'source']));
|
|
2314
|
+
await states.blockletExtras.setSettings(did, { children: dynamicChildren });
|
|
2315
|
+
|
|
2056
2316
|
return blocklet;
|
|
2057
2317
|
} catch (err) {
|
|
2058
2318
|
const b = await this._rollback(action, did, oldBlocklet);
|
|
@@ -2245,10 +2505,7 @@ class BlockletManager extends BaseBlockletManager {
|
|
|
2245
2505
|
} = blocklet;
|
|
2246
2506
|
|
|
2247
2507
|
const metas = [];
|
|
2248
|
-
if (
|
|
2249
|
-
![BlockletSource.upload, BlockletSource.local].includes(blocklet.source) &&
|
|
2250
|
-
get(oldBlocklet, 'meta.dist.integrity') !== get(blocklet, 'meta.dist.integrity')
|
|
2251
|
-
) {
|
|
2508
|
+
if (needBlockletDownload(blocklet)) {
|
|
2252
2509
|
metas.push(blocklet.meta);
|
|
2253
2510
|
}
|
|
2254
2511
|
|
|
@@ -2259,12 +2516,19 @@ class BlockletManager extends BaseBlockletManager {
|
|
|
2259
2516
|
|
|
2260
2517
|
for (const child of blocklet.children) {
|
|
2261
2518
|
const oldChild = oldChildren[child.meta.did];
|
|
2262
|
-
if (
|
|
2519
|
+
if (needBlockletDownload(child, oldChild)) {
|
|
2263
2520
|
metas.push(child.meta);
|
|
2264
2521
|
}
|
|
2265
2522
|
}
|
|
2266
2523
|
|
|
2524
|
+
// update children status
|
|
2525
|
+
const blocklet1 = await states.blocklet.setBlockletStatus(did, BlockletStatus.downloading, {
|
|
2526
|
+
children: metas.map((x) => ({ did: x.did })),
|
|
2527
|
+
});
|
|
2528
|
+
this.emit(BlockletEvents.statusChange, blocklet1);
|
|
2529
|
+
|
|
2267
2530
|
try {
|
|
2531
|
+
logger.info('Download Blocklet', { name, did, bundles: metas.map((x) => get(x, 'dist.tarball')) });
|
|
2268
2532
|
const tasks = [];
|
|
2269
2533
|
for (const meta of metas) {
|
|
2270
2534
|
const url = await this.registry.resolveTarballURL({
|
|
@@ -2406,6 +2670,20 @@ class BlockletManager extends BaseBlockletManager {
|
|
|
2406
2670
|
await states.blockletExtras.delChildConfigs(did, child.meta.did);
|
|
2407
2671
|
}
|
|
2408
2672
|
}
|
|
2673
|
+
|
|
2674
|
+
async _findNextCustomBlockletName(leftTimes = 10) {
|
|
2675
|
+
if (leftTimes <= 0) {
|
|
2676
|
+
throw new Error('Generate custom blocklet did too many times');
|
|
2677
|
+
}
|
|
2678
|
+
const number = await states.node.increaseCustomBlockletNumber();
|
|
2679
|
+
const name = `custom-${number}`;
|
|
2680
|
+
const did = toBlockletDid(name);
|
|
2681
|
+
const blocklet = await states.blocklet.getBlocklet(did);
|
|
2682
|
+
if (blocklet) {
|
|
2683
|
+
return this._findNextCustomBlockletName(leftTimes - 1);
|
|
2684
|
+
}
|
|
2685
|
+
return { did, name };
|
|
2686
|
+
}
|
|
2409
2687
|
}
|
|
2410
2688
|
|
|
2411
2689
|
module.exports = BlockletManager;
|