@abtnode/core 1.6.15 → 1.6.19
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 +429 -151
- package/lib/blocklet/migration.js +16 -52
- package/lib/event.js +1 -1
- package/lib/index.js +3 -1
- package/lib/migrations/1.6.17-blocklet-children.js +48 -0
- package/lib/router/helper.js +18 -12
- package/lib/router/manager.js +45 -41
- package/lib/states/blocklet-extras.js +39 -3
- package/lib/states/blocklet.js +89 -20
- package/lib/states/node.js +17 -2
- package/lib/util/blocklet.js +288 -67
- package/lib/util/default-node-config.js +1 -1
- package/lib/util/get-domain-for-blocklet.js +2 -2
- package/lib/util/upgrade.js +8 -4
- package/lib/validators/node.js +11 -12
- package/package.json +23 -23
|
@@ -1,67 +1,25 @@
|
|
|
1
1
|
/* eslint-disable no-await-in-loop */
|
|
2
|
-
const childProcess = require('child_process');
|
|
3
2
|
const fs = require('fs-extra');
|
|
4
3
|
const path = require('path');
|
|
5
4
|
const semver = require('semver');
|
|
5
|
+
const runScript = require('@abtnode/util/lib/run-script');
|
|
6
6
|
|
|
7
7
|
const { getMigrationScripts: getScripts } = require('../migrations');
|
|
8
8
|
const { getSafeEnv } = require('../util');
|
|
9
9
|
const { name } = require('../../package.json');
|
|
10
10
|
const logger = require('@abtnode/logger')(`${name}:blocklet:migration`); // eslint-disable-line
|
|
11
11
|
|
|
12
|
-
const _runScript = ({ appDir, env, migrationScript, progress = false }) => {
|
|
13
|
-
const safeEnv = getSafeEnv(env);
|
|
14
|
-
|
|
15
|
-
const child = childProcess.exec(`node ${migrationScript}`, {
|
|
16
|
-
cwd: appDir,
|
|
17
|
-
env: safeEnv,
|
|
18
|
-
stdio: 'inherit',
|
|
19
|
-
});
|
|
20
|
-
let hasUnhandledRejection = false;
|
|
21
|
-
|
|
22
|
-
if (progress) {
|
|
23
|
-
child.stdout.pipe(process.stdout);
|
|
24
|
-
child.stderr.pipe(process.stderr);
|
|
25
|
-
}
|
|
26
|
-
|
|
27
|
-
return new Promise((resolve, reject) => {
|
|
28
|
-
const errorMessages = [];
|
|
29
|
-
|
|
30
|
-
child.stderr.on('data', (err) => {
|
|
31
|
-
// Check if has unhandledRejection in childProcess
|
|
32
|
-
// https://stackoverflow.com/questions/32784649/gracefully-handle-errors-in-child-processes-in-nodejs
|
|
33
|
-
if (err.includes('UnhandledPromiseRejectionWarning')) {
|
|
34
|
-
hasUnhandledRejection = true;
|
|
35
|
-
}
|
|
36
|
-
errorMessages.push(err);
|
|
37
|
-
});
|
|
38
|
-
|
|
39
|
-
child.on('exit', (code) => {
|
|
40
|
-
if (errorMessages.length > 0) {
|
|
41
|
-
if (code !== 0 || hasUnhandledRejection) {
|
|
42
|
-
return reject(new Error(errorMessages.join('\r\n')));
|
|
43
|
-
}
|
|
44
|
-
|
|
45
|
-
if (!progress) {
|
|
46
|
-
errorMessages.forEach((message) => process.stderr.write(message));
|
|
47
|
-
}
|
|
48
|
-
}
|
|
49
|
-
|
|
50
|
-
return resolve();
|
|
51
|
-
});
|
|
52
|
-
});
|
|
53
|
-
};
|
|
54
|
-
|
|
55
12
|
async function runScripts({
|
|
13
|
+
blocklet,
|
|
14
|
+
appDir,
|
|
15
|
+
env,
|
|
16
|
+
oldVersion,
|
|
56
17
|
dbDir,
|
|
57
18
|
backupDir,
|
|
58
19
|
scriptsDir,
|
|
59
20
|
printInfo,
|
|
60
21
|
printSuccess,
|
|
61
22
|
printError,
|
|
62
|
-
appDir,
|
|
63
|
-
env,
|
|
64
|
-
oldVersion,
|
|
65
23
|
}) {
|
|
66
24
|
let scripts = [];
|
|
67
25
|
try {
|
|
@@ -90,7 +48,11 @@ async function runScripts({
|
|
|
90
48
|
const { script: scriptPath } = pendingScripts[i];
|
|
91
49
|
try {
|
|
92
50
|
printInfo(`Migration script started: ${scriptPath}`);
|
|
93
|
-
await
|
|
51
|
+
await runScript(`node ${path.join(scriptsDir, scriptPath)}`, [blocklet.env.appId, 'migration'].join(':'), {
|
|
52
|
+
cwd: appDir,
|
|
53
|
+
env: getSafeEnv(env),
|
|
54
|
+
silent: false,
|
|
55
|
+
});
|
|
94
56
|
printInfo(`Migration script executed: ${scriptPath}`);
|
|
95
57
|
} catch (migrationErr) {
|
|
96
58
|
printError(`Failed to execute migration script: ${scriptPath}, error: ${migrationErr.message}`);
|
|
@@ -123,6 +85,7 @@ async function doRestore({ dbDir, backupDir, printInfo, printSuccess }) {
|
|
|
123
85
|
}
|
|
124
86
|
|
|
125
87
|
module.exports = async ({
|
|
88
|
+
blocklet,
|
|
126
89
|
appDir,
|
|
127
90
|
env,
|
|
128
91
|
oldVersion,
|
|
@@ -142,15 +105,16 @@ module.exports = async ({
|
|
|
142
105
|
fs.ensureDirSync(backupDir);
|
|
143
106
|
|
|
144
107
|
await runScripts({
|
|
108
|
+
blocklet,
|
|
109
|
+
appDir,
|
|
110
|
+
env,
|
|
111
|
+
oldVersion,
|
|
112
|
+
newVersion,
|
|
145
113
|
dbDir,
|
|
146
114
|
backupDir,
|
|
147
115
|
scriptsDir,
|
|
148
116
|
printError,
|
|
149
117
|
printInfo,
|
|
150
118
|
printSuccess,
|
|
151
|
-
appDir,
|
|
152
|
-
env,
|
|
153
|
-
oldVersion,
|
|
154
|
-
newVersion,
|
|
155
119
|
});
|
|
156
120
|
};
|
package/lib/event.js
CHANGED
|
@@ -182,7 +182,7 @@ module.exports = ({
|
|
|
182
182
|
.catch((error) => logger.error('refresh blocklets failed on initialize the registry', { error }));
|
|
183
183
|
|
|
184
184
|
// We need update router on some fields change
|
|
185
|
-
const fields = ['enableWelcomePage', 'webWalletUrl'];
|
|
185
|
+
const fields = ['enableWelcomePage', 'webWalletUrl', 'registerUrl'];
|
|
186
186
|
const shouldUpdateRouter = fields.some((x) => nodeInfo[x] !== oldInfo[x]);
|
|
187
187
|
if (shouldUpdateRouter) {
|
|
188
188
|
handleRouting(nodeInfo).catch((err) => {
|
package/lib/index.js
CHANGED
|
@@ -50,6 +50,7 @@ const { toStatus, fromStatus, ensureDataDirs, getQueueConcurrencyByMem } = requi
|
|
|
50
50
|
* version
|
|
51
51
|
* runtimeConfig: {}
|
|
52
52
|
* autoUpgrade
|
|
53
|
+
* registerUrl
|
|
53
54
|
* webWalletUrl
|
|
54
55
|
*/
|
|
55
56
|
function ABTNode(options) {
|
|
@@ -196,16 +197,17 @@ function ABTNode(options) {
|
|
|
196
197
|
// Blocklet manager
|
|
197
198
|
installBlocklet: blockletManager.install.bind(blockletManager),
|
|
198
199
|
installBlockletFromVc: blockletManager.installBlockletFromVc.bind(blockletManager),
|
|
200
|
+
installComponent: blockletManager.installComponent.bind(blockletManager),
|
|
199
201
|
startBlocklet: blockletManager.start.bind(blockletManager),
|
|
200
202
|
stopBlocklet: blockletManager.stop.bind(blockletManager),
|
|
201
203
|
reloadBlocklet: blockletManager.reload.bind(blockletManager),
|
|
202
204
|
restartBlocklet: blockletManager.restart.bind(blockletManager),
|
|
203
205
|
deleteBlocklet: blockletManager.delete.bind(blockletManager),
|
|
206
|
+
deleteComponent: blockletManager.deleteComponent.bind(blockletManager),
|
|
204
207
|
cancelDownloadBlocklet: blockletManager.cancelDownload.bind(blockletManager),
|
|
205
208
|
upgradeBlocklet: blockletManager.upgrade.bind(blockletManager),
|
|
206
209
|
configBlocklet: blockletManager.config.bind(blockletManager),
|
|
207
210
|
devBlocklet: blockletManager.dev.bind(blockletManager),
|
|
208
|
-
getBlockletStatus: blockletManager.getStatus.bind(blockletManager),
|
|
209
211
|
checkChildBlockletsForUpdates: blockletManager.checkChildrenForUpdates.bind(blockletManager),
|
|
210
212
|
updateChildBlocklets: blockletManager.updateChildren.bind(blockletManager),
|
|
211
213
|
getLatestBlockletVersion: blockletManager.getLatestBlockletVersion.bind(blockletManager),
|
|
@@ -0,0 +1,48 @@
|
|
|
1
|
+
/* eslint-disable no-continue */
|
|
2
|
+
/* eslint-disable no-await-in-loop */
|
|
3
|
+
/* eslint-disable no-underscore-dangle */
|
|
4
|
+
|
|
5
|
+
module.exports = async ({ states, printInfo }) => {
|
|
6
|
+
printInfo('Try to update blocklet to 1.6.17...');
|
|
7
|
+
const blockletState = states.blocklet;
|
|
8
|
+
|
|
9
|
+
const blocklets = await blockletState.getBlocklets();
|
|
10
|
+
for (const blocklet of blocklets) {
|
|
11
|
+
if (!blocklet) {
|
|
12
|
+
continue;
|
|
13
|
+
}
|
|
14
|
+
|
|
15
|
+
if (!blocklet.children || !blocklet.children.length) {
|
|
16
|
+
continue;
|
|
17
|
+
}
|
|
18
|
+
|
|
19
|
+
const meta = blocklet.meta || {};
|
|
20
|
+
const { did } = meta;
|
|
21
|
+
if (!did) {
|
|
22
|
+
continue;
|
|
23
|
+
}
|
|
24
|
+
|
|
25
|
+
const children = (blocklet.children || []).map((child) => {
|
|
26
|
+
if (child.mountPoint) {
|
|
27
|
+
return child;
|
|
28
|
+
}
|
|
29
|
+
|
|
30
|
+
const config = (meta.children || []).find((x) => x.name === child.meta.name);
|
|
31
|
+
|
|
32
|
+
if (
|
|
33
|
+
config &&
|
|
34
|
+
config.mountPoints &&
|
|
35
|
+
config.mountPoints[0] &&
|
|
36
|
+
config.mountPoints[0].root &&
|
|
37
|
+
config.mountPoints[0].root.prefix
|
|
38
|
+
) {
|
|
39
|
+
child.mountPoint = config.mountPoints[0].root.prefix;
|
|
40
|
+
}
|
|
41
|
+
printInfo(`Set mountPoint: ${child.mountPoint} to child ${child.meta.name} in ${blocklet.meta.name}`);
|
|
42
|
+
|
|
43
|
+
return child;
|
|
44
|
+
});
|
|
45
|
+
|
|
46
|
+
await blockletState.update(blocklet._id, { $set: { children } });
|
|
47
|
+
}
|
|
48
|
+
};
|
package/lib/router/helper.js
CHANGED
|
@@ -244,6 +244,9 @@ const ensureLatestNodeInfo = async (sites = [], { withDefaultCors = true } = {})
|
|
|
244
244
|
site.domain = DOMAIN_FOR_IP_SITE_REGEXP;
|
|
245
245
|
|
|
246
246
|
if (withDefaultCors) {
|
|
247
|
+
// Allow CORS from "Install on ABT Node"
|
|
248
|
+
addCorsToSite(site, info.registerUrl);
|
|
249
|
+
|
|
247
250
|
// Allow CORS from "Web Wallet"
|
|
248
251
|
addCorsToSite(site, info.webWalletUrl);
|
|
249
252
|
}
|
|
@@ -314,7 +317,7 @@ const ensureWellknownRule = async (sites) => {
|
|
|
314
317
|
rules.forEach((rule) => {
|
|
315
318
|
if (
|
|
316
319
|
rule.to.type !== ROUTING_RULE_TYPES.BLOCKLET || // is not blocklet
|
|
317
|
-
rule.to.did !== rule.to.realDid // is a component endpoint
|
|
320
|
+
(rule.to.did !== rule.to.realDid && rule.from.pathPrefix !== '/') // is a component endpoint in sub path
|
|
318
321
|
) {
|
|
319
322
|
return;
|
|
320
323
|
}
|
|
@@ -434,7 +437,8 @@ module.exports = function getRouterHelpers({ dataDirs, routingSnapshot, routerMa
|
|
|
434
437
|
|
|
435
438
|
const https = get(info, 'routing.https', true);
|
|
436
439
|
const dashboardDomain = get(info, 'routing.dashboardDomain', '');
|
|
437
|
-
const certDownloadAddress =
|
|
440
|
+
const certDownloadAddress =
|
|
441
|
+
process.env.ABT_NODE_DASHBOARD_CERT_DOWN_URL || get(info, 'routing.dashboardCertDownloadAddress', '');
|
|
438
442
|
if (!https || !dashboardDomain || !certDownloadAddress) {
|
|
439
443
|
return;
|
|
440
444
|
}
|
|
@@ -508,9 +512,9 @@ module.exports = function getRouterHelpers({ dataDirs, routingSnapshot, routerMa
|
|
|
508
512
|
return { status: 'existed' };
|
|
509
513
|
}
|
|
510
514
|
|
|
511
|
-
logger.debug('downloading certificate', { url: downloadUrl, dashboardDomain });
|
|
515
|
+
logger.debug('downloading dashboard ip-domain certificate', { url: downloadUrl, dashboardDomain });
|
|
512
516
|
await updateDashboardCertificate({ checkExpire: false });
|
|
513
|
-
logger.debug('
|
|
517
|
+
logger.debug('downloaded dashboard ip-domain certificate', { url: downloadUrl, dashboardDomain });
|
|
514
518
|
return { status: 'downloaded' };
|
|
515
519
|
};
|
|
516
520
|
|
|
@@ -656,7 +660,9 @@ module.exports = function getRouterHelpers({ dataDirs, routingSnapshot, routerMa
|
|
|
656
660
|
|
|
657
661
|
const dashboardDomain = get(info, 'routing.dashboardDomain', '');
|
|
658
662
|
const didDomain = `${info.did.toLowerCase()}.${info.didDomain}`;
|
|
659
|
-
|
|
663
|
+
let dashboardAliasDomains = [dashboardDomain, didDomain];
|
|
664
|
+
|
|
665
|
+
dashboardAliasDomains = dashboardAliasDomains
|
|
660
666
|
.filter((item) => item && !isExistsInAlias(item))
|
|
661
667
|
.map((item) => ({ value: item, isProtected: true }));
|
|
662
668
|
|
|
@@ -742,18 +748,18 @@ module.exports = function getRouterHelpers({ dataDirs, routingSnapshot, routerMa
|
|
|
742
748
|
|
|
743
749
|
const existSite = await states.site.findOne({ domain: domainGroup });
|
|
744
750
|
if (!existSite) {
|
|
745
|
-
const
|
|
746
|
-
const appIdEnv = blocklet.environments.find((e) => e.key === 'BLOCKLET_APP_ID');
|
|
747
|
-
const domainAliases = [{ value: ipEchoDnsDomain, isProtected: true }];
|
|
751
|
+
const domainAliases = [];
|
|
748
752
|
|
|
749
753
|
const didDomain = getDidDomainForBlocklet({
|
|
750
|
-
|
|
754
|
+
name: blocklet.meta.name,
|
|
755
|
+
daemonDid: nodeInfo.did,
|
|
751
756
|
didDomain: nodeInfo.didDomain,
|
|
752
757
|
});
|
|
753
758
|
|
|
754
|
-
|
|
755
|
-
|
|
756
|
-
|
|
759
|
+
const ipEchoDnsDomain = getIpDnsDomainForBlocklet(blocklet, webInterface, nodeInfo.did);
|
|
760
|
+
|
|
761
|
+
// let didDomain in front of ipEchoDnsDomain
|
|
762
|
+
domainAliases.push({ value: didDomain, isProtected: true }, { value: ipEchoDnsDomain, isProtected: true });
|
|
757
763
|
|
|
758
764
|
await routerManager.addRoutingSite(
|
|
759
765
|
{
|
package/lib/router/manager.js
CHANGED
|
@@ -27,6 +27,7 @@ const {
|
|
|
27
27
|
BLOCKLET_BUNDLE_FOLDER,
|
|
28
28
|
BLOCKLET_DYNAMIC_PATH_PREFIX,
|
|
29
29
|
BLOCKLET_INTERFACE_TYPE_WEB,
|
|
30
|
+
BlockletGroup,
|
|
30
31
|
} = require('@blocklet/meta/lib/constants');
|
|
31
32
|
|
|
32
33
|
const {
|
|
@@ -37,6 +38,7 @@ const {
|
|
|
37
38
|
validateUpdateSite,
|
|
38
39
|
} = require('../validators/router');
|
|
39
40
|
const { getProviderFromNodeInfo, findInterfaceByName, isCLI, findInterfacePortByName } = require('../util');
|
|
41
|
+
const { findWebInterface } = require('../util/blocklet');
|
|
40
42
|
const { attachInterfaceUrls, ensureLatestInfo } = require('./helper');
|
|
41
43
|
const Router = require('./index');
|
|
42
44
|
const states = require('../states');
|
|
@@ -219,10 +221,10 @@ class RouterManager extends EventEmitter {
|
|
|
219
221
|
}
|
|
220
222
|
}
|
|
221
223
|
|
|
222
|
-
|
|
223
|
-
|
|
224
|
-
|
|
225
|
-
);
|
|
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 } });
|
|
226
228
|
logger.debug('add domain alias update result', { id, updateResult, domainAlias });
|
|
227
229
|
|
|
228
230
|
const newSite = await states.site.findOne({ _id: id });
|
|
@@ -679,49 +681,51 @@ class RouterManager extends EventEmitter {
|
|
|
679
681
|
|
|
680
682
|
// get child rules
|
|
681
683
|
const blocklet = await states.blocklet.getBlocklet(rule.to.did);
|
|
682
|
-
for (const
|
|
683
|
-
|
|
684
|
-
|
|
685
|
-
|
|
686
|
-
|
|
687
|
-
|
|
688
|
-
|
|
689
|
-
continue;
|
|
690
|
-
}
|
|
684
|
+
for (const child of blocklet.children || []) {
|
|
685
|
+
const { mountPoint } = child;
|
|
686
|
+
if (!mountPoint) {
|
|
687
|
+
logger.error(`mountPoint of child ${child.meta.name} does not exist`);
|
|
688
|
+
// eslint-disable-next-line no-continue
|
|
689
|
+
continue;
|
|
690
|
+
}
|
|
691
691
|
|
|
692
|
-
|
|
693
|
-
|
|
694
|
-
|
|
695
|
-
|
|
696
|
-
|
|
697
|
-
|
|
692
|
+
const childWebInterface = findWebInterface(child);
|
|
693
|
+
if (!childWebInterface) {
|
|
694
|
+
logger.error(`web interface of child ${child.meta.name} does not exist`);
|
|
695
|
+
// eslint-disable-next-line no-continue
|
|
696
|
+
continue;
|
|
697
|
+
}
|
|
698
698
|
|
|
699
|
-
|
|
700
|
-
|
|
701
|
-
|
|
702
|
-
|
|
703
|
-
from: {
|
|
704
|
-
pathPrefix: normalizePathPrefix(pathPrefix),
|
|
705
|
-
groupPathPrefix: rule.from.pathPrefix,
|
|
706
|
-
},
|
|
707
|
-
to: {
|
|
708
|
-
type: ROUTING_RULE_TYPES.BLOCKLET,
|
|
709
|
-
port: findInterfacePortByName(child, mountPoint.child.interfaceName),
|
|
710
|
-
did: rule.to.did, // root blocklet did
|
|
711
|
-
interfaceName: rule.to.interfaceName, // root blocklet interface
|
|
712
|
-
realDid: child.meta.did, // child blocklet did
|
|
713
|
-
realInterfaceName: mountPoint.child.interfaceName,
|
|
714
|
-
},
|
|
715
|
-
isProtected: isRootPath ? rule.isProtected : true,
|
|
716
|
-
};
|
|
717
|
-
|
|
718
|
-
rules.push(childRule);
|
|
719
|
-
}
|
|
699
|
+
const pathPrefix = path.join(rule.from.pathPrefix, mountPoint);
|
|
700
|
+
const isRootPath = pathPrefix === rule.from.pathPrefix;
|
|
701
|
+
if (isRootPath) {
|
|
702
|
+
occupied = true;
|
|
720
703
|
}
|
|
704
|
+
|
|
705
|
+
// if is root path, child rule become root rule
|
|
706
|
+
const childRule = {
|
|
707
|
+
id: isRootPath ? rule.id : uuid.v4(),
|
|
708
|
+
groupId: rule.id,
|
|
709
|
+
from: {
|
|
710
|
+
pathPrefix: normalizePathPrefix(pathPrefix),
|
|
711
|
+
groupPathPrefix: rule.from.pathPrefix,
|
|
712
|
+
},
|
|
713
|
+
to: {
|
|
714
|
+
type: ROUTING_RULE_TYPES.BLOCKLET,
|
|
715
|
+
port: findInterfacePortByName(child, childWebInterface.name),
|
|
716
|
+
did: rule.to.did, // root blocklet did
|
|
717
|
+
interfaceName: rule.to.interfaceName, // root blocklet interface
|
|
718
|
+
realDid: child.meta.did, // child blocklet did
|
|
719
|
+
realInterfaceName: childWebInterface.name,
|
|
720
|
+
},
|
|
721
|
+
isProtected: isRootPath ? rule.isProtected : true,
|
|
722
|
+
};
|
|
723
|
+
|
|
724
|
+
rules.push(childRule);
|
|
721
725
|
}
|
|
722
726
|
|
|
723
727
|
// get root rule
|
|
724
|
-
if (!occupied) {
|
|
728
|
+
if (!occupied && blocklet.meta.group !== BlockletGroup.gateway) {
|
|
725
729
|
rules.push(rule);
|
|
726
730
|
}
|
|
727
731
|
|
|
@@ -3,6 +3,7 @@
|
|
|
3
3
|
/* eslint-disable consistent-return */
|
|
4
4
|
const logger = require('@abtnode/logger')('state-blocklet-extras');
|
|
5
5
|
const camelCase = require('lodash/camelCase');
|
|
6
|
+
const get = require('lodash/get');
|
|
6
7
|
|
|
7
8
|
const BaseState = require('./base');
|
|
8
9
|
|
|
@@ -36,16 +37,28 @@ class BlockletExtrasState extends BaseState {
|
|
|
36
37
|
},
|
|
37
38
|
},
|
|
38
39
|
];
|
|
40
|
+
|
|
41
|
+
this.childExtras = this.extras.filter((x) => ['configs'].includes(x.name));
|
|
42
|
+
|
|
39
43
|
this.generateExtraFns();
|
|
40
44
|
}
|
|
41
45
|
|
|
46
|
+
delete(did) {
|
|
47
|
+
return this.remove({ did });
|
|
48
|
+
}
|
|
49
|
+
|
|
42
50
|
generateExtraFns() {
|
|
43
|
-
const methods = ['get', 'set', 'del'];
|
|
51
|
+
const methods = ['get', 'set', 'del', 'list'];
|
|
44
52
|
methods.forEach((method) => {
|
|
45
53
|
this.extras.forEach((extra) => {
|
|
46
54
|
const fn = camelCase(`${method} ${extra.name}`); // getConfigs, getRules
|
|
47
55
|
this[fn] = this.generateExtraFn(method, extra);
|
|
56
|
+
});
|
|
57
|
+
});
|
|
48
58
|
|
|
59
|
+
const childMethods = ['get', 'set', 'del'];
|
|
60
|
+
childMethods.forEach((method) => {
|
|
61
|
+
this.childExtras.forEach((extra) => {
|
|
49
62
|
const childFn = camelCase(`${method} child ${extra.name}`); // getChildConfigs, getChildRules
|
|
50
63
|
this[childFn] = this.generateExtraChildFn(method, extra);
|
|
51
64
|
});
|
|
@@ -66,14 +79,22 @@ class BlockletExtrasState extends BaseState {
|
|
|
66
79
|
if (method === 'del') {
|
|
67
80
|
return this.generateDelFn(extra);
|
|
68
81
|
}
|
|
82
|
+
|
|
83
|
+
if (method === 'list') {
|
|
84
|
+
return this.generateListFn(extra);
|
|
85
|
+
}
|
|
69
86
|
}
|
|
70
87
|
|
|
71
88
|
generateGetFn(extra) {
|
|
72
|
-
return async (did) => {
|
|
89
|
+
return async (did, path, defaultValue) => {
|
|
73
90
|
const { dek } = this.options;
|
|
74
91
|
const { name, afterGet = noop('data') } = extra;
|
|
75
92
|
const item = await this.asyncDB.findOne({ did });
|
|
76
|
-
|
|
93
|
+
const data = afterGet({ data: item ? item[name] : item, did, dek });
|
|
94
|
+
if (!path) {
|
|
95
|
+
return data;
|
|
96
|
+
}
|
|
97
|
+
return get(data, path, defaultValue);
|
|
77
98
|
};
|
|
78
99
|
}
|
|
79
100
|
|
|
@@ -118,6 +139,21 @@ class BlockletExtrasState extends BaseState {
|
|
|
118
139
|
};
|
|
119
140
|
}
|
|
120
141
|
|
|
142
|
+
generateListFn(extra) {
|
|
143
|
+
return async () => {
|
|
144
|
+
const { dek } = this.options;
|
|
145
|
+
const { name, afterGet = noop('data') } = extra;
|
|
146
|
+
const docs = await this.asyncDB.find({});
|
|
147
|
+
const list = docs
|
|
148
|
+
.filter((x) => x[name])
|
|
149
|
+
.map((x) => ({
|
|
150
|
+
did: x.did,
|
|
151
|
+
[name]: afterGet({ data: x[name], did: x.did, dek }),
|
|
152
|
+
}));
|
|
153
|
+
return list;
|
|
154
|
+
};
|
|
155
|
+
}
|
|
156
|
+
|
|
121
157
|
// generate extra child functions
|
|
122
158
|
|
|
123
159
|
generateExtraChildFn(method, extra) {
|
package/lib/states/blocklet.js
CHANGED
|
@@ -4,6 +4,7 @@
|
|
|
4
4
|
/* eslint-disable no-underscore-dangle */
|
|
5
5
|
const omit = require('lodash/omit');
|
|
6
6
|
const uniq = require('lodash/uniq');
|
|
7
|
+
const cloneDeep = require('lodash/cloneDeep');
|
|
7
8
|
const detectPort = require('detect-port');
|
|
8
9
|
const Lock = require('@abtnode/util/lib/lock');
|
|
9
10
|
const security = require('@abtnode/util/lib/security');
|
|
@@ -19,7 +20,7 @@ const {
|
|
|
19
20
|
const logger = require('@abtnode/logger')('state-blocklet');
|
|
20
21
|
|
|
21
22
|
const BaseState = require('./base');
|
|
22
|
-
const { forEachBlocklet } = require('../util/blocklet');
|
|
23
|
+
const { forEachBlocklet, checkDuplicateComponents } = require('../util/blocklet');
|
|
23
24
|
const { validateBlockletMeta } = require('../util');
|
|
24
25
|
|
|
25
26
|
const lock = new Lock('blocklet-port-assign-lock');
|
|
@@ -119,7 +120,7 @@ class BlockletState extends BaseState {
|
|
|
119
120
|
}
|
|
120
121
|
|
|
121
122
|
this.emit('remove', doc);
|
|
122
|
-
return resolve(doc);
|
|
123
|
+
return resolve(formatBlocklet(doc, 'onRead', this.options.dek));
|
|
123
124
|
});
|
|
124
125
|
})
|
|
125
126
|
);
|
|
@@ -130,9 +131,9 @@ class BlockletState extends BaseState {
|
|
|
130
131
|
meta,
|
|
131
132
|
source = BlockletSource.registry,
|
|
132
133
|
status = BlockletStatus.added,
|
|
133
|
-
deployedFrom,
|
|
134
|
+
deployedFrom = '',
|
|
134
135
|
mode = BLOCKLET_MODES.PRODUCTION,
|
|
135
|
-
|
|
136
|
+
children: rawChildren = [],
|
|
136
137
|
} = {}) {
|
|
137
138
|
return this.getBlocklet(did).then(
|
|
138
139
|
(doc) =>
|
|
@@ -152,7 +153,7 @@ class BlockletState extends BaseState {
|
|
|
152
153
|
|
|
153
154
|
const ports = await this.getBlockletPorts({ interfaces: sanitized.interfaces || [] });
|
|
154
155
|
|
|
155
|
-
const children = await this.fillChildrenPorts(
|
|
156
|
+
const children = await this.fillChildrenPorts(rawChildren, {
|
|
156
157
|
defaultPort: getMaxPort(ports),
|
|
157
158
|
});
|
|
158
159
|
|
|
@@ -196,7 +197,7 @@ class BlockletState extends BaseState {
|
|
|
196
197
|
}
|
|
197
198
|
|
|
198
199
|
try {
|
|
199
|
-
const formatted = formatBlocklet(updates, 'onUpdate', this.options.dek);
|
|
200
|
+
const formatted = formatBlocklet(cloneDeep(updates), 'onUpdate', this.options.dek);
|
|
200
201
|
const newDoc = await this.updateById(doc._id, { $set: formatted });
|
|
201
202
|
resolve(newDoc);
|
|
202
203
|
} catch (err) {
|
|
@@ -206,7 +207,7 @@ class BlockletState extends BaseState {
|
|
|
206
207
|
);
|
|
207
208
|
}
|
|
208
209
|
|
|
209
|
-
upgradeBlocklet({ meta, source, deployedFrom, children } = {}) {
|
|
210
|
+
upgradeBlocklet({ meta, source, deployedFrom = '', children } = {}) {
|
|
210
211
|
return this.getBlocklet(meta.did).then(
|
|
211
212
|
(doc) =>
|
|
212
213
|
// eslint-disable-next-line no-async-promise-executor
|
|
@@ -247,8 +248,10 @@ class BlockletState extends BaseState {
|
|
|
247
248
|
},
|
|
248
249
|
});
|
|
249
250
|
lock.release();
|
|
250
|
-
|
|
251
|
-
|
|
251
|
+
|
|
252
|
+
const formatted = formatBlocklet(newDoc, 'onRead', this.options.dek);
|
|
253
|
+
this.emit('upgrade', formatted);
|
|
254
|
+
resolve(formatted);
|
|
252
255
|
} catch (err) {
|
|
253
256
|
lock.release();
|
|
254
257
|
reject(err);
|
|
@@ -388,15 +391,23 @@ class BlockletState extends BaseState {
|
|
|
388
391
|
return result;
|
|
389
392
|
}
|
|
390
393
|
|
|
391
|
-
|
|
394
|
+
/**
|
|
395
|
+
* @param {String} did blocklet did
|
|
396
|
+
* @param {BlockletStatus} status blocklet status
|
|
397
|
+
*
|
|
398
|
+
* children status only different with parent before blocklet installation
|
|
399
|
+
* @param {Array<{did}>} children
|
|
400
|
+
*/
|
|
401
|
+
async setBlockletStatus(did, status, { children } = {}) {
|
|
392
402
|
if (typeof status === 'undefined') {
|
|
393
403
|
throw new Error('Unsupported blocklet status');
|
|
394
404
|
}
|
|
395
|
-
|
|
396
|
-
|
|
397
|
-
if (
|
|
398
|
-
return
|
|
405
|
+
|
|
406
|
+
const doc = await this.getBlocklet(did);
|
|
407
|
+
if (doc.status === status && !children) {
|
|
408
|
+
return formatBlocklet(doc, 'onRead', this.options.dek);
|
|
399
409
|
}
|
|
410
|
+
|
|
400
411
|
const updates = { status, startedAt: undefined, stoppedAt: undefined };
|
|
401
412
|
if (status === BlockletStatus.running) {
|
|
402
413
|
updates.startedAt = new Date();
|
|
@@ -408,14 +419,30 @@ class BlockletState extends BaseState {
|
|
|
408
419
|
updates.stoppedAt = new Date();
|
|
409
420
|
}
|
|
410
421
|
|
|
411
|
-
|
|
412
|
-
|
|
422
|
+
// update children status
|
|
423
|
+
updates.children = doc.children.map((child) => {
|
|
424
|
+
if (children === 'all') {
|
|
425
|
+
child.status = status;
|
|
426
|
+
return child;
|
|
427
|
+
}
|
|
428
|
+
|
|
429
|
+
if (!children) {
|
|
430
|
+
if (![BlockletStatus.waiting, BlockletStatus.upgrading, BlockletStatus.installing].includes(status)) {
|
|
431
|
+
child.status = status;
|
|
432
|
+
}
|
|
433
|
+
|
|
434
|
+
return child;
|
|
435
|
+
}
|
|
436
|
+
|
|
437
|
+
const inputChild = children.find((x) => x.did === child.meta.did);
|
|
438
|
+
if (inputChild) {
|
|
439
|
+
child.status = status;
|
|
440
|
+
}
|
|
441
|
+
return child;
|
|
413
442
|
});
|
|
414
|
-
return res;
|
|
415
|
-
}
|
|
416
443
|
|
|
417
|
-
|
|
418
|
-
return
|
|
444
|
+
await this.update(doc._id, { $set: updates });
|
|
445
|
+
return formatBlocklet({ ...doc, ...updates }, 'onRead', this.options.dek);
|
|
419
446
|
}
|
|
420
447
|
|
|
421
448
|
async fillChildrenPorts(children, { defaultPort = 0, oldChildren } = {}) {
|
|
@@ -465,6 +492,48 @@ class BlockletState extends BaseState {
|
|
|
465
492
|
|
|
466
493
|
return children;
|
|
467
494
|
}
|
|
495
|
+
|
|
496
|
+
async addChildren(did, children) {
|
|
497
|
+
const parent = await this.getBlocklet(did);
|
|
498
|
+
if (!parent) {
|
|
499
|
+
throw new Error('Blocklet does not exist');
|
|
500
|
+
}
|
|
501
|
+
|
|
502
|
+
const oldChildren = parent.children || [];
|
|
503
|
+
|
|
504
|
+
const newChildren = [...oldChildren];
|
|
505
|
+
for (const child of children) {
|
|
506
|
+
const { meta, mountPoint, sourceUrl = '', source = '', deployedFrom = '' } = child;
|
|
507
|
+
|
|
508
|
+
if (!mountPoint) {
|
|
509
|
+
throw new Error(`mountPoint is required when adding component ${meta.title || meta.name}`);
|
|
510
|
+
}
|
|
511
|
+
|
|
512
|
+
if (meta.did === parent.meta.did) {
|
|
513
|
+
throw new Error('Cannot add self as a component');
|
|
514
|
+
}
|
|
515
|
+
|
|
516
|
+
checkDuplicateComponents([child], newChildren);
|
|
517
|
+
|
|
518
|
+
newChildren.push({
|
|
519
|
+
mountPoint,
|
|
520
|
+
meta,
|
|
521
|
+
sourceUrl,
|
|
522
|
+
source,
|
|
523
|
+
deployedFrom,
|
|
524
|
+
dynamic: true,
|
|
525
|
+
status: BlockletStatus.added,
|
|
526
|
+
});
|
|
527
|
+
}
|
|
528
|
+
|
|
529
|
+
// use upgradeBlocklet to assign ports to children and write new data to db
|
|
530
|
+
return this.upgradeBlocklet({
|
|
531
|
+
meta: parent.meta,
|
|
532
|
+
source: parent.source,
|
|
533
|
+
deployedFrom: parent.deployedFrom,
|
|
534
|
+
children: newChildren,
|
|
535
|
+
});
|
|
536
|
+
}
|
|
468
537
|
}
|
|
469
538
|
|
|
470
539
|
BlockletState.BlockletStatus = BlockletStatus;
|