peek-readable
Advanced tools
Comparing version 4.0.1 to 4.0.2
@@ -0,0 +0,0 @@ export declare const defaultMessages = "End-Of-Stream"; |
@@ -0,0 +0,0 @@ "use strict"; |
@@ -1,43 +0,2 @@ | ||
/// <reference types="node" /> | ||
import * as stream from 'stream'; | ||
export { EndOfStreamError } from './EndOfFileStream'; | ||
export declare class StreamReader { | ||
private s; | ||
/** | ||
* Deferred read request | ||
*/ | ||
private request; | ||
private endOfStream; | ||
/** | ||
* Store peeked data | ||
* @type {Array} | ||
*/ | ||
private peekQueue; | ||
constructor(s: stream.Readable); | ||
/** | ||
* Read ahead (peek) from stream. Subsequent read or peeks will return the same data | ||
* @param uint8Array - Uint8Array (or Buffer) to store data read from stream in | ||
* @param offset - Offset target | ||
* @param length - Number of bytes to read | ||
* @returns Number of bytes peeked | ||
*/ | ||
peek(uint8Array: Uint8Array, offset: number, length: number): Promise<number>; | ||
/** | ||
* Read chunk from stream | ||
* @param buffer - Target Uint8Array (or Buffer) to store data read from stream in | ||
* @param offset - Offset target | ||
* @param length - Number of bytes to read | ||
* @returns Number of bytes read | ||
*/ | ||
read(buffer: Uint8Array, offset: number, length: number): Promise<number>; | ||
/** | ||
* Read chunk from stream | ||
* @param buffer Target Uint8Array (or Buffer) to store data read from stream in | ||
* @param offset Offset target | ||
* @param length Number of bytes to read | ||
* @returns Number of bytes read | ||
*/ | ||
private _read; | ||
private tryRead; | ||
private reject; | ||
} | ||
export { StreamReader } from './StreamReader'; |
143
lib/index.js
"use strict"; | ||
Object.defineProperty(exports, "__esModule", { value: true }); | ||
exports.StreamReader = exports.EndOfStreamError = void 0; | ||
const EndOfFileStream_1 = require("./EndOfFileStream"); | ||
var EndOfFileStream_2 = require("./EndOfFileStream"); | ||
Object.defineProperty(exports, "EndOfStreamError", { enumerable: true, get: function () { return EndOfFileStream_2.EndOfStreamError; } }); | ||
class Deferred { | ||
constructor() { | ||
this.resolve = () => null; | ||
this.reject = () => null; | ||
this.promise = new Promise((resolve, reject) => { | ||
this.reject = reject; | ||
this.resolve = resolve; | ||
}); | ||
} | ||
} | ||
const maxStreamReadSize = 1 * 1024 * 1024; // Maximum request length on read-stream operation | ||
class StreamReader { | ||
constructor(s) { | ||
this.s = s; | ||
/** | ||
* Deferred read request | ||
*/ | ||
this.request = null; | ||
this.endOfStream = false; | ||
/** | ||
* Store peeked data | ||
* @type {Array} | ||
*/ | ||
this.peekQueue = []; | ||
if (!s.read || !s.once) { | ||
throw new Error('Expected an instance of stream.Readable'); | ||
} | ||
this.s.once('end', () => this.reject(new EndOfFileStream_1.EndOfStreamError())); | ||
this.s.once('error', err => this.reject(err)); | ||
this.s.once('close', () => this.reject(new Error('Stream closed'))); | ||
} | ||
/** | ||
* Read ahead (peek) from stream. Subsequent read or peeks will return the same data | ||
* @param uint8Array - Uint8Array (or Buffer) to store data read from stream in | ||
* @param offset - Offset target | ||
* @param length - Number of bytes to read | ||
* @returns Number of bytes peeked | ||
*/ | ||
async peek(uint8Array, offset, length) { | ||
const bytesRead = await this.read(uint8Array, offset, length); | ||
this.peekQueue.push(uint8Array.subarray(offset, offset + bytesRead)); // Put read data back to peek buffer | ||
return bytesRead; | ||
} | ||
/** | ||
* Read chunk from stream | ||
* @param buffer - Target Uint8Array (or Buffer) to store data read from stream in | ||
* @param offset - Offset target | ||
* @param length - Number of bytes to read | ||
* @returns Number of bytes read | ||
*/ | ||
async read(buffer, offset, length) { | ||
if (length === 0) { | ||
return 0; | ||
} | ||
if (this.peekQueue.length === 0 && this.endOfStream) { | ||
throw new EndOfFileStream_1.EndOfStreamError(); | ||
} | ||
let remaining = length; | ||
let bytesRead = 0; | ||
// consume peeked data first | ||
while (this.peekQueue.length > 0 && remaining > 0) { | ||
const peekData = this.peekQueue.pop(); // Front of queue | ||
if (!peekData) | ||
throw new Error('peekData should be defined'); | ||
const lenCopy = Math.min(peekData.length, remaining); | ||
buffer.set(peekData.subarray(0, lenCopy), offset + bytesRead); | ||
bytesRead += lenCopy; | ||
remaining -= lenCopy; | ||
if (lenCopy < peekData.length) { | ||
// remainder back to queue | ||
this.peekQueue.push(peekData.subarray(lenCopy)); | ||
} | ||
} | ||
// continue reading from stream if required | ||
while (remaining > 0 && !this.endOfStream) { | ||
const reqLen = Math.min(remaining, maxStreamReadSize); | ||
const chunkLen = await this._read(buffer, offset + bytesRead, reqLen); | ||
bytesRead += chunkLen; | ||
if (chunkLen < reqLen) | ||
break; | ||
remaining -= chunkLen; | ||
} | ||
return bytesRead; | ||
} | ||
/** | ||
* Read chunk from stream | ||
* @param buffer Target Uint8Array (or Buffer) to store data read from stream in | ||
* @param offset Offset target | ||
* @param length Number of bytes to read | ||
* @returns Number of bytes read | ||
*/ | ||
async _read(buffer, offset, length) { | ||
if (this.request) | ||
throw new Error('Concurrent read operation?'); | ||
const readBuffer = this.s.read(length); | ||
if (readBuffer) { | ||
buffer.set(readBuffer, offset); | ||
return readBuffer.length; | ||
} | ||
else { | ||
this.request = { | ||
buffer, | ||
offset, | ||
length, | ||
deferred: new Deferred() | ||
}; | ||
this.s.once('readable', () => { | ||
this.tryRead(); | ||
}); | ||
return this.request.deferred.promise; | ||
} | ||
} | ||
tryRead() { | ||
if (!this.request) | ||
throw new Error('this.request should be defined'); | ||
const readBuffer = this.s.read(this.request.length); | ||
if (readBuffer) { | ||
this.request.buffer.set(readBuffer, this.request.offset); | ||
this.request.deferred.resolve(readBuffer.length); | ||
this.request = null; | ||
} | ||
else { | ||
this.s.once('readable', () => { | ||
this.tryRead(); | ||
}); | ||
} | ||
} | ||
reject(err) { | ||
this.endOfStream = true; | ||
if (this.request) { | ||
this.request.deferred.reject(err); | ||
this.request = null; | ||
} | ||
} | ||
} | ||
exports.StreamReader = StreamReader; | ||
var EndOfFileStream_1 = require("./EndOfFileStream"); | ||
Object.defineProperty(exports, "EndOfStreamError", { enumerable: true, get: function () { return EndOfFileStream_1.EndOfStreamError; } }); | ||
var StreamReader_1 = require("./StreamReader"); | ||
Object.defineProperty(exports, "StreamReader", { enumerable: true, get: function () { return StreamReader_1.StreamReader; } }); |
{ | ||
"name": "peek-readable", | ||
"version": "4.0.1", | ||
"version": "4.0.2", | ||
"description": "Read and peek from a readable stream", | ||
@@ -45,7 +45,7 @@ "author": { | ||
"devDependencies": { | ||
"@types/chai": "^4.2.21", | ||
"@types/chai": "^4.3.0", | ||
"@types/mocha": "^9.0.0", | ||
"@types/node": "^16.4.10", | ||
"@typescript-eslint/eslint-plugin": "^4.28.5", | ||
"@typescript-eslint/parser": "^4.28.5", | ||
"@types/node": "^17.0.0", | ||
"@typescript-eslint/eslint-plugin": "^4.31.0", | ||
"@typescript-eslint/parser": "^4.31.0", | ||
"add": "^2.0.6", | ||
@@ -56,8 +56,8 @@ "chai": "^4.3.4", | ||
"eslint": "^7.32.0", | ||
"mocha": "^9.0.3", | ||
"mocha": "^9.1.3", | ||
"nyc": "^15.1.0", | ||
"remark-cli": "^9.0.0", | ||
"remark-preset-lint-recommended": "^5.0.0", | ||
"remark-cli": "^10.0.0", | ||
"remark-preset-lint-recommended": "^6.1.2", | ||
"ts-node": "^10.1.0", | ||
"typescript": "^4.3.5" | ||
"typescript": "^4.4.2" | ||
}, | ||
@@ -64,0 +64,0 @@ "keywords": [ |
@@ -5,3 +5,3 @@ ![Node.js CI](https://github.com/Borewit/peek-readable/workflows/Node.js%20CI/badge.svg) | ||
[![Coverage Status](https://coveralls.io/repos/github/Borewit/peek-readable/badge.svg?branch=master)](https://coveralls.io/github/Borewit/peek-readable?branch=master) | ||
[![Codacy Badge](https://api.codacy.com/project/badge/Grade/8a89b90858734a6da07570eaf2e89849)](https://www.codacy.com/app/Borewit/peek-readable?utm_source=github.com&utm_medium=referral&utm_content=Borewit/peek-readable&utm_campaign=Badge_Grade) | ||
[![Codacy Badge](https://app.codacy.com/project/badge/Grade/d4b511481b3a4634b6ca5c0724407eb9)](https://www.codacy.com/gh/Borewit/peek-readable/dashboard?utm_source=github.com&utm_medium=referral&utm_content=Borewit/peek-readable&utm_campaign=Badge_Grade) | ||
[![Total alerts](https://img.shields.io/lgtm/alerts/g/Borewit/peek-readable.svg?logo=lgtm&logoWidth=18)](https://lgtm.com/projects/g/Borewit/peek-readable/alerts/) | ||
@@ -8,0 +8,0 @@ [![Language grade: JavaScript](https://img.shields.io/lgtm/grade/javascript/g/Borewit/peek-readable.svg?logo=lgtm&logoWidth=18)](https://lgtm.com/projects/g/Borewit/peek-readable/context:javascript) |
Sorry, the diff of this file is not supported yet
License Policy Violation
LicenseThis package is not allowed per your license policy. Review the package's license to ensure compliance.
Found 1 instance in 1 package
Major refactor
Supply chain riskPackage has recently undergone a major refactor. It may be unstable or indicate significant internal changes. Use caution when updating to versions that include significant changes.
Found 1 instance in 1 package
License Policy Violation
LicenseThis package is not allowed per your license policy. Review the package's license to ensure compliance.
Found 1 instance in 1 package
15712
11
225
1