@abtnode/core 1.16.15-beta-9318a201 → 1.16.15-beta-ed0db59e

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.
@@ -0,0 +1,108 @@
1
+ const path = require('path');
2
+ const throttle = require('lodash/throttle');
3
+ const fs = require('fs-extra');
4
+ const logger = require('@abtnode/logger')('@abtnode/core:config-synchronizer');
5
+ const { encrypt } = require('@blocklet/sdk/lib/security');
6
+ const { APP_CONFIG_FILE_PATH, APP_CONFIG_DIR, COMPONENT_ENV_FILE_NAME } = require('@blocklet/constant');
7
+
8
+ const { findComponentByIdV2, getSharedConfigObj, getBlockletAppIdList } = require('@blocklet/meta/lib/util');
9
+ const { getBlockletLanguages, getBlockletPreferences } = require('@blocklet/env/lib/util');
10
+ const { getComponentsInternalInfo } = require('@blocklet/meta/lib/blocklet');
11
+ const { getComponentApiKey } = require('@abtnode/util/lib/blocklet');
12
+
13
+ const getValueFromEnvironments = (environments, key) => {
14
+ const env = (environments || []).find((x) => x.key === key);
15
+ return env ? env.value : undefined;
16
+ };
17
+
18
+ const isAppObj = (x) => typeof x === 'object' && x !== null && !!x.meta;
19
+
20
+ class ConfigSynchronizer {
21
+ constructor({ manager, states, wait = 5000 }) {
22
+ this.manager = manager;
23
+ this.wait = wait;
24
+ this.throttles = new Map();
25
+ this.states = states;
26
+ }
27
+
28
+ async syncAppConfig(did, { serverVersion: inputServerVersion } = {}) {
29
+ try {
30
+ const app = isAppObj(did) ? did : await this.manager.getBlocklet(did);
31
+ const serverVersion = inputServerVersion || (await this.states.node.read()).version;
32
+ const env = {
33
+ appId: app.appDid,
34
+ appPid: app.appPid,
35
+ appIds: getBlockletAppIdList(app),
36
+ appName: app.meta.title,
37
+ appDescription: app.meta.description,
38
+ appUrl: getValueFromEnvironments(app.environments, 'BLOCKLET_APP_URL'),
39
+ appStorageEndpoint: getValueFromEnvironments(app.environments, 'BLOCKLET_APP_SPACE_ENDPOINT'),
40
+ languages: getBlockletLanguages(getValueFromEnvironments(app.environments, 'BLOCKLET_APP_LANGUAGES')),
41
+ preferences: getBlockletPreferences(
42
+ (app.configs || []).reduce((acc, x) => {
43
+ acc[x.key] = x.value;
44
+ return acc;
45
+ }, {})
46
+ ),
47
+ serverVersion,
48
+ };
49
+ const components = getComponentsInternalInfo(app);
50
+
51
+ const config = { env, components };
52
+
53
+ const dataDir = getValueFromEnvironments(app.environments, 'BLOCKLET_DATA_DIR');
54
+
55
+ await fs.outputFile(path.join(dataDir, APP_CONFIG_FILE_PATH), JSON.stringify(config));
56
+ } catch (error) {
57
+ logger.error('sync app config failed', { error });
58
+ }
59
+ }
60
+
61
+ async syncComponentConfig(did, rootDid, { serverSk }) {
62
+ try {
63
+ const app = await this.manager.getBlocklet(rootDid);
64
+ const component = findComponentByIdV2(app, did);
65
+ const env = {
66
+ ...component.configObj,
67
+ ...getSharedConfigObj(component, [app]),
68
+ };
69
+
70
+ const componentApiKey = getComponentApiKey({
71
+ serverSk,
72
+ app,
73
+ component,
74
+ });
75
+
76
+ const dataDir = getValueFromEnvironments(app.environments, 'BLOCKLET_DATA_DIR');
77
+
78
+ const envString = JSON.stringify(env);
79
+
80
+ await fs.outputFile(
81
+ path.join(dataDir, APP_CONFIG_DIR, component.meta.did, COMPONENT_ENV_FILE_NAME),
82
+ encrypt(envString, componentApiKey, component.meta.did)
83
+ );
84
+ } catch (error) {
85
+ logger.error('sync component config failed', { error });
86
+ }
87
+ }
88
+
89
+ async throttledSyncAppConfig(did) {
90
+ if (!this.throttles.has(did)) {
91
+ this.throttles.set(
92
+ did,
93
+ throttle(
94
+ async () => {
95
+ await this.syncAppConfig(did);
96
+ this.throttles.get(did).cancel();
97
+ this.throttles.delete(did);
98
+ },
99
+ this.wait,
100
+ { leading: false }
101
+ )
102
+ );
103
+ }
104
+ await this.throttles.get(did)();
105
+ }
106
+ }
107
+
108
+ module.exports = ConfigSynchronizer;
@@ -51,7 +51,9 @@ const { getComponentsInternalInfo } = require('@blocklet/meta/lib/blocklet');
51
51
  const { update: updateMetaFile } = require('@blocklet/meta/lib/file');
