Skip to content

Instantly share code, notes, and snippets.

@deostroll
Forked from bennadel/test.js
Created December 4, 2015 11:15
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save deostroll/d6107b6fb696d3c2d68d to your computer and use it in GitHub Desktop.
Save deostroll/d6107b6fb696d3c2d68d to your computer and use it in GitHub Desktop.
Turning Buffers Into Readable Streams In Node.js
// Required module references.
var stream = require( "stream" );
var chalk = require( "chalk" );
var util = require( "util" );
var http = require( "http" );
var fileSystem = require( "fs" );
// ---------------------------------------------------------- //
// ---------------------------------------------------------- //
// I turn the given source Buffer into a Readable stream.
function BufferStream( source ) {
if ( ! Buffer.isBuffer( source ) ) {
throw( new Error( "Source must be a buffer." ) );
}
// Super constructor.
stream.Readable.call( this );
this._source = source;
// I keep track of which portion of the source buffer is currently being pushed
// onto the internal stream buffer during read actions.
this._offset = 0;
this._length = source.length;
// When the stream has ended, try to clean up the memory references.
this.on( "end", this._destroy );
}
util.inherits( BufferStream, stream.Readable );
// I attempt to clean up variable references once the stream has been ended.
// --
// NOTE: I am not sure this is necessary. But, I'm trying to be more cognizant of memory
// usage since my Node.js apps will (eventually) never restart.
BufferStream.prototype._destroy = function() {
this._source = null;
this._offset = null;
this._length = null;
};
// I read chunks from the source buffer into the underlying stream buffer.
// --
// NOTE: We can assume the size value will always be available since we are not
// altering the readable state options when initializing the Readable stream.
BufferStream.prototype._read = function( size ) {
// If we haven't reached the end of the source buffer, push the next chunk onto
// the internal stream buffer.
if ( this._offset < this._length ) {
this.push( this._source.slice( this._offset, ( this._offset + size ) ) );
this._offset += size;
}
// If we've consumed the entire source buffer, close the readable stream.
if ( this._offset >= this._length ) {
this.push( null );
}
};
// ---------------------------------------------------------- //
// ---------------------------------------------------------- //
// Read the file into memory. We're using the "Sync" version of this to reduce the
// complexity of the exploration.
var tankGirlBuffer = fileSystem.readFileSync( "./tank-girl.png" );
// Create a web server that streams the cached file back on every request.
var server = http.createServer(
function handleHttpRequest( request, response ) {
// We're hard-coding this stuff since there's nothing dynamic about the demo.
response.writeHead(
200,
"OK",
{
"Content-Type": "image/png",
"Content-Disposition": "inline; filename=tank-girl.png",
"Contente-Length": tankGirlBuffer.length
}
);
// Crate a new instance of the Buffer Stream to wrap the cached buffer. Then,
// pipe that stream into the HTTP response.
// --
// NOTE: Once the BufferStream "ends", it will automatically end the HTTP
// response stream as well.
new BufferStream( tankGirlBuffer )
.pipe( response )
;
}
);
server.listen( 8080 );
console.log( chalk.yellow( "Server running on port 8080." ) );
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment