@abtnode/core 1.16.16-beta-d8a9fb09 → 1.16.16-beta-740ea329

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 CHANGED
@@ -143,7 +143,7 @@ class NodeAPI {
143
143
 
144
144
  // eslint-disable-next-line no-unused-vars
145
145
  async getHistory({ hours = 1 } = {}, context) {
146
- const history = await this.runtimeMonitor.getHistory();
146
+ const history = await this.runtimeMonitor.getHistory(hours);
147
147
  return getHistoryList({
148
148
  history,
149
149
  hours,
@@ -6,15 +6,26 @@ const { BLOCKLET_CONFIGURABLE_KEY } = require('@blocklet/constant');
6
6
  const removeDeletedMetaConfigs = (oldConfigs, newConfigs) =>
7
7
  oldConfigs.filter((old) => newConfigs.some(({ key, name }) => [key, name].includes(old.key)));
8
8
 
9
+ /**
10
+ * 从 blocklet.yml:environment 中导入配置:配置项字段是 name
11
+ * 主动配置:配置项字段是 key
12
+ *
13
+ * 自定义配置(customConfigs): 配置项的 custom 为 true
14
+ * 系统配置(appConfigs): 系统保留的配置项名,且 custom 为 false
15
+ * 组件配置(metaConfigs): 配置项的 custom 为 false, 且不是系统保留的配置项名
16
+ * 如果从 blocklet.yml 中导入组件配置,会删除已经删除的配置项
17
+ */
9
18
  const mergeConfigs = ({ old: oldConfigs, cur: newConfigs = [], did = '', dek = '' }) => {
10
19
  const enableSecurity = dek && did;
11
- const isUpdatingCustomConfig = newConfigs.every((x) => x.key);
20
+
21
+ const isConfigFromMeta = newConfigs.every((x) => x.key);
12
22
 
13
23
  const customConfigs = (oldConfigs || []).filter((x) => x.custom);
14
24
  const appConfigs = (oldConfigs || []).filter((x) => !x.custom && !!BLOCKLET_CONFIGURABLE_KEY[x.key]);
15
25
 
16
26
  const allMetaConfigs = (oldConfigs || []).filter((x) => !x.custom && !BLOCKLET_CONFIGURABLE_KEY[x.key]);
17
- const metaConfigs = isUpdatingCustomConfig ? allMetaConfigs : removeDeletedMetaConfigs(allMetaConfigs, newConfigs);
27
+
28
+ const metaConfigs = isConfigFromMeta ? allMetaConfigs : removeDeletedMetaConfigs(allMetaConfigs, newConfigs);
18
29
 
19
30
  // oldConfig 表示从数据库中可以用的字段
20
31
  const oldConfig = [...metaConfigs, ...appConfigs, ...customConfigs].reduce((acc, x) => {
@@ -65,16 +76,15 @@ const mergeConfigs = ({ old: oldConfigs, cur: newConfigs = [], did = '', dek = '
65
76
  const { name, key, value, default: defaultVal, required, description, secure, validation, custom, shared } = config;
66
77
  // 新增、更新或者删除
67
78
  if (key) {
68
- const originalVal = oldConfig[key] || {};
79
+ const origin = oldConfig[key] || {};
69
80
  oldConfig[key] = {
70
- ...originalVal,
71
81
  value,
72
- required: required === undefined ? false : required,
73
- description: description || '',
74
- validation: validation || '',
75
- secure: secure === undefined ? false : secure,
76
- custom: custom === undefined ? false : custom,
77
- shared,
82
+ required: required === undefined ? !!origin.required : required,
83
+ description: description || origin.description || '',
84
+ validation: validation || origin.validation || '',
85
+ secure: secure === undefined ? !!origin.secure : secure,
86
+ custom: custom === undefined ? !!origin.custom : custom,
87
+ shared: shared === undefined ? origin.shared : shared,
78
88
  };
79
89
  return;
80
90
  }
@@ -64,7 +64,7 @@ class ConfigSynchronizer {
64
64
  const component = findComponentByIdV2(app, did);
65
65
  const env = {
66
66
  ...component.configObj,
67
- ...getSharedConfigObj(component, [app]),
67
+ ...getSharedConfigObj(app, component),
68
68
  };
69
69
 
70
70
  const componentApiKey = getComponentApiKey({
@@ -115,7 +115,6 @@ const {
115
115
  filterDuplicateComponents,
116
116
  getBundleDir,
117
117
  getBlocklet,
118
- ensureEnvDefault,
119
118
  getConfigFromPreferences,
120
119
  validateAppConfig,
121
120
  checkDuplicateMountPoint,
@@ -132,6 +131,9 @@ const {
132
131
  ensureAppPortsNotOccupied,
133
132
  getComponentNamesWithVersion,
134
133
  updateDidDocument: updateBlockletDocument,
134
+ getAppConfigsFromComponent,
135
+ removeAppConfigsFromComponent,
136
+ getConfigsFromInput,
135
137
  } = require('../../util/blocklet');
136
138
  const { getDidDomainForBlocklet } = require('../../util/get-domain-for-blocklet');
137
139
  const states = require('../../states');
@@ -472,7 +474,7 @@ class DiskBlockletManager extends BaseBlockletManager {
472
474
  // check required config
473
475
  for (const component of blocklet1.children) {
474
476
  if (!shouldSkipComponent(component.meta.did, componentDids)) {
475
- const missingProps = getComponentMissingConfigs(component, [blocklet1]);
477
+ const missingProps = getComponentMissingConfigs(component, blocklet1);
476
478
  if (missingProps.length) {
477
479
  throw new Error(
478
480
  `Missing required configuration to start ${component.meta.title}: ${missingProps
@@ -931,7 +933,13 @@ class DiskBlockletManager extends BaseBlockletManager {
931
933
  fs.removeSync(path.join(app.env.dataDir, APP_CONFIG_DIR, child.meta.did, COMPONENT_ENV_FILE_NAME));
932
934
  if (keepData === false) {
933
935
  fs.removeSync(dataDir);
936
+
937
+ const componentEnvs = await states.blockletExtras.getConfigs([app.meta.did, child.meta.did]);
934
938
  await states.blockletExtras.delConfigs([app.meta.did, child.meta.did]);
939
+
940
+ // remove app configs if no component use it
941
+ const tmpApp = await this.getBlocklet(rootDid);
942
+ await removeAppConfigsFromComponent(componentEnvs, tmpApp, states.blockletExtras);
935
943
  }
936
944
 
937
945
  const newBlocklet = await this.getBlocklet(rootDid);
@@ -1149,9 +1157,17 @@ class DiskBlockletManager extends BaseBlockletManager {
1149
1157
  }
1150
1158
  await validateAppConfig(x, states);
1151
1159
  } else if (!BLOCKLET_CONFIGURABLE_KEY[x.key] && !isPreferenceKey(x)) {
1152
- if (!(blocklet.meta.environments || []).some((y) => y.name === x.key)) {
1160
+ const hasEnvInMeta = (b) => (b.meta.environments || []).some((y) => y.name === x.key);
1161
+ if (!hasEnvInMeta(blocklet)) {
1153
1162
  // forbid unknown format key
1154
- throw new Error(`unknown format key: ${x.key}`);
1163
+ if (
1164
+ // config should in component.meta.environments
1165
+ childDid ||
1166
+ // config should in app.meta.environments and or in one of component.meta.environments
1167
+ !(blocklet.children || []).some(hasEnvInMeta)
1168
+ ) {
1169
+ throw new Error(`unknown format key: ${x.key}`);
1170
+ }
1155
1171
  }
1156
1172
  }
1157
1173
 
@@ -1183,7 +1199,18 @@ class DiskBlockletManager extends BaseBlockletManager {
1183
1199
  Object.assign(blocklet.configObj, configObj);
1184
1200
 
1185
1201
  // update db
1186
- await states.blockletExtras.setConfigs([rootMetaDid, childDid].filter(Boolean), newConfigs);
1202
+ if (childDid) {
1203
+ const { sharedConfigs, selfConfigs } = getConfigsFromInput(newConfigs, blocklet.configs);
1204
+
1205
+ if (sharedConfigs.length) {
1206
+ await states.blockletExtras.setConfigs([rootMetaDid], sharedConfigs);
1207
+ }
1208
+ if (selfConfigs.length) {
1209
+ await states.blockletExtras.setConfigs([rootMetaDid, childDid], selfConfigs);
1210
+ }
1211
+ } else {
1212
+ await states.blockletExtras.setConfigs([rootMetaDid], newConfigs);
1213
+ }
1187
1214
 
1188
1215
  if (willAppSkChange) {
1189
1216
  const info = await states.node.read();
@@ -1479,7 +1506,7 @@ class DiskBlockletManager extends BaseBlockletManager {
1479
1506
  // eslint-disable-next-line no-unused-vars
1480
1507
  async getRuntimeHistory({ did, hours }, context) {
1481
1508
  const metaDid = await states.blocklet.getBlockletMetaDid(did);
1482
- const history = await this.runtimeMonitor.getHistory(metaDid);
1509
+ const history = await this.runtimeMonitor.getHistory(metaDid, hours);
1483
1510
 
1484
1511
  return getHistoryList({
1485
1512
  history,
@@ -2665,13 +2692,14 @@ class DiskBlockletManager extends BaseBlockletManager {
2665
2692
  // delete old process
2666
2693
  try {
2667
2694
  await this.deleteProcess({ did, componentDids }, context);
2668
- logger.info('delete blocklet process for upgrading', { did, name });
2695
+ logger.info('delete blocklet process for upgrading', { did, componentDids });
2669
2696
  } catch (err) {
2670
- logger.error('delete blocklet process for upgrading', { did, name, error: err });
2697
+ logger.error('delete blocklet process for upgrading', { did, componentDids, error: err });
2671
2698
  }
2672
2699
 
2673
2700
  // update state
2674
2701
  await states.blocklet.upgradeBlocklet({ meta, source, deployedFrom, children });
2702
+ logger.info('updated blocklet for upgrading', { did, componentDids, source, name });
2675
2703
  // ensure component status is upgrading
2676
2704
  await states.blocklet.setBlockletStatus(did, BlockletStatus.upgrading, { componentDids });
2677
2705
  await this._setConfigsFromMeta(did);
@@ -2689,20 +2717,22 @@ class DiskBlockletManager extends BaseBlockletManager {
2689
2717
  // post install
2690
2718
  await this._runPostInstallHook(blocklet, context);
2691
2719
 
2692
- logger.info('start migration');
2720
+ logger.info('start migration on upgrading', { did, componentDids });
2693
2721
  {
2694
2722
  const oldVersions = {};
2695
- forEachBlockletSync(oldBlocklet, (b, { id }) => {
2696
- oldVersions[id] = b.meta.version;
2723
+ forEachComponentV2Sync(oldBlocklet, (b) => {
2724
+ if (componentDids.includes(b.meta.did)) {
2725
+ oldVersions[b.meta.did] = b.meta.version;
2726
+ }
2697
2727
  });
2698
2728
  const nodeEnvironments = await states.node.getEnvironments();
2699
- const runMigration = async (b, { id, ancestors }) => {
2729
+ const runMigration = async (b) => {
2700
2730
  try {
2701
2731
  await runMigrationScripts({
2702
2732
  blocklet: b,
2703
2733
  appDir: b.env.appDir,
2704
- env: getRuntimeEnvironments(b, nodeEnvironments, ancestors),
2705
- oldVersion: oldVersions[id],
2734
+ env: getRuntimeEnvironments(b, nodeEnvironments, [blocklet]),
2735
+ oldVersion: oldVersions[b.meta.did],
2706
2736
  newVersion: b.meta.version,
2707
2737
  ...getHooksOutputFiles(b),
2708
2738
  });
@@ -2712,11 +2742,9 @@ class DiskBlockletManager extends BaseBlockletManager {
2712
2742
  throw error;
2713
2743
  }
2714
2744
  };
2715
- await forEachBlocklet(blocklet, runMigration, { parallel: true });
2745
+ await forEachComponentV2(blocklet, runMigration, { parallel: true, concurrencyLimit: 2 });
2716
2746
  }
2717
- logger.info('end migration');
2718
-
2719
- logger.info('updated blocklet for upgrading', { did, version, source, name });
2747
+ logger.info('done migration on upgrading', { did, componentDids });
2720
2748
 
2721
2749
  if (oldBlocklet.status === BlockletStatus.running) {
2722
2750
  try {
@@ -2917,7 +2945,7 @@ class DiskBlockletManager extends BaseBlockletManager {
2917
2945
  // rollback blocklet extra state
2918
2946
  await states.blockletExtras.update({ did: blocklet.meta.did }, extraState);
2919
2947
 
2920
- logger.info('blocklet rollback successfully', { did });
2948
+ logger.info('blocklet rollback successfully', { did, action });
2921
2949
  this.emit(BlockletEvents.updated, result);
2922
2950
  return result;
2923
2951
  }
@@ -2995,38 +3023,40 @@ class DiskBlockletManager extends BaseBlockletManager {
2995
3023
  async _setConfigsFromMeta(did, childDid) {
2996
3024
  const blocklet = await getBlocklet({ states, dataDirs: this.dataDirs, did });
2997
3025
 
2998
- if (!childDid) {
2999
- await forEachBlocklet(blocklet, async (b, { ancestors }) => {
3000
- const environments = [...get(b.meta, 'environments', []), ...getConfigFromPreferences(b)];
3026
+ const setConfig = async (app, component) => {
3027
+ const b = component || app;
3028
+ const environments = [...get(b.meta, 'environments', []), ...getConfigFromPreferences(b)];
3001
3029
 
3002
- // remove default if ancestors has a value
3003
- ensureEnvDefault(environments, ancestors);
3030
+ // write configs to db
3031
+ await states.blockletExtras.setConfigs([app.meta.did, component?.meta?.did].filter(Boolean), environments);
3004
3032
 
3005
- // write configs to db
3006
- await states.blockletExtras.setConfigs([...ancestors.map((x) => x.meta.did), b.meta.did], environments);
3033
+ if (component) {
3034
+ const envsInApp = await states.blockletExtras.getConfigs([app.appPid]);
3035
+ const envsInComponent = await states.blockletExtras.getConfigs([app.meta.did, component.meta.did]);
3007
3036
 
3008
- // chain config
3009
- await this._ensureAppChainConfig(
3010
- blocklet.meta.did,
3011
- environments.map((x) => ({ key: x.name, value: x.default })),
3012
- { force: false }
3013
- );
3037
+ const configs = getAppConfigsFromComponent({ environments }, envsInApp, envsInComponent);
3038
+ if (configs.length) {
3039
+ await states.blockletExtras.setConfigs(app.meta.did, configs);
3040
+ }
3041
+ }
3042
+
3043
+ // chain config
3044
+ await this._ensureAppChainConfig(
3045
+ blocklet.appPid,
3046
+ environments.map((x) => ({ key: x.name, value: x.default })),
3047
+ { force: false }
3048
+ );
3049
+ };
3050
+
3051
+ if (!childDid) {
3052
+ await setConfig(blocklet);
3053
+ await forEachComponentV2(blocklet, async (component) => {
3054
+ await setConfig(blocklet, component);
3014
3055
  });
3015
3056
  } else {
3016
- const child = blocklet.children.find((x) => x.meta.did === childDid);
3017
- await forEachBlocklet(child, async (b, { ancestors }) => {
3018
- await states.blockletExtras.setConfigs(
3019
- [blocklet.meta.did, ...ancestors.map((x) => x.meta.did), b.meta.did],
3020
- [...get(b.meta, 'environments', []), ...getConfigFromPreferences(child)]
3021
- );
3057
+ const component = blocklet.children.find((x) => x.meta.did === childDid);
3022
3058
 
3023
- // chain config
3024
- await this._ensureAppChainConfig(
3025
- blocklet.meta.did,
3026
- get(b.meta, 'environments', []).map((x) => ({ key: x.name, value: x.default })),
3027
- { force: false }
3028
- );
3029
- });
3059
+ await setConfig(blocklet, component);
3030
3060
  }
3031
3061
  }
3032
3062
 
@@ -3075,7 +3105,7 @@ class DiskBlockletManager extends BaseBlockletManager {
3075
3105
  ...getHooksOutputFiles(b),
3076
3106
  });
3077
3107
 
3078
- await forEachBlocklet(blocklet, preInstall, { parallel: true });
3108
+ await forEachBlocklet(blocklet, preInstall, { parallel: true, concurrencyLimit: 2 });
3079
3109
  }
3080
3110
 
3081
3111
  async _runPostInstallHook(blocklet, context) {
@@ -3092,7 +3122,7 @@ class DiskBlockletManager extends BaseBlockletManager {
3092
3122
  ...getHooksOutputFiles(b),
3093
3123
  });
3094
3124
 
3095
- await forEachBlocklet(blocklet, postInstall, { parallel: true });
3125
+ await forEachBlocklet(blocklet, postInstall, { parallel: true, concurrencyLimit: 2 });
3096
3126
  }
3097
3127
 
3098
3128
  async _createNotification(did, notification) {
@@ -1,6 +1,7 @@
1
1
  const path = require('path');
2
2
  const fs = require('fs-extra');
3
3
  const pick = require('lodash/pick');
4
+ const get = require('lodash/get');
4
5
  const pRetry = require('p-retry');
5
6
  const urlPathFriendly = require('@blocklet/meta/lib/url-path-friendly').default;
6
7
  const { slugify } = require('transliteration');
@@ -9,12 +10,7 @@ const { getChainClient } = require('@abtnode/util/lib/get-chain-client');
9
10
 
10
11
  const logger = require('@abtnode/logger')('@abtnode/core:migrate-application-to-struct-v2');
11
12
 
12
- const {
13
- forEachBlockletSync,
14
- getSharedConfigObj,
15
- getBlockletChainInfo,
16
- isInProgress,
17
- } = require('@blocklet/meta/lib/util');
13
+ const { forEachBlockletSync, getBlockletChainInfo, isInProgress } = require('@blocklet/meta/lib/util');
18
14
  const { SLOT_FOR_IP_DNS_SITE, MAIN_CHAIN_ENDPOINT } = require('@abtnode/constant');
19
15
 
20
16
  const {
@@ -33,6 +29,7 @@ const {
33
29
  BLOCKLET_CONFIGURABLE_KEY,
34
30
  BLOCKLET_META_FILE,
35
31
  BLOCKLET_UPLOADS_DIR,
32
+ CHAIN_PROP_MAP,
36
33
  } = require('@blocklet/constant');
37
34
  const { update: updateMetaFile } = require('@blocklet/meta/lib/file');
38
35
  const getBlockletWallet = require('@blocklet/meta/lib/wallet');
@@ -363,7 +360,55 @@ const migrateApplicationToStructV2 = async ({ did, appSk: newAppSk, context = {}
363
360
  configs: component.configs || [],
364
361
  });
365
362
 
366
- const sharedConfigObj = getSharedConfigObj(component, ancestors);
363
+ const getSharedConfigObj = () => {
364
+ const res = {};
365
+
366
+ if (!ancestors || !ancestors.length) {
367
+ return res;
368
+ }
369
+
370
+ for (let i = ancestors.length - 1; i >= 0; i--) {
371
+ const ancestor = ancestors[i];
372
+
373
+ if (Array.isArray(ancestor.configs)) {
374
+ // eslint-disable-next-line no-loop-func
375
+ ancestor.configs.forEach(({ key, value, secure, shared }) => {
376
+ if (res[key]) {
377
+ return;
378
+ }
379
+ if (!value || secure !== false || shared === false || BLOCKLET_CONFIGURABLE_KEY[key]) {
380
+ return;
381
+ }
382
+ const config = (component.configs || []).find((x) => x.key === key);
383
+
384
+ if (config && config.value) {
385
+ return;
386
+ }
387
+ res[key] = get(ancestor, `configObj.${key}`) || value;
388
+ });
389
+ }
390
+ }
391
+
392
+ // share blocklet app chain config
393
+ const ancestor = ancestors[0];
394
+ (ancestor.configs || []).forEach(({ key, value }) => {
395
+ if (
396
+ ![
397
+ BLOCKLET_CONFIGURABLE_KEY.BLOCKLET_APP_CHAIN_HOST,
398
+ BLOCKLET_CONFIGURABLE_KEY.BLOCKLET_APP_CHAIN_ID,
399
+ BLOCKLET_CONFIGURABLE_KEY.BLOCKLET_APP_CHAIN_TYPE,
400
+ ].includes(key)
401
+ ) {
402
+ return;
403
+ }
404
+
405
+ res[CHAIN_PROP_MAP[key]] = value;
406
+ });
407
+
408
+ return res;
409
+ };
410
+
411
+ const sharedConfigObj = getSharedConfigObj();
367
412
  if (sharedConfigObj) {
368
413
  Object.entries(sharedConfigObj).forEach(([key, value]) => {
369
414
  if (!extraData.configs.some((x) => x.key === key)) {
@@ -2,6 +2,7 @@ const EventEmitter = require('events');
2
2
 
3
3
  const cloneDeep = require('lodash/cloneDeep');
4
4
  const pLimit = require('p-limit');
5
+ const dayjs = require('@abtnode/util/lib/dayjs');
5
6
  const { forEachBlocklet, isGatewayBlocklet, hasStartEngine } = require('@blocklet/meta/lib/util');
6
7
  const getComponentProcessId = require('@blocklet/meta/lib/get-component-process-id');
7
8
  const { EVENTS } = require('@abtnode/constant');
@@ -53,8 +54,12 @@ class BlockletRuntimeMonitor extends EventEmitter {
53
54
  this.inProgress = false;
54
55
  }
55
56
 
56
- async getHistory(blockletDid) {
57
- const result = await this.states.runtimeInsight.findPaginated({ did: blockletDid });
57
+ async getHistory(blockletDid, hours = 1) {
58
+ const result = await this.states.runtimeInsight.findPaginated({
59
+ did: blockletDid,
60
+ startDate: dayjs().subtract(hours, 'hours').toDate().getTime(),
61
+ paging: { pageSize: hours * 360 },
62
+ });
58
63
  return (result.list || []).reverse();
59
64
  }
60
65
 
@@ -1,4 +1,5 @@
1
1
  const EventEmitter = require('events');
2
+ const dayjs = require('@abtnode/util/lib/dayjs');
2
3
  const pick = require('lodash/pick');
3
4
  const cloneDeep = require('lodash/cloneDeep');
4
5
 
@@ -93,8 +94,12 @@ class NodeRuntimeMonitor extends EventEmitter {
93
94
  return this.data.realtime;
94
95
  }
95
96
 
96
- async getHistory() {
97
- const result = await this.state.findPaginated({ did: this.did });
97
+ async getHistory(hours = 1) {
98
+ const result = await this.state.findPaginated({
99
+ did: this.did,
100
+ startDate: dayjs().subtract(hours, 'hours').toDate().getTime(),
101
+ paging: { pageSize: hours * 360 },
102
+ });
98
103
  return (result.list || []).reverse();
99
104
  }
100
105
 
@@ -247,7 +247,6 @@ Router.formatSites = (sites = []) => {
247
247
  port: daemonRule.to.port,
248
248
  did: rule.to.did,
249
249
  componentId: rule.to.componentId,
250
- cacheGroup: site.mode === BLOCKLET_MODES.PRODUCTION ? 'blockletJs' : '',
251
250
  pageGroup: rule.to.pageGroup,
252
251
  },
253
252
  });
@@ -281,7 +280,6 @@ Router.formatSites = (sites = []) => {
281
280
  to: {
282
281
  type: ROUTING_RULE_TYPES.DAEMON,
283
282
  port: daemonRule.to.port,
284
- cacheGroup: site.mode === BLOCKLET_MODES.PRODUCTION ? 'blockletJs' : '',
285
283
  pageGroup: rule.to.pageGroup,
286
284
  did: rule.to.did,
287
285
  },
@@ -140,9 +140,6 @@ class RouterManager extends EventEmitter {
140
140
  throw new Error("Can not delete this site because it's protected");
141
141
  }
142
142
 
143
- // validate router config
144
- await this.validateRouterConfig('deleteRoutingSite', { id });
145
-
146
143
  const removedSiteCount = await states.site.remove({ id });
147
144
 
148
145
  if (removedSiteCount === 0) {
@@ -365,9 +362,6 @@ class RouterManager extends EventEmitter {
365
362
  throw new Error('Deleting an system protected rule is forbidden');
366
363
  }
367
364
 
368
- // validate router config
369
- await this.validateRouterConfig('deleteRoutingRule', { id, ruleId });
370
-
371
365
  // 只要有匹配到的查询条件,不管是否删除成功都不会返回 0,所以这里没用 update 的返回值
372
366
  const doc = await states.site.findOne({ id });
373
367
  if (doc.rules.some((x) => x.id === ruleId || x.groupId === ruleId)) {
@@ -507,47 +501,34 @@ class RouterManager extends EventEmitter {
507
501
  }
508
502
 
509
503
  async validateRouterConfig(action, data) {
504
+ logger.info('validateRouterConfig.start', { action, data });
505
+
510
506
  // get data from db
511
507
  const info = await states.node.read();
512
508
  const httpsEnabled = get(info, 'routing.https', true);
513
509
 
514
510
  const certificates = httpsEnabled ? await this.certManager.getAllNormal() : [];
515
511
 
516
- let sites = await states.site.getSites();
512
+ let site;
513
+ if (data.site) {
514
+ site = cloneDeep(data.site);
515
+ } else if (data.id) {
516
+ site = await states.site.getSiteById(data.id);
517
+ }
518
+
517
519
  // mutate data by input
518
520
  const mutations = {
519
- addRoutingRule: ({ id, rule }) => {
520
- sites.forEach((site) => {
521
- if (site.id === id) {
522
- site.rules.push(rule);
523
- }
524
- });
525
- },
526
- updateRoutingRule: ({ id, rule }) => {
527
- sites.forEach((site) => {
528
- if (site.id === id) {
529
- site.rules = site.rules.map((x) => {
530
- if (x.id === rule.id) {
531
- return rule;
532
- }
533
- return x;
534
- });
535
- }
536
- });
521
+ addRoutingRule: ({ rule }) => {
522
+ site.rules.push(rule);
537
523
  },
538
- deleteRoutingRule: ({ id, ruleId }) => {
539
- sites.forEach((site) => {
540
- if (site.id === id) {
541
- site.rules = site.rules.filter((rule) => rule.id !== ruleId);
524
+ updateRoutingRule: ({ rule }) => {
525
+ site.rules = site.rules.map((x) => {
526
+ if (x.id === rule.id) {
527
+ return rule;
542
528
  }
529
+ return x;
543
530
  });
544
531
  },
545
- addRoutingSite: ({ site }) => {
546
- sites.push(site);
547
- },
548
- deleteRoutingSite: ({ id }) => {
549
- sites = sites.filter((site) => site.id !== id);
550
- },
551
532
  };
552
533
  if (mutations[action]) {
553
534
  mutations[action](cloneDeep(data));
@@ -557,11 +538,12 @@ class RouterManager extends EventEmitter {
557
538
  const providerName = getProviderFromNodeInfo(info);
558
539
  const Provider = getProvider(providerName);
559
540
  const tmpDir = path.join(os.tmpdir(), `${providerName}-${Date.now()}`);
560
- const provider = new Provider({ configDir: tmpDir });
541
+ // disable cache to reduce nginx reload time and memory consumption
542
+ const provider = new Provider({ configDir: tmpDir, cacheEnabled: false });
561
543
  const tempRouter = new Router({
562
544
  provider,
563
545
  getRoutingParams: async () => ({
564
- sites: await ensureLatestInfo(sites),
546
+ sites: await ensureLatestInfo([site]),
565
547
  certificates,
566
548
  commonHeaders: get(info, 'routing.headers', {}),
567
549
  services: [], // TODO: do we need to add some item here?
@@ -573,9 +555,10 @@ class RouterManager extends EventEmitter {
573
555
  try {
574
556
  await tempRouter.validateConfig();
575
557
  await fse.remove(tmpDir);
558
+ logger.info('validateRouterConfig.done', { action, data });
576
559
  } catch (error) {
577
560
  // 如果出错,保留 Nginx 配置文件,方便定位问题
578
- logger.error('validate router config failed', { error, action, data });
561
+ logger.error('validateRouterConfig.failed', { error, action, data });
579
562
  throw error;
580
563
  }
581
564
  }
@@ -42,7 +42,7 @@ const init = (dataDirs, config = {}) => {
42
42
  const jobState = new JobState(models.Job, config);
43
43
  const backupState = new BackupState(models.Backup, config);
44
44
  const trafficInsight = new TrafficInsightState(models.TrafficInsight, config);
45
- const runtimeInsight = new RuntimeInsightState(models.RuntimeInsight, config);
45
+ const runtimeInsight = new RuntimeInsightState(models.RuntimeInsight, { ...config, maxPageSize: 8640 });
46
46
 
47
47
  return {
48
48
  node: nodeState,
@@ -5,7 +5,6 @@ const BaseState = require('./base');
5
5
  * @extends BaseState<import('@abtnode/models').RuntimeInsightState>
6
6
  */
7
7
  class RuntimeInsight extends BaseState {
8
- // fetch data for recent hour
9
8
  findPaginated({ did = '', startDate = '', endDate = '', paging = { pageSize: 360 } } = {}) {
10
9
  const where = {};
11
10
  if (did) {
@@ -51,6 +51,10 @@ class SiteState extends BaseState {
51
51
  return sites.filter((x) => x.rules.some((r) => r.to?.did === did));
52
52
  }
53
53
 
54
+ getSiteById(id) {
55
+ return this.findOne({ id });
56
+ }
57
+
54
58
  async getSiteByRuleId(id, ruleId) {
55
59
  const site = await this.findOne({ id });
56
60
  if (site && site.rules.some((r) => r.id === ruleId)) {
@@ -85,12 +85,12 @@ const {
85
85
  forEachComponentV2Sync,
86
86
  getSharedConfigObj,
87
87
  getComponentName,
88
- isEnvShareable,
89
88
  getBlockletAppIdList,
90
89
  getChainInfo,
91
90
  isInProgress,
92
91
  isRunning,
93
92
  hasStartEngine,
93
+ isEnvShareable,
94
94
  } = require('@blocklet/meta/lib/util');
95
95
  const { getComponentsInternalInfo } = require('@blocklet/meta/lib/blocklet');
96
96
  const { titleSchema, descriptionSchema, logoSchema } = require('@blocklet/meta/lib/schema');
@@ -419,7 +419,7 @@ const getRuntimeEnvironments = (blocklet, nodeEnvironments, ancestors) => {
419
419
 
420
420
  const env = {
421
421
  ...blocklet.configObj,
422
- ...getSharedConfigObj(blocklet, ancestors),
422
+ ...getSharedConfigObj((ancestors || [])[0], blocklet),
423
423
  ...blocklet.environmentObj,
424
424
  ...devEnvironments,
425
425
  BLOCKLET_WEB_PORTS: JSON.stringify(ports),
@@ -499,7 +499,8 @@ const startBlockletProcess = async (
499
499
  throw new Error('blocklet should not be empty');
500
500
  }
501
501
 
502
- const now = Date.now();
502
+ // 需要在在这里传入字符串类型,否则进程中如法转化成 Date 对象
503
+ const now = `${new Date()}`;
503
504
 
504
505
  await forEachBlocklet(
505
506
  blocklet,
@@ -515,12 +516,12 @@ const startBlockletProcess = async (
515
516
  const { processId, logsDir, appDir } = b.env;
516
517
 
517
518
  if (skippedProcessIds.includes(processId)) {
518
- logger.info(`skip start skipped process ${processId}`);
519
+ logger.info('skip start skipped process', { processId });
519
520
  return;
520
521
  }
521
522
 
522
523
  if (shouldSkipComponent(b.meta.did, componentDids)) {
523
- logger.info(`skip start process not selected: ${b.meta.did}`, { processId });
524
+ logger.info('skip start process not selected', { processId });
524
525
  return;
525
526
  }
526
527
 
@@ -616,14 +617,14 @@ const startBlockletProcess = async (
616
617
  if (status === BlockletStatus.error) {
617
618
  throw new Error(`${processId} is not running within 3 seconds`);
618
619
  }
619
- logger.info('blocklet started', { processId, status, time: Date.now() - startedAt });
620
+ logger.info('done start blocklet', { processId, status, time: Date.now() - startedAt });
620
621
 
621
622
  // run hook
622
623
  postStart(b, { env }).catch((err) => {
623
624
  logger.error('blocklet post start failed', { processId, error: err });
624
625
  });
625
626
  },
626
- { parallel: true }
627
+ { parallel: true, concurrencyLimit: 2 }
627
628
  );
628
629
  };
629
630
 
@@ -682,12 +683,12 @@ const reloadBlockletProcess = (blocklet, { componentDids } = {}) =>
682
683
  }
683
684
 
684
685
  if (shouldSkipComponent(b.meta.did, componentDids)) {
685
- logger.info(`skip reload process not selected: ${b.meta.did}`, { processId: b.env.processId });
686
+ logger.info('skip reload process', { processId: b.env.processId });
686
687
  return;
687
688
  }
688
689
 
689
- logger.info('reload process', { processId: b.env.processId });
690
690
  await reloadProcess(b.env.processId);
691
+ logger.info('done reload process', { processId: b.env.processId });
691
692
  },
692
693
  { parallel: false }
693
694
  );
@@ -716,10 +717,10 @@ const deleteProcess = (processId) =>
716
717
  new Promise((resolve, reject) => {
717
718
  pm2.delete(processId, (err) => {
718
719
  if (isUsefulError(err)) {
719
- logger.error('blocklet process delete failed', { error: err });
720
+ logger.error('blocklet process delete failed', { processId, error: err });
720
721
  return reject(err);
721
722
  }
722
- return resolve();
723
+ return resolve(processId);
723
724
  });
724
725
  });
725
726
 
@@ -728,11 +729,11 @@ const reloadProcess = (processId) =>
728
729
  pm2.reload(processId, (err) => {
729
730
  if (err) {
730
731
  if (isUsefulError(err)) {
731
- logger.error('blocklet reload failed', { error: err });
732
+ logger.error('blocklet reload failed', { processId, error: err });
732
733
  }
733
734
  return reject(err);
734
735
  }
735
- return resolve();
736
+ return resolve(processId);
736
737
  });
737
738
  });
738
739
 
@@ -770,7 +771,7 @@ const checkBlockletProcessHealthy = async (blocklet, { minConsecutiveTime, timeo
770
771
  }
771
772
 
772
773
  if (shouldSkipComponent(b.meta.did, componentDids)) {
773
- logger.info('skip check component healthy not selected', { id: b.env.id, processId: b.env.processId });
774
+ logger.info('skip check component healthy', { processId: b.env.processId });
774
775
  return;
775
776
  }
776
777
 
@@ -778,7 +779,7 @@ const checkBlockletProcessHealthy = async (blocklet, { minConsecutiveTime, timeo
778
779
 
779
780
  const startedAt = Date.now();
780
781
  await _checkProcessHealthy(b, { minConsecutiveTime, timeout, logToTerminal });
781
- logger.info('component healthy', { did: b.meta.did, time: Date.now() - startedAt });
782
+ logger.info('done check component healthy', { processId: b.env.processId, time: Date.now() - startedAt });
782
783
  },
783
784
  { parallel: true }
784
785
  );
@@ -1292,35 +1293,6 @@ const getBlocklet = async ({
1292
1293
  return blocklet;
1293
1294
  };
1294
1295
 
1295
- /**
1296
- * this function has side effect on environments
1297
- */
1298
- const ensureEnvDefault = (environments, ancestors) => {
1299
- // remove default if ancestors has a value
1300
- const envMap = environments.reduce((o, env) => {
1301
- o[env.name] = env;
1302
- return o;
1303
- }, {});
1304
-
1305
- for (let i = ancestors.length - 1; i >= 0; i--) {
1306
- const ancestor = ancestors[i];
1307
- const aEnvironments = get(ancestor.meta, 'environments', []);
1308
- const aEnv = aEnvironments.find((x) => envMap[x.name]);
1309
-
1310
- if (!isEnvShareable(aEnv)) {
1311
- break;
1312
- }
1313
-
1314
- const env = envMap[aEnv.name];
1315
- if (isEnvShareable(env) && aEnv.default) {
1316
- env.default = '';
1317
- break;
1318
- }
1319
- }
1320
-
1321
- return environments;
1322
- };
1323
-
1324
1296
  const fromProperty2Config = (properties = {}, result) => {
1325
1297
  Object.keys(properties).forEach((key) => {
1326
1298
  const prop = properties[key];
@@ -1334,7 +1306,7 @@ const fromProperty2Config = (properties = {}, result) => {
1334
1306
  name: `${BLOCKLET_PREFERENCE_PREFIX}${key}`,
1335
1307
  required: prop.required || false,
1336
1308
  secure,
1337
- shared: !secure,
1309
+ shared: secure ? false : prop.shared,
1338
1310
  });
1339
1311
  }
1340
1312
  });
@@ -1875,6 +1847,61 @@ const updateDidDocument = async ({ blocklet, nodeInfo }) => {
1875
1847
  });
1876
1848
  };
1877
1849
 
1850
+ const getAppConfigsFromComponent = (meta, configsInApp = [], configsInComponent = []) => {
1851
+ const configs = [];
1852
+ for (const configInMeta of meta?.environments || []) {
1853
+ if (isEnvShareable(configInMeta)) {
1854
+ const configInApp = (configsInApp || []).find((x) => x.key === configInMeta.name);
1855
+ if (!configInApp) {
1856
+ const configInComponent = configsInComponent.find((y) => y.key === configInMeta.name);
1857
+ if (configInComponent && isEnvShareable(configInComponent)) {
1858
+ configs.push(configInComponent);
1859
+ }
1860
+ }
1861
+ }
1862
+ }
1863
+ return configs;
1864
+ };
1865
+
1866
+ const getConfigsFromInput = (configs = [], oldConfigs = []) => {
1867
+ const sharedConfigs = [];
1868
+ const selfConfigs = [];
1869
+
1870
+ configs.forEach((config) => {
1871
+ const oldConfig = oldConfigs.find((y) => y.key === config.key);
1872
+ if (isEnvShareable(config) || isEnvShareable(oldConfig)) {
1873
+ sharedConfigs.push(config);
1874
+ } else {
1875
+ selfConfigs.push(config);
1876
+ }
1877
+ });
1878
+
1879
+ return { sharedConfigs, selfConfigs };
1880
+ };
1881
+
1882
+ // remove app configs if no component use it
1883
+ const removeAppConfigsFromComponent = async (componentConfigs, app, blockletExtraState) => {
1884
+ const appConfigs = app.configs || [];
1885
+ const remainedConfigs = [].concat(...(app.children || []).map((x) => x.configs || []));
1886
+ const removedAppConfigs = [];
1887
+
1888
+ componentConfigs.forEach((config) => {
1889
+ const appConfig = appConfigs.find((x) => x.key === config.key);
1890
+ if (
1891
+ appConfig &&
1892
+ !appConfig.custom &&
1893
+ !(app.meta.environments || []).find((x) => x.name === config.key) &&
1894
+ !remainedConfigs.find((x) => x.key === config.key && isEnvShareable(x))
1895
+ ) {
1896
+ removedAppConfigs.push({ key: appConfig.key, value: undefined });
1897
+ }
1898
+ });
1899
+
1900
+ if (removedAppConfigs.length) {
1901
+ await blockletExtraState.setConfigs(app.meta.did, removedAppConfigs);
1902
+ }
1903
+ };
1904
+
1878
1905
  module.exports = {
1879
1906
  updateBlockletFallbackLogo,
1880
1907
  forEachBlocklet,
@@ -1913,7 +1940,6 @@ module.exports = {
1913
1940
  needBlockletDownload,
1914
1941
  ensureMeta,
1915
1942
  getBlocklet,
1916
- ensureEnvDefault,
1917
1943
  getConfigFromPreferences,
1918
1944
  createDataArchive,
1919
1945
  validateAppConfig,
@@ -1940,4 +1966,7 @@ module.exports = {
1940
1966
  updateDidDocument,
1941
1967
  getSlpDid,
1942
1968
  shouldEnableSlpDomain,
1969
+ getAppConfigsFromComponent,
1970
+ removeAppConfigsFromComponent,
1971
+ getConfigsFromInput,
1943
1972
  };
package/lib/util/log.js CHANGED
@@ -138,9 +138,11 @@ const getLogFiles = async ({ name, node }) => {
138
138
  if (name === 'blocklet-services') {
139
139
  const logDir = path.join(node.dataDirs.logs, '_abtnode');
140
140
  const info = path.join(logDir, 'service.log');
141
- const error = path.join(logDir, 'service.error.log');
142
- createFile({ info, error });
143
- return { info, error };
141
+ const access = path.join(logDir, 'service.access.log');
142
+ const stdout = path.join(logDir, 'service.stdout.log');
143
+ const stderr = path.join(logDir, 'service.stderr.log');
144
+ createFile({ info, access, stdout, stderr });
145
+ return { info, access, stdout, stderr };
144
146
  }
145
147
 
146
148
  if (name.indexOf('blocklet-') === 0) {
@@ -230,8 +232,8 @@ const getDownloadLogFilesFromServer = async ({ dates, nodeInfo, node } = {}) =>
230
232
  list.push(path.join(logDir, 'access.log*'));
231
233
 
232
234
  // abt-node-service console & gateway
233
- list.push(path.join(logDir, 'service.output.log*'));
234
- list.push(path.join(logDir, 'service.error.log*'));
235
+ list.push(path.join(logDir, 'service.stdout.log*'));
236
+ list.push(path.join(logDir, 'service.stderr.log*'));
235
237
  list.push(path.join(logDir, 'service.log*'));
236
238
 
237
239
  // abt-node-db-hub console & backup
package/package.json CHANGED
@@ -3,7 +3,7 @@
3
3
  "publishConfig": {
4
4
  "access": "public"
5
5
  },
6
- "version": "1.16.16-beta-d8a9fb09",
6
+ "version": "1.16.16-beta-740ea329",
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.16-beta-d8a9fb09",
23
- "@abtnode/auth": "1.16.16-beta-d8a9fb09",
24
- "@abtnode/certificate-manager": "1.16.16-beta-d8a9fb09",
25
- "@abtnode/constant": "1.16.16-beta-d8a9fb09",
26
- "@abtnode/cron": "1.16.16-beta-d8a9fb09",
27
- "@abtnode/logger": "1.16.16-beta-d8a9fb09",
28
- "@abtnode/models": "1.16.16-beta-d8a9fb09",
29
- "@abtnode/queue": "1.16.16-beta-d8a9fb09",
30
- "@abtnode/rbac": "1.16.16-beta-d8a9fb09",
31
- "@abtnode/router-provider": "1.16.16-beta-d8a9fb09",
32
- "@abtnode/static-server": "1.16.16-beta-d8a9fb09",
33
- "@abtnode/timemachine": "1.16.16-beta-d8a9fb09",
34
- "@abtnode/util": "1.16.16-beta-d8a9fb09",
22
+ "@abtnode/analytics": "1.16.16-beta-740ea329",
23
+ "@abtnode/auth": "1.16.16-beta-740ea329",
24
+ "@abtnode/certificate-manager": "1.16.16-beta-740ea329",
25
+ "@abtnode/constant": "1.16.16-beta-740ea329",
26
+ "@abtnode/cron": "1.16.16-beta-740ea329",
27
+ "@abtnode/logger": "1.16.16-beta-740ea329",
28
+ "@abtnode/models": "1.16.16-beta-740ea329",
29
+ "@abtnode/queue": "1.16.16-beta-740ea329",
30
+ "@abtnode/rbac": "1.16.16-beta-740ea329",
31
+ "@abtnode/router-provider": "1.16.16-beta-740ea329",
32
+ "@abtnode/static-server": "1.16.16-beta-740ea329",
33
+ "@abtnode/timemachine": "1.16.16-beta-740ea329",
34
+ "@abtnode/util": "1.16.16-beta-740ea329",
35
35
  "@arcblock/did": "1.18.89",
36
36
  "@arcblock/did-auth": "1.18.89",
37
37
  "@arcblock/did-ext": "^1.18.89",
@@ -42,12 +42,12 @@
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.16-beta-d8a9fb09",
46
- "@blocklet/env": "1.16.16-beta-d8a9fb09",
47
- "@blocklet/meta": "1.16.16-beta-d8a9fb09",
48
- "@blocklet/resolver": "1.16.16-beta-d8a9fb09",
49
- "@blocklet/sdk": "1.16.16-beta-d8a9fb09",
50
- "@did-space/client": "^0.2.169",
45
+ "@blocklet/constant": "1.16.16-beta-740ea329",
46
+ "@blocklet/env": "1.16.16-beta-740ea329",
47
+ "@blocklet/meta": "1.16.16-beta-740ea329",
48
+ "@blocklet/resolver": "1.16.16-beta-740ea329",
49
+ "@blocklet/sdk": "1.16.16-beta-740ea329",
50
+ "@did-space/client": "^0.2.170",
51
51
  "@fidm/x509": "^1.2.1",
52
52
  "@ocap/mcrypto": "1.18.89",
53
53
  "@ocap/util": "1.18.89",
@@ -100,5 +100,5 @@
100
100
  "jest": "^27.5.1",
101
101
  "unzipper": "^0.10.11"
102
102
  },
103
- "gitHead": "a03d8972fd0fafe810369efa89b03ccd0647dce5"
103
+ "gitHead": "6abb5a7319ad1093f1e2d04d76215d4a127b538d"
104
104
  }