Initial commit
commit
f4004c035d
@ -0,0 +1 @@
|
|||||||
|
node_modules
|
@ -0,0 +1,28 @@
|
|||||||
|
"use strict";
|
||||||
|
|
||||||
|
const Promise = require("bluebird");
|
||||||
|
const path = require("path");
|
||||||
|
const errorChain = require("error-chain");
|
||||||
|
|
||||||
|
const pipe = require("@promistream/pipe");
|
||||||
|
const fromNodeStream = require("@promistream/from-node-stream");
|
||||||
|
const map = require("@promistream/map");
|
||||||
|
const join = require("@promistream/join");
|
||||||
|
const splitLines = require("@promistream/split-lines");
|
||||||
|
const decodeString = require("@promistream/decode-string");
|
||||||
|
const readFile = require("./");
|
||||||
|
|
||||||
|
return Promise.try(() => {
|
||||||
|
return pipe([
|
||||||
|
readFile(path.join(__dirname, "example.js")),
|
||||||
|
decodeString("utf8"),
|
||||||
|
splitLines(),
|
||||||
|
map((line) => line.trim()),
|
||||||
|
join("\n"),
|
||||||
|
fromNodeStream(process.stdout)
|
||||||
|
]).read();
|
||||||
|
}).then(() => {
|
||||||
|
console.log("Done!");
|
||||||
|
}).catch((error) => {
|
||||||
|
console.error(errorChain.render(error));
|
||||||
|
});
|
@ -0,0 +1,78 @@
|
|||||||
|
"use strict";
|
||||||
|
|
||||||
|
const Promise = require("bluebird");
|
||||||
|
const fs = require("fs").promises;
|
||||||
|
|
||||||
|
const pipe = require("@promistream/pipe");
|
||||||
|
const simpleSource = require("@promistream/simple-source");
|
||||||
|
const sequentialize = require("@promistream/sequentialize");
|
||||||
|
const EndOfStream = require("@promistream/end-of-stream");
|
||||||
|
|
||||||
|
const { validateArguments } = require("@validatem/core");
|
||||||
|
const required = require("@validatem/required");
|
||||||
|
const isString = require("@validatem/is-string");
|
||||||
|
const isNumber = require("@validatem/is-number");
|
||||||
|
const isInteger = require("@validatem/is-integer");
|
||||||
|
const defaultTo = require("@validatem/default-to");
|
||||||
|
const either = require("@validatem/either");
|
||||||
|
const oneOf = require("@validatem/one-of");
|
||||||
|
|
||||||
|
// NOTE: Below read size is derived from the high water mark in core lib/internal/fs/streams.js
|
||||||
|
let defaultChunkSize = 64 * 1024;
|
||||||
|
|
||||||
|
function doRead(handle, length) {
|
||||||
|
// TODO: Can we safely switch to `allocUnsafe` here?
|
||||||
|
let buffer = Buffer.alloc(length);
|
||||||
|
|
||||||
|
return Promise.try(() => {
|
||||||
|
return handle.read(buffer, 0, length);
|
||||||
|
}).then((result) => {
|
||||||
|
if (result.bytesRead === 0) {
|
||||||
|
// Not documented; https://github.com/nodejs/node/issues/35363
|
||||||
|
throw new EndOfStream();
|
||||||
|
} else if (result.bytesRead === length) {
|
||||||
|
return buffer;
|
||||||
|
} else if (result.bytesRead < length) {
|
||||||
|
// TODO: For possible future performance optimization, consider reusing the remaining Buffer allocation for a next read, if possible. Need more data on how often this case occurs first, though, to justify the added complexity.
|
||||||
|
return buffer.slice(0, length);
|
||||||
|
} else {
|
||||||
|
throw new Error(`Read more bytes (${result.bytesRead}) than the specified 'length' (${length}); this should never happen!`);
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
module.exports = function createReadFileStream(_path, _options) {
|
||||||
|
let [ path, options ] = validateArguments(arguments, [
|
||||||
|
[ "path", required, isString ],
|
||||||
|
[ "options", defaultTo({}), {
|
||||||
|
chunkSize: [ isInteger, defaultTo(defaultChunkSize) ],
|
||||||
|
flag: [ defaultTo("r"), oneOf([ "a", "ax", "a+", "ax+", "as", "as+", "r", "r+", "rs+", "w", "wx", "w+", "wx+" ]) ],
|
||||||
|
mode: [ either([ isString, isNumber ]) ] // FIXME: Stricter validation
|
||||||
|
// TODO: start/end
|
||||||
|
}]
|
||||||
|
]);
|
||||||
|
|
||||||
|
let handlePromise = fs.open(path, options.flag, options.mode);
|
||||||
|
|
||||||
|
// TODO: Metadata, including stream label and file size/type/path
|
||||||
|
return pipe([
|
||||||
|
simpleSource({
|
||||||
|
onRequest: () => {
|
||||||
|
return Promise.try(() => {
|
||||||
|
// TODO: Can we optimize this by separately tracking when the open has completed, and replacing the Promise with the actual handle in that case?
|
||||||
|
return handlePromise;
|
||||||
|
}).then((handle) => {
|
||||||
|
return doRead(handle, options.chunkSize);
|
||||||
|
});
|
||||||
|
},
|
||||||
|
onAbort: (_reason) => {
|
||||||
|
return Promise.try(() => {
|
||||||
|
return handlePromise;
|
||||||
|
}).then((handle) => {
|
||||||
|
return handle.close();
|
||||||
|
});
|
||||||
|
}
|
||||||
|
}),
|
||||||
|
sequentialize()
|
||||||
|
]);
|
||||||
|
};
|
@ -0,0 +1,39 @@
|
|||||||
|
{
|
||||||
|
"name": "@promistream/read-file",
|
||||||
|
"version": "0.1.0",
|
||||||
|
"main": "index.js",
|
||||||
|
"keywords": [
|
||||||
|
"promistream"
|
||||||
|
],
|
||||||
|
"repository": "http://git.cryto.net/promistream/read-file.git",
|
||||||
|
"author": "Sven Slootweg <admin@cryto.net>",
|
||||||
|
"license": "WTFPL OR CC0-1.0",
|
||||||
|
"dependencies": {
|
||||||
|
"@promistream/end-of-stream": "^0.1.0",
|
||||||
|
"@promistream/pipe": "^0.1.1",
|
||||||
|
"@promistream/sequentialize": "^0.1.0",
|
||||||
|
"@promistream/simple-source": "^0.1.1",
|
||||||
|
"@validatem/core": "^0.3.11",
|
||||||
|
"@validatem/default-to": "^0.1.0",
|
||||||
|
"@validatem/either": "^0.1.9",
|
||||||
|
"@validatem/error": "^1.1.0",
|
||||||
|
"@validatem/is-integer": "^0.1.0",
|
||||||
|
"@validatem/is-number": "^0.1.3",
|
||||||
|
"@validatem/is-string": "^0.1.1",
|
||||||
|
"@validatem/one-of": "^0.1.1",
|
||||||
|
"@validatem/required": "^0.1.1",
|
||||||
|
"bluebird": "^3.7.2",
|
||||||
|
"default-value": "^1.0.0",
|
||||||
|
"validatem": "^0.2.1"
|
||||||
|
},
|
||||||
|
"devDependencies": {
|
||||||
|
"@joepie91/eslint-config": "^1.1.0",
|
||||||
|
"@promistream/decode-string": "^0.1.0",
|
||||||
|
"@promistream/from-node-stream": "^0.1.1",
|
||||||
|
"@promistream/join": "^0.1.0",
|
||||||
|
"@promistream/map": "^0.1.0",
|
||||||
|
"@promistream/split-lines": "^0.1.0",
|
||||||
|
"error-chain": "^0.1.0",
|
||||||
|
"eslint": "^6.8.0"
|
||||||
|
}
|
||||||
|
}
|
Loading…
Reference in New Issue