@abtnode/core 1.6.27 → 1.6.28

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/team.js CHANGED
@@ -1,7 +1,7 @@
1
1
  const { EventEmitter } = require('events');
2
2
  const pick = require('lodash/pick');
3
3
  const logger = require('@abtnode/logger')('@abtnode/core:api:team');
4
- const { ROLES, genPermissionName } = require('@abtnode/constant');
4
+ const { ROLES, genPermissionName, EVENTS } = require('@abtnode/constant');
5
5
  const { isValid: isValidDid } = require('@arcblock/did');
6
6
  const { BlockletEvents } = require('@blocklet/meta/lib/constants');
7
7
  const { validateTrustedPassportIssuers } = require('../validators/trusted-passport');
@@ -62,7 +62,7 @@ class TeamAPI extends EventEmitter {
62
62
  });
63
63
  }
64
64
 
65
- this.emit('user.added', { teamDid, user: doc });
65
+ this.emit(EVENTS.USER_ADDED, { teamDid, user: doc });
66
66
 
67
67
  return doc;
68
68
  }
@@ -110,7 +110,7 @@ class TeamAPI extends EventEmitter {
110
110
  const doc = await state.update(user);
111
111
 
112
112
  logger.info('user updated successfully', { teamDid, userDid: user.did });
113
- this.emit('user.updated', { teamDid, user: doc });
113
+ this.emit(EVENTS.USER_UPDATED, { teamDid, user: doc });
114
114
 
115
115
  return doc;
116
116
  }
@@ -132,7 +132,7 @@ class TeamAPI extends EventEmitter {
132
132
 
133
133
  logger.info('user removed successfully', { teamDid, userDid: did });
134
134
 
135
- this.emit('user.removed', { teamDid, user: { did } });
135
+ this.emit(EVENTS.USER_REMOVED, { teamDid, user: { did } });
136
136
 
137
137
  return { did };
138
138
  }
@@ -153,7 +153,7 @@ class TeamAPI extends EventEmitter {
153
153
 
154
154
  logger.info('user approval updated successfully', { teamDid, userDid: user.did, approved: user.approved });
155
155
 
156
- this.emit('user.updated', { teamDid, user: doc2 });
156
+ this.emit(EVENTS.USER_UPDATED, { teamDid, user: doc2 });
157
157
 
158
158
  return doc2;
159
159
  }
@@ -172,7 +172,7 @@ class TeamAPI extends EventEmitter {
172
172
 
173
173
  logger.info('user role updated successfully', { teamDid, userDid: user.did, role: user.role });
174
174
 
175
- this.emit('user.updated', { teamDid, user: doc });
175
+ this.emit(EVENTS.USER_UPDATED, { teamDid, user: doc });
176
176
 
177
177
  return doc;
178
178
  }
@@ -188,7 +188,7 @@ class TeamAPI extends EventEmitter {
188
188
 
189
189
  logger.info('user passport revoked successfully', { teamDid, userDid, passportId });
190
190
 
191
- this.emit('user.updated', { teamDid, user: doc });
191
+ this.emit(EVENTS.USER_UPDATED, { teamDid, user: doc });
192
192
 
193
193
  return doc;
194
194
  }
@@ -204,7 +204,7 @@ class TeamAPI extends EventEmitter {
204
204
 
205
205
  logger.info('user passport enabled successfully', { teamDid, userDid, passportId });
206
206
 
207
- this.emit('user.updated', { teamDid, user: doc });
207
+ this.emit(EVENTS.USER_UPDATED, { teamDid, user: doc });
208
208
 
209
209
  return doc;
210
210
  }
@@ -1075,16 +1075,9 @@ class BlockletManager extends BaseBlockletManager {
1075
1075
  }
1076
1076
 
1077
1077
  async getBlockletInterfaces({ blocklet, nodeInfo, context }) {
1078
- const routingRules = (await this.getRoutingRulesByDid(blocklet.meta.did)).sort((a, b) => {
1079
- // Put user-defined rules first
1080
- if (a.isProtected !== b.isProtected) {
1081
- return a.isProtected ? 1 : -1;
1082
- }
1083
- // Put shorter url first
1084
- return a.from.pathPrefix.length < b.from.pathPrefix ? 1 : -1;
1085
- });
1078
+ const routingRules = await this.getRoutingRulesByDid(blocklet.meta.did);
1086
1079
  const nodeIp = await getAccessibleExternalNodeIp(nodeInfo);
1087
- return getBlockletInterfaces({ blocklet, context, nodeInfo, routingRules, nodeIp });
1080
+ return getBlockletInterfaces({ blocklet, context, routingRules, nodeIp });
1088
1081
  }
1089
1082
 
