@abtnode/core 1.4.10 → 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 +60 -50
- package/lib/blocklet/registry.js +2 -2
- package/lib/index.js +2 -4
- package/lib/router/helper.js +105 -183
- package/lib/router/index.js +21 -2
- package/lib/states/blocklet.js +8 -7
- package/lib/util/blocklet.js +56 -35
- 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 +19 -18
- package/lib/util/get-accessible-ip.js +0 -42
|
@@ -8,6 +8,7 @@ const capitalize = require('lodash/capitalize');
|
|
|
8
8
|
const diff = require('deep-diff');
|
|
9
9
|
const { Throttle } = require('stream-throttle');
|
|
10
10
|
const { isValid: isValidDid } = require('@arcblock/did');
|
|
11
|
+
const { verifyPresentation } = require('@arcblock/vc');
|
|
11
12
|
const { toBase58 } = require('@ocap/util');
|
|
12
13
|
const { fromSecretKey } = require('@ocap/wallet');
|
|
13
14
|
|
|
@@ -15,6 +16,8 @@ const logger = require('@abtnode/logger')('@abtnode/core:blocklet:manager');
|
|
|
15
16
|
const hashFiles = require('@abtnode/util/lib/hash-files');
|
|
16
17
|
const downloadFile = require('@abtnode/util/lib/download-file');
|
|
17
18
|
const Lock = require('@abtnode/util/lib/lock');
|
|
19
|
+
const { getVcFromPresentation } = require('@abtnode/util/lib/vc');
|
|
20
|
+
const { BLOCKLET_PURCHASE_NFT_TYPE } = require('@abtnode/constant');
|
|
18
21
|
|
|
19
22
|
const getBlockletEngine = require('@blocklet/meta/lib/engine');
|
|
20
23
|
const { isFreeBlocklet } = require('@blocklet/meta/lib/payment');
|
|
@@ -31,6 +34,7 @@ const {
|
|
|
31
34
|
fromBlockletSource,
|
|
32
35
|
} = require('@blocklet/meta/lib/constants');
|
|
33
36
|
const util = require('../../util');
|
|
37
|
+
const getAccessibleExternalNodeIp = require('../../util/get-accessible-external-node-ip');
|
|
34
38
|
const {
|
|
35
39
|
forEachBlocklet,
|
|
36
40
|
getBlockletDirs,
|
|
@@ -57,6 +61,7 @@ const {
|
|
|
57
61
|
getRuntimeInfo,
|
|
58
62
|
mergeMeta,
|
|
59
63
|
getUpdateMetaList,
|
|
64
|
+
getRuntimeEnvironments,
|
|
60
65
|
} = require('../../util/blocklet');
|
|
61
66
|
const states = require('../../states');
|
|
62
67
|
const BlockletRegistry = require('../registry');
|
|
@@ -135,45 +140,46 @@ class BlockletManager extends BaseBlockletManager {
|
|
|
135
140
|
*/
|
|
136
141
|
async install(params, context) {
|
|
137
142
|
logger.debug('install blocklet', { params, context });
|
|
138
|
-
if (params.
|
|
139
|
-
|
|
140
|
-
return this._installFromId({ installId, sync }, context);
|
|
143
|
+
if (params.url) {
|
|
144
|
+
return this._installFromUrl({ url: params.url, sync: params.sync }, context);
|
|
141
145
|
}
|
|
146
|
+
|
|
142
147
|
if (params.file) {
|
|
143
148
|
const { file, did, diffVersion, deleteSet } = params;
|
|
144
149
|
return this._installFromUpload({ file, did, diffVersion, deleteSet, context });
|
|
145
150
|
}
|
|
146
151
|
|
|
147
152
|
if (params.did) {
|
|
148
|
-
return this._installFromRegistry(params.did, context);
|
|
153
|
+
return this._installFromRegistry({ did: params.did }, context);
|
|
149
154
|
}
|
|
150
155
|
|
|
151
156
|
throw new Error('Can only install blocklet from url/file/did');
|
|
152
157
|
}
|
|
153
158
|
|
|
154
159
|
// eslint-disable-next-line no-unused-vars
|
|
155
|
-
async
|
|
156
|
-
|
|
160
|
+
async getMetaFromUrl({ url }, context) {
|
|
161
|
+
const meta = await getBlockletMetaFromUrl(url);
|
|
157
162
|
|
|
158
|
-
|
|
159
|
-
|
|
163
|
+
return meta;
|
|
164
|
+
}
|
|
160
165
|
|
|
161
|
-
|
|
162
|
-
|
|
163
|
-
|
|
164
|
-
});
|
|
166
|
+
async installBlockletFromVc({ vcPresentation, challenge }, context) {
|
|
167
|
+
logger.info('Install from vc');
|
|
168
|
+
const vc = getVcFromPresentation(vcPresentation);
|
|
165
169
|
|
|
166
|
-
|
|
170
|
+
// FIXME: 这里的 trustedIssuers 相当于相信任何 VC,需要想更安全的方法
|
|
171
|
+
verifyPresentation({ presentation: vcPresentation, trustedIssuers: [get(vc, 'issuer.id')], challenge });
|
|
167
172
|
|
|
168
|
-
|
|
169
|
-
|
|
170
|
-
meta,
|
|
171
|
-
existingMeta: exist ? exist.meta : null,
|
|
172
|
-
};
|
|
173
|
-
} catch (error) {
|
|
174
|
-
logger.error('Install from url error', { url, error });
|
|
175
|
-
throw error;
|
|
173
|
+
if (!vc.type.includes(BLOCKLET_PURCHASE_NFT_TYPE)) {
|
|
174
|
+
throw new Error(`Expect ${BLOCKLET_PURCHASE_NFT_TYPE} VC type`);
|
|
176
175
|
}
|
|
176
|
+
|
|
177
|
+
const blockletUrl = get(vc, 'credentialSubject.purchased.blocklet.url');
|
|
178
|
+
const urlObject = new URL(blockletUrl);
|
|
179
|
+
const did = get(vc, 'credentialSubject.purchased.blocklet.id');
|
|
180
|
+
const registry = urlObject.origin;
|
|
181
|
+
|
|
182
|
+
return this._installFromRegistry({ did, registry }, { ...context, blockletPurchaseVerified: true });
|
|
177
183
|
}
|
|
178
184
|
|
|
179
185
|
async start({ did, checkHealthImmediately = false, throwOnError }, context) {
|
|
@@ -216,7 +222,7 @@ class BlockletManager extends BaseBlockletManager {
|
|
|
216
222
|
hooks.preStart(b, {
|
|
217
223
|
appDir: b.env.appDir,
|
|
218
224
|
hooks: Object.assign(b.meta.hooks || {}, b.meta.scripts || {}),
|
|
219
|
-
env:
|
|
225
|
+
env: getRuntimeEnvironments(b, nodeEnvironments),
|
|
220
226
|
did, // root blocklet did,
|
|
221
227
|
progress: blocklet.mode === BLOCKLET_MODES.DEVELOPMENT,
|
|
222
228
|
}),
|
|
@@ -288,7 +294,7 @@ class BlockletManager extends BaseBlockletManager {
|
|
|
288
294
|
hooks.preStop({
|
|
289
295
|
appDir: b.env.appDir,
|
|
290
296
|
hooks: Object.assign(b.meta.hooks || {}, b.meta.scripts || {}),
|
|
291
|
-
env:
|
|
297
|
+
env: getRuntimeEnvironments(b, nodeEnvironments),
|
|
292
298
|
did, // root blocklet did
|
|
293
299
|
notification: this.notification,
|
|
294
300
|
context,
|
|
@@ -361,7 +367,7 @@ class BlockletManager extends BaseBlockletManager {
|
|
|
361
367
|
hooks.preUninstall({
|
|
362
368
|
appDir: b.env.appDir,
|
|
363
369
|
hooks: Object.assign(b.meta.hooks || {}, b.meta.scripts || {}),
|
|
364
|
-
env:
|
|
370
|
+
env: getRuntimeEnvironments(b, nodeEnvironments),
|
|
365
371
|
did, // root blocklet did
|
|
366
372
|
notification: this.notification,
|
|
367
373
|
context,
|
|
@@ -472,8 +478,12 @@ class BlockletManager extends BaseBlockletManager {
|
|
|
472
478
|
if (x.key === 'BLOCKLET_APP_SK') {
|
|
473
479
|
try {
|
|
474
480
|
fromSecretKey(x.value);
|
|
475
|
-
} catch
|
|
476
|
-
|
|
481
|
+
} catch {
|
|
482
|
+
try {
|
|
483
|
+
fromSecretKey(x.value, 'eth');
|
|
484
|
+
} catch {
|
|
485
|
+
throw new Error('Invalid custom blocklet secret key');
|
|
486
|
+
}
|
|
477
487
|
}
|
|
478
488
|
}
|
|
479
489
|
|
|
@@ -483,13 +493,13 @@ class BlockletManager extends BaseBlockletManager {
|
|
|
483
493
|
}
|
|
484
494
|
}
|
|
485
495
|
|
|
486
|
-
blocklet.
|
|
496
|
+
blocklet.configObj[x.key] = x.value;
|
|
487
497
|
});
|
|
488
498
|
await hooks.preConfig({
|
|
489
499
|
appDir: blocklet.env.appDir,
|
|
490
500
|
hooks: Object.assign(blocklet.meta.hooks || {}, blocklet.meta.scripts || {}),
|
|
491
501
|
exitOnError: true,
|
|
492
|
-
env: { ...
|
|
502
|
+
env: { ...getRuntimeEnvironments(blocklet, nodeEnvironments), ...blocklet.configObj },
|
|
493
503
|
notification: this.notification,
|
|
494
504
|
did,
|
|
495
505
|
context,
|
|
@@ -891,7 +901,8 @@ class BlockletManager extends BaseBlockletManager {
|
|
|
891
901
|
// Put shorter url first
|
|
892
902
|
return a.from.pathPrefix.length < b.from.pathPrefix ? 1 : -1;
|
|
893
903
|
});
|
|
894
|
-
|
|
904
|
+
const nodeIp = await getAccessibleExternalNodeIp(nodeInfo);
|
|
905
|
+
blocklet.interfaces = getBlockletInterfaces({ blocklet, context, nodeInfo, sites: routingRules, nodeIp });
|
|
895
906
|
|
|
896
907
|
try {
|
|
897
908
|
const { appId } = blocklet.meta.group === BlockletGroup.gateway ? blocklet.children[0].env : blocklet.env;
|
|
@@ -1116,12 +1127,12 @@ class BlockletManager extends BaseBlockletManager {
|
|
|
1116
1127
|
const nodeInfo = await this.node.read();
|
|
1117
1128
|
|
|
1118
1129
|
const rootSystemEnvironments = getRootSystemEnvironments(blockletWithEnv, nodeInfo);
|
|
1119
|
-
const
|
|
1120
|
-
const overwrittenEnvironments = getOverwrittenEnvironments(blockletWithEnv);
|
|
1130
|
+
const rootConfig = blockletWithEnv.configObj;
|
|
1131
|
+
const overwrittenEnvironments = getOverwrittenEnvironments(blockletWithEnv, nodeInfo);
|
|
1121
1132
|
|
|
1122
1133
|
// fill environments to blocklet and blocklet.children
|
|
1123
1134
|
blocklet.environments = formatEnvironments({
|
|
1124
|
-
...
|
|
1135
|
+
...rootConfig,
|
|
1125
1136
|
...getSystemEnvironments(blockletWithEnv),
|
|
1126
1137
|
...rootSystemEnvironments,
|
|
1127
1138
|
...overwrittenEnvironments,
|
|
@@ -1130,11 +1141,12 @@ class BlockletManager extends BaseBlockletManager {
|
|
|
1130
1141
|
for (const child of blocklet.children) {
|
|
1131
1142
|
const childWithEnv = blockletWithEnv.children.find((x) => x.meta.did === child.meta.did);
|
|
1132
1143
|
if (childWithEnv) {
|
|
1144
|
+
const childConfig = childWithEnv.configObj;
|
|
1133
1145
|
child.environments = formatEnvironments({
|
|
1134
|
-
...
|
|
1135
|
-
...
|
|
1136
|
-
...getSystemEnvironments(childWithEnv),
|
|
1137
|
-
...rootSystemEnvironments,
|
|
1146
|
+
...childConfig, // custom env of child blocklet
|
|
1147
|
+
...rootConfig, // // custom env of root blocklet FIXME: use options or hooks to make merge logic flexible
|
|
1148
|
+
...getSystemEnvironments(childWithEnv), // system env of child blocklet
|
|
1149
|
+
...rootSystemEnvironments, // system env of root blocklet
|
|
1138
1150
|
...overwrittenEnvironments,
|
|
1139
1151
|
});
|
|
1140
1152
|
}
|
|
@@ -1152,15 +1164,15 @@ class BlockletManager extends BaseBlockletManager {
|
|
|
1152
1164
|
}
|
|
1153
1165
|
}
|
|
1154
1166
|
|
|
1155
|
-
async _installFromRegistry(did, context) {
|
|
1167
|
+
async _installFromRegistry({ did, registry }, context) {
|
|
1156
1168
|
logger.debug('start install blocklet', { did });
|
|
1157
1169
|
if (!isValidDid(did)) {
|
|
1158
1170
|
throw new Error('Blocklet did is invalid');
|
|
1159
1171
|
}
|
|
1160
1172
|
|
|
1161
|
-
const registryUrl = await states.node.getBlockletRegistry();
|
|
1173
|
+
const registryUrl = registry || (await states.node.getBlockletRegistry());
|
|
1162
1174
|
const info = await BlockletRegistry.getRegistryMeta(registryUrl);
|
|
1163
|
-
const blocklet = await this.registry.getBlocklet(did);
|
|
1175
|
+
const blocklet = await this.registry.getBlocklet(did, registryUrl);
|
|
1164
1176
|
if (!blocklet) {
|
|
1165
1177
|
throw new Error('Can not install blocklet that not found in registry');
|
|
1166
1178
|
}
|
|
@@ -1183,15 +1195,13 @@ class BlockletManager extends BaseBlockletManager {
|
|
|
1183
1195
|
});
|
|
1184
1196
|
}
|
|
1185
1197
|
|
|
1186
|
-
async
|
|
1187
|
-
logger.debug('start install blocklet', {
|
|
1188
|
-
|
|
1189
|
-
|
|
1190
|
-
}
|
|
1198
|
+
async _installFromUrl({ url, sync }, context) {
|
|
1199
|
+
logger.debug('start install blocklet', { url });
|
|
1200
|
+
|
|
1201
|
+
const meta = await getBlockletMetaFromUrl(url);
|
|
1191
1202
|
|
|
1192
|
-
const { meta, metaSource } = await this.session.end(id);
|
|
1193
1203
|
if (!meta) {
|
|
1194
|
-
throw new Error(`Can not install blocklet that not found by
|
|
1204
|
+
throw new Error(`Can not install blocklet that not found by url: ${url}`);
|
|
1195
1205
|
}
|
|
1196
1206
|
|
|
1197
1207
|
// upgrade
|
|
@@ -1200,7 +1210,7 @@ class BlockletManager extends BaseBlockletManager {
|
|
|
1200
1210
|
return this._upgrade({
|
|
1201
1211
|
meta,
|
|
1202
1212
|
source: BlockletSource.url,
|
|
1203
|
-
deployedFrom:
|
|
1213
|
+
deployedFrom: url,
|
|
1204
1214
|
sync,
|
|
1205
1215
|
context,
|
|
1206
1216
|
});
|
|
@@ -1210,7 +1220,7 @@ class BlockletManager extends BaseBlockletManager {
|
|
|
1210
1220
|
return this._install({
|
|
1211
1221
|
meta,
|
|
1212
1222
|
source: BlockletSource.url,
|
|
1213
|
-
deployedFrom:
|
|
1223
|
+
deployedFrom: url,
|
|
1214
1224
|
sync,
|
|
1215
1225
|
context,
|
|
1216
1226
|
});
|
|
@@ -1738,7 +1748,7 @@ class BlockletManager extends BaseBlockletManager {
|
|
|
1738
1748
|
const postInstall = (b) =>
|
|
1739
1749
|
hooks.postInstall({
|
|
1740
1750
|
hooks: Object.assign(b.meta.hooks || {}, b.meta.scripts || {}),
|
|
1741
|
-
env:
|
|
1751
|
+
env: getRuntimeEnvironments(b, nodeEnvironments),
|
|
1742
1752
|
appDir: blocklet.env.appDir,
|
|
1743
1753
|
did, // root blocklet did
|
|
1744
1754
|
notification: this.notification,
|
|
@@ -1824,7 +1834,7 @@ class BlockletManager extends BaseBlockletManager {
|
|
|
1824
1834
|
const postInstall = (b) =>
|
|
1825
1835
|
hooks.postInstall({
|
|
1826
1836
|
hooks: Object.assign(b.meta.hooks || {}, b.meta.scripts || {}),
|
|
1827
|
-
env:
|
|
1837
|
+
env: getRuntimeEnvironments(b, nodeEnvironments),
|
|
1828
1838
|
appDir: b.env.appDir,
|
|
1829
1839
|
did, // root blocklet did
|
|
1830
1840
|
notification: this.notification,
|
package/lib/blocklet/registry.js
CHANGED
|
@@ -57,8 +57,8 @@ class BlockletRegistry {
|
|
|
57
57
|
return list.some((x) => x.did === id || x.name === id);
|
|
58
58
|
}
|
|
59
59
|
|
|
60
|
-
getBlocklet(id) {
|
|
61
|
-
return this.getBlockletMeta({ did: id });
|
|
60
|
+
getBlocklet(id, registryUrl) {
|
|
61
|
+
return this.getBlockletMeta({ did: id, registryUrl });
|
|
62
62
|
}
|
|
63
63
|
|
|
64
64
|
// eslint-disable-next-line no-unused-vars
|
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,
|
|
@@ -185,7 +184,7 @@ function ABTNode(options) {
|
|
|
185
184
|
|
|
186
185
|
// Blocklet manager
|
|
187
186
|
installBlocklet: blockletManager.install.bind(blockletManager),
|
|
188
|
-
|
|
187
|
+
installBlockletFromVc: blockletManager.installBlockletFromVc.bind(blockletManager),
|
|
189
188
|
startBlocklet: blockletManager.start.bind(blockletManager),
|
|
190
189
|
stopBlocklet: blockletManager.stop.bind(blockletManager),
|
|
191
190
|
reloadBlocklet: blockletManager.reload.bind(blockletManager),
|
|
@@ -199,6 +198,7 @@ function ABTNode(options) {
|
|
|
199
198
|
checkChildBlockletsForUpdates: blockletManager.checkChildrenForUpdates.bind(blockletManager),
|
|
200
199
|
updateChildBlocklets: blockletManager.updateChildren.bind(blockletManager),
|
|
201
200
|
getLatestBlockletVersion: blockletManager.getLatestBlockletVersion.bind(blockletManager),
|
|
201
|
+
getBlockletMetaFromUrl: blockletManager.getMetaFromUrl.bind(blockletManager),
|
|
202
202
|
|
|
203
203
|
deleteBlockletProcess: blockletManager.deleteProcess.bind(blockletManager),
|
|
204
204
|
|
|
@@ -214,7 +214,6 @@ function ABTNode(options) {
|
|
|
214
214
|
|
|
215
215
|
// Registry
|
|
216
216
|
listBlocklets: blockletRegistry.listBlocklets.bind(blockletRegistry),
|
|
217
|
-
getBlockletMeta: blockletRegistry.getBlockletMeta.bind(blockletRegistry),
|
|
218
217
|
getRegistryMeta: BlockletRegistry.getRegistryMeta,
|
|
219
218
|
|
|
220
219
|
// Node State
|
|
@@ -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
|
@@ -4,6 +4,7 @@ const fs = require('fs-extra');
|
|
|
4
4
|
const path = require('path');
|
|
5
5
|
const tar = require('tar');
|
|
6
6
|
const get = require('lodash/get');
|
|
7
|
+
const joinUrl = require('url-join');
|
|
7
8
|
const { getProvider } = require('@abtnode/router-provider');
|
|
8
9
|
const normalizePathPrefix = require('@abtnode/util/lib/normalize-path-prefix');
|
|
9
10
|
const getTmpDirectory = require('@abtnode/util/lib/get-tmp-directory');
|
|
@@ -23,7 +24,7 @@ const {
|
|
|
23
24
|
ROUTING_RULE_TYPES,
|
|
24
25
|
CERTIFICATE_EXPIRES_OFFSET,
|
|
25
26
|
CERTIFICATE_EXPIRES_WARNING_OFFSET,
|
|
26
|
-
|
|
27
|
+
DEFAULT_DAEMON_PORT,
|
|
27
28
|
} = require('@abtnode/constant');
|
|
28
29
|
const {
|
|
29
30
|
BLOCKLET_DYNAMIC_PATH_PREFIX,
|
|
@@ -43,7 +44,6 @@ const {
|
|
|
43
44
|
getWellknownSitePort,
|
|
44
45
|
} = require('../util');
|
|
45
46
|
const { getServicesFromBlockletInterface } = require('../util/service');
|
|
46
|
-
const { getAccessibleIp, getAccessibleIpDnsDomainForNode } = require('../util/get-accessible-ip');
|
|
47
47
|
const getIpDnsDomainForBlocklet = require('../util/get-ip-dns-domain-for-blocklet');
|
|
48
48
|
|
|
49
49
|
const Router = require('./index');
|
|
@@ -208,24 +208,25 @@ const ensureLatestInterfaceInfo = async (sites = []) => {
|
|
|
208
208
|
|
|
209
209
|
const ensureWellknownRule = async (sites) => {
|
|
210
210
|
const tempSites = sites || [];
|
|
211
|
+
const wellknownPort = await getWellknownSitePort();
|
|
212
|
+
|
|
211
213
|
for (const site of tempSites) {
|
|
212
214
|
// 不向 default site & ip site & wellknown site 添加 wellknown rule
|
|
213
|
-
const
|
|
215
|
+
const isBasicSite = [
|
|
214
216
|
DOMAIN_FOR_INTERNAL_SITE,
|
|
215
217
|
DOMAIN_FOR_IP_SITE,
|
|
216
218
|
DOMAIN_FOR_DEFAULT_SITE,
|
|
217
219
|
DOMAIN_FOR_IP_SITE_REGEXP,
|
|
218
220
|
].includes(site.domain);
|
|
219
221
|
|
|
220
|
-
if (!
|
|
222
|
+
if (!isBasicSite) {
|
|
221
223
|
const isExists = site.rules.find((x) => x.from.pathPrefix === WELLKNOWN_PATH_PREFIX);
|
|
222
224
|
|
|
223
225
|
if (!isExists) {
|
|
224
226
|
site.rules.push({
|
|
225
227
|
from: { pathPrefix: WELLKNOWN_PATH_PREFIX },
|
|
226
228
|
to: {
|
|
227
|
-
|
|
228
|
-
port: await getWellknownSitePort(),
|
|
229
|
+
port: wellknownPort,
|
|
229
230
|
type: ROUTING_RULE_TYPES.GENERAL_PROXY,
|
|
230
231
|
interfaceName: BLOCKLET_INTERFACE_WELLKNOWN,
|
|
231
232
|
},
|
|
@@ -318,27 +319,6 @@ module.exports = function getRouterHelpers({ dataDirs, routingSnapshot, routerMa
|
|
|
318
319
|
const httpsCertState = states.certificate;
|
|
319
320
|
const notification = states.notification;
|
|
320
321
|
|
|
321
|
-
let _nodeDomainRequest = null; // singleton of node-domain-request
|
|
322
|
-
const _getIpDnsDomainForNode = ({ nodeInfo = {} } = {}) => {
|
|
323
|
-
const timeout = process.env.NODE_ENV === 'test' ? 500 : 5000;
|
|
324
|
-
if (_nodeDomainRequest) {
|
|
325
|
-
return _nodeDomainRequest;
|
|
326
|
-
}
|
|
327
|
-
|
|
328
|
-
const req = getAccessibleIpDnsDomainForNode({ nodeInfo, timeout });
|
|
329
|
-
_nodeDomainRequest = req;
|
|
330
|
-
|
|
331
|
-
req
|
|
332
|
-
.then(() => {
|
|
333
|
-
_nodeDomainRequest = null;
|
|
334
|
-
})
|
|
335
|
-
.catch(() => {
|
|
336
|
-
_nodeDomainRequest = null;
|
|
337
|
-
});
|
|
338
|
-
|
|
339
|
-
return req;
|
|
340
|
-
};
|
|
341
|
-
|
|
342
322
|
// site level duplication detection
|
|
343
323
|
const hasRuleByPrefix = (site, value) => site.rules.find((x) => x.isProtected && get(x, 'from.pathPrefix') === value);
|
|
344
324
|
|
|
@@ -408,25 +388,47 @@ module.exports = function getRouterHelpers({ dataDirs, routingSnapshot, routerMa
|
|
|
408
388
|
|
|
409
389
|
const addWellknownSite = async (sites, context) => {
|
|
410
390
|
const site = (sites || []).find((x) => x.name === NAME_FOR_WELLKNOWN_SITE);
|
|
411
|
-
if (site) {
|
|
412
|
-
return false;
|
|
413
|
-
}
|
|
414
391
|
|
|
415
392
|
try {
|
|
416
|
-
|
|
417
|
-
|
|
418
|
-
|
|
419
|
-
|
|
420
|
-
|
|
421
|
-
|
|
422
|
-
|
|
423
|
-
isProtected: true,
|
|
424
|
-
},
|
|
425
|
-
skipCheckDynamicBlacklist: true,
|
|
426
|
-
skipValidation: true,
|
|
393
|
+
const pathPrefix = joinUrl(WELLKNOWN_PATH_PREFIX, '/did.json');
|
|
394
|
+
const didResolverWellknownRule = {
|
|
395
|
+
from: { pathPrefix },
|
|
396
|
+
to: {
|
|
397
|
+
port: DEFAULT_DAEMON_PORT,
|
|
398
|
+
type: ROUTING_RULE_TYPES.GENERAL_PROXY,
|
|
399
|
+
interfaceName: BLOCKLET_INTERFACE_WELLKNOWN,
|
|
427
400
|
},
|
|
428
|
-
|
|
429
|
-
|
|
401
|
+
};
|
|
402
|
+
|
|
403
|
+
if (site) {
|
|
404
|
+
if (site.rules.find((r) => r.from.pathPrefix === normalizePathPrefix(pathPrefix))) {
|
|
405
|
+
return false;
|
|
406
|
+
}
|
|
407
|
+
|
|
408
|
+
await routerManager.addRoutingRule(
|
|
409
|
+
{
|
|
410
|
+
id: site.id,
|
|
411
|
+
rule: didResolverWellknownRule,
|
|
412
|
+
skipProtectedRuleChecking: true,
|
|
413
|
+
},
|
|
414
|
+
context
|
|
415
|
+
);
|
|
416
|
+
} else {
|
|
417
|
+
await routerManager.addRoutingSite(
|
|
418
|
+
{
|
|
419
|
+
site: {
|
|
420
|
+
domain: DOMAIN_FOR_INTERNAL_SITE,
|
|
421
|
+
port: await getWellknownSitePort(),
|
|
422
|
+
name: NAME_FOR_WELLKNOWN_SITE,
|
|
423
|
+
rules: [didResolverWellknownRule],
|
|
424
|
+
isProtected: true,
|
|
425
|
+
},
|
|
426
|
+
skipCheckDynamicBlacklist: true,
|
|
427
|
+
skipValidation: true,
|
|
428
|
+
},
|
|
429
|
+
context
|
|
430
|
+
);
|
|
431
|
+
}
|
|
430
432
|
|
|
431
433
|
return true;
|
|
432
434
|
} catch (err) {
|
|
@@ -555,13 +557,6 @@ module.exports = function getRouterHelpers({ dataDirs, routingSnapshot, routerMa
|
|
|
555
557
|
const _ensureBlockletSites = async (blocklet, sites, nodeInfo, context = {}) => {
|
|
556
558
|
const interfaces = (blocklet.meta.interfaces || []).filter((x) => x.type === BLOCKLET_INTERFACE_TYPE_WEB);
|
|
557
559
|
|
|
558
|
-
const nodeDomain = await _getIpDnsDomainForNode({ nodeInfo });
|
|
559
|
-
|
|
560
|
-
if (!nodeDomain) {
|
|
561
|
-
logger.error('IpDnsDomain of abtnode does not found');
|
|
562
|
-
return false;
|
|
563
|
-
}
|
|
564
|
-
|
|
565
560
|
const getPrefix = (str) => {
|
|
566
561
|
if (!str || str === '*') {
|
|
567
562
|
return '/';
|
|
@@ -571,34 +566,57 @@ module.exports = function getRouterHelpers({ dataDirs, routingSnapshot, routerMa
|
|
|
571
566
|
|
|
572
567
|
const changes = await Promise.all(
|
|
573
568
|
interfaces.map(async (x) => {
|
|
574
|
-
|
|
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
|
+
};
|
|
575
581
|
|
|
576
|
-
|
|
582
|
+
let changed = false; // if state db changed
|
|
577
583
|
|
|
578
|
-
|
|
584
|
+
const exist = await states.site.findOne({ domain });
|
|
585
|
+
if (!exist) {
|
|
579
586
|
await routerManager.addRoutingSite(
|
|
580
587
|
{
|
|
581
588
|
site: {
|
|
582
589
|
domain,
|
|
583
590
|
isProtected: true,
|
|
584
|
-
rules: [
|
|
585
|
-
{
|
|
586
|
-
from: { pathPrefix: getPrefix(x.prefix) },
|
|
587
|
-
to: {
|
|
588
|
-
port: findInterfacePortByName(blocklet, x.name),
|
|
589
|
-
did: blocklet.meta.did,
|
|
590
|
-
type: ROUTING_RULE_TYPES.BLOCKLET,
|
|
591
|
-
interfaceName: x.name, // root blocklet interface
|
|
592
|
-
},
|
|
593
|
-
isProtected: true,
|
|
594
|
-
},
|
|
595
|
-
],
|
|
591
|
+
rules: [rule],
|
|
596
592
|
},
|
|
597
593
|
skipCheckDynamicBlacklist: true,
|
|
598
594
|
},
|
|
599
595
|
context
|
|
600
596
|
);
|
|
597
|
+
logger.info('add routing site', { site: domain });
|
|
601
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
|
+
}
|
|
602
620
|
changed = true;
|
|
603
621
|
}
|
|
604
622
|
|
|
@@ -614,7 +632,7 @@ module.exports = function getRouterHelpers({ dataDirs, routingSnapshot, routerMa
|
|
|
614
632
|
*
|
|
615
633
|
* @returns {boolean} if routing changed
|
|
616
634
|
*/
|
|
617
|
-
const _ensureBlockletRulesForWellknownSite = async (blocklet, sites,
|
|
635
|
+
const _ensureBlockletRulesForWellknownSite = async (blocklet, sites, context = {}) => {
|
|
618
636
|
const wellknownSite = sites.find((x) => x.name === NAME_FOR_WELLKNOWN_SITE);
|
|
619
637
|
if (!wellknownSite) {
|
|
620
638
|
return false;
|
|
@@ -748,14 +766,13 @@ module.exports = function getRouterHelpers({ dataDirs, routingSnapshot, routerMa
|
|
|
748
766
|
};
|
|
749
767
|
|
|
750
768
|
const _removeBlockletSites = async (blocklet, nodeInfo, context = {}) => {
|
|
751
|
-
const nodeDomain = await _getIpDnsDomainForNode({ nodeInfo });
|
|
752
769
|
const interfaces = (blocklet.meta.interfaces || []).filter((x) => x.type === BLOCKLET_INTERFACE_TYPE_WEB);
|
|
753
770
|
|
|
754
771
|
const changes = await Promise.all(
|
|
755
772
|
interfaces.map(async (x) => {
|
|
756
773
|
let changed = false;
|
|
757
774
|
|
|
758
|
-
const domain = getIpDnsDomainForBlocklet(blocklet, x
|
|
775
|
+
const domain = getIpDnsDomainForBlocklet(blocklet, x);
|
|
759
776
|
|
|
760
777
|
const site = await states.site.findOne({ domain });
|
|
761
778
|
if (
|
|
@@ -799,11 +816,20 @@ module.exports = function getRouterHelpers({ dataDirs, routingSnapshot, routerMa
|
|
|
799
816
|
|
|
800
817
|
const sites = await siteState.getSites();
|
|
801
818
|
|
|
802
|
-
const
|
|
803
|
-
|
|
804
|
-
_ensureBlockletRulesForWellknownSite(blocklet, sites, nodeInfo, context),
|
|
819
|
+
const tasks = [
|
|
820
|
+
_ensureBlockletRulesForWellknownSite(blocklet, sites, context),
|
|
805
821
|
_ensureBlockletSites(blocklet, sites, nodeInfo, context),
|
|
806
|
-
]
|
|
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);
|
|
807
833
|
|
|
808
834
|
return changes.some(Boolean);
|
|
809
835
|
};
|
|
@@ -821,72 +847,14 @@ module.exports = function getRouterHelpers({ dataDirs, routingSnapshot, routerMa
|
|
|
821
847
|
return false;
|
|
822
848
|
}
|
|
823
849
|
|
|
824
|
-
|
|
825
|
-
|
|
826
|
-
|
|
827
|
-
|
|
828
|
-
|
|
829
|
-
return routerManager.deleteRoutingRulesItemByDid({ did: blocklet.meta.did }, context);
|
|
830
|
-
}
|
|
831
|
-
|
|
832
|
-
// First, we need ensure system rules for blocklet on dashboard site
|
|
833
|
-
let changed = await ensureBlockletRouting(blocklet, context);
|
|
834
|
-
|
|
835
|
-
// Then, we need to remove rules whose corresponding interface is not there any more
|
|
836
|
-
const sites = await siteState.getRulesByDid(blocklet.meta.did);
|
|
837
|
-
for (const site of sites) {
|
|
838
|
-
const rulesToRemove = [];
|
|
839
|
-
const rulesToUpdate = [];
|
|
840
|
-
for (const rule of site.rules) {
|
|
841
|
-
if (
|
|
842
|
-
rule.to.type !== ROUTING_RULE_TYPES.BLOCKLET ||
|
|
843
|
-
!rule.to.interfaceName ||
|
|
844
|
-
rule.to.did !== blocklet.meta.did
|
|
845
|
-
) {
|
|
846
|
-
// eslint-disable-next-line no-continue
|
|
847
|
-
continue;
|
|
848
|
-
}
|
|
849
|
-
|
|
850
|
-
if (hasInterface(rule.to.interfaceName) === false) {
|
|
851
|
-
rulesToRemove.push(rule.id);
|
|
852
|
-
}
|
|
853
|
-
|
|
854
|
-
if (rule.to.type === ROUTING_RULE_TYPES.BLOCKLET && rule.id === rule.groupId && !rule.isProtected) {
|
|
855
|
-
rulesToUpdate.push(rule);
|
|
856
|
-
}
|
|
857
|
-
}
|
|
858
|
-
|
|
859
|
-
for (const rule of rulesToUpdate) {
|
|
860
|
-
// eslint-disable-next-line no-await-in-loop
|
|
861
|
-
await routerManager.updateRoutingRule({ id: site.id, rule });
|
|
862
|
-
changed = true;
|
|
863
|
-
}
|
|
864
|
-
|
|
865
|
-
if (rulesToRemove.length === 0) {
|
|
866
|
-
// eslint-disable-next-line no-continue
|
|
867
|
-
continue;
|
|
868
|
-
}
|
|
869
|
-
|
|
870
|
-
try {
|
|
871
|
-
// eslint-disable-next-line no-await-in-loop
|
|
872
|
-
await states.site.update(
|
|
873
|
-
{ _id: site.id },
|
|
874
|
-
{ $set: { rules: site.rules.filter((x) => rulesToRemove.includes(x.id) === false) } }
|
|
875
|
-
);
|
|
876
|
-
changed = true;
|
|
877
|
-
logger.info('remove routing rule since interface does not exist', { rulesToRemove, did: blocklet.meta.did });
|
|
878
|
-
} catch (err) {
|
|
879
|
-
logger.error('failed to remove routing rule since interface does not exist', {
|
|
880
|
-
rulesToRemove,
|
|
881
|
-
did: blocklet.meta.did,
|
|
882
|
-
error: err,
|
|
883
|
-
});
|
|
884
|
-
}
|
|
885
|
-
}
|
|
886
|
-
|
|
887
|
-
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);
|
|
888
855
|
|
|
889
|
-
return
|
|
856
|
+
// Always return true to trigger update of provider
|
|
857
|
+
return true;
|
|
890
858
|
};
|
|
891
859
|
|
|
892
860
|
/**
|
|
@@ -903,51 +871,6 @@ module.exports = function getRouterHelpers({ dataDirs, routingSnapshot, routerMa
|
|
|
903
871
|
return ruleChanged || siteChanged;
|
|
904
872
|
};
|
|
905
873
|
|
|
906
|
-
/**
|
|
907
|
-
* Refresh ip of in ip-dns-domain if ip changed
|
|
908
|
-
*/
|
|
909
|
-
const ensureIpDnsRouting = async (context = {}, output) => {
|
|
910
|
-
const nodeInfo = await nodeState.read();
|
|
911
|
-
const sites = await siteState.getSites();
|
|
912
|
-
|
|
913
|
-
const ip = await getAccessibleIp(nodeInfo);
|
|
914
|
-
if (!ip) {
|
|
915
|
-
logger.error('Cannot get get accessible ip for this node');
|
|
916
|
-
return false;
|
|
917
|
-
}
|
|
918
|
-
|
|
919
|
-
const formattedIp = ip.replace(/\./g, '-');
|
|
920
|
-
const suffix = DEFAULT_DASHBOARD_DOMAIN.replace(/^\*/, '');
|
|
921
|
-
const domainSuffixRegex = new RegExp(`(\\d+-\\d+-\\d+-\\d+)${suffix.replace(/\./g, '\\.')}$`); // xxx-xxx-xxx-xxx.ip.abtnet.io
|
|
922
|
-
const domainSuffix = `${formattedIp}${suffix}`;
|
|
923
|
-
|
|
924
|
-
const changes = [];
|
|
925
|
-
|
|
926
|
-
sites.forEach((x) => {
|
|
927
|
-
const match = domainSuffixRegex.exec(x.domain);
|
|
928
|
-
if (match && match[1] !== formattedIp) {
|
|
929
|
-
const domain = x.domain.replace(domainSuffixRegex, domainSuffix);
|
|
930
|
-
changes.push({ id: x.id, domain });
|
|
931
|
-
}
|
|
932
|
-
});
|
|
933
|
-
|
|
934
|
-
if (changes.length) {
|
|
935
|
-
for (const change of changes) {
|
|
936
|
-
// eslint-disable-next-line no-await-in-loop
|
|
937
|
-
await siteState.update({ _id: change.id }, { $set: { domain: change.domain } });
|
|
938
|
-
if (typeof output === 'function') {
|
|
939
|
-
output(`Blocklet endpoint was updated: ${change.domain}`);
|
|
940
|
-
}
|
|
941
|
-
}
|
|
942
|
-
|
|
943
|
-
const hash = await takeRoutingSnapshot({ message: 'ensure ip dns routing rules', dryRun: false }, context);
|
|
944
|
-
logger.info('take routing snapshot on ensure dashboard routing rules', { changes, hash });
|
|
945
|
-
return true;
|
|
946
|
-
}
|
|
947
|
-
|
|
948
|
-
return false;
|
|
949
|
-
};
|
|
950
|
-
|
|
951
874
|
async function readRoutingSites() {
|
|
952
875
|
const info = await nodeState.read();
|
|
953
876
|
let snapshotHash = get(info, 'routing.snapshotHash', null);
|
|
@@ -1257,7 +1180,6 @@ module.exports = function getRouterHelpers({ dataDirs, routingSnapshot, routerMa
|
|
|
1257
1180
|
getCertificates,
|
|
1258
1181
|
getSitesFromSnapshot,
|
|
1259
1182
|
checkDomain,
|
|
1260
|
-
ensureIpDnsRouting,
|
|
1261
1183
|
|
|
1262
1184
|
getRoutingCrons: () => [
|
|
1263
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
|
@@ -183,17 +183,18 @@ const getBlockletDirs = (blocklet, { rootBlocklet, dataDirs, ensure = false } =
|
|
|
183
183
|
};
|
|
184
184
|
|
|
185
185
|
/**
|
|
186
|
-
* set 'configs',
|
|
186
|
+
* set 'configs', configObj', 'environmentObj' to blocklet
|
|
187
187
|
* @param {*} blocklet
|
|
188
188
|
* @param {*} configs
|
|
189
189
|
*/
|
|
190
190
|
const fillBlockletConfigs = (blocklet, configs) => {
|
|
191
191
|
blocklet.configs = configs || [];
|
|
192
|
-
blocklet.
|
|
192
|
+
blocklet.configObj = blocklet.configs.reduce((acc, x) => {
|
|
193
193
|
acc[x.key] = x.value;
|
|
194
194
|
return acc;
|
|
195
195
|
}, {});
|
|
196
|
-
blocklet.
|
|
196
|
+
blocklet.userEnvironments = blocklet.configObj; // deprecated
|
|
197
|
+
blocklet.environmentObj = (blocklet.environments || []).reduce((acc, x) => {
|
|
197
198
|
acc[x.key] = x.value;
|
|
198
199
|
return acc;
|
|
199
200
|
}, {});
|
|
@@ -222,56 +223,67 @@ const ensureBlockletExpanded = async (meta, appDir) => {
|
|
|
222
223
|
const getRootSystemEnvironments = (blocklet, nodeInfo) => {
|
|
223
224
|
const { did, name, title, description } = blocklet.meta;
|
|
224
225
|
let wallet;
|
|
225
|
-
let
|
|
226
|
-
let
|
|
226
|
+
let appSk;
|
|
227
|
+
let appId;
|
|
228
|
+
let appName = title || name;
|
|
229
|
+
let appDescription = description || '';
|
|
227
230
|
|
|
228
231
|
if (process.env.NODE_ENV !== 'test') {
|
|
229
|
-
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
|
+
);
|
|
230
240
|
wallet = result.wallet;
|
|
231
|
-
|
|
232
|
-
|
|
241
|
+
appSk = toHex(wallet.secretKey);
|
|
242
|
+
appId = wallet.toAddress();
|
|
243
|
+
appName = appName || result.name;
|
|
244
|
+
appDescription = appDescription || result.description;
|
|
233
245
|
} else {
|
|
234
|
-
|
|
235
|
-
|
|
246
|
+
appSk = 'AppSK:FIXME:WalletWorksFailedInJest';
|
|
247
|
+
appId = 'AppID:FIXME:WalletWorksFailedInJest';
|
|
236
248
|
}
|
|
237
249
|
|
|
238
250
|
return {
|
|
239
251
|
BLOCKLET_DID: did,
|
|
240
|
-
BLOCKLET_APP_SK:
|
|
241
|
-
BLOCKLET_APP_ID:
|
|
242
|
-
BLOCKLET_APP_NAME:
|
|
243
|
-
BLOCKLET_APP_DESCRIPTION:
|
|
252
|
+
BLOCKLET_APP_SK: appSk,
|
|
253
|
+
BLOCKLET_APP_ID: appId,
|
|
254
|
+
BLOCKLET_APP_NAME: appName,
|
|
255
|
+
BLOCKLET_APP_DESCRIPTION: appDescription,
|
|
244
256
|
};
|
|
245
257
|
};
|
|
246
258
|
|
|
247
|
-
const getOverwrittenEnvironments = (blocklet) => {
|
|
259
|
+
const getOverwrittenEnvironments = (blocklet, nodeInfo) => {
|
|
248
260
|
const result = {};
|
|
249
|
-
if (!blocklet || !blocklet.
|
|
261
|
+
if (!blocklet || !blocklet.configObj) {
|
|
250
262
|
return result;
|
|
251
263
|
}
|
|
252
264
|
|
|
253
265
|
Object.keys(BLOCKLET_CONFIGURABLE_KEY).forEach((x) => {
|
|
254
|
-
if (!blocklet.
|
|
266
|
+
if (!blocklet.configObj[x]) {
|
|
255
267
|
return;
|
|
256
268
|
}
|
|
257
269
|
|
|
258
|
-
result[x] = blocklet.
|
|
270
|
+
result[x] = blocklet.configObj[x];
|
|
259
271
|
});
|
|
260
272
|
|
|
261
273
|
const keys = ['BLOCKLET_APP_SK', 'BLOCKLET_WALLET_TYPE'];
|
|
262
|
-
const isAppDidRewritten = keys.some((key) => blocklet.
|
|
274
|
+
const isAppDidRewritten = keys.some((key) => blocklet.configObj[key]);
|
|
263
275
|
if (!isAppDidRewritten) {
|
|
264
276
|
return result;
|
|
265
277
|
}
|
|
266
278
|
|
|
267
279
|
// We use user configuration here without any validation since the validation is done during update phase
|
|
268
|
-
const { wallet } = getBlockletInfo(
|
|
269
|
-
|
|
270
|
-
|
|
271
|
-
key,
|
|
272
|
-
|
|
273
|
-
|
|
274
|
-
|
|
280
|
+
const { wallet } = getBlockletInfo(
|
|
281
|
+
{
|
|
282
|
+
meta: blocklet.meta,
|
|
283
|
+
environments: keys.map((key) => ({ key, value: blocklet.configObj[key] })).filter((x) => x.value),
|
|
284
|
+
},
|
|
285
|
+
nodeInfo.sk
|
|
286
|
+
);
|
|
275
287
|
result.BLOCKLET_APP_ID = wallet.toAddress();
|
|
276
288
|
|
|
277
289
|
return result;
|
|
@@ -297,6 +309,21 @@ const getSystemEnvironments = (blocklet) => {
|
|
|
297
309
|
};
|
|
298
310
|
};
|
|
299
311
|
|
|
312
|
+
const getRuntimeEnvironments = (blocklet, nodeEnvironments) => {
|
|
313
|
+
// pm2 will force inject env variables of daemon process to blocklet process
|
|
314
|
+
// we can only rewrite these private env variables to empty
|
|
315
|
+
const safeNodeEnvironments = nodePrivateEnvs.reduce((o, x) => {
|
|
316
|
+
o[x] = '';
|
|
317
|
+
return o;
|
|
318
|
+
}, {});
|
|
319
|
+
|
|
320
|
+
return {
|
|
321
|
+
...blocklet.environmentObj,
|
|
322
|
+
...nodeEnvironments,
|
|
323
|
+
...safeNodeEnvironments,
|
|
324
|
+
};
|
|
325
|
+
};
|
|
326
|
+
|
|
300
327
|
const isUsefulError = (err) => err && err.message !== 'process or namespace not found';
|
|
301
328
|
|
|
302
329
|
const getHealthyCheckTimeout = (blocklet, { checkHealthImmediately } = {}) => {
|
|
@@ -376,14 +403,7 @@ const startBlockletProcess = async (blocklet, { preStart = noop, nodeEnvironment
|
|
|
376
403
|
const { appMain, appId, appCwd, logsDir } = b.env;
|
|
377
404
|
|
|
378
405
|
// get env
|
|
379
|
-
|
|
380
|
-
// we can only rewrite these private env variables to empty
|
|
381
|
-
const safeNodeEnvironments = nodePrivateEnvs.reduce((o, x) => {
|
|
382
|
-
o[x] = '';
|
|
383
|
-
return o;
|
|
384
|
-
}, {});
|
|
385
|
-
|
|
386
|
-
const env = { ...nodeEnvironments, ...b.systemEnvironments, ...b.userEnvironments, ...safeNodeEnvironments };
|
|
406
|
+
const env = getRuntimeEnvironments(b, nodeEnvironments);
|
|
387
407
|
|
|
388
408
|
// run hook
|
|
389
409
|
await preStart(b);
|
|
@@ -408,7 +428,7 @@ const startBlockletProcess = async (blocklet, { preStart = noop, nodeEnvironment
|
|
|
408
428
|
|
|
409
429
|
const clusterMode = get(b.meta, 'capabilities.clusterMode', false);
|
|
410
430
|
if (clusterMode && blocklet.mode !== BLOCKLET_MODES.DEVELOPMENT) {
|
|
411
|
-
const clusterSize = Number(blocklet.
|
|
431
|
+
const clusterSize = Number(blocklet.configObj.BLOCKLET_CLUSTER_SIZE) || Number.POSITIVE_INFINITY;
|
|
412
432
|
options.execMode = 'cluster';
|
|
413
433
|
options.mergeLogs = true;
|
|
414
434
|
options.instances = Math.min(os.cpus().length, clusterSize);
|
|
@@ -872,6 +892,7 @@ module.exports = {
|
|
|
872
892
|
getRootSystemEnvironments,
|
|
873
893
|
getSystemEnvironments,
|
|
874
894
|
getOverwrittenEnvironments,
|
|
895
|
+
getRuntimeEnvironments,
|
|
875
896
|
validateBlocklet,
|
|
876
897
|
fillBlockletConfigs,
|
|
877
898
|
ensureBlockletExpanded,
|
|
@@ -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,27 +19,28 @@
|
|
|
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
|
-
"@
|
|
34
|
+
"@arcblock/vc": "^1.13.15",
|
|
35
|
+
"@blocklet/meta": "1.4.14",
|
|
35
36
|
"@fidm/x509": "^1.2.1",
|
|
36
37
|
"@nedb/core": "^1.1.0",
|
|
37
38
|
"@nedb/multi": "^1.1.0",
|
|
38
|
-
"@ocap/mcrypto": "^1.13.
|
|
39
|
-
"@ocap/util": "^1.13.
|
|
40
|
-
"@ocap/wallet": "^1.13.
|
|
39
|
+
"@ocap/mcrypto": "^1.13.15",
|
|
40
|
+
"@ocap/util": "^1.13.15",
|
|
41
|
+
"@ocap/wallet": "^1.13.15",
|
|
41
42
|
"@slack/webhook": "^5.0.3",
|
|
42
|
-
"axios": "^0.21.
|
|
43
|
+
"axios": "^0.21.4",
|
|
43
44
|
"axon": "^2.0.3",
|
|
44
45
|
"chalk": "^4.0.0",
|
|
45
46
|
"deep-diff": "^1.0.2",
|
|
@@ -71,5 +72,5 @@
|
|
|
71
72
|
"express": "^4.17.1",
|
|
72
73
|
"jest": "^26.4.2"
|
|
73
74
|
},
|
|
74
|
-
"gitHead": "
|
|
75
|
+
"gitHead": "9176b462ff92c787e18a8b218f06a451aad4cf1d"
|
|
75
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
|
-
};
|