var util = require("util"), stream = require("stream"), constants = require("./constants"); // TODO: clear up specs on returning false from a write and emitting a drain event. // Does this mean if I return false from a write, I should ignore any write requests between that false return and the drain event? var WritableStreamBuffer = module.exports = function(opts) { var that = this; stream.Stream.call(this); opts = opts || {}; var initialSize = opts.initialSize || constants.DEFAULT_INITIAL_SIZE; var incrementAmount = opts.incrementAmount || constants.DEFAULT_INCREMENT_AMOUNT; var buffer = new Buffer(initialSize); var size = 0; this.writable = true; this.readable = false; this.size = function() { return size; }; this.maxSize = function() { return buffer.length; }; this.getContents = function(length) { if(!size) return false; var data = new Buffer(Math.min(length || size, size)); buffer.copy(data, 0, 0, data.length); if(data.length < size) buffer.copy(buffer, 0, data.length); size -= data.length; return data; }; this.getContentsAsString = function(encoding, length) { if(!size) return false; var data = buffer.toString(encoding || "utf8", 0, Math.min(length || size, size)); var dataLength = Buffer.byteLength(data); if(dataLength < size) buffer.copy(buffer, 0, dataLength); size -= dataLength; return data; }; var increaseBufferIfNecessary = function(incomingDataSize) { if((buffer.length - size) < incomingDataSize) { var factor = Math.ceil((incomingDataSize - (buffer.length - size)) / incrementAmount); var newBuffer = new Buffer(buffer.length + (incrementAmount * factor)); buffer.copy(newBuffer, 0, 0, size); buffer = newBuffer; } }; this.write = function(data, encoding, callback) { if(!that.writable) return; if(Buffer.isBuffer(data)) { increaseBufferIfNecessary(data.length); data.copy(buffer, size, 0); size += data.length; } else { data = data + ""; increaseBufferIfNecessary(Buffer.byteLength(data)); buffer.write(data, size, encoding || "utf8"); size += Buffer.byteLength(data); } if(typeof callback === "function") { callback() ;} }; this.end = function() { var args = Array.prototype.slice.apply(arguments); if(args.length) that.write.apply(that, args); that.emit('finish'); that.destroy(); }; this.destroySoon = this.destroy = function() { that.writable = false; that.emit("close"); }; }; util.inherits(WritableStreamBuffer, stream.Stream);