@abtnode/core 1.15.17 → 1.16.0-beta-8ee536d7

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 +1680 -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 +576 -500
  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 +195 -138
  70. package/lib/states/blocklet.js +371 -110
  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,51 @@
1
+ const { removeSync, existsSync, move, createReadStream } = require('fs-extra');
2
+ const hasha = require('hasha');
3
+
4
+ /**
5
+ *
6
+ *
7
+ * @param {NodeJS.ReadableStream} stream1
8
+ * @param {NodeJS.ReadableStream} stream2
9
+ * @return {Promise<boolean>}
10
+ */
11
+ async function compareHash(stream1, stream2) {
12
+ const hash1 = await hasha.fromStream(stream1, {
13
+ algorithm: 'md5',
14
+ });
15
+ const hash2 = await hasha.fromStream(stream2, {
16
+ algorithm: 'md5',
17
+ });
18
+
19
+ return hash1 === hash2;
20
+ }
21
+
22
+ /**
23
+ *
24
+ * @description 比对新文件和旧文件的hash,旧文件不存在或者hash不同时,使用新文件替换,hash相同,删除新文件
25
+ * @param {string} oldFilePath
26
+ * @param {string} newFilePath
27
+ * @returns {Promise<boolean>}
28
+ */
29
+ async function compareAndMove(oldFilePath, newFilePath) {
30
+ if (!existsSync(oldFilePath)) {
31
+ await move(newFilePath, oldFilePath, { overwrite: true });
32
+ return;
33
+ }
34
+
35
+ if (!existsSync(newFilePath)) {
36
+ throw new Error(`newFilePath(${newFilePath}) not found`);
37
+ }
38
+
39
+ const isSame = await compareHash(createReadStream(oldFilePath), createReadStream(newFilePath));
40
+ if (isSame) {
41
+ removeSync(newFilePath);
42
+ return;
43
+ }
44
+
45
+ await move(newFilePath, oldFilePath, { overwrite: true });
46
+ }
47
+
48
+ module.exports = {
49
+ compareHash,
50
+ compareAndMove,
51
+ };
@@ -0,0 +1,43 @@
1
+ const archiver = require('archiver');
2
+ const { ensureDirSync, existsSync, removeSync, createWriteStream } = require('fs-extra');
3
+ const { dirname } = require('path');
4
+ const StreamZip = require('node-stream-zip');
5
+
6
+ /**
7
+ *
8
+ *
9
+ * @param {string} source ~/abc/ 通常是一个文件夹
10
+ * @param {string} target abc.zip 压缩包的名称
11
+ * @return {*}
12
+ */
13
+ function dirToZip(source, target) {
14
+ return new Promise((resolve, reject) => {
15
+ ensureDirSync(dirname(target));
16
+
17
+ if (existsSync(target)) {
18
+ removeSync(target);
19
+ }
20
+
21
+ const output = createWriteStream(target);
22
+ const archive = archiver('zip', { level: 9 });
23
+ archive.on('error', (err) => reject(err));
24
+ output.on('close', () => resolve());
25
+
26
+ archive.directory(source, false);
27
+
28
+ archive.pipe(output);
29
+ archive.finalize();
30
+ });
31
+ }
32
+
33
+ async function zipToDir(source, target) {
34
+ // eslint-disable-next-line new-cap
35
+ const zip = new StreamZip.async({ file: source });
36
+ await zip.extract(null, target);
37
+ await zip.close();
38
+ }
39
+
40
+ module.exports = {
41
+ dirToZip,
42
+ zipToDir,
43
+ };
package/lib/cert.js ADDED
@@ -0,0 +1,206 @@
1
+ const { EventEmitter } = require('events');
2
+ const CertificateManager = require('@abtnode/certificate-manager/sdk/manager');
3
+ const logger = require('@abtnode/logger')('@abtnode/core:cert');
4
+ const { EVENTS } = require('@abtnode/constant');
5
+ const { BlockletEvents } = require('@blocklet/constant');
6
+
7
+ const onCertExpired = async (cert, states) => {
8
+ logger.info('send certificate expire notification', { domain: cert.domain });
9
+ states.notification.create({
10
+ title: 'SSL Certificate Expired',
11
+ description: `Your SSL certificate for domain ${cert.domain} has expired, please update it in Blocklet Server`,
12
+ severity: 'error',
13
+ entityType: 'certificate',
14
+ entityId: cert.id,
15
+ });
16
+ };
17
+
18
+ const onCertAboutExpire = (cert, states) => {
19
+ logger.info('send certificate about-expire notification', { domain: cert.domain });
20
+ states.notification.create({
21
+ title: 'SSL Certificate Expire Warning',
22
+ description: `Your SSL certificate for domain ${cert.domain} will expire in ${
23
+ cert.expireInDays
24
+ } days (on ${new Date(cert.validTo).toLocaleString()}), please remember to update it in Blocklet Server`,
25
+ severity: 'warning',
26
+ entityType: 'certificate',
27
+ entityId: cert.id, // eslint-disable-line no-underscore-dangle
28
+ });
29
+ };
30
+
31
+ const onCertIssued = (cert, states) => {
32
+ states.notification.create({
33
+ title: 'Certificate Issued',
34
+ description: `The ${cert.domain} certificate is issued successfully`,
35
+ severity: 'success',
36
+ entityType: 'certificate',
37
+ entityId: cert.id,
38
+ });
39
+ };
40
+
41
+ const onCertIssueFailed = (cert, states) => {
42
+ states.notification.create({
43
+ title: 'Certificate Issue Failed',
44
+ description: `Failed to issue certificate for ${cert.domain}`,
45
+ severity: 'error',
46
+ entityType: 'certificate',
47
+ entityId: cert.id,
48
+ });
49
+ };
50
+
51
+ const getDomainFromInput = (input) => {
52
+ if (Object.prototype.toString.call(input) === '[object Object]') {
53
+ return input.domain;
54
+ }
55
+
56
+ return input;
57
+ };
58
+
59
+ class Cert extends EventEmitter {
60
+ constructor({ maintainerEmail, dataDir, states }) {
61
+ super();
62
+
63
+ this.manager = new CertificateManager({ maintainerEmail, dataDir });
64
+
65
+ this.manager.on('cert.issued', this._onCertIssued.bind(this));
66
+ this.manager.on('cert.expired', this._onCertExpired.bind(this));
67
+ this.manager.on('cert.about_to_expire', this._onCertAboutToExpire.bind(this));
68
+ this.manager.on('cert.error', this._onCertError.bind(this));
69
+
70
+ /**
71
+ * Array<{domain: string, did: string}>
72
+ */
73
+ this._blockletDomains = [];
74
+ this.states = states;
75
+ }
76
+
77
+ start() {
78
+ return this.manager.start();
79
+ }
80
+
81
+ static fixCertificate(entity) {
82
+ // Hack: this logic exists because gql does not allow line breaks in arg values
83
+ entity.privateKey = entity.privateKey.split('|').join('\n');
84
+ entity.certificate = entity.certificate.split('|').join('\n');
85
+ }
86
+
87
+ getAll() {
88
+ return this.manager.getAll();
89
+ }
90
+
91
+ getAllNormal() {
92
+ return this.manager.getAllNormal();
93
+ }
94
+
95
+ getNormalByDomain(domain) {
96
+ return this.manager.getNormalByDomain(domain);
97
+ }
98
+
99
+ getByDomain(inputDomain) {
100
+ const domain = getDomainFromInput(inputDomain);
101
+ return this.manager.getByDomain(domain);
102
+ }
103
+
104
+ async add(data) {
105
+ if (!data.certificate || !data.privateKey) {
106
+ throw new Error('certificate and privateKey are required');
107
+ }
108
+
109
+ Cert.fixCertificate(data);
110
+
111
+ const result = await this.manager.add(data);
112
+ logger.info('add certificate result', { name: result.name });
113
+ this.emit(EVENTS.CERT_ADDED, result);
114
+
115
+ return result;
116
+ }
117
+
118
+ /**
119
+ * @param {{
120
+ * did?:string // blocklet.meta.did
121
+ * }}
122
+ */
123
+ async issue({ domain, did }) {
124
+ logger.info(`generate certificate for ${domain}`);
125
+
126
+ if (did) {
127
+ this._bindBlocklet({ domain, did });
128
+ }
129
+
130
+ return this.manager.issue(domain);
131
+ }
132
+
133
+ async upsertByDomain(data) {
134
+ const result = await this.manager.upsertByDomain(data);
135
+ this.emit(EVENTS.CERT_UPDATED, result);
136
+
137
+ return result;
138
+ }
139
+
140
+ async update(data) {
141
+ return this.manager.update(data.id, { name: data.name, public: data.public });
142
+ }
143
+
144
+ async remove({ id }) {
145
+ await this.manager.remove(id);
146
+ logger.info('delete certificate', { id });
147
+ this.emit(EVENTS.CERT_REMOVED);
148
+
149
+ return {};
150
+ }
151
+
152
+ async addWithoutValidations(data) {
153
+ return this.manager.addWithoutValidations(data);
154
+ }
155
+
156
+ async updateWithoutValidations(id, data) {
157
+ return this.manager.updateWithoutValidations(id, data);
158
+ }
159
+
160
+ _bindBlocklet({ domain, did }) {
161
+ // only save 100 domains in memory
162
+ const list = this._blockletDomains.slice(-100).filter((x) => x.domain !== domain);
163
+ list.push({ domain, did });
164
+ this._blockletDomains = list;
165
+ }
166
+
167
+ /**
168
+ * @param {{
169
+ * blocklet: string;
170
+ * server: string;
171
+ * }} event
172
+ * @param {{
173
+ * domain: string
174
+ * }} cert
175
+ */
176
+ _emitEvent(event, cert) {
177
+ const blockletDomain = this._blockletDomains.find((x) => x.domain === cert.domain);
178
+ if (blockletDomain) {
179
+ this.emit(event.blocklet, { ...cert, meta: { did: blockletDomain.did } });
180
+ } else {
181
+ this.emit(event.server, cert);
182
+ }
183
+ }
184
+
185
+ _onCertIssued(cert) {
186
+ this._emitEvent({ blocklet: BlockletEvents.certIssued, server: EVENTS.CERT_ISSUED }, cert);
187
+
188
+ onCertIssued(cert, this.states);
189
+ }
190
+
191
+ _onCertError(cert) {
192
+ this._emitEvent({ blocklet: BlockletEvents.certError, server: EVENTS.CERT_ERROR }, cert);
193
+
194
+ onCertIssueFailed(cert, this.states);
195
+ }
196
+
197
+ _onCertExpired(cert) {
198
+ onCertExpired(cert, this.states);
199
+ }
200
+
201
+ _onCertAboutToExpire(cert) {
202
+ onCertAboutExpire(cert, this.states);
203
+ }
204
+ }
205
+
206
+ module.exports = Cert;
package/lib/event.js CHANGED
@@ -1,20 +1,23 @@
1
+ const get = require('lodash/get');
2
+ const cloneDeep = require('lodash/cloneDeep');
1
3
  const { EventEmitter } = require('events');
