Skip to content

Instantly share code, notes, and snippets.

@shimondoodkin
Created February 13, 2012 19:35
Show Gist options
  • Select an option

  • Save shimondoodkin/1819395 to your computer and use it in GitHub Desktop.

Select an option

Save shimondoodkin/1819395 to your computer and use it in GitHub Desktop.
json database for node.js , preserves recursive data structures. may need a cleanup a little bit.
/**
* Module dependencies.
*/
var express = require('express')
, routes = require('./routes')
var app = module.exports = express.createServer();
// Configuration
app.configure(function(){
app.set('views', __dirname + '/views');
app.set('view engine', 'ejs');
app.use(express.bodyParser());
app.use(express.methodOverride());
app.use(app.router);
app.use(express.static(__dirname + '/public'));
});
app.configure('development', function(){
app.use(express.errorHandler({ dumpExceptions: true, showStack: true }));
});
app.configure('production', function(){
app.use(express.errorHandler());
});
// Routes
app.get('/', routes.index);
app.get('/run', routes.run);
app.listen(3000);
console.log("Express server listening on port %d in %s mode", app.address().port, app.settings.env);
process.on('uncaughtException', function (err) {
console.log('Caught exception: ' + err.stack);
});
function handleexit(cb)
{
var f=require.resolve('./get.js');
if(require.cache[f])
{
//console.log('a',require.cache[f]);
if(require.cache[f].exports.unload)
require.cache[f].exports.unload(cb)
else
if(cb)cb();
}
else
if(cb)cb();
}
process.on('SIGTERM', function () {
console.log('Got SIGTERM, will exit in 10 seconds ');
var num=1;
var n=setInterval(function(){
console.log(num)
num++;
},1000);
var c=setTimeout(function(){
if(n)clearTimeout(n);
process.exit(0);
},10000)
handleexit(function(){
if(c)clearTimeout(c);
if(n)clearTimeout(n);
process.exit(0);
})
});
process.on('SIGINT', function () {
console.log('Got SIGINT, will exit in 10 seconds ');
var num=1;
var n=setInterval(function(){
console.log(num)
num++;
},1000);
var c=setTimeout(function(){
if(n)clearTimeout(n);
process.exit(0);
},10000)
handleexit(function(){
if(c)clearTimeout(c);
if(n)clearTimeout(n);
process.exit(0);
})
});
// var f=require.resolve('../../get.js');if(require.cache[f]){if(require.cache[f].unload) require.cache[f].unload()}delete require.cache[f];f=require(f);
// f.run(req,res);
exports.querystring=require('querystring');
var EventEmitter = require('events').EventEmitter;
EventEmitter.prototype._maxListeners=1000;
exports.unload=function(cb)
{
if(cb)cb();
}
///////////string between:
String.prototype.between = function(prefix, suffix) {
var r,s,pl,sl,e;
if(prefix instanceof RegExp)
{
r=prefix.exec(this);
if(r==null)s=-1; else s=r.index;
pl=r[0].length
}
else
{
s = this.indexOf(prefix);
pl= prefix.length
}
if (s == -1) { return ' error:between-no-start '; }
if(suffix instanceof RegExp)
{
r=suffix.exec(this.substring(s+pl,this.length));
if(r==null) e=-1; else e=r.index+s+pl;
sl=r[0].length
}
else
{
e = this.indexOf(suffix,s+pl);
sl= suffix.length
}
if (e == -1) { return ' error:between-no-end '; }
return this.substring(s+pl, e);//e
}
String.prototype.php_split=function explode (delimiter, limit) {
var string=this.valueOf();
// Splits a string on string separator and return array of components. If limit is positive only limit number of components is returned. If limit is negative all components except the last abs(limit) are returned.
//
// version: 1109.2015
// discuss at: http://phpjs.org/functions/explode
// + original by: Kevin van Zonneveld (http://kevin.vanzonneveld.net)
// + improved by: kenneth
// + improved by: Kevin van Zonneveld (http://kevin.vanzonneveld.net)
// + improved by: d3x
// + bugfixed by: Kevin van Zonneveld (http://kevin.vanzonneveld.net)
// * example 1: explode(' ', 'Kevin van Zonneveld');
// * returns 1: {0: 'Kevin', 1: 'van', 2: 'Zonneveld'}
// * example 2: explode('=', 'a=bc=d', 2);
// * returns 2: ['a', 'bc=d']
var emptyArray = {
0: ''
};
// third argument is not required
if (arguments.length < 2 || typeof arguments[0] == 'undefined' || typeof arguments[1] == 'undefined') {
return null;
}
if (delimiter === '' || delimiter === false || delimiter === null) {
return false;
}
if (typeof delimiter == 'function' || typeof delimiter == 'object' || typeof string == 'function' || typeof string == 'object') {
return emptyArray;
}
if (delimiter === true) {
delimiter = '1';
}
if (!limit) {
return string.toString().split(delimiter.toString());
}
// support for limit argument
var splitted = string.toString().split(delimiter.toString());
var partA = splitted.splice(0, limit - 1);
var partB = splitted.join(delimiter.toString());
partA.push(partB);
return partA;
}
String.prototype.betweeninc = function(prefix, suffix) {
var r,s,pl,sl,e;
if(prefix instanceof RegExp)
{
r=prefix.exec(this);
if(r==null)s=-1; else s=r.index;
pl=r[0].length
}
else
{
s = this.indexOf(prefix);
pl= prefix.length
}
if (s == -1) { return ' error:between-no-start '; }
if(suffix instanceof RegExp)
{
r=suffix.exec(this.substring(s+pl,this.length));
if(r==null) e=-1; else e=r.index+s+pl;
sl=r[0].length
}
else
{
e = this.indexOf(suffix,s+pl);
sl= suffix.length
}
if (e == -1) { return ' error:between-no-end '; }
return this.substring(s, e+sl);//e
}
String.prototype.cuttailof = function(prefix) {
var s = this.indexOf(prefix);
if (s == -1) { return ' error:cuttailfrom-no-start '; }
return this.substring(0,s+prefix.length);
}
String.prototype.cuttailofinc = function(prefix) {
var s = this.indexOf(prefix);
if (s == -1) { return ' error:cuttailfrominc-no-start '; }
return this.substring(0,s);
}
String.prototype.cuttailfrom = function(prefix) {
var s = this.lastIndexOf(prefix);
if (s == -1) { return ' error:cuttailfrom-no-start '; }
return this.substring(0,s+prefix.length);
}
String.prototype.cuttailfrominc = function(prefix) {
var s = this.lastIndexOf(prefix);
if (s == -1) { return ' error:cuttailfrominc-no-start '; }
return this.substring(0,s);
}
String.prototype.cutheadfrom = function(suffix) {
var e = this.indexOf(suffix);
if (e == -1) { return ' error:cutheadfrom-no-end '; }
return this.substring(e);
}
String.prototype.cutheadfrominc = function(suffix) {
var e = this.indexOf(suffix);
if (e == -1) { return ' error:cutheadfrominc-no-end '; }
return this.substring(e+suffix.length);
}
String.prototype.pad = String.prototype.pad || function(len, chr, dir) {
var str = this.valueOf();
len = (typeof len == 'number') ? len : 0;
chr = (typeof chr == 'string') ? chr : ' ';
dir = (/left|right|both/i).test(dir) ? dir : 'right';
var repeat = function(c, l) { // inner "character" and "length"
var repeat = '';
while (repeat.length < l) {
repeat += c;
}
return repeat.substr(0, l);
}
var diff = len - str.length;
if (diff > 0) {
switch (dir) {
case 'left':
str = '' + repeat(chr, diff) + str;
break;
case 'both':
var half = repeat(chr, Math.ceil(diff / 2));
str = (half + str + half).substr(1, len);
break;
default: // and "right"
str = '' + str + repeat(chr, diff);
}
}
return str;
};
Number.prototype.pad = Number.prototype.pad || String.prototype.pad;
String.prototype.repeat = String.prototype.repeat || function(count) {
if (count < 1) return '';
var result = '', pattern = this.valueOf();
while (count > 0) {
if (count & 1) result += pattern;
count >>= 1, pattern += pattern;
};
return result;
};
Number.prototype.escapeHtml=String.prototype.escapeHtml=function escapeHtml() {
return this.valueOf()
.replace(/&/g, "&amp;")
.replace(/</g, "&lt;")
.replace(/>/g, "&gt;")
.replace(/"/g, "&quot;")
.replace(/'/g, "&#039;");
}
////////////object clone:
var ce=require('cloneextend'); // npm install cloneextend
//console.log({aa:'bb',dd:new Date('10/10/2011')});
//console.log(ce.clone({aa:'bb',dd:new Date('10/10/2011')}));
exports.clone=ce.clone;
exports.extend=ce.extend;
Object.prototype.clone = function (name,recourlist,recourvalues)
{
var srcInstance=this;
if( srcInstance == null || typeof(srcInstance) != 'object' )
return srcInstance;
if( srcInstance instanceof Date )
{
var newInstance = new srcInstance.constructor();
newInstance.setTime(srcInstance.getTime())
return newInstance ;
}
else if( srcInstance instanceof Number || srcInstance instanceof String || srcInstance instanceof Boolean )
{
return srcInstance.valueOf();
}
if(!(recourlist instanceof Array))recourlist=[];
var newInstance = srcInstance.constructor();
for(var i in srcInstance)
if(srcInstance.hasOwnProperty(i))
//newInstance[i] = clone.call(srcInstance[i],i);
newInstance[i] = arguments.callee.call(srcInstance[i],i);
return newInstance;
}
////////////
/*
* Date Format 1.2.3
* (c) 2007-2009 Steven Levithan <stevenlevithan.com>
* MIT license
*
* Includes enhancements by Scott Trenda <scott.trenda.net>
* and Kris Kowal <cixar.com/~kris.kowal/>
*
* Accepts a date, a mask, or a date and a mask.
* Returns a formatted version of the given date.
* The date defaults to the current date/time.
* The mask defaults to dateFormat.masks.default.
*/
var dateFormat = function () {
var token = /d{1,4}|m{1,4}|yy(?:yy)?|([HhMsTt])\1?|[LloSZ]|"[^"]*"|'[^']*'/g,
timezone = /\b(?:[PMCEA][SDP]T|(?:Pacific|Mountain|Central|Eastern|Atlantic) (?:Standard|Daylight|Prevailing) Time|(?:GMT|UTC)(?:[-+]\d{4})?)\b/g,
timezoneClip = /[^-+\dA-Z]/g,
pad = function (val, len) {
val = String(val);
len = len || 2;
while (val.length < len) val = "0" + val;
return val;
};
// Regexes and supporting functions are cached through closure
return function (date, mask, utc) {
var dF = dateFormat;
// You can't provide utc if you skip other args (use the "UTC:" mask prefix)
if (arguments.length == 1 && Object.prototype.toString.call(date) == "[object String]" && !/\d/.test(date)) {
mask = date;
date = undefined;
}
// Passing date through Date applies Date.parse, if necessary
date = date ? new Date(date) : new Date;
if (isNaN(date)) throw SyntaxError("invalid date");
mask = String(dF.masks[mask] || mask || dF.masks["default"]);
// Allow setting the utc argument via the mask
if (mask.slice(0, 4) == "UTC:") {
mask = mask.slice(4);
utc = true;
}
var _ = utc ? "getUTC" : "get",
d = date[_ + "Date"](),
D = date[_ + "Day"](),
m = date[_ + "Month"](),
y = date[_ + "FullYear"](),
H = date[_ + "Hours"](),
M = date[_ + "Minutes"](),
s = date[_ + "Seconds"](),
L = date[_ + "Milliseconds"](),
o = utc ? 0 : date.getTimezoneOffset(),
flags = {
d: d,
dd: pad(d),
ddd: dF.i18n.dayNames[D],
dddd: dF.i18n.dayNames[D + 7],
m: m + 1,
mm: pad(m + 1),
mmm: dF.i18n.monthNames[m],
mmmm: dF.i18n.monthNames[m + 12],
yy: String(y).slice(2),
yyyy: y,
h: H % 12 || 12,
hh: pad(H % 12 || 12),
H: H,
HH: pad(H),
M: M,
MM: pad(M),
s: s,
ss: pad(s),
l: pad(L, 3),
L: pad(L > 99 ? Math.round(L / 10) : L),
t: H < 12 ? "a" : "p",
tt: H < 12 ? "am" : "pm",
T: H < 12 ? "A" : "P",
TT: H < 12 ? "AM" : "PM",
Z: utc ? "UTC" : (String(date).match(timezone) || [""]).pop().replace(timezoneClip, ""),
o: (o > 0 ? "-" : "+") + pad(Math.floor(Math.abs(o) / 60) * 100 + Math.abs(o) % 60, 4),
S: ["th", "st", "nd", "rd"][d % 10 > 3 ? 0 : (d % 100 - d % 10 != 10) * d % 10]
};
return mask.replace(token, function ($0) {
return $0 in flags ? flags[$0] : $0.slice(1, $0.length - 1);
});
};
}();
// Some common format strings
dateFormat.masks = {
"default": "ddd mmm dd yyyy HH:MM:ss",
shortDate: "m/d/yy",
mediumDate: "mmm d, yyyy",
longDate: "mmmm d, yyyy",
fullDate: "dddd, mmmm d, yyyy",
shortTime: "h:MM TT",
mediumTime: "h:MM:ss TT",
longTime: "h:MM:ss TT Z",
isoDate: "yyyy-mm-dd",
isoTime: "HH:MM:ss",
isoDateTime: "yyyy-mm-dd'T'HH:MM:ss",
isoUtcDateTime: "UTC:yyyy-mm-dd'T'HH:MM:ss'Z'",
isoRFC: "ddd, d mmm yyyy HH:MM:ss o"
};
// Internationalization strings
dateFormat.i18n = {
dayNames: [
"Sun", "Mon", "Tue", "Wed", "Thu", "Fri", "Sat",
"Sunday", "Monday", "Tuesday", "Wednesday", "Thursday", "Friday", "Saturday"
],
monthNames: [
"Jan", "Feb", "Mar", "Apr", "May", "Jun", "Jul", "Aug", "Sep", "Oct", "Nov", "Dec",
"January", "February", "March", "April", "May", "June", "July", "August", "September", "October", "November", "December"
]
};
// For convenience...
Date.prototype.format = function (mask, utc) {
return dateFormat(this, mask, utc);
};
////////////html parsing tools
var htmlparser = require("htmlparser2");
function parsehtml(data,cb)
{
var handler = new htmlparser.DefaultHandler(function (error, dom) {cb(error,[data,dom]);});
var parser = new htmlparser.Parser(handler);
parser.write(data);
parser.done();
}exports.parsehtml=parsehtml;
function decode_entities(s)
{
if(s==undefined)return "";
return s.replace( /\&amp;/g, '&' ).replace( /\&nbsp;/g, ' ' ).replace( /\&quot;/g, '"' ).trim();
}exports.decode_entities=decode_entities;
var rxparams=/\s*([^\s=]+)\s*=\s*'([^']*)'|\s*([^\s=]+)\s*=\s*"([^"]*)"|\s*([^\s=]+)\s*=\s*([^\s>]+)\s*|\s*([^>\s]+)\s*/gmi;
function parse_params(str)
{
var params={},m;
if(str)
while((m=rxparams.exec(str))!==null)
{
//console.log(m)
//params.exec("a=aa b='bb' c=\"\" d")
if(m[1]!=undefined)
p=[
m[1], // 'b',
m[2], // 'bb',
"'"
]
//console.log(p)
if(m[3]!=undefined)
p=[
m[3],// 'c',
m[4],// '',
'"'
]
//console.log(p)
if(m[5]!=undefined)
p=[
m[5],// 'a',
m[6],// 'aa',
""
]
//console.log(p)
if(m[7]!=undefined)
p=[
m[7],// 'd',
true,
"novalue"
]
//console.log(p)
if(typeof p[1]=="boolean")
params[decode_entities(p[0].toLowerCase())]=p[1];
else
params[decode_entities(p[0].toLowerCase())]=decode_entities(p[1]);
//allp.push(p);
}//while tags
return params;
}
var inputrxtags=/<input(\s*(\s*[^\s=]+\s*=\s*'[^']*'|\s*[^\s=]+\s*=\s*"[^"]*"|\s*[^\s=]+\s*=\s*[^\s>]+\s*|\s*[^>\s]+\s*)*\s*)>/gmi;
function get_input_tags(data)
{
var tags=[],t;
while((t=inputrxtags.exec(data))!==null)
{
tags.push(parse_params(t[1]))
//all.push([t[0],t[1],allp])
}//while tag
return tags;
}
exports.get_input_tags=get_input_tags;
//get_input_tags("<INPUT AAA=\"XXX\" sss='aa'><input ff=xx ><input ddd=\"\" ><input cc >")
function getform(data,formname)
{
data=data.between(new RegExp("<form.*"+formname+".*>","im"),"</form>");
var inputs=get_input_tags(data);
inputs=inputs.filter(function(i)
{
if(!i.name||i.name=='') return false;
if(i.type=='checkbox')
{
if(i.checked)
return true;
else
return false;
}
else
{
return true;
}
});
var re_num=/^[-]{0,1}\d+[\.]{0,1}\d*$/
var a={};inputs.forEach(function(i)
{
a[i.name]=i.value==undefined?(i.type.toLowerCase()=='checkbox'?'on':''):( re_num.test(i.value)?parseFloat(i.value):i.value );
});
inputs=a;
return inputs;
}exports.getform=getform;
function getformtag(data,formname)
{
var rxtags=new RegExp("<form(.*"+formname+".*)>","im");
var t;
while((t=rxtags.exec(data))!==null)
{
return parse_params(t[1]);
};
return {notfound:true};
}exports.getformtag=getformtag;
function printpaths(name,obj)
{
var re_num=/^\d+$/, re_validname=/^[a-zA-Z][a-zA-Z0-9]*$/;
function smartjoin(a)
{
var s='';
for(var i=0;i<a.length;i++)
{
if( re_num.test(a[i]) )
s+='['+a[i]+']'
else if( re_validname.test(a[i]) )
s+=(i>0?'.':'')+a[i]
else
{
s+='[';
try{s+=JSON.stringify(a[i])}catch(e){s+='error'}
s+=']';
}
}
return s;
}
var t="",s=[name],printed=[];
function recur(o)
{
if(printed.indexOf(o)==-1)
{
printed.push(o)
for(var i in o)
{
if(Object.hasOwnProperty.call(o,i))
{
s.push(i);
if(o[i] instanceof Array)
recur(o[i]);
else if(typeof o[i] == 'function')
t+=smartjoin(s)+'='+JSON.stringify(o[i].toString())+'\r\n';
else if(typeof o[i] == 'object')
recur(o[i]);
else
t+=smartjoin(s)+'='+JSON.stringify(o[i])+'\r\n';
s.pop();
}
}
}
}
if(obj instanceof Array)
recur(obj);
else if(typeof obj == 'function')
t+=smartjoin(s)+'='+JSON.stringify(obj[i].toString())+'\r\n';
else if(typeof obj == 'object')
recur(obj);
else
{
t+=smartjoin(s)+'=';
try{
t+=JSON.stringify(obj)+'\r\n';
}catch(e){
t+=':error:';
}
}
return t;
}exports.printpaths=printpaths;
////////////request
var request1=require('request');
var Iconv=require('iconv').Iconv;
var iconv_utf8_to_latin = new Iconv('utf-8','iso-8859-1');
var iconv_iso8859_8i_to_utf8 = new Iconv('iso-8859-8','utf-8');
function request(options,cb)
{
if(options.encoding=='iso-8859-8')
{
options.encoding='binary';
return request1(options, function(error,request,data){
try{
var data2=iconv_iso8859_8i_to_utf8.convert(iconv_utf8_to_latin.convert(data)).toString('utf8') //conver buffer to string
}
catch(e)
{
data2=null;
error=e;
}
cb(error,request,data2);
});
}
else
return request1(options,cb);
}
request.__proto__=request1;
exports.request=request;
////////////json
function stringify_stats(a,stats,context)
{
var clean_context;
if(typeof a === 'object')
{
if(!context)
{
clean_context=true;
stats=[a];
context=[];
}
else
{
a_pos=context.indexOf(a);
if( a_pos!=-1 )
{
if(stats.indexOf(a)==-1)
{
stats.push(a);
}
return;
}
}
if(context.length>900&&context.length%1000==0) console.log("doing stringify. objects done: "+context.length)
context.push(a);
if (a instanceof Array)
{
for(var l=a.length,key=0;key<l;key++)
{
if(typeof a[key] === 'object' && a[key] !== null)
stringify_stats(a[key], stats, context );
}
}
else
{
var comma=false
for (key in a)
{
if(Object.prototype.hasOwnProperty.call(a, key))
{
if(typeof a[key] === 'object' && a[key] !== null)
stringify_stats(a[key],stats,context );
}
}
}
if(clean_context)
{
delete context;
return stats;
}
}
else
return [];
}
function stringify_var(a,file)
{
if(a === undefined)
{
if(file)
{
file.write('undefined');
return;
}
else
return 'undefined';
}
else if(typeof a === 'object' && a === null)
{
if(file)
{
file.write('null');
return;
}
else
return 'null';
}
else if(typeof a === 'function')
{
if(file)
{
file.write(a.toString());
return;
}
else
return a.toString();
}
else if(a instanceof Date)
{
if(file)
{
file.write('new Date("'+a.toString()+'")');
return;
}
else
return 'new Date("'+a.toString()+'")';
}
else
{
if(file)
file.write(JSON.stringify(a));
else
return JSON.stringify(a);
}
}
function stringify(a ,varname,prefix ,sufix,file,callback,context,stats )
{
var out,clean_context;
if(typeof a !== 'object')
{
if(file)
file.write(JSON.stringify(a))
else
out=JSON.stringify(a);
return out;
}
else
{
if(context===undefined)
{
clean_context=true;
if(!varname) varname='self';
if(!prefix) prefix='';
if(!sufix) sufix='';
context=[];
stats=stringify_stats(a); // find used self references
//console.log('stats done');
// put the first element and the stack in.
out=prefix+'var '+varname+'_temp=[],'+varname+'='+varname+'_temp[0]=';
if(file)file.write(out);
}
else
{
out="";
a_pos=context.indexOf(a);
if( a_pos!=-1 )
{
a_pos=stats.indexOf(a);
if( a_pos!=-1 )
{
if(file){file.write(varname+"_temp["+a_pos+"]"); return;}
else
return varname+"_temp["+a_pos+"]";
}
}
else
{
a_pos=stats.indexOf(a);
if( a_pos!=-1 )
{
if(file)
file.write(varname+"_temp["+a_pos+"]=");
else
out+=varname+"_temp["+a_pos+"]=";
}
}
}
if(context.length>900&&context.length%1000==0) console.log(context.length)
context.push(a);
var do_stringify_var=false;
if (a instanceof Array)
{
if(file)
file.write("[");
else
out+="[";
for(var l=a.length,key=0;key<l;key++)
{
if(key!=0)
{
if(file)
file.write(",");
else
out+=',';
}
do_stringify_var=false;
if(typeof a[key] === 'object')
{
if( a[key] === null )
{
do_stringify_var=true;
}
else if( a[key].constructor.name==='Object' || a[key] instanceof Array )
{
if(file)
stringify(a[key],varname,null,null,file,null,context,stats );
else
out+=stringify(a[key],varname,null,null,file,null,context,stats );
}
else
{
do_stringify_var=true;
}
}
else
{
do_stringify_var=true;
}
if(do_stringify_var)
{
if(file)
stringify_var(a[key],file);
else
out+=stringify_var(a[key]);
}
}
if(file)
file.write(']');
else
out+=']';
}
else
{
if(file)
file.write('{');
else
out+="{";
var comma=false
for (key in a)
{
if(Object.prototype.hasOwnProperty.call(a, key))
{
if(comma)
{
if(file)
file.write(',');
else
out+=',';
}
else
comma=true;
if(file)
{
file.write(JSON.stringify(key));
file.write(':');
}
else
{
out+=JSON.stringify(key);
out+=':';
}
do_stringify_var=false;
if(typeof a[key] === 'object')
{
if( a[key] === null )
{
do_stringify_var=true;
}
else if( a[key].constructor.name==='Object' || a[key] instanceof Array )
{
if(file)
stringify(a[key],varname,null,null,file,null,context,stats );
else
out+=stringify(a[key],varname,null,null,file,null,context,stats );
}
else
{
do_stringify_var=true;
}
}
else
{
do_stringify_var=true;
}
if(do_stringify_var)
{
if(file)
stringify_var(a[key],file);
else
out+=stringify_var(a[key]);
}
}
}
if(file)
file.write('}');
else
out+="}";
}
if(clean_context)
{
delete context;
delete stats;
if(file)
file.write(";delete "+varname+'_temp;'+sufix);
else
out+=";delete "+varname+'_temp;'+sufix;
//console.log('stringify done');
if(callback)callback();
}
}
return out;
}
exports.stringify=stringify; // a very good function it preserves recursive data structure, but returns regular javascript, not json.
var fs=require('fs');
exports.fs=fs;
var path=require('path');
function save_json( object, filename, callback )
{
if(!filename) throw new Error("No filename defined (wrong arguments)");
file = fs.createWriteStream(filename,{ 'flags': 'w+', /*'encoding': 'utf-8',*/ 'mode': 0777});
stringify(object,"obj","","module.exports=obj;",file, function(){
file.end();
if(callback)callback();
});
}exports.save_json=save_json;
function load_json( object, filename)
{
// to prevent saving the source of the loaded file in memory
// load the file, clone the object and return the cloned object
// then unload the module
if(!filename) throw new Error("No filename defined (wrong arguments)");
if(!path.existsSync(filename)) return object;
var f=require.resolve(filename);
var o=require(f);
var oo=ce.clone(o);// clone it is a prototyped function from above
delete o;
if(require.cache[f])delete require.cache[f];
//if(callback)callback();
//else
return oo;
}exports.load_json=load_json;
/// simple in memory json database
var database={};
exports.database=database;
exports.database_dir=__dirname+'/database';
function load_data(name,default_object)
{
if(database[name]) return;
var file=path.resolve(exports.database_dir,name+'.js');
var d=
{
name:name,
file:file,
last_saved:new Date(),
last_activity:new Date(),
mark:function()
{
this.__proto__.last_activity=new Date();
},
save:function(cb)
{
save_data(name,cb)
},
unload:function(cb)
{
unload_data(name,cb)
}
//,onsave:function(db,cb){ do_something_with(db); if(cb)cb();};
//,onunload:function(db,cb){ do_something_with(db); if(cb)cb();};
}
var db=load_json( default_object, file );
db.__proto__=d;
database[name]=db;
return db;
}
function save_data(name,cb)
{
if(!database.hasOwnProperty(name)) return;
var d=database[name];
if(d.__proto__.last_activity>d.__proto__.last_saved)// checked 3 times little too much...
{
function save()
{
if(d.__proto__.last_activity>d.__proto__.last_saved) // check again maybe on save modified something
{
save_json( d, d.file, cb )
d.__proto__.last_saved=new Date();
}
else
if(cb)cb();
}
if(d.onsave)
d.onsave(d,save);
else
save();
}
else
if(cb)cb();
}
function unload_data(name,cb)
{
if(!database.hasOwnProperty(name)) return;
var d=database[name];
function unload()
{
save_data(d.name,function(){
delete database[name];
if(cb)cb();
});
}
if(d.onunload)
d.onunload(d,unlaod);
else
unload();
}
var async=require('async');
exports.async=async;
var saveing_data=false;
function saveall_data(cb)
{
if(saveing_data)return;
saveing_data=true;
var loop_keys=Object.keys(database);
function next()
{
if(loop_keys.length>0)loop();
else
{
saveing_data=false; if(cb)cb();
}
}
function loop()
{
var name=loop_keys.pop();
var d=database[name];
if(d.__proto__.last_activity>d.__proto__.last_saved)
{
save_data(name,next)
}
else
{
next()
}
}
next();
}
database.__proto__={
load:load_data, //f.database.load('myname',default_object)
unload:unload_data, //f.database.unload('myname',function cb(){})
save:save_data, //f.database.save('myname',function cb(){})
saveall:saveall_data // //f.database.saveall(function cb(){})
}
// f.database.myname.value=1
// f.database.myname.mark();
setInterval(saveall_data,10000);
//create folder database
var f=require('./functions.js')
f.loadall_data();
f.database.load('test',{newval:1});
console.log(f.database.test);
f.database.test.gg=6
console.log(f.database.test);
f.database.test.mark(); // mark to save later in10 seconds, call it each time you modify something.
f.database.test.save();
f.database.saveall();
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment