mirror of
https://github.com/discordjs/discord.js.git
synced 2026-03-17 20:13:30 +01:00
crappy ratelimiting it doesnt work but its here ok
This commit is contained in:
@@ -12,5 +12,6 @@ module.exports = {
|
|||||||
"guard-for-in": 0,
|
"guard-for-in": 0,
|
||||||
"no-restricted-syntax": 0,
|
"no-restricted-syntax": 0,
|
||||||
"no-param-reassign": 0,
|
"no-param-reassign": 0,
|
||||||
|
"consistent-return": 0,
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
43
src/client/rest/APIRequest.js
Normal file
43
src/client/rest/APIRequest.js
Normal file
@@ -0,0 +1,43 @@
|
|||||||
|
const request = require('superagent');
|
||||||
|
const Constants = require('../../util/Constants');
|
||||||
|
|
||||||
|
class APIRequest {
|
||||||
|
constructor(rest, method, url, auth, data, file) {
|
||||||
|
this.rest = rest;
|
||||||
|
this.method = method;
|
||||||
|
this.url = url;
|
||||||
|
this.auth = auth;
|
||||||
|
this.data = data;
|
||||||
|
this.file = file;
|
||||||
|
}
|
||||||
|
|
||||||
|
getBucketName() {
|
||||||
|
return `${this.method} ${this.url}`;
|
||||||
|
}
|
||||||
|
|
||||||
|
getAuth() {
|
||||||
|
if (this.rest.client.store.token && this.rest.client.store.user && this.rest.client.store.user.bot) {
|
||||||
|
return `Bot ${this.rest.client.store.token}`;
|
||||||
|
} else if (this.rest.client.store.token) {
|
||||||
|
return this.rest.client.store.token;
|
||||||
|
}
|
||||||
|
throw Constants.Errors.NO_TOKEN;
|
||||||
|
}
|
||||||
|
|
||||||
|
gen() {
|
||||||
|
const apiRequest = request[this.method](this.url);
|
||||||
|
if (this.auth) {
|
||||||
|
apiRequest.set('authorization', this.getAuth());
|
||||||
|
}
|
||||||
|
if (this.data) {
|
||||||
|
apiRequest.send(this.data);
|
||||||
|
}
|
||||||
|
if (this.file) {
|
||||||
|
apiRequest.attach('file', this.file.file, this.file.name);
|
||||||
|
}
|
||||||
|
apiRequest.set('User-Agent', this.rest.userAgentManager.userAgent);
|
||||||
|
return apiRequest;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
module.exports = APIRequest;
|
||||||
62
src/client/rest/Bucket.js
Normal file
62
src/client/rest/Bucket.js
Normal file
@@ -0,0 +1,62 @@
|
|||||||
|
class Bucket {
|
||||||
|
constructor(rest, limit, remainingRequests = 1, resetTime) {
|
||||||
|
this.rest = rest;
|
||||||
|
this.limit = limit;
|
||||||
|
this.remainingRequests = remainingRequests;
|
||||||
|
this.resetTime = resetTime;
|
||||||
|
this.locked = false;
|
||||||
|
this.queue = [];
|
||||||
|
this.nextCheck = null;
|
||||||
|
}
|
||||||
|
|
||||||
|
setCheck(time) {
|
||||||
|
clearTimeout(this.nextCheck);
|
||||||
|
console.log('going to iterate in', time, 'remaining:', this.queue.length);
|
||||||
|
this.nextCheck = setTimeout(() => {
|
||||||
|
this.remainingRequests = this.limit - 1;
|
||||||
|
this.locked = false;
|
||||||
|
this.process();
|
||||||
|
}, time);
|
||||||
|
}
|
||||||
|
|
||||||
|
process() {
|
||||||
|
if (this.locked) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
this.locked = true;
|
||||||
|
|
||||||
|
if (this.queue.length === 0) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (this.remainingRequests === 0) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
console.log('bucket is going to iterate', Math.min(this.remainingRequests, this.queue.length), 'items with max', this.limit, 'and remaining', this.remainingRequests);
|
||||||
|
while (Math.min(this.remainingRequests, this.queue.length) > 0) {
|
||||||
|
const item = this.queue.shift();
|
||||||
|
item.request.gen().end((err, res) => {
|
||||||
|
if (res && res.headers) {
|
||||||
|
this.limit = res.headers['x-ratelimit-limit'];
|
||||||
|
this.resetTime = Number(res.headers['x-ratelimit-reset']) * 1000;
|
||||||
|
this.setCheck((Math.max(500, this.resetTime - Date.now())) + 1000);
|
||||||
|
}
|
||||||
|
if (err) {
|
||||||
|
console.log(err.status, this.remainingRequests);
|
||||||
|
item.reject(err);
|
||||||
|
} else {
|
||||||
|
item.resolve(res && res.body ? res.body : {});
|
||||||
|
}
|
||||||
|
});
|
||||||
|
this.remainingRequests--;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
add(method) {
|
||||||
|
this.queue.push(method);
|
||||||
|
this.process();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
module.exports = Bucket;
|
||||||
@@ -2,110 +2,41 @@ const request = require('superagent');
|
|||||||
const Constants = require('../../util/Constants');
|
const Constants = require('../../util/Constants');
|
||||||
const UserAgentManager = require('./UserAgentManager');
|
const UserAgentManager = require('./UserAgentManager');
|
||||||
const RESTMethods = require('./RESTMethods');
|
const RESTMethods = require('./RESTMethods');
|
||||||
|
const Bucket = require('./Bucket');
|
||||||
|
const APIRequest = require('./APIRequest');
|
||||||
|
|
||||||
class RESTManager {
|
class RESTManager {
|
||||||
|
|
||||||
constructor(client) {
|
constructor(client) {
|
||||||
this.client = client;
|
this.client = client;
|
||||||
this.queue = [];
|
this.buckets = {};
|
||||||
this.userAgentManager = new UserAgentManager(this);
|
this.userAgentManager = new UserAgentManager(this);
|
||||||
this.methods = new RESTMethods(this);
|
this.methods = new RESTMethods(this);
|
||||||
this.rateLimitedEndpoints = {};
|
this.rateLimitedEndpoints = {};
|
||||||
}
|
}
|
||||||
|
|
||||||
addRequestToQueue(method, url, auth, data, file, resolve, reject) {
|
addToBucket(bucket, apiRequest) {
|
||||||
const endpoint = url.replace(/\/[0-9]+/g, '/:id');
|
return new Promise((resolve, reject) => {
|
||||||
|
bucket.add({
|
||||||
const rateLimitedEndpoint = this.rateLimitedEndpoints[endpoint];
|
request: apiRequest,
|
||||||
|
resolve,
|
||||||
rateLimitedEndpoint.queue = rateLimitedEndpoint.queue || [];
|
reject,
|
||||||
|
});
|
||||||
rateLimitedEndpoint.queue.push({
|
|
||||||
method,
|
|
||||||
url,
|
|
||||||
auth,
|
|
||||||
data,
|
|
||||||
file,
|
|
||||||
resolve,
|
|
||||||
reject,
|
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
processQueue(endpoint) {
|
|
||||||
const rateLimitedEndpoint = this.rateLimitedEndpoints[endpoint];
|
|
||||||
|
|
||||||
// prevent multiple queue processes
|
|
||||||
if (!rateLimitedEndpoint.timeout) {
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
// lock the queue
|
|
||||||
clearTimeout(rateLimitedEndpoint.timeout);
|
|
||||||
rateLimitedEndpoint.timeout = null;
|
|
||||||
|
|
||||||
for (const item of rateLimitedEndpoint.queue) {
|
|
||||||
this.makeRequest(item.method, item.url, item.auth, item.data, item.file)
|
|
||||||
.then(item.resolve)
|
|
||||||
.catch(item.reject);
|
|
||||||
}
|
|
||||||
|
|
||||||
rateLimitedEndpoint.queue = [];
|
|
||||||
}
|
|
||||||
|
|
||||||
makeRequest(method, url, auth, data, file) {
|
makeRequest(method, url, auth, data, file) {
|
||||||
/*
|
/*
|
||||||
file is {file, name}
|
file is {file, name}
|
||||||
*/
|
*/
|
||||||
const apiRequest = request[method](url);
|
const apiRequest = new APIRequest(this, method, url, auth, data, file);
|
||||||
|
|
||||||
const endpoint = url.replace(/\/[0-9]+/g, '/:id');
|
if (!this.buckets[apiRequest.getBucketName()]) {
|
||||||
|
console.log('new bucket', apiRequest.getBucketName());
|
||||||
if (this.rateLimitedEndpoints[endpoint] && this.rateLimitedEndpoints[endpoint].timeout) {
|
this.buckets[apiRequest.getBucketName()] = new Bucket(this, 1, 1);
|
||||||
return new Promise((resolve, reject) => {
|
|
||||||
this.addRequestToQueue(method, url, auth, data, file, resolve, reject);
|
|
||||||
});
|
|
||||||
}
|
}
|
||||||
|
|
||||||
if (auth) {
|
return this.addToBucket(this.buckets[apiRequest.getBucketName()], apiRequest);
|
||||||
if (this.client.store.token && this.client.store.user && this.client.store.user.bot) {
|
|
||||||
apiRequest.set('authorization', `Bot ${this.client.store.token}`);
|
|
||||||
} else if (this.client.store.token) {
|
|
||||||
apiRequest.set('authorization', this.client.store.token);
|
|
||||||
} else {
|
|
||||||
throw Constants.Errors.NO_TOKEN;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
if (data) {
|
|
||||||
apiRequest.send(data);
|
|
||||||
}
|
|
||||||
|
|
||||||
if (file) {
|
|
||||||
apiRequest.attach('file', file.file, file.name);
|
|
||||||
}
|
|
||||||
|
|
||||||
apiRequest.set('User-Agent', this.userAgentManager.userAgent);
|
|
||||||
|
|
||||||
return new Promise((resolve, reject) => {
|
|
||||||
apiRequest.end((err, res) => {
|
|
||||||
if (err) {
|
|
||||||
const retry = res.headers['retry-after'] || res.headers['Retry-After'];
|
|
||||||
if (retry) {
|
|
||||||
this.rateLimitedEndpoints[endpoint] = {};
|
|
||||||
this.addRequestToQueue(method, url, auth, data, file, resolve, reject);
|
|
||||||
this.rateLimitedEndpoints[endpoint].timeout = setTimeout(() => {
|
|
||||||
this.processQueue(endpoint);
|
|
||||||
}, retry);
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
reject(err);
|
|
||||||
} else {
|
|
||||||
console.log(res.headers);
|
|
||||||
resolve(res ? res.body || {} : {});
|
|
||||||
}
|
|
||||||
});
|
|
||||||
});
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -165,6 +165,7 @@ const PermissionFlags = exports.PermissionFlags = {
|
|||||||
ATTACH_FILES: 1 << 15,
|
ATTACH_FILES: 1 << 15,
|
||||||
READ_MESSAGE_HISTORY: 1 << 16,
|
READ_MESSAGE_HISTORY: 1 << 16,
|
||||||
MENTION_EVERYONE: 1 << 17,
|
MENTION_EVERYONE: 1 << 17,
|
||||||
|
EXTERNAL_EMOJIS: 1 << 18,
|
||||||
|
|
||||||
CONNECT: 1 << 20,
|
CONNECT: 1 << 20,
|
||||||
SPEAK: 1 << 21,
|
SPEAK: 1 << 21,
|
||||||
|
|||||||
@@ -141,6 +141,14 @@ client.on('message', message => {
|
|||||||
}).catch(console.log);
|
}).catch(console.log);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (message.content === 'ratelimittest') {
|
||||||
|
let i = 0;
|
||||||
|
while (i < 20) {
|
||||||
|
message.channel.sendMessage(`Testing my rates, item ${i} of 20`);
|
||||||
|
i++;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
if (message.content === 'makerole') {
|
if (message.content === 'makerole') {
|
||||||
message.guild.createRole().then(role => {
|
message.guild.createRole().then(role => {
|
||||||
message.channel.sendMessage(`Made role ${role.name}`);
|
message.channel.sendMessage(`Made role ${role.name}`);
|
||||||
|
|||||||
Reference in New Issue
Block a user