508 lines
		
	
	
		
			16 KiB
		
	
	
	
		
			JavaScript
		
	
	
	
	
	
			
		
		
	
	
			508 lines
		
	
	
		
			16 KiB
		
	
	
	
		
			JavaScript
		
	
	
	
	
	
| /**
 | |
|  **      ==============================
 | |
|  **       O           O      O   OOOO
 | |
|  **       O           O     O O  O   O
 | |
|  **       O           O     O O  O   O
 | |
|  **       OOOO   OOOO O     OOO  OOOO
 | |
|  **       O   O       O    O   O O   O
 | |
|  **       O   O       O    O   O O   O
 | |
|  **       OOOO        OOOO O   O OOOO
 | |
|  **      ==============================
 | |
|  **      Dr. Stefan Bosse http://www.bsslab.de
 | |
|  **
 | |
|  **      COPYRIGHT: THIS SOFTWARE, EXECUTABLE AND SOURCE CODE IS OWNED
 | |
|  **                 BY THE AUTHOR(S).
 | |
|  **                 THIS SOURCE CODE MAY NOT BE COPIED, EXTRACTED,
 | |
|  **                 MODIFIED, OR OTHERWISE USED IN A CONTEXT
 | |
|  **                 OUTSIDE OF THE SOFTWARE SYSTEM.
 | |
|  **
 | |
|  **    $AUTHORS:     Stefan Bosse
 | |
|  **    $INITIAL:     (C) 2015-2017 bLAB
 | |
|  **    $CREATED:     26-5-15.
 | |
|  **    $VERSION:     1.2.17
 | |
|  **
 | |
|  **    $INFO:
 | |
|  **
 | |
|  **  DOS: DOS Terminal Shell
 | |
|  **
 | |
|  **    $ENDOFINFO
 | |
|  */
 | |
| "use strict";
 | |
| var log = 0;
 | |
| var version = "1.2"
 | |
| var Io = Require('com/io');
 | |
| //Io.trace_open('/tmp/shell.trace');
 | |
| 
 | |
| var Net = Require('dos/network');
 | |
| var Buf = Require('dos/buf');
 | |
| var Sch = Require('dos/scheduler');
 | |
| var Conn = Require('dos/connection');
 | |
| var Rpc = Require('dos/rpc');
 | |
| var Std = Require('dos/std');
 | |
| var Router = Require('dos/router');
 | |
| var util = Require('util');
 | |
| var Comp = Require('com/compat');
 | |
| var assert = Comp.assert;
 | |
| var String = Comp.string;
 | |
| var Array = Comp.array;
 | |
| var Perv = Comp.pervasives;
 | |
| var Printf = Comp.printf;
 | |
| var Filename = Comp.filename;
 | |
| var Obj = Comp.obj;
 | |
| var Args = Comp.args;
 | |
| var Status = Net.Status;
 | |
| var Command = Net.Command;
 | |
| var Fs = Require('fs');
 | |
| var Dns = Require('dos/dns');
 | |
| var Cs = Require('dos/capset');
 | |
| var Getenv = Require('com/getenv');
 | |
| var Ash = Require('dos/ash');
 | |
| var HostSrv = Require('dos/hostsrv');
 | |
| 
 | |
| var trace = Io.tracing;
 | |
| 
 | |
| var options = {
 | |
|   bip:'localhost',
 | |
|   bport:3001,
 | |
|   broker: true,
 | |
|   default:false,
 | |
|   dip : 'localhost',
 | |
|   dports : [],
 | |
|   env:{},
 | |
|   hostport:undefined,
 | |
|   hostsrv:false,
 | |
|   http:false,
 | |
|   keepalive:true,
 | |
|   links:[],
 | |
|   myip:'localhost',
 | |
|   monitor:false,
 | |
|   servmode:false,
 | |
|   tcpnet:1,
 | |
|   verbose:0
 | |
| };
 | |
| 
 | |
| options.privhostport = Net.uniqport();
 | |
