mirai-js 2.8.3 → 2.8.5

Sign up to get free protection for your applications and to get access to all the features.
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 };