From 83b60c01ef91c7d9c4107ec47d86ec0353a97cd7 Mon Sep 17 00:00:00 2001 From: "Harish.K" Date: Mon, 21 Mar 2016 00:46:36 +0530 Subject: [PATCH] Tests passed Featues * Non blocking operations/Clean up synchronous codes * handle failues * more usefull logging --- app.js | 83 ++++++++++++++++++++++++++++++++++++-------------------- utils.js | 53 ++++++++++++++++++++++++++++++++---- 2 files changed, 101 insertions(+), 35 deletions(-) diff --git a/app.js b/app.js index ad9414f..df8b2d2 100644 --- a/app.js +++ b/app.js @@ -1,47 +1,74 @@ var express = require('express'); -var fs = require('fs'); var config = require( __dirname + '/./config' ); var utils = require( __dirname + '/./utils'); var NPM_PATH = config.NPM_PATH; var REGISTRY_NAME = config.REGISTRY_NAME; + var fetchAndCacheMetadata = utils.fetchAndCacheMetadata; var fetchAndCacheTarball = utils.fetchAndCacheTarball; var patchData = utils.patchData; +var fileExists = utils.fileExists; +var readFile = utils.readFile; var app = express(); app.use( function(req, res, next ){ - console.log(req.method, req.path ); + res._log = { + method: req.method, + path: req.path, + cacheHit: 'Hit', + cacheFile: '', + }; + + res.on( 'finish', function(){ + var log = this._log; + console.log( log.cacheHit, this.statusCode, log.method, log.path, ' => ', log.cacheFile ); + }); + // setTimeout( next, 1000 ); next(); }); -app.get( '/:package', function( req, res ){ +app.get( '/:package', function( req, res, next ){ var packageName = req.params.package; var cacheFile = [ NPM_PATH, REGISTRY_NAME, packageName, '.cache.json' ].join( '/' ); - var cacheData; - - if( !fs.existsSync( cacheFile ) ){ - fetchAndCacheMetadata( packageName, cacheFile ); - } - cacheData = fs.readFileSync( cacheFile, 'utf-8' ); - cacheData = JSON.parse( cacheData ); - - patchData( cacheData ); - return res.send( cacheData ); + return fileExists( cacheFile ) + .tap( function( isExists ){ + if( !isExists ){ + res._log.cacheHit = '---'; + return fetchAndCacheMetadata( packageName, cacheFile ); + } + }) + .then( function( ){ + res._log.cacheFile = cacheFile; + return readFile( cacheFile, 'utf-8' ); + }) + .then( function( cacheData ){ + cacheData = JSON.parse( cacheData ); + patchData( cacheData ); + return res.send( cacheData ); + }) + .catch( next ); }); -app.get( '/:package/-/:tarball', function( req, res ){ +app.get( '/:package/-/:tarball', function( req, res, next ){ var packageName = req.params.package; var version = req.params.tarball.match( new RegExp( packageName + '-(.*).tgz') )[1]; var packagePath = [ NPM_PATH , packageName, version, 'package.tgz'].join( '/' ); - if( !fs.existsSync( packagePath ) ){ - fetchAndCacheTarball( packageName, version, packagePath ); - } - - return fs.createReadStream( packagePath ).pipe( res ); + fileExists( packagePath ) + .tap( function( isExists ){ + if( !isExists ){ + res._log.cacheHit = '---'; + return fetchAndCacheTarball( packageName, version, packagePath ); + } + }) + .then( function(){ + res._log.cacheFile = packagePath; + return res.sendFile( packagePath ); + }) + .catch( next ); }); @@ -54,17 +81,15 @@ app.use(function(req, res, next) { // error handlers -// development error handler -// will print stacktrace -if (app.get('env') === 'development') { - app.use(function(err, req, res, next) { - res.status(err.status || 500); - res.send({ - message: err.message, - error: err - }); +app.use(function(err, req, res, next) { + console.log( err.stack ); + res.status(err.status || 500); + res.send({ + message: err.message, + error: err }); -} + if( next ) { next(); } +}); diff --git a/utils.js b/utils.js index 079ea55..24c9bc7 100644 --- a/utils.js +++ b/utils.js @@ -1,10 +1,31 @@ -var execSync = require('child_process').execSync; var path = require('path'); +var fs = require('fs'); var config = require( __dirname + '/./config' ); +var Promise = require('bluebird'); +var _exec = Promise.promisify( require('child_process').exec ); var REGISTRY_NAME = config.REGISTRY_NAME; var LOCAL_REGISTRY = config.LOCAL_REGISTRY; + +function exec( cmd, envVars ){ + return _exec( cmd, { env: envVars }); +} +exports.exec = exec; + +function fileExists( fname ){ + return new Promise( function( resolve ){ + fs.exists( fname, function(exists){ + resolve( exists ); + }); + }); +} +exports.fileExists = fileExists; + +var readFile = Promise.promisify( fs.readFile ); +exports.readFile = readFile; + + exports.patchData = function ( data ){ Object.keys(data.versions).forEach( function( v ){ var val = data.versions[v]; @@ -12,19 +33,39 @@ exports.patchData = function ( data ){ }); }; +var fetchAndCacheMetadataCmd =[ + 'mkdir $packageCacheDir', + 'wget -nv "http://$REGISTRY_NAME/$packageName" -O $cacheFile || { wgetExitStatus=$? && rm $cacheFile; exit $wgetExitStatus ; }' +].join( ';' ); + +var fetchAndCacheTarballCmd = [ + 'mkdir -p $packageTarballDir', + 'wget -nv $tarballUrl -O $tarballPath || { wgetExitStatus=$? && rm $tarballPath; exit $wgetExitStatus ; }', + 'cd $packageTarballDir; tar -xzf package.tgz package/package.json', +].join( ';' ); + exports.fetchAndCacheMetadata = function ( packageName, cacheFile ){ var packageCacheDir = path.dirname( cacheFile ); - execSync( 'mkdir ' + packageCacheDir ); - execSync( 'wget http://' + REGISTRY_NAME + '/' + packageName + ' -O ' + cacheFile ); + + return exec( fetchAndCacheMetadataCmd, { + packageCacheDir: packageCacheDir, + REGISTRY_NAME: REGISTRY_NAME, + packageName: packageName, + cacheFile: cacheFile, + }); }; exports.fetchAndCacheTarball = function ( packageName, version, tarballPath ){ var tarballUrl = 'http://' + REGISTRY_NAME + '/' + packageName + '/-/' + packageName + '-' + version + '.tgz'; var packageTarballDir = path.dirname( tarballPath ); - execSync( 'mkdir -p ' + packageTarballDir ); - execSync( 'wget ' + tarballUrl + ' -O ' + tarballPath ); - execSync( 'cd ' + packageTarballDir + ';tar -xzf package.tgz package/package.json' ); + + return exec( fetchAndCacheTarballCmd, { + packageTarballDir: packageTarballDir, + tarballUrl: tarballUrl, + tarballPath: tarballPath, + }); }; +