| options.pubhostport = Net.prv2pub(options.privhostport);
 | |
| 
 | |
| var env = Ash.Env();
 | |
| var help=false;
 | |
| var argv = Io.getargs();
 | |
| 
 | |
| options.env = env;
 | |
| 
 | |
| var readline = Require('dos/ext/readline');
 | |
| 
 | |
| Args.parse(argv, [
 | |
|     [['-help','-h'],0,function() {help=true;}],
 | |
|     ['-broker',1,function(val){
 | |
|       var tokens = Comp.string.split(':',val);
 | |
|       if (tokens.length==1)
 | |
|         options.bip=val;
 | |
|       else {
 | |
|         options.bip=tokens[0];      
 | |
|         options.bport=Perv.int_of_string(tokens[1])
 | |
|       }
 | |
|     }],
 | |
|     ['-dip',1,function(val){options.dip=val}],
 | |
|     ['-D',1,function(val){options.dports.push(Perv.int_of_string(val))}],
 | |
|     ['-L',2,function(val1,val2){options.links.push([Perv.int_of_string(val1),getip(val2),getipport(val2)])}],
 | |
|     ['-nokeepalive',0,function(val){options.keepalive=false;}],
 | |
|     ['-T',0,function(val){options.tcpnet=1;options.http=false;}],
 | |
|     ['-T2',0,function(val){options.tcpnet=2;options.http=false;}],
 | |
|     ['-H',0,function(val){options.http=true;options.tcpnet=0;}],
 | |
|     ['-server',0,function(val){options.servmode=true;}],
 | |
|     [['-default','-d'],0,function(val){options.default=true;}],
 | |
|     ['-monitor',0,function () {options.monitor++; out('Setting monitor to level '+options.monitor); }],
 | |
|     [['-v','-verbose'],0,function(val){options.verbose++; out('Setting verbosity to level '+options.verbose);}]
 | |
| ]);
 | |
| 
 | |
| if (help) {
 | |
|     Io.out('usage: '+argv[0]+' '+argv[1]);
 | |
|     Io.out('  [-H -T -T2]  Enable connection service');
 | |
|     Io.out('    T: TCPIP, 1-ch H:HTTP T2: TCPIP, 2-ch');
 | |
|     Io.out('    H: bport, T: bport+100');
 | |
|     Io.out('    (Default: -T)');
 | |
|     Io.out('  [-D <port>] UDP Server Port');
 | |
|     Io.out('  [-L <src port> <UDP dst [address:]port] UDP P2P Connection');
 | |
|     Io.out('  [-nokeepalive] Establish a new conncetion for each message.');
 | |
|     Io.out('  [-broker <ip[:ipport]>]  Broker URL (Default: '+options.bip+': HTTP '+options.bport+' TCPNET '+(options.bport+100)+')');
 | |
|     Io.out('  [-dip <VLC UDP server IP>] (Default: '+options.dip+')');
 | |
|     Io.out('  [-host <port>] Set Host Port');
 | |
|     Io.out('  [-root <cap|capfile>] Set Root Cap.');
 | |
|     Io.out('  [+root <cap|capfile>] Appennd Root Cap.');
 | |
|     Io.out('  [-default, -d] Ask broker server for default DNS => DNS root => Shell root!');
 | |
|     Io.out('  [-help -h -v -verbose -monitor]');
 | |
|     Io.out('  [-e <script>] Execute a script');
 | |
|     return;
 | |
| }
 | |
| function fail(msg) {
 | |
|     Io.stderr('[JASH]: Fatal error: '+msg+'\n');
 | |
|     Io.exit(0);
 | |
| }
 | |
| function out(msg) {
 | |
|     Io.stdout('[JASH]: '+msg+'\n');
 | |
| }
 | |
| function warn(msg) {
 | |
|     Io.stderr('[JASH]: Warning: '+msg+'\n');
 | |
| }
 | |
