mirror of
https://github.com/discordjs/discord.js.git
synced 2026-03-17 03:53:29 +01:00
fix(Voice): send keep alives without awaiting a response (#9202)
This commit is contained in:
@@ -121,23 +121,6 @@ describe('VoiceUDPSocket#performIPDiscovery', () => {
|
|||||||
expect(closed).toEqual(false);
|
expect(closed).toEqual(false);
|
||||||
});
|
});
|
||||||
|
|
||||||
test('Emits an error when no response received to keep alive messages', async () => {
|
|
||||||
const fake = new FakeSocket();
|
|
||||||
fake.send = jest.fn();
|
|
||||||
createSocket.mockImplementation(() => fake as any);
|
|
||||||
socket = new VoiceUDPSocket({ ip: '1.2.3.4', port: 25_565 });
|
|
||||||
|
|
||||||
let closed = false;
|
|
||||||
socket.on('close', () => (closed = true));
|
|
||||||
|
|
||||||
for (let index = 0; index < 15; index++) {
|
|
||||||
jest.advanceTimersToNextTimer();
|
|
||||||
await wait();
|
|
||||||
}
|
|
||||||
|
|
||||||
expect(closed).toEqual(true);
|
|
||||||
});
|
|
||||||
|
|
||||||
test('Recovers from intermittent responses', async () => {
|
test('Recovers from intermittent responses', async () => {
|
||||||
const fake = new FakeSocket();
|
const fake = new FakeSocket();
|
||||||
const fakeSend = jest.fn();
|
const fakeSend = jest.fn();
|
||||||
|
|||||||
@@ -12,11 +12,6 @@ export interface SocketConfig {
|
|||||||
port: number;
|
port: number;
|
||||||
}
|
}
|
||||||
|
|
||||||
interface KeepAlive {
|
|
||||||
timestamp: number;
|
|
||||||
value: number;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Parses the response from Discord to aid with local IP discovery.
|
* Parses the response from Discord to aid with local IP discovery.
|
||||||
*
|
*
|
||||||
@@ -41,11 +36,6 @@ export function parseLocalPacket(message: Buffer): SocketConfig {
|
|||||||
*/
|
*/
|
||||||
const KEEP_ALIVE_INTERVAL = 5e3;
|
const KEEP_ALIVE_INTERVAL = 5e3;
|
||||||
|
|
||||||
/**
|
|
||||||
* The maximum number of keep alive packets which can be missed.
|
|
||||||
*/
|
|
||||||
const KEEP_ALIVE_LIMIT = 12;
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* The maximum value of the keep alive counter.
|
* The maximum value of the keep alive counter.
|
||||||
*/
|
*/
|
||||||
@@ -72,11 +62,6 @@ export class VoiceUDPSocket extends EventEmitter {
|
|||||||
*/
|
*/
|
||||||
private readonly remote: SocketConfig;
|
private readonly remote: SocketConfig;
|
||||||
|
|
||||||
/**
|
|
||||||
* A list of keep alives that are waiting to be acknowledged.
|
|
||||||
*/
|
|
||||||
private readonly keepAlives: KeepAlive[];
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* The counter used in the keep alive mechanism.
|
* The counter used in the keep alive mechanism.
|
||||||
*/
|
*/
|
||||||
@@ -94,32 +79,26 @@ export class VoiceUDPSocket extends EventEmitter {
|
|||||||
|
|
||||||
/**
|
/**
|
||||||
* The time taken to receive a response to keep alive messages.
|
* The time taken to receive a response to keep alive messages.
|
||||||
|
*
|
||||||
|
* @deprecated This field is no longer updated as keep alive messages are no longer tracked.
|
||||||
*/
|
*/
|
||||||
public ping?: number;
|
public ping?: number;
|
||||||
|
|
||||||
/**
|
|
||||||
* The debug logger function, if debugging is enabled.
|
|
||||||
*/
|
|
||||||
private readonly debug: ((message: string) => void) | null;
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Creates a new VoiceUDPSocket.
|
* Creates a new VoiceUDPSocket.
|
||||||
*
|
*
|
||||||
* @param remote - Details of the remote socket
|
* @param remote - Details of the remote socket
|
||||||
*/
|
*/
|
||||||
public constructor(remote: SocketConfig, debug = false) {
|
public constructor(remote: SocketConfig) {
|
||||||
super();
|
super();
|
||||||
this.socket = createSocket('udp4');
|
this.socket = createSocket('udp4');
|
||||||
this.socket.on('error', (error: Error) => this.emit('error', error));
|
this.socket.on('error', (error: Error) => this.emit('error', error));
|
||||||
this.socket.on('message', (buffer: Buffer) => this.onMessage(buffer));
|
this.socket.on('message', (buffer: Buffer) => this.onMessage(buffer));
|
||||||
this.socket.on('close', () => this.emit('close'));
|
this.socket.on('close', () => this.emit('close'));
|
||||||
this.remote = remote;
|
this.remote = remote;
|
||||||
this.keepAlives = [];
|
|
||||||
this.keepAliveBuffer = Buffer.alloc(8);
|
this.keepAliveBuffer = Buffer.alloc(8);
|
||||||
this.keepAliveInterval = setInterval(() => this.keepAlive(), KEEP_ALIVE_INTERVAL);
|
this.keepAliveInterval = setInterval(() => this.keepAlive(), KEEP_ALIVE_INTERVAL);
|
||||||
setImmediate(() => this.keepAlive());
|
setImmediate(() => this.keepAlive());
|
||||||
|
|
||||||
this.debug = debug ? (message: string) => this.emit('debug', message) : null;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@@ -128,16 +107,6 @@ export class VoiceUDPSocket extends EventEmitter {
|
|||||||
* @param buffer - The received buffer
|
* @param buffer - The received buffer
|
||||||
*/
|
*/
|
||||||
private onMessage(buffer: Buffer): void {
|
private onMessage(buffer: Buffer): void {
|
||||||
// Handle keep alive message
|
|
||||||
if (buffer.length === 8) {
|
|
||||||
const counter = buffer.readUInt32LE(0);
|
|
||||||
const index = this.keepAlives.findIndex(({ value }) => value === counter);
|
|
||||||
if (index === -1) return;
|
|
||||||
this.ping = Date.now() - this.keepAlives[index]!.timestamp;
|
|
||||||
// Delete all keep alives up to and including the received one
|
|
||||||
this.keepAlives.splice(0, index);
|
|
||||||
}
|
|
||||||
|
|
||||||
// Propagate the message
|
// Propagate the message
|
||||||
this.emit('message', buffer);
|
this.emit('message', buffer);
|
||||||
}
|
}
|
||||||
@@ -146,18 +115,8 @@ export class VoiceUDPSocket extends EventEmitter {
|
|||||||
* Called at a regular interval to check whether we are still able to send datagrams to Discord.
|
* Called at a regular interval to check whether we are still able to send datagrams to Discord.
|
||||||
*/
|
*/
|
||||||
private keepAlive() {
|
private keepAlive() {
|
||||||
if (this.keepAlives.length >= KEEP_ALIVE_LIMIT) {
|
|
||||||
this.debug?.('UDP socket has not received enough responses from Discord - closing socket');
|
|
||||||
this.destroy();
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
this.keepAliveBuffer.writeUInt32LE(this.keepAliveCounter, 0);
|
this.keepAliveBuffer.writeUInt32LE(this.keepAliveCounter, 0);
|
||||||
this.send(this.keepAliveBuffer);
|
this.send(this.keepAliveBuffer);
|
||||||
this.keepAlives.push({
|
|
||||||
value: this.keepAliveCounter,
|
|
||||||
timestamp: Date.now(),
|
|
||||||
});
|
|
||||||
this.keepAliveCounter++;
|
this.keepAliveCounter++;
|
||||||
if (this.keepAliveCounter > MAX_COUNTER_VALUE) {
|
if (this.keepAliveCounter > MAX_COUNTER_VALUE) {
|
||||||
this.keepAliveCounter = 0;
|
this.keepAliveCounter = 0;
|
||||||
|
|||||||
Reference in New Issue
Block a user