@abtnode/blocklet-services 1.17.4-beta-20251201-225048-b1682a09 → 1.17.4-beta-20251202-034514-637cd8e2
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/api/services/notification/queue.js +90 -65
- package/api/socket/channel/did.js +32 -34
- package/package.json +23 -23
|
@@ -17,9 +17,11 @@ const {
|
|
|
17
17
|
NOTIFICATION_SEND_STATUS,
|
|
18
18
|
NOTIFICATION_SEND_FAILED_REASON,
|
|
19
19
|
} = require('@abtnode/constant');
|
|
20
|
+
const sleep = require('@abtnode/util/lib/sleep');
|
|
20
21
|
const { nanoid } = require('@blocklet/meta/lib/util');
|
|
21
22
|
const get = require('lodash/get');
|
|
22
23
|
const uniqBy = require('lodash/uniqBy');
|
|
24
|
+
const { getQueueConcurrencyByMem } = require('@abtnode/core/lib/util');
|
|
23
25
|
const { getBlockletInfo } = require('../../cache');
|
|
24
26
|
const { updateNotificationSendStatus } = require('../../socket/channel/did');
|
|
25
27
|
const eventHub =
|
|
@@ -29,6 +31,8 @@ const logger = require('../../libs/logger')('blocklet-services:notification-queu
|
|
|
29
31
|
|
|
30
32
|
const emailSchema = Joi.string().email().required();
|
|
31
33
|
|
|
34
|
+
const concurrency = getQueueConcurrencyByMem();
|
|
35
|
+
|
|
32
36
|
/**
|
|
33
37
|
*
|
|
34
38
|
* 校验是否是有效的 passthrough 消息
|
|
@@ -58,10 +62,14 @@ const createNotificationQueue = (name, options, handler) => {
|
|
|
58
62
|
maxRetries: 3,
|
|
59
63
|
retryDelay: 10 * 1000,
|
|
60
64
|
maxTimeout: 60 * 1000, // throw timeout error after 1 minutes
|
|
65
|
+
concurrency,
|
|
61
66
|
...(options ?? {}),
|
|
62
67
|
},
|
|
63
68
|
onJob: async (job) => {
|
|
64
69
|
await handler(job);
|
|
70
|
+
if (options.delay) {
|
|
71
|
+
await sleep(options.delay * 1000);
|
|
72
|
+
}
|
|
65
73
|
},
|
|
66
74
|
});
|
|
67
75
|
};
|
|
@@ -85,6 +93,7 @@ const init = ({ node, notificationService }) => {
|
|
|
85
93
|
{
|
|
86
94
|
maxRetries: 1,
|
|
87
95
|
retryDelay: 0,
|
|
96
|
+
enableScheduledJob: true,
|
|
88
97
|
},
|
|
89
98
|
async (job) => {
|
|
90
99
|
try {
|
|
@@ -111,28 +120,42 @@ const init = ({ node, notificationService }) => {
|
|
|
111
120
|
/**
|
|
112
121
|
* Push Kit 推送队列
|
|
113
122
|
*/
|
|
114
|
-
const pushKitPushQueue = createNotificationQueue(
|
|
115
|
-
|
|
116
|
-
|
|
123
|
+
const pushKitPushQueue = createNotificationQueue(
|
|
124
|
+
'send-notification-push',
|
|
125
|
+
{
|
|
126
|
+
enableScheduledJob: true,
|
|
127
|
+
},
|
|
128
|
+
async (job) => {
|
|
129
|
+
try {
|
|
130
|
+
const { notification, receiver, sender } = job;
|
|
117
131
|
|
|
118
|
-
|
|
119
|
-
|
|
120
|
-
|
|
132
|
+
if (!receiver) {
|
|
133
|
+
throw new Error('Invalid receiver');
|
|
134
|
+
}
|
|
121
135
|
|
|
122
|
-
|
|
123
|
-
|
|
124
|
-
|
|
125
|
-
|
|
126
|
-
|
|
127
|
-
|
|
128
|
-
|
|
129
|
-
|
|
130
|
-
|
|
131
|
-
|
|
132
|
-
|
|
136
|
+
await notificationService.sendToPush.exec({
|
|
137
|
+
sender,
|
|
138
|
+
receiver,
|
|
139
|
+
notification,
|
|
140
|
+
pushOnly: job.pushOnly,
|
|
141
|
+
});
|
|
142
|
+
} catch (error) {
|
|
143
|
+
if (error.logLevel === 'debug') {
|
|
144
|
+
logger.debug('Failed to send to push', {
|
|
145
|
+
notificationId: job.notification.id,
|
|
146
|
+
receiver: job.receiver,
|
|
147
|
+
error,
|
|
148
|
+
});
|
|
149
|
+
} else {
|
|
150
|
+
logger.error('Failed to send to push', {
|
|
151
|
+
notificationId: job.notification.id,
|
|
152
|
+
receiver: job.receiver,
|
|
153
|
+
error,
|
|
154
|
+
});
|
|
155
|
+
}
|
|
133
156
|
}
|
|
134
157
|
}
|
|
135
|
-
|
|
158
|
+
);
|
|
136
159
|
|
|
137
160
|
/**
|
|
138
161
|
* email 推送队列
|
|
@@ -184,7 +207,6 @@ const init = ({ node, notificationService }) => {
|
|
|
184
207
|
: null;
|
|
185
208
|
|
|
186
209
|
logger.info('Start send to email', {
|
|
187
|
-
email,
|
|
188
210
|
notificationId: job.notificationId,
|
|
189
211
|
});
|
|
190
212
|
await notificationService.sendToMail.exec({
|
|
@@ -206,7 +228,6 @@ const init = ({ node, notificationService }) => {
|
|
|
206
228
|
options,
|
|
207
229
|
});
|
|
208
230
|
logger.info('End send to email', {
|
|
209
|
-
email,
|
|
210
231
|
notificationId: job.notificationId,
|
|
211
232
|
});
|
|
212
233
|
} catch (error) {
|
|
@@ -381,7 +402,7 @@ const init = ({ node, notificationService }) => {
|
|
|
381
402
|
options,
|
|
382
403
|
},
|
|
383
404
|
},
|
|
384
|
-
delay:
|
|
405
|
+
delay: 8,
|
|
385
406
|
});
|
|
386
407
|
} else {
|
|
387
408
|
// eslint-disable-next-line no-lonely-if
|
|
@@ -516,12 +537,15 @@ const init = ({ node, notificationService }) => {
|
|
|
516
537
|
receiver: receiverDid,
|
|
517
538
|
});
|
|
518
539
|
pushKitPushQueue.push({
|
|
519
|
-
|
|
520
|
-
|
|
521
|
-
|
|
522
|
-
|
|
523
|
-
|
|
524
|
-
|
|
540
|
+
job: {
|
|
541
|
+
notification,
|
|
542
|
+
sender,
|
|
543
|
+
options,
|
|
544
|
+
receiver: receiverDid,
|
|
545
|
+
isResend,
|
|
546
|
+
pushOnly: props.pushOnly && !isResend,
|
|
547
|
+
},
|
|
548
|
+
delay: 10,
|
|
525
549
|
});
|
|
526
550
|
} else {
|
|
527
551
|
// eslint-disable-next-line no-lonely-if
|
|
@@ -557,13 +581,16 @@ const init = ({ node, notificationService }) => {
|
|
|
557
581
|
receiver: receiverDid,
|
|
558
582
|
});
|
|
559
583
|
walletPushQueue.push({
|
|
560
|
-
|
|
561
|
-
|
|
562
|
-
|
|
563
|
-
|
|
564
|
-
|
|
565
|
-
|
|
566
|
-
|
|
584
|
+
job: {
|
|
585
|
+
notification,
|
|
586
|
+
sender,
|
|
587
|
+
options,
|
|
588
|
+
receiver: receiverDid,
|
|
589
|
+
isResend,
|
|
590
|
+
pushOnly: props.pushOnly && !isResend,
|
|
591
|
+
source,
|
|
592
|
+
},
|
|
593
|
+
delay: 5,
|
|
567
594
|
});
|
|
568
595
|
} else {
|
|
569
596
|
// 如果是重发的消息,只需要更新推送状态,不需要更新 channel状态
|
|
@@ -628,7 +655,7 @@ const init = ({ node, notificationService }) => {
|
|
|
628
655
|
* }
|
|
629
656
|
*/
|
|
630
657
|
const queue = createNotificationQueue('notification-receivers', {}, async (job) => {
|
|
631
|
-
const { teamDid, channels, receiver, sender, notification, nodeInfo,
|
|
658
|
+
const { teamDid, channels, receiver, sender, notification, nodeInfo, ...rest } = job;
|
|
632
659
|
|
|
633
660
|
logger.info('notification start insert to queue', {
|
|
634
661
|
teamDid,
|
|
@@ -636,6 +663,17 @@ const init = ({ node, notificationService }) => {
|
|
|
636
663
|
receiver,
|
|
637
664
|
});
|
|
638
665
|
try {
|
|
666
|
+
const selection = {
|
|
667
|
+
did: 1,
|
|
668
|
+
fullName: 1,
|
|
669
|
+
email: 1,
|
|
670
|
+
extra: 1,
|
|
671
|
+
};
|
|
672
|
+
const userInfo = await node.getUser({
|
|
673
|
+
teamDid,
|
|
674
|
+
user: { did: receiver },
|
|
675
|
+
options: { enableConnectedAccount: true, selection, includePassports: false, includeConnectedAccounts: false },
|
|
676
|
+
});
|
|
639
677
|
if (!userInfo) {
|
|
640
678
|
throw new Error(`Invalid receiver user: ${receiver}`);
|
|
641
679
|
}
|
|
@@ -654,26 +692,22 @@ const init = ({ node, notificationService }) => {
|
|
|
654
692
|
});
|
|
655
693
|
// websocket 通知
|
|
656
694
|
const receiverDid = userInfo.did;
|
|
657
|
-
|
|
658
|
-
|
|
659
|
-
|
|
660
|
-
notification
|
|
661
|
-
|
|
662
|
-
|
|
663
|
-
|
|
664
|
-
|
|
665
|
-
|
|
666
|
-
|
|
667
|
-
...(rest.actorInfo ? { actorInfo: rest.actorInfo } : {}),
|
|
668
|
-
},
|
|
669
|
-
receiver: receiverDid,
|
|
670
|
-
teamDid,
|
|
671
|
-
isServices: rest.isServices,
|
|
695
|
+
websocketQueue.push({
|
|
696
|
+
input: {
|
|
697
|
+
notification: {
|
|
698
|
+
...notification,
|
|
699
|
+
entityType: rest.entityType,
|
|
700
|
+
entityId: rest.entityId,
|
|
701
|
+
componentDid: rest.componentDid,
|
|
702
|
+
source: rest.source,
|
|
703
|
+
createdAt: rest.createdAt,
|
|
704
|
+
...(rest.actorInfo ? { actorInfo: rest.actorInfo } : {}),
|
|
672
705
|
},
|
|
673
|
-
|
|
674
|
-
|
|
675
|
-
|
|
676
|
-
|
|
706
|
+
receiver: receiverDid,
|
|
707
|
+
teamDid,
|
|
708
|
+
isServices: rest.isServices,
|
|
709
|
+
},
|
|
710
|
+
});
|
|
677
711
|
}
|
|
678
712
|
|
|
679
713
|
notification.type = notification.type || 'notification';
|
|
@@ -727,7 +761,6 @@ const init = ({ node, notificationService }) => {
|
|
|
727
761
|
logger.info('notification start insert to queue:', {
|
|
728
762
|
teamDid: data?.teamDid,
|
|
729
763
|
notificationId: data?.notification?.id,
|
|
730
|
-
receivers: data?.receivers?.join(','),
|
|
731
764
|
});
|
|
732
765
|
if (isInstanceWorker()) {
|
|
733
766
|
return;
|
|
@@ -753,13 +786,7 @@ const init = ({ node, notificationService }) => {
|
|
|
753
786
|
type: 'server',
|
|
754
787
|
});
|
|
755
788
|
|
|
756
|
-
|
|
757
|
-
teamDid,
|
|
758
|
-
userDids: receivers,
|
|
759
|
-
includeConnectedAccounts: true,
|
|
760
|
-
});
|
|
761
|
-
|
|
762
|
-
if (users.length === 0) {
|
|
789
|
+
if (receivers.length === 0) {
|
|
763
790
|
throw new Error('No users found');
|
|
764
791
|
}
|
|
765
792
|
// 如果 notification 没有 id,则生成一个, wallet 要基于这唯一个ID进行处理
|
|
@@ -771,8 +798,7 @@ const init = ({ node, notificationService }) => {
|
|
|
771
798
|
notification.id = `NOTIF-${nanoid()}`;
|
|
772
799
|
}
|
|
773
800
|
|
|
774
|
-
|
|
775
|
-
const receiverDid = userInfo.did;
|
|
801
|
+
receivers.forEach((receiverDid) => {
|
|
776
802
|
queue.push({
|
|
777
803
|
...rest,
|
|
778
804
|
notification,
|
|
@@ -781,7 +807,6 @@ const init = ({ node, notificationService }) => {
|
|
|
781
807
|
receiver: receiverDid,
|
|
782
808
|
sender,
|
|
783
809
|
nodeInfo,
|
|
784
|
-
userInfo,
|
|
785
810
|
});
|
|
786
811
|
});
|
|
787
812
|
} catch (error) {
|
|
@@ -164,40 +164,38 @@ const sendToUserDid = async ({ sender, receiver: rawDid, notification, options,
|
|
|
164
164
|
|
|
165
165
|
const isServer = !teamDid || teamDid === nodeInfo.did;
|
|
166
166
|
|
|
167
|
-
|
|
168
|
-
|
|
169
|
-
|
|
170
|
-
|
|
171
|
-
|
|
172
|
-
|
|
173
|
-
|
|
174
|
-
|
|
175
|
-
|
|
176
|
-
|
|
177
|
-
|
|
178
|
-
|
|
179
|
-
|
|
180
|
-
|
|
181
|
-
|
|
182
|
-
|
|
183
|
-
|
|
184
|
-
|
|
185
|
-
|
|
186
|
-
|
|
187
|
-
|
|
188
|
-
|
|
189
|
-
|
|
190
|
-
|
|
191
|
-
|
|
192
|
-
|
|
193
|
-
|
|
194
|
-
|
|
195
|
-
|
|
196
|
-
|
|
197
|
-
}
|
|
198
|
-
|
|
199
|
-
return undefined;
|
|
200
|
-
}
|
|
167
|
+
// 开始执行 service 消息的推送,不需要同步执行
|
|
168
|
+
Promise.all(
|
|
169
|
+
notifications.map((_notification) => {
|
|
170
|
+
// 如果类型不存在或者是 notification 类型是才进行保存数据库,其他类型只需要通知到用户即可
|
|
171
|
+
// eg: type = 'passthrough', 'hi', 'connect', 'feed', 默认只需要通知 wallet
|
|
172
|
+
const pushOnly = _notification.type && _notification.type.toLowerCase() !== NOTIFICATION_TYPES.NOTIFICATION;
|
|
173
|
+
|
|
174
|
+
// 通知渠道的确定有两种方式 1. 用户传入的 channels 2. 根据 notification 类型确定
|
|
175
|
+
// 如果是 hi connect, 只需要通知 wallet
|
|
176
|
+
// passthrough 类型,用于 discuss kit 的 chat channel
|
|
177
|
+
// 1. push kit: native 通知快速跳转到 chat channel
|
|
178
|
+
// 2. app: 钱包消息,可以查看到接收到消息
|
|
179
|
+
|
|
180
|
+
return node.createNotification({
|
|
181
|
+
teamDid,
|
|
182
|
+
...(pushOnly ? { notification: _notification } : { ..._notification }),
|
|
183
|
+
receiver: rawDid,
|
|
184
|
+
componentDid: sender.componentDid,
|
|
185
|
+
// 这两个字段用于 socket 通知
|
|
186
|
+
entityType: _notification.entityType || 'blocklet',
|
|
187
|
+
entityId: _notification.entityId || sender.appDid,
|
|
188
|
+
source: isServer ? 'system' : _notification.source || 'component',
|
|
189
|
+
channels: CHANNEL_MAP[_notification.type] || channels,
|
|
190
|
+
sender,
|
|
191
|
+
options: { ...rest },
|
|
192
|
+
pushOnly,
|
|
193
|
+
});
|
|
194
|
+
})
|
|
195
|
+
).catch((error) => {
|
|
196
|
+
logger.error('Failed to send notification', { error });
|
|
197
|
+
});
|
|
198
|
+
return true;
|
|
201
199
|
};
|
|
202
200
|
|
|
203
201
|
// server send notification to app
|
package/package.json
CHANGED
|
@@ -3,7 +3,7 @@
|
|
|
3
3
|
"publishConfig": {
|
|
4
4
|
"access": "public"
|
|
5
5
|
},
|
|
6
|
-
"version": "1.17.4-beta-
|
|
6
|
+
"version": "1.17.4-beta-20251202-034514-637cd8e2",
|
|
7
7
|
"description": "Provide unified services for every blocklet",
|
|
8
8
|
"main": "api/index.js",
|
|
9
9
|
"files": [
|
|
@@ -32,17 +32,17 @@
|
|
|
32
32
|
"author": "wangshijun <wangshijun2010@gmail.com> (http://github.com/wangshijun)",
|
|
33
33
|
"license": "Apache-2.0",
|
|
34
34
|
"dependencies": {
|
|
35
|
-
"@abtnode/analytics": "1.17.4-beta-
|
|
36
|
-
"@abtnode/auth": "1.17.4-beta-
|
|
37
|
-
"@abtnode/connect-storage": "1.17.4-beta-
|
|
38
|
-
"@abtnode/constant": "1.17.4-beta-
|
|
39
|
-
"@abtnode/core": "1.17.4-beta-
|
|
40
|
-
"@abtnode/cron": "1.17.4-beta-
|
|
41
|
-
"@abtnode/db-cache": "1.17.4-beta-
|
|
42
|
-
"@abtnode/logger": "1.17.4-beta-
|
|
43
|
-
"@abtnode/models": "1.17.4-beta-
|
|
44
|
-
"@abtnode/router-templates": "1.17.4-beta-
|
|
45
|
-
"@abtnode/util": "1.17.4-beta-
|
|
35
|
+
"@abtnode/analytics": "1.17.4-beta-20251202-034514-637cd8e2",
|
|
36
|
+
"@abtnode/auth": "1.17.4-beta-20251202-034514-637cd8e2",
|
|
37
|
+
"@abtnode/connect-storage": "1.17.4-beta-20251202-034514-637cd8e2",
|
|
38
|
+
"@abtnode/constant": "1.17.4-beta-20251202-034514-637cd8e2",
|
|
39
|
+
"@abtnode/core": "1.17.4-beta-20251202-034514-637cd8e2",
|
|
40
|
+
"@abtnode/cron": "1.17.4-beta-20251202-034514-637cd8e2",
|
|
41
|
+
"@abtnode/db-cache": "1.17.4-beta-20251202-034514-637cd8e2",
|
|
42
|
+
"@abtnode/logger": "1.17.4-beta-20251202-034514-637cd8e2",
|
|
43
|
+
"@abtnode/models": "1.17.4-beta-20251202-034514-637cd8e2",
|
|
44
|
+
"@abtnode/router-templates": "1.17.4-beta-20251202-034514-637cd8e2",
|
|
45
|
+
"@abtnode/util": "1.17.4-beta-20251202-034514-637cd8e2",
|
|
46
46
|
"@arcblock/did": "^1.27.12",
|
|
47
47
|
"@arcblock/did-connect-js": "^1.27.12",
|
|
48
48
|
"@arcblock/did-ext": "^1.27.12",
|
|
@@ -52,18 +52,18 @@
|
|
|
52
52
|
"@arcblock/jwt": "^1.27.12",
|
|
53
53
|
"@arcblock/validator": "^1.27.12",
|
|
54
54
|
"@arcblock/ws": "^1.27.12",
|
|
55
|
-
"@blocklet/constant": "1.17.4-beta-
|
|
55
|
+
"@blocklet/constant": "1.17.4-beta-20251202-034514-637cd8e2",
|
|
56
56
|
"@blocklet/dbhub": "^0.2.9",
|
|
57
|
-
"@blocklet/env": "1.17.4-beta-
|
|
57
|
+
"@blocklet/env": "1.17.4-beta-20251202-034514-637cd8e2",
|
|
58
58
|
"@blocklet/error": "^0.3.3",
|
|
59
59
|
"@blocklet/form-builder": "^0.1.12",
|
|
60
60
|
"@blocklet/form-collector": "^0.1.8",
|
|
61
|
-
"@blocklet/images": "1.17.4-beta-
|
|
62
|
-
"@blocklet/js-sdk": "1.17.4-beta-
|
|
63
|
-
"@blocklet/meta": "1.17.4-beta-
|
|
64
|
-
"@blocklet/rate-limit": "1.17.4-beta-
|
|
65
|
-
"@blocklet/sdk": "1.17.4-beta-
|
|
66
|
-
"@blocklet/server-js": "1.17.4-beta-
|
|
61
|
+
"@blocklet/images": "1.17.4-beta-20251202-034514-637cd8e2",
|
|
62
|
+
"@blocklet/js-sdk": "1.17.4-beta-20251202-034514-637cd8e2",
|
|
63
|
+
"@blocklet/meta": "1.17.4-beta-20251202-034514-637cd8e2",
|
|
64
|
+
"@blocklet/rate-limit": "1.17.4-beta-20251202-034514-637cd8e2",
|
|
65
|
+
"@blocklet/sdk": "1.17.4-beta-20251202-034514-637cd8e2",
|
|
66
|
+
"@blocklet/server-js": "1.17.4-beta-20251202-034514-637cd8e2",
|
|
67
67
|
"@blocklet/theme": "^3.2.11",
|
|
68
68
|
"@blocklet/theme-builder": "0.4.8",
|
|
69
69
|
"@blocklet/uploader-server": "^0.3.12",
|
|
@@ -123,7 +123,7 @@
|
|
|
123
123
|
"whatwg-url": "14.0.0"
|
|
124
124
|
},
|
|
125
125
|
"devDependencies": {
|
|
126
|
-
"@abtnode/ux": "1.17.4-beta-
|
|
126
|
+
"@abtnode/ux": "1.17.4-beta-20251202-034514-637cd8e2",
|
|
127
127
|
"@arcblock/bridge": "^3.2.11",
|
|
128
128
|
"@arcblock/did-connect-react": "^3.2.11",
|
|
129
129
|
"@arcblock/icons": "^3.2.11",
|
|
@@ -133,7 +133,7 @@
|
|
|
133
133
|
"@blocklet/did-space-react": "^1.2.6",
|
|
134
134
|
"@blocklet/launcher-layout": "^3.2.11",
|
|
135
135
|
"@blocklet/payment-react": "^1.22.24",
|
|
136
|
-
"@blocklet/tracker": "1.17.4-beta-
|
|
136
|
+
"@blocklet/tracker": "1.17.4-beta-20251202-034514-637cd8e2",
|
|
137
137
|
"@blocklet/ui-react": "^3.2.11",
|
|
138
138
|
"@blocklet/uploader": "^0.3.12",
|
|
139
139
|
"@emotion/react": "^11.14.0",
|
|
@@ -213,5 +213,5 @@
|
|
|
213
213
|
"url": "https://github.com/ArcBlock/blocklet-server/issues",
|
|
214
214
|
"email": "shijun@arcblock.io"
|
|
215
215
|
},
|
|
216
|
-
"gitHead": "
|
|
216
|
+
"gitHead": "d0e748c5cae1a08c63cfc5bb59a6d471c3120e7a"
|
|
217
217
|
}
|