gun/node_modules/coalesce/coalesce.js
2014-04-01 15:57:24 -06:00

722 lines
23 KiB
JavaScript

module.exports=require('theory')((function(){
var web = {};
web.name = 'web';
web.version = 1.9;
web.author = 'Mark';
web.dependencies = [
'fs'
,'url'
,'path'
,'http'
,'https'
,'child_process'
];
web.init = (function(a){
function web(opt){
return web.configure(opt);
} var fs = a.fs
, path = a.path
, URL = a.url;
web.opt = {};
web.configure = (function(opt){
if(opt.how){ return }
module.reqdir = a.path.dirname((module.parent||{}).filename);
opt = a.obj.is(opt)? opt : {};
opt.host = opt.host||'localhost';
opt.port = opt.port||80;
opt.dir = opt.dir || module.reqdir || __dirname;
if(a.bi.is(opt.sec)){
opt.sec = {};
} else if(a.num.is(opt.sec)){
opt.sec = (opt.sec === -2)? {relay: true, incognito: true} : opt.sec; // incognito, eh?
}else if(a.obj.is(opt.sec)){
} else {
opt.sec = {};
}
opt.session = opt.session||{};
opt.session.sid = opt.session.sid||(function(){ return a.text.random(16) });
opt.session.tid = opt.session.tid||(function(){ return a.text.random(16) });
opt.session.expire = opt.session.expire||1000*60*60*24*7*4;
opt.session.wait = opt.session.wait||1000*60*2;
opt.cache = opt.cache||{};
opt.cache.age = opt.cache.age||0;
opt.com = opt.com||{};
opt.com.log = opt.com.log || function(w,m){};
opt.com.prefix = opt.com.prefix||'/com';
opt.com.url = opt.com.url||"http"+((opt.sec.key&&opt.sec.cert)?'s':'')+"://"
+opt.host+(opt.port?':'+opt.port:'')
+(opt.com.path||"/node_modules/sockjs/sockjs-0.3.min.js");
if(a.list.is(opt.run)){
var run = opt.run;
opt.run = {};
opt.run.is = run;
} opt.run = opt.run||{};
opt.run.impatient = opt.run.impatient||1000*3;
opt.hook = opt.hook||{};
opt.hook.pre = opt.hook.pre||(function(){});
opt.hook.aft = opt.hook.aft||(function(){});
opt.hook.err = opt.hook.err||(function(){});
opt.hook.reply = opt.hook.reply||(function(){});
opt.node = opt.node||{};
opt.node.mid = opt.node.mid || a.text.r(16);
web.opt = a.obj(opt).u(web.opt||{});
web.theorize();
web.run(opt.run.is);
web.state();
return web;
});
a.text.find.js = /\.js$/i;
web.state = (function(){
function state($){
state.com = sock.createServer({
sockjs_url: web.opt.com.url
});
state.dir = new ns.Server(web.opt.dir);
if(web.opt.sec.key && web.opt.sec.cert){
state.on = a.https.createServer({key: web.opt.sec.key, cert: web.opt.sec.cert});
} else {
state.on = a.http.createServer();
}
state.on.addListener('request',state.req);
state.on.addListener('upgrade',function(req,res){
if(state.sent(res)){ return }
res.end();
});
state.on.listen(web.opt.port, web.opt.host);
state.com.on('connection',state.con);
state.com.installHandlers(state.on,web.opt.com);
if(web.opt.node && web.opt.node.src){
if(!a.list.is(web.opt.node.src)){
web.opt.node.src = [web.opt.node.src];
}
a.list(web.opt.node.src).each(function(url){
var toe = toes.create(url);
web.node.cons[url] = toe;
toe.on('error', function(e){ console.log('ut-oh', e) }); // need to add this before the connection event.
toe.on('connection', function(){
toe.writable = true;
toe.mid = url;
toe.write(a.text.ify(a.com.meta({
what: {auth: web.opt.node.key, to: url}
,where: {mid: web.opt.node.mid}
})));
state.con(toe);
});
});
}
return web;
}
var mime = require('mime')
, ns = require('node-static')
, formidable = require('formidable')
, toes = require('sockjs-client')
, sock = require('sockjs');
state.ways = [];
state.sort = (function(A,B){
if(!A || !B){ return 0 }
A = A.flow; B = B.flow;
if(A < B){ return -1 }
else if(A > B){ return 1 }
else { return 0 }
});
state.map = (function(req,map){
var url = req.url || url;
map = map || state.ways;
return a.list(map).each(function(v,i){
if(!a.obj.is(v)){ return }
if(v.flow < (req.flow||-Infinity)){ return }
v.params = v.params || [];
if(a.text.is(v.match)){
v.regex = state.regex(v);
} if(a.text.is(v.regex)){
v.regex = new RegExp(v.regex,v.flags);
} if(a.test(v.regex).of(RegExp)){
var r = v.regex.exec(url.pathname);
if(r){
url.params = state.regex(v,r||[]);
return v;
}
} if(a.fns.is(v.match)){
if(v.match(url)){ return v}
}
})||{flow:Infinity,on:state.err};
return (0 <= r.flow && (fs.existsSync||path.existsSync)(url.file))?
url.file : r.file || url.file;
});
state.regex = (function(m,r){ // via expressjs
try{
var path = m.match, keys = m.params||[], params = {}, sensitive, strict;
if(r){ m = r;
for (var i = 1, len = m.length; i < len; ++i) {
var key = keys[i - 1];
var val = 'string' == typeof m[i]
? decodeURIComponent(m[i]) : m[i];
if (key) {
params[key.name] = val;
} else {
params[i] = val;
}
}
return params;
}
if (path instanceof RegExp) return path;
if (Array.isArray(path)) path = '(' + path.join('|') + ')';
path = path
.concat(strict ? '' : '/?')
.replace(/\/\(/g, '(?:/')
.replace(/(\/)?(\.)?:(\w+)(?:(\(.*?\)))?(\?)?(\*)?/g, function(_, slash, format, key, capture, optional, star){
keys.push({ name: key, optional: !! optional });
slash = slash || '';
return ''
+ (optional ? '' : slash)
+ '(?:'
+ (optional ? slash : '')
+ (format || '') + (capture || (format && '([^/.]+?)' || '([^/]+?)')) + ')'
+ (optional || '')
+ (star ? '(/*)?' : '');
})
.replace(/([\/.])/g, '\\$1')
.replace(/\*/g, '(.*)');
return new RegExp('^' + path + '$', sensitive ? '' : 'i');
} catch(e){ console.log("something has gone expressively wrong."); }
});
state.sent = (function(res){
if(res.headerSent) { return true }
});
state.url = (function(req){
var url = a.obj.is(req.url)? req.url : URL.parse(req.url,true);
url.ext = url.ext || path.extname(url.pathname).replace(/^\./,'');
return url;
});
state.file = (function(req,dir){
return path.normalize(path.join(dir||web.opt.dir,req.url.pathname));
});
state.way = (function(req){
var p = a.text.is(req||'')? req : (req.map.file || req.file) || '';
return path.basename(p,path.extname(p));
});
state.err = (function(req,res){
web.cookie.set(res,req.cookies);
state.dir.serve(req,res,function(e,r){
if(!e){ return web.opt.hook.aft(req,res) }
if(!req.flow){ return state.req(req,res,++req.flow) }
if(web.opt.hook.err(req,res,e,r)){ return }
if(state.sent(res)){ return }
res.writeHead(e.status, e.headers);
res.end();
});
});
state.ways.push({
way: 'state'
,match: '*'
,flow: 0
,on: state.err
})
state.req = (function(req,res){
req.url = state.url(req);
req.file = state.file(req);
req.map = state.map(req);
req.flow = req.map.flow;
req.cookies = web.cookie.parse(req);
req.cookies.sid = req.cookies.sid || web.opt.session.sid();
web.opt.hook.pre(req,res);
if(web.theorize(req,res)){ return }
if(req.flow === Infinity){ return state.err(req,res) }
a.fns.flow([function(next){
web.run.it({
file: req.map.file || req.file
,invincible: req.map.file
,reply: state.msg
},function(v){
if(v && (v=((v=state.way(req))+'.'
+a(web.run.on,v+'.meta.state.way')))
){
if(a.text(req.method).low() == 'post'){
var form = new formidable.IncomingForm();
req.form = {}; req.files = {};
form.on('field',function(k,v){
req.form[k] = v;
}).on('file',function(k,v){
if(!req.files[k]){ req.files[k] = [] }
(req.files[k]||[]).push(v);
}).on('error',function(e){
console.log("formidable error:",e);
if(form.done){ return }
next(form.done = v);
}).on('end', function(){
if(form.done){ return }
next(form.done = v);
});
return form.parse(req);
} return next(v);
} state.err(req,res);
});
},function(way,next){
var m = a.com.meta({how:{way:way,web:'state'},where:{pid:0}});
m.what.url = req.url;
m.what.form = req.form;
m.what.files = req.files;
m.what.cookies = req.cookies;
m.what.headers = req.headers;
m.what.method = a.text(req.method).low();
web.reply(m,function(m){
web.opt.hook.reply(m);
if(m && m.what !== undefined){
if(m.what.type !== undefined){
var type = mime.lookup(m.what.type||'')
,chs = mime.charsets.lookup(type);
res.setHeader('Content-Type', type + (chs ? '; charset=' + chs : ''));
} if(m.what.encoding !== undefined){
res.setHeader('Content-Encoding', m.what.encoding);
} if(m.what.cache !== undefined){
if(m.what.cache === 0){
res.setHeader('Cache-Control', 'no-cache, no-store, must-revalidate');
res.setHeader('Pragma', 'no-cache');
res.setHeader('Expires', 0);
} else {
res.setHeader('Cache-Control', m.what.cache);
}
} web.cookie.set(res,m.what.cookies||req.cookies);
if(m.what.status !== undefined){
res.statusCode = m.what.status;
} if(m.what.redirect !== undefined){
res.setHeader('Location', m.what.redirect);
res.statusCode = m.what.status || 302;
if(state.sent(res)){ return }
return res.end();
} if(m.what.body !== undefined){
if(state.sent(res)){ return }
res.end(a.text.is(m.what.body)?m.what.body:a.text.ify(m.what.body));
return web.opt.hook.aft(req,res);
} req.url.pathname = m.what.pathname||a(m.what,'url.pathname')||req.url.pathname;
if(req.flow === 0){ return state.err(req,res) }
req.flow = (m.what.flow === null)? Infinity :
a.num.is(m.what.flow)? m.what.flow : (req.flow + 1);
} next(req,res);
});
}],state.req);
});
state.msg = (function(m,opt,con){
if(!a.obj.is(m)) return;
var way = a(m,'how.way')||a(m,'way')||''
,opt = opt||{}, g;
way = a.text(way).clip('.',0,1);
if(opt != way){
if(web.run.on[way] && (g = web.run.on[way].meta) && !g.fatal){
var to = web.run.to(way);
if(way !== g.name && m && m.how && m.how.way){
m.how.way = m.how.way.replace(way, g.name);
}
to.com && to.com.send && to.com.send(m);
to.count++;
return;
} else
if(a[way]){ // TODO: Warning this is a no-joke condition! It is now on bottom, but should still think about bug edge cases like "test".
a(a(m,'how.way')+'->')(m);
return;
}else{}
if(!web.opt.sec.relay){
return;
}
}
if((con = state.sub(m)) && (m.where.on||m.where.off||m.where.at)){
m.where.at = m.where.on||m.where.off||m.where.at;
delete m.where.on;
delete m.where.off;
web.event.emit(m.where.at,m);
// toes should go here too!
return;
}
if((con = state.con.s[m.who.to]) && con.writable){
return con.write(a.text.ify(state.con.clean(m)));
}
a.obj(web.node.cons).each(function(con,i){ // distinguish between 'reply' and 'send'!
if(!con || !con.write){ return }
con.write(a.text.ify(m));
});
});
state.sub = (function(m,opt,con){
if( !a.obj.is(m) || !a.obj.is(m.where) ||
!a(m,'who.tid') || !(con = state.con.s[m.who.tid])) return;
if(m.where.off){
if(!con.hear[m.where.off]) return;
web.event.off(con.hear[m.where.off]);
delete con.hear[m.where.off];
return con;
} if(con.hear[m.where.on]) return con;
con.hear[m.where.on] = web.event.on(m.where.on,function(m){
if(!con.writable || con.tid == m.who.tid || !state.con.s[con.id]) return;
con.write(a.text.ify(state.con.clean(m)));
});
return con;
});
state.con = (function(con){
con.hear = {};
state.con.s[con.id] = con;
con.on('data',function(m){
m = a.com.meta(a.obj.ify(m),con);
if(web.node.auth(con,m)){ return }
web.cookie.tid(con,m,function(v){
if(!v){ return }
if(web.name == a.list(m.how.way.split('.')).at(1)){
m.how.way = '';
} m.where.pid = (m.where.pid === process.pid)? 0 : m.where.pid;
state.msg(m);
});
});
con.on('close',function(m){
console.log(con.id+" disconnected.");
a.obj(con.hear).each(function(v,i){
web.event.off(v);
});
delete state.con.s[con.id];
if(con.mid){
delete web.node.cons[con.mid];
}
});
con.on('error', function(e){ // TODO: if mid try to reconnect!
console.log('con error', e);
});
});
state.con.s = {};
state.con.clean = (function(m){
if(!m) return {};
m.who = {tid:m.who.tid,sid:m.who.sid
,to:m.who.to,from:m.who.from
,of:m.who.of,via:m.who.via
};
return m;
});
return state;
})();
web.reply = (function(m,fn){
if(fn){
web.run.res[m.when] = fn;
web.state.msg(m,m.how.way);
return;
}
if(fn = web.run.res[m.when]){
fn(m);
delete web.run.res[m.when];
return;
}
});
web.cookie = (function(){
function cookie($){
return web;
}
cookie.tryst = {};
cookie.parse = (function(m){
var l,p,c={};
if(a(m,'headers.cookie')){
l = m.headers.cookie.split(/\s?;\s?/ig);
a.list(l).each(function(v,i){
p = v.split(/=/);
c[p[0]] = p.slice(1).join('=');
});
} return c;
});
cookie.set = (function(res,c,tid){
var h = res.getHeader('Set-Cookie') || [], m;
if(a.text.is(h)){ h = [h] }; c = c || {};
if(c.sid){
c.sid = {value: c.sid.value || c.sid.val || c.sid, HttpOnly:true};
}
if(c.tid){
if(!tid){ delete c.tid; }
else{
c.tid = {value: c.tid.value || c.sid.tal || c.tid, HttpOnly:false};
}
}
c = a.obj(c).each(function(v,i,t){
if(a.text.is(v)){
v = {value: v};
} if(a.obj.is(v)){
i = i+'='+v.value || v.val || '';
m = a.obj(v).each(function(w,j,q){ q(a.text.low(j),w) })||{};
m.httponly = a.obj(m).has('httponly')? m.httponly : true;
m.path = m.path || '/';
if(m.path){ i += "; path=" + m.path }
if(m.expires){ i += "; expires=" + m.expires }
if(m.domain){ i += "; domain=" + m.domain }
if(m.secure){ i += "; secure" }
if(m.httponly){ i += "; HttpOnly" }
t(i);
}
})||[];
res.setHeader('Set-Cookie', a.list(h).fuse(c));
});
cookie.tid = (function(req,m,fn){
if(fn){
if(req.mid){
return fn(true);
}
if(req.sid || req.tid){
m.who = a.obj(req.who||{}).u(m.who);
m.how = a.obj(req.how||{}).u(m.how);
m.where = a.obj(req.where||{}).u(m.where);
m.who.tid = req.tid;
m.who.sid = req.sid;
return fn(true);
} if(m.who.tid){
// GETEX REDIS HERE
var s, t = a.time.is(), w, ws;
if(s = cookie.tryst[m.who.tid]){
web.state.con.s[req.tid = m.who.tid] = req;
req.sid = m.who.sid = s.sid;
if((w = a.text(m.how.way).clip('.',0,1)) && (ws=a(web.run.on,w+'.meta.stream.on'))){
var n = a.com.meta({what:s,who:m.who,how:{way:(w+='.'+ws),web:'stream'},where:{pid:0}});
n.what.data = m.what;
web.reply(n,function(n){
delete n.who.to;
delete n.where.pid;
delete n.how.way;
delete n.how.web;
req.who = n.who;
req.how = n.how;
req.where = n.where;
cookie.tid(req,m,fn);
});
} else {
fn(true);
}
} else {
if(web.opt.sec.incognito){ req.sid = req.tid = m.who.tid; fn(true) }
} delete cookie.tryst[m.who.tid];
a.obj(cookie.tryst).each(function(v,i){
if(web.opt.session.wait < t - v.ts){
delete cookie.tryst[i];
}
});
}
} if(req.url){
req.cookies = req.cookies||{};
// SETEX REDIS HERE
cookie.tryst[req.cookies.tid = web.opt.session.tid()]
= {sid: req.cookies.sid, ts: a.time.is()
, cookies: a.obj(req.cookies).each(function(v,i,t){
if(a.obj.is(v)){
t(i, v.value || v.val || '');
}else{
t(i, v || '');
}
})
}
return req.cookies;
}
});
return cookie;
})();
web.node = (function(){
function node(){
}
node.auth = function(con,m){
if(con.sid || con.tid){ return }
if(con.mid){
if(m.where){ m.where.mid = m.where.mid || con.mid }
return;
}
if(m && m.where && m.where.mid && m.what && m.what.auth){
console.log('node auth', m);
//console.log("auth machine...");
if(!web.opt.node || !web.opt.node.key){
con.close();
console.log("none");
return true;
}
if(m.where.mid === web.opt.node.mid){
con.close();
console.log("self");
return true;
}
if(m.what.auth === web.opt.node.key){
con.mid = m.where.mid;
web.node.cons[con.mid] = con;
console.log("machine auth success");
return true;
}
con.close();
return true;
}
}
node.cons = {};
return node;
})();
web.run = (function(){
function run($){
if(!$){ return web }
if(!a.list.is($)){
$ = [$];
} a.list($).each(function(v,i,t){
var p = v; p = p.slice(0,3) == '../'? module.reqdir+'/'+p : p;
p = p.slice(0,2) == './'? module.reqdir + p.slice(1) : p;
p = a.text.find.js.test(p)? p : p + '.js';
run.it({
file:p
,reply: web.state.msg
},function(v){ });
});
return web;
}
var spawn = a.child_process.spawn
, fork = a.child_process.fork;
run.on = {};
run.res = {};
run.it = (function(m,fn){
if(!m){ return }
var opt = m.what || m
, way = opt.way = web.state.way(opt.file);
if(way === theory.name){ return fn(false) }
if(opt.file == (module.parent||{}).filename){ return fn(false) }
if(!a.text.find.js.test(opt.file)){ return fn(false) } // ? why again ?
if(!(fs.existsSync||path.existsSync)(opt.file)){ return fn(false) }
if(!opt.respawn && run.on[way]){
if(a(run.on,way+'.meta.state')){ return fn(true) } // change API
return fn(false);
}
console.log("RUN :-->"+" testing "+opt.file)
var ts = a.time.is()
, p = fork(opt.file,[],{env:process.env})
, gear = run.on[way] || (run.on[way]={meta:{},cogs:{}})
, cog = gear.cogs[p.pid] = {com:p, pid:p.pid, start:ts, count:0}
gear.meta.invincible = opt.invincible;
p.on('message',function(m){
m = a.obj.ify(m);
if(a(m,'onOpen.readyState')===1){
a.time.stop(opt.impatient);
if(m && m.mod && m.mod.state){ m.mod.state.file = opt.file }
else { fn(0); fn = function(){} }
gear.meta = a.obj(m.mod).u(gear.meta);
if(gear.meta && gear.meta.name){
run.on[gear.meta.name] = gear;
}
web.state.ways.push(a(m,'mod.state'));
web.state.ways.sort(web.state.sort);
opt.invincible = gear.meta.invincible
run.track(opt,opt.reply);
fn(p.pid||true); fn = function(){};
return;
} opt.reply(m,(gear.meta&&gear.meta.name)||way);
});
p.on('exit',function(d,e){
if(cog.end){
delete gear.cogs[p.pid];
return;
} if(gear.meta.invincible){
cog.end = a.time.is();
console.log("RUN :-->"+" respawn: "+d+" >> "+way+" survived "+(cog.end - cog.start)/1000+" seconds. >> respawn: "+e);
delete gear.cogs[p.pid];
opt.respawn = true;
run.it(opt,(function(){}));
return;
} a.time.stop(opt.impatient);
fn(false); fn = function(){};
gear.meta.fatal = true;
cog.end = a.time.is();
delete cog.com; cog.com = {send:function(){}};
console.log("RUN :-->"+" exit: "+d+" >> "+way+" survived "+(cog.end - cog.start)/1000+" seconds. >> exit: "+e);
});
if(opt.respawn){ return }
opt.impatient = a.time.wait(function(){
fn(false); fn = function(){};
},web.opt.run.impatient);
});
run.tracked = {};
run.track = (function(opt,cb){ // depreciate
if(run.tracked[opt.way||opt.file]){ return }
fs.watchFile(opt.file,function(c,o){
opt.respawn = true;
run.it(opt,(function(p){
if(!p) return;
a.obj(a(run.on,opt.way+'.cogs')).each(function(v,i){
if(v.pid === p) return;
if(v.end){
v.com && v.com.kill && v.com.kill(); // not killing?
return;
}
v.end = a.time.is();
});
}),cb);
});
run.tracked[opt.way||opt.file] = true;
});
run.to = (function(way){ // TODO: Use different algorithm? Such as oldest-used first.
var low;
a.obj(a(run.on,way+'.cogs')).each(function(v,i){
low = (!v.end && v.count < (low||(low=v)).count)? v : low;
});
return low||{};
});
return run;
})();
web.event = (function(){
function event(e){
if(e){
e.on = event.on;
e.off = event.off;
e.emit = event.emit;
return e;
} return event;
}
event.w = event.w||{};
event.emit = (function(w,m){
a.obj(event.w[w]||{}).each(function(c,i){
if(c(m) === null){
delete event.w[i];
}
});
return event.w[w];
});
event.on = (function(w,c){
if(!w) return {};
var r = a.time.now();
(event.w[w]||(event.w[w]={}))[r] = c;
return r;
});
event.off = (function(w){
if(event.w[w]){
delete event.w[w];
} else {
a.obj(event.w).each(function(v,i){
delete v[w];
if(a.obj.empty(v)){
delete event.w[i];
}
});
}
});
return event;
})();
web.theorize = (function(req,res){
if(req){
if(a.text.low(web.state.way(req.url.pathname)) === theory.name){
req.cookies = web.cookie.tid(req);
if(!web.opt.no_global_theory_src){
web.cookie.set(res,req.cookies,req.cookies.tid);
if(web.state.sent(res)){ return }
res.writeHead(200, { 'Content-Type': 'text/javascript; charset=utf-8' });
res.end(a.theory_js,'utf-8');
return true;
}
}
} if(!web.opt.no_global_theory_src){
a.theory_js = a.theory_js||fs.readFileSync(process.env.totheory,'utf8');
if( (fs.existsSync||path.existsSync)(module.reqdir+'/node_modules') &&
(fs.existsSync||path.existsSync)(__dirname+'/node_modules/theory') &&
!(fs.existsSync||path.existsSync)(module.reqdir+'/node_modules/theory')){
fs.mkdirSync(module.reqdir+'/node_modules/theory')
fs.writeFileSync(module.reqdir+'/node_modules/theory/index.js'
,"module.exports=require('"
+path.relative(module.reqdir+'/node_modules/theory'
,process.env.totheory).replace(/\\/ig,'/')
+"');");
}
}
});
return a.web = web;
});
return web;
})());