@abtnode/core 1.17.8-beta-20260109-075740-5f484e08 → 1.17.8-beta-20260111-112953-aed5ff39
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/lib/api/team/access-key-manager.js +104 -0
- package/lib/api/team/invitation-manager.js +461 -0
- package/lib/api/team/notification-manager.js +189 -0
- package/lib/api/team/oauth-manager.js +60 -0
- package/lib/api/team/org-crud-manager.js +202 -0
- package/lib/api/team/org-manager.js +56 -0
- package/lib/api/team/org-member-manager.js +403 -0
- package/lib/api/team/org-query-manager.js +126 -0
- package/lib/api/team/org-resource-manager.js +186 -0
- package/lib/api/team/passport-manager.js +670 -0
- package/lib/api/team/rbac-manager.js +335 -0
- package/lib/api/team/session-manager.js +540 -0
- package/lib/api/team/store-manager.js +198 -0
- package/lib/api/team/tag-manager.js +230 -0
- package/lib/api/team/user-auth-manager.js +132 -0
- package/lib/api/team/user-manager.js +78 -0
- package/lib/api/team/user-query-manager.js +299 -0
- package/lib/api/team/user-social-manager.js +354 -0
- package/lib/api/team/user-update-manager.js +224 -0
- package/lib/api/team/verify-code-manager.js +161 -0
- package/lib/api/team.js +439 -3287
- package/lib/blocklet/manager/disk/auth-manager.js +68 -0
- package/lib/blocklet/manager/disk/backup-manager.js +288 -0
- package/lib/blocklet/manager/disk/cleanup-manager.js +157 -0
- package/lib/blocklet/manager/disk/component-manager.js +83 -0
- package/lib/blocklet/manager/disk/config-manager.js +191 -0
- package/lib/blocklet/manager/disk/controller-manager.js +64 -0
- package/lib/blocklet/manager/disk/delete-reset-manager.js +328 -0
- package/lib/blocklet/manager/disk/download-manager.js +96 -0
- package/lib/blocklet/manager/disk/env-config-manager.js +311 -0
- package/lib/blocklet/manager/disk/federated-manager.js +651 -0
- package/lib/blocklet/manager/disk/hook-manager.js +124 -0
- package/lib/blocklet/manager/disk/install-component-manager.js +95 -0
- package/lib/blocklet/manager/disk/install-core-manager.js +448 -0
- package/lib/blocklet/manager/disk/install-download-manager.js +313 -0
- package/lib/blocklet/manager/disk/install-manager.js +36 -0
- package/lib/blocklet/manager/disk/install-upgrade-manager.js +340 -0
- package/lib/blocklet/manager/disk/job-manager.js +467 -0
- package/lib/blocklet/manager/disk/lifecycle-manager.js +26 -0
- package/lib/blocklet/manager/disk/notification-manager.js +343 -0
- package/lib/blocklet/manager/disk/query-manager.js +562 -0
- package/lib/blocklet/manager/disk/settings-manager.js +507 -0
- package/lib/blocklet/manager/disk/start-manager.js +611 -0
- package/lib/blocklet/manager/disk/stop-restart-manager.js +292 -0
- package/lib/blocklet/manager/disk/update-manager.js +153 -0
- package/lib/blocklet/manager/disk.js +669 -5796
- package/lib/blocklet/manager/helper/blue-green-start-blocklet.js +5 -0
- package/lib/blocklet/manager/lock.js +18 -0
- package/lib/event/index.js +28 -24
- package/lib/util/blocklet/app-utils.js +192 -0
- package/lib/util/blocklet/blocklet-loader.js +258 -0
- package/lib/util/blocklet/config-manager.js +232 -0
- package/lib/util/blocklet/did-document.js +240 -0
- package/lib/util/blocklet/environment.js +555 -0
- package/lib/util/blocklet/health-check.js +449 -0
- package/lib/util/blocklet/install-utils.js +365 -0
- package/lib/util/blocklet/logo.js +57 -0
- package/lib/util/blocklet/meta-utils.js +269 -0
- package/lib/util/blocklet/port-manager.js +141 -0
- package/lib/util/blocklet/process-manager.js +504 -0
- package/lib/util/blocklet/runtime-info.js +105 -0
- package/lib/util/blocklet/validation.js +418 -0
- package/lib/util/blocklet.js +98 -3066
- package/lib/util/wallet-app-notification.js +40 -0
- package/package.json +22 -22
|
@@ -0,0 +1,68 @@
|
|
|
1
|
+
const omit = require('lodash/omit');
|
|
2
|
+
const { getConfigs } = require('@blocklet/meta/lib/util-config');
|
|
3
|
+
const { LOGIN_PROVIDER } = require('@blocklet/constant');
|
|
4
|
+
const { getEmailServiceProvider } = require('@abtnode/auth/lib/email');
|
|
5
|
+
|
|
6
|
+
/**
|
|
7
|
+
* Migrate blocklet authentication
|
|
8
|
+
* @param {Object} manager - BlockletManager instance
|
|
9
|
+
* @param {Object} params
|
|
10
|
+
* @param {string} params.did - Blocklet DID
|
|
11
|
+
* @returns {Promise<void>}
|
|
12
|
+
*/
|
|
13
|
+
async function migrateBlockletAuthentication(manager, { did }) {
|
|
14
|
+
const blocklet = await manager.getBlocklet(did);
|
|
15
|
+
if (blocklet.settings?.authentication) return;
|
|
16
|
+
|
|
17
|
+
const authenticationList = [];
|
|
18
|
+
|
|
19
|
+
const configs = getConfigs(blocklet, did);
|
|
20
|
+
const allowWallet = configs.find((x) => x.key === 'DID_CONNECT_ALLOW_WALLET')?.value;
|
|
21
|
+
if (['1', 'true', undefined, null].includes(allowWallet)) {
|
|
22
|
+
// 默认是允许使用 wallet
|
|
23
|
+
authenticationList.push({
|
|
24
|
+
enabled: true,
|
|
25
|
+
showQrcode: true,
|
|
26
|
+
type: 'builtin',
|
|
27
|
+
provider: LOGIN_PROVIDER.WALLET,
|
|
28
|
+
});
|
|
29
|
+
}
|
|
30
|
+
|
|
31
|
+
const isEmailServiceEnabled = Boolean(getEmailServiceProvider(blocklet));
|
|
32
|
+
if (isEmailServiceEnabled) {
|
|
33
|
+
authenticationList.push({
|
|
34
|
+
enabled: isEmailServiceEnabled,
|
|
35
|
+
type: 'builtin',
|
|
36
|
+
provider: LOGIN_PROVIDER.EMAIL,
|
|
37
|
+
});
|
|
38
|
+
}
|
|
39
|
+
|
|
40
|
+
// 对旧的数据进行转换,并保存
|
|
41
|
+
if (blocklet.settings?.oauth) {
|
|
42
|
+
const oauthList = Object.keys(blocklet.settings?.oauth)
|
|
43
|
+
.map((key) => ({
|
|
44
|
+
...omit(blocklet.settings?.oauth[key], 'order'),
|
|
45
|
+
type: 'oauth',
|
|
46
|
+
provider: key,
|
|
47
|
+
}))
|
|
48
|
+
.filter((x) => x.enabled === true);
|
|
49
|
+
authenticationList.push(...oauthList);
|
|
50
|
+
}
|
|
51
|
+
authenticationList.push({
|
|
52
|
+
enabled: true,
|
|
53
|
+
type: 'builtin',
|
|
54
|
+
provider: LOGIN_PROVIDER.PASSKEY,
|
|
55
|
+
});
|
|
56
|
+
const authentication = authenticationList.reduce((acc, curr, index) => {
|
|
57
|
+
acc[curr.provider] = {
|
|
58
|
+
...omit(curr, ['provider']),
|
|
59
|
+
order: index,
|
|
60
|
+
};
|
|
61
|
+
return acc;
|
|
62
|
+
}, {});
|
|
63
|
+
await manager.configAuthentication({ did, authentication: JSON.stringify(authentication) });
|
|
64
|
+
}
|
|
65
|
+
|
|
66
|
+
module.exports = {
|
|
67
|
+
migrateBlockletAuthentication,
|
|
68
|
+
};
|
|
@@ -0,0 +1,288 @@
|
|
|
1
|
+
const fs = require('fs-extra');
|
|
2
|
+
const path = require('path');
|
|
3
|
+
const merge = require('lodash/merge');
|
|
4
|
+
const isEmpty = require('lodash/isEmpty');
|
|
5
|
+
const { joinURL } = require('ufo');
|
|
6
|
+
const logger = require('@abtnode/logger')('@abtnode/core:blocklet:manager:backup');
|
|
7
|
+
const sleep = require('@abtnode/util/lib/sleep');
|
|
8
|
+
const { encode } = require('@abtnode/util/lib/base32');
|
|
9
|
+
const { BACKUPS, DEFAULT_DID_DOMAIN } = require('@abtnode/constant');
|
|
10
|
+
const { BlockletStatus, BlockletEvents, RESTORE_PROGRESS_STATUS } = require('@blocklet/constant');
|
|
11
|
+
|
|
12
|
+
const states = require('../../../states');
|
|
13
|
+
const { SpacesBackup } = require('../../storage/backup/spaces');
|
|
14
|
+
const { SpacesRestore } = require('../../storage/restore/spaces');
|
|
15
|
+
const {
|
|
16
|
+
getBackupJobId,
|
|
17
|
+
getBackupEndpoint,
|
|
18
|
+
getBackupFilesUrlFromEndpoint,
|
|
19
|
+
getSpaceNameByEndpoint,
|
|
20
|
+
} = require('../../../util/spaces');
|
|
21
|
+
const { shouldJobBackoff } = require('../../../util');
|
|
22
|
+
const { installApplicationFromBackup } = require('../helper/install-application-from-backup');
|
|
23
|
+
|
|
24
|
+
/**
|
|
25
|
+
* Handle backup to spaces
|
|
26
|
+
* @param {Object} manager - BlockletManager instance
|
|
27
|
+
* @param {Object} params
|
|
28
|
+
* @param {string} params.did - Blocklet DID
|
|
29
|
+
* @param {Object} params.context - Context
|
|
30
|
+
* @param {Object} params.backupState - Backup state
|
|
31
|
+
* @returns {Promise<void>}
|
|
32
|
+
*/
|
|
33
|
+
async function _onBackupToSpaces(
|
|
34
|
+
manager,
|
|
35
|
+
{
|
|
36
|
+
did,
|
|
37
|
+
context,
|
|
38
|
+
backupState = {
|
|
39
|
+
strategy: BACKUPS.STRATEGY.AUTO,
|
|
40
|
+
},
|
|
41
|
+
}
|
|
42
|
+
) {
|
|
43
|
+
const blocklet = await states.blocklet.getBlocklet(did);
|
|
44
|
+
const {
|
|
45
|
+
appDid,
|
|
46
|
+
meta: { did: appPid },
|
|
47
|
+
} = blocklet;
|
|
48
|
+
|
|
49
|
+
if (shouldJobBackoff()) {
|
|
50
|
+
const backup = await states.backup.findOne({ appPid }, {}, { createdAt: -1 });
|
|
51
|
+
const message = 'Backup to spaces is not available when blocklet server is starting.';
|
|
52
|
+
|
|
53
|
+
if (backup.status === BACKUPS.STATUS.PROGRESS) {
|
|
54
|
+
await states.backup.fail(backup.id, {
|
|
55
|
+
message,
|
|
56
|
+
});
|
|
57
|
+
}
|
|
58
|
+
|
|
59
|
+
manager.emit(BlockletEvents.backupProgress, {
|
|
60
|
+
appDid,
|
|
61
|
+
meta: { did: appPid },
|
|
62
|
+
completed: true,
|
|
63
|
+
progress: -1,
|
|
64
|
+
message,
|
|
65
|
+
backup,
|
|
66
|
+
context,
|
|
67
|
+
blocklet,
|
|
68
|
+
});
|
|
69
|
+
|
|
70
|
+
logger.warn(message);
|
|
71
|
+
return;
|
|
72
|
+
}
|
|
73
|
+
|
|
74
|
+
const spaceGateways = await manager.getBlockletSpaceGateways({ did });
|
|
75
|
+
const backupEndpoint = getBackupEndpoint(blocklet.environments);
|
|
76
|
+
if (isEmpty(spaceGateways) || isEmpty(backupEndpoint)) {
|
|
77
|
+
logger.warn('Canceled automatic backups because there is no space gateway.', { appPid });
|
|
78
|
+
|
|
79
|
+
const jobId = getBackupJobId(did);
|
|
80
|
+
await manager.backupQueue.delete(jobId);
|
|
81
|
+
await manager.updateAutoBackup({ did, autoBackup: { enabled: false } }, context);
|
|
82
|
+
|
|
83
|
+
return;
|
|
84
|
+
}
|
|
85
|
+
|
|
86
|
+
const {
|
|
87
|
+
user: { did: userDid, locale },
|
|
88
|
+
} = context;
|
|
89
|
+
|
|
90
|
+
let { referrer } = context;
|
|
91
|
+
if (isEmpty(referrer)) {
|
|
92
|
+
// fixes: https://github.com/ArcBlock/did-spaces/issues/908, referrer 在某些情况下会不存在
|
|
93
|
+
/**
|
|
94
|
+
* @type {import('@blocklet/server-js').NodeState}
|
|
95
|
+
*/
|
|
96
|
+
const node = await states.node.read();
|
|
97
|
+
referrer = joinURL(
|
|
98
|
+
`https://${encode(node.did)}.${DEFAULT_DID_DOMAIN}`,
|
|
99
|
+
node.routing.adminPath,
|
|
100
|
+
`/blocklets/${did}/didSpaces`
|
|
101
|
+
);
|
|
102
|
+
}
|
|
103
|
+
|
|
104
|
+
const verifyBackup = () => {
|
|
105
|
+
// @note: 自动备份时,应用停止运行就跳过本次备份
|
|
106
|
+
if (backupState?.strategy === BACKUPS.STRATEGY.AUTO && blocklet.status === BlockletStatus.stopped) {
|
|
107
|
+
const message =
|
|
108
|
+
'Automatic backup is only available to running blocklets, please start your blocklet before enable automatic backup.';
|
|
109
|
+
logger.error(message, { appPid });
|
|
110
|
+
|
|
111
|
+
return message;
|
|
112
|
+
}
|
|
113
|
+
|
|
114
|
+
if (backupState?.strategy === BACKUPS.STRATEGY.AUTO && shouldJobBackoff()) {
|
|
115
|
+
const message = 'Automatic backup is not available when blocklet server is starting.';
|
|
116
|
+
logger.error(message, { appPid });
|
|
117
|
+
|
|
118
|
+
return message;
|
|
119
|
+
}
|
|
120
|
+
|
|
121
|
+
return null;
|
|
122
|
+
};
|
|
123
|
+
|
|
124
|
+
let backup = await states.backup.findOne({ appPid }, {}, { createdAt: -1 });
|
|
125
|
+
if (backup?.status !== BACKUPS.STATUS.PROGRESS) {
|
|
126
|
+
const message = verifyBackup();
|
|
127
|
+
if (message) {
|
|
128
|
+
return;
|
|
129
|
+
}
|
|
130
|
+
|
|
131
|
+
// 创建备份记录
|
|
132
|
+
backup = await states.backup.start({
|
|
133
|
+
appPid,
|
|
134
|
+
userDid,
|
|
135
|
+
strategy: backupState?.strategy,
|
|
136
|
+
sourceUrl: path.join(manager.dataDirs.tmp, 'backup', appDid),
|
|
137
|
+
targetName: await getSpaceNameByEndpoint(backupEndpoint, 'DID Space'),
|
|
138
|
+
});
|
|
139
|
+
}
|
|
140
|
+
|
|
141
|
+
const spacesBackup = new SpacesBackup({ appDid, appPid, event: manager, userDid, referrer, locale, backup });
|
|
142
|
+
try {
|
|
143
|
+
const message = verifyBackup();
|
|
144
|
+
if (message) {
|
|
145
|
+
throw new Error(message);
|
|
146
|
+
}
|
|
147
|
+
|
|
148
|
+
manager.emit(BlockletEvents.backupProgress, {
|
|
149
|
+
appDid,
|
|
150
|
+
meta: { did: appPid },
|
|
151
|
+
message: 'Start backup...',
|
|
152
|
+
progress: 10,
|
|
153
|
+
completed: false,
|
|
154
|
+
});
|
|
155
|
+
await states.backup.progress(backup.id, {
|
|
156
|
+
message: 'Start backup...',
|
|
157
|
+
progress: 10,
|
|
158
|
+
});
|
|
159
|
+
await spacesBackup.backup();
|
|
160
|
+
|
|
161
|
+
await states.backup.success(backup.id, {
|
|
162
|
+
targetUrl: getBackupFilesUrlFromEndpoint(getBackupEndpoint(blocklet?.environments)),
|
|
163
|
+
metadata: {
|
|
164
|
+
count: spacesBackup.backupOutput.data?.count,
|
|
165
|
+
size: spacesBackup.backupOutput.data?.size,
|
|
166
|
+
},
|
|
167
|
+
});
|
|
168
|
+
|
|
169
|
+
// 备份成功了
|
|
170
|
+
manager.emit(BlockletEvents.backupProgress, {
|
|
171
|
+
appDid,
|
|
172
|
+
meta: { did: appPid },
|
|
173
|
+
completed: true,
|
|
174
|
+
progress: 100,
|
|
175
|
+
backup,
|
|
176
|
+
context,
|
|
177
|
+
blocklet,
|
|
178
|
+
});
|
|
179
|
+
} catch (error) {
|
|
180
|
+
// @note: 主动抛出错误表明正在备份中,不做处理
|
|
181
|
+
if (error.cause?.status === BlockletEvents.backupProgress) {
|
|
182
|
+
logger.warn(error.message);
|
|
183
|
+
return;
|
|
184
|
+
}
|
|
185
|
+
|
|
186
|
+
await states.backup.fail(backup.id, {
|
|
187
|
+
message: error?.message,
|
|
188
|
+
});
|
|
189
|
+
|
|
190
|
+
manager.emit(BlockletEvents.backupProgress, {
|
|
191
|
+
appDid,
|
|
192
|
+
meta: { did: appPid },
|
|
193
|
+
completed: true,
|
|
194
|
+
progress: -1,
|
|
195
|
+
message: error?.message,
|
|
196
|
+
backup,
|
|
197
|
+
context,
|
|
198
|
+
blocklet,
|
|
199
|
+
});
|
|
200
|
+
throw error;
|
|
201
|
+
}
|
|
202
|
+
}
|
|
203
|
+
|
|
204
|
+
/**
|
|
205
|
+
* Handle restore from spaces
|
|
206
|
+
* @param {Object} manager - BlockletManager instance
|
|
207
|
+
* @param {Object} params
|
|
208
|
+
* @param {Object} params.input - Restore input
|
|
209
|
+
* @param {Object} params.context - Context
|
|
210
|
+
* @returns {Promise<void>}
|
|
211
|
+
*/
|
|
212
|
+
async function _onRestoreFromSpaces(manager, { input, context }) {
|
|
213
|
+
try {
|
|
214
|
+
if (input.delay) {
|
|
215
|
+
await sleep(input.delay);
|
|
216
|
+
}
|
|
217
|
+
|
|
218
|
+
manager.emit(BlockletEvents.restoreProgress, {
|
|
219
|
+
appDid: input.appDid,
|
|
220
|
+
meta: { did: input.appPid },
|
|
221
|
+
status: RESTORE_PROGRESS_STATUS.start,
|
|
222
|
+
});
|
|
223
|
+
|
|
224
|
+
const userDid = context.user.did;
|
|
225
|
+
const spacesRestore = new SpacesRestore({
|
|
226
|
+
...input,
|
|
227
|
+
appPid: input.appPid,
|
|
228
|
+
event: manager,
|
|
229
|
+
userDid,
|
|
230
|
+
referrer: context.referrer,
|
|
231
|
+
});
|
|
232
|
+
const params = await spacesRestore.restore();
|
|
233
|
+
|
|
234
|
+
const removeRestoreDir = () => {
|
|
235
|
+
if (fs.existsSync(spacesRestore.restoreDir)) {
|
|
236
|
+
fs.remove(spacesRestore.restoreDir).catch((err) => {
|
|
237
|
+
logger.error('failed to remove restore dir', { error: err, dir: spacesRestore.restoreDir });
|
|
238
|
+
});
|
|
239
|
+
}
|
|
240
|
+
};
|
|
241
|
+
|
|
242
|
+
manager.emit(BlockletEvents.restoreProgress, {
|
|
243
|
+
appDid: input.appDid,
|
|
244
|
+
meta: { did: input.appPid },
|
|
245
|
+
status: RESTORE_PROGRESS_STATUS.installing,
|
|
246
|
+
});
|
|
247
|
+
|
|
248
|
+
try {
|
|
249
|
+
await installApplicationFromBackup({
|
|
250
|
+
url: `file://${spacesRestore.restoreDir}`,
|
|
251
|
+
moveDir: true,
|
|
252
|
+
...merge(...params),
|
|
253
|
+
manager,
|
|
254
|
+
states,
|
|
255
|
+
controller: input.controller,
|
|
256
|
+
context: { ...context, startImmediately: true },
|
|
257
|
+
});
|
|
258
|
+
|
|
259
|
+
removeRestoreDir();
|
|
260
|
+
} catch (error) {
|
|
261
|
+
console.error(error);
|
|
262
|
+
removeRestoreDir();
|
|
263
|
+
throw error;
|
|
264
|
+
}
|
|
265
|
+
|
|
266
|
+
manager.emit(BlockletEvents.restoreProgress, {
|
|
267
|
+
appDid: input.appDid,
|
|
268
|
+
meta: { did: input.appPid },
|
|
269
|
+
status: RESTORE_PROGRESS_STATUS.completed,
|
|
270
|
+
});
|
|
271
|
+
} catch (error) {
|
|
272
|
+
console.error(error);
|
|
273
|
+
|
|
274
|
+
manager.emit(BlockletEvents.restoreProgress, {
|
|
275
|
+
appDid: input.appDid,
|
|
276
|
+
meta: { did: input.appPid },
|
|
277
|
+
status: RESTORE_PROGRESS_STATUS.error,
|
|
278
|
+
message: error.message,
|
|
279
|
+
});
|
|
280
|
+
|
|
281
|
+
throw error;
|
|
282
|
+
}
|
|
283
|
+
}
|
|
284
|
+
|
|
285
|
+
module.exports = {
|
|
286
|
+
_onBackupToSpaces,
|
|
287
|
+
_onRestoreFromSpaces,
|
|
288
|
+
};
|
|
@@ -0,0 +1,157 @@
|
|
|
1
|
+
const path = require('path');
|
|
2
|
+
const logger = require('@abtnode/logger')('@abtnode/core:blocklet:manager:cleanup');
|
|
3
|
+
const { INSTALL_ACTIONS } = require('@abtnode/constant');
|
|
4
|
+
const { BlockletEvents } = require('@blocklet/constant');
|
|
5
|
+
|
|
6
|
+
const states = require('../../../states');
|
|
7
|
+
const checkDockerRunHistory = require('../../../util/docker/check-docker-run-history');
|
|
8
|
+
const { dockerExecChown } = require('../../../util/docker/docker-exec-chown');
|
|
9
|
+
|
|
10
|
+
/**
|
|
11
|
+
* Rollback blocklet installation/upgrade
|
|
12
|
+
* @param {Object} manager - BlockletManager instance
|
|
13
|
+
* @param {string} action - install, upgrade, installComponent, upgradeComponent
|
|
14
|
+
* @param {string} did - Blocklet DID
|
|
15
|
+
* @param {Object} oldBlocklet - Previous blocklet state
|
|
16
|
+
* @returns {Promise<Object>}
|
|
17
|
+
*/
|
|
18
|
+
async function _rollback(manager, action, did, oldBlocklet) {
|
|
19
|
+
if (action === INSTALL_ACTIONS.INSTALL) {
|
|
20
|
+
const extraState = oldBlocklet?.extraState;
|
|
21
|
+
|
|
22
|
+
// rollback blocklet extra state
|
|
23
|
+
if (extraState) {
|
|
24
|
+
await states.blockletExtras.update({ did }, extraState);
|
|
25
|
+
} else {
|
|
26
|
+
await states.blockletExtras.remove({ did });
|
|
27
|
+
}
|
|
28
|
+
|
|
29
|
+
// remove blocklet state
|
|
30
|
+
return _deleteBlocklet(manager, { did, keepData: true });
|
|
31
|
+
}
|
|
32
|
+
|
|
33
|
+
if (
|
|
34
|
+
[
|
|
35
|
+
INSTALL_ACTIONS.INSTALL_COMPONENT,
|
|
36
|
+
INSTALL_ACTIONS.UPGRADE_COMPONENT,
|
|
37
|
+
'upgrade', // for backward compatibility
|
|
38
|
+
].includes(action)
|
|
39
|
+
) {
|
|
40
|
+
const { extraState, ...blocklet } = oldBlocklet;
|
|
41
|
+
// rollback blocklet state
|
|
42
|
+
const result = await states.blocklet.updateBlocklet(did, blocklet);
|
|
43
|
+
|
|
44
|
+
// rollback blocklet extra state
|
|
45
|
+
await states.blockletExtras.update({ did: blocklet.meta.did }, extraState);
|
|
46
|
+
|
|
47
|
+
logger.info('blocklet rollback successfully', { did, action });
|
|
48
|
+
manager.emit(BlockletEvents.updated, result);
|
|
49
|
+
return result;
|
|
50
|
+
}
|
|
51
|
+
|
|
52
|
+
logger.error('rollback action is invalid', { action });
|
|
53
|
+
throw new Error(`rollback action is invalid: ${action}`);
|
|
54
|
+
}
|
|
55
|
+
|
|
56
|
+
/**
|
|
57
|
+
* Delete blocklet
|
|
58
|
+
* @param {Object} manager - BlockletManager instance
|
|
59
|
+
* @param {Object} params
|
|
60
|
+
* @param {Object} context
|
|
61
|
+
* @returns {Promise<Object>}
|
|
62
|
+
*/
|
|
63
|
+
async function _deleteBlocklet(manager, { did, keepData, keepLogsDir, keepConfigs }, context) {
|
|
64
|
+
const blocklet = await states.blocklet.getBlocklet(did);
|
|
65
|
+
const { name } = blocklet.meta;
|
|
66
|
+
const cacheDir = path.join(manager.dataDirs.cache, name);
|
|
67
|
+
|
|
68
|
+
// Cleanup db
|
|
69
|
+
await manager.teamManager.deleteTeam(blocklet.meta.did);
|
|
70
|
+
|
|
71
|
+
// Cleanup disk storage
|
|
72
|
+
await _cleanBlockletData(manager, { blocklet, keepData, keepLogsDir, keepConfigs, appCacheDir: cacheDir });
|
|
73
|
+
|
|
74
|
+
const result = await states.blocklet.deleteBlocklet(did);
|
|
75
|
+
logger.info('blocklet removed successfully', { did });
|
|
76
|
+
|
|
77
|
+
let keepRouting = true;
|
|
78
|
+
if (keepData === false || keepConfigs === false) {
|
|
79
|
+
keepRouting = false;
|
|
80
|
+
}
|
|
81
|
+
|
|
82
|
+
manager.runtimeMonitor.delete(blocklet.meta.did);
|
|
83
|
+
|
|
84
|
+
manager.emit(BlockletEvents.removed, {
|
|
85
|
+
blocklet: result,
|
|
86
|
+
context: {
|
|
87
|
+
...context,
|
|
88
|
+
keepRouting,
|
|
89
|
+
},
|
|
90
|
+
});
|
|
91
|
+
return blocklet;
|
|
92
|
+
}
|
|
93
|
+
|
|
94
|
+
/**
|
|
95
|
+
* Clean blocklet data
|
|
96
|
+
* @param {Object} manager - BlockletManager instance
|
|
97
|
+
* @param {Object} params
|
|
98
|
+
* @returns {Promise<void>}
|
|
99
|
+
*/
|
|
100
|
+
async function _cleanBlockletData(manager, { blocklet, keepData, keepLogsDir, keepConfigs, appCacheDir }) {
|
|
101
|
+
const { name } = blocklet.meta;
|
|
102
|
+
|
|
103
|
+
const dataDir = path.join(manager.dataDirs.data, name);
|
|
104
|
+
const logsDir = path.join(manager.dataDirs.logs, name);
|
|
105
|
+
const cacheDir = path.join(manager.dataDirs.cache, name);
|
|
106
|
+
const nodeInfo = await states.node.read();
|
|
107
|
+
if (checkDockerRunHistory(nodeInfo)) {
|
|
108
|
+
await dockerExecChown({
|
|
109
|
+
name: `${blocklet.meta.did}-clean-data`,
|
|
110
|
+
dirs: [dataDir, logsDir, cacheDir],
|
|
111
|
+
force: true,
|
|
112
|
+
});
|
|
113
|
+
}
|
|
114
|
+
|
|
115
|
+
logger.info(`clean blocklet ${blocklet.meta.did} data`, { keepData, keepLogsDir, keepConfigs });
|
|
116
|
+
|
|
117
|
+
if (keepData === false) {
|
|
118
|
+
await manager._safeRemoveDir(blocklet.meta.did, name, [appCacheDir, dataDir, logsDir, cacheDir]);
|
|
119
|
+
await states.blockletExtras.remove({ did: blocklet.meta.did });
|
|
120
|
+
logger.info(`removed blocklet ${blocklet.meta.did} extra data`);
|
|
121
|
+
} else {
|
|
122
|
+
if (keepLogsDir === false) {
|
|
123
|
+
await manager._safeRemoveDir(blocklet.meta.did, name, [appCacheDir, logsDir]);
|
|
124
|
+
} else {
|
|
125
|
+
await manager._safeRemoveDir(blocklet.meta.did, name, [appCacheDir]);
|
|
126
|
+
}
|
|
127
|
+
|
|
128
|
+
if (keepConfigs === false) {
|
|
129
|
+
await states.blockletExtras.remove({ did: blocklet.meta.did });
|
|
130
|
+
logger.info(`removed blocklet ${blocklet.meta.did} extra data`);
|
|
131
|
+
}
|
|
132
|
+
}
|
|
133
|
+
}
|
|
134
|
+
|
|
135
|
+
/**
|
|
136
|
+
* Get blocklet for installation with extra state
|
|
137
|
+
* @param {string} did - Blocklet DID
|
|
138
|
+
* @returns {Promise<Object|null>}
|
|
139
|
+
*/
|
|
140
|
+
async function _getBlockletForInstallation(did) {
|
|
141
|
+
const blocklet = await states.blocklet.getBlocklet(did, { decryptSk: false });
|
|
142
|
+
if (!blocklet) {
|
|
143
|
+
return null;
|
|
144
|
+
}
|
|
145
|
+
|
|
146
|
+
const extraState = await states.blockletExtras.findOne({ did: blocklet.meta.did });
|
|
147
|
+
blocklet.extraState = extraState;
|
|
148
|
+
|
|
149
|
+
return blocklet;
|
|
150
|
+
}
|
|
151
|
+
|
|
152
|
+
module.exports = {
|
|
153
|
+
_rollback,
|
|
154
|
+
_deleteBlocklet,
|
|
155
|
+
_cleanBlockletData,
|
|
156
|
+
_getBlockletForInstallation,
|
|
157
|
+
};
|
|
@@ -0,0 +1,83 @@
|
|
|
1
|
+
const logger = require('@abtnode/logger')('@abtnode/core:blocklet:manager:component');
|
|
2
|
+
const { BlockletGroup, BlockletEvents, BlockletInternalEvents, BlockletStatus } = require('@blocklet/constant');
|
|
3
|
+
const { updateMountPointSchema } = require('@blocklet/meta/lib/schema');
|
|
4
|
+
const { getComponentsInternalInfo } = require('@blocklet/meta/lib/blocklet');
|
|
5
|
+
|
|
6
|
+
const states = require('../../../states');
|
|
7
|
+
const { checkDuplicateMountPoint } = require('../../../util/blocklet');
|
|
8
|
+
|
|
9
|
+
/**
|
|
10
|
+
* Update component mount point
|
|
11
|
+
* @param {Object} manager - BlockletManager instance
|
|
12
|
+
* @param {Object} params
|
|
13
|
+
* @param {string} params.did - Component DID
|
|
14
|
+
* @param {string} params.rootDid - Root blocklet DID
|
|
15
|
+
* @param {string} params.mountPoint - New mount point
|
|
16
|
+
* @param {Object} context - Context
|
|
17
|
+
* @returns {Promise<Object>}
|
|
18
|
+
*/
|
|
19
|
+
async function updateComponentMountPoint(manager, { did, rootDid: inputRootDid, mountPoint: tmpMountPoint }, context) {
|
|
20
|
+
const mountPoint = await updateMountPointSchema.validateAsync(tmpMountPoint);
|
|
21
|
+
|
|
22
|
+
const blocklet = await states.blocklet.getBlocklet(inputRootDid);
|
|
23
|
+
|
|
24
|
+
if (!blocklet) {
|
|
25
|
+
throw new Error('blocklet does not exist');
|
|
26
|
+
}
|
|
27
|
+
|
|
28
|
+
const rootDid = blocklet.meta.did;
|
|
29
|
+
|
|
30
|
+
const isRootComponent = !did;
|
|
31
|
+
|
|
32
|
+
const component = isRootComponent ? blocklet : blocklet.children.find((x) => x.meta.did === did);
|
|
33
|
+
if (!component) {
|
|
34
|
+
throw new Error('component does not exist');
|
|
35
|
+
}
|
|
36
|
+
|
|
37
|
+
if (isRootComponent && component.group === BlockletGroup.gateway) {
|
|
38
|
+
throw new Error('cannot update mountPoint of gateway blocklet');
|
|
39
|
+
}
|
|
40
|
+
|
|
41
|
+
checkDuplicateMountPoint(blocklet, mountPoint);
|
|
42
|
+
|
|
43
|
+
component.mountPoint = mountPoint;
|
|
44
|
+
|
|
45
|
+
await states.blocklet.updateBlocklet(rootDid, { mountPoint: blocklet.mountPoint, children: blocklet.children });
|
|
46
|
+
|
|
47
|
+
manager.emit(BlockletEvents.upgraded, { blocklet, context: { ...context, createAuditLog: false } }); // trigger router refresh
|
|
48
|
+
manager.emit(BlockletInternalEvents.componentUpdated, {
|
|
49
|
+
appDid: blocklet.appDid,
|
|
50
|
+
components: getComponentsInternalInfo(blocklet).filter((x) => x.did === component.meta.did),
|
|
51
|
+
});
|
|
52
|
+
manager.configSynchronizer.throttledSyncAppConfig(blocklet.meta.did);
|
|
53
|
+
|
|
54
|
+
// Restart blocklet if it's running to pick up the new mount point
|
|
55
|
+
// Only restart the component that was modified (did)
|
|
56
|
+
if (!isRootComponent && did) {
|
|
57
|
+
const updatedBlocklet = await manager.getBlocklet(rootDid);
|
|
58
|
+
const updatedComponent = updatedBlocklet.children.find((x) => x.meta.did === did);
|
|
59
|
+
|
|
60
|
+
if (
|
|
61
|
+
updatedComponent &&
|
|
62
|
+
(updatedComponent.status === BlockletStatus.running || updatedComponent.greenStatus === BlockletStatus.running)
|
|
63
|
+
) {
|
|
64
|
+
try {
|
|
65
|
+
await manager.restart({ did: rootDid, componentDids: [did], operator: context?.user?.did }, context);
|
|
66
|
+
logger.info('restarted blocklet after mount point update', { rootDid, componentDid: did });
|
|
67
|
+
} catch (error) {
|
|
68
|
+
logger.error('failed to restart blocklet after mount point update', {
|
|
69
|
+
rootDid,
|
|
70
|
+
componentDid: did,
|
|
71
|
+
error,
|
|
72
|
+
});
|
|
73
|
+
// Don't throw error - mount point update succeeded, restart failure is logged but doesn't block the operation
|
|
74
|
+
}
|
|
75
|
+
}
|
|
76
|
+
}
|
|
77
|
+
|
|
78
|
+
return manager.getBlocklet(rootDid);
|
|
79
|
+
}
|
|
80
|
+
|
|
81
|
+
module.exports = {
|
|
82
|
+
updateComponentMountPoint,
|
|
83
|
+
};
|