@abtnode/core 1.6.16 → 1.6.17
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/lib/blocklet/manager/disk.js +373 -93
- package/lib/index.js +2 -0
- package/lib/migrations/1.6.17-blocklet-children.js +48 -0
- package/lib/router/helper.js +1 -1
- package/lib/router/manager.js +41 -37
- package/lib/states/blocklet-extras.js +39 -3
- package/lib/states/blocklet.js +4 -8
- package/lib/states/node.js +17 -2
- package/lib/util/blocklet.js +266 -67
- package/package.json +21 -21
|
@@ -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,7 +17,6 @@ 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');
|
|
@@ -24,9 +24,17 @@ const { updateBlocklet: updateDidDocument } = require('@abtnode/util/lib/did-doc
|
|
|
24
24
|
const { BLOCKLET_PURCHASE_NFT_TYPE } = require('@abtnode/constant');
|
|
25
25
|
|
|
26
26
|
const getBlockletEngine = require('@blocklet/meta/lib/engine');
|
|
27
|
-
const {
|
|
27
|
+
const {
|
|
28
|
+
isFreeBlocklet,
|
|
29
|
+
isDeletableBlocklet,
|
|
30
|
+
getRequiredMissingConfigs,
|
|
31
|
+
hasRunnableComponent,
|
|
32
|
+
} = require('@blocklet/meta/lib/util');
|
|
28
33
|
const validateBlockletEntry = require('@blocklet/meta/lib/entry');
|
|
29
34
|
const { getBlockletInfo } = require('@blocklet/meta/lib');
|
|
35
|
+
const toBlockletDid = require('@blocklet/meta/lib/did');
|
|
36
|
+
const { validateMeta } = require('@blocklet/meta/lib/validate');
|
|
37
|
+
const { update: updateMetaFile } = require('@blocklet/meta/lib/file');
|
|
30
38
|
|
|
31
39
|
const {
|
|
32
40
|
BlockletStatus,
|
|
@@ -37,6 +45,15 @@ const {
|
|
|
37
45
|
BlockletGroup,
|
|
38
46
|
fromBlockletStatus,
|
|
39
47
|
fromBlockletSource,
|
|
48
|
+
BLOCKLET_DEFAULT_PORT_NAME,
|
|
49
|
+
BLOCKLET_INTERFACE_TYPE_WEB,
|
|
50
|
+
BLOCKLET_INTERFACE_PUBLIC,
|
|
51
|
+
BLOCKLET_DYNAMIC_PATH_PREFIX,
|
|
52
|
+
BLOCKLET_INTERFACE_PROTOCOL_HTTP,
|
|
53
|
+
BLOCKLET_DEFAULT_PATH_REWRITE,
|
|
54
|
+
BLOCKLET_DEFAULT_VERSION,
|
|
55
|
+
BLOCKLET_LATEST_SPEC_VERSION,
|
|
56
|
+
BLOCKLET_META_FILE,
|
|
40
57
|
} = require('@blocklet/meta/lib/constants');
|
|
41
58
|
const util = require('../../util');
|
|
42
59
|
const {
|
|
@@ -60,16 +77,19 @@ const {
|
|
|
60
77
|
getBlockletStatusFromProcess,
|
|
61
78
|
checkBlockletProcessHealthy,
|
|
62
79
|
validateBlocklet,
|
|
63
|
-
getChildrenMeta,
|
|
64
80
|
statusMap,
|
|
65
81
|
expandTarball,
|
|
66
82
|
verifyIntegrity,
|
|
67
83
|
pruneBlockletBundle,
|
|
68
84
|
getDiskInfo,
|
|
69
85
|
getRuntimeInfo,
|
|
70
|
-
mergeMeta,
|
|
71
86
|
getUpdateMetaList,
|
|
72
87
|
getRuntimeEnvironments,
|
|
88
|
+
getSourceFromInstallParams,
|
|
89
|
+
parseChildren,
|
|
90
|
+
checkDuplicateComponents,
|
|
91
|
+
getDiffFiles,
|
|
92
|
+
getBundleDir,
|
|
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);
|
|
167
194
|
}
|
|
168
195
|
|
|
169
|
-
|
|
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 });
|
|
209
|
+
}
|
|
210
|
+
|
|
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) {
|
|
@@ -412,6 +459,22 @@ class BlockletManager extends BaseBlockletManager {
|
|
|
412
459
|
}
|
|
413
460
|
}
|
|
414
461
|
|
|
462
|
+
async deleteComponent({ did, rootDid }, context) {
|
|
463
|
+
logger.info('delete blocklet component', { did, rootDid });
|
|
464
|
+
|
|
465
|
+
const doc = await states.blocklet.getBlocklet(rootDid);
|
|
466
|
+
|
|
467
|
+
doc.children = doc.children.filter((x) => x.meta.did !== did);
|
|
468
|
+
const children = (await this._getDynamicChildrenFromSettings(rootDid)).filter((x) => x.meta.did !== did);
|
|
469
|
+
|
|
470
|
+
await states.blocklet.updateBlocklet(rootDid, doc);
|
|
471
|
+
states.blockletExtras.setSettings(rootDid, { children });
|
|
472
|
+
|
|
473
|
+
const newBlocklet = await this.ensureBlocklet(rootDid);
|
|
474
|
+
this.emit(BlockletEvents.upgraded, { blocklet: newBlocklet, context }); // trigger router refresh
|
|
475
|
+
return newBlocklet;
|
|
476
|
+
}
|
|
477
|
+
|
|
415
478
|
async cancelDownload({ did }, context) {
|
|
416
479
|
await preDownloadLock.acquire();
|
|
417
480
|
try {
|
|
@@ -664,56 +727,45 @@ class BlockletManager extends BaseBlockletManager {
|
|
|
664
727
|
}
|
|
665
728
|
|
|
666
729
|
// eslint-disable-next-line no-unused-vars
|
|
667
|
-
async diff({ did, hashFiles: clientFiles }, context) {
|
|
730
|
+
async diff({ did, hashFiles: clientFiles, rootDid: inputRootDid }, context) {
|
|
668
731
|
if (!did) {
|
|
669
732
|
throw new Error('did is empty');
|
|
670
733
|
}
|
|
734
|
+
|
|
671
735
|
if (!clientFiles || !clientFiles.length) {
|
|
672
736
|
throw new Error('hashFiles is empty');
|
|
673
737
|
}
|
|
674
738
|
|
|
675
|
-
|
|
739
|
+
const rootDid = inputRootDid || did;
|
|
740
|
+
const childDid = inputRootDid ? did : '';
|
|
741
|
+
|
|
742
|
+
if (childDid === rootDid) {
|
|
743
|
+
throw new Error('Cannot add self as a component');
|
|
744
|
+
}
|
|
745
|
+
|
|
746
|
+
logger.info('Get blocklet diff', { rootDid, childDid, clientFilesNumber: clientFiles.length });
|
|
747
|
+
|
|
748
|
+
const rootBlocklet = await states.blocklet.getBlocklet(rootDid);
|
|
749
|
+
if (childDid && !rootBlocklet) {
|
|
750
|
+
throw new Error('Root blocklet does not exist');
|
|
751
|
+
}
|
|
752
|
+
|
|
753
|
+
const state = childDid ? await (rootBlocklet.children || []).find((x) => x.meta.did === childDid) : rootBlocklet;
|
|
676
754
|
|
|
677
|
-
const state = await states.blocklet.getBlocklet(did);
|
|
678
755
|
if (!state) {
|
|
679
756
|
return {
|
|
680
757
|
hasBlocklet: false,
|
|
681
758
|
};
|
|
682
759
|
}
|
|
760
|
+
|
|
683
761
|
if (state.source === BlockletSource.local) {
|
|
684
762
|
throw new Error(`Blocklet ${state.meta.name} is already deployed from local, can not deployed from remote.`);
|
|
685
763
|
}
|
|
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
764
|
|
|
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
|
-
}
|
|
765
|
+
const { version } = state.meta;
|
|
766
|
+
const bundleDir = getBundleDir(this.installDir, state.meta);
|
|
767
|
+
const { addSet, changeSet, deleteSet } = await getDiffFiles(clientFiles, bundleDir);
|
|
768
|
+
|
|
717
769
|
logger.info('Diff files', {
|
|
718
770
|
name: state.meta.name,
|
|
719
771
|
did: state.meta.did,
|
|
@@ -722,6 +774,7 @@ class BlockletManager extends BaseBlockletManager {
|
|
|
722
774
|
changeNum: changeSet.length,
|
|
723
775
|
deleteNum: deleteSet.length,
|
|
724
776
|
});
|
|
777
|
+
|
|
725
778
|
return {
|
|
726
779
|
hasBlocklet: true,
|
|
727
780
|
version,
|
|
@@ -733,10 +786,20 @@ class BlockletManager extends BaseBlockletManager {
|
|
|
733
786
|
|
|
734
787
|
async checkChildrenForUpdates({ did }) {
|
|
735
788
|
const blocklet = await states.blocklet.getBlocklet(did);
|
|
736
|
-
const
|
|
789
|
+
const newStaticChildren = await parseChildren(blocklet.meta);
|
|
790
|
+
|
|
791
|
+
const oldDynamicChildren = await this._getDynamicChildrenFromSettings(did);
|
|
792
|
+
const noneSourceUrlChildren = oldDynamicChildren.filter((x) => !x.sourceUrl);
|
|
793
|
+
const dynamicConfig = oldDynamicChildren
|
|
794
|
+
.filter((x) => x.sourceUrl)
|
|
795
|
+
.map((x) => ({ resolved: x.sourceUrl, name: x.meta.name, mountPoint: x.mountPoint }));
|
|
796
|
+
const newDynamicChildren = [...noneSourceUrlChildren, ...(await parseChildren(dynamicConfig, { dynamic: true }))];
|
|
797
|
+
|
|
798
|
+
checkDuplicateComponents(newDynamicChildren, newStaticChildren);
|
|
799
|
+
|
|
737
800
|
const updateList = getUpdateMetaList(
|
|
738
|
-
blocklet.children.map((x) => x.meta),
|
|
739
|
-
|
|
801
|
+
[...blocklet.children.map((x) => x.meta), ...oldDynamicChildren.map((x) => x.meta)],
|
|
802
|
+
[...newStaticChildren.map((x) => x.meta), ...newDynamicChildren.map((x) => x.meta)]
|
|
740
803
|
);
|
|
741
804
|
|
|
742
805
|
if (!updateList.length) {
|
|
@@ -746,7 +809,8 @@ class BlockletManager extends BaseBlockletManager {
|
|
|
746
809
|
// start session
|
|
747
810
|
const { id: updateId } = await states.session.start({
|
|
748
811
|
did,
|
|
749
|
-
|
|
812
|
+
staticChildren: newStaticChildren,
|
|
813
|
+
dynamicChildren: newDynamicChildren,
|
|
750
814
|
});
|
|
751
815
|
|
|
752
816
|
return {
|
|
@@ -755,8 +819,18 @@ class BlockletManager extends BaseBlockletManager {
|
|
|
755
819
|
};
|
|
756
820
|
}
|
|
757
821
|
|
|
758
|
-
async updateChildren({ updateId }, context) {
|
|
759
|
-
|
|
822
|
+
async updateChildren({ updateId, did: inputDid, children: inputChildren }, context) {
|
|
823
|
+
let did;
|
|
824
|
+
let children;
|
|
825
|
+
if (!updateId && inputDid && inputChildren) {
|
|
826
|
+
did = inputDid;
|
|
827
|
+
children = inputChildren;
|
|
828
|
+
} else {
|
|
829
|
+
const sessionData = await states.session.end(updateId);
|
|
830
|
+
did = sessionData.did;
|
|
831
|
+
const { staticChildren = [], dynamicChildren = [] } = sessionData;
|
|
832
|
+
children = [...staticChildren, ...dynamicChildren.map((x) => ({ ...x, dynamic: true }))];
|
|
833
|
+
}
|
|
760
834
|
|
|
761
835
|
// get old blocklet
|
|
762
836
|
const oldBlocklet = await states.blocklet.getBlocklet(did);
|
|
@@ -769,14 +843,13 @@ class BlockletManager extends BaseBlockletManager {
|
|
|
769
843
|
did,
|
|
770
844
|
name,
|
|
771
845
|
version,
|
|
772
|
-
children:
|
|
846
|
+
children: children.map((x) => ({ name: x.meta.name, version: x.meta.version })),
|
|
773
847
|
});
|
|
774
848
|
|
|
775
849
|
// new blocklet
|
|
776
850
|
const newBlocklet = await states.blocklet.setBlockletStatus(did, BlockletStatus.waiting);
|
|
777
|
-
|
|
778
|
-
newBlocklet.
|
|
779
|
-
newBlocklet.children = await states.blocklet.getChildrenFromMetas(childrenMeta);
|
|
851
|
+
|
|
852
|
+
newBlocklet.children = children;
|
|
780
853
|
await validateBlocklet(newBlocklet);
|
|
781
854
|
|
|
782
855
|
this.emit(BlockletEvents.statusChange, newBlocklet);
|
|
@@ -849,19 +922,19 @@ class BlockletManager extends BaseBlockletManager {
|
|
|
849
922
|
logger.error('failed to delete blocklet process for dev', { error: err });
|
|
850
923
|
}
|
|
851
924
|
|
|
852
|
-
const
|
|
853
|
-
mergeMeta(meta, childrenMeta);
|
|
925
|
+
const children = await this._getChildren(meta);
|
|
854
926
|
const blocklet = await states.blocklet.addBlocklet({
|
|
855
927
|
did,
|
|
856
928
|
meta,
|
|
857
929
|
source: BlockletSource.local,
|
|
858
930
|
deployedFrom: folder,
|
|
859
931
|
mode: BLOCKLET_MODES.DEVELOPMENT,
|
|
860
|
-
|
|
932
|
+
children,
|
|
861
933
|
});
|
|
862
934
|
logger.info('add blocklet for dev', { did, version, meta });
|
|
863
935
|
|
|
864
|
-
|
|
936
|
+
const oldBlocklet = { children: children.filter((x) => x.dynamic) }; // let downloader skip re-downloading dynamic blocklet
|
|
937
|
+
await this._downloadBlocklet(blocklet, oldBlocklet);
|
|
865
938
|
await states.blocklet.setBlockletStatus(did, BlockletStatus.installed);
|
|
866
939
|
|
|
867
940
|
// Add environments
|
|
@@ -1004,7 +1077,8 @@ class BlockletManager extends BaseBlockletManager {
|
|
|
1004
1077
|
blocklet.diskInfo = await getDiskInfo(blocklet, { useFakeDiskInfo: !diskInfo });
|
|
1005
1078
|
|
|
1006
1079
|
try {
|
|
1007
|
-
const
|
|
1080
|
+
const app = blocklet.meta.group === BlockletGroup.gateway ? blocklet.children[0].env : blocklet.env;
|
|
1081
|
+
const { appId } = app;
|
|
1008
1082
|
blocklet.runtimeInfo = await getRuntimeInfo(appId);
|
|
1009
1083
|
if (blocklet.runtimeInfo.status && shouldUpdateBlockletStatus(blocklet.status)) {
|
|
1010
1084
|
blocklet.status = statusMap[blocklet.runtimeInfo.status];
|
|
@@ -1278,7 +1352,7 @@ class BlockletManager extends BaseBlockletManager {
|
|
|
1278
1352
|
}
|
|
1279
1353
|
}
|
|
1280
1354
|
|
|
1281
|
-
async
|
|
1355
|
+
async _installFromStore({ did, registry }, context) {
|
|
1282
1356
|
logger.debug('start install blocklet', { did });
|
|
1283
1357
|
if (!isValidDid(did)) {
|
|
1284
1358
|
throw new Error('Blocklet did is invalid');
|
|
@@ -1340,9 +1414,84 @@ class BlockletManager extends BaseBlockletManager {
|
|
|
1340
1414
|
});
|
|
1341
1415
|
}
|
|
1342
1416
|
|
|
1343
|
-
async
|
|
1344
|
-
|
|
1345
|
-
|
|
1417
|
+
async _installComponentFromUrl({ rootDid, mountPoint, url, context }) {
|
|
1418
|
+
const blocklet = await states.blocklet.getBlocklet(rootDid);
|
|
1419
|
+
if (!blocklet) {
|
|
1420
|
+
throw new Error('Root blocklet does not exist');
|
|
1421
|
+
}
|
|
1422
|
+
|
|
1423
|
+
const meta = await getBlockletMetaFromUrl(url);
|
|
1424
|
+
|
|
1425
|
+
if (meta.did === rootDid) {
|
|
1426
|
+
throw new Error('Cannot add self as a component');
|
|
1427
|
+
}
|
|
1428
|
+
|
|
1429
|
+
const newChildren = await parseChildren(blocklet.meta, {
|
|
1430
|
+
children: [
|
|
1431
|
+
{
|
|
1432
|
+
meta,
|
|
1433
|
+
mountPoint,
|
|
1434
|
+
sourceUrl: url,
|
|
1435
|
+
},
|
|
1436
|
+
],
|
|
1437
|
+
dynamic: true,
|
|
1438
|
+
});
|
|
1439
|
+
|
|
1440
|
+
checkDuplicateComponents(blocklet.children, newChildren);
|
|
1441
|
+
|
|
1442
|
+
return this.updateChildren(
|
|
1443
|
+
{
|
|
1444
|
+
did: rootDid,
|
|
1445
|
+
children: [...blocklet.children, ...newChildren],
|
|
1446
|
+
},
|
|
1447
|
+
context
|
|
1448
|
+
);
|
|
1449
|
+
}
|
|
1450
|
+
|
|
1451
|
+
async _installFromCreate({ title, description }, context = {}) {
|
|
1452
|
+
logger.debug('create blocklet', { title, description });
|
|
1453
|
+
|
|
1454
|
+
await joi.string().label('title').max(20).required().validateAsync(title);
|
|
1455
|
+
await joi.string().label('description').max(80).required().validateAsync(description);
|
|
1456
|
+
|
|
1457
|
+
const { did, name } = await this._findNextCustomBlockletName();
|
|
1458
|
+
const rawMeta = {
|
|
1459
|
+
name,
|
|
1460
|
+
did,
|
|
1461
|
+
title,
|
|
1462
|
+
description,
|
|
1463
|
+
version: BLOCKLET_DEFAULT_VERSION,
|
|
1464
|
+
group: BlockletGroup.gateway,
|
|
1465
|
+
interfaces: [
|
|
1466
|
+
{
|
|
1467
|
+
type: BLOCKLET_INTERFACE_TYPE_WEB,
|
|
1468
|
+
name: BLOCKLET_INTERFACE_PUBLIC,
|
|
1469
|
+
path: BLOCKLET_DEFAULT_PATH_REWRITE,
|
|
1470
|
+
prefix: BLOCKLET_DYNAMIC_PATH_PREFIX,
|
|
1471
|
+
port: BLOCKLET_DEFAULT_PORT_NAME,
|
|
1472
|
+
protocol: BLOCKLET_INTERFACE_PROTOCOL_HTTP,
|
|
1473
|
+
},
|
|
1474
|
+
],
|
|
1475
|
+
specVersion: BLOCKLET_LATEST_SPEC_VERSION,
|
|
1476
|
+
};
|
|
1477
|
+
const meta = validateMeta(rawMeta);
|
|
1478
|
+
|
|
1479
|
+
await states.blocklet.addBlocklet({
|
|
1480
|
+
did: meta.did,
|
|
1481
|
+
meta,
|
|
1482
|
+
source: BlockletSource.custom,
|
|
1483
|
+
});
|
|
1484
|
+
await this._setConfigs(did);
|
|
1485
|
+
|
|
1486
|
+
// fake install bundle
|
|
1487
|
+
const bundleDir = getBundleDir(this.installDir, meta);
|
|
1488
|
+
fs.mkdirSync(bundleDir, { recursive: true });
|
|
1489
|
+
updateMetaFile(path.join(bundleDir, BLOCKLET_META_FILE), meta);
|
|
1490
|
+
|
|
1491
|
+
return this._installBlocklet({ did, context });
|
|
1492
|
+
}
|
|
1493
|
+
|
|
1494
|
+
async _downloadFromUpload(file) {
|
|
1346
1495
|
// const { filename, mimetype, encoding, createReadStream } = await file;
|
|
1347
1496
|
const { filename, createReadStream } = await file;
|
|
1348
1497
|
const cwd = path.join(this.dataDirs.tmp, 'download');
|
|
@@ -1366,6 +1515,13 @@ class BlockletManager extends BaseBlockletManager {
|
|
|
1366
1515
|
writeStream.on('finish', resolve);
|
|
1367
1516
|
});
|
|
1368
1517
|
|
|
1518
|
+
return { cwd, tarFile };
|
|
1519
|
+
}
|
|
1520
|
+
|
|
1521
|
+
async _installFromUpload({ file, did, diffVersion, deleteSet, context }) {
|
|
1522
|
+
logger.info('install blocklet', { from: 'upload file' });
|
|
1523
|
+
const { cwd, tarFile } = await this._downloadFromUpload(file);
|
|
1524
|
+
|
|
1369
1525
|
// diff deploy
|
|
1370
1526
|
if (did && diffVersion) {
|
|
1371
1527
|
const oldBlocklet = await states.blocklet.getBlocklet(did);
|
|
@@ -1386,14 +1542,12 @@ class BlockletManager extends BaseBlockletManager {
|
|
|
1386
1542
|
throw new Error(`Can not deploy blocklet when it is ${fromBlockletStatus(oldBlocklet.status)}`);
|
|
1387
1543
|
}
|
|
1388
1544
|
|
|
1389
|
-
const { meta } = await this._resolveDiffDownload(cwd, tarFile, deleteSet, oldBlocklet);
|
|
1390
|
-
const childrenMeta = await getChildrenMeta(meta);
|
|
1391
|
-
mergeMeta(meta, childrenMeta);
|
|
1545
|
+
const { meta } = await this._resolveDiffDownload(cwd, tarFile, deleteSet, oldBlocklet.meta);
|
|
1392
1546
|
const newBlocklet = await states.blocklet.getBlocklet(did);
|
|
1393
1547
|
newBlocklet.meta = meta;
|
|
1394
1548
|
newBlocklet.source = BlockletSource.upload;
|
|
1395
1549
|
newBlocklet.deployedFrom = `Upload by ${context.user.did}`;
|
|
1396
|
-
newBlocklet.children = await
|
|
1550
|
+
newBlocklet.children = await this._getChildren(meta);
|
|
1397
1551
|
await validateBlocklet(newBlocklet);
|
|
1398
1552
|
await this._downloadBlocklet(newBlocklet, oldBlocklet);
|
|
1399
1553
|
|
|
@@ -1408,19 +1562,18 @@ class BlockletManager extends BaseBlockletManager {
|
|
|
1408
1562
|
const { meta } = await this._resolveDownload(cwd, tarFile);
|
|
1409
1563
|
const oldBlocklet = await states.blocklet.getBlocklet(meta.did);
|
|
1410
1564
|
|
|
1565
|
+
// full deploy - upgrade
|
|
1411
1566
|
if (oldBlocklet) {
|
|
1412
1567
|
if (isInProgress(oldBlocklet.status)) {
|
|
1413
1568
|
logger.error(`Can not deploy blocklet when it is ${fromBlockletStatus(oldBlocklet.status)}`);
|
|
1414
1569
|
throw new Error(`Can not deploy blocklet when it is ${fromBlockletStatus(oldBlocklet.status)}`);
|
|
1415
1570
|
}
|
|
1416
1571
|
|
|
1417
|
-
const childrenMeta = await getChildrenMeta(meta);
|
|
1418
|
-
mergeMeta(meta, childrenMeta);
|
|
1419
1572
|
const newBlocklet = await states.blocklet.getBlocklet(meta.did);
|
|
1420
1573
|
newBlocklet.meta = meta;
|
|
1421
1574
|
newBlocklet.source = BlockletSource.upload;
|
|
1422
1575
|
newBlocklet.deployedFrom = `Upload by ${context.user.did}`;
|
|
1423
|
-
newBlocklet.children = await
|
|
1576
|
+
newBlocklet.children = await this._getChildren(meta);
|
|
1424
1577
|
|
|
1425
1578
|
await validateBlocklet(newBlocklet);
|
|
1426
1579
|
await this._downloadBlocklet(newBlocklet, oldBlocklet);
|
|
@@ -1432,14 +1585,14 @@ class BlockletManager extends BaseBlockletManager {
|
|
|
1432
1585
|
});
|
|
1433
1586
|
}
|
|
1434
1587
|
|
|
1435
|
-
|
|
1436
|
-
|
|
1588
|
+
// full deploy - install
|
|
1589
|
+
const children = await this._getChildren(meta);
|
|
1437
1590
|
const blocklet = await states.blocklet.addBlocklet({
|
|
1438
1591
|
did: meta.did,
|
|
1439
1592
|
meta,
|
|
1440
1593
|
source: BlockletSource.upload,
|
|
1441
1594
|
deployedFrom: `Upload by ${context.user.did}`,
|
|
1442
|
-
|
|
1595
|
+
children,
|
|
1443
1596
|
});
|
|
1444
1597
|
|
|
1445
1598
|
await validateBlocklet(blocklet);
|
|
@@ -1447,13 +1600,92 @@ class BlockletManager extends BaseBlockletManager {
|
|
|
1447
1600
|
await this._setConfigs(meta.did);
|
|
1448
1601
|
|
|
1449
1602
|
// download
|
|
1450
|
-
await this._downloadBlocklet(
|
|
1603
|
+
await this._downloadBlocklet(
|
|
1604
|
+
blocklet,
|
|
1605
|
+
// let downloader skip re-downloading dynamic blocklet
|
|
1606
|
+
{ children: children.filter((x) => x.dynamic) }
|
|
1607
|
+
);
|
|
1451
1608
|
return this._installBlocklet({
|
|
1452
1609
|
did: meta.did,
|
|
1453
1610
|
context,
|
|
1454
1611
|
});
|
|
1455
1612
|
}
|
|
1456
1613
|
|
|
1614
|
+
async _installComponentFromUpload({ rootDid, mountPoint, file, did, diffVersion, deleteSet, context }) {
|
|
1615
|
+
logger.info('install blocklet', { from: 'upload file' });
|
|
1616
|
+
// download
|
|
1617
|
+
const { cwd, tarFile } = await this._downloadFromUpload(file);
|
|
1618
|
+
|
|
1619
|
+
const oldBlocklet = await states.blocklet.getBlocklet(rootDid);
|
|
1620
|
+
if (!oldBlocklet) {
|
|
1621
|
+
throw new Error('Root blocklet does not exist');
|
|
1622
|
+
}
|
|
1623
|
+
|
|
1624
|
+
if (isInProgress(oldBlocklet.status)) {
|
|
1625
|
+
logger.error(`Can not deploy blocklet when it is ${fromBlockletStatus(oldBlocklet.status)}`);
|
|
1626
|
+
throw new Error(`Can not deploy blocklet when it is ${fromBlockletStatus(oldBlocklet.status)}`);
|
|
1627
|
+
}
|
|
1628
|
+
|
|
1629
|
+
let meta;
|
|
1630
|
+
// diff upload
|
|
1631
|
+
if (did && diffVersion) {
|
|
1632
|
+
const oldChild = oldBlocklet.children.find((x) => x.meta.did === did);
|
|
1633
|
+
if (!oldChild) {
|
|
1634
|
+
throw new Error(`Blocklet ${did} not found when diff deploying`);
|
|
1635
|
+
}
|
|
1636
|
+
if (oldChild.meta.version !== diffVersion) {
|
|
1637
|
+
logger.error('Diff deploy: Blocklet version changed', {
|
|
1638
|
+
preVersion: diffVersion,
|
|
1639
|
+
changedVersion: oldChild.meta.version,
|
|
1640
|
+
name: oldChild.meta.name,
|
|
1641
|
+
did: oldChild.meta.did,
|
|
1642
|
+
});
|
|
1643
|
+
throw new Error('Blocklet version changed when diff deploying');
|
|
1644
|
+
}
|
|
1645
|
+
|
|
1646
|
+
meta = (await this._resolveDiffDownload(cwd, tarFile, deleteSet, oldChild.meta)).meta;
|
|
1647
|
+
} else {
|
|
1648
|
+
// full deploy
|
|
1649
|
+
meta = (await this._resolveDownload(cwd, tarFile)).meta;
|
|
1650
|
+
}
|
|
1651
|
+
|
|
1652
|
+
if (meta.did === rootDid) {
|
|
1653
|
+
// should not be here
|
|
1654
|
+
throw new Error('Cannot add self as a component');
|
|
1655
|
+
}
|
|
1656
|
+
|
|
1657
|
+
const newBlocklet = await states.blocklet.getBlocklet(rootDid);
|
|
1658
|
+
const dynamicChildren = await this._getDynamicChildrenFromSettings(rootDid);
|
|
1659
|
+
|
|
1660
|
+
const newChild = {
|
|
1661
|
+
meta,
|
|
1662
|
+
mountPoint,
|
|
1663
|
+
source: BlockletSource.upload,
|
|
1664
|
+
deployedFrom: `Upload by ${context.user.did}`,
|
|
1665
|
+
sourceUrl: '',
|
|
1666
|
+
dynamic: true,
|
|
1667
|
+
};
|
|
1668
|
+
const index = dynamicChildren.findIndex((child) => child.meta.did === meta.did);
|
|
1669
|
+
if (index >= 0) {
|
|
1670
|
+
dynamicChildren.splice(index, 1, newChild);
|
|
1671
|
+
} else {
|
|
1672
|
+
dynamicChildren.push(newChild);
|
|
1673
|
+
}
|
|
1674
|
+
|
|
1675
|
+
const staticChildren = newBlocklet.children.filter((x) => !x.dynamic);
|
|
1676
|
+
checkDuplicateComponents(dynamicChildren, staticChildren);
|
|
1677
|
+
|
|
1678
|
+
newBlocklet.children = [...staticChildren, ...dynamicChildren.map((x) => ({ ...x, dynamic: true }))];
|
|
1679
|
+
|
|
1680
|
+
await validateBlocklet(newBlocklet);
|
|
1681
|
+
|
|
1682
|
+
return this._upgradeBlocklet({
|
|
1683
|
+
oldBlocklet,
|
|
1684
|
+
newBlocklet,
|
|
1685
|
+
context,
|
|
1686
|
+
});
|
|
1687
|
+
}
|
|
1688
|
+
|
|
1457
1689
|
/**
|
|
1458
1690
|
* add to download job queue
|
|
1459
1691
|
* @param {string} did blocklet did
|
|
@@ -1488,7 +1720,14 @@ class BlockletManager extends BaseBlockletManager {
|
|
|
1488
1720
|
|
|
1489
1721
|
async prune() {
|
|
1490
1722
|
const blocklets = await states.blocklet.getBlocklets();
|
|
1491
|
-
await
|
|
1723
|
+
const settings = await states.blockletExtras.listSettings();
|
|
1724
|
+
await pruneBlockletBundle({
|
|
1725
|
+
installDir: this.dataDirs.blocklets,
|
|
1726
|
+
blocklets,
|
|
1727
|
+
blockletSettings: settings
|
|
1728
|
+
.filter((x) => x.settings.children && x.settings.children.length)
|
|
1729
|
+
.map((x) => x.settings),
|
|
1730
|
+
});
|
|
1492
1731
|
}
|
|
1493
1732
|
|
|
1494
1733
|
async getLatestBlockletVersion({ did, version }) {
|
|
@@ -1576,20 +1815,35 @@ class BlockletManager extends BaseBlockletManager {
|
|
|
1576
1815
|
blocklets.forEach(run);
|
|
1577
1816
|
}
|
|
1578
1817
|
|
|
1818
|
+
async _getChildren(meta) {
|
|
1819
|
+
const staticChildren = await parseChildren(meta);
|
|
1820
|
+
const dynamicChildren = await parseChildren(meta, {
|
|
1821
|
+
children: await states.blockletExtras.getSettings(meta.did, 'children', []),
|
|
1822
|
+
dynamic: true,
|
|
1823
|
+
});
|
|
1824
|
+
checkDuplicateComponents(dynamicChildren, staticChildren);
|
|
1825
|
+
|
|
1826
|
+
return [...staticChildren, ...dynamicChildren];
|
|
1827
|
+
}
|
|
1828
|
+
|
|
1829
|
+
async _getDynamicChildrenFromSettings(did) {
|
|
1830
|
+
const children = await states.blockletExtras.getSettings(did, 'children', []);
|
|
1831
|
+
return children.map((x) => ({ ...x, dynamic: true }));
|
|
1832
|
+
}
|
|
1833
|
+
|
|
1579
1834
|
async _install({ meta, source, deployedFrom, context, sync }) {
|
|
1580
1835
|
validateBlockletMeta(meta, { ensureDist: true });
|
|
1581
1836
|
|
|
1582
1837
|
const { name, did, version } = meta;
|
|
1583
1838
|
|
|
1584
|
-
const
|
|
1585
|
-
mergeMeta(meta, childrenMeta);
|
|
1839
|
+
const children = await this._getChildren(meta);
|
|
1586
1840
|
try {
|
|
1587
1841
|
const blocklet = await states.blocklet.addBlocklet({
|
|
1588
1842
|
did: meta.did,
|
|
1589
1843
|
meta,
|
|
1590
1844
|
source,
|
|
1591
1845
|
deployedFrom,
|
|
1592
|
-
|
|
1846
|
+
children,
|
|
1593
1847
|
});
|
|
1594
1848
|
|
|
1595
1849
|
await validateBlocklet(blocklet);
|
|
@@ -1604,6 +1858,7 @@ class BlockletManager extends BaseBlockletManager {
|
|
|
1604
1858
|
// download
|
|
1605
1859
|
const downloadParams = {
|
|
1606
1860
|
blocklet: { ...blocklet1 },
|
|
1861
|
+
oldBlocklet: { children: children.filter((x) => x.dynamic) }, // let downloader skip re-downloading dynamic blocklet
|
|
1607
1862
|
context,
|
|
1608
1863
|
postAction: 'install',
|
|
1609
1864
|
};
|
|
@@ -1662,7 +1917,7 @@ class BlockletManager extends BaseBlockletManager {
|
|
|
1662
1917
|
}
|
|
1663
1918
|
|
|
1664
1919
|
async _upgrade({ meta, source, deployedFrom, context, sync }) {
|
|
1665
|
-
validateBlockletMeta(meta, { ensureDist:
|
|
1920
|
+
validateBlockletMeta(meta, { ensureDist: meta.group !== BlockletGroup.gateway });
|
|
1666
1921
|
|
|
1667
1922
|
const { name, version, did } = meta;
|
|
1668
1923
|
|
|
@@ -1673,12 +1928,11 @@ class BlockletManager extends BaseBlockletManager {
|
|
|
1673
1928
|
logger.info(`${action} blocklet`, { did, version });
|
|
1674
1929
|
|
|
1675
1930
|
const newBlocklet = await states.blocklet.setBlockletStatus(did, BlockletStatus.waiting);
|
|
1676
|
-
|
|
1677
|
-
mergeMeta(meta, childrenMeta);
|
|
1931
|
+
|
|
1678
1932
|
newBlocklet.meta = meta;
|
|
1679
1933
|
newBlocklet.source = source;
|
|
1680
1934
|
newBlocklet.deployedFrom = deployedFrom;
|
|
1681
|
-
newBlocklet.children = await
|
|
1935
|
+
newBlocklet.children = await this._getChildren(meta);
|
|
1682
1936
|
|
|
1683
1937
|
await validateBlocklet(newBlocklet);
|
|
1684
1938
|
|
|
@@ -1781,7 +2035,7 @@ class BlockletManager extends BaseBlockletManager {
|
|
|
1781
2035
|
|
|
1782
2036
|
await ensureBlockletExpanded(meta, downloadDir);
|
|
1783
2037
|
|
|
1784
|
-
installDir =
|
|
2038
|
+
installDir = getBundleDir(this.installDir, meta);
|
|
1785
2039
|
if (fs.existsSync(installDir)) {
|
|
1786
2040
|
fs.removeSync(installDir);
|
|
1787
2041
|
logger.info('cleanup blocklet upgrade dir', { name, version, installDir });
|
|
@@ -1798,7 +2052,7 @@ class BlockletManager extends BaseBlockletManager {
|
|
|
1798
2052
|
return { meta, installDir };
|
|
1799
2053
|
}
|
|
1800
2054
|
|
|
1801
|
-
async _resolveDiffDownload(cwd, tarFile, deleteSet,
|
|
2055
|
+
async _resolveDiffDownload(cwd, tarFile, deleteSet, bundle) {
|
|
1802
2056
|
logger.info('Resolve diff download', { tarFile, cwd });
|
|
1803
2057
|
const downloadDir = path.join(cwd, `${path.basename(tarFile, path.extname(tarFile))}`);
|
|
1804
2058
|
const diffDir = `${downloadDir}-diff`;
|
|
@@ -1811,7 +2065,7 @@ class BlockletManager extends BaseBlockletManager {
|
|
|
1811
2065
|
throw error;
|
|
1812
2066
|
}
|
|
1813
2067
|
logger.info('Copy installDir to downloadDir', { installDir: this.installDir, downloadDir });
|
|
1814
|
-
await fs.copy(
|
|
2068
|
+
await fs.copy(getBundleDir(this.installDir, bundle), downloadDir);
|
|
1815
2069
|
try {
|
|
1816
2070
|
// delete
|
|
1817
2071
|
logger.info('Delete files from downloadDir', { fileNum: deleteSet.length });
|
|
@@ -1840,11 +2094,11 @@ class BlockletManager extends BaseBlockletManager {
|
|
|
1840
2094
|
|
|
1841
2095
|
await ensureBlockletExpanded(meta, downloadDir);
|
|
1842
2096
|
|
|
1843
|
-
const
|
|
1844
|
-
logger.info('Move downloadDir to installDir', { downloadDir,
|
|
1845
|
-
await fs.move(downloadDir,
|
|
2097
|
+
const bundleDir = getBundleDir(this.installDir, meta);
|
|
2098
|
+
logger.info('Move downloadDir to installDir', { downloadDir, bundleDir });
|
|
2099
|
+
await fs.move(downloadDir, bundleDir, { overwrite: true });
|
|
1846
2100
|
|
|
1847
|
-
return { meta, installDir };
|
|
2101
|
+
return { meta, installDir: bundleDir };
|
|
1848
2102
|
} catch (error) {
|
|
1849
2103
|
fs.removeSync(downloadDir);
|
|
1850
2104
|
fs.removeSync(diffDir);
|
|
@@ -1875,7 +2129,7 @@ class BlockletManager extends BaseBlockletManager {
|
|
|
1875
2129
|
hooks.preInstall({
|
|
1876
2130
|
hooks: Object.assign(b.meta.hooks || {}, b.meta.scripts || {}),
|
|
1877
2131
|
env: { ...nodeEnvironments },
|
|
1878
|
-
appDir:
|
|
2132
|
+
appDir: b.env.appDir,
|
|
1879
2133
|
did, // root blocklet did
|
|
1880
2134
|
notification: states.notification,
|
|
1881
2135
|
context,
|
|
@@ -1891,7 +2145,7 @@ class BlockletManager extends BaseBlockletManager {
|
|
|
1891
2145
|
hooks.postInstall({
|
|
1892
2146
|
hooks: Object.assign(b.meta.hooks || {}, b.meta.scripts || {}),
|
|
1893
2147
|
env: getRuntimeEnvironments(b, nodeEnvironments, blocklet),
|
|
1894
|
-
appDir:
|
|
2148
|
+
appDir: b.env.appDir,
|
|
1895
2149
|
did, // root blocklet did
|
|
1896
2150
|
notification: states.notification,
|
|
1897
2151
|
context,
|
|
@@ -1975,7 +2229,7 @@ class BlockletManager extends BaseBlockletManager {
|
|
|
1975
2229
|
hooks.preInstall({
|
|
1976
2230
|
hooks: Object.assign(b.meta.hooks || {}, b.meta.scripts || {}),
|
|
1977
2231
|
env: { ...nodeEnvironments },
|
|
1978
|
-
appDir:
|
|
2232
|
+
appDir: b.env.appDir,
|
|
1979
2233
|
did, // root blocklet did
|
|
1980
2234
|
notification: states.notification,
|
|
1981
2235
|
context,
|
|
@@ -2060,6 +2314,12 @@ class BlockletManager extends BaseBlockletManager {
|
|
|
2060
2314
|
logger.error('emit upgrade notification failed', { name, version, error });
|
|
2061
2315
|
}
|
|
2062
2316
|
|
|
2317
|
+
// Update dynamic component meta in blocklet settings
|
|
2318
|
+
const dynamicChildren = blocklet.children
|
|
2319
|
+
.filter((x) => x.dynamic)
|
|
2320
|
+
.map((x) => pick(x, ['meta', 'mountPoint', 'sourceUrl', 'source']));
|
|
2321
|
+
await states.blockletExtras.setSettings(did, { children: dynamicChildren });
|
|
2322
|
+
|
|
2063
2323
|
return blocklet;
|
|
2064
2324
|
} catch (err) {
|
|
2065
2325
|
const b = await this._rollback(action, did, oldBlocklet);
|
|
@@ -2266,12 +2526,18 @@ class BlockletManager extends BaseBlockletManager {
|
|
|
2266
2526
|
|
|
2267
2527
|
for (const child of blocklet.children) {
|
|
2268
2528
|
const oldChild = oldChildren[child.meta.did];
|
|
2269
|
-
if (
|
|
2529
|
+
if (
|
|
2530
|
+
!oldChild ||
|
|
2531
|
+
(![BlockletSource.upload, BlockletSource.local].includes(child.source) &&
|
|
2532
|
+
child.sourceUrl &&
|
|
2533
|
+
get(oldChild, 'meta.dist.integrity') !== get(child, 'meta.dist.integrity'))
|
|
2534
|
+
) {
|
|
2270
2535
|
metas.push(child.meta);
|
|
2271
2536
|
}
|
|
2272
2537
|
}
|
|
2273
2538
|
|
|
2274
2539
|
try {
|
|
2540
|
+
logger.info('Download Blocklet', { name, did, bundles: metas.map((x) => get(x, 'dist.tarball')) });
|
|
2275
2541
|
const tasks = [];
|
|
2276
2542
|
for (const meta of metas) {
|
|
2277
2543
|
const url = await this.registry.resolveTarballURL({
|
|
@@ -2413,6 +2679,20 @@ class BlockletManager extends BaseBlockletManager {
|
|
|
2413
2679
|
await states.blockletExtras.delChildConfigs(did, child.meta.did);
|
|
2414
2680
|
}
|
|
2415
2681
|
}
|
|
2682
|
+
|
|
2683
|
+
async _findNextCustomBlockletName(leftTimes = 10) {
|
|
2684
|
+
if (leftTimes <= 0) {
|
|
2685
|
+
throw new Error('Generate custom blocklet did too many times');
|
|
2686
|
+
}
|
|
2687
|
+
const number = await states.node.increaseCustomBlockletNumber();
|
|
2688
|
+
const name = `custom-${number}`;
|
|
2689
|
+
const did = toBlockletDid(name);
|
|
2690
|
+
const blocklet = await states.blocklet.getBlocklet(did);
|
|
2691
|
+
if (blocklet) {
|
|
2692
|
+
return this._findNextCustomBlockletName(leftTimes - 1);
|
|
2693
|
+
}
|
|
2694
|
+
return { did, name };
|
|
2695
|
+
}
|
|
2416
2696
|
}
|
|
2417
2697
|
|
|
2418
2698
|
module.exports = BlockletManager;
|