UNPKG

hersserver

Version:

A 'now'-alike server extension not using socket.io

227 lines (226 loc) 6.69 kB
//magic of this module is that there needs to exist a global methodmap hash somewhere function paramValArryFromQuery(query,paramdescarry){ if(!query){ return []; } if(paramdescarry==='originalhash'){ return [query]; } var ret = []; for(var i in paramdescarry){ var pd = paramdescarry[i]; if(typeof pd==='string'){ ret.push(query[pd]); continue; } if(typeof pd!=='object'){ return; } val = query[pd.name]; if((pd.regex instanceof RegExp) && (!pd.regex.test(val))){ throw 'Value '+val+' for parameter '+pd+' has to satisfy RegExp '+pd.regex.source; } if(pd.type==='int'){ var v = parseInt(val); if(isNaN(v)){ throw 'Value '+val+' for parameter '+pd.name+' has to be an integer'; } val = v; } ret.push(val); } return ret; } function BasicResponder(){ return this; } BasicResponder.prototype.clientId = function clientId(){ return 0; } BasicResponder.prototype.stringify = function stringify(content){ this.write(JSON.stringify(content)); } BasicResponder.prototype.writeandend = function writeandend(content){ this.write(content); this.end(); } BasicResponder.prototype.stringifyandend = function stringifyandend(content){ this.stringify(content); this.end(); } function NullResponder(){ return this; } NullResponder.prototype = new BasicResponder(); NullResponder.write = function write(content){} NullResponder.end = function end(){} function HTTPResponder(request,response,user){ if(response && (typeof response.write==='function') && (typeof response.end==='function') && response.socket && response.socket.remoteAddress){ this.request=request; this.response = response; this.now={socket:{handshake:{address:{address:response.socket.remoteAddress}}},user:user||{}}; }else{ this.response={write:function(){},end:function(){}}; this.now={socket:{handshake:{address:{address:''}}},user:user||{}}; } } HTTPResponder.prototype = new BasicResponder(); HTTPResponder.prototype.constructor = HTTPResponder; HTTPResponder.prototype.clientId = function(){ return this.now.user.clientId; }; HTTPResponder.prototype.write = function write(content){ this.response.write(content); } HTTPResponder.prototype.end = function end(){ this.response.end(); } function HTTPRespondingContext(handler){ var handler=handler; function realResponder(query){ if(typeof handler==='function'){ handler(new HTTPResponder(this),query); } } return realResponder; } function NOWResponder(localnow,cb){ this.now = localnow; if(typeof cb === 'function'){ this.cb = cb; }else{ this.cb = function(){} } } NOWResponder.prototype = new BasicResponder(); NOWResponder.prototype.constructor = NOWResponder; NOWResponder.prototype.clientId = function clientId(){ return this.now.user.clientId; } NOWResponder.prototype.stringify = function stringify(content){ this.write(content); } NOWResponder.prototype.write = function write(content){ this.cb(content); } NOWResponder.prototype.end = function end(){ delete this.now; delete this.cb; }; function ForkedChildResponder(){ } ForkedChildResponder.prototype = new BasicResponder(); ForkedChildResponder.prototype.clientId = function clientId(){ return 0; //process.parent.id or something alike? }; ForkedChildResponder.prototype.stringify = function stringify(content){ this.write(content); }; ForkedChildResponder.prototype.write = function write(content){ process.send(content); }; ForkedChildResponder.prototype.end = function end(){}; function NOWRespondingContext(responderobj){ var _responderobj = responderobj; function realResponder(query,cb){ if(_responderobj.level && (this.user.cookie.passcode!==serverpasscode)){ if(typeof cb==='function'){ cb(); } return; } _responderobj.nowRespond(this,query,cb); } return realResponder; } function Responder(options){ methodmap[options.name]=this; this.name = options.name; this.handler=options.handler; this.level=options.level; this.params=options.params; var nw; if(isChildProcess){ return; } if(options.parent){ nw = options.parent; console.log(options.name,'created on custom parent',nw); }else if(options.level){ nw = now.getGroup(options.level).now; console.log(options.name+' created on '+options.level); }else{ nw = everyone.now; console.log(options.name+' created on everyone'); } nw[options.name]=NOWRespondingContext(this); } Responder.prototype.forkedChildRespond = function forkedChildRespond(requestobj){ this.handler.apply(new ForkedChildResponder(),paramValArryFromQuery(requestobj,this.params)); }; Responder.prototype.httpRespond = function httpRespond(request,response,query){ var l = this.level; if(l){ var rhc = request.headers.cookie; var passcode = (/passcode=([0-9a-zA-Z]*)/).exec(rhc); if(!(passcode&&(passcode.length>1)&&(passcode[1]===serverpasscode))){ response.writeHead(403, { "Content-Type" : "text/plain" }); response.write("403 Forbidden\n"); response.end(); return; } } response.writeHead(200,{'Content-Type':'text/plain'}); //response.connection.setTimeout(5); this.handler.apply(new HTTPResponder(request,response,now.clients[query.clientId]),paramValArryFromQuery(query,this.params)); } Responder.prototype.nowRespond = function nowRespond(localnow,query,cb){ this.handler.apply(new NOWResponder(localnow,cb),paramValArryFromQuery(query,this.params)); try{ } catch(e){ cb({error:e.toString()}); } } Responder.prototype.descriptor = function descriptor(){ var ret ={name:this.name,params:[]}; for(var i in this.params){ var p = this.params[i]; if(typeof p === 'string'){ ret.params.push(p); continue; } var po={}; for(var j in p){ if(j==='regex'){ po[j]=p[j].source; }else{ po[j]=p[j]; } } ret.params.push(po); } return ret; } exports.createResponder = function(options){ if(typeof options !== 'object'){ console.trace('Cannot create a responder without an options object'); } if(typeof options.name !== 'string'){ throw 'Cannot create a responder without a name'; } if(typeof options.handler !== 'function'){ throw 'Cannot create responder '+options.name+' without a handler'; } var r = methodmap[options.name]; if(r){ throw 'Responder for '+options.name+' already exists'+r.handler.toString(); } r = new Responder(options); methodmap[options.name] = r; } exports.isResponder = function isResponder(responderobj){ return (responderobj instanceof Responder); }