@abtnode/core 1.8.65-beta-f7af64a4 → 1.8.65-beta-bfcc12ce

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.
@@ -32,7 +32,10 @@ const isMetaFileExist = (dir) => {
32
32
  * }}
33
33
  * @returns {boolean}
34
34
  */
35
- const needDownload = (component, { installDir, logger = defaultLogger, cachedBundles = [] } = {}) => {
35
+ const needDownload = (
36
+ component,
37
+ { installDir, logger = defaultLogger, cachedBundles = [], skipCheckIntegrity } = {}
38
+ ) => {
36
39
  if (component.mode === BLOCKLET_MODES.DEVELOPMENT) {
37
40
  return false;
38
41
  }
@@ -62,10 +65,15 @@ const needDownload = (component, { installDir, logger = defaultLogger, cachedBun
62
65
  return false;
63
66
  }
64
67
 
68
+ if (skipCheckIntegrity) {
69
+ return false;
70
+ }
71
+
65
72
  // check integrity
66
73
 
67
74
  const cachedBundle = cachedBundles.find((x) => x.bundleId === bundleId);
68
75
 
76
+ // FIXME: 不是新安装的组件不应该 check, 不应该 block 安装成功 https://github.com/blocklet/launcher/actions/runs/4184577090/jobs/7250416272
69
77
  if (!cachedBundle) {
70
78
  return true;
71
79
  }
@@ -84,10 +92,12 @@ const needDownload = (component, { installDir, logger = defaultLogger, cachedBun
84
92
  class BlockletDownloader extends EventEmitter {
85
93
  /**
86
94
  * @param {{
95
+ * installDir: string,
96
+ * downloadDir: string,
87
97
  * cache: {
88
98
  * set: (key: string, value: any) => Promise
89
99
  * get: (key: string) => Promise<any>
90
- * }
100
+ * },
91
101
  * }}
92
102
  */
93
103
  constructor({ installDir, downloadDir, cache, logger = defaultLogger }) {
@@ -106,20 +116,25 @@ class BlockletDownloader extends EventEmitter {
106
116
 
107
117
  /**
108
118
  * @param {{}} blocklet
109
- * @param {{}} [context={}]
119
+ * @param {{
120
+ * preDownload: ({ downloadList: Array<meta>, downloadComponentIds: Array<string> }) => any
121
+ * postDownload: ({ downloadList: Array<meta>, downloadComponentIds: Array<string>, isCancelled: boolean }) => any
122
+ * skipCheckIntegrity: boolean
123
+ * }} [options={}]
110
124
  * @return {*}
111
125
  */
112
- async download(blocklet, context = {}) {
126
+ async download(blocklet, options = {}) {
113
127
  const {
114
128
  meta: { name, did },
115
129
  } = blocklet;
116
130
 
117
131
  this.logger.info('Download Blocklet', { name, did });
118
132
 
119
- const { preDownload = () => {}, postDownload = () => {} } = context;
133
+ const { preDownload = () => {}, postDownload = () => {}, skipCheckIntegrity } = options;
120
134
 
121
135
  const { downloadComponentIds, downloadList } = await this.getDownloadList({
122
136
  blocklet,
137
+ skipCheckIntegrity,
123
138
  });
124
139
 
125
140
  await preDownload({ downloadList, downloadComponentIds });
@@ -133,13 +148,15 @@ class BlockletDownloader extends EventEmitter {
133
148
  const tasks = [];
134
149
  for (const meta of downloadList) {
135
150
  const url = meta.dist.tarball;
136
- tasks.push(this.bundleDownloader.download(meta, did, url, context));
151
+ tasks.push(this.bundleDownloader.download(meta, did, url, options));
137
152
  }
138
153
  const results = await Promise.all(tasks);
139
154
 
140
- await postDownload({ downloadList, downloadComponentIds });
155
+ const isCancelled = results.some((x) => x.isCancelled);
156
+
157
+ await postDownload({ downloadList, downloadComponentIds, isCancelled });
141
158
 
142
- if (results.find((x) => x.isCancelled)) {
159
+ if (isCancelled) {
143
160
  return { isCancelled: true };
144
161
  }
145
162
  } catch (error) {
@@ -160,11 +177,11 @@ class BlockletDownloader extends EventEmitter {
160
177
  * blocklet;
161
178
  * }}
162
179
  * @returns {{
163
- * downloadList: Array<blockletMeta>;
164
- * downloadComponentIds: Array<string>;
180
+ * downloadList: Array<import('@abtnode/client').BlockletMeta>;
181
+ * downloadComponentIds: Array<string>; // like: "z8ia1i2yq67x39vruqQTbkVcwCnqRGx8zSPsJ/z8iZwubkNdA1BfEUwc5NJpY2Jnfm7yEbyvmKS"
165
182
  * }}
166
183
  */
167
- async getDownloadList({ blocklet }) {
184
+ async getDownloadList({ blocklet, skipCheckIntegrity }) {
168
185
  const downloadComponentIds = [];
169
186
  const metas = {};
170
187
 
@@ -178,7 +195,11 @@ class BlockletDownloader extends EventEmitter {
178
195
  return;
179
196
  }
180
197
 
181
- const needComponentDownload = needDownload(component, { installDir: this.installDir, cachedBundles });
198
+ const needComponentDownload = needDownload(component, {
199
+ installDir: this.installDir,
200
+ cachedBundles,
201
+ skipCheckIntegrity,
202
+ });
182
203
  if (!needComponentDownload) {
183
204
  this.logger.info(`skip download existed bundle ${bundleId}`, { source: component.source });
184
205
  return;
@@ -129,6 +129,7 @@ const { SpacesRestore } = require('../storage/restore/spaces');
129
129
  const installFromBackup = require('./helper/install-from-backup');
130
130
  const { resolveDownload, resolveDiffDownload } = require('../downloader/resolve-download');
131
131
  const BlockletDownloader = require('../downloader/blocklet-downloader');
132
+ const RollbackCache = require('./helper/rollback-cache');
132
133
 
133
134
  const {
134
135
  isInProgress,
@@ -218,6 +219,8 @@ class BlockletManager extends BaseBlockletManager {
218
219
  cache: states.cache,
219
220
  });
220
221
 
222
+ this._rollbackCache = new RollbackCache({ dir: this.dataDirs.tmp });
223
+
221
224
  if (daemon) {
222
225
  blockletPm2Events.on('online', (data) => this._syncPm2Status('online', data.blockletDid));
223
226
  blockletPm2Events.on('stop', (data) => this._syncPm2Status('stop', data.blockletDid));
@@ -255,6 +258,10 @@ class BlockletManager extends BaseBlockletManager {
255
258
  async install(params, context = {}) {
256
259
  logger.debug('install blocklet', { params, context });
257
260
 
261
+ if (!params.controller && context?.user?.controller) {
262
+ params.controller = context.user.controller;
263
+ }
264
+
258
265
  const info = await states.node.read();
259
266
 
260
267
  context.headers = Object.assign(context?.headers || {}, {
@@ -839,12 +846,13 @@ class BlockletManager extends BaseBlockletManager {
839
846
  return newBlocklet;
840
847
  }
841
848
 
849
+ // eslint-disable-next-line no-unused-vars
842
850
  async cancelDownload({ did: inputDid }, context) {
843
851
  try {
844
852
  await statusLock.acquire();
845
853
  const blocklet = await states.blocklet.getBlocklet(inputDid);
846
854
  if (!blocklet) {
847
- throw new Error('Can not cancel download for non-exist blocklet in database.', { inputDid });
855
+ throw new Error(`Can not cancel download for non-exist blocklet in database. did: ${inputDid}`);
848
856
  }
849
857
 
850
858
  const { name, did, version } = blocklet.meta;
@@ -854,15 +862,35 @@ class BlockletManager extends BaseBlockletManager {
854
862
  }
855
863
 
856
864
  const job = await this.installQueue.get(did);
857
- if (job) {
858
- const { postAction, oldBlocklet } = job;
859
- await this._rollback(postAction, did, oldBlocklet);
860
- }
861
865
 
866
+ // cancel job
862
867
  if (blocklet.status === BlockletStatus.downloading) {
863
- await this.blockletDownloader.cancelDownload(blocklet.meta.did);
868
+ try {
869
+ await this.blockletDownloader.cancelDownload(blocklet.meta.did);
870
+ } catch (error) {
871
+ logger.error('failed to exec blockletDownloader.download', { did: blocklet.meta.did, error });
872
+ }
864
873
  } else if (blocklet.status === BlockletStatus.waiting) {
865
- await this._cancelWaiting(blocklet.meta, context);
874
+ try {
875
+ await this.installQueue.cancel(blocklet.meta.did);
876
+ } catch (error) {
877
+ logger.error('failed to cancel waiting', { did: blocklet.meta.did, error });
878
+ }
879
+ }
880
+
881
+ // rollback
882
+ if (job) {
883
+ const { postAction, oldBlocklet } = job;
884
+ await this._rollback(postAction, did, oldBlocklet);
885
+ } else {
886
+ const data = await this._rollbackCache.restore({ did });
887
+ if (data) {
888
+ const { action, oldBlocklet } = data;
889
+ await this._rollback(action, did, oldBlocklet);
890
+ await this._rollbackCache.remove({ did });
891
+ } else {
892
+ throw new Error(`Cannot find rollback data in queue or backup file of blocklet ${inputDid}`);
893
+ }
866
894
  }
867
895
 
868
896
  logger.info('cancel download blocklet', { did, name, version, status: fromBlockletStatus(blocklet.status) });
@@ -870,7 +898,18 @@ class BlockletManager extends BaseBlockletManager {
870
898
  statusLock.release();
871
899
  return blocklet;
872
900
  } catch (error) {
873
- statusLock.release();
901
+ try {
902
+ // fallback blocklet status to error
903
+ const blocklet = await states.blocklet.getBlocklet(inputDid);
904
+ if (blocklet) {
905
+ await states.blocklet.setBlockletStatus(blocklet.meta.did, BlockletStatus.error);
906
+ }
907
+ statusLock.release();
908
+ } catch (err) {
909
+ statusLock.release();
910
+ logger.error('Failed to fallback blocklet status to error on cancelDownload', { error });
911
+ }
912
+
874
913
  throw error;
875
914
  }
876
915
  }
@@ -1425,6 +1464,9 @@ class BlockletManager extends BaseBlockletManager {
1425
1464
 
1426
1465
  this.emit(BlockletEvents.statusChange, newBlocklet);
1427
1466
 
1467
+ // backup rollback data
1468
+ await this._rollbackCache.backup({ did, action, oldBlocklet });
1469
+
1428
1470
  // add to queue
1429
1471
  const ticket = this.installQueue.push(
1430
1472
  {
@@ -1722,7 +1764,7 @@ class BlockletManager extends BaseBlockletManager {
1722
1764
  async onJob(job) {
1723
1765
  if (job.entity === 'blocklet') {
1724
1766
  if (job.action === 'download') {
1725
- await this.onDownload(job);
1767
+ await this.downloadAndInstall(job);
1726
1768
  }
1727
1769
  if (job.action === 'restart') {
1728
1770
  await this.onRestart(job);
@@ -1747,33 +1789,35 @@ class BlockletManager extends BaseBlockletManager {
1747
1789
  * @return {*}
1748
1790
  * @memberof BlockletManager
1749
1791
  */
1750
- async onDownload(params) {
1751
- const { blocklet, context, postAction, oldBlocklet, throwOnError } = params;
1792
+ async downloadAndInstall(params) {
1793
+ const { blocklet, context, postAction, oldBlocklet, throwOnError, skipCheckStatusBeforeDownload } = params;
1752
1794
  const { meta } = blocklet;
1753
1795
  const { name, did, version } = meta;
1754
1796
 
1755
1797
  // check status
1756
- try {
1757
- await statusLock.acquire();
1758
-
1759
- const b0 = await states.blocklet.getBlocklet(did);
1760
- if (!b0 || ![BlockletStatus.waiting].includes(b0.status)) {
1761
- if (!b0) {
1762
- throw new Error('blocklet does not exist before downloading');
1763
- } else {
1764
- throw new Error(`blocklet status is invalid before downloading: ${fromBlockletStatus(b0.status)}`);
1798
+ if (!skipCheckStatusBeforeDownload) {
1799
+ try {
1800
+ await statusLock.acquire();
1801
+
1802
+ const b0 = await states.blocklet.getBlocklet(did);
1803
+ if (!b0 || ![BlockletStatus.waiting].includes(b0.status)) {
1804
+ if (!b0) {
1805
+ throw new Error('blocklet does not exist before downloading');
1806
+ } else {
1807
+ throw new Error(`blocklet status is invalid before downloading: ${fromBlockletStatus(b0.status)}`);
1808
+ }
1765
1809
  }
1810
+ statusLock.release();
1811
+ } catch (error) {
1812
+ statusLock.release();
1813
+ logger.error('Check blocklet status failed before downloading', {
1814
+ name,
1815
+ did,
1816
+ error,
1817
+ });
1818
+ await this._rollback(postAction, did, oldBlocklet);
1819
+ return;
1766
1820
  }
1767
- statusLock.release();
1768
- } catch (error) {
1769
- statusLock.release();
1770
- logger.error('Check blocklet status failed before downloading', {
1771
- name,
1772
- did,
1773
- error,
1774
- });
1775
- await this._rollback(postAction, did, oldBlocklet);
1776
- return;
1777
1821
  }
1778
1822
 
1779
1823
  // download bundle
@@ -1783,8 +1827,16 @@ class BlockletManager extends BaseBlockletManager {
1783
1827
  if (isCancelled) {
1784
1828
  logger.info('Download was canceled', { name, did, version });
1785
1829
 
1786
- if ((await states.blocklet.getBlockletStatus(did)) === BlockletStatus.downloading) {
1787
- await this._rollback(postAction, did, oldBlocklet);
1830
+ // rollback on download cancelled
1831
+ await statusLock.acquire();
1832
+ try {
1833
+ if ((await states.blocklet.getBlockletStatus(did)) === BlockletStatus.downloading) {
1834
+ await this._rollback(postAction, did, oldBlocklet);
1835
+ }
1836
+ statusLock.release();
1837
+ } catch (error) {
1838
+ statusLock.release();
1839
+ logger.error('Rollback blocklet failed on download canceled', { postAction, name, did, version, error });
1788
1840
  }
1789
1841
  return;
1790
1842
  }
@@ -1805,10 +1857,16 @@ class BlockletManager extends BaseBlockletManager {
1805
1857
  severity: 'error',
1806
1858
  });
1807
1859
 
1860
+ // rollback on download failed
1861
+ await statusLock.acquire();
1808
1862
  try {
1809
- await this._rollback(postAction, did, oldBlocklet);
1810
- } catch (e) {
1811
- logger.error('Rollback blocklet failed', { postAction, name, did, version });
1863
+ if ((await states.blocklet.getBlockletStatus(did)) === BlockletStatus.downloading) {
1864
+ await this._rollback(postAction, did, oldBlocklet);
1865
+ }
1866
+ statusLock.release();
1867
+ } catch (error) {
1868
+ statusLock.release();
1869
+ logger.error('Rollback blocklet failed on download failed', { postAction, name, did, version, error });
1812
1870
  }
1813
1871
 
1814
1872
  if (throwOnError) {
@@ -2336,13 +2394,20 @@ class BlockletManager extends BaseBlockletManager {
2336
2394
  newBlocklet.deployedFrom = `Upload by ${context.user.fullName}`;
2337
2395
  newBlocklet.children = await this._getChildrenForInstallation(meta);
2338
2396
  await validateBlocklet(newBlocklet);
2339
- await this._downloadBlocklet(newBlocklet);
2340
2397
 
2341
- return this._upgradeBlocklet({
2398
+ // backup rollback data
2399
+ const action = 'upgrade';
2400
+ await this._rollbackCache.backup({ did: newBlocklet.meta.did, action, oldBlocklet });
2401
+
2402
+ await this.downloadAndInstall({
2403
+ blocklet: newBlocklet,
2342
2404
  oldBlocklet,
2343
- newBlocklet,
2344
2405
  context: { ...context, forceStartProcessIds: [getComponentProcessId(newBlocklet)] },
2406
+ throwOnError: true,
2407
+ postAction: action,
2408
+ skipCheckStatusBeforeDownload: true,
2345
2409
  });
2410
+ return this.getBlocklet(newBlocklet.meta.did);
2346
2411
  }
2347
2412
 
2348
2413
  // full deploy
@@ -2362,14 +2427,20 @@ class BlockletManager extends BaseBlockletManager {
2362
2427
  newBlocklet.deployedFrom = `Upload by ${context.user.fullName}`;
2363
2428
  newBlocklet.children = await this._getChildrenForInstallation(meta);
2364
2429
 
2365
- await validateBlocklet(newBlocklet);
2366
- await this._downloadBlocklet(newBlocklet);
2430
+ // backup rollback data
2431
+ const action = 'upgrade';
2432
+ await this._rollbackCache.backup({ did: newBlocklet.meta.did, action, oldBlocklet });
2367
2433
 
2368
- return this._upgradeBlocklet({
2434
+ await validateBlocklet(newBlocklet);
2435
+ await this.downloadAndInstall({
2436
+ blocklet: newBlocklet,
2369
2437
  oldBlocklet,
2370
- newBlocklet,
2371
2438
  context: { ...context, forceStartProcessIds: [getComponentProcessId(newBlocklet)] },
2439
+ throwOnError: true,
2440
+ postAction: action,
2441
+ skipCheckStatusBeforeDownload: true,
2372
2442
  });
2443
+ return this.getBlocklet(newBlocklet.meta.did);
2373
2444
  }
2374
2445
 
2375
2446
  // full deploy - install
@@ -2383,25 +2454,31 @@ class BlockletManager extends BaseBlockletManager {
2383
2454
  children,
2384
2455
  });
2385
2456
 
2457
+ const action = 'install';
2458
+ const oldState = { extraState: oldExtraState };
2386
2459
  try {
2387
2460
  await this._setConfigsFromMeta(meta.did);
2388
2461
  await validateBlocklet(blocklet);
2389
2462
 
2390
2463
  // check duplicate appSk
2391
2464
  await checkDuplicateAppSk({ did: meta.did, states });
2392
-
2393
- // download
2394
- await this._downloadBlocklet(blocklet);
2395
-
2396
- return this._installBlocklet({
2397
- did: meta.did,
2398
- context,
2399
- oldBlocklet: { extraState: oldExtraState },
2400
- });
2401
2465
  } catch (error) {
2402
- await this._rollback('install', meta.did, { extraState: oldExtraState });
2466
+ await this._rollback(action, meta.did, oldState);
2403
2467
  throw error;
2404
2468
  }
2469
+
2470
+ // backup rollback data
2471
+ await this._rollbackCache.backup({ did: meta.did, action, oldBlocklet: oldState });
2472
+
2473
+ await this.downloadAndInstall({
2474
+ blocklet,
2475
+ oldBlocklet: oldState,
2476
+ context,
2477
+ throwOnError: true,
2478
+ postAction: action,
2479
+ skipCheckStatusBeforeDownload: true,
2480
+ });
2481
+ return this.getBlocklet(meta.did);
2405
2482
  }
2406
2483
 
2407
2484
  async _installComponentFromUpload({
@@ -2482,34 +2559,19 @@ class BlockletManager extends BaseBlockletManager {
2482
2559
 
2483
2560
  await this._upsertDynamicNavigation(newBlocklet.meta.did, newChild, { skipNavigation });
2484
2561
 
2485
- await this._downloadBlocklet(newBlocklet);
2486
-
2487
- await validateBlocklet(newBlocklet);
2562
+ // backup rollback data
2563
+ const action = 'upgrade';
2564
+ await this._rollbackCache.backup({ did: newBlocklet.meta.did, action, oldBlocklet });
2488
2565
 
2489
- return this._upgradeBlocklet({
2566
+ await this.downloadAndInstall({
2567
+ blocklet: newBlocklet,
2490
2568
  oldBlocklet,
2491
- newBlocklet,
2492
2569
  context: { ...context, forceStartProcessIds: [getComponentProcessId(newChild, [newBlocklet])] },
2570
+ throwOnError: true,
2571
+ postAction: action,
2572
+ skipCheckStatusBeforeDownload: true,
2493
2573
  });
2494
- }
2495
-
2496
- /**
2497
- * add to download job queue
2498
- * @param {string} did blocklet did
2499
- * @param {object} blocklet object
2500
- */
2501
- async download(did, blocklet) {
2502
- await states.blocklet.setBlockletStatus(did, BlockletStatus.waiting);
2503
- this.installQueue.push(
2504
- {
2505
- entity: 'blocklet',
2506
- action: 'download',
2507
- id: did,
2508
- blocklet: { ...blocklet },
2509
- postAction: 'install',
2510
- },
2511
- did
2512
- );
2574
+ return this.getBlocklet(newBlocklet.meta.did);
2513
2575
  }
2514
2576
 
2515
2577
  async prune() {
@@ -2732,6 +2794,11 @@ class BlockletManager extends BaseBlockletManager {
2732
2794
  const blocklet1 = await states.blocklet.setBlockletStatus(did, BlockletStatus.waiting);
2733
2795
  this.emit(BlockletEvents.added, blocklet1);
2734
2796
 
2797
+ const action = 'install';
2798
+ const oldBlocklet = {
2799
+ extraState: oldExtraState,
2800
+ };
2801
+
2735
2802
  /** @type {{
2736
2803
  * blocklet: any;
2737
2804
  * oldBlocklet: {
@@ -2743,16 +2810,16 @@ class BlockletManager extends BaseBlockletManager {
2743
2810
  * }} */
2744
2811
  const downloadParams = {
2745
2812
  blocklet: { ...blocklet1 },
2746
- oldBlocklet: {
2747
- children: children.filter((x) => x.dynamic), // let downloader skip re-downloading dynamic blocklet
2748
- extraState: oldExtraState,
2749
- },
2750
2813
  context,
2751
- postAction: 'install',
2814
+ postAction: action,
2815
+ oldBlocklet,
2752
2816
  };
2753
2817
 
2818
+ // backup rollback data
2819
+ await this._rollbackCache.backup({ did, action, oldBlocklet });
2820
+
2754
2821
  if (sync) {
2755
- await this.onDownload({ ...downloadParams, throwOnError: true });
2822
+ await this.downloadAndInstall({ ...downloadParams, throwOnError: true });
2756
2823
  return states.blocklet.getBlocklet(did);
2757
2824
  }
2758
2825
 
@@ -2863,8 +2930,11 @@ class BlockletManager extends BaseBlockletManager {
2863
2930
  postAction: action,
2864
2931
  };
2865
2932
 
2933
+ // backup rollback data
2934
+ await this._rollbackCache.backup({ did, action, oldBlocklet });
2935
+
2866
2936
  if (sync) {
2867
- await this.onDownload({ ...downloadParams, throwOnError: true });
2937
+ await this.downloadAndInstall({ ...downloadParams, throwOnError: true });
2868
2938
  return states.blocklet.getBlocklet(did);
2869
2939
  }
2870
2940
  const ticket = this.installQueue.push(
@@ -2961,6 +3031,8 @@ class BlockletManager extends BaseBlockletManager {
2961
3031
  entityId: did,
2962
3032
  severity: 'success',
2963
3033
  });
3034
+
3035
+ await this._rollbackCache.remove({ did: blocklet.meta.did });
2964
3036
  return blocklet;
2965
3037
  } catch (err) {
2966
3038
  const { meta } = await states.blocklet.getBlocklet(did);
@@ -3087,6 +3159,8 @@ class BlockletManager extends BaseBlockletManager {
3087
3159
  // Update dynamic component meta in blocklet settings
3088
3160
  await this._ensureDynamicChildrenInSettings(blocklet);
3089
3161
 
3162
+ await this._rollbackCache.remove({ did: blocklet.meta.did });
3163
+
3090
3164
  return blocklet;
3091
3165
  } catch (err) {
3092
3166
  const b = await this._rollback(action, did, oldBlocklet);
@@ -3150,9 +3224,11 @@ class BlockletManager extends BaseBlockletManager {
3150
3224
  });
3151
3225
  this.emit(BlockletEvents.statusChange, blocklet1);
3152
3226
  },
3153
- postDownload: async () => {
3154
- // since preferences only exist in blocklet bundle, we need to populate then after downloaded
3155
- await this._setConfigsFromMeta(did);
3227
+ postDownload: async ({ isCancelled }) => {
3228
+ if (!isCancelled) {
3229
+ // since preferences only exist in blocklet bundle, we need to populate then after downloaded
3230
+ await this._setConfigsFromMeta(did);
3231
+ }
3156
3232
  },
3157
3233
  });
3158
3234
  }
@@ -3170,12 +3246,6 @@ class BlockletManager extends BaseBlockletManager {
3170
3246
  }
3171
3247
  }
3172
3248
 
3173
- // eslint-disable-next-line no-unused-vars
3174
- async _cancelWaiting(blockletMeta, context) {
3175
- const { did } = blockletMeta;
3176
- return this.installQueue.cancel(did);
3177
- }
3178
-
3179
3249
  /**
3180
3250
  * @param {string} action install, upgrade, downgrade
3181
3251
  * @param {string} did
@@ -3343,7 +3413,7 @@ class BlockletManager extends BaseBlockletManager {
3343
3413
  }
3344
3414
 
3345
3415
  async _getBlockletForInstallation(did) {
3346
- const blocklet = await states.blocklet.getBlocklet(did);
3416
+ const blocklet = await states.blocklet.getBlocklet(did, { decryptSk: false });
3347
3417
  if (!blocklet) {
3348
3418
  return null;
3349
3419
  }
@@ -11,6 +11,14 @@ const logger = require('@abtnode/logger')('@abtnode/core:install-from-backup');
11
11
 
12
12
  const { validateBlocklet, checkDuplicateAppSk, getAppDirs } = require('../../../util/blocklet');
13
13
 
14
+ /**
15
+ *
16
+ * @param {{
17
+ * manager: import('../disk'),
18
+ * states: import('../../../states/index')
19
+ * }} param0
20
+ * @returns
21
+ */
14
22
  module.exports = async ({ url, blockletSecretKey, moveDir, context = {}, states, manager } = {}) => {
15
23
  // TODO: support more url schema feature (http, did-spaces)
16
24
  if (!url.startsWith('file://')) {
@@ -24,11 +32,7 @@ module.exports = async ({ url, blockletSecretKey, moveDir, context = {}, states,
24
32
  }
25
33
 
26
34
  // parse data from source dir
27
-
28
35
  const srcBundleDirs = await getAppDirs(path.join(dir, 'blocklets'));
29
- if (!srcBundleDirs.length) {
30
- throw new Error(`bundle dirs does not found in ${dir}`);
31
- }
32
36
 
33
37
  const srcDataDir = path.join(dir, 'data');
34
38
 
@@ -61,6 +65,7 @@ module.exports = async ({ url, blockletSecretKey, moveDir, context = {}, states,
61
65
 
62
66
  // FIXME: meta.did and meta.name should be dynamic created when installing multiple blocklet is supported
63
67
  const existState = await states.blocklet.hasBlocklet(did);
68
+
64
69
  if (existState) {
65
70
  logger.error('blocklet is already exist', { did });
66
71
  throw new Error('blocklet is already exist');
@@ -133,6 +138,8 @@ module.exports = async ({ url, blockletSecretKey, moveDir, context = {}, states,
133
138
  logger.info(`bundle is ${moveDir ? 'moved' : 'copied'} successfully`, { installDir });
134
139
  })
135
140
  );
141
+ // 从 store 下载 blocklet
142
+ await manager.blockletDownloader.download(state, { skipCheckIntegrity: true });
136
143
 
137
144
  // FIXME same as copy extra
138
145
  const dataDir = path.join(manager.dataDirs.data, appName);
@@ -0,0 +1,41 @@
1
+ const fs = require('fs-extra');
2
+ const path = require('path');
3
+
4
+ const DIR_NAME = 'rollback-cache';
5
+ const security = require('@abtnode/util/lib/security');
6
+
7
+ class RollbackCache {
8
+ constructor({ dir, dek }) {
9
+ this.dir = dir;
10
+ this.dek = dek;
11
+ }
12
+
13
+ async backup({ did, action, oldBlocklet }) {
14
+ const file = this._getFile(did);
15
+ const data = this.dek ? security.encrypt(JSON.stringify(oldBlocklet), did, this.dek) : oldBlocklet;
16
+ await fs.outputJSON(file, { action, oldBlocklet: data });
17
+ }
18
+
19
+ async remove({ did }) {
20
+ const file = this._getFile(did);
21
+ await fs.remove(file);
22
+ }
23
+
24
+ async restore({ did }) {
25
+ const file = this._getFile(did);
26
+ if (fs.existsSync(file)) {
27
+ const data = await fs.readJSON(file);
28
+ if (data?.oldBlocklet && this.dek) {
29
+ data.oldBlocklet = JSON.parse(security.decrypt(data.oldBlocklet, did, this.dek));
30
+ }
31
+ return data;
32
+ }
33
+ return null;
34
+ }
35
+
36
+ _getFile(did) {
37
+ return path.join(this.dir, DIR_NAME, `${did}.json`);
38
+ }
39
+ }
40
+
41
+ module.exports = RollbackCache;
@@ -75,6 +75,10 @@ class BlockletExtrasBackup extends BaseBackup {
75
75
  * @memberof BlockletExtrasBackup
76
76
  */
77
77
  useBlockletEncryptConfigs(configs) {
78
+ if (isEmpty(configs)) {
79
+ return;
80
+ }
81
+
78
82
  // 准备加解密所需的参数
79
83
  // @see: https://github.com/ArcBlock/blocklet-server/blob/f561ba7290285f2e23dccb6d5323eb4d43c3cc3e/core/state/lib/index.js#L59
80
84
  const dek = readFileSync(join(this.serverDataDir, '.sock'));