mirai-js 2.8.3 → 2.8.5

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.
Files changed (83) hide show
  1. package/1.mp3 +0 -0
  2. package/README.md +2 -0
  3. package/demo.ts +3 -6
  4. package/dist/browser/mirai-js.js +1 -1
  5. package/dist/node/borwserEntry.js +21 -0
  6. package/dist/node/core/uploadVoice.js +1 -1
  7. package/dist/node/lib/index.ts +0 -0
  8. package/index.ts +36 -3
  9. package/package.json +1 -1
  10. package/src/borwserEntry.js +11 -0
  11. package/src/core/uploadVoice.js +1 -1
  12. package/src/lib/index.ts +0 -0
  13. package/srcold/BaseType.d.ts +419 -0
  14. package/srcold/Bot.d.ts +567 -0
  15. package/srcold/Bot.js +1208 -0
  16. package/srcold/FileManager.js +270 -0
  17. package/srcold/Message.d.ts +66 -0
  18. package/srcold/Message.js +314 -0
  19. package/srcold/Middleware.d.ts +170 -0
  20. package/srcold/Middleware.js +657 -0
  21. package/srcold/Waiter.d.ts +13 -0
  22. package/srcold/Waiter.js +24 -0
  23. package/srcold/core/anno/deleteAnno.js +43 -0
  24. package/srcold/core/anno/getAnno.js +44 -0
  25. package/srcold/core/anno/publishAnno.js +44 -0
  26. package/srcold/core/auth.js +40 -0
  27. package/srcold/core/fs/deleteGroupFile.js +45 -0
  28. package/srcold/core/fs/getGroupFileInfo.js +46 -0
  29. package/srcold/core/fs/getGroupFileList.js +47 -0
  30. package/srcold/core/fs/makeGroupDir.js +45 -0
  31. package/srcold/core/fs/moveGroupFile.js +47 -0
  32. package/srcold/core/fs/renameGroupFile.js +44 -0
  33. package/srcold/core/fs/uploadGroupFIle.js +58 -0
  34. package/srcold/core/getFriendList.js +37 -0
  35. package/srcold/core/getGroupConfig.js +37 -0
  36. package/srcold/core/getGroupList.js +37 -0
  37. package/srcold/core/getMemberInfo.js +41 -0
  38. package/srcold/core/getMemberList.js +49 -0
  39. package/srcold/core/getSessionConfig.js +39 -0
  40. package/srcold/core/getUserProfile.js +40 -0
  41. package/srcold/core/messageFromId.js +40 -0
  42. package/srcold/core/mute.js +41 -0
  43. package/srcold/core/muteAll.js +39 -0
  44. package/srcold/core/quitGroup.js +40 -0
  45. package/srcold/core/recall.js +39 -0
  46. package/srcold/core/releaseSession.js +41 -0
  47. package/srcold/core/removeFriend.js +40 -0
  48. package/srcold/core/removeMember.js +42 -0
  49. package/srcold/core/responseBotInvitedJoinGroupRequest.js +46 -0
  50. package/srcold/core/responseFirendRequest.js +45 -0
  51. package/srcold/core/responseMemberJoinRequest.js +47 -0
  52. package/srcold/core/sendCommand.js +41 -0
  53. package/srcold/core/sendFriendMessage.js +43 -0
  54. package/srcold/core/sendGroupMessage.js +43 -0
  55. package/srcold/core/sendImageMessage.js +4 -0
  56. package/srcold/core/sendNudge.js +43 -0
  57. package/srcold/core/sendTempMessage.js +55 -0
  58. package/srcold/core/setEssence.js +44 -0
  59. package/srcold/core/setGroupConfig.js +58 -0
  60. package/srcold/core/setMemberAdmin.js +44 -0
  61. package/srcold/core/setMemberInfo.js +48 -0
  62. package/srcold/core/setSessionConfig.js +41 -0
  63. package/srcold/core/startListeningBrowser.js +62 -0
  64. package/srcold/core/startListeningNode.js +74 -0
  65. package/srcold/core/stopListeningBrowser.js +34 -0
  66. package/srcold/core/stopListeningNode.js +34 -0
  67. package/srcold/core/unmute.js +40 -0
  68. package/srcold/core/unmuteAll.js +39 -0
  69. package/srcold/core/uploadImage.js +55 -0
  70. package/srcold/core/uploadVoice.js +54 -0
  71. package/srcold/core/verify.js +41 -0
  72. package/srcold/index.d.ts +10 -0
  73. package/srcold/index.js +21 -0
  74. package/srcold/interface.js +20 -0
  75. package/srcold/polyfill/URL.js +5 -0
  76. package/srcold/polyfill/wsListener.js +6 -0
  77. package/srcold/typeHelpers.d.ts +2 -0
  78. package/srcold/util/errCode.js +23 -0
  79. package/srcold/util/errorHandler.js +24 -0
  80. package/srcold/util/getInvalidParamsString.js +12 -0
  81. package/srcold/util/isBrowserEnv.js +3 -0
  82. package/srcold/util/random.js +6 -0
  83. package/webpack.config.js +3 -2
