@abtnode/core 1.15.17 → 1.16.0-beta-b16cb035

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.
Files changed (119) hide show
  1. package/lib/api/node.js +67 -69
  2. package/lib/api/team.js +386 -55
  3. package/lib/blocklet/downloader/blocklet-downloader.js +226 -0
  4. package/lib/blocklet/downloader/bundle-downloader.js +272 -0
  5. package/lib/blocklet/downloader/constants.js +3 -0
  6. package/lib/blocklet/downloader/resolve-download.js +199 -0
  7. package/lib/blocklet/extras.js +83 -26
  8. package/lib/blocklet/hooks.js +18 -65
  9. package/lib/blocklet/manager/base.js +10 -16
  10. package/lib/blocklet/manager/disk.js +1679 -1566
  11. package/lib/blocklet/manager/helper/install-application-from-backup.js +177 -0
  12. package/lib/blocklet/manager/helper/install-application-from-dev.js +94 -0
  13. package/lib/blocklet/manager/helper/install-application-from-general.js +188 -0
  14. package/lib/blocklet/manager/helper/install-component-from-dev.js +84 -0
  15. package/lib/blocklet/manager/helper/install-component-from-upload.js +181 -0
  16. package/lib/blocklet/manager/helper/install-component-from-url.js +173 -0
  17. package/lib/blocklet/manager/helper/migrate-application-to-struct-v2.js +450 -0
  18. package/lib/blocklet/manager/helper/rollback-cache.js +41 -0
  19. package/lib/blocklet/manager/helper/upgrade-components.js +152 -0
  20. package/lib/blocklet/migration.js +30 -52
  21. package/lib/blocklet/storage/backup/audit-log.js +27 -0
  22. package/lib/blocklet/storage/backup/base.js +62 -0
  23. package/lib/blocklet/storage/backup/blocklet-extras.js +92 -0
  24. package/lib/blocklet/storage/backup/blocklet.js +70 -0
  25. package/lib/blocklet/storage/backup/blocklets.js +74 -0
  26. package/lib/blocklet/storage/backup/data.js +19 -0
  27. package/lib/blocklet/storage/backup/logs.js +24 -0
  28. package/lib/blocklet/storage/backup/routing-rule.js +19 -0
  29. package/lib/blocklet/storage/backup/spaces.js +240 -0
  30. package/lib/blocklet/storage/restore/base.js +67 -0
  31. package/lib/blocklet/storage/restore/blocklet-extras.js +86 -0
  32. package/lib/blocklet/storage/restore/blocklet.js +56 -0
  33. package/lib/blocklet/storage/restore/blocklets.js +43 -0
  34. package/lib/blocklet/storage/restore/logs.js +21 -0
  35. package/lib/blocklet/storage/restore/spaces.js +156 -0
  36. package/lib/blocklet/storage/utils/hash.js +51 -0
  37. package/lib/blocklet/storage/utils/zip.js +43 -0
  38. package/lib/cert.js +206 -0
  39. package/lib/event.js +237 -64
  40. package/lib/index.js +191 -83
  41. package/lib/migrations/1.0.21-update-config.js +1 -1
  42. package/lib/migrations/1.0.22-max-memory.js +1 -1
  43. package/lib/migrations/1.0.25.js +1 -1
  44. package/lib/migrations/1.0.32-update-config.js +1 -1
  45. package/lib/migrations/1.0.33-blocklets.js +1 -1
  46. package/lib/migrations/1.5.20-registry.js +15 -0
  47. package/lib/migrations/1.6.17-blocklet-children.js +48 -0
  48. package/lib/migrations/1.6.21-rename-ip-echo-domain.js +35 -0
  49. package/lib/migrations/1.6.4-security.js +59 -0
  50. package/lib/migrations/1.6.5-security.js +60 -0
  51. package/lib/migrations/1.6.9-update-node-info-and-certificate.js +38 -0
  52. package/lib/migrations/1.7.1-blocklet-setup.js +18 -0
  53. package/lib/migrations/1.7.12-blocklet-meta.js +51 -0
  54. package/lib/migrations/1.7.15-blocklet-bundle-source.js +42 -0
  55. package/lib/migrations/1.7.20-blocklet-component.js +41 -0
  56. package/lib/migrations/1.8.33-blocklet-mem-limit.js +20 -0
  57. package/lib/migrations/README.md +1 -1
  58. package/lib/migrations/index.js +6 -2
  59. package/lib/monitor/blocklet-runtime-monitor.js +200 -0
  60. package/lib/monitor/get-history-list.js +37 -0
  61. package/lib/monitor/node-runtime-monitor.js +228 -0
  62. package/lib/router/helper.js +572 -497
  63. package/lib/router/index.js +85 -21
  64. package/lib/router/manager.js +146 -187
  65. package/lib/states/README.md +36 -1
  66. package/lib/states/access-key.js +39 -17
  67. package/lib/states/audit-log.js +462 -0
  68. package/lib/states/base.js +4 -213
  69. package/lib/states/blocklet-extras.js +194 -138
  70. package/lib/states/blocklet.js +361 -104
  71. package/lib/states/cache.js +8 -6
  72. package/lib/states/challenge.js +5 -5
  73. package/lib/states/index.js +19 -36
  74. package/lib/states/migration.js +4 -4
  75. package/lib/states/node.js +135 -46
  76. package/lib/states/notification.js +22 -35
  77. package/lib/states/session.js +17 -9
  78. package/lib/states/site.js +50 -25
  79. package/lib/states/user.js +74 -20
  80. package/lib/states/webhook.js +10 -6
  81. package/lib/team/manager.js +124 -7
  82. package/lib/util/blocklet.js +1223 -246
  83. package/lib/util/chain.js +1 -1
  84. package/lib/util/default-node-config.js +5 -23
  85. package/lib/util/disk-monitor.js +13 -10
  86. package/lib/util/domain-status.js +84 -15
  87. package/lib/util/get-accessible-external-node-ip.js +2 -2
  88. package/lib/util/get-domain-for-blocklet.js +13 -0
  89. package/lib/util/get-meta-from-url.js +33 -0
  90. package/lib/util/index.js +207 -272
  91. package/lib/util/ip.js +6 -0
  92. package/lib/util/maintain.js +233 -0
  93. package/lib/util/public-to-store.js +85 -0
  94. package/lib/util/ready.js +1 -1
  95. package/lib/util/requirement.js +28 -9
  96. package/lib/util/reset-node.js +22 -7
  97. package/lib/util/router.js +13 -0
  98. package/lib/util/rpc.js +16 -0
  99. package/lib/util/store.js +179 -0
  100. package/lib/util/sysinfo.js +44 -0
  101. package/lib/util/ua.js +54 -0
  102. package/lib/validators/blocklet-extra.js +24 -0
  103. package/lib/validators/node.js +25 -12
  104. package/lib/validators/permission.js +16 -1
  105. package/lib/validators/role.js +17 -3
  106. package/lib/validators/router.js +40 -20
  107. package/lib/validators/trusted-passport.js +1 -0
  108. package/lib/validators/util.js +22 -5
  109. package/lib/webhook/index.js +45 -35
  110. package/lib/webhook/sender/index.js +5 -0
  111. package/lib/webhook/sender/slack/index.js +1 -1
  112. package/lib/webhook/sender/wallet/index.js +48 -0
  113. package/package.json +54 -36
  114. package/lib/blocklet/registry.js +0 -205
  115. package/lib/states/https-cert.js +0 -67
  116. package/lib/util/get-ip-dns-domain-for-blocklet.js +0 -19
  117. package/lib/util/service.js +0 -66
  118. package/lib/util/upgrade.js +0 -178
  119. /package/lib/{queue.js → util/queue.js} +0 -0
