@abtnode/core 1.16.11-next-069c3537 → 1.16.11-next-3d2b39f7

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.
@@ -54,9 +54,7 @@ const installApplicationFromGeneral = async ({
54
54
 
55
55
  // check install count
56
56
  if (controller?.nftId) {
57
- // sometimes nedb will throw error if use states.blocklet.count({ ['controller.nftId']: controller.nftId })
58
57
  const installedCount = await states.blockletExtras.count({ 'controller.nftId': controller.nftId });
59
-
60
58
  if (installedCount >= (controller.appMaxCount || 1)) {
61
59
  throw new Error(
62
60
  `You can only install ${controller.appMaxCount} blocklet with this credential: ${controller.nftId}`
@@ -120,7 +118,24 @@ const installApplicationFromGeneral = async ({
120
118
  },
121
119
  ]);
122
120
  } catch (err) {
123
- await manager._rollback('install', did, {});
121
+ const componentDid = component?.meta?.did;
122
+ logger.error('failed to create blocklet extras', { did, componentDid, error: err });
123
+
124
+ try {
125
+ await manager._rollback('install', did, {});
126
+ } catch (e) {
127
+ logger.error('failed to remove blocklet on create extras error', { did, componentDid, error: e });
128
+ }
129
+
130
+ manager._createNotification(did, {
131
+ title: 'Blocklet Install Failed',
132
+ description: `Blocklet ${title || component?.meta?.title} install failed with error: ${err.message}`,
133
+ entityType: 'blocklet',
134
+ entityId: did,
135
+ severity: 'error',
136
+ });
137
+
138
+ throw err;
124
139
  }
125
140
 
126
141
  if (!blocklet.children.length) {
@@ -56,7 +56,6 @@ const installComponentFromDev = async ({ folder, meta, rootDid, mountPoint, mana
56
56
  const newBlocklet = await states.blocklet.getBlocklet(rootDid);
57
57
  await validateBlocklet(newBlocklet);
58
58
  await manager._downloadBlocklet(newBlocklet);
59
- await states.blocklet.setBlockletStatus(rootDid, BlockletStatus.stopped);
60
59
 
61
60
  // Add Config
62
61
  await manager._setConfigsFromMeta(rootDid);
@@ -13,6 +13,7 @@ const {
13
13
  ensureMeta,
14
14
  checkStructVersion,
15
15
  checkVersionCompatibility,
16
+ getBlockletStatus,
16
17
  } = require('../../../util/blocklet');
17
18
  const { resolveDownload, resolveDiffDownload, downloadFromUpload } = require('../../downloader/resolve-download');
18
19
 
@@ -39,9 +40,10 @@ const installComponentFromUpload = async ({
39
40
  // download
40
41
  const { tarFile } = await downloadFromUpload(file, { downloadDir: path.join(manager.dataDirs.tmp, 'download') });
41
42
 
42
- if (isInProgress(oldBlocklet.status)) {
43
- logger.error(`Can not deploy blocklet when it is ${fromBlockletStatus(oldBlocklet.status)}`);
44
- throw new Error(`Can not deploy blocklet when it is ${fromBlockletStatus(oldBlocklet.status)}`);
43
+ const appStatus = getBlockletStatus(oldBlocklet);
44
+ if (isInProgress(appStatus)) {
45
+ logger.error(`Can not deploy blocklet when it is ${fromBlockletStatus(appStatus)}`);
46
+ throw new Error(`Can not deploy blocklet when it is ${fromBlockletStatus(appStatus)}`);
45
47
  }
46
48
 
47
49
  let meta;
@@ -105,6 +107,8 @@ const installComponentFromUpload = async ({
105
107
  const action = 'upgrade';
106
108
  await manager._rollbackCache.backup({ did: newBlocklet.meta.did, action, oldBlocklet });
107
109
 
110
+ const componentDids = [newChild.meta.did, ...newChildren.map((x) => x.meta.did)];
111
+
108
112
  await manager._downloadAndInstall({
109
113
  blocklet: newBlocklet,
110
114
  oldBlocklet,
@@ -112,7 +116,7 @@ const installComponentFromUpload = async ({
112
116
  throwOnError: true,
113
117
  postAction: action,
114
118
  skipCheckStatusBeforeDownload: true,
115
- selectedComponentDids: newChildren.map((x) => x.meta.did),
119
+ componentDids,
116
120
  });
117
121
  return manager.getBlocklet(newBlocklet.meta.did);
118
122
  };
@@ -127,8 +127,10 @@ const installComponentFromUrl = async ({
127
127
  throw err;
128
128
  }
129
129
 
130
+ const componentDids = [newChild.meta.did, ...newChildren.map((x) => x.meta.did)];
131
+
130
132
  // new blocklet
131
- const newBlocklet = await states.blocklet.setBlockletStatus(rootDid, BlockletStatus.waiting);
133
+ const newBlocklet = await states.blocklet.setBlockletStatus(rootDid, BlockletStatus.waiting, { componentDids });
132
134
 
133
135
  newBlocklet.children = blocklet.children;
134
136
  await validateBlocklet(newBlocklet);
@@ -138,7 +140,7 @@ const installComponentFromUrl = async ({
138
140
  const downloadParams = {
139
141
  oldBlocklet: { ...oldBlocklet },
140
142
  blocklet: { ...newBlocklet },
141
- selectedComponentDids: [newChild.meta.did, ...newChildren.map((x) => x.meta.did)],
143
+ componentDids,
142
144
  context,
143
145
  postAction: action,
144
146
  };
@@ -73,8 +73,8 @@ const check = async ({ did, states }) => {
73
73
  };
74
74
  };
75
75
 
76
- const upgrade = async ({ updateId, selectedComponentDids, context, states, manager }) => {
77
- if (!selectedComponentDids?.length) {
76
+ const upgrade = async ({ updateId, componentDids, context, states, manager }) => {
77
+ if (!componentDids?.length) {
78
78
  throw new Error('At least one component needs to be selected');
79
79
  }
80
80
 
@@ -87,7 +87,7 @@ const upgrade = async ({ updateId, selectedComponentDids, context, states, manag
87
87
  let dynamicComponents = [];
88
88
  const children = cloneDeep(oldBlocklet.children).map((oldComponent) => {
89
89
  const newComponent = sessionData.children.find((x) => x.meta.did === oldComponent.meta.did);
90
- if (newComponent && selectedComponentDids.includes(newComponent.meta.did)) {
90
+ if (newComponent && componentDids.includes(newComponent.meta.did)) {
91
91
  dynamicComponents.push(...(newComponent._dynamicComponents || []));
92
92
  delete newComponent._dynamicComponents;
93
93
  return newComponent;
@@ -97,8 +97,8 @@ const upgrade = async ({ updateId, selectedComponentDids, context, states, manag
97
97
  dynamicComponents = filterDuplicateComponents(dynamicComponents, children);
98
98
  children.push(...dynamicComponents);
99
99
 
100
- // selectedComponentDids
101
- selectedComponentDids.push(...dynamicComponents.map((x) => x.meta.did));
100
+ // componentDids
101
+ componentDids.push(...dynamicComponents.map((x) => x.meta.did));
102
102
 
103
103
  checkVersionCompatibility(children);
104
104
 
@@ -108,7 +108,7 @@ const upgrade = async ({ updateId, selectedComponentDids, context, states, manag
108
108
  });
109
109
 
110
110
  // new blocklet
111
- const newBlocklet = await states.blocklet.setBlockletStatus(did, BlockletStatus.waiting);
111
+ const newBlocklet = await states.blocklet.setBlockletStatus(did, BlockletStatus.waiting, { componentDids });
112
112
 
113
113
  newBlocklet.children = children;
114
114
  await validateBlocklet(newBlocklet);
@@ -128,7 +128,7 @@ const upgrade = async ({ updateId, selectedComponentDids, context, states, manag
128
128
  id: did,
129
129
  oldBlocklet: { ...oldBlocklet },
130
130
  blocklet: { ...newBlocklet },
131
- selectedComponentDids: selectedComponentDids || [],
131
+ componentDids: componentDids || [],
132
132
  context,
133
133
  postAction: action,
134
134
  },
@@ -27,10 +27,10 @@ class BlockletPm2Events extends EventEmitter {
27
27
  if (actualPm2Home !== expectedPm2Home) {
28
28
  return;
29
29
  }
30
- const { BLOCKLET_DID: blockletDid } = details.process || {};
31
- logger.debug('listen pm2 event', { name, blockletDid });
30
+ const { BLOCKLET_DID: blockletDid, BLOCKLET_COMPONENT_DID: componentDid } = details.process || {};
31
+ logger.debug('listen pm2 event', { name, blockletDid, componentDid });
32
32
  if (blockletDid) {
33
- this.emit(name, { blockletDid });
33
+ this.emit(name, { blockletDid, componentDid });
34
34
  }
35
35
  })
36
36
  .error((error) => {
package/lib/event.js CHANGED
@@ -3,7 +3,13 @@ const cloneDeep = require('lodash/cloneDeep');
3
3
  const { EventEmitter } = require('events');
4
4
  const { wipeSensitiveData } = require('@blocklet/meta/lib/util');
5
5
  const logger = require('@abtnode/logger')('@abtnode/core:event');
6
- const { BLOCKLET_MODES, BlockletStatus, BlockletSource, BlockletEvents } = require('@blocklet/constant');
6
+ const {
7
+ BLOCKLET_MODES,
8
+ BlockletStatus,
9
+ BlockletSource,
10
+ BlockletEvents,
11
+ BlockletInternalEvents,
12
+ } = require('@blocklet/constant');
7
13
  const { EVENTS } = require('@abtnode/constant');
8
14
  const { NodeMonitSender } = require('./monitor/node-monit-sender');
9
15
  const handleInstanceInStore = require('./util/public-to-store');
@@ -375,6 +381,10 @@ module.exports = ({
375
381
  listen(blockletManager, eventName, handleBlockletEvent);
376
382
  });
377
383
 
384
+ [BlockletInternalEvents.componentsUpdated, BlockletInternalEvents.appConfigChanged].forEach((eventName) => {
385
+ listen(blockletManager, eventName, onEvent);
386
+ });
387
+
378
388
  listen(notificationState, EVENTS.NOTIFICATION_CREATE, onEvent);
379
389
 
380
390
  listen(nodeState, BlockletEvents.purchaseChange, onEvent);
package/lib/index.js CHANGED
@@ -16,6 +16,7 @@ const getRouterHelpers = require('./router/helper');
16
16
  const TeamManager = require('./team/manager');
17
17
  const NodeAPI = require('./api/node');
18
18
  const TeamAPI = require('./api/team');
19
+ const { getLauncherSession, isLauncherSessionConsumed, setupAppOwner } = require('./util/launcher');
19
20
  const WebHook = require('./webhook');
20
21
  const states = require('./states');
21
22
  const Cert = require('./cert');
@@ -250,7 +251,6 @@ function ABTNode(options) {
250
251
  devBlocklet: blockletManager.dev.bind(blockletManager),
251
252
  checkComponentsForUpdates: blockletManager.checkComponentsForUpdates.bind(blockletManager),
252
253
  upgradeComponents: blockletManager.upgradeComponents.bind(blockletManager),
253
- getBlockletMetaFromUrl: getMetaFromUrl.bind(blockletManager),
254
254
  getBlockletForLauncher: blockletManager.getBlockletForLauncher.bind(blockletManager),
255
255
  resetBlocklet: blockletManager.reset.bind(blockletManager),
256
256
  deleteBlockletProcess: blockletManager.deleteProcess.bind(blockletManager),
@@ -266,9 +266,7 @@ function ABTNode(options) {
266
266
  migrateApplicationToStructV2: blockletManager.migrateApplicationToStructV2.bind(blockletManager),
267
267
 
268
268
  // For diagnose purpose
269
- syncBlockletStatus: blockletManager.status.bind(blockletManager),
270
269
  ensureBlockletIntegrity: blockletManager.ensureBlocklet.bind(blockletManager),
271
- updateBlockletStatus: states.blocklet.setBlockletStatus.bind(states.blocklet),
272
270
 
273
271
  getBlocklets: blockletManager.list.bind(blockletManager),
274
272
  getBlockletsFromBackup: blockletManager.listBackups.bind(blockletManager),
@@ -462,6 +460,12 @@ function ABTNode(options) {
462
460
 
463
461
  // for exporting blocklet data dir
464
462
  createBlockletDataArchive: createDataArchive,
463
+
464
+ // public utils used in launch workflow
465
+ getBlockletMetaFromUrl: getMetaFromUrl,
466
+ getLauncherSession,
467
+ isLauncherSessionConsumed,
468
+ setupAppOwner,
465
469
  };
466
470
 
467
471
  const events = createEvents({
@@ -0,0 +1,22 @@
1
+ /* eslint-disable no-await-in-loop */
2
+ /* eslint-disable no-continue */
3
+
4
+ module.exports = async ({ states, printInfo }) => {
5
+ printInfo('Try to update component status...');
6
+
7
+ const apps = await states.blocklet.find({});
8
+
9
+ for (const app of apps || []) {
10
+ const appStatus = app.status;
11
+ let shouldUpdate = false;
12
+ for (const component of app.children || []) {
13
+ shouldUpdate = true;
14
+ component.status = appStatus;
15
+ }
16
+
17
+ if (shouldUpdate) {
18
+ await states.blocklet.update({ id: app.id }, { $set: { children: app.children } });
19
+ printInfo(`Blocklet in blocklet.db updated: ${app.meta?.title}. status: ${appStatus}`);
20
+ }
21
+ }
22
+ };
@@ -116,7 +116,7 @@ class BlockletRuntimeMonitor extends EventEmitter {
116
116
  await forEachBlocklet(
117
117
  blocklet,
118
118
  async (component, { id: componentId, ancestors }) => {
119
- if (component.meta.group !== BlockletGroup.gateway) {
119
+ if (component.meta.group !== BlockletGroup.gateway && component.status === BlockletStatus.running) {
120
120
  const processId = getComponentProcessId(component, ancestors);
121
121
  try {
122
122
  const runtimeInfo = await getRuntimeInfo(processId);
@@ -132,6 +132,8 @@ class BlockletRuntimeMonitor extends EventEmitter {
132
132
  } catch (err) {
133
133
  this.logger.error('failed to get blocklet runtime info', { processId, error: err });
134
134
  }
135
+ } else {
136
+ delete this.data[blockletDid][componentId];
135
137
  }
136
138
  },
137
139
  { parallel: true }
@@ -226,6 +226,16 @@ class BlockletExtrasState extends BaseState {
226
226
  return docs.filter((x) => x.controller?.nftId).filter((x) => x.expiredAt <= deadline);
227
227
  }
228
228
 
229
+ async isLauncherSessionConsumed(sessionId) {
230
+ const count = await super.count({ 'controller.sessionId': sessionId });
231
+ return count > 0;
232
+ }
233
+
234
+ async isLauncherNftConsumed(nftId) {
235
+ const count = await super.count({ 'controller.nftId': nftId });
236
+ return count > 0;
237
+ }
238
+
229
239
  encryptSecurityData({ data, _rootDid } = {}) {
230
240
  if (!data) {
231
241
  return data;
@@ -2,6 +2,7 @@
2
2
  /* eslint-disable no-await-in-loop */
3
3
  /* eslint-disable function-paren-newline */
4
4
  /* eslint-disable no-underscore-dangle */
5
+ const pick = require('lodash/pick');
5
6
  const omit = require('lodash/omit');
6
7
  const uniq = require('lodash/uniq');
7
8
  const cloneDeep = require('lodash/cloneDeep');
@@ -13,17 +14,23 @@ const {
13
14
  getDisplayName,
14
15
  forEachBlocklet,
15
16
  forEachBlockletSync,
16
- forEachChildSync,
17
+ forEachComponentV2Sync,
17
18
  getBlockletServices,
18
19
  } = require('@blocklet/meta/lib/util');
19
- const { BlockletStatus, BlockletSource, BLOCKLET_MODES, BLOCKLET_DEFAULT_PORT_NAME } = require('@blocklet/constant');
20
+ const {
21
+ BlockletStatus,
22
+ BlockletSource,
23
+ BLOCKLET_MODES,
24
+ BLOCKLET_DEFAULT_PORT_NAME,
25
+ BlockletGroup,
26
+ } = require('@blocklet/constant');
20
27
  const { APP_STRUCT_VERSION } = require('@abtnode/constant');
21
28
 
22
29
  const logger = require('@abtnode/logger')('@abtnode/core:states:blocklet');
23
30
 
24
31
  const BaseState = require('./base');
25
32
  const { checkDuplicateComponents, ensureMeta } = require('../util/blocklet');
26
- const { validateBlockletMeta } = require('../util/blocklet');
33
+ const { validateBlockletMeta, getBlockletStatus, shouldSkipComponent } = require('../util/blocklet');
27
34
 
28
35
  const lock = new Lock('blocklet-port-assign-lock');
29
36
 
@@ -37,6 +44,10 @@ const getExternalPortsFromMeta = (meta) =>
37
44
  (meta.interfaces || []).map((x) => x.port && x.port.external).filter(Boolean);
38
45
 
39
46
  const formatBlocklet = (blocklet, phase, dek) => {
47
+ if (phase === 'onRead') {
48
+ blocklet.status = getBlockletStatus(blocklet);
49
+ }
50
+
40
51
  forEachBlockletSync(blocklet, (b) => {
41
52
  if (b.meta) {
42
53
  fixPerson(b.meta);
@@ -273,6 +284,9 @@ class BlockletState extends BaseState {
273
284
 
274
285
  const formatted = formatBlocklet(cloneDeep(updates), 'onUpdate', this.config.dek);
275
286
  const [, [updated]] = await this.update({ id: doc.id }, { $set: formatted });
287
+
288
+ updated.status = getBlockletStatus(updated);
289
+
276
290
  return updated;
277
291
  }
278
292
 
@@ -480,62 +494,55 @@ class BlockletState extends BaseState {
480
494
  }
481
495
 
482
496
  /**
483
- * @param {String} did blocklet did
497
+ * @param {Did} did blocklet did
484
498
  * @param {BlockletStatus} status blocklet status
485
- *
486
- * children status only different with parent before blocklet installation
487
- * @param {Array<componentId>} children
499
+ * @param {{
500
+ * componentDids?: Array<Did>
501
+ * }}
488
502
  */
489
- async setBlockletStatus(did, status, { children } = {}) {
503
+ async setBlockletStatus(did, status, { componentDids } = {}) {
490
504
  if (typeof status === 'undefined') {
491
505
  throw new Error('Unsupported blocklet status');
492
506
  }
493
507
 
494
508
  const doc = await this.getBlocklet(did);
495
- if (doc.status === status && !children) {
496
- return formatBlocklet(doc, 'onRead', this.config.dek);
497
- }
498
509
 
499
- const updates = { status, startedAt: null, stoppedAt: null };
500
- if (status === BlockletStatus.running) {
501
- updates.startedAt = new Date();
502
- }
503
- if (status === BlockletStatus.installed) {
504
- updates.installedAt = new Date();
510
+ if (doc.meta?.group === BlockletGroup.gateway && !doc.children?.length) {
511
+ return this.updateBlocklet(did, { status });
505
512
  }
506
- if (status === BlockletStatus.stopped) {
507
- updates.stoppedAt = new Date();
513
+
514
+ // for backward compatibility
515
+ if (!doc.structVersion && !doc.children?.length) {
516
+ return this.updateBlocklet(did, { status });
508
517
  }
509
518
 
510
519
  // update children status
511
- forEachChildSync(doc, (child, { id }) => {
512
- if (children === 'all') {
513
- child.status = status;
520
+ forEachComponentV2Sync(doc, (component) => {
521
+ if (component.meta.group === BlockletGroup.gateway) {
514
522
  return;
515
523
  }
516
524
 
517
- if (!children) {
518
- if (
519
- ![
520
- BlockletStatus.waiting,
521
- BlockletStatus.upgrading,
522
- BlockletStatus.installing,
523
- BlockletStatus.starting,
524
- ].includes(status)
525
- ) {
526
- child.status = status;
527
- }
528
-
525
+ if (shouldSkipComponent(component.meta.did, componentDids)) {
529
526
  return;
530
527
  }
531
528
 
532
- if (children.includes(id)) {
533
- child.status = status;
529
+ component.status = status;
530
+ if (status === BlockletStatus.running) {
531
+ component.startedAt = new Date();
532
+ component.stoppedAt = null;
533
+ }
534
+ if (status === BlockletStatus.stopped) {
535
+ component.startedAt = null;
536
+ component.stoppedAt = new Date();
534
537
  }
535
538
  });
536
539
 
537
- updates.children = doc.children;
538
- return this.updateBlocklet(did, updates);
540
+ return this.updateBlocklet(did, pick(doc, ['status', 'children']));
541
+ }
542
+
543
+ async setInstalledAt(did) {
544
+ logger.info('setInstalledAt', { did });
545
+ return this.updateBlocklet(did, { installedAt: new Date() });
539
546
  }
540
547
 
541
548
  async fillChildrenPorts(children, { defaultPort = 0, oldChildren, returnMaxPort } = {}) {
@@ -253,6 +253,7 @@ class NodeState extends BaseState {
253
253
  async getEnvironments() {
254
254
  return this.read().then((info) => ({
255
255
  ABT_NODE: info.version,
256
+ ABT_NODE_VERSION: info.version,
256
257
  ABT_NODE_DID: info.did,
257
258
  ABT_NODE_SK: info.sk,
258
259
  ABT_NODE_PK: info.pk,