@abtnode/core 1.4.13 → 1.4.14
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/blocklet/manager/disk.js +3 -1
- package/lib/index.js +0 -2
- package/lib/router/helper.js +58 -161
- package/lib/router/index.js +21 -2
- package/lib/states/blocklet.js +8 -7
- package/lib/util/blocklet.js +23 -15
- package/lib/util/get-accessible-external-node-ip.js +41 -0
- package/lib/util/get-ip-dns-domain-for-blocklet.js +5 -2
- package/lib/util/index.js +33 -18
- package/lib/util/upgrade.js +5 -1
- package/package.json +18 -18
- package/lib/util/get-accessible-ip.js +0 -42
|
@@ -34,6 +34,7 @@ const {
|
|
|
34
34
|
fromBlockletSource,
|
|
35
35
|
} = require('@blocklet/meta/lib/constants');
|
|
36
36
|
const util = require('../../util');
|
|
37
|
+
const getAccessibleExternalNodeIp = require('../../util/get-accessible-external-node-ip');
|
|
37
38
|
const {
|
|
38
39
|
forEachBlocklet,
|
|
39
40
|
getBlockletDirs,
|
|
@@ -900,7 +901,8 @@ class BlockletManager extends BaseBlockletManager {
|
|
|
900
901
|
// Put shorter url first
|
|
901
902
|
return a.from.pathPrefix.length < b.from.pathPrefix ? 1 : -1;
|
|
902
903
|
});
|
|
903
|
-
|
|
904
|
+
const nodeIp = await getAccessibleExternalNodeIp(nodeInfo);
|
|
905
|
+
blocklet.interfaces = getBlockletInterfaces({ blocklet, context, nodeInfo, sites: routingRules, nodeIp });
|
|
904
906
|
|
|
905
907
|
try {
|
|
906
908
|
const { appId } = blocklet.meta.group === BlockletGroup.gateway ? blocklet.children[0].env : blocklet.env;
|
package/lib/index.js
CHANGED
|
@@ -129,7 +129,6 @@ function ABTNode(options) {
|
|
|
129
129
|
getRoutingSites,
|
|
130
130
|
getSnapshotSites,
|
|
131
131
|
ensureDashboardRouting,
|
|
132
|
-
ensureIpDnsRouting,
|
|
133
132
|
ensureBlockletRouting,
|
|
134
133
|
ensureBlockletRoutingForUpgrade,
|
|
135
134
|
removeBlockletRouting,
|
|
@@ -305,7 +304,6 @@ function ABTNode(options) {
|
|
|
305
304
|
takeRoutingSnapshot,
|
|
306
305
|
getSitesFromSnapshot,
|
|
307
306
|
ensureDashboardRouting,
|
|
308
|
-
ensureIpDnsRouting,
|
|
309
307
|
|
|
310
308
|
addDomainAlias: routerManager.addDomainAlias.bind(routerManager),
|
|
311
309
|
deleteDomainAlias: routerManager.deleteDomainAlias.bind(routerManager),
|
package/lib/router/helper.js
CHANGED
|
@@ -24,7 +24,6 @@ const {
|
|
|
24
24
|
ROUTING_RULE_TYPES,
|
|
25
25
|
CERTIFICATE_EXPIRES_OFFSET,
|
|
26
26
|
CERTIFICATE_EXPIRES_WARNING_OFFSET,
|
|
27
|
-
DEFAULT_DASHBOARD_DOMAIN,
|
|
28
27
|
DEFAULT_DAEMON_PORT,
|
|
29
28
|
} = require('@abtnode/constant');
|
|
30
29
|
const {
|
|
@@ -45,7 +44,6 @@ const {
|
|
|
45
44
|
getWellknownSitePort,
|
|
46
45
|
} = require('../util');
|
|
47
46
|
const { getServicesFromBlockletInterface } = require('../util/service');
|
|
48
|
-
const { getAccessibleIp, getAccessibleIpDnsDomainForNode } = require('../util/get-accessible-ip');
|
|
49
47
|
const getIpDnsDomainForBlocklet = require('../util/get-ip-dns-domain-for-blocklet');
|
|
50
48
|
|
|
51
49
|
const Router = require('./index');
|
|
@@ -321,27 +319,6 @@ module.exports = function getRouterHelpers({ dataDirs, routingSnapshot, routerMa
|
|
|
321
319
|
const httpsCertState = states.certificate;
|
|
322
320
|
const notification = states.notification;
|
|
323
321
|
|
|
324
|
-
let _nodeDomainRequest = null; // singleton of node-domain-request
|
|
325
|
-
const _getIpDnsDomainForNode = ({ nodeInfo = {} } = {}) => {
|
|
326
|
-
const timeout = process.env.NODE_ENV === 'test' ? 500 : 5000;
|
|
327
|
-
if (_nodeDomainRequest) {
|
|
328
|
-
return _nodeDomainRequest;
|
|
329
|
-
}
|
|
330
|
-
|
|
331
|
-
const req = getAccessibleIpDnsDomainForNode({ nodeInfo, timeout });
|
|
332
|
-
_nodeDomainRequest = req;
|
|
333
|
-
|
|
334
|
-
req
|
|
335
|
-
.then(() => {
|
|
336
|
-
_nodeDomainRequest = null;
|
|
337
|
-
})
|
|
338
|
-
.catch(() => {
|
|
339
|
-
_nodeDomainRequest = null;
|
|
340
|
-
});
|
|
341
|
-
|
|
342
|
-
return req;
|
|
343
|
-
};
|
|
344
|
-
|
|
345
322
|
// site level duplication detection
|
|
346
323
|
const hasRuleByPrefix = (site, value) => site.rules.find((x) => x.isProtected && get(x, 'from.pathPrefix') === value);
|
|
347
324
|
|
|
@@ -580,13 +557,6 @@ module.exports = function getRouterHelpers({ dataDirs, routingSnapshot, routerMa
|
|
|
580
557
|
const _ensureBlockletSites = async (blocklet, sites, nodeInfo, context = {}) => {
|
|
581
558
|
const interfaces = (blocklet.meta.interfaces || []).filter((x) => x.type === BLOCKLET_INTERFACE_TYPE_WEB);
|
|
582
559
|
|
|
583
|
-
const nodeDomain = await _getIpDnsDomainForNode({ nodeInfo });
|
|
584
|
-
|
|
585
|
-
if (!nodeDomain) {
|
|
586
|
-
logger.error('IpDnsDomain of abtnode does not found');
|
|
587
|
-
return false;
|
|
588
|
-
}
|
|
589
|
-
|
|
590
560
|
const getPrefix = (str) => {
|
|
591
561
|
if (!str || str === '*') {
|
|
592
562
|
return '/';
|
|
@@ -596,34 +566,57 @@ module.exports = function getRouterHelpers({ dataDirs, routingSnapshot, routerMa
|
|
|
596
566
|
|
|
597
567
|
const changes = await Promise.all(
|
|
598
568
|
interfaces.map(async (x) => {
|
|
599
|
-
|
|
569
|
+
const domain = getIpDnsDomainForBlocklet(blocklet, x);
|
|
570
|
+
const pathPrefix = getPrefix(x.prefix);
|
|
571
|
+
const rule = {
|
|
572
|
+
from: { pathPrefix },
|
|
573
|
+
to: {
|
|
574
|
+
port: findInterfacePortByName(blocklet, x.name),
|
|
575
|
+
did: blocklet.meta.did,
|
|
576
|
+
type: ROUTING_RULE_TYPES.BLOCKLET,
|
|
577
|
+
interfaceName: x.name, // root blocklet interface
|
|
578
|
+
},
|
|
579
|
+
isProtected: true,
|
|
580
|
+
};
|
|
600
581
|
|
|
601
|
-
|
|
582
|
+
let changed = false; // if state db changed
|
|
602
583
|
|
|
603
|
-
|
|
584
|
+
const exist = await states.site.findOne({ domain });
|
|
585
|
+
if (!exist) {
|
|
604
586
|
await routerManager.addRoutingSite(
|
|
605
587
|
{
|
|
606
588
|
site: {
|
|
607
589
|
domain,
|
|
608
590
|
isProtected: true,
|
|
609
|
-
rules: [
|
|
610
|
-
{
|
|
611
|
-
from: { pathPrefix: getPrefix(x.prefix) },
|
|
612
|
-
to: {
|
|
613
|
-
port: findInterfacePortByName(blocklet, x.name),
|
|
614
|
-
did: blocklet.meta.did,
|
|
615
|
-
type: ROUTING_RULE_TYPES.BLOCKLET,
|
|
616
|
-
interfaceName: x.name, // root blocklet interface
|
|
617
|
-
},
|
|
618
|
-
isProtected: true,
|
|
619
|
-
},
|
|
620
|
-
],
|
|
591
|
+
rules: [rule],
|
|
621
592
|
},
|
|
622
593
|
skipCheckDynamicBlacklist: true,
|
|
623
594
|
},
|
|
624
595
|
context
|
|
625
596
|
);
|
|
597
|
+
logger.info('add routing site', { site: domain });
|
|
626
598
|
|
|
599
|
+
changed = true;
|
|
600
|
+
} else {
|
|
601
|
+
const existRule = (exist.rules || []).find((y) => get(y, 'from.pathPrefix') === pathPrefix);
|
|
602
|
+
if (existRule) {
|
|
603
|
+
await routerManager.updateRoutingRule({
|
|
604
|
+
id: exist.id,
|
|
605
|
+
rule: {
|
|
606
|
+
...rule,
|
|
607
|
+
id: exist.id,
|
|
608
|
+
},
|
|
609
|
+
skipProtectedRuleChecking: true,
|
|
610
|
+
});
|
|
611
|
+
logger.info('update routing rule for site', { site: domain });
|
|
612
|
+
} else {
|
|
613
|
+
await routerManager.addRoutingRule({
|
|
614
|
+
id: exist.id,
|
|
615
|
+
rule,
|
|
616
|
+
skipProtectedRuleChecking: true,
|
|
617
|
+
});
|
|
618
|
+
logger.info('add routing rule for site', { site: domain });
|
|
619
|
+
}
|
|
627
620
|
changed = true;
|
|
628
621
|
}
|
|
629
622
|
|
|
@@ -773,14 +766,13 @@ module.exports = function getRouterHelpers({ dataDirs, routingSnapshot, routerMa
|
|
|
773
766
|
};
|
|
774
767
|
|
|
775
768
|
const _removeBlockletSites = async (blocklet, nodeInfo, context = {}) => {
|
|
776
|
-
const nodeDomain = await _getIpDnsDomainForNode({ nodeInfo });
|
|
777
769
|
const interfaces = (blocklet.meta.interfaces || []).filter((x) => x.type === BLOCKLET_INTERFACE_TYPE_WEB);
|
|
778
770
|
|
|
779
771
|
const changes = await Promise.all(
|
|
780
772
|
interfaces.map(async (x) => {
|
|
781
773
|
let changed = false;
|
|
782
774
|
|
|
783
|
-
const domain = getIpDnsDomainForBlocklet(blocklet, x
|
|
775
|
+
const domain = getIpDnsDomainForBlocklet(blocklet, x);
|
|
784
776
|
|
|
785
777
|
const site = await states.site.findOne({ domain });
|
|
786
778
|
if (
|
|
@@ -824,11 +816,20 @@ module.exports = function getRouterHelpers({ dataDirs, routingSnapshot, routerMa
|
|
|
824
816
|
|
|
825
817
|
const sites = await siteState.getSites();
|
|
826
818
|
|
|
827
|
-
const
|
|
828
|
-
_ensureBlockletRulesForDashboardSite(blocklet, sites, nodeInfo, context),
|
|
819
|
+
const tasks = [
|
|
829
820
|
_ensureBlockletRulesForWellknownSite(blocklet, sites, context),
|
|
830
821
|
_ensureBlockletSites(blocklet, sites, nodeInfo, context),
|
|
831
|
-
]
|
|
822
|
+
];
|
|
823
|
+
|
|
824
|
+
if (nodeInfo.mode === NODE_MODES.DEBUG || ['e2e', 'test'].includes(process.env.NODE_ENV)) {
|
|
825
|
+
logger.info('Add blocklet endpoint in dashboard site', {
|
|
826
|
+
nodeMode: nodeInfo.mode,
|
|
827
|
+
NODE_ENV: process.env.NODE_ENV,
|
|
828
|
+
});
|
|
829
|
+
tasks.push(_ensureBlockletRulesForDashboardSite(blocklet, sites, nodeInfo, context));
|
|
830
|
+
}
|
|
831
|
+
|
|
832
|
+
const changes = await Promise.all(tasks);
|
|
832
833
|
|
|
833
834
|
return changes.some(Boolean);
|
|
834
835
|
};
|
|
@@ -846,72 +847,14 @@ module.exports = function getRouterHelpers({ dataDirs, routingSnapshot, routerMa
|
|
|
846
847
|
return false;
|
|
847
848
|
}
|
|
848
849
|
|
|
849
|
-
|
|
850
|
-
|
|
851
|
-
|
|
852
|
-
|
|
853
|
-
|
|
854
|
-
return routerManager.deleteRoutingRulesItemByDid({ did: blocklet.meta.did }, context);
|
|
855
|
-
}
|
|
856
|
-
|
|
857
|
-
// First, we need ensure system rules for blocklet on dashboard site
|
|
858
|
-
let changed = await ensureBlockletRouting(blocklet, context);
|
|
859
|
-
|
|
860
|
-
// Then, we need to remove rules whose corresponding interface is not there any more
|
|
861
|
-
const sites = await siteState.getRulesByDid(blocklet.meta.did);
|
|
862
|
-
for (const site of sites) {
|
|
863
|
-
const rulesToRemove = [];
|
|
864
|
-
const rulesToUpdate = [];
|
|
865
|
-
for (const rule of site.rules) {
|
|
866
|
-
if (
|
|
867
|
-
rule.to.type !== ROUTING_RULE_TYPES.BLOCKLET ||
|
|
868
|
-
!rule.to.interfaceName ||
|
|
869
|
-
rule.to.did !== blocklet.meta.did
|
|
870
|
-
) {
|
|
871
|
-
// eslint-disable-next-line no-continue
|
|
872
|
-
continue;
|
|
873
|
-
}
|
|
874
|
-
|
|
875
|
-
if (hasInterface(rule.to.interfaceName) === false) {
|
|
876
|
-
rulesToRemove.push(rule.id);
|
|
877
|
-
}
|
|
878
|
-
|
|
879
|
-
if (rule.to.type === ROUTING_RULE_TYPES.BLOCKLET && rule.id === rule.groupId && !rule.isProtected) {
|
|
880
|
-
rulesToUpdate.push(rule);
|
|
881
|
-
}
|
|
882
|
-
}
|
|
883
|
-
|
|
884
|
-
for (const rule of rulesToUpdate) {
|
|
885
|
-
// eslint-disable-next-line no-await-in-loop
|
|
886
|
-
await routerManager.updateRoutingRule({ id: site.id, rule });
|
|
887
|
-
changed = true;
|
|
888
|
-
}
|
|
889
|
-
|
|
890
|
-
if (rulesToRemove.length === 0) {
|
|
891
|
-
// eslint-disable-next-line no-continue
|
|
892
|
-
continue;
|
|
893
|
-
}
|
|
894
|
-
|
|
895
|
-
try {
|
|
896
|
-
// eslint-disable-next-line no-await-in-loop
|
|
897
|
-
await states.site.update(
|
|
898
|
-
{ _id: site.id },
|
|
899
|
-
{ $set: { rules: site.rules.filter((x) => rulesToRemove.includes(x.id) === false) } }
|
|
900
|
-
);
|
|
901
|
-
changed = true;
|
|
902
|
-
logger.info('remove routing rule since interface does not exist', { rulesToRemove, did: blocklet.meta.did });
|
|
903
|
-
} catch (err) {
|
|
904
|
-
logger.error('failed to remove routing rule since interface does not exist', {
|
|
905
|
-
rulesToRemove,
|
|
906
|
-
did: blocklet.meta.did,
|
|
907
|
-
error: err,
|
|
908
|
-
});
|
|
909
|
-
}
|
|
910
|
-
}
|
|
911
|
-
|
|
912
|
-
await _removeBlockletSites(blocklet, nodeInfo, context);
|
|
850
|
+
await routerManager.deleteRoutingRulesItemByDid(
|
|
851
|
+
{ did: blocklet.meta.did, ruleFilter: (x) => x.isProtected },
|
|
852
|
+
context
|
|
853
|
+
);
|
|
854
|
+
await ensureBlockletRouting(blocklet, context);
|
|
913
855
|
|
|
914
|
-
return
|
|
856
|
+
// Always return true to trigger update of provider
|
|
857
|
+
return true;
|
|
915
858
|
};
|
|
916
859
|
|
|
917
860
|
/**
|
|
@@ -928,51 +871,6 @@ module.exports = function getRouterHelpers({ dataDirs, routingSnapshot, routerMa
|
|
|
928
871
|
return ruleChanged || siteChanged;
|
|
929
872
|
};
|
|
930
873
|
|
|
931
|
-
/**
|
|
932
|
-
* Refresh ip of in ip-dns-domain if ip changed
|
|
933
|
-
*/
|
|
934
|
-
const ensureIpDnsRouting = async (context = {}, output) => {
|
|
935
|
-
const nodeInfo = await nodeState.read();
|
|
936
|
-
const sites = await siteState.getSites();
|
|
937
|
-
|
|
938
|
-
const ip = await getAccessibleIp(nodeInfo);
|
|
939
|
-
if (!ip) {
|
|
940
|
-
logger.error('Cannot get get accessible ip for this node');
|
|
941
|
-
return false;
|
|
942
|
-
}
|
|
943
|
-
|
|
944
|
-
const formattedIp = ip.replace(/\./g, '-');
|
|
945
|
-
const suffix = DEFAULT_DASHBOARD_DOMAIN.replace(/^\*/, '');
|
|
946
|
-
const domainSuffixRegex = new RegExp(`(\\d+-\\d+-\\d+-\\d+)${suffix.replace(/\./g, '\\.')}$`); // xxx-xxx-xxx-xxx.ip.abtnet.io
|
|
947
|
-
const domainSuffix = `${formattedIp}${suffix}`;
|
|
948
|
-
|
|
949
|
-
const changes = [];
|
|
950
|
-
|
|
951
|
-
sites.forEach((x) => {
|
|
952
|
-
const match = domainSuffixRegex.exec(x.domain);
|
|
953
|
-
if (match && match[1] !== formattedIp) {
|
|
954
|
-
const domain = x.domain.replace(domainSuffixRegex, domainSuffix);
|
|
955
|
-
changes.push({ id: x.id, domain });
|
|
956
|
-
}
|
|
957
|
-
});
|
|
958
|
-
|
|
959
|
-
if (changes.length) {
|
|
960
|
-
for (const change of changes) {
|
|
961
|
-
// eslint-disable-next-line no-await-in-loop
|
|
962
|
-
await siteState.update({ _id: change.id }, { $set: { domain: change.domain } });
|
|
963
|
-
if (typeof output === 'function') {
|
|
964
|
-
output(`Blocklet endpoint was updated: ${change.domain}`);
|
|
965
|
-
}
|
|
966
|
-
}
|
|
967
|
-
|
|
968
|
-
const hash = await takeRoutingSnapshot({ message: 'ensure ip dns routing rules', dryRun: false }, context);
|
|
969
|
-
logger.info('take routing snapshot on ensure dashboard routing rules', { changes, hash });
|
|
970
|
-
return true;
|
|
971
|
-
}
|
|
972
|
-
|
|
973
|
-
return false;
|
|
974
|
-
};
|
|
975
|
-
|
|
976
874
|
async function readRoutingSites() {
|
|
977
875
|
const info = await nodeState.read();
|
|
978
876
|
let snapshotHash = get(info, 'routing.snapshotHash', null);
|
|
@@ -1282,7 +1180,6 @@ module.exports = function getRouterHelpers({ dataDirs, routingSnapshot, routerMa
|
|
|
1282
1180
|
getCertificates,
|
|
1283
1181
|
getSitesFromSnapshot,
|
|
1284
1182
|
checkDomain,
|
|
1285
|
-
ensureIpDnsRouting,
|
|
1286
1183
|
|
|
1287
1184
|
getRoutingCrons: () => [
|
|
1288
1185
|
{
|
package/lib/router/index.js
CHANGED
|
@@ -48,6 +48,23 @@ const mergeAllowedOrigins = (domain, allowedOrigins) => {
|
|
|
48
48
|
return origins;
|
|
49
49
|
};
|
|
50
50
|
|
|
51
|
+
const getRoutingTable = ({ sites, nodeInfo }) => {
|
|
52
|
+
let routingTable = Router.formatSites(sites);
|
|
53
|
+
routingTable = expandSites(routingTable);
|
|
54
|
+
|
|
55
|
+
// put dashboardDomain to last, to let blockletDomain match first
|
|
56
|
+
// e.g.
|
|
57
|
+
// dashboardDomain: 192-168-3-2.ip.abtnet.io
|
|
58
|
+
// blockletDomain: static-demo-xxx-192-168-3-2.ip.abtnet.io
|
|
59
|
+
const dashboardDomain = get(nodeInfo, 'routing.dashboardDomain', '');
|
|
60
|
+
const index = routingTable.findIndex((x) => x.domain === dashboardDomain);
|
|
61
|
+
if (index > -1) {
|
|
62
|
+
routingTable.push(...routingTable.splice(index, 1));
|
|
63
|
+
}
|
|
64
|
+
|
|
65
|
+
return routingTable;
|
|
66
|
+
};
|
|
67
|
+
|
|
51
68
|
class Router {
|
|
52
69
|
/**
|
|
53
70
|
* Router
|
|
@@ -77,12 +94,13 @@ class Router {
|
|
|
77
94
|
|
|
78
95
|
logger.info('updateRoutingTable sites:', { sites });
|
|
79
96
|
|
|
80
|
-
this.routingTable =
|
|
97
|
+
this.routingTable = getRoutingTable({ sites, nodeInfo });
|
|
98
|
+
|
|
81
99
|
logger.info('updateRoutingTable routingTable:', { routingTable: this.routingTable });
|
|
82
100
|
logger.info('updateRoutingTable certificates:', { certificates: certificates.map((item) => item.domain) });
|
|
83
101
|
|
|
84
102
|
await this.provider.update({
|
|
85
|
-
routingTable:
|
|
103
|
+
routingTable: this.routingTable,
|
|
86
104
|
certificates,
|
|
87
105
|
globalHeaders: headers,
|
|
88
106
|
services,
|
|
@@ -218,5 +236,6 @@ Router.flattenSitesToRules = (sites = [], info = {}) => {
|
|
|
218
236
|
};
|
|
219
237
|
|
|
220
238
|
Router._expandSites = expandSites; // eslint-disable-line no-underscore-dangle
|
|
239
|
+
Router._getRoutingTable = getRoutingTable; // eslint-disable-line no-underscore-dangle
|
|
221
240
|
|
|
222
241
|
module.exports = Router;
|
package/lib/states/blocklet.js
CHANGED
|
@@ -1,6 +1,7 @@
|
|
|
1
1
|
/* eslint-disable no-await-in-loop */
|
|
2
2
|
/* eslint-disable function-paren-newline */
|
|
3
3
|
/* eslint-disable no-underscore-dangle */
|
|
4
|
+
const omit = require('lodash/omit');
|
|
4
5
|
const uniq = require('lodash/uniq');
|
|
5
6
|
const detectPort = require('detect-port');
|
|
6
7
|
const Lock = require('@abtnode/util/lib/lock');
|
|
@@ -128,8 +129,6 @@ class BlockletState extends BaseState {
|
|
|
128
129
|
// get ports
|
|
129
130
|
await lock.acquire();
|
|
130
131
|
|
|
131
|
-
delete meta.htmlAst;
|
|
132
|
-
|
|
133
132
|
const ports = await this.getBlockletPorts({ interfaces: sanitized.interfaces || [] });
|
|
134
133
|
|
|
135
134
|
const children = await this.fillChildrenPorts(this.getChildrenFromMetas(childrenMeta), {
|
|
@@ -140,7 +139,7 @@ class BlockletState extends BaseState {
|
|
|
140
139
|
this.db.insert(
|
|
141
140
|
{
|
|
142
141
|
mode,
|
|
143
|
-
meta: sanitized,
|
|
142
|
+
meta: omit(sanitized, ['htmlAst']),
|
|
144
143
|
status,
|
|
145
144
|
source,
|
|
146
145
|
deployedFrom,
|
|
@@ -177,13 +176,15 @@ class BlockletState extends BaseState {
|
|
|
177
176
|
}
|
|
178
177
|
|
|
179
178
|
try {
|
|
179
|
+
fixPerson(meta);
|
|
180
|
+
fixInterfaces(meta);
|
|
181
|
+
const sanitized = validateBlockletMeta(meta);
|
|
182
|
+
|
|
180
183
|
// get ports
|
|
181
184
|
await lock.acquire();
|
|
182
185
|
|
|
183
|
-
delete meta.htmlAst;
|
|
184
|
-
|
|
185
186
|
const ports = await this.getBlockletPorts({
|
|
186
|
-
interfaces:
|
|
187
|
+
interfaces: sanitized.interfaces || [],
|
|
187
188
|
skipOccupiedCheckPorts: getExternalPortsFromMeta(doc.meta),
|
|
188
189
|
});
|
|
189
190
|
Object.keys(ports).forEach((p) => {
|
|
@@ -197,7 +198,7 @@ class BlockletState extends BaseState {
|
|
|
197
198
|
// add to db
|
|
198
199
|
const newDoc = await this.updateById(doc._id, {
|
|
199
200
|
$set: {
|
|
200
|
-
meta,
|
|
201
|
+
meta: omit(sanitized, ['htmlAst']),
|
|
201
202
|
source,
|
|
202
203
|
deployedFrom,
|
|
203
204
|
children,
|
package/lib/util/blocklet.js
CHANGED
|
@@ -223,25 +223,36 @@ const ensureBlockletExpanded = async (meta, appDir) => {
|
|
|
223
223
|
const getRootSystemEnvironments = (blocklet, nodeInfo) => {
|
|
224
224
|
const { did, name, title, description } = blocklet.meta;
|
|
225
225
|
let wallet;
|
|
226
|
-
let
|
|
227
|
-
let
|
|
226
|
+
let appSk;
|
|
227
|
+
let appId;
|
|
228
|
+
let appName = title || name;
|
|
229
|
+
let appDescription = description || '';
|
|
228
230
|
|
|
229
231
|
if (process.env.NODE_ENV !== 'test') {
|
|
230
|
-
const
|
|
232
|
+
const keys = Object.keys(BLOCKLET_CONFIGURABLE_KEY);
|
|
233
|
+
const result = getBlockletInfo(
|
|
234
|
+
{
|
|
235
|
+
meta: blocklet.meta,
|
|
236
|
+
environments: keys.map((key) => ({ key, value: blocklet.configObj[key] })).filter((x) => x.value),
|
|
237
|
+
},
|
|
238
|
+
nodeInfo.sk
|
|
239
|
+
);
|
|
231
240
|
wallet = result.wallet;
|
|
232
|
-
|
|
233
|
-
|
|
241
|
+
appSk = toHex(wallet.secretKey);
|
|
242
|
+
appId = wallet.toAddress();
|
|
243
|
+
appName = appName || result.name;
|
|
244
|
+
appDescription = appDescription || result.description;
|
|
234
245
|
} else {
|
|
235
|
-
|
|
236
|
-
|
|
246
|
+
appSk = 'AppSK:FIXME:WalletWorksFailedInJest';
|
|
247
|
+
appId = 'AppID:FIXME:WalletWorksFailedInJest';
|
|
237
248
|
}
|
|
238
249
|
|
|
239
250
|
return {
|
|
240
251
|
BLOCKLET_DID: did,
|
|
241
|
-
BLOCKLET_APP_SK:
|
|
242
|
-
BLOCKLET_APP_ID:
|
|
243
|
-
BLOCKLET_APP_NAME:
|
|
244
|
-
BLOCKLET_APP_DESCRIPTION:
|
|
252
|
+
BLOCKLET_APP_SK: appSk,
|
|
253
|
+
BLOCKLET_APP_ID: appId,
|
|
254
|
+
BLOCKLET_APP_NAME: appName,
|
|
255
|
+
BLOCKLET_APP_DESCRIPTION: appDescription,
|
|
245
256
|
};
|
|
246
257
|
};
|
|
247
258
|
|
|
@@ -269,10 +280,7 @@ const getOverwrittenEnvironments = (blocklet, nodeInfo) => {
|
|
|
269
280
|
const { wallet } = getBlockletInfo(
|
|
270
281
|
{
|
|
271
282
|
meta: blocklet.meta,
|
|
272
|
-
environments: keys.map((key) => ({
|
|
273
|
-
key,
|
|
274
|
-
value: blocklet.configObj[key] || blocklet.environmentObj[key],
|
|
275
|
-
})),
|
|
283
|
+
environments: keys.map((key) => ({ key, value: blocklet.configObj[key] })).filter((x) => x.value),
|
|
276
284
|
},
|
|
277
285
|
nodeInfo.sk
|
|
278
286
|
);
|
|
@@ -0,0 +1,41 @@
|
|
|
1
|
+
const joinUrl = require('url-join');
|
|
2
|
+
const axios = require('@abtnode/util/lib/axios');
|
|
3
|
+
const { DEFAULT_DASHBOARD_DOMAIN, DEFAULT_ADMIN_PATH } = require('@abtnode/constant');
|
|
4
|
+
const { get: getIp } = require('./ip');
|
|
5
|
+
|
|
6
|
+
const getNodeDomain = (ip) => (ip ? DEFAULT_DASHBOARD_DOMAIN.replace(/^\*/, ip.replace(/\./g, '-')) : '');
|
|
7
|
+
|
|
8
|
+
let accessibleIp = null; // cache
|
|
9
|
+
|
|
10
|
+
const timeout = process.env.NODE_ENV === 'test' ? 500 : 5000;
|
|
11
|
+
|
|
12
|
+
// check if node dashboard https endpoint return 2xx
|
|
13
|
+
// FIXME: check connected by wellknown endpoint
|
|
14
|
+
const checkConnected = async ({ ip, nodeInfo }) => {
|
|
15
|
+
const { adminPath = DEFAULT_ADMIN_PATH } = nodeInfo.routing || {};
|
|
16
|
+
const origin = `https://${getNodeDomain(ip)}`;
|
|
17
|
+
const endpoint = joinUrl(origin, adminPath);
|
|
18
|
+
await axios.get(endpoint, { timeout });
|
|
19
|
+
};
|
|
20
|
+
|
|
21
|
+
/**
|
|
22
|
+
* Get accessible external ip of abtnode
|
|
23
|
+
*/
|
|
24
|
+
const getAccessibleExternalNodeIp = async (nodeInfo) => {
|
|
25
|
+
const { external } = await getIp();
|
|
26
|
+
|
|
27
|
+
if (accessibleIp === external) {
|
|
28
|
+
return accessibleIp;
|
|
29
|
+
}
|
|
30
|
+
|
|
31
|
+
try {
|
|
32
|
+
await checkConnected({ ip: external, nodeInfo });
|
|
33
|
+
accessibleIp = external;
|
|
34
|
+
} catch {
|
|
35
|
+
accessibleIp = null;
|
|
36
|
+
}
|
|
37
|
+
|
|
38
|
+
return accessibleIp;
|
|
39
|
+
};
|
|
40
|
+
|
|
41
|
+
module.exports = getAccessibleExternalNodeIp;
|
|
@@ -1,14 +1,17 @@
|
|
|
1
1
|
const slugify = require('slugify');
|
|
2
|
+
const { DEFAULT_IP_DNS_DOMAIN_SUFFIX, SLOT_FOR_IP_DNS_SITE } = require('@abtnode/constant');
|
|
2
3
|
|
|
3
4
|
const formatName = (name) => slugify(name.replace(/^[@./-]/, '').replace(/[@./]/g, '-'));
|
|
4
5
|
|
|
5
6
|
const hiddenInterfaceNames = ['public', 'publicUrl'];
|
|
6
7
|
|
|
7
|
-
const getIpDnsDomainForBlocklet = (blocklet, blockletInterface
|
|
8
|
+
const getIpDnsDomainForBlocklet = (blocklet, blockletInterface) => {
|
|
8
9
|
const nameSuffix = blocklet.meta.did.slice(-3).toLowerCase();
|
|
9
10
|
const iName = hiddenInterfaceNames.includes(blockletInterface.name) ? '' : blockletInterface.name.toLowerCase();
|
|
10
11
|
|
|
11
|
-
return `${formatName(blocklet.meta.name)}-${nameSuffix}${
|
|
12
|
+
return `${formatName(blocklet.meta.name)}-${nameSuffix}${
|
|
13
|
+
iName ? '-' : ''
|
|
14
|
+
}${iName}-${SLOT_FOR_IP_DNS_SITE}.${DEFAULT_IP_DNS_DOMAIN_SUFFIX}`;
|
|
12
15
|
};
|
|
13
16
|
|
|
14
17
|
module.exports = getIpDnsDomainForBlocklet;
|
package/lib/util/index.js
CHANGED
|
@@ -27,6 +27,8 @@ const {
|
|
|
27
27
|
DEFAULT_HTTP_PORT,
|
|
28
28
|
DEFAULT_HTTPS_PORT,
|
|
29
29
|
ROUTING_RULE_TYPES,
|
|
30
|
+
SLOT_FOR_IP_DNS_SITE,
|
|
31
|
+
DEFAULT_IP_DNS_DOMAIN_SUFFIX,
|
|
30
32
|
} = require('@abtnode/constant');
|
|
31
33
|
|
|
32
34
|
const DEFAULT_WELLKNOWN_PORT = 8088;
|
|
@@ -71,34 +73,42 @@ const getInterfaceUrl = ({ baseUrl, url, version }) => {
|
|
|
71
73
|
|
|
72
74
|
const trimSlash = (str = '') => str.replace(/^\/+/, '').replace(/\/+$/, '');
|
|
73
75
|
|
|
74
|
-
const getBlockletHost = ({ domain, context }) => {
|
|
76
|
+
const getBlockletHost = ({ domain, context, nodeIp }) => {
|
|
77
|
+
const { protocol, port } = context || {};
|
|
78
|
+
|
|
75
79
|
if (domain === DOMAIN_FOR_DEFAULT_SITE) {
|
|
76
80
|
return '';
|
|
77
81
|
}
|
|
78
82
|
|
|
79
83
|
let tmpDomain = domain;
|
|
80
84
|
if ([DOMAIN_FOR_IP_SITE, DOMAIN_FOR_IP_SITE_REGEXP].includes(domain) || !domain) {
|
|
81
|
-
tmpDomain = context.hostname;
|
|
85
|
+
tmpDomain = context.hostname || '';
|
|
82
86
|
}
|
|
83
87
|
|
|
84
|
-
if (
|
|
85
|
-
|
|
88
|
+
if (tmpDomain.includes(SLOT_FOR_IP_DNS_SITE)) {
|
|
89
|
+
const ipRegex = /\d+[-.]\d+[-.]\d+[-.]\d+/;
|
|
90
|
+
const match = ipRegex.exec(context.hostname);
|
|
91
|
+
if (match) {
|
|
92
|
+
const ip = match[0].replace(/\./g, '-');
|
|
93
|
+
tmpDomain = tmpDomain.replace(SLOT_FOR_IP_DNS_SITE, ip);
|
|
94
|
+
} else if (nodeIp) {
|
|
95
|
+
tmpDomain = tmpDomain.replace(SLOT_FOR_IP_DNS_SITE, nodeIp.replace(/\./g, '-'));
|
|
96
|
+
}
|
|
86
97
|
}
|
|
87
98
|
|
|
88
|
-
|
|
89
|
-
|
|
90
|
-
|
|
91
|
-
return tmpDomain; // 不展示 https 中的 443 端口
|
|
92
|
-
}
|
|
99
|
+
if (!port) {
|
|
100
|
+
return tmpDomain;
|
|
101
|
+
}
|
|
93
102
|
|
|
94
|
-
|
|
103
|
+
if (protocol === 'https' && Number(port) === 443) {
|
|
104
|
+
return tmpDomain; // 不展示 https 中的 443 端口
|
|
95
105
|
}
|
|
96
106
|
|
|
97
|
-
if (
|
|
107
|
+
if (Number(port) === 80) {
|
|
98
108
|
return tmpDomain; // 不展示 http 中的 80 端
|
|
99
109
|
}
|
|
100
110
|
|
|
101
|
-
return `${tmpDomain}:${
|
|
111
|
+
return `${tmpDomain}:${port}`;
|
|
102
112
|
};
|
|
103
113
|
|
|
104
114
|
/**
|
|
@@ -145,15 +155,19 @@ const getAuthConfig = (rule, blocklet) => {
|
|
|
145
155
|
return auth.config;
|
|
146
156
|
};
|
|
147
157
|
|
|
148
|
-
const getBlockletBaseUrls = ({ routingEnabled = false, port, sites = [], context = {}, blocklet }) => {
|
|
149
|
-
const protocol = 'http'; // TODO: 这里固定为 http, 因为判断 url 是不是 https 和证书相关,这里实现的话比较复杂
|
|
158
|
+
const getBlockletBaseUrls = ({ routingEnabled = false, port, sites = [], context = {}, blocklet, nodeIp }) => {
|
|
150
159
|
let baseUrls = [];
|
|
151
160
|
|
|
152
161
|
if (routingEnabled && Array.isArray(sites) && sites.length > 0) {
|
|
153
162
|
baseUrls = sites
|
|
154
163
|
.map((site) => {
|
|
155
|
-
const host = getBlockletHost({ domain: site.from.domain, context });
|
|
164
|
+
const host = getBlockletHost({ domain: site.from.domain, context, nodeIp });
|
|
156
165
|
if (host) {
|
|
166
|
+
let protocol = 'http'; // TODO: 这里固定为 http, 因为判断 url 是不是 https 和证书相关,这里实现的话比较复杂
|
|
167
|
+
if (host.includes(DEFAULT_IP_DNS_DOMAIN_SUFFIX)) {
|
|
168
|
+
protocol = 'https';
|
|
169
|
+
}
|
|
170
|
+
|
|
157
171
|
return {
|
|
158
172
|
ruleId: site.id,
|
|
159
173
|
baseUrl: `${protocol}://${host}/${trimSlash(site.from.pathPrefix)}`,
|
|
@@ -167,14 +181,14 @@ const getBlockletBaseUrls = ({ routingEnabled = false, port, sites = [], context
|
|
|
167
181
|
.filter(Boolean);
|
|
168
182
|
}
|
|
169
183
|
|
|
170
|
-
if (!baseUrls.length && isIp(context.hostname)
|
|
171
|
-
baseUrls = [{ baseUrl:
|
|
184
|
+
if (!baseUrls.length && isIp(context.hostname)) {
|
|
185
|
+
baseUrls = [{ baseUrl: `http://${context.hostname}:${port}` }];
|
|
172
186
|
}
|
|
173
187
|
|
|
174
188
|
return baseUrls;
|
|
175
189
|
};
|
|
176
190
|
|
|
177
|
-
const getBlockletInterfaces = ({ blocklet, context, nodeInfo, sites }) => {
|
|
191
|
+
const getBlockletInterfaces = ({ blocklet, context, nodeInfo, sites, nodeIp }) => {
|
|
178
192
|
const interfaces = [];
|
|
179
193
|
(blocklet.meta.interfaces || []).forEach((x) => {
|
|
180
194
|
if (x.port && x.port.external) {
|
|
@@ -202,6 +216,7 @@ const getBlockletInterfaces = ({ blocklet, context, nodeInfo, sites }) => {
|
|
|
202
216
|
}),
|
|
203
217
|
context,
|
|
204
218
|
blocklet,
|
|
219
|
+
nodeIp,
|
|
205
220
|
});
|
|
206
221
|
|
|
207
222
|
baseUrls.forEach(({ baseUrl, ruleId, interfaceName, authConfig }) => {
|
package/lib/util/upgrade.js
CHANGED
|
@@ -140,7 +140,11 @@ const doUpgrade = async (session) => {
|
|
|
140
140
|
await goNextState(NODE_UPGRADE_PROGRESS.COMPLETE);
|
|
141
141
|
await sleep(5000);
|
|
142
142
|
await states.node.updateNodeInfo({ nextVersion: '', version: to, upgradeSessionId: '' });
|
|
143
|
-
|
|
143
|
+
try {
|
|
144
|
+
await states.node.exitMode(NODE_MODES.MAINTENANCE);
|
|
145
|
+
} catch (error) {
|
|
146
|
+
logger.error('Failed to exit maintenance mode', { error });
|
|
147
|
+
}
|
|
144
148
|
}
|
|
145
149
|
await lock.release();
|
|
146
150
|
};
|
package/package.json
CHANGED
|
@@ -3,7 +3,7 @@
|
|
|
3
3
|
"publishConfig": {
|
|
4
4
|
"access": "public"
|
|
5
5
|
},
|
|
6
|
-
"version": "1.4.
|
|
6
|
+
"version": "1.4.14",
|
|
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.4.
|
|
23
|
-
"@abtnode/cron": "1.4.
|
|
24
|
-
"@abtnode/event-hub": "1.4.
|
|
25
|
-
"@abtnode/logger": "1.4.
|
|
26
|
-
"@abtnode/queue": "1.4.
|
|
27
|
-
"@abtnode/rbac": "1.4.
|
|
28
|
-
"@abtnode/router-provider": "1.4.
|
|
29
|
-
"@abtnode/static-server": "1.4.
|
|
30
|
-
"@abtnode/timemachine": "1.4.
|
|
31
|
-
"@abtnode/util": "1.4.
|
|
32
|
-
"@arcblock/did": "^1.13.
|
|
22
|
+
"@abtnode/constant": "1.4.14",
|
|
23
|
+
"@abtnode/cron": "1.4.14",
|
|
24
|
+
"@abtnode/event-hub": "1.4.14",
|
|
25
|
+
"@abtnode/logger": "1.4.14",
|
|
26
|
+
"@abtnode/queue": "1.4.14",
|
|
27
|
+
"@abtnode/rbac": "1.4.14",
|
|
28
|
+
"@abtnode/router-provider": "1.4.14",
|
|
29
|
+
"@abtnode/static-server": "1.4.14",
|
|
30
|
+
"@abtnode/timemachine": "1.4.14",
|
|
31
|
+
"@abtnode/util": "1.4.14",
|
|
32
|
+
"@arcblock/did": "^1.13.15",
|
|
33
33
|
"@arcblock/pm2-events": "^0.0.5",
|
|
34
|
-
"@arcblock/vc": "^1.13.
|
|
35
|
-
"@blocklet/meta": "1.4.
|
|
34
|
+
"@arcblock/vc": "^1.13.15",
|
|
35
|
+
"@blocklet/meta": "1.4.14",
|
|
36
36
|
"@fidm/x509": "^1.2.1",
|
|
37
37
|
"@nedb/core": "^1.1.0",
|
|
38
38
|
"@nedb/multi": "^1.1.0",
|
|
39
|
-
"@ocap/mcrypto": "^1.13.
|
|
40
|
-
"@ocap/util": "^1.13.
|
|
41
|
-
"@ocap/wallet": "^1.13.
|
|
39
|
+
"@ocap/mcrypto": "^1.13.15",
|
|
40
|
+
"@ocap/util": "^1.13.15",
|
|
41
|
+
"@ocap/wallet": "^1.13.15",
|
|
42
42
|
"@slack/webhook": "^5.0.3",
|
|
43
43
|
"axios": "^0.21.4",
|
|
44
44
|
"axon": "^2.0.3",
|
|
@@ -72,5 +72,5 @@
|
|
|
72
72
|
"express": "^4.17.1",
|
|
73
73
|
"jest": "^26.4.2"
|
|
74
74
|
},
|
|
75
|
-
"gitHead": "
|
|
75
|
+
"gitHead": "9176b462ff92c787e18a8b218f06a451aad4cf1d"
|
|
76
76
|
}
|
|
@@ -1,42 +0,0 @@
|
|
|
1
|
-
const joinUrl = require('url-join');
|
|
2
|
-
const axios = require('@abtnode/util/lib/axios');
|
|
3
|
-
const getIp = require('@abtnode/util/lib/get-ip');
|
|
4
|
-
const { DEFAULT_DASHBOARD_DOMAIN, DEFAULT_ADMIN_PATH } = require('@abtnode/constant');
|
|
5
|
-
|
|
6
|
-
const getNodeDomain = (ip) => (ip ? DEFAULT_DASHBOARD_DOMAIN.replace(/^\*/, ip.replace(/\./g, '-')) : '');
|
|
7
|
-
|
|
8
|
-
const getAccessibleIp = async ({ nodeInfo = {}, timeout = 5000 } = {}) => {
|
|
9
|
-
const { adminPath = DEFAULT_ADMIN_PATH } = nodeInfo.routing || {};
|
|
10
|
-
|
|
11
|
-
// check if node dashboard https endpoint return 2xx
|
|
12
|
-
// FIXME: check connected by wellknown endpoint
|
|
13
|
-
const checkConnected = async ({ ip }) => {
|
|
14
|
-
const origin = `https://${getNodeDomain(ip)}`;
|
|
15
|
-
const endpoint = joinUrl(origin, adminPath);
|
|
16
|
-
await axios.get(endpoint, { timeout });
|
|
17
|
-
};
|
|
18
|
-
|
|
19
|
-
const { internal, external } = await getIp({ timeout });
|
|
20
|
-
|
|
21
|
-
if (!external) {
|
|
22
|
-
return internal;
|
|
23
|
-
}
|
|
24
|
-
|
|
25
|
-
try {
|
|
26
|
-
await checkConnected({ ip: external });
|
|
27
|
-
return external;
|
|
28
|
-
} catch {
|
|
29
|
-
return internal;
|
|
30
|
-
}
|
|
31
|
-
};
|
|
32
|
-
|
|
33
|
-
const getAccessibleIpDnsDomainForNode = async ({ nodeInfo = {}, timeout = 5000 } = {}) => {
|
|
34
|
-
const accessibleIp = await getAccessibleIp({ nodeInfo, timeout });
|
|
35
|
-
|
|
36
|
-
return getNodeDomain(accessibleIp);
|
|
37
|
-
};
|
|
38
|
-
|
|
39
|
-
module.exports = {
|
|
40
|
-
getAccessibleIp,
|
|
41
|
-
getAccessibleIpDnsDomainForNode,
|
|
42
|
-
};
|