2
- const { BLOCKLET_MODES } = require('@blocklet/meta/lib/constants');
4
+ const { wipeSensitiveData } = require('@blocklet/meta/lib/util');
3
5
  const logger = require('@abtnode/logger')('@abtnode/core:event');
4
- const { BlockletStatus, BlockletSource, BlockletEvents } = require('@blocklet/meta/lib/constants');
6
+ const { BLOCKLET_MODES, BlockletStatus, BlockletSource, BlockletEvents } = require('@blocklet/constant');
7
+ const { EVENTS } = require('@abtnode/constant');
8
+ const handleInstanceInStore = require('./util/public-to-store');
5
9
 
6
10
  const eventHub =
7
11
  process.env.NODE_ENV === 'test' ? require('@arcblock/event-hub/single') : require('@arcblock/event-hub');
8
12
 
9
- const { isCLI } = require('./util');
10
13
  const states = require('./states');
14
+ const { isBeforeInstalled } = require('./util');
11
15
 
12
16
  const routingSnapshotPrefix = (blocklet) => (blocklet.mode === BLOCKLET_MODES.DEVELOPMENT ? '[DEV] ' : '');
13
17
 
14
18
  // Initialize the event queue: this will make events across process
15
19
  module.exports = ({
16
20
  blockletManager,
17
- blockletRegistry,
18
21
  ensureBlockletRouting,
19
22
  ensureBlockletRoutingForUpgrade,
20
23
  removeBlockletRouting,
@@ -22,34 +25,63 @@ module.exports = ({
22
25
  handleRouting,
23
26
  domainStatus,
24
27
  teamAPI,
28
+ teamManager,
29
+ certManager,
30
+ routerManager,
31
+ node,
32
+ nodeRuntimeMonitor,
25
33
  }) => {
26
34
  const notificationState = states.notification;
27
35
  const nodeState = states.node;
28
36
 
29
37
  const events = new EventEmitter();
30
- // HACK: do not emit any events from CLI
31
- if (isCLI() && process.env.NODE_ENV !== 'test') {
32
- events.emit = (name) => logger.debug('stopped core state event in CLI', name);
33
- }
34
-
35
- // Push events to event hub for other process to consume
36
- const originEmit = events.emit.bind(events);
37
- events.emit = (name, ...args) => {
38
- logger.debug('proxy event to event hub', { name });
39
- eventHub.broadcast(name, ...args);
40
- originEmit(name, ...args);
41
- };
38
+ events.setMaxListeners(0);
42
39
 
43
40
  let eventHandler = null;
41
+ events.setEventHandler = (handler) => {
42
+ if (typeof handler === 'function') {
43
+ eventHandler = handler;
44
+ }
45
+ };
46
+
47
+ // Listen events from eventHub and call eventHandler
48
+ [...Object.values(BlockletEvents), ...Object.values(EVENTS)].forEach((name) => {
49
+ eventHub.on(name, (data) => {
50
+ if (name === BlockletEvents.removed) {
51
+ // Cleanup cache in teamManager for every node instance
52
+ teamManager.deleteTeam(data?.meta?.did, { closeDatabase: false });
53
+ }
44
54
 
55
+ if (typeof eventHandler === 'function') {
56
+ eventHandler({ name, data });
57
+ }
58
+ });
59
+ });
60
+
61
+ // Wipe sensitive data
62
+ // Emit events to event hub
63
+ // Emit events to node listener
45
64
  const onEvent = (name, data) => {
65
+ let safeData = data;
66
+ if (get(data, 'meta.did', '')) {
67
+ safeData = wipeSensitiveData(cloneDeep(data));
68
+ }
69
+
70
+ logger.debug('proxy event to event hub', { name });
71
+ eventHub.broadcast(name, safeData);
72
+ events.emit(name, safeData);
73
+ };
74
+
75
+ // Emit events to node listener
76
+ // Call eventHandler
77
+ const onInternalEvent = (name, data) => {
46
78
  events.emit(name, data);
47
79
  if (typeof eventHandler === 'function') {
48
80
  eventHandler({ name, data });
49
81
  }
50
82
  };
51
83
 
52
- const handleBlockletAdd = async (name, { blocklet, context }) => {
84
+ const handleBlockletInstall = async (name, { blocklet, context }) => {
53
85
  try {
54
86
  const changed = await ensureBlockletRouting(blocklet, context);
55
87
  if (changed) {
@@ -72,11 +104,13 @@ module.exports = ({
72
104
  severity: 'error',
73
105
  });
74
106
  }
75
-
76
- onEvent(name, blocklet);
77
107
  };
78
108
 
79
109
  const handleBlockletRemove = async (name, { blocklet, context }) => {
110
+ if (context?.skipAll) {
111
+ return;
112
+ }
113
+
80
114
  try {
81
115
  const changed = await removeBlockletRouting(blocklet, context);
82
116
 
@@ -96,8 +130,6 @@ module.exports = ({
96
130
  } catch (error) {
97
131
  logger.error('prune blocklet app folder error', { event: name, error });
98
132
  }
99
-
100
- onEvent(name, blocklet);
101
133
  };
102
134
 
103
135
  const handleBlockletUpgrade = async (name, { blocklet, context }) => {
@@ -114,6 +146,14 @@ module.exports = ({
114
146
  await teamAPI.refreshBlockletInterfacePermissions(blocklet.meta);
115
147
  } catch (error) {
116
148
  logger.error('upgrade blocklet routing rules error', { event: name, error });
149
+ notificationState.create({
150
+ title: 'Blocklet URL Mapping Error',
151
+ // eslint-disable-next-line max-len
152
+ description: `Failed to upgrade URL mapping for blocklet ${blocklet.meta.name}@${blocklet.meta.version}, due to: ${error.message}`,
153
+ entityType: 'blocklet',
154
+ entityId: blocklet.meta.did,
155
+ severity: 'error',
156
+ });
117
157
  }
118
158
 
119
159
  try {
@@ -121,11 +161,9 @@ module.exports = ({
121
161
  } catch (error) {
122
162
  logger.error('prune blocklet app folder error', { event: name, error });
123
163
  }
124
-
125
- onEvent(name, blocklet);
126
164
  };
127
165
 
128
- const handleCLIEvent = (eventName) => {
166
+ const handleServerEvent = (eventName) => {
129
167
  const [, status] = eventName.split('.');
130
168
  onEvent(eventName, {
131
169
  title: `Blocklet Server ${status}`,
@@ -135,6 +173,108 @@ module.exports = ({
135
173
  });
136
174
  };
137
175
 
176
+ /**
177
+ *
178
+ * @description 事件必须注册在这里才能被发布出去
179
+ * @param {string} eventName
180
+ * @param {any} payload
181
+ */
182
+ const handleBlockletEvent = async (eventName, payload) => {
183
+ const blocklet = payload.blocklet || payload;
184
+
185
+ if ([BlockletEvents.installed].includes(eventName)) {
186
+ await handleBlockletInstall(eventName, payload);
187
+
188
+ try {
189
+ await node.createAuditLog({
190
+ action: 'installBlocklet',
191
+ args: {
192
+ did: blocklet.meta.did,
193
+ },
194
+ context: payload.context || {},
195
+ result: blocklet,
196
+ });
197
+ } catch (error) {
198
+ logger.error('Failed to createAuditLog for installBlocklet', { error });
199
+ }
200
+ } else if ([BlockletEvents.upgraded, BlockletEvents.downgraded].includes(eventName)) {
201
+ await handleBlockletUpgrade(eventName, payload);
202
+
203
+ if (payload?.context?.createAuditLog !== false) {
204
+ try {
205
+ await node.createAuditLog({
206
+ action: 'upgradeBlocklet',
207
+ args: {
208
+ did: blocklet.meta.did,
209
+ },
210
+ context: payload.context || {},
211
+ result: blocklet,
212
+ });
213
+ } catch (error) {
214
+ logger.error('Failed to createAuditLog for upgradeBlocklet', { error });
215
+ }
216
+ }
217
+ } else if ([BlockletEvents.removed, BlockletEvents.dataCleaned].includes(eventName)) {
218
+ await handleBlockletRemove(eventName, payload);
219
+ } else if ([BlockletEvents.started].includes(eventName)) {
220
+ const { publicToStore } = blocklet.settings || {};
221
+ if (publicToStore) {
222
+ handleInstanceInStore(blocklet, { publicToStore }).catch((error) => {
223
+ logger.error('handleInstanceInStore failed', { message: error.message });
224
+ });
225
+ }
226
+ } else if ([BlockletEvents.upgradeFailed, BlockletEvents.downgradeFailed].includes(eventName)) {
227
+ try {
228
+ await node.createAuditLog({
229
+ action: 'upgradeBlocklet',
230
+ args: {
231
+ did: blocklet.meta.did,
232
+ },
233
+ context: payload.context || {},
234
+ result: {
235
+ ...blocklet,
236
+ resultStatus: 'failed',
237
+ },
238
+ });
239
+ } catch (error) {
240
+ logger.error('Failed to createAuditLog for upgradeBlocklet failed', { error });
241
+ }
242
+ } else if (BlockletEvents.appDidChanged === eventName) {
243
+ const hash = await takeRoutingSnapshot(
244
+ { message: `${routingSnapshotPrefix(blocklet)}Update blocklet ${blocklet.meta.name} app did`, dryRun: false },
245
+ get(payload, 'context') || {}
246
+ );
247
+
248
+ logger.info('take snapshot after updated blocklet app', { event: eventName, did: blocklet.meta.did, hash });
249
+ } else if (BlockletEvents.spaceConnected === eventName) {
250
+ nodeState
251
+ .read()
252
+ .then((info) => handleRouting(info))
253
+ .catch((err) => {
254
+ logger.error('Reload gateway failed on blocklet.connectedSpace', { error: err });
255
+ });
256
+ logger.info('Reload gateway after blocklet connected to space', { event: eventName, did: blocklet.appDid });
257
+ }
258
+
259
+ if (
260
+ ![BlockletEvents.removed, BlockletEvents.dataCleaned].includes(eventName) &&
261
+ blocklet.status &&
262
+ !isBeforeInstalled(blocklet.status)
263
+ ) {
264
+ try {
265
+ await blockletManager.runtimeMonitor.monit(blocklet.meta.did);
266
+ } catch (error) {
267
+ logger.error('monit runtime info failed', { eventName, error });
268
+ }
269
+ }
270
+
271
+ if (payload.blocklet && !payload.meta) {
272
+ onEvent(eventName, payload.blocklet);
273
+ } else {
274
+ onEvent(eventName, payload);
275
+ }
276
+ };
277
+
138
278
  const downloadAddedBlocklet = async () => {
139
279
  try {
140
280
  const blocklets = await states.blocklet.find({
@@ -151,31 +291,50 @@ module.exports = ({
151
291
  }
152
292
  };
153
293
 
154
- blockletManager.on(BlockletEvents.statusChange, (data) => onEvent(BlockletEvents.statusChange, data));
155
- blockletManager.on(BlockletEvents.added, (data) => onEvent(BlockletEvents.added, data));
156
- blockletManager.on(BlockletEvents.installed, (data) => handleBlockletAdd(BlockletEvents.installed, data));
157
- blockletManager.on(BlockletEvents.installFailed, (data) => onEvent(BlockletEvents.installFailed, data));
158
- blockletManager.on(BlockletEvents.deployed, (data) => handleBlockletAdd(BlockletEvents.deployed, data));
159
- blockletManager.on(BlockletEvents.started, (data) => onEvent(BlockletEvents.started, data));
160
- blockletManager.on(BlockletEvents.startFailed, (data) => onEvent(BlockletEvents.startFailed, data));
161
- blockletManager.on(BlockletEvents.reloaded, (data) => onEvent(BlockletEvents.reloaded, data));
162
- blockletManager.on(BlockletEvents.updated, (data) => onEvent(BlockletEvents.updated, data));
163
- blockletManager.on(BlockletEvents.downloadFailed, (data) => onEvent(BlockletEvents.downloadFailed, data));
164
- blockletManager.on(BlockletEvents.upgraded, (data) => handleBlockletUpgrade(BlockletEvents.upgraded, data));
165
- blockletManager.on(BlockletEvents.downgraded, (data) => handleBlockletUpgrade(BlockletEvents.downgraded, data));
166
- blockletManager.on(BlockletEvents.removed, (data) => handleBlockletRemove(BlockletEvents.removed, data));
167
- notificationState.on('notification.create', (data) => onEvent('notification.create', data));
168
- nodeState.on(BlockletEvents.purchaseChange, (data) => onEvent(BlockletEvents.purchaseChange, data));
169
- nodeState.on('routing.updated', (nodeInfo) => onEvent('routing.updated', { routing: nodeInfo.routing }));
170
- nodeState.once('node.addedOwner', () => downloadAddedBlocklet());
171
- nodeState.on('node.updated', (nodeInfo, oldInfo) => {
172
- onEvent('node.updated', { did: nodeInfo.did });
173
- blockletRegistry
174
- .refreshBlocklets()
175
- .catch((error) => logger.error('refresh blocklets failed on initialize the registry', { error }));
294
+ /**
295
+ *
296
+ *
297
+ * @param {*} subject
298
+ * @param {string} event
299
+ * @param {(event: string, data: any) => Promise<void> | void} handler
300
+ */
301
+ const listen = (subject, event, handler) => subject.on(event, (data) => handler(event, data));
302
+
303
+ [
304
+ BlockletEvents.added,
305
+ BlockletEvents.downloadFailed,
306
+ BlockletEvents.installed,
307
+ BlockletEvents.installFailed,
308
+ BlockletEvents.upgraded,
309
+ BlockletEvents.upgradeFailed,
310
+ BlockletEvents.downgraded,
311
+ BlockletEvents.downgradeFailed,
312
+ BlockletEvents.updated,
313
+ BlockletEvents.statusChange,
314
+ BlockletEvents.removed,
315
+ BlockletEvents.started,
316
+ BlockletEvents.startFailed,
317
+ BlockletEvents.stopped,
318
+ BlockletEvents.appDidChanged,
319
+
320
+ BlockletEvents.backupProgress,
321
+ BlockletEvents.restoreProgress,
322
+
323
+ BlockletEvents.spaceConnected,
324
+ ].forEach((eventName) => {
325
+ listen(blockletManager, eventName, handleBlockletEvent);
326
+ });
327
+
328
+ listen(notificationState, EVENTS.NOTIFICATION_CREATE, onEvent);
329
+
330
+ listen(nodeState, BlockletEvents.purchaseChange, onEvent);
331
+ nodeState.on(EVENTS.ROUTING_UPDATED, (nodeInfo) => onEvent(EVENTS.ROUTING_UPDATED, { routing: nodeInfo.routing }));
332
+ nodeState.once(EVENTS.NODE_ADDED_OWNER, () => downloadAddedBlocklet());
333
+ nodeState.on(EVENTS.NODE_UPDATED, (nodeInfo, oldInfo) => {
334
+ onEvent(EVENTS.NODE_UPDATED, { did: nodeInfo.did });
176
335
 
177
336
  // We need update router on some fields change
178
- const fields = ['enableWelcomePage', 'webWalletUrl'];
337
+ const fields = ['enableWelcomePage', 'webWalletUrl', 'registerUrl'];
179
338
  const shouldUpdateRouter = fields.some((x) => nodeInfo[x] !== oldInfo[x]);
180
339
  if (shouldUpdateRouter) {
181
340
  handleRouting(nodeInfo).catch((err) => {
@@ -183,26 +342,40 @@ module.exports = ({
183
342
  });
184
343
  }
185
344
  });
186
- nodeState.on('node.upgrade.progress', (session) => onEvent('node.upgrade.progress', session));
187
- domainStatus.on('domain.status', (data) => {
188
- if (data) {
189
- onEvent('domain.status', data);
190
- }
345
+
346
+ listen(nodeState, EVENTS.NODE_MAINTAIN_PROGRESS, onEvent);
347
+ nodeState.on(EVENTS.RELOAD_GATEWAY, (nodeInfo) => {
348
+ handleRouting(nodeInfo).catch((err) => {
349
+ logger.error('Handle routing failed on node.updated', { error: err });
350
+ });
191
351
  });
192
- teamAPI.on('user.added', (data) => onEvent('user.added', data));
193
- teamAPI.on('user.removed', (data) => onEvent('user.removed', data));
194
- teamAPI.on('user.updated', (data) => onEvent('user.updated', data));
195
- teamAPI.on(BlockletEvents.updated, (data) => onEvent(BlockletEvents.updated, data));
196
352
 
197
- events.setEventHandler = (handler) => {
198
- if (typeof handler === 'function') {
199
- eventHandler = handler;
200
- }
201
- };
353
+ [EVENTS.DOMAIN_STATUS, BlockletEvents.domainStatus].forEach((eventName) => {
354
+ domainStatus.on(eventName, (data) => {
355
+ if (data) {
356
+ onEvent(eventName, data);
357
+ }
358
+ });
359
+ });
360
+
361
+ listen(teamAPI, EVENTS.USER_ADDED, onEvent);
362
+ listen(teamAPI, EVENTS.USER_REMOVED, onEvent);
363
+ listen(teamAPI, EVENTS.USER_UPDATED, onEvent);
364
+ listen(teamAPI, BlockletEvents.updated, onEvent);
365
+ listen(teamManager, BlockletEvents.storeChange, onEvent);
366
+
367
+ listen(certManager, EVENTS.CERT_ISSUED, onEvent);
368
+ listen(certManager, EVENTS.CERT_ERROR, onEvent);
369
+ listen(certManager, BlockletEvents.certIssued, onEvent);
370
+ listen(certManager, BlockletEvents.certError, onEvent);
371
+
372
+ listen(routerManager, BlockletEvents.updated, onEvent);
373
+
374
+ listen(nodeRuntimeMonitor, EVENTS.NODE_RUNTIME_INFO, onInternalEvent);
375
+ listen(blockletManager.runtimeMonitor, EVENTS.BLOCKLETS_RUNTIME_INFO, onInternalEvent);
202
376
 
203
- events.handleBlockletAdd = handleBlockletAdd;
204
- events.handleBlockletRemove = handleBlockletRemove;
205
- events.handleCLIEvent = handleCLIEvent;
377
+ events.handleServerEvent = handleServerEvent;
378
+ events.handleBlockletEvent = handleBlockletEvent;
206
379
 
207
380
  return events;
208
381
  };