From e75dd2638c2e479b5756b38986fe980582beda6d Mon Sep 17 00:00:00 2001 From: Amish Shah Date: Sat, 10 Sep 2016 22:12:03 +0100 Subject: [PATCH] Add Burst requests - addresses #656 --- src/client/rest/RESTManager.js | 3 + src/client/rest/RequestHandlers/Batch.js | 0 src/client/rest/RequestHandlers/Burst.js | 73 ++++++++++++++++++++++++ src/util/Constants.js | 2 +- test/random.js | 4 +- 5 files changed, 79 insertions(+), 3 deletions(-) delete mode 100644 src/client/rest/RequestHandlers/Batch.js create mode 100644 src/client/rest/RequestHandlers/Burst.js diff --git a/src/client/rest/RESTManager.js b/src/client/rest/RESTManager.js index a2c11dd94..a56118a8e 100644 --- a/src/client/rest/RESTManager.js +++ b/src/client/rest/RESTManager.js @@ -1,6 +1,7 @@ const UserAgentManager = require('./UserAgentManager'); const RESTMethods = require('./RESTMethods'); const SequentialRequestHandler = require('./RequestHandlers/Sequential'); +const BurstRequestHandler = require('./RequestHandlers/Burst'); const APIRequest = require('./APIRequest'); const Constants = require('../../util/Constants'); @@ -28,6 +29,8 @@ class RESTManager { switch (this.client.options.api_request_method) { case 'sequential': return SequentialRequestHandler; + case 'burst': + return BurstRequestHandler; default: throw new Error(Constants.Errors.INVALID_RATE_LIMIT_METHOD); } diff --git a/src/client/rest/RequestHandlers/Batch.js b/src/client/rest/RequestHandlers/Batch.js deleted file mode 100644 index e69de29bb..000000000 diff --git a/src/client/rest/RequestHandlers/Burst.js b/src/client/rest/RequestHandlers/Burst.js new file mode 100644 index 000000000..0793cc00b --- /dev/null +++ b/src/client/rest/RequestHandlers/Burst.js @@ -0,0 +1,73 @@ +const RequestHandler = require('./RequestHandler'); + +class BurstRequestHandler extends RequestHandler { + + constructor(restManager, endpoint) { + super(restManager, endpoint); + this.requestRemaining = 1; + this.first = true; + } + + push(request) { + super.push(request); + this.handle(); + } + + handleNext(time) { + if (this.waiting) return; + this.waiting = true; + this.restManager.client.setTimeout(() => { + this.requestRemaining = this.requestLimit; + this.waiting = false; + this.handle(); + }, time); + } + + execute(item) { + item.request.gen().end((err, res) => { + if (res && res.headers) { + this.requestLimit = res.headers['x-ratelimit-limit']; + this.requestResetTime = Number(res.headers['x-ratelimit-reset']) * 1000; + this.requestRemaining = Number(res.headers['x-ratelimit-remaining']); + this.timeDifference = Date.now() - new Date(res.headers.date).getTime(); + this.handleNext((this.requestResetTime - Date.now()) + this.timeDifference + 1000); + } + if (err) { + if (err.status === 429) { + this.requestRemaining = 0; + this.queue.unshift(item); + this.restManager.client.setTimeout(() => { + this.globalLimit = false; + this.handle(); + }, Number(res.headers['retry-after']) + 500); + if (res.headers['x-ratelimit-global']) { + this.globalLimit = true; + } + } else { + item.reject(err); + } + } else { + this.globalLimit = false; + const data = res && res.body ? res.body : {}; + item.resolve(data); + if (this.first) { + this.first = false; + this.handle(); + } + } + }); + } + + + handle() { + super.handle(); + if (this.requestRemaining < 1 || this.queue.length === 0 || this.globalLimit) return; + while (this.queue.length > 0 && this.requestRemaining > 0) { + this.execute(this.queue.shift()); + this.requestRemaining--; + } + } + +} + +module.exports = BurstRequestHandler; diff --git a/src/util/Constants.js b/src/util/Constants.js index 911f8bad0..14a8a8ca7 100644 --- a/src/util/Constants.js +++ b/src/util/Constants.js @@ -16,7 +16,7 @@ * protocol_version: 6, * max_message_cache: 200, * rest_ws_bridge_timeout: 5000, - * api_request_method: 'sequential', + * api_request_method: 'sequential', // can be sequential or burst * shard_id: 0, * shard_count: 0, * fetch_all_members: false, diff --git a/test/random.js b/test/random.js index d1bf6a914..f487eb6b9 100644 --- a/test/random.js +++ b/test/random.js @@ -4,7 +4,7 @@ const Discord = require('../'); const request = require('superagent'); const fs = require('fs'); -const client = new Discord.Client({ fetch_all_members: false }); +const client = new Discord.Client({ fetch_all_members: false, api_request_method: 'burst' }); const { email, password, token } = require('./auth.json'); @@ -134,7 +134,7 @@ client.on('message', msg => { msg.channel.guild.channels.get(chan).join() .then(conn => { msg.reply('done'); - disp = conn.player.playStream(ytdl('https://www.youtube.com/watch?v=nbXgHAzUWB0', {filter : 'audioonly'})); + disp = conn.player.playStream(ytdl('https://www.youtube.com/watch?v=dc-nyGo0aC8', {filter : 'audioonly'})); conn.player.on('debug', console.log); conn.player.on('error', err => console.log(123, err)); disp.on('error', err => console.log(123, err));