@abtnode/core 1.5.14 → 1.5.15

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.
@@ -26,7 +26,7 @@ const mergeConfigs = (oldConfigs, newConfigs = []) => {
26
26
  // newConfig 为用户传的,也可以是从环境变量中去读的
27
27
  const uniqConfigs = uniqBy(newConfigs, (x) => x.key || x.name);
28
28
 
29
- // `BLOCKLET_*` and `ABT_NODE_*` vars can only be set by ABT Node Daemon with only a few exceptions.
29
+ // `BLOCKLET_*` and `ABT_NODE_*` vars can only be set by Blocklet Server Daemon with only a few exceptions.
30
30
  const newConfig = uniqConfigs.filter((x) => {
31
31
  const key = x.key || x.name;
32
32
 
@@ -955,7 +955,7 @@ class BlockletManager extends BaseBlockletManager {
955
955
  return a.from.pathPrefix.length < b.from.pathPrefix ? 1 : -1;
956
956
  });
957
957
  const nodeIp = await getAccessibleExternalNodeIp(nodeInfo);
958
- return getBlockletInterfaces({ blocklet, context, nodeInfo, sites: routingRules, nodeIp });
958
+ return getBlockletInterfaces({ blocklet, context, nodeInfo, routingRules, nodeIp });
959
959
  }
960
960
 
961
961
  async attachRuntimeInfo({ did, nodeInfo, diskInfo = true, context, cachedBlocklet }) {
@@ -3,7 +3,7 @@ const { BlockletGroup } = require('@blocklet/meta/lib/constants');
3
3
  const joinURL = require('url-join');
4
4
  const get = require('lodash/get');
5
5
  const pick = require('lodash/pick');
6
- const { BLOCKLET_REGISTRY_API_PREFIX } = require('@abtnode/constant');
6
+ const { BLOCKLET_STORE_API_PREFIX } = require('@abtnode/constant');
7
7
 
8
8
  const { name } = require('../../package.json');
9
9
 
@@ -63,7 +63,7 @@ class BlockletRegistry {
63
63
 
64
64
  const url = joinURL(
65
65
  registryUrl || defaultRegistryUrl,
66
- BLOCKLET_REGISTRY_API_PREFIX,
66
+ BLOCKLET_STORE_API_PREFIX,
67
67
  `/blocklets/${did}/blocklet.json?__t__=${Date.now()}`
68
68
  );
69
69
 
@@ -109,7 +109,7 @@ class BlockletRegistry {
109
109
 
110
110
  async refreshBlocklets(context) {
111
111
  const registryUrl = await states.node.getBlockletRegistry();
112
- const url = joinURL(registryUrl, BLOCKLET_REGISTRY_API_PREFIX, '/blocklets.json');
112
+ const url = joinURL(registryUrl, BLOCKLET_STORE_API_PREFIX, '/blocklets.json');
113
113
  try {
114
114
  let res = await request.get(url, {
115
115
  validateStatus: (status) => (status >= 200 && status < 300) || status === 304,
@@ -153,7 +153,7 @@ class BlockletRegistry {
153
153
  }
154
154
 
155
155
  BlockletRegistry.validateRegistryURL = async (registry) => {
156
- const url = joinURL(registry, BLOCKLET_REGISTRY_API_PREFIX, `/blocklets.json?__t__=${Date.now()}`);
156
+ const url = joinURL(registry, BLOCKLET_STORE_API_PREFIX, `/blocklets.json?__t__=${Date.now()}`);
157
157
  try {
158
158
  const res = await request.get(url);
159
159
  if (Array.isArray(res.data)) {
@@ -170,7 +170,7 @@ BlockletRegistry.validateRegistryURL = async (registry) => {
170
170
 
171
171
  BlockletRegistry.getRegistryMeta = async (registry) => {
172
172
  try {
173
- const url = joinURL(registry, BLOCKLET_REGISTRY_API_PREFIX, `/registry.json?__t__=${Date.now()}`);
173
+ const url = joinURL(registry, BLOCKLET_STORE_API_PREFIX, `/registry.json?__t__=${Date.now()}`);
174
174
  const { data } = await request.get(url);
175
175
 
176
176
  if (!data) {
package/lib/event.js CHANGED
@@ -128,8 +128,8 @@ module.exports = ({
128
128
  const handleCLIEvent = (eventName) => {
129
129
  const [, status] = eventName.split('.');
130
130
  onEvent(eventName, {
131
- title: `ABT Node ${status}`,
132
- description: `ABT Node is ${status} successfully`,
131
+ title: `Blocklet Server ${status}`,
132
+ description: `Blocklet Server is ${status} successfully`,
133
133
  entityType: 'node',
134
134
  status: 'success',
135
135
  });
@@ -0,0 +1,184 @@
1
+ /* eslint-disable no-continue */
2
+ /* eslint-disable no-await-in-loop */
3
+ const normalizePathPrefix = require('@abtnode/util/lib/normalize-path-prefix');
4
+
5
+ const findBlocklet = (site, blocklets) => {
6
+ // prefix = /
7
+ const rootRule = site.rules.find((x) => x.from.pathPrefix === '/' && x.to.type === 'blocklet');
8
+ if (rootRule) {
9
+ const blocklet = blocklets.find((x) => x.meta.did === rootRule.to.did);
10
+ if (blocklet) {
11
+ return blocklet;
12
+ }
13
+ }
14
+
15
+ for (const rule of site.rules) {
16
+ if (rule.to.type === 'blocklet') {
17
+ const blocklet = blocklets.find((x) => x.meta.did === rule.to.did);
18
+ if (blocklet) {
19
+ return blocklet;
20
+ }
21
+ }
22
+ }
23
+
24
+ return null;
25
+ };
26
+
27
+ const mergeSite = (newSite, oldSite) => {
28
+ const { domain, domainAliases = [], isProtected, rules, corsAllowedOrigins } = oldSite;
29
+
30
+ // merge domain
31
+ const domains = [
32
+ {
33
+ value: domain,
34
+ isProtected,
35
+ },
36
+ ...(domainAliases || []).map((x) => (typeof x === 'string' ? { value: x, isProtected: false } : x)),
37
+ ];
38
+ domains.forEach((x) => {
39
+ if (!newSite.domainAliases.some((y) => y.value === x.value)) {
40
+ newSite.domainAliases.push(x);
41
+ }
42
+ });
43
+
44
+ // merge cors
45
+ (corsAllowedOrigins || []).forEach((x) => {
46
+ if (!newSite.corsAllowedOrigins.includes(x)) {
47
+ newSite.corsAllowedOrigins.push(x);
48
+ }
49
+ });
50
+
51
+ // merge rules
52
+ (rules || []).forEach((x) => {
53
+ if (!newSite.rules.some((y) => normalizePathPrefix(y.from.pathPrefix) === normalizePathPrefix(x.from.pathPrefix))) {
54
+ newSite.rules.push(x);
55
+ }
56
+ });
57
+ };
58
+
59
+ module.exports = async ({ states, node, printInfo }) => {
60
+ printInfo('Migrate site to 2.0 version for router...\n');
61
+
62
+ const sites = await states.site.getSites();
63
+ const blocklets = await states.blocklet.getBlocklets();
64
+ printInfo(`Find blocklets: ${blocklets.length}`);
65
+
66
+ // blocklet site which ends with 888-888-888-888.ip.abtnet.io
67
+ const blockletSystemSites = [];
68
+
69
+ // custom site added by user
70
+ const customSites = [];
71
+
72
+ sites.forEach((site) => {
73
+ const { domain } = site;
74
+
75
+ // filter 3 default basic site
76
+ if (domain === '' || domain === '127.0.0.1' || domain === '*') {
77
+ return;
78
+ }
79
+
80
+ const blocklet = findBlocklet(site, blocklets);
81
+
82
+ if (domain.endsWith('888-888-888-888.ip.abtnet.io')) {
83
+ blockletSystemSites.push({
84
+ site,
85
+ blocklet,
86
+ });
87
+ } else {
88
+ customSites.push({
89
+ site,
90
+ blocklet,
91
+ });
92
+ }
93
+ });
94
+
95
+ printInfo(
96
+ `Find sites: ${sites.length}; blockletSystemSites: ${blockletSystemSites.length}; customSites: ${customSites.length}\n`
97
+ );
98
+ printInfo(`blockletSystemSites: ${blockletSystemSites.map((x) => x.site.domain).join(', ')}\n`);
99
+ printInfo(`customSites: ${customSites.map((x) => x.site.domain).join(', ')}\n`);
100
+
101
+ // generate new blocklet site for every installed blocklet
102
+ const newBlockletSites = {}; // <blockletDid>: <site>
103
+ for (const blocklet of blocklets) {
104
+ const domain = `${blocklet.meta.did}.blocklet-domain-group`;
105
+ newBlockletSites[blocklet.meta.did] = {
106
+ domain,
107
+ domainAliases: [],
108
+ isProtected: true,
109
+ rules: [],
110
+ corsAllowedOrigins: [],
111
+ };
112
+ }
113
+ printInfo(
114
+ `newBlockletSites: ${Object.values(newBlockletSites)
115
+ .map((x) => x.domain)
116
+ .join(', ')}\n`
117
+ );
118
+
119
+ printInfo('\n');
120
+ printInfo('Start merge blockletSystemSites to new sites');
121
+ for (const { site: oldSite, blocklet } of blockletSystemSites) {
122
+ // merge blockletSystemSite to new blocklet site
123
+ if (blocklet) {
124
+ const newSite = newBlockletSites[blocklet.meta.did];
125
+ mergeSite(newSite, oldSite);
126
+ printInfo(`Merge site from ${oldSite.domain} to ${newSite.domain}`);
127
+ }
128
+ }
129
+
130
+ printInfo('\n');
131
+ printInfo('Start merge customSites to new sites');
132
+ for (const { site: oldSite, blocklet } of customSites) {
133
+ // reserve custom site which not belong to any blocklet
134
+ if (!blocklet) {
135
+ printInfo(`Skip merge custom site: ${oldSite.domain}`);
136
+ oldSite.skip = true;
137
+ continue;
138
+ }
139
+ // merge custom site to new blocklet site
140
+ const newSite = newBlockletSites[blocklet.meta.did];
141
+ mergeSite(newSite, oldSite);
142
+ printInfo(`Merge site from ${oldSite.domain} to ${newSite.domain}`);
143
+ }
144
+
145
+ printInfo('\n');
146
+ printInfo('Start delete blockletSystemSites from db');
147
+ for (const { site: oldSite } of blockletSystemSites) {
148
+ if (oldSite.skip) {
149
+ printInfo(`Skip delete site from db: ${oldSite.domain}`);
150
+ continue;
151
+ }
152
+ // delete each blockletSystemSite
153
+ await states.site.remove({ _id: oldSite.id });
154
+ printInfo(`Delete site from db: ${oldSite.domain}`);
155
+ }
156
+
157
+ printInfo('\n');
158
+ printInfo('Start delete customSites from db');
159
+ for (const { site: oldSite } of customSites) {
160
+ if (oldSite.skip) {
161
+ printInfo(`Skip delete site from db: ${oldSite.domain}`);
162
+ continue;
163
+ }
164
+ // delete custom site which bind to a blocklet
165
+ await states.site.remove({ _id: oldSite.id });
166
+ printInfo(`Delete site from db: ${oldSite.domain}`);
167
+ }
168
+
169
+ // add new blocklet site to db
170
+ printInfo('\n');
171
+ printInfo('Start add new sites to db');
172
+ for (const site of Object.values(newBlockletSites)) {
173
+ await states.site.add(site);
174
+ printInfo(`Add site to db: ${site.domain}`);
175
+ }
176
+
177
+ await node.takeRoutingSnapshot({
178
+ message: 'Migrate site to 2.0 version for router',
179
+ dryRun: false,
180
+ handleRouting: false,
181
+ });
182
+ printInfo('\n');
183
+ printInfo('Take routing snapshot');
184
+ };
@@ -28,11 +28,14 @@ const {
28
28
  CERTIFICATE_EXPIRES_WARNING_OFFSET,
29
29
  DEFAULT_DAEMON_PORT,
30
30
  DEFAULT_SERVICE_PATH,
31
+ SLOT_FOR_IP_DNS_SITE,
32
+ BLOCKLET_SITE_GROUP_SUFFIX,
31
33
  } = require('@abtnode/constant');
32
34
  const {
33
35
  BLOCKLET_DYNAMIC_PATH_PREFIX,
34
36
  BLOCKLET_INTERFACE_TYPE_WEB,
35
37
  BLOCKLET_INTERFACE_WELLKNOWN,
38
+ BLOCKLET_INTERFACE_TYPE_WELLKNOWN,
36
39
  } = require('@blocklet/meta/lib/constants');
37
40
 
38
41
  // eslint-disable-next-line global-require
@@ -48,15 +51,58 @@ const {
48
51
  } = require('../util');
49
52
  const { getServicesFromBlockletInterface } = require('../util/service');
50
53
  const getIpDnsDomainForBlocklet = require('../util/get-ip-dns-domain-for-blocklet');
54
+ const { getFromCache: getAccessibleExternalNodeIp } = require('../util/get-accessible-external-node-ip');
51
55
 
52
56
  const Router = require('./index');
53
57
  const states = require('../states');
54
58
 
55
- const attachInterfaceUrls = async ({ sites = [], context }) => {
59
+ /**
60
+ * replace 888-888-888-888 with accessible ip for domain
61
+ */
62
+ const attachRuntimeDomainAliases = async ({ sites = [], context = {}, node }) => {
63
+ let ip;
64
+ const ipRegex = /\d+[-.]\d+[-.]\d+[-.]\d+/;
65
+ const match = ipRegex.exec(context.hostname);
66
+ if (match) {
67
+ ip = match[0].replace(/\./g, '-');
68
+ } else if (node) {
69
+ const nodeInfo = await node.read();
70
+ const nodeIp = await getAccessibleExternalNodeIp(nodeInfo);
71
+ if (nodeIp) {
72
+ ip = nodeIp;
73
+ }
74
+ }
75
+
76
+ const getDomainAliases = (site) =>
77
+ (site.domainAliases || []).map((domain) => {
78
+ if (!domain.value) {
79
+ return domain;
80
+ }
81
+ if (domain.value.includes(SLOT_FOR_IP_DNS_SITE) && ip) {
82
+ domain.value = domain.value.replace(SLOT_FOR_IP_DNS_SITE, ip);
83
+ }
84
+ return domain;
85
+ });
86
+
87
+ if (!Array.isArray(sites)) {
88
+ sites.domainAliases = getDomainAliases(sites);
89
+ return sites;
90
+ }
91
+
92
+ return sites.map((site) => {
93
+ site.domainAliases = getDomainAliases(site);
94
+
95
+ return site;
96
+ });
97
+ };
98
+
99
+ const attachInterfaceUrls = async ({ sites = [], context, node }) => {
56
100
  if (!sites) {
57
101
  return [];
58
102
  }
59
103
 
104
+ attachRuntimeDomainAliases({ sites, context, node });
105
+
60
106
  const getUrl = (rule, domain = '') => {
61
107
  const host = getBlockletHost({ domain, context });
62
108
  const prefix = trimSlash(rule.from.pathPrefix);
@@ -340,7 +386,7 @@ const ensureAuthService = async (sites = [], blockletManager) => {
340
386
  // we should only use rule.to.realInterfaceName, rule.to.interfaceName is for backward compatible
341
387
  const interfaceName = rule.to.realInterfaceName || rule.to.interfaceName;
342
388
  const { interfaces } = blocklet.meta;
343
- const _interface = interfaces.find((x) => x.type === 'web' && x.name === interfaceName);
389
+ const _interface = interfaces.find((x) => x.type === BLOCKLET_INTERFACE_TYPE_WEB && x.name === interfaceName);
344
390
  if (_interface) {
345
391
  rule.services = rule.services || [];
346
392
  rule.services.unshift(...getServicesFromBlockletInterface(_interface, { logError: logger.error }));
@@ -596,10 +642,13 @@ module.exports = function getRouterHelpers({ dataDirs, routingSnapshot, routerMa
596
642
  /**
597
643
  * Add system sites for blocklet
598
644
  *
599
- * @returns {boolean} if routing changed
645
+ * @returns {boolean} if routing state db changed
600
646
  */
601
647
  const _ensureBlockletSites = async (blocklet, sites, nodeInfo, context = {}) => {
602
- const interfaces = (blocklet.meta.interfaces || []).filter((x) => x.type === BLOCKLET_INTERFACE_TYPE_WEB);
648
+ const webInterface = (blocklet.meta.interfaces || []).find((x) => x.type === BLOCKLET_INTERFACE_TYPE_WEB);
649
+ if (!webInterface) {
650
+ return false;
651
+ }
603
652
 
604
653
  const getPrefix = (str) => {
605
654
  if (!str || str === '*') {
@@ -608,68 +657,59 @@ module.exports = function getRouterHelpers({ dataDirs, routingSnapshot, routerMa
608
657
  return `/${str}`.replace(/^\/+/, '/');
609
658
  };
610
659
 
611
- const changes = await Promise.all(
612
- interfaces.map(async (x) => {
613
- const domain = getIpDnsDomainForBlocklet(blocklet, x);
614
- const pathPrefix = getPrefix(x.prefix);
615
- const rule = {
616
- from: { pathPrefix },
617
- to: {
618
- port: findInterfacePortByName(blocklet, x.name),
619
- did: blocklet.meta.did,
620
- type: ROUTING_RULE_TYPES.BLOCKLET,
621
- interfaceName: x.name, // root blocklet interface
622
- },
623
- isProtected: true,
624
- };
660
+ const domainGroup = `${blocklet.meta.did}${BLOCKLET_SITE_GROUP_SUFFIX}`;
661
+ const domain = getIpDnsDomainForBlocklet(blocklet, webInterface);
662
+ const pathPrefix = getPrefix(webInterface.prefix);
663
+ const rule = {
664
+ from: { pathPrefix },
665
+ to: {
666
+ port: findInterfacePortByName(blocklet, webInterface.name),
667
+ did: blocklet.meta.did,
668
+ type: ROUTING_RULE_TYPES.BLOCKLET,
669
+ interfaceName: webInterface.name, // root blocklet interface
670
+ },
671
+ isProtected: true,
672
+ };
625
673
 
626
- let changed = false; // if state db changed
627
-
628
- const exist = await states.site.findOne({ domain });
629
- if (!exist) {
630
- await routerManager.addRoutingSite(
631
- {
632
- site: {
633
- domain,
634
- isProtected: true,
635
- // FIXME: tmp fix for https://github.com/ArcBlock/abt-node/issues/3526
636
- corsAllowedOrigins: ['*'],
637
- rules: [rule],
638
- },
639
- skipCheckDynamicBlacklist: true,
640
- },
641
- context
642
- );
643
- logger.info('add routing site', { site: domain });
674
+ const existSite = await states.site.findOne({ domain: domainGroup });
675
+ if (!existSite) {
676
+ await routerManager.addRoutingSite(
677
+ {
678
+ site: {
679
+ domain: domainGroup,
680
+ domainAliases: [{ value: domain, isProtected: true }],
681
+ isProtected: true,
682
+ rules: [rule],
683
+ },
684
+ skipCheckDynamicBlacklist: true,
685
+ },
686
+ context
687
+ );
688
+ logger.info('add routing site', { site: domain });
644
689
 
645
- changed = true;
646
- } else {
647
- const existRule = (exist.rules || []).find((y) => get(y, 'from.pathPrefix') === pathPrefix);
648
- if (existRule) {
649
- await routerManager.updateRoutingRule({
650
- id: exist.id,
651
- rule: {
652
- ...rule,
653
- id: exist.id,
654
- },
655
- skipProtectedRuleChecking: true,
656
- });
657
- logger.info('update routing rule for site', { site: domain });
658
- } else {
659
- await routerManager.addRoutingRule({
660
- id: exist.id,
661
- rule,
662
- });
663
- logger.info('add routing rule for site', { site: domain });
664
- }
665
- changed = true;
666
- }
690
+ return true;
691
+ }
667
692
 
668
- return changed;
669
- })
670
- );
693
+ const existRule = (existSite.rules || []).find((y) => get(y, 'from.pathPrefix') === pathPrefix);
694
+ if (existRule) {
695
+ await routerManager.updateRoutingRule({
696
+ id: existSite.id,
697
+ rule: {
698
+ ...rule,
699
+ id: existRule.id,
700
+ },
701
+ skipProtectedRuleChecking: true,
702
+ });
703
+ logger.info('update routing rule for site', { site: domain });
704
+ } else {
705
+ await routerManager.addRoutingRule({
706
+ id: existSite.id,
707
+ rule,
708
+ });
709
+ logger.info('add routing rule for site', { site: domain });
710
+ }
671
711
 
672
- return changes.some(Boolean);
712
+ return true;
673
713
  };
674
714
 
675
715
  /**
@@ -684,7 +724,7 @@ module.exports = function getRouterHelpers({ dataDirs, routingSnapshot, routerMa
684
724
  }
685
725
 
686
726
  const tasks = (blocklet.meta.interfaces || [])
687
- .filter((x) => x.name === BLOCKLET_INTERFACE_WELLKNOWN)
727
+ .filter((x) => x.type === BLOCKLET_INTERFACE_TYPE_WELLKNOWN)
688
728
  .map(async (x) => {
689
729
  const pathPrefix = normalizePathPrefix(x.prefix);
690
730
  if (!pathPrefix.startsWith(WELLKNOWN_PATH_PREFIX)) {
@@ -811,30 +851,15 @@ module.exports = function getRouterHelpers({ dataDirs, routingSnapshot, routerMa
811
851
  };
812
852
 
813
853
  const _removeBlockletSites = async (blocklet, nodeInfo, context = {}) => {
814
- const interfaces = (blocklet.meta.interfaces || []).filter((x) => x.type === BLOCKLET_INTERFACE_TYPE_WEB);
815
-
816
- const changes = await Promise.all(
817
- interfaces.map(async (x) => {
818
- let changed = false;
819
-
820
- const domain = getIpDnsDomainForBlocklet(blocklet, x);
821
-
822
- const site = await states.site.findOne({ domain });
823
- if (
824
- site &&
825
- site.isProtected &&
826
- (!site.domainAliases || !site.domainAliases.length) &&
827
- (!site.rules || !site.rules.length)
828
- ) {
829
- await routerManager.deleteRoutingSite({ id: site.id }, context);
830
- changed = true;
831
- }
854
+ let changed = false;
832
855
 
833
- return changed;
834
- })
835
- );
856
+ const site = await states.site.findOne({ domain: `${blocklet.meta.did}${BLOCKLET_SITE_GROUP_SUFFIX}` });
857
+ if (site) {
858
+ await routerManager.deleteRoutingSite({ id: site.id }, context);
859
+ changed = true;
860
+ }
836
861
 
837
- return changes.some(Boolean);
862
+ return changed;
838
863
  };
839
864
 
840
865
  /**
@@ -854,8 +879,8 @@ module.exports = function getRouterHelpers({ dataDirs, routingSnapshot, routerMa
854
879
  return false;
855
880
  }
856
881
 
857
- const interfaces = (blocklet.meta.interfaces || []).filter((x) => x.type === BLOCKLET_INTERFACE_TYPE_WEB);
858
- if (interfaces.length === 0) {
882
+ const hasWebInterface = (blocklet.meta.interfaces || []).some((x) => x.type === BLOCKLET_INTERFACE_TYPE_WEB);
883
+ if (!hasWebInterface) {
859
884
  return false;
860
885
  }
861
886
 
@@ -886,9 +911,11 @@ module.exports = function getRouterHelpers({ dataDirs, routingSnapshot, routerMa
886
911
  * @returns {boolean} if routing changed
887
912
  */
888
913
  const ensureBlockletCustomRouting = async (blocklet) => {
914
+ // Only one blocklet web interface can be declared since router 2.0
889
915
  const interfaces = (blocklet.meta.interfaces || []).filter((x) => x.type === BLOCKLET_INTERFACE_TYPE_WEB);
890
916
  const hasInterface = (name) => interfaces.some((x) => x.name === name);
891
- const sites = await siteState.getRulesByDid(blocklet.meta.did);
917
+
918
+ const sites = await siteState.getSitesByBlocklet(blocklet.meta.did);
892
919
  let changed = false;
893
920
 
894
921
  for (const site of sites) {
@@ -1164,7 +1191,7 @@ module.exports = function getRouterHelpers({ dataDirs, routingSnapshot, routerMa
1164
1191
  if (msg.length < 5) {
1165
1192
  throw new Error('Message cannot be less than 5 characters');
1166
1193
  }
1167
- if (msg.length > 100) {
1194
+ if (msg.length > 150) {
1168
1195
  throw new Error('Message cannot exceed 100 characters');
1169
1196
  }
1170
1197
  }
@@ -1216,12 +1243,17 @@ module.exports = function getRouterHelpers({ dataDirs, routingSnapshot, routerMa
1216
1243
  return attachInterfaceUrls({
1217
1244
  sites: await ensureLatestInfo(sites, { withDefaultCors }),
1218
1245
  context,
1246
+ node: nodeState,
1219
1247
  });
1220
1248
  };
1221
1249
 
1222
1250
  const getSnapshotSites = async ({ hash }, context = {}, { withDefaultCors = true } = {}) => {
1223
1251
  const sites = await routingSnapshot.readSnapshotSites(hash);
1224
- return attachInterfaceUrls({ sites: await ensureLatestInfo(sites, { withDefaultCors }), context });
1252
+ return attachInterfaceUrls({
1253
+ sites: await ensureLatestInfo(sites, { withDefaultCors }),
1254
+ context,
1255
+ node: nodeState,
1256
+ });
1225
1257
  };
1226
1258
 
1227
1259
  const getCertificates = async () => {
@@ -1262,7 +1294,7 @@ module.exports = function getRouterHelpers({ dataDirs, routingSnapshot, routerMa
1262
1294
  logger.info('send certificate expire notification', { domain: cert.domain });
1263
1295
  notification.create({
1264
1296
  title: 'SSL Certificate Expired',
1265
- description: `Your SSL certificate for domain ${cert.domain} has expired, please update it in ABT Node`,
1297
+ description: `Your SSL certificate for domain ${cert.domain} has expired, please update it in Blocklet Server`,
1266
1298
  severity: 'error',
1267
1299
  entityType: 'certificate',
1268
1300
  entityId: cert._id, // eslint-disable-line no-underscore-dangle
@@ -1276,7 +1308,7 @@ module.exports = function getRouterHelpers({ dataDirs, routingSnapshot, routerMa
1276
1308
  cert.domain
1277
1309
  } will expire in ${expireInDays} days (on ${new Date(
1278
1310
  cert.validTo
1279
- ).toLocaleString()}), please remember to update it in ABT Node`,
1311
+ ).toLocaleString()}), please remember to update it in Blocklet Server`,
1280
1312
  severity: 'warning',
1281
1313
  entityType: 'certificate',
1282
1314
  entityId: cert._id, // eslint-disable-line no-underscore-dangle
@@ -6,6 +6,7 @@ const {
6
6
  ROUTING_RULE_TYPES,
7
7
  DEFAULT_DASHBOARD_DOMAIN,
8
8
  BLOCKLET_PROXY_PATH_PREFIX,
9
+ BLOCKLET_SITE_GROUP_SUFFIX,
9
10
  } = require('@abtnode/constant');
10
11
  const { BLOCKLET_UI_INTERFACES } = require('@blocklet/meta/lib/constants');
11
12
  const { pick } = require('lodash');
@@ -26,7 +27,11 @@ const expandSites = (sites = []) => {
26
27
  });
27
28
 
28
29
  delete site.domainAliases;
29
- result.push(site);
30
+
31
+ // skip site if domain is BLOCKLET_SITE_GROUP
32
+ if (!site.domain.endsWith(BLOCKLET_SITE_GROUP_SUFFIX)) {
33
+ result.push(site);
34
+ }
30
35
  });
31
36
 
32
37
  const defaultSite = result.find((site) => site.domain === DOMAIN_FOR_DEFAULT_SITE);
@@ -45,7 +50,10 @@ const mergeAllowedOrigins = (domain, allowedOrigins) => {
45
50
  origins.push(domain);
46
51
  }
47
52
 
48
- return origins;
53
+ // skip site if domain is BLOCKLET_SITE_GROUP
54
+ const res = origins.filter((x) => !x.endsWith(BLOCKLET_SITE_GROUP_SUFFIX));
55
+
56
+ return res;
49
57
  };
50
58
 
51
59
  const getRoutingTable = ({ sites, nodeInfo }) => {
@@ -121,7 +121,7 @@ class RouterManager extends EventEmitter {
121
121
  await this.validateRouterConfig('addRoutingSite', { site: newSite });
122
122
 
123
123
  const result = await states.site.add(newSite);
124
- await attachInterfaceUrls({ sites: result, context });
124
+ await attachInterfaceUrls({ sites: result, context, node: states.node });
125
125
 
126
126
  this.emit('router.site.created', result);
127
127
  return result;
@@ -181,7 +181,7 @@ class RouterManager extends EventEmitter {
181
181
  this.emit('router.site.updated', params.id);
182
182
 
183
183
  const dbSite = await states.site.findOne({ _id: params.id });
184
- await attachInterfaceUrls({ sites: dbSite, context });
184
+ await attachInterfaceUrls({ sites: dbSite, context, node: states.node });
185
185
  return dbSite;
186
186
  }
187
187
 
@@ -207,7 +207,7 @@ class RouterManager extends EventEmitter {
207
207
  logger.debug('add domain alias update result', { id, updateResult, domainAlias });
208
208
 
209
209
  const newSite = await states.site.findOne({ _id: id });
210
- await attachInterfaceUrls({ sites: newSite, context });
210
+ await attachInterfaceUrls({ sites: newSite, context, node: states.node });
211
211
 
212
212
  return newSite;
213
213
  }
@@ -230,7 +230,7 @@ class RouterManager extends EventEmitter {
230
230
  const updateResult = await states.site.update({ _id: id }, { $set: { domainAliases: dbSite.domainAliases } });
231
231
  logger.debug('remove domain alias update result', { id, updateResult, domainAlias });
232
232
 
233
- await attachInterfaceUrls({ sites: dbSite, context });
233
+ await attachInterfaceUrls({ sites: dbSite, context, node: states.node });
234
234
 
235
235
  return dbSite;
236
236
  }
@@ -265,7 +265,7 @@ class RouterManager extends EventEmitter {
265
265
  }
266
266
 
267
267
  const newSite = await states.site.findOne({ _id: id });
268
- await attachInterfaceUrls({ sites: newSite, context });
268
+ await attachInterfaceUrls({ sites: newSite, context, node: states.node });
269
269
 
270
270
  this.emit('router.rule.created', newSite);
271
271
  return newSite;
@@ -306,7 +306,7 @@ class RouterManager extends EventEmitter {
306
306
  logger.info('update result', { updateResult });
307
307
  const newSite = await states.site.findOne({ _id: id });
308
308
 
309
- await attachInterfaceUrls({ sites: newSite, context });
309
+ await attachInterfaceUrls({ sites: newSite, context, node: states.node });
310
310
 
311
311
  this.emit('router.rule.updated', newSite);
312
312
 
@@ -335,7 +335,7 @@ class RouterManager extends EventEmitter {
335
335
  logger.info('router.rule.removed', { id, ruleId });
336
336
  const newSite = await states.site.findOne({ _id: id });
337
337
 
338
- await attachInterfaceUrls({ sites: newSite, context });
338
+ await attachInterfaceUrls({ sites: newSite, context, node: states.node });
339
339
 
340
340
  this.emit('router.rule.removed', newSite);
341
341
  return newSite;
@@ -33,7 +33,7 @@ class SiteState extends BaseState {
33
33
  return SiteState.renameIdFiledName(result);
34
34
  }
35
35
 
36
- async getRulesByDid(did) {
36
+ async getSitesByBlocklet(did) {
37
37
  const rules = await this.asyncDB.find({ 'rules.to.did': did });
38
38
  return SiteState.renameIdFiledName(rules);
39
39
  }
@@ -190,7 +190,7 @@ class TeamManager extends EventEmitter {
190
190
  // first getRBAC after blocklet added
191
191
  if (!this.cache[did].rbac) {
192
192
  if (this.isNodeTeam(did)) {
193
- throw new Error('ABT Node rbac instance has not been initialized');
193
+ throw new Error('Blocklet Server rbac instance has not been initialized');
194
194
  }
195
195
 
196
196
  // FIXME: cross process lock
@@ -1,7 +1,7 @@
1
1
  const {
2
2
  NODE_REGISTER_URL,
3
- BLOCKLET_REGISTRY_URL,
4
- BLOCKLET_REGISTRY_URL_DEV,
3
+ BLOCKLET_STORE_URL,
4
+ BLOCKLET_STORE_URL_DEV,
5
5
  WEB_WALLET_URL,
6
6
  NODE_PACKAGE_NAME,
7
7
  NODE_COMMAND_NAME,
@@ -23,18 +23,18 @@ const defaultNodeConfigs = {
23
23
  blockletRegistryList: {
24
24
  getDefaultValue: () => [
25
25
  {
26
- name: 'Official Registry',
26
+ name: 'Official Store',
27
27
  description: 'ArcBlock official blocklet registry',
28
- url: BLOCKLET_REGISTRY_URL,
28
+ url: BLOCKLET_STORE_URL,
29
29
  logoUrl: '/logo.png',
30
30
  maintainer: 'arcblock',
31
31
  selected: true,
32
32
  protected: true,
33
33
  },
34
34
  {
35
- name: 'Dev Registry',
35
+ name: 'Dev Store',
36
36
  description: 'ArcBlock dev registry that contains demo and example blocklets',
37
- url: BLOCKLET_REGISTRY_URL_DEV,
37
+ url: BLOCKLET_STORE_URL_DEV,
38
38
  maintainer: 'arcblock',
39
39
  logoUrl: '/logo.png',
40
40
  selected: false,
package/lib/util/index.js CHANGED
@@ -29,7 +29,9 @@ const {
29
29
  ROUTING_RULE_TYPES,
30
30
  SLOT_FOR_IP_DNS_SITE,
31
31
  DEFAULT_IP_DNS_DOMAIN_SUFFIX,
32
+ BLOCKLET_SITE_GROUP_SUFFIX,
32
33
  } = require('@abtnode/constant');
34
+ const { BLOCKLET_INTERFACE_TYPE_WEB } = require('@blocklet/meta/lib/constants');
33
35
 
34
36
  const DEFAULT_WELLKNOWN_PORT = 8088;
35
37
 
@@ -137,7 +139,7 @@ const getAuthConfig = (rule, blocklet) => {
137
139
  // find interface in meta
138
140
  const interfaceName = rule.to.realInterfaceName;
139
141
  const { interfaces } = _blocklet.meta;
140
- const _interface = interfaces.find((x) => x.type === 'web' && x.name === interfaceName);
142
+ const _interface = interfaces.find((x) => x.type === BLOCKLET_INTERFACE_TYPE_WEB && x.name === interfaceName);
141
143
 
142
144
  if (!_interface) {
143
145
  return null;
@@ -155,13 +157,14 @@ const getAuthConfig = (rule, blocklet) => {
155
157
  return auth.config;
156
158
  };
157
159
 
158
- const getBlockletBaseUrls = ({ routingEnabled = false, port, sites = [], context = {}, blocklet, nodeIp }) => {
160
+ const getBlockletBaseUrls = ({ routingEnabled = false, port, rules = [], context = {}, blocklet, nodeIp }) => {
159
161
  let baseUrls = [];
160
162
 
161
- if (routingEnabled && Array.isArray(sites) && sites.length > 0) {
162
- baseUrls = sites
163
- .map((site) => {
164
- const host = getBlockletHost({ domain: site.from.domain, context, nodeIp });
163
+ if (routingEnabled && Array.isArray(rules) && rules.length > 0) {
164
+ baseUrls = rules
165
+ .filter((rule) => !(rule.from.domain || '').endsWith(BLOCKLET_SITE_GROUP_SUFFIX))
166
+ .map((rule) => {
167
+ const host = getBlockletHost({ domain: rule.from.domain, context, nodeIp });
165
168
  if (host) {
166
169
  let protocol = 'http'; // TODO: 这里固定为 http, 因为判断 url 是不是 https 和证书相关,这里实现的话比较复杂
167
170
  if (host.includes(DEFAULT_IP_DNS_DOMAIN_SUFFIX)) {
@@ -169,10 +172,10 @@ const getBlockletBaseUrls = ({ routingEnabled = false, port, sites = [], context
169
172
  }
170
173
 
171
174
  return {
172
- ruleId: site.id,
173
- baseUrl: `${protocol}://${host}/${trimSlash(site.from.pathPrefix)}`,
174
- interfaceName: get(site, 'to.interfaceName', ''),
175
- authConfig: getAuthConfig(site, blocklet),
175
+ ruleId: rule.id,
176
+ baseUrl: `${protocol}://${host}/${trimSlash(rule.from.pathPrefix)}`,
177
+ interfaceName: get(rule, 'to.interfaceName', ''),
178
+ authConfig: getAuthConfig(rule, blocklet),
176
179
  };
177
180
  }
178
181
 
@@ -188,7 +191,7 @@ const getBlockletBaseUrls = ({ routingEnabled = false, port, sites = [], context
188
191
  return baseUrls;
189
192
  };
190
193
 
191
- const getBlockletInterfaces = ({ blocklet, context, nodeInfo, sites, nodeIp }) => {
194
+ const getBlockletInterfaces = ({ blocklet, context, nodeInfo, routingRules, nodeIp }) => {
192
195
  const interfaces = [];
193
196
  (blocklet.meta.interfaces || []).forEach((x) => {
194
197
  if (x.port && x.port.external) {
@@ -196,7 +199,7 @@ const getBlockletInterfaces = ({ blocklet, context, nodeInfo, sites, nodeIp }) =
196
199
  const baseUrls = getBlockletBaseUrls({
197
200
  routingEnabled: false,
198
201
  port: x.port.external,
199
- sites: [],
202
+ rules: [],
200
203
  context,
201
204
  });
202
205
  baseUrls.forEach(({ baseUrl }) => interfaces.push({ type: x.type, name: x.name, url: baseUrl }));
@@ -206,9 +209,11 @@ const getBlockletInterfaces = ({ blocklet, context, nodeInfo, sites, nodeIp }) =
206
209
  const baseUrls = getBlockletBaseUrls({
207
210
  routingEnabled: isRoutingEnabled(nodeInfo.routing),
208
211
  port,
209
- sites: (sites || []).filter((r) => {
212
+ rules: (routingRules || []).filter((r) => {
210
213
  return (
211
214
  // don't show wellknown interface
215
+ r.to.type !== ROUTING_RULE_TYPES.GENERAL_PROXY &&
216
+ // LEGACY don't show wellknown interface
212
217
  r.to.interfaceName !== BLOCKLET_INTERFACE_WELLKNOWN &&
213
218
  // don't show child blocklet interface
214
219
  (!r.from.groupPathPrefix || r.from.pathPrefix === r.from.groupPathPrefix)
@@ -329,7 +334,7 @@ const getDataDirs = (dataDir) => ({
329
334
  services: path.join(dataDir, 'services'),
330
335
  });
331
336
 
332
- // Ensure data dir for ABT Node exists
337
+ // Ensure data dir for Blocklet Server exists
333
338
  const ensureDataDirs = (dataDir) => {
334
339
  try {
335
340
  logger.info('ensure data dir', { dataDir });
package/lib/util/ready.js CHANGED
@@ -29,19 +29,19 @@ const createStateReadyHandler =
29
29
  // eslint-disable-next-line no-underscore-dangle
30
30
  await states.node.remove({ _id: state._id });
31
31
  console.error('\n\x1b[31m======================================================');
32
- console.error(`Data dir: ${options.dataDir} is used by another ABT Node instance, abort!`);
33
- console.error('Sharing data dir between ABT Node instances may break things!');
32
+ console.error(`Data dir: ${options.dataDir} is used by another Blocklet Server instance, abort!`);
33
+ console.error('Sharing data dir between Blocklet Server instances may break things!');
34
34
  console.error('======================================================\x1b[0m');
35
35
  console.log('\nIf you intend to use this dir:');
36
- console.log(` 1. Stop ABT Node by ${chalk.cyan('abtnode stop --force')}`);
36
+ console.log(` 1. Stop Blocklet Server by ${chalk.cyan('abtnode stop --force')}`);
37
37
  console.log(` 2. Clear data dir by ${chalk.cyan(`rm -r ${options.dataDir}`)}`);
38
- console.log(` 3. Reinitialize and start ABT Node`);
38
+ console.log(' 3. Reinitialize and start Blocklet Server');
39
39
  process.exit(1);
40
40
  }
41
41
  }
42
42
  })
43
43
  .catch((err) => {
44
- console.error('Can not ready node state on ABT Node start:', err.message);
44
+ console.error('Can not ready node state on Blocklet Server start:', err.message);
45
45
  process.exit(1);
46
46
  });
47
47
  };
@@ -36,15 +36,15 @@ const checkNewVersion = async (params, context) => {
36
36
  const latestVersion = versions[0].version;
37
37
  if (semver.gt(latestVersion, info.version)) {
38
38
  // if (semver.gte(latestVersion, info.version)) {
39
- logger.info('New version found for abt node', {
39
+ logger.info('New version found for Blocklet Server', {
40
40
  latestVersion,
41
41
  currentVersion: info.version,
42
42
  nextVersion: info.nextVersion,
43
43
  });
44
44
  await states.node.updateNodeInfo({ nextVersion: latestVersion });
45
45
  await states.notification.create({
46
- title: 'ABT Node upgrade available',
47
- description: 'A new and improved version of ABT Node is now available',
46
+ title: 'Blocklet Server upgrade available',
47
+ description: 'A new and improved version of blocklet server is now available',
48
48
  entityType: 'node',
49
49
  severity: 'info',
50
50
  sticky: true,
@@ -57,7 +57,7 @@ const checkNewVersion = async (params, context) => {
57
57
 
58
58
  return '';
59
59
  } catch (err) {
60
- logger.error('Failed to check new version for abt node', { error: err });
60
+ logger.error('Failed to check new version for Blocklet Server', { error: err });
61
61
  }
62
62
 
63
63
  return '';
@@ -83,6 +83,13 @@ const corsSchema = Joi.array()
83
83
 
84
84
  const ruleJoiSchema = Joi.object(ruleSchema);
85
85
 
86
+ const addDomainAlias = Joi.alternatives()
87
+ .try(
88
+ Joi.string().domain({ minDomainSegments: 1, tlds: false }),
89
+ Joi.string().regex(WILDCARD_DOMAIN_REGEX) // 这种其实是一种特殊的 tld
90
+ )
91
+ .required();
92
+
86
93
  const addSiteSchema = Joi.object({
87
94
  domain: Joi.alternatives()
88
95
  .try(
@@ -92,6 +99,12 @@ const addSiteSchema = Joi.object({
92
99
  )
93
100
  .required()
94
101
  .messages(domainMessages),
102
+ domainAliases: Joi.array().items(
103
+ Joi.object({
104
+ value: addDomainAlias,
105
+ isProtected: Joi.boolean(),
106
+ })
107
+ ),
95
108
  isProtected: Joi.boolean(),
96
109
  rules: Joi.array().items(ruleJoiSchema),
97
110
  corsAllowedOrigins: corsSchema,
@@ -109,13 +122,6 @@ const updateSite = Joi.object({
109
122
  .messages(domainMessages),
110
123
  });
111
124
 
112
- const addDomainAlias = Joi.alternatives()
113
- .try(
114
- Joi.string().domain({ minDomainSegments: 1, tlds: false }),
115
- Joi.string().regex(WILDCARD_DOMAIN_REGEX) // 这种其实是一种特殊的 tld
116
- )
117
- .required();
118
-
119
125
  const addRuleSchema = Joi.object({
120
126
  id: Joi.string().required(),
121
127
  rule: ruleJoiSchema,
@@ -15,7 +15,7 @@ const getSlackUrlInfo = (actionPath = '/notifications', urls) => {
15
15
  type: 'section',
16
16
  text: {
17
17
  type: 'mrkdwn',
18
- text: 'Use the following links to visit the blocklet detail on your ABT Node dashboard:',
18
+ text: 'Use the following links to visit the blocklet detail on your Blocklet Server dashboard:',
19
19
  },
20
20
  });
21
21
  } else {
@@ -23,7 +23,7 @@ const getSlackUrlInfo = (actionPath = '/notifications', urls) => {
23
23
  type: 'section',
24
24
  text: {
25
25
  type: 'mrkdwn',
26
- text: 'Use the following links to visit your ABT Node dashboard:',
26
+ text: 'Use the following links to visit your Blocklet Server dashboard:',
27
27
  },
28
28
  });
29
29
  }
@@ -56,7 +56,7 @@ class SlackSender extends BaseSender {
56
56
 
57
57
  await webhook.send({
58
58
  ...messageTypes[type],
59
- username: 'ABT Node',
59
+ username: 'Blocklet Server',
60
60
  icon_url: 'https://releases.arcblockio.cn/arcblock.png',
61
61
  });
62
62
  } catch (error) {
package/package.json CHANGED
@@ -3,7 +3,7 @@
3
3
  "publishConfig": {
4
4
  "access": "public"
5
5
  },
6
- "version": "1.5.14",
6
+ "version": "1.5.15",
7
7
  "description": "",
8
8
  "main": "lib/index.js",
9
9
  "files": [
@@ -19,26 +19,26 @@
19
19
  "author": "wangshijun <wangshijun2010@gmail.com> (http://github.com/wangshijun)",
20
20
  "license": "MIT",
21
21
  "dependencies": {
22
- "@abtnode/constant": "1.5.14",
23
- "@abtnode/cron": "1.5.14",
24
- "@abtnode/logger": "1.5.14",
25
- "@abtnode/queue": "1.5.14",
26
- "@abtnode/rbac": "1.5.14",
27
- "@abtnode/router-provider": "1.5.14",
28
- "@abtnode/static-server": "1.5.14",
29
- "@abtnode/timemachine": "1.5.14",
30
- "@abtnode/util": "1.5.14",
31
- "@arcblock/did": "^1.13.60",
32
- "@arcblock/event-hub": "1.13.60",
22
+ "@abtnode/constant": "1.5.15",
23
+ "@abtnode/cron": "1.5.15",
24
+ "@abtnode/logger": "1.5.15",
25
+ "@abtnode/queue": "1.5.15",
26
+ "@abtnode/rbac": "1.5.15",
27
+ "@abtnode/router-provider": "1.5.15",
28
+ "@abtnode/static-server": "1.5.15",
29
+ "@abtnode/timemachine": "1.5.15",
30
+ "@abtnode/util": "1.5.15",
31
+ "@arcblock/did": "^1.13.61",
32
+ "@arcblock/event-hub": "1.13.61",
33
33
  "@arcblock/pm2-events": "^0.0.5",
34
- "@arcblock/vc": "^1.13.60",
35
- "@blocklet/meta": "1.5.14",
34
+ "@arcblock/vc": "^1.13.61",
35
+ "@blocklet/meta": "1.5.15",
36
36
  "@fidm/x509": "^1.2.1",
37
37
  "@nedb/core": "^1.2.2",
38
38
  "@nedb/multi": "^1.2.2",
39
- "@ocap/mcrypto": "^1.13.60",
40
- "@ocap/util": "^1.13.60",
41
- "@ocap/wallet": "^1.13.60",
39
+ "@ocap/mcrypto": "^1.13.61",
40
+ "@ocap/util": "^1.13.61",
41
+ "@ocap/wallet": "^1.13.61",
42
42
  "@slack/webhook": "^5.0.3",
43
43
  "axios": "^0.21.4",
44
44
  "axon": "^2.0.3",
@@ -73,5 +73,5 @@
73
73
  "express": "^4.17.1",
74
74
  "jest": "^27.3.1"
75
75
  },
76
- "gitHead": "9759378266a2d13a5083398490c7baed39e19f31"
76
+ "gitHead": "dae9d209af2576152ad85f13a2fc4855969608ed"
77
77
  }