@abtnode/core 1.7.10 → 1.7.13
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 +7 -1
- package/lib/api/team.js +2 -2
- package/lib/blocklet/manager/disk.js +141 -81
- package/lib/blocklet/registry.js +6 -2
- package/lib/event.js +5 -0
- package/lib/index.js +39 -7
- package/lib/migrations/1.7.12-blocklet-meta.js +51 -0
- package/lib/router/index.js +7 -0
- package/lib/states/README.md +31 -1
- package/lib/states/audit-log.js +382 -0
- package/lib/states/blocklet.js +9 -7
- package/lib/states/index.js +3 -0
- package/lib/states/node.js +8 -0
- package/lib/util/blocklet.js +102 -43
- package/lib/util/index.js +35 -0
- package/lib/util/ip.js +6 -0
- package/lib/util/rpc.js +16 -0
- package/lib/util/ua.js +54 -0
- package/lib/util/upgrade.js +3 -15
- package/lib/validators/node.js +13 -0
- package/package.json +21 -20
package/lib/states/index.js
CHANGED
|
@@ -10,6 +10,7 @@ const MigrationState = require('./migration');
|
|
|
10
10
|
const SessionState = require('./session');
|
|
11
11
|
const ExtrasState = require('./blocklet-extras');
|
|
12
12
|
const CacheState = require('./cache');
|
|
13
|
+
const AuditLogState = require('./audit-log');
|
|
13
14
|
|
|
14
15
|
const init = (dataDirs, options) => {
|
|
15
16
|
const notificationState = new NotificationState(dataDirs.core, options);
|
|
@@ -23,6 +24,7 @@ const init = (dataDirs, options) => {
|
|
|
23
24
|
const sessionState = new SessionState(dataDirs.core, options);
|
|
24
25
|
const extrasState = new ExtrasState(dataDirs.core, options);
|
|
25
26
|
const cacheState = new CacheState(dataDirs.core, options);
|
|
27
|
+
const auditLogState = new AuditLogState(dataDirs.core, options);
|
|
26
28
|
|
|
27
29
|
return {
|
|
28
30
|
node: nodeState,
|
|
@@ -36,6 +38,7 @@ const init = (dataDirs, options) => {
|
|
|
36
38
|
session: sessionState,
|
|
37
39
|
blockletExtras: extrasState,
|
|
38
40
|
cache: cacheState,
|
|
41
|
+
auditLog: auditLogState,
|
|
39
42
|
};
|
|
40
43
|
};
|
|
41
44
|
|
package/lib/states/node.js
CHANGED
|
@@ -278,6 +278,14 @@ class NodeState extends BaseState {
|
|
|
278
278
|
await this.update(_id, { $set: { customBlockletNumber: num } });
|
|
279
279
|
return num;
|
|
280
280
|
}
|
|
281
|
+
|
|
282
|
+
async updateGateway(gateway) {
|
|
283
|
+
const [, nodeInfo] = await this.update({}, { $set: { 'routing.requestLimit': gateway.requestLimit } });
|
|
284
|
+
|
|
285
|
+
this.emit(EVENTS.RELOAD_GATEWAY, nodeInfo);
|
|
286
|
+
|
|
287
|
+
return nodeInfo.routing;
|
|
288
|
+
}
|
|
281
289
|
}
|
|
282
290
|
|
|
283
291
|
module.exports = NodeState;
|
package/lib/util/blocklet.js
CHANGED
|
@@ -6,7 +6,6 @@ const os = require('os');
|
|
|
6
6
|
const tar = require('tar');
|
|
7
7
|
const get = require('lodash/get');
|
|
8
8
|
const intersection = require('lodash/intersection');
|
|
9
|
-
const intersectionBy = require('lodash/intersectionBy');
|
|
10
9
|
const streamToPromise = require('stream-to-promise');
|
|
11
10
|
const { Throttle } = require('stream-throttle');
|
|
12
11
|
const ssri = require('ssri');
|
|
@@ -43,6 +42,7 @@ const getBlockletEngine = require('@blocklet/meta/lib/engine');
|
|
|
43
42
|
const getBlockletInfo = require('@blocklet/meta/lib/info');
|
|
44
43
|
const { validateMeta, fixAndValidateService } = require('@blocklet/meta/lib/validate');
|
|
45
44
|
const { forEachBlocklet, isFreeBlocklet, getDisplayName, findWebInterface } = require('@blocklet/meta/lib/util');
|
|
45
|
+
const toBlockletDid = require('@blocklet/meta/lib/did');
|
|
46
46
|
|
|
47
47
|
const { validate: validateEngine, get: getEngine } = require('../blocklet/manager/engine');
|
|
48
48
|
|
|
@@ -103,7 +103,10 @@ const PRIVATE_NODE_ENVS = [
|
|
|
103
103
|
* appMain: app entry file or script (run appMain to start blocklet process)
|
|
104
104
|
* appCwd: cwd of appMain
|
|
105
105
|
*/
|
|
106
|
-
const getBlockletDirs = (
|
|
106
|
+
const getBlockletDirs = (
|
|
107
|
+
blocklet,
|
|
108
|
+
{ rootBlocklet, dataDirs, ensure = false, e2eMode = false, validate = true } = {}
|
|
109
|
+
) => {
|
|
107
110
|
if (!rootBlocklet) {
|
|
108
111
|
// eslint-disable-next-line no-param-reassign
|
|
109
112
|
rootBlocklet = blocklet;
|
|
@@ -133,7 +136,7 @@ const getBlockletDirs = (blocklet, { rootBlocklet, dataDirs, ensure = false, e2e
|
|
|
133
136
|
}
|
|
134
137
|
}
|
|
135
138
|
|
|
136
|
-
if (!main && !startFromDevEntry && group !== BlockletGroup.gateway) {
|
|
139
|
+
if (validate && !main && !startFromDevEntry && group !== BlockletGroup.gateway) {
|
|
137
140
|
throw new Error('Incorrect blocklet manifest: missing `main` field');
|
|
138
141
|
}
|
|
139
142
|
|
|
@@ -163,7 +166,7 @@ const getBlockletDirs = (blocklet, { rootBlocklet, dataDirs, ensure = false, e2e
|
|
|
163
166
|
|
|
164
167
|
mainDir = appDir;
|
|
165
168
|
|
|
166
|
-
if (!startFromDevEntry && !isBeforeInstalled(rootBlocklet.status)) {
|
|
169
|
+
if (validate && !startFromDevEntry && !isBeforeInstalled(rootBlocklet.status)) {
|
|
167
170
|
try {
|
|
168
171
|
validateBlockletEntry(appDir, blocklet.meta);
|
|
169
172
|
} catch (err) {
|
|
@@ -171,7 +174,7 @@ const getBlockletDirs = (blocklet, { rootBlocklet, dataDirs, ensure = false, e2e
|
|
|
171
174
|
}
|
|
172
175
|
}
|
|
173
176
|
|
|
174
|
-
if (!BLOCKLET_GROUPS.includes(group)) {
|
|
177
|
+
if (validate && !BLOCKLET_GROUPS.includes(group)) {
|
|
175
178
|
throw new CustomError('BLOCKLET_CORRUPTED', `Unsupported blocklet type ${group}`);
|
|
176
179
|
}
|
|
177
180
|
|
|
@@ -633,25 +636,30 @@ const reloadProcess = (appId) =>
|
|
|
633
636
|
});
|
|
634
637
|
});
|
|
635
638
|
|
|
639
|
+
const parseChildren = (children, parentMeta = {}, { dynamic } = {}) => {
|
|
640
|
+
const configs = Array.isArray(parentMeta) ? parentMeta : parentMeta.children || [];
|
|
641
|
+
|
|
642
|
+
children.forEach((x) => {
|
|
643
|
+
if (dynamic !== undefined) {
|
|
644
|
+
x.dynamic = !!dynamic;
|
|
645
|
+
}
|
|
646
|
+
});
|
|
647
|
+
|
|
648
|
+
mergeMeta(configs, children);
|
|
649
|
+
return children;
|
|
650
|
+
};
|
|
651
|
+
|
|
636
652
|
/**
|
|
637
653
|
* this function has side effect on children
|
|
638
654
|
*/
|
|
639
|
-
const
|
|
655
|
+
const parseChildrenFromMeta = async (src, { dynamic } = {}) => {
|
|
640
656
|
const configs = Array.isArray(src) ? src : src.children || [];
|
|
641
657
|
|
|
642
|
-
if (children) {
|
|
643
|
-
children.forEach((x) => {
|
|
644
|
-
x.dynamic = !!dynamic;
|
|
645
|
-
});
|
|
646
|
-
mergeMeta(configs, children);
|
|
647
|
-
return children;
|
|
648
|
-
}
|
|
649
|
-
|
|
650
658
|
if (!configs || !configs.length) {
|
|
651
659
|
return [];
|
|
652
660
|
}
|
|
653
661
|
|
|
654
|
-
const
|
|
662
|
+
const children = [];
|
|
655
663
|
|
|
656
664
|
for (const config of configs) {
|
|
657
665
|
const mountPoint = config.mountPoint || config.mountPoints[0].root.prefix;
|
|
@@ -660,15 +668,6 @@ const parseChildren = async (src, { children, dynamic } = {}) => {
|
|
|
660
668
|
}
|
|
661
669
|
|
|
662
670
|
const m = await getBlockletMetaFromUrl(config.resolved);
|
|
663
|
-
if (m.name !== config.name) {
|
|
664
|
-
logger.error('Resolved child blocklet name does not match in the configuration', {
|
|
665
|
-
expected: config.name,
|
|
666
|
-
resolved: m.name,
|
|
667
|
-
});
|
|
668
|
-
throw new Error(
|
|
669
|
-
`Child blocklet name does not match in the configuration. expected: ${config.name}, resolved: ${m.name}`
|
|
670
|
-
);
|
|
671
|
-
}
|
|
672
671
|
validateBlockletMeta(m, { ensureDist: true });
|
|
673
672
|
|
|
674
673
|
const webInterface = findWebInterface(m);
|
|
@@ -681,17 +680,26 @@ const parseChildren = async (src, { children, dynamic } = {}) => {
|
|
|
681
680
|
throw new Error(`Prefix does not match in child ${config.name}. expected: ${rule}, resolved: ${mountPoint}`);
|
|
682
681
|
}
|
|
683
682
|
|
|
684
|
-
|
|
683
|
+
const meta = ensureMeta(m, { name: config.name });
|
|
684
|
+
if (config.title) {
|
|
685
|
+
meta.title = config.title;
|
|
686
|
+
}
|
|
687
|
+
if (config.description) {
|
|
688
|
+
meta.description = config.description;
|
|
689
|
+
}
|
|
690
|
+
|
|
691
|
+
const child = {
|
|
685
692
|
mountPoint,
|
|
686
|
-
meta
|
|
687
|
-
dynamic: !!dynamic,
|
|
693
|
+
meta,
|
|
688
694
|
sourceUrl: config.resolved,
|
|
689
|
-
}
|
|
695
|
+
};
|
|
696
|
+
|
|
697
|
+
children.push(child);
|
|
690
698
|
}
|
|
691
699
|
|
|
692
|
-
|
|
700
|
+
parseChildren(children, configs, { dynamic });
|
|
693
701
|
|
|
694
|
-
return
|
|
702
|
+
return children;
|
|
695
703
|
};
|
|
696
704
|
|
|
697
705
|
const validateBlocklet = (blocklet) =>
|
|
@@ -800,7 +808,7 @@ const pruneBlockletBundle = async ({ blocklets, installDir, blockletSettings })
|
|
|
800
808
|
].includes(blocklet.status)
|
|
801
809
|
) {
|
|
802
810
|
logger.info('There are blocklet activities in progress, abort pruning', {
|
|
803
|
-
|
|
811
|
+
bundleName: blocklet.meta.bundleName,
|
|
804
812
|
status: fromBlockletStatus(blocklet.status),
|
|
805
813
|
});
|
|
806
814
|
return;
|
|
@@ -810,14 +818,16 @@ const pruneBlockletBundle = async ({ blocklets, installDir, blockletSettings })
|
|
|
810
818
|
// blockletMap: { <[scope/]name/version>: true }
|
|
811
819
|
const blockletMap = {};
|
|
812
820
|
for (const blocklet of blocklets) {
|
|
813
|
-
blockletMap[`${blocklet.meta.
|
|
821
|
+
blockletMap[`${blocklet.meta.bundleName}/${blocklet.meta.version}`] = true;
|
|
814
822
|
for (const child of blocklet.children || []) {
|
|
815
|
-
blockletMap[`${child.meta.
|
|
823
|
+
blockletMap[`${child.meta.bundleName}/${child.meta.version}`] = true;
|
|
816
824
|
}
|
|
817
825
|
}
|
|
818
826
|
for (const setting of blockletSettings) {
|
|
819
827
|
for (const child of setting.children || []) {
|
|
820
|
-
|
|
828
|
+
if (child.status !== BlockletStatus.deleted) {
|
|
829
|
+
blockletMap[`${child.meta.bundleName}/${child.meta.version}`] = true;
|
|
830
|
+
}
|
|
821
831
|
}
|
|
822
832
|
}
|
|
823
833
|
|
|
@@ -1006,11 +1016,7 @@ const mergeMeta = (source, childrenMeta = []) => {
|
|
|
1006
1016
|
});
|
|
1007
1017
|
};
|
|
1008
1018
|
|
|
1009
|
-
const
|
|
1010
|
-
if (meta.did !== did) {
|
|
1011
|
-
throw new Error('Invalid blocklet meta: did does not match');
|
|
1012
|
-
}
|
|
1013
|
-
|
|
1019
|
+
const fixAndVerifyMetaFromStore = (meta) => {
|
|
1014
1020
|
const sanitized = validateMeta(meta, { ensureDist: false, schemaOptions: { noDefaults: true, stripUnknown: true } });
|
|
1015
1021
|
|
|
1016
1022
|
try {
|
|
@@ -1057,8 +1063,10 @@ const getSourceFromInstallParams = (params) => {
|
|
|
1057
1063
|
throw new Error('Can only install blocklet from store/url/upload/custom');
|
|
1058
1064
|
};
|
|
1059
1065
|
|
|
1060
|
-
const checkDuplicateComponents = (
|
|
1061
|
-
const duplicates =
|
|
1066
|
+
const checkDuplicateComponents = (components = []) => {
|
|
1067
|
+
const duplicates = components.filter(
|
|
1068
|
+
(item, index) => components.findIndex((x) => x.meta.did === item.meta.did) !== index
|
|
1069
|
+
);
|
|
1062
1070
|
if (duplicates.length) {
|
|
1063
1071
|
throw new Error(
|
|
1064
1072
|
`Cannot add duplicate component${duplicates.length > 1 ? 's' : ''}: ${duplicates
|
|
@@ -1066,6 +1074,13 @@ const checkDuplicateComponents = (dynamicComponents, staticComponents) => {
|
|
|
1066
1074
|
.join(', ')}`
|
|
1067
1075
|
);
|
|
1068
1076
|
}
|
|
1077
|
+
|
|
1078
|
+
const duplicateMountPoints = components.filter(
|
|
1079
|
+
(item, index) => components.findIndex((x) => x.mountPoint === item.mountPoint) !== index
|
|
1080
|
+
);
|
|
1081
|
+
if (duplicateMountPoints.length) {
|
|
1082
|
+
throw new Error(`mountpoint must be unique: ${duplicateMountPoints.map((x) => x.mountPoint).join(', ')}`);
|
|
1083
|
+
}
|
|
1069
1084
|
};
|
|
1070
1085
|
|
|
1071
1086
|
const getDiffFiles = async (inputFiles, sourceDir) => {
|
|
@@ -1109,7 +1124,7 @@ const getDiffFiles = async (inputFiles, sourceDir) => {
|
|
|
1109
1124
|
};
|
|
1110
1125
|
};
|
|
1111
1126
|
|
|
1112
|
-
const getBundleDir = (installDir,
|
|
1127
|
+
const getBundleDir = (installDir, meta) => path.join(installDir, meta.bundleName || meta.name, meta.version);
|
|
1113
1128
|
|
|
1114
1129
|
const needBlockletDownload = (blocklet, oldBlocklet) => {
|
|
1115
1130
|
if ([BlockletSource.upload, BlockletSource.local, BlockletSource.custom].includes(blocklet.source)) {
|
|
@@ -1139,9 +1154,51 @@ const verifyPurchase = (meta, opts = {}) => {
|
|
|
1139
1154
|
throw new Error('Can not install a non-free blocklet directly');
|
|
1140
1155
|
};
|
|
1141
1156
|
|
|
1157
|
+
const findAvailableDid = (meta, siblings) => {
|
|
1158
|
+
const reg = /-(\d+)$/;
|
|
1159
|
+
const match = reg.exec(meta.name);
|
|
1160
|
+
|
|
1161
|
+
const newName = match ? meta.name.replace(reg, `-${Number(match[1]) + 1}`) : `${meta.name}-1`;
|
|
1162
|
+
const newDid = toBlockletDid(newName);
|
|
1163
|
+
const newMeta = { name: newName, did: newDid };
|
|
1164
|
+
|
|
1165
|
+
if (!(siblings || []).some((x) => x.did === newMeta.did)) {
|
|
1166
|
+
return newMeta;
|
|
1167
|
+
}
|
|
1168
|
+
|
|
1169
|
+
return findAvailableDid(newMeta, siblings);
|
|
1170
|
+
};
|
|
1171
|
+
|
|
1172
|
+
const ensureMeta = (meta, { name, did } = {}) => {
|
|
1173
|
+
if (name && did && toBlockletDid(name) !== did) {
|
|
1174
|
+
throw new Error('name does not match with did');
|
|
1175
|
+
}
|
|
1176
|
+
|
|
1177
|
+
const newMeta = {
|
|
1178
|
+
...meta,
|
|
1179
|
+
};
|
|
1180
|
+
|
|
1181
|
+
if (!newMeta.did || !newMeta.name || toBlockletDid(newMeta.name) !== newMeta.did) {
|
|
1182
|
+
throw new Error('name does not match with did in meta');
|
|
1183
|
+
}
|
|
1184
|
+
|
|
1185
|
+
if (!meta.bundleDid) {
|
|
1186
|
+
newMeta.bundleDid = meta.did;
|
|
1187
|
+
newMeta.bundleName = meta.name;
|
|
1188
|
+
}
|
|
1189
|
+
|
|
1190
|
+
if (name) {
|
|
1191
|
+
newMeta.name = name;
|
|
1192
|
+
newMeta.did = did || toBlockletDid(name);
|
|
1193
|
+
}
|
|
1194
|
+
|
|
1195
|
+
return newMeta;
|
|
1196
|
+
};
|
|
1197
|
+
|
|
1142
1198
|
module.exports = {
|
|
1143
1199
|
forEachBlocklet,
|
|
1144
1200
|
getBlockletMetaFromUrl,
|
|
1201
|
+
parseChildrenFromMeta,
|
|
1145
1202
|
parseChildren,
|
|
1146
1203
|
getBlockletDirs,
|
|
1147
1204
|
getRootSystemEnvironments,
|
|
@@ -1166,7 +1223,7 @@ module.exports = {
|
|
|
1166
1223
|
getDiskInfo,
|
|
1167
1224
|
getRuntimeInfo,
|
|
1168
1225
|
mergeMeta,
|
|
1169
|
-
|
|
1226
|
+
fixAndVerifyMetaFromStore,
|
|
1170
1227
|
getUpdateMetaList,
|
|
1171
1228
|
getSourceFromInstallParams,
|
|
1172
1229
|
findWebInterface,
|
|
@@ -1175,4 +1232,6 @@ module.exports = {
|
|
|
1175
1232
|
getBundleDir,
|
|
1176
1233
|
needBlockletDownload,
|
|
1177
1234
|
verifyPurchase,
|
|
1235
|
+
findAvailableDid,
|
|
1236
|
+
ensureMeta,
|
|
1178
1237
|
};
|
package/lib/util/index.js
CHANGED
|
@@ -474,6 +474,39 @@ const getSafeEnv = (inputEnv, processEnv = process.env) => {
|
|
|
474
474
|
return mergedEnv;
|
|
475
475
|
};
|
|
476
476
|
|
|
477
|
+
// For performance sake, we only support 1 param here, and the cache is flushed every minute
|
|
478
|
+
const memoizeAsync = (fn, flushInterval = 60000) => {
|
|
479
|
+
const cache = new Map();
|
|
480
|
+
setInterval(() => cache.clear(), flushInterval);
|
|
481
|
+
|
|
482
|
+
return (arg) => {
|
|
483
|
+
if (cache.has(arg)) {
|
|
484
|
+
return cache.get(arg);
|
|
485
|
+
}
|
|
486
|
+
|
|
487
|
+
// eslint-disable-next-line prefer-spread
|
|
488
|
+
const result = fn.apply(null, [arg]);
|
|
489
|
+
cache.set(arg, result);
|
|
490
|
+
|
|
491
|
+
return result;
|
|
492
|
+
};
|
|
493
|
+
};
|
|
494
|
+
|
|
495
|
+
const getStateCrons = (states) => [
|
|
496
|
+
{
|
|
497
|
+
name: 'cleanup-audit-logs',
|
|
498
|
+
time: '0 0 6 * * *', // cleanup old logs every day at 6am
|
|
499
|
+
// time: '0 */5 * * * *', // cleanup every 5 minutes
|
|
500
|
+
options: { runOnInit: false },
|
|
501
|
+
fn: async () => {
|
|
502
|
+
const removed = await states.auditLog.remove({
|
|
503
|
+
createdAt: { $lt: new Date(Date.now() - 1000 * 60 * 60 * 24 * 90) },
|
|
504
|
+
});
|
|
505
|
+
logger.info(`Removed ${removed} audit logs`);
|
|
506
|
+
},
|
|
507
|
+
},
|
|
508
|
+
];
|
|
509
|
+
|
|
477
510
|
const lib = {
|
|
478
511
|
validateOwner,
|
|
479
512
|
getProviderFromNodeInfo,
|
|
@@ -510,6 +543,8 @@ const lib = {
|
|
|
510
543
|
transformIPToDomain,
|
|
511
544
|
getQueueConcurrencyByMem,
|
|
512
545
|
getSafeEnv,
|
|
546
|
+
memoizeAsync,
|
|
547
|
+
getStateCrons,
|
|
513
548
|
};
|
|
514
549
|
|
|
515
550
|
module.exports = lib;
|
package/lib/util/ip.js
CHANGED
|
@@ -1,6 +1,9 @@
|
|
|
1
1
|
const getIp = require('@abtnode/util/lib/get-ip');
|
|
2
2
|
const logger = require('@abtnode/logger')('@abtnode/core:ip');
|
|
3
3
|
|
|
4
|
+
const doRpc = require('./rpc');
|
|
5
|
+
const { memoizeAsync } = require('./index');
|
|
6
|
+
|
|
4
7
|
let cache = null;
|
|
5
8
|
const fetch = async () => {
|
|
6
9
|
try {
|
|
@@ -22,6 +25,9 @@ const cron = {
|
|
|
22
25
|
fn: fetch,
|
|
23
26
|
};
|
|
24
27
|
|
|
28
|
+
const lookup = memoizeAsync((ip) => doRpc({ command: 'lookup', ip }));
|
|
29
|
+
|
|
25
30
|
module.exports.fetch = fetch;
|
|
26
31
|
module.exports.get = get;
|
|
27
32
|
module.exports.cron = cron;
|
|
33
|
+
module.exports.lookup = lookup;
|
package/lib/util/rpc.js
ADDED
|
@@ -0,0 +1,16 @@
|
|
|
1
|
+
const axon = require('axon');
|
|
2
|
+
const logger = require('@abtnode/logger')('@abtnode/core:rpc');
|
|
3
|
+
|
|
4
|
+
const sock = axon.socket('req');
|
|
5
|
+
sock.connect(Number(process.env.ABT_NODE_UPDATER_PORT || 40405), '127.0.0.1');
|
|
6
|
+
|
|
7
|
+
const doRpc = async (message) =>
|
|
8
|
+
new Promise((resolve) => {
|
|
9
|
+
logger.info('send rpc request', message);
|
|
10
|
+
sock.send(JSON.stringify(message), (result) => {
|
|
11
|
+
logger.info('receive rpc response', result);
|
|
12
|
+
resolve(result);
|
|
13
|
+
});
|
|
14
|
+
});
|
|
15
|
+
|
|
16
|
+
module.exports = doRpc;
|
package/lib/util/ua.js
ADDED
|
@@ -0,0 +1,54 @@
|
|
|
1
|
+
const semver = require('semver');
|
|
2
|
+
const parser = require('ua-parser-js');
|
|
3
|
+
const packageJson = require('../../package.json');
|
|
4
|
+
|
|
5
|
+
const { memoizeAsync } = require('./index');
|
|
6
|
+
|
|
7
|
+
const parseWalletUA = (userAgent) => {
|
|
8
|
+
const ua = (userAgent || '').toString().toLowerCase();
|
|
9
|
+
let os = '';
|
|
10
|
+
let version = '';
|
|
11
|
+
if (ua.indexOf('android') > -1) {
|
|
12
|
+
os = 'android';
|
|
13
|
+
} else if (ua.indexOf('darwin') > -1) {
|
|
14
|
+
os = 'ios';
|
|
15
|
+
} else if (ua.indexOf('arcwallet') === 0) {
|
|
16
|
+
os = 'web';
|
|
17
|
+
}
|
|
18
|
+
|
|
19
|
+
const match = ua.split(/\s+/).find((x) => x.startsWith('arcwallet'));
|
|
20
|
+
if (match) {
|
|
21
|
+
const tmp = match.split('/');
|
|
22
|
+
if (tmp.length > 1 && semver.coerce(tmp[1])) {
|
|
23
|
+
version = semver.coerce(tmp[1]).version;
|
|
24
|
+
}
|
|
25
|
+
}
|
|
26
|
+
|
|
27
|
+
return { os, version };
|
|
28
|
+
};
|
|
29
|
+
|
|
30
|
+
const parse = memoizeAsync((ua) => {
|
|
31
|
+
let result = parser(ua);
|
|
32
|
+
if (result.browser.name) {
|
|
33
|
+
return result;
|
|
34
|
+
}
|
|
35
|
+
|
|
36
|
+
result = parseWalletUA(ua);
|
|
37
|
+
if (result.version) {
|
|
38
|
+
return {
|
|
39
|
+
browser: {
|
|
40
|
+
name: `DID Wallet ${result.os.toUpperCase()}`,
|
|
41
|
+
version: result.version,
|
|
42
|
+
},
|
|
43
|
+
};
|
|
44
|
+
}
|
|
45
|
+
|
|
46
|
+
return {
|
|
47
|
+
browser: {
|
|
48
|
+
name: 'CLI',
|
|
49
|
+
version: packageJson.version,
|
|
50
|
+
},
|
|
51
|
+
};
|
|
52
|
+
});
|
|
53
|
+
|
|
54
|
+
module.exports = { parse };
|
package/lib/util/upgrade.js
CHANGED
|
@@ -1,5 +1,4 @@
|
|
|
1
1
|
/* eslint-disable no-param-reassign */
|
|
2
|
-
const axon = require('axon');
|
|
3
2
|
const semver = require('semver');
|
|
4
3
|
const sleep = require('@abtnode/util/lib/sleep');
|
|
5
4
|
const { NODE_MODES, NODE_UPGRADE_PROGRESS, EVENTS } = require('@abtnode/constant');
|
|
@@ -8,21 +7,10 @@ const Lock = require('@abtnode/util/lib/lock');
|
|
|
8
7
|
const logger = require('@abtnode/logger')('@abtnode/core:upgrade');
|
|
9
8
|
|
|
10
9
|
const states = require('../states');
|
|
10
|
+
const doRpc = require('./rpc');
|
|
11
11
|
|
|
12
12
|
const lock = new Lock('node-upgrade-lock');
|
|
13
13
|
|
|
14
|
-
// Connect to updater and send RPC call
|
|
15
|
-
const sock = axon.socket('req');
|
|
16
|
-
sock.connect(Number(process.env.ABT_NODE_UPDATER_PORT), '127.0.0.1');
|
|
17
|
-
const waitUpdaterRpc = async (message) =>
|
|
18
|
-
new Promise((resolve) => {
|
|
19
|
-
logger.info('send command to updater process', message);
|
|
20
|
-
sock.send(JSON.stringify(message), (result) => {
|
|
21
|
-
logger.info('receive response from updater process', result);
|
|
22
|
-
resolve(result);
|
|
23
|
-
});
|
|
24
|
-
});
|
|
25
|
-
|
|
26
14
|
// eslint-disable-next-line no-unused-vars
|
|
27
15
|
const checkNewVersion = async (params, context) => {
|
|
28
16
|
try {
|
|
@@ -120,7 +108,7 @@ const doUpgrade = async (session) => {
|
|
|
120
108
|
|
|
121
109
|
// 2. install specified version
|
|
122
110
|
if (session.stage === NODE_UPGRADE_PROGRESS.INSTALLING) {
|
|
123
|
-
await
|
|
111
|
+
await doRpc({ command: 'install', version: to });
|
|
124
112
|
logger.info('new version installed for upgrading', { from, to, sessionId });
|
|
125
113
|
await goNextState(NODE_UPGRADE_PROGRESS.RESTARTING);
|
|
126
114
|
}
|
|
@@ -131,7 +119,7 @@ const doUpgrade = async (session) => {
|
|
|
131
119
|
await sleep(3000);
|
|
132
120
|
await goNextState(NODE_UPGRADE_PROGRESS.CLEANUP);
|
|
133
121
|
await sleep(3000);
|
|
134
|
-
await
|
|
122
|
+
await doRpc({ command: 'restart', dataDir: process.env.ABT_NODE_DATA_DIR });
|
|
135
123
|
await lock.release();
|
|
136
124
|
return; // we should abort here and resume after restart
|
|
137
125
|
}
|
package/lib/validators/node.js
CHANGED
|
@@ -1,4 +1,5 @@
|
|
|
1
1
|
/* eslint-disable newline-per-chained-call */
|
|
2
|
+
const { GATEWAY_REQ_LIMIT } = require('@abtnode/constant');
|
|
2
3
|
const Joi = require('joi');
|
|
3
4
|
const { getMultipleLangParams } = require('./util');
|
|
4
5
|
|
|
@@ -42,6 +43,18 @@ const nodeInfoSchema = Joi.object({
|
|
|
42
43
|
}),
|
|
43
44
|
}).options({ stripUnknown: true });
|
|
44
45
|
|
|
46
|
+
const updateGatewaySchema = Joi.object({
|
|
47
|
+
requestLimit: Joi.object({
|
|
48
|
+
enabled: Joi.bool().required(),
|
|
49
|
+
rate: Joi.number()
|
|
50
|
+
.min(GATEWAY_REQ_LIMIT.min)
|
|
51
|
+
.max(GATEWAY_REQ_LIMIT.max)
|
|
52
|
+
.when('requestLimit.enabled', { is: true, then: Joi.required() }),
|
|
53
|
+
ipHeader: Joi.string().allow('').trim(),
|
|
54
|
+
}),
|
|
55
|
+
});
|
|
56
|
+
|
|
45
57
|
module.exports = {
|
|
46
58
|
validateNodeInfo: (entity, context) => nodeInfoSchema.validateAsync(entity, getMultipleLangParams(context)),
|
|
59
|
+
validateUpdateGateway: (entity, context) => updateGatewaySchema.validateAsync(entity, getMultipleLangParams(context)),
|
|
47
60
|
};
|
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.13",
|
|
7
7
|
"description": "",
|
|
8
8
|
"main": "lib/index.js",
|
|
9
9
|
"files": [
|
|
@@ -19,29 +19,29 @@
|
|
|
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.
|
|
22
|
+
"@abtnode/certificate-manager": "1.7.13",
|
|
23
|
+
"@abtnode/constant": "1.7.13",
|
|
24
|
+
"@abtnode/cron": "1.7.13",
|
|
25
|
+
"@abtnode/db": "1.7.13",
|
|
26
|
+
"@abtnode/logger": "1.7.13",
|
|
27
|
+
"@abtnode/queue": "1.7.13",
|
|
28
|
+
"@abtnode/rbac": "1.7.13",
|
|
29
|
+
"@abtnode/router-provider": "1.7.13",
|
|
30
|
+
"@abtnode/static-server": "1.7.13",
|
|
31
|
+
"@abtnode/timemachine": "1.7.13",
|
|
32
|
+
"@abtnode/util": "1.7.13",
|
|
33
|
+
"@arcblock/did": "^1.16.6",
|
|
34
34
|
"@arcblock/did-motif": "^1.1.5",
|
|
35
|
-
"@arcblock/event-hub": "1.16.
|
|
35
|
+
"@arcblock/event-hub": "1.16.6",
|
|
36
36
|
"@arcblock/pm2-events": "^0.0.5",
|
|
37
|
-
"@arcblock/vc": "^1.16.
|
|
38
|
-
"@blocklet/meta": "1.7.
|
|
37
|
+
"@arcblock/vc": "^1.16.6",
|
|
38
|
+
"@blocklet/meta": "1.7.13",
|
|
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.6",
|
|
43
|
+
"@ocap/util": "^1.16.6",
|
|
44
|
+
"@ocap/wallet": "^1.16.6",
|
|
45
45
|
"@slack/webhook": "^5.0.3",
|
|
46
46
|
"axios": "^0.26.1",
|
|
47
47
|
"axon": "^2.0.3",
|
|
@@ -67,6 +67,7 @@
|
|
|
67
67
|
"stream-to-promise": "^3.0.0",
|
|
68
68
|
"systeminformation": "^5.11.5",
|
|
69
69
|
"tar": "^6.1.0",
|
|
70
|
+
"ua-parser-js": "^1.0.2",
|
|
70
71
|
"unzipper": "^0.10.11",
|
|
71
72
|
"url-join": "^4.0.1",
|
|
72
73
|
"uuid": "7.0.3"
|
|
@@ -77,5 +78,5 @@
|
|
|
77
78
|
"express": "^4.17.1",
|
|
78
79
|
"jest": "^27.4.5"
|
|
79
80
|
},
|
|
80
|
-
"gitHead": "
|
|
81
|
+
"gitHead": "c35c485417df0e023c06c09557644b46a6c8c655"
|
|
81
82
|
}
|