Home Manual Reference Source Repository

src/resources/base/DownloadedResource.js

/*
 * BSD 3-Clause License
 *
 * Copyright (c) 2020, Mapcreator
 * All rights reserved.
 *
 * Redistribution and use in source and binary forms, with or without
 * modification, are permitted provided that the following conditions are met:
 *
 *  Redistributions of source code must retain the above copyright notice, this
 *   list of conditions and the following disclaimer.
 *
 *  Redistributions in binary form must reproduce the above copyright notice,
 *   this list of conditions and the following disclaimer in the documentation
 *   and/or other materials provided with the distribution.
 *
 *  Neither the name of the copyright holder nor the names of its
 *   contributors may be used to endorse or promote products derived from
 *   this software without specific prior written permission.
 *
 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
 * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
 * DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE
 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
 * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
 * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
 * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
 * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
 */

import { base64Encode } from '../../utils/base64';
import { isNode } from '../../utils/node';

/**
 * Downloaded resource from the api
 */
export default class DownloadedResource {
  /**
   *
   * @param {ArrayBuffer|Buffer} data - Data
   * @param {string} [type=application/octet-stream] - Mime-type
   * @param {string} [fileName=Untitled] - File name
   */
  constructor (data, type = 'application/octet-stream', fileName = 'Untitled') {
    this._data = data;
    this._type = type;
    this._fileName = fileName;
  }

  /**
   * Build instance from response
   * @param {Response} response - Response
   * @returns {DownloadedResource} - Instance
   */
  static async fromResponse (response) {
    // Get data
    const data = await response.arrayBuffer();

    // Find mimeType
    let mimeType;
    const contentType = response.headers.get('content-type');

    if (contentType) {
      mimeType = contentType.split(';')[0].trim();
    }

    // Extract file name
    let fileName;
    const contentDisposition = response.headers.get('content-disposition');

    if (contentDisposition) {
      const regex = /filename[^;=\n]*=((['"])(.*?)\2|([^;\s]*))/i;
      const matches = regex.exec(contentDisposition);

      if (matches) {
        fileName = matches[3] || matches[4];
      }
    }

    return new DownloadedResource(data, mimeType, fileName);
  }

  /**
   * In Nodejs it will return a {@link Buffer} and in the browser it will respond with a {@link ArrayBuffer}
   * @returns {ArrayBuffer|Buffer} - Resource data
   */
  get data () {
    return this._data;
  }

  /**
   * Resource mime-type
   * @return {string} - Mime-type
   */
  get type () {
    return this._type;
  }

  /**
   * Resource file name, if available
   * @return {string} - File name
   */
  get fileName () {
    return this._fileName;
  }

  /**
   * Get the size of the data
   * @return {Number} - Size in bytes
   */
  get size () {
    return this.data.length;
  }

  /**
   * Create a object url
   * The URL lifetime is tied to the document in the window on which it
   * was created. The new object URL represents the resource.
   * *Do not forget* to release the object urls once used.
   * @see https://developer.mozilla.org/en-US/docs/Web/API/URL/createObjectURL
   * @see https://developer.mozilla.org/en-US/docs/Web/API/URL/createObjectURL#Memory_management
   * @return {string} - Object url
   */
  createObjectUrl () {
    if (isNode()) {
      throw new Error('Object urls are not supported by Node');
    }

    return URL.createObjectURL(this.createBlob());
  }

  /**
   * Create a blob from the resource
   * @returns {Blob}
   */
  createBlob () {
    return new Blob([this.data], { type: this.type });
  }

  /**
   * Get base64-encoded data uri
   * @see https://developer.mozilla.org/en-US/docs/Web/HTTP/Basics_of_HTTP/Data_URIs
   * @returns {string} - Data uri
   */
  toDataUri () {
    return `data:${this.type};base64,${this.toBase64()}`;
  }

  /**
   * Base64 encode data
   * @returns {string} - Base64 encoded data
   */
  toBase64 () {
    return base64Encode(this.data);
  }

  /**
   * @inheritDoc
   */
  toString () {
    return this.data.toString();
  }
}