@@ -0,0 +1,59 @@
1
+ /* eslint-disable no-await-in-loop */
2
+ const fs = require('fs');
3
+ const path = require('path');
4
+ const crypto = require('crypto');
5
+ const yaml = require('js-yaml');
6
+ const cloneDeep = require('lodash/cloneDeep');
7
+ const security = require('@abtnode/util/lib/security');
8
+
9
+ module.exports = async ({ states, configFile, dataDir }) => {
10
+ if (process.env.CI || process.env.NODE_ENV === 'test') {
11
+ return;
12
+ }
13
+
14
+ const file = path.join(dataDir, '.sock');
15
+ if (fs.existsSync(file)) {
16
+ return;
17
+ }
18
+
19
+ try {
20
+ fs.writeFileSync(file, crypto.randomBytes(32), { encoding: 'binary', mode: '0600' });
21
+
22
+ const config = yaml.load(fs.readFileSync(configFile).toString(), { json: true });
23
+ config.node.sk = security.encrypt(config.node.sk, config.node.did, fs.readFileSync(file));
24
+ fs.writeFileSync(configFile, yaml.dump(config));
25
+ await states.node.updateNodeInfo({ sk: config.node.sk });
26
+
27
+ const items = await states.blockletExtras.find();
28
+ for (const item of items) {
29
+ const newConfigs = cloneDeep(item.configs || []).map((c) => {
30
+ if (c.secure) {
31
+ c.value = security.encrypt(c.value, item.did, fs.readFileSync(file));
32
+ }
33
+
34
+ return c;
35
+ });
36
+
37
+ const newChildren = cloneDeep(item.children || []).map((x) => {
38
+ return {
39
+ ...x,
40
+ configs: cloneDeep(x.configs || []).map((c) => {
41
+ if (c.secure) {
42
+ c.value = security.encrypt(c.value, item.did, fs.readFileSync(file));
43
+ }
44
+
45
+ return c;
46
+ }),
47
+ };
48
+ });
49
+
50
+ await states.blockletExtras.update({ did: item.did }, { $set: { configs: newConfigs, children: newChildren } });
51
+ }
52
+
53
+ states.node.compactDatafile();
54
+ states.blockletExtras.compactDatafile();
55
+ } catch (err) {
56
+ console.error(err);
57
+ throw err;
58
+ }
59
+ };
@@ -0,0 +1,60 @@
1
+ /* eslint-disable no-await-in-loop */
2
+ const fs = require('fs');
3
+ const path = require('path');
4
+ const uniq = require('lodash/uniq');
5
+ const cloneDeep = require('lodash/cloneDeep');
6
+ const security = require('@abtnode/util/lib/security');
7
+ const { forEachBlocklet } = require('@blocklet/meta/lib/util');
8
+
9
+ module.exports = async ({ states, dataDir }) => {
10
+ if (process.env.CI || process.env.NODE_ENV === 'test') {
11
+ return;
12
+ }
13
+
14
+ const file = path.join(dataDir, '.sock');
15
+ if (fs.existsSync(file) === false) {
16
+ return;
17
+ }
18
+
19
+ try {
20
+ const extras = await states.blockletExtras.find();
21
+ const blocklets = await states.blocklet.find();
22
+ for (const blocklet of blocklets) {
23
+ forEachBlocklet(
24
+ blocklet,
25
+ (b) => {
26
+ let configKeys;
27
+ const extra = extras.find((x) => x.did === blocklet.meta.did);
28
+ const rootKeys = (extra.configs || []).map((x) => x.key);
29
+ if (b.meta.did === blocklet.meta.did) {
30
+ configKeys = rootKeys;
31
+ } else {
32
+ const childExtra = (extra.children || []).find((x) => x.did === b.meta.did);
33
+ const childKeys = childExtra ? childExtra.configs.map((x) => x.key) : [];
34
+ configKeys = uniq([...rootKeys, ...childKeys]);
35
+ }
36
+
37
+ b.environments = cloneDeep(b.environments || [])
38
+ .filter((x) => configKeys.includes(x.key) === false)
39
+ .map((c) => {
40
+ if (c.key === 'BLOCKLET_APP_SK') {
41
+ c.value = security.encrypt(c.value, b.meta.did, fs.readFileSync(file));
42
+ }
43
+
44
+ return c;
45
+ });
46
+ },
47
+ { sync: true }
48
+ );
49
+
50
+ await states.blocklet.updateById(blocklet._id, {
51
+ $set: { environments: blocklet.environments, children: blocklet.children, migratedFrom: '1.6.5' },
52
+ });
53
+ }
54
+
55
+ states.blocklet.compactDatafile();
56
+ } catch (err) {
57
+ console.error(err);
58
+ throw err;
59
+ }
60
+ };
@@ -0,0 +1,38 @@
1
+ /* eslint-disable no-await-in-loop */
2
+
3
+ const { DEFAULT_DID_REGISTRY, DEFAULT_DID_DOMAIN } = require('@abtnode/constant');
4
+ const { isEmpty, omit } = require('lodash');
5
+
6
+ const updateNodeInfo = async ({ printInfo, states }) => {
7
+ // add didRegistry and didDomain
8
+ const info = await states.node.read();
9
+ const data = {};
10
+ if (!info.didRegistry) {
11
+ data.didRegistry = DEFAULT_DID_REGISTRY;
12
+ }
13
+
14
+ if (!info.didDomain) {
15
+ data.didDomain = DEFAULT_DID_DOMAIN;
16
+ }
17
+
18
+ if (!isEmpty(data)) {
19
+ await states.node.update({ _id: info._id }, { $set: data });
20
+ }
21
+
22
+ printInfo('update did registry and did domain successfully');
23
+ };
24
+
25
+ const updateCertificate = async ({ node, printInfo }) => {
26
+ const certs = await node.certManager.getAllNormal();
27
+ for (const cert of certs || []) {
28
+ await node.certManager.updateWithoutValidations(cert.id, omit(cert, 'id'));
29
+ }
30
+
31
+ printInfo('update certificate successfully');
32
+ };
33
+
34
+ /* eslint-disable no-underscore-dangle */
35
+ module.exports = async ({ node, printInfo, states }) => {
36
+ await updateNodeInfo({ printInfo, states });
37
+ await updateCertificate({ node, printInfo, states });
38
+ };
@@ -0,0 +1,18 @@
1
+ /* eslint-disable no-continue */
2
+ /* eslint-disable no-await-in-loop */
3
+ /* eslint-disable no-underscore-dangle */
4
+
5
+ module.exports = async ({ states, printInfo }) => {
6
+ printInfo('Try to update blocklet server to 1.7.1...');
7
+
8
+ const blockletExtras = await states.blockletExtras.find({});
9
+ for (const extra of blockletExtras) {
10
+ if (!extra) {
11
+ continue;
12
+ }
13
+
14
+ await states.blockletExtras.setSettings(extra.did, { initialized: true });
15
+
16
+ printInfo(`Set initialized: ${extra.did}`);
17
+ }
18
+ };
@@ -0,0 +1,51 @@
1
+ /* eslint-disable no-continue */
2
+ /* eslint-disable no-await-in-loop */
3
+ /* eslint-disable no-underscore-dangle */
4
+
5
+ module.exports = async ({ states, printInfo }) => {
6
+ printInfo('Try to update blocklet server to 1.7.12...');
7
+
8
+ const blocklets = await states.blocklet.getBlocklets();
9
+
10
+ for (const blocklet of blocklets) {
11
+ let changed = false;
12
+
13
+ if (!blocklet.meta.bundleDid) {
14
+ blocklet.meta.bundleDid = blocklet.meta.did;
15
+ blocklet.meta.bundleName = blocklet.meta.name;
16
+ changed = true;
17
+ }
18
+
19
+ (blocklet.children || []).forEach((child) => {
20
+ if (!child.meta.bundleDid) {
21
+ child.meta.bundleDid = child.meta.did;
22
+ child.meta.bundleName = child.meta.name;
23
+ changed = true;
24
+ }
25
+ });
26
+
27
+ if (changed) {
28
+ await states.blocklet.updateBlocklet(blocklet.meta.did, { meta: blocklet.meta, children: blocklet.children });
29
+ printInfo(`Blocklet meta in blocklet.db updated: ${blocklet.meta.did}`);
30
+ }
31
+ }
32
+
33
+ const blockletExtras = await states.blockletExtras.find({});
34
+
35
+ for (const extra of blockletExtras) {
36
+ let changed = false;
37
+ const children = await states.blockletExtras.getSettings(extra.did, 'children', []);
38
+ (children || []).forEach((child) => {
39
+ if (!child.meta.bundleDid) {
40
+ child.meta.bundleDid = child.meta.did;
41
+ child.meta.bundleName = child.meta.name;
42
+ changed = true;
43
+ }
44
+ });
45
+
46
+ if (changed) {
47
+ await states.blockletExtras.setSettings(extra.did, { children });
48
+ printInfo(`Blocklet dynamic component meta in blocklet_extra.db updated: ${extra.did}`);
49
+ }
50
+ }
51
+ };
@@ -0,0 +1,42 @@
1
+ /* eslint-disable no-continue */
2
+ /* eslint-disable no-await-in-loop */
3
+ /* eslint-disable no-underscore-dangle */
4
+
5
+ module.exports = async ({ states, printInfo }) => {
6
+ printInfo('Try to update blocklet server to 1.7.15...');
7
+
8
+ const blocklets = await states.blocklet.getBlocklets();
9
+
10
+ for (const blocklet of blocklets) {
11
+ (blocklet.children || []).forEach((child) => {
12
+ const { sourceUrl } = child;
13
+ delete child.sourceUrl;
14
+ if (sourceUrl && !child.bundleSource) {
15
+ child.bundleSource = {
16
+ url: sourceUrl,
17
+ };
18
+ }
19
+ });
20
+
21
+ await states.blocklet.updateBlocklet(blocklet.meta.did, { children: blocklet.children });
22
+ printInfo(`Blocklet children in blocklet.db updated: ${blocklet.meta.did}`);
23
+ }
24
+
25
+ const blockletExtras = await states.blockletExtras.find({});
26
+
27
+ for (const extra of blockletExtras) {
28
+ const children = await states.blockletExtras.getSettings(extra.did, 'children', []);
29
+ (children || []).forEach((child) => {
30
+ const { sourceUrl } = child;
31
+ delete child.sourceUrl;
32
+ if (sourceUrl && !child.bundleSource) {
33
+ child.bundleSource = {
34
+ url: sourceUrl,
35
+ };
36
+ }
37
+ });
38
+
39
+ await states.blockletExtras.setSettings(extra.did, { children });
40
+ printInfo(`Blocklet dynamic component in blocklet_extra.db updated: ${extra.did}`);
41
+ }
42
+ };
@@ -0,0 +1,41 @@
1
+ /* eslint-disable no-await-in-loop */
2
+ /* eslint-disable no-continue */
3
+
4
+ module.exports = async ({ states, printInfo }) => {
5
+ printInfo('Try to delete realDid, realInterface and add componentId in db...');
6
+
7
+ const sites = await states.site.find({});
8
+
9
+ for (const site of sites) {
10
+ let changed = false;
11
+ for (const rule of site.rules || []) {
12
+ if (!rule.to) {
13
+ continue;
14
+ }
15
+
16
+ if (rule.to.type !== 'blocklet') {
17
+ continue;
18
+ }
19
+
20
+ if (rule.to.componentId) {
21
+ continue;
22
+ }
23
+
24
+ if (!rule.to.realDid || rule.to.did === rule.to.realDid) {
25
+ rule.to.componentId = rule.to.did;
26
+ } else {
27
+ rule.to.componentId = `${rule.to.did}/${rule.to.realDid}`;
28
+ }
29
+
30
+ delete rule.to.realDid;
31
+ delete rule.to.realInterfaceName;
32
+
33
+ changed = true;
34
+ }
35
+
36
+ if (changed) {
37
+ await states.site.update({ _id: site._id }, site);
38
+ printInfo(`site ${site.domain} has been updated`);
39
+ }
40
+ }
41
+ };
@@ -0,0 +1,20 @@
1
+ /* eslint-disable no-await-in-loop */
2
+ /* eslint-disable no-continue */
3
+
4
+ const { BLOCKLET_MAX_MEM_LIMIT_IN_MB } = require('@abtnode/constant');
5
+
6
+ module.exports = async ({ states, printInfo }) => {
7
+ printInfo('Try to update blockletMaxMemoryLimit...');
8
+
9
+ const info = await states.node.read();
10
+ if (
11
+ info?.runtimeConfig?.blockletMaxMemoryLimit &&
12
+ info.runtimeConfig.blockletMaxMemoryLimit < BLOCKLET_MAX_MEM_LIMIT_IN_MB
13
+ ) {
14
+ info.runtimeConfig.blockletMaxMemoryLimit = BLOCKLET_MAX_MEM_LIMIT_IN_MB;
15
+ await states.node.updateNodeInfo(info);
16
+ printInfo(`Update blockletMaxMemoryLimit to ${BLOCKLET_MAX_MEM_LIMIT_IN_MB}MB`);
17
+ } else {
18
+ printInfo(`No need to update blockletMaxMemoryLimit (${info?.runtimeConfig?.blockletMaxMemoryLimit}MB)`);
19
+ }
20
+ };
@@ -41,7 +41,7 @@ module.exports = async ({ states, config, configFile, printInfo }) => {
41
41
  printInfo('Try to update node config to 1.0.21...');
42
42
  let changed = false;
43
43
 
44
- const rawConfig = yaml.safeLoad(fs.readFileSync(configFile).toString());
44
+ const rawConfig = yaml.load(fs.readFileSync(configFile).toString());
45
45
  const info = await states.node.read();
46
46
 
47
47
  const updates = [
@@ -132,9 +132,13 @@ const runMigrationScripts = async ({
132
132
  for (let i = 0; i < scripts.length; i++) {
133
133
  const { script, version } = scripts[i];
134
134
  try {
135
- const executed = await node.isMigrationExecuted({ script, version });
136
- if (executed === false) {
135
+ if (process.env.NODE_ENV === 'development') {
137
136
  pending.push(scripts[i]);
137
+ } else {
138
+ const executed = await node.isMigrationExecuted({ script, version });
139
+ if (executed === false) {
140
+ pending.push(scripts[i]);
141
+ }
138
142
  }
139
143
  } catch (err) {
140
144
  printError(`Failed to detect migration script execution status: ${script}, error: ${err.message}`);
@@ -0,0 +1,200 @@
1
+ const EventEmitter = require('events');
2
+
3
+ const cloneDeep = require('lodash/cloneDeep');
4
+ const pLimit = require('p-limit');
5
+ const { forEachBlocklet } = require('@blocklet/meta/lib/util');
6
+ const getComponentProcessId = require('@blocklet/meta/lib/get-component-process-id');
7
+ const { EVENTS } = require('@abtnode/constant');
8
+ const { BlockletStatus, BlockletGroup } = require('@blocklet/constant');
9
+ const defaultLogger = require('@abtnode/logger')('blocklet-runtime-monitor');
10
+
11
+ const { getRuntimeInfo } = require('../util/blocklet');
12
+
13
+ // type BlockletHistoryItem = {
14
+ // date: number;
15
+ // cpu: number;
16
+ // mem: number;
17
+ // };
18
+
19
+ // type History = Array<BlockletHistoryItem>;
20
+
21
+ // type RuntimeInfo = {
22
+ // pid: number;
23
+ // uptime: number;
24
+ // memoryUsage: number;
25
+ // cpuUsage: number;
26
+ // status: string;
27
+ // };
28
+
29
+ // type ComponentMonitorData = {
30
+ // runtimeInfo: RuntimeInfo;
31
+ // }
32
+
33
+ // type AppMonitorData = ComponentMonitorData & {
34
+ // history: History;
35
+ // }
36
+
37
+ // type BlockletMonitorData = {
38
+ // app: AppMonitorData;
39
+ // [componentId: string]: ComponentMonitorData;
40
+ // }
41
+
42
+ // type MonitorData = {
43
+ // [blockletDid: string]: BlockletMonitorData;
44
+ // }
45
+
46
+ class BlockletRuntimeMonitor extends EventEmitter {
47
+ constructor({ historyLength = 100, states, logger = defaultLogger } = {}) {
48
+ super();
49
+
50
+ /**
51
+ * private
52
+ */
53
+ this.historyLength = historyLength;
54
+ this.states = states;
55
+ this.data = {};
56
+ this.logger = logger;
57
+ this.inProgress = false;
58
+ }
59
+
60
+ getHistory(blockletDid) {
61
+ if (!this.data[blockletDid]) {
62
+ return [];
63
+ }
64
+
65
+ return this.data[blockletDid].app.history || [];
66
+ }
67
+
68
+ getRuntimeInfo(blockletDid, componentId = 'app') {
69
+ if (!this.data[blockletDid]) {
70
+ return null;
71
+ }
72
+
73
+ if (!this.data[blockletDid][componentId]) {
74
+ return null;
75
+ }
76
+
77
+ return this.data[blockletDid][componentId].runtimeInfo;
78
+ }
79
+
80
+ async monit(did) {
81
+ const blocklet = await this.states.blocklet.getBlocklet(did);
82
+ await this._monit(blocklet);
83
+ }
84
+
85
+ async _monit(blocklet, { addToHistory } = {}) {
86
+ const {
87
+ meta: { did: blockletDid },
88
+ status,
89
+ } = blocklet;
90
+
91
+ if (status !== BlockletStatus.running) {
92
+ if (this.data[blockletDid]) {
93
+ Object.keys(this.data[blockletDid]).forEach((key) => {
94
+ delete this.data[blockletDid][key].runtimeInfo;
95
+ });
96
+ }
97
+ return;
98
+ }
99
+
100
+ this.data[blockletDid] = this.data[blockletDid] || {
101
+ app: {
102
+ runtimeInfo: {
103
+ memoryUsage: 0,
104
+ cpuUsage: 0,
105
+ pid: -1,
106
+ uptime: 0,
107
+ status: '',
108
+ },
109
+ history: [],
110
+ },
111
+ };
112
+
113
+ let appCpu = 0;
114
+ let appMem = 0;
115
+
116
+ await forEachBlocklet(
117
+ blocklet,
118
+ async (component, { id: componentId, ancestors }) => {
119
+ if (component.meta.group !== BlockletGroup.gateway) {
120
+ const processId = getComponentProcessId(component, ancestors);
121
+ try {
122
+ const runtimeInfo = await getRuntimeInfo(processId);
123
+
124
+ this.data[blockletDid][componentId] = { runtimeInfo };
125
+
126
+ if (!component.mountPoint || component.mountPoint === '/') {
127
+ this.data[blockletDid].app.runtimeInfo = cloneDeep(runtimeInfo);
128
+ }
129
+
130
+ appCpu += runtimeInfo.cpuUsage || 0;
131
+ appMem += runtimeInfo.memoryUsage || 0;
132
+ } catch (err) {
133
+ this.logger.error('failed to get blocklet runtime info', { processId, error: err });
134
+ }
135
+ }
136
+ },
137
+ { parallel: true }
138
+ );
139
+
140
+ this.data[blockletDid].app.runtimeInfo.cpuUsage = appCpu;
141
+ this.data[blockletDid].app.runtimeInfo.memoryUsage = appMem;
142
+
143
+ // push to history
144
+ if (addToHistory) {
145
+ this._push(blockletDid, { date: Date.now(), cpu: appCpu, mem: appMem });
146
+ }
147
+ }
148
+
149
+ async monitAll() {
150
+ if (this.inProgress) {
151
+ this.logger.error('monitoring is in progress');
152
+ return;
153
+ }
154
+
155
+ this.inProgress = true;
156
+
157
+ try {
158
+ const blocklets = await this.states.blocklet.getBlocklets();
159
+
160
+ const limit = pLimit(5);
161
+ await Promise.allSettled(
162
+ blocklets.map((blocklet) =>
163
+ limit(async () => {
164
+ await this._monit(blocklet, { addToHistory: true });
165
+ })
166
+ )
167
+ );
168
+
169
+ this.inProgress = false;
170
+
171
+ // emit event
172
+ const eventData = [];
173
+ Object.entries(this.data).forEach(([did, x]) => {
174
+ Object.entries(x).forEach(([componentId, { runtimeInfo }]) => {
175
+ if (componentId !== 'app') {
176
+ eventData.push({ did, componentId, runtimeInfo });
177
+ }
178
+ });
179
+ });
180
+ this.emit(EVENTS.BLOCKLETS_RUNTIME_INFO, eventData);
181
+ } catch (error) {
182
+ this.inProgress = false;
183
+ this.logger.error('monit blocklet runtime failed', { error });
184
+ }
185
+ }
186
+
187
+ delete(blockletDid) {
188
+ delete this.data[blockletDid];
189
+ }
190
+
191
+ _push(blockletDid, value) {
192
+ const arr = this.data[blockletDid].app.history;
193
+ arr.push(value);
194
+ if (arr.length > this.historyLength) {
195
+ arr.shift();
196
+ }
197
+ }
198
+ }
199
+
200
+ module.exports.BlockletRuntimeMonitor = BlockletRuntimeMonitor;
@@ -0,0 +1,37 @@
1
+ const maxBy = require('lodash/maxBy');
2
+
3
+ const getHistoryList = ({ history, hours, recordIntervalSec, props = [] }) => {
4
+ if (hours < 1 || hours > 24) {
5
+ throw new Error('hours should between 1 to 24');
6
+ }
7
+ const intHours = Math.floor(hours);
8
+
9
+ const nPerHour = (60 / recordIntervalSec) * 60;
10
+ const n = nPerHour * intHours;
11
+ const list = history.slice(-n);
12
+
13
+ let i = list.length;
14
+
15
+ const res = [];
16
+
17
+ while (i > 0 && res.length < nPerHour) {
18
+ const arr = list.slice(Math.max(0, i - intHours), i);
19
+
20
+ // 取一段时间的最大值
21
+ if (props && props.length) {
22
+ const obj = {};
23
+ props.forEach((p) => {
24
+ obj[p] = (maxBy(arr, (x) => x[p]) || {})[p];
25
+ });
26
+ res.unshift(obj);
27
+ } else {
28
+ res.unshift(Math.max(...arr));
29
+ }
30
+
31
+ i -= intHours;
32
+ }
33
+
34
+ return res;
35
+ };
36
+
37
+ module.exports = getHistoryList;