UNPKG

tomahawk-plugin-kv-memory-store

Version:

Tomahawk plugin, implementing a Key Value Pair Store in Memory.

246 lines (225 loc) 8.42 kB
module.exports = function () { var fs = require('fs'), path = require('path') function isUndefined(object) { return typeof(object) === 'undefined'; } function create(app, config, io) { config = config || {plugins:{store:{}}}; var interval = config.plugins.store.interval || 1000, keyValuePairs = {}, keySets = {}, modified = false, connected = false, filename = null, version = config.version || '0.0.0', logger = config.logger || {log:function(){}}, meta = config.meta || {$_id:'kv-store'}; function status(next) { process.nextTick(function () { if (next) next(null, { connected : connected, modified : modified, status : 'OK' }); }); } function connect(url, next) { filename = url + '.json'; filename = filename.replace('${HOME}', process.env.HOME); filename = filename.replace('${CWD}', process.cwd()); if (!fs.existsSync(path.dirname(filename))) { fs.mkdirSync(path.dirname(filename)); } load(function (err, value, meta) { connected = true; autosave(); if (next) next(err, value, meta); }); } function close(next) { save(function (err) { connected = false; if (next) next(err); }); } function get(key, next) { if (key.indexOf('*') !== -1) { tuples = _keys(key, true); process.nextTick(function () { if (next) next(null, tuples, meta); }); } else { process.nextTick(function () { if (next) next(null, keyValuePairs[key], meta); }); } } function set(tuples, next) { tuples.forEach(function (tuple) { keyValuePairs[tuple.key] = tuple.value; }); modified = true; process.nextTick(function () { if (next) next(null, 'OK', meta); }); } function del(key, next) { var keys = [], count = 0; if (key instanceof Array) keys = key else if (key.indexOf('*') !== -1) keys = _keys(key); else keys = [key]; keys.forEach(function (key) { if (!isUndefined(keyValuePairs[key])) { ++count; delete keyValuePairs[key]; } }); modified = true; process.nextTick(function () { if (next) next(null, count, meta); }); } function sget(setName, member, next) { logger.log('debug', 'kv-memory::sget(setName: %s, member:%s) >>> %j', setName, member, keySets, meta); // Does the set exists if (keySets[setName]) { // Get all members? if (member === '*') { process.nextTick(function () { logger.log('debug', 'kv-memory::sget(setName: %s, member:%s) >>> %j >>> %j', setName, member, keySets, Object.keys(keySets[setName]), meta); if (next) next(null, Object.keys(keySets[setName]), meta); }); return; } else { process.nextTick(function () { if (next) next(null, isUndefined(keySets[setName][member])?0:1, meta); }); return; } } else { // set does not exists. Return empty array if asking for all members // or false if only one member process.nextTick(function () { if (next) next(null, (member === '*' ? [] : 0), meta); }); return; } } function sadd(tuples, next) { logger.log('debug', 'kv-memory::sadd(tuples: %j)', tuples, meta); var count = 0; tuples.forEach(function (tuple) { if (isUndefined(keySets[tuple.key])) { keySets[tuple.key] = {}; } keySets[tuple.key][tuple.value] = 1; ++count; }); modified = true; process.nextTick(function () { if (next) next(null, count, meta); }); } function sdel(setName, member, next) { logger.log('debug', 'kv-memory::sdel(setName: %s, member: %j)', setName, member, meta); var count = 0; // Does the set exists if (keySets[setName]) { // delete the whole set if (member === '*') { count += Object.keys(keySets[setName]).length; delete keySets[setName] modified = true; } else { // delete the member if it exists if (!isUndefined(keySets[setName][member])) { delete keySets[setName][member] ++count; modified = true; } } } process.nextTick(function () { if (next) next(null, count, meta); }); } //////////////////////////// PRIVATE /////////////////////////////////// function _keys(key, withValue) { withValue = withValue || false; var tuples = [], regex = '^' + key.replace(/\*/g, '.*') + '$'; for (var name in keyValuePairs) { if (keyValuePairs.hasOwnProperty(name) && name.match(regex)) { tuples.push(withValue ? {key: name, value: keyValuePairs[name]} : name); } } return tuples; } function save(next) { if (modified) { try { var payload = { keyValuePairs : keyValuePairs, keySets : keySets }; modified = false; fs.writeFile(filename, JSON.stringify(payload), function (err) { if (next) next(err); }); } catch (e) { if (next) next(e); } } else { if (next) next(null); } } function load(next) { fs.readFile(filename, function (err, data) { if (!err) { try { container = JSON.parse(data); if (container.keyValuePairs && container.keySets) { keyValuePairs = container.keyValuePairs; keySets = container.keySets; } else { keyValuePairs = container; } } catch (e) { err = e; } } if (next) next(err); }); } function autosave() { save(function (err) { setTimeout(function () { autosave(); },interval); }); } //////////////////////////////////////////////////////////////////////// return { constructor : function (next) { connect(process.env.KVSTORE_FILENAME || config.plugins.store.filename || 'tomahawk', next); }, shutdown : function (next) { close(next); }, status : status, connect : connect, close : close, get : get, set : set, del : del, sadd : sadd, sget : sget, sdel : sdel }; } return create; }();