@@ -70,7 +70,8 @@ func (s *Session) request(method, urlStr, contentType string, b []byte, bucketID
70
70
if bucketID == "" {
71
71
bucketID = strings .SplitN (urlStr , "?" , 2 )[0 ]
72
72
}
73
- return s .RequestWithLockedBucket (method , urlStr , contentType , b , s .Ratelimiter .LockBucket (bucketID ))
73
+
74
+ return s .RequestWithBucket (method , urlStr , contentType , b , s .Ratelimiter .GetBucket (bucketID ))
74
75
}
75
76
76
77
type ReaderWithMockClose struct {
@@ -82,17 +83,12 @@ func (rwmc *ReaderWithMockClose) Close() error {
82
83
}
83
84
84
85
// RequestWithLockedBucket makes a request using a bucket that's already been locked
85
- func (s * Session ) RequestWithLockedBucket (method , urlStr , contentType string , b []byte , bucket * Bucket ) (response []byte , err error ) {
86
+ func (s * Session ) RequestWithBucket (method , urlStr , contentType string , b []byte , bucket * Bucket ) (response []byte , err error ) {
86
87
87
88
for i := 0 ; i < s .MaxRestRetries ; i ++ {
88
- if i != 0 {
89
- // bucket is unlocked during retry downtimes, lock it here again
90
- s .Ratelimiter .LockBucketObject (bucket )
91
- }
92
-
93
89
var retry bool
94
90
var ratelimited bool
95
- response , retry , ratelimited , err = s .doRequestLockedBucket (method , urlStr , contentType , b , bucket )
91
+ response , retry , ratelimited , err = s .doRequest (method , urlStr , contentType , b , bucket )
96
92
if ! retry {
97
93
break
98
94
}
@@ -114,58 +110,14 @@ const (
114
110
CtxKeyRatelimitBucket CtxKey = iota
115
111
)
116
112
117
- // RequestWithLockedBucket makes a request using a bucket that's already been locked
118
- func (s * Session ) doRequestLockedBucket (method , urlStr , contentType string , b []byte , bucket * Bucket ) (response []byte , retry bool , ratelimitRetry bool , err error ) {
119
- if s .Debug {
120
- log .Printf ("API REQUEST %8s :: %s\n " , method , urlStr )
121
- log .Printf ("API REQUEST PAYLOAD :: [%s]\n " , string (b ))
122
- }
113
+ // doRequest makes a request using a bucket
114
+ func (s * Session ) doRequest (method , urlStr , contentType string , b []byte , bucket * Bucket ) (response []byte , retry bool , ratelimitRetry bool , err error ) {
123
115
124
116
if atomic .LoadInt32 (s .tokenInvalid ) != 0 {
125
117
return nil , false , false , ErrTokenInvalid
126
118
}
127
119
128
- req , err := http .NewRequest (method , urlStr , bytes .NewReader (b ))
129
- if err != nil {
130
- bucket .Release (nil )
131
- return
132
- }
133
-
134
- req .GetBody = func () (io.ReadCloser , error ) {
135
- return & ReaderWithMockClose {bytes .NewReader (b )}, nil
136
- }
137
-
138
- // Not used on initial login..
139
- // TODO: Verify if a login, otherwise complain about no-token
140
- if s .Token != "" {
141
- req .Header .Set ("authorization" , s .Token )
142
- }
143
-
144
- // Discord's API returns a 400 Bad Request is Content-Type is set, but the
145
- // request body is empty.
146
- if b != nil {
147
- req .Header .Set ("Content-Type" , contentType )
148
- }
149
-
150
- // TODO: Make a configurable static variable.
151
- req .Header .Set ("User-Agent" , fmt .Sprintf ("DiscordBot (https://github.com/jonas747/discordgo, v%s)" , VERSION ))
152
- req .Header .Set ("X-RateLimit-Precision" , "millisecond" )
153
-
154
- // for things such as stats collecting in the roundtripper for example
155
- ctx := context .WithValue (req .Context (), CtxKeyRatelimitBucket , bucket )
156
- req = req .WithContext (ctx )
157
-
158
- if s .Debug {
159
- for k , v := range req .Header {
160
- log .Printf ("API REQUEST HEADER :: [%s] = %+v\n " , k , v )
161
- }
162
- }
163
-
164
- resp , err := s .Client .Do (req )
165
- if err != nil {
166
- bucket .Release (nil )
167
- return nil , true , false , err
168
- }
120
+ req , resp , err := s .innerDoRequest (method , urlStr , contentType , b , bucket )
169
121
170
122
defer func () {
171
123
err2 := resp .Body .Close ()
@@ -174,11 +126,6 @@ func (s *Session) doRequestLockedBucket(method, urlStr, contentType string, b []
174
126
}
175
127
}()
176
128
177
- err = bucket .Release (resp .Header )
178
- if err != nil {
179
- return
180
- }
181
-
182
129
response , err = ioutil .ReadAll (resp .Body )
183
130
if err != nil {
184
131
return nil , true , false , err
@@ -242,6 +189,63 @@ func (s *Session) doRequestLockedBucket(method, urlStr, contentType string, b []
242
189
return
243
190
}
244
191
192
+ func (s * Session ) innerDoRequest (method , urlStr , contentType string , b []byte , bucket * Bucket ) (* http.Request , * http.Response , error ) {
193
+ bucketLockID := s .Ratelimiter .LockBucketObject (bucket )
194
+ defer func () {
195
+ err := bucket .Release (nil , bucketLockID )
196
+ if err != nil {
197
+ s .log (LogError , "failed unlocking ratelimit bucket: %v" , err )
198
+ }
199
+ }()
200
+
201
+ if s .Debug {
202
+ log .Printf ("API REQUEST %8s :: %s\n " , method , urlStr )
203
+ log .Printf ("API REQUEST PAYLOAD :: [%s]\n " , string (b ))
204
+ }
205
+
206
+ req , err := http .NewRequest (method , urlStr , bytes .NewReader (b ))
207
+ if err != nil {
208
+ return nil , nil , err
209
+ }
210
+
211
+ req .GetBody = func () (io.ReadCloser , error ) {
212
+ return & ReaderWithMockClose {bytes .NewReader (b )}, nil
213
+ }
214
+
215
+ // Not used on initial login..
216
+ // TODO: Verify if a login, otherwise complain about no-token
217
+ if s .Token != "" {
218
+ req .Header .Set ("authorization" , s .Token )
219
+ }
220
+
221
+ // Discord's API returns a 400 Bad Request is Content-Type is set, but the
222
+ // request body is empty.
223
+ if b != nil {
224
+ req .Header .Set ("Content-Type" , contentType )
225
+ }
226
+
227
+ // TODO: Make a configurable static variable.
228
+ req .Header .Set ("User-Agent" , fmt .Sprintf ("DiscordBot (https://github.com/jonas747/discordgo, v%s)" , VERSION ))
229
+ req .Header .Set ("X-RateLimit-Precision" , "millisecond" )
230
+
231
+ // for things such as stats collecting in the roundtripper for example
232
+ ctx := context .WithValue (req .Context (), CtxKeyRatelimitBucket , bucket )
233
+ req = req .WithContext (ctx )
234
+
235
+ if s .Debug {
236
+ for k , v := range req .Header {
237
+ log .Printf ("API REQUEST HEADER :: [%s] = %+v\n " , k , v )
238
+ }
239
+ }
240
+
241
+ resp , err := s .Client .Do (req )
242
+ if err == nil {
243
+ err = bucket .Release (resp .Header , bucketLockID )
244
+ }
245
+
246
+ return req , resp , err
247
+ }
248
+
245
249
func unmarshal (data []byte , v interface {}) error {
246
250
err := json .Unmarshal (data , v )
247
251
return err
0 commit comments