mirror of
https://github.com/discordjs/discord.js.git
synced 2026-03-11 09:03:29 +01:00
feat(DataResolver): prefer streams over buffers (#4075)
* feat(DataResolver): prefer streams over buffers * feat(DataResolver): add `resolveFileAsBuffer` Add `resolveFileAsBuffer` to use it in `resolveImage` which still requires Buffers to work. * fix(DataResolver): make sure `resolveFile` always returns a Promise * refactor(DataResolver): use for-await-of * fix(DataResolver): use forked form-data which supports custom streams * fix(APIRequest): use forked form-data in code too Co-authored-by: - <5144598+-@users.noreply.github.com> Co-authored-by: SpaceEEC <spaceeec@yahoo.com>
This commit is contained in:
@@ -1,8 +1,8 @@
|
||||
'use strict';
|
||||
|
||||
const https = require('https');
|
||||
const FormData = require('@discordjs/form-data');
|
||||
const AbortController = require('abort-controller');
|
||||
const FormData = require('form-data');
|
||||
const fetch = require('node-fetch');
|
||||
const { browser, UserAgent } = require('../util/Constants');
|
||||
|
||||
|
||||
@@ -2,6 +2,7 @@
|
||||
|
||||
const fs = require('fs');
|
||||
const path = require('path');
|
||||
const stream = require('stream');
|
||||
const fetch = require('node-fetch');
|
||||
const { Error: DiscordError, TypeError } = require('../errors');
|
||||
const { browser } = require('../util/Constants');
|
||||
@@ -45,7 +46,7 @@ class DataResolver {
|
||||
if (typeof image === 'string' && image.startsWith('data:')) {
|
||||
return image;
|
||||
}
|
||||
const file = await this.resolveFile(image);
|
||||
const file = await this.resolveFileAsBuffer(image);
|
||||
return DataResolver.resolveBase64(file);
|
||||
}
|
||||
|
||||
@@ -79,42 +80,47 @@ class DataResolver {
|
||||
* @see {@link https://nodejs.org/api/stream.html}
|
||||
*/
|
||||
|
||||
/**
|
||||
* Resolves a BufferResolvable to a Buffer or a Stream.
|
||||
* @param {BufferResolvable|Stream} resource The buffer or stream resolvable to resolve
|
||||
* @returns {Promise<Buffer|Stream>}
|
||||
*/
|
||||
static async resolveFile(resource) {
|
||||
if (!browser && Buffer.isBuffer(resource)) return resource;
|
||||
if (browser && resource instanceof ArrayBuffer) return Util.convertToBuffer(resource);
|
||||
if (resource instanceof stream.Readable) return resource;
|
||||
|
||||
if (typeof resource === 'string') {
|
||||
if (/^https?:\/\//.test(resource)) {
|
||||
const res = await fetch(resource);
|
||||
return browser ? res.blob() : res.body;
|
||||
} else if (!browser) {
|
||||
return new Promise((resolve, reject) => {
|
||||
const file = path.resolve(resource);
|
||||
fs.stat(file, (err, stats) => {
|
||||
if (err) return reject(err);
|
||||
if (!stats.isFile()) return reject(new DiscordError('FILE_NOT_FOUND', file));
|
||||
return resolve(fs.createReadStream(file));
|
||||
});
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
throw new TypeError('REQ_RESOURCE_TYPE');
|
||||
}
|
||||
|
||||
/**
|
||||
* Resolves a BufferResolvable to a Buffer.
|
||||
* @param {BufferResolvable|Stream} resource The buffer or stream resolvable to resolve
|
||||
* @returns {Promise<Buffer>}
|
||||
*/
|
||||
static resolveFile(resource) {
|
||||
if (!browser && Buffer.isBuffer(resource)) return Promise.resolve(resource);
|
||||
if (browser && resource instanceof ArrayBuffer) return Promise.resolve(Util.convertToBuffer(resource));
|
||||
static async resolveFileAsBuffer(resource) {
|
||||
const file = await this.resolveFile(resource);
|
||||
if (Buffer.isBuffer(file)) return file;
|
||||
|
||||
if (typeof resource === 'string') {
|
||||
if (/^https?:\/\//.test(resource)) {
|
||||
return fetch(resource).then(res => (browser ? res.blob() : res.buffer()));
|
||||
} else if (!browser) {
|
||||
return new Promise((resolve, reject) => {
|
||||
const file = browser ? resource : path.resolve(resource);
|
||||
fs.stat(file, (err, stats) => {
|
||||
if (err) return reject(err);
|
||||
if (!stats.isFile()) return reject(new DiscordError('FILE_NOT_FOUND', file));
|
||||
fs.readFile(file, (err2, data) => {
|
||||
if (err2) reject(err2);
|
||||
else resolve(data);
|
||||
});
|
||||
return null;
|
||||
});
|
||||
});
|
||||
}
|
||||
} else if (typeof resource.pipe === 'function') {
|
||||
return new Promise((resolve, reject) => {
|
||||
const buffers = [];
|
||||
resource.once('error', reject);
|
||||
resource.on('data', data => buffers.push(data));
|
||||
resource.once('end', () => resolve(Buffer.concat(buffers)));
|
||||
});
|
||||
}
|
||||
|
||||
return Promise.reject(new TypeError('REQ_RESOURCE_TYPE'));
|
||||
const buffers = [];
|
||||
for await (const data of file) buffers.push(data);
|
||||
return Buffer.concat(buffers);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
Reference in New Issue
Block a user