@abtnode/core 1.16.6-beta-4562aa60 → 1.16.6-beta-eaa4d39d
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 +38 -2
- package/lib/blocklet/manager/disk.js +67 -36
- package/lib/blocklet/manager/helper/install-application-from-dev.js +5 -3
- package/lib/blocklet/manager/helper/install-component-from-url.js +3 -0
- package/lib/blocklet/storage/backup/spaces.js +5 -1
- package/lib/blocklet/storage/restore/spaces.js +5 -1
- package/lib/crons/check-new-version.js +68 -0
- package/lib/{util/disk-monitor.js → crons/monitor-disk-usage.js} +2 -2
- package/lib/crons/rotate-pm2-logs/index.js +41 -0
- package/lib/crons/rotate-pm2-logs/script.js +56 -0
- package/lib/index.js +8 -4
- package/lib/processes/updater.js +160 -0
- package/lib/router/helper.js +4 -7
- package/lib/states/node.js +1 -0
- package/lib/states/user.js +237 -8
- package/lib/util/blocklet.js +67 -10
- package/lib/util/ip.js +0 -6
- package/lib/util/maintain.js +9 -64
- package/lib/util/rotator.js +194 -0
- package/lib/util/rpc.js +69 -8
- package/lib/validators/user.js +44 -0
- package/package.json +32 -27
package/lib/api/team.js
CHANGED
|
@@ -110,6 +110,42 @@ class TeamAPI extends EventEmitter {
|
|
|
110
110
|
|
|
111
111
|
// User && Invitation
|
|
112
112
|
|
|
113
|
+
async loginUser({ teamDid, user }) {
|
|
114
|
+
const state = await this.getUserState(teamDid);
|
|
115
|
+
const nodeInfo = await this.node.read();
|
|
116
|
+
|
|
117
|
+
if (user.role === ROLES.OWNER) {
|
|
118
|
+
if (teamDid !== nodeInfo.did) {
|
|
119
|
+
throw new Error('Cannot add user of owner role');
|
|
120
|
+
}
|
|
121
|
+
|
|
122
|
+
if (await state.count({ role: ROLES.OWNER })) {
|
|
123
|
+
throw new Error('The owner already exists');
|
|
124
|
+
}
|
|
125
|
+
}
|
|
126
|
+
|
|
127
|
+
const { _action, ...doc } = await state.login(user);
|
|
128
|
+
if (_action === 'update') {
|
|
129
|
+
logger.info('user updated successfully', { teamDid, userDid: user.did });
|
|
130
|
+
this.emit(EVENTS.USER_UPDATED, { teamDid, user: doc });
|
|
131
|
+
} else if (_action === 'add') {
|
|
132
|
+
if (teamDid === nodeInfo.did && nodeInfo.nodeOwner && user.did !== nodeInfo.nodeOwner.did) {
|
|
133
|
+
await this.notification.create({
|
|
134
|
+
title: 'New member join',
|
|
135
|
+
description: `User with Name (${user.fullName}) and DID (${user.did}) has joined this server`,
|
|
136
|
+
entityType: 'node',
|
|
137
|
+
action: '/team/members',
|
|
138
|
+
entityId: user.did,
|
|
139
|
+
severity: 'success',
|
|
140
|
+
});
|
|
141
|
+
}
|
|
142
|
+
|
|
143
|
+
logger.info('user added successfully', { teamDid, userDid: user.did, userPk: user.pk, userName: user.fullName });
|
|
144
|
+
this.emit(EVENTS.USER_ADDED, { teamDid, user: doc });
|
|
145
|
+
}
|
|
146
|
+
return doc;
|
|
147
|
+
}
|
|
148
|
+
|
|
113
149
|
async addUser({ teamDid, user }) {
|
|
114
150
|
const state = await this.getUserState(teamDid);
|
|
115
151
|
|
|
@@ -239,10 +275,10 @@ class TeamAPI extends EventEmitter {
|
|
|
239
275
|
return res;
|
|
240
276
|
}
|
|
241
277
|
|
|
242
|
-
async getUser({ teamDid, user }) {
|
|
278
|
+
async getUser({ teamDid, user, options = {} }) {
|
|
243
279
|
const state = await this.getUserState(teamDid);
|
|
244
280
|
|
|
245
|
-
return state.getUser(user.did);
|
|
281
|
+
return state.getUser(user.did, options);
|
|
246
282
|
}
|
|
247
283
|
|
|
248
284
|
async getOwner({ teamDid }) {
|
|
@@ -4,6 +4,7 @@ const fs = require('fs-extra');
|
|
|
4
4
|
const path = require('path');
|
|
5
5
|
const flat = require('flat');
|
|
6
6
|
const get = require('lodash/get');
|
|
7
|
+
const omit = require('lodash/omit');
|
|
7
8
|
const uniq = require('lodash/uniq');
|
|
8
9
|
const merge = require('lodash/merge');
|
|
9
10
|
const pick = require('lodash/pick');
|
|
@@ -61,6 +62,7 @@ const {
|
|
|
61
62
|
BLOCKLET_META_FILE,
|
|
62
63
|
BLOCKLET_CONFIGURABLE_KEY,
|
|
63
64
|
RESTORE_PROGRESS_STATUS,
|
|
65
|
+
CHAIN_PROP_MAP_REVERSE,
|
|
64
66
|
} = require('@blocklet/constant');
|
|
65
67
|
const util = require('../../util');
|
|
66
68
|
const {
|
|
@@ -79,6 +81,7 @@ const {
|
|
|
79
81
|
getBlockletStatusFromProcess,
|
|
80
82
|
checkBlockletProcessHealthy,
|
|
81
83
|
validateBlocklet,
|
|
84
|
+
validateBlockletChainInfo,
|
|
82
85
|
statusMap,
|
|
83
86
|
pruneBlockletBundle,
|
|
84
87
|
getDiskInfo,
|
|
@@ -99,6 +102,8 @@ const {
|
|
|
99
102
|
checkVersionCompatibility,
|
|
100
103
|
getBlockletKnownAs,
|
|
101
104
|
updateBlockletFallbackLogo,
|
|
105
|
+
ensureAppLogo,
|
|
106
|
+
getBlockletDidDomainList,
|
|
102
107
|
} = require('../../util/blocklet');
|
|
103
108
|
const states = require('../../states');
|
|
104
109
|
const BaseBlockletManager = require('./base');
|
|
@@ -106,7 +111,6 @@ const { get: getEngine } = require('./engine');
|
|
|
106
111
|
const blockletPm2Events = require('./pm2-events');
|
|
107
112
|
const runMigrationScripts = require('../migration');
|
|
108
113
|
const hooks = require('../hooks');
|
|
109
|
-
const { getDidDomainForBlocklet } = require('../../util/get-domain-for-blocklet');
|
|
110
114
|
const handleInstanceInStore = require('../../util/public-to-store');
|
|
111
115
|
const { BlockletRuntimeMonitor } = require('../../monitor/blocklet-runtime-monitor');
|
|
112
116
|
const getHistoryList = require('../../monitor/get-history-list');
|
|
@@ -433,6 +437,7 @@ class BlockletManager extends BaseBlockletManager {
|
|
|
433
437
|
|
|
434
438
|
// validate requirement and engine
|
|
435
439
|
await validateBlocklet(blocklet);
|
|
440
|
+
await validateBlockletChainInfo(blocklet);
|
|
436
441
|
|
|
437
442
|
if (!hasRunnableComponent(blocklet)) {
|
|
438
443
|
throw new Error('No runnable component found');
|
|
@@ -613,7 +618,7 @@ class BlockletManager extends BaseBlockletManager {
|
|
|
613
618
|
* @memberof BlockletManager
|
|
614
619
|
*/
|
|
615
620
|
// eslint-disable-next-line no-unused-vars
|
|
616
|
-
async
|
|
621
|
+
async restoreBlocklet(input, context) {
|
|
617
622
|
const { from, ...param } = input;
|
|
618
623
|
if (from === 'spaces') {
|
|
619
624
|
return this._restoreFromSpaces(param, context);
|
|
@@ -999,7 +1004,6 @@ class BlockletManager extends BaseBlockletManager {
|
|
|
999
1004
|
return getBackupList(this.dataDirs.data);
|
|
1000
1005
|
}
|
|
1001
1006
|
|
|
1002
|
-
// CAUTION: this method currently only support config by blocklet.meta.did
|
|
1003
1007
|
// eslint-disable-next-line no-unused-vars
|
|
1004
1008
|
async config({ did, configs: newConfigs, skipHook, skipDidDocument }, context) {
|
|
1005
1009
|
// todo: skipDidDocument will be deleted
|
|
@@ -1091,10 +1095,6 @@ class BlockletManager extends BaseBlockletManager {
|
|
|
1091
1095
|
this.emit(BlockletEvents.spaceConnected, blocklet);
|
|
1092
1096
|
}
|
|
1093
1097
|
|
|
1094
|
-
if (willAppDidChange && !skipDidDocument) {
|
|
1095
|
-
await this._updateDidDocument(blocklet);
|
|
1096
|
-
}
|
|
1097
|
-
|
|
1098
1098
|
// update blocklet meta
|
|
1099
1099
|
if (blocklet.structVersion && !childDids.length) {
|
|
1100
1100
|
const changedTitle = newConfigs.find((x) => x.key === BLOCKLET_CONFIGURABLE_KEY.BLOCKLET_APP_NAME)?.value;
|
|
@@ -1113,11 +1113,20 @@ class BlockletManager extends BaseBlockletManager {
|
|
|
1113
1113
|
}
|
|
1114
1114
|
}
|
|
1115
1115
|
|
|
1116
|
+
// chain config
|
|
1117
|
+
await this._ensureAppChainConfig(rootMetaDid, newConfigs);
|
|
1118
|
+
|
|
1116
1119
|
await this._updateBlockletEnvironment(rootDid);
|
|
1117
1120
|
|
|
1118
1121
|
// response
|
|
1119
1122
|
const newState = await this.getBlocklet(rootDid);
|
|
1123
|
+
|
|
1124
|
+
if (willAppDidChange && !skipDidDocument) {
|
|
1125
|
+
await this._updateDidDocument(newState);
|
|
1126
|
+
}
|
|
1127
|
+
|
|
1120
1128
|
this.emit(BlockletEvents.updated, newState);
|
|
1129
|
+
|
|
1121
1130
|
return newState;
|
|
1122
1131
|
}
|
|
1123
1132
|
|
|
@@ -1962,13 +1971,7 @@ class BlockletManager extends BaseBlockletManager {
|
|
|
1962
1971
|
logger.info('blocklet installed', { source, did: meta.did });
|
|
1963
1972
|
|
|
1964
1973
|
// logo
|
|
1965
|
-
|
|
1966
|
-
const fileName = blocklet.children[0].meta.logo;
|
|
1967
|
-
const src = path.join(getBundleDir(this.installDir, blocklet.children[0].meta), fileName);
|
|
1968
|
-
const dist = path.join(getBundleDir(this.installDir, blocklet.meta), fileName);
|
|
1969
|
-
await fs.copy(src, dist);
|
|
1970
|
-
}
|
|
1971
|
-
|
|
1974
|
+
await ensureAppLogo(blocklet, this.installDir);
|
|
1972
1975
|
await updateBlockletFallbackLogo(blocklet);
|
|
1973
1976
|
|
|
1974
1977
|
// Init db
|
|
@@ -2275,12 +2278,12 @@ class BlockletManager extends BaseBlockletManager {
|
|
|
2275
2278
|
const nodeInfo = await states.node.read();
|
|
2276
2279
|
const { wallet } = getBlockletInfo(blocklet, nodeInfo.sk);
|
|
2277
2280
|
didDocument
|
|
2278
|
-
.
|
|
2281
|
+
.disableBlockletDNS({ appPid: blocklet.appPid, wallet, didRegistryUrl: nodeInfo.didRegistry })
|
|
2279
2282
|
.then(() => {
|
|
2280
|
-
logger.info(`disabled blocklet ${blocklet.
|
|
2283
|
+
logger.info(`disabled blocklet ${blocklet.appPid} dns`);
|
|
2281
2284
|
})
|
|
2282
2285
|
.catch((err) => {
|
|
2283
|
-
logger.error(`disable blocklet ${blocklet.
|
|
2286
|
+
logger.error(`disable blocklet ${blocklet.appPid} dns failed`, { error: err });
|
|
2284
2287
|
});
|
|
2285
2288
|
}
|
|
2286
2289
|
|
|
@@ -2346,6 +2349,9 @@ class BlockletManager extends BaseBlockletManager {
|
|
|
2346
2349
|
|
|
2347
2350
|
// write configs to db
|
|
2348
2351
|
await states.blockletExtras.setConfigs([...ancestors.map((x) => x.meta.did), b.meta.did], environments);
|
|
2352
|
+
|
|
2353
|
+
// chain config
|
|
2354
|
+
await this._ensureAppChainConfig(blocklet.meta.did, environments, 'name');
|
|
2349
2355
|
});
|
|
2350
2356
|
} else {
|
|
2351
2357
|
const child = blocklet.children.find((x) => x.meta.did === childDid);
|
|
@@ -2354,6 +2360,9 @@ class BlockletManager extends BaseBlockletManager {
|
|
|
2354
2360
|
[blocklet.meta.did, ...ancestors.map((x) => x.meta.did), b.meta.did],
|
|
2355
2361
|
[...get(b.meta, 'environments', []), ...getConfigFromPreferences(child)]
|
|
2356
2362
|
);
|
|
2363
|
+
|
|
2364
|
+
// chain config
|
|
2365
|
+
await this._ensureAppChainConfig(blocklet.meta.did, get(b.meta, 'environments', []), 'name');
|
|
2357
2366
|
});
|
|
2358
2367
|
}
|
|
2359
2368
|
}
|
|
@@ -2540,32 +2549,24 @@ class BlockletManager extends BaseBlockletManager {
|
|
|
2540
2549
|
async _updateDidDocument(blocklet) {
|
|
2541
2550
|
const nodeInfo = await states.node.read();
|
|
2542
2551
|
|
|
2543
|
-
const { wallet } = getBlockletInfo(
|
|
2544
|
-
{
|
|
2545
|
-
meta: blocklet.meta,
|
|
2546
|
-
environments: [BLOCKLET_CONFIGURABLE_KEY.BLOCKLET_APP_SK, BLOCKLET_CONFIGURABLE_KEY.BLOCKLET_WALLET_TYPE]
|
|
2547
|
-
.map((key) => ({ key, value: blocklet.configObj[key] }))
|
|
2548
|
-
.filter((x) => x.value),
|
|
2549
|
-
},
|
|
2550
|
-
nodeInfo.sk
|
|
2551
|
-
);
|
|
2552
|
-
const didDomain = getDidDomainForBlocklet({ appPid: blocklet.appPid, didDomain: nodeInfo.didDomain });
|
|
2553
|
-
|
|
2554
2552
|
const domainAliases = (get(blocklet, 'site.domainAliases') || []).filter(
|
|
2555
2553
|
(item) => !item.value.endsWith(nodeInfo.didDomain) && !item.value.endsWith('did.staging.arcblock.io') // did.staging.arcblock.io 是旧 did domain, 但主要存在于比较旧的节点中, 需要做兼容
|
|
2556
2554
|
);
|
|
2557
2555
|
|
|
2558
|
-
|
|
2556
|
+
const didDomainList = getBlockletDidDomainList(blocklet, nodeInfo);
|
|
2557
|
+
domainAliases.push(...didDomainList);
|
|
2559
2558
|
|
|
2560
2559
|
// 先更新 routing rule db 中的 domain aliases, 这一步的目的是为了后面用
|
|
2561
2560
|
await states.site.updateDomainAliasList(blocklet.site.id, domainAliases);
|
|
2562
2561
|
|
|
2563
2562
|
this.emit(BlockletEvents.appDidChanged, blocklet);
|
|
2564
2563
|
|
|
2564
|
+
const { wallet } = getBlockletInfo(blocklet, nodeInfo.sk);
|
|
2565
|
+
const alsoKnownAs = getBlockletKnownAs(blocklet);
|
|
2565
2566
|
await didDocument.updateBlockletDocument({
|
|
2566
2567
|
wallet,
|
|
2567
2568
|
appPid: blocklet.appPid,
|
|
2568
|
-
alsoKnownAs
|
|
2569
|
+
alsoKnownAs,
|
|
2569
2570
|
daemonDidDomain: util.getServerDidDomain(nodeInfo),
|
|
2570
2571
|
didRegistryUrl: nodeInfo.didRegistry,
|
|
2571
2572
|
domain: nodeInfo.didDomain,
|
|
@@ -2603,12 +2604,21 @@ class BlockletManager extends BaseBlockletManager {
|
|
|
2603
2604
|
async _backupToSpaces({ blocklet }, context) {
|
|
2604
2605
|
const userDid = context.user.did;
|
|
2605
2606
|
const { referrer } = context;
|
|
2606
|
-
const {
|
|
2607
|
+
const {
|
|
2608
|
+
appDid,
|
|
2609
|
+
meta: { did: appPid },
|
|
2610
|
+
} = blocklet;
|
|
2607
2611
|
|
|
2608
|
-
const spacesBackup = new SpacesBackup({ appDid, event: this, userDid, referrer });
|
|
2609
|
-
this.emit(BlockletEvents.backupProgress, {
|
|
2612
|
+
const spacesBackup = new SpacesBackup({ appDid, appPid, event: this, userDid, referrer });
|
|
2613
|
+
this.emit(BlockletEvents.backupProgress, {
|
|
2614
|
+
appDid,
|
|
2615
|
+
meta: { did: appPid },
|
|
2616
|
+
message: 'Start backup...',
|
|
2617
|
+
progress: 10,
|
|
2618
|
+
completed: false,
|
|
2619
|
+
});
|
|
2610
2620
|
await spacesBackup.backup();
|
|
2611
|
-
this.emit(BlockletEvents.backupProgress, { appDid, completed: true, progress: 100 });
|
|
2621
|
+
this.emit(BlockletEvents.backupProgress, { appDid, meta: { did: appPid }, completed: true, progress: 100 });
|
|
2612
2622
|
}
|
|
2613
2623
|
|
|
2614
2624
|
/**
|
|
@@ -2634,11 +2644,17 @@ class BlockletManager extends BaseBlockletManager {
|
|
|
2634
2644
|
await sleep(input.delay);
|
|
2635
2645
|
}
|
|
2636
2646
|
|
|
2637
|
-
|
|
2647
|
+
const appPid = input.appDid;
|
|
2648
|
+
|
|
2649
|
+
this.emit(BlockletEvents.restoreProgress, {
|
|
2650
|
+
appDid: input.appDid,
|
|
2651
|
+
meta: { did: appPid },
|
|
2652
|
+
status: RESTORE_PROGRESS_STATUS.start,
|
|
2653
|
+
});
|
|
2638
2654
|
|
|
2639
2655
|
const userDid = context.user.did;
|
|
2640
2656
|
|
|
2641
|
-
const spacesRestore = new SpacesRestore({ ...input, event: this, userDid, referrer: context.referrer });
|
|
2657
|
+
const spacesRestore = new SpacesRestore({ ...input, appPid, event: this, userDid, referrer: context.referrer });
|
|
2642
2658
|
const params = await spacesRestore.restore();
|
|
2643
2659
|
|
|
2644
2660
|
const removeRestoreDir = () => {
|
|
@@ -2702,6 +2718,21 @@ class BlockletManager extends BaseBlockletManager {
|
|
|
2702
2718
|
throw error;
|
|
2703
2719
|
}
|
|
2704
2720
|
}
|
|
2721
|
+
|
|
2722
|
+
async _ensureAppChainConfig(metaDid, configs, key = 'key') {
|
|
2723
|
+
const chainConfigs = configs.filter((x) => ['CHAIN_HOST', 'CHAIN_ID', 'CHAIN_TYPE'].includes(x[key]));
|
|
2724
|
+
if (chainConfigs.length) {
|
|
2725
|
+
const items = chainConfigs.map((x) => ({
|
|
2726
|
+
...omit(x, ['description', 'validation']),
|
|
2727
|
+
[key]: CHAIN_PROP_MAP_REVERSE[x[key]],
|
|
2728
|
+
shared: true,
|
|
2729
|
+
secure: false,
|
|
2730
|
+
required: false,
|
|
2731
|
+
custom: false,
|
|
2732
|
+
}));
|
|
2733
|
+
await states.blockletExtras.setConfigs(metaDid, items);
|
|
2734
|
+
}
|
|
2735
|
+
}
|
|
2705
2736
|
}
|
|
2706
2737
|
|
|
2707
2738
|
module.exports = BlockletManager;
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
const { BlockletStatus, BLOCKLET_MODES, fromBlockletStatus, BlockletSource } = require('@blocklet/constant');
|
|
2
2
|
|
|
3
3
|
const logger = require('@abtnode/logger')('@abtnode/core:install-app-dev');
|
|
4
|
-
const { ensureMeta, updateBlockletFallbackLogo } = require('../../../util/blocklet');
|
|
4
|
+
const { ensureMeta, updateBlockletFallbackLogo, ensureAppLogo } = require('../../../util/blocklet');
|
|
5
5
|
|
|
6
6
|
/**
|
|
7
7
|
*
|
|
@@ -79,10 +79,12 @@ const installApplicationFromDev = async ({ folder, meta, states, manager } = {})
|
|
|
79
79
|
|
|
80
80
|
await states.blocklet.setBlockletStatus(did, BlockletStatus.installed);
|
|
81
81
|
|
|
82
|
-
|
|
83
|
-
|
|
82
|
+
// logo
|
|
83
|
+
await ensureAppLogo(blocklet, manager.installDir);
|
|
84
84
|
await updateBlockletFallbackLogo(blocklet);
|
|
85
85
|
|
|
86
|
+
blocklet = await manager.getBlocklet(did);
|
|
87
|
+
|
|
86
88
|
return blocklet;
|
|
87
89
|
};
|
|
88
90
|
|
|
@@ -117,6 +117,9 @@ const installComponentFromUrl = async ({
|
|
|
117
117
|
}
|
|
118
118
|
|
|
119
119
|
await states.blockletExtras.setConfigs([blocklet.meta.did, newChild.meta.did], configs);
|
|
120
|
+
|
|
121
|
+
// chain config
|
|
122
|
+
await manager._ensureAppChainConfig(blocklet.meta.did, configs);
|
|
120
123
|
}
|
|
121
124
|
} catch (err) {
|
|
122
125
|
logger.error('Add component failed', err);
|
|
@@ -1,6 +1,7 @@
|
|
|
1
1
|
/**
|
|
2
2
|
* @typedef {{
|
|
3
3
|
* appDid: string
|
|
4
|
+
* appPid: string,
|
|
4
5
|
* event: import('events').EventEmitter,
|
|
5
6
|
* userDid: string,
|
|
6
7
|
* referrer: string,
|
|
@@ -147,6 +148,7 @@ class SpacesBackup extends BaseBackup {
|
|
|
147
148
|
async export() {
|
|
148
149
|
this.input.event.emit(BlockletEvents.backupProgress, {
|
|
149
150
|
appDid: this.input.appDid,
|
|
151
|
+
meta: { did: this.input.appPid },
|
|
150
152
|
message: 'Preparing data for backup...',
|
|
151
153
|
progress: 15,
|
|
152
154
|
completed: false,
|
|
@@ -156,6 +158,7 @@ class SpacesBackup extends BaseBackup {
|
|
|
156
158
|
|
|
157
159
|
this.input.event.emit(BlockletEvents.backupProgress, {
|
|
158
160
|
appDid: this.input.appDid,
|
|
161
|
+
meta: { did: this.input.appPid },
|
|
159
162
|
message: 'Data ready, start backup...',
|
|
160
163
|
progress: 20,
|
|
161
164
|
completed: false,
|
|
@@ -193,11 +196,12 @@ class SpacesBackup extends BaseBackup {
|
|
|
193
196
|
// FIXME: @yejianchao 这里需要更完整的黑名单
|
|
194
197
|
return object.name !== '.DS_Store';
|
|
195
198
|
},
|
|
196
|
-
|
|
199
|
+
onAfterUpload: (data) => {
|
|
197
200
|
logger.info('backup progress', { appDid: this.input.appDid, data });
|
|
198
201
|
const percent = (data.completed * 100) / data.total;
|
|
199
202
|
this.input.event.emit(BlockletEvents.backupProgress, {
|
|
200
203
|
appDid: this.input.appDid,
|
|
204
|
+
meta: { did: this.input.appDid },
|
|
201
205
|
message: `Uploading file ${basename(data.key)} (${data.completed}/${data.total})`,
|
|
202
206
|
// 0.8 是因为上传文件到 spaces 占进度的 80%,+ 20 是因为需要累加之前的进度
|
|
203
207
|
progress: +Math.ceil(percent * 0.8).toFixed(2) + 20,
|
|
@@ -1,6 +1,7 @@
|
|
|
1
1
|
/**
|
|
2
2
|
* @typedef {{
|
|
3
3
|
* appDid: string; // --> appDid
|
|
4
|
+
* appPid: string;
|
|
4
5
|
* endpoint: string;
|
|
5
6
|
* password: Buffer; // derived from (appSk, appDid)
|
|
6
7
|
* delegation: string; // from appDid --> serverDid for downloading
|
|
@@ -118,10 +119,11 @@ class SpacesRestore extends BaseRestore {
|
|
|
118
119
|
debug: true,
|
|
119
120
|
concurrency: 32,
|
|
120
121
|
retryCount: 10,
|
|
121
|
-
|
|
122
|
+
onAfterUpload: (data) => {
|
|
122
123
|
logger.info('restore progress', { appDid: this.input.appDid, data });
|
|
123
124
|
this.input.event.emit(BlockletEvents.restoreProgress, {
|
|
124
125
|
appDid: this.input.appDid,
|
|
126
|
+
meta: { did: this.input.appPid },
|
|
125
127
|
status: RESTORE_PROGRESS_STATUS.downloading,
|
|
126
128
|
data,
|
|
127
129
|
});
|
|
@@ -140,6 +142,7 @@ class SpacesRestore extends BaseRestore {
|
|
|
140
142
|
async import(params) {
|
|
141
143
|
this.input.event.emit(BlockletEvents.restoreProgress, {
|
|
142
144
|
appDid: this.input.appDid,
|
|
145
|
+
meta: { did: this.input.appPid },
|
|
143
146
|
status: RESTORE_PROGRESS_STATUS.importData,
|
|
144
147
|
});
|
|
145
148
|
|
|
@@ -150,6 +153,7 @@ class SpacesRestore extends BaseRestore {
|
|
|
150
153
|
);
|
|
151
154
|
this.input.event.emit(BlockletEvents.restoreProgress, {
|
|
152
155
|
appDid: this.input.appDid,
|
|
156
|
+
meta: { did: this.input.appPid },
|
|
153
157
|
status: RESTORE_PROGRESS_STATUS.importDataSuccess,
|
|
154
158
|
});
|
|
155
159
|
}
|
|
@@ -0,0 +1,68 @@
|
|
|
1
|
+
/* eslint-disable no-param-reassign */
|
|
2
|
+
const semver = require('semver');
|
|
3
|
+
const listNpmPackageVersion = require('@abtnode/util/lib/list-npm-package-version');
|
|
4
|
+
const logger = require('@abtnode/logger')('@abtnode/core:maintain');
|
|
5
|
+
|
|
6
|
+
const states = require('../states');
|
|
7
|
+
|
|
8
|
+
// eslint-disable-next-line no-unused-vars
|
|
9
|
+
const checkNewVersion = async (params, context) => {
|
|
10
|
+
try {
|
|
11
|
+
const info = await states.node.read();
|
|
12
|
+
|
|
13
|
+
if (!process.env.ABT_NODE_PACKAGE_NAME) {
|
|
14
|
+
logger.error('ABT_NODE_PACKAGE_NAME name was not found in environment');
|
|
15
|
+
return '';
|
|
16
|
+
}
|
|
17
|
+
|
|
18
|
+
const versions = await listNpmPackageVersion(process.env.ABT_NODE_PACKAGE_NAME, {
|
|
19
|
+
includePrereleases: !!info.enableBetaRelease,
|
|
20
|
+
});
|
|
21
|
+
if (Array.isArray(versions) && versions.length) {
|
|
22
|
+
const latestVersionStr = versions[0].version;
|
|
23
|
+
const latestVersion = semver.coerce(latestVersionStr);
|
|
24
|
+
const currentVersion = semver.coerce(info.version);
|
|
25
|
+
if (latestVersionStr !== info.version && semver.gte(latestVersion, currentVersion)) {
|
|
26
|
+
logger.info('New version found for Blocklet Server', {
|
|
27
|
+
latestVersion: latestVersionStr,
|
|
28
|
+
currentVersion: info.version,
|
|
29
|
+
nextVersion: info.nextVersion,
|
|
30
|
+
});
|
|
31
|
+
await states.node.updateNodeInfo({ nextVersion: latestVersionStr });
|
|
32
|
+
await states.notification.create({
|
|
33
|
+
title: 'Blocklet Server upgrade available',
|
|
34
|
+
description: 'A new and improved version of blocklet server is now available',
|
|
35
|
+
entityType: 'node',
|
|
36
|
+
severity: 'info',
|
|
37
|
+
sticky: true,
|
|
38
|
+
action: '/settings/about',
|
|
39
|
+
});
|
|
40
|
+
|
|
41
|
+
return latestVersionStr;
|
|
42
|
+
}
|
|
43
|
+
}
|
|
44
|
+
|
|
45
|
+
return '';
|
|
46
|
+
} catch (err) {
|
|
47
|
+
logger.error('Failed to check new version for Blocklet Server', { error: err });
|
|
48
|
+
}
|
|
49
|
+
|
|
50
|
+
return '';
|
|
51
|
+
};
|
|
52
|
+
|
|
53
|
+
const getCron = () => ({
|
|
54
|
+
name: 'check-new-version',
|
|
55
|
+
time: '0 0 8 * * *', // check every day
|
|
56
|
+
// time: '0 */5 * * * *', // check every 5 minutes
|
|
57
|
+
fn: async () => {
|
|
58
|
+
const info = await states.node.read();
|
|
59
|
+
if (!info.autoUpgrade) {
|
|
60
|
+
return;
|
|
61
|
+
}
|
|
62
|
+
|
|
63
|
+
checkNewVersion();
|
|
64
|
+
},
|
|
65
|
+
options: { runOnInit: false },
|
|
66
|
+
});
|
|
67
|
+
|
|
68
|
+
module.exports = { getCron, checkNewVersion };
|
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
const logger = require('@abtnode/logger')('@abtnode/disk-monitor');
|
|
2
|
-
const info = require('
|
|
2
|
+
const info = require('../util/sysinfo');
|
|
3
3
|
|
|
4
4
|
const states = require('../states');
|
|
5
5
|
|
|
@@ -29,7 +29,7 @@ const check = async (threshold) => {
|
|
|
29
29
|
};
|
|
30
30
|
|
|
31
31
|
const getCron = () => ({
|
|
32
|
-
name: 'disk-
|
|
32
|
+
name: 'monitor-disk-usage',
|
|
33
33
|
time: '0 5 * * * *', // check every hour
|
|
34
34
|
fn: async () => {
|
|
35
35
|
const nodeInfo = await states.node.read();
|
|
@@ -0,0 +1,41 @@
|
|
|
1
|
+
/* eslint-disable no-console */
|
|
2
|
+
const path = require('path');
|
|
3
|
+
const spawn = require('cross-spawn');
|
|
4
|
+
const { LOG_RETAIN_IN_DAYS } = require('@abtnode/constant');
|
|
5
|
+
|
|
6
|
+
const getCron = () => ({
|
|
7
|
+
name: 'rotate-pm2-logs',
|
|
8
|
+
time: '0 0 * * *', // default : every day at midnight
|
|
9
|
+
options: { runOnInit: false },
|
|
10
|
+
fn: async () => {
|
|
11
|
+
console.info(`Log rotator started on ${new Date().toISOString()}`);
|
|
12
|
+
const child = spawn('node', [path.join(__dirname, './script.js')], {
|
|
13
|
+
detached: true,
|
|
14
|
+
windowsHide: true, // required for Windows
|
|
15
|
+
cwd: process.cwd(),
|
|
16
|
+
timeout: 30 * 60 * 1000, // 30 minutes
|
|
17
|
+
shell: process.env.SHELL || false,
|
|
18
|
+
stdio: ['ignore', process.stdout, process.stderr],
|
|
19
|
+
env: {
|
|
20
|
+
PATH: process.env.PATH,
|
|
21
|
+
PM2_HOME: process.env.PM2_HOME,
|
|
22
|
+
COMPRESS: true,
|
|
23
|
+
RETAIN: LOG_RETAIN_IN_DAYS,
|
|
24
|
+
},
|
|
25
|
+
});
|
|
26
|
+
|
|
27
|
+
child.on('error', (err) => {
|
|
28
|
+
console.error('Log rotator errored', err);
|
|
29
|
+
});
|
|
30
|
+
|
|
31
|
+
child.on('close', (code) => {
|
|
32
|
+
console.info(`Log rotator exited with code ${code} on ${new Date().toISOString()}`);
|
|
33
|
+
});
|
|
34
|
+
|
|
35
|
+
child.unref();
|
|
36
|
+
},
|
|
37
|
+
});
|
|
38
|
+
|
|
39
|
+
module.exports = {
|
|
40
|
+
getCron,
|
|
41
|
+
};
|
|
@@ -0,0 +1,56 @@
|
|
|
1
|
+
/* eslint-disable no-console */
|
|
2
|
+
const pm2 = require('@abtnode/util/lib/async-pm2');
|
|
3
|
+
|
|
4
|
+
const LogRotator = require('../../util/rotator');
|
|
5
|
+
|
|
6
|
+
const RETAIN = parseInt(process.env.RETAIN || '', 10);
|
|
7
|
+
const COMPRESS = JSON.parse(process.env.COMPRESS || 'false');
|
|
8
|
+
const DATE_FORMAT = process.env.DATE_FORMAT || 'YYYY-MM-DD';
|
|
9
|
+
const { TZ } = process.env;
|
|
10
|
+
|
|
11
|
+
const logRotate = new LogRotator({ compress: COMPRESS, dateFormat: DATE_FORMAT, tz: TZ, retain: RETAIN });
|
|
12
|
+
|
|
13
|
+
// register the cron to force rotate file
|
|
14
|
+
console.info('Start rotating pm2 logs...');
|
|
15
|
+
|
|
16
|
+
// get list of process managed by pm2
|
|
17
|
+
pm2.connect((err) => {
|
|
18
|
+
if (err) {
|
|
19
|
+
console.error('Can not connect to pm2 daemon', err);
|
|
20
|
+
process.exit(1);
|
|
21
|
+
}
|
|
22
|
+
|
|
23
|
+
// eslint-disable-next-line no-shadow
|
|
24
|
+
pm2.list(async (err, apps) => {
|
|
25
|
+
if (err) {
|
|
26
|
+
console.error('Can not list apps from pm2', err);
|
|
27
|
+
process.exit(1);
|
|
28
|
+
}
|
|
29
|
+
|
|
30
|
+
const appMap = {};
|
|
31
|
+
|
|
32
|
+
// force rotate for each app
|
|
33
|
+
await Promise.allSettled(
|
|
34
|
+
apps.map((app) => {
|
|
35
|
+
// if apps instances are multi and one of the instances has rotated, ignore
|
|
36
|
+
if (app.pm2_env.instances > 1 && appMap[app.name]) {
|
|
37
|
+
return Promise.resolve(true);
|
|
38
|
+
}
|
|
39
|
+
|
|
40
|
+
appMap[app.name] = app;
|
|
41
|
+
|
|
42
|
+
return logRotate
|
|
43
|
+
.proceedPm2App(app)
|
|
44
|
+
.then(() => {
|
|
45
|
+
console.info(`Rotate ${app.name} log files succeed`);
|
|
46
|
+
})
|
|
47
|
+
.catch((error) => {
|
|
48
|
+
console.error(`Rotate ${app.name} log files failed`, { error });
|
|
49
|
+
});
|
|
50
|
+
})
|
|
51
|
+
);
|
|
52
|
+
|
|
53
|
+
console.info('Done rotating pm2 logs...');
|
|
54
|
+
process.exit(0);
|
|
55
|
+
});
|
|
56
|
+
});
|
package/lib/index.js
CHANGED
|
@@ -24,7 +24,9 @@ const IP = require('./util/ip');
|
|
|
24
24
|
const DomainStatus = require('./util/domain-status');
|
|
25
25
|
const Maintain = require('./util/maintain');
|
|
26
26
|
const resetNode = require('./util/reset-node');
|
|
27
|
-
const DiskMonitor = require('./
|
|
27
|
+
const DiskMonitor = require('./crons/monitor-disk-usage');
|
|
28
|
+
const LogRotator = require('./crons/rotate-pm2-logs');
|
|
29
|
+
const VersionChecker = require('./crons/check-new-version');
|
|
28
30
|
const StoreUtil = require('./util/store');
|
|
29
31
|
const createQueue = require('./util/queue');
|
|
30
32
|
const createEvents = require('./event');
|
|
@@ -235,7 +237,7 @@ function ABTNode(options) {
|
|
|
235
237
|
updateComponentTitle: blockletManager.updateComponentTitle.bind(blockletManager),
|
|
236
238
|
updateComponentMountPoint: blockletManager.updateComponentMountPoint.bind(blockletManager),
|
|
237
239
|
backupBlocklet: blockletManager.backup.bind(blockletManager),
|
|
238
|
-
restoreBlocklet: blockletManager.
|
|
240
|
+
restoreBlocklet: blockletManager.restoreBlocklet.bind(blockletManager),
|
|
239
241
|
migrateApplicationToStructV2: blockletManager.migrateApplicationToStructV2.bind(blockletManager),
|
|
240
242
|
|
|
241
243
|
// For diagnose purpose
|
|
@@ -301,6 +303,7 @@ function ABTNode(options) {
|
|
|
301
303
|
getNodeUsers: () => teamAPI.getUsers({ teamDid: options.nodeDid }),
|
|
302
304
|
getNodeUser: (user) => teamAPI.getUser({ teamDid: options.nodeDid, user }),
|
|
303
305
|
addUser: teamAPI.addUser.bind(teamAPI),
|
|
306
|
+
loginUser: teamAPI.loginUser.bind(teamAPI),
|
|
304
307
|
removeUser: teamAPI.removeUser.bind(teamAPI),
|
|
305
308
|
updateUser: teamAPI.updateUser.bind(teamAPI),
|
|
306
309
|
updateUserApproval: teamAPI.updateUserApproval.bind(teamAPI),
|
|
@@ -402,8 +405,8 @@ function ABTNode(options) {
|
|
|
402
405
|
markMigrationExecuted: states.migration.markExecuted.bind(states.migration),
|
|
403
406
|
|
|
404
407
|
// Upgrading
|
|
408
|
+
checkNodeVersion: VersionChecker.checkNewVersion,
|
|
405
409
|
upgradeNodeVersion: () => Maintain.triggerMaintain({ action: 'upgrade', next: Maintain.resumeMaintain }),
|
|
406
|
-
checkNodeVersion: Maintain.checkNewVersion,
|
|
407
410
|
restartServer: () => Maintain.triggerMaintain({ action: 'restart', next: Maintain.resumeMaintain }),
|
|
408
411
|
isBeingMaintained: Maintain.isBeingMaintained,
|
|
409
412
|
resumeMaintain: Maintain.resumeMaintain,
|
|
@@ -452,10 +455,11 @@ function ABTNode(options) {
|
|
|
452
455
|
context: { states, events, webhook },
|
|
453
456
|
jobs: [
|
|
454
457
|
IP.cron,
|
|
455
|
-
|
|
458
|
+
VersionChecker.getCron(),
|
|
456
459
|
...getRoutingCrons(),
|
|
457
460
|
...blockletManager.getCrons(),
|
|
458
461
|
DiskMonitor.getCron(),
|
|
462
|
+
LogRotator.getCron(),
|
|
459
463
|
...getStateCrons(states),
|
|
460
464
|
...nodeAPI.getCrons(),
|
|
461
465
|
],
|