systemquery/src/lib/io/StreamHelpers.mjs

83 lines
2.7 KiB
JavaScript
Raw Normal View History

"use strict";
/* This Source Code Form is subject to the terms of the Mozilla Public
* License, v. 2.0. If a copy of the MPL was not distributed with this
* file, You can obtain one at https://mozilla.org/MPL/2.0/. */
/*
* A pair of functions to make writing to streams in Node.js less painful.
* I've used these in a number of different projects so far, and they both
* *appear* to be stable.
* @licence MPL-2.0
*
* Changelog
*********************************
* 22nd March 2021
* We should have brought this into our code snippet library *ages* ago lol :P
*/
/**
* Writes data to a stream, automatically waiting for the drain event if asked.
* @param {stream.Writable} stream_out The writable stream to write to.
* @param {string|Buffer|Uint8Array} data The data to write.
* @return {Promise} A promise that resolves when writing is complete.
*/
function write_safe(stream_out, data, timeout = null) {
return new Promise(function (resolve, reject) {
// console.log(`Beginning write`);
// Handle errors
let handler_error = (error) => {
stream_out.off("error", handler_error);
// console.log(`Error received, handler detached, rejecting`);
reject(error);
};
stream_out.on("error", handler_error);
let returnval = typeof data == "string" ? stream_out.write(data, "utf-8") : stream_out.write(data);
// console.log(`Write returned`, returnval);
if(returnval) {
// We're good to go
stream_out.off("error", handler_error);
// console.log("We're good to go, handler detached, resolving");
resolve();
}
else {
let handler_drain = () => {
stream_out.off("error", handler_error);
if(timeout !== null) clearTimeout(id);
// console.log(`Drain event received, handler detached, resolving`);
resolve();
};
let id;
if(timeout !== null)
id = setTimeout(() => {
stream_out.off("drain", handler_drain);
handler_error(new Error(`Error: Timeout reached waiting for drain event`));
}, timeout);
// We need to wait for the drain event before continuing
// console.log(`Waiting for drain event`);
stream_out.once("drain", handler_drain);
}
});
}
/**
* Waits for the given stream to end and finish writing data.
* @param {stream.Writable} stream The stream to end.
* @param {Buffer|string} [chunk=undefined] Optional. A chunk to write when calling .end().
* @return {Promise} A Promise that resolves when writing is complete.
*/
function end_safe(stream) {
return new Promise((resolve, _reject) => {
// Handle streams that have already been closed
if(stream.writableFinished) resolve();
stream.once("finish", resolve);
stream.end();
});
}
export {
write_safe, end_safe
};