@abtnode/core 1.7.6 → 1.7.9
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/team.js +14 -4
- package/lib/blocklet/manager/disk.js +116 -12
- package/lib/blocklet/migration.js +8 -0
- package/lib/event.js +10 -0
- package/lib/index.js +5 -0
- package/lib/migrations/1.0.21-update-config.js +1 -1
- package/lib/migrations/1.0.22-max-memory.js +1 -1
- package/lib/migrations/1.0.25.js +1 -1
- package/lib/migrations/1.0.32-update-config.js +1 -1
- package/lib/migrations/1.6.21-rename-ip-echo-domain.js +1 -1
- package/lib/migrations/1.6.4-security.js +1 -1
- package/lib/migrations/README.md +1 -1
- package/lib/router/helper.js +11 -90
- package/lib/states/blocklet.js +18 -1
- package/lib/team/manager.js +13 -0
- package/lib/util/blocklet.js +11 -6
- package/lib/util/get-domain-for-blocklet.js +1 -1
- package/package.json +23 -23
package/lib/api/team.js
CHANGED
|
@@ -104,6 +104,19 @@ class TeamAPI extends EventEmitter {
|
|
|
104
104
|
return state.getUser(user.did);
|
|
105
105
|
}
|
|
106
106
|
|
|
107
|
+
async getOwner({ teamDid }) {
|
|
108
|
+
const owner = await this.teamManager.getOwner(teamDid);
|
|
109
|
+
|
|
110
|
+
if (!owner) {
|
|
111
|
+
return null;
|
|
112
|
+
}
|
|
113
|
+
|
|
114
|
+
const state = await this.getUserState(teamDid);
|
|
115
|
+
|
|
116
|
+
const full = await state.getUser(owner.did);
|
|
117
|
+
return full || owner;
|
|
118
|
+
}
|
|
119
|
+
|
|
107
120
|
async updateUser({ teamDid, user }) {
|
|
108
121
|
const state = await this.getUserState(teamDid);
|
|
109
122
|
|
|
@@ -211,7 +224,7 @@ class TeamAPI extends EventEmitter {
|
|
|
211
224
|
|
|
212
225
|
// Invite member
|
|
213
226
|
|
|
214
|
-
async createInvitation({ teamDid, role, remark
|
|
227
|
+
async createInvitation({ teamDid, role, remark }, context) {
|
|
215
228
|
await this.teamManager.checkEnablePassportIssuance(teamDid);
|
|
216
229
|
|
|
217
230
|
if (!role) {
|
|
@@ -242,7 +255,6 @@ class TeamAPI extends EventEmitter {
|
|
|
242
255
|
expireDate,
|
|
243
256
|
inviter: user,
|
|
244
257
|
teamDid,
|
|
245
|
-
interfaceName,
|
|
246
258
|
});
|
|
247
259
|
|
|
248
260
|
logger.info('Create invite member', { role, user, inviteId });
|
|
@@ -254,7 +266,6 @@ class TeamAPI extends EventEmitter {
|
|
|
254
266
|
expireDate: new Date(expireDate).toString(),
|
|
255
267
|
inviter: user,
|
|
256
268
|
teamDid,
|
|
257
|
-
interfaceName,
|
|
258
269
|
};
|
|
259
270
|
}
|
|
260
271
|
|
|
@@ -271,7 +282,6 @@ class TeamAPI extends EventEmitter {
|
|
|
271
282
|
expireDate: new Date(d.expireDate).toString(),
|
|
272
283
|
inviter: d.inviter,
|
|
273
284
|
teamDid: d.teamDid,
|
|
274
|
-
interfaceName: d.interfaceName,
|
|
275
285
|
}));
|
|
276
286
|
}
|
|
277
287
|
|
|
@@ -15,7 +15,7 @@ const { isValid: isValidDid } = require('@arcblock/did');
|
|
|
15
15
|
const { verifyPresentation } = require('@arcblock/vc');
|
|
16
16
|
const { toBase58, isHex } = require('@ocap/util');
|
|
17
17
|
const { fromSecretKey } = require('@ocap/wallet');
|
|
18
|
-
const {
|
|
18
|
+
const { toSvg: createDidLogo } =
|
|
19
19
|
process.env.NODE_ENV !== 'test' ? require('@arcblock/did-motif') : require('@arcblock/did-motif/dist/did-motif.cjs');
|
|
20
20
|
|
|
21
21
|
const logger = require('@abtnode/logger')('@abtnode/core:blocklet:manager');
|
|
@@ -104,6 +104,7 @@ const blockletPm2Events = require('./pm2-events');
|
|
|
104
104
|
const { getFactoryState } = require('../../util/chain');
|
|
105
105
|
const runMigrationScripts = require('../migration');
|
|
106
106
|
const hooks = require('../hooks');
|
|
107
|
+
const { formatName } = require('../../util/get-domain-for-blocklet');
|
|
107
108
|
|
|
108
109
|
const {
|
|
109
110
|
isInProgress,
|
|
@@ -113,6 +114,7 @@ const {
|
|
|
113
114
|
shouldUpdateBlockletStatus,
|
|
114
115
|
getBlockletMeta,
|
|
115
116
|
validateBlockletMeta,
|
|
117
|
+
validateOwner,
|
|
116
118
|
} = util;
|
|
117
119
|
|
|
118
120
|
const preDownloadLock = new Lock('pre-download-lock');
|
|
@@ -255,7 +257,7 @@ class BlockletManager extends BaseBlockletManager {
|
|
|
255
257
|
}
|
|
256
258
|
|
|
257
259
|
const blocklet = await states.blocklet.getBlocklet(meta.did);
|
|
258
|
-
const isRunning = blocklet
|
|
260
|
+
const isRunning = blocklet ? blocklet.status === BlockletStatus.running : false;
|
|
259
261
|
|
|
260
262
|
return { meta, isFree, isInstalled: !!blocklet, isRunning };
|
|
261
263
|
}
|
|
@@ -279,9 +281,9 @@ class BlockletManager extends BaseBlockletManager {
|
|
|
279
281
|
return this._installFromStore({ did, registry }, { ...context, blockletPurchaseVerified: true });
|
|
280
282
|
}
|
|
281
283
|
|
|
282
|
-
async start({ did, checkHealthImmediately = false,
|
|
284
|
+
async start({ did, throwOnError, checkHealthImmediately = false, e2eMode = false }, context) {
|
|
283
285
|
logger.info('start blocklet', { did });
|
|
284
|
-
const blocklet = await this.ensureBlocklet(did);
|
|
286
|
+
const blocklet = await this.ensureBlocklet(did, e2eMode);
|
|
285
287
|
|
|
286
288
|
try {
|
|
287
289
|
if (!hasRunnableComponent(blocklet)) {
|
|
@@ -319,6 +321,7 @@ class BlockletManager extends BaseBlockletManager {
|
|
|
319
321
|
}),
|
|
320
322
|
nodeEnvironments,
|
|
321
323
|
nodeInfo: await states.node.read(),
|
|
324
|
+
e2eMode,
|
|
322
325
|
});
|
|
323
326
|
|
|
324
327
|
// check blocklet healthy
|
|
@@ -481,6 +484,40 @@ class BlockletManager extends BaseBlockletManager {
|
|
|
481
484
|
}
|
|
482
485
|
}
|
|
483
486
|
|
|
487
|
+
async reset({ did }, context = {}) {
|
|
488
|
+
logger.info('reset blocklet', { did });
|
|
489
|
+
|
|
490
|
+
const blocklet = await this.ensureBlocklet(did);
|
|
491
|
+
|
|
492
|
+
if (isInProgress(blocklet.status)) {
|
|
493
|
+
throw new Error('Cannot reset when blocklet is in progress');
|
|
494
|
+
}
|
|
495
|
+
|
|
496
|
+
try {
|
|
497
|
+
await this.deleteProcess({ did }, context);
|
|
498
|
+
} catch {
|
|
499
|
+
// do nothing
|
|
500
|
+
}
|
|
501
|
+
|
|
502
|
+
// Cleanup disk storage
|
|
503
|
+
const { name } = blocklet.meta;
|
|
504
|
+
const dataDir = path.join(this.dataDirs.data, name);
|
|
505
|
+
const logsDir = path.join(this.dataDirs.logs, name);
|
|
506
|
+
const cacheDir = path.join(this.dataDirs.cache, name);
|
|
507
|
+
fs.removeSync(cacheDir);
|
|
508
|
+
fs.removeSync(dataDir);
|
|
509
|
+
fs.removeSync(logsDir);
|
|
510
|
+
|
|
511
|
+
// Reset config in db
|
|
512
|
+
await this._delExtras(did);
|
|
513
|
+
await this._setConfigs(did);
|
|
514
|
+
await this.updateBlockletEnvironment(did);
|
|
515
|
+
await this.resetSiteByDid(did, context);
|
|
516
|
+
|
|
517
|
+
logger.info('blocklet reset', { did });
|
|
518
|
+
return blocklet;
|
|
519
|
+
}
|
|
520
|
+
|
|
484
521
|
async deleteComponent({ did, rootDid }, context) {
|
|
485
522
|
logger.info('delete blocklet component', { did, rootDid });
|
|
486
523
|
|
|
@@ -928,14 +965,22 @@ class BlockletManager extends BaseBlockletManager {
|
|
|
928
965
|
* After the dev function finished, the caller should send a BlockletEvents.deployed event to the daemon
|
|
929
966
|
* @returns {Object} blocklet
|
|
930
967
|
*/
|
|
931
|
-
async dev(folder) {
|
|
932
|
-
logger.info('dev
|
|
968
|
+
async dev(folder, { rootDid, mountPoint } = {}) {
|
|
969
|
+
logger.info('dev component', { folder, rootDid, mountPoint });
|
|
933
970
|
|
|
934
971
|
const meta = getBlockletMeta(folder);
|
|
935
972
|
if (meta.group !== 'static' && (!meta.scripts || !meta.scripts.dev)) {
|
|
936
973
|
throw new Error('Incorrect blocklet manifest: missing `scripts.dev` field');
|
|
937
974
|
}
|
|
938
975
|
|
|
976
|
+
if (rootDid) {
|
|
977
|
+
return this._devComponent({ folder, meta, rootDid, mountPoint });
|
|
978
|
+
}
|
|
979
|
+
|
|
980
|
+
return this._devBlocklet({ folder, meta });
|
|
981
|
+
}
|
|
982
|
+
|
|
983
|
+
async _devBlocklet({ folder, meta }) {
|
|
939
984
|
const { did, version } = meta;
|
|
940
985
|
|
|
941
986
|
const exist = await states.blocklet.getBlocklet(did);
|
|
@@ -985,10 +1030,63 @@ class BlockletManager extends BaseBlockletManager {
|
|
|
985
1030
|
|
|
986
1031
|
const blocklet = await this.ensureBlocklet(did);
|
|
987
1032
|
|
|
1033
|
+
await fs.writeFile(path.join(blocklet.env.dataDir, 'logo.svg'), createDidLogo(blocklet.meta.did));
|
|
1034
|
+
|
|
988
1035
|
return blocklet;
|
|
989
1036
|
}
|
|
990
1037
|
|
|
991
|
-
async
|
|
1038
|
+
async _devComponent({ folder, meta, rootDid, mountPoint }) {
|
|
1039
|
+
const { did, version } = meta;
|
|
1040
|
+
|
|
1041
|
+
const existRoot = await states.blocklet.getBlocklet(rootDid);
|
|
1042
|
+
if (!existRoot) {
|
|
1043
|
+
throw new Error('Root blocklet does not exist');
|
|
1044
|
+
}
|
|
1045
|
+
|
|
1046
|
+
const exist = existRoot.children.find((x) => x.meta.did === meta.did);
|
|
1047
|
+
if (exist) {
|
|
1048
|
+
if (exist.mode === BLOCKLET_MODES.PRODUCTION) {
|
|
1049
|
+
throw new Error('The blocklet component of production mode already exists, please remove it before developing');
|
|
1050
|
+
}
|
|
1051
|
+
|
|
1052
|
+
const status = fromBlockletStatus(exist.status);
|
|
1053
|
+
if (['starting', 'running'].includes(status)) {
|
|
1054
|
+
throw new Error(`The blocklet component is already on ${status}, please stop it before developing`);
|
|
1055
|
+
}
|
|
1056
|
+
|
|
1057
|
+
logger.info('remove blocklet component for dev', { did, version });
|
|
1058
|
+
|
|
1059
|
+
await this.deleteComponent({ did, rootDid });
|
|
1060
|
+
}
|
|
1061
|
+
|
|
1062
|
+
const defaultPath = formatName(meta.name);
|
|
1063
|
+
const children = await parseChildren(existRoot.meta, {
|
|
1064
|
+
children: [
|
|
1065
|
+
{
|
|
1066
|
+
meta,
|
|
1067
|
+
mountPoint: mountPoint || `/${defaultPath}`,
|
|
1068
|
+
source: BlockletSource.local,
|
|
1069
|
+
deployedFrom: folder,
|
|
1070
|
+
status: BlockletStatus.installed,
|
|
1071
|
+
mode: BLOCKLET_MODES.DEVELOPMENT,
|
|
1072
|
+
},
|
|
1073
|
+
],
|
|
1074
|
+
dynamic: true,
|
|
1075
|
+
});
|
|
1076
|
+
await states.blocklet.addChildren(rootDid, children);
|
|
1077
|
+
|
|
1078
|
+
logger.info('add blocklet component for dev', { did, version, meta });
|
|
1079
|
+
|
|
1080
|
+
// Add environments
|
|
1081
|
+
await this._setConfigs(rootDid);
|
|
1082
|
+
await this.updateBlockletEnvironment(rootDid);
|
|
1083
|
+
|
|
1084
|
+
const rootBlocklet = await this.ensureBlocklet(rootDid);
|
|
1085
|
+
|
|
1086
|
+
return rootBlocklet;
|
|
1087
|
+
}
|
|
1088
|
+
|
|
1089
|
+
async ensureBlocklet(did, e2eMode = false) {
|
|
992
1090
|
if (!isValidDid(did)) {
|
|
993
1091
|
throw new Error(`Blocklet did is invalid: ${did}`);
|
|
994
1092
|
}
|
|
@@ -1006,6 +1104,7 @@ class BlockletManager extends BaseBlockletManager {
|
|
|
1006
1104
|
...getBlockletDirs(blocklet, {
|
|
1007
1105
|
dataDirs: this.dataDirs,
|
|
1008
1106
|
ensure: true,
|
|
1107
|
+
e2eMode,
|
|
1009
1108
|
}),
|
|
1010
1109
|
};
|
|
1011
1110
|
|
|
@@ -1049,9 +1148,14 @@ class BlockletManager extends BaseBlockletManager {
|
|
|
1049
1148
|
return blocklet;
|
|
1050
1149
|
}
|
|
1051
1150
|
|
|
1052
|
-
async setInitialized({ did }) {
|
|
1151
|
+
async setInitialized({ did, owner }) {
|
|
1152
|
+
if (!validateOwner(owner)) {
|
|
1153
|
+
throw new Error('Blocklet owner is invalid');
|
|
1154
|
+
}
|
|
1155
|
+
|
|
1053
1156
|
const blocklet = await states.blocklet.getBlocklet(did);
|
|
1054
|
-
await states.blockletExtras.setSettings(blocklet.meta.did, { initialized: true });
|
|
1157
|
+
await states.blockletExtras.setSettings(blocklet.meta.did, { initialized: true, owner });
|
|
1158
|
+
logger.info('Blocklet initialized', { did, owner });
|
|
1055
1159
|
|
|
1056
1160
|
this.emit(BlockletEvents.updated, { meta: { did: blocklet.meta.did } });
|
|
1057
1161
|
|
|
@@ -1734,7 +1838,7 @@ class BlockletManager extends BaseBlockletManager {
|
|
|
1734
1838
|
meta,
|
|
1735
1839
|
mountPoint,
|
|
1736
1840
|
source: BlockletSource.upload,
|
|
1737
|
-
deployedFrom: `Upload by ${context.user.
|
|
1841
|
+
deployedFrom: `Upload by ${context.user.fullName}`,
|
|
1738
1842
|
sourceUrl: '',
|
|
1739
1843
|
dynamic: true,
|
|
1740
1844
|
};
|
|
@@ -2216,7 +2320,7 @@ class BlockletManager extends BaseBlockletManager {
|
|
|
2216
2320
|
blocklet = await this.ensureBlocklet(did);
|
|
2217
2321
|
logger.info('blocklet installed', { source, did: meta.did });
|
|
2218
2322
|
|
|
2219
|
-
await fs.writeFile(path.join(blocklet.env.dataDir, 'logo.
|
|
2323
|
+
await fs.writeFile(path.join(blocklet.env.dataDir, 'logo.svg'), createDidLogo(blocklet.meta.did));
|
|
2220
2324
|
|
|
2221
2325
|
this.emit(BlockletEvents.installed, { blocklet, context });
|
|
2222
2326
|
|
|
@@ -2344,7 +2448,7 @@ class BlockletManager extends BaseBlockletManager {
|
|
|
2344
2448
|
|
|
2345
2449
|
blocklet = await this.ensureBlocklet(did, context);
|
|
2346
2450
|
|
|
2347
|
-
await fs.writeFile(path.join(blocklet.env.dataDir, 'logo.
|
|
2451
|
+
await fs.writeFile(path.join(blocklet.env.dataDir, 'logo.svg'), createDidLogo(blocklet.meta.did));
|
|
2348
2452
|
|
|
2349
2453
|
this.refreshListCache();
|
|
2350
2454
|
|
|
@@ -21,6 +21,7 @@ async function runScripts({
|
|
|
21
21
|
printSuccess,
|
|
22
22
|
printError,
|
|
23
23
|
}) {
|
|
24
|
+
// 获取所有待执行的脚本
|
|
24
25
|
let scripts = [];
|
|
25
26
|
try {
|
|
26
27
|
scripts = await getScripts(scriptsDir);
|
|
@@ -37,13 +38,17 @@ async function runScripts({
|
|
|
37
38
|
}
|
|
38
39
|
|
|
39
40
|
printInfo('pending scripts', pendingScripts);
|
|
41
|
+
// 执行脚本前需要对数据库文件做一次备份
|
|
40
42
|
try {
|
|
41
43
|
await doBackup({ dbDir, backupDir, printInfo, printSuccess, printError });
|
|
42
44
|
} catch (err) {
|
|
43
45
|
printError(`Failed to backup state db due to ${err.message}, abort!`);
|
|
46
|
+
// 备份失败时,需要移除备份目录
|
|
47
|
+
fs.removeSync(backupDir);
|
|
44
48
|
throw err;
|
|
45
49
|
}
|
|
46
50
|
|
|
51
|
+
// 按照顺序依次执行 migration 脚本
|
|
47
52
|
for (let i = 0; i < pendingScripts.length; i++) {
|
|
48
53
|
const { script: scriptPath } = pendingScripts[i];
|
|
49
54
|
try {
|
|
@@ -59,7 +64,10 @@ async function runScripts({
|
|
|
59
64
|
|
|
60
65
|
try {
|
|
61
66
|
await doRestore({ dbDir, backupDir, printInfo, printSuccess, printError });
|
|
67
|
+
// 恢复备份成功时,需要移除备份目录
|
|
68
|
+
fs.removeSync(backupDir);
|
|
62
69
|
} catch (restoreErr) {
|
|
70
|
+
// 如果恢复备份失败,则保留备份目录,恢复数据
|
|
63
71
|
printError(`Failed to restore state db due to: ${restoreErr.message}`);
|
|
64
72
|
}
|
|
65
73
|
|
package/lib/event.js
CHANGED
|
@@ -30,6 +30,8 @@ module.exports = ({
|
|
|
30
30
|
const nodeState = states.node;
|
|
31
31
|
|
|
32
32
|
const events = new EventEmitter();
|
|
33
|
+
events.setMaxListeners(0);
|
|
34
|
+
|
|
33
35
|
// HACK: do not emit any events from CLI
|
|
34
36
|
if (isCLI() && process.env.NODE_ENV !== 'test') {
|
|
35
37
|
events.emit = (name) => logger.debug('stopped core state event in CLI', name);
|
|
@@ -123,6 +125,14 @@ module.exports = ({
|
|
|
123
125
|
await teamAPI.refreshBlockletInterfacePermissions(blocklet.meta);
|
|
124
126
|
} catch (error) {
|
|
125
127
|
logger.error('upgrade blocklet routing rules error', { event: name, error });
|
|
128
|
+
notificationState.create({
|
|
129
|
+
title: 'Blocklet URL Mapping Error',
|
|
130
|
+
// eslint-disable-next-line max-len
|
|
131
|
+
description: `Failed to upgrade URL mapping for blocklet ${blocklet.meta.name}@${blocklet.meta.version}, due to: ${error.message}`,
|
|
132
|
+
entityType: 'blocklet',
|
|
133
|
+
entityId: blocklet.meta.did,
|
|
134
|
+
severity: 'error',
|
|
135
|
+
});
|
|
126
136
|
}
|
|
127
137
|
|
|
128
138
|
try {
|
package/lib/index.js
CHANGED
|
@@ -133,11 +133,13 @@ function ABTNode(options) {
|
|
|
133
133
|
registry: blockletRegistry,
|
|
134
134
|
daemon: options.daemon,
|
|
135
135
|
});
|
|
136
|
+
blockletManager.setMaxListeners(0);
|
|
136
137
|
|
|
137
138
|
const {
|
|
138
139
|
handleRouting,
|
|
139
140
|
getRoutingRulesByDid,
|
|
140
141
|
getSiteByDid,
|
|
142
|
+
resetSiteByDid,
|
|
141
143
|
updateNodeRouting,
|
|
142
144
|
takeRoutingSnapshot,
|
|
143
145
|
getRoutingSites,
|
|
@@ -159,6 +161,7 @@ function ABTNode(options) {
|
|
|
159
161
|
|
|
160
162
|
blockletManager.getRoutingRulesByDid = getRoutingRulesByDid;
|
|
161
163
|
blockletManager.getSiteByDid = getSiteByDid;
|
|
164
|
+
blockletManager.resetSiteByDid = resetSiteByDid;
|
|
162
165
|
|
|
163
166
|
// Generate an on node ready callback
|
|
164
167
|
const onStatesReady = createStateReadyQueue({ states, options, dataDirs });
|
|
@@ -216,6 +219,7 @@ function ABTNode(options) {
|
|
|
216
219
|
updateChildBlocklets: blockletManager.updateChildren.bind(blockletManager),
|
|
217
220
|
getLatestBlockletVersion: blockletManager.getLatestBlockletVersion.bind(blockletManager),
|
|
218
221
|
getBlockletMetaFromUrl: blockletManager.getMetaFromUrl.bind(blockletManager),
|
|
222
|
+
resetBlocklet: blockletManager.reset.bind(blockletManager),
|
|
219
223
|
|
|
220
224
|
deleteBlockletProcess: blockletManager.deleteProcess.bind(blockletManager),
|
|
221
225
|
|
|
@@ -261,6 +265,7 @@ function ABTNode(options) {
|
|
|
261
265
|
getUsers: teamAPI.getUsers.bind(teamAPI),
|
|
262
266
|
getUsersCount: teamAPI.getUsersCount.bind(teamAPI),
|
|
263
267
|
getUser: teamAPI.getUser.bind(teamAPI),
|
|
268
|
+
getOwner: teamAPI.getOwner.bind(teamAPI),
|
|
264
269
|
getNodeUsers: () => teamAPI.getUsers({ teamDid: options.nodeDid }),
|
|
265
270
|
getNodeUser: (user) => teamAPI.getUser({ teamDid: options.nodeDid, user }),
|
|
266
271
|
addUser: teamAPI.addUser.bind(teamAPI),
|
|
@@ -7,7 +7,7 @@ module.exports = async ({ states, config, configFile, printInfo }) => {
|
|
|
7
7
|
printInfo('Try to update node config to 1.0.21...');
|
|
8
8
|
let changed = false;
|
|
9
9
|
|
|
10
|
-
const rawConfig = yaml.
|
|
10
|
+
const rawConfig = yaml.load(fs.readFileSync(configFile).toString());
|
|
11
11
|
const info = await states.node.read();
|
|
12
12
|
|
|
13
13
|
const updates = [
|
|
@@ -13,7 +13,7 @@ module.exports = async ({ states, config, configFile, printInfo }) => {
|
|
|
13
13
|
printInfo('Try to update node config to 1.0.22...');
|
|
14
14
|
let changed = false;
|
|
15
15
|
|
|
16
|
-
const rawConfig = yaml.
|
|
16
|
+
const rawConfig = yaml.load(fs.readFileSync(configFile).toString());
|
|
17
17
|
const info = await states.node.read();
|
|
18
18
|
|
|
19
19
|
const updates = [
|
package/lib/migrations/1.0.25.js
CHANGED
|
@@ -10,7 +10,7 @@ module.exports = async ({ states, config, configFile, printInfo }) => {
|
|
|
10
10
|
printInfo('Try to update node config to 1.0.25...');
|
|
11
11
|
let changed = false;
|
|
12
12
|
|
|
13
|
-
const rawConfig = yaml.
|
|
13
|
+
const rawConfig = yaml.load(fs.readFileSync(configFile).toString());
|
|
14
14
|
const info = await states.node.read();
|
|
15
15
|
|
|
16
16
|
const updates = [
|
|
@@ -7,7 +7,7 @@ module.exports = async ({ states, config, configFile, printInfo }) => {
|
|
|
7
7
|
printInfo('Try to update node config to 1.0.32...');
|
|
8
8
|
let changed = false;
|
|
9
9
|
|
|
10
|
-
const rawConfig = yaml.
|
|
10
|
+
const rawConfig = yaml.load(fs.readFileSync(configFile).toString());
|
|
11
11
|
const info = await states.node.read();
|
|
12
12
|
|
|
13
13
|
const updates = [{ key: 'routing.https', value: true }];
|
|
@@ -22,7 +22,7 @@ module.exports = async ({ states, printInfo, configFile }) => {
|
|
|
22
22
|
await states.node.updateNodeInfo(info);
|
|
23
23
|
|
|
24
24
|
if (process.env.NODE_ENV !== 'development') {
|
|
25
|
-
let rawConfig = yaml.
|
|
25
|
+
let rawConfig = yaml.load(fs.readFileSync(configFile).toString());
|
|
26
26
|
set(rawConfig, 'node.routing.ipWildcardDomain', info.routing.ipWildcardDomain);
|
|
27
27
|
set(rawConfig, 'node.routing.wildcardCertHost', DEFAULT_WILDCARD_CERT_HOST);
|
|
28
28
|
set(rawConfig, 'node.didDomain', DEFAULT_DID_DOMAIN);
|
|
@@ -19,7 +19,7 @@ module.exports = async ({ states, configFile, dataDir }) => {
|
|
|
19
19
|
try {
|
|
20
20
|
fs.writeFileSync(file, crypto.randomBytes(32), { encoding: 'binary', mode: '0600' });
|
|
21
21
|
|
|
22
|
-
const config = yaml.
|
|
22
|
+
const config = yaml.load(fs.readFileSync(configFile).toString(), { json: true });
|
|
23
23
|
config.node.sk = security.encrypt(config.node.sk, config.node.did, fs.readFileSync(file));
|
|
24
24
|
fs.writeFileSync(configFile, yaml.dump(config));
|
|
25
25
|
await states.node.updateNodeInfo({ sk: config.node.sk });
|
package/lib/migrations/README.md
CHANGED
|
@@ -41,7 +41,7 @@ module.exports = async ({ states, config, configFile, printInfo }) => {
|
|
|
41
41
|
printInfo('Try to update node config to 1.0.21...');
|
|
42
42
|
let changed = false;
|
|
43
43
|
|
|
44
|
-
const rawConfig = yaml.
|
|
44
|
+
const rawConfig = yaml.load(fs.readFileSync(configFile).toString());
|
|
45
45
|
const info = await states.node.read();
|
|
46
46
|
|
|
47
47
|
const updates = [
|
package/lib/router/helper.js
CHANGED
|
@@ -863,88 +863,6 @@ module.exports = function getRouterHelpers({ dataDirs, routingSnapshot, routerMa
|
|
|
863
863
|
return changes.some(Boolean);
|
|
864
864
|
};
|
|
865
865
|
|
|
866
|
-
/**
|
|
867
|
-
* Add system routing rules for blocklet in dashboard site
|
|
868
|
-
*
|
|
869
|
-
* @returns {boolean} if routing changed
|
|
870
|
-
* TODO: do we still need this?
|
|
871
|
-
*/
|
|
872
|
-
const _ensureBlockletRulesForDashboardSite = async (blocklet, sites, nodeInfo, context = {}) => {
|
|
873
|
-
// blocklet level duplication detection
|
|
874
|
-
const findRulesByInterface = (site, value) =>
|
|
875
|
-
site.rules.filter((x) => x.isProtected && x.to.did === blocklet.meta.did && get(x, 'to.interfaceName') === value);
|
|
876
|
-
|
|
877
|
-
const ipSite = sites.find((x) => x.domain === DOMAIN_FOR_IP_SITE);
|
|
878
|
-
if (!ipSite) {
|
|
879
|
-
logger.warn(`Routing rule for dashboard not found, abort on ensure rules for blocklet ${blocklet.meta.did}`);
|
|
880
|
-
return false;
|
|
881
|
-
}
|
|
882
|
-
|
|
883
|
-
// If we have rule for legacy path prefix, just return
|
|
884
|
-
const pathPrefixLegacy = normalizePathPrefix(`/${nodeInfo.routing.adminPath}/${blocklet.meta.name}`);
|
|
885
|
-
if (hasRuleByPrefix(ipSite, pathPrefixLegacy)) {
|
|
886
|
-
return false;
|
|
887
|
-
}
|
|
888
|
-
|
|
889
|
-
const removedRuleIds = [];
|
|
890
|
-
const changes = await Promise.all(
|
|
891
|
-
blocklet.meta.interfaces.map(async (x) => {
|
|
892
|
-
let changed = false; // if state db was mutated
|
|
893
|
-
let pathPrefix = '';
|
|
894
|
-
if (x.prefix === BLOCKLET_DYNAMIC_PATH_PREFIX) {
|
|
895
|
-
// pathPrefix for dynamic path: `/{adminPath}/{blockletName}/{interfaceName}`
|
|
896
|
-
pathPrefix = normalizePathPrefix(`/${pathPrefixLegacy}/${x.name}`);
|
|
897
|
-
} else {
|
|
898
|
-
// pathPrefix for fixed path: `/{interfacePrefix}`
|
|
899
|
-
pathPrefix = normalizePathPrefix(x.prefix);
|
|
900
|
-
}
|
|
901
|
-
|
|
902
|
-
// Remove if we have rule with same interface
|
|
903
|
-
const exists = findRulesByInterface(ipSite, x.name);
|
|
904
|
-
if (exists.length) {
|
|
905
|
-
// Note: we need to keep a list of removed rules since we might remove multiple rules in the loop
|
|
906
|
-
exists.forEach((e) => removedRuleIds.push(e.id));
|
|
907
|
-
await states.site.update(
|
|
908
|
-
{ _id: ipSite.id },
|
|
909
|
-
{ $set: { rules: ipSite.rules.filter((r) => removedRuleIds.includes(r.id) === false) } }
|
|
910
|
-
);
|
|
911
|
-
changed = true;
|
|
912
|
-
} else if (hasRuleByPrefix(ipSite, pathPrefix)) {
|
|
913
|
-
// Skip same pathPrefix rules
|
|
914
|
-
return changed;
|
|
915
|
-
}
|
|
916
|
-
|
|
917
|
-
// 不在 dashboard site 中添加 path 和 prefix 都是根路径(/) 的路由
|
|
918
|
-
if (x.path === '/' && x.prefix === '/') {
|
|
919
|
-
return changed;
|
|
920
|
-
}
|
|
921
|
-
|
|
922
|
-
await routerManager.addRoutingRule(
|
|
923
|
-
{
|
|
924
|
-
id: ipSite.id,
|
|
925
|
-
rule: {
|
|
926
|
-
from: { pathPrefix },
|
|
927
|
-
to: {
|
|
928
|
-
type: ROUTING_RULE_TYPES.BLOCKLET,
|
|
929
|
-
port: findInterfacePortByName(blocklet, x.name),
|
|
930
|
-
did: blocklet.meta.did, // root blocklet did
|
|
931
|
-
interfaceName: x.name, // root blocklet interface
|
|
932
|
-
},
|
|
933
|
-
isProtected: true,
|
|
934
|
-
},
|
|
935
|
-
skipCheckDynamicBlacklist: true,
|
|
936
|
-
},
|
|
937
|
-
context
|
|
938
|
-
);
|
|
939
|
-
changed = true;
|
|
940
|
-
|
|
941
|
-
return changed;
|
|
942
|
-
})
|
|
943
|
-
);
|
|
944
|
-
|
|
945
|
-
return changes.some(Boolean);
|
|
946
|
-
};
|
|
947
|
-
|
|
948
866
|
const _removeBlockletSites = async (blocklet, nodeInfo, context = {}) => {
|
|
949
867
|
let changed = false;
|
|
950
868
|
|
|
@@ -980,14 +898,6 @@ module.exports = function getRouterHelpers({ dataDirs, routingSnapshot, routerMa
|
|
|
980
898
|
_ensureBlockletSites(blocklet, sites, nodeInfo, context),
|
|
981
899
|
];
|
|
982
900
|
|
|
983
|
-
if (nodeInfo.mode === NODE_MODES.DEBUG || ['e2e', 'test'].includes(process.env.NODE_ENV)) {
|
|
984
|
-
logger.info('Add blocklet endpoint in dashboard site', {
|
|
985
|
-
nodeMode: nodeInfo.mode,
|
|
986
|
-
NODE_ENV: process.env.NODE_ENV,
|
|
987
|
-
});
|
|
988
|
-
tasks.push(_ensureBlockletRulesForDashboardSite(blocklet, sites, nodeInfo, context));
|
|
989
|
-
}
|
|
990
|
-
|
|
991
901
|
const changes = await Promise.all(tasks);
|
|
992
902
|
|
|
993
903
|
return changes.some(Boolean);
|
|
@@ -1131,6 +1041,16 @@ module.exports = function getRouterHelpers({ dataDirs, routingSnapshot, routerMa
|
|
|
1131
1041
|
return (sites || []).find((x) => x.domain === domain);
|
|
1132
1042
|
}
|
|
1133
1043
|
|
|
1044
|
+
async function resetSiteByDid(did, { refreshRouterProvider = true } = {}) {
|
|
1045
|
+
const blocklet = await states.blocklet.getBlocklet(did);
|
|
1046
|
+
await removeBlockletRouting(blocklet);
|
|
1047
|
+
await ensureBlockletRouting(blocklet);
|
|
1048
|
+
if (refreshRouterProvider) {
|
|
1049
|
+
const hash = await takeRoutingSnapshot({ message: `Reset blocklet ${did}`, dryRun: false });
|
|
1050
|
+
logger.info('reset blocklet routing rules', { did, hash });
|
|
1051
|
+
}
|
|
1052
|
+
}
|
|
1053
|
+
|
|
1134
1054
|
const providers = {}; // we need to keep reference for different router instances
|
|
1135
1055
|
const handleRouting = async (nodeInfo) => {
|
|
1136
1056
|
const providerName = get(nodeInfo, 'routing.provider', null);
|
|
@@ -1382,6 +1302,7 @@ module.exports = function getRouterHelpers({ dataDirs, routingSnapshot, routerMa
|
|
|
1382
1302
|
handleRouting,
|
|
1383
1303
|
getRoutingRulesByDid,
|
|
1384
1304
|
getSiteByDid,
|
|
1305
|
+
resetSiteByDid,
|
|
1385
1306
|
updateNodeRouting,
|
|
1386
1307
|
takeRoutingSnapshot,
|
|
1387
1308
|
getRoutingSites,
|
package/lib/states/blocklet.js
CHANGED
|
@@ -66,6 +66,16 @@ const formatBlocklet = (blocklet, phase, dek) => {
|
|
|
66
66
|
return blocklet;
|
|
67
67
|
};
|
|
68
68
|
|
|
69
|
+
const fixChildren = (children) => {
|
|
70
|
+
if (!children) {
|
|
71
|
+
return;
|
|
72
|
+
}
|
|
73
|
+
|
|
74
|
+
children.forEach((child) => {
|
|
75
|
+
child.mode = child.mode || BLOCKLET_MODES.PRODUCTION;
|
|
76
|
+
});
|
|
77
|
+
};
|
|
78
|
+
|
|
69
79
|
class BlockletState extends BaseState {
|
|
70
80
|
/**
|
|
71
81
|
* Creates an instance of BlockletState
|
|
@@ -163,6 +173,8 @@ class BlockletState extends BaseState {
|
|
|
163
173
|
defaultPort: getMaxPort(ports),
|
|
164
174
|
});
|
|
165
175
|
|
|
176
|
+
fixChildren(children);
|
|
177
|
+
|
|
166
178
|
// add to db
|
|
167
179
|
this.db.insert(
|
|
168
180
|
{
|
|
@@ -244,6 +256,8 @@ class BlockletState extends BaseState {
|
|
|
244
256
|
logger.info('Fill children ports when when upgrading blocklet', { name: doc.meta.name, did: doc.meta.did });
|
|
245
257
|
await this.fillChildrenPorts(children, { oldChildren: doc.children, defaultPort: getMaxPort(ports) });
|
|
246
258
|
|
|
259
|
+
fixChildren(children);
|
|
260
|
+
|
|
247
261
|
// add to db
|
|
248
262
|
const newDoc = await this.updateBlocklet(meta.did, {
|
|
249
263
|
meta: omit(sanitized, ['htmlAst']),
|
|
@@ -506,7 +520,7 @@ class BlockletState extends BaseState {
|
|
|
506
520
|
|
|
507
521
|
const newChildren = [...oldChildren];
|
|
508
522
|
for (const child of children) {
|
|
509
|
-
const { meta, mountPoint, sourceUrl = '', source = '', deployedFrom = '' } = child;
|
|
523
|
+
const { meta, mountPoint, sourceUrl = '', source = '', deployedFrom = '', mode } = child;
|
|
510
524
|
|
|
511
525
|
if (!mountPoint) {
|
|
512
526
|
throw new Error(`mountPoint is required when adding component ${getDisplayName(child, true)}`);
|
|
@@ -524,9 +538,12 @@ class BlockletState extends BaseState {
|
|
|
524
538
|
sourceUrl,
|
|
525
539
|
source,
|
|
526
540
|
deployedFrom,
|
|
541
|
+
mode,
|
|
527
542
|
dynamic: true,
|
|
528
543
|
status: BlockletStatus.added,
|
|
529
544
|
});
|
|
545
|
+
|
|
546
|
+
fixChildren(newChildren);
|
|
530
547
|
}
|
|
531
548
|
|
|
532
549
|
// use upgradeBlocklet to assign ports to children and write new data to db
|
package/lib/team/manager.js
CHANGED
|
@@ -267,6 +267,19 @@ class TeamManager extends EventEmitter {
|
|
|
267
267
|
}
|
|
268
268
|
}
|
|
269
269
|
|
|
270
|
+
async getOwner(did) {
|
|
271
|
+
let owner;
|
|
272
|
+
if (this.isNodeTeam(did)) {
|
|
273
|
+
const nodeInfo = await this.states.node.read();
|
|
274
|
+
owner = get(nodeInfo, 'nodeOwner');
|
|
275
|
+
} else {
|
|
276
|
+
const settings = await this.states.blockletExtras.getSettings(did);
|
|
277
|
+
owner = get(settings, 'owner');
|
|
278
|
+
}
|
|
279
|
+
|
|
280
|
+
return owner;
|
|
281
|
+
}
|
|
282
|
+
|
|
270
283
|
// =======
|
|
271
284
|
// Private
|
|
272
285
|
// =======
|
package/lib/util/blocklet.js
CHANGED
|
@@ -104,7 +104,7 @@ const PRIVATE_NODE_ENVS = [
|
|
|
104
104
|
* appMain: app entry file or script (run appMain to start blocklet process)
|
|
105
105
|
* appCwd: cwd of appMain
|
|
106
106
|
*/
|
|
107
|
-
const getBlockletDirs = (blocklet, { rootBlocklet, dataDirs, ensure = false } = {}) => {
|
|
107
|
+
const getBlockletDirs = (blocklet, { rootBlocklet, dataDirs, ensure = false, e2eMode = false } = {}) => {
|
|
108
108
|
if (!rootBlocklet) {
|
|
109
109
|
// eslint-disable-next-line no-param-reassign
|
|
110
110
|
rootBlocklet = blocklet;
|
|
@@ -126,8 +126,13 @@ const getBlockletDirs = (blocklet, { rootBlocklet, dataDirs, ensure = false } =
|
|
|
126
126
|
|
|
127
127
|
const { main, group } = blocklet.meta;
|
|
128
128
|
|
|
129
|
-
|
|
130
|
-
|
|
129
|
+
let startFromDevEntry = '';
|
|
130
|
+
if (blocklet.mode === BLOCKLET_MODES.DEVELOPMENT && blocklet.meta.scripts) {
|
|
131
|
+
startFromDevEntry = blocklet.meta.scripts.dev;
|
|
132
|
+
if (e2eMode && blocklet.meta.scripts.e2eDev) {
|
|
133
|
+
startFromDevEntry = blocklet.meta.scripts.e2eDev;
|
|
134
|
+
}
|
|
135
|
+
}
|
|
131
136
|
|
|
132
137
|
if (!main && !startFromDevEntry && group !== BlockletGroup.gateway) {
|
|
133
138
|
throw new Error('Incorrect blocklet manifest: missing `main` field');
|
|
@@ -174,7 +179,7 @@ const getBlockletDirs = (blocklet, { rootBlocklet, dataDirs, ensure = false } =
|
|
|
174
179
|
let appMain = null;
|
|
175
180
|
let appCwd = null;
|
|
176
181
|
if (startFromDevEntry) {
|
|
177
|
-
appMain =
|
|
182
|
+
appMain = startFromDevEntry;
|
|
178
183
|
appCwd = appDir;
|
|
179
184
|
} else if (group === 'dapp') {
|
|
180
185
|
appMain = getBlockletEngine(blocklet.meta).script || BLOCKLET_ENTRY_FILE;
|
|
@@ -414,7 +419,7 @@ const getBlockletMetaFromUrl = async (url) => {
|
|
|
414
419
|
* Start all precesses of a blocklet
|
|
415
420
|
* @param {*} blocklet should contain env props
|
|
416
421
|
*/
|
|
417
|
-
const startBlockletProcess = async (blocklet, { preStart = noop, nodeEnvironments, nodeInfo } = {}) => {
|
|
422
|
+
const startBlockletProcess = async (blocklet, { preStart = noop, nodeEnvironments, nodeInfo, e2eMode } = {}) => {
|
|
418
423
|
if (!blocklet) {
|
|
419
424
|
throw new Error('blocklet should not be empty');
|
|
420
425
|
}
|
|
@@ -463,7 +468,7 @@ const startBlockletProcess = async (blocklet, { preStart = noop, nodeEnvironment
|
|
|
463
468
|
}
|
|
464
469
|
|
|
465
470
|
if (b.mode === BLOCKLET_MODES.DEVELOPMENT) {
|
|
466
|
-
options.env.NODE_ENV = 'development';
|
|
471
|
+
options.env.NODE_ENV = e2eMode ? 'e2e' : 'development';
|
|
467
472
|
options.env.BROWSER = 'none';
|
|
468
473
|
options.env.PORT = options.env[BLOCKLET_DEFAULT_PORT_NAME];
|
|
469
474
|
options.script = appMain;
|
|
@@ -23,4 +23,4 @@ const getDidDomainForBlocklet = ({ name, daemonDid, didDomain }) => {
|
|
|
23
23
|
return `${prefix}-${daemonDid.toLowerCase()}.${didDomain}`;
|
|
24
24
|
};
|
|
25
25
|
|
|
26
|
-
module.exports = { getIpDnsDomainForBlocklet, getDidDomainForBlocklet };
|
|
26
|
+
module.exports = { getIpDnsDomainForBlocklet, getDidDomainForBlocklet, formatName };
|
package/package.json
CHANGED
|
@@ -3,7 +3,7 @@
|
|
|
3
3
|
"publishConfig": {
|
|
4
4
|
"access": "public"
|
|
5
5
|
},
|
|
6
|
-
"version": "1.7.
|
|
6
|
+
"version": "1.7.9",
|
|
7
7
|
"description": "",
|
|
8
8
|
"main": "lib/index.js",
|
|
9
9
|
"files": [
|
|
@@ -19,32 +19,32 @@
|
|
|
19
19
|
"author": "wangshijun <wangshijun2010@gmail.com> (http://github.com/wangshijun)",
|
|
20
20
|
"license": "MIT",
|
|
21
21
|
"dependencies": {
|
|
22
|
-
"@abtnode/certificate-manager": "1.7.
|
|
23
|
-
"@abtnode/constant": "1.7.
|
|
24
|
-
"@abtnode/cron": "1.7.
|
|
25
|
-
"@abtnode/db": "1.7.
|
|
26
|
-
"@abtnode/logger": "1.7.
|
|
27
|
-
"@abtnode/queue": "1.7.
|
|
28
|
-
"@abtnode/rbac": "1.7.
|
|
29
|
-
"@abtnode/router-provider": "1.7.
|
|
30
|
-
"@abtnode/static-server": "1.7.
|
|
31
|
-
"@abtnode/timemachine": "1.7.
|
|
32
|
-
"@abtnode/util": "1.7.
|
|
33
|
-
"@arcblock/did": "^1.16.
|
|
34
|
-
"@arcblock/did-motif": "^1.1.
|
|
35
|
-
"@arcblock/event-hub": "1.16.
|
|
22
|
+
"@abtnode/certificate-manager": "1.7.9",
|
|
23
|
+
"@abtnode/constant": "1.7.9",
|
|
24
|
+
"@abtnode/cron": "1.7.9",
|
|
25
|
+
"@abtnode/db": "1.7.9",
|
|
26
|
+
"@abtnode/logger": "1.7.9",
|
|
27
|
+
"@abtnode/queue": "1.7.9",
|
|
28
|
+
"@abtnode/rbac": "1.7.9",
|
|
29
|
+
"@abtnode/router-provider": "1.7.9",
|
|
30
|
+
"@abtnode/static-server": "1.7.9",
|
|
31
|
+
"@abtnode/timemachine": "1.7.9",
|
|
32
|
+
"@abtnode/util": "1.7.9",
|
|
33
|
+
"@arcblock/did": "^1.16.4",
|
|
34
|
+
"@arcblock/did-motif": "^1.1.5",
|
|
35
|
+
"@arcblock/event-hub": "1.16.4",
|
|
36
36
|
"@arcblock/pm2-events": "^0.0.5",
|
|
37
|
-
"@arcblock/vc": "^1.16.
|
|
38
|
-
"@blocklet/meta": "1.7.
|
|
37
|
+
"@arcblock/vc": "^1.16.4",
|
|
38
|
+
"@blocklet/meta": "1.7.9",
|
|
39
39
|
"@fidm/x509": "^1.2.1",
|
|
40
40
|
"@nedb/core": "^1.2.2",
|
|
41
41
|
"@nedb/multi": "^1.2.2",
|
|
42
|
-
"@ocap/mcrypto": "^1.16.
|
|
43
|
-
"@ocap/util": "^1.16.
|
|
44
|
-
"@ocap/wallet": "^1.16.
|
|
42
|
+
"@ocap/mcrypto": "^1.16.4",
|
|
43
|
+
"@ocap/util": "^1.16.4",
|
|
44
|
+
"@ocap/wallet": "^1.16.4",
|
|
45
45
|
"@slack/webhook": "^5.0.3",
|
|
46
46
|
"ajv": "^7.0.3",
|
|
47
|
-
"axios": "^0.
|
|
47
|
+
"axios": "^0.26.1",
|
|
48
48
|
"axon": "^2.0.3",
|
|
49
49
|
"chalk": "^4.0.0",
|
|
50
50
|
"deep-diff": "^1.0.2",
|
|
@@ -56,7 +56,7 @@
|
|
|
56
56
|
"is-ip": "^3.1.0",
|
|
57
57
|
"is-url": "^1.2.4",
|
|
58
58
|
"joi": "^17.6.0",
|
|
59
|
-
"js-yaml": "^
|
|
59
|
+
"js-yaml": "^4.1.0",
|
|
60
60
|
"lodash": "^4.17.21",
|
|
61
61
|
"lru-cache": "^6.0.0",
|
|
62
62
|
"pm2": "^5.1.2",
|
|
@@ -78,5 +78,5 @@
|
|
|
78
78
|
"express": "^4.17.1",
|
|
79
79
|
"jest": "^27.4.5"
|
|
80
80
|
},
|
|
81
|
-
"gitHead": "
|
|
81
|
+
"gitHead": "285f4fedd41fcb8e1814ce5d8250ac10616e67e0"
|
|
82
82
|
}
|