UNPKG

uspring

Version:

A very fast Webserver which has interface like springboot

92 lines (91 loc) 4.2 kB
"use strict"; Object.defineProperty(exports, "__esModule", { value: true }); var openStreams = 0; var streamIndex = 0; /* Helper function to pipe the ReadaleStream over an Http responses */ function pipeStreamOverResponse(res, readStream, totalSize) { /* Careful! If Node.js would emit error before the first res.tryEnd, res will hang and never time out */ /* For this demo, I skipped checking for Node.js errors, you are free to PR fixes to this example */ readStream.on('data', function (chunk) { /* We only take standard V8 units of data */ var ab = toArrayBuffer(chunk); /* Store where we are, globally, in our response */ var lastOffset = res.getWriteOffset(); /* Streaming a chunk returns whether that chunk was sent, and if that chunk was last */ var _a = res.tryEnd(ab, totalSize), ok = _a[0], done = _a[1]; /* Did we successfully send last chunk? */ if (done) { onAbortedOrFinishedResponse(res, readStream); } else if (!ok) { /* If we could not send this chunk, pause */ readStream.pause(); /* Save unsent chunk for when we can send it */ res.ab = ab; res.abOffset = lastOffset; /* Register async handlers for drainage */ res.onWritable(function (offset) { /* Here the timeout is off, we can spend as much time before calling tryEnd we want to */ /* On failure the timeout will start */ var _a = res.tryEnd(res.ab.slice(offset - res.abOffset), totalSize), ok = _a[0], done = _a[1]; if (done) { onAbortedOrFinishedResponse(res, readStream); } else if (ok) { /* We sent a chunk and it was not the last one, so let's resume reading. * Timeout is still disabled, so we can spend any amount of time waiting * for more chunks to send. */ readStream.resume(); } /* We always have to return true/false in onWritable. * If you did not send anything, return true for success. */ return ok; }); } }).on('error', function () { /* Todo: handle errors of the stream, probably good to simply close the response */ console.error('Unhandled read error from Node.js, you need to handle this!'); res.close(); }); /* If you plan to asyncronously respond later on, you MUST listen to onAborted BEFORE returning */ res.onAborted(function () { onAbortedOrFinishedResponse(res, readStream); }); } exports.pipeStreamOverResponse = pipeStreamOverResponse; /* Helper function converting Node.js buffer to ArrayBuffer */ function toArrayBuffer(buffer) { return buffer.buffer.slice(buffer.byteOffset, buffer.byteOffset + buffer.byteLength); } exports.toArrayBuffer = toArrayBuffer; /* Either onAborted or simply finished request */ function onAbortedOrFinishedResponse(res, readStream) { if (res.id == -1) { console.error("ERROR! onAbortedOrFinishedResponse called twice for the same res!"); } else { // console.log('Stream was closed, openStreams: ' + --openStreams); console.timeEnd(res.id); } /* Mark this response already accounted for */ res.id = -1; } exports.onAbortedOrFinishedResponse = onAbortedOrFinishedResponse; function streamToString(stream) { var chunks = []; return new Promise(function (resolve, reject) { stream.on('data', function (chunk) { return chunks.push(chunk); }); stream.on('error', reject); stream.on('end', function () { return resolve(Buffer.concat(chunks).toString('utf8')); }); }); } exports.streamToString = streamToString; function streamToBuffer(stream) { var chunks = []; return new Promise(function (resolve, reject) { stream.on('data', function (chunk) { return chunks.push(chunk); }); stream.on('error', reject); stream.on('end', function () { return resolve(Buffer.concat(chunks)); }); }); } exports.streamToBuffer = streamToBuffer;