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

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
  {
@@ -1433,6 +1475,7 @@ class BlockletManager extends BaseBlockletManager {
1433
1475
  id: did,
1434
1476
  oldBlocklet: { ...oldBlocklet },
1435
1477
  blocklet: { ...newBlocklet },
1478
+ selectedComponentDids: selectedComponentDids || [],
1436
1479
  version,
1437
1480
  context,
1438
1481
  postAction: action,
@@ -1722,7 +1765,7 @@ class BlockletManager extends BaseBlockletManager {
1722
1765
  async onJob(job) {
1723
1766
  if (job.entity === 'blocklet') {
1724
1767
  if (job.action === 'download') {
1725
- await this.onDownload(job);
1768
+ await this.downloadAndInstall(job);
1726
1769
  }
1727
1770
  if (job.action === 'restart') {
1728
1771
  await this.onRestart(job);
@@ -1742,49 +1785,78 @@ class BlockletManager extends BaseBlockletManager {
1742
1785
  * context: {},
1743
1786
  * postAction: 'install' | 'upgrade' | 'downgrade',
1744
1787
  * oldBlocklet: {},
1745
- * throwOnError: Error
1788
+ * throwOnError: Error,
1789
+ * skipCheckStatusBeforeDownload: boolean,
1790
+ * selectedComponentDids: Array<did>,
1746
1791
  * }} params
1747
1792
  * @return {*}
1748
1793
  * @memberof BlockletManager
1749
1794
  */
1750
- async onDownload(params) {
1751
- const { blocklet, context, postAction, oldBlocklet, throwOnError } = params;
1795
+ async downloadAndInstall(params) {
1796
+ const {
1797
+ blocklet,
1798
+ context,
1799
+ postAction,
1800
+ oldBlocklet,
1801
+ throwOnError,
1802
+ skipCheckStatusBeforeDownload,
1803
+ selectedComponentDids,
1804
+ } = params;
1752
1805
  const { meta } = blocklet;
1753
1806
  const { name, did, version } = meta;
1754
1807
 
1755
1808
  // 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)}`);
1809
+ if (!skipCheckStatusBeforeDownload) {
1810
+ try {
1811
+ await statusLock.acquire();
1812
+
1813
+ const b0 = await states.blocklet.getBlocklet(did);
1814
+ if (!b0 || ![BlockletStatus.waiting].includes(b0.status)) {
1815
+ if (!b0) {
1816
+ throw new Error('blocklet does not exist before downloading');
1817
+ } else {
1818
+ throw new Error(`blocklet status is invalid before downloading: ${fromBlockletStatus(b0.status)}`);
1819
+ }
1765
1820
  }
1821
+ statusLock.release();
1822
+ } catch (error) {
1823
+ statusLock.release();
1824
+ logger.error('Check blocklet status failed before downloading', {
1825
+ name,
1826
+ did,
1827
+ error,
1828
+ });
1829
+ await this._rollback(postAction, did, oldBlocklet);
1830
+ return;
1766
1831
  }
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
1832
  }
1778
1833
 
1779
1834
  // download bundle
1780
1835
  try {
1781
- const { isCancelled } = await this._downloadBlocklet(blocklet, context);
1836
+ const blockletForDownload = {
1837
+ ...blocklet,
1838
+ children: (blocklet.children || []).filter((x) => {
1839
+ if (selectedComponentDids?.length) {
1840
+ return selectedComponentDids.includes(x.meta.did);
1841
+ }
1842
+ return x;
1843
+ }),
1844
+ };
1845
+ const { isCancelled } = await this._downloadBlocklet(blockletForDownload, context);
1782
1846
 
1783
1847
  if (isCancelled) {
1784
1848
  logger.info('Download was canceled', { name, did, version });
1785
1849
 
1786
- if ((await states.blocklet.getBlockletStatus(did)) === BlockletStatus.downloading) {
1787
- await this._rollback(postAction, did, oldBlocklet);
1850
+ // rollback on download cancelled
1851
+ await statusLock.acquire();
1852
+ try {
1853
+ if ((await states.blocklet.getBlockletStatus(did)) === BlockletStatus.downloading) {
1854
+ await this._rollback(postAction, did, oldBlocklet);
1855
+ }
1856
+ statusLock.release();
1857
+ } catch (error) {
1858
+ statusLock.release();
1859
+ logger.error('Rollback blocklet failed on download canceled', { postAction, name, did, version, error });
1788
1860
  }
1789
1861
  return;
1790
1862
  }
@@ -1805,10 +1877,16 @@ class BlockletManager extends BaseBlockletManager {
1805
1877
  severity: 'error',
1806
1878
  });
1807
1879
 
1880
+ // rollback on download failed
1881
+ await statusLock.acquire();
1808
1882
  try {
1809
- await this._rollback(postAction, did, oldBlocklet);
1810
- } catch (e) {
1811
- logger.error('Rollback blocklet failed', { postAction, name, did, version });
1883
+ if ((await states.blocklet.getBlockletStatus(did)) === BlockletStatus.downloading) {
1884
+ await this._rollback(postAction, did, oldBlocklet);
1885
+ }
1886
+ statusLock.release();
1887
+ } catch (error) {
1888
+ statusLock.release();
1889
+ logger.error('Rollback blocklet failed on download failed', { postAction, name, did, version, error });
1812
1890
  }
1813
1891
 
1814
1892
  if (throwOnError) {
@@ -2225,6 +2303,7 @@ class BlockletManager extends BaseBlockletManager {
2225
2303
  did: rootDid,
2226
2304
  children: [...blocklet.children, newChild],
2227
2305
  oldBlocklet: blocklet,
2306
+ selectedComponents: [newChild.meta.did],
2228
2307
  },
2229
2308
  context
2230
2309
  );
@@ -2336,13 +2415,20 @@ class BlockletManager extends BaseBlockletManager {
2336
2415
  newBlocklet.deployedFrom = `Upload by ${context.user.fullName}`;
2337
2416
  newBlocklet.children = await this._getChildrenForInstallation(meta);
2338
2417
  await validateBlocklet(newBlocklet);
2339
- await this._downloadBlocklet(newBlocklet);
2340
2418
 
2341
- return this._upgradeBlocklet({
2419
+ // backup rollback data
2420
+ const action = 'upgrade';
2421
+ await this._rollbackCache.backup({ did: newBlocklet.meta.did, action, oldBlocklet });
2422
+
2423
+ await this.downloadAndInstall({
2424
+ blocklet: newBlocklet,
2342
2425
  oldBlocklet,
2343
- newBlocklet,
2344
2426
  context: { ...context, forceStartProcessIds: [getComponentProcessId(newBlocklet)] },
2427
+ throwOnError: true,
2428
+ postAction: action,
2429
+ skipCheckStatusBeforeDownload: true,
2345
2430
  });
2431
+ return this.getBlocklet(newBlocklet.meta.did);
2346
2432
  }
2347
2433
 
2348
2434
  // full deploy
@@ -2362,14 +2448,20 @@ class BlockletManager extends BaseBlockletManager {
2362
2448
  newBlocklet.deployedFrom = `Upload by ${context.user.fullName}`;
2363
2449
  newBlocklet.children = await this._getChildrenForInstallation(meta);
2364
2450
 
2365
- await validateBlocklet(newBlocklet);
2366
- await this._downloadBlocklet(newBlocklet);
2451
+ // backup rollback data
2452
+ const action = 'upgrade';
2453
+ await this._rollbackCache.backup({ did: newBlocklet.meta.did, action, oldBlocklet });
2367
2454
 
2368
- return this._upgradeBlocklet({
2455
+ await validateBlocklet(newBlocklet);
2456
+ await this.downloadAndInstall({
2457
+ blocklet: newBlocklet,
2369
2458
  oldBlocklet,
2370
- newBlocklet,
2371
2459
  context: { ...context, forceStartProcessIds: [getComponentProcessId(newBlocklet)] },
2460
+ throwOnError: true,
2461
+ postAction: action,
2462
+ skipCheckStatusBeforeDownload: true,
2372
2463
  });
2464
+ return this.getBlocklet(newBlocklet.meta.did);
2373
2465
  }
2374
2466
 
2375
2467
  // full deploy - install
@@ -2383,25 +2475,31 @@ class BlockletManager extends BaseBlockletManager {
2383
2475
  children,
2384
2476
  });
2385
2477
 
2478
+ const action = 'install';
2479
+ const oldState = { extraState: oldExtraState };
2386
2480
  try {
2387
2481
  await this._setConfigsFromMeta(meta.did);
2388
2482
  await validateBlocklet(blocklet);
2389
2483
 
2390
2484
  // check duplicate appSk
2391
2485
  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
2486
  } catch (error) {
2402
- await this._rollback('install', meta.did, { extraState: oldExtraState });
2487
+ await this._rollback(action, meta.did, oldState);
2403
2488
  throw error;
2404
2489
  }
2490
+
2491
+ // backup rollback data
2492
+ await this._rollbackCache.backup({ did: meta.did, action, oldBlocklet: oldState });
2493
+
2494
+ await this.downloadAndInstall({
2495
+ blocklet,
2496
+ oldBlocklet: oldState,
2497
+ context,
2498
+ throwOnError: true,
2499
+ postAction: action,
2500
+ skipCheckStatusBeforeDownload: true,
2501
+ });
2502
+ return this.getBlocklet(meta.did);
2405
2503
  }
2406
2504
 
2407
2505
  async _installComponentFromUpload({
@@ -2482,34 +2580,20 @@ class BlockletManager extends BaseBlockletManager {
2482
2580
 
2483
2581
  await this._upsertDynamicNavigation(newBlocklet.meta.did, newChild, { skipNavigation });
2484
2582
 
2485
- await this._downloadBlocklet(newBlocklet);
2486
-
2487
- await validateBlocklet(newBlocklet);
2583
+ // backup rollback data
2584
+ const action = 'upgrade';
2585
+ await this._rollbackCache.backup({ did: newBlocklet.meta.did, action, oldBlocklet });
2488
2586
 
2489
- return this._upgradeBlocklet({
2587
+ await this.downloadAndInstall({
2588
+ blocklet: newBlocklet,
2490
2589
  oldBlocklet,
2491
- newBlocklet,
2492
2590
  context: { ...context, forceStartProcessIds: [getComponentProcessId(newChild, [newBlocklet])] },
2591
+ throwOnError: true,
2592
+ postAction: action,
2593
+ skipCheckStatusBeforeDownload: true,
2594
+ selectedComponentDids: [newChild.meta.did],
2493
2595
  });
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
- );
2596
+ return this.getBlocklet(newBlocklet.meta.did);
2513
2597
  }
2514
2598
 
2515
2599
  async prune() {
@@ -2732,6 +2816,11 @@ class BlockletManager extends BaseBlockletManager {
2732
2816
  const blocklet1 = await states.blocklet.setBlockletStatus(did, BlockletStatus.waiting);
2733
2817
  this.emit(BlockletEvents.added, blocklet1);
2734
2818
 
2819
+ const action = 'install';
2820
+ const oldBlocklet = {
2821
+ extraState: oldExtraState,
2822
+ };
2823
+
2735
2824
  /** @type {{
2736
2825
  * blocklet: any;
2737
2826
  * oldBlocklet: {
@@ -2743,16 +2832,16 @@ class BlockletManager extends BaseBlockletManager {
2743
2832
  * }} */
2744
2833
  const downloadParams = {
2745
2834
  blocklet: { ...blocklet1 },
2746
- oldBlocklet: {
2747
- children: children.filter((x) => x.dynamic), // let downloader skip re-downloading dynamic blocklet
2748
- extraState: oldExtraState,
2749
- },
2750
2835
  context,
2751
- postAction: 'install',
2836
+ postAction: action,
2837
+ oldBlocklet,
2752
2838
  };
2753
2839
 
2840
+ // backup rollback data
2841
+ await this._rollbackCache.backup({ did, action, oldBlocklet });
2842
+
2754
2843
  if (sync) {
2755
- await this.onDownload({ ...downloadParams, throwOnError: true });
2844
+ await this.downloadAndInstall({ ...downloadParams, throwOnError: true });
2756
2845
  return states.blocklet.getBlocklet(did);
2757
2846
  }
2758
2847
 
@@ -2863,8 +2952,11 @@ class BlockletManager extends BaseBlockletManager {
2863
2952
  postAction: action,
2864
2953
  };
2865
2954
 
2955
+ // backup rollback data
2956
+ await this._rollbackCache.backup({ did, action, oldBlocklet });
2957
+
2866
2958
  if (sync) {
2867
- await this.onDownload({ ...downloadParams, throwOnError: true });
2959
+ await this.downloadAndInstall({ ...downloadParams, throwOnError: true });
2868
2960
  return states.blocklet.getBlocklet(did);
2869
2961
  }
2870
2962
  const ticket = this.installQueue.push(
@@ -2961,6 +3053,8 @@ class BlockletManager extends BaseBlockletManager {
2961
3053
  entityId: did,
2962
3054
  severity: 'success',
2963
3055
  });
3056
+
3057
+ await this._rollbackCache.remove({ did: blocklet.meta.did });
2964
3058
  return blocklet;
2965
3059
  } catch (err) {
2966
3060
  const { meta } = await states.blocklet.getBlocklet(did);
@@ -3087,6 +3181,8 @@ class BlockletManager extends BaseBlockletManager {
3087
3181
  // Update dynamic component meta in blocklet settings
3088
3182
  await this._ensureDynamicChildrenInSettings(blocklet);
3089
3183
 
3184
+ await this._rollbackCache.remove({ did: blocklet.meta.did });
3185
+
3090
3186
  return blocklet;
3091
3187
  } catch (err) {
3092
3188
  const b = await this._rollback(action, did, oldBlocklet);
@@ -3150,9 +3246,11 @@ class BlockletManager extends BaseBlockletManager {
3150
3246
  });
3151
3247
  this.emit(BlockletEvents.statusChange, blocklet1);
3152
3248
  },
3153
- postDownload: async () => {
3154
- // since preferences only exist in blocklet bundle, we need to populate then after downloaded
3155
- await this._setConfigsFromMeta(did);
3249
+ postDownload: async ({ isCancelled }) => {
3250
+ if (!isCancelled) {
3251
+ // since preferences only exist in blocklet bundle, we need to populate then after downloaded
3252
+ await this._setConfigsFromMeta(did);
3253
+ }
3156
3254
  },
3157
3255
  });
3158
3256
  }
@@ -3170,12 +3268,6 @@ class BlockletManager extends BaseBlockletManager {
3170
3268
  }
3171
3269
  }
3172
3270
 
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
3271
  /**
3180
3272
  * @param {string} action install, upgrade, downgrade
3181
3273
  * @param {string} did
@@ -3343,7 +3435,7 @@ class BlockletManager extends BaseBlockletManager {
3343
3435
  }
3344
3436
 
3345
3437
  async _getBlockletForInstallation(did) {
3346
- const blocklet = await states.blocklet.getBlocklet(did);
3438
+ const blocklet = await states.blocklet.getBlocklet(did, { decryptSk: false });
3347
3439
  if (!blocklet) {
3348
3440
  return null;
3349
3441
  }
@@ -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);