Name: js-handler/server
| 1: | #!/usr/bin/nodejs |
| 2: | var instances = new Array(); |
| 3: | |
| 4: | function Status(i,m) { |
| 5: | this.id = i; |
| 6: | this.message = m; |
| 7: | var self = this; |
| 8: | this.update = function(i,m) { |
| 9: | self.id = i; |
| 10: | self.message = m; |
| 11: | } |
| 12: | } |
| 13: | |
| 14: | function Execution(c,d,e,n,v,ins) { |
| 15: | var code = this.code = c; |
| 16: | var data = this.data = d; |
| 17: | var endpoints = this.endpoints = e; |
| 18: | var output = this.output = false; |
| 19: | var state = this.state = "not executed"; |
| 20: | var instance = this.instance = ins; |
| 21: | var status = this.status = new Status(0,''); |
| 22: | |
| 23: | if (typeof(n) != 'undefined' && typeof(v) != 'undefined') { |
| 24: | var result_name = this.result_name = n; |
| 25: | var result_value = this.result_value = v; |
| 26: | } |
| 27: | } |
| 28: | |
| 29: | // New Execution |
| 30: | function postScript(req, res, next) { |
| 31: | if (!("dataelements" in req.params)) { return next(new restify.InvalidArgumentError("No dataelements")); } |
| 32: | if (!("endpoints" in req.params)) { return next(new restify.InvalidArgumentError("No endpoints")); } |
| 33: | if (!("code" in req.params)) { return next(new restify.InvalidArgumentError("No code")); } |
| 34: | |
| 35: | var dataelements = JSON.parse(req.params.dataelements); |
| 36: | var endpoints = JSON.parse(req.params.endpoints); |
| 37: | var code = req.params.code; |
| 38: | |
| 39: | // for asynchronous execution |
| 40: | var callback = req.params.callback; |
| 41: | |
| 42: | // var instanceCounter; |
| 43: | instances.push(0); |
| 44: | var instanceCounter = instances.length-1; |
| 45: | |
| 46: | var t = new Execution(code,dataelements,endpoints,req.params.resultname,req.params.resultvalue,instanceCounter); |
| 47: | |
| 48: | //callback defined, asyn execution |
| 49: | if (typeof(callback) != 'undefined') { |
| 50: | res.contentType = 'text/plain'; |
| 51: | res.send(200,instanceCounter.toString()); |
| 52: | } |
| 53: | |
| 54: | var worker = new webworker(function(){ |
| 55: | function ExecutionResult(d,e,o,s) { |
| 56: | this.data = d; |
| 57: | this.endpoints = e; |
| 58: | this.output = o; |
| 59: | this.status = s; |
| 60: | } |
| 61: | |
| 62: | onmessage = function (exec) { |
| 63: | var data = exec.data.data; |
| 64: | var endpoints = exec.data.endpoints; |
| 65: | var status = exec.data.status; |
| 66: | |
| 67: | try { |
| 68: | eval('var ' + exec.data.result_name + ' = JSON.parse(exec.data.result_value)'); |
| 69: | |
| 70: | var output = eval(exec.data.code); |
| 71: | var exres = new ExecutionResult(data,endpoints,output,status); |
| 72: | |
| 73: | postMessage(exres); |
| 74: | } catch (e) { |
| 75: | console.log(e.message); |
| 76: | var exres = new ExecutionResult(); |
| 77: | exres.error = e.message; |
| 78: | postMessage(exres); |
| 79: | } |
| 80: | } |
| 81: | }); |
| 82: | |
| 83: | // receiving data from worker after execution |
| 84: | worker.onmessage = function (exres) { |
| 85: | t.data = exres.data.data; |
| 86: | t.endpoints = exres.data.endpoints; |
| 87: | t.status = exres.data.status |
| 88: | t.output = exres.data.output; |
| 89: | t.error = exres.data.error; |
| 90: | t.result = exres.data.result; |
| 91: | worker.terminate(); |
| 92: | |
| 93: | if (typeof(callback) == 'undefined') { |
| 94: | if (typeof(t.error) != 'undefined') { // there is an error |
| 95: | delete instances[t.instance]; |
| 96: | return next(new restify.InternalError(t.error)); |
| 97: | } else { // there is NOOOOO error |
| 98: | t.state = "executed"; |
| 99: | res.contentType = 'text/plain'; |
| 100: | res.send(200,t.instance.toString()); |
| 101: | } |
| 102: | } else { |
| 103: | |
| 104: | var client = restify.createStringClient({ |
| 105: | url: callback, |
| 106: | version: '*' |
| 107: | }); |
| 108: | |
| 109: | if (typeof(t.error) != 'undefined') { // there is an error |
| 110: | delete instances[t.instance]; |
| 111: | client.post('',{instance:"error"},function (err,req,res,obj){ if (err) { console.log(err); } }); |
| 112: | } else { // there is NOOOOO error |
| 113: | t.state = "executed"; |
| 114: | client.post('', {instance: t.instance.toString()},function (err,req,res,obj){ if (err) { console.log(err); } }); |
| 115: | } |
| 116: | |
| 117: | } |
| 118: | }; |
| 119: | |
| 120: | // pass code and vars to worker |
| 121: | instances[t.instance] = t; |
| 122: | worker.postMessage(t); |
| 123: | } |
| 124: | |
| 125: | // read Execution details |
| 126: | function getDataelements(req, res, next){ |
| 127: | var id = req.params.instance; |
| 128: | if (!(id in instances)) { return next(new restify.InvalidArgumentError("No instance")); } |
| 129: | res.contentType = 'application/json'; |
| 130: | res.send(instances[id].data); |
| 131: | } |
| 132: | function getEndpoints(req, res, next){ |
| 133: | var id = req.params.instance; |
| 134: | if (!(id in instances)) { return next(new restify.InvalidArgumentError("No instance")); } |
| 135: | res.contentType = 'application/json'; |
| 136: | res.send(instances[id].endpoints); |
| 137: | } |
| 138: | function getStatus(req, res, next){ |
| 139: | var id = req.params.instance; |
| 140: | if (!(id in instances)) { return next(new restify.InvalidArgumentError("No instance")); } |
| 141: | res.contentType = 'application/json'; |
| 142: | res.send(instances[id].status); |
| 143: | } |
| 144: | function getOutput(req, res, next){ |
| 145: | var id = req.params.instance; |
| 146: | if (!(id in instances)) { return next(new restify.InvalidArgumentError("No instance")); } |
| 147: | if (instances[id].output == false) { |
| 148: | res.contentType = 'text/plain'; |
| 149: | res.send('false'); |
| 150: | } else { |
| 151: | res.contentType = 'application/json'; |
| 152: | res.send(200,instances[id].output); |
| 153: | } |
| 154: | } |
| 155: | function getState(req, res, next){ |
| 156: | var id = req.params.instance; |
| 157: | if (!(id in instances)) { return next(new restify.InvalidArgumentError("No instance")); } |
| 158: | res.contentType = 'application/json'; |
| 159: | res.send(instances[id].state); |
| 160: | } |
| 161: | |
| 162: | function getFull(req, res, next) { |
| 163: | var id = req.params.instance; |
| 164: | if (!(id in instances)) { return next(new restify.InvalidArgumentError("No instance")); } |
| 165: | res.contentType = 'application/json'; |
| 166: | res.send({ 'endpoints': instances[id].endpoints, 'dataelements': instances[id].data, 'output': instances[id].output, 'status': instances[id].status, 'state': instances[id].state }); |
| 167: | } |
| 168: | |
| 169: | function riddlDesc(req, res, next) { |
| 170: | res.contentType = 'text/plain'; |
| 171: | res.send(200,"Nothing to see here. Move along."); |
| 172: | } |
| 173: | |
| 174: | function deleteInstance(req,res,next) { |
| 175: | var id = req.params.instance; |
| 176: | if (!(id in instances)) { |
| 177: | res.contentType = 'text/plain'; |
| 178: | res.send(500,"instance "+id+" not existing"); |
| 179: | } |
| 180: | delete instances[id]; |
| 181: | res.send(200); |
| 182: | } |
| 183: | |
| 184: | /************/ |
| 185: | /*** MAIN ***/ |
| 186: | /************/ |
| 187: | var port = '9292'; |
| 188: | var host = '0.0.0.0'; |
| 189: | |
| 190: | var restify = require('restify'); |
| 191: | var daemon = require('daemon'); |
| 192: | var opt = require('optimist'); |
| 193: | var url = require('url'); |
| 194: | var fs = require('fs'); |
| 195: | var webworker = require('webworker-threads').Worker; |
| 196: | |
| 197: | var server = restify.createServer(); |
| 198: | server.use(restify.queryParser()); |
| 199: | server.use(restify.bodyParser()); |
| 200: | server.use(restify.CORS()); |
| 201: | |
| 202: | server.get('/', riddlDesc); |
| 203: | server.post('/', postScript); |
| 204: | server.get('/:instance', getFull); |
| 205: | server.get('/:instance/dataelements', getDataelements); |
| 206: | server.get('/:instance/endpoints', getEndpoints); |
| 207: | server.get('/:instance/status', getStatus); |
| 208: | server.get('/:instance/output', getOutput); |
| 209: | server.get('/:instance/state', getState); |
| 210: | server.del('/:instance', deleteInstance); |
| 211: | |
| 212: | var argv = opt |
| 213: | .usage("Usage:\n $0 [options] start|stop|info") |
| 214: | .boolean('v') |
| 215: | .alias('v','verbose') |
| 216: | .boolean('h') |
| 217: | .alias('h','help') |
| 218: | .describe('h','available options.') |
| 219: | .describe('v','do not daemonize server.') |
| 220: | .argv; |
| 221: | |
| 222: | try { |
| 223: | var pid = fs.readFileSync(process.argv[1].replace(/(\.[^\.]+)?$/,'.pid'),{encoding: 'utf-8'}); |
| 224: | } catch(err) { |
| 225: | var pid = -1; |
| 226: | } |
| 227: | switch (argv._[0]) { |
| 228: | case "stop": |
| 229: | if (pid != -1) process.kill(pid); |
| 230: | break; |
| 231: | |
| 232: | case "start": |
| 233: | try { |
| 234: | if (pid != -1) { |
| 235: | process.kill(pid,0); |
| 236: | console.log('server already running'); |
| 237: | break; |
| 238: | } |
| 239: | } catch(err) { } |
| 240: | if (argv['v']) { |
| 241: | server.listen(port, host, function() { |
| 242: | console.log('%s listening at %s', server.name, host + ':' + port); |
| 243: | fs.writeFile(process.argv[1].replace(/(\.[^\.]+)?$/,'.pid'),process.pid); |
| 244: | }); |
| 245: | } else { |
| 246: | server.listen(port, host, function() { |
| 247: | console.log('%s listening at %s', server.name, host + ':' + port); |
| 248: | daemon(); |
| 249: | fs.writeFile(process.argv[1].replace(/(\.[^\.]+)?$/,'.pid'),process.pid); |
| 250: | }); |
| 251: | } |
| 252: | break; |
| 253: | |
| 254: | case "info": |
| 255: | try { |
| 256: | if (pid == -1) shit(); |
| 257: | process.kill(pid,0); |
| 258: | } catch(err) { |
| 259: | console.log('no server running'); |
| 260: | break; |
| 261: | } |
| 262: | console.log('%s listening at %s, PID %s', server.name, host + ':' + port, pid); |
| 263: | break; |
| 264: | |
| 265: | default: |
| 266: | var help = opt.help().replace(/\n\s*\n/,"\n"); |
| 267: | help += ' start Start the server.\n stop Stop the server.\n info Get information about the server.'; |
| 268: | console.log(help); |
| 269: | } |
