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:
}