discord-sb.js 1.2.3 → 1.3.1

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 (51) hide show
  1. package/package.json +13 -12
  2. package/src/client/BaseClient.js +24 -0
  3. package/src/client/Client.js +11 -4
  4. package/src/client/WebhookClient.js +1 -1
  5. package/src/client/actions/Action.js +39 -22
  6. package/src/client/actions/InviteCreate.js +1 -1
  7. package/src/client/actions/InviteDelete.js +1 -1
  8. package/src/client/actions/MessageCreate.js +6 -6
  9. package/src/client/actions/MessageDelete.js +3 -1
  10. package/src/client/actions/MessageDeleteBulk.js +6 -9
  11. package/src/client/actions/MessageReactionAdd.js +12 -9
  12. package/src/client/actions/MessageReactionRemove.js +3 -14
  13. package/src/client/actions/MessageReactionRemoveAll.js +8 -5
  14. package/src/client/actions/MessageReactionRemoveEmoji.js +3 -1
  15. package/src/client/actions/MessageUpdate.js +3 -1
  16. package/src/client/actions/PresenceUpdate.js +8 -3
  17. package/src/client/actions/ThreadListSync.js +6 -5
  18. package/src/client/actions/ThreadMembersUpdate.js +10 -6
  19. package/src/client/actions/TypingStart.js +3 -1
  20. package/src/client/actions/VoiceStateUpdate.js +20 -7
  21. package/src/client/voice/ClientVoiceManager.js +18 -7
  22. package/src/client/voice/StreamEventRouter.js +60 -0
  23. package/src/client/voice/VoiceConnection.js +91 -167
  24. package/src/client/voice/networking/VoiceUDPClient.js +25 -11
  25. package/src/client/voice/networking/VoiceWebSocket.js +87 -26
  26. package/src/client/websocket/DispatchTable.js +7 -0
  27. package/src/client/websocket/GatewaySendScheduler.js +107 -0
  28. package/src/client/websocket/WebSocketManager.js +26 -22
  29. package/src/client/websocket/WebSocketShard.js +161 -51
  30. package/src/client/websocket/handlers/GUILD_CREATE.js +4 -5
  31. package/src/client/websocket/handlers/GUILD_MEMBERS_CHUNK.js +8 -2
  32. package/src/client/websocket/handlers/READY.js +72 -59
  33. package/src/client/websocket/handlers/USER_REQUIRED_ACTION_UPDATE.js +13 -9
  34. package/src/client/websocket/handlers/VOICE_SERVER_UPDATE.js +7 -1
  35. package/src/managers/GuildMemberManager.js +8 -3
  36. package/src/managers/MessageManager.js +27 -23
  37. package/src/managers/QuestManager.js +7 -9
  38. package/src/rest/APIRequest.js +40 -43
  39. package/src/rest/APIRouter.js +1 -1
  40. package/src/rest/RESTManager.js +69 -2
  41. package/src/rest/RateLimitCoordinator.js +156 -0
  42. package/src/rest/RequestHandler.js +162 -91
  43. package/src/structures/DMChannel.js +5 -2
  44. package/src/structures/GroupDMChannel.js +5 -2
  45. package/src/structures/interfaces/Collector.js +2 -1
  46. package/src/util/Constants.js +41 -2
  47. package/src/util/FastQueue.js +93 -0
  48. package/src/util/ListenerUtil.js +12 -0
  49. package/src/util/Options.js +2 -2
  50. package/src/util/RemoteAuth.js +9 -1
  51. package/typings/index.d.ts +64 -41
@@ -3,6 +3,7 @@
3
3
  const VoiceConnection = require('./VoiceConnection');
4
4
  const { Error } = require('../../errors');
5
5
  const { Events } = require('../../util/Constants');
6
+ const { hasListener } = require('../../util/ListenerUtil');
6
7
 
