@abtnode/core 1.8.30 → 1.8.32
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 +3 -3
- package/lib/api/team.js +22 -4
- package/lib/blocklet/manager/disk.js +312 -180
- package/lib/index.js +5 -7
- package/lib/states/README.md +3 -0
- package/lib/states/blocklet.js +29 -23
- package/lib/states/user.js +16 -0
- package/lib/team/manager.js +2 -2
- package/lib/util/blocklet.js +4 -4
- package/lib/util/requirement.js +26 -10
- package/lib/util/{registry.js → store.js} +51 -0
- package/lib/validators/blocklet.js +15 -0
- package/package.json +26 -26
- package/lib/blocklet/registry.js +0 -74
|
@@ -23,7 +23,7 @@ const logger = require('@abtnode/logger')('@abtnode/core:blocklet:manager');
|
|
|
23
23
|
const downloadFile = require('@abtnode/util/lib/download-file');
|
|
24
24
|
const Lock = require('@abtnode/util/lib/lock');
|
|
25
25
|
const { getVcFromPresentation } = require('@abtnode/util/lib/vc');
|
|
26
|
-
const { VC_TYPE_BLOCKLET_PURCHASE, WHO_CAN_ACCESS } = require('@abtnode/constant');
|
|
26
|
+
const { VC_TYPE_BLOCKLET_PURCHASE, WHO_CAN_ACCESS, SERVER_ROLES } = require('@abtnode/constant');
|
|
27
27
|
|
|
28
28
|
const getBlockletEngine = require('@blocklet/meta/lib/engine');
|
|
29
29
|
const {
|
|
@@ -38,6 +38,7 @@ const {
|
|
|
38
38
|
forEachChild,
|
|
39
39
|
getComponentId,
|
|
40
40
|
getComponentBundleId,
|
|
41
|
+
isExternalBlocklet,
|
|
41
42
|
} = require('@blocklet/meta/lib/util');
|
|
42
43
|
const getComponentProcessId = require('@blocklet/meta/lib/get-component-process-id');
|
|
43
44
|
const validateBlockletEntry = require('@blocklet/meta/lib/entry');
|
|
@@ -47,6 +48,8 @@ const { update: updateMetaFile } = require('@blocklet/meta/lib/file');
|
|
|
47
48
|
const { titleSchema, descriptionSchema, mountPointSchema, logoSchema } = require('@blocklet/meta/lib/schema');
|
|
48
49
|
const hasReservedKey = require('@blocklet/meta/lib/has-reserved-key');
|
|
49
50
|
|
|
51
|
+
const { toExternalBlocklet } = toBlockletDid;
|
|
52
|
+
|
|
50
53
|
const {
|
|
51
54
|
BlockletStatus,
|
|
52
55
|
BlockletSource,
|
|
@@ -105,9 +108,8 @@ const {
|
|
|
105
108
|
getBlocklet,
|
|
106
109
|
ensureEnvDefault,
|
|
107
110
|
} = require('../../util/blocklet');
|
|
108
|
-
const
|
|
111
|
+
const StoreUtil = require('../../util/store');
|
|
109
112
|
const states = require('../../states');
|
|
110
|
-
const BlockletRegistry = require('../registry');
|
|
111
113
|
const BaseBlockletManager = require('./base');
|
|
112
114
|
const { get: getEngine } = require('./engine');
|
|
113
115
|
const blockletPm2Events = require('./pm2-events');
|
|
@@ -169,11 +171,14 @@ const getSkippedProcessIds = ({ newBlocklet, oldBlocklet, context = {} }) => {
|
|
|
169
171
|
return res;
|
|
170
172
|
};
|
|
171
173
|
|
|
174
|
+
const getBlockletIndex = (meta, controller) =>
|
|
175
|
+
controller ? toExternalBlocklet(meta.name, controller.id) : { did: meta.did, name: meta.name };
|
|
176
|
+
|
|
172
177
|
class BlockletManager extends BaseBlockletManager {
|
|
173
178
|
/**
|
|
174
179
|
* @param {*} dataDirs generate by ../../util:getDataDirs
|
|
175
180
|
*/
|
|
176
|
-
constructor({ dataDirs,
|
|
181
|
+
constructor({ dataDirs, startQueue, installQueue, daemon = false, teamManager }) {
|
|
177
182
|
super();
|
|
178
183
|
|
|
179
184
|
this.dataDirs = dataDirs;
|
|
@@ -190,7 +195,6 @@ class BlockletManager extends BaseBlockletManager {
|
|
|
190
195
|
* { [download-did-version]: Lock }
|
|
191
196
|
*/
|
|
192
197
|
this.downloadLocks = {};
|
|
193
|
-
this.registry = registry;
|
|
194
198
|
|
|
195
199
|
// cached installed blocklets for performance
|
|
196
200
|
this.cachedBlocklets = null;
|
|
@@ -198,7 +202,7 @@ class BlockletManager extends BaseBlockletManager {
|
|
|
198
202
|
// cached blocklet latest versions from each registries
|
|
199
203
|
this.cachedBlockletVersions = new LRU({
|
|
200
204
|
max: 40, // cache at most 40 blocklets
|
|
201
|
-
maxAge: process.env.NODE_ENV === 'test' ? 500 : 5 * 60 * 1000, // cache for 5 minute
|
|
205
|
+
maxAge: process.env.NODE_ENV === 'test' ? 500 : 0.5 * 60 * 1000, // cache for 0.5 minute
|
|
202
206
|
});
|
|
203
207
|
|
|
204
208
|
if (daemon) {
|
|
@@ -216,8 +220,17 @@ class BlockletManager extends BaseBlockletManager {
|
|
|
216
220
|
*
|
|
217
221
|
* @param {{
|
|
218
222
|
* url: string;
|
|
219
|
-
*
|
|
220
|
-
*
|
|
223
|
+
* file: string;
|
|
224
|
+
* diffVersion: string;
|
|
225
|
+
* deleteSet: Array<string>;
|
|
226
|
+
* did: string;
|
|
227
|
+
* title: string;
|
|
228
|
+
* description: string;
|
|
229
|
+
* sync: boolean = false; // download synchronously, not use queue
|
|
230
|
+
* delay: number; // push download task to queue after a delay
|
|
231
|
+
* downloadTokenList: Array<{did: string, token: string}>;
|
|
232
|
+
* startImmediately: boolean;
|
|
233
|
+
* controller: Controller
|
|
221
234
|
* }} params
|
|
222
235
|
* @param {{
|
|
223
236
|
* [key: string]: any
|
|
@@ -245,7 +258,8 @@ class BlockletManager extends BaseBlockletManager {
|
|
|
245
258
|
}
|
|
246
259
|
|
|
247
260
|
if (source === BlockletSource.url) {
|
|
248
|
-
|
|
261
|
+
const { url, controller, sync, delay } = params;
|
|
262
|
+
return this._installFromUrl({ url, controller, sync, delay }, context);
|
|
249
263
|
}
|
|
250
264
|
|
|
251
265
|
if (source === BlockletSource.upload) {
|
|
@@ -254,7 +268,8 @@ class BlockletManager extends BaseBlockletManager {
|
|
|
254
268
|
}
|
|
255
269
|
|
|
256
270
|
if (source === BlockletSource.registry) {
|
|
257
|
-
|
|
271
|
+
const { did, controller, sync, delay } = params;
|
|
272
|
+
return this._installFromStore({ did, controller, sync, delay }, context);
|
|
258
273
|
}
|
|
259
274
|
|
|
260
275
|
if (source === BlockletSource.custom) {
|
|
@@ -283,15 +298,38 @@ class BlockletManager extends BaseBlockletManager {
|
|
|
283
298
|
* @param {String} name custom component name
|
|
284
299
|
*
|
|
285
300
|
* @param {ConfigEntry} configs pre configs
|
|
301
|
+
* @param {Boolean} skipNavigation
|
|
286
302
|
*/
|
|
287
303
|
async installComponent(
|
|
288
|
-
{
|
|
304
|
+
{
|
|
305
|
+
rootDid,
|
|
306
|
+
mountPoint,
|
|
307
|
+
url,
|
|
308
|
+
file,
|
|
309
|
+
did,
|
|
310
|
+
diffVersion,
|
|
311
|
+
deleteSet,
|
|
312
|
+
title,
|
|
313
|
+
name,
|
|
314
|
+
configs,
|
|
315
|
+
downloadTokenList,
|
|
316
|
+
skipNavigation,
|
|
317
|
+
},
|
|
289
318
|
context = {}
|
|
290
319
|
) {
|
|
291
320
|
logger.debug('start install component', { rootDid, mountPoint, url });
|
|
292
321
|
|
|
293
322
|
if (file) {
|
|
294
|
-
return this._installComponentFromUpload({
|
|
323
|
+
return this._installComponentFromUpload({
|
|
324
|
+
rootDid,
|
|
325
|
+
mountPoint,
|
|
326
|
+
file,
|
|
327
|
+
did,
|
|
328
|
+
diffVersion,
|
|
329
|
+
deleteSet,
|
|
330
|
+
skipNavigation,
|
|
331
|
+
context,
|
|
332
|
+
});
|
|
295
333
|
}
|
|
296
334
|
|
|
297
335
|
if (url) {
|
|
@@ -305,6 +343,7 @@ class BlockletManager extends BaseBlockletManager {
|
|
|
305
343
|
name,
|
|
306
344
|
configs,
|
|
307
345
|
downloadTokenList,
|
|
346
|
+
skipNavigation,
|
|
308
347
|
});
|
|
309
348
|
}
|
|
310
349
|
|
|
@@ -319,7 +358,7 @@ class BlockletManager extends BaseBlockletManager {
|
|
|
319
358
|
|
|
320
359
|
if (checkPrice && !isFree && meta.nftFactory) {
|
|
321
360
|
try {
|
|
322
|
-
const registryMeta = await
|
|
361
|
+
const registryMeta = await StoreUtil.getRegistryMeta(new URL(url).origin);
|
|
323
362
|
|
|
324
363
|
if (registryMeta.chainHost) {
|
|
325
364
|
const state = await getFactoryState(registryMeta.chainHost, meta.nftFactory);
|
|
@@ -332,12 +371,33 @@ class BlockletManager extends BaseBlockletManager {
|
|
|
332
371
|
}
|
|
333
372
|
}
|
|
334
373
|
|
|
335
|
-
const { inStore, registryUrl } = await parseSourceUrl(url);
|
|
374
|
+
const { inStore, registryUrl } = await StoreUtil.parseSourceUrl(url);
|
|
375
|
+
|
|
376
|
+
return { meta, isFree, inStore, registryUrl };
|
|
377
|
+
}
|
|
378
|
+
|
|
379
|
+
async getBlockletByBundle({ did, name }, context) {
|
|
380
|
+
if (toBlockletDid(name) !== did) {
|
|
381
|
+
throw new Error('did and name does not match');
|
|
382
|
+
}
|
|
383
|
+
|
|
384
|
+
if (!context?.user) {
|
|
385
|
+
throw new Error('user does not exist');
|
|
386
|
+
}
|
|
387
|
+
|
|
388
|
+
let blockletDid = did;
|
|
389
|
+
let isExternal = false;
|
|
390
|
+
|
|
391
|
+
if (context.user.role === SERVER_ROLES.EXTERNAL_BLOCKLET_CONTROLLER) {
|
|
392
|
+
blockletDid = toExternalBlocklet(name, context.user.did, { didOnly: true });
|
|
393
|
+
isExternal = true;
|
|
394
|
+
}
|
|
395
|
+
|
|
396
|
+
const blocklet = await states.blocklet.getBlocklet(blockletDid);
|
|
336
397
|
|
|
337
|
-
const blocklet = await states.blocklet.getBlocklet(meta.did);
|
|
338
398
|
const isRunning = blocklet ? blocklet.status === BlockletStatus.running : false;
|
|
339
399
|
|
|
340
|
-
return {
|
|
400
|
+
return { isInstalled: !!blocklet, isRunning, blockletDid, isExternal };
|
|
341
401
|
}
|
|
342
402
|
|
|
343
403
|
async installBlockletFromVc({ vcPresentation, challenge }, context) {
|
|
@@ -364,6 +424,15 @@ class BlockletManager extends BaseBlockletManager {
|
|
|
364
424
|
const blocklet = await this.ensureBlocklet(did, { e2eMode });
|
|
365
425
|
|
|
366
426
|
try {
|
|
427
|
+
// blocklet may be manually stopped durning starting
|
|
428
|
+
// so error message would not be sent if blocklet is stopped
|
|
429
|
+
// so we need update status first
|
|
430
|
+
await states.blocklet.setBlockletStatus(did, BlockletStatus.starting);
|
|
431
|
+
blocklet.status = BlockletStatus.starting;
|
|
432
|
+
|
|
433
|
+
// validate requirement and engine
|
|
434
|
+
await validateBlocklet(blocklet);
|
|
435
|
+
|
|
367
436
|
if (!hasRunnableComponent(blocklet)) {
|
|
368
437
|
throw new Error('No runnable component found');
|
|
369
438
|
}
|
|
@@ -376,9 +445,6 @@ class BlockletManager extends BaseBlockletManager {
|
|
|
376
445
|
);
|
|
377
446
|
}
|
|
378
447
|
|
|
379
|
-
// update status
|
|
380
|
-
await states.blocklet.setBlockletStatus(did, BlockletStatus.starting);
|
|
381
|
-
blocklet.status = BlockletStatus.starting;
|
|
382
448
|
this.emit(BlockletEvents.statusChange, blocklet);
|
|
383
449
|
|
|
384
450
|
if (blocklet.mode === BLOCKLET_MODES.DEVELOPMENT) {
|
|
@@ -787,36 +853,46 @@ class BlockletManager extends BaseBlockletManager {
|
|
|
787
853
|
return this.attachRuntimeInfo({ did, nodeInfo, diskInfo: true, context });
|
|
788
854
|
}
|
|
789
855
|
|
|
790
|
-
async list({ includeRuntimeInfo = true, useCache = true } = {}, context) {
|
|
856
|
+
async list({ includeRuntimeInfo = true, useCache = true, filter } = {}, context) {
|
|
791
857
|
const blocklets = await states.blocklet.getBlocklets();
|
|
792
|
-
|
|
793
|
-
|
|
794
|
-
|
|
858
|
+
let list = blocklets;
|
|
859
|
+
|
|
860
|
+
if (includeRuntimeInfo) {
|
|
861
|
+
const nodeInfo = await states.node.read();
|
|
862
|
+
const updated = (
|
|
863
|
+
await Promise.all(
|
|
864
|
+
blocklets.map((x) => {
|
|
865
|
+
if (isBeforeInstalled(x.status)) {
|
|
866
|
+
return x;
|
|
867
|
+
}
|
|
795
868
|
|
|
796
|
-
|
|
797
|
-
|
|
798
|
-
await Promise.all(
|
|
799
|
-
blocklets.map((x) => {
|
|
800
|
-
if (isBeforeInstalled(x.status)) {
|
|
801
|
-
return x;
|
|
802
|
-
}
|
|
869
|
+
const cachedBlocklet =
|
|
870
|
+
useCache && this.cachedBlocklets ? this.cachedBlocklets.find((y) => y.meta.did === x.meta.did) : null;
|
|
803
871
|
|
|
804
|
-
|
|
805
|
-
|
|
872
|
+
return this.attachRuntimeInfo({
|
|
873
|
+
did: x.meta.did,
|
|
874
|
+
nodeInfo,
|
|
875
|
+
diskInfo: false,
|
|
876
|
+
context,
|
|
877
|
+
cachedBlocklet,
|
|
878
|
+
});
|
|
879
|
+
})
|
|
880
|
+
)
|
|
881
|
+
).filter(Boolean);
|
|
806
882
|
|
|
807
|
-
|
|
808
|
-
|
|
809
|
-
|
|
810
|
-
diskInfo: false,
|
|
811
|
-
context,
|
|
812
|
-
cachedBlocklet,
|
|
813
|
-
});
|
|
814
|
-
})
|
|
815
|
-
)
|
|
816
|
-
).filter(Boolean);
|
|
883
|
+
this.cachedBlocklets = cloneDeep(updated);
|
|
884
|
+
list = updated;
|
|
885
|
+
}
|
|
817
886
|
|
|
818
|
-
|
|
819
|
-
|
|
887
|
+
if (filter === 'external-excluded') {
|
|
888
|
+
return list.filter((x) => !isExternalBlocklet(x));
|
|
889
|
+
}
|
|
890
|
+
|
|
891
|
+
if (filter === 'external-only') {
|
|
892
|
+
return list.filter(isExternalBlocklet);
|
|
893
|
+
}
|
|
894
|
+
|
|
895
|
+
return list;
|
|
820
896
|
}
|
|
821
897
|
|
|
822
898
|
// eslint-disable-next-line no-unused-vars
|
|
@@ -1043,13 +1119,11 @@ class BlockletManager extends BaseBlockletManager {
|
|
|
1043
1119
|
|
|
1044
1120
|
const upgradeFromRegistry = registryUrl || blocklet.deployedFrom;
|
|
1045
1121
|
|
|
1046
|
-
|
|
1047
|
-
|
|
1048
|
-
|
|
1049
|
-
|
|
1050
|
-
|
|
1051
|
-
context
|
|
1052
|
-
);
|
|
1122
|
+
let newVersionMeta = await StoreUtil.getBlockletMeta({
|
|
1123
|
+
did: blocklet.meta.bundleDid,
|
|
1124
|
+
registryUrl: upgradeFromRegistry,
|
|
1125
|
+
});
|
|
1126
|
+
newVersionMeta = ensureMeta(newVersionMeta, { name: blocklet.meta.name, did: blocklet.meta.did });
|
|
1053
1127
|
|
|
1054
1128
|
function getSignature(signatures = [], oldSignatures = []) {
|
|
1055
1129
|
// if blocklet installed from local, upload, url, the signature is undefined, should return null
|
|
@@ -1335,20 +1409,31 @@ class BlockletManager extends BaseBlockletManager {
|
|
|
1335
1409
|
|
|
1336
1410
|
const oldBlocklet = { children: children.filter((x) => x.dynamic) }; // let downloader skip re-downloading dynamic blocklet
|
|
1337
1411
|
await this._downloadBlocklet(added, oldBlocklet);
|
|
1338
|
-
await states.blocklet.setBlockletStatus(did, BlockletStatus.installed);
|
|
1339
1412
|
|
|
1340
|
-
// Add
|
|
1413
|
+
// Add Config
|
|
1341
1414
|
await this._setConfigsFromMeta(did);
|
|
1415
|
+
let blocklet = await this.ensureBlocklet(did);
|
|
1416
|
+
|
|
1417
|
+
// pre install
|
|
1418
|
+
await this._runPreInstallHook(blocklet);
|
|
1419
|
+
|
|
1420
|
+
// Add environments
|
|
1342
1421
|
await this.updateBlockletEnvironment(did);
|
|
1422
|
+
blocklet = await this.ensureBlocklet(did);
|
|
1343
1423
|
|
|
1344
|
-
|
|
1424
|
+
// post install
|
|
1425
|
+
await this._runPostInstallHook(blocklet);
|
|
1426
|
+
|
|
1427
|
+
await states.blocklet.setBlockletStatus(did, BlockletStatus.installed);
|
|
1428
|
+
|
|
1429
|
+
blocklet = await this.ensureBlocklet(did);
|
|
1345
1430
|
|
|
1346
1431
|
await fs.writeFile(path.join(blocklet.env.dataDir, 'logo.svg'), createDidLogo(blocklet.meta.did));
|
|
1347
1432
|
|
|
1348
1433
|
return blocklet;
|
|
1349
1434
|
}
|
|
1350
1435
|
|
|
1351
|
-
async _devComponent({ folder, meta, rootDid, mountPoint }) {
|
|
1436
|
+
async _devComponent({ folder, meta, rootDid, mountPoint, skipNavigation = true }) {
|
|
1352
1437
|
const { did, version } = meta;
|
|
1353
1438
|
|
|
1354
1439
|
const existRoot = await states.blocklet.getBlocklet(rootDid);
|
|
@@ -1373,36 +1458,44 @@ class BlockletManager extends BaseBlockletManager {
|
|
|
1373
1458
|
}
|
|
1374
1459
|
|
|
1375
1460
|
const defaultPath = formatName(meta.name);
|
|
1376
|
-
const
|
|
1377
|
-
|
|
1378
|
-
|
|
1379
|
-
|
|
1380
|
-
|
|
1381
|
-
|
|
1382
|
-
|
|
1383
|
-
|
|
1384
|
-
|
|
1385
|
-
|
|
1386
|
-
|
|
1387
|
-
];
|
|
1388
|
-
await validateBlocklet(children[0]);
|
|
1389
|
-
await states.blocklet.addChildren(rootDid, children);
|
|
1461
|
+
const component = {
|
|
1462
|
+
meta: ensureMeta(meta),
|
|
1463
|
+
mountPoint: mountPoint || `/${defaultPath}`,
|
|
1464
|
+
source: BlockletSource.local,
|
|
1465
|
+
deployedFrom: folder,
|
|
1466
|
+
status: BlockletStatus.installed,
|
|
1467
|
+
mode: BLOCKLET_MODES.DEVELOPMENT,
|
|
1468
|
+
dynamic: true,
|
|
1469
|
+
children: await parseChildrenFromMeta(meta, { ancestors: [{ mountPoint: mountPoint || `/${defaultPath}` }] }),
|
|
1470
|
+
};
|
|
1471
|
+
await validateBlocklet(component);
|
|
1472
|
+
await states.blocklet.addChildren(rootDid, [component]);
|
|
1390
1473
|
|
|
1391
1474
|
const newBlocklet = await states.blocklet.getBlocklet(rootDid);
|
|
1392
1475
|
await this._downloadBlocklet(newBlocklet, existRoot);
|
|
1393
1476
|
await states.blocklet.setBlockletStatus(rootDid, BlockletStatus.stopped);
|
|
1394
1477
|
|
|
1395
|
-
await this._upsertDynamicNavigation(existRoot.meta.did,
|
|
1478
|
+
await this._upsertDynamicNavigation(existRoot.meta.did, component, { skipNavigation });
|
|
1396
1479
|
|
|
1397
|
-
// Add
|
|
1480
|
+
// Add Config
|
|
1398
1481
|
await this._setConfigsFromMeta(rootDid);
|
|
1482
|
+
let blocklet = await this.ensureBlocklet(rootDid);
|
|
1483
|
+
|
|
1484
|
+
// pre install
|
|
1485
|
+
await this._runPreInstallHook(blocklet);
|
|
1486
|
+
|
|
1487
|
+
// Add environments
|
|
1399
1488
|
await this.updateBlockletEnvironment(rootDid);
|
|
1489
|
+
blocklet = await this.ensureBlocklet(rootDid);
|
|
1490
|
+
|
|
1491
|
+
// post install
|
|
1492
|
+
await this._runPostInstallHook(blocklet);
|
|
1400
1493
|
|
|
1401
1494
|
logger.info('add blocklet component for dev', { did, version, meta });
|
|
1402
1495
|
|
|
1403
|
-
|
|
1496
|
+
blocklet = await this.ensureBlocklet(rootDid);
|
|
1404
1497
|
|
|
1405
|
-
return
|
|
1498
|
+
return blocklet;
|
|
1406
1499
|
}
|
|
1407
1500
|
|
|
1408
1501
|
async ensureBlocklet(did, opts = {}) {
|
|
@@ -1857,13 +1950,15 @@ class BlockletManager extends BaseBlockletManager {
|
|
|
1857
1950
|
* did: string;
|
|
1858
1951
|
* registry: string;
|
|
1859
1952
|
* sync: boolean;
|
|
1953
|
+
* delay: number;
|
|
1954
|
+
* controller: Controller;
|
|
1860
1955
|
* }} params
|
|
1861
1956
|
* @param {*} context
|
|
1862
1957
|
* @return {*}
|
|
1863
1958
|
* @memberof BlockletManager
|
|
1864
1959
|
*/
|
|
1865
1960
|
async _installFromStore(params, context) {
|
|
1866
|
-
const { did, registry, sync } = params;
|
|
1961
|
+
const { did, registry, sync, delay, controller } = params;
|
|
1867
1962
|
|
|
1868
1963
|
logger.debug('start install blocklet', { did });
|
|
1869
1964
|
if (!isValidDid(did)) {
|
|
@@ -1871,67 +1966,96 @@ class BlockletManager extends BaseBlockletManager {
|
|
|
1871
1966
|
}
|
|
1872
1967
|
|
|
1873
1968
|
const registryUrl = registry || (await states.node.getBlockletRegistry());
|
|
1874
|
-
const info = await
|
|
1875
|
-
const meta = await
|
|
1969
|
+
const info = await StoreUtil.getRegistryMeta(registryUrl);
|
|
1970
|
+
const meta = await StoreUtil.getBlockletMeta({ did, registryUrl });
|
|
1876
1971
|
if (!meta) {
|
|
1877
1972
|
throw new Error('Can not install blocklet that not found in registry');
|
|
1878
1973
|
}
|
|
1879
1974
|
|
|
1880
|
-
const
|
|
1975
|
+
const { did: blockletDid, name: blockletName } = getBlockletIndex(meta, controller);
|
|
1976
|
+
|
|
1977
|
+
const state = await states.blocklet.getBlocklet(blockletDid);
|
|
1978
|
+
|
|
1881
1979
|
if (state) {
|
|
1882
1980
|
throw new Error('Can not install an already installed blocklet');
|
|
1883
1981
|
}
|
|
1884
1982
|
|
|
1983
|
+
if (controller?.vcId) {
|
|
1984
|
+
// sometimes nedb will throw error if use states.blocklet.count({ ['controller.vcId']: controller.vcId })
|
|
1985
|
+
const blocklets = await states.blocklet.find({}, { controller: 1 });
|
|
1986
|
+
const count = blocklets.filter((x) => x.controller?.vcId === controller.vcId).length;
|
|
1987
|
+
|
|
1988
|
+
if (count >= (controller.appMaxCount || 1)) {
|
|
1989
|
+
throw new Error(
|
|
1990
|
+
`You can only install ${controller.appMaxCount} blocklet with this credential: ${controller.vcId}`
|
|
1991
|
+
);
|
|
1992
|
+
}
|
|
1993
|
+
}
|
|
1994
|
+
|
|
1885
1995
|
// install
|
|
1886
1996
|
return this._install({
|
|
1887
|
-
meta,
|
|
1997
|
+
meta: ensureMeta(meta, { did: blockletDid, name: blockletName }),
|
|
1888
1998
|
source: BlockletSource.registry,
|
|
1889
1999
|
deployedFrom: info.cdnUrl || registryUrl,
|
|
1890
2000
|
sync,
|
|
2001
|
+
delay,
|
|
2002
|
+
controller,
|
|
1891
2003
|
context,
|
|
1892
2004
|
});
|
|
1893
2005
|
}
|
|
1894
2006
|
|
|
1895
2007
|
/**
|
|
1896
|
-
*
|
|
2008
|
+
* @type {{
|
|
2009
|
+
* id: string;
|
|
2010
|
+
* vcId: string;
|
|
2011
|
+
* expireDate: Date;
|
|
2012
|
+
* }} Controller
|
|
1897
2013
|
*
|
|
1898
2014
|
* @param {{
|
|
1899
2015
|
* url: string;
|
|
1900
2016
|
* sync: boolean;
|
|
2017
|
+
* delay: number;
|
|
2018
|
+
* controller: Controller;
|
|
1901
2019
|
* }} params
|
|
1902
2020
|
* @param {{}} context
|
|
1903
2021
|
* @return {*}
|
|
1904
2022
|
* @memberof BlockletManager
|
|
1905
2023
|
*/
|
|
1906
2024
|
async _installFromUrl(params, context) {
|
|
1907
|
-
const { url, sync } = params;
|
|
2025
|
+
const { url, sync, delay, controller } = params;
|
|
1908
2026
|
|
|
1909
2027
|
logger.debug('start install blocklet', { url });
|
|
1910
2028
|
|
|
1911
|
-
const
|
|
2029
|
+
const bundleMeta = await getBlockletMetaFromUrl(url);
|
|
2030
|
+
|
|
2031
|
+
if (!bundleMeta) {
|
|
2032
|
+
throw new Error(`Can not install blocklet that not found by url: ${url}`);
|
|
2033
|
+
}
|
|
2034
|
+
|
|
2035
|
+
const { did: blockletDid, name: blockletName } = getBlockletIndex(bundleMeta, controller);
|
|
2036
|
+
|
|
2037
|
+
// install from store if url is a store url
|
|
2038
|
+
const { inStore, registryUrl, blockletDid: bundleDid } = await StoreUtil.parseSourceUrl(url, controller);
|
|
1912
2039
|
if (inStore) {
|
|
1913
2040
|
const exist = await states.blocklet.getBlocklet(blockletDid);
|
|
1914
2041
|
if (exist) {
|
|
1915
|
-
return this.upgrade({ did: blockletDid, registryUrl }, context);
|
|
2042
|
+
return this.upgrade({ did: blockletDid, registryUrl, sync, delay }, context);
|
|
1916
2043
|
}
|
|
1917
2044
|
|
|
1918
|
-
return this._installFromStore({ did:
|
|
2045
|
+
return this._installFromStore({ did: bundleDid, registry: registryUrl, controller, sync, delay }, context);
|
|
1919
2046
|
}
|
|
1920
2047
|
|
|
1921
|
-
const meta =
|
|
1922
|
-
|
|
1923
|
-
if (!meta) {
|
|
1924
|
-
throw new Error(`Can not install blocklet that not found by url: ${url}`);
|
|
1925
|
-
}
|
|
2048
|
+
const meta = ensureMeta(bundleMeta, { name: blockletName, did: blockletDid });
|
|
1926
2049
|
|
|
1927
2050
|
// upgrade
|
|
1928
|
-
const exist = await states.blocklet.getBlocklet(
|
|
2051
|
+
const exist = await states.blocklet.getBlocklet(blockletDid);
|
|
1929
2052
|
if (exist) {
|
|
1930
2053
|
return this._upgrade({
|
|
1931
2054
|
meta,
|
|
1932
2055
|
source: BlockletSource.url,
|
|
1933
2056
|
deployedFrom: url,
|
|
1934
2057
|
sync,
|
|
2058
|
+
delay,
|
|
1935
2059
|
context,
|
|
1936
2060
|
});
|
|
1937
2061
|
}
|
|
@@ -1942,6 +2066,8 @@ class BlockletManager extends BaseBlockletManager {
|
|
|
1942
2066
|
source: BlockletSource.url,
|
|
1943
2067
|
deployedFrom: url,
|
|
1944
2068
|
sync,
|
|
2069
|
+
delay,
|
|
2070
|
+
controller,
|
|
1945
2071
|
context,
|
|
1946
2072
|
});
|
|
1947
2073
|
}
|
|
@@ -1956,13 +2082,14 @@ class BlockletManager extends BaseBlockletManager {
|
|
|
1956
2082
|
did: inputDid,
|
|
1957
2083
|
configs,
|
|
1958
2084
|
downloadTokenList,
|
|
2085
|
+
skipNavigation,
|
|
1959
2086
|
}) {
|
|
1960
2087
|
const blocklet = await this._getBlockletForInstallation(rootDid);
|
|
1961
2088
|
if (!blocklet) {
|
|
1962
2089
|
throw new Error('Root blocklet does not exist');
|
|
1963
2090
|
}
|
|
1964
2091
|
|
|
1965
|
-
const { inStore } = await parseSourceUrl(url);
|
|
2092
|
+
const { inStore } = await StoreUtil.parseSourceUrl(url);
|
|
1966
2093
|
|
|
1967
2094
|
const meta = await getBlockletMetaFromUrl(url);
|
|
1968
2095
|
|
|
@@ -2018,7 +2145,7 @@ class BlockletManager extends BaseBlockletManager {
|
|
|
2018
2145
|
await states.blocklet.addChildren(rootDid, [newChild]);
|
|
2019
2146
|
|
|
2020
2147
|
// update navigation
|
|
2021
|
-
await this._upsertDynamicNavigation(blocklet.meta.did, newChild);
|
|
2148
|
+
await this._upsertDynamicNavigation(blocklet.meta.did, newChild, { skipNavigation });
|
|
2022
2149
|
|
|
2023
2150
|
// update configs
|
|
2024
2151
|
if (Array.isArray(configs)) {
|
|
@@ -2100,7 +2227,7 @@ class BlockletManager extends BaseBlockletManager {
|
|
|
2100
2227
|
.pipe(writeStream);
|
|
2101
2228
|
readStream.on('error', (error) => {
|
|
2102
2229
|
logger.error('File upload read stream failed', { error });
|
|
2103
|
-
writeStream.destroy(new Error(
|
|
2230
|
+
writeStream.destroy(new Error(`File upload read stream failed, ${error.message}`));
|
|
2104
2231
|
});
|
|
2105
2232
|
writeStream.on('error', (error) => {
|
|
2106
2233
|
logger.error('File upload write stream failed', { error });
|
|
@@ -2213,7 +2340,16 @@ class BlockletManager extends BaseBlockletManager {
|
|
|
2213
2340
|
}
|
|
2214
2341
|
}
|
|
2215
2342
|
|
|
2216
|
-
async _installComponentFromUpload({
|
|
2343
|
+
async _installComponentFromUpload({
|
|
2344
|
+
rootDid,
|
|
2345
|
+
mountPoint,
|
|
2346
|
+
file,
|
|
2347
|
+
did,
|
|
2348
|
+
diffVersion,
|
|
2349
|
+
deleteSet,
|
|
2350
|
+
skipNavigation,
|
|
2351
|
+
context,
|
|
2352
|
+
}) {
|
|
2217
2353
|
logger.info('install blocklet', { from: 'upload file' });
|
|
2218
2354
|
// download
|
|
2219
2355
|
const { cwd, tarFile } = await this._downloadFromUpload(file);
|
|
@@ -2280,7 +2416,7 @@ class BlockletManager extends BaseBlockletManager {
|
|
|
2280
2416
|
|
|
2281
2417
|
checkDuplicateComponents(newBlocklet.children);
|
|
2282
2418
|
|
|
2283
|
-
await this._upsertDynamicNavigation(newBlocklet.meta.did, newChild);
|
|
2419
|
+
await this._upsertDynamicNavigation(newBlocklet.meta.did, newChild, { skipNavigation });
|
|
2284
2420
|
|
|
2285
2421
|
await this._downloadBlocklet(newBlocklet, oldBlocklet);
|
|
2286
2422
|
|
|
@@ -2403,12 +2539,14 @@ class BlockletManager extends BaseBlockletManager {
|
|
|
2403
2539
|
* deployedFrom: string;
|
|
2404
2540
|
* context: {}
|
|
2405
2541
|
* sync: boolean = false;
|
|
2542
|
+
* delay: number;
|
|
2543
|
+
* controller: Controller;
|
|
2406
2544
|
* }} params
|
|
2407
2545
|
* @return {*}
|
|
2408
2546
|
* @memberof BlockletManager
|
|
2409
2547
|
*/
|
|
2410
2548
|
async _install(params) {
|
|
2411
|
-
const { meta, source, deployedFrom, context, sync } = params;
|
|
2549
|
+
const { meta, source, deployedFrom, context, sync, delay, controller } = params;
|
|
2412
2550
|
|
|
2413
2551
|
validateBlockletMeta(meta, { ensureDist: true });
|
|
2414
2552
|
|
|
@@ -2424,6 +2562,7 @@ class BlockletManager extends BaseBlockletManager {
|
|
|
2424
2562
|
source,
|
|
2425
2563
|
deployedFrom,
|
|
2426
2564
|
children,
|
|
2565
|
+
controller,
|
|
2427
2566
|
});
|
|
2428
2567
|
|
|
2429
2568
|
await validateBlocklet(blocklet);
|
|
@@ -2459,31 +2598,33 @@ class BlockletManager extends BaseBlockletManager {
|
|
|
2459
2598
|
return states.blocklet.getBlocklet(did);
|
|
2460
2599
|
}
|
|
2461
2600
|
|
|
2462
|
-
|
|
2463
|
-
|
|
2464
|
-
|
|
2465
|
-
|
|
2466
|
-
|
|
2467
|
-
|
|
2468
|
-
|
|
2469
|
-
|
|
2470
|
-
|
|
2471
|
-
|
|
2472
|
-
|
|
2473
|
-
|
|
2474
|
-
|
|
2475
|
-
|
|
2476
|
-
|
|
2477
|
-
|
|
2601
|
+
setTimeout(() => {
|
|
2602
|
+
const ticket = this.installQueue.push(
|
|
2603
|
+
{
|
|
2604
|
+
entity: 'blocklet',
|
|
2605
|
+
action: 'download',
|
|
2606
|
+
id: did,
|
|
2607
|
+
...downloadParams,
|
|
2608
|
+
},
|
|
2609
|
+
did
|
|
2610
|
+
);
|
|
2611
|
+
ticket.on('failed', async (err) => {
|
|
2612
|
+
logger.error('failed to install blocklet', { name, did, version, error: err });
|
|
2613
|
+
try {
|
|
2614
|
+
await this._rollback('install', did, { extraState: oldExtraState });
|
|
2615
|
+
} catch (e) {
|
|
2616
|
+
logger.error('failed to remove blocklet on install error', { did: meta.did, error: e });
|
|
2617
|
+
}
|
|
2478
2618
|
|
|
2479
|
-
|
|
2480
|
-
|
|
2481
|
-
|
|
2482
|
-
|
|
2483
|
-
|
|
2484
|
-
|
|
2619
|
+
states.notification.create({
|
|
2620
|
+
title: 'Blocklet Install Failed',
|
|
2621
|
+
description: `Blocklet ${name}@${version} install failed with error: ${err.message || 'queue exception'}`,
|
|
2622
|
+
entityType: 'blocklet',
|
|
2623
|
+
entityId: did,
|
|
2624
|
+
severity: 'error',
|
|
2625
|
+
});
|
|
2485
2626
|
});
|
|
2486
|
-
});
|
|
2627
|
+
}, delay || 0);
|
|
2487
2628
|
|
|
2488
2629
|
return blocklet1;
|
|
2489
2630
|
} catch (err) {
|
|
@@ -2746,33 +2887,14 @@ class BlockletManager extends BaseBlockletManager {
|
|
|
2746
2887
|
}
|
|
2747
2888
|
|
|
2748
2889
|
// pre install
|
|
2749
|
-
|
|
2750
|
-
const preInstall = (b) =>
|
|
2751
|
-
hooks.preInstall(b.env.processId, {
|
|
2752
|
-
hooks: Object.assign(b.meta.hooks || {}, b.meta.scripts || {}),
|
|
2753
|
-
env: { ...nodeEnvironments },
|
|
2754
|
-
appDir: b.env.appDir,
|
|
2755
|
-
did, // root blocklet did
|
|
2756
|
-
notification: states.notification,
|
|
2757
|
-
context,
|
|
2758
|
-
});
|
|
2759
|
-
await forEachBlocklet(blocklet, preInstall, { parallel: true });
|
|
2890
|
+
await this._runPreInstallHook(blocklet, context);
|
|
2760
2891
|
|
|
2761
2892
|
// Add environments
|
|
2762
2893
|
await this.updateBlockletEnvironment(meta.did);
|
|
2763
2894
|
blocklet = await this.ensureBlocklet(did);
|
|
2764
2895
|
|
|
2765
2896
|
// post install
|
|
2766
|
-
|
|
2767
|
-
hooks.postInstall(b.env.processId, {
|
|
2768
|
-
hooks: Object.assign(b.meta.hooks || {}, b.meta.scripts || {}),
|
|
2769
|
-
env: getRuntimeEnvironments(b, nodeEnvironments, ancestors),
|
|
2770
|
-
appDir: b.env.appDir,
|
|
2771
|
-
did, // root blocklet did
|
|
2772
|
-
notification: states.notification,
|
|
2773
|
-
context,
|
|
2774
|
-
});
|
|
2775
|
-
await forEachBlocklet(blocklet, postInstall, { parallel: true });
|
|
2897
|
+
await this._runPostInstallHook(blocklet, context);
|
|
2776
2898
|
|
|
2777
2899
|
await states.blocklet.setBlockletStatus(did, BlockletStatus.installed);
|
|
2778
2900
|
blocklet = await this.ensureBlocklet(did);
|
|
@@ -2858,33 +2980,14 @@ class BlockletManager extends BaseBlockletManager {
|
|
|
2858
2980
|
let blocklet = await this.ensureBlocklet(did);
|
|
2859
2981
|
|
|
2860
2982
|
// pre install
|
|
2861
|
-
|
|
2862
|
-
const preInstall = (b) =>
|
|
2863
|
-
hooks.preInstall(b.env.processId, {
|
|
2864
|
-
hooks: Object.assign(b.meta.hooks || {}, b.meta.scripts || {}),
|
|
2865
|
-
env: { ...nodeEnvironments },
|
|
2866
|
-
appDir: b.env.appDir,
|
|
2867
|
-
did, // root blocklet did
|
|
2868
|
-
notification: states.notification,
|
|
2869
|
-
context,
|
|
2870
|
-
});
|
|
2871
|
-
await forEachBlocklet(blocklet, preInstall, { parallel: true });
|
|
2983
|
+
await this._runPreInstallHook(blocklet, context);
|
|
2872
2984
|
|
|
2873
2985
|
// Add environments
|
|
2874
2986
|
await this.updateBlockletEnvironment(did);
|
|
2875
2987
|
blocklet = await this.ensureBlocklet(did);
|
|
2876
2988
|
|
|
2877
2989
|
// post install
|
|
2878
|
-
|
|
2879
|
-
hooks.postInstall(b.env.processId, {
|
|
2880
|
-
hooks: Object.assign(b.meta.hooks || {}, b.meta.scripts || {}),
|
|
2881
|
-
env: getRuntimeEnvironments(b, nodeEnvironments, ancestors),
|
|
2882
|
-
appDir: b.env.appDir,
|
|
2883
|
-
did, // root blocklet did
|
|
2884
|
-
notification: states.notification,
|
|
2885
|
-
context,
|
|
2886
|
-
});
|
|
2887
|
-
await forEachBlocklet(blocklet, postInstall, { parallel: true });
|
|
2990
|
+
await this._runPostInstallHook(blocklet, context);
|
|
2888
2991
|
|
|
2889
2992
|
logger.info('start migration');
|
|
2890
2993
|
try {
|
|
@@ -2892,6 +2995,7 @@ class BlockletManager extends BaseBlockletManager {
|
|
|
2892
2995
|
forEachBlockletSync(oldBlocklet, (b, { id }) => {
|
|
2893
2996
|
oldVersions[id] = b.meta.version;
|
|
2894
2997
|
});
|
|
2998
|
+
const nodeEnvironments = await states.node.getEnvironments();
|
|
2895
2999
|
const runMigration = (b, { id, ancestors }) => {
|
|
2896
3000
|
return runMigrationScripts({
|
|
2897
3001
|
blocklet: b,
|
|
@@ -3241,11 +3345,7 @@ class BlockletManager extends BaseBlockletManager {
|
|
|
3241
3345
|
logger.info('Download Blocklet', { name, did, bundles: metas.map((x) => get(x, 'dist.tarball')) });
|
|
3242
3346
|
const tasks = [];
|
|
3243
3347
|
for (const meta of metas) {
|
|
3244
|
-
const url =
|
|
3245
|
-
did,
|
|
3246
|
-
tarball: get(meta, 'dist.tarball'),
|
|
3247
|
-
registryUrl: blocklet.source === BlockletSource.registry ? blocklet.deployedFrom : undefined,
|
|
3248
|
-
});
|
|
3348
|
+
const url = meta.dist.tarball;
|
|
3249
3349
|
tasks.push(this._downloadBundle(meta, did, url, context));
|
|
3250
3350
|
}
|
|
3251
3351
|
const results = await Promise.all(tasks);
|
|
@@ -3410,13 +3510,17 @@ class BlockletManager extends BaseBlockletManager {
|
|
|
3410
3510
|
return { did, name };
|
|
3411
3511
|
}
|
|
3412
3512
|
|
|
3413
|
-
async _upsertDynamicNavigation(did, child) {
|
|
3513
|
+
async _upsertDynamicNavigation(did, child, { skipNavigation } = {}) {
|
|
3414
3514
|
const navigation = await states.blockletExtras.getSettings(did, 'navigation', []);
|
|
3415
3515
|
const item = { title: child.meta.title, child: child.meta.name };
|
|
3416
3516
|
const index = navigation.findIndex((x) => x.child === item.child);
|
|
3417
3517
|
if (index > -1) {
|
|
3418
|
-
|
|
3419
|
-
|
|
3518
|
+
if (skipNavigation) {
|
|
3519
|
+
navigation.splice(index, 1);
|
|
3520
|
+
} else {
|
|
3521
|
+
navigation.splice(index, 1, item);
|
|
3522
|
+
}
|
|
3523
|
+
} else if (!skipNavigation) {
|
|
3420
3524
|
navigation.push(item);
|
|
3421
3525
|
}
|
|
3422
3526
|
await states.blockletExtras.setSettings(did, { navigation });
|
|
@@ -3435,24 +3539,20 @@ class BlockletManager extends BaseBlockletManager {
|
|
|
3435
3539
|
}
|
|
3436
3540
|
|
|
3437
3541
|
async _getLatestBlockletVersionFromStore({ blocklet, version }) {
|
|
3542
|
+
const { deployedFrom: registryUrl } = blocklet;
|
|
3438
3543
|
const { did, bundleDid } = blocklet.meta;
|
|
3439
3544
|
|
|
3440
3545
|
let versions = this.cachedBlockletVersions.get(did);
|
|
3441
3546
|
|
|
3442
3547
|
if (!versions) {
|
|
3443
|
-
const
|
|
3444
|
-
|
|
3445
|
-
|
|
3446
|
-
|
|
3447
|
-
|
|
3448
|
-
|
|
3449
|
-
|
|
3450
|
-
return;
|
|
3451
|
-
}
|
|
3452
|
-
logger.error('get blocklet meta from registry failed', { did, error });
|
|
3453
|
-
})); // prettier-ignore
|
|
3548
|
+
const item = await StoreUtil.getBlockletMeta({ did: bundleDid, registryUrl });
|
|
3549
|
+
|
|
3550
|
+
if (!item) {
|
|
3551
|
+
return null;
|
|
3552
|
+
}
|
|
3553
|
+
|
|
3554
|
+
versions = [{ did, version: item.version }];
|
|
3454
3555
|
|
|
3455
|
-
versions = await Promise.all(tasks);
|
|
3456
3556
|
this.cachedBlockletVersions.set(did, versions);
|
|
3457
3557
|
}
|
|
3458
3558
|
|
|
@@ -3505,6 +3605,38 @@ class BlockletManager extends BaseBlockletManager {
|
|
|
3505
3605
|
|
|
3506
3606
|
return versions[0];
|
|
3507
3607
|
}
|
|
3608
|
+
|
|
3609
|
+
async _runPreInstallHook(blocklet, context) {
|
|
3610
|
+
const nodeEnvironments = await states.node.getEnvironments();
|
|
3611
|
+
|
|
3612
|
+
const preInstall = (b) =>
|
|
3613
|
+
hooks.preInstall(b.env.processId, {
|
|
3614
|
+
hooks: Object.assign(b.meta.hooks || {}, b.meta.scripts || {}),
|
|
3615
|
+
env: { ...nodeEnvironments },
|
|
3616
|
+
appDir: b.env.appDir,
|
|
3617
|
+
did: blocklet.meta.did, // root blocklet did
|
|
3618
|
+
notification: states.notification,
|
|
3619
|
+
context,
|
|
3620
|
+
});
|
|
3621
|
+
|
|
3622
|
+
await forEachBlocklet(blocklet, preInstall, { parallel: true });
|
|
3623
|
+
}
|
|
3624
|
+
|
|
3625
|
+
async _runPostInstallHook(blocklet, context) {
|
|
3626
|
+
const nodeEnvironments = await states.node.getEnvironments();
|
|
3627
|
+
|
|
3628
|
+
const postInstall = (b, { ancestors }) =>
|
|
3629
|
+
hooks.postInstall(b.env.processId, {
|
|
3630
|
+
hooks: Object.assign(b.meta.hooks || {}, b.meta.scripts || {}),
|
|
3631
|
+
env: getRuntimeEnvironments(b, nodeEnvironments, ancestors),
|
|
3632
|
+
appDir: b.env.appDir,
|
|
3633
|
+
did: blocklet.meta.did, // root blocklet did
|
|
3634
|
+
notification: states.notification,
|
|
3635
|
+
context,
|
|
3636
|
+
});
|
|
3637
|
+
|
|
3638
|
+
await forEachBlocklet(blocklet, postInstall, { parallel: true });
|
|
3639
|
+
}
|
|
3508
3640
|
}
|
|
3509
3641
|
|
|
3510
3642
|
module.exports = BlockletManager;
|