106 lines
2.7 KiB
JavaScript
106 lines
2.7 KiB
JavaScript
import {statSync, createReadStream, promises as fs} from 'fs';
|
|
import {basename} from 'path';
|
|
import {MessageChannel} from 'worker_threads';
|
|
|
|
import File from './file.js';
|
|
import Blob from './index.js';
|
|
|
|
const {stat} = fs;
|
|
|
|
const DOMException = globalThis.DOMException || (() => {
|
|
const port = new MessageChannel().port1
|
|
const ab = new ArrayBuffer(0)
|
|
try { port.postMessage(ab, [ab, ab]) }
|
|
catch (err) { return err.constructor }
|
|
})()
|
|
|
|
/**
|
|
* @param {string} path filepath on the disk
|
|
* @param {string} [type] mimetype to use
|
|
*/
|
|
const blobFromSync = (path, type) => fromBlob(statSync(path), path, type);
|
|
|
|
/**
|
|
* @param {string} path filepath on the disk
|
|
* @param {string} [type] mimetype to use
|
|
*/
|
|
const blobFrom = (path, type) => stat(path).then(stat => fromBlob(stat, path, type));
|
|
|
|
/**
|
|
* @param {string} path filepath on the disk
|
|
* @param {string} [type] mimetype to use
|
|
*/
|
|
const fileFrom = (path, type) => stat(path).then(stat => fromFile(stat, path, type));
|
|
|
|
/**
|
|
* @param {string} path filepath on the disk
|
|
* @param {string} [type] mimetype to use
|
|
*/
|
|
const fileFromSync = (path, type) => fromFile(statSync(path), path, type);
|
|
|
|
// @ts-ignore
|
|
const fromBlob = (stat, path, type = '') => new Blob([new BlobDataItem({
|
|
path,
|
|
size: stat.size,
|
|
lastModified: stat.mtimeMs,
|
|
start: 0
|
|
})], {type});
|
|
|
|
// @ts-ignore
|
|
const fromFile = (stat, path, type = '') => new File([new BlobDataItem({
|
|
path,
|
|
size: stat.size,
|
|
lastModified: stat.mtimeMs,
|
|
start: 0
|
|
})], basename(path), { type, lastModified: stat.mtimeMs });
|
|
|
|
/**
|
|
* This is a blob backed up by a file on the disk
|
|
* with minium requirement. Its wrapped around a Blob as a blobPart
|
|
* so you have no direct access to this.
|
|
*
|
|
* @private
|
|
*/
|
|
class BlobDataItem {
|
|
#path;
|
|
#start;
|
|
|
|
constructor(options) {
|
|
this.#path = options.path;
|
|
this.#start = options.start;
|
|
this.size = options.size;
|
|
this.lastModified = options.lastModified
|
|
}
|
|
|
|
/**
|
|
* Slicing arguments is first validated and formatted
|
|
* to not be out of range by Blob.prototype.slice
|
|
*/
|
|
slice(start, end) {
|
|
return new BlobDataItem({
|
|
path: this.#path,
|
|
lastModified: this.lastModified,
|
|
size: end - start,
|
|
start
|
|
});
|
|
}
|
|
|
|
async * stream() {
|
|
const {mtimeMs} = await stat(this.#path)
|
|
if (mtimeMs > this.lastModified) {
|
|
throw new DOMException('The requested file could not be read, typically due to permission problems that have occurred after a reference to a file was acquired.', 'NotReadableError');
|
|
}
|
|
yield * createReadStream(this.#path, {
|
|
start: this.#start,
|
|
end: this.#start + this.size - 1
|
|
});
|
|
}
|
|
|
|
get [Symbol.toStringTag]() {
|
|
return 'Blob';
|
|
}
|
|
}
|
|
|
|
export default blobFromSync;
|
|
export {File, Blob, blobFrom, blobFromSync, fileFrom, fileFromSync};
|