@abtnode/core 1.6.22 → 1.6.25
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 +27 -10
- package/lib/blocklet/registry.js +4 -51
- package/lib/event.js +1 -0
- package/lib/index.js +7 -0
- package/lib/router/helper.js +55 -59
- package/lib/router/index.js +10 -5
- package/lib/router/manager.js +4 -4
- package/lib/states/blocklet.js +15 -16
- package/lib/states/node.js +2 -2
- package/lib/states/site.js +9 -0
- package/lib/util/blocklet.js +3 -3
- package/lib/util/disk-monitor.js +13 -10
- package/lib/util/get-domain-for-blocklet.js +4 -1
- package/lib/util/index.js +3 -5
- package/lib/util/registry.js +90 -0
- package/lib/util/service.js +5 -20
- package/lib/util/sysinfo.js +79 -0
- package/lib/validators/router.js +7 -0
- package/lib/validators/trusted-passport.js +1 -0
- package/lib/webhook/index.js +1 -1
- package/package.json +23 -20
|
@@ -92,6 +92,7 @@ const {
|
|
|
92
92
|
needBlockletDownload,
|
|
93
93
|
verifyPurchase,
|
|
94
94
|
} = require('../../util/blocklet');
|
|
95
|
+
const { parseSourceUrl } = require('../../util/registry');
|
|
95
96
|
const states = require('../../states');
|
|
96
97
|
const BlockletRegistry = require('../registry');
|
|
97
98
|
const BaseBlockletManager = require('./base');
|
|
@@ -176,6 +177,9 @@ class BlockletManager extends BaseBlockletManager {
|
|
|
176
177
|
logger.debug('install blocklet', { params, context });
|
|
177
178
|
|
|
178
179
|
const source = getSourceFromInstallParams(params);
|
|
180
|
+
if (typeof context.startImmediately === 'undefined') {
|
|
181
|
+
context.startImmediately = !!params.startImmediately;
|
|
182
|
+
}
|
|
179
183
|
|
|
180
184
|
if (source === BlockletSource.url) {
|
|
181
185
|
return this._installFromUrl({ url: params.url, sync: params.sync }, context);
|
|
@@ -673,7 +677,7 @@ class BlockletManager extends BaseBlockletManager {
|
|
|
673
677
|
/**
|
|
674
678
|
* upgrade blocklet from registry
|
|
675
679
|
*/
|
|
676
|
-
async upgrade({ did, registryUrl }, context) {
|
|
680
|
+
async upgrade({ did, registryUrl, sync }, context) {
|
|
677
681
|
const blocklet = await states.blocklet.getBlocklet(did);
|
|
678
682
|
|
|
679
683
|
// TODO: 查看了下目前页面中的升级按钮,都是会传 registryUrl 过来的,这个函数里的逻辑感觉需要在以后做一个简化
|
|
@@ -740,6 +744,7 @@ class BlockletManager extends BaseBlockletManager {
|
|
|
740
744
|
source: BlockletSource.registry,
|
|
741
745
|
deployedFrom: upgradeFromRegistry,
|
|
742
746
|
context,
|
|
747
|
+
sync,
|
|
743
748
|
});
|
|
744
749
|
}
|
|
745
750
|
|
|
@@ -920,7 +925,6 @@ class BlockletManager extends BaseBlockletManager {
|
|
|
920
925
|
}
|
|
921
926
|
|
|
922
927
|
const { did, version } = meta;
|
|
923
|
-
meta.title = `[DEV] ${meta.title || meta.name}`;
|
|
924
928
|
|
|
925
929
|
const exist = await states.blocklet.getBlocklet(did);
|
|
926
930
|
if (exist) {
|
|
@@ -1104,11 +1108,13 @@ class BlockletManager extends BaseBlockletManager {
|
|
|
1104
1108
|
blocklet.diskInfo = await getDiskInfo(blocklet, { useFakeDiskInfo: !diskInfo });
|
|
1105
1109
|
|
|
1106
1110
|
try {
|
|
1107
|
-
const app = blocklet.meta.group === BlockletGroup.gateway ? blocklet.children[0]
|
|
1108
|
-
|
|
1109
|
-
|
|
1110
|
-
|
|
1111
|
-
blocklet.status
|
|
1111
|
+
const app = blocklet.meta.group === BlockletGroup.gateway ? blocklet.children[0] : blocklet;
|
|
1112
|
+
if (app) {
|
|
1113
|
+
const { appId } = app.env;
|
|
1114
|
+
blocklet.runtimeInfo = await getRuntimeInfo(appId);
|
|
1115
|
+
if (blocklet.runtimeInfo.status && shouldUpdateBlockletStatus(blocklet.status)) {
|
|
1116
|
+
blocklet.status = statusMap[blocklet.runtimeInfo.status];
|
|
1117
|
+
}
|
|
1112
1118
|
}
|
|
1113
1119
|
} catch (err) {
|
|
1114
1120
|
if (err.code !== 'BLOCKLET_PROCESS_404') {
|
|
@@ -1379,7 +1385,7 @@ class BlockletManager extends BaseBlockletManager {
|
|
|
1379
1385
|
}
|
|
1380
1386
|
}
|
|
1381
1387
|
|
|
1382
|
-
async _installFromStore({ did, registry }, context) {
|
|
1388
|
+
async _installFromStore({ did, registry, sync }, context) {
|
|
1383
1389
|
logger.debug('start install blocklet', { did });
|
|
1384
1390
|
if (!isValidDid(did)) {
|
|
1385
1391
|
throw new Error('Blocklet did is invalid');
|
|
@@ -1404,6 +1410,7 @@ class BlockletManager extends BaseBlockletManager {
|
|
|
1404
1410
|
meta,
|
|
1405
1411
|
source: BlockletSource.registry,
|
|
1406
1412
|
deployedFrom: info.cdnUrl || registryUrl,
|
|
1413
|
+
sync,
|
|
1407
1414
|
context,
|
|
1408
1415
|
});
|
|
1409
1416
|
}
|
|
@@ -1411,6 +1418,16 @@ class BlockletManager extends BaseBlockletManager {
|
|
|
1411
1418
|
async _installFromUrl({ url, sync }, context) {
|
|
1412
1419
|
logger.debug('start install blocklet', { url });
|
|
1413
1420
|
|
|
1421
|
+
const { inStore, registryUrl, blockletDid } = await parseSourceUrl(url);
|
|
1422
|
+
if (inStore) {
|
|
1423
|
+
const exist = await states.blocklet.getBlocklet(blockletDid);
|
|
1424
|
+
if (exist) {
|
|
1425
|
+
return this.upgrade({ did: blockletDid, registryUrl }, context);
|
|
1426
|
+
}
|
|
1427
|
+
|
|
1428
|
+
return this._installFromStore({ did: blockletDid, registry: registryUrl }, context);
|
|
1429
|
+
}
|
|
1430
|
+
|
|
1414
1431
|
const meta = await getBlockletMetaFromUrl(url);
|
|
1415
1432
|
|
|
1416
1433
|
if (!meta) {
|
|
@@ -2335,7 +2352,7 @@ class BlockletManager extends BaseBlockletManager {
|
|
|
2335
2352
|
} catch (err) {
|
|
2336
2353
|
const b = await this._rollback(action, did, oldBlocklet);
|
|
2337
2354
|
logger.error(`failed to ${action} blocklet`, { did, version, name, error: err });
|
|
2338
|
-
this.emit(BlockletEvents.updated,
|
|
2355
|
+
this.emit(BlockletEvents.updated, b);
|
|
2339
2356
|
states.notification.create({
|
|
2340
2357
|
title: `Blocklet ${capitalize(action)} Failed`,
|
|
2341
2358
|
description: `Blocklet ${name}@${version} ${action} failed with error: ${err.message}`,
|
|
@@ -2622,7 +2639,7 @@ class BlockletManager extends BaseBlockletManager {
|
|
|
2622
2639
|
const result = await states.blocklet.updateBlocklet(did, oldBlocklet);
|
|
2623
2640
|
await this._setConfigs(did);
|
|
2624
2641
|
logger.info('blocklet rollback successfully', { did });
|
|
2625
|
-
this.emit(BlockletEvents.updated,
|
|
2642
|
+
this.emit(BlockletEvents.updated, result);
|
|
2626
2643
|
return result;
|
|
2627
2644
|
}
|
|
2628
2645
|
|
package/lib/blocklet/registry.js
CHANGED
|
@@ -1,9 +1,7 @@
|
|
|
1
|
-
const isBase64 = require('is-base64');
|
|
2
1
|
const { BlockletGroup } = require('@blocklet/meta/lib/constants');
|
|
3
2
|
const joinURL = require('url-join');
|
|
4
3
|
const get = require('lodash/get');
|
|
5
|
-
const
|
|
6
|
-
const { BLOCKLET_STORE_API_PREFIX, BLOCKLET_STORE_META_PATH } = require('@abtnode/constant');
|
|
4
|
+
const { BLOCKLET_STORE_API_PREFIX } = require('@abtnode/constant');
|
|
7
5
|
|
|
8
6
|
const { name } = require('../../package.json');
|
|
9
7
|
|
|
@@ -15,6 +13,7 @@ const states = require('../states');
|
|
|
15
13
|
const isRequirementsSatisfied = require('../util/requirement');
|
|
16
14
|
const { fixAndVerifyBlockletMeta } = require('../util/blocklet');
|
|
17
15
|
const { translate } = require('../locales');
|
|
16
|
+
const { validateRegistryURL, getRegistryMeta } = require('../util/registry');
|
|
18
17
|
|
|
19
18
|
const DEFAULT_REFRESH_INTERVAL = 1 * 60 * 1000;
|
|
20
19
|
const MAX_REFRESH_INTERVAL = 1 * 60 * 1000;
|
|
@@ -152,54 +151,8 @@ class BlockletRegistry {
|
|
|
152
151
|
}
|
|
153
152
|
}
|
|
154
153
|
|
|
155
|
-
BlockletRegistry.validateRegistryURL =
|
|
156
|
-
const url = joinURL(registry, BLOCKLET_STORE_API_PREFIX, `/blocklets.json?__t__=${Date.now()}`);
|
|
157
|
-
try {
|
|
158
|
-
const res = await request.get(url);
|
|
159
|
-
if (Array.isArray(res.data)) {
|
|
160
|
-
return res.data;
|
|
161
|
-
}
|
|
162
|
-
|
|
163
|
-
logger.error('Blocklet list fetch failed ', { url, data: res.data });
|
|
164
|
-
throw new Error('blocklet list fetch failed');
|
|
165
|
-
} catch (error) {
|
|
166
|
-
logger.error('Blocklet registry refresh failed', { url, error });
|
|
167
|
-
throw new Error(`Invalid Blocklet Registry URL ${registry}: ${error.message}`);
|
|
168
|
-
}
|
|
169
|
-
};
|
|
170
|
-
|
|
171
|
-
BlockletRegistry.getRegistryMeta = async (registry) => {
|
|
172
|
-
try {
|
|
173
|
-
const url = joinURL(registry, BLOCKLET_STORE_META_PATH, `?__t__=${Date.now()}`);
|
|
174
|
-
const { data } = await request.get(url);
|
|
175
|
-
|
|
176
|
-
if (!data) {
|
|
177
|
-
return {};
|
|
178
|
-
}
|
|
154
|
+
BlockletRegistry.validateRegistryURL = validateRegistryURL;
|
|
179
155
|
|
|
180
|
-
|
|
181
|
-
|
|
182
|
-
const missingFields = requiredFields.filter((x) => !data[x]);
|
|
183
|
-
if (missingFields.length > 0) {
|
|
184
|
-
throw new Error(`the registry missing required information: ${missingFields.join(', ')}`);
|
|
185
|
-
}
|
|
186
|
-
|
|
187
|
-
const result = pick(data, ['id', 'name', 'description', 'maintainer', 'cdnUrl', 'chainHost']);
|
|
188
|
-
const { logoUrl } = data;
|
|
189
|
-
if (logoUrl) {
|
|
190
|
-
if (logoUrl.startsWith('http') === true) {
|
|
191
|
-
result.logoUrl = logoUrl;
|
|
192
|
-
} else if (isBase64(logoUrl, { allowMime: true })) {
|
|
193
|
-
result.logoUrl = logoUrl;
|
|
194
|
-
} else {
|
|
195
|
-
result.logoUrl = joinURL(registry, logoUrl);
|
|
196
|
-
}
|
|
197
|
-
}
|
|
198
|
-
|
|
199
|
-
return result;
|
|
200
|
-
} catch (err) {
|
|
201
|
-
throw new Error(`Can not get meta info for registry [${registry}]: ${err.message}`);
|
|
202
|
-
}
|
|
203
|
-
};
|
|
156
|
+
BlockletRegistry.getRegistryMeta = getRegistryMeta;
|
|
204
157
|
|
|
205
158
|
module.exports = BlockletRegistry;
|
package/lib/event.js
CHANGED
|
@@ -208,6 +208,7 @@ module.exports = ({
|
|
|
208
208
|
};
|
|
209
209
|
|
|
210
210
|
events.handleBlockletAdd = handleBlockletAdd;
|
|
211
|
+
events.handleBlockletUpgrade = handleBlockletUpgrade;
|
|
211
212
|
events.handleBlockletRemove = handleBlockletRemove;
|
|
212
213
|
events.handleServerEvent = handleServerEvent;
|
|
213
214
|
events.onEvent = onEvent;
|
package/lib/index.js
CHANGED
|
@@ -35,6 +35,7 @@ const createQueue = require('./queue');
|
|
|
35
35
|
const createEvents = require('./event');
|
|
36
36
|
const pm2Events = require('./blocklet/manager/pm2-events');
|
|
37
37
|
const { createStateReadyQueue, createStateReadyHandler } = require('./util/ready');
|
|
38
|
+
const { getSysInfo, SysInfoEmitter } = require('./util/sysinfo');
|
|
38
39
|
const { toStatus, fromStatus, ensureDataDirs, getQueueConcurrencyByMem } = require('./util');
|
|
39
40
|
|
|
40
41
|
/**
|
|
@@ -148,6 +149,7 @@ function ABTNode(options) {
|
|
|
148
149
|
getSitesFromSnapshot,
|
|
149
150
|
getRoutingCrons,
|
|
150
151
|
ensureWildcardCerts,
|
|
152
|
+
getRouterProvider,
|
|
151
153
|
} = getRouterHelpers({ dataDirs, routingSnapshot, routerManager, blockletManager, certManager });
|
|
152
154
|
|
|
153
155
|
const teamManager = new TeamManager({ nodeDid: options.nodeDid, dataDirs, states });
|
|
@@ -367,6 +369,11 @@ function ABTNode(options) {
|
|
|
367
369
|
|
|
368
370
|
// Services
|
|
369
371
|
getServices: (params, context) => getServices({ stringifySchema: true }, context),
|
|
372
|
+
|
|
373
|
+
// Utilities: moved here because some deps require native build
|
|
374
|
+
getSysInfo,
|
|
375
|
+
getSysInfoEmitter: (interval) => new SysInfoEmitter(interval),
|
|
376
|
+
getRouterProvider,
|
|
370
377
|
};
|
|
371
378
|
|
|
372
379
|
const webhook = WebHook({ events, dataDirs, instance });
|
package/lib/router/helper.js
CHANGED
|
@@ -9,12 +9,11 @@ const isEqual = require('lodash/isEqual');
|
|
|
9
9
|
const joinUrl = require('url-join');
|
|
10
10
|
const { getProvider } = require('@abtnode/router-provider');
|
|
11
11
|
const normalizePathPrefix = require('@abtnode/util/lib/normalize-path-prefix');
|
|
12
|
-
const
|
|
12
|
+
const getTmpDir = require('@abtnode/util/lib/get-tmp-directory');
|
|
13
13
|
const downloadFile = require('@abtnode/util/lib/download-file');
|
|
14
14
|
const {
|
|
15
15
|
DOMAIN_FOR_DEFAULT_SITE,
|
|
16
16
|
DOMAIN_FOR_IP_SITE_REGEXP,
|
|
17
|
-
ROUTER_PROVIDER_NONE,
|
|
18
17
|
DOMAIN_FOR_INTERNAL_SITE,
|
|
19
18
|
WELLKNOWN_PATH_PREFIX,
|
|
20
19
|
WELLKNOWN_AUTH_PATH_PREFIX,
|
|
@@ -30,6 +29,7 @@ const {
|
|
|
30
29
|
BLOCKLET_SITE_GROUP_SUFFIX,
|
|
31
30
|
WELLKNOWN_ACME_CHALLENGE_PREFIX,
|
|
32
31
|
WELLKNOWN_DID_RESOLVER_PREFIX,
|
|
32
|
+
WELLKNOWN_PING_PREFIX,
|
|
33
33
|
} = require('@abtnode/constant');
|
|
34
34
|
const {
|
|
35
35
|
BLOCKLET_DYNAMIC_PATH_PREFIX,
|
|
@@ -449,7 +449,7 @@ module.exports = function getRouterHelpers({ dataDirs, routingSnapshot, routerMa
|
|
|
449
449
|
const hasRuleByPrefix = (site, value) => site.rules.find((x) => x.isProtected && get(x, 'from.pathPrefix') === value);
|
|
450
450
|
|
|
451
451
|
const downloadCert = async ({ domain, url }) => {
|
|
452
|
-
const destFolder =
|
|
452
|
+
const destFolder = getTmpDir(path.join(`certificate-${Date.now()}`));
|
|
453
453
|
try {
|
|
454
454
|
const filename = path.join(destFolder, 'certificate.tar.gz');
|
|
455
455
|
fs.ensureDirSync(destFolder);
|
|
@@ -511,11 +511,6 @@ module.exports = function getRouterHelpers({ dataDirs, routingSnapshot, routerMa
|
|
|
511
511
|
|
|
512
512
|
const updateDashboardCertificates = async () => {
|
|
513
513
|
const info = await nodeState.read();
|
|
514
|
-
const provider = getProviderFromNodeInfo(info);
|
|
515
|
-
if (provider === ROUTER_PROVIDER_NONE) {
|
|
516
|
-
return;
|
|
517
|
-
}
|
|
518
|
-
|
|
519
514
|
const https = get(info, 'routing.https', true);
|
|
520
515
|
const ipWildcardDomain = get(info, 'routing.ipWildcardDomain', '');
|
|
521
516
|
const didDomain = info.didDomain;
|
|
@@ -597,6 +592,20 @@ module.exports = function getRouterHelpers({ dataDirs, routingSnapshot, routerMa
|
|
|
597
592
|
to: proxyTarget,
|
|
598
593
|
};
|
|
599
594
|
|
|
595
|
+
const pingWellknownRule = {
|
|
596
|
+
isProtected: true,
|
|
597
|
+
from: { pathPrefix: WELLKNOWN_PING_PREFIX },
|
|
598
|
+
to: {
|
|
599
|
+
type: ROUTING_RULE_TYPES.DIRECT_RESPONSE,
|
|
600
|
+
response: {
|
|
601
|
+
status: 200,
|
|
602
|
+
contentType: 'application/javascript',
|
|
603
|
+
body: "console.log('ping: pong')",
|
|
604
|
+
},
|
|
605
|
+
port: info.port,
|
|
606
|
+
},
|
|
607
|
+
};
|
|
608
|
+
|
|
600
609
|
if (site) {
|
|
601
610
|
const didResolverRuleUpdateRes = await upsertSiteRule(
|
|
602
611
|
{
|
|
@@ -614,7 +623,15 @@ module.exports = function getRouterHelpers({ dataDirs, routingSnapshot, routerMa
|
|
|
614
623
|
context
|
|
615
624
|
);
|
|
616
625
|
|
|
617
|
-
|
|
626
|
+
const pingRuleRes = await upsertSiteRule(
|
|
627
|
+
{
|
|
628
|
+
site,
|
|
629
|
+
rule: pingWellknownRule,
|
|
630
|
+
},
|
|
631
|
+
context
|
|
632
|
+
);
|
|
633
|
+
|
|
634
|
+
return didResolverRuleUpdateRes || acmeRuleUpdateRes || pingRuleRes;
|
|
618
635
|
}
|
|
619
636
|
|
|
620
637
|
await routerManager.addRoutingSite(
|
|
@@ -623,7 +640,7 @@ module.exports = function getRouterHelpers({ dataDirs, routingSnapshot, routerMa
|
|
|
623
640
|
domain: DOMAIN_FOR_INTERNAL_SITE,
|
|
624
641
|
port: await getWellknownSitePort(),
|
|
625
642
|
name: NAME_FOR_WELLKNOWN_SITE,
|
|
626
|
-
rules: [didResolverWellknownRule, acmeChallengeWellknownRule],
|
|
643
|
+
rules: [didResolverWellknownRule, acmeChallengeWellknownRule, pingWellknownRule],
|
|
627
644
|
isProtected: true,
|
|
628
645
|
},
|
|
629
646
|
skipCheckDynamicBlacklist: true,
|
|
@@ -647,12 +664,6 @@ module.exports = function getRouterHelpers({ dataDirs, routingSnapshot, routerMa
|
|
|
647
664
|
*/
|
|
648
665
|
const ensureDashboardRouting = async (context = {}) => {
|
|
649
666
|
const info = await nodeState.read();
|
|
650
|
-
|
|
651
|
-
const provider = getProviderFromNodeInfo(info);
|
|
652
|
-
if (provider === ROUTER_PROVIDER_NONE) {
|
|
653
|
-
return false;
|
|
654
|
-
}
|
|
655
|
-
|
|
656
667
|
const sites = await siteState.getSites();
|
|
657
668
|
let dashboardSite = (sites || []).find((x) => x.domain === DOMAIN_FOR_IP_SITE);
|
|
658
669
|
const updatedResult = [];
|
|
@@ -893,6 +904,7 @@ module.exports = function getRouterHelpers({ dataDirs, routingSnapshot, routerMa
|
|
|
893
904
|
* Add system routing rules for blocklet in dashboard site
|
|
894
905
|
*
|
|
895
906
|
* @returns {boolean} if routing changed
|
|
907
|
+
* TODO: do we still need this?
|
|
896
908
|
*/
|
|
897
909
|
const _ensureBlockletRulesForDashboardSite = async (blocklet, sites, nodeInfo, context = {}) => {
|
|
898
910
|
// blocklet level duplication detection
|
|
@@ -993,12 +1005,6 @@ module.exports = function getRouterHelpers({ dataDirs, routingSnapshot, routerMa
|
|
|
993
1005
|
*/
|
|
994
1006
|
const ensureBlockletRouting = async (blocklet, context = {}) => {
|
|
995
1007
|
const nodeInfo = await nodeState.read();
|
|
996
|
-
|
|
997
|
-
const provider = getProviderFromNodeInfo(nodeInfo);
|
|
998
|
-
if (provider === ROUTER_PROVIDER_NONE) {
|
|
999
|
-
return false;
|
|
1000
|
-
}
|
|
1001
|
-
|
|
1002
1008
|
const hasWebInterface = (blocklet.meta.interfaces || []).some((x) => x.type === BLOCKLET_INTERFACE_TYPE_WEB);
|
|
1003
1009
|
if (!hasWebInterface) {
|
|
1004
1010
|
return false;
|
|
@@ -1098,12 +1104,6 @@ module.exports = function getRouterHelpers({ dataDirs, routingSnapshot, routerMa
|
|
|
1098
1104
|
* @returns {boolean} if routing changed
|
|
1099
1105
|
*/
|
|
1100
1106
|
const ensureBlockletRoutingForUpgrade = async (blocklet, context = {}) => {
|
|
1101
|
-
const nodeInfo = await nodeState.read();
|
|
1102
|
-
const provider = getProviderFromNodeInfo(nodeInfo);
|
|
1103
|
-
if (provider === ROUTER_PROVIDER_NONE) {
|
|
1104
|
-
return false;
|
|
1105
|
-
}
|
|
1106
|
-
|
|
1107
1107
|
await routerManager.deleteRoutingRulesItemByDid(
|
|
1108
1108
|
{ did: blocklet.meta.did, ruleFilter: (x) => x.isProtected },
|
|
1109
1109
|
context
|
|
@@ -1158,14 +1158,11 @@ module.exports = function getRouterHelpers({ dataDirs, routingSnapshot, routerMa
|
|
|
1158
1158
|
return rules.filter((rule) => rule.to.did === did);
|
|
1159
1159
|
}
|
|
1160
1160
|
|
|
1161
|
-
const
|
|
1161
|
+
const providers = {}; // we need to keep reference for different router instances
|
|
1162
1162
|
const handleRouting = async (nodeInfo) => {
|
|
1163
1163
|
const providerName = get(nodeInfo, 'routing.provider', null);
|
|
1164
1164
|
const httpsEnabled = get(nodeInfo, 'routing.https', true);
|
|
1165
1165
|
logger.debug('handle routing', { providerName, httpsEnabled });
|
|
1166
|
-
if (providerName === ROUTER_PROVIDER_NONE) {
|
|
1167
|
-
return;
|
|
1168
|
-
}
|
|
1169
1166
|
|
|
1170
1167
|
const Provider = getProvider(providerName);
|
|
1171
1168
|
const checkResult = await Provider.check({ configDir: dataDirs.router });
|
|
@@ -1173,12 +1170,12 @@ module.exports = function getRouterHelpers({ dataDirs, routingSnapshot, routerMa
|
|
|
1173
1170
|
throw new Error(`${providerName} pre-check failed, ${checkResult.error}`);
|
|
1174
1171
|
}
|
|
1175
1172
|
|
|
1176
|
-
if (
|
|
1177
|
-
await
|
|
1173
|
+
if (providers[providerName]) {
|
|
1174
|
+
await providers[providerName].reload();
|
|
1178
1175
|
} else {
|
|
1179
|
-
|
|
1176
|
+
providers[providerName] = new Router({
|
|
1180
1177
|
provider: new Provider({
|
|
1181
|
-
|
|
1178
|
+
configDir: path.join(dataDirs.router, providerName),
|
|
1182
1179
|
httpPort: nodeInfo.routing.httpPort || DEFAULT_HTTP_PORT,
|
|
1183
1180
|
httpsPort: nodeInfo.routing.httpsPort || DEFAULT_HTTPS_PORT,
|
|
1184
1181
|
cacheDisabled: nodeInfo.mode === NODE_MODES.DEBUG,
|
|
@@ -1216,11 +1213,11 @@ module.exports = function getRouterHelpers({ dataDirs, routingSnapshot, routerMa
|
|
|
1216
1213
|
},
|
|
1217
1214
|
});
|
|
1218
1215
|
|
|
1219
|
-
certManager.on('cert.added', () =>
|
|
1220
|
-
certManager.on('cert.removed', () =>
|
|
1221
|
-
certManager.on('cert.issued', () =>
|
|
1216
|
+
certManager.on('cert.added', () => providers[providerName].reload());
|
|
1217
|
+
certManager.on('cert.removed', () => providers[providerName].reload());
|
|
1218
|
+
certManager.on('cert.issued', () => providers[providerName].reload());
|
|
1222
1219
|
|
|
1223
|
-
await
|
|
1220
|
+
await providers[providerName].start();
|
|
1224
1221
|
}
|
|
1225
1222
|
};
|
|
1226
1223
|
|
|
@@ -1228,8 +1225,8 @@ module.exports = function getRouterHelpers({ dataDirs, routingSnapshot, routerMa
|
|
|
1228
1225
|
const info = await nodeState.read();
|
|
1229
1226
|
const providerName = get(info, 'routing.provider', null);
|
|
1230
1227
|
|
|
1231
|
-
if (providerName &&
|
|
1232
|
-
await
|
|
1228
|
+
if (providerName && providers[providerName] && typeof providers[providerName].rotateLogs === 'function') {
|
|
1229
|
+
await providers[providerName].rotateLogs();
|
|
1233
1230
|
}
|
|
1234
1231
|
};
|
|
1235
1232
|
|
|
@@ -1258,30 +1255,28 @@ module.exports = function getRouterHelpers({ dataDirs, routingSnapshot, routerMa
|
|
|
1258
1255
|
await handleRouting(result);
|
|
1259
1256
|
|
|
1260
1257
|
if (newProvider !== info.routing.provider) {
|
|
1261
|
-
|
|
1262
|
-
|
|
1263
|
-
|
|
1264
|
-
|
|
1265
|
-
|
|
1266
|
-
|
|
1267
|
-
const
|
|
1268
|
-
|
|
1269
|
-
|
|
1270
|
-
|
|
1271
|
-
const ensureBlockletResults = await Promise.all(blocklets.map((x) => ensureBlocklet(x)));
|
|
1258
|
+
// Ensure we have system sites for daemon
|
|
1259
|
+
await ensureDashboardRouting(context);
|
|
1260
|
+
|
|
1261
|
+
// Ensure we have system rules for blocklets
|
|
1262
|
+
const blocklets = await blockletState.getBlocklets();
|
|
1263
|
+
const ensureBlocklet = async (x) => {
|
|
1264
|
+
const blocklet = await blockletManager.ensureBlocklet(x.meta.did);
|
|
1265
|
+
return ensureBlockletRouting(blocklet, context);
|
|
1266
|
+
};
|
|
1267
|
+
const ensureBlockletResults = await Promise.all(blocklets.map((x) => ensureBlocklet(x)));
|
|
1272
1268
|
|
|
1273
|
-
|
|
1274
|
-
|
|
1275
|
-
|
|
1276
|
-
|
|
1277
|
-
}
|
|
1269
|
+
// We need to take snapshot after system rules ensured
|
|
1270
|
+
if (ensureBlockletResults.filter(Boolean).length) {
|
|
1271
|
+
await takeRoutingSnapshot({ message: `Switch routing engine to ${newProvider}`, dryRun: false }, context);
|
|
1272
|
+
logger.info(`take routing snapshot on switch engine: ${newProvider}`, { ensureBlockletResults });
|
|
1278
1273
|
}
|
|
1279
1274
|
|
|
1280
1275
|
const Provider = getProvider(info.routing.provider);
|
|
1281
1276
|
if (Provider) {
|
|
1282
1277
|
try {
|
|
1283
1278
|
const providerInstance = new Provider({
|
|
1284
|
-
|
|
1279
|
+
configDir: path.join(dataDirs.router, info.routing.provider),
|
|
1285
1280
|
httpPort: info.routing.httpPort || DEFAULT_HTTP_PORT,
|
|
1286
1281
|
httpsPort: info.routing.httpsPort || DEFAULT_HTTPS_PORT,
|
|
1287
1282
|
cacheDisabled: info.mode === NODE_MODES.DEBUG,
|
|
@@ -1424,6 +1419,7 @@ module.exports = function getRouterHelpers({ dataDirs, routingSnapshot, routerMa
|
|
|
1424
1419
|
ensureWildcardCerts,
|
|
1425
1420
|
addWellknownSite,
|
|
1426
1421
|
upsertSiteRule,
|
|
1422
|
+
getRouterProvider: (name) => providers[name],
|
|
1427
1423
|
|
|
1428
1424
|
getRoutingCrons: () => [
|
|
1429
1425
|
{
|
package/lib/router/index.js
CHANGED
|
@@ -117,12 +117,7 @@ class Router {
|
|
|
117
117
|
}
|
|
118
118
|
|
|
119
119
|
async update() {
|
|
120
|
-
if (!this.provider) {
|
|
121
|
-
throw new Error('use setProvider() to set provider first');
|
|
122
|
-
}
|
|
123
|
-
|
|
124
120
|
logger.info('router: update');
|
|
125
|
-
|
|
126
121
|
await this.updateRoutingTable();
|
|
127
122
|
await this.provider.reload();
|
|
128
123
|
}
|
|
@@ -139,6 +134,12 @@ class Router {
|
|
|
139
134
|
return this.provider.restart();
|
|
140
135
|
}
|
|
141
136
|
|
|
137
|
+
async reload() {
|
|
138
|
+
logger.info('router: reload');
|
|
139
|
+
await this.updateRoutingTable();
|
|
140
|
+
return this.provider.reload();
|
|
141
|
+
}
|
|
142
|
+
|
|
142
143
|
stop() {
|
|
143
144
|
logger.info('router: stop');
|
|
144
145
|
return this.provider.stop();
|
|
@@ -153,6 +154,10 @@ class Router {
|
|
|
153
154
|
logger.info('router: rotate logs');
|
|
154
155
|
await this.provider.rotateLogs();
|
|
155
156
|
}
|
|
157
|
+
|
|
158
|
+
getLogFilesForToday() {
|
|
159
|
+
return this.provider.getLogFilesForToday();
|
|
160
|
+
}
|
|
156
161
|
}
|
|
157
162
|
|
|
158
163
|
Router.formatSites = (sites = []) => {
|
package/lib/router/manager.js
CHANGED
|
@@ -594,8 +594,8 @@ class RouterManager extends EventEmitter {
|
|
|
594
594
|
// get provider
|
|
595
595
|
const providerName = getProviderFromNodeInfo(info);
|
|
596
596
|
const Provider = getProvider(providerName);
|
|
597
|
-
const
|
|
598
|
-
const provider = new Provider({
|
|
597
|
+
const tmpDir = path.join(os.tmpdir(), `${providerName}-${Date.now()}`);
|
|
598
|
+
const provider = new Provider({ configDir: tmpDir });
|
|
599
599
|
const tempRouter = new Router({
|
|
600
600
|
provider,
|
|
601
601
|
getRoutingParams: async () => ({
|
|
@@ -610,10 +610,10 @@ class RouterManager extends EventEmitter {
|
|
|
610
610
|
await tempRouter.updateRoutingTable();
|
|
611
611
|
try {
|
|
612
612
|
await tempRouter.validateConfig();
|
|
613
|
-
await fse.remove(
|
|
613
|
+
await fse.remove(tmpDir);
|
|
614
614
|
} catch (error) {
|
|
615
615
|
logger.error('validate router config failed', { error, action, data });
|
|
616
|
-
await fse.remove(
|
|
616
|
+
await fse.remove(tmpDir);
|
|
617
617
|
throw error;
|
|
618
618
|
}
|
|
619
619
|
}
|
package/lib/states/blocklet.js
CHANGED
|
@@ -9,6 +9,7 @@ const detectPort = require('detect-port');
|
|
|
9
9
|
const Lock = require('@abtnode/util/lib/lock');
|
|
10
10
|
const security = require('@abtnode/util/lib/security');
|
|
11
11
|
const { fixPerson, fixInterfaces } = require('@blocklet/meta/lib/fix');
|
|
12
|
+
const { getDisplayName } = require('@blocklet/meta/lib/util');
|
|
12
13
|
const {
|
|
13
14
|
BlockletStatus,
|
|
14
15
|
BlockletSource,
|
|
@@ -25,6 +26,7 @@ const { validateBlockletMeta } = require('../util');
|
|
|
25
26
|
|
|
26
27
|
const lock = new Lock('blocklet-port-assign-lock');
|
|
27
28
|
|
|
29
|
+
const isHex = (str) => /^0x[0-9a-f]+$/i.test(str);
|
|
28
30
|
const getMaxPort = (ports = {}) => Math.max(Object.values(ports).map(Number));
|
|
29
31
|
|
|
30
32
|
const getExternalPortsFromMeta = (meta) =>
|
|
@@ -50,10 +52,10 @@ const formatBlocklet = (blocklet, phase, dek) => {
|
|
|
50
52
|
if (!env) {
|
|
51
53
|
return;
|
|
52
54
|
}
|
|
53
|
-
if (phase === 'onUpdate' && env.value
|
|
55
|
+
if (phase === 'onUpdate' && isHex(env.value) === true) {
|
|
54
56
|
env.value = security.encrypt(env.value, b.meta.did, dek);
|
|
55
57
|
}
|
|
56
|
-
if (phase === 'onRead' && env.value
|
|
58
|
+
if (phase === 'onRead' && isHex(env.value) === false) {
|
|
57
59
|
env.value = security.decrypt(env.value, b.meta.did, dek);
|
|
58
60
|
}
|
|
59
61
|
});
|
|
@@ -243,20 +245,17 @@ class BlockletState extends BaseState {
|
|
|
243
245
|
await this.fillChildrenPorts(children, { oldChildren: doc.children, defaultPort: getMaxPort(ports) });
|
|
244
246
|
|
|
245
247
|
// add to db
|
|
246
|
-
const newDoc = await this.
|
|
247
|
-
|
|
248
|
-
|
|
249
|
-
|
|
250
|
-
|
|
251
|
-
|
|
252
|
-
ports,
|
|
253
|
-
},
|
|
248
|
+
const newDoc = await this.updateBlocklet(meta.did, {
|
|
249
|
+
meta: omit(sanitized, ['htmlAst']),
|
|
250
|
+
source,
|
|
251
|
+
deployedFrom,
|
|
252
|
+
children,
|
|
253
|
+
ports,
|
|
254
254
|
});
|
|
255
255
|
lock.release();
|
|
256
256
|
|
|
257
|
-
|
|
258
|
-
|
|
259
|
-
resolve(formatted);
|
|
257
|
+
this.emit('upgrade', newDoc);
|
|
258
|
+
resolve(newDoc);
|
|
260
259
|
} catch (err) {
|
|
261
260
|
lock.release();
|
|
262
261
|
reject(err);
|
|
@@ -446,8 +445,7 @@ class BlockletState extends BaseState {
|
|
|
446
445
|
return child;
|
|
447
446
|
});
|
|
448
447
|
|
|
449
|
-
|
|
450
|
-
return formatBlocklet({ ...doc, ...updates }, 'onRead', this.options.dek);
|
|
448
|
+
return this.updateBlocklet(did, updates);
|
|
451
449
|
}
|
|
452
450
|
|
|
453
451
|
async fillChildrenPorts(children, { defaultPort = 0, oldChildren } = {}) {
|
|
@@ -511,7 +509,7 @@ class BlockletState extends BaseState {
|
|
|
511
509
|
const { meta, mountPoint, sourceUrl = '', source = '', deployedFrom = '' } = child;
|
|
512
510
|
|
|
513
511
|
if (!mountPoint) {
|
|
514
|
-
throw new Error(`mountPoint is required when adding component ${
|
|
512
|
+
throw new Error(`mountPoint is required when adding component ${getDisplayName(child, true)}`);
|
|
515
513
|
}
|
|
516
514
|
|
|
517
515
|
if (meta.did === parent.meta.did) {
|
|
@@ -542,5 +540,6 @@ class BlockletState extends BaseState {
|
|
|
542
540
|
}
|
|
543
541
|
|
|
544
542
|
BlockletState.BlockletStatus = BlockletStatus;
|
|
543
|
+
BlockletState.formatBlocklet = formatBlocklet;
|
|
545
544
|
|
|
546
545
|
module.exports = BlockletState;
|
package/lib/states/node.js
CHANGED
|
@@ -6,7 +6,7 @@ const isEmpty = require('lodash/isEmpty');
|
|
|
6
6
|
const security = require('@abtnode/util/lib/security');
|
|
7
7
|
const { isFromPublicKey } = require('@arcblock/did');
|
|
8
8
|
const logger = require('@abtnode/logger')('@abtnode/core:node');
|
|
9
|
-
const {
|
|
9
|
+
const { NODE_MODES, DISK_ALERT_THRESHOLD_PERCENT } = require('@abtnode/constant');
|
|
10
10
|
|
|
11
11
|
const BaseState = require('./base');
|
|
12
12
|
const { validateOwner } = require('../util');
|
|
@@ -87,7 +87,7 @@ class NodeState extends BaseState {
|
|
|
87
87
|
nodeOwner,
|
|
88
88
|
port,
|
|
89
89
|
version,
|
|
90
|
-
routing = { provider:
|
|
90
|
+
routing = { provider: 'default' },
|
|
91
91
|
docker,
|
|
92
92
|
mode,
|
|
93
93
|
runtimeConfig,
|
package/lib/states/site.js
CHANGED
|
@@ -1,4 +1,5 @@
|
|
|
1
1
|
const logger = require('@abtnode/logger')('@abtnode/core:states:site');
|
|
2
|
+
const { toSlotDomain } = require('@abtnode/router-provider/lib/util');
|
|
2
3
|
|
|
3
4
|
const BaseState = require('./base');
|
|
4
5
|
|
|
@@ -75,6 +76,14 @@ class SiteState extends BaseState {
|
|
|
75
76
|
|
|
76
77
|
return count > 0;
|
|
77
78
|
}
|
|
79
|
+
|
|
80
|
+
async findOneByDomain(domain) {
|
|
81
|
+
// eslint-disable-next-line no-param-reassign
|
|
82
|
+
domain = toSlotDomain(domain);
|
|
83
|
+
return this.asyncDB.findOne({
|
|
84
|
+
$or: [{ domain }, { domainAliases: domain }, { 'domainAliases.value': domain }],
|
|
85
|
+
});
|
|
86
|
+
}
|
|
78
87
|
}
|
|
79
88
|
|
|
80
89
|
module.exports = SiteState;
|
package/lib/util/blocklet.js
CHANGED
|
@@ -42,7 +42,7 @@ const validateBlockletEntry = require('@blocklet/meta/lib/entry');
|
|
|
42
42
|
const getBlockletEngine = require('@blocklet/meta/lib/engine');
|
|
43
43
|
const getBlockletInfo = require('@blocklet/meta/lib/info');
|
|
44
44
|
const { validateMeta, fixAndValidateService } = require('@blocklet/meta/lib/validate');
|
|
45
|
-
const { forEachBlocklet, isFreeBlocklet } = require('@blocklet/meta/lib/util');
|
|
45
|
+
const { forEachBlocklet, isFreeBlocklet, getDisplayName } = require('@blocklet/meta/lib/util');
|
|
46
46
|
|
|
47
47
|
const { validate: validateEngine, get: getEngine } = require('../blocklet/manager/engine');
|
|
48
48
|
|
|
@@ -456,7 +456,7 @@ const startBlockletProcess = async (blocklet, { preStart = noop, nodeEnvironment
|
|
|
456
456
|
|
|
457
457
|
const clusterMode = get(b.meta, 'capabilities.clusterMode', false);
|
|
458
458
|
if (clusterMode && blocklet.mode !== BLOCKLET_MODES.DEVELOPMENT) {
|
|
459
|
-
const clusterSize = Number(blocklet.configObj.BLOCKLET_CLUSTER_SIZE) ||
|
|
459
|
+
const clusterSize = Number(blocklet.configObj.BLOCKLET_CLUSTER_SIZE) || +process.env.ABT_NODE_MAX_CLUSTER_SIZE;
|
|
460
460
|
options.execMode = 'cluster';
|
|
461
461
|
options.mergeLogs = true;
|
|
462
462
|
options.instances = Math.min(os.cpus().length, clusterSize);
|
|
@@ -1069,7 +1069,7 @@ const checkDuplicateComponents = (dynamicComponents, staticComponents) => {
|
|
|
1069
1069
|
if (duplicates.length) {
|
|
1070
1070
|
throw new Error(
|
|
1071
1071
|
`Cannot add duplicate component${duplicates.length > 1 ? 's' : ''}: ${duplicates
|
|
1072
|
-
.map((x) => x
|
|
1072
|
+
.map((x) => getDisplayName(x, true))
|
|
1073
1073
|
.join(', ')}`
|
|
1074
1074
|
);
|
|
1075
1075
|
}
|
package/lib/util/disk-monitor.js
CHANGED
|
@@ -1,22 +1,26 @@
|
|
|
1
|
-
const systeminformation = require('@abtnode/util/lib/sys-info');
|
|
2
1
|
const logger = require('@abtnode/logger')('@abtnode/disk-monitor');
|
|
2
|
+
const info = require('./sysinfo');
|
|
3
3
|
|
|
4
4
|
const states = require('../states');
|
|
5
5
|
|
|
6
6
|
/**
|
|
7
|
-
*
|
|
8
|
-
* @param {number} threshold Threshold for disk alarms, percentage
|
|
7
|
+
* @param {number} threshold Threshold for disk alerts, percentage
|
|
9
8
|
*/
|
|
10
9
|
const check = async (threshold) => {
|
|
11
|
-
const
|
|
12
|
-
const
|
|
13
|
-
|
|
14
|
-
|
|
10
|
+
const { disks } = await info.getSysInfo();
|
|
11
|
+
for (const disk of disks) {
|
|
12
|
+
const usageRatio = (disk.used / disk.total) * 100;
|
|
13
|
+
const usageRatioPercent = `${usageRatio.toFixed(2)}%`;
|
|
14
|
+
logger.info('check disk usage', { usage: usageRatioPercent, threshold });
|
|
15
15
|
|
|
16
|
-
|
|
16
|
+
if (usageRatio < threshold) {
|
|
17
|
+
return;
|
|
18
|
+
}
|
|
19
|
+
|
|
20
|
+
// eslint-disable-next-line no-await-in-loop
|
|
17
21
|
await states.notification.create({
|
|
18
22
|
title: 'Disk Usage Alert',
|
|
19
|
-
description: `More than ${
|
|
23
|
+
description: `More than ${usageRatioPercent} space has been used for disk ${disk.device}, the blocklet server may not function properly.`,
|
|
20
24
|
entityType: 'node',
|
|
21
25
|
severity: 'warning',
|
|
22
26
|
sticky: true,
|
|
@@ -30,7 +34,6 @@ const getCron = () => ({
|
|
|
30
34
|
fn: async () => {
|
|
31
35
|
const nodeInfo = await states.node.read();
|
|
32
36
|
const threshold = nodeInfo.diskAlertThreshold;
|
|
33
|
-
|
|
34
37
|
await check(threshold);
|
|
35
38
|
},
|
|
36
39
|
options: { runOnInit: true },
|
|
@@ -1,5 +1,6 @@
|
|
|
1
1
|
const slugify = require('slugify');
|
|
2
2
|
const { DEFAULT_IP_DNS_DOMAIN_SUFFIX } = require('@abtnode/constant');
|
|
3
|
+
const md5 = require('@abtnode/util/lib/md5');
|
|
3
4
|
|
|
4
5
|
const SLOT_FOR_IP_DNS_SITE = '888-888-888-888';
|
|
5
6
|
|
|
@@ -17,7 +18,9 @@ const getIpDnsDomainForBlocklet = (blocklet, blockletInterface) => {
|
|
|
17
18
|
};
|
|
18
19
|
|
|
19
20
|
const getDidDomainForBlocklet = ({ name, daemonDid, didDomain }) => {
|
|
20
|
-
|
|
21
|
+
const prefix = md5(name).substring(0, 8);
|
|
22
|
+
|
|
23
|
+
return `${prefix}-${daemonDid.toLowerCase()}.${didDomain}`;
|
|
21
24
|
};
|
|
22
25
|
|
|
23
26
|
module.exports = { getIpDnsDomainForBlocklet, getDidDomainForBlocklet };
|
package/lib/util/index.js
CHANGED
|
@@ -20,7 +20,6 @@ const { validateMeta, fixAndValidateService } = require('@blocklet/meta/lib/vali
|
|
|
20
20
|
const { BlockletStatus, BLOCKLET_INTERFACE_WELLKNOWN } = require('@blocklet/meta/lib/constants');
|
|
21
21
|
const {
|
|
22
22
|
StatusCode,
|
|
23
|
-
ROUTER_PROVIDER_NONE,
|
|
24
23
|
DOMAIN_FOR_DEFAULT_SITE,
|
|
25
24
|
DOMAIN_FOR_IP_SITE,
|
|
26
25
|
DOMAIN_FOR_IP_SITE_REGEXP,
|
|
@@ -242,7 +241,7 @@ const getBlockletInterfaces = ({ blocklet, context, nodeInfo, routingRules, node
|
|
|
242
241
|
return uniqBy(interfaces, 'url');
|
|
243
242
|
};
|
|
244
243
|
|
|
245
|
-
const isRoutingEnabled = (routing) => !!routing && !!routing.provider
|
|
244
|
+
const isRoutingEnabled = (routing) => !!routing && !!routing.provider;
|
|
246
245
|
|
|
247
246
|
const isInProgress = (status) =>
|
|
248
247
|
[
|
|
@@ -283,7 +282,7 @@ const asyncExec = (command, options) =>
|
|
|
283
282
|
});
|
|
284
283
|
});
|
|
285
284
|
|
|
286
|
-
const getProviderFromNodeInfo = (
|
|
285
|
+
const getProviderFromNodeInfo = (info) => get(info, 'routing.provider', 'default');
|
|
287
286
|
|
|
288
287
|
const isCLI = () => !process.env.ABT_NODE_SK;
|
|
289
288
|
|
|
@@ -370,9 +369,8 @@ const getBaseUrls = async (node, ips) => {
|
|
|
370
369
|
return { protocol, port };
|
|
371
370
|
};
|
|
372
371
|
|
|
373
|
-
if (info.routing.provider
|
|
372
|
+
if (info.routing.provider && info.routing.snapshotHash && info.routing.adminPath) {
|
|
374
373
|
const sites = await node.getSitesFromSnapshot();
|
|
375
|
-
|
|
376
374
|
const { ipWildcardDomain } = info.routing;
|
|
377
375
|
const adminPath = normalizePathPrefix(info.routing.adminPath);
|
|
378
376
|
const tmpHttpPort = getPort(httpPort, DEFAULT_HTTP_PORT);
|
|
@@ -0,0 +1,90 @@
|
|
|
1
|
+
const joinURL = require('url-join');
|
|
2
|
+
const pick = require('lodash/pick');
|
|
3
|
+
const isBase64 = require('is-base64');
|
|
4
|
+
|
|
5
|
+
const { BLOCKLET_STORE_API_PREFIX, BLOCKLET_STORE_META_PATH } = require('@abtnode/constant');
|
|
6
|
+
|
|
7
|
+
const { name } = require('../../package.json');
|
|
8
|
+
const logger = require('@abtnode/logger')(`${name}:util:registry`); // eslint-disable-line
|
|
9
|
+
|
|
10
|
+
const request = require('./request');
|
|
11
|
+
|
|
12
|
+
const validateRegistryURL = async (registry) => {
|
|
13
|
+
const url = joinURL(registry, BLOCKLET_STORE_API_PREFIX, `/blocklets.json?__t__=${Date.now()}`);
|
|
14
|
+
try {
|
|
15
|
+
const res = await request.get(url);
|
|
16
|
+
if (Array.isArray(res.data)) {
|
|
17
|
+
return res.data;
|
|
18
|
+
}
|
|
19
|
+
|
|
20
|
+
logger.error('Blocklet list fetch failed ', { url, data: res.data });
|
|
21
|
+
throw new Error('blocklet list fetch failed');
|
|
22
|
+
} catch (error) {
|
|
23
|
+
logger.error('Blocklet registry refresh failed', { url, error });
|
|
24
|
+
throw new Error(`Invalid Blocklet Registry URL ${registry}: ${error.message}`);
|
|
25
|
+
}
|
|
26
|
+
};
|
|
27
|
+
|
|
28
|
+
const getRegistryMeta = async (registry) => {
|
|
29
|
+
try {
|
|
30
|
+
const url = joinURL(registry, BLOCKLET_STORE_META_PATH, `?__t__=${Date.now()}`);
|
|
31
|
+
const { data } = await request.get(url);
|
|
32
|
+
|
|
33
|
+
if (!data) {
|
|
34
|
+
return {};
|
|
35
|
+
}
|
|
36
|
+
|
|
37
|
+
const requiredFields = ['name', 'description', 'maintainer'];
|
|
38
|
+
|
|
39
|
+
const missingFields = requiredFields.filter((x) => !data[x]);
|
|
40
|
+
if (missingFields.length > 0) {
|
|
41
|
+
throw new Error(`the registry missing required information: ${missingFields.join(', ')}`);
|
|
42
|
+
}
|
|
43
|
+
|
|
44
|
+
const result = pick(data, ['id', 'name', 'description', 'maintainer', 'cdnUrl', 'chainHost']);
|
|
45
|
+
const { logoUrl } = data;
|
|
46
|
+
if (logoUrl) {
|
|
47
|
+
if (logoUrl.startsWith('http') === true) {
|
|
48
|
+
result.logoUrl = logoUrl;
|
|
49
|
+
} else if (isBase64(logoUrl, { allowMime: true })) {
|
|
50
|
+
result.logoUrl = logoUrl;
|
|
51
|
+
} else {
|
|
52
|
+
result.logoUrl = joinURL(registry, logoUrl);
|
|
53
|
+
}
|
|
54
|
+
}
|
|
55
|
+
|
|
56
|
+
return result;
|
|
57
|
+
} catch (err) {
|
|
58
|
+
throw new Error(`Can not get meta info for registry [${registry}]: ${err.message}`);
|
|
59
|
+
}
|
|
60
|
+
};
|
|
61
|
+
|
|
62
|
+
const parseSourceUrl = async (url) => {
|
|
63
|
+
const { origin, pathname } = new URL(url);
|
|
64
|
+
|
|
65
|
+
const match = pathname.match(/^\/api\/blocklets\/(\w*)\/blocklet\.json/);
|
|
66
|
+
if (match) {
|
|
67
|
+
try {
|
|
68
|
+
const m = await getRegistryMeta(origin);
|
|
69
|
+
if (m && m.id) {
|
|
70
|
+
return {
|
|
71
|
+
inStore: true,
|
|
72
|
+
registryUrl: origin,
|
|
73
|
+
blockletDid: match[1],
|
|
74
|
+
};
|
|
75
|
+
}
|
|
76
|
+
} catch {
|
|
77
|
+
// meat is not in store, do nothing
|
|
78
|
+
}
|
|
79
|
+
}
|
|
80
|
+
|
|
81
|
+
return {
|
|
82
|
+
inStore: false,
|
|
83
|
+
};
|
|
84
|
+
};
|
|
85
|
+
|
|
86
|
+
module.exports = {
|
|
87
|
+
validateRegistryURL,
|
|
88
|
+
getRegistryMeta,
|
|
89
|
+
parseSourceUrl,
|
|
90
|
+
};
|
package/lib/util/service.js
CHANGED
|
@@ -1,30 +1,15 @@
|
|
|
1
1
|
const fs = require('fs-extra');
|
|
2
|
-
const { NODE_SERVICES } = require('@abtnode/constant');
|
|
3
|
-
|
|
4
|
-
const servicesNames = Object.values(NODE_SERVICES);
|
|
5
2
|
|
|
6
3
|
const getServices = ({ stringifySchema = false } = {}) =>
|
|
7
|
-
|
|
4
|
+
['auth']
|
|
8
5
|
.map((x) => {
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
// Read service meta
|
|
12
|
-
try {
|
|
13
|
-
const packageFile = require.resolve(`${x}/package.json`);
|
|
14
|
-
const { name, description, version } = fs.readJSONSync(packageFile);
|
|
15
|
-
service.name = name;
|
|
16
|
-
service.description = description || name;
|
|
17
|
-
service.version = version;
|
|
18
|
-
} catch (err) {
|
|
19
|
-
return null;
|
|
20
|
-
}
|
|
6
|
+
let service;
|
|
21
7
|
|
|
22
|
-
// Read service config: optional
|
|
23
8
|
try {
|
|
24
|
-
const
|
|
25
|
-
service
|
|
9
|
+
const metaFile = require.resolve(`@abtnode/blocklet-services/services/${x}/meta.json`);
|
|
10
|
+
service = fs.readJSONSync(metaFile);
|
|
26
11
|
} catch (err) {
|
|
27
|
-
service
|
|
12
|
+
service = {};
|
|
28
13
|
}
|
|
29
14
|
|
|
30
15
|
if (stringifySchema) {
|
|
@@ -0,0 +1,79 @@
|
|
|
1
|
+
const EventEmitter = require('events');
|
|
2
|
+
const driveList = require('drivelist');
|
|
3
|
+
const si = require('systeminformation');
|
|
4
|
+
const checkDiskSpace = require('check-disk-space').default;
|
|
5
|
+
|
|
6
|
+
const getSysInfo = async () => {
|
|
7
|
+
const [info, drives] = await Promise.all([
|
|
8
|
+
si.get({
|
|
9
|
+
cpu: 'physicalCores',
|
|
10
|
+
mem: '*',
|
|
11
|
+
currentLoad: '*',
|
|
12
|
+
osInfo: 'platform',
|
|
13
|
+
}),
|
|
14
|
+
driveList.list(),
|
|
15
|
+
]);
|
|
16
|
+
|
|
17
|
+
return {
|
|
18
|
+
cpu: {
|
|
19
|
+
...info.currentLoad,
|
|
20
|
+
...info.cpu,
|
|
21
|
+
},
|
|
22
|
+
mem: info.mem,
|
|
23
|
+
os: info.osInfo,
|
|
24
|
+
disks: await Promise.all(
|
|
25
|
+
drives
|
|
26
|
+
.filter((x) => x.isSystem && x.isVirtual === false && x.mountpoints.length)
|
|
27
|
+
.map(async (x) => {
|
|
28
|
+
const result = await checkDiskSpace(x.mountpoints[0].path);
|
|
29
|
+
return {
|
|
30
|
+
device: x.device,
|
|
31
|
+
mountPoint: result.diskPath,
|
|
32
|
+
total: result.size,
|
|
33
|
+
used: result.size - result.free,
|
|
34
|
+
free: result.free,
|
|
35
|
+
};
|
|
36
|
+
})
|
|
37
|
+
),
|
|
38
|
+
};
|
|
39
|
+
};
|
|
40
|
+
|
|
41
|
+
class SysInfoEmitter extends EventEmitter {
|
|
42
|
+
constructor(interval = 3000) {
|
|
43
|
+
super();
|
|
44
|
+
this.timer = null;
|
|
45
|
+
this.polling = false;
|
|
46
|
+
this.interval = interval;
|
|
47
|
+
}
|
|
48
|
+
|
|
49
|
+
startPolling() {
|
|
50
|
+
if (this.polling) {
|
|
51
|
+
return;
|
|
52
|
+
}
|
|
53
|
+
|
|
54
|
+
if (this.timer) {
|
|
55
|
+
clearInterval(this.timer);
|
|
56
|
+
this.timer = null;
|
|
57
|
+
}
|
|
58
|
+
|
|
59
|
+
this.polling = true;
|
|
60
|
+
this.timer = setInterval(() => {
|
|
61
|
+
getSysInfo().then((info) => {
|
|
62
|
+
if (info) {
|
|
63
|
+
this.emit('info', info);
|
|
64
|
+
}
|
|
65
|
+
});
|
|
66
|
+
}, this.interval);
|
|
67
|
+
}
|
|
68
|
+
|
|
69
|
+
stopPolling() {
|
|
70
|
+
if (this.timer) {
|
|
71
|
+
clearInterval(this.timer);
|
|
72
|
+
this.timer = null;
|
|
73
|
+
this.polling = false;
|
|
74
|
+
}
|
|
75
|
+
}
|
|
76
|
+
}
|
|
77
|
+
|
|
78
|
+
module.exports.getSysInfo = getSysInfo;
|
|
79
|
+
module.exports.SysInfoEmitter = SysInfoEmitter;
|
package/lib/validators/router.js
CHANGED
|
@@ -39,6 +39,7 @@ const ruleSchema = {
|
|
|
39
39
|
ROUTING_RULE_TYPES.BLOCKLET,
|
|
40
40
|
ROUTING_RULE_TYPES.REDIRECT,
|
|
41
41
|
ROUTING_RULE_TYPES.GENERAL_PROXY,
|
|
42
|
+
ROUTING_RULE_TYPES.DIRECT_RESPONSE,
|
|
42
43
|
ROUTING_RULE_TYPES.NONE
|
|
43
44
|
)
|
|
44
45
|
.required(),
|
|
@@ -54,6 +55,12 @@ const ruleSchema = {
|
|
|
54
55
|
.label('interface name')
|
|
55
56
|
.when('type', { is: ROUTING_RULE_TYPES.BLOCKLET, then: Joi.required() }),
|
|
56
57
|
realInterfaceName: Joi.string().label('real interface name'), // child blocklet interface
|
|
58
|
+
response: Joi.object({ status: Joi.number().required(), contentType: Joi.string(), body: Joi.string().required() })
|
|
59
|
+
.label('response')
|
|
60
|
+
.when('type', {
|
|
61
|
+
is: ROUTING_RULE_TYPES.DIRECT_RESPONSE,
|
|
62
|
+
then: Joi.required(),
|
|
63
|
+
}),
|
|
57
64
|
},
|
|
58
65
|
|
|
59
66
|
// List of services that manipulate the request before the upstream blocklet
|
package/lib/webhook/index.js
CHANGED
|
@@ -64,7 +64,7 @@ module.exports = ({ events, dataDirs, instance }) => {
|
|
|
64
64
|
const webhookList = await webhookState.list();
|
|
65
65
|
const nodeInfo = await nodeState.read();
|
|
66
66
|
const { internal, external } = await IP.get();
|
|
67
|
-
const baseUrls = await getBaseUrls(instance, [
|
|
67
|
+
const baseUrls = await getBaseUrls(instance, [external, internal]);
|
|
68
68
|
const senderFns = {};
|
|
69
69
|
|
|
70
70
|
if (webhookList.length) {
|
package/package.json
CHANGED
|
@@ -3,7 +3,7 @@
|
|
|
3
3
|
"publishConfig": {
|
|
4
4
|
"access": "public"
|
|
5
5
|
},
|
|
6
|
-
"version": "1.6.
|
|
6
|
+
"version": "1.6.25",
|
|
7
7
|
"description": "",
|
|
8
8
|
"main": "lib/index.js",
|
|
9
9
|
"files": [
|
|
@@ -19,34 +19,36 @@
|
|
|
19
19
|
"author": "wangshijun <wangshijun2010@gmail.com> (http://github.com/wangshijun)",
|
|
20
20
|
"license": "MIT",
|
|
21
21
|
"dependencies": {
|
|
22
|
-
"@abtnode/certificate-manager": "1.6.
|
|
23
|
-
"@abtnode/constant": "1.6.
|
|
24
|
-
"@abtnode/cron": "1.6.
|
|
25
|
-
"@abtnode/db": "1.6.
|
|
26
|
-
"@abtnode/logger": "1.6.
|
|
27
|
-
"@abtnode/queue": "1.6.
|
|
28
|
-
"@abtnode/rbac": "1.6.
|
|
29
|
-
"@abtnode/router-provider": "1.6.
|
|
30
|
-
"@abtnode/static-server": "1.6.
|
|
31
|
-
"@abtnode/timemachine": "1.6.
|
|
32
|
-
"@abtnode/util": "1.6.
|
|
33
|
-
"@arcblock/did": "^1.14.
|
|
34
|
-
"@arcblock/event-hub": "1.14.
|
|
22
|
+
"@abtnode/certificate-manager": "1.6.25",
|
|
23
|
+
"@abtnode/constant": "1.6.25",
|
|
24
|
+
"@abtnode/cron": "1.6.25",
|
|
25
|
+
"@abtnode/db": "1.6.25",
|
|
26
|
+
"@abtnode/logger": "1.6.25",
|
|
27
|
+
"@abtnode/queue": "1.6.25",
|
|
28
|
+
"@abtnode/rbac": "1.6.25",
|
|
29
|
+
"@abtnode/router-provider": "1.6.25",
|
|
30
|
+
"@abtnode/static-server": "1.6.25",
|
|
31
|
+
"@abtnode/timemachine": "1.6.25",
|
|
32
|
+
"@abtnode/util": "1.6.25",
|
|
33
|
+
"@arcblock/did": "^1.14.19",
|
|
34
|
+
"@arcblock/event-hub": "1.14.19",
|
|
35
35
|
"@arcblock/pm2-events": "^0.0.5",
|
|
36
|
-
"@arcblock/vc": "^1.14.
|
|
37
|
-
"@blocklet/meta": "1.6.
|
|
36
|
+
"@arcblock/vc": "^1.14.19",
|
|
37
|
+
"@blocklet/meta": "1.6.25",
|
|
38
38
|
"@fidm/x509": "^1.2.1",
|
|
39
39
|
"@nedb/core": "^1.2.2",
|
|
40
40
|
"@nedb/multi": "^1.2.2",
|
|
41
|
-
"@ocap/mcrypto": "^1.14.
|
|
42
|
-
"@ocap/util": "^1.14.
|
|
43
|
-
"@ocap/wallet": "^1.14.
|
|
41
|
+
"@ocap/mcrypto": "^1.14.19",
|
|
42
|
+
"@ocap/util": "^1.14.19",
|
|
43
|
+
"@ocap/wallet": "^1.14.19",
|
|
44
44
|
"@slack/webhook": "^5.0.3",
|
|
45
45
|
"axios": "^0.25.0",
|
|
46
46
|
"axon": "^2.0.3",
|
|
47
47
|
"chalk": "^4.0.0",
|
|
48
|
+
"check-disk-space": "^3.2.0",
|
|
48
49
|
"deep-diff": "^1.0.2",
|
|
49
50
|
"detect-port": "^1.3.0",
|
|
51
|
+
"drivelist": "^9.2.4",
|
|
50
52
|
"flat": "^5.0.2",
|
|
51
53
|
"fs-extra": "^10.0.0",
|
|
52
54
|
"get-port": "^5.1.1",
|
|
@@ -64,6 +66,7 @@
|
|
|
64
66
|
"ssri": "^8.0.0",
|
|
65
67
|
"stream-throttle": "^0.1.3",
|
|
66
68
|
"stream-to-promise": "^3.0.0",
|
|
69
|
+
"systeminformation": "^5.11.5",
|
|
67
70
|
"tar": "^6.1.0",
|
|
68
71
|
"unzipper": "^0.10.11",
|
|
69
72
|
"url-join": "^4.0.1",
|
|
@@ -75,5 +78,5 @@
|
|
|
75
78
|
"express": "^4.17.1",
|
|
76
79
|
"jest": "^27.4.5"
|
|
77
80
|
},
|
|
78
|
-
"gitHead": "
|
|
81
|
+
"gitHead": "bd2ad7d90fbd1b3786702dfca1ab28dcec9a7bc7"
|
|
79
82
|
}
|