1090
1083
  async attachRuntimeInfo({ did, nodeInfo, diskInfo = true, context, cachedBlocklet }) {
@@ -1267,17 +1260,20 @@ class BlockletManager extends BaseBlockletManager {
1267
1260
  this.emit(BlockletEvents.statusChange, state);
1268
1261
 
1269
1262
  try {
1270
- await this._installBlocklet({
1263
+ const installedBlocklet = await this._installBlocklet({
1271
1264
  did,
1272
1265
  context,
1273
1266
  });
1274
1267
 
1275
1268
  if (context.startImmediately) {
1276
- try {
1277
- logger.info('start blocklet after installed', { did });
1278
- await this.start({ did, checkHealthImmediately: true });
1279
- } catch (error) {
1280
- logger.warn('attempt to start immediately failed', { did, error });
1269
+ const missingProps = getRequiredMissingConfigs(installedBlocklet);
1270
+ if (!missingProps.length) {
1271
+ try {
1272
+ logger.info('start blocklet after installed', { did });
1273
+ await this.start({ did, checkHealthImmediately: true });
1274
+ } catch (error) {
1275
+ logger.warn('attempt to start immediately failed', { did, error });
1276
+ }
1281
1277
  }
1282
1278
  }
1283
1279
  } catch (err) {
package/lib/event.js CHANGED
@@ -1,10 +1,10 @@
1
1
  const get = require('lodash/get');
2
2
  const cloneDeep = require('lodash/cloneDeep');
3
3
  const { EventEmitter } = require('events');
4
- const { BLOCKLET_MODES } = require('@blocklet/meta/lib/constants');
5
4
  const { wipeSensitiveData } = require('@blocklet/meta/lib/util');
6
5
  const logger = require('@abtnode/logger')('@abtnode/core:event');
7
- const { BlockletStatus, BlockletSource, BlockletEvents } = require('@blocklet/meta/lib/constants');
6
+ const { BLOCKLET_MODES, BlockletStatus, BlockletSource, BlockletEvents } = require('@blocklet/meta/lib/constants');
7
+ const { EVENTS } = require('@abtnode/constant');
8
8
 
9
9
  const eventHub =
10
10
  process.env.NODE_ENV === 'test' ? require('@arcblock/event-hub/single') : require('@arcblock/event-hub');
@@ -43,6 +43,15 @@ module.exports = ({
43
43
  originEmit(name, ...args);
44
44
  };
45
45
 
46
+ // Subscribe events from eventHub and proxy to eventHandler
47
+ [...Object.values(BlockletEvents), ...Object.values(EVENTS)].forEach((name) => {
48
+ eventHub.on(name, (data) => {
49
+ if (typeof eventHandler === 'function') {
50
+ eventHandler({ name, data });
51
+ }
52
+ });
53
+ });
54
+
46
55
  let eventHandler = null;
47
56
 
48
57
  const onEvent = (name, data) => {
@@ -51,9 +60,6 @@ module.exports = ({
51
60
  safeData = wipeSensitiveData(cloneDeep(data));
52
61
  }
53
62
  events.emit(name, safeData);
54
- if (typeof eventHandler === 'function') {
55
- eventHandler({ name, data: safeData });
56
- }
57
63
  };
58
64
 
59
65
  const handleBlockletAdd = async (name, { blocklet, context }) => {
@@ -79,8 +85,6 @@ module.exports = ({
79
85
  severity: 'error',
80
86
  });
81
87
  }
82
-
83
- onEvent(name, blocklet);
84
88
  };
85
89
 
86
90
  const handleBlockletRemove = async (name, { blocklet, context }) => {
@@ -103,8 +107,6 @@ module.exports = ({
103
107
  } catch (error) {
104
108
  logger.error('prune blocklet app folder error', { event: name, error });
105
109
  }
106
-
107
- onEvent(name, blocklet);
108
110
  };
109
111
 
110
112
  const handleBlockletUpgrade = async (name, { blocklet, context }) => {
@@ -128,8 +130,6 @@ module.exports = ({
128
130
  } catch (error) {
129
131
  logger.error('prune blocklet app folder error', { event: name, error });
130
132
  }
131
-
132
- onEvent(name, blocklet);
133
133
  };
134
134
 
135
135
  const handleServerEvent = (eventName) => {
@@ -142,6 +142,22 @@ module.exports = ({
142
142
  });
143
143
  };
144
144
 
145
+ const handleBlockletEvent = async (eventName, payload) => {
146
+ if ([BlockletEvents.deployed, BlockletEvents.installed].includes(eventName)) {
147
+ await handleBlockletAdd(eventName, payload);
148
+ } else if ([BlockletEvents.upgraded, BlockletEvents.downgraded].includes(eventName)) {
149
+ await handleBlockletUpgrade(eventName, payload);
150
+ } else if ([BlockletEvents.removed].includes(eventName)) {
151
+ await handleBlockletRemove(eventName, payload);
152
+ }
153
+
154
+ if (payload.blocklet && !payload.meta) {
155
+ onEvent(eventName, payload.blocklet);
156
+ } else {
157
+ onEvent(eventName, payload);
158
+ }
159
+ };
160
+
145
161
  const downloadAddedBlocklet = async () => {
146
162
  try {
147
163
  const blocklets = await states.blocklet.find({
@@ -158,25 +174,17 @@ module.exports = ({
158
174
  }
159
175
  };
160
176
 
161
- blockletManager.on(BlockletEvents.statusChange, (data) => onEvent(BlockletEvents.statusChange, data));
162
- blockletManager.on(BlockletEvents.added, (data) => onEvent(BlockletEvents.added, data));
163
- blockletManager.on(BlockletEvents.installed, (data) => handleBlockletAdd(BlockletEvents.installed, data));
164
- blockletManager.on(BlockletEvents.installFailed, (data) => onEvent(BlockletEvents.installFailed, data));
165
- blockletManager.on(BlockletEvents.deployed, (data) => handleBlockletAdd(BlockletEvents.deployed, data));
166
- blockletManager.on(BlockletEvents.started, (data) => onEvent(BlockletEvents.started, data));
167
- blockletManager.on(BlockletEvents.startFailed, (data) => onEvent(BlockletEvents.startFailed, data));
168
- blockletManager.on(BlockletEvents.reloaded, (data) => onEvent(BlockletEvents.reloaded, data));
169
- blockletManager.on(BlockletEvents.updated, (data) => onEvent(BlockletEvents.updated, data));
170
- blockletManager.on(BlockletEvents.downloadFailed, (data) => onEvent(BlockletEvents.downloadFailed, data));
171
- blockletManager.on(BlockletEvents.upgraded, (data) => handleBlockletUpgrade(BlockletEvents.upgraded, data));
172
- blockletManager.on(BlockletEvents.downgraded, (data) => handleBlockletUpgrade(BlockletEvents.downgraded, data));
173
- blockletManager.on(BlockletEvents.removed, (data) => handleBlockletRemove(BlockletEvents.removed, data));
174
- notificationState.on('notification.create', (data) => onEvent('notification.create', data));
177
+ Object.values(BlockletEvents).forEach((eventName) => {
178
+ blockletManager.on(eventName, (data) => handleBlockletEvent(eventName, data));
179
+ });
180
+
181
+ notificationState.on(EVENTS.NOTIFICATION_CREATE, (data) => onEvent(EVENTS.NOTIFICATION_CREATE, data));
182
+
175
183
  nodeState.on(BlockletEvents.purchaseChange, (data) => onEvent(BlockletEvents.purchaseChange, data));
176
- nodeState.on('routing.updated', (nodeInfo) => onEvent('routing.updated', { routing: nodeInfo.routing }));
177
- nodeState.once('node.addedOwner', () => downloadAddedBlocklet());
178
- nodeState.on('node.updated', (nodeInfo, oldInfo) => {
179
- onEvent('node.updated', { did: nodeInfo.did });
184
+ nodeState.on(EVENTS.ROUTING_UPDATED, (nodeInfo) => onEvent(EVENTS.ROUTING_UPDATED, { routing: nodeInfo.routing }));
185
+ nodeState.once(EVENTS.NODE_ADDED_OWNER, () => downloadAddedBlocklet());
186
+ nodeState.on(EVENTS.NODE_UPDATED, (nodeInfo, oldInfo) => {
187
+ onEvent(EVENTS.NODE_UPDATED, { did: nodeInfo.did });
180
188
  blockletRegistry
181
189
  .refreshBlocklets()
182
190
  .catch((error) => logger.error('refresh blocklets failed on initialize the registry', { error }));
@@ -190,15 +198,17 @@ module.exports = ({
190
198
  });
191
199
  }
192
200
  });
193
- nodeState.on('node.upgrade.progress', (session) => onEvent('node.upgrade.progress', session));
194
- domainStatus.on('domain.status', (data) => {
201
+ nodeState.on(EVENTS.NODE_UPGRADE_PROGRESS, (session) => onEvent(EVENTS.NODE_UPGRADE_PROGRESS, session));
202
+
203
+ domainStatus.on(EVENTS.DOMAIN_STATUS, (data) => {
195
204
  if (data) {
196
- onEvent('domain.status', data);
205
+ onEvent(EVENTS.DOMAIN_STATUS, data);
197
206
  }
198
207
  });
199
- teamAPI.on('user.added', (data) => onEvent('user.added', data));
200
- teamAPI.on('user.removed', (data) => onEvent('user.removed', data));
201
- teamAPI.on('user.updated', (data) => onEvent('user.updated', data));
208
+
209
+ teamAPI.on(EVENTS.USER_ADDED, (data) => onEvent(EVENTS.USER_ADDED, data));
210
+ teamAPI.on(EVENTS.USER_REMOVED, (data) => onEvent(EVENTS.USER_REMOVED, data));
211
+ teamAPI.on(EVENTS.USER_UPDATED, (data) => onEvent(EVENTS.USER_UPDATED, data));
202
212
  teamAPI.on(BlockletEvents.updated, (data) => onEvent(BlockletEvents.updated, data));
203
213
 
204
214
  events.setEventHandler = (handler) => {
@@ -207,11 +217,8 @@ module.exports = ({
207
217
  }
208
218
  };
209
219
 
210
- events.handleBlockletAdd = handleBlockletAdd;
211
- events.handleBlockletUpgrade = handleBlockletUpgrade;
212
- events.handleBlockletRemove = handleBlockletRemove;
213
220
  events.handleServerEvent = handleServerEvent;
214
- events.onEvent = onEvent;
221
+ events.handleBlockletEvent = handleBlockletEvent;
215
222
 
216
223
  return events;
217
224
  };
package/lib/index.js CHANGED
@@ -11,7 +11,7 @@ const {
11
11
  toBlockletSource,
12
12
  } = require('@blocklet/meta/lib/constants');
13
13
  const { listProviders } = require('@abtnode/router-provider');
14
- const { DEFAULT_CERTIFICATE_EMAIL } = require('@abtnode/constant');
14
+ const { DEFAULT_CERTIFICATE_EMAIL, EVENTS } = require('@abtnode/constant');
15
15
 
16
16
  const RoutingSnapshot = require('./states/routing-snapshot');
17
17
  const BlockletRegistry = require('./blocklet/registry');
@@ -408,14 +408,14 @@ function ABTNode(options) {
408
408
  initCron();
409
409
  } else {
410
410
  // We should only respond to pm2 events when node is alive
411
- events.on('node.started', async () => {
411
+ events.on(EVENTS.NODE_STARTED, async () => {
412
412
  pm2Events.resume();
413
413
  initCron();
414
414
  });
415
415
  }
416
416
  }
417
417
 
418
- events.on('node.stopped', () => {
418
+ events.on(EVENTS.NODE_STOPPED, () => {
419
419
  pm2Events.pause();
420
420
  });
421
421
 
@@ -16,7 +16,7 @@ const {
16
16
  DOMAIN_FOR_IP_SITE_REGEXP,
17
17
  DOMAIN_FOR_INTERNAL_SITE,
18
18
  WELLKNOWN_PATH_PREFIX,
19
- WELLKNOWN_AUTH_PATH_PREFIX,
19
+ WELLKNOWN_SERVICE_PATH_PREFIX,
20
20
  DOMAIN_FOR_IP_SITE,
21
21
  NAME_FOR_WELLKNOWN_SITE,
22
22
  DEFAULT_HTTP_PORT,
@@ -49,7 +49,6 @@ const {
49
49
  findInterfacePortByName,
50
50
  getWellknownSitePort,
51
51
  } = require('../util');
52
- const { getServicesFromBlockletInterface } = require('../util/service');
53
52
  const { getIpDnsDomainForBlocklet, getDidDomainForBlocklet } = require('../util/get-domain-for-blocklet');
54
53
  const { getFromCache: getAccessibleExternalNodeIp } = require('../util/get-accessible-external-node-ip');
55
54
 
@@ -144,7 +143,7 @@ const attachInterfaceUrls = async ({ sites = [], context, node }) => {
144
143
  ruleId,
145
144
  type: x.type,
146
145
  name: x.name,
147
- url: getInterfaceUrl({ baseUrl, url: '/', version: blocklet.meta.version }),
146
+ url: getInterfaceUrl({ baseUrl, url: '/' }),
148
147
  });
149
148
  }
150
149
  });
@@ -280,9 +279,9 @@ const ensureLatestInterfaceInfo = async (sites = []) => {
280
279
  }
281
280
 
282
281
  site.rules = site.rules.map((rule) => {
283
- // If a rule already has a target and target is WELLKNOWN_AUTH_PATH_PREFIX, just return
282
+ // If a rule already has a target and target is WELLKNOWN_SERVICE_PATH_PREFIX, just return
284
283
  // Indicates that the rule id generated by the system for auth service
285
- if (rule.isProtected && rule.to.target === WELLKNOWN_AUTH_PATH_PREFIX) {
284
+ if (rule.isProtected && rule.to.target === WELLKNOWN_SERVICE_PATH_PREFIX) {
286
285
  return rule;
287
286
  }
288
287
 
@@ -325,7 +324,7 @@ const ensureWellknownRule = async (sites) => {
325
324
  });
326
325
  }
327
326
 
328
- // add /.well-known/auth for blocklet
327
+ // add /.well-known/service for blocklet
329
328
  const rules = cloneDeep(site.rules);
330
329
  rules.forEach((rule) => {
331
330
  if (
@@ -336,11 +335,11 @@ const ensureWellknownRule = async (sites) => {
336
335
  }
337
336
 
338
337
  // already exists
339
- if (rule.from.pathPrefix.endsWith(WELLKNOWN_AUTH_PATH_PREFIX)) {
338
+ if (rule.from.pathPrefix.endsWith(WELLKNOWN_SERVICE_PATH_PREFIX)) {
340
339
  return;
341
340
  }
342
341
 
343
- const pathPrefix = joinUrl(rule.from.pathPrefix, WELLKNOWN_AUTH_PATH_PREFIX);
342
+ const pathPrefix = joinUrl(rule.from.pathPrefix, WELLKNOWN_SERVICE_PATH_PREFIX);
344
343
 
345
344
  // already exists
346
345
  if (site.rules.some((x) => x.from.pathPrefix === pathPrefix)) {
@@ -348,8 +347,6 @@ const ensureWellknownRule = async (sites) => {
348
347
  }
349
348
 
350
349
  rule.from.pathPrefix = pathPrefix;
351
- // let service gateway keep WELLKNOWN_AUTH_PATH_PREFIX prefix
352
- rule.to.target = WELLKNOWN_AUTH_PATH_PREFIX;
353
350
  rule.isProtected = true;
354
351
  site.rules.push(rule);
355
352
  });
@@ -389,43 +386,6 @@ const ensureLatestInfo = async (sites = [], { withDefaultCors = true } = {}) =>
389
386
  return ensureLatestInterfaceInfo(result);
390
387
  };
391
388
 
392
- const ensureAuthService = async (sites = [], blockletManager) => {
393
- const blocklets = await blockletManager.list({ includeRuntimeInfo: false });
394
- const blockletMap = blocklets.reduce((o, x) => {
395
- o[x.meta.did] = x;
396
- return o;
397
- }, {});
398
-
399
- sites.forEach((site) => {
400
- site.rules.forEach((rule) => {
401
- if (rule.to.type !== ROUTING_RULE_TYPES.BLOCKLET || !blockletMap[rule.to.did]) {
402
- return;
403
- }
404
-
405
- // find blocklet
406
- let blocklet = blockletMap[rule.to.did];
407
- if (rule.to.realDid && rule.to.did !== rule.to.realDid) {
408
- blocklet = (blocklet.children || []).find((x) => x.meta.did === rule.to.realDid);
409
- }
410
- if (!blocklet) {
411
- return;
412
- }
413
-
414
- // find interface
415
- // we should only use rule.to.realInterfaceName, rule.to.interfaceName is for backward compatible
416
- const interfaceName = rule.to.realInterfaceName || rule.to.interfaceName;
417
- const { interfaces } = blocklet.meta;
418
- const _interface = interfaces.find((x) => x.type === BLOCKLET_INTERFACE_TYPE_WEB && x.name === interfaceName);
419
- if (_interface) {
420
- rule.services = rule.services || [];
421
- rule.services.unshift(...getServicesFromBlockletInterface(_interface, { logError: logger.error }));
422
- }
423
- });
424
- });
425
-
426
- return sites;
427
- };
428
-
429
389
  const decompressCertificates = async (source, dest) => {
430
390
  fs.ensureDirSync(dest);
431
391
  await tar.x({ file: source, C: dest });
@@ -600,7 +560,7 @@ module.exports = function getRouterHelpers({ dataDirs, routingSnapshot, routerMa
600
560
  response: {
601
561
  status: 200,
602
562
  contentType: 'application/javascript',
603
- body: "console.log('ping: pong')",
563
+ body: "'pong'",
604
564
  },
605
565
  port: info.port,
606
566
  },
@@ -1154,7 +1114,11 @@ module.exports = function getRouterHelpers({ dataDirs, routingSnapshot, routerMa
1154
1114
  async function getRoutingRulesByDid(did) {
1155
1115
  const info = await nodeState.read();
1156
1116
  const { sites } = await readRoutingSites();
1157
- const rules = Router.flattenSitesToRules(sites, info);
1117
+ const domain = getBlockletDomainGroupName(did);
1118
+ const rules = Router.flattenSitesToRules(
1119
+ (sites || []).filter((x) => x.domain === domain),
1120
+ info
1121
+ );
1158
1122
  return rules.filter((rule) => rule.to.did === did);
1159
1123
  }
1160
1124
 
@@ -1186,7 +1150,6 @@ module.exports = function getRouterHelpers({ dataDirs, routingSnapshot, routerMa
1186
1150
  let { sites } = await readRoutingSites();
1187
1151
  sites = await filterSitesForRemovedBlocklets(sites);
1188
1152
  sites = await ensureLatestInfo(sites);
1189
- sites = await ensureAuthService(sites, blockletManager);
1190
1153
  sites = await ensureServiceRule(sites);
1191
1154
  sites = await ensureRootRule(sites);
1192
1155
 
@@ -6,7 +6,7 @@ const isEmpty = require('lodash/isEmpty');
6
6
  const security = require('@abtnode/util/lib/security');
7
7
  const { isFromPublicKey } = require('@arcblock/did');
8
8
  const logger = require('@abtnode/logger')('@abtnode/core:node');
9
- const { NODE_MODES, DISK_ALERT_THRESHOLD_PERCENT } = require('@abtnode/constant');
9
+ const { NODE_MODES, DISK_ALERT_THRESHOLD_PERCENT, EVENTS } = require('@abtnode/constant');
10
10
 
11
11
  const BaseState = require('./base');
12
12
  const { validateOwner } = require('../util');
@@ -164,7 +164,7 @@ class NodeState extends BaseState {
164
164
  const record = await this.read();
165
165
 
166
166
  const updateResult = await this.update(record._id, { $set: omit(entity, ['ownerNft', 'sk']) });
167
- this.emit('node.updated', updateResult, record);
167
+ this.emit(EVENTS.NODE_UPDATED, updateResult, record);
168
168
  return updateResult;
169
169
  }
170
170
 
@@ -174,7 +174,7 @@ class NodeState extends BaseState {
174
174
  }
175
175
 
176
176
  const nodeInfo = await this.updateNodeInfo({ routing: entity });
177
- this.emit('routing.updated', nodeInfo);
177
+ this.emit(EVENTS.ROUTING_UPDATED, nodeInfo);
178
178
 
179
179
  return nodeInfo;
180
180
  }
@@ -221,7 +221,7 @@ class NodeState extends BaseState {
221
221
  $set: { nodeOwner: owner, initialized, initializedAt: initialized ? new Date() : null },
222
222
  });
223
223
 
224
- this.emit('node.addedOwner', updateResult);
224
+ this.emit(EVENTS.NODE_ADDED_OWNER, updateResult);
225
225
 
226
226
  return updateResult;
227
227
  });
@@ -1,5 +1,6 @@
1
1
  const get = require('lodash/get');
2
2
  const logger = require('@abtnode/logger')('@abtnode/core:states:notification');
3
+ const { EVENTS } = require('@abtnode/constant');
3
4
 
4
5
  const BaseState = require('./base');
5
6
 
@@ -46,7 +47,7 @@ class NotificationState extends BaseState {
46
47
  }
47
48
 
48
49
  logger.info('create', { data });
49
- this.emit('notification.create', data);
50
+ this.emit(EVENTS.NOTIFICATION_CREATE, data);
50
51
  return resolve(data);
51
52
  }
52
53
  );
@@ -1,5 +1,6 @@
1
1
  const { EventEmitter } = require('events');
2
2
  const logger = require('@abtnode/logger')('@abtnode/domain-status');
3
+ const { EVENTS } = require('@abtnode/constant');
3
4
  const { checkDomainDNS } = require('./index');
4
5
 
5
6
  const dnsStatusStore = Object.create(null);
@@ -35,7 +36,7 @@ class DomainStatus extends EventEmitter {
35
36
  Promise.all([this.routerManager.getMatchedCert(domain), checkDomainDnsWrapper(domain)])
36
37
  .then((data) => {
37
38
  const [matchedCert, dns] = data;
38
- this.emit('domain.status', { domain, matchedCert, isHttps: !!matchedCert, dns });
39
+ this.emit(EVENTS.DOMAIN_STATUS, { domain, matchedCert, isHttps: !!matchedCert, dns });
39
40
  })
40
41
  .catch((error) => {
41
42
  logger.error('check domain status error', { domain, error });
package/lib/util/index.js CHANGED
@@ -12,7 +12,6 @@ const { isFromPublicKey } = require('@arcblock/did');
12
12
  const joinUrl = require('url-join');
13
13
  const { Certificate } = require('@fidm/x509');
14
14
  const getPortLib = require('get-port');
15
- const isIp = require('is-ip');
16
15
  const v8 = require('v8');
17
16
  const normalizePathPrefix = require('@abtnode/util/lib/normalize-path-prefix');
18
17
  const parseBlockletMeta = require('@blocklet/meta/lib/parse');
@@ -30,13 +29,12 @@ const {
30
29
  DEFAULT_IP_DNS_DOMAIN_SUFFIX,
31
30
  BLOCKLET_SITE_GROUP_SUFFIX,
32
31
  } = require('@abtnode/constant');
33
- const { BLOCKLET_INTERFACE_TYPE_WEB } = require('@blocklet/meta/lib/constants');
34
32
 
35
33
  const DEFAULT_WELLKNOWN_PORT = 8088;
36
34
 
37
35
  const logger = require('@abtnode/logger')('@abtnode/core:util');
38
36
 
39
- const { getServices, getServicesFromBlockletInterface } = require('./service');
37
+ const { getServices } = require('./service');
40
38
  const request = require('./request');
41
39
 
42
40
  const validateOwner = (owner) => {
@@ -53,7 +51,7 @@ const fromStatus = (v) => {
53
51
  return match ? match[0] : 'unknown';
54
52
  };
55
53
 
56
- const getInterfaceUrl = ({ baseUrl, url, version }) => {
54
+ const getInterfaceUrl = ({ baseUrl, url }) => {
57
55
  if (!url) {
58
56
  return '';
59
57
  }
@@ -63,11 +61,6 @@ const getInterfaceUrl = ({ baseUrl, url, version }) => {
63
61
  }
64
62
 
65
63
  const parsed = new URL(joinUrl(baseUrl, url));
66
- const params = parsed.searchParams;
67
-
68
- if (version) {
69
- params.set('__bv__', version);
70
- }
71
64
 
72
65
  return parsed.href;
73
66
  };
@@ -112,104 +105,43 @@ const getBlockletHost = ({ domain, context, nodeIp }) => {
112
105
  return `${tmpDomain}:${port}`;
113
106
  };
114
107
 
115
- /**
116
- * Get config of auth service of blocklet component specified the routing rule
117
- * @param {*} rule routing rule
118
- * @param {*} blocklet
119
- * @returns
120
- */
121
- const getAuthConfig = (rule, blocklet) => {
122
- if (!blocklet || !rule || rule.to.type !== ROUTING_RULE_TYPES.BLOCKLET || rule.to.did !== blocklet.meta.did) {
123
- return null;
124
- }
125
-
126
- // find blocklet component
127
- const isRootRule = rule.to.did === rule.to.realDid;
128
- let _blocklet;
129
- if (isRootRule) {
130
- _blocklet = blocklet;
131
- } else {
132
- _blocklet = (blocklet.children || []).find((x) => x.meta.did === rule.to.realDid);
133
- }
134
- if (!_blocklet) {
135
- return null;
136
- }
137
-
138
- // find interface in meta
139
- const interfaceName = rule.to.realInterfaceName;
140
- const { interfaces } = _blocklet.meta;
141
- const _interface = interfaces.find((x) => x.type === BLOCKLET_INTERFACE_TYPE_WEB && x.name === interfaceName);
142
-
143
- if (!_interface) {
144
- return null;
145
- }
146
-
147
- // find auth service
148
- const auth = getServicesFromBlockletInterface(_interface, { stringifyConfig: false }).find(
149
- (x) => x.name === '@abtnode/auth-service'
150
- );
151
-
152
- if (!auth) {
153
- return null;
108
+ const getBlockletBaseUrls = ({ rules = [], context = {}, nodeIp }) => {
109
+ if (!Array.isArray(rules) || !rules.length) {
110
+ return [];
154
111
  }
155
112
 
156
- return auth.config;
157
- };
158
-
159
- const getBlockletBaseUrls = ({ routingEnabled = false, port, rules = [], context = {}, blocklet, nodeIp }) => {
160
- let baseUrls = [];
161
-
162
- if (routingEnabled && Array.isArray(rules) && rules.length > 0) {
163
- baseUrls = rules
164
- .filter((rule) => !(rule.from.domain || '').endsWith(BLOCKLET_SITE_GROUP_SUFFIX))
165
- .map((rule) => {
166
- const host = getBlockletHost({ domain: rule.from.domain, context, nodeIp });
167
- if (host) {
168
- let protocol = 'http'; // TODO: 这里固定为 http, 因为判断 url 是不是 https 和证书相关,这里实现的话比较复杂
169
- if (host.includes(DEFAULT_IP_DNS_DOMAIN_SUFFIX)) {
170
- protocol = 'https';
171
- }
172
-
173
- return {
174
- ruleId: rule.id,
175
- baseUrl: `${protocol}://${host}/${trimSlash(rule.from.pathPrefix)}`,
176
- interfaceName: get(rule, 'to.interfaceName', ''),
177
- authConfig: getAuthConfig(rule, blocklet),
178
- };
113
+ return rules
114
+ .map((rule) => {
115
+ const host = getBlockletHost({ domain: rule.from.domain, context, nodeIp });
116
+ if (host) {
117
+ let protocol = 'http'; // TODO: 这里固定为 http, 因为判断 url 是不是 https 和证书相关,这里实现的话比较复杂
118
+ if (host.includes(DEFAULT_IP_DNS_DOMAIN_SUFFIX)) {
119
+ protocol = 'https';
179
120
  }
180
121
 
181
- return null;
182
- })
183
- .filter(Boolean);
184
- }
185
-
186
- if (!baseUrls.length && isIp(context.hostname)) {
187
- baseUrls = [{ baseUrl: `http://${context.hostname}:${port}` }];
188
- }
122
+ return {
123
+ ruleId: rule.id,
124
+ baseUrl: `${protocol}://${host}/${trimSlash(rule.from.pathPrefix)}`,
125
+ interfaceName: get(rule, 'to.interfaceName', ''),
126
+ };
127
+ }
189
128
 
190
- return baseUrls;
129
+ return null;
130
+ })
131
+ .filter(Boolean);
191
132
  };
192
133
 
193
- const getBlockletInterfaces = ({ blocklet, context, nodeInfo, routingRules, nodeIp }) => {
134
+ const getBlockletInterfaces = ({ blocklet, context, routingRules, nodeIp }) => {
194
135
  const interfaces = [];
195
- (blocklet.meta.interfaces || []).forEach((x) => {
196
- if (x.port && x.port.external) {
197
- // If an interface was exposed through external port, path is not appended
198
- const baseUrls = getBlockletBaseUrls({
199
- routingEnabled: false,
200
- port: x.port.external,
201
- rules: [],
202
- context,
203
- });
204
- baseUrls.forEach(({ baseUrl }) => interfaces.push({ type: x.type, name: x.name, url: baseUrl }));
205
- } else {
136
+ (blocklet.meta.interfaces || [])
137
+ .filter((x) => !get(x, 'port.external'))
138
+ .forEach((x) => {
206
139
  // Otherwise, the url is composed with routing rules
207
- const port = x.port && x.port.internal ? blocklet.ports[x.port.internal] : blocklet.ports[x.port];
208
140
  const baseUrls = getBlockletBaseUrls({
209
- routingEnabled: isRoutingEnabled(nodeInfo.routing),
210
- port,
211
141
  rules: (routingRules || []).filter((r) => {
212
142
  return (
143
+ // don't show group domain
144
+ !(r.from.domain || '').endsWith(BLOCKLET_SITE_GROUP_SUFFIX) &&
213
145
  // don't show wellknown interface
214
146
  r.to.type !== ROUTING_RULE_TYPES.GENERAL_PROXY &&
215
147
  // LEGACY don't show wellknown interface
@@ -219,11 +151,10 @@ const getBlockletInterfaces = ({ blocklet, context, nodeInfo, routingRules, node
219
151
  );
220
152
  }),
221
153
  context,
222
- blocklet,
223
154
  nodeIp,
224
155
  });
225
156
 
226
- baseUrls.forEach(({ baseUrl, ruleId, interfaceName, authConfig }) => {
157
+ baseUrls.forEach(({ baseUrl, ruleId, interfaceName }) => {
227
158
  if (interfaceName && interfaceName !== x.name) {
228
159
  return;
229
160
  }
@@ -231,12 +162,10 @@ const getBlockletInterfaces = ({ blocklet, context, nodeInfo, routingRules, node
231
162
  ruleId,
232
163
  type: x.type,
233
164
  name: x.name,
234
- url: getInterfaceUrl({ baseUrl, url: '/', version: blocklet.meta.version }),
235
- authConfig,
165
+ url: getInterfaceUrl({ baseUrl, url: '/' }),
236
166
  });
237
167
  });
238
- }
239
- });
168
+ });
240
169
 
241
170
  return uniqBy(interfaces, 'url');
242
171
  };
@@ -1,51 +1,67 @@
1
1
  const fs = require('fs-extra');
2
+ const cloneDeep = require('lodash/cloneDeep');
3
+ const Ajv = require('ajv').default;
2
4
 
3
- const getServices = ({ stringifySchema = false } = {}) =>
4
- ['auth']
5
- .map((x) => {
6
- let service;
7
-
8
- try {
9
- const metaFile = require.resolve(`@abtnode/blocklet-services/services/${x}/meta.json`);
10
- service = fs.readJSONSync(metaFile);
11
- } catch (err) {
12
- service = {};
13
- }
14
-
15
- if (stringifySchema) {
16
- service.schema = JSON.stringify(service.schema);
17
- }
18
-
19
- return service;
20
- })
21
- .filter((x) => x.name && x.version);
22
-
23
- const getServicesFromBlockletInterface = (
24
- interfaceMeta,
25
- { logError, services = getServices(), stringifyConfig = true } = {}
26
- ) => {
27
- const list = interfaceMeta.services || [];
28
- return list
29
- .map((s) => {
30
- const service = services.find((t) => t.name === s.name);
31
-
32
- if (!service) {
33
- if (typeof logError === 'function') {
34
- logError('Service in blocklet meta was not found in node');
35
- }
36
- return null;
37
- }
38
-
39
- const { name, version, description } = service;
40
-
41
- const config = stringifyConfig ? JSON.stringify(s.config) : s.config;
42
-
43
- return { name, version, description, config };
44
- })
45
- .filter(Boolean);
5
+ const ajv = new Ajv({
6
+ useDefaults: true,
7
+ removeAdditional: 'all',
8
+ });
9
+
10
+ const SERVICES = {
11
+ AUTH: fs.readJSONSync(require.resolve('@abtnode/blocklet-services/configs/auth.json')),
12
+ };
13
+
14
+ const getServices = ({ stringifySchema = false } = {}) => {
15
+ const list = Object.values(SERVICES).map((x) => {
16
+ const data = cloneDeep(x);
17
+ if (stringifySchema) {
18
+ data.schema = JSON.stringify(x.schema);
19
+ }
20
+ return data;
21
+ });
22
+
23
+ // backward compatible
24
+ const authService = cloneDeep(list.find((x) => x.name === 'auth'));
25
+ authService.name = '@abtnode/auth-service';
26
+ list.push(authService);
27
+
28
+ return list;
29
+ };
30
+
31
+ const getServiceMeta = (serviceName) => {
32
+ if (!serviceName) {
33
+ throw new Error('service name should not be empty');
34
+ }
35
+ const metas = getServices();
36
+ const meta = metas.find((x) => x.name === serviceName);
37
+ if (!meta) {
38
+ throw new Error(`service ${serviceName} does not exist`);
39
+ }
40
+
41
+ return meta;
42
+ };
43
+
44
+ const getServiceConfig = (service, customConfig) => {
45
+ const serviceMeta = typeof service === 'string' ? getServiceMeta(service) : service;
46
+
47
+ const validate = ajv.compile(serviceMeta.schema.JSONSchema);
48
+
49
+ const data = cloneDeep(customConfig || {});
50
+ // this method may have side effect thar will fill default value to customConfig
51
+ validate(data || {});
52
+
53
+ return data;
54
+ };
55
+
56
+ const getDefaultServiceConfig = (service) => {
57
+ const serviceMeta = typeof service === 'string' ? getServiceMeta(service) : service;
58
+
59
+ // parse empty custom config to get default config
60
+ return getServiceConfig(serviceMeta, {});
46
61
  };
47
62
 
48
63
  module.exports = {
49
64
  getServices,
50
- getServicesFromBlockletInterface,
65
+ getServiceConfig,
66
+ getDefaultServiceConfig,
51
67
  };
@@ -2,7 +2,7 @@
2
2
  const axon = require('axon');
3
3
  const semver = require('semver');
4
4
  const sleep = require('@abtnode/util/lib/sleep');
5
- const { NODE_MODES, NODE_UPGRADE_PROGRESS } = require('@abtnode/constant');
5
+ const { NODE_MODES, NODE_UPGRADE_PROGRESS, EVENTS } = require('@abtnode/constant');
6
6
  const listNpmPackageVersion = require('@abtnode/util/lib/list-npm-package-version');
7
7
  const Lock = require('@abtnode/util/lib/lock');
8
8
  const logger = require('@abtnode/logger')('@abtnode/core:upgrade');
@@ -108,7 +108,7 @@ const doUpgrade = async (session) => {
108
108
  const goNextState = async (stage) => {
109
109
  session = await states.session.update(sessionId, { stage });
110
110
  // Emit events so client will keep up
111
- states.node.emit('node.upgrade.progress', session);
111
+ states.node.emit(EVENTS.NODE_UPGRADE_PROGRESS, session);
112
112
  };
113
113
 
114
114
  // 1. enter maintenance mode
@@ -1,6 +1,7 @@
1
1
  const logger = require('@abtnode/logger')('@abtnode/core:webhook:index');
2
2
 
3
3
  const sortPriorityUrl = require('@abtnode/util/lib/sort-priority-url');
4
+ const { EVENTS } = require('@abtnode/constant');
4
5
  const WebHookSender = require('./sender');
5
6
  const createQueue = require('../queue');
6
7
  const IP = require('../util/ip');
@@ -105,15 +106,15 @@ module.exports = ({ events, dataDirs, instance }) => {
105
106
  },
106
107
  });
107
108
 
108
- events.on('notification.create', (data) => {
109
+ events.on(EVENTS.NOTIFICATION_CREATE, (data) => {
109
110
  const { title, description, severity, action, entityType } = data;
110
111
  queue.push({ title, description, status: severity, action, entityType });
111
112
  });
112
113
 
113
- events.on('node.started', async (message) => {
114
+ events.on(EVENTS.NODE_STARTED, async (message) => {
114
115
  await sendMessage(message);
115
116
  });
116
- events.on('node.stopped', async (message) => {
117
+ events.on(EVENTS.NODE_STOPPED, async (message) => {
117
118
  await sendMessage(message);
118
119
  });
119
120
 
package/package.json CHANGED
@@ -3,7 +3,7 @@
3
3
  "publishConfig": {
4
4
  "access": "public"
5
5
  },
6
- "version": "1.6.27",
6
+ "version": "1.6.28",
7
7
  "description": "",
8
8
  "main": "lib/index.js",
9
9
  "files": [
@@ -19,22 +19,22 @@
19
19
  "author": "wangshijun <wangshijun2010@gmail.com> (http://github.com/wangshijun)",
20
20
  "license": "MIT",
21
21
  "dependencies": {
22
- "@abtnode/certificate-manager": "1.6.27",
23
- "@abtnode/constant": "1.6.27",
24
- "@abtnode/cron": "1.6.27",
25
- "@abtnode/db": "1.6.27",
26
- "@abtnode/logger": "1.6.27",
27
- "@abtnode/queue": "1.6.27",
28
- "@abtnode/rbac": "1.6.27",
29
- "@abtnode/router-provider": "1.6.27",
30
- "@abtnode/static-server": "1.6.27",
31
- "@abtnode/timemachine": "1.6.27",
32
- "@abtnode/util": "1.6.27",
22
+ "@abtnode/certificate-manager": "1.6.28",
23
+ "@abtnode/constant": "1.6.28",
24
+ "@abtnode/cron": "1.6.28",
25
+ "@abtnode/db": "1.6.28",
26
+ "@abtnode/logger": "1.6.28",
27
+ "@abtnode/queue": "1.6.28",
28
+ "@abtnode/rbac": "1.6.28",
29
+ "@abtnode/router-provider": "1.6.28",
30
+ "@abtnode/static-server": "1.6.28",
31
+ "@abtnode/timemachine": "1.6.28",
32
+ "@abtnode/util": "1.6.28",
33
33
  "@arcblock/did": "^1.14.19",
34
34
  "@arcblock/event-hub": "1.14.19",
35
35
  "@arcblock/pm2-events": "^0.0.5",
36
36
  "@arcblock/vc": "^1.14.19",
37
- "@blocklet/meta": "1.6.27",
37
+ "@blocklet/meta": "1.6.28",
38
38
  "@fidm/x509": "^1.2.1",
39
39
  "@nedb/core": "^1.2.2",
40
40
  "@nedb/multi": "^1.2.2",
@@ -42,6 +42,7 @@
42
42
  "@ocap/util": "^1.14.19",
43
43
  "@ocap/wallet": "^1.14.19",
44
44
  "@slack/webhook": "^5.0.3",
45
+ "ajv": "^7.0.3",
45
46
  "axios": "^0.25.0",
46
47
  "axon": "^2.0.3",
47
48
  "chalk": "^4.0.0",
@@ -76,5 +77,5 @@
76
77
  "express": "^4.17.1",
77
78
  "jest": "^27.4.5"
78
79
  },
79
- "gitHead": "5ec2dbcfa7d9464c0430ea3112e4fe0fbab65414"
80
+ "gitHead": "acef8ea339bd8fc9c785312eb5a1a113ecbf0d4d"
80
81
  }