mirror of
https://github.com/discordjs/discord.js.git
synced 2026-03-17 03:53: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:
@@ -48,8 +48,8 @@
|
|||||||
"unpkg": "./webpack/discord.min.js",
|
"unpkg": "./webpack/discord.min.js",
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"@discordjs/collection": "^0.1.5",
|
"@discordjs/collection": "^0.1.5",
|
||||||
|
"@discordjs/form-data": "^3.0.1",
|
||||||
"abort-controller": "^3.0.0",
|
"abort-controller": "^3.0.0",
|
||||||
"form-data": "^3.0.0",
|
|
||||||
"node-fetch": "^2.6.0",
|
"node-fetch": "^2.6.0",
|
||||||
"prism-media": "^1.2.0",
|
"prism-media": "^1.2.0",
|
||||||
"setimmediate": "^1.0.5",
|
"setimmediate": "^1.0.5",
|
||||||
|
|||||||
@@ -1,8 +1,8 @@
|
|||||||
'use strict';
|
'use strict';
|
||||||
|
|
||||||
const https = require('https');
|
const https = require('https');
|
||||||
|
const FormData = require('@discordjs/form-data');
|
||||||
const AbortController = require('abort-controller');
|
const AbortController = require('abort-controller');
|
||||||
const FormData = require('form-data');
|
|
||||||
const fetch = require('node-fetch');
|
const fetch = require('node-fetch');
|
||||||
const { browser, UserAgent } = require('../util/Constants');
|
const { browser, UserAgent } = require('../util/Constants');
|
||||||
|
|
||||||
|
|||||||
@@ -2,6 +2,7 @@
|
|||||||
|
|
||||||
const fs = require('fs');
|
const fs = require('fs');
|
||||||
const path = require('path');
|
const path = require('path');
|
||||||
|
const stream = require('stream');
|
||||||
const fetch = require('node-fetch');
|
const fetch = require('node-fetch');
|
||||||
const { Error: DiscordError, TypeError } = require('../errors');
|
const { Error: DiscordError, TypeError } = require('../errors');
|
||||||
const { browser } = require('../util/Constants');
|
const { browser } = require('../util/Constants');
|
||||||
@@ -45,7 +46,7 @@ class DataResolver {
|
|||||||
if (typeof image === 'string' && image.startsWith('data:')) {
|
if (typeof image === 'string' && image.startsWith('data:')) {
|
||||||
return image;
|
return image;
|
||||||
}
|
}
|
||||||
const file = await this.resolveFile(image);
|
const file = await this.resolveFileAsBuffer(image);
|
||||||
return DataResolver.resolveBase64(file);
|
return DataResolver.resolveBase64(file);
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -79,42 +80,47 @@ class DataResolver {
|
|||||||
* @see {@link https://nodejs.org/api/stream.html}
|
* @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.
|
* Resolves a BufferResolvable to a Buffer.
|
||||||
* @param {BufferResolvable|Stream} resource The buffer or stream resolvable to resolve
|
* @param {BufferResolvable|Stream} resource The buffer or stream resolvable to resolve
|
||||||
* @returns {Promise<Buffer>}
|
* @returns {Promise<Buffer>}
|
||||||
*/
|
*/
|
||||||
static resolveFile(resource) {
|
static async resolveFileAsBuffer(resource) {
|
||||||
if (!browser && Buffer.isBuffer(resource)) return Promise.resolve(resource);
|
const file = await this.resolveFile(resource);
|
||||||
if (browser && resource instanceof ArrayBuffer) return Promise.resolve(Util.convertToBuffer(resource));
|
if (Buffer.isBuffer(file)) return file;
|
||||||
|
|
||||||
if (typeof resource === 'string') {
|
const buffers = [];
|
||||||
if (/^https?:\/\//.test(resource)) {
|
for await (const data of file) buffers.push(data);
|
||||||
return fetch(resource).then(res => (browser ? res.blob() : res.buffer()));
|
return Buffer.concat(buffers);
|
||||||
} 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'));
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
7
typings/index.d.ts
vendored
7
typings/index.d.ts
vendored
@@ -11,10 +11,10 @@ declare enum ChannelType {
|
|||||||
|
|
||||||
declare module 'discord.js' {
|
declare module 'discord.js' {
|
||||||
import BaseCollection from '@discordjs/collection';
|
import BaseCollection from '@discordjs/collection';
|
||||||
import { EventEmitter } from 'events';
|
|
||||||
import { Stream, Readable, Writable } from 'stream';
|
|
||||||
import { ChildProcess } from 'child_process';
|
import { ChildProcess } from 'child_process';
|
||||||
|
import { EventEmitter } from 'events';
|
||||||
import { PathLike } from 'fs';
|
import { PathLike } from 'fs';
|
||||||
|
import { Readable, Stream, Writable } from 'stream';
|
||||||
import * as WebSocket from 'ws';
|
import * as WebSocket from 'ws';
|
||||||
|
|
||||||
export const version: string;
|
export const version: string;
|
||||||
@@ -539,7 +539,8 @@ declare module 'discord.js' {
|
|||||||
|
|
||||||
export class DataResolver {
|
export class DataResolver {
|
||||||
public static resolveBase64(data: Base64Resolvable): string;
|
public static resolveBase64(data: Base64Resolvable): string;
|
||||||
public static resolveFile(resource: BufferResolvable | Stream): Promise<Buffer>;
|
public static resolveFile(resource: BufferResolvable | Stream): Promise<Buffer | Stream>;
|
||||||
|
public static resolveFileAsBuffer(resource: BufferResolvable | Stream): Promise<Buffer>;
|
||||||
public static resolveImage(resource: BufferResolvable | Base64Resolvable): Promise<string>;
|
public static resolveImage(resource: BufferResolvable | Base64Resolvable): Promise<string>;
|
||||||
public static resolveInviteCode(data: InviteResolvable): string;
|
public static resolveInviteCode(data: InviteResolvable): string;
|
||||||
}
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user