16
16
use Discord \Exceptions \Rest \NoPermissionsException ;
17
17
use Discord \Exceptions \Rest \NotFoundException ;
18
18
use Discord \Parts \Channel \Channel ;
19
+ use Exception ;
19
20
use GuzzleHttp \Psr7 \Response ;
20
21
use Illuminate \Support \Str ;
21
22
use React \Promise \Deferred ;
@@ -46,7 +47,7 @@ class Http
46
47
private $ token ;
47
48
48
49
/**
49
- * @var string
50
+ * @var
50
51
*/
51
52
private $ version ;
52
53
@@ -107,20 +108,27 @@ public function __call(string $name, array $params): PromiseInterface
107
108
*
108
109
* @param string $method The request method.
109
110
* @param string $url The endpoint that will be queried.
110
- * @param array|null $content Parameters that will be encoded into JSON and sent with the request.
111
+ * @param array $content Parameters that will be encoded into JSON and sent with the request.
8000
111
112
* @param array $extraHeaders Extra headers to send with the request.
112
113
* @param bool|int|null $cache If an integer is passed, used as cache TTL, if null is passed, default TTL is
113
114
* used, if false, cache is disabled
114
115
* @param array $options Array of options to pass to Guzzle.
115
116
*
117
+ * @throws ContentTooLongException
118
+ * @throws DiscordRequestFailedException
119
+ * @throws NoPermissionsException
120
+ * @throws NotFoundException
121
+ *
116
122
* @return PromiseInterface
117
123
*/
118
- private function runRequest (string $ method , string $ url , ? array $ content , array $ extraHeaders , $ cache , array $ options ): PromiseInterface
124
+ private function runRequest ($ method , $ url , $ content , $ extraHeaders , $ cache , $ options ): PromiseInterface
119
125
{
120
126
$ deferred = new Deferred ();
121
127
$ disable_json = false ;
122
128
123
- $ header ['User-Agent ' ] = $ this ->getUserAgent ();
129
+ $ headers = [
130
+ 'User-Agent ' => $ this ->getUserAgent (),
131
+ ];
124
132
125
133
if (! isset ($ options ['multipart ' ])) {
126
134
$ headers ['Content-Length ' ] = 0 ;
@@ -183,20 +191,24 @@ function ($content) use ($deferred) {
183
191
/**
184
192
* Uploads a file to a channel.
185
193
*
186
- * @param Channel $channel The channel to send to.
187
- * @param string $filepath The path to the file.
188
- * @param string $filename The name to upload the file as.
189
- * @param string|null $content Extra text content to go with the file.
190
- * @param bool $tts Whether the message should be TTS.
194
+ * @param Channel $channel The channel to send to.
195
+ * @param string $filepath The path to the file.
196
+ * @param string $filename The name to upload the file as.
197
+ * @param string $content Extra text content to go with the file.
198
+ * @param bool $tts Whether the message should be TTS.
191
199
*
192
200
* @return PromiseInterface
193
201
*/
194
- public function sendFile (Channel $ channel , string $ filepath , string $ filename , ? string $ content , bool $ tts = false ): PromiseInterface
202
+ public function sendFile (Channel $ channel , $ filepath , $ filename , $ content , $ tts ): PromiseInterface
195
203
{
204
+ $ deferred = new Deferred ();
205
+
206
+ $ boundary = '----DiscordPHPSendFileBoundary ' ;
207
+ $ body = '' ;
196
208
$ multipart = [
197
209
[
198
210
'name ' => 'file ' ,
199
- 'contents ' => fopen ($ filepath, ' r ' ),
211
+ 'contents ' => file_get_contents ($ filepath ),
200
212
'filename ' => $ filename ,
201
213
],
202
214
[
@@ -205,18 +217,88 @@ public function sendFile(Channel $channel, string $filepath, string $filename, ?
205
217
],
206
218
[
207
219
'name ' => 'content ' ,
208
- 'contents ' => $ content ,
220
+ 'contents ' => ( string ) $ content ,
209
221
],
210
222
];
211
223
212
- return $ this ->runRequest (
6D40
div>
224
+ $ body = $ this ->arrayToMultipart ($ multipart , $ boundary );
225
+ $ headers = [
226
+ 'Content-Type ' => 'multipart/form-data; boundary= ' .substr ($ boundary , 2 ),
227
+ 'Content-Length ' => strlen ($ body ),
228
+ 'authorization ' => $ this ->token ,
229
+ 'User-Agent ' => $ this ->getUserAgent (),
230
+ ];
231
+
232
+ $ this ->driver ->runRequest (
213
233
'POST ' ,
214
234
"channels/ {$ channel ->id }/messages " ,
215
- null ,
216
- [],
217
- false ,
218
- ['multipart ' => $ multipart ]
235
+ $ headers ,
236
+ $ body
237
+ )->then (
238
+ function ($ response ) use ($ deferred ) {
239
+ $ json = json_decode ($ response ->getBody ());
240
+ $ deferred ->resolve ($ json );
241
+ },
242
+ function ($ e ) use ($ deferred , $ channel ) {
243
+ if (! ($ e instanceof \Exception)) {
244
+ if (is_callable ([$ e , 'getStatusCode ' ])) {
245
+ $ e = $ this ->handleError (
246
+ $ e ->getStatusCode (),
247
+ $ e ->getReasonPhrase (),
248
+ $ e ->getBody (),
249
+ "channels/ {$ channel ->id }/messages "
250
+ );
251
+ } else {
252
+ $ e = $ this ->handleError (
253
+ 0 ,
254
+ 'unknown ' ,
255
+ 'unknown ' ,
256
+ "channels/ {$ channel ->id }/messages "
257
+ );
258
+ }
259
+ }
260
+
261
+ $ deferred ->reject ($ e );
262
+ }
219
263
);
264
+
265
+ return $ deferred ->promise ();
266
+ }
267
+
268
+ /**
269
+ * Converts an array of key => value to a multipart body.
270
+ *
271
+ * @param array $multipart
272
+ * @param string $boundary
273
+ *
274
+ * @return string
275
+ */
276
+ private function arrayToMultipart (array $ multipart , string $ boundary ): string
277
+ {
278
+ $ body = '' ;
279
+
280
+ foreach ($ multipart as $ part ) {
281
+ $ body .= $ boundary ."\n" ;
282
+ $ body .= 'Content-Disposition: form-data; name=" ' .$ part ['name ' ].'" ' ;
283
+
284
+ if (isset ($ part ['filename ' ])) {
285
+ $ body .= '; filename=" ' .$ part ['filename ' ].'" ' ;
286
+ }
287
+
288
+ $ body .= "\n" ;
289
+
290
+ if (isset ($ part ['headers ' ])) {
291
+ foreach ($ part ['headers ' ] as $ header => $ val ) {
292
+ $ body .= $ header .': ' .$ val ."\n" ;
293
+ }
294
+ }
295
+
296
+ $ body .= "\n" .$ part ['contents ' ]."\n" ;
297
+ }
298
+
299
+ $ body .= $ boundary ."-- \n" ;
300
+
301
+ return $ body ;
220
302
}
221
303
222
304
/**
@@ -227,9 +309,14 @@ public function sendFile(Channel $channel, string $filepath, string $filename, ?
227
309
* @param string $content The HTTP response content.
228
310
* @param string $url The HTTP url.
229
311
*
230
- * @return DiscordRequestFailedException Returned when the request fails.
312
+ * @return \Discord\Exceptions\DiscordRequestFailedException Returned when the request fails.
313
+ * @return \Discord\Exceptions\Rest\ContentTooLongException Returned when the content is longer than 2000
314
+ * characters.
315
+ * @return \Discord\Exceptions\Rest\NotFoundException Returned when the server returns 404 Not Found.
316
+ * @return \Discord\Exceptions\Rest\NoPermissionsException Returned when you do not have permissions to do
317
+ * something.
231
318
*/
232
- public function handleError (int $ errorCode , $ message , string $ content , string $ url ): DiscordRequestFailedException
319
+ public function handleError ($ errorCode , $ message , $ content , $ url ): Exception
233
320
{
234
321
if (! is_string ($ message )) {
235
322
$ message = $ message ->getReasonPhrase ();
0 commit comments