Mon 21 Jul 22:43:21 CEST 2025

This commit is contained in:
sbosse 2025-07-21 22:47:50 +02:00
parent bd72de8968
commit 7511972ed0

507
js/dos/appl/shell.js Normal file
View File

@ -0,0 +1,507 @@
/**
** ==============================
** 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();