11'use strict' ;
22
3+ const AsyncQueue = require ( './AsyncQueue' ) ;
34const DiscordAPIError = require ( './DiscordAPIError' ) ;
45const HTTPError = require ( './HTTPError' ) ;
56const {
@@ -25,46 +26,31 @@ function calculateReset(reset, serverDate) {
2526class RequestHandler {
2627 constructor ( manager ) {
2728 this . manager = manager ;
28- this . busy = false ;
29- this . queue = [ ] ;
29+ this . queue = new AsyncQueue ( ) ;
3030 this . reset = - 1 ;
3131 this . remaining = - 1 ;
3232 this . limit = - 1 ;
3333 this . retryAfter = - 1 ;
3434 }
3535
36- push ( request ) {
37- if ( this . busy ) {
38- this . queue . push ( request ) ;
39- return this . run ( ) ;
40- } else {
41- return this . execute ( request ) ;
36+ async push ( request ) {
37+ await this . queue . wait ( ) ;
38+ try {
39+ return await this . execute ( request ) ;
40+ } finally {
41+ this . queue . shift ( ) ;
4242 }
4343 }
4444
45- run ( ) {
46- if ( this . queue . length === 0 ) return Promise . resolve ( ) ;
47- return this . execute ( this . queue . shift ( ) ) ;
48- }
49-
5045 get limited ( ) {
5146 return Boolean ( this . manager . globalTimeout ) || ( this . remaining <= 0 && Date . now ( ) < this . reset ) ;
5247 }
5348
5449 get _inactive ( ) {
55- return this . queue . length === 0 && ! this . limited && this . busy !== true ;
50+ return this . queue . remaining === 0 && ! this . limited ;
5651 }
5752
58- async execute ( item ) {
59- // Insert item back to the beginning if currently busy
60- if ( this . busy ) {
61- this . queue . unshift ( item ) ;
62- return null ;
63- }
64-
65- this . busy = true ;
66- const { reject, request, resolve } = item ;
67-
53+ async execute ( request ) {
6854 // After calculations and requests have been done, pre-emptively stop further requests
6955 if ( this . limited ) {
7056 const timeout = this . reset + this . manager . client . options . restTimeOffset - Date . now ( ) ;
@@ -103,8 +89,7 @@ class RequestHandler {
10389 res = await request . make ( ) ;
10490 } catch ( error ) {
10591 // NodeFetch error expected for all "operational" errors, such as 500 status code
106- this . busy = false ;
107- return reject ( new HTTPError ( error . message , error . constructor . name , error . status , request . method , request . path ) ) ;
92+ throw new HTTPError ( error . message , error . constructor . name , error . status , request . method , request . path ) ;
10893 }
10994
11095 if ( res && res . headers ) {
@@ -120,7 +105,7 @@ class RequestHandler {
120105 this . retryAfter = retryAfter ? Number ( retryAfter ) : - 1 ;
121106
122107 // https://github.com/discordapp/discord-api-docs/issues/182
123- if ( item . request . route . includes ( 'reactions' ) ) {
108+ if ( request . route . includes ( 'reactions' ) ) {
124109 this . reset = new Date ( serverDate ) . getTime ( ) - getAPIOffset ( serverDate ) + 250 ;
125110 }
126111
@@ -137,42 +122,39 @@ class RequestHandler {
137122 }
138123 }
139124
140- // Finished handling headers, safe to unlock manager
141- this . busy = false ;
142-
143125 if ( res . ok ) {
144- const success = await parseResponse ( res ) ;
145126 // Nothing wrong with the request, proceed with the next one
146- resolve ( success ) ;
147- return this . run ( ) ;
148- } else if ( res . status === 429 ) {
127+ return parseResponse ( res ) ;
128+ }
129+
130+ // Handle ratelimited requests
131+ if ( res . status === 429 ) {
149132 // A ratelimit was hit - this should never happen
150- this . queue . unshift ( item ) ;
151- this . manager . client . emit ( 'debug' , `429 hit on route ${ item . request . route } ` ) ;
133+ this . manager . client . emit ( 'debug' , `429 hit on route ${ request . route } ` ) ;
152134 await Util . delayFor ( this . retryAfter ) ;
153- return this . run ( ) ;
154- } else if ( res . status >= 500 && res . status < 600 ) {
135+ return this . execute ( request ) ;
136+ }
137+
138+ // Handle server errors
139+ if ( res . status >= 500 && res . status < 600 ) {
155140 // Retry the specified number of times for possible serverside issues
156- if ( item . retries === this . manager . client . options . retryLimit ) {
157- return reject (
158- new HTTPError ( res . statusText , res . constructor . name , res . status , item . request . method , request . path ) ,
159- ) ;
160- } else {
161- item . retries ++ ;
162- this . queue . unshift ( item ) ;
163- return this . run ( ) ;
141+ if ( request . retries === this . manager . client . options . retryLimit ) {
142+ throw new HTTPError ( res . statusText , res . constructor . name , res . status , request . method , request . path ) ;
164143 }
165- } else {
166- // Handle possible malformed requests
167- try {
168- const data = await parseResponse ( res ) ;
169- if ( res . status >= 400 && res . status < 500 ) {
170- return reject ( new DiscordAPIError ( request . path , data , request . method , res . status ) ) ;
171- }
172- return null ;
173- } catch ( err ) {
174- return reject ( new HTTPError ( err . message , err . constructor . name , err . status , request . method , request . path ) ) ;
144+
145+ request . retries ++ ;
146+ return this . execute ( request ) ;
147+ }
148+
149+ // Handle possible malformed requests
150+ try {
151+ const data = await parseResponse ( res ) ;
152+ if ( res . status >= 400 && res . status < 500 ) {
153+ throw new DiscordAPIError ( request . path , data , request . method , res . status ) ;
175154 }
155+ return null ;
156+ } catch ( err ) {
157+ throw new HTTPError ( err . message , err . constructor . name , err . status , request . method , request . path ) ;
176158 }
177159 }
178160}
0 commit comments