it-byte-stream
Version:
Read and write arbitrary bytes over a duplex stream
96 lines • 3.08 kB
JavaScript
/**
* @packageDocumentation
*
* This module makes it easy to send and receive bytes over streams.
*
* @example
*
* ```typescript
* import { byteStream } from 'it-byte-stream'
*
* const stream = byteStream(duplex)
*
* // read the next chunk
* const bytes = await stream.read()
*
* // read the next five bytes
* const fiveBytes = await stream.read(5)
*
* // write bytes into the stream
* await stream.write(Uint8Array.from([0, 1, 2, 3, 4]))
* ```
*/
import { queuelessPushable } from 'it-queueless-pushable';
import { raceSignal } from 'race-signal';
import { Uint8ArrayList } from 'uint8arraylist';
import { UnexpectedEOFError } from './errors.js';
export function byteStream(duplex, opts) {
const write = queuelessPushable();
duplex.sink(write).catch(async (err) => {
await write.end(err);
});
duplex.sink = async (source) => {
for await (const buf of source) {
await write.push(buf);
}
await write.end();
};
let source = duplex.source;
if (duplex.source[Symbol.iterator] != null) {
source = duplex.source[Symbol.iterator]();
}
else if (duplex.source[Symbol.asyncIterator] != null) {
source = duplex.source[Symbol.asyncIterator]();
}
const readBuffer = new Uint8ArrayList();
const W = {
read: async (options) => {
options?.signal?.throwIfAborted();
if (options?.bytes == null) {
// just read whatever arrives
const { done, value } = await raceSignal(source.next(), options?.signal);
if (done === true) {
return null;
}
return value;
}
while (readBuffer.byteLength < options.bytes) {
const { value, done } = await raceSignal(source.next(), options?.signal);
if (done === true) {
throw new UnexpectedEOFError('unexpected end of input');
}
readBuffer.append(value);
}
const buf = readBuffer.sublist(0, options.bytes);
readBuffer.consume(options.bytes);
return buf;
},
write: async (data, options) => {
options?.signal?.throwIfAborted();
// just write
if (data instanceof Uint8Array) {
await write.push(data, options);
}
else {
await write.push(data.subarray(), options);
}
},
unwrap: () => {
if (readBuffer.byteLength > 0) {
const originalStream = duplex.source;
duplex.source = (async function* () {
if (opts?.yieldBytes === false) {
yield readBuffer;
}
else {
yield* readBuffer;
}
yield* originalStream;
}());
}
return duplex;
}
};
return W;
}
//# sourceMappingURL=index.js.map