Initial commit

master
Sven Slootweg 3 years ago
commit f4004c035d

@ -0,0 +1,3 @@
{
"extends": "@joepie91/eslint-config"
}

1
.gitignore vendored

@ -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"
}
}

File diff suppressed because it is too large Load Diff
Loading…
Cancel
Save