« index
Coverage for /Users/kris/q-io/reader.js : 93%
129 lines |
121 run |
8 missing |
0 partial |
23 blocks |
16 blocks run |
7 blocks missing
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 | var Q = require("q"); /** * Wraps a Node readable stream, providing an API similar * to a Narwhal synchronous `io` stream except returning * Q promises for long latency operations. * @param stream any Node readable stream * @returns {Promise * Reader} a promise for * the text stream reader. * @constructor */ module.exports = Reader; function Reader(_stream, charset) { var self = Object.create(Reader.prototype); if (charset && _stream.setEncoding) // TODO complain about inconsistency _stream.setEncoding(charset); var begin = Q.defer(); var end = Q.defer(); _stream.on("error", function (reason) { begin.reject(reason); }); var chunks = []; var receiver; _stream.on("end", function () { begin.resolve(self); end.resolve() }); _stream.on("data", function (chunk) { begin.resolve(self); if (receiver) { receiver(chunk); } else { chunks.push(chunk); } }); function slurp() { var result; if (charset) { result = chunks.join(""); } else { result = self.constructor.join(chunks); } chunks.splice(0, chunks.length); return result; } /*** * Reads all of the remaining data from the stream. * @returns {Promise * String} a promise for a String * containing the entirety the remaining stream. */ self.read = function () { receiver = undefined; var deferred = Q.defer(); Q.done(end.promise, function () { deferred.resolve(slurp()); }); return deferred.promise; }; /*** * Reads and writes all of the remaining data from the * stream in chunks. * @param {Function(Promise * String)} write a function * to be called on each chunk of input from this stream. * @returns {Promise * Undefined} a promise that will * be resolved when the input is depleted. */ self.forEach = function (write) { if (chunks && chunks.length) write(slurp()); receiver = write; return Q.when(end.promise, function () { receiver = undefined; }); }; self.close = function () { _stream.destroy(); }; return begin.promise; } /* Reads an entire forEachable stream of buffers and returns a single buffer. */ Reader.read = read; function read(stream, charset) { var chunks = []; stream.forEach(function (chunk) { chunks.push(chunk); }); if (charset) { return chunks.join(""); } else { return join(chunks); } } Reader.join = join; function join(buffers) { var length = 0; var at; var i; var ii = buffers.length; var buffer; var result; for (i = 0; i < ii; i++) { buffer = buffers[i]; length += buffer.length; } result = new Buffer(length); at = 0; for (i = 0; i < ii; i++) { buffer = buffers[i]; buffer.copy(result, at, 0); at += buffer.length; } buffers.splice(0, ii, result); return result; } |