confection
Version:
A configuration management server written in node, using redis for a backend.
210 lines (147 loc) • 3.79 kB
JavaScript
/*
Storage is a light wrapper around redis. It was implemented this way to make sure storage is modular and can be upgraded
later if other storage options are desired.
*/
var crypto = require( 'crypto' );
var redis = require( 'redis' );
var client = null;
var clientConnectErr = null;
var initCallbacks = [];
module.exports.init = function ( params, callback ) {
if ( typeof params === 'function' ) {
callback = params;
params = {};
}
initCallbacks.push( callback );
function flushCallback( callback, err ) {
process.nextTick( function () {
executeCallback( callback, err );
} );
}
function flushInitCallbacks() {
while ( initCallbacks.length > 0 ) {
flushCallback( initCallbacks.shift(), clientConnectErr );
}
}
if ( !client ) {
params = {
host: "localhost",
port: 6379,
options: {}
}.mixin( params );
client = redis.createClient( params.port, params.host, params.options );
var errorHandler = function () {
client = null;
clientConnectErr = 'failed to connect';
client.removeListener( 'connect', connectHandler );
flushInitCallbacks();
};
var connectHandler = function () {
clientConnectErr = null;
client.removeListener( 'error', errorHandler );
flushInitCallbacks();
};
client.on( 'connect', connectHandler );
client.on( 'error', errorHandler );
}
else {
flushInitCallbacks();
}
};
module.exports.getConf = function ( key, callback ) {
getRaw( key, 'moduleConfig', callback );
};
module.exports.setConf = function ( key, conf, callback ) {
setRaw( key, 'moduleConfig', conf, callback );
};
module.exports.delConf = function ( key, callback ) {
delRaw( key, 'moduleConfig', callback );
};
module.exports.isAuthorized = function ( key, callback ) {
getRaw( key, 'auth', function ( err, value ) {
executeCallback( callback, ( value && !err ) );
} );
};
module.exports.generateAuthKey = function ( callback ) {
var hash = crypto.createHash( 'sha1' );
hash.update( new Date().getTime() + "|" + Math.random() );
hash = hash.digest( 'hex' );
setRaw( hash, 'auth', true, function ( err ) {
if ( err ) {
executeCallback( callback, null );
}
else {
executeCallback( callback, hash );
}
} );
};
module.exports.delAuthKey = function ( key, callback ) {
delRaw( key, 'auth', callback );
};
function delRaw( key, type, callback ) {
checkReady();
client.del( encodeKey( key, type ), function ( err ) {
executeCallback( callback, err ? "could not delete " + type : null );
} );
}
function getRaw( key, type, callback ) {
checkReady();
client.get( encodeKey( key, type ), function ( err, data ) {
if ( err ) {
executeCallback( callback, err, null );
}
else {
executeCallback( callback, null, decodeData( data ) );
}
} );
}
function setRaw( key, type, data, callback ) {
checkReady();
data = encodeData( data );
if ( !data ) {
executeCallback( callback, type + " could not be serialized", null );
return;
}
client.set( encodeKey( key, type ), data, function ( err, data ) {
if ( err || !data ) {
executeCallback( callback, "could not store " + type );
}
else {
executeCallback( callback, null );
}
} );
}
function executeCallback() {
var args = Array.prototype.slice.call( arguments );
if ( typeof args[0] === 'function' ) {
args[0].apply( {}, args.slice( 1 ) );
}
}
function encodeKey( key, type ) {
return type + ":" + key;
}
function encodeData( data ) {
try {
return JSON.stringify( data );
}
catch ( e ) {
return null;
}
}
function decodeData( data ) {
if ( !data ) {
return null;
}
try {
return JSON.parse( data );
}
catch ( e ) {
return null;
}
}
function checkReady() {
if ( !client ) {
throw "storage has not been initialized";
}
}
;