| var scheduler = Sch.TaskScheduler();
 | |
| scheduler.Init();
 | |
| 
 | |
| // Set-up the network environment ..
 | |
| // typeof options : {http,tcpnet,dports,bip,bport,myip,verbose}
 | |
| var network = Conn.setup(options);
 | |
| 
 | |
| 
 | |
| var todo=[];
 | |
| 
 | |
| var router = network.router;
 | |
| var rpc = network.rpc;
 | |
| 
 | |
| 
 | |
| 
 | |
| var StdInt = Std.StdInt(rpc);
 | |
| var DnsInt = Dns.DnsInt(rpc);
 | |
| var CsInt = Cs.CsInt(rpc);
 | |
| var ash = Ash.Ash(rpc,scheduler,env);
 | |
| 
 | |
| if (!Comp.isNodeJS()) {
 | |
|     fail('Shell can only be executed on the node.js platform.');
 | |
| }
 | |
| 
 | |
| 
 | |
| var cap;
 | |
| if (Obj.isString(env.rootdir)) {
 | |
|     cap=Net.Parse.capability(env.rootdir,0);
 | |
|     if(cap!=undefined) {
 | |
|         env.rootdir=CsInt.cs_singleton(cap.cap);
 | |
|         DnsInt.set_rootdir(env.rootdir);
 | |
|     }
 | |
| } else env.rootdir=undefined;
 | |
| if (Obj.isString(env.workdir)) {
 | |
|     cap=Net.Parse.capability(env.workdir,0);
 | |
|     if(cap!=undefined) {
 | |
|         env.workdir=CsInt.cs_singleton(cap.cap);
 | |
|     }
 | |
| } else env.workdir=undefined;
 | |
| 
 | |
| 
 | |
| var stat=Status.STD_OK;
 | |
| Args.parse(argv, [
 | |
|     [['-root','-r'],1,function(val) {
 | |
|         cap = Net.Parse.capability(val, 0);
 | |
|         if (cap != undefined) {
 | |
|             env.rootdir = CsInt.cs_singleton(cap.cap);
 | |
|             if (env.workdir == undefined) env.workdir = env.rootdir;
 | |
|         } else {
 | |
|             /*
 | |
|             ** Capabiliy file path?
 | |
|              */
 | |
|             cap = Net.cap_of_file(val);
 | |
|             env.rootdir = CsInt.cs_singleton(cap);
 | |
|             if (env.workdir == undefined) env.workdir = env.rootdir;
 | |
|         }
 | |
|     }],
 | |
|     [['+root','+r'],1,function(val) {
 | |
|         var dnscap,dnscs;
 | |
|         dnscap = Net.Parse.capability(val, 0);
 | |
|         if (dnscap == undefined) {
 | |
|             /*
 | |
|              ** Capabiliy file path?
 | |
|              */
 | |
|             dnscap = Net.cap_of_file(val);
 | |
|         } else dnscap=dnscap.cap;
 | |
|         if (dnscap != undefined) {            
 | |
|             todo.push([
 | |
|                 function () {
 | |
|                     var name = Net.Print.port(dnscap.cap_port);
 | |
|                     dnscs = CsInt.cs_singleton(dnscap);
 | |
|                     out('Append DNS ROOT: ' + Net.Print.capability(dnscap));
 | |
|                     hostsrv.append('dns/'+name, dnscs, function (_stat) {stat=_stat});
 | |
|                     if (stat != Status.STD_OK) out('Cannot append ' + name + ': ' + Status.print(stat));
 | |
|                     stat = hostsrv.append('dns/default', dnscs);
 | |
|                 },
 | |
|                 function () {
 | |
|                     if (dnscs != undefined && env.defafs==undefined) {
 | |
|                         DnsInt.dns_getdefafs(dnscs,function(_stat,_cap) {
 | |
|                             out('Default AFS: '+Status.print(_stat)+' is '+ Net.Print.capability(_cap));
 | |
|                             if (_stat==Status.STD_OK) {
 | |
|                                 env.defafs=_cap;
 | |
|                                 var name=Net.Print.port(_cap.cap_port);
 | |
|                                 var afscs = CsInt.cs_singleton(_cap);
 | |
|                                 out('Append AFS: ' + Net.Print.capability(_cap));
 | |
|                                 hostsrv.append('afs/'+name,afscs, function (_stat) {stat=_stat});
 | |
|                                 if (stat!=Status.STD_OK) out('Cannot append '+name+': '+Status.print(stat));
 | |
|                             }
 | |
|                         })
 | |
|                     }
 | |
|                 }
 | |
| 
 | |
|             ])
 | |
|         } else {
 | |
|             out('DNS_ROOT: invalid capability (or file) ' + val);
 | |
|         }
 | |
|     }],
 | |
|     [['-host','-h'],1,function(val) {
 | |
|         var port = Net.Parse.port(val, 0);
 | |
|         if (port != undefined) {
 | |
|             options.hostport = port.port;
 | |
|             todo.push([
 | |
|                 function () {
 | |
|                     DnsInt.dns_getrootcap(options.hostport, function (_stat, _cap) {
 | |
|                             stat = _stat;
 | |
|                             if (stat==Status.STD_OK) {
 | |
|                                 env.rootdir = CsInt.cs_singleton(_cap);
 | |
|                             }
 | |
|                     })
 | |
|                 },
 | |
|                 function () {
 | |
|                     if (stat != Status.STD_OK) {
 | |
|                         Io.out('DNS_ROOT: DNS_GETROOT failed for host ' +
 | |
|                             Net.Print.port(options.hostport) + ': ' +
 | |
|                             Status.print(stat));
 | |
|                         rl.setPrompt(env.prompt());
 | |
|                         rl.prompt();
 | |
|                     } else {
 | |
|                         Io.out('DNS ROOT: '+Net.Print.capability(CsInt.cs_to_cap(env.rootdir)));
 | |
|                         if (env.workdir == undefined) env.workdir = env.rootdir;
 | |
|                     }
 | |
|                 }
 | |
|             ]);
 | |
|         }
 | |
| 
 | |
|     }],
 | |
|     [['-exec','-e'],1,function(val) {
 | |
|         if (!Io.exists(val)) {
 | |
|             fail('file not found: '+val);
 | |
|         } else {
 | |
|             var file=Io.read_file(val);
 | |
|             if (file==undefined) fail('can\'t read file '+val);
 | |
|             var lines=String.split('\n',file);
 | |
|             Array.concat(env.script,lines);
 | |
|         }
 | |
|     }]
 | |
| ]);
 | |
| 
 | |
| var action=false;
 | |
| /**
 | |
|  *
 | |
|  * @type {undefined|hostserver}
 | |
|  */
 | |
| var hostsrv=undefined;
 | |
| if (options.hostport==undefined) 
 | |
|   hostsrv=HostSrv.HostServer(scheduler,rpc,options);
 | |
| 
 | |
| todo.push([
 | |
|     function () {
 | |
|         /*
 | |
|          ** Was the root DNS root already set?
 | |
|          */
 | |
|         if (env.rootdir==undefined && hostsrv!=undefined) {
 | |
|             action=true;
 | |
|             /*
 | |
|              ** Get the DNS root from our embedded host server...
 | |
|              */
 | |
|             Io.out('Using local host server DNS ..');
 | |
|             env.rootdir = Cs.Copy.capset(hostsrv.rootcs);
 | |
|             env.hostname = Net.Print.port(options.pubhostport);
 | |
|             stat=Status.STD_OK;
 | |
|         }
 | |
|     },
 | |
|     function () {
 | |
|         if (action) {
 | |
|             action=false;
 | |
|             if (stat != Status.STD_OK) {
 | |
|                 Io.out('DNS_ROOT: failed for host ' +
 | |
|                 Net.Print.port(options.pubhostport) + ': ' +
 | |
|                 Status.print(stat));
 | |
|             } else {
 | |
|                 if (env.workdir == undefined) env.workdir = env.rootdir;
 | |
|             }
 | |
|         }
 | |
|         out('DNS ROOT: ' + Net.Print.capability(CsInt.cs_to_cap(env.rootdir)));
 | |
|     },
 | |
|     function () {
 | |
|         if (env.rootdir != undefined) {
 | |
|             DnsInt.dns_getdefafs(env.rootdir,function(_stat,_cap) {
 | |
|                 out('Default AFS: '+Status.print(_stat)+' is '+ Net.Print.capability(_cap));
 | |
|                 if (_stat==Status.STD_OK) {
 | |
|                     env.defafs=_cap;
 | |
|                 }
 | |
|             })
 | |
|         }
 | |
|     },
 | |
|     function () {
 | |
|         ash.dns.env.rootdir=env.rootdir;
 | |
|         ash.dns.env.workdir=env.workdir;
 | |
|     }
 | |
| ]);
 | |
| 
 | |
| 
 | |
| var rl = readline.createInterface({
 | |
|     input: process.stdin,
 | |
|     output: process.stdout,
 | |
|     completer : function (cmdline) {
 | |
|         var args = Array.filter(String.split(' ', cmdline), function (str) {
 | |
|             return str != '';
 | |
|         });
 | |
|         var completed=cmdline;
 | |
|         var choices=[];
 | |
|         var argi = 0;
 | |
|         if (args.length>0) {
 | |
|             if (String.equal(args[0],'cd') ||
 | |
|                 String.equal(args[0],'dir') ||
 | |
|                 String.equal(args[0],'del')) {
 | |
|                 choices=env.workrows;
 | |
|                 Array.iter(args,function (arg,index) {
 | |
|                     if (String.get(arg,0)!='-') argi=index;
 | |
|                 });
 | |
|                 if (args.length==1 || argi==0) {
 | |
|                     choices=env.workrows;
 | |
|                     if (choices.length==1) completed='';
 | |
|                 } else {
 | |
|                     var matches=Array.filter(choices,function (choice) {
 | |
|                         return (choice.indexOf(args[argi])!=-1);
 | |
|                     });
 | |
|                     completed = args[argi];
 | |
|                     choices = matches;
 | |
|                 }
 | |
|             }
 | |
|         }
 | |
|         return [choices,completed];
 | |
|     }
 | |
| });
 | |
| 
 | |
| if (Array.empty(env.script))
 | |
|     Io.stdout(
 | |
|     ' +------------------------------------------------+\n' +
 | |
|     ' | JASH ' + Printf.sprintf2(['v. ',['%7s',version],['%32s','']]) + '|\n'+
 | |
|     ' | JS Distributed Amoeba Virtual Machine Shell    |\n' +
 | |
|     ' +------------------------------------------------+\n\n');
 | |
| 
 | |
| 
 | |
| 
 | |
| stat=Status.STD_OK;
 | |
| var cmdline='';
 | |
| var line;
 | |
| /*
 | |
| ** Main interpreter loop
 | |
|  */
 | |
| Sch.ScheduleBlock([],function (e) {
 | |
|     Io.out('[SHELL] uncaught exception:');
 | |
|     if (typeof e != 'number') Io.printstack(e,'Shell.top');
 | |
|     else Io.out(Status.print(e));
 | |
|     process.exit(0);
 | |
| });
 | |
| 
 | |
| if (!options.servmode) {
 | |
|     var context = Sch.GetCurrent();
 | |
|     rl.on('line', function (line) {
 | |
|         Sch.Wakeup(context);
 | |
|         cmdline = line;
 | |
|     });
 | |
| 
 | |
|     rl.on('close', function () {
 | |
|         Sch.Wakeup(context);
 | |
|         stat = Status.STD_INTR;
 | |
|     });
 | |
|     Sch.ScheduleLoop(function () {
 | |
|         return (stat == Status.STD_OK);
 | |
|     }, [
 | |
|         function () {
 | |
|             if (!Array.empty(env.script)) {
 | |
|                 env.in_script = true;
 | |
|                 cmdline = Array.head(env.script);
 | |
|                 env.script = Array.tail(env.script);
 | |
|             } else {
 | |
|                 Sch.Suspend();
 | |
|                 cmdline = '';
 | |
|                 rl.setPrompt(env.prompt());
 | |
|                 rl.prompt();
 | |
|             }
 | |
|         },
 | |
|         function () {
 | |
|             var path;
 | |
|             if (stat != Status.STD_OK) throw stat;
 | |
|             ash.exec(cmdline);
 | |
|         }
 | |
|     ], [
 | |
|         function () {
 | |
|             if (!env.in_script) Io.out('\nHave a great day!');
 | |
|             process.exit(0);
 | |
|         }
 | |
|     ], function (e) {
 | |
|         if (typeof e != 'number') {
 | |
|             Io.out('[SHELL] uncaught exception:');
 | |
|             Io.printstack(e);
 | |
|         }
 | |
|         else if (e != Status.STD_INTR) {
 | |
|             Io.out('[SHELL] uncaught error:');
 | |
|             Io.out(Status.print(e));
 | |
|         }
 | |
|         if (!env.in_script) Io.out('\nHave a great day!');
 | |
|         process.exit(0);
 | |
|     });
 | |
| }
 | |
| 
 | |
| ash.register_action('import',function (args) {
 | |
|     var path;
 | |
|     args=Array.tail(args);
 | |
|     var len=args.length;
 | |
|     Sch.ScheduleLoop(function(index) {
 | |
|         path=args[index];
 | |
|         return index<len;
 | |
|         }, [
 | |
|         function() {
 | |
|             var file = Filename.basename(path);
 | |
|             var data = Io.read_file(path);
 | |
|             if (data!=undefined) {
 | |
|                 var size = data.length;
 | |
|                 var buf = Buf.Buffer();
 | |
|                 Buf.buf_of_str(buf, data);
 | |
|                 Io.out('Importing file ' + file + ' [' + size + '] ... ');
 | |
|                 ash.writefile(file, buf, function (stat, cap) {
 | |
|                     Io.out(Status.print(stat));
 | |
|                 });
 | |
|             } else {
 | |
|                 Io.out(Status.print(Status.STD_IOERR));
 | |
|             }
 | |
|         }]);
 | |
| });
 | |
| 
 | |
| ash.register_action('export',function (args) {
 | |
|     var file;
 | |
|     var stat;
 | |
|     var data,buf;
 | |
|     args=Array.tail(args);
 | |
|     var len=args.length;
 | |
|     Sch.ScheduleLoop(function(index) {
 | |
|         file=args[index];
 | |
|         return index<len;
 | |
|     }, [
 | |
|         function() {
 | |
|             Io.out('Exporting file ' + file + ' ... ');
 | |
|             ash.readfile(file, function (_stat, _buf) {
 | |
|                 stat=_stat;
 | |
|                 buf=_buf;
 | |
|                 Io.out(Status.print(stat)+' '+buf.data.length);
 | |
|                 if (stat==Status.STD_OK)
 | |
|                     data = Buf.buf_to_str(buf);
 | |
|             });
 | |
|         },
 | |
|         function () {
 | |
|             if (stat==Status.STD_OK) {
 | |
|                 stat = Io.write_file(file,data);
 | |
|                 if (stat<=0) Io.out(Status.print(Status.STD_IOERR));
 | |
|             }
 | |
| 
 | |
|         }
 | |
|     ]);
 | |
| });
 | |
| 
 | |
| Sch.ScheduleBlock(Array.flatten(todo));
 | |
| 
 | |
| // Start up the network ..
 | |
| network.init(network.start);
 | |
| 
 | |
| scheduler.Run();
 |