Create blob backed up by filesystem (#55)

* create a blob backed up by filesystem
* added code coverage test for filesystem blobs
* updated readme for using filesystem
* install peer dep
* added from to files array in package.json
This commit is contained in:
Jimmy Wärting
2020-07-28 17:42:31 +02:00
committed by GitHub
parent ae6b565ae6
commit 3217da9bc7
5 changed files with 98 additions and 1 deletions
+1
View File
@@ -47,6 +47,7 @@ jobs:
node-version: ${{steps.get-version.outputs.node}}
- run: npm install
- run: npm install domexception
- run: npm run report -- --colors
+18
View File
@@ -27,6 +27,24 @@ fetch('https://httpbin.org/post', {
.then(json => console.log(json));
```
### Blob part backed up by filesystem
To use, install [domexception](https://github.com/jsdom/domexception).
```sh
npm install fetch-blob domexception
```
```js
const blobFrom = require('fetch-blob/from.js');
const blob1 = blobFrom('./2-GiB-file.bin');
const blob2 = blobFrom('./2-GiB-file.bin');
// Not a 4 GiB memory snapshot, just holds 3 references
// points to where data is located on the disk
const blob = new Blob([blob1, blob2]);
console.log(blob.size) // 4 GiB
```
See the [MDN documentation](https://developer.mozilla.org/en-US/docs/Web/API/Blob) and [tests](https://github.com/node-fetch/fetch-blob/blob/master/test.js) for more details.
[npm-image]: https://flat.badgen.net/npm/v/fetch-blob
+57
View File
@@ -0,0 +1,57 @@
const {statSync, createReadStream} = require('fs');
const Blob = require('.');
const DOMException = require('domexception');
/**
* @param {string} path filepath on the disk
* @returns {Blob}
*/
function blobFrom(path) {
const {size, mtime} = statSync(path);
const blob = new BlobDataItem({path, size, mtime});
return new Blob([blob]);
}
/**
* This is a blob backed up by a file on the disk
* with minium requirement
*
* @private
*/
class BlobDataItem {
constructor(options) {
this.size = options.size;
this.path = options.path;
this.start = options.start;
this.mtime = options.mtime;
}
// Slicing arguments is validated and formated
// by Blob.prototype.slice
slice(start, end) {
return new BlobDataItem({
path: this.path,
start,
mtime: this.mtime,
size: end - start
});
}
stream() {
if (statSync(this.path).mtime > this.mtime) {
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');
}
return createReadStream(this.path, {
start: this.start,
end: this.start + this.size - 1
});
}
get [Symbol.toStringTag]() {
return 'Blob';
}
}
module.exports = blobFrom;
+4 -1
View File
@@ -4,6 +4,7 @@
"description": "A Blob implementation in Node.js, originally from node-fetch.",
"main": "index.js",
"files": [
"from.js",
"index.js",
"index.d.ts"
],
@@ -48,5 +49,7 @@
}
]
},
"dependencies": {}
"peerDependencies": {
"domexception": "^2.0.1"
}
}
+18
View File
@@ -1,5 +1,7 @@
const fs = require('fs');
const test = require('ava');
const Blob = require('.');
const blobFrom = require('./from');
const getStream = require('get-stream');
const {Response} = require('node-fetch');
const {TextDecoder} = require('util');
@@ -142,3 +144,19 @@ test('Blob works with node-fetch Response.text()', async t => {
const text = await response.text();
t.is(text, data);
});
test('blob part backed up by filesystem', async t => {
const blob = blobFrom('./LICENSE');
t.is(await blob.slice(0, 3).text(), 'MIT');
t.is(await blob.slice(4, 11).text(), 'License');
});
test('Reading after modified should fail', async t => {
const blob = blobFrom('./LICENSE');
await new Promise(resolve => setTimeout(resolve, 100));
const now = new Date();
// Change modified time
fs.utimesSync('./LICENSE', now, now);
const error = await blob.text().catch(error => error);
t.is(error.name, 'NotReadableError');
});