@abtnode/core 1.6.17 → 1.6.21
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/api/node.js +1 -1
- package/lib/blocklet/hooks.js +16 -63
- package/lib/blocklet/manager/disk.js +85 -76
- package/lib/blocklet/migration.js +16 -52
- package/lib/event.js +3 -2
- package/lib/index.js +2 -3
- package/lib/migrations/1.6.21-rename-ip-echo-domain.js +27 -0
- package/lib/router/helper.js +80 -59
- package/lib/router/index.js +6 -6
- package/lib/router/manager.js +4 -4
- package/lib/states/blocklet.js +80 -4
- package/lib/states/node.js +4 -3
- package/lib/util/blocklet.js +50 -3
- package/lib/util/get-domain-for-blocklet.js +2 -2
- package/lib/util/index.js +5 -5
- package/lib/util/upgrade.js +8 -4
- package/package.json +22 -22
package/lib/event.js
CHANGED
|
@@ -132,7 +132,7 @@ module.exports = ({
|
|
|
132
132
|
onEvent(name, blocklet);
|
|
133
133
|
};
|
|
134
134
|
|
|
135
|
-
const
|
|
135
|
+
const handleServerEvent = (eventName) => {
|
|
136
136
|
const [, status] = eventName.split('.');
|
|
137
137
|
onEvent(eventName, {
|
|
138
138
|
title: `Blocklet Server ${status}`,
|
|
@@ -209,7 +209,8 @@ module.exports = ({
|
|
|
209
209
|
|
|
210
210
|
events.handleBlockletAdd = handleBlockletAdd;
|
|
211
211
|
events.handleBlockletRemove = handleBlockletRemove;
|
|
212
|
-
events.
|
|
212
|
+
events.handleServerEvent = handleServerEvent;
|
|
213
|
+
events.onEvent = onEvent;
|
|
213
214
|
|
|
214
215
|
return events;
|
|
215
216
|
};
|
package/lib/index.js
CHANGED
|
@@ -147,7 +147,7 @@ function ABTNode(options) {
|
|
|
147
147
|
getCertificates,
|
|
148
148
|
getSitesFromSnapshot,
|
|
149
149
|
getRoutingCrons,
|
|
150
|
-
|
|
150
|
+
ensureWildcardCerts,
|
|
151
151
|
} = getRouterHelpers({ dataDirs, routingSnapshot, routerManager, blockletManager, certManager });
|
|
152
152
|
|
|
153
153
|
const teamManager = new TeamManager({ nodeDid: options.nodeDid, dataDirs, states });
|
|
@@ -208,7 +208,6 @@ function ABTNode(options) {
|
|
|
208
208
|
upgradeBlocklet: blockletManager.upgrade.bind(blockletManager),
|
|
209
209
|
configBlocklet: blockletManager.config.bind(blockletManager),
|
|
210
210
|
devBlocklet: blockletManager.dev.bind(blockletManager),
|
|
211
|
-
getBlockletStatus: blockletManager.getStatus.bind(blockletManager),
|
|
212
211
|
checkChildBlockletsForUpdates: blockletManager.checkChildrenForUpdates.bind(blockletManager),
|
|
213
212
|
updateChildBlocklets: blockletManager.updateChildren.bind(blockletManager),
|
|
214
213
|
getLatestBlockletVersion: blockletManager.getLatestBlockletVersion.bind(blockletManager),
|
|
@@ -319,7 +318,7 @@ function ABTNode(options) {
|
|
|
319
318
|
takeRoutingSnapshot,
|
|
320
319
|
getSitesFromSnapshot,
|
|
321
320
|
ensureDashboardRouting,
|
|
322
|
-
|
|
321
|
+
ensureWildcardCerts,
|
|
323
322
|
|
|
324
323
|
addDomainAlias: routerManager.addDomainAlias.bind(routerManager),
|
|
325
324
|
deleteDomainAlias: routerManager.deleteDomainAlias.bind(routerManager),
|
|
@@ -0,0 +1,27 @@
|
|
|
1
|
+
const yaml = require('js-yaml');
|
|
2
|
+
const fs = require('fs');
|
|
3
|
+
const set = require('lodash/set');
|
|
4
|
+
const omit = require('lodash/omit');
|
|
5
|
+
const { DEFAULT_WILDCARD_CERT_HOST, DEFAULT_DID_DOMAIN, DEFAULT_DID_REGISTRY } = require('@abtnode/constant');
|
|
6
|
+
|
|
7
|
+
module.exports = async ({ states, printInfo, configFile }) => {
|
|
8
|
+
printInfo('Try to rename dashboardDomain to ipWildcardDomain in db...');
|
|
9
|
+
|
|
10
|
+
let info = await states.node.read();
|
|
11
|
+
set(info, 'routing.ipWildcardDomain', info.routing.dashboardDomain);
|
|
12
|
+
set(info, 'routing.wildcardCertHost', DEFAULT_WILDCARD_CERT_HOST);
|
|
13
|
+
set(info, 'didDomain', DEFAULT_DID_DOMAIN);
|
|
14
|
+
set(info, 'didRegistry', DEFAULT_DID_REGISTRY);
|
|
15
|
+
info = omit(info, 'routing.dashboardDomain');
|
|
16
|
+
|
|
17
|
+
await states.node.updateNodeInfo(info);
|
|
18
|
+
|
|
19
|
+
let rawConfig = yaml.safeLoad(fs.readFileSync(configFile).toString());
|
|
20
|
+
set(rawConfig, 'node.routing.ipWildcardDomain', info.routing.ipWildcardDomain);
|
|
21
|
+
set(rawConfig, 'node.routing.wildcardCertHost', DEFAULT_WILDCARD_CERT_HOST);
|
|
22
|
+
set(rawConfig, 'node.didDomain', DEFAULT_DID_DOMAIN);
|
|
23
|
+
set(rawConfig, 'node.didRegistry', DEFAULT_DID_REGISTRY);
|
|
24
|
+
rawConfig = omit(rawConfig, 'node.routing.dashboardDomain');
|
|
25
|
+
fs.writeFileSync(configFile, yaml.dump(rawConfig));
|
|
26
|
+
printInfo(`> Persist new config to file: ${configFile}`);
|
|
27
|
+
};
|
package/lib/router/helper.js
CHANGED
|
@@ -419,6 +419,13 @@ const decompressCertificates = async (source, dest) => {
|
|
|
419
419
|
return dest;
|
|
420
420
|
};
|
|
421
421
|
|
|
422
|
+
const joinCertDownUrl = (baseUrl, name) => joinUrl(baseUrl, '/certs', name);
|
|
423
|
+
|
|
424
|
+
const getIpEchoCertDownloadUrl = (baseUrl) => joinCertDownUrl(baseUrl, 'ip-abtnet-io.tar.gz');
|
|
425
|
+
const getDidDomainCertDownloadUrl = (baseUrl) => joinCertDownUrl(baseUrl, 'did-abtnet-io.tar.gz');
|
|
426
|
+
const getDownloadCertBaseUrl = (info) =>
|
|
427
|
+
process.env.ABT_NODE_WILDCARD_CERT_HOST || get(info, 'routing.wildcardCertHost', '');
|
|
428
|
+
|
|
422
429
|
module.exports = function getRouterHelpers({ dataDirs, routingSnapshot, routerManager, blockletManager, certManager }) {
|
|
423
430
|
const nodeState = states.node;
|
|
424
431
|
const blockletState = states.blocklet;
|
|
@@ -428,46 +435,13 @@ module.exports = function getRouterHelpers({ dataDirs, routingSnapshot, routerMa
|
|
|
428
435
|
// site level duplication detection
|
|
429
436
|
const hasRuleByPrefix = (site, value) => site.rules.find((x) => x.isProtected && get(x, 'from.pathPrefix') === value);
|
|
430
437
|
|
|
431
|
-
const
|
|
432
|
-
const info = await nodeState.read();
|
|
433
|
-
const provider = getProviderFromNodeInfo(info);
|
|
434
|
-
if (provider === ROUTER_PROVIDER_NONE) {
|
|
435
|
-
return;
|
|
436
|
-
}
|
|
437
|
-
|
|
438
|
-
const https = get(info, 'routing.https', true);
|
|
439
|
-
const dashboardDomain = get(info, 'routing.dashboardDomain', '');
|
|
440
|
-
const certDownloadAddress =
|
|
441
|
-
process.env.ABT_NODE_DASHBOARD_CERT_DOWN_URL || get(info, 'routing.dashboardCertDownloadAddress', '');
|
|
442
|
-
if (!https || !dashboardDomain || !certDownloadAddress) {
|
|
443
|
-
return;
|
|
444
|
-
}
|
|
445
|
-
|
|
446
|
-
if (checkExpire) {
|
|
447
|
-
try {
|
|
448
|
-
const cert = await routerManager.findCertificateByDomain(dashboardDomain);
|
|
449
|
-
if (!cert) {
|
|
450
|
-
return;
|
|
451
|
-
}
|
|
452
|
-
|
|
453
|
-
const now = Date.now();
|
|
454
|
-
const certInfo = getHttpsCertInfo(cert.certificate);
|
|
455
|
-
if (certInfo.validTo - now >= CERTIFICATE_EXPIRES_OFFSET) {
|
|
456
|
-
logger.info('skip dashboard certificate update before not expired');
|
|
457
|
-
return;
|
|
458
|
-
}
|
|
459
|
-
} catch (err) {
|
|
460
|
-
logger.error('failed to check dashboard certificate expiration', { error: err });
|
|
461
|
-
return;
|
|
462
|
-
}
|
|
463
|
-
}
|
|
464
|
-
|
|
438
|
+
const downloadCert = async ({ domain, url }) => {
|
|
465
439
|
const destFolder = getTmpDirectory(path.join(`certificate-${Date.now()}`));
|
|
466
440
|
try {
|
|
467
441
|
const filename = path.join(destFolder, 'certificate.tar.gz');
|
|
468
442
|
fs.ensureDirSync(destFolder);
|
|
469
443
|
|
|
470
|
-
await downloadFile(
|
|
444
|
+
await downloadFile(url, filename);
|
|
471
445
|
await decompressCertificates(filename, destFolder);
|
|
472
446
|
|
|
473
447
|
const certificateFilePath = path.join(destFolder, 'cert.pem');
|
|
@@ -485,7 +459,7 @@ module.exports = function getRouterHelpers({ dataDirs, routingSnapshot, routerMa
|
|
|
485
459
|
const privateKey = fs.readFileSync(privateKeyFilePath).toString();
|
|
486
460
|
|
|
487
461
|
await certManager.upsertByDomain({
|
|
488
|
-
domain
|
|
462
|
+
domain,
|
|
489
463
|
privateKey,
|
|
490
464
|
certificate,
|
|
491
465
|
isProtected: true,
|
|
@@ -499,23 +473,68 @@ module.exports = function getRouterHelpers({ dataDirs, routingSnapshot, routerMa
|
|
|
499
473
|
}
|
|
500
474
|
};
|
|
501
475
|
|
|
502
|
-
const
|
|
476
|
+
const updateCert = async (domain, url) => {
|
|
477
|
+
try {
|
|
478
|
+
const cert = await routerManager.findCertificateByDomain(domain);
|
|
479
|
+
if (!cert) {
|
|
480
|
+
return;
|
|
481
|
+
}
|
|
482
|
+
|
|
483
|
+
const now = Date.now();
|
|
484
|
+
const certInfo = getHttpsCertInfo(cert.certificate);
|
|
485
|
+
if (certInfo.validTo - now >= CERTIFICATE_EXPIRES_OFFSET) {
|
|
486
|
+
logger.info('skip dashboard certificate update before not expired', { domain, url });
|
|
487
|
+
return;
|
|
488
|
+
}
|
|
489
|
+
|
|
490
|
+
await downloadCert({
|
|
491
|
+
domain,
|
|
492
|
+
url,
|
|
493
|
+
});
|
|
494
|
+
} catch (err) {
|
|
495
|
+
logger.error('failed to check dashboard certificate expiration', { error: err, domain, url });
|
|
496
|
+
}
|
|
497
|
+
};
|
|
498
|
+
|
|
499
|
+
const updateDashboardCertificates = async () => {
|
|
503
500
|
const info = await nodeState.read();
|
|
504
|
-
const
|
|
505
|
-
|
|
506
|
-
|
|
507
|
-
throw new Error('dashboardCertDownloadAddress and dashboardDomain are not found in the routing configs');
|
|
501
|
+
const provider = getProviderFromNodeInfo(info);
|
|
502
|
+
if (provider === ROUTER_PROVIDER_NONE) {
|
|
503
|
+
return;
|
|
508
504
|
}
|
|
509
505
|
|
|
510
|
-
const
|
|
511
|
-
|
|
512
|
-
|
|
506
|
+
const https = get(info, 'routing.https', true);
|
|
507
|
+
const ipWildcardDomain = get(info, 'routing.ipWildcardDomain', '');
|
|
508
|
+
const didDomain = info.didDomain;
|
|
509
|
+
const certDownloadAddress = getDownloadCertBaseUrl(info);
|
|
510
|
+
if (!https || !certDownloadAddress) {
|
|
511
|
+
return;
|
|
513
512
|
}
|
|
514
513
|
|
|
515
|
-
|
|
516
|
-
await
|
|
517
|
-
|
|
518
|
-
|
|
514
|
+
await updateCert(ipWildcardDomain, getIpEchoCertDownloadUrl(certDownloadAddress));
|
|
515
|
+
await updateCert(`*.${didDomain}`, getDidDomainCertDownloadUrl(certDownloadAddress));
|
|
516
|
+
};
|
|
517
|
+
|
|
518
|
+
const ensureWildcardCerts = async () => {
|
|
519
|
+
const info = await nodeState.read();
|
|
520
|
+
const didDomain = info.didDomain;
|
|
521
|
+
const ipWildcardDomain = get(info, 'routing.ipWildcardDomain', '');
|
|
522
|
+
|
|
523
|
+
const ensureDomainCert = async (domain, url) => {
|
|
524
|
+
const cert = await certManager.getByDomain(domain);
|
|
525
|
+
if (!cert) {
|
|
526
|
+
await downloadCert({
|
|
527
|
+
domain,
|
|
528
|
+
url,
|
|
529
|
+
});
|
|
530
|
+
}
|
|
531
|
+
};
|
|
532
|
+
|
|
533
|
+
const certBaseUrl = getDownloadCertBaseUrl(info);
|
|
534
|
+
await Promise.all([
|
|
535
|
+
ensureDomainCert(ipWildcardDomain, getIpEchoCertDownloadUrl(certBaseUrl)),
|
|
536
|
+
ensureDomainCert(`*.${didDomain}`, getDidDomainCertDownloadUrl(certBaseUrl)),
|
|
537
|
+
]);
|
|
519
538
|
};
|
|
520
539
|
|
|
521
540
|
const upsertSiteRule = async ({ site, rule }, context) => {
|
|
@@ -658,9 +677,11 @@ module.exports = function getRouterHelpers({ dataDirs, routingSnapshot, routerMa
|
|
|
658
677
|
return domainAlias === item;
|
|
659
678
|
});
|
|
660
679
|
|
|
661
|
-
const
|
|
680
|
+
const ipWildcardDomain = get(info, 'routing.ipWildcardDomain', '');
|
|
662
681
|
const didDomain = `${info.did.toLowerCase()}.${info.didDomain}`;
|
|
663
|
-
|
|
682
|
+
let dashboardAliasDomains = [ipWildcardDomain, didDomain];
|
|
683
|
+
|
|
684
|
+
dashboardAliasDomains = dashboardAliasDomains
|
|
664
685
|
.filter((item) => item && !isExistsInAlias(item))
|
|
665
686
|
.map((item) => ({ value: item, isProtected: true }));
|
|
666
687
|
|
|
@@ -746,18 +767,18 @@ module.exports = function getRouterHelpers({ dataDirs, routingSnapshot, routerMa
|
|
|
746
767
|
|
|
747
768
|
const existSite = await states.site.findOne({ domain: domainGroup });
|
|
748
769
|
if (!existSite) {
|
|
749
|
-
const
|
|
750
|
-
const appIdEnv = blocklet.environments.find((e) => e.key === 'BLOCKLET_APP_ID');
|
|
751
|
-
const domainAliases = [{ value: ipEchoDnsDomain, isProtected: true }];
|
|
770
|
+
const domainAliases = [];
|
|
752
771
|
|
|
753
772
|
const didDomain = getDidDomainForBlocklet({
|
|
754
|
-
|
|
773
|
+
name: blocklet.meta.name,
|
|
774
|
+
daemonDid: nodeInfo.did,
|
|
755
775
|
didDomain: nodeInfo.didDomain,
|
|
756
776
|
});
|
|
757
777
|
|
|
758
|
-
|
|
759
|
-
|
|
760
|
-
|
|
778
|
+
const ipEchoDnsDomain = getIpDnsDomainForBlocklet(blocklet, webInterface, nodeInfo.did);
|
|
779
|
+
|
|
780
|
+
// let didDomain in front of ipEchoDnsDomain
|
|
781
|
+
domainAliases.push({ value: didDomain, isProtected: true }, { value: ipEchoDnsDomain, isProtected: true });
|
|
761
782
|
|
|
762
783
|
await routerManager.addRoutingSite(
|
|
763
784
|
{
|
|
@@ -1386,7 +1407,7 @@ module.exports = function getRouterHelpers({ dataDirs, routingSnapshot, routerMa
|
|
|
1386
1407
|
getSitesFromSnapshot,
|
|
1387
1408
|
getCertificates,
|
|
1388
1409
|
checkDomain,
|
|
1389
|
-
|
|
1410
|
+
ensureWildcardCerts,
|
|
1390
1411
|
addWellknownSite,
|
|
1391
1412
|
upsertSiteRule,
|
|
1392
1413
|
|
|
@@ -1394,7 +1415,7 @@ module.exports = function getRouterHelpers({ dataDirs, routingSnapshot, routerMa
|
|
|
1394
1415
|
{
|
|
1395
1416
|
name: 'update-dashboard-certificate',
|
|
1396
1417
|
time: '0 1 */6 * * *', // refetch on 0:00, 6:00, etc.
|
|
1397
|
-
fn: () =>
|
|
1418
|
+
fn: () => updateDashboardCertificates(),
|
|
1398
1419
|
options: { runOnInit: true },
|
|
1399
1420
|
},
|
|
1400
1421
|
{
|
package/lib/router/index.js
CHANGED
|
@@ -60,12 +60,12 @@ const getRoutingTable = ({ sites, nodeInfo }) => {
|
|
|
60
60
|
let routingTable = Router.formatSites(sites);
|
|
61
61
|
routingTable = expandSites(routingTable);
|
|
62
62
|
|
|
63
|
-
// put
|
|
63
|
+
// put ipWildcardDomain to last, to let blockletDomain match first
|
|
64
64
|
// e.g.
|
|
65
|
-
//
|
|
65
|
+
// ipWildcardDomain: 192-168-3-2.ip.abtnet.io
|
|
66
66
|
// blockletDomain: static-demo-xxx-192-168-3-2.ip.abtnet.io
|
|
67
|
-
const
|
|
68
|
-
const index = routingTable.findIndex((x) => x.domain ===
|
|
67
|
+
const ipWildcardDomain = get(nodeInfo, 'routing.ipWildcardDomain', '');
|
|
68
|
+
const index = routingTable.findIndex((x) => x.domain === ipWildcardDomain);
|
|
69
69
|
if (index > -1) {
|
|
70
70
|
routingTable.push(...routingTable.splice(index, 1));
|
|
71
71
|
}
|
|
@@ -219,11 +219,11 @@ Router.formatSites = (sites = []) => {
|
|
|
219
219
|
|
|
220
220
|
Router.flattenSitesToRules = (sites = [], info = {}) => {
|
|
221
221
|
const result = [];
|
|
222
|
-
const
|
|
222
|
+
const ipWildcardDomain = get(info, 'routing.ipWildcardDomain', DEFAULT_DASHBOARD_DOMAIN);
|
|
223
223
|
sites.forEach((site) => {
|
|
224
224
|
const aliases = (site.domainAliases || [])
|
|
225
225
|
.map((x) => (typeof x === 'string' ? x : x.value))
|
|
226
|
-
.filter((x) => x !==
|
|
226
|
+
.filter((x) => x !== ipWildcardDomain)
|
|
227
227
|
.filter(Boolean);
|
|
228
228
|
|
|
229
229
|
if (Array.isArray(site.rules) && site.rules.length > 0) {
|
package/lib/router/manager.js
CHANGED
|
@@ -221,10 +221,10 @@ class RouterManager extends EventEmitter {
|
|
|
221
221
|
}
|
|
222
222
|
}
|
|
223
223
|
|
|
224
|
-
|
|
225
|
-
|
|
226
|
-
|
|
227
|
-
);
|
|
224
|
+
// let custom domain in front of protected domain
|
|
225
|
+
const domainAliases = [{ value: domainAlias, isProtected: false }, ...dbSite.domainAliases];
|
|
226
|
+
|
|
227
|
+
const updateResult = await states.site.update({ _id: id }, { $set: { domainAliases } });
|
|
228
228
|
logger.debug('add domain alias update result', { id, updateResult, domainAlias });
|
|
229
229
|
|
|
230
230
|
const newSite = await states.site.findOne({ _id: id });
|
package/lib/states/blocklet.js
CHANGED
|
@@ -20,7 +20,7 @@ const {
|
|
|
20
20
|
const logger = require('@abtnode/logger')('state-blocklet');
|
|
21
21
|
|
|
22
22
|
const BaseState = require('./base');
|
|
23
|
-
const { forEachBlocklet } = require('../util/blocklet');
|
|
23
|
+
const { forEachBlocklet, checkDuplicateComponents } = require('../util/blocklet');
|
|
24
24
|
const { validateBlockletMeta } = require('../util');
|
|
25
25
|
|
|
26
26
|
const lock = new Lock('blocklet-port-assign-lock');
|
|
@@ -80,7 +80,11 @@ class BlockletState extends BaseState {
|
|
|
80
80
|
|
|
81
81
|
getBlocklet(did) {
|
|
82
82
|
return new Promise((resolve, reject) => {
|
|
83
|
-
|
|
83
|
+
if (!did) {
|
|
84
|
+
resolve(null);
|
|
85
|
+
}
|
|
86
|
+
|
|
87
|
+
this.db.findOne({ $or: [{ 'meta.did': did }, { appDid: did }] }, (err, doc) => {
|
|
84
88
|
if (err) {
|
|
85
89
|
return reject(err);
|
|
86
90
|
}
|
|
@@ -160,6 +164,7 @@ class BlockletState extends BaseState {
|
|
|
160
164
|
// add to db
|
|
161
165
|
this.db.insert(
|
|
162
166
|
{
|
|
167
|
+
appDid: null, // will updated later when updating blocklet environments
|
|
163
168
|
mode,
|
|
164
169
|
meta: omit(sanitized, ['htmlAst']),
|
|
165
170
|
status,
|
|
@@ -391,13 +396,20 @@ class BlockletState extends BaseState {
|
|
|
391
396
|
return result;
|
|
392
397
|
}
|
|
393
398
|
|
|
394
|
-
|
|
399
|
+
/**
|
|
400
|
+
* @param {String} did blocklet did
|
|
401
|
+
* @param {BlockletStatus} status blocklet status
|
|
402
|
+
*
|
|
403
|
+
* children status only different with parent before blocklet installation
|
|
404
|
+
* @param {Array<{did}>} children
|
|
405
|
+
*/
|
|
406
|
+
async setBlockletStatus(did, status, { children } = {}) {
|
|
395
407
|
if (typeof status === 'undefined') {
|
|
396
408
|
throw new Error('Unsupported blocklet status');
|
|
397
409
|
}
|
|
398
410
|
|
|
399
411
|
const doc = await this.getBlocklet(did);
|
|
400
|
-
if (doc.status === status) {
|
|
412
|
+
if (doc.status === status && !children) {
|
|
401
413
|
return formatBlocklet(doc, 'onRead', this.options.dek);
|
|
402
414
|
}
|
|
403
415
|
|
|
@@ -412,6 +424,28 @@ class BlockletState extends BaseState {
|
|
|
412
424
|
updates.stoppedAt = new Date();
|
|
413
425
|
}
|
|
414
426
|
|
|
427
|
+
// update children status
|
|
428
|
+
updates.children = doc.children.map((child) => {
|
|
429
|
+
if (children === 'all') {
|
|
430
|
+
child.status = status;
|
|
431
|
+
return child;
|
|
432
|
+
}
|
|
433
|
+
|
|
434
|
+
if (!children) {
|
|
435
|
+
if (![BlockletStatus.waiting, BlockletStatus.upgrading, BlockletStatus.installing].includes(status)) {
|
|
436
|
+
child.status = status;
|
|
437
|
+
}
|
|
438
|
+
|
|
439
|
+
return child;
|
|
440
|
+
}
|
|
441
|
+
|
|
442
|
+
const inputChild = children.find((x) => x.did === child.meta.did);
|
|
443
|
+
if (inputChild) {
|
|
444
|
+
child.status = status;
|
|
445
|
+
}
|
|
446
|
+
return child;
|
|
447
|
+
});
|
|
448
|
+
|
|
415
449
|
await this.update(doc._id, { $set: updates });
|
|
416
450
|
return formatBlocklet({ ...doc, ...updates }, 'onRead', this.options.dek);
|
|
417
451
|
}
|
|
@@ -463,6 +497,48 @@ class BlockletState extends BaseState {
|
|
|
463
497
|
|
|
464
498
|
return children;
|
|
465
499
|
}
|
|
500
|
+
|
|
501
|
+
async addChildren(did, children) {
|
|
502
|
+
const parent = await this.getBlocklet(did);
|
|
503
|
+
if (!parent) {
|
|
504
|
+
throw new Error('Blocklet does not exist');
|
|
505
|
+
}
|
|
506
|
+
|
|
507
|
+
const oldChildren = parent.children || [];
|
|
508
|
+
|
|
509
|
+
const newChildren = [...oldChildren];
|
|
510
|
+
for (const child of children) {
|
|
511
|
+
const { meta, mountPoint, sourceUrl = '', source = '', deployedFrom = '' } = child;
|
|
512
|
+
|
|
513
|
+
if (!mountPoint) {
|
|
514
|
+
throw new Error(`mountPoint is required when adding component ${meta.title || meta.name}`);
|
|
515
|
+
}
|
|
516
|
+
|
|
517
|
+
if (meta.did === parent.meta.did) {
|
|
518
|
+
throw new Error('Cannot add self as a component');
|
|
519
|
+
}
|
|
520
|
+
|
|
521
|
+
checkDuplicateComponents([child], newChildren);
|
|
522
|
+
|
|
523
|
+
newChildren.push({
|
|
524
|
+
mountPoint,
|
|
525
|
+
meta,
|
|
526
|
+
sourceUrl,
|
|
527
|
+
source,
|
|
528
|
+
deployedFrom,
|
|
529
|
+
dynamic: true,
|
|
530
|
+
status: BlockletStatus.added,
|
|
531
|
+
});
|
|
532
|
+
}
|
|
533
|
+
|
|
534
|
+
// use upgradeBlocklet to assign ports to children and write new data to db
|
|
535
|
+
return this.upgradeBlocklet({
|
|
536
|
+
meta: parent.meta,
|
|
537
|
+
source: parent.source,
|
|
538
|
+
deployedFrom: parent.deployedFrom,
|
|
539
|
+
children: newChildren,
|
|
540
|
+
});
|
|
541
|
+
}
|
|
466
542
|
}
|
|
467
543
|
|
|
468
544
|
BlockletState.BlockletStatus = BlockletStatus;
|
package/lib/states/node.js
CHANGED
|
@@ -92,7 +92,7 @@ class NodeState extends BaseState {
|
|
|
92
92
|
mode,
|
|
93
93
|
runtimeConfig,
|
|
94
94
|
ownerNft,
|
|
95
|
-
|
|
95
|
+
launcher,
|
|
96
96
|
didRegistry,
|
|
97
97
|
didDomain,
|
|
98
98
|
enablePassportIssuance = true,
|
|
@@ -128,7 +128,7 @@ class NodeState extends BaseState {
|
|
|
128
128
|
runtimeConfig,
|
|
129
129
|
ownerNft,
|
|
130
130
|
diskAlertThreshold: DISK_ALERT_THRESHOLD_PERCENT,
|
|
131
|
-
|
|
131
|
+
launcher: launcher || undefined,
|
|
132
132
|
didRegistry,
|
|
133
133
|
didDomain,
|
|
134
134
|
enablePassportIssuance,
|
|
@@ -162,7 +162,8 @@ class NodeState extends BaseState {
|
|
|
162
162
|
// FIXME: 这个接口比较危险,可能会修改一些本不应该修改的字段,后续需要考虑改进
|
|
163
163
|
async updateNodeInfo(entity = {}) {
|
|
164
164
|
const record = await this.read();
|
|
165
|
-
|
|
165
|
+
|
|
166
|
+
const updateResult = await this.update(record._id, { $set: omit(entity, ['ownerNft', 'sk']) });
|
|
166
167
|
this.emit('node.updated', updateResult, record);
|
|
167
168
|
return updateResult;
|
|
168
169
|
}
|
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 } = require('@blocklet/meta/lib/util');
|
|
45
|
+
const { forEachBlocklet, isFreeBlocklet } = require('@blocklet/meta/lib/util');
|
|
46
46
|
|
|
47
47
|
const { validate: validateEngine, get: getEngine } = require('../blocklet/manager/engine');
|
|
48
48
|
|
|
@@ -252,7 +252,7 @@ const getRootSystemEnvironments = (blocklet, nodeInfo) => {
|
|
|
252
252
|
const appDescription = description || result.description;
|
|
253
253
|
|
|
254
254
|
// FIXME: we should use https here when possible, eg, when did-gateway is available
|
|
255
|
-
const appUrl = `http://${getDidDomainForBlocklet({
|
|
255
|
+
const appUrl = `http://${getDidDomainForBlocklet({ name, daemonDid: nodeInfo.did, didDomain: nodeInfo.didDomain })}`;
|
|
256
256
|
|
|
257
257
|
return {
|
|
258
258
|
BLOCKLET_DID: did,
|
|
@@ -951,7 +951,7 @@ const getRuntimeInfo = async (appId) => {
|
|
|
951
951
|
|
|
952
952
|
/**
|
|
953
953
|
* merge services
|
|
954
|
-
* from meta.children[].mountPoints[].services
|
|
954
|
+
* from meta.children[].mountPoints[].services, meta.children[].services
|
|
955
955
|
* to childrenMeta[].interfaces[].services
|
|
956
956
|
*
|
|
957
957
|
* @param {array<child>|object{children:array}} source e.g. [<config>] or { children: [<config>] }
|
|
@@ -993,6 +993,23 @@ const mergeMeta = (source, childrenMeta = []) => {
|
|
|
993
993
|
childInterface.services = services;
|
|
994
994
|
}
|
|
995
995
|
});
|
|
996
|
+
|
|
997
|
+
if (config.services) {
|
|
998
|
+
const childInterface = findWebInterface(childMeta);
|
|
999
|
+
if (childInterface) {
|
|
1000
|
+
// merge
|
|
1001
|
+
const services = childInterface.services || [];
|
|
1002
|
+
config.services.forEach((x) => {
|
|
1003
|
+
const index = services.findIndex((y) => y.name === x.name);
|
|
1004
|
+
if (index >= 0) {
|
|
1005
|
+
services.splice(index, 1, x);
|
|
1006
|
+
} else {
|
|
1007
|
+
services.push(x);
|
|
1008
|
+
}
|
|
1009
|
+
});
|
|
1010
|
+
childInterface.services = services;
|
|
1011
|
+
}
|
|
1012
|
+
}
|
|
996
1013
|
});
|
|
997
1014
|
};
|
|
998
1015
|
|
|
@@ -1101,6 +1118,34 @@ const getDiffFiles = async (inputFiles, sourceDir) => {
|
|
|
1101
1118
|
|
|
1102
1119
|
const getBundleDir = (installDir, bundle) => path.join(installDir, bundle.name, bundle.version);
|
|
1103
1120
|
|
|
1121
|
+
const needBlockletDownload = (blocklet, oldBlocklet) => {
|
|
1122
|
+
if ([BlockletSource.upload, BlockletSource.local, BlockletSource.custom].includes(blocklet.source)) {
|
|
1123
|
+
return false;
|
|
1124
|
+
}
|
|
1125
|
+
|
|
1126
|
+
if (!get(oldBlocklet, 'meta.dist.integrity')) {
|
|
1127
|
+
return true;
|
|
1128
|
+
}
|
|
1129
|
+
|
|
1130
|
+
if (get(oldBlocklet, 'meta.dist.integrity') === get(blocklet, 'meta.dist.integrity')) {
|
|
1131
|
+
return false;
|
|
1132
|
+
}
|
|
1133
|
+
|
|
1134
|
+
return true;
|
|
1135
|
+
};
|
|
1136
|
+
|
|
1137
|
+
const verifyPurchase = (meta, opts = {}) => {
|
|
1138
|
+
if (opts.blockletPurchaseVerified) {
|
|
1139
|
+
return true;
|
|
1140
|
+
}
|
|
1141
|
+
|
|
1142
|
+
if (isFreeBlocklet(meta)) {
|
|
1143
|
+
return true;
|
|
1144
|
+
}
|
|
1145
|
+
|
|
1146
|
+
throw new Error('Can not install a non-free blocklet directly');
|
|
1147
|
+
};
|
|
1148
|
+
|
|
1104
1149
|
module.exports = {
|
|
1105
1150
|
forEachBlocklet,
|
|
1106
1151
|
getBlockletMetaFromUrl,
|
|
@@ -1135,4 +1180,6 @@ module.exports = {
|
|
|
1135
1180
|
checkDuplicateComponents,
|
|
1136
1181
|
getDiffFiles,
|
|
1137
1182
|
getBundleDir,
|
|
1183
|
+
needBlockletDownload,
|
|
1184
|
+
verifyPurchase,
|
|
1138
1185
|
};
|
|
@@ -16,8 +16,8 @@ const getIpDnsDomainForBlocklet = (blocklet, blockletInterface) => {
|
|
|
16
16
|
}${iName}-${SLOT_FOR_IP_DNS_SITE}.${DEFAULT_IP_DNS_DOMAIN_SUFFIX}`;
|
|
17
17
|
};
|
|
18
18
|
|
|
19
|
-
const getDidDomainForBlocklet = ({
|
|
20
|
-
return `${
|
|
19
|
+
const getDidDomainForBlocklet = ({ name, daemonDid, didDomain }) => {
|
|
20
|
+
return `${formatName(name)}-${daemonDid.toLowerCase()}.${didDomain}`;
|
|
21
21
|
};
|
|
22
22
|
|
|
23
23
|
module.exports = { getIpDnsDomainForBlocklet, getDidDomainForBlocklet };
|
package/lib/util/index.js
CHANGED
|
@@ -373,7 +373,7 @@ const getBaseUrls = async (node, ips) => {
|
|
|
373
373
|
if (info.routing.provider !== ROUTER_PROVIDER_NONE && info.routing.snapshotHash && info.routing.adminPath) {
|
|
374
374
|
const sites = await node.getSitesFromSnapshot();
|
|
375
375
|
|
|
376
|
-
const {
|
|
376
|
+
const { ipWildcardDomain } = info.routing;
|
|
377
377
|
const adminPath = normalizePathPrefix(info.routing.adminPath);
|
|
378
378
|
const tmpHttpPort = getPort(httpPort, DEFAULT_HTTP_PORT);
|
|
379
379
|
|
|
@@ -383,12 +383,12 @@ const getBaseUrls = async (node, ips) => {
|
|
|
383
383
|
};
|
|
384
384
|
});
|
|
385
385
|
|
|
386
|
-
if (
|
|
387
|
-
const site = sites.find((c) => (c.domainAliases || []).find((item) => item.value ===
|
|
386
|
+
if (ipWildcardDomain) {
|
|
387
|
+
const site = sites.find((c) => (c.domainAliases || []).find((item) => item.value === ipWildcardDomain));
|
|
388
388
|
if (site) {
|
|
389
|
-
const httpInfo = await getHttpInfo(
|
|
389
|
+
const httpInfo = await getHttpInfo(ipWildcardDomain);
|
|
390
390
|
const httpsUrls = availableIps.map((ip) => ({
|
|
391
|
-
url: `${httpInfo.protocol}://${transformIPToDomain(ip)}.${
|
|
391
|
+
url: `${httpInfo.protocol}://${transformIPToDomain(ip)}.${ipWildcardDomain.substring(2)}${
|
|
392
392
|
httpInfo.port
|
|
393
393
|
}${adminPath}`,
|
|
394
394
|
}));
|
package/lib/util/upgrade.js
CHANGED
|
@@ -27,9 +27,6 @@ const waitUpdaterRpc = async (message) =>
|
|
|
27
27
|
const checkNewVersion = async (params, context) => {
|
|
28
28
|
try {
|
|
29
29
|
const info = await states.node.read();
|
|
30
|
-
if (!info.autoUpgrade) {
|
|
31
|
-
return '';
|
|
32
|
-
}
|
|
33
30
|
|
|
34
31
|
if (!process.env.ABT_NODE_PACKAGE_NAME) {
|
|
35
32
|
logger.error('ABT_NODE_PACKAGE_NAME name was not found in environment');
|
|
@@ -176,7 +173,14 @@ const getCron = () => ({
|
|
|
176
173
|
name: 'check-update',
|
|
177
174
|
time: '0 0 8 * * *', // check every day
|
|
178
175
|
// time: '0 */5 * * * *', // check every 5 minutes
|
|
179
|
-
fn:
|
|
176
|
+
fn: async () => {
|
|
177
|
+
const info = await states.node.read();
|
|
178
|
+
if (!info.autoUpgrade) {
|
|
179
|
+
return;
|
|
180
|
+
}
|
|
181
|
+
|
|
182
|
+
checkNewVersion();
|
|
183
|
+
},
|
|
180
184
|
options: { runOnInit: false },
|
|
181
185
|
});
|
|
182
186
|
|