@@ -0,0 +1,657 @@
1
+ const responseFirendRequest = require('./core/responseFirendRequest');
2
+ const responseMemberJoinRequest = require('./core/responseMemberJoinRequest');
3
+ const responseBotInvitedJoinGroupRequest = require('./core/responseBotInvitedJoinGroupRequest');
4
+
5
+ /**
6
+ * @description 为事件处理器提供中间件
7
+ * @use 在 MiddleWare 的实例上链式调用需要的中间件方法,最后
8
+ * 调用 done 并传入一个回调函数,该函数将在中间件结束后被调用
9
+ */
10
+ class Middleware {
11
+ constructor() {
12
+ this.middleware = [];
13
+ this.catcher = undefined;
14
+ }
15
+
16
+ /**
17
+ * @description 自动重新登陆
18
+ * @param {string} baseUrl mirai-api-http server 的地址
19
+ * @param {string} verifyKey mirai-api-http server 设置的 verifyKey
20
+ * @param {string} password 欲重新登陆的 qq 密码
21
+ */
22
+ autoReLogin({ password }) {
23
+ this.middleware.push(async (data, next) => {
24
+ try {
25
+ await data.bot.sendCommand({
26
+ command: ['/login', data.qq, password],
27
+ });
28
+ await data.bot.open();
29
+ await next();
30
+ } catch (error) {
31
+ if (this.catcher) {
32
+ this.catcher(error);
33
+ } else {
34
+ throw error;
35
+ }
36
+ }
37
+
38
+ });
39
+ return this;
40
+ }
41
+
42
+ /**
43
+ * @description 自动重建 ws 连接
44
+ */
45
+ autoReconnection() {
46
+ this.middleware.push(async (data, next) => {
47
+ try {
48
+ await data.bot.open();
49
+ await next();
50
+ } catch (error) {
51
+ if (this.catcher) {
52
+ this.catcher(error);
53
+ } else {
54
+ throw error;
55
+ }
56
+ }
57
+ });
58
+ return this;
59
+ }
60
+
61
+ /**
62
+ * @description 过滤出指定类型的消息,消息类型为 key,对应类型的
63
+ * message 数组为 value,置于 data.classified
64
+ * @param {string[]} typeArr message 的类型,例如 Plain Image Voice
65
+ */
66
+ messageProcessor(typeArr) {
67
+ this.middleware.push(async (data, next) => {
68
+ try {
69
+ const result = {};
70
+ typeArr.forEach((type) => {
71
+ result[type] = data.messageChain.filter((message) => message.type == type);
72
+ });
73
+ data.classified = result;
74
+ await next();
75
+ } catch (error) {
76
+ if (this.catcher) {
77
+ this.catcher(error);
78
+ } else {
79
+ throw error;
80
+ }
81
+ }
82
+
83
+ });
84
+ return this;
85
+ }
86
+
87
+ /**
88
+ * @description 过滤出字符串类型的 message,并拼接在一起,置于 data.text
89
+ */
90
+ textProcessor() {
91
+ this.middleware.push(async (data, next) => {
92
+ try {
93
+ data.text = data.messageChain
94
+ .filter((val) => val.type == 'Plain')
95
+ .map((val) => val.text)
96
+ .join('');
97
+ await next();
98
+ } catch (error) {
99
+ if (this.catcher) {
100
+ this.catcher(error);
101
+ } else {
102
+ throw error;
103
+ }
104
+ }
105
+ });
106
+ return this;
107
+ }
108
+
109
+ /**
110
+ * @description 过滤出消息 id,置于 data.messageId
111
+ */
112
+ messageIdProcessor() {
113
+ this.middleware.push(async (data, next) => {
114
+ try {
115
+ data.messageId = Array.isArray(data.messageChain) ? data.messageChain[0]?.id : undefined;
116
+ await next();
117
+ } catch (error) {
118
+ if (this.catcher) {
119
+ this.catcher(error);
120
+ } else {
121
+ throw error;
122
+ }
123
+ }
124
+ });
125
+ return this;
126
+ }
127
+
128
+ /**
129
+ * @description 过滤指定的群消息
130
+ * @param {number[]} groupArr 允许通过的群号数组
131
+ * @param {boolean} allow 允许通过还是禁止通过
132
+ */
133
+ groupFilter(groupArr, allow = true) {
134
+ const groupSet = new Set(groupArr);
135
+
136
+ this.middleware.push(async (data, next) => {
137
+ try {
138
+ // 检查参数
139
+ if (!(data?.sender?.group?.id)) {
140
+ throw new Error('Middleware.groupFilter 消息格式出错');
141
+ }
142
+
143
+ // 如果 id 在 set 里,根据 allow 判断是否交给下一个中间件处理
144
+ if (groupSet.has(data.sender.group.id)) {
145
+ return allow && next();
146
+ }
147
+ !allow && await next();
148
+ } catch (error) {
149
+ if (this.catcher) {
150
+ this.catcher(error);
151
+ } else {
152
+ throw error;
153
+ }
154
+ }
155
+ });
156
+ return this;
157
+ }
158
+
159
+ /**
160
+ * @description 过滤指定的好友消息
161
+ * @param {number[]} friendArr 好友 qq 号数组
162
+ * @param {boolean} allow 允许通过还是禁止通过
163
+ */
164
+ friendFilter(friendArr, allow = true) {
165
+ const groupSet = new Set(friendArr);
166
+
167
+ this.middleware.push(async (data, next) => {
168
+ try {
169
+ // 检查参数
170
+ if (!(data?.sender?.id)) {
171
+ throw new Error('Middleware.friendFilter 消息格式出错');
172
+ }
173
+
174
+ // 如果 id 在 set 里,根据 allow 判断是否交给下一个中间件处理
175
+ if (groupSet.has(data.sender.id)) {
176
+ return allow && await next();
177
+ }
178
+ !allow && await next();
179
+ } catch (error) {
180
+ if (this.catcher) {
181
+ this.catcher(error);
182
+ } else {
183
+ throw error;
184
+ }
185
+ }
186
+ });
187
+ return this;
188
+ }
189
+
190
+ /**
191
+ * @description 过滤指定群的群成员的消息
192
+ * @param {Map} groupMemberMap 群和成员的 Map
193
+ * @param {boolean} allow 允许通过还是禁止通过
194
+ * 结构 { number => array[number], } key 为允许通过的群号,value 为该群允许通过的成员 qq
195
+ */
196
+ groupMemberFilter(groupMemberMap, allow = true) {
197
+ // 每个 qq 数组变成 Set
198
+ for (const group in groupMemberMap) {
199
+ groupMemberMap[group] = new Set(groupMemberMap[group]);
200
+ }
201
+
202
+ this.middleware.push(async (data, next) => {
203
+ try {
204
+ // 检查参数
205
+ if (!(data?.sender?.id)) {
206
+ throw new Error('Middleware.friendFilter 消息格式出错');
207
+ }
208
+
209
+ // 检查是否是群消息
210
+ if (!(data.sender.group)) {
211
+ return;
212
+ }
213
+
214
+ // 检查是否是允许通过的群成员,是则交给下一个中间件处理
215
+ if (data.sender.group.id in groupMemberMap &&
216
+ groupMemberMap[data.sender.group.id].has(data.sender.id)) {
217
+ return allow && await next();
218
+ }
219
+ !allow && await next();
220
+ } catch (error) {
221
+ if (this.catcher) {
222
+ this.catcher(error);
223
+ } else {
224
+ throw error;
225
+ }
226
+ }
227
+ });
228
+ return this;
229
+ }
230
+
231
+ /**
232
+ * @description 这是一个对话锁,保证群中同一成员不能在中途触发处理器
233
+ * @use 在你需要保护的过程结束后调用 data.unlock 即可
234
+ */
235
+ memberLock({ autoUnlock = false } = {}) {
236
+ const memberMap = {/* group -> memberSet */ };
237
+ this.middleware.push(async (data, next) => {
238
+ try {
239
+ // 检查参数
240
+ if (!data.sender?.group?.id) {
241
+ throw new Error('Middleware.memberLock 消息格式出错');
242
+ }
243
+
244
+ // 若该 group 不存在对应的 Set,则添加
245
+ if (!(memberMap[data.sender?.group?.id] instanceof Set)) {
246
+ memberMap[data.sender?.group?.id] = new Set();
247
+ }
248
+
249
+ // 是否正在对话
250
+ if (memberMap[data.sender?.group?.id].has(data.sender?.id)) {
251
+ // 正在对话则返回
252
+ return;
253
+ } else {
254
+ // 未在对话,则加入对应的 Set,然后继续
255
+ memberMap[data.sender?.group?.id].add(data.sender?.id);
256
+ let locked = true;
257
+ const unlock = () => {
258
+ memberMap[data.sender?.group?.id].delete(data.sender?.id);
259
+ locked = false;
260
+ };
261
+ data.unlock = unlock;
262
+
263
+ // 等待下游中间件结束后 unlock
264
+ await next();
265
+ autoUnlock && locked && unlock();
266
+ }
267
+ } catch (error) {
268
+ if (this.catcher) {
269
+ this.catcher(error);
270
+ } else {
271
+ throw error;
272
+ }
273
+ }
274
+ });
275
+ return this;
276
+ }
277
+
278
+ /**
279
+ * @description 这是一个对话锁,保证同一好友不能在中途触发处理器
280
+ * @use 在你需要保护的过程结束后调用 data.unlock 即可
281
+ */
282
+ friendLock({ autoUnlock = false } = {}) {
283
+ const friendSet = new Set();
284
+ this.middleware.push(async (data, next) => {
285
+ try {
286
+ // 检查参数
287
+ if (!data.sender?.id) {
288
+ throw new Error('Middleware.memberLock 消息格式出错');
289
+ }
290
+
291
+ // 是否正在对话
292
+ if (friendSet.has(data.sender?.id)) {
293
+ // 正在对话则返回
294
+ return;
295
+ } else {
296
+ // 未在对话,则加入 Set,然后继续
297
+ friendSet.add(data.sender?.id);
298
+ let locked = true;
299
+ const unlock = () => {
300
+ friendSet.delete(data.sender?.id);
301
+ locked = false;
302
+ };
303
+ data.unlock = unlock;
304
+
305
+ // 等待下游中间件结束后 unlock
306
+ await next();
307
+ autoUnlock && locked && unlock();
308
+ }
309
+ } catch (error) {
310
+ if (this.catcher) {
311
+ this.catcher(error);
312
+ } else {
313
+ throw error;
314
+ }
315
+ }
316
+ });
317
+ return this;
318
+ }
319
+
320
+ /**
321
+ * @description 过滤包含指定 @ 信息的消息
322
+ * @param {number[]} atArr 必选,qq 号数组
323
+ * @param {boolean} allow 可选,允许通过还是禁止通过
324
+ */
325
+ atFilter(friendArr, allow = true) {
326
+ const friendSet = new Set(friendArr);
327
+
328
+ this.middleware.push(async (data, next) => {
329
+ try {
330
+ // 检查参数
331
+ if (!(data?.messageChain)) {
332
+ throw new Error('Middleware.atFilter 消息格式出错');
333
+ }
334
+
335
+ // 如果 id 在 set 里,根据 allow 判断是否交给下一个中间件处理
336
+ for (const message of data.messageChain) {
337
+ if (message?.type == 'At' && friendSet.has(message?.target)) {
338
+ return allow && await next();
339
+ }
340
+ }
341
+ !allow && await next();
342
+ } catch (error) {
343
+ if (this.catcher) {
344
+ this.catcher(error);
345
+ } else {
346
+ throw error;
347
+ }
348
+ }
349
+ });
350
+ return this;
351
+ }
352
+
353
+ /**
354
+ * @description 用于 NewFriendRequestEvent 的中间件,经过该中间件后,将在 data 下放置三个方法
355
+ * agree、refuse、refuseAndAddBlacklist,调用后将分别进行好友请求的 同意、拒绝和拒绝并加入黑名单
356
+ */
357
+ friendRequestProcessor() {
358
+ this.middleware.push(async (data, next) => {
359
+ try {
360
+ // 事件类型
361
+ if (data.type != 'NewFriendRequestEvent') {
362
+ throw new Error('Middleware.NewFriendRequestEvent 消息格式出错');
363
+ }
364
+
365
+ // ? baseUrl, sessionKey 放在内部获取,使用最新的实例状态
366
+ const baseUrl = data.bot.getBaseUrl();
367
+ const sessionKey = data.bot.getSessionKey();
368
+ const { eventId, fromId, groupId } = data;
369
+
370
+ // 同意
371
+ data.agree = async (message) => {
372
+ await responseFirendRequest({
373
+ baseUrl, sessionKey, eventId, fromId, groupId,
374
+ message, operate: 0,
375
+ });
376
+ };
377
+
378
+ // 拒绝
379
+ data.refuse = async (message) => {
380
+ await responseFirendRequest({
381
+ baseUrl, sessionKey, eventId, fromId, groupId,
382
+ message, operate: 1,
383
+ });
384
+ };
385
+
386
+ // 拒绝并加入黑名单
387
+ data.refuseAndAddBlacklist = async (message) => {
388
+ await responseFirendRequest({
389
+ baseUrl, sessionKey, eventId, fromId, groupId,
390
+ message, operate: 2,
391
+ });
392
+ };
393
+
394
+ await next();
395
+ } catch (error) {
396
+ if (this.catcher) {
397
+ this.catcher(error);
398
+ } else {
399
+ throw error;
400
+ }
401
+ }
402
+ });
403
+ return this;
404
+ }
405
+
406
+ /**
407
+ * @description 用于 MemberJoinRequestEvent 的中间件,经过该中间件后,将在 data 下放置五个方法
408
+ * agree 同意
409
+ * refuse 拒绝
410
+ * ignore 忽略
411
+ * refuseAndAddBlacklist 拒绝并移入黑名单
412
+ * ignoreAndAddBlacklist 忽略并移入黑名单
413
+ */
414
+ memberJoinRequestProcessor() {
415
+ this.middleware.push(async (data, next) => {
416
+ try {
417
+ // 事件类型
418
+ if (data.type != 'MemberJoinRequestEvent') {
419
+ throw new Error('Middleware.memberJoinRequestProcessor 消息格式出错');
420
+ }
421
+
422
+ // ? baseUrl, sessionKey 放在内部获取,使用最新的实例状态
423
+ const baseUrl = data.bot.getBaseUrl();
424
+ const sessionKey = data.bot.getSessionKey();
425
+ const { eventId, fromId, groupId } = data;
426
+
427
+ // 同意
428
+ data.agree = async (message) => {
429
+ await responseMemberJoinRequest({
430
+ baseUrl, sessionKey, eventId, fromId, groupId,
431
+ message, operate: 0,
432
+ });
433
+ };
434
+
435
+ // 拒绝
436
+ data.refuse = async (message) => {
437
+ await responseMemberJoinRequest({
438
+ baseUrl, sessionKey, eventId, fromId, groupId,
439
+ message, operate: 1,
440
+ });
441
+ };
442
+
443
+ // 忽略
444
+ data.ignore = async (message) => {
445
+ await responseMemberJoinRequest({
446
+ baseUrl, sessionKey, eventId, fromId, groupId,
447
+ message, operate: 2,
448
+ });
449
+ };
450
+
451
+ // 拒绝并加入黑名单
452
+ data.refuseAndAddBlacklist = async (message) => {
453
+ await responseMemberJoinRequest({
454
+ baseUrl, sessionKey, eventId, fromId, groupId,
455
+ message, operate: 3,
456
+ });
457
+ };
458
+
459
+ // 忽略并加入黑名单
460
+ data.ignoreAndAddBlacklist = async (message) => {
461
+ await responseMemberJoinRequest({
462
+ baseUrl, sessionKey, eventId, fromId, groupId,
463
+ message, operate: 4,
464
+ });
465
+ };
466
+
467
+ await next();
468
+ } catch (error) {
469
+ if (this.catcher) {
470
+ this.catcher(error);
471
+ } else {
472
+ throw error;
473
+ }
474
+ }
475
+ });
476
+ return this;
477
+ }
478
+
479
+
480
+ /**
481
+ * ! 自动同意时,不会触发该事件
482
+ * @description 用于 BotInvitedJoinGroupRequestEvent 的中间件,经过该中间件后,将在 data 下放置两个方法
483
+ * agree 同意
484
+ * refuse 拒绝
485
+ */
486
+ invitedJoinGroupRequestProcessor() {
487
+ this.middleware.push(async (data, next) => {
488
+ try {
489
+ // 事件类型
490
+ if (data.type != 'BotInvitedJoinGroupRequestEvent') {
491
+ throw new Error('Middleware.invitedJoinGroupRequestProcessor 消息格式出错');
492
+ }
493
+
494
+ // ? baseUrl, sessionKey 放在内部获取,使用最新的实例状态
495
+ const baseUrl = data.bot.getBaseUrl();
496
+ const sessionKey = data.bot.getSessionKey();
497
+ const { eventId, fromId, groupId } = data;
498
+
499
+ // 同意
500
+ data.agree = async (message) => {
501
+ await responseBotInvitedJoinGroupRequest({
502
+ baseUrl, sessionKey, eventId, fromId, groupId,
503
+ message, operate: 0,
504
+ });
505
+ };
506
+
507
+ // 拒绝
508
+ data.refuse = async (message) => {
509
+ await responseBotInvitedJoinGroupRequest({
510
+ baseUrl, sessionKey, eventId, fromId, groupId,
511
+ message, operate: 1,
512
+ });
513
+ };
514
+
515
+ await next();
516
+ } catch (error) {
517
+ if (this.catcher) {
518
+ this.catcher(error);
519
+ } else {
520
+ throw error;
521
+ }
522
+ }
523
+ });
524
+ return this;
525
+ }
526
+
527
+ /**
528
+ * @description Waiter 的包装器,提供方便的同步 IO 方式
529
+ */
530
+ syncWrapper() {
531
+ this.middleware.push(async (data, next) => {
532
+ try {
533
+ // 事件类型
534
+ if (data.type != 'GroupMessage' && data.type != 'FriendMessage') {
535
+ throw new Error('Middleware.syncWrapper 消息格式出错');
536
+ }
537
+ const watiForMessageChain = async (qq) => {
538
+ qq = qq ?? data?.sender?.id;
539
+ if (qq == undefined) {
540
+ throw new Error('Middleware.syncWrapper 消息格式出错');
541
+ }
542
+ do {
543
+ var { messageChain, id } = await data.bot?.waiter?.wait(data.type, ({ messageChain, sender: { id } }) => ({ messageChain, id })) ?? {};
544
+ } while (qq != id);
545
+
546
+ return messageChain;
547
+ };
548
+
549
+ const waitForText = async (qq) => {
550
+ qq = qq ?? data?.sender?.id;
551
+ if (qq == undefined) {
552
+ throw new Error('Middleware.syncWrapper 消息格式出错');
553
+ }
554
+ do {
555
+ var { text, id } = await data.bot?.waiter?.wait(data.type, new Middleware().textProcessor().done(({ text, sender: { id } }) => ({ text, id }))) ?? {};
556
+ } while (qq != id);
557
+ return text;
558
+ };
559
+
560
+ const waitForCustom = async (qq, processor) => {
561
+ qq = qq ?? data?.sender?.id;
562
+ if (qq == undefined) {
563
+ throw new Error('Middleware.syncWrapper 消息格式出错');
564
+ }
565
+ do {
566
+ var data = await data.bot?.waiter?.wait(data.type, new Middleware().textProcessor().done((data) => data));
567
+ } while (qq != data?.sender?.id);
568
+ return await processor(data);
569
+ };
570
+
571
+ data.waitFor = {
572
+ groupMember: (qq = undefined) => {
573
+ return {
574
+ messageChain: () => watiForMessageChain(qq),
575
+ text: () => waitForText(qq),
576
+ custom: (processor) => waitForCustom(qq, processor),
577
+ };
578
+ },
579
+ friend: (qq) => {
580
+ return {
581
+ messageChain: () => watiForMessageChain(qq),
582
+ text: () => waitForText(qq),
583
+ custom: (processor) => waitForCustom(qq, processor),
584
+ };
585
+ },
586
+ messageChain: () => watiForMessageChain(data.sender.id),
587
+ text: () => waitForText(data.sender.id),
588
+ custom: (processor) => waitForCustom(data.sender.id, processor),
589
+ };
590
+
591
+ await next();
592
+ } catch (error) {
593
+ if (this.catcher) {
594
+ this.catcher(error);
595
+ } else {
596
+ throw error;
597
+ }
598
+ }
599
+ });
600
+ return this;
601
+ }
602
+
603
+
604
+
605
+ /**
606
+ * @description 添加一个自定义中间件
607
+ * @param {function} callback (data, next) => void
608
+ */
609
+ use(callback) {
610
+ this.middleware.push(async (data, next) => {
611
+ // 捕获错误
612
+ try {
613
+ await callback(data, next);
614
+ } catch (error) {
615
+ if (this.catcher) {
616
+ this.catcher(error);
617
+ } else {
618
+ throw error;
619
+ }
620
+ }
621
+ });
622
+ return this;
623
+ }
624
+
625
+ /**
626
+ * @description 使用错误处理器
627
+ * @param {function} catcher 错误处理器 (err) => void
628
+ */
629
+ catch(catcher) {
630
+ this.catcher = catcher;
631
+ return this;
632
+ }
633
+
634
+ /**
635
+ * @description 生成一个带有中间件的事件处理器
636
+ * @param {function} callback 事件处理器
637
+ */
638
+ done(callback) {
639
+ return data => {
640
+ return new Promise(resolve => {
641
+ // 从右侧递归合并中间件链
642
+ this.middleware.reduceRight((next, middleware) => {
643
+ return async () => resolve(await middleware(data, next));
644
+ }, async () => {
645
+ // 最深层递归,即开发者提供的回调函数
646
+ let returnVal = callback instanceof Function ? (await callback(data)) : undefined;
647
+
648
+ // 异步返回
649
+ resolve(returnVal);
650
+ })();
651
+ });
652
+ };
653
+
654
+ }
655
+ }
656
+
657
+ module.exports = { Middleware };
@@ -0,0 +1,13 @@
1
+ import { EventType, Processor } from './BaseType';
2
+ import { Bot } from './Bot';
3
+
4
+ export class Waiter {
5
+ private bot: Bot;
6
+
7
+ /**
8
+ * @description 等待一次消息,经过开发者提供的处理器后返回到异步代码处
9
+ * @param eventType 事件类型
10
+ * @param callback 处理器,其返回值将被 resolve,传递到外部
11
+ */
12
+ wait(eventType: EventType, callback: Processor): Promise<any>;
13
+ }
@@ -0,0 +1,24 @@
1
+ /**
2
+ * @description 每个 Bot 实例将维护一个 Waiter 实例,它用来同步等待一次用户输入
3
+ * @use 使用 bot.waiter
4
+ */
5
+ class Waiter {
6
+ constructor(bot) {
7
+ this.bot = bot;
8
+ }
9
+
10
+ /**
11
+ * @description 等待一次消息,经过开发者提供的处理器后返回到异步代码处
12
+ * @param {string} eventType 事件类型
13
+ * @param {function} callback 处理器,其返回值将被 resolve,传递到外部
14
+ */
15
+ async wait(eventType, callback) {
16
+ return new Promise(resolve => {
17
+ // 注册严格的一次事件,等待回调
18
+ this.bot.one(eventType, async data => resolve(await callback(data)), true);
19
+ });
20
+ }
21
+
22
+ }
23
+
24
+ module.exports = { Waiter };