470 lines
14 KiB
JavaScript
470 lines
14 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: 23.9.2016
|
|
** $VERSION: 1.1.17
|
|
**
|
|
** $INFO:
|
|
**
|
|
** Standard Request Command Line Application
|
|
**
|
|
** $ENDOFINFO
|
|
*/
|
|
var log = 0;
|
|
|
|
var Io = Require('com/io');
|
|
//Io.trace_open('/tmp/std.trace');
|
|
|
|
if (typeof Shell == 'object') Io.set_stdout(Shell.stdout);
|
|
|
|
var Net = Require('dos/network');
|
|
var Sch = Require('dos/scheduler');
|
|
var Conn = Require('dos/connection');
|
|
var Std = Require('dos/std');
|
|
var Dns = Require('dos/dns');
|
|
var Cs = Require('dos/capset');
|
|
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 Args = Comp.args;
|
|
var Status = Net.Status;
|
|
var Command = Net.Command;
|
|
|
|
var trace = Io.tracing;
|
|
|
|
var options = {
|
|
afs : undefined,
|
|
bip:'localhost',
|
|
bport:3001,
|
|
broker: true,
|
|
caps:[],
|
|
cmd:[Command.STD_TOUCH,Command.STD_AGE],
|
|
default:false,
|
|
delay:0,
|
|
dip : 'localhost',
|
|
dns : undefined,
|
|
dports : [],
|
|
echo:false,
|
|
env:{},
|
|
hostname:Io.hostname(),
|
|
hostport:undefined,
|
|
hostsrv:false,
|
|
http:false,
|
|
interval:1000,
|
|
keepalive:true,
|
|
links:[],
|
|
maxlive:8,
|
|
monitor:0,
|
|
myip:'localhost',
|
|
print : false,
|
|
root:'/',
|
|
run:1,
|
|
servmode:false,
|
|
tcpnet:1,
|
|
verbose:0
|
|
};
|
|
|
|
var help=false;
|
|
var shift='';
|
|
|
|
var env={};
|
|
options.env=env;
|
|
var argv = Io.getargs();
|
|
|
|
var out = function (s) {Io.out('[GC] '+s)};
|
|
|
|
function err(msg) {
|
|
out('Error: gc '+Comp.array.tail(argv,2)+' => '+msg);
|
|
Io.exit();
|
|
}
|
|
|
|
|
|
if (typeof Shell == 'object') Io.set_args(Shell.args);
|
|
Args.parse(argv, [
|
|
[['-h','-help'],0,function() {help=true}],
|
|
[['-v','-verbose'],0,function() {options.verbose++;options.echo=true}],
|
|
[['-d','-default'],0,function() {options.default=true;}],
|
|
['-monitor',0,function() {options.monitor++;}],
|
|
['-print',0,function() {options.print=true;}],
|
|
['-delay',1,function(val) {options.delay=Perv.int_of_string(val);}],
|
|
['-interval',1,function(val) {options.interval=Perv.int_of_string(val);}],
|
|
['-run',1,function(val) {options.run=Perv.int_of_string(val);}],
|
|
['-dns',1,function(val) {options.dns=val;}],
|
|
['-afs',1,function(val) {options.afs=val;}],
|
|
['-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;}],
|
|
['-fcap',1,function(val){options.fcap=val}],
|
|
[function(val){
|
|
options.dns=val;
|
|
}]
|
|
],2);
|
|
|
|
|
|
if (help) {
|
|
Io.out('usage: '+argv[0]+' [<DNS server>]'+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(' [-help -h -v -verbose -monitor]');
|
|
Io.out(' [-delay <millisec>] Start-up delay');
|
|
Io.out(' [-interval <millisec>] Loop interval');
|
|
Io.out(' [-root <path>] DNS Root path (default '+options.root+')');
|
|
Io.out(' [-afs <capfile|cap>] AFS server capability');
|
|
Io.out(' [-dns <capfile|cap>] DNS server capability');
|
|
Io.out(' [-run <number of service loop runs>] 0:infinite loop');
|
|
Io.out(' [-default -d] Ask broker server for default DNS');
|
|
return;
|
|
}
|
|
|
|
|
|
options.privhostport = Net.uniqport();
|
|
options.pubhostport = Net.prv2pub(options.privhostport);
|
|
|
|
if (options.echo) out('['+Net.Print.port(options.pubhostport)+'] '+argv[1]+' '+
|
|
(options.cmd[0]?Command.print(options.cmd[0]):'')+
|
|
(options.cmd[1]?' '+Command.print(options.cmd[1]):'')+ ' ' + options.caps);
|
|
|
|
var scheduler = Sch.TaskScheduler();
|
|
scheduler.Init();
|
|
//scheduler.log(2);
|
|
|
|
|
|
|
|
// Set-up the network environment ..
|
|
// typeof options : {http,tcpnet,dports,bip,bport,myip,verbose}
|
|
var network = Conn.setup(options);
|
|
|
|
var StdInt = Std.StdInt(network.rpc);
|
|
var DnsInt = Dns.DnsInt(network.rpc);
|
|
var CsInt = Cs.CsInt(network.rpc);
|
|
|
|
var cap;
|
|
if (env.rootdir) {
|
|
DnsInt.set_rootdir(env.rootdir);
|
|
}
|
|
|
|
|
|
var schedules=[];
|
|
|
|
var stat,data;
|
|
|
|
function action () {
|
|
var aged,
|
|
cap,
|
|
cs,
|
|
csnew,
|
|
capp,
|
|
dir,
|
|
error,
|
|
failed0,
|
|
path,
|
|
remain,
|
|
row,
|
|
rowi,
|
|
rows,
|
|
stat=Status.STD_UNKNOWN,
|
|
touched=0,
|
|
trash=[],
|
|
n;
|
|
|
|
function statcb(_stat) {stat=_stat};
|
|
function resolve (name,cb) {
|
|
var cap,cp;
|
|
if (env.rootdir) {
|
|
/*
|
|
** Look-up from DNS ...
|
|
*/
|
|
DnsInt.dns_lookup(env.rootdir,name,function (_stat,_cs) {
|
|
if (_stat==Status.STD_OK) cb(_stat,CsInt.cs_to_cap(_cs));
|
|
else cb(_stat);
|
|
})
|
|
} else if (Io.exists(name)) {
|
|
/*
|
|
** It is a capability file
|
|
*/
|
|
cap = Net.cap_of_file(name);
|
|
if (cap) {
|
|
env.rootdir=options.dns=CsInt.cs_singleton(cap);
|
|
cb(Status.STD_OK,cap);
|
|
} else {
|
|
err('Invalid capability file: '+name);
|
|
}
|
|
|
|
} else {
|
|
/*
|
|
** Is it a capability string?
|
|
*/
|
|
cp=Net.Parse.capability(name,0);
|
|
if (cp==undefined) {
|
|
/*
|
|
** It is a port string?
|
|
*/
|
|
cp=Net.Parse.port(name,0);
|
|
if (cp!=undefined) {
|
|
cap=Net.Capability(cp.port);
|
|
}
|
|
} else {
|
|
cap=cp.cap;
|
|
}
|
|
if (cp==undefined) {
|
|
err('Invalid capability or port: '+name);
|
|
}
|
|
env.rootdir=options.dns=CsInt.cs_singleton(cap);
|
|
cb(Status.STD_OK,cap);
|
|
}
|
|
}
|
|
path=options.root;
|
|
|
|
function scan (rootcs,path) {
|
|
var stat=Status.STD_UNKNOWN,
|
|
remain,dir,cs,msg,info,
|
|
entry;
|
|
function statcb(_stat,_msg) {stat=_stat;msg=_msg;};
|
|
function err(msg) {out(msg); failed++; error=Status.STD_NOTNOW;};
|
|
B([
|
|
function () {
|
|
if (options.verbose) out('Scanning '+path+', root='+Cs.Print.capset(rootcs));
|
|
DnsInt.dns_list(rootcs,function (_stat,_dir) {
|
|
stat=_stat; dir=_dir;
|
|
});
|
|
},
|
|
function () {
|
|
rowi=0;
|
|
if (stat==Status.STD_OK)
|
|
L(
|
|
function (index) {rowi=index; return index<dir.di_rows.length},
|
|
[
|
|
function () {
|
|
// console.log(rows[index].name);
|
|
// console.log(dir.di_rows[rowi])
|
|
error=false;
|
|
entry=path+(path=='/'?'':'/')+
|
|
dir.di_rows[rowi].de_name;
|
|
DnsInt.dns_lookup(rootcs,dir.di_rows[rowi].de_name,function (_stat,_cs){
|
|
stat=_stat;
|
|
cs=_cs;
|
|
})
|
|
},
|
|
function () {
|
|
if (stat==Status.STD_OK) {
|
|
// get info
|
|
cap=CsInt.cs_to_cap(cs);
|
|
if (cap) StdInt.std_info(cap,statcb);
|
|
} else if (!error) {
|
|
err('DNS lookup of '+entry+' failed: '+Status.print(stat));
|
|
}
|
|
|
|
},
|
|
function () {
|
|
if (stat==Status.RPC_FAILURE) {
|
|
if (trash[entry]==undefined) trash[entry]=options.maxlive;
|
|
else {
|
|
trash[entry]--;
|
|
if (trash[entry]==0) {
|
|
out('Deleting '+entry);
|
|
DnsInt.dns_delete(rootcs,dir.di_rows[rowi].de_name,function (stat) {
|
|
if (stat!=Status.STD_OK)
|
|
err(entry+' not deleted: '+Status.print(stat));
|
|
});
|
|
}
|
|
}
|
|
}
|
|
else if (stat==Status.STD_OK) {
|
|
// touch it
|
|
info=msg;
|
|
if (cap) StdInt.std_touch(cap,statcb);
|
|
if (trash[entry]!=undefined) trash[entry]=undefined;
|
|
} else if (!error)
|
|
err(entry+' not responding: '+Status.print(stat));
|
|
},
|
|
function () {
|
|
if (stat==Status.STD_OK) {
|
|
touched++;
|
|
if (options.verbose) out('Touched '+entry);
|
|
if (info && Comp.string.startsWith(info,'/D'))
|
|
scan(cs,entry);
|
|
} else if (!error)
|
|
err('Touching of '+entry+' failed: '+Status.print(stat));
|
|
|
|
}
|
|
],
|
|
[
|
|
function () {}
|
|
],
|
|
function (stat) {console.log(stat)}
|
|
);
|
|
else
|
|
out('DNS list of '+path+' failed: '+Status.print(stat));
|
|
|
|
}
|
|
]);
|
|
}
|
|
L(
|
|
function(index) {n=index; return options.run==0?true:index<options.run;},
|
|
[
|
|
function () {
|
|
if (options.verbose) out('Run '+n+' ..');
|
|
touched=0;
|
|
failed=0;
|
|
error=Status.STD_OK;
|
|
},
|
|
function () {
|
|
stat=Status.STD_NOTNOW;
|
|
cap=CsInt.cs_to_cap(env.rootdir);
|
|
if (cap) StdInt.std_touch(cap,statcb);
|
|
},
|
|
function () {
|
|
if (stat==Status.STD_OK) scan(env.rootdir,path);
|
|
else error=stat;
|
|
},
|
|
function () {
|
|
if (error) return;
|
|
// age it
|
|
if (options.verbose) out(' [touched='+touched+', failed='+failed+']');
|
|
if (options.verbose) out('Aging (I) '+Net.Print.capability(options.dns));
|
|
if (failed==0) {
|
|
StdInt.std_age(options.dns,statcb);
|
|
aged++;
|
|
} else {
|
|
stat=Status.STD_NOTNOW;
|
|
error=stat;
|
|
}
|
|
},
|
|
function () {
|
|
if (error) return;
|
|
error=stat;
|
|
if (stat!=Status.STD_OK) {
|
|
out('Aging (I) failed: '+Status.print(stat));
|
|
}
|
|
},
|
|
function () {
|
|
if (error) return;
|
|
if (stat==Status.STD_OK && options.afs) {
|
|
if (options.verbose) out('Aging (II) '+Net.Print.capability(options.afs));
|
|
StdInt.std_age(options.afs,statcb);
|
|
}
|
|
},
|
|
function () {
|
|
if (!error && options.afs && stat!=Status.STD_OK) {
|
|
out('Aging (II) failed: '+Status.print(stat));
|
|
error=stat;
|
|
}
|
|
// if (stat!=Status.STD_OK || error) throw stat;
|
|
if (error) out('Run '+n+' failed: '+Status.print(error));
|
|
Sch.Delay(options.interval)
|
|
}
|
|
],
|
|
[
|
|
function () {
|
|
out('Exiting.');
|
|
process.exit(0)
|
|
}
|
|
],
|
|
function (stat) {
|
|
out('Failed: '+Status.print(stat));
|
|
}
|
|
);
|
|
|
|
|
|
B([
|
|
function () {
|
|
if (options.delay) Delay(options.delay);
|
|
},
|
|
function () {
|
|
out('Starting ..');
|
|
resolve(options.dns||options.root,function (_stat,cap) {
|
|
if (_stat==Status.STD_OK) {
|
|
out('Using DNS cap '+Net.Print.capability(cap));
|
|
options.dns=cap;
|
|
} else {
|
|
out('No DNS resolved!: '+Status.print(_stat));
|
|
}
|
|
stat=_stat;
|
|
});
|
|
},
|
|
function () {
|
|
if (stat!=Status.STD_OK) throw stat;
|
|
if (options.afs) resolve(options.afs,function (stat,cap) {
|
|
if (stat==Status.STD_OK) {
|
|
out('Using AFS cap '+Net.Print.capability(cap));
|
|
options.afs=cap;
|
|
}
|
|
});
|
|
else if (options.dns) DnsInt.dns_getdefafs(env.rootdir,function (stat,cap) {
|
|
if (stat==Status.STD_OK) {
|
|
out('Using default AFS cap '+Net.Print.capability(cap));
|
|
options.afs=cap;
|
|
}
|
|
});
|
|
},
|
|
]);
|
|
}
|
|
|
|
action ();
|
|
|
|
var hostsrv;
|
|
if (options.hostsrv)
|
|
hostsrv = HostSrv.HostServer(scheduler,
|
|
network.rpc,
|
|
options,
|
|
'GC.'+options.hostname,
|
|
options.env);
|
|
|
|
|
|
var interrupt=0;
|
|
|
|
process.on('SIGINT', function () {
|
|
out('Got SIGINT ..');
|
|
interrupt++;
|
|
if (interrupt>1) process.exit(2);
|
|
});
|
|
|
|
|
|
if (options.verbose) out('My host port: '+Net.Print.port(options.pubhostport));
|
|
|
|
|
|
// Start up the network ..
|
|
network.init(network.start);
|
|
|
|
scheduler.Run();
|