@abtnode/core 1.6.21 → 1.6.24
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/migrations/1.6.21-rename-ip-echo-domain.js +17 -9
- package/lib/migrations/index.js +6 -2
- package/lib/router/helper.js +69 -59
- package/lib/router/index.js +12 -7
- 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-accessible-external-node-ip.js +2 -2
- 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 +24 -25
- 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 });
|
|
@@ -2,13 +2,18 @@ const yaml = require('js-yaml');
|
|
|
2
2
|
const fs = require('fs');
|
|
3
3
|
const set = require('lodash/set');
|
|
4
4
|
const omit = require('lodash/omit');
|
|
5
|
-
const {
|
|
5
|
+
const {
|
|
6
|
+
DEFAULT_WILDCARD_CERT_HOST,
|
|
7
|
+
DEFAULT_DID_DOMAIN,
|
|
8
|
+
DEFAULT_DID_REGISTRY,
|
|
9
|
+
DEFAULT_IP_DOMAIN,
|
|
10
|
+
} = require('@abtnode/constant');
|
|
6
11
|
|
|
7
12
|
module.exports = async ({ states, printInfo, configFile }) => {
|
|
8
13
|
printInfo('Try to rename dashboardDomain to ipWildcardDomain in db...');
|
|
9
14
|
|
|
10
15
|
let info = await states.node.read();
|
|
11
|
-
set(info, 'routing.ipWildcardDomain', info.routing.dashboardDomain);
|
|
16
|
+
set(info, 'routing.ipWildcardDomain', info.routing.dashboardDomain || DEFAULT_IP_DOMAIN);
|
|
12
17
|
set(info, 'routing.wildcardCertHost', DEFAULT_WILDCARD_CERT_HOST);
|
|
13
18
|
set(info, 'didDomain', DEFAULT_DID_DOMAIN);
|
|
14
19
|
set(info, 'didRegistry', DEFAULT_DID_REGISTRY);
|
|
@@ -16,12 +21,15 @@ module.exports = async ({ states, printInfo, configFile }) => {
|
|
|
16
21
|
|
|
17
22
|
await states.node.updateNodeInfo(info);
|
|
18
23
|
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
24
|
+
if (process.env.NODE_ENV !== 'development') {
|
|
25
|
+
let rawConfig = yaml.safeLoad(fs.readFileSync(configFile).toString());
|
|
26
|
+
set(rawConfig, 'node.routing.ipWildcardDomain', info.routing.ipWildcardDomain);
|
|
27
|
+
set(rawConfig, 'node.routing.wildcardCertHost', DEFAULT_WILDCARD_CERT_HOST);
|
|
28
|
+
set(rawConfig, 'node.didDomain', DEFAULT_DID_DOMAIN);
|
|
29
|
+
set(rawConfig, 'node.didRegistry', DEFAULT_DID_REGISTRY);
|
|
30
|
+
rawConfig = omit(rawConfig, 'node.routing.dashboardDomain');
|
|
31
|
+
fs.writeFileSync(configFile, yaml.dump(rawConfig));
|
|
32
|
+
}
|
|
33
|
+
|
|
26
34
|
printInfo(`> Persist new config to file: ${configFile}`);
|
|
27
35
|
};
|
package/lib/migrations/index.js
CHANGED
|
@@ -132,9 +132,13 @@ const runMigrationScripts = async ({
|
|
|
132
132
|
for (let i = 0; i < scripts.length; i++) {
|
|
133
133
|
const { script, version } = scripts[i];
|
|
134
134
|
try {
|
|
135
|
-
|
|
136
|
-
if (executed === false) {
|
|
135
|
+
if (process.env.NODE_ENV === 'development') {
|
|
137
136
|
pending.push(scripts[i]);
|
|
137
|
+
} else {
|
|
138
|
+
const executed = await node.isMigrationExecuted({ script, version });
|
|
139
|
+
if (executed === false) {
|
|
140
|
+
pending.push(scripts[i]);
|
|
141
|
+
}
|
|
138
142
|
}
|
|
139
143
|
} catch (err) {
|
|
140
144
|
printError(`Failed to detect migration script execution status: ${script}, error: ${err.message}`);
|
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,
|
|
@@ -223,6 +223,19 @@ const ensureServiceRule = async (sites) => {
|
|
|
223
223
|
return site;
|
|
224
224
|
});
|
|
225
225
|
};
|
|
226
|
+
const ensureRootRule = async (sites) => {
|
|
227
|
+
return sites.map((site) => {
|
|
228
|
+
if (!isBasicSite(site.domain) && !site.rules.some((x) => x.from.pathPrefix === '/')) {
|
|
229
|
+
site.rules.push({
|
|
230
|
+
from: { pathPrefix: '/' },
|
|
231
|
+
to: {
|
|
232
|
+
type: ROUTING_RULE_TYPES.NONE,
|
|
233
|
+
},
|
|
234
|
+
});
|
|
235
|
+
}
|
|
236
|
+
return site;
|
|
237
|
+
});
|
|
238
|
+
};
|
|
226
239
|
|
|
227
240
|
const ensureLatestNodeInfo = async (sites = [], { withDefaultCors = true } = {}) => {
|
|
228
241
|
const info = await states.node.read();
|
|
@@ -436,7 +449,7 @@ module.exports = function getRouterHelpers({ dataDirs, routingSnapshot, routerMa
|
|
|
436
449
|
const hasRuleByPrefix = (site, value) => site.rules.find((x) => x.isProtected && get(x, 'from.pathPrefix') === value);
|
|
437
450
|
|
|
438
451
|
const downloadCert = async ({ domain, url }) => {
|
|
439
|
-
const destFolder =
|
|
452
|
+
const destFolder = getTmpDir(path.join(`certificate-${Date.now()}`));
|
|
440
453
|
try {
|
|
441
454
|
const filename = path.join(destFolder, 'certificate.tar.gz');
|
|
442
455
|
fs.ensureDirSync(destFolder);
|
|
@@ -498,11 +511,6 @@ module.exports = function getRouterHelpers({ dataDirs, routingSnapshot, routerMa
|
|
|
498
511
|
|
|
499
512
|
const updateDashboardCertificates = async () => {
|
|
500
513
|
const info = await nodeState.read();
|
|
501
|
-
const provider = getProviderFromNodeInfo(info);
|
|
502
|
-
if (provider === ROUTER_PROVIDER_NONE) {
|
|
503
|
-
return;
|
|
504
|
-
}
|
|
505
|
-
|
|
506
514
|
const https = get(info, 'routing.https', true);
|
|
507
515
|
const ipWildcardDomain = get(info, 'routing.ipWildcardDomain', '');
|
|
508
516
|
const didDomain = info.didDomain;
|
|
@@ -584,6 +592,20 @@ module.exports = function getRouterHelpers({ dataDirs, routingSnapshot, routerMa
|
|
|
584
592
|
to: proxyTarget,
|
|
585
593
|
};
|
|
586
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
|
+
|
|
587
609
|
if (site) {
|
|
588
610
|
const didResolverRuleUpdateRes = await upsertSiteRule(
|
|
589
611
|
{
|
|
@@ -601,7 +623,15 @@ module.exports = function getRouterHelpers({ dataDirs, routingSnapshot, routerMa
|
|
|
601
623
|
context
|
|
602
624
|
);
|
|
603
625
|
|
|
604
|
-
|
|
626
|
+
const pingRuleRes = await upsertSiteRule(
|
|
627
|
+
{
|
|
628
|
+
site,
|
|
629
|
+
rule: pingWellknownRule,
|
|
630
|
+
},
|
|
631
|
+
context
|
|
632
|
+
);
|
|
633
|
+
|
|
634
|
+
return didResolverRuleUpdateRes || acmeRuleUpdateRes || pingRuleRes;
|
|
605
635
|
}
|
|
606
636
|
|
|
607
637
|
await routerManager.addRoutingSite(
|
|
@@ -610,7 +640,7 @@ module.exports = function getRouterHelpers({ dataDirs, routingSnapshot, routerMa
|
|
|
610
640
|
domain: DOMAIN_FOR_INTERNAL_SITE,
|
|
611
641
|
port: await getWellknownSitePort(),
|
|
612
642
|
name: NAME_FOR_WELLKNOWN_SITE,
|
|
613
|
-
rules: [didResolverWellknownRule, acmeChallengeWellknownRule],
|
|
643
|
+
rules: [didResolverWellknownRule, acmeChallengeWellknownRule, pingWellknownRule],
|
|
614
644
|
isProtected: true,
|
|
615
645
|
},
|
|
616
646
|
skipCheckDynamicBlacklist: true,
|
|
@@ -634,12 +664,6 @@ module.exports = function getRouterHelpers({ dataDirs, routingSnapshot, routerMa
|
|
|
634
664
|
*/
|
|
635
665
|
const ensureDashboardRouting = async (context = {}) => {
|
|
636
666
|
const info = await nodeState.read();
|
|
637
|
-
|
|
638
|
-
const provider = getProviderFromNodeInfo(info);
|
|
639
|
-
if (provider === ROUTER_PROVIDER_NONE) {
|
|
640
|
-
return false;
|
|
641
|
-
}
|
|
642
|
-
|
|
643
667
|
const sites = await siteState.getSites();
|
|
644
668
|
let dashboardSite = (sites || []).find((x) => x.domain === DOMAIN_FOR_IP_SITE);
|
|
645
669
|
const updatedResult = [];
|
|
@@ -880,6 +904,7 @@ module.exports = function getRouterHelpers({ dataDirs, routingSnapshot, routerMa
|
|
|
880
904
|
* Add system routing rules for blocklet in dashboard site
|
|
881
905
|
*
|
|
882
906
|
* @returns {boolean} if routing changed
|
|
907
|
+
* TODO: do we still need this?
|
|
883
908
|
*/
|
|
884
909
|
const _ensureBlockletRulesForDashboardSite = async (blocklet, sites, nodeInfo, context = {}) => {
|
|
885
910
|
// blocklet level duplication detection
|
|
@@ -980,12 +1005,6 @@ module.exports = function getRouterHelpers({ dataDirs, routingSnapshot, routerMa
|
|
|
980
1005
|
*/
|
|
981
1006
|
const ensureBlockletRouting = async (blocklet, context = {}) => {
|
|
982
1007
|
const nodeInfo = await nodeState.read();
|
|
983
|
-
|
|
984
|
-
const provider = getProviderFromNodeInfo(nodeInfo);
|
|
985
|
-
if (provider === ROUTER_PROVIDER_NONE) {
|
|
986
|
-
return false;
|
|
987
|
-
}
|
|
988
|
-
|
|
989
1008
|
const hasWebInterface = (blocklet.meta.interfaces || []).some((x) => x.type === BLOCKLET_INTERFACE_TYPE_WEB);
|
|
990
1009
|
if (!hasWebInterface) {
|
|
991
1010
|
return false;
|
|
@@ -1085,12 +1104,6 @@ module.exports = function getRouterHelpers({ dataDirs, routingSnapshot, routerMa
|
|
|
1085
1104
|
* @returns {boolean} if routing changed
|
|
1086
1105
|
*/
|
|
1087
1106
|
const ensureBlockletRoutingForUpgrade = async (blocklet, context = {}) => {
|
|
1088
|
-
const nodeInfo = await nodeState.read();
|
|
1089
|
-
const provider = getProviderFromNodeInfo(nodeInfo);
|
|
1090
|
-
if (provider === ROUTER_PROVIDER_NONE) {
|
|
1091
|
-
return false;
|
|
1092
|
-
}
|
|
1093
|
-
|
|
1094
1107
|
await routerManager.deleteRoutingRulesItemByDid(
|
|
1095
1108
|
{ did: blocklet.meta.did, ruleFilter: (x) => x.isProtected },
|
|
1096
1109
|
context
|
|
@@ -1145,14 +1158,11 @@ module.exports = function getRouterHelpers({ dataDirs, routingSnapshot, routerMa
|
|
|
1145
1158
|
return rules.filter((rule) => rule.to.did === did);
|
|
1146
1159
|
}
|
|
1147
1160
|
|
|
1148
|
-
const
|
|
1161
|
+
const providers = {}; // we need to keep reference for different router instances
|
|
1149
1162
|
const handleRouting = async (nodeInfo) => {
|
|
1150
1163
|
const providerName = get(nodeInfo, 'routing.provider', null);
|
|
1151
1164
|
const httpsEnabled = get(nodeInfo, 'routing.https', true);
|
|
1152
1165
|
logger.debug('handle routing', { providerName, httpsEnabled });
|
|
1153
|
-
if (providerName === ROUTER_PROVIDER_NONE) {
|
|
1154
|
-
return;
|
|
1155
|
-
}
|
|
1156
1166
|
|
|
1157
1167
|
const Provider = getProvider(providerName);
|
|
1158
1168
|
const checkResult = await Provider.check({ configDir: dataDirs.router });
|
|
@@ -1160,12 +1170,12 @@ module.exports = function getRouterHelpers({ dataDirs, routingSnapshot, routerMa
|
|
|
1160
1170
|
throw new Error(`${providerName} pre-check failed, ${checkResult.error}`);
|
|
1161
1171
|
}
|
|
1162
1172
|
|
|
1163
|
-
if (
|
|
1164
|
-
await
|
|
1173
|
+
if (providers[providerName]) {
|
|
1174
|
+
await providers[providerName].reload();
|
|
1165
1175
|
} else {
|
|
1166
|
-
|
|
1176
|
+
providers[providerName] = new Router({
|
|
1167
1177
|
provider: new Provider({
|
|
1168
|
-
|
|
1178
|
+
configDir: path.join(dataDirs.router, providerName),
|
|
1169
1179
|
httpPort: nodeInfo.routing.httpPort || DEFAULT_HTTP_PORT,
|
|
1170
1180
|
httpsPort: nodeInfo.routing.httpsPort || DEFAULT_HTTPS_PORT,
|
|
1171
1181
|
cacheDisabled: nodeInfo.mode === NODE_MODES.DEBUG,
|
|
@@ -1178,6 +1188,7 @@ module.exports = function getRouterHelpers({ dataDirs, routingSnapshot, routerMa
|
|
|
1178
1188
|
sites = await ensureLatestInfo(sites);
|
|
1179
1189
|
sites = await ensureAuthService(sites, blockletManager);
|
|
1180
1190
|
sites = await ensureServiceRule(sites);
|
|
1191
|
+
sites = await ensureRootRule(sites);
|
|
1181
1192
|
|
|
1182
1193
|
const certificates = httpsEnabled ? await certManager.getAllNormal() : [];
|
|
1183
1194
|
|
|
@@ -1202,11 +1213,11 @@ module.exports = function getRouterHelpers({ dataDirs, routingSnapshot, routerMa
|
|
|
1202
1213
|
},
|
|
1203
1214
|
});
|
|
1204
1215
|
|
|
1205
|
-
certManager.on('cert.added', () =>
|
|
1206
|
-
certManager.on('cert.removed', () =>
|
|
1207
|
-
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());
|
|
1208
1219
|
|
|
1209
|
-
await
|
|
1220
|
+
await providers[providerName].start();
|
|
1210
1221
|
}
|
|
1211
1222
|
};
|
|
1212
1223
|
|
|
@@ -1214,8 +1225,8 @@ module.exports = function getRouterHelpers({ dataDirs, routingSnapshot, routerMa
|
|
|
1214
1225
|
const info = await nodeState.read();
|
|
1215
1226
|
const providerName = get(info, 'routing.provider', null);
|
|
1216
1227
|
|
|
1217
|
-
if (providerName &&
|
|
1218
|
-
await
|
|
1228
|
+
if (providerName && providers[providerName] && typeof providers[providerName].rotateLogs === 'function') {
|
|
1229
|
+
await providers[providerName].rotateLogs();
|
|
1219
1230
|
}
|
|
1220
1231
|
};
|
|
1221
1232
|
|
|
@@ -1244,30 +1255,28 @@ module.exports = function getRouterHelpers({ dataDirs, routingSnapshot, routerMa
|
|
|
1244
1255
|
await handleRouting(result);
|
|
1245
1256
|
|
|
1246
1257
|
if (newProvider !== info.routing.provider) {
|
|
1247
|
-
|
|
1248
|
-
|
|
1249
|
-
|
|
1250
|
-
|
|
1251
|
-
|
|
1252
|
-
|
|
1253
|
-
const
|
|
1254
|
-
|
|
1255
|
-
|
|
1256
|
-
|
|
1257
|
-
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)));
|
|
1258
1268
|
|
|
1259
|
-
|
|
1260
|
-
|
|
1261
|
-
|
|
1262
|
-
|
|
1263
|
-
}
|
|
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 });
|
|
1264
1273
|
}
|
|
1265
1274
|
|
|
1266
1275
|
const Provider = getProvider(info.routing.provider);
|
|
1267
1276
|
if (Provider) {
|
|
1268
1277
|
try {
|
|
1269
1278
|
const providerInstance = new Provider({
|
|
1270
|
-
|
|
1279
|
+
configDir: path.join(dataDirs.router, info.routing.provider),
|
|
1271
1280
|
httpPort: info.routing.httpPort || DEFAULT_HTTP_PORT,
|
|
1272
1281
|
httpsPort: info.routing.httpsPort || DEFAULT_HTTPS_PORT,
|
|
1273
1282
|
cacheDisabled: info.mode === NODE_MODES.DEBUG,
|
|
@@ -1410,6 +1419,7 @@ module.exports = function getRouterHelpers({ dataDirs, routingSnapshot, routerMa
|
|
|
1410
1419
|
ensureWildcardCerts,
|
|
1411
1420
|
addWellknownSite,
|
|
1412
1421
|
upsertSiteRule,
|
|
1422
|
+
getRouterProvider: (name) => providers[name],
|
|
1413
1423
|
|
|
1414
1424
|
getRoutingCrons: () => [
|
|
1415
1425
|
{
|
package/lib/router/index.js
CHANGED
|
@@ -5,7 +5,7 @@ const {
|
|
|
5
5
|
DOMAIN_FOR_DEFAULT_SITE,
|
|
6
6
|
DOMAIN_FOR_IP_SITE_REGEXP,
|
|
7
7
|
ROUTING_RULE_TYPES,
|
|
8
|
-
|
|
8
|
+
DEFAULT_IP_DOMAIN,
|
|
9
9
|
BLOCKLET_PROXY_PATH_PREFIX,
|
|
10
10
|
BLOCKLET_SITE_GROUP_SUFFIX,
|
|
11
11
|
} = require('@abtnode/constant');
|
|
@@ -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 = []) => {
|
|
@@ -219,7 +224,7 @@ Router.formatSites = (sites = []) => {
|
|
|
219
224
|
|
|
220
225
|
Router.flattenSitesToRules = (sites = [], info = {}) => {
|
|
221
226
|
const result = [];
|
|
222
|
-
const ipWildcardDomain = get(info, 'routing.ipWildcardDomain',
|
|
227
|
+
const ipWildcardDomain = get(info, 'routing.ipWildcardDomain', DEFAULT_IP_DOMAIN);
|
|
223
228
|
sites.forEach((site) => {
|
|
224
229
|
const aliases = (site.domainAliases || [])
|
|
225
230
|
.map((x) => (typeof x === 'string' ? x : x.value))
|
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,9 +1,9 @@
|
|
|
1
1
|
const joinUrl = require('url-join');
|
|
2
2
|
const axios = require('@abtnode/util/lib/axios');
|
|
3
|
-
const {
|
|
3
|
+
const { DEFAULT_IP_DOMAIN, DEFAULT_ADMIN_PATH } = require('@abtnode/constant');
|
|
4
4
|
const { get: getIp } = require('./ip');
|
|
5
5
|
|
|
6
|
-
const getNodeDomain = (ip) => (ip ?
|
|
6
|
+
const getNodeDomain = (ip) => (ip ? DEFAULT_IP_DOMAIN.replace(/^\*/, ip.replace(/\./g, '-')) : '');
|
|
7
7
|
|
|
8
8
|
let cache = null;
|
|
9
9
|
|
|
@@ -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
|
@@ -1,13 +1,13 @@
|
|
|
1
1
|
const logger = require('@abtnode/logger')('@abtnode/core:webhook:index');
|
|
2
|
-
const upperFirst = require('lodash/upperFirst');
|
|
3
2
|
|
|
3
|
+
const sortPriorityUrl = require('@abtnode/util/lib/sort-priority-url');
|
|
4
4
|
const WebHookSender = require('./sender');
|
|
5
5
|
const createQueue = require('../queue');
|
|
6
6
|
const IP = require('../util/ip');
|
|
7
7
|
const states = require('../states');
|
|
8
8
|
const { getBaseUrls } = require('../util');
|
|
9
9
|
|
|
10
|
-
const getSlackUrlInfo = (actionPath = '/notifications', urls) => {
|
|
10
|
+
const getSlackUrlInfo = async (actionPath = '/notifications', urls) => {
|
|
11
11
|
const info = [];
|
|
12
12
|
|
|
13
13
|
if (actionPath && actionPath.startsWith('/blocklet/')) {
|
|
@@ -28,29 +28,27 @@ const getSlackUrlInfo = (actionPath = '/notifications', urls) => {
|
|
|
28
28
|
});
|
|
29
29
|
}
|
|
30
30
|
|
|
31
|
-
const
|
|
32
|
-
const
|
|
33
|
-
|
|
34
|
-
const
|
|
35
|
-
const
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
const normalized = `${x.url}${actionPath}`.replace(`${protocol}//`, '').replace(/\/+/g, '/');
|
|
39
|
-
const url = `${protocol}//${normalized}`;
|
|
40
|
-
elements.push({
|
|
41
|
-
type: 'button',
|
|
42
|
-
text: {
|
|
43
|
-
type: 'plain_text',
|
|
44
|
-
text: `${upperFirst(x.type)} Address`,
|
|
45
|
-
},
|
|
46
|
-
style: 'primary',
|
|
47
|
-
value: `${upperFirst(x.type)} Address`,
|
|
48
|
-
url,
|
|
49
|
-
});
|
|
50
|
-
});
|
|
31
|
+
const prioritys = await sortPriorityUrl(urls);
|
|
32
|
+
const priorityUrl = prioritys[0].url;
|
|
33
|
+
|
|
34
|
+
const { protocol } = new URL(priorityUrl);
|
|
35
|
+
const normalized = `${priorityUrl}${actionPath}`.replace(`${protocol}//`, '').replace(/\/+/g, '/');
|
|
36
|
+
const url = `${protocol}//${normalized}`;
|
|
37
|
+
|
|
51
38
|
info.push({
|
|
52
39
|
type: 'actions',
|
|
53
|
-
elements
|
|
40
|
+
elements: [
|
|
41
|
+
{
|
|
42
|
+
type: 'button',
|
|
43
|
+
text: {
|
|
44
|
+
type: 'plain_text',
|
|
45
|
+
text: 'Click Me',
|
|
46
|
+
},
|
|
47
|
+
style: 'primary',
|
|
48
|
+
value: 'Click Me',
|
|
49
|
+
url,
|
|
50
|
+
},
|
|
51
|
+
],
|
|
54
52
|
});
|
|
55
53
|
|
|
56
54
|
return info;
|
|
@@ -66,7 +64,7 @@ module.exports = ({ events, dataDirs, instance }) => {
|
|
|
66
64
|
const webhookList = await webhookState.list();
|
|
67
65
|
const nodeInfo = await nodeState.read();
|
|
68
66
|
const { internal, external } = await IP.get();
|
|
69
|
-
const baseUrls = await getBaseUrls(instance, [
|
|
67
|
+
const baseUrls = await getBaseUrls(instance, [external, internal]);
|
|
70
68
|
const senderFns = {};
|
|
71
69
|
|
|
72
70
|
if (webhookList.length) {
|
|
@@ -79,7 +77,8 @@ module.exports = ({ events, dataDirs, instance }) => {
|
|
|
79
77
|
const { name } = nodeInfo;
|
|
80
78
|
const options = { ...message, nodeInfo: `*${name}*` };
|
|
81
79
|
if (item.type === 'slack') {
|
|
82
|
-
|
|
80
|
+
// eslint-disable-next-line
|
|
81
|
+
options.urlInfo = await getSlackUrlInfo(message.action, baseUrls);
|
|
83
82
|
}
|
|
84
83
|
try {
|
|
85
84
|
// eslint-disable-next-line
|
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.24",
|
|
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.24",
|
|
23
|
+
"@abtnode/constant": "1.6.24",
|
|
24
|
+
"@abtnode/cron": "1.6.24",
|
|
25
|
+
"@abtnode/db": "1.6.24",
|
|
26
|
+
"@abtnode/logger": "1.6.24",
|
|
27
|
+
"@abtnode/queue": "1.6.24",
|
|
28
|
+
"@abtnode/rbac": "1.6.24",
|
|
29
|
+
"@abtnode/router-provider": "1.6.24",
|
|
30
|
+
"@abtnode/static-server": "1.6.24",
|
|
31
|
+
"@abtnode/timemachine": "1.6.24",
|
|
32
|
+
"@abtnode/util": "1.6.24",
|
|
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.24",
|
|
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": "6bd8792a155ebbbefea6ca3d42c5b59b354d9879"
|
|
79
82
|
}
|