@abtnode/core 1.16.21-beta-445a8baa → 1.16.21-beta-2e75c75c
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.js +22 -7
- package/lib/blocklet/manager/disk.js +293 -13
- package/lib/index.js +26 -0
- package/lib/states/user.js +0 -1
- package/lib/team/manager.js +18 -0
- package/lib/util/log.js +45 -24
- package/lib/util/spaces.js +10 -0
- package/package.json +32 -32
package/lib/api/team.js
CHANGED
|
@@ -1399,7 +1399,7 @@ class TeamAPI extends EventEmitter {
|
|
|
1399
1399
|
|
|
1400
1400
|
const userSessions = await state.model.findAll({
|
|
1401
1401
|
where,
|
|
1402
|
-
attributes: ['id', 'appPid', 'userDid', 'visitorId', 'passportId', 'updatedAt'],
|
|
1402
|
+
attributes: ['id', 'appPid', 'userDid', 'visitorId', 'passportId', 'updatedAt', 'extra'],
|
|
1403
1403
|
include: {
|
|
1404
1404
|
model: userState.model,
|
|
1405
1405
|
as: 'user',
|
|
@@ -1442,10 +1442,11 @@ class TeamAPI extends EventEmitter {
|
|
|
1442
1442
|
* @param {string} params.lastLoginIp - 记录的 userSession 中当前用户的最后登录 ip
|
|
1443
1443
|
* @param {string} params.passportId - 记录的 userSession 中当前用户登录所使用的 passportId
|
|
1444
1444
|
* @param {string} params.status - 记录的 userSession 的状态
|
|
1445
|
+
* @param {Object} params.extra - 记录的 userSession 额外的数据
|
|
1445
1446
|
* @returns
|
|
1446
1447
|
*/
|
|
1447
1448
|
|
|
1448
|
-
async upsertUserSession({ teamDid, appPid, userDid, visitorId, ua, lastLoginIp, passportId, status }) {
|
|
1449
|
+
async upsertUserSession({ teamDid, appPid, userDid, visitorId, ua, lastLoginIp, passportId, status, extra }) {
|
|
1449
1450
|
if (!userDid) {
|
|
1450
1451
|
throw new Error('userDid are required');
|
|
1451
1452
|
}
|
|
@@ -1459,13 +1460,14 @@ class TeamAPI extends EventEmitter {
|
|
|
1459
1460
|
lastLoginIp,
|
|
1460
1461
|
appPid,
|
|
1461
1462
|
passportId,
|
|
1463
|
+
extra,
|
|
1462
1464
|
});
|
|
1463
|
-
logger.info('insert userSession successfully', { userDid, ua, lastLoginIp, appPid, passportId });
|
|
1465
|
+
logger.info('insert userSession successfully', { userDid, ua, lastLoginIp, appPid, passportId, extra });
|
|
1464
1466
|
} else {
|
|
1465
1467
|
const exist = await state.findOne({ userDid, visitorId, appPid });
|
|
1466
1468
|
if (exist) {
|
|
1467
|
-
[, [data]] = await state.update(exist.id, { ua, lastLoginIp, passportId, status });
|
|
1468
|
-
logger.info('update userSession successfully', { id: exist.id, ua, lastLoginIp, passportId, status });
|
|
1469
|
+
[, [data]] = await state.update(exist.id, { ua, lastLoginIp, passportId, status, extra });
|
|
1470
|
+
logger.info('update userSession successfully', { id: exist.id, ua, lastLoginIp, passportId, status, extra });
|
|
1469
1471
|
} else {
|
|
1470
1472
|
data = await state.insert({
|
|
1471
1473
|
visitorId,
|
|
@@ -1474,8 +1476,17 @@ class TeamAPI extends EventEmitter {
|
|
|
1474
1476
|
lastLoginIp,
|
|
1475
1477
|
appPid,
|
|
1476
1478
|
passportId,
|
|
1479
|
+
extra,
|
|
1480
|
+
});
|
|
1481
|
+
logger.info('insert userSession successfully', {
|
|
1482
|
+
visitorId,
|
|
1483
|
+
userDid,
|
|
1484
|
+
ua,
|
|
1485
|
+
lastLoginIp,
|
|
1486
|
+
appPid,
|
|
1487
|
+
passportId,
|
|
1488
|
+
extra,
|
|
1477
1489
|
});
|
|
1478
|
-
logger.info('insert userSession successfully', { visitorId, userDid, ua, lastLoginIp, appPid, passportId });
|
|
1479
1490
|
}
|
|
1480
1491
|
}
|
|
1481
1492
|
|
|
@@ -1491,9 +1502,10 @@ class TeamAPI extends EventEmitter {
|
|
|
1491
1502
|
* @param {string} params.ua - 同步的 userSession 中当前用户所使用设备的 ua
|
|
1492
1503
|
* @param {string} params.lastLoginIp - 同步的 userSession 中当前用户的最后登录 ip
|
|
1493
1504
|
* @param {string} params.passportId - 同步的 userSession 中当前用户登录所使用的 passportId
|
|
1505
|
+
* @param {object} params.extra - 同步的 userSession 中当前用户登录额外的数据
|
|
1494
1506
|
* @returns
|
|
1495
1507
|
*/
|
|
1496
|
-
async syncUserSession({ teamDid, targetAppPid, userDid, visitorId, ua, lastLoginIp, passportId }) {
|
|
1508
|
+
async syncUserSession({ teamDid, targetAppPid, userDid, visitorId, ua, lastLoginIp, passportId, extra }) {
|
|
1497
1509
|
if (!targetAppPid) return;
|
|
1498
1510
|
|
|
1499
1511
|
const blocklet = await getBlocklet({ did: teamDid, states: this.states, dataDirs: this.dataDirs });
|
|
@@ -1526,6 +1538,7 @@ class TeamAPI extends EventEmitter {
|
|
|
1526
1538
|
lastLoginIp,
|
|
1527
1539
|
appPid,
|
|
1528
1540
|
passportId,
|
|
1541
|
+
extra,
|
|
1529
1542
|
};
|
|
1530
1543
|
await callFederated({
|
|
1531
1544
|
action: 'sync',
|
|
@@ -1543,6 +1556,7 @@ class TeamAPI extends EventEmitter {
|
|
|
1543
1556
|
appPid,
|
|
1544
1557
|
passportId,
|
|
1545
1558
|
targetSite,
|
|
1559
|
+
extra,
|
|
1546
1560
|
});
|
|
1547
1561
|
} catch (err) {
|
|
1548
1562
|
logger.info(
|
|
@@ -1555,6 +1569,7 @@ class TeamAPI extends EventEmitter {
|
|
|
1555
1569
|
appPid,
|
|
1556
1570
|
passportId,
|
|
1557
1571
|
targetSite,
|
|
1572
|
+
extra,
|
|
1558
1573
|
},
|
|
1559
1574
|
err
|
|
1560
1575
|
);
|
|
@@ -30,6 +30,7 @@ const {
|
|
|
30
30
|
BACKUPS,
|
|
31
31
|
DEFAULT_DID_DOMAIN,
|
|
32
32
|
FEDERATED,
|
|
33
|
+
CHECK_UPDATE,
|
|
33
34
|
} = require('@abtnode/constant');
|
|
34
35
|
|
|
35
36
|
const getBlockletEngine = require('@blocklet/meta/lib/engine');
|
|
@@ -50,6 +51,7 @@ const {
|
|
|
50
51
|
findComponentByIdV2,
|
|
51
52
|
isGatewayBlocklet,
|
|
52
53
|
hasStartEngine,
|
|
54
|
+
getDisplayName,
|
|
53
55
|
} = require('@blocklet/meta/lib/util');
|
|
54
56
|
const { getComponentsInternalInfo } = require('@blocklet/meta/lib/blocklet');
|
|
55
57
|
const { update: updateMetaFile } = require('@blocklet/meta/lib/file');
|
|
@@ -96,6 +98,7 @@ const pRetry = require('p-retry');
|
|
|
96
98
|
const isFunction = require('lodash/isFunction');
|
|
97
99
|
const { encode } = require('@abtnode/util/lib/base32');
|
|
98
100
|
const formatContext = require('@abtnode/util/lib/format-context');
|
|
101
|
+
const md5 = require('@abtnode/util/lib/md5');
|
|
99
102
|
const { consumeServerlessNFT, consumeLauncherSession } = require('../../util/launcher');
|
|
100
103
|
const util = require('../../util');
|
|
101
104
|
const {
|
|
@@ -173,6 +176,7 @@ const {
|
|
|
173
176
|
getBackupEndpoint,
|
|
174
177
|
getSpaceNameByEndpoint,
|
|
175
178
|
getBackupJobId,
|
|
179
|
+
getCheckUpdateJobId,
|
|
176
180
|
} = require('../../util/spaces');
|
|
177
181
|
const { validateAddSpaceGateway, validateUpdateSpaceGateway } = require('../../validators/space-gateway');
|
|
178
182
|
const { sessionConfigSchema } = require('../../validators/util');
|
|
@@ -216,7 +220,16 @@ const pm2StatusMap = {
|
|
|
216
220
|
const getBlockletEngineNameByPlatform = (blockletMeta) => getBlockletEngine(blockletMeta).interpreter;
|
|
217
221
|
|
|
218
222
|
class DiskBlockletManager extends BaseBlockletManager {
|
|
219
|
-
constructor({
|
|
223
|
+
constructor({
|
|
224
|
+
dataDirs,
|
|
225
|
+
startQueue,
|
|
226
|
+
installQueue,
|
|
227
|
+
backupQueue,
|
|
228
|
+
restoreQueue,
|
|
229
|
+
checkUpdateQueue,
|
|
230
|
+
daemon = false,
|
|
231
|
+
teamManager,
|
|
232
|
+
}) {
|
|
220
233
|
super();
|
|
221
234
|
|
|
222
235
|
this.dataDirs = dataDirs;
|
|
@@ -228,6 +241,7 @@ class DiskBlockletManager extends BaseBlockletManager {
|
|
|
228
241
|
*/
|
|
229
242
|
this.backupQueue = backupQueue;
|
|
230
243
|
this.restoreQueue = restoreQueue;
|
|
244
|
+
this.checkUpdateQueue = checkUpdateQueue;
|
|
231
245
|
this.teamManager = teamManager;
|
|
232
246
|
|
|
233
247
|
if (isFunction(this.backupQueue.on)) {
|
|
@@ -271,33 +285,54 @@ class DiskBlockletManager extends BaseBlockletManager {
|
|
|
271
285
|
blockletPm2Events.on('online', (data) => this._syncPm2Status('online', data.blockletDid, data.componentDid));
|
|
272
286
|
blockletPm2Events.on('stop', (data) => this._syncPm2Status('stop', data.blockletDid, data.componentDid));
|
|
273
287
|
}
|
|
288
|
+
|
|
289
|
+
if (isFunction(this.checkUpdateQueue?.on)) {
|
|
290
|
+
/**
|
|
291
|
+
*
|
|
292
|
+
* @param {{
|
|
293
|
+
* id: string,
|
|
294
|
+
* job: { did: string }
|
|
295
|
+
* }} param0
|
|
296
|
+
*/
|
|
297
|
+
const handleCheckUpdateComplete = async ({ id: jobId, job }) => {
|
|
298
|
+
await this.checkUpdateQueue.delete(jobId);
|
|
299
|
+
const { did } = job;
|
|
300
|
+
const checkUpdate = await this.getAutoCheckUpdate({ did });
|
|
301
|
+
if (checkUpdate?.enabled) {
|
|
302
|
+
this.checkUpdateQueue.push(job, jobId, true, CHECK_UPDATE.JOB.INTERVAL);
|
|
303
|
+
}
|
|
304
|
+
};
|
|
305
|
+
this.checkUpdateQueue.on('finished', handleCheckUpdateComplete).on('failed', handleCheckUpdateComplete);
|
|
306
|
+
}
|
|
274
307
|
}
|
|
275
308
|
|
|
276
309
|
async initialize() {
|
|
277
310
|
await this.ensureAutoBackupJobs();
|
|
311
|
+
await this.ensureAutoCheckUpdateJobs();
|
|
278
312
|
}
|
|
279
313
|
|
|
280
|
-
async
|
|
281
|
-
const blocklets = await states.blockletExtras.find(
|
|
282
|
-
'settings.autoBackup.enabled': true,
|
|
283
|
-
});
|
|
314
|
+
async ensureJobs({ queue, getJobId, find, entity, action, interval, restoreCancelled }) {
|
|
315
|
+
const blocklets = await states.blockletExtras.find(find);
|
|
284
316
|
|
|
285
317
|
const info = await states.node.read();
|
|
286
318
|
|
|
287
319
|
await Promise.all(
|
|
288
320
|
blocklets.map(async (x) => {
|
|
289
321
|
const { did } = x;
|
|
290
|
-
const jobId =
|
|
291
|
-
const job = await
|
|
322
|
+
const jobId = getJobId(did);
|
|
323
|
+
const job = await queue.get(jobId);
|
|
324
|
+
if (restoreCancelled) {
|
|
325
|
+
queue.restoreCancelled(jobId);
|
|
326
|
+
}
|
|
292
327
|
|
|
293
328
|
if (job) {
|
|
294
329
|
return;
|
|
295
330
|
}
|
|
296
331
|
|
|
297
|
-
|
|
332
|
+
queue.push(
|
|
298
333
|
{
|
|
299
|
-
entity
|
|
300
|
-
action
|
|
334
|
+
entity,
|
|
335
|
+
action,
|
|
301
336
|
did,
|
|
302
337
|
context: formatContext({
|
|
303
338
|
user: { did: info.did },
|
|
@@ -305,12 +340,40 @@ class DiskBlockletManager extends BaseBlockletManager {
|
|
|
305
340
|
},
|
|
306
341
|
jobId,
|
|
307
342
|
true,
|
|
308
|
-
|
|
343
|
+
interval
|
|
309
344
|
);
|
|
310
345
|
})
|
|
311
346
|
);
|
|
312
347
|
}
|
|
313
348
|
|
|
349
|
+
async ensureAutoBackupJobs() {
|
|
350
|
+
await this.ensureJobs({
|
|
351
|
+
queue: this.backupQueue,
|
|
352
|
+
getJobId: getBackupJobId,
|
|
353
|
+
find: {
|
|
354
|
+
'settings.autoBackup.enabled': true,
|
|
355
|
+
},
|
|
356
|
+
entity: 'blocklet',
|
|
357
|
+
action: 'backupToSpaces',
|
|
358
|
+
interval: BACKUPS.JOB.INTERVAL,
|
|
359
|
+
restoreCancelled: false,
|
|
360
|
+
});
|
|
361
|
+
}
|
|
362
|
+
|
|
363
|
+
async ensureAutoCheckUpdateJobs() {
|
|
364
|
+
await this.ensureJobs({
|
|
365
|
+
queue: this.checkUpdateQueue,
|
|
366
|
+
getJobId: getCheckUpdateJobId,
|
|
367
|
+
find: {
|
|
368
|
+
'settings.autoCheckUpdate.enabled': true,
|
|
369
|
+
},
|
|
370
|
+
entity: 'blocklet',
|
|
371
|
+
action: 'autoCheckUpdate',
|
|
372
|
+
interval: CHECK_UPDATE.JOB.INTERVAL,
|
|
373
|
+
restoreCancelled: true,
|
|
374
|
+
});
|
|
375
|
+
}
|
|
376
|
+
|
|
314
377
|
// ============================================================================================
|
|
315
378
|
// Public API for Installing/Upgrading Application or Components
|
|
316
379
|
// ============================================================================================
|
|
@@ -1024,6 +1087,7 @@ class DiskBlockletManager extends BaseBlockletManager {
|
|
|
1024
1087
|
entityId: newBlocklet.meta.did,
|
|
1025
1088
|
severity: 'success',
|
|
1026
1089
|
action: `/blocklets/${newBlocklet.meta.did}/components`,
|
|
1090
|
+
blockletDashboardAction: '/.well-known/service/admin/components',
|
|
1027
1091
|
});
|
|
1028
1092
|
|
|
1029
1093
|
this.emit(BlockletEvents.componentRemoved, {
|
|
@@ -1792,6 +1856,10 @@ class DiskBlockletManager extends BaseBlockletManager {
|
|
|
1792
1856
|
if (job.action === 'restoreFromSpaces') {
|
|
1793
1857
|
await this._onRestoreFromSpaces(job);
|
|
1794
1858
|
}
|
|
1859
|
+
|
|
1860
|
+
if (job.action === 'autoCheckUpdate') {
|
|
1861
|
+
await this._onCheckForComponentUpdate(job);
|
|
1862
|
+
}
|
|
1795
1863
|
}
|
|
1796
1864
|
}
|
|
1797
1865
|
|
|
@@ -1985,10 +2053,52 @@ class DiskBlockletManager extends BaseBlockletManager {
|
|
|
1985
2053
|
*/
|
|
1986
2054
|
async getAutoBackup({ did }) {
|
|
1987
2055
|
const autoBackup = await states.blockletExtras.getSettings(did, 'autoBackup', { enabled: false });
|
|
1988
|
-
|
|
1989
2056
|
return autoBackup;
|
|
1990
2057
|
}
|
|
1991
2058
|
|
|
2059
|
+
/**
|
|
2060
|
+
* @description
|
|
2061
|
+
* @param {{
|
|
2062
|
+
* did: string,
|
|
2063
|
+
* autoCheckUpdate: import('@abtnode/client').AutoCheckUpdate
|
|
2064
|
+
* }} { did, autoCheckUpdate }
|
|
2065
|
+
* @param {{}} context
|
|
2066
|
+
* @memberof DiskBlockletManager
|
|
2067
|
+
*/
|
|
2068
|
+
async updateAutoCheckUpdate({ did, autoCheckUpdate }, context) {
|
|
2069
|
+
/** @type {import('@abtnode/client').AutoCheckUpdate} */
|
|
2070
|
+
const value = { ...autoCheckUpdate };
|
|
2071
|
+
await states.blockletExtras.setSettings(did, { autoCheckUpdate: value });
|
|
2072
|
+
const jobId = getCheckUpdateJobId(did);
|
|
2073
|
+
await this.checkUpdateQueue.delete(jobId);
|
|
2074
|
+
|
|
2075
|
+
logger.info('updateAutoCheckUpdate.$value', value);
|
|
2076
|
+
|
|
2077
|
+
if (value.enabled) {
|
|
2078
|
+
this.checkUpdateQueue.push(
|
|
2079
|
+
{
|
|
2080
|
+
entity: 'blocklet',
|
|
2081
|
+
action: 'autoCheckUpdate',
|
|
2082
|
+
did,
|
|
2083
|
+
context,
|
|
2084
|
+
},
|
|
2085
|
+
jobId,
|
|
2086
|
+
true,
|
|
2087
|
+
CHECK_UPDATE.JOB.DAY_INTERVAL
|
|
2088
|
+
);
|
|
2089
|
+
}
|
|
2090
|
+
}
|
|
2091
|
+
|
|
2092
|
+
/**
|
|
2093
|
+
* @description
|
|
2094
|
+
* @param {import('@abtnode/client').RequestGetAutoCheckUpdateInput} { did }
|
|
2095
|
+
* @return {Promise<import('@abtnode/client').AutoCheckUpdate>}
|
|
2096
|
+
* @memberof DiskBlockletManager
|
|
2097
|
+
*/
|
|
2098
|
+
getAutoCheckUpdate({ did }) {
|
|
2099
|
+
return states.blockletExtras.getSettings(did, 'autoCheckUpdate', { enabled: false });
|
|
2100
|
+
}
|
|
2101
|
+
|
|
1992
2102
|
/**
|
|
1993
2103
|
* @description
|
|
1994
2104
|
* @param {{ did: string }} { did }
|
|
@@ -2563,6 +2673,176 @@ class DiskBlockletManager extends BaseBlockletManager {
|
|
|
2563
2673
|
}
|
|
2564
2674
|
}
|
|
2565
2675
|
|
|
2676
|
+
async _onCheckForComponentUpdate({ did }) {
|
|
2677
|
+
const list = await UpgradeComponents.check({ did, states });
|
|
2678
|
+
if (!list || !list.updateList?.length) {
|
|
2679
|
+
return;
|
|
2680
|
+
}
|
|
2681
|
+
const updateList = list.updateList.map((item) => {
|
|
2682
|
+
return { title: item.meta.title, description: item.meta.description, version: item.meta.version };
|
|
2683
|
+
});
|
|
2684
|
+
|
|
2685
|
+
const checkUpdateMd5 = md5(JSON.stringify(updateList));
|
|
2686
|
+
const oldMd5 = await states.blockletExtras.getSettings(did, 'checkUpdateMd5', '');
|
|
2687
|
+
// notification has been sent, no more
|
|
2688
|
+
if (checkUpdateMd5 === oldMd5) {
|
|
2689
|
+
return;
|
|
2690
|
+
}
|
|
2691
|
+
const blocklet = await this.getBlocklet(did);
|
|
2692
|
+
const firstComponent = updateList[0];
|
|
2693
|
+
const blockletTitle = getDisplayName(blocklet);
|
|
2694
|
+
|
|
2695
|
+
const description = {
|
|
2696
|
+
en: `${blockletTitle} has components with a new version: ${firstComponent.title} ${firstComponent.version} ${
|
|
2697
|
+
updateList.length > 1 ? 'and more...' : '.'
|
|
2698
|
+
}`,
|
|
2699
|
+
zh: `${blockletTitle} 的组件有新版本: ${firstComponent.title} ${updateList.length > 1 ? '等等...' : '.'}`,
|
|
2700
|
+
};
|
|
2701
|
+
const title = {
|
|
2702
|
+
en: `${blockletTitle} has components with a new version`,
|
|
2703
|
+
zh: `${blockletTitle} 的组件有新版本`,
|
|
2704
|
+
};
|
|
2705
|
+
const body = {
|
|
2706
|
+
en: `${blockletTitle} has new versions of the following components:`,
|
|
2707
|
+
zh: `${blockletTitle} 以下组件有新版:`,
|
|
2708
|
+
};
|
|
2709
|
+
const button = {
|
|
2710
|
+
en: 'Upgrade to new version',
|
|
2711
|
+
zh: '升级到新版本',
|
|
2712
|
+
};
|
|
2713
|
+
|
|
2714
|
+
const action = `/blocklets/${did}/components?checkUpdate=1`;
|
|
2715
|
+
const blockletDashboardAction = '/.well-known/service/admin/components?checkUpdate=1';
|
|
2716
|
+
const users = await this.teamManager.getOwnerAndAdminUsers(did, 1);
|
|
2717
|
+
const nodeInfo = await states.node.read();
|
|
2718
|
+
const { wallet } = getBlockletInfo(blocklet, nodeInfo.sk);
|
|
2719
|
+
|
|
2720
|
+
const attachments = [
|
|
2721
|
+
{
|
|
2722
|
+
type: 'section',
|
|
2723
|
+
fields: updateList
|
|
2724
|
+
.slice(0, 3)
|
|
2725
|
+
.map((item) => {
|
|
2726
|
+
return [
|
|
2727
|
+
{
|
|
2728
|
+
type: 'text',
|
|
2729
|
+
data: { type: 'plain', color: '#9397A1', text: item.title },
|
|
2730
|
+
},
|
|
2731
|
+
{
|
|
2732
|
+
type: 'text',
|
|
2733
|
+
data: { type: 'plain', text: item.version },
|
|
2734
|
+
},
|
|
2735
|
+
];
|
|
2736
|
+
})
|
|
2737
|
+
.flat(),
|
|
2738
|
+
},
|
|
2739
|
+
];
|
|
2740
|
+
|
|
2741
|
+
try {
|
|
2742
|
+
await this._sendAllMessageToUser({
|
|
2743
|
+
did,
|
|
2744
|
+
blocklet,
|
|
2745
|
+
title,
|
|
2746
|
+
body,
|
|
2747
|
+
button,
|
|
2748
|
+
attachments,
|
|
2749
|
+
description,
|
|
2750
|
+
action,
|
|
2751
|
+
blockletDashboardAction,
|
|
2752
|
+
sender: {
|
|
2753
|
+
appDid: wallet.address,
|
|
2754
|
+
appSk: wallet.secretKey,
|
|
2755
|
+
},
|
|
2756
|
+
users,
|
|
2757
|
+
});
|
|
2758
|
+
await states.blockletExtras.setSettings(did, { checkUpdateMd5 });
|
|
2759
|
+
} catch (err) {
|
|
2760
|
+
logger.error('send checked update email failed', { error: err });
|
|
2761
|
+
}
|
|
2762
|
+
}
|
|
2763
|
+
|
|
2764
|
+
/**
|
|
2765
|
+
* @description send notification to multiple users, and send different notifications according to the user's own language
|
|
2766
|
+
* @param {{
|
|
2767
|
+
* did: string,
|
|
2768
|
+
* blocklet: import('@abtnode/client').BlockletState,
|
|
2769
|
+
* title: {zh: string, en: string},
|
|
2770
|
+
* body: {zh: string, en: string},
|
|
2771
|
+
* button: {zh: string, en: string},
|
|
2772
|
+
* description: {zh: string, en: string},
|
|
2773
|
+
* attachments: Array<import('@abtnode/client').NotificationAttachment>,
|
|
2774
|
+
* action: string,
|
|
2775
|
+
* blockletDashboardAction: string,
|
|
2776
|
+
* sender: { appDid: string, appSk: string },
|
|
2777
|
+
* users: Array<{ did: string, locale: string }>
|
|
2778
|
+
* */
|
|
2779
|
+
async _sendAllMessageToUser({
|
|
2780
|
+
did,
|
|
2781
|
+
blocklet,
|
|
2782
|
+
title,
|
|
2783
|
+
body,
|
|
2784
|
+
button,
|
|
2785
|
+
description,
|
|
2786
|
+
attachments,
|
|
2787
|
+
action,
|
|
2788
|
+
blockletDashboardAction,
|
|
2789
|
+
sender,
|
|
2790
|
+
users,
|
|
2791
|
+
}) {
|
|
2792
|
+
this._createNotification(did, {
|
|
2793
|
+
title: '',
|
|
2794
|
+
description: description.en,
|
|
2795
|
+
entityType: 'blocklet',
|
|
2796
|
+
entityId: did,
|
|
2797
|
+
severity: 'success',
|
|
2798
|
+
action,
|
|
2799
|
+
blockletDashboardAction,
|
|
2800
|
+
});
|
|
2801
|
+
|
|
2802
|
+
const zhUsers = users.filter((x) => x.locale === 'zh');
|
|
2803
|
+
const enUsers = users.filter((x) => x.locale !== 'zh');
|
|
2804
|
+
const url = `http://${getDidDomainForBlocklet({
|
|
2805
|
+
did: blocklet.appPid,
|
|
2806
|
+
})}`;
|
|
2807
|
+
const link = `${url}${blockletDashboardAction}`;
|
|
2808
|
+
|
|
2809
|
+
// send in batches by language
|
|
2810
|
+
if (zhUsers.length) {
|
|
2811
|
+
await sendToUser(
|
|
2812
|
+
zhUsers.map((x) => x.did),
|
|
2813
|
+
{
|
|
2814
|
+
title: title.zh,
|
|
2815
|
+
body: body.zh,
|
|
2816
|
+
attachments,
|
|
2817
|
+
actions: [
|
|
2818
|
+
{
|
|
2819
|
+
name: button.zh,
|
|
2820
|
+
link,
|
|
2821
|
+
},
|
|
2822
|
+
],
|
|
2823
|
+
},
|
|
2824
|
+
sender
|
|
2825
|
+
);
|
|
2826
|
+
}
|
|
2827
|
+
if (enUsers.length) {
|
|
2828
|
+
await sendToUser(
|
|
2829
|
+
enUsers.map((x) => x.did),
|
|
2830
|
+
{
|
|
2831
|
+
title: title.en,
|
|
2832
|
+
body: body.en,
|
|
2833
|
+
attachments,
|
|
2834
|
+
actions: [
|
|
2835
|
+
{
|
|
2836
|
+
name: button.en,
|
|
2837
|
+
link,
|
|
2838
|
+
},
|
|
2839
|
+
],
|
|
2840
|
+
},
|
|
2841
|
+
sender
|
|
2842
|
+
);
|
|
2843
|
+
}
|
|
2844
|
+
}
|
|
2845
|
+
|
|
2566
2846
|
async getBlockletEnvironments(did) {
|
|
2567
2847
|
const blockletWithEnv = await this.getBlocklet(did);
|
|
2568
2848
|
const nodeInfo = await states.node.read();
|
|
@@ -3427,10 +3707,10 @@ class DiskBlockletManager extends BaseBlockletManager {
|
|
|
3427
3707
|
if (!isExternal) {
|
|
3428
3708
|
await states.notification.create({ ...notification, blockletUrl });
|
|
3429
3709
|
}
|
|
3430
|
-
|
|
3431
3710
|
await this.teamManager.createNotification({
|
|
3432
3711
|
teamDid: did,
|
|
3433
3712
|
...notification,
|
|
3713
|
+
action: notification.blockletDashboardAction || notification.action,
|
|
3434
3714
|
blockletUrl,
|
|
3435
3715
|
});
|
|
3436
3716
|
} catch (error) {
|
package/lib/index.js
CHANGED
|
@@ -162,6 +162,27 @@ function ABTNode(options) {
|
|
|
162
162
|
},
|
|
163
163
|
});
|
|
164
164
|
|
|
165
|
+
const checkUpdateQueue = createQueue({
|
|
166
|
+
daemon: options.daemon,
|
|
167
|
+
model: states.job,
|
|
168
|
+
name: 'check_update_queue',
|
|
169
|
+
onJob: async (job) => {
|
|
170
|
+
// eslint-disable-next-line no-use-before-define
|
|
171
|
+
if (typeof blockletManager.onJob === 'function') {
|
|
172
|
+
// eslint-disable-next-line no-use-before-define
|
|
173
|
+
await blockletManager.onJob(job);
|
|
174
|
+
}
|
|
175
|
+
},
|
|
176
|
+
options: {
|
|
177
|
+
concurrency,
|
|
178
|
+
maxRetries: 0,
|
|
179
|
+
retryDelay: 10000, // retry after 10 seconds
|
|
180
|
+
maxTimeout: 60 * 1000 * 60, // throw timeout error after 60 minutes
|
|
181
|
+
id: (job) => (job ? md5(`${job.entity}-${job.action}-${job.id}`) : ''),
|
|
182
|
+
enableScheduledJob: true,
|
|
183
|
+
},
|
|
184
|
+
});
|
|
185
|
+
|
|
165
186
|
const certManager = new Cert({
|
|
166
187
|
maintainerEmail: DEFAULT_CERTIFICATE_EMAIL,
|
|
167
188
|
dataDir: dataDirs.certManagerModule,
|
|
@@ -188,6 +209,7 @@ function ABTNode(options) {
|
|
|
188
209
|
installQueue,
|
|
189
210
|
backupQueue,
|
|
190
211
|
restoreQueue,
|
|
212
|
+
checkUpdateQueue,
|
|
191
213
|
daemon: options.daemon,
|
|
192
214
|
teamManager,
|
|
193
215
|
});
|
|
@@ -330,6 +352,10 @@ function ABTNode(options) {
|
|
|
330
352
|
// blocklet backup record
|
|
331
353
|
getBlockletBackups: blockletManager.getBlockletBackups.bind(blockletManager),
|
|
332
354
|
|
|
355
|
+
// check update
|
|
356
|
+
updateAutoCheckUpdate: blockletManager.updateAutoCheckUpdate.bind(blockletManager),
|
|
357
|
+
getAutoCheckUpdate: blockletManager.getAutoCheckUpdate.bind(blockletManager),
|
|
358
|
+
|
|
333
359
|
// Store
|
|
334
360
|
getBlockletMeta: StoreUtil.getBlockletMeta,
|
|
335
361
|
getStoreMeta: StoreUtil.getStoreMeta,
|
package/lib/states/user.js
CHANGED
package/lib/team/manager.js
CHANGED
|
@@ -7,6 +7,7 @@ const { EventEmitter } = require('events');
|
|
|
7
7
|
const upperFirst = require('lodash/upperFirst');
|
|
8
8
|
const get = require('lodash/get');
|
|
9
9
|
const pick = require('lodash/pick');
|
|
10
|
+
const { Op } = require('sequelize');
|
|
10
11
|
|
|
11
12
|
const { createRBAC, MemoryStorage, SequelizeStorage } = require('@abtnode/rbac');
|
|
12
13
|
const logger = require('@abtnode/logger')('@abtnode/core:team:manager');
|
|
@@ -453,6 +454,23 @@ class TeamManager extends EventEmitter {
|
|
|
453
454
|
getPid(did) {
|
|
454
455
|
return this.isNodeTeam(did) ? did : this.states.blocklet.getBlockletMetaDid(did);
|
|
455
456
|
}
|
|
457
|
+
|
|
458
|
+
async getOwnerAndAdminUsers(did, approved) {
|
|
459
|
+
const passportState = await this.getPassportState(did);
|
|
460
|
+
|
|
461
|
+
const passorts = await passportState.find({
|
|
462
|
+
where: { [Op.or]: [{ role: 'owner' }, { role: 'admin' }] },
|
|
463
|
+
attributes: ['userDid'],
|
|
464
|
+
});
|
|
465
|
+
const userDids = passorts.map((d) => d.userDid);
|
|
466
|
+
|
|
467
|
+
const userState = await this.getUserState(did);
|
|
468
|
+
const users = await userState.find({
|
|
469
|
+
where: { did: userDids, approved },
|
|
470
|
+
attributes: ['did', 'locale'],
|
|
471
|
+
});
|
|
472
|
+
return users;
|
|
473
|
+
}
|
|
456
474
|
}
|
|
457
475
|
|
|
458
476
|
module.exports = TeamManager;
|
package/lib/util/log.js
CHANGED
|
@@ -87,15 +87,21 @@ class StreamLog {
|
|
|
87
87
|
}
|
|
88
88
|
|
|
89
89
|
const createFile = (files) => {
|
|
90
|
-
|
|
91
|
-
|
|
90
|
+
files.forEach((file) => {
|
|
91
|
+
const targetFile = typeof file === 'string' ? file : file.target;
|
|
92
|
+
|
|
93
|
+
if (!fs.existsSync(targetFile)) {
|
|
92
94
|
try {
|
|
93
|
-
const dir = path.dirname(
|
|
95
|
+
const dir = path.dirname(targetFile);
|
|
94
96
|
fs.mkdirSync(dir, { recursive: true });
|
|
95
97
|
} catch (err) {
|
|
96
98
|
// Do nothing
|
|
97
99
|
}
|
|
98
|
-
fs.writeFileSync(
|
|
100
|
+
fs.writeFileSync(targetFile, '', 'utf8');
|
|
101
|
+
}
|
|
102
|
+
|
|
103
|
+
if (file.symbol && !fs.existsSync(file.symbol)) {
|
|
104
|
+
fs.symlinkSync(targetFile, file.symbol);
|
|
99
105
|
}
|
|
100
106
|
});
|
|
101
107
|
};
|
|
@@ -112,25 +118,28 @@ const getLogFiles = async ({ name, node }) => {
|
|
|
112
118
|
if (name === 'abtnode') {
|
|
113
119
|
const logDir = path.join(node.dataDirs.logs, '_abtnode');
|
|
114
120
|
|
|
115
|
-
const
|
|
116
|
-
const
|
|
121
|
+
const infoSymbol = path.join(logDir, 'daemon.log');
|
|
122
|
+
const infoTarget = path.join(logDir, `daemon-${date}.log`);
|
|
123
|
+
const errorSymbol = path.join(logDir, 'daemon-error.log');
|
|
124
|
+
const errorTarget = path.join(logDir, `daemon-error-${date}.log`);
|
|
125
|
+
|
|
117
126
|
const access = path.join(logDir, 'access.log');
|
|
118
127
|
const stdout = path.join(logDir, 'daemon.stdout.log');
|
|
119
128
|
const stderr = path.join(logDir, 'daemon.stderr.log');
|
|
120
129
|
const pm2 = path.join(process.env.PM2_HOME, 'pm2.log');
|
|
121
130
|
|
|
122
|
-
createFile(
|
|
123
|
-
|
|
124
|
-
|
|
131
|
+
createFile([
|
|
132
|
+
{ symbol: infoSymbol, target: infoTarget },
|
|
133
|
+
{ symbol: errorSymbol, target: errorTarget },
|
|
125
134
|
access,
|
|
126
135
|
stdout,
|
|
127
136
|
stderr,
|
|
128
137
|
pm2,
|
|
129
|
-
|
|
138
|
+
]);
|
|
130
139
|
|
|
131
140
|
return {
|
|
132
|
-
info,
|
|
133
|
-
error,
|
|
141
|
+
info: infoSymbol,
|
|
142
|
+
error: errorSymbol,
|
|
134
143
|
access,
|
|
135
144
|
stdout,
|
|
136
145
|
stderr,
|
|
@@ -140,13 +149,22 @@ const getLogFiles = async ({ name, node }) => {
|
|
|
140
149
|
|
|
141
150
|
if (name === 'blocklet-services') {
|
|
142
151
|
const logDir = path.join(node.dataDirs.logs, '_abtnode');
|
|
143
|
-
const
|
|
144
|
-
const
|
|
152
|
+
const infoSymbol = path.join(logDir, 'service.log');
|
|
153
|
+
const infoTarget = path.join(logDir, `service-${date}.log`);
|
|
154
|
+
const errorSymbol = path.join(logDir, 'service-error.log');
|
|
155
|
+
const errorTarget = path.join(logDir, `service-error-${date}.log`);
|
|
145
156
|
const access = path.join(logDir, 'service.access.log');
|
|
146
157
|
const stdout = path.join(logDir, 'service.stdout.log');
|
|
147
158
|
const stderr = path.join(logDir, 'service.stderr.log');
|
|
148
|
-
createFile(
|
|
149
|
-
|
|
159
|
+
createFile([
|
|
160
|
+
{ info: infoSymbol, target: infoTarget },
|
|
161
|
+
{ symbol: errorSymbol, target: errorTarget },
|
|
162
|
+
access,
|
|
163
|
+
stdout,
|
|
164
|
+
stderr,
|
|
165
|
+
]);
|
|
166
|
+
|
|
167
|
+
return { info: infoSymbol, error: errorSymbol, access, stdout, stderr };
|
|
150
168
|
}
|
|
151
169
|
|
|
152
170
|
if (name.indexOf('blocklet-') === 0) {
|
|
@@ -164,23 +182,25 @@ const getLogFiles = async ({ name, node }) => {
|
|
|
164
182
|
}
|
|
165
183
|
|
|
166
184
|
const dir = path.join(node.dataDirs.logs, blockletName);
|
|
167
|
-
const
|
|
168
|
-
const
|
|
185
|
+
const infoSymbol = path.join(dir, 'info.log');
|
|
186
|
+
const infoTarget = path.join(dir, `info-${date}.log`);
|
|
187
|
+
const errorSymbol = path.join(dir, 'info-error.log');
|
|
188
|
+
const errorTarget = path.join(dir, `info-error-${date}.log`);
|
|
169
189
|
const access = path.join(dir, 'access.log');
|
|
170
190
|
const stdout = path.join(dir, 'output.log');
|
|
171
191
|
const stderr = path.join(dir, 'error.log');
|
|
172
192
|
|
|
173
|
-
createFile(
|
|
174
|
-
|
|
175
|
-
|
|
193
|
+
createFile([
|
|
194
|
+
{ symbol: infoSymbol, target: infoTarget },
|
|
195
|
+
{ symbol: errorSymbol, target: errorTarget },
|
|
176
196
|
access,
|
|
177
197
|
stdout,
|
|
178
198
|
stderr,
|
|
179
|
-
|
|
199
|
+
]);
|
|
180
200
|
|
|
181
201
|
return {
|
|
182
|
-
info,
|
|
183
|
-
error,
|
|
202
|
+
info: infoSymbol,
|
|
203
|
+
error: errorSymbol,
|
|
184
204
|
access,
|
|
185
205
|
stdout,
|
|
186
206
|
stderr,
|
|
@@ -343,6 +363,7 @@ const createStreamLogManager = ({ onLog, onGetLogFiles }) => {
|
|
|
343
363
|
// update files
|
|
344
364
|
// push recent 100 log
|
|
345
365
|
const { recent = 100, ...logFiles } = await onGetLogFiles(name);
|
|
366
|
+
|
|
346
367
|
const changed = await log.setFiles(logFiles);
|
|
347
368
|
logger.info('log stream: added', { name, logFiles });
|
|
348
369
|
log.getRecent(recent, (error, level, data) => {
|
package/lib/util/spaces.js
CHANGED
|
@@ -81,10 +81,20 @@ function getBackupJobId(did) {
|
|
|
81
81
|
return `${did}.backupToSpaces`;
|
|
82
82
|
}
|
|
83
83
|
|
|
84
|
+
/**
|
|
85
|
+
* @description
|
|
86
|
+
* @param {string} did
|
|
87
|
+
* @return {string}
|
|
88
|
+
*/
|
|
89
|
+
function getCheckUpdateJobId(did) {
|
|
90
|
+
return `${did}.checkUpdate`;
|
|
91
|
+
}
|
|
92
|
+
|
|
84
93
|
module.exports = {
|
|
85
94
|
getBackupEndpoint,
|
|
86
95
|
getBackupFilesUrlFromEndpoint,
|
|
87
96
|
getDIDSpacesUrlFromEndpoint,
|
|
88
97
|
getSpaceNameByEndpoint,
|
|
89
98
|
getBackupJobId,
|
|
99
|
+
getCheckUpdateJobId,
|
|
90
100
|
};
|
package/package.json
CHANGED
|
@@ -3,7 +3,7 @@
|
|
|
3
3
|
"publishConfig": {
|
|
4
4
|
"access": "public"
|
|
5
5
|
},
|
|
6
|
-
"version": "1.16.21-beta-
|
|
6
|
+
"version": "1.16.21-beta-2e75c75c",
|
|
7
7
|
"description": "",
|
|
8
8
|
"main": "lib/index.js",
|
|
9
9
|
"files": [
|
|
@@ -19,39 +19,39 @@
|
|
|
19
19
|
"author": "wangshijun <wangshijun2010@gmail.com> (http://github.com/wangshijun)",
|
|
20
20
|
"license": "Apache-2.0",
|
|
21
21
|
"dependencies": {
|
|
22
|
-
"@abtnode/analytics": "1.16.21-beta-
|
|
23
|
-
"@abtnode/auth": "1.16.21-beta-
|
|
24
|
-
"@abtnode/certificate-manager": "1.16.21-beta-
|
|
25
|
-
"@abtnode/constant": "1.16.21-beta-
|
|
26
|
-
"@abtnode/cron": "1.16.21-beta-
|
|
27
|
-
"@abtnode/logger": "1.16.21-beta-
|
|
28
|
-
"@abtnode/models": "1.16.21-beta-
|
|
29
|
-
"@abtnode/queue": "1.16.21-beta-
|
|
30
|
-
"@abtnode/rbac": "1.16.21-beta-
|
|
31
|
-
"@abtnode/router-provider": "1.16.21-beta-
|
|
32
|
-
"@abtnode/static-server": "1.16.21-beta-
|
|
33
|
-
"@abtnode/timemachine": "1.16.21-beta-
|
|
34
|
-
"@abtnode/util": "1.16.21-beta-
|
|
35
|
-
"@arcblock/did": "1.18.
|
|
36
|
-
"@arcblock/did-auth": "1.18.
|
|
37
|
-
"@arcblock/did-ext": "^1.18.
|
|
22
|
+
"@abtnode/analytics": "1.16.21-beta-2e75c75c",
|
|
23
|
+
"@abtnode/auth": "1.16.21-beta-2e75c75c",
|
|
24
|
+
"@abtnode/certificate-manager": "1.16.21-beta-2e75c75c",
|
|
25
|
+
"@abtnode/constant": "1.16.21-beta-2e75c75c",
|
|
26
|
+
"@abtnode/cron": "1.16.21-beta-2e75c75c",
|
|
27
|
+
"@abtnode/logger": "1.16.21-beta-2e75c75c",
|
|
28
|
+
"@abtnode/models": "1.16.21-beta-2e75c75c",
|
|
29
|
+
"@abtnode/queue": "1.16.21-beta-2e75c75c",
|
|
30
|
+
"@abtnode/rbac": "1.16.21-beta-2e75c75c",
|
|
31
|
+
"@abtnode/router-provider": "1.16.21-beta-2e75c75c",
|
|
32
|
+
"@abtnode/static-server": "1.16.21-beta-2e75c75c",
|
|
33
|
+
"@abtnode/timemachine": "1.16.21-beta-2e75c75c",
|
|
34
|
+
"@abtnode/util": "1.16.21-beta-2e75c75c",
|
|
35
|
+
"@arcblock/did": "1.18.108",
|
|
36
|
+
"@arcblock/did-auth": "1.18.108",
|
|
37
|
+
"@arcblock/did-ext": "^1.18.108",
|
|
38
38
|
"@arcblock/did-motif": "^1.1.13",
|
|
39
|
-
"@arcblock/did-util": "1.18.
|
|
40
|
-
"@arcblock/event-hub": "1.18.
|
|
41
|
-
"@arcblock/jwt": "^1.18.
|
|
39
|
+
"@arcblock/did-util": "1.18.108",
|
|
40
|
+
"@arcblock/event-hub": "1.18.108",
|
|
41
|
+
"@arcblock/jwt": "^1.18.108",
|
|
42
42
|
"@arcblock/pm2-events": "^0.0.5",
|
|
43
|
-
"@arcblock/validator": "^1.18.
|
|
44
|
-
"@arcblock/vc": "1.18.
|
|
45
|
-
"@blocklet/constant": "1.16.21-beta-
|
|
46
|
-
"@blocklet/env": "1.16.21-beta-
|
|
47
|
-
"@blocklet/meta": "1.16.21-beta-
|
|
48
|
-
"@blocklet/resolver": "1.16.21-beta-
|
|
49
|
-
"@blocklet/sdk": "1.16.21-beta-
|
|
50
|
-
"@did-space/client": "^0.3.
|
|
43
|
+
"@arcblock/validator": "^1.18.108",
|
|
44
|
+
"@arcblock/vc": "1.18.108",
|
|
45
|
+
"@blocklet/constant": "1.16.21-beta-2e75c75c",
|
|
46
|
+
"@blocklet/env": "1.16.21-beta-2e75c75c",
|
|
47
|
+
"@blocklet/meta": "1.16.21-beta-2e75c75c",
|
|
48
|
+
"@blocklet/resolver": "1.16.21-beta-2e75c75c",
|
|
49
|
+
"@blocklet/sdk": "1.16.21-beta-2e75c75c",
|
|
50
|
+
"@did-space/client": "^0.3.49",
|
|
51
51
|
"@fidm/x509": "^1.2.1",
|
|
52
|
-
"@ocap/mcrypto": "1.18.
|
|
53
|
-
"@ocap/util": "1.18.
|
|
54
|
-
"@ocap/wallet": "1.18.
|
|
52
|
+
"@ocap/mcrypto": "1.18.108",
|
|
53
|
+
"@ocap/util": "1.18.108",
|
|
54
|
+
"@ocap/wallet": "1.18.108",
|
|
55
55
|
"@slack/webhook": "^5.0.4",
|
|
56
56
|
"archiver": "^5.3.1",
|
|
57
57
|
"axios": "^0.27.2",
|
|
@@ -102,5 +102,5 @@
|
|
|
102
102
|
"jest": "^27.5.1",
|
|
103
103
|
"unzipper": "^0.10.11"
|
|
104
104
|
},
|
|
105
|
-
"gitHead": "
|
|
105
|
+
"gitHead": "1fca0b58e1ed4f7a9bb268829a7c84290a01c89d"
|
|
106
106
|
}
|