789 lines
		
	
	
		
			25 KiB
		
	
	
	
		
			JavaScript
		
	
	
	
	
	
			
		
		
	
	
			789 lines
		
	
	
		
			25 KiB
		
	
	
	
		
			JavaScript
		
	
	
	
	
	
| // some annoying nodejs fixes
 | |
| process.noDeprecation = true;
 | |
| process.env["NODE_TLS_REJECT_UNAUTHORIZED"] = 0;
 | |
| module.paths.push(process.env.HOME+'/node_modules')
 | |
| 
 | |
| var proc    = require('child_process');
 | |
| var http    = require('http')
 | |
| var https
 | |
| var fs      = require('fs')
 | |
| var Path    = require('path')
 | |
| var execSync  = require("child_process").execSync;
 | |
| 
 | |
| // Optional websocket interface
 | |
| var WebSocket;
 | |
| try { WebSocket = require('ws') } catch (e) { /* no ws module installed */ }
 | |
| try { https = require('https') } catch (e) { /* no https module installed */ }
 | |
| 
 | |
| process.argv.shift();
 | |
| process.argv.shift();
 | |
| 
 | |
| var config = {
 | |
|   version     : "1.7.1",
 | |
|   TIMEOUT     : 100000,
 | |
|   PORT        : 11111,
 | |
|   PORTWS      : 11112,
 | |
|   verbose     : 0,
 | |
|   handleIndex : 1000,
 | |
|   commands    : process.argv,
 | |
| }
 | |
| 
 | |
| if (process.argv.indexOf('-v')!=-1) {
 | |
|   config.verbose++;
 | |
| }
 | |
| 
 | |
| var time = function () { return Math.floor(Date.now()/1000) }
 | |
| print = console.log;
 | |
| 
 | |
| function log(msg) {
 | |
|   console.log('[WEX] '+msg);
 | |
| }
 | |
| 
 | |
| var Consoles = [];
 | |
| function GET(url,params, cb) {
 | |
|   var ishttps= url.match(/https:/)!=null;
 | |
|   if (ishttps && !https) {
 | |
|     if (cb) return cb(new Error('ENOTSUPPORTED'));
 | |
|   }
 | |
|   url=url.replace(/http[s]?:\/\//,'');
 | |
|   var parts = url.split(':'),
 | |
|       host  = parts[0].split('/')[0],
 | |
|       path  = parts[parts.length-1].split('/').slice(1).join('/'),
 | |
|       port  = (parts[1]||(ishttps?'443':'80')).split('/')[0];
 | |
|   if (params) {
 | |
|         var o=params,sep='';
 | |
|         params='/?';
 | |
|         for(var p in o) {
 | |
|           params = params + sep + p + '='+o[p];
 | |
|           sep='&';
 | |
|         } 
 | |
|   } else params='';
 | |
|   path += params; 
 | |
|   // print(host,path,port,ishttps)
 | |
|   var get_options = {
 | |
|       host: host,
 | |
|       port: port,
 | |
|       path: path,
 | |
|       method: 'GET',
 | |
|       keepAlive: true,
 | |
|       headers: {
 | |
|           // 'Content-Type': 'application/x-www-form-urlencoded',
 | |
|       }
 | |
|   };
 | |
|   // console.log('GET', post_options,post_data)
 | |
|   var get_req = (ishttps?https:http).request(get_options, function(res) {
 | |
|       res.setEncoding('utf8');
 | |
|       
 | |
|       var data='';
 | |
|       res.on('data', function (chunk) {
 | |
|         data += chunk;
 | |
|         // console.log('Response: ' + chunk);
 | |
|       });
 | |
|       res.on('end', function () {
 | |
|         try {
 | |
|           var result=JSONfn.parse(data);
 | |
|           // console.log('GET: ',result);
 | |
|         } catch (e) { print(data.slice(0,100)); result=new Error(e.toString()+' ['+data.slice(0,200)+']'); }
 | |
|         if (cb) cb(result);
 | |
|       });
 | |
|   });
 | |
|   get_req.on('error',function (err) {
 | |
|     // console.log(err)
 | |
|     if (cb) cb(err); else console.log(url,err);
 | |
|   });
 | |
|   get_req.setNoDelay();
 | |
|   // get_req.write();
 | |
|   get_req.end();
 | |
| }
 | |
| function get(url, cb) {
 | |
|   var ishttps= url.match(/https:/)!=null;
 | |
|   if (ishttps && !https) {
 | |
|     if (cb) return cb(new Error('ENOTSUPPORTED'));
 | |
|   }
 | |
|   url=url.replace(/http[s]?:\/\//,'');
 | |
|   var parts = url.split(':'),
 | |
|       host  = parts[0].split('/')[0],
 | |
|       path  = parts[parts.length-1].split('/').slice(1).join('/'),
 | |
|       port  = (parts[1]||(ishttps?'443':'80')).split('/')[0];
 | |
|   // print(host,path,port,ishttps)
 | |
|   var get_options = {
 | |
|       host: host,
 | |
|       port: port,
 | |
|       path: path[0]=='/'?path:'/'+path,
 | |
|       method: 'GET',
 | |
|       keepAlive: true,
 | |
|       headers: {
 | |
|         // 'Content-Type': 'application/x-www-form-urlencoded',
 | |
|         'User-Agent':'Mozilla/5.0 (X11; Linux i686; rv:52.0) Gecko/20100101 Firefox/52.0',
 | |
|         'Accept':"text/html,application/xhtml+xml,application/xml;q=0.9,*/*;q=0.8",
 | |
|       }
 | |
|   };
 | |
|   // console.log('GET', get_options)
 | |
|   var get_req = (ishttps?https:http).request(get_options, function(res) {
 | |
|     res.setEncoding('binary');
 | |
|     // res.setEncoding('utf8');
 | |
|     var data = [];
 | |
|     res.on('data', function (chunk) {
 | |
|       data.push(Buffer.from(chunk, 'binary'));
 | |
|       // console.log('Response: ' + chunk);
 | |
|     });
 | |
|     res.on('end', function () {
 | |
|       var buffer = Buffer.concat(data);
 | |
|       cb(buffer,res.headers)
 | |
|     });
 | |
|   });
 | |
|   get_req.on('error',function (err) {
 | |
|     // console.log(err)
 | |
|     if (cb) cb(err); else console.log(url,err);
 | |
|   });
 | |
|   get_req.setNoDelay();
 | |
|   // get_req.write();
 | |
|   get_req.end();
 | |
| }
 | |
| function POST(url, data, cb) {
 | |
|   var params,headers;
 | |
|   if (data && data.params && data.data != undefined) {
 | |
|     params=data.params;
 | |
|     headers=data.headers;
 | |
|     data=data.data;
 | |
|   }
 | |
|   var ishttps= url.match(/https:/);
 | |
|   if (ishttps && !https) {
 | |
|     if (cb) return cb(new Error('ENOTSUPPORTED'));
 | |
|   }
 | |
|   url=url.replace(/http[s]?:\/\//,'');
 | |
|   var parts = url.split(':'),
 | |
|       host  = parts[0].split('/')[0],
 | |
|       path  = parts[parts.length-1].split('/').slice(1).join('/'),
 | |
|       port  = (parts[1]||(ishttps?'443':'80')).split('/')[0];
 | |
|   if (params) {
 | |
|         var o=params,sep='';
 | |
|         params='/?';
 | |
|         for(var p in o) {
 | |
|           params = params + sep + p + '='+o[p];
 | |
|           sep='&';
 | |
|         } 
 | |
|   } else params='';
 | |
|   var post_data = typeof data == 'string'?data:JSON.stringify(data);
 | |
|   var post_options = {
 | |
|       host: host,
 | |
|       port: port,
 | |
|       path: '/'+path+params,
 | |
|       method: 'POST',
 | |
|       keepAlive: true,
 | |
|       headers: headers || {
 | |
|           'Content-Type': 'application/json', // ?? 'application/x-www-form-urlencoded',
 | |
|           // 'Content-Length': Buffer.byteLength(post_data)
 | |
|           'Content-Length': post_data.length,
 | |
|       }
 | |
|   };
 | |
|   // console.log('POST', post_options,post_data)
 | |
|   var post_req = (ishttps?https:http).request(post_options, function(res) {
 | |
|       res.setEncoding('utf8');
 | |
|       
 | |
|       var data='';
 | |
|       res.on('data', function (chunk) {
 | |
|         data += chunk;
 | |
|         // console.log('Response: ' + chunk);
 | |
|       });
 | |
|       res.on('end', function () {
 | |
|         try {
 | |
|           var result=JSON.parse(data);
 | |
|           // console.log('POST: ',result);
 | |
|         } catch (e) { print(data.slice(0,100)); result=new Error(e.toString()+' ['+data.slice(0,200)+']'); }
 | |
|         if (cb) cb(result);
 | |
|       });
 | |
|   });
 | |
|   post_req.on('error',function (err) {
 | |
|     if (cb) cb(err); else console.log(url,err)
 | |
|   });
 | |
|   post_req.setNoDelay();
 | |
|   // console.log('POST: ',post_data);
 | |
|   // post the data
 | |
|   post_req.write(post_data);
 | |
|   post_req.end();
 | |
| }
 | |
| function Post(url, data, cb) {
 | |
|   var params,headers;
 | |
|   if (data && data.params && data.data != undefined) {
 | |
|     params=data.params;
 | |
|     headers=data.headers;
 | |
|     data=data.data;
 | |
|   }
 | |
|   var ishttps= url.match(/https:/);
 | |
|   if (ishttps && !https) {
 | |
|     if (cb) return cb(new Error('ENOTSUPPORTED'));
 | |
|   }
 | |
|   url=url.replace(/http[s]?:\/\//,'');
 | |
|   var parts = url.split(':'),
 | |
|       host  = parts[0].split('/')[0],
 | |
|       path  = parts[parts.length-1].split('/').slice(1).join('/'),
 | |
|       port  = (parts[1]||(ishttps?'443':'80')).split('/')[0];
 | |
|   if (params) {
 | |
|         var o=params,sep='';
 | |
|         params='/?';
 | |
|         for(var p in o) {
 | |
|           params = params + sep + p + '='+o[p];
 | |
|           sep='&';
 | |
|         } 
 | |
|   } else params='';
 | |
|   var text=[];
 | |
|   for(var p in data) {
 | |
|     text.push(p+'='+encodeURI(data[p]));
 | |
|   }
 | |
|   text=text.join('&');
 | |
|   var post_data = typeof data == 'string'?data:JSON.stringify(data);
 | |
|   var post_options = {
 | |
|       host: host,
 | |
|       port: port,
 | |
|       path: '/'+path+params,
 | |
|       method: 'POST',
 | |
|       keepAlive: true,
 | |
|       headers: headers || {
 | |
|           'Content-Type': 'application/x-www-form-urlencoded',
 | |
|           // 'Content-Length': Buffer.byteLength(post_data)
 | |
|           'Content-Length': text.length,
 | |
|       }
 | |
|   };
 | |
|   // console.log('Post', post_options,post_data)
 | |
|   var post_req = (ishttps?https:http).request(post_options, function(res) {
 | |
|       res.setEncoding('utf8');
 | |
|       
 | |
|       var data='';
 | |
|       res.on('data', function (chunk) {
 | |
|         data += chunk;
 | |
|         // console.log('Response: ' + chunk);
 | |
|       });
 | |
|       res.on('end', function () {
 | |
|         try {
 | |
|           var result=JSON.parse(data);
 | |
|           // console.log('POST: ',result);
 | |
|         } catch (e) { print(data.slice(0,100)); result=new Error(e.toString()+' ['+data.slice(0,200)+']'); }
 | |
|         if (cb) cb(result);
 | |
|       });
 | |
|   });
 | |
|   post_req.on('error',function (err) {
 | |
|     if (cb) cb(err); else console.log(url,err)
 | |
|   });
 | |
|   post_req.setNoDelay();
 | |
|   // console.log('POST: ',post_data);
 | |
|   // post the data
 | |
|   // console.log(text)
 | |
|   post_req.write(text);
 | |
|   post_req.end();
 | |
| }
 | |
| 
 | |
| 
 | |
| function typedarrayTObase64(ta,ftyp) {
 | |
|   var b,i;
 | |
|   if (ta.buffer instanceof ArrayBuffer) {
 | |
|     b=Buffer(ta.buffer);
 | |
|     if (b.length>0) return b.toString('base64');
 | |
|   }
 | |
|   // Fall-back conversion
 | |
|   switch (ftyp) {
 | |
|     case Float32Array: 
 | |
|       b = Buffer(ta.length*4);
 | |
|       for(i=0;i<ta.length;i++) b.writeFloatLE(ta[i],i*4);
 | |
|       return b.toString('base64');
 | |
|     case Float64Array: 
 | |
|       b = Buffer(ta.length*8);
 | |
|       for(i=0;i<ta.length;i++) b.writeDoubleLE(ta[i],i*8);
 | |
|       return b.toString('base64');
 | |
|     case Int16Array: 
 | |
|       b = Buffer(ta.length*2);
 | |
|       for(i=0;i<ta.length;i++) b.writeInt16LE(ta[i],i*2);
 | |
|       return b.toString('base64');
 | |
|     case Int32Array: 
 | |
|       b = Buffer(ta.length*4);
 | |
|       for(i=0;i<ta.length;i++) b.writeInt32LE(ta[i],i*4);
 | |
|       return b.toString('base64');
 | |
|   }
 | |
|   return ta.toString();
 | |
| }
 | |
| function base64TOtypedarray(buff,ftyp) {
 | |
|   var i,ta;
 | |
|   if (buff.buffer instanceof ArrayBuffer) {
 | |
|     switch (ftyp) {
 | |
|       case Float32Array: return new Float32Array((new Uint8Array(buff)).buffer);
 | |
|       case Float64Array: return new Float64Array((new Uint8Array(buff)).buffer);
 | |
|       case Int16Array:   return new Int16Array((new Uint8Array(buff)).buffer);
 | |
|       case Int32Array:   return new Int32Array((new Uint8Array(buff)).buffer);
 | |
|     }
 | |
|   } else if (typeof Uint8Array.from != 'undefined') {
 | |
|     switch (ftyp) {
 | |
|       case Float32Array: return new Float32Array(Uint8Array.from(buff).buffer);
 | |
|       case Float64Array: return new Float64Array(Uint8Array.from(buff).buffer);
 | |
|       case Int16Array:   return new Int16Array(Uint8Array.from(buff).buffer);
 | |
|       case Int32Array:   return new Int32Array(Uint8Array.from(buff).buffer);
 | |
|     }
 | |
|   } else {
 | |
|     // Fall-back conversion
 | |
|     switch (ftyp) {
 | |
|       case Float32Array: 
 | |
|         ta=new Float32Array(buff.length/4);
 | |
|         for(i=0;i<ta.length;i++) 
 | |
|           ta[i]=buff.readFloatLE(i*4);
 | |
|         return ta;
 | |
|       case Float64Array: 
 | |
|         ta=new Float64Array(buff.length/8);
 | |
|         for(i=0;i<ta.length;i++) 
 | |
|           ta[i]=buff.readDoubleLE(i*8);
 | |
|         return ta;
 | |
|       case Int16Array: 
 | |
|         ta=new Int16Array(buff.length/2);
 | |
|         for(i=0;i<ta.length;i++) 
 | |
|           ta[i]=buff.readInt16LE(i*2);
 | |
|         return ta;
 | |
|       case Int32Array: 
 | |
|         ta=new Int32Array(buff.length/4);
 | |
|         for(i=0;i<ta.length;i++) 
 | |
|           ta[i]=buff.readInt32LE(i*4);
 | |
|         return ta;
 | |
|     }
 | |
|   }
 | |
| }
 | |
| var JSONfn = {}
 | |
| 
 | |
|   JSONfn.stringify = function (obj) {
 | |
| 
 | |
|     return JSON.stringify(obj, function (key, value) {
 | |
|       if (value instanceof Function || typeof value == 'function')
 | |
|         return '_PxEnUf_' +Buffer(value.toString(true)).toString('base64');  // try minification (true) if supported
 | |
|       if (value instanceof Buffer)
 | |
|         return '_PxEfUb_' +value.toString('base64');
 | |
|       if (typeof Float64Array != 'undefined' && value instanceof Float64Array)
 | |
|         return '_PxE6Lf_' + typedarrayTObase64(value,Float64Array);
 | |
|       if (typeof Float32Array != 'undefined' && value instanceof Float32Array)
 | |
|         return '_PxE3Lf_' + typedarrayTObase64(value,Float32Array);
 | |
|       if (typeof Int16Array != 'undefined' && value instanceof Int16Array)
 | |
|         return '_PxE1Ni_' + typedarrayTObase64(value,Int16Array);
 | |
|       if (typeof Int32Array != 'undefined' && value instanceof Int32Array)
 | |
|         return '_PxE3Ni_' + typedarrayTObase64(value,Int32Array);
 | |
|       if (value instanceof RegExp)
 | |
|         return '_PxEgEr_' + value;
 | |
|       
 | |
|       return value;
 | |
|     });
 | |
|   };
 | |
| 
 | |
|   JSONfn.parse = function (str, mask) {
 | |
|     var code;
 | |
|     try {
 | |
|       with (mask||{}) {
 | |
|         code= JSON.parse(str, function (key, value) {
 | |
|           var prefix;
 | |
| 
 | |
|           try {
 | |
|             if (typeof value != 'string') {
 | |
|               return value;
 | |
|             }
 | |
|             if (value.length < 8) {
 | |
|               return value;
 | |
|             }
 | |
|             prefix = value.substring(0, 8);
 | |
| 
 | |
|             if (prefix === '_PxEnUf_') {
 | |
|               var code = value.slice(8);
 | |
|               if (code.indexOf('function')==0)  // Backward comp.
 | |
|                 return eval('(' + code + ')');
 | |
|               else
 | |
|                 return eval('(' + Buffer(code,'base64').toString() + ')');
 | |
|             }
 | |
|             if (prefix === '_PxEfUb_')
 | |
|               return Buffer(value.slice(8),'base64');
 | |
|             if (prefix === '_PxE6Lf_')
 | |
|               return base64TOtypedarray(Buffer(value.slice(8),'base64'),Float64Array);
 | |
|             if (prefix === '_PxE3Lf_')
 | |
|               return base64TOtypedarray(Buffer(value.slice(8),'base64'),Float32Array);
 | |
|             if (prefix === '_PxE1Ni_')
 | |
|               return base64TOtypedarray(Buffer(value.slice(8),'base64'),Int16Array);
 | |
|             if (prefix === '_PxE3Ni_')
 | |
|               return base64TOtypedarray(Buffer(value.slice(8),'base64'),Int32Array);
 | |
|             if (prefix === '_PxEgEr_')
 | |
|               return eval(value.slice(8));
 | |
|            
 | |
|             return value;
 | |
|           } catch (e) {
 | |
|             throw {error:e,value:value};
 | |
|           }
 | |
|         });
 | |
|      };
 | |
|     } catch (e) {
 | |
|       throw e.error||e;
 | |
|     }
 | |
|    return code;
 | |
|   };
 | |
| 
 | |
|   JSONfn.clone = function (obj, date2obj) {
 | |
|     return exports.parse(exports.stringify(obj), date2obj);
 | |
|   };
 | |
|   JSONfn.current =function (module) { current=module.current; };
 | |
| 
 | |
|   /* Remove any buffer toJSON bindings */
 | |
|   if (typeof Buffer != 'undefined' && Buffer.prototype.toJSON) delete Buffer.prototype.toJSON;
 | |
|   if (typeof buffer == 'object' && buffer.Buffer) delete buffer.Buffer.prototype.toJSON;
 | |
|   // Alias
 | |
|   JSONfn.serialize   = exports.stringify;
 | |
|   JSONfn.deserialize = exports.parse;
 | |
|   
 | |
| 
 | |
| 
 | |
| function mkdtemp (index) {
 | |
|   rmdtemp(index);
 | |
|   fs.mkdirSync('/tmp/webx-'+index);
 | |
|   return '/tmp/webx-'+index
 | |
| }
 | |
| 
 | |
| function rmdir(path) {
 | |
|   if( fs.existsSync(path) ) {
 | |
|     fs.readdirSync(path).forEach(function(file,index){
 | |
|       var curPath = path + "/" + file;
 | |
|       if(fs.lstatSync(curPath).isDirectory()) { // recurse
 | |
|         rmdir(curPath);
 | |
|       } else { // delete file
 | |
|         fs.unlinkSync(curPath);
 | |
|       }
 | |
|     });
 | |
|     fs.rmdirSync(path);
 | |
|   }
 | |
| };
 | |
| 
 | |
| function rmdtemp (index) {
 | |
|   rmdir('/tmp/webx-'+index)
 | |
| }
 | |
| 
 | |
| /*
 | |
| ** Parse query string '?attr=val&attr=val... and return parameter record
 | |
| */
 | |
| function parseQueryString( url ) {
 | |
|     var queryString = url.substring( url.indexOf('?') + 1 );
 | |
|     if (queryString == url) return [];
 | |
|     var params = {}, queries, temp, i, l;
 | |
|     // Split into key/value pairs
 | |
|     queries = queryString.split("&");
 | |
|     // Convert the array of strings into an object
 | |
|     for ( i = 0, l = queries.length; i < l; i++ ) {
 | |
|         temp = queries[i].split('=');
 | |
|         if (temp[1]==undefined) temp[1]='true';
 | |
|         params[temp[0]] = temp[1].replace('%20',' ');
 | |
|     }
 | |
|     return params;
 | |
| }
 | |
| function reply(response,body,headers) {
 | |
|   header={'Access-Control-Allow-Origin': '*',
 | |
|           'Access-Control-Allow-Credentials': 'true',
 | |
|           'Content-Type': 'text/plain'};
 | |
|   if (headers) { header={}; for(var p in headers) header[p]=headers[p] };
 | |
|   response.writeHead(200,header);
 | |
|   response.write(body);
 | |
|   response.end();
 | |
| }
 | |
| 
 | |
| function execute(options) {
 | |
|   if (commands.indexOf(options.command)==-1) return;
 | |
| 
 | |
|   var stdoutBroken,stderrBroken;
 | |
|   var tmp=mkdtemp(options.handle);
 | |
|   
 | |
|   Consoles[options.handle]={stdout:[],stderr:[],output:{},exit:false,status:0,tid:0};
 | |
|   
 | |
|   if (options.input) {
 | |
|     for (var p in options.input) {
 | |
|       fs.writeFileSync(tmp+'/'+p,Buffer(options.input[p],'base64'),'binary');
 | |
|     }    
 | |
|   }
 | |
|   var pro = proc.spawn(options.command, options.arguments, {
 | |
|     cwd:tmp
 | |
|   });
 | |
| 
 | |
|   if (config.verbose) print(options)
 | |
|   else print('[PRO '+options.handle+']',options.command,options.arguments);
 | |
| 
 | |
|   pro.stdout.on('data', function (data) {
 | |
|     var msg = data.toString(),
 | |
|         lines = msg.split('\n');
 | |
|     if (config.verbose) print('['+options.handle+'] stdout:<'+msg+'>');
 | |
|     if (stdoutBroken) lines[0] = stdoutBroken+lines[0]; stdoutBroken=null;
 | |
|     if (lines[lines.length-1]!='') stdoutBroken=lines.pop();
 | |
|     else lines.pop();
 | |
|     Consoles[options.handle].stdout=Consoles[options.handle].stdout.concat(lines);
 | |
|   });
 | |
| 
 | |
|   pro.stderr.on('data', function (data) {
 | |
|     var msg = data.toString(),
 | |
|         lines = msg.split('\n');
 | |
|     if (config.verbose) print('['+options.handle+'] stderr:<'+msg+'>');
 | |
|     if (stderrBroken) lines[0] = stderrBroken+lines[0]; stderrBroken=null;
 | |
|     if (lines[lines.length-1]!='') stderrBroken=lines.pop();
 | |
|     else lines.pop();
 | |
|     Consoles[options.handle].stderr=Consoles[options.handle].stderr.concat(lines);
 | |
|   });
 | |
| 
 | |
|   pro.on('exit', function (code) {
 | |
|     print('[PRO '+options.handle+'] child process exited with code ' + String(code));
 | |
|     if (options.output) {
 | |
|       // All files will be base64 encoded (handling binary and text data the same way)
 | |
|       options.output.forEach(function (file) {
 | |
|         try {
 | |
|           var data = fs.readFileSync(tmp+'/'+file,'binary');
 | |
|           Consoles[options.handle].stdout.push('[PRO] Saving '+file+' ['+data.length+'] ..');
 | |
|           if (data && data.length) Consoles[options.handle].output[file]=
 | |
|             Buffer(data,'binary').toString('base64');
 | |
|           // print(Consoles[options.handle].output[file].substring(0,16));
 | |
|         } catch (e) {
 | |
|           print(e)
 | |
|         }
 | |
|       })
 | |
|     }
 | |
|     Consoles[options.handle].exit=code;
 | |
|     rmdtemp(options.handle)
 | |
|   });
 | |
|   
 | |
|   return 'OK';
 | |
| }
 | |
| 
 | |
| function rpc(request,response) {
 | |
|   var status=0,data='',files;
 | |
|   if (config.verbose) print(request.command,request.dir,request.file,request.mimetype,request.data && request.data.length)
 | |
|   try {
 | |
|     switch (request.command) {
 | |
|       case 'GET': 
 | |
|         console.log(request)
 | |
|         GET(request.url,request.params, function (result) {
 | |
|           // console.log('result',result)
 | |
|           if (result instanceof Error) {status=result.toString(); result=''};
 | |
|           reply(response,JSONfn.stringify({status:status,reply:result,handle:request.handle}))
 | |
|         })
 | |
|         return;
 | |
|         break;
 | |
|       case 'Post': 
 | |
|         console.log(request)
 | |
|         Post(request.url,request.data, function (result) {
 | |
|           // console.log('result',result)
 | |
|           if (result instanceof Error) {status=result.toString(); result=''};
 | |
|           reply(response,JSONfn.stringify({status:status,reply:result,handle:request.handle}))
 | |
|         })
 | |
|         return;
 | |
|         break;
 | |
|       case 'POST': 
 | |
|         console.log(request)
 | |
|         POST(request.url,request.data, function (result) {
 | |
|           // console.log('result',result)
 | |
|           if (result instanceof Error) {status=result.toString(); result=''};
 | |
|           reply(response,JSONfn.stringify({status:status,reply:result,handle:request.handle}))
 | |
|         })
 | |
|         return;
 | |
|         break;
 | |
|       case 'list':
 | |
|         request.dir=request.dir.replace(/^~/,process.env.HOME);
 | |
|         files = fs.readdirSync(request.dir);
 | |
|         files = files.map(function (entry) {
 | |
|           try {
 | |
|             var stat=fs.statSync(request.dir+'/'+entry);
 | |
|             return {name:entry,dir:stat.isDirectory(),size:stat.size,time:stat.mtime};
 | |
|           } catch (e)  {};
 | |
|         }).filter(function (entry) { return entry });
 | |
|         data = [{name:'..',dir:true}].concat(files);
 | |
|         break;
 | |
|       case 'load':
 | |
|         request.dir=request.dir.replace(/^~/,process.env.HOME);
 | |
|         if (request.mimetype.indexOf('text')==0) {
 | |
|           data=fs.readFileSync(request.dir+'/'+request.file,'utf8');
 | |
|         } else if (request.mimetype.indexOf('binary')!=-1) {
 | |
|           data=fs.readFileSync(request.dir+'/'+request.file,'binary');
 | |
|         }
 | |
|         break;
 | |
|       case 'lookup':
 | |
|         var stat=fs.statSync(request.path);
 | |
|         data={name:request.path,dir:stat.isDirectory(),size:stat.size,time:stat.mtime};
 | |
|         break;
 | |
|       case 'save':
 | |
|         request.dir=request.dir.replace(/^~/,process.env.HOME);
 | |
|         if (request.mimetype.indexOf('text')==0) {
 | |
|           fs.writeFileSync(request.dir+'/'+request.file,request.data,'utf8',{});
 | |
|         } else if (request.mimetype.indexOf('binary')!=-1) {
 | |
|           fs.writeFileSync(request.dir+'/'+request.file,Buffer(request.data),'binary',{});
 | |
|         }
 | |
|         break;
 | |
|       case 'shell':
 | |
|         status=null;data=null;
 | |
|         var pro = proc.exec('cd '+request.dir+';'+request.exec, function (err,stdout,stderr) {
 | |
|           data=stdout;
 | |
|           if (stderr) date = data + '\n' + stderr;
 | |
|           print(data)
 | |
|           if (status!=null) 
 | |
|             reply(response,JSON.stringify({status:status,reply:data,handle:request.handle}))        
 | |
|         });
 | |
|         pro.on('exit', function (code) {
 | |
|           if (data==null) status=code;
 | |
|           else
 | |
|             reply(response,JSON.stringify({status:code,reply:data,handle:request.handle}))        
 | |
|         });
 | |
|         return;  // reply send on exit or error
 | |
|         break;
 | |
|       dedault:
 | |
|         status=execute(request,response);
 | |
|     }
 | |
|   } catch (e) {
 | |
|     status=e.toString();
 | |
|   }
 | |
|   // print(status)
 | |
|   reply(response,JSONfn.stringify({status:status,reply:data,handle:request.handle}))
 | |
| }
 | |
| 
 | |
| function isThisLocalhost(ip) {
 | |
|   return ip.indexOf("127.0.0.1")==0 || 
 | |
|          ip.indexOf("::ffff:127.0.0.1") == 0 || 
 | |
|          ip.indexOf("::1") == 0 || 
 | |
|          ip.indexOf("localhost") == 0;
 | |
| }
 | |
| 
 | |
| function proxy(method,headers,path,response) {
 | |
|   // console.log(method,headers,path);
 | |
|   // TODO: curreltly assumes binary requests...
 | |
|   if (config.verbose) print('proxy '+path);
 | |
|   if (method=='GET') get(path,function (data,headers) {
 | |
|     // console.log(headers,data.length);
 | |
|     headers['access-control-allow-origin']='*';
 | |
|     response.writeHead(200,headers||{});
 | |
|     response.write(data);
 | |
|     response.end();
 | |
|   })
 | |
| }
 | |
| 
 | |
| function server () {
 | |
|   var dirCache=[];
 | |
|   var webSrv = http.createServer(function (request,response) {
 | |
|     // only local requests are accepted
 | |
|     if (!isThisLocalhost(request.headers.host)) return;
 | |
|   
 | |
|     var body,header,sep,query,res,now,path,
 | |
|         rid = request.connection.remoteAddress+':'+request.connection.remotePort;
 | |
|     
 | |
|     if (config.verbose) print(request.url,request.connection.remoteAddress,request.connection.remotePort);
 | |
|     if (request.url.length) 
 | |
|       query=parseQueryString(request.url);
 | |
|     else 
 | |
|       query={}
 | |
| 
 | |
|     path=request.url.match(/\/([^?]+)/);
 | |
|     if (path) path=path[1];
 | |
|     if (config.verbose) print(query,path);
 | |
|     now=time()
 | |
|     if (/^http[s]*/.test(path)) {
 | |
|       // proxy service
 | |
|       return proxy(request.method,request.headers,path,response);
 | |
|     }
 | |
|     switch (request.method) {
 | |
|       case 'GET':
 | |
|         if (query.handle && Consoles[query.handle]) {
 | |
|           reply(response,JSONfn.stringify({
 | |
|             handle:query.handle,
 | |
|             stdout:Consoles[query.handle].stdout,
 | |
|             stderr:Consoles[query.handle].stderr,
 | |
|             output:Consoles[query.handle].output,
 | |
|             tid:Consoles[query.handle].tid++,
 | |
|             exit:Consoles[query.handle].exit,
 | |
|           }));
 | |
|           Consoles[query.handle].stdout=[];
 | |
|           Consoles[query.handle].stderr=[];
 | |
|         } else if (path) {
 | |
|           try {
 | |
|             if (path[0]!='/' && dirCache[rid]) path=dirCache[rid]+'/'+path;
 | |
|             else dirCache[rid]=Path.dirname(path);
 | |
|             var data=fs.readFileSync(path,'utf8');
 | |
|             if (config.verbose) print('Loading '+path);
 | |
|             reply(response,data,{
 | |
|               'Content-Type': 'text/html; charset=UTF-8',
 | |
|               'Cross-Origin-Opener-Policy': 'same-origin',
 | |
|               'Cross-Origin-Embedder-Policy': 'require-corp',
 | |
|             });
 | |
|           } catch (e) {
 | |
|             if (config.verbose) print(e.toString())
 | |
|             reply(response,e.toString());
 | |
|           }
 | |
|         }
 | |
|         break;
 | |
|         
 | |
|       case 'POST':
 | |
|         body = '';
 | |
|         request.on('data', function (chunk) {
 | |
|           body = body + chunk;
 | |
|         });
 | |
|         request.on('end', function () {
 | |
|           var cmd,stat;
 | |
|           // handle copy request {id:string,data:string}
 | |
|           try {
 | |
|             // print(body)
 | |
|             cmd=JSONfn.parse(body)
 | |
|             cmd.handle=config.handleIndex++;
 | |
|             rpc(cmd,response)  
 | |
|           } catch (err) {
 | |
|             log(err.toString())
 | |
|             reply(response,JSONfn.stringify({err:err.toString()}));
 | |
|           }
 | |
|         });
 | |
|         break;
 | |
|     }
 | |
|   })
 | |
|   
 | |
|   webSrv.on("connection", function (socket) {
 | |
|       // socket.setNoDelay(true);
 | |
|   });
 | |
| 
 | |
|   webSrv.on("error", function (err) {
 | |
|     log(err)
 | |
|     process.exit();
 | |
|   });
 | |
| 
 | |
|   webSrv.listen(config.PORT,function (err) {
 | |
|     log('HTTP Service started (http://localhost:'+config.PORT+')');
 | |
|   });
 | |
|  
 | |
|   
 | |
|   // Start garbage collector
 | |
|   gc=setInterval(function () {
 | |
|     var now = time();
 | |
|   },1000);
 | |
|   
 | |
|   if (WebSocket) {
 | |
|     // Start a connection-based WebSocket Server
 | |
|     var wss = new WebSocket.Server({ port: config.PORTWS })
 | |
| 
 | |
|     wss.on('connection', function (ws) {
 | |
|       log('ws.connection.open')
 | |
|       ws.on('message', function (message) {
 | |
|         var cmd, response = {
 | |
|           write     : function (data) { ws.send (data) },
 | |
|           writeHead : function () {},
 | |
|           end       : function () {}
 | |
|         };
 | |
|         try {
 | |
|             // print(body)
 | |
|             cmd=JSONfn.parse(message)
 | |
|             cmd.handle=config.handleIndex++;
 | |
|             rpc(cmd,response)            
 | |
|         } catch (err) {
 | |
|             log(err.toString())
 | |
|             reply(response,JSONfn.stringify({err:err.toString()}));
 | |
|         }
 | |
|       })
 | |
|       ws.on('error', function (err) {
 | |
|         console.log(err);
 | |
|       })
 | |
|       ws.on('close', function () {
 | |
|         console.log('ws.connection.close')
 | |
|       });
 | |
|     })
 | |
|     wss.on('error', function (error) {
 | |
|       console.log(error)
 | |
|     }) 
 | |
|     log('WebSocket Service started (ws://localhost:'+config.PORTWS+')');
 | |
|   }
 | |
|   log('WEB Processor Ver. '+config.version+' started.');
 | |
|   return webSrv;
 | |
| }
 | |
| 
 | |
| server()
 |