52
52
  const { titleSchema, updateMountPointSchema, environmentNameSchema } = require('@blocklet/meta/lib/schema');
53
53
  const { emailConfigSchema } = require('@blocklet/sdk/lib/validators/email');
54
+ const { encrypt } = require('@blocklet/sdk/lib/security');
54
55
  const Lock = require('@abtnode/util/lib/lock');
56
+ const { getComponentApiKey } = require('@abtnode/util/lib/blocklet');
55
57
  const defaults = require('lodash/defaults');
56
58
 
57
59
  const {
@@ -77,6 +79,8 @@ const {
77
79
  CHAIN_PROP_MAP_REVERSE,
78
80
  BLOCKLET_CONTROLLER_STATUS,
79
81
  SUSPENDED_REASON,
82
+ APP_CONFIG_DIR,
83
+ COMPONENT_ENV_FILE_NAME,
80
84
  } = require('@blocklet/constant');
81
85
  const isUndefined = require('lodash/isUndefined');
82
86
  const { WELLKNOWN_SERVICE_PATH_PREFIX, WELLKNOWN_BLOCKLET_ADMIN_PATH } = require('@abtnode/constant');
@@ -159,6 +163,7 @@ const { validateAddSpaceGateway, validateUpdateSpaceGateway } = require('../../v
159
163
  const { sessionConfigSchema } = require('../../validators/util');
160
164
 
161
165
  const request = require('../../util/request');
166
+ const ConfigSynchronizer = require('./config-synchronizer');
162
167
 
163
168
  const { formatEnvironments, getBlockletMeta, validateOwner, isCLI } = util;
164
169
 
@@ -210,6 +215,8 @@ class DiskBlockletManager extends BaseBlockletManager {
210
215
 
211
216
  this._rollbackCache = new RollbackCache({ dir: this.dataDirs.tmp });
212
217
 
218
+ this.configSynchronizer = new ConfigSynchronizer({ manager: this, states });
219
+
213
220
  if (daemon) {
214
221
  blockletPm2Events.on('online', (data) => this._syncPm2Status('online', data.blockletDid, data.componentDid));
215
222
  blockletPm2Events.on('stop', (data) => this._syncPm2Status('stop', data.blockletDid, data.componentDid));
@@ -501,6 +508,8 @@ class DiskBlockletManager extends BaseBlockletManager {
501
508
  // start process
502
509
  const nodeEnvironments = await states.node.getEnvironments();
503
510
 
511
+ await this.configSynchronizer.syncAppConfig(blocklet);
512
+
504
513
  await startBlockletProcess(blocklet, {
505
514
  ...context,
506
515
  preStart: getHookFn('preStart'),
@@ -509,6 +518,7 @@ class DiskBlockletManager extends BaseBlockletManager {
509
518
  nodeInfo: await states.node.read(),
510
519
  e2eMode,
511
520
  componentDids,
521
+ configSynchronizer: this.configSynchronizer,
512
522
  });
513
523
 
514
524
  // check blocklet healthy
@@ -626,6 +636,7 @@ class DiskBlockletManager extends BaseBlockletManager {
626
636
  appDid: blocklet.appDid,
627
637
  components: getComponentsInternalInfo(res),
628
638
  });
639
+ this.configSynchronizer.throttledSyncAppConfig(blocklet.meta.did);
629
640
 
630
641
  this._createNotification(did, {
631
642
  title: '',
@@ -876,9 +887,9 @@ class DiskBlockletManager extends BaseBlockletManager {
876
887
  async deleteComponent({ did, rootDid, keepData, keepState }, context) {
877
888
  logger.info('delete blocklet component', { did, rootDid, keepData });
878
889
 
879
- const blocklet = await this.getBlocklet(rootDid);
890
+ const app = await this.getBlocklet(rootDid);
880
891
 
881
- const child = blocklet.children.find((x) => x.meta.did === did);
892
+ const child = app.children.find((x) => x.meta.did === did);
882
893
  if (!child) {
883
894
  throw new Error('Component does not exist');
884
895
  }
@@ -902,25 +913,25 @@ class DiskBlockletManager extends BaseBlockletManager {
902
913
  // delete process
903
914
  try {
904
915
  const skippedProcessIds = [];
905
- forEachBlockletSync(blocklet, (b) => {
916
+ forEachBlockletSync(app, (b) => {
906
917
  if (!b.env.id.startsWith(child.env.id)) {
907
918
  skippedProcessIds.push(b.env.processId);
908
919
  }
909
920
  });
910
- await deleteBlockletProcess(blocklet, { skippedProcessIds });
921
+ await deleteBlockletProcess(app, { skippedProcessIds });
911
922
  logger.info('delete blocklet process for deleting component', { did, rootDid });
912
923
  } catch (err) {
913
924
  logger.error('delete blocklet process for deleting component', { did, rootDid, error: err });
914
925
  }
915
926
 
916
927
  // delete storage
917
- const childBlocklet = blocklet.children.find((x) => x.meta.did === did);
918
- const { cacheDir, logsDir, dataDir } = childBlocklet.env;
928
+ const { cacheDir, logsDir, dataDir } = child.env;
919
929
  fs.removeSync(cacheDir);
920
930
  fs.removeSync(logsDir);
931
+ fs.removeSync(path.join(app.env.dataDir, APP_CONFIG_DIR, child.meta.did, COMPONENT_ENV_FILE_NAME));
921
932
  if (keepData === false) {
922
933
  fs.removeSync(dataDir);
923
- await states.blockletExtras.delConfigs([blocklet.meta.did, child.meta.did]);
934
+ await states.blockletExtras.delConfigs([app.meta.did, child.meta.did]);
924
935
  }
925
936
 
926
937
  const newBlocklet = await this.getBlocklet(rootDid);
@@ -944,19 +955,20 @@ class DiskBlockletManager extends BaseBlockletManager {
944
955
  });
945
956
 
946
957
  this.emit(BlockletEvents.componentRemoved, {
947
- ...blocklet,
958
+ ...app,
948
959
  componentDids: [child.meta.did],
949
960
  });
950
961
 
951
962
  this.emit(BlockletInternalEvents.componentRemoved, {
952
- appDid: blocklet.appDid,
963
+ appDid: app.appDid,
953
964
  components: [{ did: child.meta.did }],
954
965
  });
955
966
  // for backward compatibility
956
967
  this.emit(BlockletInternalEvents.componentsUpdated, {
957
- appDid: blocklet.appDid,
968
+ appDid: app.appDid,
958
969
  components: getComponentsInternalInfo(newBlocklet),
959
970
  });
971
+ this.configSynchronizer.throttledSyncAppConfig(app.meta.did);
960
972
 
961
973
  return { ...newBlocklet, deletedComponent: child };
962
974
  }
@@ -1225,9 +1237,21 @@ class DiskBlockletManager extends BaseBlockletManager {
1225
1237
  appDid: rootDid,
1226
1238
  configs: newConfigs.map((x) => ({ key: x.key, value: x.value })),
1227
1239
  });
1240
+ this.configSynchronizer.throttledSyncAppConfig(blocklet.meta.did);
1228
1241
  }
1229
1242
 
1230
1243
  this.emit(BlockletEvents.updated, newState);
1244
+ const serverSk = (await states.node.read()).sk;
1245
+ if (childDid) {
1246
+ const configs = JSON.stringify(newConfigs.map((x) => ({ key: x.key, value: x.value })));
1247
+ this.emit(BlockletInternalEvents.componentConfigChanged, {
1248
+ appDid: rootDid,
1249
+ componentDid: childDid,
1250
+ configs: encrypt(configs, getComponentApiKey({ serverSk, app: ancestors[0], component: blocklet }), childDid),
1251
+ });
1252
+
1253
+ this.configSynchronizer.syncComponentConfig(childDid, rootDid, { serverSk });
1254
+ }
1231
1255
 
1232
1256
  return newState;
1233
1257
  }
@@ -1418,6 +1442,7 @@ class DiskBlockletManager extends BaseBlockletManager {
1418
1442
  appDid: blocklet.appDid,
1419
1443
  components: getComponentsInternalInfo(blocklet),
1420
1444
  });
1445
+ this.configSynchronizer.throttledSyncAppConfig(blocklet.meta.did);
1421
1446
 
1422
1447
  return this.getBlocklet(rootDid);
1423
1448
  }
@@ -1818,6 +1843,10 @@ class DiskBlockletManager extends BaseBlockletManager {
1818
1843
  }
1819
1844
  }
1820
1845
 
1846
+ syncAppConfig(did, { serverVersion } = {}) {
1847
+ return this.configSynchronizer.syncAppConfig(did, { serverVersion });
1848
+ }
1849
+
1821
1850
  // ============================================================================================
1822
1851
  // Private API that are used by self of helper function
1823
1852
  // ============================================================================================
@@ -2076,6 +2105,7 @@ class DiskBlockletManager extends BaseBlockletManager {
2076
2105
  appDid: blocklet.appDid,
2077
2106
  components: getComponentsInternalInfo(res),
2078
2107
  });
2108
+ this.configSynchronizer.throttledSyncAppConfig(res);
2079
2109
 
2080
2110
  this.emit(BlockletEvents.statusChange, res);
2081
2111
  this.emit(BlockletEvents.started, { ...res, componentDids });
@@ -2274,7 +2304,7 @@ class DiskBlockletManager extends BaseBlockletManager {
2274
2304
  const nodeInfo = await states.node.read();
2275
2305
 
2276
2306
  const appSystemEnvironments = {
2277
- ...getAppSystemEnvironments(blockletWithEnv, nodeInfo),
2307
+ ...getAppSystemEnvironments(blockletWithEnv, nodeInfo, this.dataDirs),
2278
2308
  ...getAppOverwrittenEnvironments(blockletWithEnv, nodeInfo),
2279
2309
  };
2280
2310
 
@@ -2770,6 +2800,7 @@ class DiskBlockletManager extends BaseBlockletManager {
2770
2800
  appDid: blocklet.appDid,
2771
2801
  components: getComponentsInternalInfo(blocklet),
2772
2802
  });
2803
+ this.configSynchronizer.throttledSyncAppConfig(blocklet);
2773
2804
 
2774
2805
  return blocklet;
2775
2806
  } catch (err) {
@@ -62,6 +62,8 @@ const installApplicationFromDev = async ({ folder, meta, states, manager } = {})
62
62
  }
63
63
  await updateBlockletFallbackLogo(blocklet);
64
64
 
65
+ await states.blocklet.setInstalledAt(did);
66
+
65
67
  blocklet = await manager.getBlocklet(did);
66
68
 
67
69
  return blocklet;
@@ -94,12 +94,16 @@ const installComponentFromUrl = async ({
94
94
  // if upgrade, do not update mountPoint and title
95
95
  newChild.mountPoint = blocklet.children[index].mountPoint;
96
96
  newChild.meta.title = blocklet.children[index].meta.title;
97
+ newChild.installedAt = blocklet.children[index].installedAt;
97
98
  blocklet.children.splice(index, 1, newChild);
98
99
  } else {
99
100
  dynamicComponents.unshift(newChild);
100
101
  }
101
102
 
102
- const newChildren = filterDuplicateComponents(dynamicComponents, blocklet.children);
103
+ const newChildren = filterDuplicateComponents(dynamicComponents, blocklet.children).map((x) => ({
104
+ ...x,
105
+ installedAt: new Date(),
106
+ }));
103
107
 
104
108
  blocklet.children.push(...newChildren);
105
109
 
package/lib/index.js CHANGED
@@ -273,6 +273,7 @@ function ABTNode(options) {
273
273
  backupBlocklet: blockletManager.backup.bind(blockletManager),
274
274
  restoreBlocklet: blockletManager.restoreBlocklet.bind(blockletManager),
275
275
  migrateApplicationToStructV2: blockletManager.migrateApplicationToStructV2.bind(blockletManager),
276
+ syncAppConfig: blockletManager.syncAppConfig.bind(blockletManager),
276
277
 
277
278
  // For diagnose purpose
278
279
  syncBlockletStatus: blockletManager.status.bind(blockletManager),
@@ -263,7 +263,7 @@ const ensureBlockletExpanded = async (meta, appDir) => {
263
263
  }
264
264
  };
265
265
 
266
- const getAppSystemEnvironments = (blocklet, nodeInfo) => {
266
+ const getAppSystemEnvironments = (blocklet, nodeInfo, dataDirs) => {
267
267
  const { did, name, title, description } = blocklet.meta;
268
268
  const keys = Object.keys(BLOCKLET_CONFIGURABLE_KEY);
269
269
  const result = getBlockletInfo(
@@ -311,6 +311,7 @@ const getAppSystemEnvironments = (blocklet, nodeInfo) => {
311
311
  BLOCKLET_APP_NAME: appName,
312
312
  BLOCKLET_APP_DESCRIPTION: appDescription,
313
313
  BLOCKLET_APP_URL: appUrl,
314
+ BLOCKLET_APP_DATA_DIR: path.join(dataDirs.data, blocklet.meta.name),
314
315
  };
315
316
  };
316
317
 
@@ -491,6 +492,7 @@ const startBlockletProcess = async (
491
492
  e2eMode,
492
493
  skippedProcessIds = [],
493
494
  componentDids,
495
+ configSynchronizer,
494
496
  } = {}
495
497
  ) => {
496
498
  if (!blocklet) {
@@ -604,6 +606,10 @@ const startBlockletProcess = async (
604
606
  }
605
607
  }
606
608
 
609
+ await configSynchronizer.syncComponentConfig(b.meta.did, blocklet.meta.did, {
610
+ serverSk: nodeEnvironments.ABT_NODE_SK,
611
+ });
612
+
607
613
  await pm2.startAsync(options);
608
614
 
609
615
  const status = await getProcessState(processId);
package/package.json CHANGED
@@ -3,7 +3,7 @@
3
3
  "publishConfig": {
4
4
  "access": "public"
5
5
  },
6
- "version": "1.16.15-beta-9318a201",
6
+ "version": "1.16.15-beta-ed0db59e",
7
7
  "description": "",
8
8
  "main": "lib/index.js",
9
9
  "files": [
@@ -19,19 +19,19 @@
19
19
  "author": "wangshijun <wangshijun2010@gmail.com> (http://github.com/wangshijun)",
20
20
  "license": "Apache-2.0",
21
21
  "dependencies": {
22
- "@abtnode/analytics": "1.16.15-beta-9318a201",
23
- "@abtnode/auth": "1.16.15-beta-9318a201",
24
- "@abtnode/certificate-manager": "1.16.15-beta-9318a201",
25
- "@abtnode/constant": "1.16.15-beta-9318a201",
26
- "@abtnode/cron": "1.16.15-beta-9318a201",
27
- "@abtnode/logger": "1.16.15-beta-9318a201",
28
- "@abtnode/models": "1.16.15-beta-9318a201",
29
- "@abtnode/queue": "1.16.15-beta-9318a201",
30
- "@abtnode/rbac": "1.16.15-beta-9318a201",
31
- "@abtnode/router-provider": "1.16.15-beta-9318a201",
32
- "@abtnode/static-server": "1.16.15-beta-9318a201",
33
- "@abtnode/timemachine": "1.16.15-beta-9318a201",
34
- "@abtnode/util": "1.16.15-beta-9318a201",
22
+ "@abtnode/analytics": "1.16.15-beta-ed0db59e",
23
+ "@abtnode/auth": "1.16.15-beta-ed0db59e",
24
+ "@abtnode/certificate-manager": "1.16.15-beta-ed0db59e",
25
+ "@abtnode/constant": "1.16.15-beta-ed0db59e",
26
+ "@abtnode/cron": "1.16.15-beta-ed0db59e",
27
+ "@abtnode/logger": "1.16.15-beta-ed0db59e",
28
+ "@abtnode/models": "1.16.15-beta-ed0db59e",
29
+ "@abtnode/queue": "1.16.15-beta-ed0db59e",
30
+ "@abtnode/rbac": "1.16.15-beta-ed0db59e",
31
+ "@abtnode/router-provider": "1.16.15-beta-ed0db59e",
32
+ "@abtnode/static-server": "1.16.15-beta-ed0db59e",
33
+ "@abtnode/timemachine": "1.16.15-beta-ed0db59e",
34
+ "@abtnode/util": "1.16.15-beta-ed0db59e",
35
35
  "@arcblock/did": "1.18.89",
36
36
  "@arcblock/did-auth": "1.18.89",
37
37
  "@arcblock/did-ext": "^1.18.89",
@@ -42,10 +42,11 @@
42
42
  "@arcblock/pm2-events": "^0.0.5",
43
43
  "@arcblock/validator": "^1.18.89",
44
44
  "@arcblock/vc": "1.18.89",
45
- "@blocklet/constant": "1.16.15-beta-9318a201",
46
- "@blocklet/meta": "1.16.15-beta-9318a201",
47
- "@blocklet/resolver": "1.16.15-beta-9318a201",
48
- "@blocklet/sdk": "1.16.15-beta-9318a201",
45
+ "@blocklet/constant": "1.16.15-beta-ed0db59e",
46
+ "@blocklet/env": "1.16.15-beta-ed0db59e",
47
+ "@blocklet/meta": "1.16.15-beta-ed0db59e",
48
+ "@blocklet/resolver": "1.16.15-beta-ed0db59e",
49
+ "@blocklet/sdk": "1.16.15-beta-ed0db59e",
49
50
  "@did-space/client": "^0.2.163",
50
51
  "@fidm/x509": "^1.2.1",
51
52
  "@ocap/mcrypto": "1.18.89",
@@ -98,5 +99,5 @@
98
99
  "jest": "^27.5.1",
99
100
  "unzipper": "^0.10.11"
100
101
  },
101
- "gitHead": "f3722cbd4fe10c5fa083cad7e859ecff6095060d"
102
+ "gitHead": "647ebe45f6214ea5c284c9234f1319b6ff72f915"
102
103
  }