7
8
  /**
8
9
  * Manages voice connections for the client
@@ -42,8 +43,7 @@ class ClientVoiceManager {
42
43
 
43
44
  onVoiceServer(payload) {
44
45
  const { guild_id, channel_id, token, endpoint } = payload;
45
- this.client.emit(
46
- 'debug',
46
+ this._debug(
47
47
  `[VOICE] voiceServer ${channel_id ? 'channel' : 'guild'}: ${
48
48
  channel_id || guild_id
49
49
  } token: ${token} endpoint: ${endpoint}`,
@@ -68,7 +68,7 @@ class ClientVoiceManager {
68
68
  }
69
69
  // Main lib
70
70
  const connection = this.connection;
71
- this.client.emit('debug', `[VOICE] connection? ${!!connection}, ${guild_id} ${session_id} ${channel_id}`);
71
+ this._debug(`[VOICE] connection? ${!!connection}, ${guild_id} ${session_id} ${channel_id}`);
72
72
  if (!connection) return;
73
73
  if (!channel_id) {
74
74
  connection._disconnect();
@@ -80,7 +80,7 @@ class ClientVoiceManager {
80
80
  connection.channel = channel;
81
81
  connection.setSessionId(session_id);
82
82
  } else {
83
- this.client.emit('debug', `[VOICE] disconnecting from guild ${guild_id} as channel ${channel_id} is uncached`);
83
+ this._debug(`[VOICE] disconnecting from guild ${guild_id} as channel ${channel_id} is uncached`);
84
84
  connection.disconnect();
85
85
  }
86
86
  }
@@ -117,9 +117,14 @@ class ClientVoiceManager {
117
117
  } else {
118
118
  connection = new VoiceConnection(this, channel);
119
119
  if (config?.videoCodec) connection.setVideoCodec(config.videoCodec);
120
- connection.on('debug', msg =>
121
- this.client.emit('debug', `[VOICE (${channel.guild?.id || channel.id}:${connection.status})]: ${msg}`),
122
- );
120
+ const forwardDebug = msg => {
121
+ if (hasListener(this.client, Events.DEBUG)) {
122
+ this.client.emit(Events.DEBUG, `[VOICE (${channel.guild?.id || channel.id}:${connection.status})]: ${msg}`);
123
+ }
124
+ };
125
+ forwardDebug.__voiceForwarder = true;
126
+ connection.on('debug', forwardDebug);
127
+ connection._voiceDebugForwarder = forwardDebug;
123
128
  connection.authenticate({
124
129
  self_mute: Boolean(config.selfMute),
125
130
  self_deaf: Boolean(config.selfDeaf),
@@ -146,6 +151,12 @@ class ClientVoiceManager {
146
151
  });
147
152
  });
148
153
  }
154
+
155
+ _debug(message) {
156
+ if (hasListener(this.client, Events.DEBUG)) {
157
+ this.client.emit(Events.DEBUG, message);
158
+ }
159
+ }
149
160
  }
150
161
 
151
162
  module.exports = ClientVoiceManager;
@@ -0,0 +1,60 @@
1
+ 'use strict';
2
+
3
+ const { parseStreamKey } = require('./util/Function');
4
+
5
+ class StreamEventRouter {
6
+ constructor(connection) {
7
+ this.connection = connection;
8
+ this._onRaw = this._onRaw.bind(this);
9
+ this._attached = false;
10
+ }
11
+
12
+ attach() {
13
+ if (this._attached) return;
14
+ this.connection.channel.client.on('raw', this._onRaw);
15
+ this._attached = true;
16
+ }
17
+
18
+ detach() {
19
+ if (!this._attached) return;
20
+ this.connection.channel.client.removeListener('raw', this._onRaw);
21
+ this._attached = false;
22
+ }
23
+
24
+ _onRaw(packet) {
25
+ if (typeof packet !== 'object' || !packet.t || !packet.d?.stream_key) return;
26
+ const { t: event, d: data } = packet;
27
+ const streamKey = parseStreamKey(data.stream_key);
28
+ if (this.connection.channel.id !== streamKey.channelId) return;
29
+
30
+ if (streamKey.userId === this.connection.channel.client.user.id && this.connection.streamConnection) {
31
+ this._applyEvent(this.connection.streamConnection, event, data);
32
+ }
33
+
34
+ const watched = this.connection.streamWatchConnection.get(streamKey.userId);
35
+ if (watched) {
36
+ this._applyEvent(watched, event, data, true);
37
+ }
38
+ }
39
+
40
+ _applyEvent(connection, event, data, isWatcher = false) {
41
+ switch (event) {
42
+ case 'STREAM_CREATE':
43
+ connection.setSessionId(this.connection.authentication.sessionId);
44
+ connection.serverId = data.rtc_server_id;
45
+ break;
46
+ case 'STREAM_SERVER_UPDATE':
47
+ connection.setTokenAndEndpoint(data.token, data.endpoint);
48
+ break;
49
+ case 'STREAM_DELETE':
50
+ connection.disconnect();
51
+ if (isWatcher) connection.receiver.packets.destroyAllStream();
52
+ break;
53
+ case 'STREAM_UPDATE':
54
+ connection.update(data);
55
+ break;
56
+ }
57
+ }
58
+ }
59
+
60
+ module.exports = StreamEventRouter;
@@ -4,15 +4,16 @@ const EventEmitter = require('events');
4
4
  const { getCiphers } = require('node:crypto');
5
5
  const { setTimeout } = require('node:timers');
6
6
  const { Collection } = require('@discordjs/collection');
7
+ const StreamEventRouter = require('./StreamEventRouter');
7
8
  const VoiceUDP = require('./networking/VoiceUDPClient');
8
9
  const VoiceWebSocket = require('./networking/VoiceWebSocket');
9
10
  const MediaPlayer = require('./player/MediaPlayer');
10
11
  const VoiceReceiver = require('./receiver/Receiver');
11
- const { parseStreamKey } = require('./util/Function');
12
12
  const PlayInterface = require('./util/PlayInterface');
13
13
  const Silence = require('./util/Silence');
14
14
  const { Error } = require('../../errors');
15
15
  const { Opcodes, VoiceOpcodes, VoiceStatus, Events } = require('../../util/Constants');
16
+ const { hasListener } = require('../../util/ListenerUtil');
16
17
  const Speaking = require('../../util/Speaking');
17
18
  const Util = require('../../util/Util');
18
19
 
@@ -85,6 +86,7 @@ class VoiceConnection extends EventEmitter {
85
86
  * @private
86
87
  */
