mirror of
https://github.com/discordjs/discord.js.git
synced 2026-03-16 11:33:30 +01:00
Fix massive timeout/interval memory leaks
This commit is contained in:
@@ -103,8 +103,8 @@ class Client extends EventEmitter {
|
|||||||
* @type {?Date}
|
* @type {?Date}
|
||||||
*/
|
*/
|
||||||
this.readyTime = null;
|
this.readyTime = null;
|
||||||
this._intervals = [];
|
|
||||||
this._timeouts = [];
|
this._timeouts = [];
|
||||||
|
this._intervals = [];
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@@ -138,34 +138,18 @@ class Client extends EventEmitter {
|
|||||||
destroy() {
|
destroy() {
|
||||||
return new Promise((resolve, reject) => {
|
return new Promise((resolve, reject) => {
|
||||||
this.manager.destroy().then(() => {
|
this.manager.destroy().then(() => {
|
||||||
this._intervals.map(i => clearInterval(i));
|
for (const i of this._intervals) clearInterval(i);
|
||||||
this._timeouts.map(t => clearTimeout(t));
|
for (const t of this._timeouts) clearTimeout(t);
|
||||||
|
this._timeouts = [];
|
||||||
|
this._intervals = [];
|
||||||
this.token = null;
|
this.token = null;
|
||||||
this.email = null;
|
this.email = null;
|
||||||
this.password = null;
|
this.password = null;
|
||||||
this._timeouts = [];
|
|
||||||
this._intervals = [];
|
|
||||||
resolve();
|
resolve();
|
||||||
}).catch(reject);
|
}).catch(reject);
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
setInterval(...params) {
|
|
||||||
const interval = setInterval(...params);
|
|
||||||
this._intervals.push(interval);
|
|
||||||
return interval;
|
|
||||||
}
|
|
||||||
|
|
||||||
setTimeout(...params) {
|
|
||||||
const restParams = params.slice(1);
|
|
||||||
const timeout = setTimeout(() => {
|
|
||||||
this._timeouts.splice(this._timeouts.indexOf(params[0]), 1);
|
|
||||||
params[0]();
|
|
||||||
}, ...restParams);
|
|
||||||
this._timeouts.push(timeout);
|
|
||||||
return timeout;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* This shouldn't really be necessary to most developers as it is automatically invoked every 30 seconds, however
|
* This shouldn't really be necessary to most developers as it is automatically invoked every 30 seconds, however
|
||||||
* if you wish to force a sync of Guild data, you can use this. Only applicable to user accounts.
|
* if you wish to force a sync of Guild data, you can use this. Only applicable to user accounts.
|
||||||
@@ -237,6 +221,31 @@ class Client extends EventEmitter {
|
|||||||
get status() {
|
get status() {
|
||||||
return this.ws.status;
|
return this.ws.status;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
setTimeout(fn, ...params) {
|
||||||
|
const timeout = setTimeout(() => {
|
||||||
|
fn();
|
||||||
|
this._timeouts.splice(this._timeouts.indexOf(timeout), 1);
|
||||||
|
}, ...params);
|
||||||
|
this._timeouts.push(timeout);
|
||||||
|
return timeout;
|
||||||
|
}
|
||||||
|
|
||||||
|
clearTimeout(timeout) {
|
||||||
|
clearTimeout(timeout);
|
||||||
|
this._timeouts.splice(this._timeouts.indexOf(timeout), 1);
|
||||||
|
}
|
||||||
|
|
||||||
|
setInterval(...params) {
|
||||||
|
const interval = setInterval(...params);
|
||||||
|
this._intervals.push(interval);
|
||||||
|
return interval;
|
||||||
|
}
|
||||||
|
|
||||||
|
clearInterval(interval) {
|
||||||
|
clearInterval(interval);
|
||||||
|
this._intervals.splice(this._intervals.indexOf(interval), 1);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
module.exports = Client;
|
module.exports = Client;
|
||||||
|
|||||||
@@ -31,12 +31,15 @@ class ClientManager {
|
|||||||
*/
|
*/
|
||||||
this.client.emit(Constants.Events.DEBUG, `Authenticated using token ${token}`);
|
this.client.emit(Constants.Events.DEBUG, `Authenticated using token ${token}`);
|
||||||
this.client.token = token;
|
this.client.token = token;
|
||||||
|
const timeout = this.client.setTimeout(() => reject(new Error(Constants.Errors.TOOK_TOO_LONG)), 1000 * 300);
|
||||||
this.client.rest.methods.getGateway().then(gateway => {
|
this.client.rest.methods.getGateway().then(gateway => {
|
||||||
this.client.emit(Constants.Events.DEBUG, `Using gateway ${gateway}`);
|
this.client.emit(Constants.Events.DEBUG, `Using gateway ${gateway}`);
|
||||||
this.client.ws.connect(gateway);
|
this.client.ws.connect(gateway);
|
||||||
this.client.once(Constants.Events.READY, () => resolve(token));
|
this.client.once(Constants.Events.READY, () => {
|
||||||
|
resolve(token);
|
||||||
|
this.client.clearTimeout(timeout);
|
||||||
|
});
|
||||||
}).catch(reject);
|
}).catch(reject);
|
||||||
this.client.setTimeout(() => reject(new Error(Constants.Errors.TOOK_TOO_LONG)), 1000 * 300);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
|||||||
@@ -31,7 +31,7 @@ class VoiceConnectionWebSocket extends EventEmitter {
|
|||||||
|
|
||||||
_shutdown() {
|
_shutdown() {
|
||||||
if (this.ws) this.ws.close();
|
if (this.ws) this.ws.close();
|
||||||
clearInterval(this.heartbeat);
|
this.voiceConnection.manager.client.clearInterval(this.heartbeat);
|
||||||
}
|
}
|
||||||
|
|
||||||
_onOpen() {
|
_onOpen() {
|
||||||
|
|||||||
@@ -19,7 +19,7 @@ class TypingStartHandler extends AbstractHandler {
|
|||||||
typing.lastTimestamp = timestamp;
|
typing.lastTimestamp = timestamp;
|
||||||
typing.resetTimeout(tooLate(channel, user));
|
typing.resetTimeout(tooLate(channel, user));
|
||||||
} else {
|
} else {
|
||||||
channel._typing.set(user.id, new TypingData(timestamp, timestamp, tooLate(channel, user)));
|
channel._typing.set(user.id, new TypingData(client, timestamp, timestamp, tooLate(channel, user)));
|
||||||
client.emit(Constants.Events.TYPING_START, channel, user);
|
client.emit(Constants.Events.TYPING_START, channel, user);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -27,14 +27,15 @@ class TypingStartHandler extends AbstractHandler {
|
|||||||
}
|
}
|
||||||
|
|
||||||
class TypingData {
|
class TypingData {
|
||||||
constructor(since, lastTimestamp, _timeout) {
|
constructor(client, since, lastTimestamp, _timeout) {
|
||||||
|
this.client = client;
|
||||||
this.since = since;
|
this.since = since;
|
||||||
this.lastTimestamp = lastTimestamp;
|
this.lastTimestamp = lastTimestamp;
|
||||||
this._timeout = _timeout;
|
this._timeout = _timeout;
|
||||||
}
|
}
|
||||||
|
|
||||||
resetTimeout(_timeout) {
|
resetTimeout(_timeout) {
|
||||||
clearTimeout(this._timeout);
|
this.client.clearTimeout(this._timeout);
|
||||||
this._timeout = _timeout;
|
this._timeout = _timeout;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -232,7 +232,7 @@ class TextBasedChannel {
|
|||||||
const entry = this.client.user._typing.get(this.id);
|
const entry = this.client.user._typing.get(this.id);
|
||||||
entry.count--;
|
entry.count--;
|
||||||
if (entry.count <= 0 || force) {
|
if (entry.count <= 0 || force) {
|
||||||
clearInterval(entry.interval);
|
this.client.clearInterval(entry.interval);
|
||||||
this.client.user._typing.delete(this.id);
|
this.client.user._typing.delete(this.id);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user