@abtnode/core 1.8.64 → 1.8.65-beta-5405baf2
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/blocklet/downloader/blocklet-downloader.js +205 -0
- package/lib/blocklet/downloader/bundle-downloader.js +267 -0
- package/lib/blocklet/downloader/constants.js +3 -0
- package/lib/blocklet/downloader/resolve-download.js +168 -0
- package/lib/blocklet/manager/disk.js +77 -468
- package/lib/router/helper.js +10 -4
- package/lib/router/manager.js +22 -21
- package/lib/states/site.js +1 -0
- package/lib/validators/router.js +6 -8
- package/package.json +17 -17
|
@@ -1,7 +1,6 @@
|
|
|
1
1
|
/* eslint-disable no-underscore-dangle */
|
|
2
2
|
/* eslint-disable no-await-in-loop */
|
|
3
3
|
const fs = require('fs-extra');
|
|
4
|
-
const { fileURLToPath } = require('url');
|
|
5
4
|
const path = require('path');
|
|
6
5
|
const flat = require('flat');
|
|
7
6
|
const get = require('lodash/get');
|
|
@@ -17,14 +16,12 @@ const didDocument = require('@abtnode/util/lib/did-document');
|
|
|
17
16
|
const { sign } = require('@arcblock/jwt');
|
|
18
17
|
const { isValid: isValidDid } = require('@arcblock/did');
|
|
19
18
|
const { verifyPresentation } = require('@arcblock/vc');
|
|
20
|
-
const { toBase58 } = require('@ocap/util');
|
|
21
19
|
const { toSvg: createDidLogo } =
|
|
22
20
|
process.env.NODE_ENV !== 'test' ? require('@arcblock/did-motif') : require('@arcblock/did-motif/dist/did-motif.cjs');
|
|
23
21
|
const getBlockletInfo = require('@blocklet/meta/lib/info');
|
|
22
|
+
const sleep = require('@abtnode/util/lib/sleep');
|
|
24
23
|
|
|
25
24
|
const logger = require('@abtnode/logger')('@abtnode/core:blocklet:manager');
|
|
26
|
-
const downloadFile = require('@abtnode/util/lib/download-file');
|
|
27
|
-
const Lock = require('@abtnode/util/lib/lock');
|
|
28
25
|
const { getVcFromPresentation } = require('@abtnode/util/lib/vc');
|
|
29
26
|
const {
|
|
30
27
|
VC_TYPE_BLOCKLET_PURCHASE,
|
|
@@ -45,17 +42,16 @@ const {
|
|
|
45
42
|
forEachChildSync,
|
|
46
43
|
forEachBlocklet,
|
|
47
44
|
getComponentId,
|
|
48
|
-
getComponentBundleId,
|
|
49
45
|
isPreferenceKey,
|
|
50
46
|
getRolesFromAuthConfig,
|
|
51
47
|
} = require('@blocklet/meta/lib/util');
|
|
52
48
|
const getComponentProcessId = require('@blocklet/meta/lib/get-component-process-id');
|
|
53
|
-
const validateBlockletEntry = require('@blocklet/meta/lib/entry');
|
|
54
49
|
const toBlockletDid = require('@blocklet/meta/lib/did');
|
|
55
50
|
const { validateMeta } = require('@blocklet/meta/lib/validate');
|
|
56
51
|
const { update: updateMetaFile } = require('@blocklet/meta/lib/file');
|
|
57
52
|
const { titleSchema, mountPointSchema, environmentNameSchema } = require('@blocklet/meta/lib/schema');
|
|
58
53
|
const hasReservedKey = require('@blocklet/meta/lib/has-reserved-key');
|
|
54
|
+
const Lock = require('@abtnode/util/lib/lock');
|
|
59
55
|
|
|
60
56
|
const { toExternalBlocklet } = toBlockletDid;
|
|
61
57
|
|
|
@@ -63,7 +59,6 @@ const {
|
|
|
63
59
|
BlockletStatus,
|
|
64
60
|
BlockletSource,
|
|
65
61
|
BlockletEvents,
|
|
66
|
-
BLOCKLET_BUNDLE_FOLDER,
|
|
67
62
|
BLOCKLET_MODES,
|
|
68
63
|
BlockletGroup,
|
|
69
64
|
fromBlockletStatus,
|
|
@@ -86,7 +81,6 @@ const {
|
|
|
86
81
|
} = require('../../util/get-accessible-external-node-ip');
|
|
87
82
|
const {
|
|
88
83
|
getBlockletMetaFromUrl,
|
|
89
|
-
ensureBlockletExpanded,
|
|
90
84
|
getAppSystemEnvironments,
|
|
91
85
|
getComponentSystemEnvironments,
|
|
92
86
|
getAppOverwrittenEnvironments,
|
|
@@ -99,8 +93,6 @@ const {
|
|
|
99
93
|
checkBlockletProcessHealthy,
|
|
100
94
|
validateBlocklet,
|
|
101
95
|
statusMap,
|
|
102
|
-
expandTarball,
|
|
103
|
-
verifyIntegrity,
|
|
104
96
|
pruneBlockletBundle,
|
|
105
97
|
getDiskInfo,
|
|
106
98
|
getUpdateMetaList,
|
|
@@ -110,7 +102,6 @@ const {
|
|
|
110
102
|
checkDuplicateComponents,
|
|
111
103
|
getDiffFiles,
|
|
112
104
|
getBundleDir,
|
|
113
|
-
needBlockletDownload,
|
|
114
105
|
findAvailableDid,
|
|
115
106
|
ensureMeta,
|
|
116
107
|
getBlocklet,
|
|
@@ -131,12 +122,13 @@ const runMigrationScripts = require('../migration');
|
|
|
131
122
|
const hooks = require('../hooks');
|
|
132
123
|
const { formatName, getDidDomainForBlocklet } = require('../../util/get-domain-for-blocklet');
|
|
133
124
|
const handleInstanceInStore = require('../../util/public-to-store');
|
|
134
|
-
const { getNFTState, getServerDidDomain } = require('../../util');
|
|
135
125
|
const { BlockletRuntimeMonitor } = require('../../monitor/blocklet-runtime-monitor');
|
|
136
126
|
const getHistoryList = require('../../monitor/get-history-list');
|
|
137
127
|
const { SpacesBackup } = require('../storage/backup/spaces');
|
|
138
128
|
const { SpacesRestore } = require('../storage/restore/spaces');
|
|
139
129
|
const installFromBackup = require('./helper/install-from-backup');
|
|
130
|
+
const { resolveDownload, resolveDiffDownload } = require('../downloader/resolve-download');
|
|
131
|
+
const BlockletDownloader = require('../downloader/blocklet-downloader');
|
|
140
132
|
|
|
141
133
|
const {
|
|
142
134
|
isInProgress,
|
|
@@ -150,8 +142,6 @@ const {
|
|
|
150
142
|
|
|
151
143
|
const statusLock = new Lock('blocklet-status-lock');
|
|
152
144
|
|
|
153
|
-
const asyncFs = fs.promises;
|
|
154
|
-
|
|
155
145
|
const pm2StatusMap = {
|
|
156
146
|
online: BlockletStatus.running,
|
|
157
147
|
stop: BlockletStatus.stopped,
|
|
@@ -211,15 +201,6 @@ class BlockletManager extends BaseBlockletManager {
|
|
|
211
201
|
this.installQueue = installQueue;
|
|
212
202
|
this.teamManager = teamManager;
|
|
213
203
|
|
|
214
|
-
/**
|
|
215
|
-
* { did: Map({ <childDid>: <downloadFile.cancelCtrl> }) }
|
|
216
|
-
*/
|
|
217
|
-
this.downloadCtrls = {};
|
|
218
|
-
/**
|
|
219
|
-
* { [download-did-version]: Lock }
|
|
220
|
-
*/
|
|
221
|
-
this.downloadLocks = {};
|
|
222
|
-
|
|
223
204
|
// cached installed blocklets for performance
|
|
224
205
|
this.cachedBlocklets = null;
|
|
225
206
|
|
|
@@ -231,6 +212,12 @@ class BlockletManager extends BaseBlockletManager {
|
|
|
231
212
|
|
|
232
213
|
this.runtimeMonitor = new BlockletRuntimeMonitor({ historyLength: MONITOR_HISTORY_LENGTH, states });
|
|
233
214
|
|
|
215
|
+
this.blockletDownloader = new BlockletDownloader({
|
|
216
|
+
installDir: this.installDir,
|
|
217
|
+
downloadDir: this.dataDirs.tmp,
|
|
218
|
+
cache: states.cache,
|
|
219
|
+
});
|
|
220
|
+
|
|
234
221
|
if (daemon) {
|
|
235
222
|
blockletPm2Events.on('online', (data) => this._syncPm2Status('online', data.blockletDid));
|
|
236
223
|
blockletPm2Events.on('stop', (data) => this._syncPm2Status('stop', data.blockletDid));
|
|
@@ -877,7 +864,7 @@ class BlockletManager extends BaseBlockletManager {
|
|
|
877
864
|
}
|
|
878
865
|
|
|
879
866
|
if (blocklet.status === BlockletStatus.downloading) {
|
|
880
|
-
await this.
|
|
867
|
+
await this.blockletDownloader.cancelDownload(blocklet.meta.did);
|
|
881
868
|
} else if (blocklet.status === BlockletStatus.waiting) {
|
|
882
869
|
await this._cancelWaiting(blocklet.meta, context);
|
|
883
870
|
}
|
|
@@ -920,8 +907,8 @@ class BlockletManager extends BaseBlockletManager {
|
|
|
920
907
|
const blocklet = await this.ensureBlocklet(did, { throwOnNotExist: false });
|
|
921
908
|
return blocklet;
|
|
922
909
|
} catch (e) {
|
|
923
|
-
logger.error('get blocklet detail error', { error: e
|
|
924
|
-
return null;
|
|
910
|
+
logger.error('get blocklet detail error', { error: e });
|
|
911
|
+
return null; // TODO: 直接返回没有 runtime info 的数据
|
|
925
912
|
}
|
|
926
913
|
}
|
|
927
914
|
|
|
@@ -1549,8 +1536,7 @@ class BlockletManager extends BaseBlockletManager {
|
|
|
1549
1536
|
});
|
|
1550
1537
|
logger.info('add blocklet for dev', { did, version, meta });
|
|
1551
1538
|
|
|
1552
|
-
|
|
1553
|
-
await this._downloadBlocklet(added, oldBlocklet);
|
|
1539
|
+
await this._downloadBlocklet(added);
|
|
1554
1540
|
|
|
1555
1541
|
// Add Config
|
|
1556
1542
|
await this._setConfigsFromMeta(did);
|
|
@@ -1614,7 +1600,7 @@ class BlockletManager extends BaseBlockletManager {
|
|
|
1614
1600
|
await states.blocklet.addChildren(rootDid, [component]);
|
|
1615
1601
|
|
|
1616
1602
|
const newBlocklet = await states.blocklet.getBlocklet(rootDid);
|
|
1617
|
-
await this._downloadBlocklet(newBlocklet
|
|
1603
|
+
await this._downloadBlocklet(newBlocklet);
|
|
1618
1604
|
await states.blocklet.setBlockletStatus(rootDid, BlockletStatus.stopped);
|
|
1619
1605
|
|
|
1620
1606
|
await this._upsertDynamicNavigation(existRoot.meta.did, component, { skipNavigation });
|
|
@@ -1862,7 +1848,7 @@ class BlockletManager extends BaseBlockletManager {
|
|
|
1862
1848
|
|
|
1863
1849
|
// download bundle
|
|
1864
1850
|
try {
|
|
1865
|
-
const { isCancelled } = await this._downloadBlocklet(blocklet,
|
|
1851
|
+
const { isCancelled } = await this._downloadBlocklet(blocklet, context);
|
|
1866
1852
|
|
|
1867
1853
|
if (isCancelled) {
|
|
1868
1854
|
logger.info('Download was canceled', { name, did, version });
|
|
@@ -2388,7 +2374,7 @@ class BlockletManager extends BaseBlockletManager {
|
|
|
2388
2374
|
|
|
2389
2375
|
async _installFromUpload({ file, did, diffVersion, deleteSet, context }) {
|
|
2390
2376
|
logger.info('install blocklet', { from: 'upload file' });
|
|
2391
|
-
const {
|
|
2377
|
+
const { tarFile } = await this._downloadFromUpload(file);
|
|
2392
2378
|
|
|
2393
2379
|
// diff deploy
|
|
2394
2380
|
if (did && diffVersion) {
|
|
@@ -2410,14 +2396,17 @@ class BlockletManager extends BaseBlockletManager {
|
|
|
2410
2396
|
throw new Error(`Can not deploy blocklet when it is ${fromBlockletStatus(oldBlocklet.status)}`);
|
|
2411
2397
|
}
|
|
2412
2398
|
|
|
2413
|
-
const { meta } = await
|
|
2399
|
+
const { meta } = await resolveDiffDownload(tarFile, this.installDir, {
|
|
2400
|
+
deleteSet,
|
|
2401
|
+
meta: oldBlocklet.meta,
|
|
2402
|
+
});
|
|
2414
2403
|
const newBlocklet = await states.blocklet.getBlocklet(did);
|
|
2415
2404
|
newBlocklet.meta = ensureMeta(meta);
|
|
2416
2405
|
newBlocklet.source = BlockletSource.upload;
|
|
2417
2406
|
newBlocklet.deployedFrom = `Upload by ${context.user.fullName}`;
|
|
2418
2407
|
newBlocklet.children = await this._getChildrenForInstallation(meta);
|
|
2419
2408
|
await validateBlocklet(newBlocklet);
|
|
2420
|
-
await this._downloadBlocklet(newBlocklet
|
|
2409
|
+
await this._downloadBlocklet(newBlocklet);
|
|
2421
2410
|
|
|
2422
2411
|
return this._upgradeBlocklet({
|
|
2423
2412
|
oldBlocklet,
|
|
@@ -2427,7 +2416,7 @@ class BlockletManager extends BaseBlockletManager {
|
|
|
2427
2416
|
}
|
|
2428
2417
|
|
|
2429
2418
|
// full deploy
|
|
2430
|
-
const { meta } = await
|
|
2419
|
+
const { meta } = await resolveDownload(tarFile, this.installDir);
|
|
2431
2420
|
const oldBlocklet = await this._getBlockletForInstallation(meta.did);
|
|
2432
2421
|
|
|
2433
2422
|
// full deploy - upgrade
|
|
@@ -2444,7 +2433,7 @@ class BlockletManager extends BaseBlockletManager {
|
|
|
2444
2433
|
newBlocklet.children = await this._getChildrenForInstallation(meta);
|
|
2445
2434
|
|
|
2446
2435
|
await validateBlocklet(newBlocklet);
|
|
2447
|
-
await this._downloadBlocklet(newBlocklet
|
|
2436
|
+
await this._downloadBlocklet(newBlocklet);
|
|
2448
2437
|
|
|
2449
2438
|
return this._upgradeBlocklet({
|
|
2450
2439
|
oldBlocklet,
|
|
@@ -2472,11 +2461,7 @@ class BlockletManager extends BaseBlockletManager {
|
|
|
2472
2461
|
await checkDuplicateAppSk({ did: meta.did, states });
|
|
2473
2462
|
|
|
2474
2463
|
// download
|
|
2475
|
-
await this._downloadBlocklet(
|
|
2476
|
-
blocklet,
|
|
2477
|
-
// let downloader skip re-downloading dynamic blocklet
|
|
2478
|
-
{ children: children.filter((x) => x.dynamic) }
|
|
2479
|
-
);
|
|
2464
|
+
await this._downloadBlocklet(blocklet);
|
|
2480
2465
|
|
|
2481
2466
|
return this._installBlocklet({
|
|
2482
2467
|
did: meta.did,
|
|
@@ -2501,7 +2486,7 @@ class BlockletManager extends BaseBlockletManager {
|
|
|
2501
2486
|
}) {
|
|
2502
2487
|
logger.info('install blocklet', { from: 'upload file' });
|
|
2503
2488
|
// download
|
|
2504
|
-
const {
|
|
2489
|
+
const { tarFile } = await this._downloadFromUpload(file);
|
|
2505
2490
|
|
|
2506
2491
|
const oldBlocklet = await this._getBlockletForInstallation(rootDid);
|
|
2507
2492
|
if (!oldBlocklet) {
|
|
@@ -2530,10 +2515,10 @@ class BlockletManager extends BaseBlockletManager {
|
|
|
2530
2515
|
throw new Error('Blocklet version changed when diff deploying');
|
|
2531
2516
|
}
|
|
2532
2517
|
|
|
2533
|
-
meta = (await
|
|
2518
|
+
meta = (await resolveDiffDownload(tarFile, this.installDir, { deleteSet, meta: oldChild.meta })).meta;
|
|
2534
2519
|
} else {
|
|
2535
2520
|
// full deploy
|
|
2536
|
-
meta = (await
|
|
2521
|
+
meta = (await resolveDownload(tarFile, this.installDir)).meta;
|
|
2537
2522
|
}
|
|
2538
2523
|
|
|
2539
2524
|
if (meta.did === rootDid) {
|
|
@@ -2567,7 +2552,7 @@ class BlockletManager extends BaseBlockletManager {
|
|
|
2567
2552
|
|
|
2568
2553
|
await this._upsertDynamicNavigation(newBlocklet.meta.did, newChild, { skipNavigation });
|
|
2569
2554
|
|
|
2570
|
-
await this._downloadBlocklet(newBlocklet
|
|
2555
|
+
await this._downloadBlocklet(newBlocklet);
|
|
2571
2556
|
|
|
2572
2557
|
await validateBlocklet(newBlocklet);
|
|
2573
2558
|
|
|
@@ -2649,6 +2634,7 @@ class BlockletManager extends BaseBlockletManager {
|
|
|
2649
2634
|
{
|
|
2650
2635
|
name: 'delete-expired-external-blocklet',
|
|
2651
2636
|
time: '0 */30 * * * *', // 30min
|
|
2637
|
+
options: { runOnInit: false },
|
|
2652
2638
|
fn: () => this._deleteExpiredExternalBlocklet(),
|
|
2653
2639
|
},
|
|
2654
2640
|
{
|
|
@@ -2906,137 +2892,6 @@ class BlockletManager extends BaseBlockletManager {
|
|
|
2906
2892
|
return newBlocklet;
|
|
2907
2893
|
}
|
|
2908
2894
|
|
|
2909
|
-
/**
|
|
2910
|
-
* decompress file, format dir and move to installDir
|
|
2911
|
-
* @param {string} cwd
|
|
2912
|
-
* @param {string} tarFile
|
|
2913
|
-
* @param {object} originalMeta for verification
|
|
2914
|
-
* @param {object} option
|
|
2915
|
-
*/
|
|
2916
|
-
async _resolveDownload(cwd, tarFile, originalMeta, { removeTarFile = true } = {}) {
|
|
2917
|
-
const downloadDir = path.join(cwd, `${path.basename(tarFile, path.extname(tarFile))}`);
|
|
2918
|
-
const tmp = `${downloadDir}-tmp`;
|
|
2919
|
-
try {
|
|
2920
|
-
await expandTarball({ source: tarFile, dest: tmp, strip: 0 });
|
|
2921
|
-
} catch (error) {
|
|
2922
|
-
logger.error('expand blocklet tar file error');
|
|
2923
|
-
throw error;
|
|
2924
|
-
} finally {
|
|
2925
|
-
if (removeTarFile) {
|
|
2926
|
-
fs.removeSync(tarFile);
|
|
2927
|
-
}
|
|
2928
|
-
}
|
|
2929
|
-
let installDir;
|
|
2930
|
-
let meta;
|
|
2931
|
-
try {
|
|
2932
|
-
// resolve dir
|
|
2933
|
-
let dir = tmp;
|
|
2934
|
-
const files = await asyncFs.readdir(dir);
|
|
2935
|
-
if (files.includes('package')) {
|
|
2936
|
-
dir = path.join(tmp, 'package');
|
|
2937
|
-
} else if (files.length === 1) {
|
|
2938
|
-
const d = path.join(dir, files[0]);
|
|
2939
|
-
if ((await asyncFs.stat(d)).isDirectory()) {
|
|
2940
|
-
dir = d;
|
|
2941
|
-
}
|
|
2942
|
-
}
|
|
2943
|
-
|
|
2944
|
-
if (fs.existsSync(path.join(dir, BLOCKLET_BUNDLE_FOLDER))) {
|
|
2945
|
-
dir = path.join(dir, BLOCKLET_BUNDLE_FOLDER);
|
|
2946
|
-
}
|
|
2947
|
-
|
|
2948
|
-
logger.info('Move downloadDir to installDir', { downloadDir });
|
|
2949
|
-
await fs.move(dir, downloadDir, { overwrite: true });
|
|
2950
|
-
fs.removeSync(tmp);
|
|
2951
|
-
|
|
2952
|
-
meta = getBlockletMeta(downloadDir, { ensureMain: true });
|
|
2953
|
-
const { did, name, version } = meta;
|
|
2954
|
-
|
|
2955
|
-
// validate
|
|
2956
|
-
if (
|
|
2957
|
-
originalMeta &&
|
|
2958
|
-
(originalMeta.did !== did || originalMeta.name !== name || originalMeta.version !== version)
|
|
2959
|
-
) {
|
|
2960
|
-
logger.error('Meta has differences', { originalMeta, meta });
|
|
2961
|
-
throw new Error('There are differences between the meta from tarball file and the original meta');
|
|
2962
|
-
}
|
|
2963
|
-
await validateBlockletEntry(downloadDir, meta);
|
|
2964
|
-
|
|
2965
|
-
await ensureBlockletExpanded(meta, downloadDir);
|
|
2966
|
-
|
|
2967
|
-
installDir = getBundleDir(this.installDir, meta);
|
|
2968
|
-
if (fs.existsSync(installDir)) {
|
|
2969
|
-
fs.removeSync(installDir);
|
|
2970
|
-
logger.info('cleanup blocklet upgrade dir', { name, version, installDir });
|
|
2971
|
-
}
|
|
2972
|
-
|
|
2973
|
-
fs.mkdirSync(installDir, { recursive: true });
|
|
2974
|
-
|
|
2975
|
-
await fs.move(downloadDir, installDir, { overwrite: true });
|
|
2976
|
-
} catch (error) {
|
|
2977
|
-
fs.removeSync(downloadDir);
|
|
2978
|
-
fs.removeSync(tmp);
|
|
2979
|
-
throw error;
|
|
2980
|
-
}
|
|
2981
|
-
|
|
2982
|
-
return { meta, installDir };
|
|
2983
|
-
}
|
|
2984
|
-
|
|
2985
|
-
async _resolveDiffDownload(cwd, tarFile, deleteSet, bundle) {
|
|
2986
|
-
logger.info('Resolve diff download', { tarFile, cwd });
|
|
2987
|
-
const downloadDir = path.join(cwd, `${path.basename(tarFile, path.extname(tarFile))}`);
|
|
2988
|
-
const diffDir = `${downloadDir}-diff`;
|
|
2989
|
-
try {
|
|
2990
|
-
await expandTarball({ source: tarFile, dest: diffDir, strip: 0 });
|
|
2991
|
-
fs.removeSync(tarFile);
|
|
2992
|
-
} catch (error) {
|
|
2993
|
-
fs.removeSync(tarFile);
|
|
2994
|
-
logger.error('expand blocklet tar file error');
|
|
2995
|
-
throw error;
|
|
2996
|
-
}
|
|
2997
|
-
logger.info('Copy installDir to downloadDir', { installDir: this.installDir, downloadDir });
|
|
2998
|
-
await fs.copy(getBundleDir(this.installDir, bundle), downloadDir);
|
|
2999
|
-
try {
|
|
3000
|
-
// delete
|
|
3001
|
-
logger.info('Delete files from downloadDir', { fileNum: deleteSet.length });
|
|
3002
|
-
// eslint-disable-next-line no-restricted-syntax
|
|
3003
|
-
for (const file of deleteSet) {
|
|
3004
|
-
await fs.remove(path.join(downloadDir, file));
|
|
3005
|
-
}
|
|
3006
|
-
// walk & cover
|
|
3007
|
-
logger.info('Move files from diffDir to downloadDir', { diffDir, downloadDir });
|
|
3008
|
-
const walkDiff = async (dir) => {
|
|
3009
|
-
const files = await asyncFs.readdir(dir);
|
|
3010
|
-
// eslint-disable-next-line no-restricted-syntax
|
|
3011
|
-
for (const file of files) {
|
|
3012
|
-
const p = path.join(dir, file);
|
|
3013
|
-
const stat = await asyncFs.stat(p);
|
|
3014
|
-
if (stat.isDirectory()) {
|
|
3015
|
-
await walkDiff(p);
|
|
3016
|
-
} else if (stat.isFile()) {
|
|
3017
|
-
await fs.move(p, path.join(downloadDir, path.relative(diffDir, p)), { overwrite: true });
|
|
3018
|
-
}
|
|
3019
|
-
}
|
|
3020
|
-
};
|
|
3021
|
-
await walkDiff(diffDir);
|
|
3022
|
-
fs.removeSync(diffDir);
|
|
3023
|
-
const meta = getBlockletMeta(downloadDir, { ensureMain: true });
|
|
3024
|
-
|
|
3025
|
-
await ensureBlockletExpanded(meta, downloadDir);
|
|
3026
|
-
|
|
3027
|
-
// move to installDir
|
|
3028
|
-
const bundleDir = getBundleDir(this.installDir, meta);
|
|
3029
|
-
logger.info('Move downloadDir to installDir', { downloadDir, bundleDir });
|
|
3030
|
-
await fs.move(downloadDir, bundleDir, { overwrite: true });
|
|
3031
|
-
|
|
3032
|
-
return { meta, installDir: bundleDir };
|
|
3033
|
-
} catch (error) {
|
|
3034
|
-
fs.removeSync(downloadDir);
|
|
3035
|
-
fs.removeSync(diffDir);
|
|
3036
|
-
throw error;
|
|
3037
|
-
}
|
|
3038
|
-
}
|
|
3039
|
-
|
|
3040
2895
|
/**
|
|
3041
2896
|
* @param {string} opt.did
|
|
3042
2897
|
* @param {object} opt.context
|
|
@@ -3267,275 +3122,33 @@ class BlockletManager extends BaseBlockletManager {
|
|
|
3267
3122
|
await states.blockletExtras.setSettings(did, { children: dynamicChildren });
|
|
3268
3123
|
}
|
|
3269
3124
|
|
|
3270
|
-
/**
|
|
3271
|
-
*
|
|
3272
|
-
*
|
|
3273
|
-
* @param {{
|
|
3274
|
-
* url: string,
|
|
3275
|
-
* cwd: string,
|
|
3276
|
-
* tarball: string,
|
|
3277
|
-
* did: string,
|
|
3278
|
-
* integrity: string,
|
|
3279
|
-
* verify: boolean = true,
|
|
3280
|
-
* ctrlStore: {},
|
|
3281
|
-
* rootDid: string,
|
|
3282
|
-
* context: {} = {},
|
|
3283
|
-
* }} { url, cwd, tarball, did, integrity, verify = true, ctrlStore = {}, rootDid, context = {} }
|
|
3284
|
-
* @return {*}
|
|
3285
|
-
* @memberof BlockletManager
|
|
3286
|
-
*/
|
|
3287
|
-
async _downloadTarball({ url, cwd, tarball, did, integrity, verify = true, ctrlStore = {}, rootDid, context = {} }) {
|
|
3288
|
-
fs.mkdirSync(cwd, { recursive: true });
|
|
3289
|
-
|
|
3290
|
-
const tarballName = url.split('/').slice(-1)[0];
|
|
3291
|
-
|
|
3292
|
-
const tarballPath = path.join(cwd, tarballName);
|
|
3293
|
-
|
|
3294
|
-
const { protocol } = new URL(url);
|
|
3295
|
-
|
|
3296
|
-
const cachedTarFile = await this._getCachedTarFile(integrity);
|
|
3297
|
-
if (cachedTarFile) {
|
|
3298
|
-
logger.info('found cache tarFile', { did, tarballName, integrity });
|
|
3299
|
-
await fs.move(cachedTarFile, tarballPath, { overwrite: true });
|
|
3300
|
-
} else if (protocol.startsWith('file')) {
|
|
3301
|
-
await fs.copy(decodeURIComponent(fileURLToPath(url)), tarballPath);
|
|
3302
|
-
} else {
|
|
3303
|
-
const cancelCtrl = new downloadFile.CancelCtrl();
|
|
3304
|
-
|
|
3305
|
-
if (!ctrlStore[rootDid]) {
|
|
3306
|
-
ctrlStore[rootDid] = new Map();
|
|
3307
|
-
}
|
|
3308
|
-
ctrlStore[rootDid].set(did, cancelCtrl);
|
|
3309
|
-
|
|
3310
|
-
const headers = context.headers ? cloneDeep(context.headers) : {};
|
|
3311
|
-
const exist = (context.downloadTokenList || []).find((x) => x.did === did);
|
|
3312
|
-
if (exist) {
|
|
3313
|
-
headers['x-download-token'] = exist.token;
|
|
3314
|
-
}
|
|
3315
|
-
|
|
3316
|
-
await downloadFile(url, path.join(cwd, tarballName), { cancelCtrl }, { ...context, headers });
|
|
3317
|
-
|
|
3318
|
-
if (ctrlStore[rootDid]) {
|
|
3319
|
-
ctrlStore[rootDid].delete(did);
|
|
3320
|
-
if (!ctrlStore[rootDid].size) {
|
|
3321
|
-
delete ctrlStore[rootDid];
|
|
3322
|
-
}
|
|
3323
|
-
}
|
|
3324
|
-
|
|
3325
|
-
if (cancelCtrl.isCancelled) {
|
|
3326
|
-
return downloadFile.CANCEL;
|
|
3327
|
-
}
|
|
3328
|
-
}
|
|
3329
|
-
|
|
3330
|
-
if (verify) {
|
|
3331
|
-
try {
|
|
3332
|
-
await verifyIntegrity({ file: tarballPath, integrity });
|
|
3333
|
-
} catch (error) {
|
|
3334
|
-
logger.error('verify integrity error', { error, tarball, url });
|
|
3335
|
-
throw new Error(`${tarball} integrity check failed.`);
|
|
3336
|
-
}
|
|
3337
|
-
}
|
|
3338
|
-
|
|
3339
|
-
return tarballPath;
|
|
3340
|
-
}
|
|
3341
|
-
|
|
3342
|
-
/**
|
|
3343
|
-
* use LRU algorithm
|
|
3344
|
-
*/
|
|
3345
|
-
async _addCacheTarFile(tarballPath, integrity) {
|
|
3346
|
-
// eslint-disable-next-line no-param-reassign
|
|
3347
|
-
integrity = toBase58(integrity);
|
|
3348
|
-
|
|
3349
|
-
// move tarball to cache dir
|
|
3350
|
-
const cwd = path.join(this.dataDirs.tmp, 'download-cache');
|
|
3351
|
-
const cachePath = path.join(cwd, `${integrity}.tar.gz`);
|
|
3352
|
-
await fs.ensureDir(cwd);
|
|
3353
|
-
await fs.move(tarballPath, cachePath, { overwrite: true });
|
|
3354
|
-
|
|
3355
|
-
const key = 'blocklet:manager:downloadCache';
|
|
3356
|
-
const cacheList = (await states.cache.get(key)) || [];
|
|
3357
|
-
const exist = cacheList.find((x) => x.integrity === integrity);
|
|
3358
|
-
|
|
3359
|
-
// update
|
|
3360
|
-
if (exist) {
|
|
3361
|
-
logger.info('update cache tarFile', { base58: integrity });
|
|
3362
|
-
exist.accessAt = Date.now();
|
|
3363
|
-
await states.cache.set(key, cacheList);
|
|
3364
|
-
return;
|
|
3365
|
-
}
|
|
3366
|
-
|
|
3367
|
-
// add
|
|
3368
|
-
cacheList.push({ integrity, accessAt: Date.now() });
|
|
3369
|
-
if (cacheList.length > 10) {
|
|
3370
|
-
// find and remove
|
|
3371
|
-
let minIndex = 0;
|
|
3372
|
-
let min = cacheList[0];
|
|
3373
|
-
cacheList.forEach((x, i) => {
|
|
3374
|
-
if (x.accessAt < min.accessAt) {
|
|
3375
|
-
minIndex = i;
|
|
3376
|
-
min = x;
|
|
3377
|
-
}
|
|
3378
|
-
});
|
|
3379
|
-
|
|
3380
|
-
cacheList.splice(minIndex, 1);
|
|
3381
|
-
await fs.remove(path.join(cwd, `${min.integrity}.tar.gz`));
|
|
3382
|
-
logger.info('remove cache tarFile', { base58: min.integrity });
|
|
3383
|
-
}
|
|
3384
|
-
logger.info('add cache tarFile', { base58: integrity });
|
|
3385
|
-
|
|
3386
|
-
// update
|
|
3387
|
-
await states.cache.set(key, cacheList);
|
|
3388
|
-
}
|
|
3389
|
-
|
|
3390
|
-
async _getCachedTarFile(integrity) {
|
|
3391
|
-
// eslint-disable-next-line no-param-reassign
|
|
3392
|
-
integrity = toBase58(integrity);
|
|
3393
|
-
|
|
3394
|
-
const cwd = path.join(this.dataDirs.tmp, 'download-cache');
|
|
3395
|
-
const cachePath = path.join(cwd, `${integrity}.tar.gz`);
|
|
3396
|
-
|
|
3397
|
-
if (fs.existsSync(cachePath)) {
|
|
3398
|
-
return cachePath;
|
|
3399
|
-
}
|
|
3400
|
-
|
|
3401
|
-
return null;
|
|
3402
|
-
}
|
|
3403
|
-
|
|
3404
|
-
/**
|
|
3405
|
-
*
|
|
3406
|
-
*
|
|
3407
|
-
* @param {*} meta
|
|
3408
|
-
* @param {*} rootDid
|
|
3409
|
-
* @param {*} url
|
|
3410
|
-
* @param {{}} [context={}]
|
|
3411
|
-
* @return {*}
|
|
3412
|
-
* @memberof BlockletManager
|
|
3413
|
-
*/
|
|
3414
|
-
async _downloadBundle(meta, rootDid, url, context = {}) {
|
|
3415
|
-
const { bundleName: name, bundleDid: did, version, dist = {} } = meta;
|
|
3416
|
-
const { tarball, integrity } = dist;
|
|
3417
|
-
|
|
3418
|
-
const lockName = `download-${did}-${version}`;
|
|
3419
|
-
let lock = this.downloadLocks[lockName];
|
|
3420
|
-
if (!lock) {
|
|
3421
|
-
lock = new Lock(lockName);
|
|
3422
|
-
this.downloadLocks[lockName] = lock;
|
|
3423
|
-
}
|
|
3424
|
-
|
|
3425
|
-
try {
|
|
3426
|
-
await lock.acquire();
|
|
3427
|
-
logger.info('downloaded blocklet for installing', { name, version, tarball, integrity });
|
|
3428
|
-
const cwd = path.join(this.dataDirs.tmp, 'download', name);
|
|
3429
|
-
await fs.ensureDir(cwd);
|
|
3430
|
-
logger.info('start download blocklet', { name, version, cwd, tarball, integrity });
|
|
3431
|
-
const tarballPath = await this._downloadTarball({
|
|
3432
|
-
name,
|
|
3433
|
-
did,
|
|
3434
|
-
version,
|
|
3435
|
-
cwd,
|
|
3436
|
-
tarball,
|
|
3437
|
-
integrity,
|
|
3438
|
-
verify: true,
|
|
3439
|
-
ctrlStore: this.downloadCtrls,
|
|
3440
|
-
rootDid,
|
|
3441
|
-
url,
|
|
3442
|
-
context,
|
|
3443
|
-
});
|
|
3444
|
-
logger.info('downloaded blocklet tar file', { name, version, tarballPath });
|
|
3445
|
-
if (tarballPath === downloadFile.CANCEL) {
|
|
3446
|
-
lock.release();
|
|
3447
|
-
return { isCancelled: true };
|
|
3448
|
-
}
|
|
3449
|
-
|
|
3450
|
-
// resolve tarball and mv tarball to cache after resolved
|
|
3451
|
-
await this._resolveDownload(cwd, tarballPath, null, { removeTarFile: false });
|
|
3452
|
-
await this._addCacheTarFile(tarballPath, integrity);
|
|
3453
|
-
|
|
3454
|
-
logger.info('resolved blocklet tar file to install dir', { name, version });
|
|
3455
|
-
lock.release();
|
|
3456
|
-
return { isCancelled: false };
|
|
3457
|
-
} catch (error) {
|
|
3458
|
-
lock.release();
|
|
3459
|
-
throw error;
|
|
3460
|
-
}
|
|
3461
|
-
}
|
|
3462
|
-
|
|
3463
3125
|
/**
|
|
3464
3126
|
*
|
|
3465
3127
|
*
|
|
3466
3128
|
* @param {{}} blocklet
|
|
3467
|
-
* @param {{}} [oldBlocklet={}]
|
|
3468
3129
|
* @param {{}} [context={}]
|
|
3469
3130
|
* @return {*}
|
|
3470
3131
|
* @memberof BlockletManager
|
|
3471
3132
|
*/
|
|
3472
|
-
async _downloadBlocklet(blocklet,
|
|
3133
|
+
async _downloadBlocklet(blocklet, context = {}) {
|
|
3473
3134
|
const {
|
|
3474
|
-
meta: {
|
|
3135
|
+
meta: { did },
|
|
3475
3136
|
} = blocklet;
|
|
3476
3137
|
|
|
3477
|
-
|
|
3478
|
-
|
|
3479
|
-
|
|
3480
|
-
|
|
3481
|
-
|
|
3482
|
-
|
|
3483
|
-
|
|
3484
|
-
|
|
3485
|
-
|
|
3486
|
-
|
|
3487
|
-
|
|
3488
|
-
|
|
3489
|
-
|
|
3490
|
-
if (needBlockletDownload(component, oldComponentObj[componentId])) {
|
|
3491
|
-
const bundleId = getComponentBundleId(component);
|
|
3492
|
-
|
|
3493
|
-
if (metaObj[bundleId]) {
|
|
3494
|
-
if (get(component, 'meta.dist.integrity') !== get(metaObj[bundleId], 'dist.integrity')) {
|
|
3495
|
-
// FIXME: what should we do if component bundle integrity not same in different apps
|
|
3496
|
-
logger.error(`find duplicate bundle with different integrity when downloading ${blocklet.meta.title}`, {
|
|
3497
|
-
bundleId,
|
|
3498
|
-
});
|
|
3499
|
-
}
|
|
3500
|
-
|
|
3501
|
-
logger.info(`skip download duplicate bundle ${bundleId}`);
|
|
3502
|
-
return;
|
|
3503
|
-
}
|
|
3504
|
-
|
|
3505
|
-
metaObj[bundleId] = component.meta;
|
|
3506
|
-
metas.push(component.meta);
|
|
3507
|
-
downloadComponentIds.push(componentId);
|
|
3508
|
-
}
|
|
3509
|
-
});
|
|
3510
|
-
|
|
3511
|
-
// update children status
|
|
3512
|
-
const blocklet1 = await states.blocklet.setBlockletStatus(did, BlockletStatus.downloading, {
|
|
3513
|
-
children: downloadComponentIds,
|
|
3138
|
+
return this.blockletDownloader.download(blocklet, {
|
|
3139
|
+
...context,
|
|
3140
|
+
preDownload: async ({ downloadComponentIds }) => {
|
|
3141
|
+
// update children status
|
|
3142
|
+
const blocklet1 = await states.blocklet.setBlockletStatus(did, BlockletStatus.downloading, {
|
|
3143
|
+
children: downloadComponentIds,
|
|
3144
|
+
});
|
|
3145
|
+
this.emit(BlockletEvents.statusChange, blocklet1);
|
|
3146
|
+
},
|
|
3147
|
+
postDownload: async () => {
|
|
3148
|
+
// since preferences only exist in blocklet bundle, we need to populate then after downloaded
|
|
3149
|
+
await this._setConfigsFromMeta(did);
|
|
3150
|
+
},
|
|
3514
3151
|
});
|
|
3515
|
-
this.emit(BlockletEvents.statusChange, blocklet1);
|
|
3516
|
-
|
|
3517
|
-
try {
|
|
3518
|
-
logger.info('Download Blocklet', { name, did, bundles: metas.map((x) => get(x, 'dist.tarball')) });
|
|
3519
|
-
const tasks = [];
|
|
3520
|
-
for (const meta of metas) {
|
|
3521
|
-
const url = meta.dist.tarball;
|
|
3522
|
-
tasks.push(this._downloadBundle(meta, did, url, context));
|
|
3523
|
-
}
|
|
3524
|
-
const results = await Promise.all(tasks);
|
|
3525
|
-
|
|
3526
|
-
// since preferences only exist in blocklet bundle, we need to populate then after downloaded
|
|
3527
|
-
await this._setConfigsFromMeta(did);
|
|
3528
|
-
|
|
3529
|
-
if (results.find((x) => x.isCancelled)) {
|
|
3530
|
-
return { isCancelled: true };
|
|
3531
|
-
}
|
|
3532
|
-
} catch (error) {
|
|
3533
|
-
logger.error('Download blocklet failed', { did, name, error });
|
|
3534
|
-
await this._cancelDownload(blocklet.meta);
|
|
3535
|
-
throw error;
|
|
3536
|
-
}
|
|
3537
|
-
|
|
3538
|
-
return { isCancelled: false };
|
|
3539
3152
|
}
|
|
3540
3153
|
|
|
3541
3154
|
async _syncPm2Status(pm2Status, did) {
|
|
@@ -3551,17 +3164,6 @@ class BlockletManager extends BaseBlockletManager {
|
|
|
3551
3164
|
}
|
|
3552
3165
|
}
|
|
3553
3166
|
|
|
3554
|
-
// eslint-disable-next-line no-unused-vars
|
|
3555
|
-
async _cancelDownload(blockletMeta, context) {
|
|
3556
|
-
const { did } = blockletMeta;
|
|
3557
|
-
|
|
3558
|
-
if (this.downloadCtrls[did]) {
|
|
3559
|
-
for (const cancelCtrl of this.downloadCtrls[did].values()) {
|
|
3560
|
-
cancelCtrl.cancel();
|
|
3561
|
-
}
|
|
3562
|
-
}
|
|
3563
|
-
}
|
|
3564
|
-
|
|
3565
3167
|
// eslint-disable-next-line no-unused-vars
|
|
3566
3168
|
async _cancelWaiting(blockletMeta, context) {
|
|
3567
3169
|
const { did } = blockletMeta;
|
|
@@ -3848,48 +3450,55 @@ class BlockletManager extends BaseBlockletManager {
|
|
|
3848
3450
|
async _deleteExpiredExternalBlocklet() {
|
|
3849
3451
|
try {
|
|
3850
3452
|
logger.info('start check expired external blocklet');
|
|
3851
|
-
const
|
|
3852
|
-
|
|
3853
|
-
|
|
3453
|
+
const blockletExtras = await states.blockletExtras.find(
|
|
3454
|
+
{
|
|
3455
|
+
controller: {
|
|
3456
|
+
$exists: true,
|
|
3457
|
+
},
|
|
3458
|
+
'controller.expiredAt': {
|
|
3459
|
+
$exists: false,
|
|
3460
|
+
},
|
|
3854
3461
|
},
|
|
3855
|
-
|
|
3856
|
-
|
|
3857
|
-
const nodeInfo = await states.node.read();
|
|
3462
|
+
{ did: 1, meta: 1, controller: 1 }
|
|
3463
|
+
);
|
|
3858
3464
|
|
|
3859
|
-
const
|
|
3465
|
+
for (const data of blockletExtras) {
|
|
3860
3466
|
try {
|
|
3861
|
-
const assetState = await getNFTState(
|
|
3467
|
+
const assetState = await util.getNFTState(data.controller.chainHost, data.controller.nftId);
|
|
3862
3468
|
const isExpired = isNFTExpired(assetState);
|
|
3469
|
+
|
|
3863
3470
|
if (isExpired) {
|
|
3864
3471
|
logger.info('the blocklet already expired', {
|
|
3865
|
-
|
|
3866
|
-
nftId:
|
|
3472
|
+
blockletDid: data.meta.did,
|
|
3473
|
+
nftId: data.controller.nftId,
|
|
3867
3474
|
});
|
|
3868
3475
|
|
|
3869
|
-
await this.delete({ did:
|
|
3476
|
+
await this.delete({ did: data.meta.did, keepData: true, keepConfigs: true, keepLogsDir: true });
|
|
3870
3477
|
logger.info('the expired blocklet already deleted', {
|
|
3871
|
-
|
|
3872
|
-
nftId:
|
|
3873
|
-
did: blocklet.meta.did,
|
|
3478
|
+
blockletDid: data.meta.did,
|
|
3479
|
+
nftId: data.controller.nftId,
|
|
3874
3480
|
});
|
|
3875
3481
|
|
|
3876
3482
|
const expiredAt = getNftExpirationDate(assetState);
|
|
3877
|
-
await states.blockletExtras.updateExpireInfo({ did:
|
|
3483
|
+
await states.blockletExtras.updateExpireInfo({ did: data.meta.did, expiredAt });
|
|
3878
3484
|
logger.info('updated expired blocklet extra info', {
|
|
3879
|
-
|
|
3880
|
-
|
|
3881
|
-
did: blocklet.meta.did,
|
|
3485
|
+
nftId: data.controller.nftId,
|
|
3486
|
+
blockletDid: data.meta.did,
|
|
3882
3487
|
});
|
|
3488
|
+
|
|
3489
|
+
// 删除 blocklet 后会 reload nginx, 所以这里每次删除一个
|
|
3490
|
+
if (process.env.NODE_ENV !== 'test') {
|
|
3491
|
+
await sleep(10 * 1000);
|
|
3492
|
+
}
|
|
3883
3493
|
}
|
|
3884
3494
|
} catch (error) {
|
|
3885
|
-
logger.error('
|
|
3886
|
-
|
|
3887
|
-
nftId:
|
|
3495
|
+
logger.error('delete expired blocklet failed', {
|
|
3496
|
+
blockletDid: data.meta.did,
|
|
3497
|
+
nftId: data.controller.nftId,
|
|
3498
|
+
error,
|
|
3888
3499
|
});
|
|
3889
3500
|
}
|
|
3890
|
-
}
|
|
3891
|
-
|
|
3892
|
-
await Promise.all(tasks);
|
|
3501
|
+
}
|
|
3893
3502
|
|
|
3894
3503
|
logger.info('check expired external blocklet end');
|
|
3895
3504
|
} catch (error) {
|
|
@@ -3960,7 +3569,7 @@ class BlockletManager extends BaseBlockletManager {
|
|
|
3960
3569
|
await didDocument.updateBlockletDocument({
|
|
3961
3570
|
wallet,
|
|
3962
3571
|
blockletAppDid: appSystemEnvironments.BLOCKLET_APP_ID,
|
|
3963
|
-
daemonDidDomain: getServerDidDomain(nodeInfo),
|
|
3572
|
+
daemonDidDomain: util.getServerDidDomain(nodeInfo),
|
|
3964
3573
|
didRegistryUrl: nodeInfo.didRegistry,
|
|
3965
3574
|
domain: nodeInfo.didDomain,
|
|
3966
3575
|
});
|