87
88
  this.authentication = {};
89
+ this._voiceSequence = -1;
88
90
 
89
91
  /**
90
92
  * The audio player for this voice connection
@@ -98,7 +100,7 @@ class VoiceConnection extends EventEmitter {
98
100
  * @event VoiceConnection#debug
99
101
  * @param {string} message The debug message
100
102
  */
101
- this.emit('debug', `media player - ${m}`);
103
+ this._debug(`media player - ${m}`);
102
104
  });
103
105
 
104
106
  this.player.on('error', e => {
@@ -166,6 +168,7 @@ class VoiceConnection extends EventEmitter {
166
168
  * @type {Collection<Snowflake, StreamConnectionReadonly>}
167
169
  */
168
170
  this.streamWatchConnection = new Collection();
171
+ this._streamEventRouter = new StreamEventRouter(this);
169
172
  }
170
173
 
171
174
  /**
@@ -195,6 +198,28 @@ class VoiceConnection extends EventEmitter {
195
198
  return this.player.videoDispatcher;
196
199
  }
197
200
 
201
+ hasDebugListeners() {
202
+ const forwardingListeners = this._voiceDebugForwarder ? 1 : 0;
203
+ const hasClientDebugListener = hasListener(this.client, Events.DEBUG);
204
+ return this.listenerCount('debug') > forwardingListeners || hasClientDebugListener;
205
+ }
206
+
207
+ _debug(message) {
208
+ if (!this.hasDebugListeners()) return;
209
+ this.emit('debug', message);
210
+ }
211
+
212
+ _debugLazy(factory) {
213
+ if (!this.hasDebugListeners()) return;
214
+ this.emit('debug', factory());
215
+ }
216
+
217
+ sendGatewayPacket(packet) {
218
+ const shard = this.channel?.shard ?? this.channel?.client?.ws?.shards?.first?.();
219
+ if (shard) return shard.send(packet);
220
+ return this.channel.client.ws.broadcast(packet);
221
+ }
222
+
198
223
  /**
199
224
  * Sets whether the voice connection should display as "speaking", "soundshare" or "none".
200
225
  * @param {BitFieldResolvable} value The new speaking state
@@ -213,7 +238,7 @@ class VoiceConnection extends EventEmitter {
213
238
  },
214
239
  })
215
240
  .catch(e => {
216
- this.emit('debug', e);
241
+ this._debug(e);
217
242
  });
218
243
  }
219
244
 
@@ -239,7 +264,7 @@ class VoiceConnection extends EventEmitter {
239
264
  if (!value) {
240
265
  this.sockets.ws
241
266
  .sendPacket({
242
- op: VoiceOpcodes.SOURCES,
267
+ op: VoiceOpcodes.VIDEO,
243
268
  d: {
244
269
  audio_ssrc: this.authentication.ssrc,
245
270
  video_ssrc: 0,
@@ -248,12 +273,12 @@ class VoiceConnection extends EventEmitter {
248
273
  },
249
274
  })
250
275
  .catch(e => {
251
- this.emit('debug', e);
276
+ this._debug(e);
252
277
  });
253
278
  } else {
254
279
  this.sockets.ws
255
280
  .sendPacket({
256
- op: VoiceOpcodes.SOURCES,
281
+ op: VoiceOpcodes.VIDEO,
257
282
  d: {
258
283
  audio_ssrc: this.authentication.ssrc,
259
284
  video_ssrc: this.authentication.ssrc + 1,
@@ -278,7 +303,7 @@ class VoiceConnection extends EventEmitter {
278
303
  },
279
304
  })
280
305
  .catch(e => {
281
- this.emit('debug', e);
306
+ this._debug(e);
282
307
  });
283
308
  }
284
309
  }
@@ -310,9 +335,9 @@ class VoiceConnection extends EventEmitter {
310
335
  options,
311
336
  );
312
337
 
313
- this.emit('debug', `Sending voice state update: ${JSON.stringify(options)}`);
338
+ this._debugLazy(() => `Sending voice state update: ${JSON.stringify(options)}`);
314
339
 
315
- return this.channel.client.ws.broadcast({
340
+ return this.sendGatewayPacket({
316
341
  op: Opcodes.VOICE_STATE_UPDATE,
317
342
  d: options,
318
343
  });
@@ -326,7 +351,7 @@ class VoiceConnection extends EventEmitter {
326
351
  * @private
327
352
  */
328
353
  setTokenAndEndpoint(token, endpoint) {
329
- this.emit('debug', `Token "${token}" and endpoint "${endpoint}"`);
354
+ this._debug(`Token "${token}" and endpoint "${endpoint}"`);
330
355
  if (!endpoint) {
331
356
  // Signifies awaiting endpoint stage
332
357
  return;
@@ -338,7 +363,7 @@ class VoiceConnection extends EventEmitter {
338
363
  }
339
364
 
340
365
  endpoint = endpoint.match(/([^:]*)/)[0];
341
- this.emit('debug', `Endpoint resolved as ${endpoint}`);
366
+ this._debug(`Endpoint resolved as ${endpoint}`);
342
367
 
343
368
  if (!endpoint) {
344
369
  this.authenticateFailed('VOICE_INVALID_ENDPOINT');
@@ -360,7 +385,7 @@ class VoiceConnection extends EventEmitter {
360
385
  * @private
361
386
  */
362
387
  setSessionId(sessionId) {
363
- this.emit('debug', `Setting sessionId ${sessionId} (stored as "${this.authentication.sessionId}")`);
388
+ this._debug(`Setting sessionId ${sessionId} (stored as "${this.authentication.sessionId}")`);
364
389
  if (!sessionId) {
365
390
  this.authenticateFailed('VOICE_SESSION_ABSENT');
366
391
  return;
@@ -386,7 +411,7 @@ class VoiceConnection extends EventEmitter {
386
411
  */
387
412
  checkAuthenticated() {
388
413
  const { token, endpoint, sessionId } = this.authentication;
389
- this.emit('debug', `Authenticated with sessionId ${sessionId}`);
414
+ this._debug(`Authenticated with sessionId ${sessionId}`);
390
415
  if (token && endpoint && sessionId) {
391
416
  this.status = VoiceStatus.CONNECTING;
392
417
  /**
@@ -405,7 +430,7 @@ class VoiceConnection extends EventEmitter {
405
430
  */
406
431
  authenticateFailed(reason) {
407
432
  clearTimeout(this.connectTimeout);
408
- this.emit('debug', `Authenticate failed - ${reason}`);
433
+ this._debug(`Authenticate failed - ${reason}`);
409
434
  if (this.status === VoiceStatus.AUTHENTICATING) {
410
435
  /**
411
436
  * Emitted when we fail to initiate a voice connection.
@@ -455,7 +480,7 @@ class VoiceConnection extends EventEmitter {
455
480
  this.authentication.endpoint = endpoint;
456
481
  this.speaking = new Speaking().freeze();
457
482
  this.status = VoiceStatus.RECONNECTING;
458
- this.emit('debug', `Reconnecting to ${endpoint}`);
483
+ this._debug(`Reconnecting to ${endpoint}`);
459
484
  /**
460
485
  * Emitted when the voice connection is reconnecting (typically after a region change).
461
486
  * @event VoiceConnection#reconnecting
@@ -469,7 +494,7 @@ class VoiceConnection extends EventEmitter {
469
494
  */
470
495
  disconnect() {
471
496
  this.emit('closing');
472
- this.emit('debug', 'disconnect() triggered');
497
+ this._debug('disconnect() triggered');
473
498
  clearTimeout(this.connectTimeout);
474
499
  const conn = this.voiceManager.connection;
475
500
  if (conn === this) this.voiceManager.connection = null;
@@ -502,7 +527,8 @@ class VoiceConnection extends EventEmitter {
502
527
  this.speaking = new Speaking().freeze();
503
528
  const { ws, udp } = this.sockets;
504
529
 
505
- this.emit('debug', 'Connection clean up');
530
+ this._debug('Connection clean up');
531
+ this._streamEventRouter.detach();
506
532
 
507
533
  if (ws) {
508
534
  ws.removeAllListeners('error');
@@ -523,7 +549,7 @@ class VoiceConnection extends EventEmitter {
523
549
  * @private
524
550
  */
525
551
  connect() {
526
- this.emit('debug', `Connect triggered`);
552
+ this._debug('Connect triggered');
527
553
  if (this.status !== VoiceStatus.RECONNECTING) {
528
554
  if (this.sockets.ws) throw new Error('WS_CONNECTION_EXISTS');
529
555
  if (this.sockets.udp) throw new Error('UDP_CONNECTION_EXISTS');
@@ -537,11 +563,12 @@ class VoiceConnection extends EventEmitter {
537
563
 
538
564
  const { ws, udp } = this.sockets;
539
565
 
540
- ws.on('debug', msg => this.emit('debug', msg));
541
- udp.on('debug', msg => this.emit('debug', msg));
566
+ ws.on('debug', msg => this._debug(msg));
567
+ udp.on('debug', msg => this._debug(msg));
542
568
  ws.on('error', err => this.emit('error', err));
543
569
  udp.on('error', err => this.emit('error', err));
544
570
  ws.on('ready', this.onReady.bind(this));
571
+ ws.on('resumed', this.onResumed.bind(this));
545
572
  ws.on('sessionDescription', this.onSessionDescription.bind(this));
546
573
  ws.on('startSpeaking', this.onStartSpeaking.bind(this));
547
574
  ws.on('startStreaming', this.onStartStreaming.bind(this));
@@ -559,7 +586,7 @@ class VoiceConnection extends EventEmitter {
559
586
  for (let mode of data.modes) {
560
587
  if (SUPPORTED_MODES.includes(mode)) {
561
588
  this.authentication.mode = mode;
562
- this.emit('debug', `Selecting the ${mode} mode`);
589
+ this._debug(`Selecting the ${mode} mode`);
563
590
  break;
564
591
  }
565
592
  }
@@ -576,7 +603,7 @@ class VoiceConnection extends EventEmitter {
576
603
  this.status = VoiceStatus.CONNECTED;
577
604
  const ready = () => {
578
605
  clearTimeout(this.connectTimeout);
579
- this.emit('debug', `Ready with authentication details: ${JSON.stringify(this.authentication)}`);
606
+ this._debugLazy(() => `Ready with authentication details: ${JSON.stringify(this.authentication)}`);
580
607
  /**
581
608
  * Emitted once the connection is ready, when a promise to join a voice channel resolves,
582
609
  * the connection will already be ready.
@@ -593,6 +620,13 @@ class VoiceConnection extends EventEmitter {
593
620
  }
594
621
  }
595
622
 
623
+ onResumed() {
624
+ this.status = VoiceStatus.CONNECTED;
625
+ clearTimeout(this.connectTimeout);
626
+ this._debug('[WS] Voice session resumed');
627
+ this.emit('resumed');
628
+ }
629
+
596
630
  onStartSpeaking({ user_id, ssrc, speaking }) {
597
631
  this.ssrcMap.set(+ssrc, {
598
632
  ...(this.ssrcMap.get(+ssrc) || {}),
@@ -680,77 +714,22 @@ class VoiceConnection extends EventEmitter {
680
714
  } else {
681
715
  const connection = (this.streamConnection = new StreamConnection(this.voiceManager, this.channel, this));
682
716
  connection.setVideoCodec(this.videoCodec); // Sync :?
683
- // Setup event...
684
- if (!this.eventHook) {
685
- this.eventHook = true; // Dont listen this event two times :/
686
- this.channel.client.on('raw', packet => {
687
- if (typeof packet !== 'object' || !packet.t || !packet.d || !packet.d?.stream_key) {
688
- return;
689
- }
690
- const { t: event, d: data } = packet;
691
- const StreamKey = parseStreamKey(data.stream_key);
692
- if (
693
- StreamKey.userId === this.channel.client.user.id &&
694
- this.channel.id == StreamKey.channelId &&
695
- this.streamConnection
696
- ) {
697
- // Current user stream
698
- switch (event) {
699
- case 'STREAM_CREATE': {
700
- this.streamConnection.setSessionId(this.authentication.sessionId);
701
- this.streamConnection.serverId = data.rtc_server_id;
702
- break;
703
- }
704
- case 'STREAM_SERVER_UPDATE': {
705
- this.streamConnection.setTokenAndEndpoint(data.token, data.endpoint);
706
- break;
707
- }
708
- case 'STREAM_DELETE': {
709
- this.streamConnection.disconnect();
710
- break;
711
- }
712
- case 'STREAM_UPDATE': {
713
- this.streamConnection.update(data);
714
- break;
715
- }
716
- }
717
- }
718
- if (this.streamWatchConnection.has(StreamKey.userId) && this.channel.id == StreamKey.channelId) {
719
- const streamConnection = this.streamWatchConnection.get(StreamKey.userId);
720
- // Watch user stream
721
- switch (event) {
722
- case 'STREAM_CREATE': {
723
- streamConnection.setSessionId(this.authentication.sessionId);
724
- streamConnection.serverId = data.rtc_server_id;
725
- break;
726
- }
727
- case 'STREAM_SERVER_UPDATE': {
728
- streamConnection.setTokenAndEndpoint(data.token, data.endpoint);
729
- break;
730
- }
731
- case 'STREAM_DELETE': {
732
- streamConnection.disconnect();
733
- streamConnection.receiver.packets.destroyAllStream();
734
- break;
735
- }
736
- case 'STREAM_UPDATE': {
737
- streamConnection.update(data);
738
- break;
739
- }
740
- }
741
- }
742
- });
743
- }
717
+ this._streamEventRouter.attach();
744
718
 
745
719
  connection.sendSignalScreenshare();
746
720
  connection.sendScreenshareState(true);
747
721
 
748
- connection.on('debug', msg =>
749
- this.channel.client.emit(
750
- 'debug',
751
- `[VOICE STREAM (${this.channel.guild?.id || this.channel.id}:${connection.status})]: ${msg}`,
752
- ),
753
- );
722
+ const forwardStreamDebug = msg => {
723
+ if (hasListener(this.channel.client, Events.DEBUG)) {
724
+ this.channel.client.emit(
725
+ Events.DEBUG,
726
+ `[VOICE STREAM (${this.channel.guild?.id || this.channel.id}:${connection.status})]: ${msg}`,
727
+ );
728
+ }
729
+ };
730
+ forwardStreamDebug.__voiceForwarder = true;
731
+ connection.on('debug', forwardStreamDebug);
732
+ connection._voiceDebugForwarder = forwardStreamDebug;
754
733
  connection.once('failed', reason => {
755
734
  this.streamConnection = null;
756
735
  reject(reason);
@@ -794,78 +773,23 @@ class VoiceConnection extends EventEmitter {
794
773
  const connection = new StreamConnectionReadonly(this.voiceManager, this.channel, this, userId);
795
774
  this.streamWatchConnection.set(userId, connection);
796
775
  connection.setVideoCodec(this.videoCodec);
797
- // Setup event...
798
- if (!this.eventHook) {
799
- this.eventHook = true; // Dont listen this event two times :/
800
- this.channel.client.on('raw', packet => {
801
- if (typeof packet !== 'object' || !packet.t || !packet.d || !packet.d?.stream_key) {
802
- return;
803
- }
804
- const { t: event, d: data } = packet;
805
- const StreamKey = parseStreamKey(data.stream_key);
806
- if (
807
- StreamKey.userId === this.channel.client.user.id &&
808
- this.channel.id == StreamKey.channelId &&
809
- this.streamConnection
810
- ) {
811
- // Current user stream
812
- switch (event) {
813
- case 'STREAM_CREATE': {
814
- this.streamConnection.setSessionId(this.authentication.sessionId);
815
- this.streamConnection.serverId = data.rtc_server_id;
816
- break;
817
- }
818
- case 'STREAM_SERVER_UPDATE': {
819
- this.streamConnection.setTokenAndEndpoint(data.token, data.endpoint);
820
- break;
821
- }
822
- case 'STREAM_DELETE': {
823
- this.streamConnection.disconnect();
824
- break;
825
- }
826
- case 'STREAM_UPDATE': {
827
- this.streamConnection.update(data);
828
- break;
829
- }
830
- }
831
- }
832
- if (this.streamWatchConnection.has(StreamKey.userId) && this.channel.id == StreamKey.channelId) {
833
- const streamConnection = this.streamWatchConnection.get(StreamKey.userId);
834
- // Watch user stream
835
- switch (event) {
836
- case 'STREAM_CREATE': {
837
- streamConnection.setSessionId(this.authentication.sessionId);
838
- streamConnection.serverId = data.rtc_server_id;
839
- break;
840
- }
841
- case 'STREAM_SERVER_UPDATE': {
842
- streamConnection.setTokenAndEndpoint(data.token, data.endpoint);
843
- break;
844
- }
845
- case 'STREAM_DELETE': {
846
- streamConnection.disconnect();
847
- streamConnection.receiver.packets.destroyAllStream();
848
- break;
849
- }
850
- case 'STREAM_UPDATE': {
851
- streamConnection.update(data);
852
- break;
853
- }
854
- }
855
- }
856
- });
857
- }
776
+ this._streamEventRouter.attach();
858
777
 
859
778
  connection.sendSignalScreenshare();
860
779
 
861
- connection.on('debug', msg =>
862
- this.channel.client.emit(
863
- 'debug',
864
- `[VOICE STREAM WATCH (${userId}>${this.channel.guild?.id || this.channel.id}:${
865
- connection.status
866
- })]: ${msg}`,
867
- ),
868
- );
780
+ const forwardStreamWatchDebug = msg => {
781
+ if (hasListener(this.channel.client, Events.DEBUG)) {
782
+ this.channel.client.emit(
783
+ Events.DEBUG,
784
+ `[VOICE STREAM WATCH (${userId}>${this.channel.guild?.id || this.channel.id}:${
785
+ connection.status
786
+ })]: ${msg}`,
787
+ );
788
+ }
789
+ };
790
+ forwardStreamWatchDebug.__voiceForwarder = true;
791
+ connection.on('debug', forwardStreamWatchDebug);
792
+ connection._voiceDebugForwarder = forwardStreamWatchDebug;
869
793
  connection.once('failed', reason => {
870
794
  this.streamWatchConnection.delete(userId);
871
795
  reject(reason);
@@ -986,7 +910,7 @@ class StreamConnection extends VoiceConnection {
986
910
  disconnect() {
987
911
  if (this.#requestDisconnect) return;
988
912
  this.emit('closing');
989
- this.emit('debug', 'Stream: disconnect() triggered');
913
+ this._debug('Stream: disconnect() triggered');
990
914
  clearTimeout(this.connectTimeout);
991
915
  if (this.voiceConnection.streamConnection === this) this.voiceConnection.streamConnection = null;
992
916
  this.sendStopScreenshare();
@@ -1004,8 +928,8 @@ class StreamConnection extends VoiceConnection {
1004
928
  channel_id: this.channel.id,
1005
929
  preferred_region: null,
1006
930
  };
1007
- this.emit('debug', `Signal Stream: ${JSON.stringify(data)}`);
1008
- return this.channel.client.ws.broadcast({
931
+ this._debugLazy(() => `Signal Stream: ${JSON.stringify(data)}`);
932
+ return this.sendGatewayPacket({
1009
933
  op: Opcodes.STREAM_CREATE,
1010
934
  d: data,
1011
935
  });
@@ -1032,7 +956,7 @@ class StreamConnection extends VoiceConnection {
1032
956
  },
1033
957
  );
1034
958
  this.isPaused = isPaused;
1035
- this.channel.client.ws.broadcast({
959
+ this.sendGatewayPacket({
1036
960
  op: Opcodes.STREAM_SET_PAUSED,
1037
961
  d: {
1038
962
  stream_key: this.streamKey,
@@ -1048,7 +972,7 @@ class StreamConnection extends VoiceConnection {
1048
972
  */
1049
973
  sendStopScreenshare() {
1050
974
  this.#requestDisconnect = true;
1051
- this.channel.client.ws.broadcast({
975
+ this.sendGatewayPacket({
1052
976
  op: Opcodes.STREAM_DELETE,
1053
977
  d: {
1054
978
  stream_key: this.streamKey,
@@ -1177,7 +1101,7 @@ class StreamConnectionReadonly extends VoiceConnection {
1177
1101
  disconnect() {
1178
1102
  if (this.#requestDisconnect) return;
1179
1103
  this.emit('closing');
1180
- this.emit('debug', 'Stream: disconnect() triggered');
1104
+ this._debug('Stream: disconnect() triggered');
1181
1105
  clearTimeout(this.connectTimeout);
1182
1106
  this.voiceConnection.streamWatchConnection.delete(this.userId);
1183
1107
  this.sendStopScreenshare();
@@ -1189,8 +1113,8 @@ class StreamConnectionReadonly extends VoiceConnection {
1189
1113
  * @returns {void}
1190
1114
  */
1191
1115
  sendSignalScreenshare() {
1192
- this.emit('debug', `Signal Stream Watch: ${this.streamKey}`);
1193
- return this.channel.client.ws.broadcast({
1116
+ this._debug(`Signal Stream Watch: ${this.streamKey}`);
1117
+ return this.sendGatewayPacket({
1194
1118
  op: Opcodes.STREAM_WATCH,
1195
1119
  d: {
1196
1120
  stream_key: this.streamKey,
@@ -1205,7 +1129,7 @@ class StreamConnectionReadonly extends VoiceConnection {
1205
1129
  */
1206
1130
  sendStopScreenshare() {
1207
1131
  this.#requestDisconnect = true;
1208
- this.channel.client.ws.broadcast({
1132
+ this.sendGatewayPacket({
1209
1133
  op: Opcodes.STREAM_DELETE,
1210
1134
  d: {
1211
1135
  stream_key: this.streamKey,