/** ** ============================== ** 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) 2006-2017 bLAB ** $CREATED: 10-3-16 by sbosse. ** $VERSION: 1.3.4 ** ** $INFO: ** ** JAM Standalone Node VM ** ** $ENDOFINFO */ var onexit=false; var start=false; var options = { amp:false, aport:6000, connect:[], debug:false, verbose:0 }; global.config={simulation:false}; var Io = Require('com/io'); var Comp = Require('com/compat'); var Db = Require('db/db'); var Aios = Require('jam/aios'); var Buf = Require('dos/buf'); var Net = Require('dos/network'); var Esprima = Require('parser/esprima'); var Json = Require('jam/jsonfn'); var Db = Require('db/db'); var out = function (msg) { Io.out('[JAM] '+msg)}; var jam = function (options) { var self=this; this.options = options||{}; this.verbose = options.verbose||0; if (!this.options.id) this.options.id=Aios.aidgen(); this.world = Aios.World.World([],{id:this.options.id,classes:options.classes||[]}); this.node = Aios.Node.Node({id:this.options.id,position:{x:0,y:0}},true); this.world.addNode(this.node); this.run=false; this.loopnext=none; this.looprun=false; this.loop = function () { var loop = function () { self.looprun=true; var nexttime=Aios.scheduler(); self.looprun=false; var curtime=Aios.time(); if (self.options.verbose>1) self.out('loop: nexttime='+nexttime+ ' ('+(nexttime>0?nexttime-curtime:0)+')'); if (nexttime>0) self.looprun=setTimeout(loop,nexttime-curtime); else if (nexttime<0) self.looprun=setImmediate(loop); else self.looprun=setTimeout(loop,1000); }; self.loopnext = setTimeout(loop,1); }; this.out=function (msg) { Io.out('[JAM '+self.options.id+'] '+msg) }; this.err=function (msg,err) { self.out('Error: '+msg); throw (err||'Error'); } this.warn=function (msg) { self.out('Warning: '+msg); } this.amp=options.amp; this.aport=options.aport||6000; } // Import analyzer class... var JamAnal = Require('jam/analyzer'); JamAnal.current(Aios); jam.prototype.analyze=JamAnal.jamc.prototype.analyze; jam.prototype.syntax=JamAnal.jamc.prototype.syntax; /** Add agent class to the JAM world and create sandboxed constructors. * type constructor = function|string */ jam.prototype.addClass = function (name,constructor,env) { this.world.addClass(name,constructor,env); if (this.verbose) this.out('Agent class '+name+' added to world library.'); }; /** Create and start an agent from class ac with arguments. * Ac is either already loaded (i.e., ac specifies the class name) or * AC is supplied as a constructor function (ac), a class name, or a sandboxed constructor * {fun:function,mask:{}} object for a specific level. * * type of ac = string|object|function * type of args = * [] * level = {0,1,2,3} * */ jam.prototype.create = function (ac,args,level) { var node=this.node, process=none,sac; if (level==undefined) level=1; if (Comp.obj.isFunction(ac) || Comp.obj.isObject(ac)) { // Create a sandboxed constructor function and agent process process = Aios.Code.createOn(node,ac,args,level); if (process) return process.agent.id; } else { // Use an already sandboxed constructor if (this.world.classes[ac]) process = Aios.Code.createOn(node,this.world.classes[ac][level],args); else this.out('create: Cannot find agent class '+ac); if (process) { process.agent.ac=ac; return process.agent.id; } else this.out('create: Cannot find agent class '+ac+' for level '+level); return none; } } /** Read and compile agent class templates from file * */ jam.prototype.readClass = function (file) { var ac, text, modu={}, m,p, env, interface, regex1, ast=null, all=null, off=null; if (this.options.verbose>0) this.out('Looking up agent class template(s) from '+file); modu=Require(file); if (Comp.obj.isEmpty(modu)) { if (this.options.verbose>0) this.out('Importing agent class template(s) from file '+file); if (Comp.string.get(file,0)!='/') file = './'+file; all=Io.read_file(file); ast=Esprima.parse(all, { tolerant: true, loc:true }); modu=require(file); } if (!modu) this.out('Importing of agent class template(s) from '+file+' failed (empty).'); for (m in modu) { ac=modu[m]; env={}; if (all) off=this.syntax.find(ast,'VariableDeclarator',m); if (off && off.loc) this.syntax.offset=off.loc.start.line-1; content = 'var ac = '+ac; syntax = Esprima.parse(content, {tolerant: true, loc:true }); interface = this.analyze(syntax,{classname:m,level:2,verbose:this.options.verbose||0}); for (var p in interface.activities) env[p]=p; with (env) { eval(content) }; if (options.verbose>0) this.out('Adding agent class constructor '+m+' ('+(typeof ac)+').'); this.addClass(m,ac,env); this.syntax.offset=0; } }; /** Start the JAM scheduler * */ jam.prototype.start=function () { this.run=true; this.out('Starting ..'); this.loop(); } /** Start AMP service port */ jam.prototype.startAmp = function () { var self=this; var ip = 'localhost'; this.out('Starting AMP server on port '+this.aport); this.amp = Aios.Chan.Amp({rcv:ip+':'+this.aport,snd_ip:ip,verbose:this.options.verbose}); this.amp.receiver(function (handler) { var code,agentid,stat; if (!handler) return; if (self.options.verbose>0) { self.out('AMP: got request:'); console.log(handler) }; switch (handler.cmd) { case Net.Command.PS_EXEC: code = Buf.buf_get_string(handler.buf); // console.log(code); // console.log(myJam.amp.url(handler.remote)) self.node.receive(code); break; case Net.Command.PS_STUN: agentid = Buf.buf_get_string(handler.buf); stat=Aios.kill(agentid); if (stat) self.out('Agent '+agentid+' terminated.'); break; } }); } /** Stop the JAM scheduler * */ jam.prototype.stop=function () { this.run=false; this.out('Stopping ..'); if (this.loopnext) clearTimeout(this.loopnext); } var Jam = function(options) { var obj = new jam(options); return obj; }; function usage(error) { var msg='Agent JavaScript Machine'+NL; msg += 'usage: jam [options]'+NL; msg += ' -c .js : Load an agent class template from file'+NL; msg += ' -r [,,..] : Create an agent from a class template'+NL; msg += ' -A : Start AMP service on specified port'+NL; msg += ' -L : Connect this node (from) to another (to) using AMP (url/port)'+NL; msg += ' -s : Start scheduler loop'+NL; msg += ' -v : Increase verbosity level'+NL; msg += ' -h -help --help : Print this help'+NL; msg += ' : N,S,W,E,NW,NE,SW,SE,UP,DOWN'+NL; out(msg); if (error) out(error); onexit=true; } Comp.args.parse(Io.getargs(),[ [['-h','-help','--help'],0,function () {usage()}], ['-v',0,function () {options.verbose++; out('Setting verbosity level to '+options.verbose); config.verbose=true;}], ['-s',0,function () {start=true;}], ['-d',0,function () {options.debug=true;}] ]); var myJam = Jam(options); Comp.args.parse(Io.getargs(),[ ['-c',1,function (file) { if (options.debug) myJam.readClass(file); else try { myJam.readClass(file) } catch (e) { myJam.out('Compilation failed: '+e+'.'); Io.exit(); } }], ['-A',1,function (port) { myJam.amp=true; myJam.aport=port; myJam.startAmp(); }], ['-L',3,function (dir,port1,port2) { var _options; switch (dir) { case 'N': dir=Aios.DIR.NORTH;break; case 'S': dir=Aios.DIR.SOUTH; break; case 'W': dir=Aios.DIR.WEST; break; case 'E': dir=Aios.DIR.EAST; break; default: usage('Invalid first argment of -L'); } _options={rcv:port1,snd:port2,amp:true,verbose:options.verbose}; myJam.world.connectPhy(dir,myJam.node,_options); }], ['-r',2,function (ac,args) { try { if (args.length < 2) args='[]'; var _args = Comp.array.map(Comp.string.split(',',Comp.string.trim(args,1,1)),function (arg) { try {var num=Number(arg); if (isNaN(num)) return arg; else return num;} catch (e) {return arg } }); myJam.create(ac,_args) } catch (e) { myJam.out('Failed to start agent '+ac+' '+args+': '+e); } }], ['-db',2,function (path,chan) { var res; myJam.db=Db.Sqlc(path,chan); myJam.db.init(function (res){ console.log('init: '+res); myJam.db.exec('help',function (repl) { console.log(repl); }); } ); }] ]); if (!onexit && start) myJam.start();