@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.
- package/lib/blocklet/downloader/blocklet-downloader.js +33 -12
- package/lib/blocklet/manager/disk.js +187 -95
- package/lib/blocklet/manager/helper/install-from-backup.js +11 -4
- package/lib/blocklet/manager/helper/rollback-cache.js +41 -0
- package/lib/blocklet/storage/backup/blocklet-extras.js +4 -0
- package/lib/blocklet/storage/backup/blocklets.js +23 -29
- package/lib/blocklet/storage/backup/data.js +2 -2
- package/lib/blocklet/storage/backup/logs.js +3 -2
- package/lib/blocklet/storage/backup/spaces.js +3 -14
- package/lib/blocklet/storage/restore/blocklet-extras.js +5 -3
- package/lib/blocklet/storage/restore/blocklets.js +29 -11
- package/lib/blocklet/storage/restore/logs.js +21 -0
- package/lib/blocklet/storage/restore/spaces.js +6 -1
- package/lib/blocklet/storage/utils/hash.js +51 -0
- package/lib/blocklet/storage/utils/zip.js +43 -0
- package/lib/router/helper.js +64 -12
- package/lib/router/index.js +4 -0
- package/lib/states/blocklet.js +2 -2
- package/lib/util/blocklet.js +1 -1
- package/package.json +27 -25
|
@@ -32,7 +32,10 @@ const isMetaFileExist = (dir) => {
|
|
|
32
32
|
* }}
|
|
33
33
|
* @returns {boolean}
|
|
34
34
|
*/
|
|
35
|
-
const needDownload = (
|
|
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 {{
|
|
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,
|
|
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 = () => {} } =
|
|
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,
|
|
151
|
+
tasks.push(this.bundleDownloader.download(meta, did, url, options));
|
|
137
152
|
}
|
|
138
153
|
const results = await Promise.all(tasks);
|
|
139
154
|
|
|
140
|
-
|
|
155
|
+
const isCancelled = results.some((x) => x.isCancelled);
|
|
156
|
+
|
|
157
|
+
await postDownload({ downloadList, downloadComponentIds, isCancelled });
|
|
141
158
|
|
|
142
|
-
if (
|
|
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<
|
|
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, {
|
|
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(
|
|
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
|
-
|
|
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
|
-
|
|
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
|
-
|
|
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.
|
|
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
|
|
1751
|
-
const {
|
|
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
|
-
|
|
1757
|
-
|
|
1758
|
-
|
|
1759
|
-
|
|
1760
|
-
|
|
1761
|
-
if (!b0) {
|
|
1762
|
-
|
|
1763
|
-
|
|
1764
|
-
|
|
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
|
|
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
|
-
|
|
1787
|
-
|
|
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
|
|
1810
|
-
|
|
1811
|
-
|
|
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
|
-
|
|
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
|
-
|
|
2366
|
-
|
|
2451
|
+
// backup rollback data
|
|
2452
|
+
const action = 'upgrade';
|
|
2453
|
+
await this._rollbackCache.backup({ did: newBlocklet.meta.did, action, oldBlocklet });
|
|
2367
2454
|
|
|
2368
|
-
|
|
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(
|
|
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
|
-
|
|
2486
|
-
|
|
2487
|
-
await
|
|
2583
|
+
// backup rollback data
|
|
2584
|
+
const action = 'upgrade';
|
|
2585
|
+
await this._rollbackCache.backup({ did: newBlocklet.meta.did, action, oldBlocklet });
|
|
2488
2586
|
|
|
2489
|
-
|
|
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:
|
|
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.
|
|
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.
|
|
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
|
-
|
|
3155
|
-
|
|
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);
|