UNPKG

tweekdb

Version:

The flat-file, in-memory, remote-sync or hybrid db that is as lightning as you configure it to be.

438 lines (370 loc) 10.8 kB
const fs = require('fs'), zlib = require('zlib'), utils = require('./lib/utils'), enc = require('./lib/enc'); let config, cwd = process.cwd(), cnf_url = cwd + '/tweekdb.json'; try { config = require(cnf_url); utils.cl(config.settings.verbose,['init','config file found.'],96); } catch (err) { config = require('./config'); utils.cl(config.settings.verbose,['init','config file not found, loading defaults.'],96); } Object.freeze(config); const vb = config.settings.verbose, lp = config.settings.lodash_path; let _ = require(lp); if(config.settings.noconflict){ _ = _.runInContext(); } function tweekdb(src, cnf){ cnf = cnf || {}; this.src = src; this.schema = cnf.schema || config.schema; this.serialize = cnf.serialize || JSON.stringify; this.deserialize = cnf.deserialize || JSON.parse; this.cron = cnf.cron || null; this.encryption = cnf.encryption || config.encryption.enabled; this.backup = cnf.backup || config.backup.enabled; this.gzip = cnf.gzip || config.gzip.enabled; this.gzip_backup = config.gzip.backup; if(config.static.enabled){ this.static_dest = config.static.dest; } if(config.fetch.enabled){ this.fetch_config = cnf.fetch_config || config.fetch.config; } if(config.sync.enabled){ this.sync_config = cnf.sync_config || config.sync.config; } if(this.encryption){ this.secret = config.encryption.secret || null; this.enc_cnf = config.encryption.settings || null; } if(this.backup){ this.backup_pre = config.backup.pre || '.'; this.backup_ext = config.backup.ext || 'tmp'; } } tweekdb.prototype = { load: function(cb) { let src = this.src, data; if(!cb){ try { data = fs.readFileSync(src); data = utils.check_read(this, data, config); utils.cl(vb,['status','db '+ src +' cached and ready.'],96); return this.deserialize(data); } catch(e) { utils.cl(vb,['warning','unable to load data, creating new...'],91); try { data = fs.readFileSync(this.backup_pre + src +'.'+ this.backup_ext); data = utils.check_read(this, data, config); utils.cl(vb,['status','db '+ src +' backup cached and ready.'],96); return data ? this.deserialize(data) : this.schema; } catch (err) { data = this.serialize(this.schema); if(this.encryption){ data = enc.encrypt(data, this.secret, this.enc_cnf); } if(this.gzip){ data = zlib.gzipSync(data, config.gzip.settings); } fs.writeFileSync(src, data); utils.cl(vb,['status','new db '+ src +' cached and ready.'],96); return this.schema; } } } else { let $this = this; fs.readFile(src, function(err,data){ if(err){ fs.readFile(this.backup_pre + src +'.'+ this.backup_ext, function(err, res){ if(err){ data = $this.serialize($this.schema); if($this.encryption){ data = enc.encrypt(data, $this.secret, $this.enc_cnf); } if($this.gzip){ data = zlib.gzipSync(data, config.gzip.settings); } fs.writeFileSync(src, data); cb(false, $this.schema); utils.cl(vb,['status','new db '+ src +' cached and ready.'],96); return } if($this.gzip || this.gzip_backup){ res = zlib.unzipSync(res, config.gzip.settings); } res = res.toString('utf8'); if($this.encryption){ res = enc.decrypt(res, $this.secret, $this.enc_cnf); } cb(false, $this.deserialize(res)); utils.cl(vb,['status','db '+ src +' backup cached and ready.'],96); }); } else { data = utils.check_read($this, data, config); cb(false, $this.deserialize(data)); utils.cl(vb,['status','db '+ src +' cached and ready.'],96); } }) } }, save: function(data, cb) { let src = this.src; data = utils.check_write(this, data, config); if(!cb){ let res = fs.writeFileSync(src, data); utils.write_backup(this, data, config); if(!config.turbo.enabled){ return res; } } else { let $this = this; fs.writeFile(src, data, function(err){ if(!config.turbo.enabled){ if(err){return cb(err)} cb(false) } else { if(err){ return utils.cl(vb,['error','Turbo file write failed'],91); } } utils.write_backup($this, data, config); }) } }, set_backup: function(data, cb) { let dest = config.backup.pre + this.src +'.'+ config.backup.ext; data = utils.check_write(this, data, config); if(!cb){ return fs.writeFileSync(dest, data); } fs.writeFile(dest, data, function(err){ if(err){return cb(err)} cb(false) }) }, cron_job: function(db){ this.cron(db) } } if(config.static.enabled){ tweekdb.prototype.static = function(data, title, cb){ if(typeof data !== 'string'){ data = JSON.stringify(data) } let dest = this.static_dest + title + '.json'; if(!cb){ return fs.writeFileSync(dest, data); } else { fs.writeFile(dest, data, function(err){ if(err){return cb(err)} cb(false) }) } } } if(config.fetch.enabled){ tweekdb.prototype.fetch = function(cb){ let $this = this, arr = ['key','cert','pfx']; for (let i = 0; i < arr.length; i++) { if(this.fetch_config[arr[i]]){ this.fetch_config[arr[i]] = fs.readFileSync(this.fetch_config[arr[i]]) if(arr[i] === 'ca'){ this.fetch_config[arr[i]] = [this.fetch_config[arr[i]]] } } } utils.req($this, 'fetch_config', config, function(err,data){ if(err){return cb(err)} try { if($this.encryption){ data = enc.decrypt(data, $this.secret, $this.enc_cnf); } data = $this.deserialize(data); cb(false, data); utils.cl(vb,['status','db from '+ $this.fetch_config.hostname +' cached and ready.'],96); } catch (err) { throw err; } }) } } if(config.sync.enabled){ tweekdb.prototype.sync = function(body, cb){ let $this = this, arr = ['key','cert','pfx']; if(typeof body !== 'string'){ try { body = JSON.stringify(body); } catch (err) { return cb('invalid sync data') } } if(this.encryption){ body = enc.encrypt(body, this.secret, this.enc_cnf); } for (let i = 0; i < arr.length; i++) { if(this.sync_config[arr[i]]){ this.sync_config[arr[i]] = fs.readFileSync(this.sync_config[arr[i]]) if(arr[i] === 'ca'){ this.sync_config[arr[i]] = [this.sync_config[arr[i]]] } } } this.sync_config.headers['Content-Length'] = body.length; utils.req($this, 'sync_config', config, function(err,data){ if(err){return cb(err)} try { data = $this.deserialize(data); cb(false, data); utils.cl(vb,['status','db from '+ $this.sync_config.hostname +' cached and ready.'],96); } catch (err) { throw err; } }) } } function tweek(src) { const db = _.chain({}); _.prototype.save = _.wrap(_.prototype.value, function(func, cb) { if(!cb){ return db.save(func.apply(this)) } else { db.save(func.apply(this), function(err,res){ if(err){return cb(err)} cb(false,res) }) } }) if(config.static.enabled){ _.prototype.static = _.wrap(_.prototype.value, function(func, title, cb) { if(!cb){ return src.static(func.apply(this), title) } else { src.static(func.apply(this), title, function(err,res){ if(err){return cb(err)} cb(false,res) }) } }) } _.prototype.val = _.prototype.value function set_state(state) { db.__wrapped__ = state return db } db._ = _ db.load = function(cb){ if(!cb){ return set_state(src.load()) } else { src.load(function(err,data){ if(err){return cb(err)} cb(false, set_state(data)) }) } } if(config.fetch.enabled){ db.fetch = function(cb){ src.fetch(function(err,data){ if(err){return cb(err)} cb(false, set_state(data)) }) } } if(config.sync.enabled){ db.sync = function(cb){ src.sync(db.val(), cb) } } db.save_state = function(data, cb){ if(!cb){ src.save(db.val()); return data; } else { src.save(db.val(), function(err){ if(err){return cb(err)} cb(false, data) }) } } db.backup = function(cb){ return src.set_backup(db.val(), cb); } if(config.turbo.enabled){ let timeout; db.save = function(data, cb) { const later = function() { timeout = null; db.save_state(data, cb) }; if(!timeout || typeof timeout === 'object'){ clearTimeout(timeout); timeout = setTimeout(later, config.turbo.ms); if(typeof timeout === 'object'){ if(cb){ return cb(false) } return true } } } } else { db.save = db.save_state; } db.cache = function(state){ return set_state(state); } if(config.settings.crypto_utils){ let cnf_enc = config.encryption; db.hmac = function(data, secret){ return enc.hmac(data, secret, config.hmac.digest, config.hmac.encode); } db.hash = function(data){ return enc.hash(data, config.hmac.digest, config.hmac.encode); } db.uuid = enc.uuidv4; db.rnd = enc.rnd; db.encrypt = function(data, secret){ if(!secret){ secret = cnf_enc.secret; } return enc.encrypt(data, secret, cnf_enc.settings); } db.decrypt = function(data, secret){ if(!secret){ secret = cnf_enc.secret; } return enc.decrypt(data, cnf_enc.secret, cnf_enc.settings); } db.keygen = function(){ return enc.keygen( cnf_enc.secret_len, cnf_enc.iterations, cnf_enc.settings.digest, cnf_enc.settings.encode ) } } if(config.settings.dev){ db.clone_config = function(){ fs.writeFileSync(cnf_url, JSON.stringify(config,0,2)) } } if(config.cron.enabled){ utils.cl(vb,['build','initializing cron tasks...'],96); setInterval(function(){ src.cron_job(db.value()) },config.cron.ms) } utils.cl(vb,['build','build status success.'],96); return db; } module.exports = { tweek, tweekdb }