Created
September 15, 2014 12:25
-
-
Save bennadel/b35f3a15cb3b03ddbcf8 to your computer and use it in GitHub Desktop.
Turning Buffers Into Readable Streams In Node.js
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
// 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