buddy

node MVC discord bot
Log | Files | Refs | README

DataResolver.js (3907B)


      1 'use strict';
      2 
      3 const fs = require('fs');
      4 const path = require('path');
      5 const stream = require('stream');
      6 const fetch = require('node-fetch');
      7 const { Error: DiscordError, TypeError } = require('../errors');
      8 const { browser } = require('../util/Constants');
      9 const Util = require('../util/Util');
     10 
     11 /**
     12  * The DataResolver identifies different objects and tries to resolve a specific piece of information from them.
     13  * @private
     14  */
     15 class DataResolver {
     16   constructor() {
     17     throw new Error(`The ${this.constructor.name} class may not be instantiated.`);
     18   }
     19 
     20   /**
     21    * Data that can be resolved to give an invite code. This can be:
     22    * * An invite code
     23    * * An invite URL
     24    * @typedef {string} InviteResolvable
     25    */
     26 
     27   /**
     28    * Resolves InviteResolvable to an invite code.
     29    * @param {InviteResolvable} data The invite resolvable to resolve
     30    * @returns {string}
     31    */
     32   static resolveInviteCode(data) {
     33     const inviteRegex = /discord(?:app\.com\/invite|\.gg(?:\/invite)?)\/([\w-]{2,255})/i;
     34     const match = inviteRegex.exec(data);
     35     if (match && match[1]) return match[1];
     36     return data;
     37   }
     38 
     39   /**
     40    * Resolves a Base64Resolvable, a string, or a BufferResolvable to a Base 64 image.
     41    * @param {BufferResolvable|Base64Resolvable} image The image to be resolved
     42    * @returns {Promise<?string>}
     43    */
     44   static async resolveImage(image) {
     45     if (!image) return null;
     46     if (typeof image === 'string' && image.startsWith('data:')) {
     47       return image;
     48     }
     49     const file = await this.resolveFileAsBuffer(image);
     50     return DataResolver.resolveBase64(file);
     51   }
     52 
     53   /**
     54    * Data that resolves to give a Base64 string, typically for image uploading. This can be:
     55    * * A Buffer
     56    * * A base64 string
     57    * @typedef {Buffer|string} Base64Resolvable
     58    */
     59 
     60   /**
     61    * Resolves a Base64Resolvable to a Base 64 image.
     62    * @param {Base64Resolvable} data The base 64 resolvable you want to resolve
     63    * @returns {?string}
     64    */
     65   static resolveBase64(data) {
     66     if (Buffer.isBuffer(data)) return `data:image/jpg;base64,${data.toString('base64')}`;
     67     return data;
     68   }
     69 
     70   /**
     71    * Data that can be resolved to give a Buffer. This can be:
     72    * * A Buffer
     73    * * The path to a local file
     74    * * A URL
     75    * @typedef {string|Buffer} BufferResolvable
     76    */
     77 
     78   /**
     79    * @external Stream
     80    * @see {@link https://nodejs.org/api/stream.html}
     81    */
     82 
     83   /**
     84    * Resolves a BufferResolvable to a Buffer or a Stream.
     85    * @param {BufferResolvable|Stream} resource The buffer or stream resolvable to resolve
     86    * @returns {Promise<Buffer|Stream>}
     87    */
     88   static async resolveFile(resource) {
     89     if (!browser && Buffer.isBuffer(resource)) return resource;
     90     if (browser && resource instanceof ArrayBuffer) return Util.convertToBuffer(resource);
     91     if (resource instanceof stream.Readable) return resource;
     92 
     93     if (typeof resource === 'string') {
     94       if (/^https?:\/\//.test(resource)) {
     95         const res = await fetch(resource);
     96         return browser ? res.blob() : res.body;
     97       } else if (!browser) {
     98         return new Promise((resolve, reject) => {
     99           const file = path.resolve(resource);
    100           fs.stat(file, (err, stats) => {
    101             if (err) return reject(err);
    102             if (!stats.isFile()) return reject(new DiscordError('FILE_NOT_FOUND', file));
    103             return resolve(fs.createReadStream(file));
    104           });
    105         });
    106       }
    107     }
    108 
    109     throw new TypeError('REQ_RESOURCE_TYPE');
    110   }
    111 
    112   /**
    113    * Resolves a BufferResolvable to a Buffer.
    114    * @param {BufferResolvable|Stream} resource The buffer or stream resolvable to resolve
    115    * @returns {Promise<Buffer>}
    116    */
    117   static async resolveFileAsBuffer(resource) {
    118     const file = await this.resolveFile(resource);
    119     if (Buffer.isBuffer(file)) return file;
    120 
    121     const buffers = [];
    122     for await (const data of file) buffers.push(data);
    123     return Buffer.concat(buffers);
    124   }
    125 }
    126 
    127 module.exports = DataResolver;