@abtnode/core 1.6.16 → 1.6.20
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 +425 -151
- package/lib/blocklet/migration.js +16 -52
- package/lib/event.js +3 -2
- package/lib/index.js +2 -1
- package/lib/migrations/1.6.17-blocklet-children.js +48 -0
- package/lib/router/helper.js +11 -9
- package/lib/router/manager.js +45 -41
- package/lib/states/blocklet-extras.js +39 -3
- package/lib/states/blocklet.js +84 -12
- package/lib/states/node.js +17 -2
- package/lib/util/blocklet.js +284 -68
- package/lib/util/get-domain-for-blocklet.js +2 -2
- package/lib/util/upgrade.js +8 -4
- package/package.json +23 -23
|
@@ -3,12 +3,13 @@
|
|
|
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');
|
|
@@ -16,17 +17,23 @@ 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
|
|
@@ -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
|
|
|
@@ -561,14 +627,13 @@ class BlockletManager extends BaseBlockletManager {
|
|
|
561
627
|
}
|
|
562
628
|
|
|
563
629
|
// FIXME: we should also call preConfig for child blocklets
|
|
564
|
-
await hooks.preConfig({
|
|
630
|
+
await hooks.preConfig(blocklet.env.appId, {
|
|
565
631
|
appDir: blocklet.env.appDir,
|
|
566
632
|
hooks: Object.assign(blocklet.meta.hooks || {}, blocklet.meta.scripts || {}),
|
|
567
633
|
exitOnError: true,
|
|
568
634
|
env: { ...getRuntimeEnvironments(blocklet, nodeEnvironments), ...blocklet.configObj },
|
|
569
635
|
did,
|
|
570
636
|
context,
|
|
571
|
-
progress: blocklet.mode === BLOCKLET_MODES.DEVELOPMENT,
|
|
572
637
|
});
|
|
573
638
|
|
|
574
639
|
// update db
|
|
@@ -664,56 +729,45 @@ class BlockletManager extends BaseBlockletManager {
|
|
|
664
729
|
}
|
|
665
730
|
|
|
666
731
|
// eslint-disable-next-line no-unused-vars
|
|
667
|
-
async diff({ did, hashFiles: clientFiles }, context) {
|
|
732
|
+
async diff({ did, hashFiles: clientFiles, rootDid: inputRootDid }, context) {
|
|
668
733
|
if (!did) {
|
|
669
734
|
throw new Error('did is empty');
|
|
670
735
|
}
|
|
736
|
+
|
|
671
737
|
if (!clientFiles || !clientFiles.length) {
|
|
672
738
|
throw new Error('hashFiles is empty');
|
|
673
739
|
}
|
|
674
740
|
|
|
675
|
-
|
|
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;
|
|
676
756
|
|
|
677
|
-
const state = await states.blocklet.getBlocklet(did);
|
|
678
757
|
if (!state) {
|
|
679
758
|
return {
|
|
680
759
|
hasBlocklet: false,
|
|
681
760
|
};
|
|
682
761
|
}
|
|
762
|
+
|
|
683
763
|
if (state.source === BlockletSource.local) {
|
|
684
764
|
throw new Error(`Blocklet ${state.meta.name} is already deployed from local, can not deployed from remote.`);
|
|
685
765
|
}
|
|
686
|
-
const { name, version } = state.meta;
|
|
687
|
-
const installDir = path.join(this.installDir, name, version);
|
|
688
|
-
// eslint-disable-next-line no-param-reassign
|
|
689
|
-
clientFiles = clientFiles.reduce((obj, item) => {
|
|
690
|
-
obj[item.file] = item.hash;
|
|
691
|
-
return obj;
|
|
692
|
-
}, {});
|
|
693
766
|
|
|
694
|
-
const {
|
|
695
|
-
|
|
696
|
-
|
|
697
|
-
|
|
698
|
-
logger.info('Get files hash', { filesNum: Object.keys(files).length });
|
|
699
|
-
|
|
700
|
-
const addSet = [];
|
|
701
|
-
const changeSet = [];
|
|
702
|
-
const deleteSet = [];
|
|
703
|
-
const diffFiles = diff(files, clientFiles);
|
|
704
|
-
if (diffFiles) {
|
|
705
|
-
diffFiles.forEach((item) => {
|
|
706
|
-
if (item.kind === 'D') {
|
|
707
|
-
deleteSet.push(item.path[0]);
|
|
708
|
-
}
|
|
709
|
-
if (item.kind === 'E') {
|
|
710
|
-
changeSet.push(item.path[0]);
|
|
711
|
-
}
|
|
712
|
-
if (item.kind === 'N') {
|
|
713
|
-
addSet.push(item.path[0]);
|
|
714
|
-
}
|
|
715
|
-
});
|
|
716
|
-
}
|
|
767
|
+
const { version } = state.meta;
|
|
768
|
+
const bundleDir = getBundleDir(this.installDir, state.meta);
|
|
769
|
+
const { addSet, changeSet, deleteSet } = await getDiffFiles(clientFiles, bundleDir);
|
|
770
|
+
|
|
717
771
|
logger.info('Diff files', {
|
|
718
772
|
name: state.meta.name,
|
|
719
773
|
did: state.meta.did,
|
|
@@ -722,6 +776,7 @@ class BlockletManager extends BaseBlockletManager {
|
|
|
722
776
|
changeNum: changeSet.length,
|
|
723
777
|
deleteNum: deleteSet.length,
|
|
724
778
|
});
|
|
779
|
+
|
|
725
780
|
return {
|
|
726
781
|
hasBlocklet: true,
|
|
727
782
|
version,
|
|
@@ -733,10 +788,20 @@ class BlockletManager extends BaseBlockletManager {
|
|
|
733
788
|
|
|
734
789
|
async checkChildrenForUpdates({ did }) {
|
|
735
790
|
const blocklet = await states.blocklet.getBlocklet(did);
|
|
736
|
-
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
|
+
|
|
737
802
|
const updateList = getUpdateMetaList(
|
|
738
|
-
blocklet.children.map((x) => x.meta),
|
|
739
|
-
|
|
803
|
+
[...blocklet.children.map((x) => x.meta), ...oldDynamicChildren.map((x) => x.meta)],
|
|
804
|
+
[...newStaticChildren.map((x) => x.meta), ...newDynamicChildren.map((x) => x.meta)]
|
|
740
805
|
);
|
|
741
806
|
|
|
742
807
|
if (!updateList.length) {
|
|
@@ -746,7 +811,8 @@ class BlockletManager extends BaseBlockletManager {
|
|
|
746
811
|
// start session
|
|
747
812
|
const { id: updateId } = await states.session.start({
|
|
748
813
|
did,
|
|
749
|
-
|
|
814
|
+
staticChildren: newStaticChildren,
|
|
815
|
+
dynamicChildren: newDynamicChildren,
|
|
750
816
|
});
|
|
751
817
|
|
|
752
818
|
return {
|
|
@@ -755,11 +821,23 @@ class BlockletManager extends BaseBlockletManager {
|
|
|
755
821
|
};
|
|
756
822
|
}
|
|
757
823
|
|
|
758
|
-
async updateChildren({ updateId }, context) {
|
|
759
|
-
|
|
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
|
+
}
|
|
760
839
|
|
|
761
840
|
// get old blocklet
|
|
762
|
-
const oldBlocklet = await states.blocklet.getBlocklet(did);
|
|
763
841
|
const { meta } = oldBlocklet;
|
|
764
842
|
const { name, version } = meta;
|
|
765
843
|
|
|
@@ -769,14 +847,13 @@ class BlockletManager extends BaseBlockletManager {
|
|
|
769
847
|
did,
|
|
770
848
|
name,
|
|
771
849
|
version,
|
|
772
|
-
children:
|
|
850
|
+
children: children.map((x) => ({ name: x.meta.name, version: x.meta.version })),
|
|
773
851
|
});
|
|
774
852
|
|
|
775
853
|
// new blocklet
|
|
776
854
|
const newBlocklet = await states.blocklet.setBlockletStatus(did, BlockletStatus.waiting);
|
|
777
|
-
|
|
778
|
-
newBlocklet.
|
|
779
|
-
newBlocklet.children = await states.blocklet.getChildrenFromMetas(childrenMeta);
|
|
855
|
+
|
|
856
|
+
newBlocklet.children = children;
|
|
780
857
|
await validateBlocklet(newBlocklet);
|
|
781
858
|
|
|
782
859
|
this.emit(BlockletEvents.statusChange, newBlocklet);
|
|
@@ -814,6 +891,11 @@ class BlockletManager extends BaseBlockletManager {
|
|
|
814
891
|
// ============================================================================================
|
|
815
892
|
// Internal API that are used by public APIs and called from CLI
|
|
816
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
|
+
*/
|
|
817
899
|
async dev(folder) {
|
|
818
900
|
logger.info('dev blocklet', { folder });
|
|
819
901
|
|
|
@@ -846,30 +928,33 @@ class BlockletManager extends BaseBlockletManager {
|
|
|
846
928
|
await this.deleteProcess({ did });
|
|
847
929
|
logger.info('delete blocklet precess for dev', { did, version });
|
|
848
930
|
} catch (err) {
|
|
849
|
-
|
|
931
|
+
if (process.env.NODE_ENV !== 'development') {
|
|
932
|
+
logger.error('failed to delete blocklet process for dev', { error: err });
|
|
933
|
+
}
|
|
850
934
|
}
|
|
851
935
|
|
|
852
|
-
const
|
|
853
|
-
|
|
854
|
-
const blocklet = await states.blocklet.addBlocklet({
|
|
936
|
+
const children = await this._getChildren(meta);
|
|
937
|
+
const added = await states.blocklet.addBlocklet({
|
|
855
938
|
did,
|
|
856
939
|
meta,
|
|
857
940
|
source: BlockletSource.local,
|
|
858
941
|
deployedFrom: folder,
|
|
859
942
|
mode: BLOCKLET_MODES.DEVELOPMENT,
|
|
860
|
-
|
|
943
|
+
children,
|
|
861
944
|
});
|
|
862
945
|
logger.info('add blocklet for dev', { did, version, meta });
|
|
863
946
|
|
|
864
|
-
|
|
947
|
+
const oldBlocklet = { children: children.filter((x) => x.dynamic) }; // let downloader skip re-downloading dynamic blocklet
|
|
948
|
+
await this._downloadBlocklet(added, oldBlocklet);
|
|
865
949
|
await states.blocklet.setBlockletStatus(did, BlockletStatus.installed);
|
|
866
950
|
|
|
867
951
|
// Add environments
|
|
868
952
|
await this._setConfigs(did);
|
|
869
953
|
await this.updateBlockletEnvironment(did);
|
|
870
954
|
|
|
871
|
-
|
|
872
|
-
|
|
955
|
+
const blocklet = await this.ensureBlocklet(did);
|
|
956
|
+
|
|
957
|
+
return blocklet;
|
|
873
958
|
}
|
|
874
959
|
|
|
875
960
|
async ensureBlocklet(did) {
|
|
@@ -1004,7 +1089,8 @@ class BlockletManager extends BaseBlockletManager {
|
|
|
1004
1089
|
blocklet.diskInfo = await getDiskInfo(blocklet, { useFakeDiskInfo: !diskInfo });
|
|
1005
1090
|
|
|
1006
1091
|
try {
|
|
1007
|
-
const
|
|
1092
|
+
const app = blocklet.meta.group === BlockletGroup.gateway ? blocklet.children[0].env : blocklet.env;
|
|
1093
|
+
const { appId } = app;
|
|
1008
1094
|
blocklet.runtimeInfo = await getRuntimeInfo(appId);
|
|
1009
1095
|
if (blocklet.runtimeInfo.status && shouldUpdateBlockletStatus(blocklet.status)) {
|
|
1010
1096
|
blocklet.status = statusMap[blocklet.runtimeInfo.status];
|
|
@@ -1097,9 +1183,6 @@ class BlockletManager extends BaseBlockletManager {
|
|
|
1097
1183
|
return;
|
|
1098
1184
|
}
|
|
1099
1185
|
|
|
1100
|
-
const blocklet1 = await states.blocklet.setBlockletStatus(did, BlockletStatus.downloading);
|
|
1101
|
-
this.emit(BlockletEvents.statusChange, blocklet1);
|
|
1102
|
-
|
|
1103
1186
|
preDownloadLock.release();
|
|
1104
1187
|
|
|
1105
1188
|
const { isCancelled } = await this._downloadBlocklet(blocklet, oldBlocklet);
|
|
@@ -1245,14 +1328,15 @@ class BlockletManager extends BaseBlockletManager {
|
|
|
1245
1328
|
const blocklet = await states.blocklet.getBlocklet(did);
|
|
1246
1329
|
const nodeInfo = await states.node.read();
|
|
1247
1330
|
|
|
1248
|
-
const rootSystemEnvironments =
|
|
1249
|
-
|
|
1331
|
+
const rootSystemEnvironments = {
|
|
1332
|
+
...getRootSystemEnvironments(blockletWithEnv, nodeInfo),
|
|
1333
|
+
...getOverwrittenEnvironments(blockletWithEnv, nodeInfo),
|
|
1334
|
+
};
|
|
1250
1335
|
|
|
1251
1336
|
// fill environments to blocklet and blocklet.children
|
|
1252
1337
|
blocklet.environments = formatEnvironments({
|
|
1253
1338
|
...getSystemEnvironments(blockletWithEnv),
|
|
1254
1339
|
...rootSystemEnvironments,
|
|
1255
|
-
...overwrittenEnvironments,
|
|
1256
1340
|
});
|
|
1257
1341
|
|
|
1258
1342
|
for (const child of blocklet.children) {
|
|
@@ -1261,11 +1345,13 @@ class BlockletManager extends BaseBlockletManager {
|
|
|
1261
1345
|
child.environments = formatEnvironments({
|
|
1262
1346
|
...getSystemEnvironments(childWithEnv), // system env of child blocklet
|
|
1263
1347
|
...rootSystemEnvironments, // system env of root blocklet
|
|
1264
|
-
...overwrittenEnvironments,
|
|
1265
1348
|
});
|
|
1266
1349
|
}
|
|
1267
1350
|
}
|
|
1268
1351
|
|
|
1352
|
+
// put BLOCKLET_APP_ID at root level for indexing
|
|
1353
|
+
blocklet.appDid = rootSystemEnvironments.BLOCKLET_APP_ID;
|
|
1354
|
+
|
|
1269
1355
|
// update state to db
|
|
1270
1356
|
return states.blocklet.updateBlocklet(did, blocklet);
|
|
1271
1357
|
}
|
|
@@ -1278,7 +1364,7 @@ class BlockletManager extends BaseBlockletManager {
|
|
|
1278
1364
|
}
|
|
1279
1365
|
}
|
|
1280
1366
|
|
|
1281
|
-
async
|
|
1367
|
+
async _installFromStore({ did, registry }, context) {
|
|
1282
1368
|
logger.debug('start install blocklet', { did });
|
|
1283
1369
|
if (!isValidDid(did)) {
|
|
1284
1370
|
throw new Error('Blocklet did is invalid');
|
|
@@ -1340,9 +1426,92 @@ class BlockletManager extends BaseBlockletManager {
|
|
|
1340
1426
|
});
|
|
1341
1427
|
}
|
|
1342
1428
|
|
|
1343
|
-
async
|
|
1344
|
-
|
|
1345
|
-
|
|
1429
|
+
async _installComponentFromUrl({ rootDid, mountPoint, url, context }) {
|
|
1430
|
+
const blocklet = await states.blocklet.getBlocklet(rootDid);
|
|
1431
|
+
if (!blocklet) {
|
|
1432
|
+
throw new Error('Root blocklet does not exist');
|
|
1433
|
+
}
|
|
1434
|
+
|
|
1435
|
+
const meta = await getBlockletMetaFromUrl(url);
|
|
1436
|
+
|
|
1437
|
+
if (meta.did === rootDid) {
|
|
1438
|
+
throw new Error('Cannot add self as a component');
|
|
1439
|
+
}
|
|
1440
|
+
|
|
1441
|
+
if (!isComponentBlocklet(meta)) {
|
|
1442
|
+
throw new Error('The blocklet cannot be a component');
|
|
1443
|
+
}
|
|
1444
|
+
|
|
1445
|
+
const newChildren = await parseChildren(blocklet.meta, {
|
|
1446
|
+
children: [
|
|
1447
|
+
{
|
|
1448
|
+
meta,
|
|
1449
|
+
mountPoint,
|
|
1450
|
+
sourceUrl: url,
|
|
1451
|
+
},
|
|
1452
|
+
],
|
|
1453
|
+
dynamic: true,
|
|
1454
|
+
});
|
|
1455
|
+
|
|
1456
|
+
checkDuplicateComponents(blocklet.children, newChildren);
|
|
1457
|
+
|
|
1458
|
+
// add component to db
|
|
1459
|
+
await states.blocklet.addChildren(rootDid, newChildren);
|
|
1460
|
+
|
|
1461
|
+
return this.updateChildren(
|
|
1462
|
+
{
|
|
1463
|
+
did: rootDid,
|
|
1464
|
+
children: [...blocklet.children, ...newChildren],
|
|
1465
|
+
oldBlocklet: blocklet,
|
|
1466
|
+
},
|
|
1467
|
+
context
|
|
1468
|
+
);
|
|
1469
|
+
}
|
|
1470
|
+
|
|
1471
|
+
async _installFromCreate({ title, description }, context = {}) {
|
|
1472
|
+
logger.debug('create blocklet', { title, description });
|
|
1473
|
+
|
|
1474
|
+
await joi.string().label('title').max(20).required().validateAsync(title);
|
|
1475
|
+
await joi.string().label('description').max(80).required().validateAsync(description);
|
|
1476
|
+
|
|
1477
|
+
const { did, name } = await this._findNextCustomBlockletName();
|
|
1478
|
+
const rawMeta = {
|
|
1479
|
+
name,
|
|
1480
|
+
did,
|
|
1481
|
+
title,
|
|
1482
|
+
description,
|
|
1483
|
+
version: BLOCKLET_DEFAULT_VERSION,
|
|
1484
|
+
group: BlockletGroup.gateway,
|
|
1485
|
+
interfaces: [
|
|
1486
|
+
{
|
|
1487
|
+
type: BLOCKLET_INTERFACE_TYPE_WEB,
|
|
1488
|
+
name: BLOCKLET_INTERFACE_PUBLIC,
|
|
1489
|
+
path: BLOCKLET_DEFAULT_PATH_REWRITE,
|
|
1490
|
+
prefix: BLOCKLET_DYNAMIC_PATH_PREFIX,
|
|
1491
|
+
port: BLOCKLET_DEFAULT_PORT_NAME,
|
|
1492
|
+
protocol: BLOCKLET_INTERFACE_PROTOCOL_HTTP,
|
|
1493
|
+
},
|
|
1494
|
+
],
|
|
1495
|
+
specVersion: BLOCKLET_LATEST_SPEC_VERSION,
|
|
1496
|
+
};
|
|
1497
|
+
const meta = validateMeta(rawMeta);
|
|
1498
|
+
|
|
1499
|
+
await states.blocklet.addBlocklet({
|
|
1500
|
+
did: meta.did,
|
|
1501
|
+
meta,
|
|
1502
|
+
source: BlockletSource.custom,
|
|
1503
|
+
});
|
|
1504
|
+
await this._setConfigs(did);
|
|
1505
|
+
|
|
1506
|
+
// fake install bundle
|
|
1507
|
+
const bundleDir = getBundleDir(this.installDir, meta);
|
|
1508
|
+
fs.mkdirSync(bundleDir, { recursive: true });
|
|
1509
|
+
updateMetaFile(path.join(bundleDir, BLOCKLET_META_FILE), meta);
|
|
1510
|
+
|
|
1511
|
+
return this._installBlocklet({ did, context });
|
|
1512
|
+
}
|
|
1513
|
+
|
|
1514
|
+
async _downloadFromUpload(file) {
|
|
1346
1515
|
// const { filename, mimetype, encoding, createReadStream } = await file;
|
|
1347
1516
|
const { filename, createReadStream } = await file;
|
|
1348
1517
|
const cwd = path.join(this.dataDirs.tmp, 'download');
|
|
@@ -1366,6 +1535,13 @@ class BlockletManager extends BaseBlockletManager {
|
|
|
1366
1535
|
writeStream.on('finish', resolve);
|
|
1367
1536
|
});
|
|
1368
1537
|
|
|
1538
|
+
return { cwd, tarFile };
|
|
1539
|
+
}
|
|
1540
|
+
|
|
1541
|
+
async _installFromUpload({ file, did, diffVersion, deleteSet, context }) {
|
|
1542
|
+
logger.info('install blocklet', { from: 'upload file' });
|
|
1543
|
+
const { cwd, tarFile } = await this._downloadFromUpload(file);
|
|
1544
|
+
|
|
1369
1545
|
// diff deploy
|
|
1370
1546
|
if (did && diffVersion) {
|
|
1371
1547
|
const oldBlocklet = await states.blocklet.getBlocklet(did);
|
|
@@ -1386,14 +1562,12 @@ class BlockletManager extends BaseBlockletManager {
|
|
|
1386
1562
|
throw new Error(`Can not deploy blocklet when it is ${fromBlockletStatus(oldBlocklet.status)}`);
|
|
1387
1563
|
}
|
|
1388
1564
|
|
|
1389
|
-
const { meta } = await this._resolveDiffDownload(cwd, tarFile, deleteSet, oldBlocklet);
|
|
1390
|
-
const childrenMeta = await getChildrenMeta(meta);
|
|
1391
|
-
mergeMeta(meta, childrenMeta);
|
|
1565
|
+
const { meta } = await this._resolveDiffDownload(cwd, tarFile, deleteSet, oldBlocklet.meta);
|
|
1392
1566
|
const newBlocklet = await states.blocklet.getBlocklet(did);
|
|
1393
1567
|
newBlocklet.meta = meta;
|
|
1394
1568
|
newBlocklet.source = BlockletSource.upload;
|
|
1395
1569
|
newBlocklet.deployedFrom = `Upload by ${context.user.did}`;
|
|
1396
|
-
newBlocklet.children = await
|
|
1570
|
+
newBlocklet.children = await this._getChildren(meta);
|
|
1397
1571
|
await validateBlocklet(newBlocklet);
|
|
1398
1572
|
await this._downloadBlocklet(newBlocklet, oldBlocklet);
|
|
1399
1573
|
|
|
@@ -1408,19 +1582,18 @@ class BlockletManager extends BaseBlockletManager {
|
|
|
1408
1582
|
const { meta } = await this._resolveDownload(cwd, tarFile);
|
|
1409
1583
|
const oldBlocklet = await states.blocklet.getBlocklet(meta.did);
|
|
1410
1584
|
|
|
1585
|
+
// full deploy - upgrade
|
|
1411
1586
|
if (oldBlocklet) {
|
|
1412
1587
|
if (isInProgress(oldBlocklet.status)) {
|
|
1413
1588
|
logger.error(`Can not deploy blocklet when it is ${fromBlockletStatus(oldBlocklet.status)}`);
|
|
1414
1589
|
throw new Error(`Can not deploy blocklet when it is ${fromBlockletStatus(oldBlocklet.status)}`);
|
|
1415
1590
|
}
|
|
1416
1591
|
|
|
1417
|
-
const childrenMeta = await getChildrenMeta(meta);
|
|
1418
|
-
mergeMeta(meta, childrenMeta);
|
|
1419
1592
|
const newBlocklet = await states.blocklet.getBlocklet(meta.did);
|
|
1420
1593
|
newBlocklet.meta = meta;
|
|
1421
1594
|
newBlocklet.source = BlockletSource.upload;
|
|
1422
1595
|
newBlocklet.deployedFrom = `Upload by ${context.user.did}`;
|
|
1423
|
-
newBlocklet.children = await
|
|
1596
|
+
newBlocklet.children = await this._getChildren(meta);
|
|
1424
1597
|
|
|
1425
1598
|
await validateBlocklet(newBlocklet);
|
|
1426
1599
|
await this._downloadBlocklet(newBlocklet, oldBlocklet);
|
|
@@ -1432,14 +1605,14 @@ class BlockletManager extends BaseBlockletManager {
|
|
|
1432
1605
|
});
|
|
1433
1606
|
}
|
|
1434
1607
|
|
|
1435
|
-
|
|
1436
|
-
|
|
1608
|
+
// full deploy - install
|
|
1609
|
+
const children = await this._getChildren(meta);
|
|
1437
1610
|
const blocklet = await states.blocklet.addBlocklet({
|
|
1438
1611
|
did: meta.did,
|
|
1439
1612
|
meta,
|
|
1440
1613
|
source: BlockletSource.upload,
|
|
1441
1614
|
deployedFrom: `Upload by ${context.user.did}`,
|
|
1442
|
-
|
|
1615
|
+
children,
|
|
1443
1616
|
});
|
|
1444
1617
|
|
|
1445
1618
|
await validateBlocklet(blocklet);
|
|
@@ -1447,13 +1620,92 @@ class BlockletManager extends BaseBlockletManager {
|
|
|
1447
1620
|
await this._setConfigs(meta.did);
|
|
1448
1621
|
|
|
1449
1622
|
// download
|
|
1450
|
-
await this._downloadBlocklet(
|
|
1623
|
+
await this._downloadBlocklet(
|
|
1624
|
+
blocklet,
|
|
1625
|
+
// let downloader skip re-downloading dynamic blocklet
|
|
1626
|
+
{ children: children.filter((x) => x.dynamic) }
|
|
1627
|
+
);
|
|
1451
1628
|
return this._installBlocklet({
|
|
1452
1629
|
did: meta.did,
|
|
1453
1630
|
context,
|
|
1454
1631
|
});
|
|
1455
1632
|
}
|
|
1456
1633
|
|
|
1634
|
+
async _installComponentFromUpload({ rootDid, mountPoint, file, did, diffVersion, deleteSet, context }) {
|
|
1635
|
+
logger.info('install blocklet', { from: 'upload file' });
|
|
1636
|
+
// download
|
|
1637
|
+
const { cwd, tarFile } = await this._downloadFromUpload(file);
|
|
1638
|
+
|
|
1639
|
+
const oldBlocklet = await states.blocklet.getBlocklet(rootDid);
|
|
1640
|
+
if (!oldBlocklet) {
|
|
1641
|
+
throw new Error('Root blocklet does not exist');
|
|
1642
|
+
}
|
|
1643
|
+
|
|
1644
|
+
if (isInProgress(oldBlocklet.status)) {
|
|
1645
|
+
logger.error(`Can not deploy blocklet when it is ${fromBlockletStatus(oldBlocklet.status)}`);
|
|
1646
|
+
throw new Error(`Can not deploy blocklet when it is ${fromBlockletStatus(oldBlocklet.status)}`);
|
|
1647
|
+
}
|
|
1648
|
+
|
|
1649
|
+
let meta;
|
|
1650
|
+
// diff upload
|
|
1651
|
+
if (did && diffVersion) {
|
|
1652
|
+
const oldChild = oldBlocklet.children.find((x) => x.meta.did === did);
|
|
1653
|
+
if (!oldChild) {
|
|
1654
|
+
throw new Error(`Blocklet ${did} not found when diff deploying`);
|
|
1655
|
+
}
|
|
1656
|
+
if (oldChild.meta.version !== diffVersion) {
|
|
1657
|
+
logger.error('Diff deploy: Blocklet version changed', {
|
|
1658
|
+
preVersion: diffVersion,
|
|
1659
|
+
changedVersion: oldChild.meta.version,
|
|
1660
|
+
name: oldChild.meta.name,
|
|
1661
|
+
did: oldChild.meta.did,
|
|
1662
|
+
});
|
|
1663
|
+
throw new Error('Blocklet version changed when diff deploying');
|
|
1664
|
+
}
|
|
1665
|
+
|
|
1666
|
+
meta = (await this._resolveDiffDownload(cwd, tarFile, deleteSet, oldChild.meta)).meta;
|
|
1667
|
+
} else {
|
|
1668
|
+
// full deploy
|
|
1669
|
+
meta = (await this._resolveDownload(cwd, tarFile)).meta;
|
|
1670
|
+
}
|
|
1671
|
+
|
|
1672
|
+
if (meta.did === rootDid) {
|
|
1673
|
+
// should not be here
|
|
1674
|
+
throw new Error('Cannot add self as a component');
|
|
1675
|
+
}
|
|
1676
|
+
|
|
1677
|
+
const newBlocklet = await states.blocklet.getBlocklet(rootDid);
|
|
1678
|
+
const dynamicChildren = await this._getDynamicChildrenFromSettings(rootDid);
|
|
1679
|
+
|
|
1680
|
+
const newChild = {
|
|
1681
|
+
meta,
|
|
1682
|
+
mountPoint,
|
|
1683
|
+
source: BlockletSource.upload,
|
|
1684
|
+
deployedFrom: `Upload by ${context.user.did}`,
|
|
1685
|
+
sourceUrl: '',
|
|
1686
|
+
dynamic: true,
|
|
1687
|
+
};
|
|
1688
|
+
const index = dynamicChildren.findIndex((child) => child.meta.did === meta.did);
|
|
1689
|
+
if (index >= 0) {
|
|
1690
|
+
dynamicChildren.splice(index, 1, newChild);
|
|
1691
|
+
} else {
|
|
1692
|
+
dynamicChildren.push(newChild);
|
|
1693
|
+
}
|
|
1694
|
+
|
|
1695
|
+
const staticChildren = newBlocklet.children.filter((x) => !x.dynamic);
|
|
1696
|
+
checkDuplicateComponents(dynamicChildren, staticChildren);
|
|
1697
|
+
|
|
1698
|
+
newBlocklet.children = [...staticChildren, ...dynamicChildren.map((x) => ({ ...x, dynamic: true }))];
|
|
1699
|
+
|
|
1700
|
+
await validateBlocklet(newBlocklet);
|
|
1701
|
+
|
|
1702
|
+
return this._upgradeBlocklet({
|
|
1703
|
+
oldBlocklet,
|
|
1704
|
+
newBlocklet,
|
|
1705
|
+
context,
|
|
1706
|
+
});
|
|
1707
|
+
}
|
|
1708
|
+
|
|
1457
1709
|
/**
|
|
1458
1710
|
* add to download job queue
|
|
1459
1711
|
* @param {string} did blocklet did
|
|
@@ -1473,22 +1725,16 @@ class BlockletManager extends BaseBlockletManager {
|
|
|
1473
1725
|
);
|
|
1474
1726
|
}
|
|
1475
1727
|
|
|
1476
|
-
async getStatus(did) {
|
|
1477
|
-
if (!did) {
|
|
1478
|
-
throw new Error('did is required');
|
|
1479
|
-
}
|
|
1480
|
-
|
|
1481
|
-
const blocklet = await states.blocklet.getBlocklet(did);
|
|
1482
|
-
if (!blocklet) {
|
|
1483
|
-
return null;
|
|
1484
|
-
}
|
|
1485
|
-
|
|
1486
|
-
return { name: blocklet.meta.name, did: blocklet.meta.did, status: blocklet.status };
|
|
1487
|
-
}
|
|
1488
|
-
|
|
1489
1728
|
async prune() {
|
|
1490
1729
|
const blocklets = await states.blocklet.getBlocklets();
|
|
1491
|
-
await
|
|
1730
|
+
const settings = await states.blockletExtras.listSettings();
|
|
1731
|
+
await pruneBlockletBundle({
|
|
1732
|
+
installDir: this.dataDirs.blocklets,
|
|
1733
|
+
blocklets,
|
|
1734
|
+
blockletSettings: settings
|
|
1735
|
+
.filter((x) => x.settings.children && x.settings.children.length)
|
|
1736
|
+
.map((x) => x.settings),
|
|
1737
|
+
});
|
|
1492
1738
|
}
|
|
1493
1739
|
|
|
1494
1740
|
async getLatestBlockletVersion({ did, version }) {
|
|
@@ -1576,20 +1822,35 @@ class BlockletManager extends BaseBlockletManager {
|
|
|
1576
1822
|
blocklets.forEach(run);
|
|
1577
1823
|
}
|
|
1578
1824
|
|
|
1825
|
+
async _getChildren(meta) {
|
|
1826
|
+
const staticChildren = await parseChildren(meta);
|
|
1827
|
+
const dynamicChildren = await parseChildren(meta, {
|
|
1828
|
+
children: await states.blockletExtras.getSettings(meta.did, 'children', []),
|
|
1829
|
+
dynamic: true,
|
|
1830
|
+
});
|
|
1831
|
+
checkDuplicateComponents(dynamicChildren, staticChildren);
|
|
1832
|
+
|
|
1833
|
+
return [...staticChildren, ...dynamicChildren];
|
|
1834
|
+
}
|
|
1835
|
+
|
|
1836
|
+
async _getDynamicChildrenFromSettings(did) {
|
|
1837
|
+
const children = await states.blockletExtras.getSettings(did, 'children', []);
|
|
1838
|
+
return children.map((x) => ({ ...x, dynamic: true }));
|
|
1839
|
+
}
|
|
1840
|
+
|
|
1579
1841
|
async _install({ meta, source, deployedFrom, context, sync }) {
|
|
1580
1842
|
validateBlockletMeta(meta, { ensureDist: true });
|
|
1581
1843
|
|
|
1582
1844
|
const { name, did, version } = meta;
|
|
1583
1845
|
|
|
1584
|
-
const
|
|
1585
|
-
mergeMeta(meta, childrenMeta);
|
|
1846
|
+
const children = await this._getChildren(meta);
|
|
1586
1847
|
try {
|
|
1587
1848
|
const blocklet = await states.blocklet.addBlocklet({
|
|
1588
1849
|
did: meta.did,
|
|
1589
1850
|
meta,
|
|
1590
1851
|
source,
|
|
1591
1852
|
deployedFrom,
|
|
1592
|
-
|
|
1853
|
+
children,
|
|
1593
1854
|
});
|
|
1594
1855
|
|
|
1595
1856
|
await validateBlocklet(blocklet);
|
|
@@ -1604,6 +1865,7 @@ class BlockletManager extends BaseBlockletManager {
|
|
|
1604
1865
|
// download
|
|
1605
1866
|
const downloadParams = {
|
|
1606
1867
|
blocklet: { ...blocklet1 },
|
|
1868
|
+
oldBlocklet: { children: children.filter((x) => x.dynamic) }, // let downloader skip re-downloading dynamic blocklet
|
|
1607
1869
|
context,
|
|
1608
1870
|
postAction: 'install',
|
|
1609
1871
|
};
|
|
@@ -1662,7 +1924,7 @@ class BlockletManager extends BaseBlockletManager {
|
|
|
1662
1924
|
}
|
|
1663
1925
|
|
|
1664
1926
|
async _upgrade({ meta, source, deployedFrom, context, sync }) {
|
|
1665
|
-
validateBlockletMeta(meta, { ensureDist:
|
|
1927
|
+
validateBlockletMeta(meta, { ensureDist: meta.group !== BlockletGroup.gateway });
|
|
1666
1928
|
|
|
1667
1929
|
const { name, version, did } = meta;
|
|
1668
1930
|
|
|
@@ -1673,12 +1935,11 @@ class BlockletManager extends BaseBlockletManager {
|
|
|
1673
1935
|
logger.info(`${action} blocklet`, { did, version });
|
|
1674
1936
|
|
|
1675
1937
|
const newBlocklet = await states.blocklet.setBlockletStatus(did, BlockletStatus.waiting);
|
|
1676
|
-
|
|
1677
|
-
mergeMeta(meta, childrenMeta);
|
|
1938
|
+
|
|
1678
1939
|
newBlocklet.meta = meta;
|
|
1679
1940
|
newBlocklet.source = source;
|
|
1680
1941
|
newBlocklet.deployedFrom = deployedFrom;
|
|
1681
|
-
newBlocklet.children = await
|
|
1942
|
+
newBlocklet.children = await this._getChildren(meta);
|
|
1682
1943
|
|
|
1683
1944
|
await validateBlocklet(newBlocklet);
|
|
1684
1945
|
|
|
@@ -1781,7 +2042,7 @@ class BlockletManager extends BaseBlockletManager {
|
|
|
1781
2042
|
|
|
1782
2043
|
await ensureBlockletExpanded(meta, downloadDir);
|
|
1783
2044
|
|
|
1784
|
-
installDir =
|
|
2045
|
+
installDir = getBundleDir(this.installDir, meta);
|
|
1785
2046
|
if (fs.existsSync(installDir)) {
|
|
1786
2047
|
fs.removeSync(installDir);
|
|
1787
2048
|
logger.info('cleanup blocklet upgrade dir', { name, version, installDir });
|
|
@@ -1798,7 +2059,7 @@ class BlockletManager extends BaseBlockletManager {
|
|
|
1798
2059
|
return { meta, installDir };
|
|
1799
2060
|
}
|
|
1800
2061
|
|
|
1801
|
-
async _resolveDiffDownload(cwd, tarFile, deleteSet,
|
|
2062
|
+
async _resolveDiffDownload(cwd, tarFile, deleteSet, bundle) {
|
|
1802
2063
|
logger.info('Resolve diff download', { tarFile, cwd });
|
|
1803
2064
|
const downloadDir = path.join(cwd, `${path.basename(tarFile, path.extname(tarFile))}`);
|
|
1804
2065
|
const diffDir = `${downloadDir}-diff`;
|
|
@@ -1811,7 +2072,7 @@ class BlockletManager extends BaseBlockletManager {
|
|
|
1811
2072
|
throw error;
|
|
1812
2073
|
}
|
|
1813
2074
|
logger.info('Copy installDir to downloadDir', { installDir: this.installDir, downloadDir });
|
|
1814
|
-
await fs.copy(
|
|
2075
|
+
await fs.copy(getBundleDir(this.installDir, bundle), downloadDir);
|
|
1815
2076
|
try {
|
|
1816
2077
|
// delete
|
|
1817
2078
|
logger.info('Delete files from downloadDir', { fileNum: deleteSet.length });
|
|
@@ -1840,11 +2101,11 @@ class BlockletManager extends BaseBlockletManager {
|
|
|
1840
2101
|
|
|
1841
2102
|
await ensureBlockletExpanded(meta, downloadDir);
|
|
1842
2103
|
|
|
1843
|
-
const
|
|
1844
|
-
logger.info('Move downloadDir to installDir', { downloadDir,
|
|
1845
|
-
await fs.move(downloadDir,
|
|
2104
|
+
const bundleDir = getBundleDir(this.installDir, meta);
|
|
2105
|
+
logger.info('Move downloadDir to installDir', { downloadDir, bundleDir });
|
|
2106
|
+
await fs.move(downloadDir, bundleDir, { overwrite: true });
|
|
1846
2107
|
|
|
1847
|
-
return { meta, installDir };
|
|
2108
|
+
return { meta, installDir: bundleDir };
|
|
1848
2109
|
} catch (error) {
|
|
1849
2110
|
fs.removeSync(downloadDir);
|
|
1850
2111
|
fs.removeSync(diffDir);
|
|
@@ -1872,10 +2133,10 @@ class BlockletManager extends BaseBlockletManager {
|
|
|
1872
2133
|
// pre install
|
|
1873
2134
|
const nodeEnvironments = await states.node.getEnvironments();
|
|
1874
2135
|
const preInstall = (b) =>
|
|
1875
|
-
hooks.preInstall({
|
|
2136
|
+
hooks.preInstall(b.env.appId, {
|
|
1876
2137
|
hooks: Object.assign(b.meta.hooks || {}, b.meta.scripts || {}),
|
|
1877
2138
|
env: { ...nodeEnvironments },
|
|
1878
|
-
appDir:
|
|
2139
|
+
appDir: b.env.appDir,
|
|
1879
2140
|
did, // root blocklet did
|
|
1880
2141
|
notification: states.notification,
|
|
1881
2142
|
context,
|
|
@@ -1888,10 +2149,10 @@ class BlockletManager extends BaseBlockletManager {
|
|
|
1888
2149
|
|
|
1889
2150
|
// post install
|
|
1890
2151
|
const postInstall = (b) =>
|
|
1891
|
-
hooks.postInstall({
|
|
2152
|
+
hooks.postInstall(b.env.appId, {
|
|
1892
2153
|
hooks: Object.assign(b.meta.hooks || {}, b.meta.scripts || {}),
|
|
1893
2154
|
env: getRuntimeEnvironments(b, nodeEnvironments, blocklet),
|
|
1894
|
-
appDir:
|
|
2155
|
+
appDir: b.env.appDir,
|
|
1895
2156
|
did, // root blocklet did
|
|
1896
2157
|
notification: states.notification,
|
|
1897
2158
|
context,
|
|
@@ -1901,17 +2162,6 @@ class BlockletManager extends BaseBlockletManager {
|
|
|
1901
2162
|
await states.blocklet.setBlockletStatus(did, BlockletStatus.installed);
|
|
1902
2163
|
blocklet = await this.ensureBlocklet(did);
|
|
1903
2164
|
logger.info('blocklet installed', { source, did: meta.did });
|
|
1904
|
-
if (process.env.NODE_ENV !== 'test') {
|
|
1905
|
-
const nodeInfo = await states.node.read();
|
|
1906
|
-
const blockletInfo = getBlockletInfo(blocklet, nodeInfo.sk);
|
|
1907
|
-
const updateDidDnsResult = await updateDidDocument({
|
|
1908
|
-
wallet: blockletInfo.wallet,
|
|
1909
|
-
domain: nodeInfo.didDomain,
|
|
1910
|
-
nodeDid: nodeInfo.did,
|
|
1911
|
-
didRegistryUrl: nodeInfo.didRegistry,
|
|
1912
|
-
});
|
|
1913
|
-
logger.info('updated did document', { updateDidDnsResult, blockletId: blocklet.meta.did });
|
|
1914
|
-
}
|
|
1915
2165
|
|
|
1916
2166
|
this.emit(BlockletEvents.installed, { blocklet, context });
|
|
1917
2167
|
|
|
@@ -1972,10 +2222,10 @@ class BlockletManager extends BaseBlockletManager {
|
|
|
1972
2222
|
// pre install
|
|
1973
2223
|
const nodeEnvironments = await states.node.getEnvironments();
|
|
1974
2224
|
const preInstall = (b) =>
|
|
1975
|
-
hooks.preInstall({
|
|
2225
|
+
hooks.preInstall(b.env.appId, {
|
|
1976
2226
|
hooks: Object.assign(b.meta.hooks || {}, b.meta.scripts || {}),
|
|
1977
2227
|
env: { ...nodeEnvironments },
|
|
1978
|
-
appDir:
|
|
2228
|
+
appDir: b.env.appDir,
|
|
1979
2229
|
did, // root blocklet did
|
|
1980
2230
|
notification: states.notification,
|
|
1981
2231
|
context,
|
|
@@ -1988,7 +2238,7 @@ class BlockletManager extends BaseBlockletManager {
|
|
|
1988
2238
|
|
|
1989
2239
|
// post install
|
|
1990
2240
|
const postInstall = (b) =>
|
|
1991
|
-
hooks.postInstall({
|
|
2241
|
+
hooks.postInstall(b.env.appId, {
|
|
1992
2242
|
hooks: Object.assign(b.meta.hooks || {}, b.meta.scripts || {}),
|
|
1993
2243
|
env: getRuntimeEnvironments(b, nodeEnvironments, blocklet),
|
|
1994
2244
|
appDir: b.env.appDir,
|
|
@@ -2004,10 +2254,10 @@ class BlockletManager extends BaseBlockletManager {
|
|
|
2004
2254
|
if (b.meta.did === did) {
|
|
2005
2255
|
return runMigrationScripts({
|
|
2006
2256
|
blocklet: b,
|
|
2257
|
+
appDir: b.env.appDir,
|
|
2258
|
+
env: getRuntimeEnvironments(b, nodeEnvironments, blocklet),
|
|
2007
2259
|
oldVersion,
|
|
2008
2260
|
newVersion: version,
|
|
2009
|
-
env: getRuntimeEnvironments(b, nodeEnvironments, blocklet),
|
|
2010
|
-
appDir: b.env.appDir,
|
|
2011
2261
|
did: b.meta.did,
|
|
2012
2262
|
notification: states.notification,
|
|
2013
2263
|
context,
|
|
@@ -2034,7 +2284,7 @@ class BlockletManager extends BaseBlockletManager {
|
|
|
2034
2284
|
} else {
|
|
2035
2285
|
const status =
|
|
2036
2286
|
oldBlocklet.status === BlockletStatus.installed ? BlockletStatus.installed : BlockletStatus.stopped;
|
|
2037
|
-
await states.blocklet.setBlockletStatus(did, status);
|
|
2287
|
+
await states.blocklet.setBlockletStatus(did, status, { children: 'all' });
|
|
2038
2288
|
}
|
|
2039
2289
|
|
|
2040
2290
|
blocklet = await this.ensureBlocklet(did, context);
|
|
@@ -2060,6 +2310,12 @@ class BlockletManager extends BaseBlockletManager {
|
|
|
2060
2310
|
logger.error('emit upgrade notification failed', { name, version, error });
|
|
2061
2311
|
}
|
|
2062
2312
|
|
|
2313
|
+
// Update dynamic component meta in blocklet settings
|
|
2314
|
+
const dynamicChildren = blocklet.children
|
|
2315
|
+
.filter((x) => x.dynamic)
|
|
2316
|
+
.map((x) => pick(x, ['meta', 'mountPoint', 'sourceUrl', 'source']));
|
|
2317
|
+
await states.blockletExtras.setSettings(did, { children: dynamicChildren });
|
|
2318
|
+
|
|
2063
2319
|
return blocklet;
|
|
2064
2320
|
} catch (err) {
|
|
2065
2321
|
const b = await this._rollback(action, did, oldBlocklet);
|
|
@@ -2252,10 +2508,7 @@ class BlockletManager extends BaseBlockletManager {
|
|
|
2252
2508
|
} = blocklet;
|
|
2253
2509
|
|
|
2254
2510
|
const metas = [];
|
|
2255
|
-
if (
|
|
2256
|
-
![BlockletSource.upload, BlockletSource.local].includes(blocklet.source) &&
|
|
2257
|
-
get(oldBlocklet, 'meta.dist.integrity') !== get(blocklet, 'meta.dist.integrity')
|
|
2258
|
-
) {
|
|
2511
|
+
if (needBlockletDownload(blocklet)) {
|
|
2259
2512
|
metas.push(blocklet.meta);
|
|
2260
2513
|
}
|
|
2261
2514
|
|
|
@@ -2266,12 +2519,19 @@ class BlockletManager extends BaseBlockletManager {
|
|
|
2266
2519
|
|
|
2267
2520
|
for (const child of blocklet.children) {
|
|
2268
2521
|
const oldChild = oldChildren[child.meta.did];
|
|
2269
|
-
if (
|
|
2522
|
+
if (needBlockletDownload(child, oldChild)) {
|
|
2270
2523
|
metas.push(child.meta);
|
|
2271
2524
|
}
|
|
2272
2525
|
}
|
|
2273
2526
|
|
|
2527
|
+
// update children status
|
|
2528
|
+
const blocklet1 = await states.blocklet.setBlockletStatus(did, BlockletStatus.downloading, {
|
|
2529
|
+
children: metas.map((x) => ({ did: x.did })),
|
|
2530
|
+
});
|
|
2531
|
+
this.emit(BlockletEvents.statusChange, blocklet1);
|
|
2532
|
+
|
|
2274
2533
|
try {
|
|
2534
|
+
logger.info('Download Blocklet', { name, did, bundles: metas.map((x) => get(x, 'dist.tarball')) });
|
|
2275
2535
|
const tasks = [];
|
|
2276
2536
|
for (const meta of metas) {
|
|
2277
2537
|
const url = await this.registry.resolveTarballURL({
|
|
@@ -2413,6 +2673,20 @@ class BlockletManager extends BaseBlockletManager {
|
|
|
2413
2673
|
await states.blockletExtras.delChildConfigs(did, child.meta.did);
|
|
2414
2674
|
}
|
|
2415
2675
|
}
|
|
2676
|
+
|
|
2677
|
+
async _findNextCustomBlockletName(leftTimes = 10) {
|
|
2678
|
+
if (leftTimes <= 0) {
|
|
2679
|
+
throw new Error('Generate custom blocklet did too many times');
|
|
2680
|
+
}
|
|
2681
|
+
const number = await states.node.increaseCustomBlockletNumber();
|
|
2682
|
+
const name = `custom-${number}`;
|
|
2683
|
+
const did = toBlockletDid(name);
|
|
2684
|
+
const blocklet = await states.blocklet.getBlocklet(did);
|
|
2685
|
+
if (blocklet) {
|
|
2686
|
+
return this._findNextCustomBlockletName(leftTimes - 1);
|
|
2687
|
+
}
|
|
2688
|
+
return { did, name };
|
|
2689
|
+
}
|
|
2416
2690
|
}
|
|
2417
2691
|
|
|
2418
2692
|
module.exports = BlockletManager;
|